From e44c078ebcea9d81da6d61a0ae596a3e46e9a12d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Fri, 14 Nov 2025 09:18:36 +0100 Subject: treewide: full update in some time --- pkgs/default.nix | 27 +- pkgs/linux-openwrt-one-mediatek.patch | 2353 + pkgs/linux-openwrt-one.patch | 2508 + pkgs/linux_6_12-openwrt-one.patch | 222237 +++++++++++++++++++++++++++++++ 4 files changed, 227121 insertions(+), 4 deletions(-) create mode 100644 pkgs/linux-openwrt-one-mediatek.patch create mode 100644 pkgs/linux-openwrt-one.patch create mode 100644 pkgs/linux_6_12-openwrt-one.patch (limited to 'pkgs') diff --git a/pkgs/default.nix b/pkgs/default.nix index f80464b..3ebbe20 100644 --- a/pkgs/default.nix +++ b/pkgs/default.nix @@ -37,6 +37,7 @@ final: prev: { filesToInstall = ["build/${platform}/release/bl2.bin" "build/${platform}/release/bl31.bin"]; }; ubootOpenWrtOne = + # ubiupdatevol /dev/ubi0_2 u-boot.fip (final.buildUBoot { defconfig = "mt7981_openwrt-one-spi-nand_defconfig"; extraMeta.platforms = ["aarch64-linux"]; @@ -50,12 +51,15 @@ final: prev: { CONFIG_PCI=y CONFIG_PCIE_MEDIATEK_GEN3=y CONFIG_PCI_DEBUG=y - CONFIG_DM_DEBUG=y + CONFIG_DM_REGULATOR=y CONFIG_NVME=y CONFIG_NVME_PCI=y CONFIG_CMD_NVME=y - #CONFIG_FS_BTRFS=y - #CONFIG_CMD_BTRFS=y + CONFIG_EFI_PARTITION=y + + CONFIG_CMD_SYSBOOT=y + CONFIG_SUPPORT_RAW_INITRD=y + CONFIG_BOARD_LATE_INIT=n ''; postBuild = '' @@ -67,6 +71,21 @@ final: prev: { }).overrideAttrs (oldAttrs: { nativeBuildInputs = [final.buildPackages.unixtools.xxd] ++ oldAttrs.nativeBuildInputs; }); + linuxOpenWrtOne = final.buildLinux { + version = "6.18.0-rc1"; + src = final.buildPackages.fetchgit { + url = "git://git.kernel.org/pub/scm/linux/kernel/git/mediatek/linux.git"; + rev = "d7d7ac9af8cb72e3e3816ae9da3d9ee1bdfa4f9b"; + hash = "sha256-h1DwHDHQ4LfqVYkp/e36c3NLnhbg1ozmjtrtAk5AzZE="; + }; + kernelPatches = [ + { + name = "openwrt-one"; + patch = ./linux-openwrt-one-mediatek.patch; + #patch = ./linux-openwrt-one.patch; + } + ]; + }; # nixpkgs patches ubootRaspberryPi3_btrfs = prev.buildUBoot { @@ -91,7 +110,7 @@ final: prev: { }); gvproxy = - if prev.hostPlatform.is32bit + if prev.stdenv.hostPlatform.is32bit then # Downgrade to get 32bit support working prev.gvproxy.overrideAttrs (oldAttrs: { diff --git a/pkgs/linux-openwrt-one-mediatek.patch b/pkgs/linux-openwrt-one-mediatek.patch new file mode 100644 index 0000000..acd7247 --- /dev/null +++ b/pkgs/linux-openwrt-one-mediatek.patch @@ -0,0 +1,2353 @@ +From patchwork Wed Nov 5 21:17:56 2025 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +X-Patchwork-Submitter: Sjoerd Simons +X-Patchwork-Id: 14300874 +Return-Path: + +X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on + aws-us-west-2-korg-lkml-1.web.codeaurora.org +Received: from bombadil.infradead.org (bombadil.infradead.org + [198.137.202.133]) + (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) + (No client certificate requested) + by smtp.lore.kernel.org (Postfix) with ESMTPS id 27658CCF9F8 + for ; + Wed, 5 Nov 2025 21:18:45 +0000 (UTC) +DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; + d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help + :List-Post:List-Archive:List-Unsubscribe:List-Id:Cc:To:In-Reply-To:References + :Message-Id:Content-Transfer-Encoding:Content-Type:MIME-Version:Subject:Date: + From:Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From: + Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; + bh=pbQ8LYX0/2mwbWfiTZ/4KA3hdnCFGb6BlEXU0Ey9ARA=; b=Cb1OaY2B9saEFea6/QEEi37zhv + kpuXc+/J3xLGdmXg1TgcfNhB1PgVJeHXsfGLBBv+8BqqtOGAq61FNtd4UMut0B8xvKju6uWFRG+Tv + 55yGZ+IbVkoRqnKrI9MSxZpc30KfsN67z/V62HyKChRUaho5wsoyN3Lh4kBPKAEtCqtn8RgRrYvIK + R1P1yDXBWFspsdPhxifl5ZO4WKHs+qNrHKE8cXV31J5ndei6QhrQqSaWTjBTtAKYRFiXrKCdFSf4Y + poCUJ0Uurw4eLSPKTYF6Bzm+hssBZKvhbHAXibEM0Z+vTRRB4RLSlprAKw8lC1Ia2PS4voS6kkQhk + V6br6Mvg==; +Received: from localhost ([::1] helo=bombadil.infradead.org) + by bombadil.infradead.org with esmtp (Exim 4.98.2 #2 (Red Hat Linux)) + id 1vGktv-0000000EU4a-2qhd; + Wed, 05 Nov 2025 21:18:43 +0000 +Received: from bali.collaboradmins.com ([2a01:4f8:201:9162::2]) + by bombadil.infradead.org with esmtps (Exim 4.98.2 #2 (Red Hat Linux)) + id 1vGktq-0000000ETy8-1Ir7; + Wed, 05 Nov 2025 21:18:40 +0000 +DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; + s=mail; t=1762377515; + bh=vTtFVwZhj2dtk28F9mb0pMLT2K98WweVea9+cuC24ag=; + h=From:Date:Subject:References:In-Reply-To:To:Cc:From; + b=pSe49kn1CNJa/3TIsAfyiPmVF6y8Y8PaNI39JUJJAAPA5wWIFh6XiC4HVZx6wEFNL + L5Kdzgoirrmikw+CUAcBOG09J/CVlUGuVArOzbmO7Wslf7ZxtcAwnpndJ43sBsrCq1 + v/WOwnTgqG36ax9SAtLwXvRr9iFPFbDxYpPnBjW0uNx0LGTceQTwIerakX6nh/fve2 + gDgnn7FFMsjEfMxOyPv6ZSm9V2QYVpS7DfzQzkZ+RBkSvVkeyS66FamW1RxSMduaYI + esxgWGjHuf5H2/qYR975Jxrx8kLKRiAIjaJPBj3Zh03WC2gVt5fDKiYp1fSDHIIPAT + u+lL/PGRDqsvQ== +Received: from beast.luon.net (unknown [IPv6:2a10:3781:2531::8]) + (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) + key-exchange X25519 server-signature RSA-PSS (4096 bits)) + (No client certificate requested) + (Authenticated sender: sjoerd) + by bali.collaboradmins.com (Postfix) with ESMTPSA id 0483317E12AA; + Wed, 5 Nov 2025 22:18:35 +0100 (CET) +Received: by beast.luon.net (Postfix, from userid 1000) + id 916BF10F352DB; Wed, 05 Nov 2025 22:18:34 +0100 (CET) +From: Sjoerd Simons +Date: Wed, 05 Nov 2025 22:17:56 +0100 +Subject: [PATCH v3 01/13] arm64: dts: mediatek: mt7981b-openwrt-one: Enable + SPI NOR +MIME-Version: 1.0 +Message-Id: <20251105-openwrt-one-network-v3-1-008e2cab38d1@collabora.com> +References: <20251105-openwrt-one-network-v3-0-008e2cab38d1@collabora.com> +In-Reply-To: <20251105-openwrt-one-network-v3-0-008e2cab38d1@collabora.com> +To: Rob Herring , Krzysztof Kozlowski , + Conor Dooley , + Matthias Brugger , + AngeloGioacchino Del Regno , + Ryder Lee , + Jianjun Wang , + Bjorn Helgaas , + Lorenzo Pieralisi , =?utf-8?q?Krzysztof_Wilczy?= + =?utf-8?q?=C5=84ski?= , + Manivannan Sadhasivam , + Chunfeng Yun , Vinod Koul , + Kishon Vijay Abraham I , Lee Jones , + Andrew Lunn , + "David S. Miller" , Eric Dumazet , + Jakub Kicinski , Paolo Abeni , + Lorenzo Bianconi , Felix Fietkau +Cc: kernel@collabora.com, devicetree@vger.kernel.org, + linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, + linux-mediatek@lists.infradead.org, linux-pci@vger.kernel.org, + linux-phy@lists.infradead.org, netdev@vger.kernel.org, + Daniel Golle , Bryan Hinton , + Sjoerd Simons +X-Mailer: b4 0.14.3 +X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 +X-CRM114-CacheID: sfid-20251105_131838_527801_38763342 +X-CRM114-Status: GOOD ( 13.98 ) +X-BeenThere: linux-mediatek@lists.infradead.org +X-Mailman-Version: 2.1.34 +Precedence: list +List-Id: +List-Unsubscribe: , + +List-Archive: +List-Post: +List-Help: +List-Subscribe: , + +Sender: "Linux-mediatek" +Errors-To: + linux-mediatek-bounces+linux-mediatek=archiver.kernel.org@lists.infradead.org + +The openwrt one has a SPI NOR flash which from factory is used for: +* Recovery system +* WiFi eeprom data +* ethernet Mac addresses + +Describe this following the same partitions as the openwrt configuration +uses. + +Signed-off-by: Sjoerd Simons +--- +V2 -> V3: Move earlier in the patch sequence +V1 -> V2: + - Use numeric drive-strength values rather then defines + - Make nvmem cell labers more meaningfull + - Only define nvmem cells used in later patches by devicetree +--- + .../boot/dts/mediatek/mt7981b-openwrt-one.dts | 79 ++++++++++++++++++++++ + arch/arm64/boot/dts/mediatek/mt7981b.dtsi | 2 +- + 2 files changed, 80 insertions(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7981b-openwrt-one.dts b/arch/arm64/boot/dts/mediatek/mt7981b-openwrt-one.dts +index 968b91f55bb27..6bb98629f4536 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7981b-openwrt-one.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7981b-openwrt-one.dts +@@ -3,6 +3,7 @@ + /dts-v1/; + + #include "mt7981b.dtsi" ++#include "dt-bindings/pinctrl/mt65xx.h" + + / { + compatible = "openwrt,one", "mediatek,mt7981b"; +@@ -22,6 +23,84 @@ memory@40000000 { + }; + }; + ++&pio { ++ spi2_flash_pins: spi2-pins { ++ mux { ++ function = "spi"; ++ groups = "spi2"; ++ }; ++ ++ conf-pu { ++ bias-pull-up = ; ++ drive-strength = <8>; ++ pins = "SPI2_CS", "SPI2_WP"; ++ }; ++ ++ conf-pd { ++ bias-pull-down = ; ++ drive-strength = <8>; ++ pins = "SPI2_CLK", "SPI2_MOSI", "SPI2_MISO"; ++ }; ++ }; ++}; ++ ++&spi2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spi2_flash_pins>; ++ status = "okay"; ++ ++ flash@0 { ++ compatible = "jedec,spi-nor"; ++ reg = <0>; ++ spi-max-frequency = <40000000>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ partitions { ++ compatible = "fixed-partitions"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ partition@0 { ++ reg = <0x00000 0x40000>; ++ label = "bl2-nor"; ++ }; ++ ++ partition@40000 { ++ reg = <0x40000 0xc0000>; ++ label = "factory"; ++ read-only; ++ ++ nvmem-layout { ++ compatible = "fixed-layout"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ wifi_factory_calibration: eeprom@0 { ++ reg = <0x0 0x1000>; ++ }; ++ ++ wan_factory_mac: macaddr@24 { ++ reg = <0x24 0x6>; ++ compatible = "mac-base"; ++ #nvmem-cell-cells = <1>; ++ }; ++ }; ++ }; ++ ++ partition@100000 { ++ reg = <0x100000 0x80000>; ++ label = "fip-nor"; ++ }; ++ ++ partition@180000 { ++ reg = <0x180000 0xc80000>; ++ label = "recovery"; ++ }; ++ }; ++ }; ++}; ++ + &uart0 { + status = "okay"; + }; +diff --git a/arch/arm64/boot/dts/mediatek/mt7981b.dtsi b/arch/arm64/boot/dts/mediatek/mt7981b.dtsi +index 130ce2fda3995..f00e5bf63de35 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7981b.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7981b.dtsi +@@ -156,7 +156,7 @@ i2c@11007000 { + status = "disabled"; + }; + +- spi@11009000 { ++ spi2: spi@11009000 { + compatible = "mediatek,mt7981-spi-ipm", "mediatek,spi-ipm"; + reg = <0 0x11009000 0 0x1000>; + interrupts = ; + +From patchwork Wed Nov 5 21:17:57 2025 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +X-Patchwork-Submitter: Sjoerd Simons +X-Patchwork-Id: 14300873 +Return-Path: + +X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on + aws-us-west-2-korg-lkml-1.web.codeaurora.org +Received: from bombadil.infradead.org (bombadil.infradead.org + [198.137.202.133]) + (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) + (No client certificate requested) + by smtp.lore.kernel.org (Postfix) with ESMTPS id 5417DCCFA0D + for ; + Wed, 5 Nov 2025 21:18:42 +0000 (UTC) +DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; + d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help + :List-Post:List-Archive:List-Unsubscribe:List-Id:Cc:To:In-Reply-To:References + :Message-Id:Content-Transfer-Encoding:Content-Type:MIME-Version:Subject:Date: + From:Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From: + Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; + bh=avlKJcLS27IiW4i/NSTPBJCPoTBFD15wkzKpbeqsTtI=; b=0jtAGvteycn59TWzuemDgRp4w5 + 5dy7ghMpYQVtdnPSRv7SaM6c9hVChRvqTe0BFX1mEo0kRMl8CatERDhe/C5LAkW4L2nNRe5dK+Myb + rlXQNXnz3kWe5icAVDFMpTILVcW374QdriXL6aIxWrYhjhpEQlZq95LLP2gmlp9IsvLjeO++cdbQ1 + hgf8Ggvi/s/xTDt8HMTmf/kap2uq6WDxCgZkRjJHzvcSzKXBtbcGp3qzeYolHhgS55MJ9xoOFnnqA + u6SRlmgQm+gQP08ZKGnSh20dgkpTjHwIRc3XH1N1+PfrkK5gNwKPmb1TxwKOiJ46ekRDgUmzNUZWT + moS5gY4g==; +Received: from localhost ([::1] helo=bombadil.infradead.org) + by bombadil.infradead.org with esmtp (Exim 4.98.2 #2 (Red Hat Linux)) + id 1vGkts-0000000ETzl-3ajb; + Wed, 05 Nov 2025 21:18:40 +0000 +Received: from bali.collaboradmins.com ([2a01:4f8:201:9162::2]) + by bombadil.infradead.org with esmtps (Exim 4.98.2 #2 (Red Hat Linux)) + id 1vGktq-0000000ETy1-0qjw; + Wed, 05 Nov 2025 21:18:39 +0000 +DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; + s=mail; t=1762377515; + bh=bArrOhdqiPrD9jwVtY5HEE/53V3p8i0UZ8xJQqCPlD0=; + h=From:Date:Subject:References:In-Reply-To:To:Cc:From; + b=VOReS/tBa/q6ng2Yhr2+/vUP5UB2401ugVhFf+0UORldLzyq+GXymaYL+4TyWBzbq + E5iJPmF4FgnRteq2+Zzs4MGmfv6KXhmt2G3qH5ETOCYYTIUARBRY6u25jdHX+O/gMo + RQjh+GIR3h/L5Zus48T6qNKpMtJhHs1KZ5A/r+YahUv+BbOSHCEvWT7GIIh/9XOhL7 + 6WqcFwJl8Xo3y+1LOMSyZZ/b8WZs6XemcZZkphmKBEawG5voNrNc2TjHbEBZ2Imc79 + JR7TkSCCYcSdQkGq79iDohJaa4FfGFvVEDfMbGBBWDITlglqViL0jmLc5ieNhvCiXt + VgNVVQbZqGcxg== +Received: from beast.luon.net (unknown [IPv6:2a10:3781:2531::8]) + (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) + key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest + SHA256) + (No client certificate requested) + (Authenticated sender: sjoerd) + by bali.collaboradmins.com (Postfix) with ESMTPSA id E12A417E129C; + Wed, 5 Nov 2025 22:18:34 +0100 (CET) +Received: by beast.luon.net (Postfix, from userid 1000) + id 96B5110F352DD; Wed, 05 Nov 2025 22:18:34 +0100 (CET) +From: Sjoerd Simons +Date: Wed, 05 Nov 2025 22:17:57 +0100 +Subject: [PATCH v3 02/13] arm64: dts: mediatek: mt7981b-openwrt-one: Enable + software leds +MIME-Version: 1.0 +Message-Id: <20251105-openwrt-one-network-v3-2-008e2cab38d1@collabora.com> +References: <20251105-openwrt-one-network-v3-0-008e2cab38d1@collabora.com> +In-Reply-To: <20251105-openwrt-one-network-v3-0-008e2cab38d1@collabora.com> +To: Rob Herring , Krzysztof Kozlowski , + Conor Dooley , + Matthias Brugger , + AngeloGioacchino Del Regno , + Ryder Lee , + Jianjun Wang , + Bjorn Helgaas , + Lorenzo Pieralisi , =?utf-8?q?Krzysztof_Wilczy?= + =?utf-8?q?=C5=84ski?= , + Manivannan Sadhasivam , + Chunfeng Yun , Vinod Koul , + Kishon Vijay Abraham I , Lee Jones , + Andrew Lunn , + "David S. Miller" , Eric Dumazet , + Jakub Kicinski , Paolo Abeni , + Lorenzo Bianconi , Felix Fietkau +Cc: kernel@collabora.com, devicetree@vger.kernel.org, + linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, + linux-mediatek@lists.infradead.org, linux-pci@vger.kernel.org, + linux-phy@lists.infradead.org, netdev@vger.kernel.org, + Daniel Golle , Bryan Hinton , + Sjoerd Simons +X-Mailer: b4 0.14.3 +X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 +X-CRM114-CacheID: sfid-20251105_131838_423983_A7543089 +X-CRM114-Status: GOOD ( 14.52 ) +X-BeenThere: linux-mediatek@lists.infradead.org +X-Mailman-Version: 2.1.34 +Precedence: list +List-Id: +List-Unsubscribe: , + +List-Archive: +List-Post: +List-Help: +List-Subscribe: , + +Sender: "Linux-mediatek" +Errors-To: + linux-mediatek-bounces+linux-mediatek=archiver.kernel.org@lists.infradead.org + +The openwrt has 3 status leds at the front: +* red: Used as failsafe led by openwrt +* white: Used as boot led by openwrt +* green: Used as running/upgrade led by openwrt + +On the back each RJ45 jack has the typical amber/green leds. For the WAN +jack this is hardware controlled by the phy, for LAN these are under +software control and enabled by this patch. + +Signed-off-by: Sjoerd Simons +--- +V2 -> V3: Move earlier in the patch sequence +V1 -> V2: + - Improve commit message + - Re-order nodes to be alphabetical +--- + .../boot/dts/mediatek/mt7981b-openwrt-one.dts | 59 ++++++++++++++++++++++ + arch/arm64/boot/dts/mediatek/mt7981b.dtsi | 2 +- + 2 files changed, 60 insertions(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7981b-openwrt-one.dts b/arch/arm64/boot/dts/mediatek/mt7981b-openwrt-one.dts +index 6bb98629f4536..2e39e72877301 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7981b-openwrt-one.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7981b-openwrt-one.dts +@@ -3,6 +3,8 @@ + /dts-v1/; + + #include "mt7981b.dtsi" ++#include ++#include + #include "dt-bindings/pinctrl/mt65xx.h" + + / { +@@ -21,9 +23,60 @@ memory@40000000 { + reg = <0 0x40000000 0 0x40000000>; + device_type = "memory"; + }; ++ ++ pwm-leds { ++ compatible = "pwm-leds"; ++ ++ led-0 { ++ color = ; ++ default-brightness = <0>; ++ function = LED_FUNCTION_STATUS; ++ max-brightness = <255>; ++ pwms = <&pwm 0 10000>; ++ }; ++ ++ led-1 { ++ color = ; ++ default-brightness = <0>; ++ function = LED_FUNCTION_STATUS; ++ max-brightness = <255>; ++ pwms = <&pwm 1 10000>; ++ }; ++ }; ++ ++ gpio-leds { ++ compatible = "gpio-leds"; ++ ++ led-0 { ++ color = ; ++ function = LED_FUNCTION_STATUS; ++ gpios = <&pio 9 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ led-1 { ++ color = ; ++ function = LED_FUNCTION_LAN; ++ gpios = <&pio 34 GPIO_ACTIVE_LOW>; ++ linux,default-trigger = "netdev"; ++ }; ++ ++ led-2 { ++ color = ; ++ function = LED_FUNCTION_LAN; ++ gpios = <&pio 35 GPIO_ACTIVE_LOW>; ++ linux,default-trigger = "netdev"; ++ }; ++ }; + }; + + &pio { ++ pwm_pins: pwm-pins { ++ mux { ++ function = "pwm"; ++ groups = "pwm0_0", "pwm1_1"; ++ }; ++ }; ++ + spi2_flash_pins: spi2-pins { + mux { + function = "spi"; +@@ -44,6 +97,12 @@ conf-pd { + }; + }; + ++&pwm { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pwm_pins>; ++ status = "okay"; ++}; ++ + &spi2 { + pinctrl-names = "default"; + pinctrl-0 = <&spi2_flash_pins>; +diff --git a/arch/arm64/boot/dts/mediatek/mt7981b.dtsi b/arch/arm64/boot/dts/mediatek/mt7981b.dtsi +index f00e5bf63de35..416096b80770c 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7981b.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7981b.dtsi +@@ -94,7 +94,7 @@ apmixedsys: clock-controller@1001e000 { + #clock-cells = <1>; + }; + +- pwm@10048000 { ++ pwm: pwm@10048000 { + compatible = "mediatek,mt7981-pwm"; + reg = <0 0x10048000 0 0x1000>; + clocks = <&infracfg CLK_INFRA_PWM_STA>, + +From patchwork Wed Nov 5 21:17:58 2025 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +X-Patchwork-Submitter: Sjoerd Simons +X-Patchwork-Id: 14300882 +Return-Path: + +X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on + aws-us-west-2-korg-lkml-1.web.codeaurora.org +Received: from bombadil.infradead.org (bombadil.infradead.org + [198.137.202.133]) + (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) + (No client certificate requested) + by smtp.lore.kernel.org (Postfix) with ESMTPS id 96882CCFA1D + for ; + Wed, 5 Nov 2025 21:19:09 +0000 (UTC) +DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; + d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help + :List-Post:List-Archive:List-Unsubscribe:List-Id:Cc:To:In-Reply-To:References + :Message-Id:Content-Transfer-Encoding:Content-Type:MIME-Version:Subject:Date: + From:Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From: + Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; + bh=YTHvtBL+VZnUTHjrz6ClSw7+XPBkv6t8SxYxsbAo8Ew=; b=HqaKb7lXfmU+r1K0zRQqpAo1TC + dJNXPMCIpwbBK264GNPcxjw372eoyVGs5ByAGDZn/OCM5/9QzniFovhHsv/m9OeKk462mAtHNpOQP + Nytx7Mj90jizLzg9FkzQUuTvBSvnz4nh+0zbAAKfC+L+iLhY34I4XMhxdIN9QeOSXLHTgZhMtnqQ4 + mcN4czHjko6wUJIy4e2qEqDMKhZdt5qXy+4FsGOvVIMiqwiK2zguLCFc09+1ql9aGfo3SqzWMR1Ss + a/t8K6MhlKAAJCe1jvIoipcITv1fLOMsktu3avvVBQ3xbd1EYf4CE/rRP6046K3fseEYzAzWs2wEj + kqgClckA==; +Received: from localhost ([::1] helo=bombadil.infradead.org) + by bombadil.infradead.org with esmtp (Exim 4.98.2 #2 (Red Hat Linux)) + id 1vGkuK-0000000EUcY-1yA8; + Wed, 05 Nov 2025 21:19:08 +0000 +Received: from bali.collaboradmins.com ([148.251.105.195]) + by bombadil.infradead.org with esmtps (Exim 4.98.2 #2 (Red Hat Linux)) + id 1vGktv-0000000EU0m-0kG8; + Wed, 05 Nov 2025 21:18:46 +0000 +DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; + s=mail; t=1762377520; + bh=BNloXSmxfui+A+UD0vb6639VkVLh4h7qFS1iqqJUbUo=; + h=From:Date:Subject:References:In-Reply-To:To:Cc:From; + b=XpSLf1aGffJeN3zx8uRhcaOmvn2uTssdN8S/TbdnUE69GnvkRSpHrFeCAMfgFw6h+ + WBE8bR6DFUQSFUfl/t8PJarzCojzGlWEe/Bjpwy//0LUvlJ4H2KglxqzierbnbGWkJ + JxcwY+/LDHd88TJx4wF2pxlYa68pFOAAGnZ+LVsowRN70g0ShSx+cKfz/MuBEEx866 + eY2aaiv7kk6cgbVTTgbQpofXT93rsBTiSVOz3zUbIplNpgMBhJP8HWFRc1NYQ6iiQc + z6Bp9JVIF1zTXGnS32qST64tNFlO9EM6BZ3Y+WERvYeLEXmsObKq7fVOFZwuL1SDIz + lkVC+aPo126sA== +Received: from beast.luon.net (unknown [IPv6:2a10:3781:2531::8]) + (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) + key-exchange X25519 server-signature RSA-PSS (4096 bits)) + (No client certificate requested) + (Authenticated sender: sjoerd) + by bali.collaboradmins.com (Postfix) with ESMTPSA id EB61317E1562; + Wed, 5 Nov 2025 22:18:39 +0100 (CET) +Received: by beast.luon.net (Postfix, from userid 1000) + id 9C16B10F352DF; Wed, 05 Nov 2025 22:18:34 +0100 (CET) +From: Sjoerd Simons +Date: Wed, 05 Nov 2025 22:17:58 +0100 +Subject: [PATCH v3 03/13] dt-bindings: mfd: syscon: Add mt7981-topmisc +MIME-Version: 1.0 +Message-Id: <20251105-openwrt-one-network-v3-3-008e2cab38d1@collabora.com> +References: <20251105-openwrt-one-network-v3-0-008e2cab38d1@collabora.com> +In-Reply-To: <20251105-openwrt-one-network-v3-0-008e2cab38d1@collabora.com> +To: Rob Herring , Krzysztof Kozlowski , + Conor Dooley , + Matthias Brugger , + AngeloGioacchino Del Regno , + Ryder Lee , + Jianjun Wang , + Bjorn Helgaas , + Lorenzo Pieralisi , =?utf-8?q?Krzysztof_Wilczy?= + =?utf-8?q?=C5=84ski?= , + Manivannan Sadhasivam , + Chunfeng Yun , Vinod Koul , + Kishon Vijay Abraham I , Lee Jones , + Andrew Lunn , + "David S. Miller" , Eric Dumazet , + Jakub Kicinski , Paolo Abeni , + Lorenzo Bianconi , Felix Fietkau +Cc: kernel@collabora.com, devicetree@vger.kernel.org, + linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, + linux-mediatek@lists.infradead.org, linux-pci@vger.kernel.org, + linux-phy@lists.infradead.org, netdev@vger.kernel.org, + Daniel Golle , Bryan Hinton , + Sjoerd Simons , + Conor Dooley +X-Mailer: b4 0.14.3 +X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 +X-CRM114-CacheID: sfid-20251105_131843_431301_903B5158 +X-CRM114-Status: UNSURE ( 9.26 ) +X-CRM114-Notice: Please train this message. +X-BeenThere: linux-mediatek@lists.infradead.org +X-Mailman-Version: 2.1.34 +Precedence: list +List-Id: +List-Unsubscribe: , + +List-Archive: +List-Post: +List-Help: +List-Subscribe: , + +Sender: "Linux-mediatek" +Errors-To: + linux-mediatek-bounces+linux-mediatek=archiver.kernel.org@lists.infradead.org + +This hardware block amongst other things includes a multiplexer for a +high-speed Combo-Phy. This binding allows exposing the multiplexer + +Acked-by: Conor Dooley +Reviewed-by: AngeloGioacchino Del Regno +Signed-off-by: Sjoerd Simons +--- + Documentation/devicetree/bindings/mfd/syscon.yaml | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/Documentation/devicetree/bindings/mfd/syscon.yaml b/Documentation/devicetree/bindings/mfd/syscon.yaml +index 657c38175fba2..51511078c4c3b 100644 +--- a/Documentation/devicetree/bindings/mfd/syscon.yaml ++++ b/Documentation/devicetree/bindings/mfd/syscon.yaml +@@ -193,6 +193,7 @@ properties: + - mediatek,mt2701-pctl-a-syscfg + - mediatek,mt2712-pctl-a-syscfg + - mediatek,mt6397-pctl-pmic-syscfg ++ - mediatek,mt7981-topmisc + - mediatek,mt7988-topmisc + - mediatek,mt8135-pctl-a-syscfg + - mediatek,mt8135-pctl-b-syscfg + +From patchwork Wed Nov 5 21:17:59 2025 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +X-Patchwork-Submitter: Sjoerd Simons +X-Patchwork-Id: 14300883 +Return-Path: + +X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on + aws-us-west-2-korg-lkml-1.web.codeaurora.org +Received: from bombadil.infradead.org (bombadil.infradead.org + [198.137.202.133]) + (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) + (No client certificate requested) + by smtp.lore.kernel.org (Postfix) with ESMTPS id 750F7CCFA1C + for ; + Wed, 5 Nov 2025 21:19:09 +0000 (UTC) +DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; + d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help + :List-Post:List-Archive:List-Unsubscribe:List-Id:Cc:To:In-Reply-To:References + :Message-Id:Content-Transfer-Encoding:Content-Type:MIME-Version:Subject:Date: + From:Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From: + Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; + bh=j/r2anqRW+90VM9McPY+HL40VXbPRjGoaWqnMpIZ0Fs=; b=IaKu3jz6YFxlujvK4OcXhsqFrZ + t+qFR7JRHh0BUB6pHb1n9aOWU4LQgNs0tnGcy3xCEy7MjpCeY8KvKVusalNzRjDFaBYnXr+VWZJJR + PjvC0fKtomtszWd4fzB8mCulXXJKBbWmeoxmjaEMCbGevdVSLDL1NWWbQWG2BDtoqG+E5BnpuH6SM + ZhOF9A6np+uAo40Vv7h/e3rcKcEVgabuWM7sABvHfbqH2pQEje931ivi3kXY7unZyHg2Ot7yMWnww + x7BoB1wUCYmAcaf0PGZcT5JjLu9TEnKI+8XXk+6A4vnvVsxnDdXPGXHbbG2lmTQnfgh8sGhdjG/sF + 3f5TA0Xg==; +Received: from localhost ([::1] helo=bombadil.infradead.org) + by bombadil.infradead.org with esmtp (Exim 4.98.2 #2 (Red Hat Linux)) + id 1vGkuK-0000000EUbg-0Ql9; + Wed, 05 Nov 2025 21:19:08 +0000 +Received: from bali.collaboradmins.com ([2a01:4f8:201:9162::2]) + by bombadil.infradead.org with esmtps (Exim 4.98.2 #2 (Red Hat Linux)) + id 1vGktv-0000000EU0g-1snN; + Wed, 05 Nov 2025 21:18:46 +0000 +DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; + s=mail; t=1762377515; + bh=JdKvpThqp3TDs4o0pkrFusvXBPtE9LtpoPmwO6qXgiM=; + h=From:Date:Subject:References:In-Reply-To:To:Cc:From; + b=ZTJBt+chv2OorZPxJOTV0pe1cpqVHLoTNLfzME7KhrNsfGLdxx4oH4GlB0XTU3ZzV + Dg/1pyFg1MGW0e662nfEk1S8BJrzpfsREKZsEPGeAY2p05QsUhTegWiVIBXoO1G2nv + mfEov68FCA/RIqnRgXKcmwscA6qChdT1wHsVU4wdvAWeKz6S+JOOJNWAAhNo2hDtD1 + t0a14zBni0iDuSr1ArRKL9Bm1jdw/nG6dqU++jjHl20Cwo/N52n0Bo9o7E+I+I6CIb + 5MRJJoYhfbIbU9KPj9WrxNuNRuWVAHXdyvnH5AkIoYVAjapxGp/1IYQ56If0dyk/Fw + PLZas/NOkgAGA== +Received: from beast.luon.net (unknown [IPv6:2a10:3781:2531::8]) + (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) + key-exchange X25519 server-signature RSA-PSS (4096 bits)) + (No client certificate requested) + (Authenticated sender: sjoerd) + by bali.collaboradmins.com (Postfix) with ESMTPSA id 061F717E1396; + Wed, 5 Nov 2025 22:18:35 +0100 (CET) +Received: by beast.luon.net (Postfix, from userid 1000) + id 9FA6010F352E1; Wed, 05 Nov 2025 22:18:34 +0100 (CET) +From: Sjoerd Simons +Date: Wed, 05 Nov 2025 22:17:59 +0100 +Subject: [PATCH v3 04/13] dt-bindings: PCI: mediatek-gen3: Add MT7981 PCIe + compatible +MIME-Version: 1.0 +Message-Id: <20251105-openwrt-one-network-v3-4-008e2cab38d1@collabora.com> +References: <20251105-openwrt-one-network-v3-0-008e2cab38d1@collabora.com> +In-Reply-To: <20251105-openwrt-one-network-v3-0-008e2cab38d1@collabora.com> +To: Rob Herring , Krzysztof Kozlowski , + Conor Dooley , + Matthias Brugger , + AngeloGioacchino Del Regno , + Ryder Lee , + Jianjun Wang , + Bjorn Helgaas , + Lorenzo Pieralisi , =?utf-8?q?Krzysztof_Wilczy?= + =?utf-8?q?=C5=84ski?= , + Manivannan Sadhasivam , + Chunfeng Yun , Vinod Koul , + Kishon Vijay Abraham I , Lee Jones , + Andrew Lunn , + "David S. Miller" , Eric Dumazet , + Jakub Kicinski , Paolo Abeni , + Lorenzo Bianconi , Felix Fietkau +Cc: kernel@collabora.com, devicetree@vger.kernel.org, + linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, + linux-mediatek@lists.infradead.org, linux-pci@vger.kernel.org, + linux-phy@lists.infradead.org, netdev@vger.kernel.org, + Daniel Golle , Bryan Hinton , + Sjoerd Simons , + Conor Dooley +X-Mailer: b4 0.14.3 +X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 +X-CRM114-CacheID: sfid-20251105_131843_768347_BD42A9AF +X-CRM114-Status: UNSURE ( 9.72 ) +X-CRM114-Notice: Please train this message. +X-BeenThere: linux-mediatek@lists.infradead.org +X-Mailman-Version: 2.1.34 +Precedence: list +List-Id: +List-Unsubscribe: , + +List-Archive: +List-Post: +List-Help: +List-Subscribe: , + +Sender: "Linux-mediatek" +Errors-To: + linux-mediatek-bounces+linux-mediatek=archiver.kernel.org@lists.infradead.org + +Add compatible string for MediaTek MT7981 PCIe Gen3 controller. +The MT7981 PCIe controller is compatible with the MT8192 PCIe +controller. + +Acked-by: Conor Dooley +Reviewed-by: AngeloGioacchino Del Regno +Signed-off-by: Sjoerd Simons +--- +V1 -> V2: Improve commit subject +--- + Documentation/devicetree/bindings/pci/mediatek-pcie-gen3.yaml | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/Documentation/devicetree/bindings/pci/mediatek-pcie-gen3.yaml b/Documentation/devicetree/bindings/pci/mediatek-pcie-gen3.yaml +index 0278845701ce8..4db700fc36ba7 100644 +--- a/Documentation/devicetree/bindings/pci/mediatek-pcie-gen3.yaml ++++ b/Documentation/devicetree/bindings/pci/mediatek-pcie-gen3.yaml +@@ -48,6 +48,7 @@ properties: + oneOf: + - items: + - enum: ++ - mediatek,mt7981-pcie + - mediatek,mt7986-pcie + - mediatek,mt8188-pcie + - mediatek,mt8195-pcie + +From patchwork Wed Nov 5 21:18:00 2025 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +X-Patchwork-Submitter: Sjoerd Simons +X-Patchwork-Id: 14300876 +Return-Path: + +X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on + aws-us-west-2-korg-lkml-1.web.codeaurora.org +Received: from bombadil.infradead.org (bombadil.infradead.org + [198.137.202.133]) + (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) + (No client certificate requested) + by smtp.lore.kernel.org (Postfix) with ESMTPS id E1750CCFA1B + for ; + Wed, 5 Nov 2025 21:18:52 +0000 (UTC) +DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; + d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help + :List-Post:List-Archive:List-Unsubscribe:List-Id:Cc:To:In-Reply-To:References + :Message-Id:Content-Transfer-Encoding:Content-Type:MIME-Version:Subject:Date: + From:Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From: + Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; + bh=ksghHQTQZO35rk2pD4ByHO3UcRzFD5f5eXAve+3bdKg=; b=F7ytra4BobFP2vF4cJkBEFcr1N + nb92KC2u8M293hQqGx8pfMMv/5RQ+5or+2cx3IocNILotBgcFIL7Qli3JtoeTwCGaeaYPgqvodnN/ + 3nmfTFZ+FN88+6FxpzPkFJHaEnLqmVdZOS1o0bULqKO19A5/kmjIra/ZMje7YF3nheOYc0+GgkVLn + c5ZA22taPPoMbVW1vEw6ivJns6Q9eF/4CRvqiNq8iaMzBNSAzZ47rezQ9DUe720t1WEateAAGtSTx + teZzG3tBmgSgo4CdeBCCxvH+tQOI8aGBsWB39s48iqM9o0GQJOoPSqmm5aa45Ra5UPLUtcTCZcOuU + WeOaKIlA==; +Received: from localhost ([::1] helo=bombadil.infradead.org) + by bombadil.infradead.org with esmtp (Exim 4.98.2 #2 (Red Hat Linux)) + id 1vGku1-0000000EUDZ-2DzO; + Wed, 05 Nov 2025 21:18:49 +0000 +Received: from bali.collaboradmins.com ([148.251.105.195]) + by bombadil.infradead.org with esmtps (Exim 4.98.2 #2 (Red Hat Linux)) + id 1vGktu-0000000ETzV-01bB; + Wed, 05 Nov 2025 21:18:43 +0000 +DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; + s=mail; t=1762377515; + bh=0HQMjZYjWvOC8AwZB4R1t/Hz5V/fyYneHN+5PdUNP20=; + h=From:Date:Subject:References:In-Reply-To:To:Cc:From; + b=E+0/zF+6oMms5hJTlxoUCNIi/DeN8KiZrnBjTBO/RUtepOeAYNieN3YDaZ8sXRCTg + 0R4a3m6gZap6/EjIdz0PgdQPDVl9JQK5VgB55EKabHBR9y9ltShIHngSc/xm9yFlMI + e6ixnHLiAseOdlMdjnDpsPHOMWyTbKeOpTxoXQKNIAcKLCostve024jIAdX+WRmgu5 + 6NqNKuorQRxMCvKTbxg23/bThwa8zbmNRYlUVmCggyw/jMvLUIxcgoofcpGAaa5WNW + TNK9SI7WAfpfKHGvNQQrbqK72CLMqOvL0yUsGw5hcX5VNIfNcnZGSDoK7P7sGaTTge + EvrkabOTCXGdQ== +Received: from beast.luon.net (unknown [IPv6:2a10:3781:2531::8]) + (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) + key-exchange X25519 server-signature RSA-PSS (4096 bits)) + (No client certificate requested) + (Authenticated sender: sjoerd) + by bali.collaboradmins.com (Postfix) with ESMTPSA id D171217E141C; + Wed, 5 Nov 2025 22:18:35 +0100 (CET) +Received: by beast.luon.net (Postfix, from userid 1000) + id A705710F352E3; Wed, 05 Nov 2025 22:18:34 +0100 (CET) +From: Sjoerd Simons +Date: Wed, 05 Nov 2025 22:18:00 +0100 +Subject: [PATCH v3 05/13] dt-bindings: phy: mediatek,tphy: Add support for + MT7981 +MIME-Version: 1.0 +Message-Id: <20251105-openwrt-one-network-v3-5-008e2cab38d1@collabora.com> +References: <20251105-openwrt-one-network-v3-0-008e2cab38d1@collabora.com> +In-Reply-To: <20251105-openwrt-one-network-v3-0-008e2cab38d1@collabora.com> +To: Rob Herring , Krzysztof Kozlowski , + Conor Dooley , + Matthias Brugger , + AngeloGioacchino Del Regno , + Ryder Lee , + Jianjun Wang , + Bjorn Helgaas , + Lorenzo Pieralisi , =?utf-8?q?Krzysztof_Wilczy?= + =?utf-8?q?=C5=84ski?= , + Manivannan Sadhasivam , + Chunfeng Yun , Vinod Koul , + Kishon Vijay Abraham I , Lee Jones , + Andrew Lunn , + "David S. Miller" , Eric Dumazet , + Jakub Kicinski , Paolo Abeni , + Lorenzo Bianconi , Felix Fietkau +Cc: kernel@collabora.com, devicetree@vger.kernel.org, + linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, + linux-mediatek@lists.infradead.org, linux-pci@vger.kernel.org, + linux-phy@lists.infradead.org, netdev@vger.kernel.org, + Daniel Golle , Bryan Hinton , + Sjoerd Simons , + Conor Dooley +X-Mailer: b4 0.14.3 +X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 +X-CRM114-CacheID: sfid-20251105_131842_202316_35B8CB33 +X-CRM114-Status: UNSURE ( 9.72 ) +X-CRM114-Notice: Please train this message. +X-BeenThere: linux-mediatek@lists.infradead.org +X-Mailman-Version: 2.1.34 +Precedence: list +List-Id: +List-Unsubscribe: , + +List-Archive: +List-Post: +List-Help: +List-Subscribe: , + +Sender: "Linux-mediatek" +Errors-To: + linux-mediatek-bounces+linux-mediatek=archiver.kernel.org@lists.infradead.org + +Add a compatible string for Filogic 820, this chip integrates a MediaTek +generic T-PHY version 2 + +Acked-by: Conor Dooley +Reviewed-by: AngeloGioacchino Del Regno +Signed-off-by: Sjoerd Simons +--- + Documentation/devicetree/bindings/phy/mediatek,tphy.yaml | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/Documentation/devicetree/bindings/phy/mediatek,tphy.yaml b/Documentation/devicetree/bindings/phy/mediatek,tphy.yaml +index b2218c1519391..ff5c77ef11765 100644 +--- a/Documentation/devicetree/bindings/phy/mediatek,tphy.yaml ++++ b/Documentation/devicetree/bindings/phy/mediatek,tphy.yaml +@@ -80,6 +80,7 @@ properties: + - mediatek,mt2712-tphy + - mediatek,mt6893-tphy + - mediatek,mt7629-tphy ++ - mediatek,mt7981-tphy + - mediatek,mt7986-tphy + - mediatek,mt8183-tphy + - mediatek,mt8186-tphy + +From patchwork Wed Nov 5 21:18:01 2025 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +X-Patchwork-Submitter: Sjoerd Simons +X-Patchwork-Id: 14300875 +Return-Path: + +X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on + aws-us-west-2-korg-lkml-1.web.codeaurora.org +Received: from bombadil.infradead.org (bombadil.infradead.org + [198.137.202.133]) + (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) + (No client certificate requested) + by smtp.lore.kernel.org (Postfix) with ESMTPS id C874ACCFA0D + for ; + Wed, 5 Nov 2025 21:18:46 +0000 (UTC) +DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; + d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help + :List-Post:List-Archive:List-Unsubscribe:List-Id:Cc:To:In-Reply-To:References + :Message-Id:Content-Transfer-Encoding:Content-Type:MIME-Version:Subject:Date: + From:Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From: + Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; + bh=OewVkhzvg4trcmQP7/dgtYYz1ryrPP/rqMADz2pCeIY=; b=eBnFgMQu6a8d0DML7ZzSSFNoCZ + DqFsz4ne4kYrtfFmuvmuEkbTrqGBdzE9131EyGzy/uA9Fq6yDTXgNMsimzA7/m1N1Q6u63d8WdjF/ + 3p66nHdfIAb9N1dVcrm9CPX2RFnbVDyEBv2tvm8iY3tMxgDaKYzpFgnxYrJcfyLRPBXbxhVyGJo5d + LcYXnXYVHZUyPL0ll5Y41IouTph2oNeLpCfnVlngJIy/I5Hf2Jr8TfSYR6tbWiJ/o7WPCFM6DnKrG + C2JBp2cYtt1ba9c40i6XiU+AIs27VIcIrTN3Bwd5sH0Ia6FMxOTi1w3J4jXDXj0p6Zsosm0Iq0ypr + S3OLKEeg==; +Received: from localhost ([::1] helo=bombadil.infradead.org) + by bombadil.infradead.org with esmtp (Exim 4.98.2 #2 (Red Hat Linux)) + id 1vGktx-0000000EU6b-0FrT; + Wed, 05 Nov 2025 21:18:45 +0000 +Received: from bali.collaboradmins.com ([2a01:4f8:201:9162::2]) + by bombadil.infradead.org with esmtps (Exim 4.98.2 #2 (Red Hat Linux)) + id 1vGktq-0000000ETy7-1d4m; + Wed, 05 Nov 2025 21:18:40 +0000 +DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; + s=mail; t=1762377515; + bh=USBTzS5LeZooJ42tEMhi7N85ITpVvJxHo6le5MQpsP8=; + h=From:Date:Subject:References:In-Reply-To:To:Cc:From; + b=WUkRIO/LYeerYC6Qq/d0vAfift6ItxGSaUObXGhLruOzlq7/kcBr+2CN1AmZAyYlB + ZRHuj0ONVxvE+iM881QLIewGCInjRhlpv766aT3kf5EdndnvQpUWI6mGcXSL9+D0bN + 0ymjCtAs+DhWJriToq1IQY5gRFeScXU6UIUtzPu2MxzrkrxXxGN01BwA6CQ4EmIum6 + Pk5d7dytEcRSh4zBULWcisWeYuZETEWT38J4AeK75/W2ocxODRxIv13QX4OA+rI2Yu + gHgcEnQgXIYVVIgDHHmZ463GAH23E5F2DeDcWV6rYF/15ONDTxTVsY/8HKSAF8qhz4 + Y2Ku4wTENqHjg== +Received: from beast.luon.net (simons.connected.by.freedominter.net + [45.83.240.172]) + (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) + key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest + SHA256) + (No client certificate requested) + (Authenticated sender: sjoerd) + by bali.collaboradmins.com (Postfix) with ESMTPSA id 5918117E13DC; + Wed, 5 Nov 2025 22:18:35 +0100 (CET) +Received: by beast.luon.net (Postfix, from userid 1000) + id AC8E110F352E5; Wed, 05 Nov 2025 22:18:34 +0100 (CET) +From: Sjoerd Simons +Date: Wed, 05 Nov 2025 22:18:01 +0100 +Subject: [PATCH v3 06/13] arm64: dts: mediatek: mt7981b: Add PCIe and USB + support +MIME-Version: 1.0 +Message-Id: <20251105-openwrt-one-network-v3-6-008e2cab38d1@collabora.com> +References: <20251105-openwrt-one-network-v3-0-008e2cab38d1@collabora.com> +In-Reply-To: <20251105-openwrt-one-network-v3-0-008e2cab38d1@collabora.com> +To: Rob Herring , Krzysztof Kozlowski , + Conor Dooley , + Matthias Brugger , + AngeloGioacchino Del Regno , + Ryder Lee , + Jianjun Wang , + Bjorn Helgaas , + Lorenzo Pieralisi , =?utf-8?q?Krzysztof_Wilczy?= + =?utf-8?q?=C5=84ski?= , + Manivannan Sadhasivam , + Chunfeng Yun , Vinod Koul , + Kishon Vijay Abraham I , Lee Jones , + Andrew Lunn , + "David S. Miller" , Eric Dumazet , + Jakub Kicinski , Paolo Abeni , + Lorenzo Bianconi , Felix Fietkau +Cc: kernel@collabora.com, devicetree@vger.kernel.org, + linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, + linux-mediatek@lists.infradead.org, linux-pci@vger.kernel.org, + linux-phy@lists.infradead.org, netdev@vger.kernel.org, + Daniel Golle , Bryan Hinton , + Sjoerd Simons +X-Mailer: b4 0.14.3 +X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 +X-CRM114-CacheID: sfid-20251105_131838_605736_F24BF5C4 +X-CRM114-Status: GOOD ( 13.23 ) +X-BeenThere: linux-mediatek@lists.infradead.org +X-Mailman-Version: 2.1.34 +Precedence: list +List-Id: +List-Unsubscribe: , + +List-Archive: +List-Post: +List-Help: +List-Subscribe: , + +Sender: "Linux-mediatek" +Errors-To: + linux-mediatek-bounces+linux-mediatek=archiver.kernel.org@lists.infradead.org + +Add device tree nodes for PCIe controller and USB3 XHCI host +controller on MT7981B SoC. Both controllers share the USB3 PHY +which can be configured for either USB3 or PCIe operation. + +The USB3 XHCI controller supports USB 2.0 and USB 3.0 SuperSpeed +operation. The PCIe controller is compatible with PCIe Gen2 +specifications. + +Also add the topmisc syscon node required for USB/PCIe PHY +multiplexing. + +Reviewed-by: AngeloGioacchino Del Regno +Signed-off-by: Sjoerd Simons +--- +V1 -> V2: Keep xhci reg and phys properties in single lines +--- + arch/arm64/boot/dts/mediatek/mt7981b.dtsi | 80 +++++++++++++++++++++++++++++++ + 1 file changed, 80 insertions(+) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7981b.dtsi b/arch/arm64/boot/dts/mediatek/mt7981b.dtsi +index 416096b80770c..d3f37413413e2 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7981b.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7981b.dtsi +@@ -2,6 +2,7 @@ + + #include + #include ++#include + #include + + / { +@@ -223,6 +224,55 @@ auxadc: adc@1100d000 { + status = "disabled"; + }; + ++ xhci: usb@11200000 { ++ compatible = "mediatek,mt7986-xhci", "mediatek,mtk-xhci"; ++ reg = <0 0x11200000 0 0x2e00>, <0 0x11203e00 0 0x0100>; ++ reg-names = "mac", "ippc"; ++ clocks = <&infracfg CLK_INFRA_IUSB_SYS_CK>, ++ <&infracfg CLK_INFRA_IUSB_CK>, ++ <&infracfg CLK_INFRA_IUSB_133_CK>, ++ <&infracfg CLK_INFRA_IUSB_66M_CK>, ++ <&topckgen CLK_TOP_U2U3_XHCI_SEL>; ++ clock-names = "sys_ck", "ref_ck", "mcu_ck", "dma_ck", "xhci_ck"; ++ interrupts = ; ++ phys = <&u2port0 PHY_TYPE_USB2>, <&u3port0 PHY_TYPE_USB3>; ++ status = "disabled"; ++ }; ++ ++ pcie: pcie@11280000 { ++ compatible = "mediatek,mt7981-pcie", ++ "mediatek,mt8192-pcie"; ++ reg = <0 0x11280000 0 0x4000>; ++ reg-names = "pcie-mac"; ++ ranges = <0x82000000 0 0x20000000 ++ 0x0 0x20000000 0 0x10000000>; ++ bus-range = <0x00 0xff>; ++ clocks = <&infracfg CLK_INFRA_IPCIE_CK>, ++ <&infracfg CLK_INFRA_IPCIE_PIPE_CK>, ++ <&infracfg CLK_INFRA_IPCIER_CK>, ++ <&infracfg CLK_INFRA_IPCIEB_CK>; ++ clock-names = "pl_250m", "tl_26m", "peri_26m", "top_133m"; ++ device_type = "pci"; ++ phys = <&u3port0 PHY_TYPE_PCIE>; ++ phy-names = "pcie-phy"; ++ interrupts = ; ++ interrupt-map-mask = <0 0 0 7>; ++ interrupt-map = <0 0 0 1 &pcie_intc 0>, ++ <0 0 0 2 &pcie_intc 1>, ++ <0 0 0 3 &pcie_intc 2>, ++ <0 0 0 4 &pcie_intc 3>; ++ #address-cells = <3>; ++ #interrupt-cells = <1>; ++ #size-cells = <2>; ++ status = "disabled"; ++ ++ pcie_intc: interrupt-controller { ++ interrupt-controller; ++ #address-cells = <0>; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ + pio: pinctrl@11d00000 { + compatible = "mediatek,mt7981-pinctrl"; + reg = <0 0x11d00000 0 0x1000>, +@@ -252,6 +302,36 @@ mux { + }; + }; + ++ topmisc: topmisc@11d10000 { ++ compatible = "mediatek,mt7981-topmisc", "syscon"; ++ reg = <0 0x11d10000 0 0x10000>; ++ #clock-cells = <1>; ++ }; ++ ++ usb_phy: t-phy@11e10000 { ++ compatible = "mediatek,mt7981-tphy", ++ "mediatek,generic-tphy-v2"; ++ ranges = <0 0 0x11e10000 0x1700>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ status = "disabled"; ++ ++ u2port0: usb-phy@0 { ++ reg = <0x0 0x700>; ++ clocks = <&topckgen CLK_TOP_USB_FRMCNT_SEL>; ++ clock-names = "ref"; ++ #phy-cells = <1>; ++ }; ++ ++ u3port0: usb-phy@700 { ++ reg = <0x700 0x900>; ++ clocks = <&topckgen CLK_TOP_USB3_PHY_SEL>; ++ clock-names = "ref"; ++ #phy-cells = <1>; ++ mediatek,syscon-type = <&topmisc 0x218 0>; ++ }; ++ }; ++ + efuse@11f20000 { + compatible = "mediatek,mt7981-efuse", "mediatek,efuse"; + reg = <0 0x11f20000 0 0x1000>; + +From patchwork Wed Nov 5 21:18:02 2025 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +X-Patchwork-Submitter: Sjoerd Simons +X-Patchwork-Id: 14300885 +Return-Path: + +X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on + aws-us-west-2-korg-lkml-1.web.codeaurora.org +Received: from bombadil.infradead.org (bombadil.infradead.org + [198.137.202.133]) + (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) + (No client certificate requested) + by smtp.lore.kernel.org (Postfix) with ESMTPS id 3EC2DCCFA1B + for ; + Wed, 5 Nov 2025 21:19:10 +0000 (UTC) +DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; + d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help + :List-Post:List-Archive:List-Unsubscribe:List-Id:Cc:To:In-Reply-To:References + :Message-Id:Content-Transfer-Encoding:Content-Type:MIME-Version:Subject:Date: + From:Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From: + Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; + bh=5LeoqZv3J6t2Lu06YdrFLcmlUA455lKj3p+A2h/ypu8=; b=PfxLR/Mh2vBYaTJCsX5x5GiFJT + c0XXtfD6Q7TsmIVYzLO9l2tgwYZnmIEkVuwoQmVgaUOTuLbleLuWmFzxr8IXcuR4lVScxkNwxJOJ4 + arLlD/JihJ70w8AtqG+NlDelQAmD9eRvnysxvuQgTkrITmUAZDlfRKn6+oLfUtx4wsOrp+6lU/m0I + AFoY/3+mRPZVyjWrkB1aPP2LkchYiZ6ExCSaXXkYP9MoyhWinMA0n9ufduTt9gxOfaa5Z7ZEcqneh + O0ujcAlTyM7uqLKAMRxQpZML9inVDQvrpvFzsHSPE10NZVbkZ8vrdEyEEX7d90jfmPjBu/JMouO7L + EmjFICkQ==; +Received: from localhost ([::1] helo=bombadil.infradead.org) + by bombadil.infradead.org with esmtp (Exim 4.98.2 #2 (Red Hat Linux)) + id 1vGkuL-0000000EUdx-0bjn; + Wed, 05 Nov 2025 21:19:09 +0000 +Received: from bali.collaboradmins.com ([148.251.105.195]) + by bombadil.infradead.org with esmtps (Exim 4.98.2 #2 (Red Hat Linux)) + id 1vGktv-0000000EU0s-1jI7; + Wed, 05 Nov 2025 21:18:46 +0000 +DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; + s=mail; t=1762377516; + bh=qtE8TxX+bp4mVeKXXycM622mPKaw8qoe/nGz0YEjV0g=; + h=From:Date:Subject:References:In-Reply-To:To:Cc:From; + b=IaRJcfEJJPmuVxfIA0AMonJG0NAIwG2GFs1HcbU8uvXF99pgELvzC5G7nSSRhwUVJ + LuwV5lD0JO+6NbQDCg/6824/ru1L/WtPNmPZ9XIv2dmNWRPrG1D+ir8Y18q8GzoaIE + qEW8KlPcmRtH5QYv8gEmfKMpqY/vnwuoHhrQxhH/YBZUJn8Mrio3T/yeFVOaa9Kfp/ + 3bU7QVAyxxZtxGmkVSf/V0rYQ39sDr5ivWxPxN2ygRhLyKoa/vXN3Zh8b/MbgnaR53 + jdmgxlQ8Y7in86CB/YBRRqqqam07WivxiWw5icWmtAT4asEubhTmOpyhAMNyxRoJ/A + g3EvDDnrDetBw== +Received: from beast.luon.net (unknown [IPv6:2a10:3781:2531::8]) + (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) + key-exchange X25519 server-signature RSA-PSS (4096 bits)) + (No client certificate requested) + (Authenticated sender: sjoerd) + by bali.collaboradmins.com (Postfix) with ESMTPSA id 4164C17E1500; + Wed, 5 Nov 2025 22:18:36 +0100 (CET) +Received: by beast.luon.net (Postfix, from userid 1000) + id B209C10F352E7; Wed, 05 Nov 2025 22:18:34 +0100 (CET) +From: Sjoerd Simons +Date: Wed, 05 Nov 2025 22:18:02 +0100 +Subject: [PATCH v3 07/13] arm64: dts: mediatek: mt7981b-openwrt-one: Enable + PCIe and USB +MIME-Version: 1.0 +Message-Id: <20251105-openwrt-one-network-v3-7-008e2cab38d1@collabora.com> +References: <20251105-openwrt-one-network-v3-0-008e2cab38d1@collabora.com> +In-Reply-To: <20251105-openwrt-one-network-v3-0-008e2cab38d1@collabora.com> +To: Rob Herring , Krzysztof Kozlowski , + Conor Dooley , + Matthias Brugger , + AngeloGioacchino Del Regno , + Ryder Lee , + Jianjun Wang , + Bjorn Helgaas , + Lorenzo Pieralisi , =?utf-8?q?Krzysztof_Wilczy?= + =?utf-8?q?=C5=84ski?= , + Manivannan Sadhasivam , + Chunfeng Yun , Vinod Koul , + Kishon Vijay Abraham I , Lee Jones , + Andrew Lunn , + "David S. Miller" , Eric Dumazet , + Jakub Kicinski , Paolo Abeni , + Lorenzo Bianconi , Felix Fietkau +Cc: kernel@collabora.com, devicetree@vger.kernel.org, + linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, + linux-mediatek@lists.infradead.org, linux-pci@vger.kernel.org, + linux-phy@lists.infradead.org, netdev@vger.kernel.org, + Daniel Golle , Bryan Hinton , + Sjoerd Simons +X-Mailer: b4 0.14.3 +X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 +X-CRM114-CacheID: sfid-20251105_131843_751628_5822FC28 +X-CRM114-Status: GOOD ( 11.99 ) +X-BeenThere: linux-mediatek@lists.infradead.org +X-Mailman-Version: 2.1.34 +Precedence: list +List-Id: +List-Unsubscribe: , + +List-Archive: +List-Post: +List-Help: +List-Subscribe: , + +Sender: "Linux-mediatek" +Errors-To: + linux-mediatek-bounces+linux-mediatek=archiver.kernel.org@lists.infradead.org + +Enable the PCIe controller and USB3 XHCI host on the OpenWrt One +board. The USB controller is configured for USB 2.0 only mode, as the +shared USB3/PCIe PHY is dedicated to PCIe functionality on this board. + +Signed-off-by: Sjoerd Simons +--- + .../boot/dts/mediatek/mt7981b-openwrt-one.dts | 43 ++++++++++++++++++++++ + 1 file changed, 43 insertions(+) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7981b-openwrt-one.dts b/arch/arm64/boot/dts/mediatek/mt7981b-openwrt-one.dts +index 2e39e72877301..7382599cfea29 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7981b-openwrt-one.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7981b-openwrt-one.dts +@@ -67,9 +67,40 @@ led-2 { + linux,default-trigger = "netdev"; + }; + }; ++ ++ reg_3p3v: regulator-3p3v { ++ compatible = "regulator-fixed"; ++ regulator-name = "fixed-3.3V"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ reg_5v: regulator-5v { ++ compatible = "regulator-fixed"; ++ regulator-name = "fixed-5V"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++}; ++ ++&pcie { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pcie_pins>; ++ status = "okay"; + }; + + &pio { ++ pcie_pins: pcie-pins { ++ mux { ++ function = "pcie"; ++ groups = "pcie_pereset"; ++ }; ++ }; ++ + pwm_pins: pwm-pins { + mux { + function = "pwm"; +@@ -163,3 +194,15 @@ partition@180000 { + &uart0 { + status = "okay"; + }; ++ ++&usb_phy { ++ status = "okay"; ++}; ++ ++&xhci { ++ phys = <&u2port0 PHY_TYPE_USB2>; ++ vusb33-supply = <®_3p3v>; ++ vbus-supply = <®_5v>; ++ mediatek,u3p-dis-msk = <0x01>; ++ status = "okay"; ++}; + +From patchwork Wed Nov 5 21:18:03 2025 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +X-Patchwork-Submitter: Sjoerd Simons +X-Patchwork-Id: 14300879 +Return-Path: + +X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on + aws-us-west-2-korg-lkml-1.web.codeaurora.org +Received: from bombadil.infradead.org (bombadil.infradead.org + [198.137.202.133]) + (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) + (No client certificate requested) + by smtp.lore.kernel.org (Postfix) with ESMTPS id 68EEECCFA1A + for ; + Wed, 5 Nov 2025 21:18:57 +0000 (UTC) +DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; + d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help + :List-Post:List-Archive:List-Unsubscribe:List-Id:Cc:To:In-Reply-To:References + :Message-Id:Content-Transfer-Encoding:Content-Type:MIME-Version:Subject:Date: + From:Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From: + Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; + bh=U/HWjTcrTykICPk85BFLbniT6AbycVyNQZ2wskKa2+Y=; b=x5M00nhbHn+3doFPziZ5+1s+cC + nSFohk31+n65D5KFc3MQkD/xhAnz+cbHNi1o66MbO0Al6zxPP0czjOlmx/3UUy+2UyciVb71uaDyY + mWFtQPe3Uv+g8U6qsB5q5G8wXcDoCX0l7y8qqjSf225PjfL/f+EY8TtLMsuuD6apduiPoxYUwf0hU + pgoh3Qpe0A58fLM0kkFvlOEUjN7zJuMUTtVUy//izs9Xz7IiWWFaOqAFCmnMqWtxnygW8SDmiPNwU + E8feSR2lr2PkXvYtb56ovazoEyqlIt+48k4TMCer5QVKK3OG3xvUI6WHCy+bN71Pj9VwoU9CiGUmh + s0d94Bbg==; +Received: from localhost ([::1] helo=bombadil.infradead.org) + by bombadil.infradead.org with esmtp (Exim 4.98.2 #2 (Red Hat Linux)) + id 1vGku7-0000000EUKu-1vzn; + Wed, 05 Nov 2025 21:18:55 +0000 +Received: from bali.collaboradmins.com ([2a01:4f8:201:9162::2]) + by bombadil.infradead.org with esmtps (Exim 4.98.2 #2 (Red Hat Linux)) + id 1vGktu-0000000EU01-3nAf; + Wed, 05 Nov 2025 21:18:45 +0000 +DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; + s=mail; t=1762377516; + bh=awDSMBDJzPPS4EnVp8+B6nVYbJz7nRdZNkEF4vHPpPs=; + h=From:Date:Subject:References:In-Reply-To:To:Cc:From; + b=ci42NPe8j7NJSLA1jJMH0sd/AmJryok+Vl512uKMGj5mF2Kxb3nn2pL+6hJVPtci6 + ZZkmTVlO1SqVesFxzX+Q4zRKCSPVZeCb7E01Cdng8wUwBesuwK9m0Tn2PfSzaN4oDo + fKbUfb5awtUm/uQeA2LTeJgBs9vIHwaBI8zxpWSsM6pXLyiBIHKqlnnW3zA9NjO1i/ + ZuSqud86yIDPzsXOaxa3W11u+/4aMukzxMhNeOP9SWxZTMBWKM9ln5DhMMsdFaT1m0 + abYnXSsuUk+88l4wwcitMfj6JmgzN8RAJhIpUuBOXP3w4aG5Tl1kvPzmbFApEnf0/2 + KMjrOAZnCGYig== +Received: from beast.luon.net (unknown [IPv6:2a10:3781:2531::8]) + (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) + key-exchange X25519 server-signature RSA-PSS (4096 bits)) + (No client certificate requested) + (Authenticated sender: sjoerd) + by bali.collaboradmins.com (Postfix) with ESMTPSA id 0997B17E1465; + Wed, 5 Nov 2025 22:18:36 +0100 (CET) +Received: by beast.luon.net (Postfix, from userid 1000) + id B56D010F352E9; Wed, 05 Nov 2025 22:18:34 +0100 (CET) +From: Sjoerd Simons +Date: Wed, 05 Nov 2025 22:18:03 +0100 +Subject: [PATCH v3 08/13] dt-bindings: net: mediatek,net: Correct bindings + for MT7981 +MIME-Version: 1.0 +Message-Id: <20251105-openwrt-one-network-v3-8-008e2cab38d1@collabora.com> +References: <20251105-openwrt-one-network-v3-0-008e2cab38d1@collabora.com> +In-Reply-To: <20251105-openwrt-one-network-v3-0-008e2cab38d1@collabora.com> +To: Rob Herring , Krzysztof Kozlowski , + Conor Dooley , + Matthias Brugger , + AngeloGioacchino Del Regno , + Ryder Lee , + Jianjun Wang , + Bjorn Helgaas , + Lorenzo Pieralisi , =?utf-8?q?Krzysztof_Wilczy?= + =?utf-8?q?=C5=84ski?= , + Manivannan Sadhasivam , + Chunfeng Yun , Vinod Koul , + Kishon Vijay Abraham I , Lee Jones , + Andrew Lunn , + "David S. Miller" , Eric Dumazet , + Jakub Kicinski , Paolo Abeni , + Lorenzo Bianconi , Felix Fietkau +Cc: kernel@collabora.com, devicetree@vger.kernel.org, + linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, + linux-mediatek@lists.infradead.org, linux-pci@vger.kernel.org, + linux-phy@lists.infradead.org, netdev@vger.kernel.org, + Daniel Golle , Bryan Hinton , + Sjoerd Simons +X-Mailer: b4 0.14.3 +X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 +X-CRM114-CacheID: sfid-20251105_131843_168278_91D1058F +X-CRM114-Status: GOOD ( 10.93 ) +X-BeenThere: linux-mediatek@lists.infradead.org +X-Mailman-Version: 2.1.34 +Precedence: list +List-Id: +List-Unsubscribe: , + +List-Archive: +List-Post: +List-Help: +List-Subscribe: , + +Sender: "Linux-mediatek" +Errors-To: + linux-mediatek-bounces+linux-mediatek=archiver.kernel.org@lists.infradead.org + +Different SoCs can have different numbers of Wireless Ethernet +Dispatch (WED) units, specifically the MT7981 only has a single WED. +Furthermore the MT7981 uses infracfg for PHY switching. Adjust bindings +to match both aspects. + +Signed-off-by: Sjoerd Simons +--- +V2 -> V3: Only update MT7981 constraints rather then defaults +V1 -> V2: Only overwrite constraints that are different from the default +--- + Documentation/devicetree/bindings/net/mediatek,net.yaml | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/Documentation/devicetree/bindings/net/mediatek,net.yaml b/Documentation/devicetree/bindings/net/mediatek,net.yaml +index b45f67f92e80d..c49871438efc7 100644 +--- a/Documentation/devicetree/bindings/net/mediatek,net.yaml ++++ b/Documentation/devicetree/bindings/net/mediatek,net.yaml +@@ -338,12 +338,14 @@ allOf: + - const: netsys0 + - const: netsys1 + +- mediatek,infracfg: false +- + mediatek,sgmiisys: + minItems: 2 + maxItems: 2 + ++ mediatek,wed: ++ minItems: 1 ++ maxItems: 1 ++ + - if: + properties: + compatible: + +From patchwork Wed Nov 5 21:18:04 2025 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +X-Patchwork-Submitter: Sjoerd Simons +X-Patchwork-Id: 14300880 +Return-Path: + +X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on + aws-us-west-2-korg-lkml-1.web.codeaurora.org +Received: from bombadil.infradead.org (bombadil.infradead.org + [198.137.202.133]) + (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) + (No client certificate requested) + by smtp.lore.kernel.org (Postfix) with ESMTPS id 7FBBCCCFA1B + for ; + Wed, 5 Nov 2025 21:19:07 +0000 (UTC) +DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; + d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help + :List-Post:List-Archive:List-Unsubscribe:List-Id:Cc:To:In-Reply-To:References + :Message-Id:Content-Transfer-Encoding:Content-Type:MIME-Version:Subject:Date: + From:Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From: + Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; + bh=ueCHoKYMg9K7QpsQLRQi0Sc30bMhBHa09ApzlEJfMVY=; b=oliYQgrzXGp3vf+njo9cxmoUI0 + SYH4m3tbm1tJIntPx9Y9w063n6upSy6atQ0W8wAeqeCt9R9CjK2fHnsbSZOGr8/TkQ2QLNTMKv0Qb + PCbjTvPayNSWTUKEI8iL4LjsbVafBOIVPC+QHjLq+Zll58hjqW/bDzeVw/I/GsuLEL+ST9EcYKtDa + Bb74sy8jrdoDTGwg09mXBpei524ik5p1AFNq/aC63kwwNJL1D/hw7nPJpdv+kxwohYVdYqqkOyFtp + dcJ01OouhL2/Bzzb8bm1+1mXERn6C9/wo65rN+SHocGUc5sL3HMNwpvLGN53seLpDIKnjRGhNVqbl + Jan3eReA==; +Received: from localhost ([::1] helo=bombadil.infradead.org) + by bombadil.infradead.org with esmtp (Exim 4.98.2 #2 (Red Hat Linux)) + id 1vGkuH-0000000EUXq-1q2R; + Wed, 05 Nov 2025 21:19:05 +0000 +Received: from bali.collaboradmins.com ([2a01:4f8:201:9162::2]) + by bombadil.infradead.org with esmtps (Exim 4.98.2 #2 (Red Hat Linux)) + id 1vGktu-0000000ETzU-0GDS; + Wed, 05 Nov 2025 21:18:46 +0000 +DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; + s=mail; t=1762377515; + bh=BQ/4Q4O4iwtOMxBPtuM66Fi5zxdH24aH3c3Edh+F6Gw=; + h=From:Date:Subject:References:In-Reply-To:To:Cc:From; + b=IRXC0OH241ZhJ2dEV4LfgFdc4A+BagnFWsrrwtn3vopT0NppteIBKbXw109zFFIMG + 2fkF/7w+APwUdAHb8p8WH8NejrZz9YQMjnZYmts9yjB2RC4J/8uGXcVWaPrpN2OYHr + 63AzqjmeOxP0yepmJ8/ngYGq5byQ6vpaSRrfSu1mB8RcYDlBcOy0Q3f8kKlFvO2QET + hax6ycKibWsvT1isXzFk5Wf6lyrxvYFABMBQ/cW3mVVXCXYlzjQlqImgmKg3Qs5l2N + lKwf4s814rTjC+0SRKPGpYey5S1ExcBlNy1zKk1+38i7C0VxUAa2NfJi4pv43fB8MB + fv/XeT07/fxDA== +Received: from beast.luon.net (simons.connected.by.freedominter.net + [45.83.240.172]) + (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) + key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest + SHA256) + (No client certificate requested) + (Authenticated sender: sjoerd) + by bali.collaboradmins.com (Postfix) with ESMTPSA id 6263917E1401; + Wed, 5 Nov 2025 22:18:35 +0100 (CET) +Received: by beast.luon.net (Postfix, from userid 1000) + id BD7E410F352EB; Wed, 05 Nov 2025 22:18:34 +0100 (CET) +From: Sjoerd Simons +Date: Wed, 05 Nov 2025 22:18:04 +0100 +Subject: [PATCH v3 09/13] arm64: dts: mediatek: mt7981b: Add Ethernet and + WiFi offload support +MIME-Version: 1.0 +Message-Id: <20251105-openwrt-one-network-v3-9-008e2cab38d1@collabora.com> +References: <20251105-openwrt-one-network-v3-0-008e2cab38d1@collabora.com> +In-Reply-To: <20251105-openwrt-one-network-v3-0-008e2cab38d1@collabora.com> +To: Rob Herring , Krzysztof Kozlowski , + Conor Dooley , + Matthias Brugger , + AngeloGioacchino Del Regno , + Ryder Lee , + Jianjun Wang , + Bjorn Helgaas , + Lorenzo Pieralisi , =?utf-8?q?Krzysztof_Wilczy?= + =?utf-8?q?=C5=84ski?= , + Manivannan Sadhasivam , + Chunfeng Yun , Vinod Koul , + Kishon Vijay Abraham I , Lee Jones , + Andrew Lunn , + "David S. Miller" , Eric Dumazet , + Jakub Kicinski , Paolo Abeni , + Lorenzo Bianconi , Felix Fietkau +Cc: kernel@collabora.com, devicetree@vger.kernel.org, + linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, + linux-mediatek@lists.infradead.org, linux-pci@vger.kernel.org, + linux-phy@lists.infradead.org, netdev@vger.kernel.org, + Daniel Golle , Bryan Hinton , + Sjoerd Simons +X-Mailer: b4 0.14.3 +X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 +X-CRM114-CacheID: sfid-20251105_131842_314327_85CB8EE5 +X-CRM114-Status: GOOD ( 13.34 ) +X-BeenThere: linux-mediatek@lists.infradead.org +X-Mailman-Version: 2.1.34 +Precedence: list +List-Id: +List-Unsubscribe: , + +List-Archive: +List-Post: +List-Help: +List-Subscribe: , + +Sender: "Linux-mediatek" +Errors-To: + linux-mediatek-bounces+linux-mediatek=archiver.kernel.org@lists.infradead.org + +Add device tree nodes for the Ethernet subsystem on MT7981B SoC, +including: +- Ethernet MAC controller with dual GMAC support +- Wireless Ethernet Dispatch (WED) +- SGMII PHY controllers for high-speed Ethernet interfaces +- Reserved memory regions for WiFi offload processor + +Signed-off-by: Sjoerd Simons +--- +V1 -> V2: Don't add unneeded interrupt-parent +--- + arch/arm64/boot/dts/mediatek/mt7981b.dtsi | 133 +++++++++++++++++++++++++++++- + 1 file changed, 132 insertions(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7981b.dtsi b/arch/arm64/boot/dts/mediatek/mt7981b.dtsi +index d3f37413413e2..6be588be3761a 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7981b.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7981b.dtsi +@@ -2,6 +2,7 @@ + + #include + #include ++#include + #include + #include + +@@ -47,11 +48,36 @@ reserved-memory { + #size-cells = <2>; + ranges; + ++ wo_boot: wo-boot@15194000 { ++ reg = <0 0x15194000 0 0x1000>; ++ no-map; ++ }; ++ ++ wo_ilm0: wo-ilm@151e0000 { ++ reg = <0 0x151e0000 0 0x8000>; ++ no-map; ++ }; ++ ++ wo_dlm0: wo-dlm@151e8000 { ++ reg = <0 0x151e8000 0 0x2000>; ++ no-map; ++ }; ++ + /* 192 KiB reserved for ARM Trusted Firmware (BL31) */ + secmon_reserved: secmon@43000000 { + reg = <0 0x43000000 0 0x30000>; + no-map; + }; ++ ++ wo_emi0: wo-emi@47d80000 { ++ reg = <0 0x47d80000 0 0x40000>; ++ no-map; ++ }; ++ ++ wo_data: wo-data@47dc0000 { ++ reg = <0 0x47dc0000 0 0x240000>; ++ no-map; ++ }; + }; + + soc { +@@ -107,6 +133,18 @@ pwm: pwm@10048000 { + #pwm-cells = <2>; + }; + ++ sgmiisys0: syscon@10060000 { ++ compatible = "mediatek,mt7981-sgmiisys_0", "syscon"; ++ reg = <0 0x10060000 0 0x1000>; ++ #clock-cells = <1>; ++ }; ++ ++ sgmiisys1: syscon@10070000 { ++ compatible = "mediatek,mt7981-sgmiisys_1", "syscon"; ++ reg = <0 0x10070000 0 0x1000>; ++ #clock-cells = <1>; ++ }; ++ + uart0: serial@11002000 { + compatible = "mediatek,mt7981-uart", "mediatek,mt6577-uart"; + reg = <0 0x11002000 0 0x100>; +@@ -345,15 +383,108 @@ soc-uuid@140 { + thermal_calibration: thermal-calib@274 { + reg = <0x274 0xc>; + }; ++ ++ phy_calibration: phy-calib@8dc { ++ reg = <0x8dc 0x10>; ++ }; + }; + +- clock-controller@15000000 { ++ ethsys: clock-controller@15000000 { + compatible = "mediatek,mt7981-ethsys", "syscon"; + reg = <0 0x15000000 0 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + ++ wed: wed@15010000 { ++ compatible = "mediatek,mt7981-wed", ++ "syscon"; ++ reg = <0 0x15010000 0 0x1000>; ++ interrupts = ; ++ memory-region = <&wo_emi0>, <&wo_ilm0>, <&wo_dlm0>, ++ <&wo_data>, <&wo_boot>; ++ memory-region-names = "wo-emi", "wo-ilm", "wo-dlm", ++ "wo-data", "wo-boot"; ++ mediatek,wo-ccif = <&wo_ccif0>; ++ }; ++ ++ eth: ethernet@15100000 { ++ compatible = "mediatek,mt7981-eth"; ++ reg = <0 0x15100000 0 0x40000>; ++ assigned-clocks = <&topckgen CLK_TOP_NETSYS_2X_SEL>, ++ <&topckgen CLK_TOP_SGM_325M_SEL>; ++ assigned-clock-parents = <&topckgen CLK_TOP_CB_NET2_800M>, ++ <&topckgen CLK_TOP_CB_SGM_325M>; ++ clocks = <ðsys CLK_ETH_FE_EN>, ++ <ðsys CLK_ETH_GP2_EN>, ++ <ðsys CLK_ETH_GP1_EN>, ++ <ðsys CLK_ETH_WOCPU0_EN>, ++ <&topckgen CLK_TOP_SGM_REG>, ++ <&sgmiisys0 CLK_SGM0_TX_EN>, ++ <&sgmiisys0 CLK_SGM0_RX_EN>, ++ <&sgmiisys0 CLK_SGM0_CK0_EN>, ++ <&sgmiisys0 CLK_SGM0_CDR_CK0_EN>, ++ <&sgmiisys1 CLK_SGM1_TX_EN>, ++ <&sgmiisys1 CLK_SGM1_RX_EN>, ++ <&sgmiisys1 CLK_SGM1_CK1_EN>, ++ <&sgmiisys1 CLK_SGM1_CDR_CK1_EN>, ++ <&topckgen CLK_TOP_NETSYS_SEL>, ++ <&topckgen CLK_TOP_NETSYS_500M_SEL>; ++ clock-names = "fe", "gp2", "gp1", "wocpu0", ++ "sgmii_ck", ++ "sgmii_tx250m", "sgmii_rx250m", ++ "sgmii_cdr_ref", "sgmii_cdr_fb", ++ "sgmii2_tx250m", "sgmii2_rx250m", ++ "sgmii2_cdr_ref", "sgmii2_cdr_fb", ++ "netsys0", "netsys1"; ++ interrupts = , ++ , ++ , ++ , ++ , ++ , ++ , ++ ; ++ interrupt-names = "fe0", "fe1", "fe2", "fe3", "pdma0", ++ "pdma1", "pdma2", "pdma3"; ++ sram = <ð_sram>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ mediatek,ethsys = <ðsys>; ++ mediatek,sgmiisys = <&sgmiisys0>, <&sgmiisys1>; ++ mediatek,infracfg = <&topmisc>; ++ mediatek,wed = <&wed>; ++ status = "disabled"; ++ ++ mdio_bus: mdio-bus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ int_gbe_phy: ethernet-phy@0 { ++ compatible = "ethernet-phy-ieee802.3-c22"; ++ reg = <0>; ++ phy-mode = "gmii"; ++ phy-is-integrated; ++ nvmem-cells = <&phy_calibration>; ++ nvmem-cell-names = "phy-cal-data"; ++ }; ++ }; ++ }; ++ ++ eth_sram: sram@15140000 { ++ compatible = "mmio-sram"; ++ reg = <0 0x15140000 0 0x40000>; ++ ranges = <0 0x15140000 0 0x40000>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ }; ++ ++ wo_ccif0: syscon@151a5000 { ++ compatible = "mediatek,mt7986-wo-ccif", "syscon"; ++ reg = <0 0x151a5000 0 0x1000>; ++ interrupts = ; ++ }; ++ + wifi@18000000 { + compatible = "mediatek,mt7981-wmac"; + reg = <0 0x18000000 0 0x1000000>, + +From patchwork Wed Nov 5 21:18:05 2025 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +X-Patchwork-Submitter: Sjoerd Simons +X-Patchwork-Id: 14300881 +Return-Path: + +X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on + aws-us-west-2-korg-lkml-1.web.codeaurora.org +Received: from bombadil.infradead.org (bombadil.infradead.org + [198.137.202.133]) + (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) + (No client certificate requested) + by smtp.lore.kernel.org (Postfix) with ESMTPS id 0C278CCFA0D + for ; + Wed, 5 Nov 2025 21:19:09 +0000 (UTC) +DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; + d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help + :List-Post:List-Archive:List-Unsubscribe:List-Id:Cc:To:In-Reply-To:References + :Message-Id:Content-Transfer-Encoding:Content-Type:MIME-Version:Subject:Date: + From:Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From: + Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; + bh=VGCX3mgdLYE3ZtU21iczIBrppRvsmuNEB9MXEkOTjzE=; b=vwuFO9rp4k3Jzt7q1sPWRB5CPb + QEUY+zTxr5r7y0khdN18kt0qP0XyiCYfwKjL4Ud+lhyRQ6asf5RVVQgi+3DjAJcXsg2foGiAu1w8c + 83G2UpXXeWjSoVb6RhL2IDxiibl1EioKC18NeU5NPgzQ1in8oRuZQPJBJqJH0Nuv6+TYcattdfdoE + 9sMmuYoxqw8kgr+zgp7Pk5HwFN2MwBzE3/1xTYfuv9JeYOposIx65HjchoulcRkLyAD2boK9EVPib + 1a9mNgXVo34a/bqIiLYsrtRf+gXgf+BGAQMBSe/eieTg8ik2d2H8gul5GOgtNJGAn0SOYHZz0NTOY + p2BeDGoA==; +Received: from localhost ([::1] helo=bombadil.infradead.org) + by bombadil.infradead.org with esmtp (Exim 4.98.2 #2 (Red Hat Linux)) + id 1vGkuJ-0000000EUas-2SQB; + Wed, 05 Nov 2025 21:19:07 +0000 +Received: from bali.collaboradmins.com ([148.251.105.195]) + by bombadil.infradead.org with esmtps (Exim 4.98.2 #2 (Red Hat Linux)) + id 1vGktu-0000000ETzZ-10Ek; + Wed, 05 Nov 2025 21:18:46 +0000 +DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; + s=mail; t=1762377515; + bh=8iJNPpI85EcL2zA7omSQYgyHFc03BY1+Hwd6GqmpZ7c=; + h=From:Date:Subject:References:In-Reply-To:To:Cc:From; + b=bhcUswclG/V7+nJL9BrqpvNYkBM0psesnDqRq4okPos7i3GdGONTy0afA68KlTBYl + zpMIv8lqWjOkFGB3cGxu5HSPs4wGpRySiOTO6Rc3Zaz3r+M/Xmasu82dcfGbvYc0za + DS59SGV8KrRBldu6YfMedk/I+R3jD5xdRQwb5RWuwM52ePJZCjHxyJnlN7lc7F7oej + YKuwFLLB2CaQPDm4h67Kqrd6o+IkWXx61A0SevTi6yc4fDg5Z7k393cfyU++BRjjdE + /w2GvFBsr6KtHHMcS+sog8i4wMR48Uw2+7jiNyhYttvT82m0pxA32Vbotz4MPtu175 + eAxrkt5hWJEBQ== +Received: from beast.luon.net (simons.connected.by.freedominter.net + [45.83.240.172]) + (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) + key-exchange X25519 server-signature RSA-PSS (4096 bits)) + (No client certificate requested) + (Authenticated sender: sjoerd) + by bali.collaboradmins.com (Postfix) with ESMTPSA id 8797817E1416; + Wed, 5 Nov 2025 22:18:35 +0100 (CET) +Received: by beast.luon.net (Postfix, from userid 1000) + id C315110F352ED; Wed, 05 Nov 2025 22:18:34 +0100 (CET) +From: Sjoerd Simons +Date: Wed, 05 Nov 2025 22:18:05 +0100 +Subject: [PATCH v3 10/13] arm64: dts: mediatek: mt7981b-openwrt-one: Enable + Ethernet +MIME-Version: 1.0 +Message-Id: <20251105-openwrt-one-network-v3-10-008e2cab38d1@collabora.com> +References: <20251105-openwrt-one-network-v3-0-008e2cab38d1@collabora.com> +In-Reply-To: <20251105-openwrt-one-network-v3-0-008e2cab38d1@collabora.com> +To: Rob Herring , Krzysztof Kozlowski , + Conor Dooley , + Matthias Brugger , + AngeloGioacchino Del Regno , + Ryder Lee , + Jianjun Wang , + Bjorn Helgaas , + Lorenzo Pieralisi , =?utf-8?q?Krzysztof_Wilczy?= + =?utf-8?q?=C5=84ski?= , + Manivannan Sadhasivam , + Chunfeng Yun , Vinod Koul , + Kishon Vijay Abraham I , Lee Jones , + Andrew Lunn , + "David S. Miller" , Eric Dumazet , + Jakub Kicinski , Paolo Abeni , + Lorenzo Bianconi , Felix Fietkau +Cc: kernel@collabora.com, devicetree@vger.kernel.org, + linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, + linux-mediatek@lists.infradead.org, linux-pci@vger.kernel.org, + linux-phy@lists.infradead.org, netdev@vger.kernel.org, + Daniel Golle , Bryan Hinton , + Sjoerd Simons +X-Mailer: b4 0.14.3 +X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 +X-CRM114-CacheID: sfid-20251105_131842_555266_32BA2742 +X-CRM114-Status: GOOD ( 12.02 ) +X-BeenThere: linux-mediatek@lists.infradead.org +X-Mailman-Version: 2.1.34 +Precedence: list +List-Id: +List-Unsubscribe: , + +List-Archive: +List-Post: +List-Help: +List-Subscribe: , + +Sender: "Linux-mediatek" +Errors-To: + linux-mediatek-bounces+linux-mediatek=archiver.kernel.org@lists.infradead.org + +Enable the Ethernet subsystem on OpenWrt One board with dual-MAC +configuration: +- GMAC0: Connected to external Airoha EN8811H 2.5GbE PHY via SGMII + (2500base-x mode) for WAN connectivity with LED indicators +- GMAC1: Connected to internal MT7981 1GbE PHY (GMII mode) for LAN + +Ethernet aliases are defined to provide consistent network interface +naming (ethernet0 = LAN, ethernet1 = WAN). + +Signed-off-by: Sjoerd Simons +--- +V1 -> V2: + - Switch gmac0 phy irq to Level + - Update mac nvmem label name +--- + .../boot/dts/mediatek/mt7981b-openwrt-one.dts | 58 ++++++++++++++++++++++ + 1 file changed, 58 insertions(+) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7981b-openwrt-one.dts b/arch/arm64/boot/dts/mediatek/mt7981b-openwrt-one.dts +index 7382599cfea29..2aea899006453 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7981b-openwrt-one.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7981b-openwrt-one.dts +@@ -12,6 +12,8 @@ / { + model = "OpenWrt One"; + + aliases { ++ ethernet0 = &gmac1; ++ ethernet1 = &gmac0; + serial0 = &uart0; + }; + +@@ -87,6 +89,58 @@ reg_5v: regulator-5v { + }; + }; + ++ð { ++ status = "okay"; ++ ++ /* WAN interface */ ++ gmac0: mac@0 { ++ compatible = "mediatek,eth-mac"; ++ reg = <0>; ++ nvmem-cells = <&wan_factory_mac 0>; ++ nvmem-cell-names = "mac-address"; ++ phy-mode = "2500base-x"; ++ phy-handle = <&phy15>; ++ }; ++ ++ /* LAN interface */ ++ gmac1: mac@1 { ++ compatible = "mediatek,eth-mac"; ++ reg = <1>; ++ phy-mode = "gmii"; ++ phy-handle = <&int_gbe_phy>; ++ }; ++}; ++ ++&mdio_bus { ++ phy15: ethernet-phy@f { ++ compatible = "ethernet-phy-id03a2.a411"; ++ reg = <0xf>; ++ interrupt-parent = <&pio>; ++ interrupts = <38 IRQ_TYPE_LEVEL_LOW>; ++ reset-gpios = <&pio 39 GPIO_ACTIVE_LOW>; ++ reset-assert-us = <10000>; ++ reset-deassert-us = <20000>; ++ airoha,pnswap-rx; ++ ++ leds { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ led@0 { ++ reg = <0>; ++ function = LED_FUNCTION_WAN; ++ color = ; ++ }; ++ ++ led@1 { ++ reg = <1>; ++ function = LED_FUNCTION_WAN; ++ color = ; ++ }; ++ }; ++ }; ++}; ++ + &pcie { + pinctrl-names = "default"; + pinctrl-0 = <&pcie_pins>; +@@ -191,6 +245,10 @@ partition@180000 { + }; + }; + ++&sgmiisys0 { ++ mediatek,pnswap; ++}; ++ + &uart0 { + status = "okay"; + }; + +From patchwork Wed Nov 5 21:18:06 2025 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +X-Patchwork-Submitter: Sjoerd Simons +X-Patchwork-Id: 14300877 +Return-Path: + +X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on + aws-us-west-2-korg-lkml-1.web.codeaurora.org +Received: from bombadil.infradead.org (bombadil.infradead.org + [198.137.202.133]) + (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) + (No client certificate requested) + by smtp.lore.kernel.org (Postfix) with ESMTPS id 2E87CCCFA1A + for ; + Wed, 5 Nov 2025 21:18:55 +0000 (UTC) +DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; + d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help + :List-Post:List-Archive:List-Unsubscribe:List-Id:Cc:To:In-Reply-To:References + :Message-Id:Content-Transfer-Encoding:Content-Type:MIME-Version:Subject:Date: + From:Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From: + Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; + bh=dp/5wNhrbtwapW+ZRZXWBO5in38eZanyORlRgzGBhBc=; b=HDpGPrRFhEkMZcqEdHJx+Vn1M2 + TkwKEG4kr3h94GIgzaEjizmXEWjtODFNgDp5TEvYipzUeVYIzoMSkYwpDj7d5lVb6K3afrMhJx+f8 + jwamxSICsK2lCglepocgq8ZhCM4AkGfIzaMtPFRS+YD9gahvAwA3YNb8bn+VCMODpHc8MV8WRMyJ2 + DezENNKuVapHl29K0UYDDYFM85KA8pquvksKYCvK1uF3ma0Ik6wggwMvwkAlHie6+nlOI8HmpZrEA + 7g49saKBuKAc+Exloy/lK+tB6FKwHWy+ckCJrPG554fXYRgFKBrkMEzRvD94JnfZuzO+n8qbdplAY + pvOoLKCg==; +Received: from localhost ([::1] helo=bombadil.infradead.org) + by bombadil.infradead.org with esmtp (Exim 4.98.2 #2 (Red Hat Linux)) + id 1vGku5-0000000EUIM-3LQQ; + Wed, 05 Nov 2025 21:18:53 +0000 +Received: from bali.collaboradmins.com ([2a01:4f8:201:9162::2]) + by bombadil.infradead.org with esmtps (Exim 4.98.2 #2 (Red Hat Linux)) + id 1vGktu-0000000ETzX-0JYf; + Wed, 05 Nov 2025 21:18:44 +0000 +DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; + s=mail; t=1762377515; + bh=haXHZnrCQw87Hh0XlwT4Nqlq0lDr5SGoeyDsPgAcJ6c=; + h=From:Date:Subject:References:In-Reply-To:To:Cc:From; + b=N1qA/7AmkMt4wN9yHy1phEnePp5ToltlmZwi7UCQxXJhlXCL6boQBVdmwpoNtT8KS + 1X9s51SEPTLvco84Ou9mu/1q7X9ITJ4rv9QHS1yryzpoUpFuSCo/fOTVZq8ISh6Krx + kSMG98HfMijUn/ebXM+RRkEg5wOX6HPEg09mKH//uRLukU2lb/Mi4AnOqXIlIpgD8e + l9PVEOccMc5Mt25cBc+GBXKeuDbglnliEVbfnq/ctRiishATKfBCbtrXO+OtmOaATJ + DRXagBcQDZ/Ww8oM9BTwO4aphu2lcOX1lSnzmWSMOud08FP0ecqwbQ7Sa0UvpvhoKH + whKx1JPflZ1mA== +Received: from beast.luon.net (unknown [IPv6:2a10:3781:2531::8]) + (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) + key-exchange X25519 server-signature RSA-PSS (4096 bits)) + (No client certificate requested) + (Authenticated sender: sjoerd) + by bali.collaboradmins.com (Postfix) with ESMTPSA id 8654D17E1402; + Wed, 5 Nov 2025 22:18:35 +0100 (CET) +Received: by beast.luon.net (Postfix, from userid 1000) + id C8D3810F352EF; Wed, 05 Nov 2025 22:18:34 +0100 (CET) +From: Sjoerd Simons +Date: Wed, 05 Nov 2025 22:18:06 +0100 +Subject: [PATCH v3 11/13] arm64: dts: mediatek: mt7981b: Disable wifi by + default +MIME-Version: 1.0 +Message-Id: <20251105-openwrt-one-network-v3-11-008e2cab38d1@collabora.com> +References: <20251105-openwrt-one-network-v3-0-008e2cab38d1@collabora.com> +In-Reply-To: <20251105-openwrt-one-network-v3-0-008e2cab38d1@collabora.com> +To: Rob Herring , Krzysztof Kozlowski , + Conor Dooley , + Matthias Brugger , + AngeloGioacchino Del Regno , + Ryder Lee , + Jianjun Wang , + Bjorn Helgaas , + Lorenzo Pieralisi , =?utf-8?q?Krzysztof_Wilczy?= + =?utf-8?q?=C5=84ski?= , + Manivannan Sadhasivam , + Chunfeng Yun , Vinod Koul , + Kishon Vijay Abraham I , Lee Jones , + Andrew Lunn , + "David S. Miller" , Eric Dumazet , + Jakub Kicinski , Paolo Abeni , + Lorenzo Bianconi , Felix Fietkau +Cc: kernel@collabora.com, devicetree@vger.kernel.org, + linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, + linux-mediatek@lists.infradead.org, linux-pci@vger.kernel.org, + linux-phy@lists.infradead.org, netdev@vger.kernel.org, + Daniel Golle , Bryan Hinton , + Sjoerd Simons +X-Mailer: b4 0.14.3 +X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 +X-CRM114-CacheID: sfid-20251105_131842_292326_8E07EA97 +X-CRM114-Status: GOOD ( 10.46 ) +X-BeenThere: linux-mediatek@lists.infradead.org +X-Mailman-Version: 2.1.34 +Precedence: list +List-Id: +List-Unsubscribe: , + +List-Archive: +List-Post: +List-Help: +List-Subscribe: , + +Sender: "Linux-mediatek" +Errors-To: + linux-mediatek-bounces+linux-mediatek=archiver.kernel.org@lists.infradead.org + +Disable the wifi block by default as it won't function properly without +at least pin muxing. + +This doesn't enable wifi on any of the existing mt7981b devices as a +required memory-region property is missing, causing the driver to fail +probing anyway. + +Signed-off-by: Sjoerd Simons +--- +V2: Newly introduced patch +--- + arch/arm64/boot/dts/mediatek/mt7981b.dtsi | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7981b.dtsi b/arch/arm64/boot/dts/mediatek/mt7981b.dtsi +index 6be588be3761a..1f4c114354660 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7981b.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7981b.dtsi +@@ -499,6 +499,7 @@ wifi@18000000 { + clock-names = "mcu", "ap2conn"; + resets = <&watchdog MT7986_TOPRGU_CONSYS_SW_RST>; + reset-names = "consys"; ++ status = "disabled"; + }; + }; + + +From patchwork Wed Nov 5 21:18:07 2025 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +X-Patchwork-Submitter: Sjoerd Simons +X-Patchwork-Id: 14300884 +Return-Path: + +X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on + aws-us-west-2-korg-lkml-1.web.codeaurora.org +Received: from bombadil.infradead.org (bombadil.infradead.org + [198.137.202.133]) + (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) + (No client certificate requested) + by smtp.lore.kernel.org (Postfix) with ESMTPS id B140FCCFA1A + for ; + Wed, 5 Nov 2025 21:19:10 +0000 (UTC) +DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; + d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help + :List-Post:List-Archive:List-Unsubscribe:List-Id:Cc:To:In-Reply-To:References + :Message-Id:Content-Transfer-Encoding:Content-Type:MIME-Version:Subject:Date: + From:Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From: + Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; + bh=nah67Wz58HCqfn8dBCUyWhoscQpKpdn3omH+G+6PS0A=; b=rwXtntNHwuvdukJCDC6Up7uSd8 + qSMngpRBUThJUYoIU+X/SdqchVcj1mAbnCWCcsIBs3BeKRQYdDwc0OliYwD77KRZ3Lb8TTQaFxDvN + CMmFNeb+9fPK5KRu7XMtRilC5OQr9TJLSbEIs66DVWDo7glxNu1sJtyl5l+6sleidO24iztDkk8s3 + 5mxEOyZToooppfVbldmIKV+kHmjpzWboIl/+ANmR8vX9NPRhL3rBDQ031N5gd0qqh7hFtha5I4VS9 + +CAOU1vvXXbkM7X8wWNv3WixPw+qMGtGKjnRqbaeIuIgIKTPYRJF2VvxhK1bGMvBC1N44KT/Q+gUe + RGunAF9w==; +Received: from localhost ([::1] helo=bombadil.infradead.org) + by bombadil.infradead.org with esmtp (Exim 4.98.2 #2 (Red Hat Linux)) + id 1vGkuL-0000000EUfc-2xLB; + Wed, 05 Nov 2025 21:19:09 +0000 +Received: from bali.collaboradmins.com ([148.251.105.195]) + by bombadil.infradead.org with esmtps (Exim 4.98.2 #2 (Red Hat Linux)) + id 1vGktx-0000000EU5D-3EZ4; + Wed, 05 Nov 2025 21:18:47 +0000 +DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; + s=mail; t=1762377520; + bh=HT2YugA6R+JpQglGJhQu+r3GtnpE3Srg2faLNwIOQZE=; + h=From:Date:Subject:References:In-Reply-To:To:Cc:From; + b=pX5785XeaN9MSnSwL2CJEFah8vNhRL8O3uSgIa5IIUsi0dsVKQvFHNPboZ1/t6VGy + HYMGlF/jafIWUIBCk3xUfon2NPBc/8iS7yAe6TOMu+7np1x2bdtprDcNn2WTGFcX5c + t9YD1NdO/D97DTeU+AuNZeMagJIob4P/4RUTgI0pyfPYexY505AVtR4IYod4lwE/iD + 14zbJi4IQ7nOQq2nXVZRLfsFZOl8Se0bc8bOiGCKbU7u2hCgO/MHEZmy7Tp5lOFOO+ + arFcHIVGSPsrSCy0aGHPYhJxu8F2xT+eBJsfmFn39sWISuHJXg3lY64C/eh1tAKFqu + /M/mfIOF6ApyQ== +Received: from beast.luon.net (unknown [IPv6:2a10:3781:2531::8]) + (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) + key-exchange X25519 server-signature RSA-PSS (4096 bits)) + (No client certificate requested) + (Authenticated sender: sjoerd) + by bali.collaboradmins.com (Postfix) with ESMTPSA id 6F62117E156C; + Wed, 5 Nov 2025 22:18:40 +0100 (CET) +Received: by beast.luon.net (Postfix, from userid 1000) + id CC1B810F352F1; Wed, 05 Nov 2025 22:18:34 +0100 (CET) +From: Sjoerd Simons +Date: Wed, 05 Nov 2025 22:18:07 +0100 +Subject: [PATCH v3 12/13] arm64: dts: mediatek: mt7981b: Add wifi memory + region +MIME-Version: 1.0 +Message-Id: <20251105-openwrt-one-network-v3-12-008e2cab38d1@collabora.com> +References: <20251105-openwrt-one-network-v3-0-008e2cab38d1@collabora.com> +In-Reply-To: <20251105-openwrt-one-network-v3-0-008e2cab38d1@collabora.com> +To: Rob Herring , Krzysztof Kozlowski , + Conor Dooley , + Matthias Brugger , + AngeloGioacchino Del Regno , + Ryder Lee , + Jianjun Wang , + Bjorn Helgaas , + Lorenzo Pieralisi , =?utf-8?q?Krzysztof_Wilczy?= + =?utf-8?q?=C5=84ski?= , + Manivannan Sadhasivam , + Chunfeng Yun , Vinod Koul , + Kishon Vijay Abraham I , Lee Jones , + Andrew Lunn , + "David S. Miller" , Eric Dumazet , + Jakub Kicinski , Paolo Abeni , + Lorenzo Bianconi , Felix Fietkau +Cc: kernel@collabora.com, devicetree@vger.kernel.org, + linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, + linux-mediatek@lists.infradead.org, linux-pci@vger.kernel.org, + linux-phy@lists.infradead.org, netdev@vger.kernel.org, + Daniel Golle , Bryan Hinton , + Sjoerd Simons +X-Mailer: b4 0.14.3 +X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 +X-CRM114-CacheID: sfid-20251105_131846_015183_8582BEB8 +X-CRM114-Status: GOOD ( 10.43 ) +X-BeenThere: linux-mediatek@lists.infradead.org +X-Mailman-Version: 2.1.34 +Precedence: list +List-Id: +List-Unsubscribe: , + +List-Archive: +List-Post: +List-Help: +List-Subscribe: , + +Sender: "Linux-mediatek" +Errors-To: + linux-mediatek-bounces+linux-mediatek=archiver.kernel.org@lists.infradead.org + +Add required memory region for the builtin wifi block. + +Signed-off-by: Sjoerd Simons +--- +V1 -> V2: Don't set status to in this patch +--- + arch/arm64/boot/dts/mediatek/mt7981b.dtsi | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7981b.dtsi b/arch/arm64/boot/dts/mediatek/mt7981b.dtsi +index 1f4c114354660..a7be3670e0059 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7981b.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7981b.dtsi +@@ -69,6 +69,11 @@ secmon_reserved: secmon@43000000 { + no-map; + }; + ++ wmcpu_emi: wmcpu-reserved@47c80000 { ++ reg = <0 0x47c80000 0 0x100000>; ++ no-map; ++ }; ++ + wo_emi0: wo-emi@47d80000 { + reg = <0 0x47d80000 0 0x40000>; + no-map; +@@ -497,6 +502,7 @@ wifi@18000000 { + clocks = <&topckgen CLK_TOP_NETSYS_MCU_SEL>, + <&topckgen CLK_TOP_AP2CNN_HOST_SEL>; + clock-names = "mcu", "ap2conn"; ++ memory-region = <&wmcpu_emi>; + resets = <&watchdog MT7986_TOPRGU_CONSYS_SW_RST>; + reset-names = "consys"; + status = "disabled"; + +From patchwork Wed Nov 5 21:18:08 2025 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +X-Patchwork-Submitter: Sjoerd Simons +X-Patchwork-Id: 14300878 +Return-Path: + +X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on + aws-us-west-2-korg-lkml-1.web.codeaurora.org +Received: from bombadil.infradead.org (bombadil.infradead.org + [198.137.202.133]) + (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) + (No client certificate requested) + by smtp.lore.kernel.org (Postfix) with ESMTPS id DE387CCFA0D + for ; + Wed, 5 Nov 2025 21:18:55 +0000 (UTC) +DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; + d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help + :List-Post:List-Archive:List-Unsubscribe:List-Id:Cc:To:In-Reply-To:References + :Message-Id:Content-Transfer-Encoding:Content-Type:MIME-Version:Subject:Date: + From:Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From: + Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; + bh=AX63OyLy843bMJU2Vw7R714gkAf6ineUAbu3ZUG0cdE=; b=ZRKcM6HIodlVbEC70EorBJAyJh + 552RX6pkev2+tNToWznPyVIos9AboxUUd2sjhhfhx0aqynRHDDHY2Qt/9ewZB3GYWcjaIvW0uR+Vp + 7Vmvv07L5TqUdlzWnr1/py76XtK4Ggp8FDQk/xV8s2DiF9iD73X6A+rDfDdL2gNZTe7oHkBaWomp6 + lTDZXCF4u8YCKTRI5Nqss4g3RGRguSeXKvnfMGtNdsIQM/pRbcyitz09k0PELWP6rbnTqctF7W5So + q2F4WLeM/N319Jsfx026hbrW3QApgxD/jjhirAw3lm/E7KYAL66g9BUfWJQdsuKFeKBFIbgS89bqC + 9jRkNpqw==; +Received: from localhost ([::1] helo=bombadil.infradead.org) + by bombadil.infradead.org with esmtp (Exim 4.98.2 #2 (Red Hat Linux)) + id 1vGku6-0000000EUJE-1gzs; + Wed, 05 Nov 2025 21:18:54 +0000 +Received: from bali.collaboradmins.com ([2a01:4f8:201:9162::2]) + by bombadil.infradead.org with esmtps (Exim 4.98.2 #2 (Red Hat Linux)) + id 1vGktu-0000000ETzx-2I9Z; + Wed, 05 Nov 2025 21:18:44 +0000 +DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; + s=mail; t=1762377516; + bh=l3tEWhRqP4lk80hQap0vJX2rjpGnZh5LT9KfShignVs=; + h=From:Date:Subject:References:In-Reply-To:To:Cc:From; + b=RZt8bfUA3x1BMPbp6nkMXKDVBZsmSqC8Cr6yQf9Bmt2Dn+/fwoSYvUgfRuREfi7tC + Q/Q8f7iMK8cG1uT2ybpCwmTx6q0+56XFN+FUXpTwPkiJMlqFbUFh6CDhq3d/Sb3pYd + 0khH4Qat4TIVxrmiUAmDbJPZJT6v44l65FEstFParsZO2eah/zNv3Ok8LrSTZFrPLT + QOlF3l0Ffm4b5G93+j/mYrVhX1W2ZC5PZDl3BBzk01fwCQCSA3FY8u3Pgkmvk7bXAF + cQY9ji73EbfDjeSbnSNsBMHmBoCAp688kMuyKVrKb17vGX9Deq5zuP796vQziSjtIf + lHPsXdw8w/mGw== +Received: from beast.luon.net (unknown [IPv6:2a10:3781:2531::8]) + (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) + key-exchange X25519 server-signature RSA-PSS (4096 bits)) + (No client certificate requested) + (Authenticated sender: sjoerd) + by bali.collaboradmins.com (Postfix) with ESMTPSA id 3395417E14FF; + Wed, 5 Nov 2025 22:18:36 +0100 (CET) +Received: by beast.luon.net (Postfix, from userid 1000) + id D51B210F352F3; Wed, 05 Nov 2025 22:18:34 +0100 (CET) +From: Sjoerd Simons +Date: Wed, 05 Nov 2025 22:18:08 +0100 +Subject: [PATCH v3 13/13] arm64: dts: mediatek: mt7981b-openwrt-one: Enable + wifi +MIME-Version: 1.0 +Message-Id: <20251105-openwrt-one-network-v3-13-008e2cab38d1@collabora.com> +References: <20251105-openwrt-one-network-v3-0-008e2cab38d1@collabora.com> +In-Reply-To: <20251105-openwrt-one-network-v3-0-008e2cab38d1@collabora.com> +To: Rob Herring , Krzysztof Kozlowski , + Conor Dooley , + Matthias Brugger , + AngeloGioacchino Del Regno , + Ryder Lee , + Jianjun Wang , + Bjorn Helgaas , + Lorenzo Pieralisi , =?utf-8?q?Krzysztof_Wilczy?= + =?utf-8?q?=C5=84ski?= , + Manivannan Sadhasivam , + Chunfeng Yun , Vinod Koul , + Kishon Vijay Abraham I , Lee Jones , + Andrew Lunn , + "David S. Miller" , Eric Dumazet , + Jakub Kicinski , Paolo Abeni , + Lorenzo Bianconi , Felix Fietkau +Cc: kernel@collabora.com, devicetree@vger.kernel.org, + linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, + linux-mediatek@lists.infradead.org, linux-pci@vger.kernel.org, + linux-phy@lists.infradead.org, netdev@vger.kernel.org, + Daniel Golle , Bryan Hinton , + Sjoerd Simons +X-Mailer: b4 0.14.3 +X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 +X-CRM114-CacheID: sfid-20251105_131842_784749_B7C916F9 +X-CRM114-Status: GOOD ( 12.16 ) +X-BeenThere: linux-mediatek@lists.infradead.org +X-Mailman-Version: 2.1.34 +Precedence: list +List-Id: +List-Unsubscribe: , + +List-Archive: +List-Post: +List-Help: +List-Subscribe: , + +Sender: "Linux-mediatek" +Errors-To: + linux-mediatek-bounces+linux-mediatek=archiver.kernel.org@lists.infradead.org + +Enable Dual-band WiFI 6 functionality on the Openwrt One + +Signed-off-by: Sjoerd Simons +--- +V2 -> V3: replace MTK_DRIVE_4mA with direct value +V1 -> V2: Update eeprom node label +--- + .../boot/dts/mediatek/mt7981b-openwrt-one.dts | 24 ++++++++++++++++++++++ + arch/arm64/boot/dts/mediatek/mt7981b.dtsi | 2 +- + 2 files changed, 25 insertions(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7981b-openwrt-one.dts b/arch/arm64/boot/dts/mediatek/mt7981b-openwrt-one.dts +index 2aea899006453..3de368c73bc81 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7981b-openwrt-one.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7981b-openwrt-one.dts +@@ -180,6 +180,22 @@ conf-pd { + pins = "SPI2_CLK", "SPI2_MOSI", "SPI2_MISO"; + }; + }; ++ ++ wifi_dbdc_pins: wifi-dbdc-pins { ++ mux { ++ function = "eth"; ++ groups = "wf0_mode1"; ++ }; ++ ++ conf { ++ pins = "WF_HB1", "WF_HB2", "WF_HB3", "WF_HB4", ++ "WF_HB0", "WF_HB0_B", "WF_HB5", "WF_HB6", ++ "WF_HB7", "WF_HB8", "WF_HB9", "WF_HB10", ++ "WF_TOP_CLK", "WF_TOP_DATA", "WF_XO_REQ", ++ "WF_CBA_RESETB", "WF_DIG_RESETB"; ++ drive-strength = <4>; ++ }; ++ }; + }; + + &pwm { +@@ -257,6 +273,14 @@ &usb_phy { + status = "okay"; + }; + ++&wifi { ++ nvmem-cells = <&wifi_factory_calibration>; ++ nvmem-cell-names = "eeprom"; ++ pinctrl-names = "dbdc"; ++ pinctrl-0 = <&wifi_dbdc_pins>; ++ status = "okay"; ++}; ++ + &xhci { + phys = <&u2port0 PHY_TYPE_USB2>; + vusb33-supply = <®_3p3v>; +diff --git a/arch/arm64/boot/dts/mediatek/mt7981b.dtsi b/arch/arm64/boot/dts/mediatek/mt7981b.dtsi +index a7be3670e0059..66d89495bac52 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7981b.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7981b.dtsi +@@ -490,7 +490,7 @@ wo_ccif0: syscon@151a5000 { + interrupts = ; + }; + +- wifi@18000000 { ++ wifi: wifi@18000000 { + compatible = "mediatek,mt7981-wmac"; + reg = <0 0x18000000 0 0x1000000>, + <0 0x10003000 0 0x1000>, diff --git a/pkgs/linux-openwrt-one.patch b/pkgs/linux-openwrt-one.patch new file mode 100644 index 0000000..62c20ad --- /dev/null +++ b/pkgs/linux-openwrt-one.patch @@ -0,0 +1,2508 @@ +From 9c7cb0b21491ba7fd804f669b969418e33270142 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Wed, 28 Dec 2022 23:44:42 +0000 +Subject: [PATCH 01/12] complete mt7981 dts + +working: + * Ethernet (fully working incl. ppe) + * UART + * SPI-NAND flash + * thermal sensors (SoC and mxl-gpy) + * random number generator via SMC + * USB 1.1, 2.0 and 3.0 + * WiFi with MT7976C 2.4G+5G DBDC incl. WED offloading + * PWM +--- + arch/arm64/boot/dts/mediatek/mt7981b.dtsi | 566 +++++++++++++++++++++- + 1 file changed, 554 insertions(+), 12 deletions(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7981b.dtsi b/arch/arm64/boot/dts/mediatek/mt7981b.dtsi +index 5cbea9cd411f..6a816e5c1f46 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7981b.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7981b.dtsi +@@ -1,7 +1,14 @@ + // SPDX-License-Identifier: GPL-2.0-only OR MIT + + #include ++#include ++#include + #include ++#include ++#include ++#include ++#include ++#include + #include + + / { +@@ -41,6 +48,57 @@ psci { + method = "smc"; + }; + ++ fan: pwm-fan { ++ compatible = "pwm-fan"; ++ /* cooling level (0, 1, 2, 3) : (0% duty, 50% duty, 75% duty, 100% duty) */ ++ cooling-levels = <0 128 192 255>; ++ #cooling-cells = <2>; ++ status = "disabled"; ++ }; ++ ++ reg_3p3v: regulator-3p3v { ++ compatible = "regulator-fixed"; ++ regulator-name = "fixed-3.3V"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ /* 64 KiB reserved for ramoops/pstore */ ++ ramoops@42ff0000 { ++ compatible = "ramoops"; ++ reg = <0 0x42ff0000 0 0x10000>; ++ record-size = <0x1000>; ++ }; ++ ++ /* 192 KiB reserved for ARM Trusted Firmware (BL31) */ ++ secmon_reserved: secmon@43000000 { ++ reg = <0 0x43000000 0 0x30000>; ++ no-map; ++ }; ++ ++ wmcpu_emi: wmcpu-reserved@47c80000 { ++ reg = <0 0x47c80000 0 0x100000>; ++ no-map; ++ }; ++ ++ wo_emi0: wo-emi@47d80000 { ++ reg = <0 0x47d80000 0 0x40000>; ++ no-map; ++ }; ++ ++ wo_data: wo-data@47dc0000 { ++ reg = <0 0x47dc0000 0 0x240000>; ++ no-map; ++ }; ++ }; ++ + soc { + compatible = "simple-bus"; + ranges; +@@ -76,13 +134,13 @@ watchdog: watchdog@1001c000 { + #reset-cells = <1>; + }; + +- clock-controller@1001e000 { +- compatible = "mediatek,mt7981-apmixedsys"; ++ apmixedsys: clock-controller@1001e000 { ++ compatible = "mediatek,mt7981-apmixedsys", "syscon"; + reg = <0 0x1001e000 0 0x1000>; + #clock-cells = <1>; + }; + +- pwm@10048000 { ++ pwm: pwm@10048000 { + compatible = "mediatek,mt7981-pwm"; + reg = <0 0x10048000 0 0x1000>; + clocks = <&infracfg CLK_INFRA_PWM_STA>, +@@ -94,7 +152,21 @@ pwm@10048000 { + #pwm-cells = <2>; + }; + +- serial@11002000 { ++ crypto: crypto@10320000 { ++ compatible = "inside-secure,safexcel-eip97"; ++ reg = <0 0x10320000 0 0x40000>; ++ interrupts = , ++ , ++ , ++ ; ++ interrupt-names = "ring0", "ring1", "ring2", "ring3"; ++ clocks = <&topckgen CLK_TOP_EIP97B>; ++ clock-names = "top_eip97_ck"; ++ assigned-clocks = <&topckgen CLK_TOP_EIP97B_SEL>; ++ assigned-clock-parents = <&topckgen CLK_TOP_CB_NET1_D5>; ++ }; ++ ++ uart0: serial@11002000 { + compatible = "mediatek,mt7981-uart", "mediatek,mt6577-uart"; + reg = <0 0x11002000 0 0x100>; + interrupts = ; +@@ -105,7 +177,7 @@ serial@11002000 { + status = "disabled"; + }; + +- serial@11003000 { ++ uart1: serial@11003000 { + compatible = "mediatek,mt7981-uart", "mediatek,mt6577-uart"; + reg = <0 0x11003000 0 0x100>; + interrupts = ; +@@ -116,7 +188,7 @@ serial@11003000 { + status = "disabled"; + }; + +- serial@11004000 { ++ uart2: serial@11004000 { + compatible = "mediatek,mt7981-uart", "mediatek,mt6577-uart"; + reg = <0 0x11004000 0 0x100>; + interrupts = ; +@@ -127,11 +199,12 @@ serial@11004000 { + status = "disabled"; + }; + +- i2c@11007000 { ++ i2c0: i2c@11007000 { + compatible = "mediatek,mt7981-i2c"; + reg = <0 0x11007000 0 0x1000>, + <0 0x10217080 0 0x80>; + interrupts = ; ++ clock-div = <1>; + clocks = <&infracfg CLK_INFRA_I2C0_CK>, + <&infracfg CLK_INFRA_AP_DMA_CK>, + <&infracfg CLK_INFRA_I2C_MCK_CK>, +@@ -142,7 +215,32 @@ i2c@11007000 { + status = "disabled"; + }; + +- spi@11009000 { ++ thermal: thermal@1100c800 { ++ #thermal-sensor-cells = <1>; ++ compatible = "mediatek,mt7981-thermal", "mediatek,mt7986-thermal"; ++ reg = <0 0x1100c800 0 0x800>; ++ interrupts = ; ++ clocks = <&infracfg CLK_INFRA_THERM_CK>, ++ <&infracfg CLK_INFRA_ADC_26M_CK>; ++ clock-names = "therm", "auxadc"; ++ mediatek,auxadc = <&auxadc>; ++ mediatek,apmixedsys = <&apmixedsys>; ++ nvmem-cells = <&thermal_calibration>; ++ nvmem-cell-names = "calibration-data"; ++ }; ++ ++ auxadc: adc@1100d000 { ++ compatible = "mediatek,mt7981-auxadc", ++ "mediatek,mt7986-auxadc", ++ "mediatek,mt7622-auxadc"; ++ reg = <0 0x1100d000 0 0x1000>; ++ clocks = <&infracfg CLK_INFRA_ADC_26M_CK>, ++ <&infracfg CLK_INFRA_ADC_FRC_CK>; ++ clock-names = "main", "32k"; ++ #io-channel-cells = <1>; ++ }; ++ ++ spi2: spi@11009000 { + compatible = "mediatek,mt7981-spi-ipm", "mediatek,spi-ipm"; + reg = <0 0x11009000 0 0x1000>; + interrupts = ; +@@ -156,7 +254,7 @@ spi@11009000 { + status = "disabled"; + }; + +- spi@1100a000 { ++ spi0: spi@1100a000 { + compatible = "mediatek,mt7981-spi-ipm", "mediatek,spi-ipm"; + reg = <0 0x1100a000 0 0x1000>; + interrupts = ; +@@ -170,7 +268,7 @@ spi@1100a000 { + status = "disabled"; + }; + +- spi@1100b000 { ++ spi1: spi@1100b000 { + compatible = "mediatek,mt7981-spi-ipm", "mediatek,spi-ipm"; + reg = <0 0x1100b000 0 0x1000>; + interrupts = ; +@@ -184,6 +282,41 @@ spi@1100b000 { + status = "disabled"; + }; + ++ pcie: pcie@11280000 { ++ compatible = "mediatek,mt7981-pcie", ++ "mediatek,mt8192-pcie"; ++ device_type = "pci"; ++ reg = <0 0x11280000 0 0x4000>; ++ reg-names = "pcie-mac"; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ interrupts = ; ++ bus-range = <0x00 0xff>; ++ ranges = <0x82000000 0 0x20000000 ++ 0x0 0x20000000 0 0x10000000>; ++ status = "disabled"; ++ ++ clocks = <&infracfg CLK_INFRA_IPCIE_CK>, ++ <&infracfg CLK_INFRA_IPCIE_PIPE_CK>, ++ <&infracfg CLK_INFRA_IPCIER_CK>, ++ <&infracfg CLK_INFRA_IPCIEB_CK>; ++ ++ phys = <&u3port0 PHY_TYPE_PCIE>; ++ phy-names = "pcie-phy"; ++ ++ #interrupt-cells = <1>; ++ interrupt-map-mask = <0 0 0 7>; ++ interrupt-map = <0 0 0 1 &pcie_intc 0>, ++ <0 0 0 2 &pcie_intc 1>, ++ <0 0 0 3 &pcie_intc 2>, ++ <0 0 0 4 &pcie_intc 3>; ++ pcie_intc: interrupt-controller { ++ interrupt-controller; ++ #address-cells = <0>; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ + pio: pinctrl@11d00000 { + compatible = "mediatek,mt7981-pinctrl"; + reg = <0 0x11d00000 0 0x1000>, +@@ -204,6 +337,49 @@ pio: pinctrl@11d00000 { + gpio-controller; + #gpio-cells = <2>; + #interrupt-cells = <2>; ++ ++ mdio_pins: mdc-mdio-pins { ++ mux { ++ function = "eth"; ++ groups = "smi_mdc_mdio"; ++ }; ++ }; ++ ++ uart0_pins: uart0-pins { ++ mux { ++ function = "uart"; ++ groups = "uart0"; ++ }; ++ }; ++ ++ wifi_dbdc_pins: wifi-dbdc-pins { ++ mux { ++ function = "eth"; ++ groups = "wf0_mode1"; ++ }; ++ conf { ++ pins = "WF_HB1", "WF_HB2", "WF_HB3", "WF_HB4", ++ "WF_HB0", "WF_HB0_B", "WF_HB5", "WF_HB6", ++ "WF_HB7", "WF_HB8", "WF_HB9", "WF_HB10", ++ "WF_TOP_CLK", "WF_TOP_DATA", "WF_XO_REQ", ++ "WF_CBA_RESETB", "WF_DIG_RESETB"; ++ drive-strength = ; ++ }; ++ }; ++ ++ gbe_led0_pins: gbe-led0-pins { ++ mux { ++ function = "led"; ++ groups = "gbe_led0"; ++ }; ++ }; ++ ++ gbe_led1_pins: gbe-led1-pins { ++ mux { ++ function = "led"; ++ groups = "gbe_led1"; ++ }; ++ }; + }; + + efuse@11f20000 { +@@ -211,17 +387,318 @@ efuse@11f20000 { + reg = <0 0x11f20000 0 0x1000>; + #address-cells = <1>; + #size-cells = <1>; ++ ++ thermal_calibration: thermal-calib@274 { ++ reg = <0x274 0xc>; ++ }; ++ ++ phy_calibration: phy-calib@8dc { ++ reg = <0x8dc 0x10>; ++ }; ++ ++ comb_rx_imp_p0: usb3-rx-imp@8c8 { ++ reg = <0x8c8 1>; ++ bits = <0 5>; ++ }; ++ ++ comb_tx_imp_p0: usb3-tx-imp@8c8 { ++ reg = <0x8c8 2>; ++ bits = <5 5>; ++ }; ++ ++ comb_intr_p0: usb3-intr@8c9 { ++ reg = <0x8c9 1>; ++ bits = <2 6>; ++ }; + }; + +- clock-controller@15000000 { ++ ethsys: clock-controller@15000000 { + compatible = "mediatek,mt7981-ethsys", "syscon"; + reg = <0 0x15000000 0 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + +- wifi@18000000 { ++ wed: wed@15010000 { ++ compatible = "mediatek,mt7981-wed", ++ "mediatek,mt7986-wed", ++ "syscon"; ++ reg = <0 0x15010000 0 0x1000>; ++ interrupt-parent = <&gic>; ++ interrupts = ; ++ memory-region = <&wo_emi0>, <&wo_data>; ++ memory-region-names = "wo-emi", "wo-data"; ++ mediatek,wo-ccif = <&wo_ccif0>; ++ mediatek,wo-ilm = <&wo_ilm0>; ++ mediatek,wo-dlm = <&wo_dlm0>; ++ mediatek,wo-cpuboot = <&wo_cpuboot>; ++ }; ++ ++ eth: ethernet@15100000 { ++ compatible = "mediatek,mt7981-eth"; ++ reg = <0 0x15100000 0 0x80000>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ interrupts = , ++ , ++ , ++ ; ++ clocks = <ðsys CLK_ETH_FE_EN>, ++ <ðsys CLK_ETH_GP2_EN>, ++ <ðsys CLK_ETH_GP1_EN>, ++ <ðsys CLK_ETH_WOCPU0_EN>, ++ <&sgmiisys0 CLK_SGM0_TX_EN>, ++ <&sgmiisys0 CLK_SGM0_RX_EN>, ++ <&sgmiisys0 CLK_SGM0_CK0_EN>, ++ <&sgmiisys0 CLK_SGM0_CDR_CK0_EN>, ++ <&sgmiisys1 CLK_SGM1_TX_EN>, ++ <&sgmiisys1 CLK_SGM1_RX_EN>, ++ <&sgmiisys1 CLK_SGM1_CK1_EN>, ++ <&sgmiisys1 CLK_SGM1_CDR_CK1_EN>, ++ <&topckgen CLK_TOP_SGM_REG>, ++ <&topckgen CLK_TOP_NETSYS_SEL>, ++ <&topckgen CLK_TOP_NETSYS_500M_SEL>; ++ clock-names = "fe", "gp2", "gp1", "wocpu0", ++ "sgmii_tx250m", "sgmii_rx250m", ++ "sgmii_cdr_ref", "sgmii_cdr_fb", ++ "sgmii2_tx250m", "sgmii2_rx250m", ++ "sgmii2_cdr_ref", "sgmii2_cdr_fb", ++ "sgmii_ck", "netsys0", "netsys1"; ++ assigned-clocks = <&topckgen CLK_TOP_NETSYS_2X_SEL>, ++ <&topckgen CLK_TOP_SGM_325M_SEL>; ++ assigned-clock-parents = <&topckgen CLK_TOP_CB_NET2_800M>, ++ <&topckgen CLK_TOP_CB_SGM_325M>; ++ mediatek,ethsys = <ðsys>; ++ mediatek,sgmiisys = <&sgmiisys0>, <&sgmiisys1>; ++ mediatek,infracfg = <&topmisc>; ++ mediatek,wed = <&wed>; ++ status = "disabled"; ++ ++ mdio_bus: mdio-bus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ int_gbe_phy: ethernet-phy@0 { ++ reg = <0>; ++ compatible = "ethernet-phy-ieee802.3-c22"; ++ phy-mode = "gmii"; ++ phy-is-integrated; ++ nvmem-cells = <&phy_calibration>; ++ nvmem-cell-names = "phy-cal-data"; ++ ++ leds { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ int_gbe_phy_led0: int-gbe-phy-led0@0 { ++ reg = <0>; ++ function = LED_FUNCTION_LAN; ++ pinctrl-0 = <&gbe_led0_pins>; ++ pinctrl-names = "default"; ++ status = "disabled"; ++ }; ++ ++ int_gbe_phy_led1: int-gbe-phy-led1@1 { ++ reg = <1>; ++ function = LED_FUNCTION_LAN; ++ pinctrl-0 = <&gbe_led1_pins>; ++ pinctrl-names = "default"; ++ status = "disabled"; ++ }; ++ }; ++ }; ++ }; ++ }; ++ ++ wdma: wdma@15104800 { ++ compatible = "mediatek,wed-wdma"; ++ reg = <0 0x15104800 0 0x400>, ++ <0 0x15104c00 0 0x400>; ++ }; ++ ++ ap2woccif: ap2woccif@151a5000 { ++ compatible = "mediatek,ap2woccif"; ++ reg = <0 0x151a5000 0 0x1000>, ++ <0 0x151ad000 0 0x1000>; ++ interrupt-parent = <&gic>; ++ interrupts = , ++ ; ++ }; ++ ++ wo_dlm0: syscon@151e8000 { ++ compatible = "mediatek,mt7986-wo-dlm", "syscon"; ++ reg = <0 0x151e8000 0 0x2000>; ++ }; ++ ++ wo_ilm0: syscon@151e0000 { ++ compatible = "mediatek,mt7986-wo-ilm", "syscon"; ++ reg = <0 0x151e0000 0 0x8000>; ++ }; ++ ++ wo_cpuboot: syscon@15194000 { ++ compatible = "mediatek,mt7986-wo-cpuboot", "syscon"; ++ reg = <0 0x15194000 0 0x1000>; ++ }; ++ ++ wo_ccif0: syscon@151a5000 { ++ compatible = "mediatek,mt7986-wo-ccif", "syscon"; ++ reg = <0 0x151a5000 0 0x1000>; ++ interrupt-parent = <&gic>; ++ interrupts = ; ++ }; ++ ++ sgmiisys0: syscon@10060000 { ++ compatible = "mediatek,mt7981-sgmiisys_0", "mediatek,mt7986-sgmiisys_0", "syscon"; ++ reg = <0 0x10060000 0 0x1000>; ++ mediatek,pnswap; ++ #clock-cells = <1>; ++ }; ++ ++ sgmiisys1: syscon@10070000 { ++ compatible = "mediatek,mt7981-sgmiisys_1", "mediatek,mt7986-sgmiisys_1", "syscon"; ++ reg = <0 0x10070000 0 0x1000>; ++ #clock-cells = <1>; ++ }; ++ ++ topmisc: topmisc@11d10000 { ++ compatible = "mediatek,mt7981-topmisc", "syscon"; ++ reg = <0 0x11d10000 0 0x10000>; ++ #clock-cells = <1>; ++ }; ++ ++ snand: snfi@11005000 { ++ compatible = "mediatek,mt7986-snand"; ++ reg = <0 0x11005000 0 0x1000>, <0 0x11006000 0 0x1000>; ++ reg-names = "nfi", "ecc"; ++ interrupts = ; ++ clocks = <&infracfg CLK_INFRA_SPINFI1_CK>, ++ <&infracfg CLK_INFRA_NFI1_CK>, ++ <&infracfg CLK_INFRA_NFI_HCK_CK>; ++ clock-names = "pad_clk", "nfi_clk", "nfi_hclk"; ++ assigned-clocks = <&topckgen CLK_TOP_SPINFI_SEL>, ++ <&topckgen CLK_TOP_NFI1X_SEL>; ++ assigned-clock-parents = <&topckgen CLK_TOP_CB_M_D8>, ++ <&topckgen CLK_TOP_CB_M_D8>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ mmc0: mmc@11230000 { ++ compatible = "mediatek,mt7986-mmc", ++ "mediatek,mt7981-mmc"; ++ reg = <0 0x11230000 0 0x1000>, <0 0x11c20000 0 0x1000>; ++ interrupts = ; ++ clocks = <&infracfg CLK_INFRA_MSDC_CK>, ++ <&infracfg CLK_INFRA_MSDC_HCK_CK>, ++ <&infracfg CLK_INFRA_MSDC_66M_CK>, ++ <&infracfg CLK_INFRA_MSDC_133M_CK>; ++ assigned-clocks = <&topckgen CLK_TOP_EMMC_208M_SEL>, ++ <&topckgen CLK_TOP_EMMC_400M_SEL>; ++ assigned-clock-parents = <&topckgen CLK_TOP_CB_M_D2>, ++ <&topckgen CLK_TOP_CB_NET2_D2>; ++ clock-names = "source", "hclk", "axi_cg", "ahb_cg"; ++ status = "disabled"; ++ }; ++ ++ wed_pcie: wed_pcie@10003000 { ++ compatible = "mediatek,wed_pcie"; ++ reg = <0 0x10003000 0 0x10>; ++ }; ++ ++ consys: consys@10000000 { ++ compatible = "mediatek,mt7981-consys"; ++ reg = <0 0x10000000 0 0x8600000>; ++ memory-region = <&wmcpu_emi>; ++ }; ++ ++ xhci: usb@11200000 { ++ compatible = "mediatek,mt7986-xhci", ++ "mediatek,mtk-xhci"; ++ reg = <0 0x11200000 0 0x2e00>, ++ <0 0x11203e00 0 0x0100>; ++ reg-names = "mac", "ippc"; ++ interrupts = ; ++ clocks = <&infracfg CLK_INFRA_IUSB_SYS_CK>, ++ <&infracfg CLK_INFRA_IUSB_CK>, ++ <&infracfg CLK_INFRA_IUSB_133_CK>, ++ <&infracfg CLK_INFRA_IUSB_66M_CK>, ++ <&topckgen CLK_TOP_U2U3_XHCI_SEL>; ++ clock-names = "sys_ck", ++ "ref_ck", ++ "mcu_ck", ++ "dma_ck", ++ "xhci_ck"; ++ phys = <&u2port0 PHY_TYPE_USB2>, ++ <&u3port0 PHY_TYPE_USB3>; ++ vusb33-supply = <®_3p3v>; ++ status = "disabled"; ++ }; ++ ++ usb_phy: usb-phy@11e10000 { ++ compatible = "mediatek,mt7981", ++ "mediatek,generic-tphy-v2"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges = <0 0 0x11e10000 0x1700>; ++ status = "disabled"; ++ ++ u2port0: usb-phy@0 { ++ reg = <0x0 0x700>; ++ clocks = <&topckgen CLK_TOP_USB_FRMCNT_SEL>; ++ clock-names = "ref"; ++ #phy-cells = <1>; ++ }; ++ ++ u3port0: usb-phy@700 { ++ reg = <0x700 0x900>; ++ clocks = <&topckgen CLK_TOP_USB3_PHY_SEL>; ++ clock-names = "ref"; ++ #phy-cells = <1>; ++ mediatek,syscon-type = <&topmisc 0x218 0>; ++ status = "okay"; ++ }; ++ }; ++ ++ ++ afe: audio-controller@11210000 { ++ compatible = "mediatek,mt79xx-audio"; ++ reg = <0 0x11210000 0 0x9000>; ++ interrupts = ; ++ clocks = <&infracfg CLK_INFRA_AUD_BUS_CK>, ++ <&infracfg CLK_INFRA_AUD_26M_CK>, ++ <&infracfg CLK_INFRA_AUD_L_CK>, ++ <&infracfg CLK_INFRA_AUD_AUD_CK>, ++ <&infracfg CLK_INFRA_AUD_EG2_CK>, ++ <&topckgen CLK_TOP_AUD_SEL>; ++ clock-names = "aud_bus_ck", ++ "aud_26m_ck", ++ "aud_l_ck", ++ "aud_aud_ck", ++ "aud_eg2_ck", ++ "aud_sel"; ++ assigned-clocks = <&topckgen CLK_TOP_AUD_SEL>, ++ <&topckgen CLK_TOP_A1SYS_SEL>, ++ <&topckgen CLK_TOP_AUD_L_SEL>, ++ <&topckgen CLK_TOP_A_TUNER_SEL>; ++ assigned-clock-parents = <&topckgen CLK_TOP_CB_APLL2_196M>, ++ <&topckgen CLK_TOP_APLL2_D4>, ++ <&topckgen CLK_TOP_CB_APLL2_196M>, ++ <&topckgen CLK_TOP_APLL2_D4>; ++ status = "disabled"; ++ }; ++ ++ ice: ice_debug { ++ compatible = "mediatek,mt7981-ice_debug", ++ "mediatek,mt2701-ice_debug"; ++ clocks = <&infracfg CLK_INFRA_DBG_CK>; ++ clock-names = "ice_dbg"; ++ }; ++ ++ wifi: wifi@18000000 { + compatible = "mediatek,mt7981-wmac"; ++ pinctrl-0 = <&wifi_dbdc_pins>; ++ pinctrl-names = "dbdc"; + reg = <0 0x18000000 0 0x1000000>, + <0 0x10003000 0 0x1000>, + <0 0x11d10000 0 0x1000>; +@@ -234,6 +711,67 @@ wifi@18000000 { + clock-names = "mcu", "ap2conn"; + resets = <&watchdog MT7986_TOPRGU_CONSYS_SW_RST>; + reset-names = "consys"; ++ memory-region = <&wmcpu_emi>; ++ status = "disabled"; ++ }; ++ }; ++ ++ thermal-zones { ++ cpu_thermal: cpu-thermal { ++ polling-delay-passive = <1000>; ++ polling-delay = <1000>; ++ thermal-sensors = <&thermal 0>; ++ trips { ++ cpu_trip_crit: crit { ++ temperature = <125000>; ++ hysteresis = <2000>; ++ type = "critical"; ++ }; ++ ++ cpu_trip_hot: hot { ++ temperature = <120000>; ++ hysteresis = <2000>; ++ type = "hot"; ++ }; ++ ++ cpu_trip_active_high: active-high { ++ temperature = <115000>; ++ hysteresis = <2000>; ++ type = "active"; ++ }; ++ ++ cpu_trip_active_med: active-med { ++ temperature = <85000>; ++ hysteresis = <2000>; ++ type = "active"; ++ }; ++ ++ cpu_trip_active_low: active-low { ++ temperature = <60000>; ++ hysteresis = <2000>; ++ type = "active"; ++ }; ++ }; ++ ++ cooling-maps { ++ cpu-active-high { ++ /* active: set fan to cooling level 3 */ ++ cooling-device = <&fan 3 3>; ++ trip = <&cpu_trip_active_high>; ++ }; ++ ++ cpu-active-med { ++ /* active: set fan to cooling level 2 */ ++ cooling-device = <&fan 2 2>; ++ trip = <&cpu_trip_active_med>; ++ }; ++ ++ cpu-active-low { ++ /* passive: set fan to cooling level 1 */ ++ cooling-device = <&fan 1 1>; ++ trip = <&cpu_trip_active_low>; ++ }; ++ }; + }; + }; + +@@ -245,4 +783,8 @@ timer { + , + ; + }; ++ ++ trng { ++ compatible = "mediatek,mt7981-rng"; ++ }; + }; +-- +2.51.0 + + +From c99275204c5709fa159c2cbbdc6dd25bad49f882 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= +Date: Thu, 2 Oct 2025 11:54:23 +0200 +Subject: [PATCH 02/12] Pull OpenWrt One device tree from OpenWrt master + +The commit used: 915a57ccd9086db88ee74cfa531ff13f8652a447 +--- + .../boot/dts/mediatek/mt7981b-openwrt-one.dts | 460 +++++++++++++++++- + 1 file changed, 457 insertions(+), 3 deletions(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7981b-openwrt-one.dts b/arch/arm64/boot/dts/mediatek/mt7981b-openwrt-one.dts +index 4f6cbb491287..5f54506b2cba 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7981b-openwrt-one.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7981b-openwrt-one.dts +@@ -1,15 +1,469 @@ +-// SPDX-License-Identifier: GPL-2.0-only OR MIT ++// SPDX-License-Identifier: (GPL-2.0 OR MIT) + + /dts-v1/; +- + #include "mt7981b.dtsi" + + / { +- compatible = "openwrt,one", "mediatek,mt7981b"; + model = "OpenWrt One"; ++ compatible = "openwrt,one", "mediatek,mt7981"; ++ ++ aliases { ++ ethernet0 = &gmac1; ++ label-mac-device = &gmac0; ++ led-boot = &led_status_white; ++ led-failsafe = &led_status_red; ++ led-running = &led_status_green; ++ led-upgrade = &led_status_green; ++ serial0 = &uart0; ++ }; ++ ++ chosen { ++ stdout-path = "serial0:115200n8"; ++ rootdisk = <&ubi_fit_volume>; ++ }; + + memory@40000000 { + reg = <0 0x40000000 0 0x40000000>; + device_type = "memory"; + }; ++ ++ reg_3p3v: regulator-3p3v { ++ compatible = "regulator-fixed"; ++ regulator-name = "fixed-3.3V"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ reg_5v: regulator-5v { ++ compatible = "regulator-fixed"; ++ regulator-name = "fixed-5V"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ gpio-keys { ++ compatible = "gpio-keys"; ++ ++ user { ++ label = "user"; ++ linux,code = ; ++ gpios = <&pio 0 GPIO_ACTIVE_LOW>; ++ }; ++ ++ reset { ++ label = "reset"; ++ linux,code = ; ++ gpios = <&pio 1 GPIO_ACTIVE_LOW>; ++ }; ++ }; ++ ++ pwm-leds { ++ compatible = "pwm-leds"; ++ ++ led_status_white: led-0 { ++ color = ; ++ function = LED_FUNCTION_STATUS; ++ pwms = <&pwm 0 10000>; ++ linux,default-trigger = "pattern"; ++ led-pattern = <0 500 25 500>; ++ }; ++ ++ led_status_green: led-1 { ++ color = ; ++ function = LED_FUNCTION_STATUS; ++ pwms = <&pwm 1 10000>; ++ }; ++ }; ++ ++ gpio-leds { ++ compatible = "gpio-leds"; ++ ++ led_status_red: led-0 { ++ color = ; ++ function = LED_FUNCTION_STATUS; ++ gpios = <&pio 9 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ led-1 { ++ function = LED_FUNCTION_LAN; ++ color = ; ++ gpios = <&pio 34 GPIO_ACTIVE_LOW>; ++ }; ++ ++ led-2 { ++ function = LED_FUNCTION_LAN; ++ color = ; ++ gpios = <&pio 35 GPIO_ACTIVE_LOW>; ++ }; ++ }; ++ ++ gpio-export { ++ compatible = "gpio-export"; ++ ++ gpio-0 { ++ gpio-export,name = "mikrobus-reset"; ++ gpio-export,output = <1>; ++ gpios = <&pio 2 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ gpio-1 { ++ gpio-export,name = "watchdog-enable"; ++ gpio-export,output = <1>; ++ gpios = <&pio 11 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ gpio-2 { ++ gpio-export,name = "usb-enable"; ++ gpio-export,output = <1>; ++ gpios = <&pio 14 GPIO_ACTIVE_HIGH>; ++ }; ++ }; ++ ++ gpio-watchdog { ++ compatible = "linux,wdt-gpio"; ++ gpios = <&pio 8 GPIO_ACTIVE_LOW>; ++ hw_algo = "toggle"; ++ hw_margin_ms = <25000>; ++ always-running; ++ }; ++}; ++ ++ð { ++ status = "okay"; ++ ++ gmac0: mac@0 { ++ compatible = "mediatek,eth-mac"; ++ reg = <0>; ++ phy-handle = <&phy15>; ++ phy-mode = "2500base-x"; ++ nvmem-cell-names = "mac-address"; ++ nvmem-cells = <&macaddr_factory_24>; ++ }; ++ ++ gmac1: mac@1 { ++ compatible = "mediatek,eth-mac"; ++ reg = <1>; ++ phy-mode = "gmii"; ++ phy-handle = <&int_gbe_phy>; ++ }; ++}; ++ ++&mdio_bus { ++ phy15: phy@f { ++ reg = <0xf>; ++ ++ airoha,pnswap-rx; ++ ++ interrupt-parent = <&pio>; ++ interrupts = <38 IRQ_TYPE_EDGE_FALLING>; ++ reset-gpios = <&pio 39 GPIO_ACTIVE_LOW>; ++ reset-assert-us = <10000>; ++ reset-deassert-us = <20000>; ++ ++ phy-mode = "2500base-x"; ++ full-duplex; ++ pause; ++ ++ leds { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ led@0 { ++ reg = <0>; ++ function = LED_FUNCTION_WAN; ++ color = ; ++ }; ++ ++ led@1 { ++ reg = <1>; ++ function = LED_FUNCTION_WAN; ++ color = ; ++ }; ++ }; ++ }; ++}; ++ ++&crypto { ++ status = "okay"; ++}; ++ ++&pio { ++ spi0_flash_pins: spi0-pins { ++ mux { ++ function = "spi"; ++ groups = "spi0", "spi0_wp_hold"; ++ }; ++ ++ conf-pu { ++ pins = "SPI0_CS", "SPI0_HOLD", "SPI0_WP"; ++ drive-strength = ; ++ bias-pull-up = ; ++ }; ++ ++ conf-pd { ++ pins = "SPI0_CLK", "SPI0_MOSI", "SPI0_MISO"; ++ drive-strength = ; ++ bias-pull-down = ; ++ }; ++ }; ++ ++ spi1_flash_pins: spi1-pins { ++ mux { ++ function = "spi"; ++ groups = "spi1_1"; ++ }; ++ ++ conf-pu { ++ pins = "SPI1_CS"; ++ drive-strength = ; ++ bias-pull-up = ; ++ }; ++ ++ conf-pd { ++ pins = "SPI1_CLK", "SPI1_MOSI", "SPI1_MISO"; ++ drive-strength = ; ++ bias-pull-down = ; ++ }; ++ }; ++ ++ spi2_flash_pins: spi2-pins { ++ mux { ++ function = "spi"; ++ groups = "spi2"; ++ }; ++ ++ conf-pu { ++ pins = "SPI2_CS", "SPI2_WP"; ++ drive-strength = ; ++ bias-pull-up = ; ++ }; ++ ++ conf-pd { ++ pins = "SPI2_CLK", "SPI2_MOSI", "SPI2_MISO"; ++ drive-strength = ; ++ bias-pull-down = ; ++ }; ++ }; ++ ++ i2c_pins: i2c-pins { ++ mux { ++ function = "i2c"; ++ groups = "i2c0_0"; ++ }; ++ }; ++ ++ uart2_pins: uart2-pins { ++ mux { ++ function = "uart"; ++ groups = "uart2_0_tx_rx"; ++ }; ++ }; ++ ++ pwm_pins: pwm-pins { ++ mux { ++ function = "pwm"; ++ groups = "pwm0_0", "pwm1_1"; ++ }; ++ }; ++ ++ pcie_pins: pcie-pins { ++ mux { ++ function = "pcie"; ++ groups = "pcie_pereset"; ++ }; ++ }; ++}; ++ ++&pwm { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pwm_pins>; ++ status = "okay"; ++}; ++ ++&i2c0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c_pins>; ++ status = "okay"; ++ ++ rtc@51 { ++ compatible = "nxp,pcf8563"; ++ reg = <0x51>; ++ }; ++}; ++ ++&spi0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spi0_flash_pins>; ++ cs-gpios = <0>, <0>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ flash@1 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "spi-nand"; ++ reg = <1>; ++ spi-max-frequency = <52000000>; ++ ++ spi-cal-enable; ++ spi-cal-mode = "read-data"; ++ spi-cal-datalen = <7>; ++ spi-cal-data = /bits/ 8 <0x53 0x50 0x49 0x4E 0x41 0x4E 0x44>; ++ spi-cal-addrlen = <5>; ++ spi-cal-addr = /bits/ 32 <0x0 0x0 0x0 0x0 0x0>; ++ ++ partitions { ++ compatible = "fixed-partitions"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ partition@0 { ++ label = "bl2"; ++ reg = <0x0 0x100000>; ++ read-only; ++ }; ++ ++ partition@580000 { ++ label = "ubi"; ++ reg = <0x100000 0xFF00000>; ++ compatible = "linux,ubi"; ++ ++ volumes { ++ ubi_fit_volume: ubi-volume-fit { ++ volname = "fit"; ++ }; ++ }; ++ }; ++ }; ++ }; ++}; ++ ++&spi1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spi1_flash_pins>; ++ status = "okay"; ++}; ++ ++&spi2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spi2_flash_pins>; ++ status = "okay"; ++ ++ flash@0 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "jedec,spi-nor"; ++ reg = <0>; ++ ++ spi-max-frequency = <52000000>; ++ ++ partitions { ++ compatible = "fixed-partitions"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ partition@0 { ++ label = "bl2-nor"; ++ reg = <0x00000 0x40000>; ++ }; ++ ++ partition@40000 { ++ label = "factory"; ++ reg = <0x40000 0xc0000>; ++ read-only; ++ ++ nvmem-layout { ++ compatible = "fixed-layout"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ eeprom_factory_0: eeprom@0 { ++ reg = <0x0 0x1000>; ++ }; ++ ++ macaddr_factory_4: macaddr@4 { ++ reg = <0x4 0x6>; ++ compatible = "mac-base"; ++ #nvmem-cell-cells = <1>; ++ }; ++ ++ macaddr_factory_24: macaddr@24 { ++ reg = <0x24 0x6>; ++ compatible = "mac-base"; ++ }; ++ }; ++ }; ++ ++ partition@100000 { ++ label = "fip-nor"; ++ reg = <0x100000 0x80000>; ++ }; ++ ++ partition@180000 { ++ label = "recovery"; ++ reg = <0x180000 0xc80000>; ++ }; ++ }; ++ }; ++}; ++ ++&xhci { ++ phys = <&u2port0 PHY_TYPE_USB2>; ++ vusb33-supply = <®_3p3v>; ++ vbus-supply = <®_5v>; ++ mediatek,u3p-dis-msk = <0x01>; ++ status = "okay"; ++}; ++ ++&uart0 { ++ status = "okay"; ++}; ++ ++&uart2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&uart2_pins>; ++ status = "okay"; ++}; ++ ++&usb_phy { ++ status = "okay"; ++}; ++ ++&watchdog { ++ status = "okay"; ++}; ++ ++&wifi { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ nvmem-cells = <&eeprom_factory_0>; ++ nvmem-cell-names = "eeprom"; ++ status = "okay"; ++ ++ band@0 { ++ reg = <0>; ++ nvmem-cells = <&macaddr_factory_4 0>; ++ nvmem-cell-names = "mac-address"; ++ }; ++ ++ band@1 { ++ reg = <1>; ++ nvmem-cells = <&macaddr_factory_4 7>; ++ nvmem-cell-names = "mac-address"; ++ }; ++}; ++ ++&pcie { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pcie_pins>; ++ status = "okay"; ++}; ++ ++&sgmiisys0 { ++ /delete-node/ mediatek,pnswap; + }; +-- +2.51.0 + + +From faeb104b5fbd6383664672f1324d74eef55507b5 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Thu, 27 Oct 2022 23:39:52 +0200 +Subject: [PATCH 03/12] net: ethernet: mtk_eth_soc: compile out netsys v2 code + on mt7621 + +Avoid some branches in the hot path on low-end devices with limited CPU power, +and reduce code size + +Signed-off-by: Felix Fietkau +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +index 0168e2fbc619..2f89a06471e3 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -1383,6 +1383,22 @@ struct mtk_mac { + /* the struct describing the SoC. these are declared in the soc_xyz.c files */ + extern const struct of_device_id of_mtk_match[]; + ++#ifdef CONFIG_SOC_MT7621 ++static inline bool mtk_is_netsys_v1(struct mtk_eth *eth) ++{ ++ return true; ++} ++ ++static inline bool mtk_is_netsys_v2_or_greater(struct mtk_eth *eth) ++{ ++ return false; ++} ++ ++static inline bool mtk_is_netsys_v3_or_greater(struct mtk_eth *eth) ++{ ++ return false; ++} ++#else + static inline bool mtk_is_netsys_v1(struct mtk_eth *eth) + { + return eth->soc->version == 1; +@@ -1397,6 +1413,7 @@ static inline bool mtk_is_netsys_v3_or_greater(struct mtk_eth *eth) + { + return eth->soc->version > 2; + } ++#endif + + static inline struct mtk_foe_entry * + mtk_foe_get_entry(struct mtk_ppe *ppe, u16 hash) +-- +2.51.0 + + +From 6e848e9de009eeafe0d970f0914c3d6441c843bb Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Thu, 3 Nov 2022 12:38:49 +0100 +Subject: [PATCH 04/12] net: ethernet: mtk_eth_soc: work around issue with + sending small fragments + +When lots of frames are sent with a number of very small fragments, an +internal FIFO can overflow, causing the DMA engine to lock up lock up and +transmit attempts time out. + +Fix this on MT7986 by increasing the reserved FIFO space. +Fix this on older chips by detecting the presence of small fragments and use +skb_gso_segment + skb_linearize to deal with them. + +Signed-off-by: Felix Fietkau +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 39 +++++++++++++++++++-- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 2 +- + 2 files changed, 38 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +index e68997a29191..2931376785f2 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -1752,12 +1753,28 @@ static void mtk_wake_queue(struct mtk_eth *eth) + } + } + ++static bool mtk_skb_has_small_frag(struct sk_buff *skb) ++{ ++ int min_size = 16; ++ int i; ++ ++ if (skb_headlen(skb) < min_size) ++ return true; ++ ++ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) ++ if (skb_frag_size(&skb_shinfo(skb)->frags[i]) < min_size) ++ return true; ++ ++ return false; ++} ++ + static netdev_tx_t mtk_start_xmit(struct sk_buff *skb, struct net_device *dev) + { + struct mtk_mac *mac = netdev_priv(dev); + struct mtk_eth *eth = mac->hw; + struct mtk_tx_ring *ring = ð->tx_ring; + struct net_device_stats *stats = &dev->stats; ++ struct sk_buff *segs, *next; + bool gso = false; + int tx_num; + +@@ -1786,6 +1803,18 @@ static netdev_tx_t mtk_start_xmit(struct sk_buff *skb, struct net_device *dev) + return NETDEV_TX_BUSY; + } + ++ if (mtk_is_netsys_v1(eth) && ++ skb_is_gso(skb) && mtk_skb_has_small_frag(skb)) { ++ segs = skb_gso_segment(skb, dev->features & ~NETIF_F_ALL_TSO); ++ if (IS_ERR(segs)) ++ goto drop; ++ ++ if (segs) { ++ consume_skb(skb); ++ skb = segs; ++ } ++ } ++ + /* TSO: fill MSS info in tcp checksum field */ + if (skb_is_gso(skb)) { + if (skb_cow_head(skb, 0)) { +@@ -1801,8 +1830,14 @@ static netdev_tx_t mtk_start_xmit(struct sk_buff *skb, struct net_device *dev) + } + } + +- if (mtk_tx_map(skb, dev, tx_num, ring, gso) < 0) +- goto drop; ++ skb_list_walk_safe(skb, skb, next) { ++ if ((mtk_is_netsys_v1(eth) && ++ mtk_skb_has_small_frag(skb) && skb_linearize(skb)) || ++ mtk_tx_map(skb, dev, tx_num, ring, gso) < 0) { ++ stats->tx_dropped++; ++ dev_kfree_skb_any(skb); ++ } ++ } + + if (unlikely(atomic_read(&ring->free_count) <= ring->thresh)) + netif_tx_stop_all_queues(dev); +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +index 2f89a06471e3..ee7bb3b7b93a 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -280,7 +280,7 @@ + #define MTK_CHK_DDONE_EN BIT(28) + #define MTK_DMAD_WR_WDONE BIT(26) + #define MTK_WCOMP_EN BIT(24) +-#define MTK_RESV_BUF (0x40 << 16) ++#define MTK_RESV_BUF (0x80 << 16) + #define MTK_MUTLI_CNT (0x4 << 12) + #define MTK_LEAKY_BUCKET_EN BIT(11) + +-- +2.51.0 + + +From 0cdfa5eb67e05aeb2b35960db1b797a945902091 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Mon, 14 Jul 2025 10:52:59 +0200 +Subject: [PATCH 05/12] net: ethernet: mtk_eth_soc: shrink struct mtk_tx_buf + +There is no need to track the difference between dma_map_page +and dma_map_single, since they're unmapped in exactly the same way. +Also reorder fields in order to avoid padding. + +Signed-off-by: Felix Fietkau +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 42 ++++++--------------- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 13 +------ + 2 files changed, 14 insertions(+), 41 deletions(-) + +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +index 2931376785f2..3b81ea22bbea 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -1386,32 +1386,19 @@ static int txd_to_idx(struct mtk_tx_ring *ring, void *dma, u32 txd_size) + static void mtk_tx_unmap(struct mtk_eth *eth, struct mtk_tx_buf *tx_buf, + struct xdp_frame_bulk *bq, bool napi) + { +- if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) { +- if (tx_buf->flags & MTK_TX_FLAGS_SINGLE0) { +- dma_unmap_single(eth->dma_dev, +- dma_unmap_addr(tx_buf, dma_addr0), +- dma_unmap_len(tx_buf, dma_len0), +- DMA_TO_DEVICE); +- } else if (tx_buf->flags & MTK_TX_FLAGS_PAGE0) { +- dma_unmap_page(eth->dma_dev, +- dma_unmap_addr(tx_buf, dma_addr0), +- dma_unmap_len(tx_buf, dma_len0), +- DMA_TO_DEVICE); +- } +- } else { +- if (dma_unmap_len(tx_buf, dma_len0)) { +- dma_unmap_page(eth->dma_dev, +- dma_unmap_addr(tx_buf, dma_addr0), +- dma_unmap_len(tx_buf, dma_len0), +- DMA_TO_DEVICE); +- } ++ if (dma_unmap_len(tx_buf, dma_len0)) { ++ dma_unmap_page(eth->dma_dev, ++ dma_unmap_addr(tx_buf, dma_addr0), ++ dma_unmap_len(tx_buf, dma_len0), ++ DMA_TO_DEVICE); ++ } + +- if (dma_unmap_len(tx_buf, dma_len1)) { +- dma_unmap_page(eth->dma_dev, +- dma_unmap_addr(tx_buf, dma_addr1), +- dma_unmap_len(tx_buf, dma_len1), +- DMA_TO_DEVICE); +- } ++ if (!MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA) && ++ dma_unmap_len(tx_buf, dma_len1)) { ++ dma_unmap_page(eth->dma_dev, ++ dma_unmap_addr(tx_buf, dma_addr1), ++ dma_unmap_len(tx_buf, dma_len1), ++ DMA_TO_DEVICE); + } + + if (tx_buf->data && tx_buf->data != (void *)MTK_DMA_DUMMY_DESC) { +@@ -1433,7 +1420,6 @@ static void mtk_tx_unmap(struct mtk_eth *eth, struct mtk_tx_buf *tx_buf, + xdp_return_frame(xdpf); + } + } +- tx_buf->flags = 0; + tx_buf->data = NULL; + } + +@@ -1598,7 +1584,6 @@ static int mtk_tx_map(struct sk_buff *skb, struct net_device *dev, + + mtk_tx_set_dma_desc(dev, itxd, &txd_info); + +- itx_buf->flags |= MTK_TX_FLAGS_SINGLE0; + itx_buf->mac_id = mac->id; + setup_tx_buf(eth, itx_buf, itxd_pdma, txd_info.addr, txd_info.size, + k++); +@@ -1646,7 +1631,6 @@ static int mtk_tx_map(struct sk_buff *skb, struct net_device *dev, + if (new_desc) + memset(tx_buf, 0, sizeof(*tx_buf)); + tx_buf->data = (void *)MTK_DMA_DUMMY_DESC; +- tx_buf->flags |= MTK_TX_FLAGS_PAGE0; + tx_buf->mac_id = mac->id; + + setup_tx_buf(eth, tx_buf, txd_pdma, txd_info.addr, +@@ -1979,8 +1963,6 @@ static int mtk_xdp_frame_map(struct mtk_eth *eth, struct net_device *dev, + txd_info->size, DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(eth->dma_dev, txd_info->addr))) + return -ENOMEM; +- +- tx_buf->flags |= MTK_TX_FLAGS_SINGLE0; + } else { + struct page *page = virt_to_head_page(data); + +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +index ee7bb3b7b93a..19381abcdfc6 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -728,14 +728,6 @@ struct mtk_hw_stats { + struct u64_stats_sync syncp; + }; + +-enum mtk_tx_flags { +- /* PDMA descriptor can point at 1-2 segments. This enum allows us to +- * track how memory was allocated so that it can be freed properly. +- */ +- MTK_TX_FLAGS_SINGLE0 = 0x01, +- MTK_TX_FLAGS_PAGE0 = 0x02, +-}; +- + /* This enum allows us to identify how the clock is defined on the array of the + * clock in the order + */ +@@ -908,13 +900,12 @@ enum mtk_tx_buf_type { + */ + struct mtk_tx_buf { + enum mtk_tx_buf_type type; ++ u16 mac_id; + void *data; + +- u16 mac_id; +- u16 flags; + DEFINE_DMA_UNMAP_ADDR(dma_addr0); +- DEFINE_DMA_UNMAP_LEN(dma_len0); + DEFINE_DMA_UNMAP_ADDR(dma_addr1); ++ DEFINE_DMA_UNMAP_LEN(dma_len0); + DEFINE_DMA_UNMAP_LEN(dma_len1); + }; + +-- +2.51.0 + + +From 498cd003f1c801ad2e11f51dddf9aa075f412477 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Thu, 22 Aug 2024 18:02:17 +0200 +Subject: [PATCH 06/12] net: bridge: fix switchdev host mdb entry updates + +When a mdb entry is removed, the bridge switchdev code can issue a +switchdev_port_obj_del call for a port that was not offloaded. + +This leads to an imbalance in switchdev_port_obj_add/del calls, since +br_switchdev_mdb_replay has not been called for the port before. + +This can lead to potential multicast forwarding issues and messages such as: +mt7915e 0000:01:00.0 wl1-ap0: Failed to del Host Multicast Database entry + (object id=3) with error: -ENOENT (-2). + +Fix this issue by checking the port offload status when iterating over +lower devs. + +Signed-off-by: Felix Fietkau +--- + net/bridge/br_switchdev.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/net/bridge/br_switchdev.c b/net/bridge/br_switchdev.c +index fe3f7bbe86ee..b898e1a4b5ff 100644 +--- a/net/bridge/br_switchdev.c ++++ b/net/bridge/br_switchdev.c +@@ -576,10 +576,18 @@ static void br_switchdev_host_mdb(struct net_device *dev, + struct net_bridge_mdb_entry *mp, int type) + { + struct net_device *lower_dev; ++ struct net_bridge_port *port; + struct list_head *iter; + +- netdev_for_each_lower_dev(dev, lower_dev, iter) ++ rcu_read_lock(); ++ netdev_for_each_lower_dev(dev, lower_dev, iter) { ++ port = br_port_get_rcu(lower_dev); ++ if (!port || !port->offload_count) ++ continue; ++ + br_switchdev_host_mdb_one(dev, lower_dev, mp, type); ++ } ++ rcu_read_unlock(); + } + + static int +-- +2.51.0 + + +From 96b0666b743311a15d8e01016462d7cf57764f62 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Mon, 21 Mar 2022 20:39:59 +0100 +Subject: [PATCH 07/12] net: ethernet: mtk_eth_soc: enable threaded NAPI + +This can improve performance under load by ensuring that NAPI processing is +not pinned on CPU 0. + +Signed-off-by: Felix Fietkau +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +index 3b81ea22bbea..a5586bd06490 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -5306,6 +5306,8 @@ static int mtk_probe(struct platform_device *pdev) + dev_err(eth->dev, "failed to allocated dummy device\n"); + goto err_unreg_netdev; + } ++ eth->dummy_dev->threaded = 1; ++ strcpy(eth->dummy_dev->name, "mtk_eth"); + netif_napi_add(eth->dummy_dev, ð->tx_napi, mtk_napi_tx); + netif_napi_add(eth->dummy_dev, ð->rx_napi, mtk_napi_rx); + +-- +2.51.0 + + +From 0666439429f6983cde79712125d76e21fea034f8 Mon Sep 17 00:00:00 2001 +From: Chad Monroe +Date: Mon, 16 Sep 2024 19:29:03 -0700 +Subject: [PATCH 08/12] net: ethernet: mediatek: increase QDMA RESV_BUF size + +Increase QDMA RESV_BUF from 2K to 3K for netsys v2 to match Mediatek SDK[1]. +This helps reduce the possibility of Ethernet transmit timeouts. + +[1]: https://git01.mediatek.com/plugins/gitiles/openwrt/feeds/mtk-openwrt-feeds/+/19d8456c3051e5f6dabf42fa770916a2126ea4bf + +Signed-off-by: Chad Monroe +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 6 ++++-- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 1 + + 2 files changed, 5 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +index a5586bd06490..9d6f395f73dc 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -3487,12 +3487,14 @@ static int mtk_start_dma(struct mtk_eth *eth) + MTK_TX_BT_32DWORDS | MTK_NDP_CO_PRO | + MTK_RX_2B_OFFSET | MTK_TX_WB_DDONE; + +- if (mtk_is_netsys_v2_or_greater(eth)) ++ if (mtk_is_netsys_v2_or_greater(eth)) { ++ val &= ~MTK_RESV_BUF_MASK; + val |= MTK_MUTLI_CNT | MTK_RESV_BUF | + MTK_WCOMP_EN | MTK_DMAD_WR_WDONE | + MTK_CHK_DDONE_EN; +- else ++ } else { + val |= MTK_RX_BT_32DWORDS; ++ } + mtk_w32(eth, val, reg_map->qdma.glo_cfg); + + mtk_w32(eth, +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +index 19381abcdfc6..b9da762fcc70 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -282,6 +282,7 @@ + #define MTK_WCOMP_EN BIT(24) + #define MTK_RESV_BUF (0x80 << 16) + #define MTK_MUTLI_CNT (0x4 << 12) ++#define MTK_RESV_BUF_MASK (0xff << 16) + #define MTK_LEAKY_BUCKET_EN BIT(11) + + /* QDMA Flow Control Register */ +-- +2.51.0 + + +From 80b5de03406650271a4a5fafb06d06dbe4fd8846 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Thu, 23 Mar 2023 10:24:11 +0100 +Subject: [PATCH 09/12] net: ethernet: mtk_eth_soc: improve keeping track of + offloaded flows + +Unify tracking of L2 and L3 flows. Use the generic list field in struct +mtk_foe_entry for tracking L2 subflows. Preparation for improving +flow accounting support. + +Signed-off-by: Felix Fietkau +--- + drivers/net/ethernet/mediatek/mtk_ppe.c | 162 ++++++++++++------------ + drivers/net/ethernet/mediatek/mtk_ppe.h | 15 +-- + 2 files changed, 86 insertions(+), 91 deletions(-) + +diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.c b/drivers/net/ethernet/mediatek/mtk_ppe.c +index ada852adc5f7..5b352ab64ef7 100644 +--- a/drivers/net/ethernet/mediatek/mtk_ppe.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.c +@@ -479,42 +479,43 @@ int mtk_foe_entry_set_queue(struct mtk_eth *eth, struct mtk_foe_entry *entry, + return 0; + } + ++static int ++mtk_flow_entry_match_len(struct mtk_eth *eth, struct mtk_foe_entry *entry) ++{ ++ int type = mtk_get_ib1_pkt_type(eth, entry->ib1); ++ ++ if (type > MTK_PPE_PKT_TYPE_IPV4_DSLITE) ++ return offsetof(struct mtk_foe_entry, ipv6._rsv); ++ else ++ return offsetof(struct mtk_foe_entry, ipv4.ib2); ++} ++ + static bool + mtk_flow_entry_match(struct mtk_eth *eth, struct mtk_flow_entry *entry, +- struct mtk_foe_entry *data) ++ struct mtk_foe_entry *data, int len) + { +- int type, len; +- + if ((data->ib1 ^ entry->data.ib1) & MTK_FOE_IB1_UDP) + return false; + +- type = mtk_get_ib1_pkt_type(eth, entry->data.ib1); +- if (type > MTK_PPE_PKT_TYPE_IPV4_DSLITE) +- len = offsetof(struct mtk_foe_entry, ipv6._rsv); +- else +- len = offsetof(struct mtk_foe_entry, ipv4.ib2); +- + return !memcmp(&entry->data.data, &data->data, len - 4); + } + + static void +-__mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) ++__mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry, ++ bool set_state) + { +- struct hlist_head *head; + struct hlist_node *tmp; + + if (entry->type == MTK_FLOW_TYPE_L2) { + rhashtable_remove_fast(&ppe->l2_flows, &entry->l2_node, + mtk_flow_l2_ht_params); + +- head = &entry->l2_flows; +- hlist_for_each_entry_safe(entry, tmp, head, l2_data.list) +- __mtk_foe_entry_clear(ppe, entry); ++ hlist_for_each_entry_safe(entry, tmp, &entry->l2_flows, l2_list) ++ __mtk_foe_entry_clear(ppe, entry, set_state); + return; + } + +- hlist_del_init(&entry->list); +- if (entry->hash != 0xffff) { ++ if (entry->hash != 0xffff && set_state) { + struct mtk_foe_entry *hwe = mtk_foe_get_entry(ppe, entry->hash); + + hwe->ib1 &= ~MTK_FOE_IB1_STATE; +@@ -535,7 +536,8 @@ __mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) + if (entry->type != MTK_FLOW_TYPE_L2_SUBFLOW) + return; + +- hlist_del_init(&entry->l2_data.list); ++ hlist_del_init(&entry->l2_list); ++ hlist_del_init(&entry->list); + kfree(entry); + } + +@@ -551,68 +553,57 @@ static int __mtk_foe_entry_idle_time(struct mtk_ppe *ppe, u32 ib1) + return now - timestamp; + } + ++static bool ++mtk_flow_entry_update(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) ++{ ++ struct mtk_foe_entry foe = {}; ++ struct mtk_foe_entry *hwe; ++ u16 hash = entry->hash; ++ int len; ++ ++ if (hash == 0xffff) ++ return false; ++ ++ hwe = mtk_foe_get_entry(ppe, hash); ++ len = mtk_flow_entry_match_len(ppe->eth, &entry->data); ++ memcpy(&foe, hwe, len); ++ ++ if (!mtk_flow_entry_match(ppe->eth, entry, &foe, len) || ++ FIELD_GET(MTK_FOE_IB1_STATE, foe.ib1) != MTK_FOE_STATE_BIND) ++ return false; ++ ++ entry->data.ib1 = foe.ib1; ++ ++ return true; ++} ++ + static void + mtk_flow_entry_update_l2(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) + { + u32 ib1_ts_mask = mtk_get_ib1_ts_mask(ppe->eth); + struct mtk_flow_entry *cur; +- struct mtk_foe_entry *hwe; + struct hlist_node *tmp; + int idle; + + idle = __mtk_foe_entry_idle_time(ppe, entry->data.ib1); +- hlist_for_each_entry_safe(cur, tmp, &entry->l2_flows, l2_data.list) { ++ hlist_for_each_entry_safe(cur, tmp, &entry->l2_flows, l2_list) { + int cur_idle; +- u32 ib1; +- +- hwe = mtk_foe_get_entry(ppe, cur->hash); +- ib1 = READ_ONCE(hwe->ib1); + +- if (FIELD_GET(MTK_FOE_IB1_STATE, ib1) != MTK_FOE_STATE_BIND) { +- cur->hash = 0xffff; +- __mtk_foe_entry_clear(ppe, cur); ++ if (!mtk_flow_entry_update(ppe, cur)) { ++ __mtk_foe_entry_clear(ppe, entry, false); + continue; + } + +- cur_idle = __mtk_foe_entry_idle_time(ppe, ib1); ++ cur_idle = __mtk_foe_entry_idle_time(ppe, cur->data.ib1); + if (cur_idle >= idle) + continue; + + idle = cur_idle; + entry->data.ib1 &= ~ib1_ts_mask; +- entry->data.ib1 |= ib1 & ib1_ts_mask; ++ entry->data.ib1 |= cur->data.ib1 & ib1_ts_mask; + } + } + +-static void +-mtk_flow_entry_update(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) +-{ +- struct mtk_foe_entry foe = {}; +- struct mtk_foe_entry *hwe; +- +- spin_lock_bh(&ppe_lock); +- +- if (entry->type == MTK_FLOW_TYPE_L2) { +- mtk_flow_entry_update_l2(ppe, entry); +- goto out; +- } +- +- if (entry->hash == 0xffff) +- goto out; +- +- hwe = mtk_foe_get_entry(ppe, entry->hash); +- memcpy(&foe, hwe, ppe->eth->soc->foe_entry_size); +- if (!mtk_flow_entry_match(ppe->eth, entry, &foe)) { +- entry->hash = 0xffff; +- goto out; +- } +- +- entry->data.ib1 = foe.ib1; +- +-out: +- spin_unlock_bh(&ppe_lock); +-} +- + static void + __mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_foe_entry *entry, + u16 hash) +@@ -653,7 +644,8 @@ __mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_foe_entry *entry, + void mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) + { + spin_lock_bh(&ppe_lock); +- __mtk_foe_entry_clear(ppe, entry); ++ __mtk_foe_entry_clear(ppe, entry, true); ++ hlist_del_init(&entry->list); + spin_unlock_bh(&ppe_lock); + } + +@@ -700,8 +692,8 @@ mtk_foe_entry_commit_subflow(struct mtk_ppe *ppe, struct mtk_flow_entry *entry, + { + const struct mtk_soc_data *soc = ppe->eth->soc; + struct mtk_flow_entry *flow_info; +- struct mtk_foe_entry foe = {}, *hwe; + struct mtk_foe_mac_info *l2; ++ struct mtk_foe_entry *hwe; + u32 ib1_mask = mtk_get_ib1_pkt_type_mask(ppe->eth) | MTK_FOE_IB1_UDP; + int type; + +@@ -709,30 +701,30 @@ mtk_foe_entry_commit_subflow(struct mtk_ppe *ppe, struct mtk_flow_entry *entry, + if (!flow_info) + return; + +- flow_info->l2_data.base_flow = entry; + flow_info->type = MTK_FLOW_TYPE_L2_SUBFLOW; + flow_info->hash = hash; + hlist_add_head(&flow_info->list, + &ppe->foe_flow[hash / soc->hash_offset]); +- hlist_add_head(&flow_info->l2_data.list, &entry->l2_flows); ++ hlist_add_head(&flow_info->l2_list, &entry->l2_flows); + + hwe = mtk_foe_get_entry(ppe, hash); +- memcpy(&foe, hwe, soc->foe_entry_size); +- foe.ib1 &= ib1_mask; +- foe.ib1 |= entry->data.ib1 & ~ib1_mask; ++ memcpy(&flow_info->data, hwe, soc->foe_entry_size); ++ flow_info->data.ib1 &= ib1_mask; ++ flow_info->data.ib1 |= entry->data.ib1 & ~ib1_mask; + +- l2 = mtk_foe_entry_l2(ppe->eth, &foe); ++ l2 = mtk_foe_entry_l2(ppe->eth, &flow_info->data); + memcpy(l2, &entry->data.bridge.l2, sizeof(*l2)); + +- type = mtk_get_ib1_pkt_type(ppe->eth, foe.ib1); ++ type = mtk_get_ib1_pkt_type(ppe->eth, flow_info->data.ib1); + if (type == MTK_PPE_PKT_TYPE_IPV4_HNAPT) +- memcpy(&foe.ipv4.new, &foe.ipv4.orig, sizeof(foe.ipv4.new)); ++ memcpy(&flow_info->data.ipv4.new, &flow_info->data.ipv4.orig, ++ sizeof(flow_info->data.ipv4.new)); + else if (type >= MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T && l2->etype == ETH_P_IP) + l2->etype = ETH_P_IPV6; + +- *mtk_foe_entry_ib2(ppe->eth, &foe) = entry->data.bridge.ib2; ++ *mtk_foe_entry_ib2(ppe->eth, &flow_info->data) = entry->data.bridge.ib2; + +- __mtk_foe_entry_commit(ppe, &foe, hash); ++ __mtk_foe_entry_commit(ppe, &flow_info->data, hash); + } + + void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash) +@@ -742,9 +734,11 @@ void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash) + struct mtk_foe_entry *hwe = mtk_foe_get_entry(ppe, hash); + struct mtk_flow_entry *entry; + struct mtk_foe_bridge key = {}; ++ struct mtk_foe_entry foe = {}; + struct hlist_node *n; + struct ethhdr *eh; + bool found = false; ++ int entry_len; + u8 *tag; + + spin_lock_bh(&ppe_lock); +@@ -752,20 +746,14 @@ void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash) + if (FIELD_GET(MTK_FOE_IB1_STATE, hwe->ib1) == MTK_FOE_STATE_BIND) + goto out; + +- hlist_for_each_entry_safe(entry, n, head, list) { +- if (entry->type == MTK_FLOW_TYPE_L2_SUBFLOW) { +- if (unlikely(FIELD_GET(MTK_FOE_IB1_STATE, hwe->ib1) == +- MTK_FOE_STATE_BIND)) +- continue; +- +- entry->hash = 0xffff; +- __mtk_foe_entry_clear(ppe, entry); +- continue; +- } ++ entry_len = mtk_flow_entry_match_len(ppe->eth, hwe); ++ memcpy(&foe, hwe, entry_len); + +- if (found || !mtk_flow_entry_match(ppe->eth, entry, hwe)) { ++ hlist_for_each_entry_safe(entry, n, head, list) { ++ if (found || ++ !mtk_flow_entry_match(ppe->eth, entry, &foe, entry_len)) { + if (entry->hash != 0xffff) +- entry->hash = 0xffff; ++ __mtk_foe_entry_clear(ppe, entry, false); + continue; + } + +@@ -816,9 +804,17 @@ void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash) + + int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) + { +- mtk_flow_entry_update(ppe, entry); ++ int idle; ++ ++ spin_lock_bh(&ppe_lock); ++ if (entry->type == MTK_FLOW_TYPE_L2) ++ mtk_flow_entry_update_l2(ppe, entry); ++ else ++ mtk_flow_entry_update(ppe, entry); ++ idle = __mtk_foe_entry_idle_time(ppe, entry->data.ib1); ++ spin_unlock_bh(&ppe_lock); + +- return __mtk_foe_entry_idle_time(ppe, entry->data.ib1); ++ return idle; + } + + int mtk_ppe_prepare_reset(struct mtk_ppe *ppe) +diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.h b/drivers/net/ethernet/mediatek/mtk_ppe.h +index 223f709e2704..aa0799c1ce95 100644 +--- a/drivers/net/ethernet/mediatek/mtk_ppe.h ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.h +@@ -286,7 +286,12 @@ enum { + + struct mtk_flow_entry { + union { +- struct hlist_node list; ++ /* regular flows + L2 subflows */ ++ struct { ++ struct hlist_node list; ++ struct hlist_node l2_list; ++ }; ++ /* L2 flows */ + struct { + struct rhash_head l2_node; + struct hlist_head l2_flows; +@@ -296,13 +301,7 @@ struct mtk_flow_entry { + s8 wed_index; + u8 ppe_index; + u16 hash; +- union { +- struct mtk_foe_entry data; +- struct { +- struct mtk_flow_entry *base_flow; +- struct hlist_node list; +- } l2_data; +- }; ++ struct mtk_foe_entry data; + struct rhash_head node; + unsigned long cookie; + }; +-- +2.51.0 + + +From ecc4b72e231898cf8e61dd3dac99b8a36224cd41 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Thu, 23 Mar 2023 11:05:22 +0100 +Subject: [PATCH 10/12] net: ethernet: mediatek: fix ppe flow accounting for L2 + flows + +For L2 flows, the packet/byte counters should report the sum of the +counters of their subflows, both current and expired. +In order to make this work, change the way that accounting data is tracked. +Reset counters when a flow enters bind. Once it expires (or enters unbind), +store the last counter value in struct mtk_flow_entry. + +Signed-off-by: Felix Fietkau +--- + drivers/net/ethernet/mediatek/mtk_ppe.c | 140 ++++++++++-------- + drivers/net/ethernet/mediatek/mtk_ppe.h | 8 +- + .../net/ethernet/mediatek/mtk_ppe_debugfs.c | 2 +- + .../net/ethernet/mediatek/mtk_ppe_offload.c | 17 +-- + 4 files changed, 89 insertions(+), 78 deletions(-) + +diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.c b/drivers/net/ethernet/mediatek/mtk_ppe.c +index 5b352ab64ef7..96365a75b198 100644 +--- a/drivers/net/ethernet/mediatek/mtk_ppe.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.c +@@ -83,9 +83,9 @@ static int mtk_ppe_mib_wait_busy(struct mtk_ppe *ppe) + int ret; + u32 val; + +- ret = readl_poll_timeout(ppe->base + MTK_PPE_MIB_SER_CR, val, +- !(val & MTK_PPE_MIB_SER_CR_ST), +- 20, MTK_PPE_WAIT_TIMEOUT_US); ++ ret = readl_poll_timeout_atomic(ppe->base + MTK_PPE_MIB_SER_CR, val, ++ !(val & MTK_PPE_MIB_SER_CR_ST), ++ 20, MTK_PPE_WAIT_TIMEOUT_US); + + if (ret) + dev_err(ppe->dev, "MIB table busy"); +@@ -93,17 +93,31 @@ static int mtk_ppe_mib_wait_busy(struct mtk_ppe *ppe) + return ret; + } + +-static int mtk_mib_entry_read(struct mtk_ppe *ppe, u16 index, u64 *bytes, u64 *packets) ++static inline struct mtk_foe_accounting * ++mtk_ppe_acct_data(struct mtk_ppe *ppe, u16 index) ++{ ++ if (!ppe->acct_table) ++ return NULL; ++ ++ return ppe->acct_table + index * sizeof(struct mtk_foe_accounting); ++} ++ ++struct mtk_foe_accounting *mtk_ppe_mib_entry_read(struct mtk_ppe *ppe, u16 index) + { + u32 val, cnt_r0, cnt_r1, cnt_r2; ++ struct mtk_foe_accounting *acct; + int ret; + + val = FIELD_PREP(MTK_PPE_MIB_SER_CR_ADDR, index) | MTK_PPE_MIB_SER_CR_ST; + ppe_w32(ppe, MTK_PPE_MIB_SER_CR, val); + ++ acct = mtk_ppe_acct_data(ppe, index); ++ if (!acct) ++ return NULL; ++ + ret = mtk_ppe_mib_wait_busy(ppe); + if (ret) +- return ret; ++ return acct; + + cnt_r0 = readl(ppe->base + MTK_PPE_MIB_SER_R0); + cnt_r1 = readl(ppe->base + MTK_PPE_MIB_SER_R1); +@@ -112,19 +126,19 @@ static int mtk_mib_entry_read(struct mtk_ppe *ppe, u16 index, u64 *bytes, u64 *p + if (mtk_is_netsys_v3_or_greater(ppe->eth)) { + /* 64 bit for each counter */ + u32 cnt_r3 = readl(ppe->base + MTK_PPE_MIB_SER_R3); +- *bytes = ((u64)cnt_r1 << 32) | cnt_r0; +- *packets = ((u64)cnt_r3 << 32) | cnt_r2; ++ acct->bytes += ((u64)cnt_r1 << 32) | cnt_r0; ++ acct->packets += ((u64)cnt_r3 << 32) | cnt_r2; + } else { + /* 48 bit byte counter, 40 bit packet counter */ + u32 byte_cnt_low = FIELD_GET(MTK_PPE_MIB_SER_R0_BYTE_CNT_LOW, cnt_r0); + u32 byte_cnt_high = FIELD_GET(MTK_PPE_MIB_SER_R1_BYTE_CNT_HIGH, cnt_r1); + u32 pkt_cnt_low = FIELD_GET(MTK_PPE_MIB_SER_R1_PKT_CNT_LOW, cnt_r1); + u32 pkt_cnt_high = FIELD_GET(MTK_PPE_MIB_SER_R2_PKT_CNT_HIGH, cnt_r2); +- *bytes = ((u64)byte_cnt_high << 32) | byte_cnt_low; +- *packets = ((u64)pkt_cnt_high << 16) | pkt_cnt_low; ++ acct->bytes += ((u64)byte_cnt_high << 32) | byte_cnt_low; ++ acct->packets += ((u64)pkt_cnt_high << 16) | pkt_cnt_low; + } + +- return 0; ++ return acct; + } + + static void mtk_ppe_cache_clear(struct mtk_ppe *ppe) +@@ -522,14 +536,6 @@ __mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry, + hwe->ib1 |= FIELD_PREP(MTK_FOE_IB1_STATE, MTK_FOE_STATE_INVALID); + dma_wmb(); + mtk_ppe_cache_clear(ppe); +- +- if (ppe->accounting) { +- struct mtk_foe_accounting *acct; +- +- acct = ppe->acct_table + entry->hash * sizeof(*acct); +- acct->packets = 0; +- acct->bytes = 0; +- } + } + entry->hash = 0xffff; + +@@ -554,11 +560,14 @@ static int __mtk_foe_entry_idle_time(struct mtk_ppe *ppe, u32 ib1) + } + + static bool +-mtk_flow_entry_update(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) ++mtk_flow_entry_update(struct mtk_ppe *ppe, struct mtk_flow_entry *entry, ++ u64 *packets, u64 *bytes) + { ++ struct mtk_foe_accounting *acct; + struct mtk_foe_entry foe = {}; + struct mtk_foe_entry *hwe; + u16 hash = entry->hash; ++ bool ret = false; + int len; + + if (hash == 0xffff) +@@ -569,18 +578,35 @@ mtk_flow_entry_update(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) + memcpy(&foe, hwe, len); + + if (!mtk_flow_entry_match(ppe->eth, entry, &foe, len) || +- FIELD_GET(MTK_FOE_IB1_STATE, foe.ib1) != MTK_FOE_STATE_BIND) +- return false; ++ FIELD_GET(MTK_FOE_IB1_STATE, foe.ib1) != MTK_FOE_STATE_BIND) { ++ acct = mtk_ppe_acct_data(ppe, hash); ++ if (acct) { ++ entry->prev_packets += acct->packets; ++ entry->prev_bytes += acct->bytes; ++ } ++ ++ goto out; ++ } + + entry->data.ib1 = foe.ib1; ++ acct = mtk_ppe_mib_entry_read(ppe, hash); ++ ret = true; ++ ++out: ++ if (acct) { ++ *packets += acct->packets; ++ *bytes += acct->bytes; ++ } + +- return true; ++ return ret; + } + + static void + mtk_flow_entry_update_l2(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) + { + u32 ib1_ts_mask = mtk_get_ib1_ts_mask(ppe->eth); ++ u64 *packets = &entry->packets; ++ u64 *bytes = &entry->bytes; + struct mtk_flow_entry *cur; + struct hlist_node *tmp; + int idle; +@@ -589,7 +615,9 @@ mtk_flow_entry_update_l2(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) + hlist_for_each_entry_safe(cur, tmp, &entry->l2_flows, l2_list) { + int cur_idle; + +- if (!mtk_flow_entry_update(ppe, cur)) { ++ if (!mtk_flow_entry_update(ppe, cur, packets, bytes)) { ++ entry->prev_packets += cur->prev_packets; ++ entry->prev_bytes += cur->prev_bytes; + __mtk_foe_entry_clear(ppe, entry, false); + continue; + } +@@ -604,10 +632,29 @@ mtk_flow_entry_update_l2(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) + } + } + ++void mtk_foe_entry_get_stats(struct mtk_ppe *ppe, struct mtk_flow_entry *entry, ++ int *idle) ++{ ++ entry->packets = entry->prev_packets; ++ entry->bytes = entry->prev_bytes; ++ ++ spin_lock_bh(&ppe_lock); ++ ++ if (entry->type == MTK_FLOW_TYPE_L2) ++ mtk_flow_entry_update_l2(ppe, entry); ++ else ++ mtk_flow_entry_update(ppe, entry, &entry->packets, &entry->bytes); ++ ++ *idle = __mtk_foe_entry_idle_time(ppe, entry->data.ib1); ++ ++ spin_unlock_bh(&ppe_lock); ++} ++ + static void + __mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_foe_entry *entry, + u16 hash) + { ++ struct mtk_foe_accounting *acct; + struct mtk_eth *eth = ppe->eth; + u16 timestamp = mtk_eth_timestamp(eth); + struct mtk_foe_entry *hwe; +@@ -638,6 +685,12 @@ __mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_foe_entry *entry, + + dma_wmb(); + ++ acct = mtk_ppe_mib_entry_read(ppe, hash); ++ if (acct) { ++ acct->packets = 0; ++ acct->bytes = 0; ++ } ++ + mtk_ppe_cache_clear(ppe); + } + +@@ -802,21 +855,6 @@ void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash) + spin_unlock_bh(&ppe_lock); + } + +-int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) +-{ +- int idle; +- +- spin_lock_bh(&ppe_lock); +- if (entry->type == MTK_FLOW_TYPE_L2) +- mtk_flow_entry_update_l2(ppe, entry); +- else +- mtk_flow_entry_update(ppe, entry); +- idle = __mtk_foe_entry_idle_time(ppe, entry->data.ib1); +- spin_unlock_bh(&ppe_lock); +- +- return idle; +-} +- + int mtk_ppe_prepare_reset(struct mtk_ppe *ppe) + { + if (!ppe) +@@ -844,32 +882,6 @@ int mtk_ppe_prepare_reset(struct mtk_ppe *ppe) + return mtk_ppe_wait_busy(ppe); + } + +-struct mtk_foe_accounting *mtk_foe_entry_get_mib(struct mtk_ppe *ppe, u32 index, +- struct mtk_foe_accounting *diff) +-{ +- struct mtk_foe_accounting *acct; +- int size = sizeof(struct mtk_foe_accounting); +- u64 bytes, packets; +- +- if (!ppe->accounting) +- return NULL; +- +- if (mtk_mib_entry_read(ppe, index, &bytes, &packets)) +- return NULL; +- +- acct = ppe->acct_table + index * size; +- +- acct->bytes += bytes; +- acct->packets += packets; +- +- if (diff) { +- diff->bytes = bytes; +- diff->packets = packets; +- } +- +- return acct; +-} +- + struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, int index) + { + bool accounting = eth->soc->has_accounting; +diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.h b/drivers/net/ethernet/mediatek/mtk_ppe.h +index aa0799c1ce95..9a4990aa5fa5 100644 +--- a/drivers/net/ethernet/mediatek/mtk_ppe.h ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.h +@@ -304,6 +304,8 @@ struct mtk_flow_entry { + struct mtk_foe_entry data; + struct rhash_head node; + unsigned long cookie; ++ u64 prev_packets, prev_bytes; ++ u64 packets, bytes; + }; + + struct mtk_mib_entry { +@@ -348,6 +350,7 @@ void mtk_ppe_deinit(struct mtk_eth *eth); + void mtk_ppe_start(struct mtk_ppe *ppe); + int mtk_ppe_stop(struct mtk_ppe *ppe); + int mtk_ppe_prepare_reset(struct mtk_ppe *ppe); ++struct mtk_foe_accounting *mtk_ppe_mib_entry_read(struct mtk_ppe *ppe, u16 index); + + void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash); + +@@ -397,9 +400,8 @@ int mtk_foe_entry_set_queue(struct mtk_eth *eth, struct mtk_foe_entry *entry, + unsigned int queue); + int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_flow_entry *entry); + void mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry); +-int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry); + int mtk_ppe_debugfs_init(struct mtk_ppe *ppe, int index); +-struct mtk_foe_accounting *mtk_foe_entry_get_mib(struct mtk_ppe *ppe, u32 index, +- struct mtk_foe_accounting *diff); ++void mtk_foe_entry_get_stats(struct mtk_ppe *ppe, struct mtk_flow_entry *entry, ++ int *idle); + + #endif +diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c b/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c +index 570ebf91f693..9259d0925b88 100644 +--- a/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c +@@ -97,7 +97,7 @@ mtk_ppe_debugfs_foe_show(struct seq_file *m, void *private, bool bind) + if (bind && state != MTK_FOE_STATE_BIND) + continue; + +- acct = mtk_foe_entry_get_mib(ppe, i, NULL); ++ acct = mtk_ppe_mib_entry_read(ppe, i); + + type = mtk_get_ib1_pkt_type(ppe->eth, entry->ib1); + seq_printf(m, "%05x %s %7s", i, +diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c +index e9bd32741983..af8e0107fb93 100644 +--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c +@@ -522,24 +522,21 @@ static int + mtk_flow_offload_stats(struct mtk_eth *eth, struct flow_cls_offload *f) + { + struct mtk_flow_entry *entry; +- struct mtk_foe_accounting diff; +- u32 idle; ++ u64 packets, bytes; ++ int idle; + + entry = rhashtable_lookup(ð->flow_table, &f->cookie, + mtk_flow_ht_params); + if (!entry) + return -ENOENT; + +- idle = mtk_foe_entry_idle_time(eth->ppe[entry->ppe_index], entry); ++ packets = entry->packets; ++ bytes = entry->bytes; ++ mtk_foe_entry_get_stats(eth->ppe[entry->ppe_index], entry, &idle); ++ f->stats.pkts += entry->packets - packets; ++ f->stats.bytes += entry->bytes - bytes; + f->stats.lastused = jiffies - idle * HZ; + +- if (entry->hash != 0xFFFF && +- mtk_foe_entry_get_mib(eth->ppe[entry->ppe_index], entry->hash, +- &diff)) { +- f->stats.pkts += diff.packets; +- f->stats.bytes += diff.bytes; +- } +- + return 0; + } + +-- +2.51.0 + + +From 0d9be0a839c47582a77b1c63164b2e93a48973ac Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Fri, 12 Sep 2025 14:18:14 +0200 +Subject: [PATCH 11/12] net: ethernet: mtk_eth_soc: zero initialize PPE flow + table + +Avoid picking up flows from last boot or other invalid data + +Signed-off-by: Felix Fietkau +--- + drivers/net/ethernet/mediatek/mtk_ppe.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.c b/drivers/net/ethernet/mediatek/mtk_ppe.c +index 96365a75b198..cb08d132bad9 100644 +--- a/drivers/net/ethernet/mediatek/mtk_ppe.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.c +@@ -914,6 +914,7 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, int index) + if (!foe) + goto err_free_l2_flows; + ++ memset(foe, 0, MTK_PPE_ENTRIES * soc->foe_entry_size); + ppe->foe_table = foe; + + foe_flow_size = (MTK_PPE_ENTRIES / soc->hash_offset) * +@@ -928,6 +929,7 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, int index) + if (!mib) + return NULL; + ++ memset(mib, 0, MTK_PPE_ENTRIES * sizeof(*mib)); + ppe->mib_table = mib; + + acct = devm_kzalloc(dev, MTK_PPE_ENTRIES * sizeof(*acct), +-- +2.51.0 + + +From 3b613fe4850f9bbb32417ef3c2c48c5f65f0111d Mon Sep 17 00:00:00 2001 +From: Bo-Cun Chen +Date: Wed, 27 Nov 2024 13:36:49 +0800 +Subject: [PATCH 12/12] net: ethernet: mtk_eth_soc: add hw dump for forced + reset + +Without this patch, the ETH driver is unable to dump the registers +before triggering a forced reset. + +Signed-off-by: Bo-Cun Chen +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 55 +++++++++++++++++++++ + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 1 + + 2 files changed, 56 insertions(+) + +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +index 9d6f395f73dc..110dac8248df 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -65,6 +65,7 @@ static const struct mtk_reg_map mtk_reg_map = { + .rx_ptr = 0x1900, + .rx_cnt_cfg = 0x1904, + .qcrx_ptr = 0x1908, ++ .page = 0x19f0, + .glo_cfg = 0x1a04, + .rst_idx = 0x1a08, + .delay_irq = 0x1a0c, +@@ -131,6 +132,7 @@ static const struct mtk_reg_map mt7986_reg_map = { + .rx_ptr = 0x4500, + .rx_cnt_cfg = 0x4504, + .qcrx_ptr = 0x4508, ++ .page = 0x45f0, + .glo_cfg = 0x4604, + .rst_idx = 0x4608, + .delay_irq = 0x460c, +@@ -182,6 +184,7 @@ static const struct mtk_reg_map mt7988_reg_map = { + .rx_ptr = 0x4500, + .rx_cnt_cfg = 0x4504, + .qcrx_ptr = 0x4508, ++ .page = 0x45f0, + .glo_cfg = 0x4604, + .rst_idx = 0x4608, + .delay_irq = 0x460c, +@@ -3913,6 +3916,56 @@ static void mtk_set_mcr_max_rx(struct mtk_mac *mac, u32 val) + mtk_w32(mac->hw, mcr_new, MTK_MAC_MCR(mac->id)); + } + ++static void mtk_hw_dump_reg(struct mtk_eth *eth, char *name, u32 offset, u32 range) ++{ ++ u32 cur = offset; ++ ++ pr_info("\n==================== %s ====================\n", name); ++ while (cur < offset + range) { ++ pr_info("0x%08x: %08x %08x %08x %08x\n", ++ cur, mtk_r32(eth, cur), mtk_r32(eth, cur + 0x4), ++ mtk_r32(eth, cur + 0x8), mtk_r32(eth, cur + 0xc)); ++ cur += 0x10; ++ } ++} ++ ++static void mtk_hw_dump(struct mtk_eth *eth) ++{ ++ const struct mtk_reg_map *reg_map = eth->soc->reg_map; ++ u32 id; ++ ++ mtk_hw_dump_reg(eth, "FE", 0x0, 0x600); ++ mtk_hw_dump_reg(eth, "FE", 0x1400, 0x300); ++ mtk_hw_dump_reg(eth, "ADMA", reg_map->pdma.rx_ptr, 0x300); ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) { ++ for (id = 0; id < MTK_QDMA_NUM_QUEUES / 16; id++) { ++ mtk_w32(eth, id, reg_map->qdma.page); ++ pr_info("\nQDMA PAGE:%x ", mtk_r32(eth, reg_map->qdma.page)); ++ mtk_hw_dump_reg(eth, "QDMA", reg_map->qdma.qtx_cfg, 0x100); ++ mtk_w32(eth, 0, reg_map->qdma.page); ++ } ++ mtk_hw_dump_reg(eth, "QDMA", reg_map->qdma.rx_ptr, 0x300); ++ } ++ if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) { ++ mtk_hw_dump_reg(eth, "WDMA0", reg_map->wdma_base[0], 0x400); ++ mtk_hw_dump_reg(eth, "WDMA1", reg_map->wdma_base[1], 0x400); ++ if (mtk_is_netsys_v3_or_greater(eth)) ++ mtk_hw_dump_reg(eth, "WDMA2", reg_map->wdma_base[2], 0x400); ++ } ++ mtk_hw_dump_reg(eth, "PPE0", reg_map->ppe_base + 0x200, 0x200); ++ if (!mtk_is_netsys_v1(eth)) ++ mtk_hw_dump_reg(eth, "PPE1", reg_map->ppe_base + 0x600, 0x200); ++ if (mtk_is_netsys_v3_or_greater(eth)) ++ mtk_hw_dump_reg(eth, "PPE2", reg_map->ppe_base + 0xE00, 0x200); ++ mtk_hw_dump_reg(eth, "GMAC", 0x10000, 0x300); ++ if (mtk_is_netsys_v3_or_greater(eth)) ++ mtk_hw_dump_reg(eth, "GMAC", 0x10300, 0x100); ++ if (mtk_is_netsys_v3_or_greater(eth)) { ++ mtk_hw_dump_reg(eth, "XGMAC0", 0x12000, 0x300); ++ mtk_hw_dump_reg(eth, "XGMAC1", 0x13000, 0x300); ++ } ++} ++ + static void mtk_hw_reset(struct mtk_eth *eth) + { + u32 val; +@@ -4392,6 +4445,8 @@ static void mtk_pending_work(struct work_struct *work) + rtnl_lock(); + set_bit(MTK_RESETTING, ð->state); + ++ mtk_hw_dump(eth); ++ + mtk_prepare_for_reset(eth); + mtk_wed_fe_reset(); + /* Run again reset preliminary configuration in order to avoid any +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +index b9da762fcc70..64b94b21b493 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -1152,6 +1152,7 @@ struct mtk_reg_map { + u32 rx_ptr; /* rx base pointer */ + u32 rx_cnt_cfg; /* rx max count configuration */ + u32 qcrx_ptr; /* rx cpu pointer */ ++ u32 page; /* page configuration */ + u32 glo_cfg; /* global configuration */ + u32 rst_idx; /* reset index */ + u32 delay_irq; /* delay interrupt */ +-- +2.51.0 + diff --git a/pkgs/linux_6_12-openwrt-one.patch b/pkgs/linux_6_12-openwrt-one.patch new file mode 100644 index 0000000..1e231cf --- /dev/null +++ b/pkgs/linux_6_12-openwrt-one.patch @@ -0,0 +1,222237 @@ +From 1d094806fc13ed0e5ed368b9a7da338ac24457f9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= +Date: Mon, 3 Nov 2025 15:48:42 +0100 +Subject: [PATCH 001/517] OpenWrt files + +--- + .../mtd/partitions/openwrt,uimage.yaml | 91 + + Documentation/networking/adm6996.txt | 110 + + .../mt7981-rfb-mxl-2p5g-phy-eth1.dtso | 34 + + .../mt7981-rfb-mxl-2p5g-phy-swp5.dtso | 35 + + .../dts/mediatek/mt7981-rfb-spim-nand.dtso | 78 + + arch/arm64/boot/dts/mediatek/mt7981-rfb.dts | 189 + + .../dts/mediatek/mt7986a-rfb-spim-nand.dts | 52 + + .../dts/mediatek/mt7986a-rfb-spim-nor.dts | 51 + + arch/arm64/boot/dts/mediatek/mt7986a-rfb.dtsi | 391 + + arch/mips/fw/myloader/Makefile | 5 + + arch/mips/fw/myloader/myloader.c | 63 + + drivers/bcma/fallback-sprom.c | 534 + + drivers/bcma/fallback-sprom.h | 7 + + drivers/leds/leds-smartrg-system.c | 225 + + drivers/mfd/airoha-an8855.c | 278 + + drivers/mtd/mtdsplit/Kconfig | 117 + + drivers/mtd/mtdsplit/Makefile | 20 + + drivers/mtd/mtdsplit/mtdsplit.c | 130 + + drivers/mtd/mtdsplit/mtdsplit.h | 67 + + drivers/mtd/mtdsplit/mtdsplit_bcm63xx.c | 186 + + drivers/mtd/mtdsplit/mtdsplit_bcm_wfi.c | 535 + + drivers/mtd/mtdsplit/mtdsplit_brnimage.c | 104 + + drivers/mtd/mtdsplit/mtdsplit_cfe_bootfs.c | 90 + + drivers/mtd/mtdsplit/mtdsplit_elf.c | 287 + + drivers/mtd/mtdsplit/mtdsplit_eva.c | 103 + + drivers/mtd/mtdsplit/mtdsplit_fit.c | 365 + + drivers/mtd/mtdsplit/mtdsplit_h3c_vfs.c | 167 + + drivers/mtd/mtdsplit/mtdsplit_jimage.c | 284 + + drivers/mtd/mtdsplit/mtdsplit_lzma.c | 109 + + drivers/mtd/mtdsplit/mtdsplit_minor.c | 142 + + drivers/mtd/mtdsplit/mtdsplit_mstc_boot.c | 270 + + drivers/mtd/mtdsplit/mtdsplit_seama.c | 118 + + drivers/mtd/mtdsplit/mtdsplit_seil.c | 191 + + drivers/mtd/mtdsplit/mtdsplit_squashfs.c | 72 + + drivers/mtd/mtdsplit/mtdsplit_tplink.c | 176 + + drivers/mtd/mtdsplit/mtdsplit_trx.c | 155 + + drivers/mtd/mtdsplit/mtdsplit_uimage.c | 282 + + drivers/mtd/mtdsplit/mtdsplit_wrgg.c | 142 + + drivers/mtd/nand/mtk_bmt.c | 474 + + drivers/mtd/nand/mtk_bmt.h | 137 + + drivers/mtd/nand/mtk_bmt_bbt.c | 203 + + drivers/mtd/nand/mtk_bmt_nmbm.c | 2348 ++ + drivers/mtd/nand/mtk_bmt_v2.c | 506 + + drivers/mtd/parsers/routerbootpart.c | 365 + + drivers/net/dsa/an8855.c | 2308 ++ + drivers/net/dsa/an8855.h | 783 + + drivers/net/mdio/mdio-an8855.c | 113 + + drivers/net/phy/adm6996.c | 1241 + + drivers/net/phy/adm6996.h | 186 + + drivers/net/phy/air_an8855.c | 267 + + drivers/net/phy/ar8216.c | 2909 ++ + drivers/net/phy/ar8216.h | 725 + + drivers/net/phy/ar8327.c | 1589 ++ + drivers/net/phy/ar8327.h | 334 + + drivers/net/phy/b53/Kconfig | 37 + + drivers/net/phy/b53/Makefile | 10 + + drivers/net/phy/b53/b53_common.c | 1724 ++ + drivers/net/phy/b53/b53_mdio.c | 436 + + drivers/net/phy/b53/b53_mmap.c | 239 + + drivers/net/phy/b53/b53_phy_fixup.c | 55 + + drivers/net/phy/b53/b53_priv.h | 336 + + drivers/net/phy/b53/b53_regs.h | 348 + + drivers/net/phy/b53/b53_spi.c | 344 + + drivers/net/phy/b53/b53_srab.c | 376 + + drivers/net/phy/en8801sc.c | 1117 + + drivers/net/phy/en8801sc.h | 250 + + drivers/net/phy/ip17xx.c | 1370 + + drivers/net/phy/psb6970.c | 443 + + drivers/net/phy/rtk/Makefile | 66 + + drivers/net/phy/rtk/rtl8367c/acl.c | 2061 ++ + drivers/net/phy/rtk/rtl8367c/cpu.c | 537 + + drivers/net/phy/rtk/rtl8367c/dot1x.c | 843 + + drivers/net/phy/rtk/rtl8367c/eee.c | 162 + + drivers/net/phy/rtk/rtl8367c/i2c.c | 436 + + drivers/net/phy/rtk/rtl8367c/igmp.c | 1555 ++ + drivers/net/phy/rtk/rtl8367c/include/acl.h | 990 + + drivers/net/phy/rtk/rtl8367c/include/cpu.h | 327 + + drivers/net/phy/rtk/rtl8367c/include/dot1x.h | 470 + + drivers/net/phy/rtk/rtl8367c/include/eee.h | 82 + + drivers/net/phy/rtk/rtl8367c/include/i2c.h | 168 + + drivers/net/phy/rtk/rtl8367c/include/igmp.h | 769 + + .../net/phy/rtk/rtl8367c/include/interrupt.h | 254 + + drivers/net/phy/rtk/rtl8367c/include/l2.h | 1181 + + drivers/net/phy/rtk/rtl8367c/include/leaky.h | 371 + + drivers/net/phy/rtk/rtl8367c/include/led.h | 481 + + drivers/net/phy/rtk/rtl8367c/include/mirror.h | 272 + + drivers/net/phy/rtk/rtl8367c/include/oam.h | 188 + + drivers/net/phy/rtk/rtl8367c/include/port.h | 959 + + drivers/net/phy/rtk/rtl8367c/include/ptp.h | 511 + + drivers/net/phy/rtk/rtl8367c/include/qos.h | 781 + + drivers/net/phy/rtk/rtl8367c/include/rate.h | 305 + + drivers/net/phy/rtk/rtl8367c/include/rldp.h | 264 + + .../net/phy/rtk/rtl8367c/include/rtk_error.h | 229 + + .../net/phy/rtk/rtl8367c/include/rtk_hal.h | 44 + + .../net/phy/rtk/rtl8367c/include/rtk_switch.h | 741 + + .../net/phy/rtk/rtl8367c/include/rtk_types.h | 155 + + .../rtk/rtl8367c/include/rtl8367c_asicdrv.h | 129 + + .../rtl8367c/include/rtl8367c_asicdrv_acl.h | 231 + + .../include/rtl8367c_asicdrv_cputag.h | 49 + + .../rtl8367c/include/rtl8367c_asicdrv_dot1x.h | 52 + + .../rtl8367c/include/rtl8367c_asicdrv_eav.h | 109 + + .../rtl8367c/include/rtl8367c_asicdrv_eee.h | 31 + + .../rtl8367c/include/rtl8367c_asicdrv_fc.h | 99 + + .../rtl8367c/include/rtl8367c_asicdrv_green.h | 36 + + .../rtl8367c/include/rtl8367c_asicdrv_hsb.h | 43 + + .../rtl8367c/include/rtl8367c_asicdrv_i2c.h | 47 + + .../rtl8367c/include/rtl8367c_asicdrv_igmp.h | 169 + + .../include/rtl8367c_asicdrv_inbwctrl.h | 30 + + .../include/rtl8367c_asicdrv_interrupt.h | 66 + + .../rtl8367c/include/rtl8367c_asicdrv_led.h | 138 + + .../rtl8367c/include/rtl8367c_asicdrv_lut.h | 159 + + .../rtl8367c/include/rtl8367c_asicdrv_meter.h | 34 + + .../rtl8367c/include/rtl8367c_asicdrv_mib.h | 133 + + .../include/rtl8367c_asicdrv_mii_mgr.h | 26 + + .../include/rtl8367c_asicdrv_mirror.h | 49 + + .../rtl8367c/include/rtl8367c_asicdrv_misc.h | 34 + + .../rtl8367c/include/rtl8367c_asicdrv_oam.h | 47 + + .../rtl8367c/include/rtl8367c_asicdrv_phy.h | 43 + + .../rtl8367c/include/rtl8367c_asicdrv_port.h | 237 + + .../include/rtl8367c_asicdrv_portIsolation.h | 28 + + .../rtl8367c/include/rtl8367c_asicdrv_qos.h | 96 + + .../rtl8367c/include/rtl8367c_asicdrv_rldp.h | 60 + + .../rtl8367c/include/rtl8367c_asicdrv_rma.h | 57 + + .../include/rtl8367c_asicdrv_scheduling.h | 58 + + .../rtl8367c/include/rtl8367c_asicdrv_storm.h | 61 + + .../rtl8367c/include/rtl8367c_asicdrv_svlan.h | 132 + + .../include/rtl8367c_asicdrv_trunking.h | 48 + + .../rtl8367c_asicdrv_unknownMulticast.h | 59 + + .../rtl8367c/include/rtl8367c_asicdrv_vlan.h | 157 + + .../phy/rtk/rtl8367c/include/rtl8367c_base.h | 596 + + .../phy/rtk/rtl8367c/include/rtl8367c_reg.h | 22819 ++++++++++++++++ + drivers/net/phy/rtk/rtl8367c/include/smi.h | 54 + + drivers/net/phy/rtk/rtl8367c/include/stat.h | 433 + + drivers/net/phy/rtk/rtl8367c/include/storm.h | 422 + + drivers/net/phy/rtk/rtl8367c/include/svlan.h | 896 + + drivers/net/phy/rtk/rtl8367c/include/trap.h | 757 + + drivers/net/phy/rtk/rtl8367c/include/trunk.h | 328 + + drivers/net/phy/rtk/rtl8367c/include/vlan.h | 892 + + drivers/net/phy/rtk/rtl8367c/interrupt.c | 434 + + drivers/net/phy/rtk/rtl8367c/l2.c | 2911 ++ + drivers/net/phy/rtk/rtl8367c/leaky.c | 590 + + drivers/net/phy/rtk/rtl8367c/led.c | 792 + + drivers/net/phy/rtk/rtl8367c/mirror.c | 548 + + drivers/net/phy/rtk/rtl8367c/oam.c | 245 + + drivers/net/phy/rtk/rtl8367c/port.c | 2467 ++ + drivers/net/phy/rtk/rtl8367c/ptp.c | 759 + + drivers/net/phy/rtk/rtl8367c/qos.c | 1452 + + drivers/net/phy/rtk/rtl8367c/rate.c | 607 + + drivers/net/phy/rtk/rtl8367c/rldp.c | 468 + + drivers/net/phy/rtk/rtl8367c/rtk_hal.c | 839 + + drivers/net/phy/rtk/rtl8367c/rtk_switch.c | 1794 ++ + .../net/phy/rtk/rtl8367c/rtl8367c_asicdrv.c | 639 + + .../phy/rtk/rtl8367c/rtl8367c_asicdrv_acl.c | 1173 + + .../rtk/rtl8367c/rtl8367c_asicdrv_cputag.c | 369 + + .../phy/rtk/rtl8367c/rtl8367c_asicdrv_dot1x.c | 415 + + .../phy/rtk/rtl8367c/rtl8367c_asicdrv_eav.c | 877 + + .../phy/rtk/rtl8367c/rtl8367c_asicdrv_eee.c | 141 + + .../phy/rtk/rtl8367c/rtl8367c_asicdrv_fc.c | 1354 + + .../phy/rtk/rtl8367c/rtl8367c_asicdrv_green.c | 445 + + .../phy/rtk/rtl8367c/rtl8367c_asicdrv_hsb.c | 81 + + .../phy/rtk/rtl8367c/rtl8367c_asicdrv_i2c.c | 474 + + .../phy/rtk/rtl8367c/rtl8367c_asicdrv_igmp.c | 2109 ++ + .../rtk/rtl8367c/rtl8367c_asicdrv_inbwctrl.c | 164 + + .../rtk/rtl8367c/rtl8367c_asicdrv_interrupt.c | 205 + + .../phy/rtk/rtl8367c/rtl8367c_asicdrv_led.c | 727 + + .../phy/rtk/rtl8367c/rtl8367c_asicdrv_lut.c | 1549 ++ + .../phy/rtk/rtl8367c/rtl8367c_asicdrv_meter.c | 305 + + .../phy/rtk/rtl8367c/rtl8367c_asicdrv_mib.c | 570 + + .../rtk/rtl8367c/rtl8367c_asicdrv_mirror.c | 472 + + .../phy/rtk/rtl8367c/rtl8367c_asicdrv_misc.c | 268 + + .../phy/rtk/rtl8367c/rtl8367c_asicdrv_oam.c | 194 + + .../phy/rtk/rtl8367c/rtl8367c_asicdrv_phy.c | 394 + + .../phy/rtk/rtl8367c/rtl8367c_asicdrv_port.c | 5752 ++++ + .../rtl8367c/rtl8367c_asicdrv_portIsolation.c | 119 + + .../phy/rtk/rtl8367c/rtl8367c_asicdrv_qos.c | 778 + + .../phy/rtk/rtl8367c/rtl8367c_asicdrv_rldp.c | 674 + + .../phy/rtk/rtl8367c/rtl8367c_asicdrv_rma.c | 362 + + .../rtl8367c/rtl8367c_asicdrv_scheduling.c | 525 + + .../phy/rtk/rtl8367c/rtl8367c_asicdrv_storm.c | 851 + + .../phy/rtk/rtl8367c/rtl8367c_asicdrv_svlan.c | 1003 + + .../rtk/rtl8367c/rtl8367c_asicdrv_trunking.c | 356 + + .../rtl8367c_asicdrv_unknownMulticast.c | 238 + + .../phy/rtk/rtl8367c/rtl8367c_asicdrv_vlan.c | 1505 + + drivers/net/phy/rtk/rtl8367c/smi.c | 442 + + drivers/net/phy/rtk/rtl8367c/stat.c | 626 + + drivers/net/phy/rtk/rtl8367c/storm.c | 816 + + drivers/net/phy/rtk/rtl8367c/svlan.c | 2415 ++ + drivers/net/phy/rtk/rtl8367c/trap.c | 1229 + + drivers/net/phy/rtk/rtl8367c/trunk.c | 605 + + drivers/net/phy/rtk/rtl8367c/vlan.c | 2124 ++ + drivers/net/phy/rtk/rtl8367s.c | 580 + + drivers/net/phy/rtk/rtl8367s_dbg.c | 648 + + drivers/net/phy/rtk/rtl8367s_mdio.c | 301 + + drivers/net/phy/rtl8261n/Kconfig | 5 + + drivers/net/phy/rtl8261n/Makefile | 11 + + .../phy/rtl8261n/construct/conf_rtl8261n_c.c | 1465 + + .../phy/rtl8261n/construct/conf_rtl8264b.c | 2177 ++ + drivers/net/phy/rtl8261n/error.h | 165 + + drivers/net/phy/rtl8261n/phy_patch.c | 188 + + drivers/net/phy/rtl8261n/phy_patch.h | 174 + + drivers/net/phy/rtl8261n/phy_rtl826xb_patch.c | 1031 + + drivers/net/phy/rtl8261n/phy_rtl826xb_patch.h | 63 + + drivers/net/phy/rtl8261n/rtk_osal.c | 57 + + drivers/net/phy/rtl8261n/rtk_osal.h | 99 + + drivers/net/phy/rtl8261n/rtk_phy.c | 324 + + drivers/net/phy/rtl8261n/rtk_phylib.c | 108 + + drivers/net/phy/rtl8261n/rtk_phylib.h | 106 + + drivers/net/phy/rtl8261n/rtk_phylib_def.h | 166 + + .../net/phy/rtl8261n/rtk_phylib_rtl826xb.c | 57 + + .../net/phy/rtl8261n/rtk_phylib_rtl826xb.h | 19 + + drivers/net/phy/rtl8261n/type.h | 117 + + drivers/net/phy/rtl8306.c | 1063 + + drivers/net/phy/rtl8366_smi.c | 1625 ++ + drivers/net/phy/rtl8366_smi.h | 171 + + drivers/net/phy/rtl8366rb.c | 1529 ++ + drivers/net/phy/rtl8366s.c | 1317 + + drivers/net/phy/rtl8367.c | 1859 ++ + drivers/net/phy/rtl8367b.c | 1649 ++ + drivers/net/phy/swconfig.c | 1242 + + drivers/net/phy/swconfig_leds.c | 555 + + drivers/nvmem/an8855-efuse.c | 63 + + drivers/platform/mikrotik/Kconfig | 31 + + drivers/platform/mikrotik/Makefile | 6 + + drivers/platform/mikrotik/rb_hardconfig.c | 844 + + drivers/platform/mikrotik/rb_hardconfig.h | 32 + + drivers/platform/mikrotik/rb_lz77.c | 446 + + drivers/platform/mikrotik/rb_lz77.h | 35 + + drivers/platform/mikrotik/rb_nvmem.c | 230 + + drivers/platform/mikrotik/rb_softconfig.c | 795 + + drivers/platform/mikrotik/routerboot.c | 251 + + drivers/platform/mikrotik/routerboot.h | 38 + + drivers/ssb/fallback-sprom.c | 745 + + drivers/ssb/fallback-sprom.h | 7 + + include/dt-bindings/mtd/partitions/uimage.h | 198 + + include/linux/ar8216_platform.h | 134 + + include/linux/ath5k_platform.h | 30 + + include/linux/mfd/airoha-an8855-mfd.h | 41 + + include/linux/mtd/mtk_bmt.h | 18 + + include/linux/myloader.h | 121 + + include/linux/platform_data/adm6996-gpio.h | 29 + + include/linux/routerboot.h | 106 + + include/linux/rtl8366.h | 42 + + include/linux/rtl8367.h | 63 + + include/linux/switch.h | 179 + + include/uapi/linux/switch.h | 119 + + 245 files changed, 143699 insertions(+) + create mode 100644 Documentation/devicetree/bindings/mtd/partitions/openwrt,uimage.yaml + create mode 100644 Documentation/networking/adm6996.txt + create mode 100644 arch/arm64/boot/dts/mediatek/mt7981-rfb-mxl-2p5g-phy-eth1.dtso + create mode 100644 arch/arm64/boot/dts/mediatek/mt7981-rfb-mxl-2p5g-phy-swp5.dtso + create mode 100644 arch/arm64/boot/dts/mediatek/mt7981-rfb-spim-nand.dtso + create mode 100644 arch/arm64/boot/dts/mediatek/mt7981-rfb.dts + create mode 100644 arch/arm64/boot/dts/mediatek/mt7986a-rfb-spim-nand.dts + create mode 100644 arch/arm64/boot/dts/mediatek/mt7986a-rfb-spim-nor.dts + create mode 100644 arch/arm64/boot/dts/mediatek/mt7986a-rfb.dtsi + create mode 100644 arch/mips/fw/myloader/Makefile + create mode 100644 arch/mips/fw/myloader/myloader.c + create mode 100644 drivers/bcma/fallback-sprom.c + create mode 100644 drivers/bcma/fallback-sprom.h + create mode 100644 drivers/leds/leds-smartrg-system.c + create mode 100644 drivers/mfd/airoha-an8855.c + create mode 100644 drivers/mtd/mtdsplit/Kconfig + create mode 100644 drivers/mtd/mtdsplit/Makefile + create mode 100644 drivers/mtd/mtdsplit/mtdsplit.c + create mode 100644 drivers/mtd/mtdsplit/mtdsplit.h + create mode 100644 drivers/mtd/mtdsplit/mtdsplit_bcm63xx.c + create mode 100644 drivers/mtd/mtdsplit/mtdsplit_bcm_wfi.c + create mode 100644 drivers/mtd/mtdsplit/mtdsplit_brnimage.c + create mode 100644 drivers/mtd/mtdsplit/mtdsplit_cfe_bootfs.c + create mode 100644 drivers/mtd/mtdsplit/mtdsplit_elf.c + create mode 100644 drivers/mtd/mtdsplit/mtdsplit_eva.c + create mode 100644 drivers/mtd/mtdsplit/mtdsplit_fit.c + create mode 100644 drivers/mtd/mtdsplit/mtdsplit_h3c_vfs.c + create mode 100644 drivers/mtd/mtdsplit/mtdsplit_jimage.c + create mode 100644 drivers/mtd/mtdsplit/mtdsplit_lzma.c + create mode 100644 drivers/mtd/mtdsplit/mtdsplit_minor.c + create mode 100644 drivers/mtd/mtdsplit/mtdsplit_mstc_boot.c + create mode 100644 drivers/mtd/mtdsplit/mtdsplit_seama.c + create mode 100644 drivers/mtd/mtdsplit/mtdsplit_seil.c + create mode 100644 drivers/mtd/mtdsplit/mtdsplit_squashfs.c + create mode 100644 drivers/mtd/mtdsplit/mtdsplit_tplink.c + create mode 100644 drivers/mtd/mtdsplit/mtdsplit_trx.c + create mode 100644 drivers/mtd/mtdsplit/mtdsplit_uimage.c + create mode 100644 drivers/mtd/mtdsplit/mtdsplit_wrgg.c + create mode 100644 drivers/mtd/nand/mtk_bmt.c + create mode 100644 drivers/mtd/nand/mtk_bmt.h + create mode 100644 drivers/mtd/nand/mtk_bmt_bbt.c + create mode 100644 drivers/mtd/nand/mtk_bmt_nmbm.c + create mode 100644 drivers/mtd/nand/mtk_bmt_v2.c + create mode 100644 drivers/mtd/parsers/routerbootpart.c + create mode 100644 drivers/net/dsa/an8855.c + create mode 100644 drivers/net/dsa/an8855.h + create mode 100644 drivers/net/mdio/mdio-an8855.c + create mode 100644 drivers/net/phy/adm6996.c + create mode 100644 drivers/net/phy/adm6996.h + create mode 100644 drivers/net/phy/air_an8855.c + create mode 100644 drivers/net/phy/ar8216.c + create mode 100644 drivers/net/phy/ar8216.h + create mode 100644 drivers/net/phy/ar8327.c + create mode 100644 drivers/net/phy/ar8327.h + create mode 100644 drivers/net/phy/b53/Kconfig + create mode 100644 drivers/net/phy/b53/Makefile + create mode 100644 drivers/net/phy/b53/b53_common.c + create mode 100644 drivers/net/phy/b53/b53_mdio.c + create mode 100644 drivers/net/phy/b53/b53_mmap.c + create mode 100644 drivers/net/phy/b53/b53_phy_fixup.c + create mode 100644 drivers/net/phy/b53/b53_priv.h + create mode 100644 drivers/net/phy/b53/b53_regs.h + create mode 100644 drivers/net/phy/b53/b53_spi.c + create mode 100644 drivers/net/phy/b53/b53_srab.c + create mode 100644 drivers/net/phy/en8801sc.c + create mode 100644 drivers/net/phy/en8801sc.h + create mode 100644 drivers/net/phy/ip17xx.c + create mode 100644 drivers/net/phy/psb6970.c + create mode 100644 drivers/net/phy/rtk/Makefile + create mode 100644 drivers/net/phy/rtk/rtl8367c/acl.c + create mode 100644 drivers/net/phy/rtk/rtl8367c/cpu.c + create mode 100644 drivers/net/phy/rtk/rtl8367c/dot1x.c + create mode 100644 drivers/net/phy/rtk/rtl8367c/eee.c + create mode 100644 drivers/net/phy/rtk/rtl8367c/i2c.c + create mode 100644 drivers/net/phy/rtk/rtl8367c/igmp.c + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/acl.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/cpu.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/dot1x.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/eee.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/i2c.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/igmp.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/interrupt.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/l2.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/leaky.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/led.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/mirror.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/oam.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/port.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/ptp.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/qos.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rate.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rldp.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtk_error.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtk_hal.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtk_switch.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtk_types.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_acl.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_cputag.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_dot1x.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_eav.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_eee.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_fc.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_green.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_hsb.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_i2c.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_igmp.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_inbwctrl.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_interrupt.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_led.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_lut.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_meter.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_mib.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_mii_mgr.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_mirror.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_misc.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_oam.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_phy.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_port.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_portIsolation.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_qos.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_rldp.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_rma.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_scheduling.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_storm.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_svlan.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_trunking.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_unknownMulticast.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_vlan.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_base.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_reg.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/smi.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/stat.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/storm.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/svlan.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/trap.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/trunk.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/include/vlan.h + create mode 100644 drivers/net/phy/rtk/rtl8367c/interrupt.c + create mode 100644 drivers/net/phy/rtk/rtl8367c/l2.c + create mode 100644 drivers/net/phy/rtk/rtl8367c/leaky.c + create mode 100644 drivers/net/phy/rtk/rtl8367c/led.c + create mode 100644 drivers/net/phy/rtk/rtl8367c/mirror.c + create mode 100644 drivers/net/phy/rtk/rtl8367c/oam.c + create mode 100644 drivers/net/phy/rtk/rtl8367c/port.c + create mode 100644 drivers/net/phy/rtk/rtl8367c/ptp.c + create mode 100644 drivers/net/phy/rtk/rtl8367c/qos.c + create mode 100644 drivers/net/phy/rtk/rtl8367c/rate.c + create mode 100644 drivers/net/phy/rtk/rtl8367c/rldp.c + create mode 100644 drivers/net/phy/rtk/rtl8367c/rtk_hal.c + create mode 100644 drivers/net/phy/rtk/rtl8367c/rtk_switch.c + create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv.c + create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_acl.c + create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_cputag.c + create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_dot1x.c + create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_eav.c + create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_eee.c + create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_fc.c + create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_green.c + create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_hsb.c + create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_i2c.c + create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_igmp.c + create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_inbwctrl.c + create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_interrupt.c + create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_led.c + create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_lut.c + create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_meter.c + create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_mib.c + create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_mirror.c + create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_misc.c + create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_oam.c + create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_phy.c + create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_port.c + create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_portIsolation.c + create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_qos.c + create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_rldp.c + create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_rma.c + create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_scheduling.c + create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_storm.c + create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_svlan.c + create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_trunking.c + create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_unknownMulticast.c + create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_vlan.c + create mode 100644 drivers/net/phy/rtk/rtl8367c/smi.c + create mode 100644 drivers/net/phy/rtk/rtl8367c/stat.c + create mode 100644 drivers/net/phy/rtk/rtl8367c/storm.c + create mode 100644 drivers/net/phy/rtk/rtl8367c/svlan.c + create mode 100644 drivers/net/phy/rtk/rtl8367c/trap.c + create mode 100644 drivers/net/phy/rtk/rtl8367c/trunk.c + create mode 100644 drivers/net/phy/rtk/rtl8367c/vlan.c + create mode 100644 drivers/net/phy/rtk/rtl8367s.c + create mode 100644 drivers/net/phy/rtk/rtl8367s_dbg.c + create mode 100644 drivers/net/phy/rtk/rtl8367s_mdio.c + create mode 100644 drivers/net/phy/rtl8261n/Kconfig + create mode 100644 drivers/net/phy/rtl8261n/Makefile + create mode 100644 drivers/net/phy/rtl8261n/construct/conf_rtl8261n_c.c + create mode 100644 drivers/net/phy/rtl8261n/construct/conf_rtl8264b.c + create mode 100644 drivers/net/phy/rtl8261n/error.h + create mode 100644 drivers/net/phy/rtl8261n/phy_patch.c + create mode 100644 drivers/net/phy/rtl8261n/phy_patch.h + create mode 100644 drivers/net/phy/rtl8261n/phy_rtl826xb_patch.c + create mode 100644 drivers/net/phy/rtl8261n/phy_rtl826xb_patch.h + create mode 100644 drivers/net/phy/rtl8261n/rtk_osal.c + create mode 100644 drivers/net/phy/rtl8261n/rtk_osal.h + create mode 100644 drivers/net/phy/rtl8261n/rtk_phy.c + create mode 100644 drivers/net/phy/rtl8261n/rtk_phylib.c + create mode 100644 drivers/net/phy/rtl8261n/rtk_phylib.h + create mode 100644 drivers/net/phy/rtl8261n/rtk_phylib_def.h + create mode 100644 drivers/net/phy/rtl8261n/rtk_phylib_rtl826xb.c + create mode 100644 drivers/net/phy/rtl8261n/rtk_phylib_rtl826xb.h + create mode 100644 drivers/net/phy/rtl8261n/type.h + create mode 100644 drivers/net/phy/rtl8306.c + create mode 100644 drivers/net/phy/rtl8366_smi.c + create mode 100644 drivers/net/phy/rtl8366_smi.h + create mode 100644 drivers/net/phy/rtl8366rb.c + create mode 100644 drivers/net/phy/rtl8366s.c + create mode 100644 drivers/net/phy/rtl8367.c + create mode 100644 drivers/net/phy/rtl8367b.c + create mode 100644 drivers/net/phy/swconfig.c + create mode 100644 drivers/net/phy/swconfig_leds.c + create mode 100644 drivers/nvmem/an8855-efuse.c + create mode 100644 drivers/platform/mikrotik/Kconfig + create mode 100644 drivers/platform/mikrotik/Makefile + create mode 100644 drivers/platform/mikrotik/rb_hardconfig.c + create mode 100644 drivers/platform/mikrotik/rb_hardconfig.h + create mode 100644 drivers/platform/mikrotik/rb_lz77.c + create mode 100644 drivers/platform/mikrotik/rb_lz77.h + create mode 100644 drivers/platform/mikrotik/rb_nvmem.c + create mode 100644 drivers/platform/mikrotik/rb_softconfig.c + create mode 100644 drivers/platform/mikrotik/routerboot.c + create mode 100644 drivers/platform/mikrotik/routerboot.h + create mode 100644 drivers/ssb/fallback-sprom.c + create mode 100644 drivers/ssb/fallback-sprom.h + create mode 100644 include/dt-bindings/mtd/partitions/uimage.h + create mode 100644 include/linux/ar8216_platform.h + create mode 100644 include/linux/ath5k_platform.h + create mode 100644 include/linux/mfd/airoha-an8855-mfd.h + create mode 100644 include/linux/mtd/mtk_bmt.h + create mode 100644 include/linux/myloader.h + create mode 100644 include/linux/platform_data/adm6996-gpio.h + create mode 100644 include/linux/routerboot.h + create mode 100644 include/linux/rtl8366.h + create mode 100644 include/linux/rtl8367.h + create mode 100644 include/linux/switch.h + create mode 100644 include/uapi/linux/switch.h + +diff --git a/Documentation/devicetree/bindings/mtd/partitions/openwrt,uimage.yaml b/Documentation/devicetree/bindings/mtd/partitions/openwrt,uimage.yaml +new file mode 100644 +index 000000000000..d052ab1fc981 +--- /dev/null ++++ b/Documentation/devicetree/bindings/mtd/partitions/openwrt,uimage.yaml +@@ -0,0 +1,91 @@ ++# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/mtd/partitions/openwrt,uimage.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: OpenWrt variations of U-Boot Image partitions ++ ++maintainers: ++ - Bjørn Mork ++ ++description: | ++ The image format defined by the boot loader "Das U-Boot" is often ++ modified or extended by device vendors. This defines a few optional ++ properties which can be used to describe such modifications. ++ ++# partition.txt defines common properties, but has not yet been ++# converted to YAML ++#allOf: ++# - $ref: ../partition.yaml# ++ ++properties: ++ compatible: ++ items: ++ - enum: ++ - openwrt,uimage ++ - const: denx,uimage ++ ++ openwrt,padding: ++ description: Number of padding bytes between header and data ++ $ref: /schemas/types.yaml#/definitions/uint32 ++ default: 0 ++ ++ openwrt,ih-magic: ++ description: U-Boot Image Header magic number. ++ $ref: /schemas/types.yaml#/definitions/uint32 ++ default: 0x27051956 # IH_MAGIC ++ ++ openwrt,ih-type: ++ description: U-Boot Image type ++ $ref: /schemas/types.yaml#/definitions/uint32 ++ default: 2 # IH_TYPE_KERNEL ++ ++ openwrt,offset: ++ description: ++ Offset between partition start and U-Boot Image in bytes ++ $ref: /schemas/types.yaml#/definitions/uint32 ++ default: 0 ++ ++ openwrt,partition-magic: ++ description: ++ Magic number found at the start of the partition. Will only be ++ validated if both this property and openwrt,offset is non-zero ++ $ref: /schemas/types.yaml#/definitions/uint32 ++ default: 0 ++ ++required: ++ - compatible ++ - reg ++ ++#unevaluatedProperties: false ++additionalProperties: false ++ ++examples: ++ - | ++ // device with non-default magic ++ partition@300000 { ++ compatible = "openwrt,uimage", "denx,uimage"; ++ reg = <0x00300000 0xe80000>; ++ label = "firmware"; ++ openwrt,ih-magic = <0x4e474520>; ++ }; ++ - | ++ // device with U-Boot Image at an offset, with a partition magic value ++ partition@70000 { ++ compatible = "openwrt,uimage", "denx,uimage"; ++ reg = <0x00070000 0x00790000>; ++ label = "firmware"; ++ openwrt,offset = <20>; ++ openwrt,partition-magic = <0x43535953>; ++ }; ++ - | ++ // device using a non-default image type ++ #include "dt-bindings/mtd/partitions/uimage.h" ++ partition@6c0000 { ++ compatible = "openwrt,uimage", "denx,uimage"; ++ reg = <0x6c0000 0x1900000>; ++ label = "firmware"; ++ openwrt,ih-magic = <0x33373033>; ++ openwrt,ih-type = ; ++ }; +diff --git a/Documentation/networking/adm6996.txt b/Documentation/networking/adm6996.txt +new file mode 100644 +index 000000000000..ab59f1df0337 +--- /dev/null ++++ b/Documentation/networking/adm6996.txt +@@ -0,0 +1,110 @@ ++------- ++ ++ADM6996FC / ADM6996M switch chip driver ++ ++ ++1. General information ++ ++ This driver supports the FC and M models only. The ADM6996F and L are ++ completely different chips. ++ ++ Support for the FC model is extremely limited at the moment. There is no VLAN ++ support as of yet. The driver will not offer an swconfig interface for the FC ++ chip. ++ ++1.1 VLAN IDs ++ ++ It is possible to define 16 different VLANs. Every VLAN has an identifier, its ++ VLAN ID. It is easiest if you use at most VLAN IDs 0-15. In that case, the ++ swconfig based configuration is very straightforward. To define two VLANs with ++ IDs 4 and 5, you can invoke, for example: ++ ++ # swconfig dev ethX vlan 4 set ports '0 1t 2 5t' ++ # swconfig dev ethX vlan 5 set ports '0t 1t 5t' ++ ++ The swconfig framework will automatically invoke 'port Y set pvid Z' for every ++ port that is an untagged member of VLAN Y, setting its Primary VLAN ID. In ++ this example, ports 0 and 2 would get "pvid 4". The Primary VLAN ID of a port ++ is the VLAN ID associated with untagged packets coming in on that port. ++ ++ But if you wish to use VLAN IDs outside the range 0-15, this automatic ++ behaviour of the swconfig framework becomes a problem. The 16 VLANs that ++ swconfig can configure on the ADM6996 also have a "vid" setting. By default, ++ this is the same as the number of the VLAN entry, to make the simple behaviour ++ above possible. To still support a VLAN with a VLAN ID higher than 15 ++ (presumably because you are in a network where such VLAN IDs are already in ++ use), you can change the "vid" setting of the VLAN to anything in the range ++ 0-1023. But suppose you did the following: ++ ++ # swconfig dev ethX vlan 0 set vid 998 ++ # swconfig dev ethX vlan 0 set ports '0 2 5t' ++ ++ Now the swconfig framework will issue 'port 0 set pvid 0' and 'port 2 set pvid ++ 0'. But the "pvid" should be set to 998, so you are responsible for manually ++ fixing this! ++ ++1.2 VLAN filtering ++ ++ The switch is configured to apply source port filtering. This means that ++ packets are only accepted when the port the packets came in on is a member of ++ the VLAN the packet should go to. ++ ++ Only membership of a VLAN is tested, it does not matter whether it is a tagged ++ or untagged membership. ++ ++ For untagged packets, the destination VLAN is the Primary VLAN ID of the ++ incoming port. So if the PVID of a port is 0, but that port is not a member of ++ the VLAN with ID 0, this means that untagged packets on that port are dropped. ++ This can be used as a roundabout way of dropping untagged packets from a port, ++ a mode often referred to as "Admit only tagged packets". ++ ++1.3 Reset ++ ++ The two supported chip models do not have a sofware-initiated reset. When the ++ driver is initialised, as well as when the 'reset' swconfig option is invoked, ++ the driver will set those registers it knows about and supports to the correct ++ default value. But there are a lot of registers in the chip that the driver ++ does not support. If something changed those registers, invoking 'reset' or ++ performing a warm reboot might still leave the chip in a "broken" state. Only ++ a hardware reset will bring it back in the default state. ++ ++2. Technical details on PHYs and the ADM6996 ++ ++ From the viewpoint of the Linux kernel, it is common that an Ethernet adapter ++ can be seen as a separate MAC entity and a separate PHY entity. The PHY entity ++ can be queried and set through registers accessible via an MDIO bus. A PHY ++ normally has a single address on that bus, in the range 0 through 31. ++ ++ The ADM6996 has special-purpose registers in the range of PHYs 0 through 10. ++ Even though all these registers control a single ADM6996 chip, the Linux ++ kernel treats this as 11 separate PHYs. The driver will bind to these ++ addresses to prevent a different PHY driver from binding and corrupting these ++ registers. ++ ++ What Linux sees as the PHY on address 0 is meant for the Ethernet MAC ++ connected to the CPU port of the ADM6996 switch chip (port 5). This is the ++ Ethernet MAC you will use to send and receive data through the switch. ++ ++ The PHYs at addresses 16 through 20 map to the PHYs on ports 0 through 4 of ++ the switch chip. These can be accessed with the Generic PHY driver, as the ++ registers have the common layout. ++ ++ If a second Ethernet MAC on your board is wired to the port 4 PHY, that MAC ++ needs to bind to PHY address 20 for the port to work correctly. ++ ++ The ADM6996 switch driver will reset the ports 0 through 3 on startup and when ++ 'reset' is invoked. This could clash with a different PHY driver if the kernel ++ binds a PHY driver to address 16 through 19. ++ ++ If Linux binds a PHY on addresses 1 through 10 to an Ethernet MAC, the ADM6996 ++ driver will simply always report a connected 100 Mbit/s full-duplex link for ++ that PHY, and provide no other functionality. This is most likely not what you ++ want. So if you see a message in your log ++ ++ ethX: PHY overlaps ADM6996, providing fixed PHY yy. ++ ++ This is most likely an indication that ethX will not work properly, and your ++ kernel needs to be configured to attach a different PHY to that Ethernet MAC. ++ ++ Controlling the mapping between MACs and PHYs is usually done in platform- or ++ board-specific fixup code. The ADM6996 driver has no influence over this. +diff --git a/arch/arm64/boot/dts/mediatek/mt7981-rfb-mxl-2p5g-phy-eth1.dtso b/arch/arm64/boot/dts/mediatek/mt7981-rfb-mxl-2p5g-phy-eth1.dtso +new file mode 100644 +index 000000000000..51d5dc661ad6 +--- /dev/null ++++ b/arch/arm64/boot/dts/mediatek/mt7981-rfb-mxl-2p5g-phy-eth1.dtso +@@ -0,0 +1,34 @@ ++/* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */ ++/dts-v1/; ++/plugin/; ++ ++#include ++ ++/ { ++ compatible = "mediatek,mt7981-rfb", "mediatek,mt7981"; ++ ++ fragment@0 { ++ target = <&gmac1>; ++ __overlay__ { ++ phy-mode = "2500base-x"; ++ phy-handle = <&phy5>; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&mdio_bus>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reset-gpios = <&pio 14 GPIO_ACTIVE_LOW>; ++ reset-delay-us = <600>; ++ reset-post-delay-us = <20000>; ++ ++ phy5: ethernet-phy@5 { ++ reg = <5>; ++ compatible = "ethernet-phy-ieee802.3-c45"; ++ phy-mode = "2500base-x"; ++ }; ++ }; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/mediatek/mt7981-rfb-mxl-2p5g-phy-swp5.dtso b/arch/arm64/boot/dts/mediatek/mt7981-rfb-mxl-2p5g-phy-swp5.dtso +new file mode 100644 +index 000000000000..4cc3cf1df6cf +--- /dev/null ++++ b/arch/arm64/boot/dts/mediatek/mt7981-rfb-mxl-2p5g-phy-swp5.dtso +@@ -0,0 +1,35 @@ ++/* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */ ++/dts-v1/; ++/plugin/; ++ ++#include ++ ++/ { ++ compatible = "mediatek,mt7981-rfb", "mediatek,mt7981"; ++ ++ fragment@0 { ++ target = <&sw_p5>; ++ __overlay__ { ++ phy-mode = "2500base-x"; ++ phy-handle = <&phy5>; ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&mdio_bus>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reset-gpios = <&pio 14 GPIO_ACTIVE_LOW>; ++ reset-delay-us = <600>; ++ reset-post-delay-us = <20000>; ++ ++ phy5: ethernet-phy@5 { ++ reg = <5>; ++ compatible = "ethernet-phy-ieee802.3-c45"; ++ phy-mode = "2500base-x"; ++ }; ++ }; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/mediatek/mt7981-rfb-spim-nand.dtso b/arch/arm64/boot/dts/mediatek/mt7981-rfb-spim-nand.dtso +new file mode 100644 +index 000000000000..af4845ec6cff +--- /dev/null ++++ b/arch/arm64/boot/dts/mediatek/mt7981-rfb-spim-nand.dtso +@@ -0,0 +1,78 @@ ++/* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "mediatek,mt7981-rfb", "mediatek,mt7981"; ++ ++ fragment@0 { ++ target = <&chosen>; ++ rootdisk-spim-nand = <&ubi_rootdisk>; ++ }; ++ ++ fragment@1 { ++ target = <&spi0>; ++ __overlay__ { ++ status = "okay"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ spi_nand: spi_nand@1 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "spi-nand"; ++ reg = <1>; ++ spi-max-frequency = <10000000>; ++ spi-tx-bus-width = <4>; ++ spi-rx-bus-width = <4>; ++ ++ partitions { ++ compatible = "fixed-partitions"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ partition@0 { ++ label = "BL2"; ++ reg = <0x00000 0x0100000>; ++ read-only; ++ }; ++ ++ partition@100000 { ++ label = "u-boot-env"; ++ reg = <0x0100000 0x0080000>; ++ }; ++ ++ factory: partition@180000 { ++ label = "Factory"; ++ reg = <0x180000 0x0200000>; ++ }; ++ ++ partition@380000 { ++ label = "FIP"; ++ reg = <0x380000 0x0200000>; ++ }; ++ ++ partition@580000 { ++ label = "ubi"; ++ reg = <0x580000 0x4000000>; ++ compatible = "linux,ubi"; ++ ++ volumes { ++ ubi_rootdisk: ubi-volume-fit { ++ volname = "fit"; ++ }; ++ }; ++ }; ++ }; ++ }; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&wifi>; ++ __overlay__ { ++ mediatek,mtd-eeprom = <&factory 0x0>; ++ status = "okay"; ++ }; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/mediatek/mt7981-rfb.dts b/arch/arm64/boot/dts/mediatek/mt7981-rfb.dts +new file mode 100644 +index 000000000000..155157762479 +--- /dev/null ++++ b/arch/arm64/boot/dts/mediatek/mt7981-rfb.dts +@@ -0,0 +1,189 @@ ++// SPDX-License-Identifier: (GPL-2.0 OR MIT) ++/* ++ * Copyright (C) 2022 MediaTek Inc. ++ * Author: Sam.Shih ++ */ ++ ++/dts-v1/; ++#include "mt7981b.dtsi" ++ ++/ { ++ model = "MediaTek MT7981 RFB"; ++ compatible = "mediatek,mt7981-rfb", "mediatek,mt7981"; ++ ++ aliases { ++ serial0 = &uart0; ++ }; ++ ++ chosen: chosen { ++ stdout-path = "serial0:115200n8"; ++ bootargs-append = " root=/dev/fit0 rootwait"; ++ }; ++ ++ memory@40000000 { ++ reg = <0 0x40000000 0 0x20000000>; ++ device_type = "memory"; ++ }; ++ ++ reg_3p3v: regulator-3p3v { ++ compatible = "regulator-fixed"; ++ regulator-name = "fixed-3.3V"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ reg_5v: regulator-5v { ++ compatible = "regulator-fixed"; ++ regulator-name = "fixed-5V"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ gpio-keys { ++ compatible = "gpio-keys"; ++ reset { ++ label = "reset"; ++ linux,code = ; ++ gpios = <&pio 1 GPIO_ACTIVE_LOW>; ++ }; ++ wps { ++ label = "wps"; ++ linux,code = ; ++ gpios = <&pio 0 GPIO_ACTIVE_HIGH>; ++ }; ++ }; ++}; ++ ++ð { ++ status = "okay"; ++ ++ gmac0: mac@0 { ++ compatible = "mediatek,eth-mac"; ++ reg = <0>; ++ phy-mode = "2500base-x"; ++ ++ fixed-link { ++ speed = <2500>; ++ full-duplex; ++ pause; ++ }; ++ }; ++ ++ gmac1: mac@1 { ++ compatible = "mediatek,eth-mac"; ++ reg = <1>; ++ phy-mode = "gmii"; ++ phy-handle = <&int_gbe_phy>; ++ }; ++}; ++ ++&mdio_bus { ++ switch: switch@1f { ++ compatible = "mediatek,mt7531"; ++ reg = <31>; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ interrupt-parent = <&pio>; ++ interrupts = <38 IRQ_TYPE_LEVEL_HIGH>; ++ reset-gpios = <&pio 5 GPIO_ACTIVE_HIGH>; ++ }; ++}; ++ ++&crypto { ++ status = "okay"; ++}; ++ ++&pio { ++ spi0_flash_pins: spi0-pins { ++ mux { ++ function = "spi"; ++ groups = "spi0", "spi0_wp_hold"; ++ }; ++ conf-pu { ++ pins = "SPI0_CS", "SPI0_HOLD", "SPI0_WP"; ++ drive-strength = ; ++ bias-pull-up = ; ++ }; ++ conf-pd { ++ pins = "SPI0_CLK", "SPI0_MOSI", "SPI0_MISO"; ++ drive-strength = ; ++ bias-pull-down = ; ++ }; ++ }; ++ ++}; ++ ++&spi0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spi0_flash_pins>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++}; ++ ++&switch { ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ reg = <0>; ++ label = "lan1"; ++ }; ++ ++ port@1 { ++ reg = <1>; ++ label = "lan2"; ++ }; ++ ++ port@2 { ++ reg = <2>; ++ label = "lan3"; ++ }; ++ ++ port@3 { ++ reg = <3>; ++ label = "lan4"; ++ }; ++ ++ sw_p5: port@5 { ++ reg = <5>; ++ label = "lan5"; ++ status = "disabled"; ++ }; ++ ++ port@6 { ++ reg = <6>; ++ ethernet = <&gmac0>; ++ phy-mode = "2500base-x"; ++ ++ fixed-link { ++ speed = <2500>; ++ full-duplex; ++ pause; ++ }; ++ }; ++ }; ++}; ++ ++&xhci { ++ vusb33-supply = <®_3p3v>; ++ vbus-supply = <®_5v>; ++ status = "okay"; ++}; ++ ++&uart0 { ++ status = "okay"; ++}; ++ ++&usb_phy { ++ status = "okay"; ++}; ++ ++&watchdog { ++ status = "okay"; ++}; +diff --git a/arch/arm64/boot/dts/mediatek/mt7986a-rfb-spim-nand.dts b/arch/arm64/boot/dts/mediatek/mt7986a-rfb-spim-nand.dts +new file mode 100644 +index 000000000000..479a5ca2fc4d +--- /dev/null ++++ b/arch/arm64/boot/dts/mediatek/mt7986a-rfb-spim-nand.dts +@@ -0,0 +1,52 @@ ++/* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */ ++ ++#include "mt7986a-rfb.dtsi" ++ ++/ { ++ compatible = "mediatek,mt7986a-rfb-snand"; ++}; ++ ++&spi0 { ++ status = "okay"; ++ ++ spi_nand: spi_nand@1 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "spi-nand"; ++ reg = <1>; ++ spi-max-frequency = <10000000>; ++ spi-tx-bus-width = <4>; ++ spi-rx-bus-width = <4>; ++ ++ partitions { ++ compatible = "fixed-partitions"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ partition@0 { ++ label = "BL2"; ++ reg = <0x00000 0x0100000>; ++ read-only; ++ }; ++ partition@100000 { ++ label = "u-boot-env"; ++ reg = <0x0100000 0x0080000>; ++ }; ++ factory: partition@180000 { ++ label = "Factory"; ++ reg = <0x180000 0x0200000>; ++ }; ++ partition@380000 { ++ label = "FIP"; ++ reg = <0x380000 0x0200000>; ++ }; ++ partition@580000 { ++ label = "ubi"; ++ reg = <0x580000 0x4000000>; ++ }; ++ }; ++ }; ++}; ++ ++&wifi { ++ mediatek,mtd-eeprom = <&factory 0>; ++}; +diff --git a/arch/arm64/boot/dts/mediatek/mt7986a-rfb-spim-nor.dts b/arch/arm64/boot/dts/mediatek/mt7986a-rfb-spim-nor.dts +new file mode 100644 +index 000000000000..ea148315f055 +--- /dev/null ++++ b/arch/arm64/boot/dts/mediatek/mt7986a-rfb-spim-nor.dts +@@ -0,0 +1,51 @@ ++/* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */ ++ ++#include "mt7986a-rfb.dtsi" ++ ++/ { ++ compatible = "mediatek,mt7986a-rfb-snor"; ++}; ++ ++&spi0 { ++ status = "okay"; ++ ++ spi_nor: spi_nor@0 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "jedec,spi-nor"; ++ reg = <0>; ++ spi-max-frequency = <52000000>; ++ spi-tx-bus-width = <4>; ++ spi-rx-bus-width = <4>; ++ partitions { ++ compatible = "fixed-partitions"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ partition@00000 { ++ label = "BL2"; ++ reg = <0x00000 0x0040000>; ++ }; ++ partition@40000 { ++ label = "u-boot-env"; ++ reg = <0x40000 0x0010000>; ++ }; ++ factory: partition@50000 { ++ label = "Factory"; ++ reg = <0x50000 0x00B0000>; ++ }; ++ partition@100000 { ++ label = "FIP"; ++ reg = <0x100000 0x0080000>; ++ }; ++ partition@180000 { ++ label = "firmware"; ++ reg = <0x180000 0xE00000>; ++ }; ++ }; ++ }; ++}; ++ ++&wifi { ++ mediatek,mtd-eeprom = <&factory 0>; ++}; +diff --git a/arch/arm64/boot/dts/mediatek/mt7986a-rfb.dtsi b/arch/arm64/boot/dts/mediatek/mt7986a-rfb.dtsi +new file mode 100644 +index 000000000000..1dfb64d4565e +--- /dev/null ++++ b/arch/arm64/boot/dts/mediatek/mt7986a-rfb.dtsi +@@ -0,0 +1,391 @@ ++// SPDX-License-Identifier: (GPL-2.0 OR MIT) ++/* ++ * Copyright (C) 2021 MediaTek Inc. ++ * Author: Sam.Shih ++ */ ++ ++/dts-v1/; ++#include ++#include ++#include "mt7986a.dtsi" ++ ++/ { ++ model = "MediaTek MT7986a RFB"; ++ compatible = "mediatek,mt7986a-rfb"; ++ ++ aliases { ++ serial0 = &uart0; ++ }; ++ ++ chosen { ++ stdout-path = "serial0:115200n8"; ++ }; ++ ++ memory@40000000 { ++ reg = <0 0x40000000 0 0x40000000>; ++ device_type = "memory"; ++ }; ++ ++ reg_1p8v: regulator-1p8v { ++ compatible = "regulator-fixed"; ++ regulator-name = "fixed-1.8V"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ reg_3p3v: regulator-3p3v { ++ compatible = "regulator-fixed"; ++ regulator-name = "fixed-3.3V"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ reg_5v: regulator-5v { ++ compatible = "regulator-fixed"; ++ regulator-name = "fixed-5V"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++}; ++ ++ð { ++ status = "okay"; ++ ++ gmac0: mac@0 { ++ compatible = "mediatek,eth-mac"; ++ reg = <0>; ++ phy-mode = "2500base-x"; ++ ++ fixed-link { ++ speed = <2500>; ++ full-duplex; ++ pause; ++ }; ++ }; ++ ++ gmac1: mac@1 { ++ compatible = "mediatek,eth-mac"; ++ reg = <1>; ++ phy-mode = "2500base-x"; ++ }; ++ ++ mdio: mdio-bus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ }; ++}; ++ ++&wifi { ++ status = "okay"; ++ pinctrl-names = "default", "dbdc"; ++ pinctrl-0 = <&wf_2g_5g_pins>; ++ pinctrl-1 = <&wf_dbdc_pins>; ++}; ++ ++&mdio { ++ phy5: phy@5 { ++ compatible = "ethernet-phy-id67c9.de0a"; ++ reg = <5>; ++ ++ reset-gpios = <&pio 6 GPIO_ACTIVE_LOW>; ++ reset-deassert-us = <20000>; ++ }; ++ ++ phy6: phy@6 { ++ compatible = "ethernet-phy-id67c9.de0a"; ++ reg = <6>; ++ }; ++ ++ switch: switch@1f { ++ compatible = "mediatek,mt7531"; ++ reg = <31>; ++ reset-gpios = <&pio 5 GPIO_ACTIVE_HIGH>; ++ }; ++}; ++ ++&crypto { ++ status = "okay"; ++}; ++ ++&mmc0 { ++ pinctrl-names = "default", "state_uhs"; ++ pinctrl-0 = <&mmc0_pins_default>; ++ pinctrl-1 = <&mmc0_pins_uhs>; ++ bus-width = <8>; ++ max-frequency = <200000000>; ++ cap-mmc-highspeed; ++ mmc-hs200-1_8v; ++ mmc-hs400-1_8v; ++ hs400-ds-delay = <0x14014>; ++ vmmc-supply = <®_3p3v>; ++ vqmmc-supply = <®_1p8v>; ++ non-removable; ++ no-sd; ++ no-sdio; ++ status = "okay"; ++}; ++ ++&pcie { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pcie_pins>; ++ status = "okay"; ++}; ++ ++&pcie_phy { ++ status = "okay"; ++}; ++ ++&pio { ++ mmc0_pins_default: mmc0-pins { ++ mux { ++ function = "emmc"; ++ groups = "emmc_51"; ++ }; ++ conf-cmd-dat { ++ pins = "EMMC_DATA_0", "EMMC_DATA_1", "EMMC_DATA_2", ++ "EMMC_DATA_3", "EMMC_DATA_4", "EMMC_DATA_5", ++ "EMMC_DATA_6", "EMMC_DATA_7", "EMMC_CMD"; ++ input-enable; ++ drive-strength = ; ++ bias-pull-up = ; /* pull-up 10K */ ++ }; ++ conf-clk { ++ pins = "EMMC_CK"; ++ drive-strength = ; ++ bias-pull-down = ; /* pull-down 50K */ ++ }; ++ conf-ds { ++ pins = "EMMC_DSL"; ++ bias-pull-down = ; /* pull-down 50K */ ++ }; ++ conf-rst { ++ pins = "EMMC_RSTB"; ++ drive-strength = ; ++ bias-pull-up = ; /* pull-up 10K */ ++ }; ++ }; ++ ++ mmc0_pins_uhs: mmc0-uhs-pins { ++ mux { ++ function = "emmc"; ++ groups = "emmc_51"; ++ }; ++ conf-cmd-dat { ++ pins = "EMMC_DATA_0", "EMMC_DATA_1", "EMMC_DATA_2", ++ "EMMC_DATA_3", "EMMC_DATA_4", "EMMC_DATA_5", ++ "EMMC_DATA_6", "EMMC_DATA_7", "EMMC_CMD"; ++ input-enable; ++ drive-strength = ; ++ bias-pull-up = ; /* pull-up 10K */ ++ }; ++ conf-clk { ++ pins = "EMMC_CK"; ++ drive-strength = ; ++ bias-pull-down = ; /* pull-down 50K */ ++ }; ++ conf-ds { ++ pins = "EMMC_DSL"; ++ bias-pull-down = ; /* pull-down 50K */ ++ }; ++ conf-rst { ++ pins = "EMMC_RSTB"; ++ drive-strength = ; ++ bias-pull-up = ; /* pull-up 10K */ ++ }; ++ }; ++ ++ pcie_pins: pcie-pins { ++ mux { ++ function = "pcie"; ++ groups = "pcie_clk", "pcie_wake", "pcie_pereset"; ++ }; ++ }; ++ ++ spic_pins_g2: spic-pins-29-to-32 { ++ mux { ++ function = "spi"; ++ groups = "spi1_2"; ++ }; ++ }; ++ ++ spi_flash_pins: spi-flash-pins-33-to-38 { ++ mux { ++ function = "spi"; ++ groups = "spi0", "spi0_wp_hold"; ++ }; ++ conf-pu { ++ pins = "SPI2_CS", "SPI2_HOLD", "SPI2_WP"; ++ drive-strength = ; ++ bias-disable; /* bias-disable */ ++ }; ++ conf-pd { ++ pins = "SPI2_CLK", "SPI2_MOSI", "SPI2_MISO"; ++ drive-strength = ; ++ bias-disable; /* bias-disable */ ++ }; ++ }; ++ ++ uart1_pins: uart1-pins { ++ mux { ++ function = "uart"; ++ groups = "uart1"; ++ }; ++ }; ++ ++ uart2_pins: uart2-pins { ++ mux { ++ function = "uart"; ++ groups = "uart2"; ++ }; ++ }; ++ ++ wf_2g_5g_pins: wf_2g_5g-pins { ++ mux { ++ function = "wifi"; ++ groups = "wf_2g", "wf_5g"; ++ }; ++ conf { ++ pins = "WF0_HB1", "WF0_HB2", "WF0_HB3", "WF0_HB4", ++ "WF0_HB0", "WF0_HB0_B", "WF0_HB5", "WF0_HB6", ++ "WF0_HB7", "WF0_HB8", "WF0_HB9", "WF0_HB10", ++ "WF0_TOP_CLK", "WF0_TOP_DATA", "WF1_HB1", ++ "WF1_HB2", "WF1_HB3", "WF1_HB4", "WF1_HB0", ++ "WF1_HB5", "WF1_HB6", "WF1_HB7", "WF1_HB8", ++ "WF1_TOP_CLK", "WF1_TOP_DATA"; ++ drive-strength = ; ++ }; ++ }; ++ ++ wf_dbdc_pins: wf_dbdc-pins { ++ mux { ++ function = "wifi"; ++ groups = "wf_dbdc"; ++ }; ++ conf { ++ pins = "WF0_HB1", "WF0_HB2", "WF0_HB3", "WF0_HB4", ++ "WF0_HB0", "WF0_HB0_B", "WF0_HB5", "WF0_HB6", ++ "WF0_HB7", "WF0_HB8", "WF0_HB9", "WF0_HB10", ++ "WF0_TOP_CLK", "WF0_TOP_DATA", "WF1_HB1", ++ "WF1_HB2", "WF1_HB3", "WF1_HB4", "WF1_HB0", ++ "WF1_HB5", "WF1_HB6", "WF1_HB7", "WF1_HB8", ++ "WF1_TOP_CLK", "WF1_TOP_DATA"; ++ drive-strength = ; ++ }; ++ }; ++}; ++ ++&spi0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spi_flash_pins>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++}; ++ ++&spi1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spic_pins_g2>; ++ status = "okay"; ++ ++ proslic_spi: proslic_spi@0 { ++ compatible = "silabs,proslic_spi"; ++ reg = <0>; ++ spi-max-frequency = <10000000>; ++ spi-cpha = <1>; ++ spi-cpol = <1>; ++ channel_count = <1>; ++ debug_level = <4>; /* 1 = TRC, 2 = DBG, 4 = ERR */ ++ reset-gpios = <&pio 7 GPIO_ACTIVE_HIGH>; ++ ig,enable-spi = <1>; /* 1: Enable, 0: Disable */ ++ }; ++}; ++ ++&gmac1 { ++ phy-mode = "2500base-x"; ++ phy-connection-type = "2500base-x"; ++ phy-handle = <&phy6>; ++}; ++ ++&switch { ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ reg = <0>; ++ label = "lan1"; ++ }; ++ ++ port@1 { ++ reg = <1>; ++ label = "lan2"; ++ }; ++ ++ port@2 { ++ reg = <2>; ++ label = "lan3"; ++ }; ++ ++ port@3 { ++ reg = <3>; ++ label = "lan4"; ++ }; ++ ++ port@4 { ++ reg = <4>; ++ label = "wan"; ++ }; ++ ++ port@5 { ++ reg = <5>; ++ label = "lan6"; ++ ++ phy-mode = "2500base-x"; ++ phy-handle = <&phy5>; ++ }; ++ ++ port@6 { ++ reg = <6>; ++ ethernet = <&gmac0>; ++ phy-mode = "2500base-x"; ++ ++ fixed-link { ++ speed = <2500>; ++ full-duplex; ++ pause; ++ }; ++ }; ++ }; ++}; ++ ++&ssusb { ++ vusb33-supply = <®_3p3v>; ++ vbus-supply = <®_5v>; ++ status = "okay"; ++}; ++ ++&uart0 { ++ status = "okay"; ++}; ++ ++&uart1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&uart1_pins>; ++ status = "okay"; ++}; ++ ++&uart2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&uart2_pins>; ++ status = "okay"; ++}; ++ ++&usb_phy { ++ status = "okay"; ++}; +diff --git a/arch/mips/fw/myloader/Makefile b/arch/mips/fw/myloader/Makefile +new file mode 100644 +index 000000000000..34acfd01cc0a +--- /dev/null ++++ b/arch/mips/fw/myloader/Makefile +@@ -0,0 +1,5 @@ ++# ++# Makefile for the Compex's MyLoader support on MIPS architecture ++# ++ ++lib-y += myloader.o +diff --git a/arch/mips/fw/myloader/myloader.c b/arch/mips/fw/myloader/myloader.c +new file mode 100644 +index 000000000000..a26f9ad3fdbf +--- /dev/null ++++ b/arch/mips/fw/myloader/myloader.c +@@ -0,0 +1,63 @@ ++/* ++ * Compex's MyLoader specific prom routines ++ * ++ * Copyright (C) 2007-2008 Gabor Juhos ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#define SYS_PARAMS_ADDR KSEG1ADDR(0x80000800) ++#define BOARD_PARAMS_ADDR KSEG1ADDR(0x80000A00) ++#define PART_TABLE_ADDR KSEG1ADDR(0x80000C00) ++#define BOOT_PARAMS_ADDR KSEG1ADDR(0x80000E00) ++ ++static struct myloader_info myloader_info __initdata; ++static int myloader_found __initdata; ++ ++struct myloader_info * __init myloader_get_info(void) ++{ ++ struct mylo_system_params *sysp; ++ struct mylo_board_params *boardp; ++ struct mylo_partition_table *parts; ++ ++ if (myloader_found) ++ return &myloader_info; ++ ++ sysp = (struct mylo_system_params *)(SYS_PARAMS_ADDR); ++ boardp = (struct mylo_board_params *)(BOARD_PARAMS_ADDR); ++ parts = (struct mylo_partition_table *)(PART_TABLE_ADDR); ++ ++ printk(KERN_DEBUG "MyLoader: sysp=%08x, boardp=%08x, parts=%08x\n", ++ sysp->magic, boardp->magic, parts->magic); ++ ++ /* Check for some magic numbers */ ++ if (sysp->magic != MYLO_MAGIC_SYS_PARAMS || ++ boardp->magic != MYLO_MAGIC_BOARD_PARAMS || ++ le32_to_cpu(parts->magic) != MYLO_MAGIC_PARTITIONS) ++ return NULL; ++ ++ printk(KERN_DEBUG "MyLoader: id=%04x:%04x, sub_id=%04x:%04x\n", ++ sysp->vid, sysp->did, sysp->svid, sysp->sdid); ++ ++ myloader_info.vid = sysp->vid; ++ myloader_info.did = sysp->did; ++ myloader_info.svid = sysp->svid; ++ myloader_info.sdid = sysp->sdid; ++ ++ memcpy(myloader_info.macs, boardp->addr, sizeof(myloader_info.macs)); ++ ++ myloader_found = 1; ++ ++ return &myloader_info; ++} +diff --git a/drivers/bcma/fallback-sprom.c b/drivers/bcma/fallback-sprom.c +new file mode 100644 +index 000000000000..6932c3c8f574 +--- /dev/null ++++ b/drivers/bcma/fallback-sprom.c +@@ -0,0 +1,534 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * BCMA Fallback SPROM Driver ++ * ++ * Copyright (C) 2020 Ãlvaro Fernández Rojas ++ * Copyright (C) 2014 Jonas Gorski ++ * Copyright (C) 2008 Maxime Bizon ++ * Copyright (C) 2008 Florian Fainelli ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "fallback-sprom.h" ++ ++#define BCMA_FBS_MAX_SIZE 468 ++ ++/* SPROM Extraction */ ++#define SPOFF(offset) ((offset) / sizeof(u16)) ++ ++#define SPEX(_outvar, _offset, _mask, _shift) \ ++ out->_outvar = ((in[SPOFF(_offset)] & (_mask)) >> (_shift)) ++ ++#define SPEX32(_outvar, _offset, _mask, _shift) \ ++ out->_outvar = ((((u32)in[SPOFF((_offset)+2)] << 16 | \ ++ in[SPOFF(_offset)]) & (_mask)) >> (_shift)) ++ ++#define SPEX_ARRAY8(_field, _offset, _mask, _shift) \ ++ do { \ ++ SPEX(_field[0], _offset + 0, _mask, _shift); \ ++ SPEX(_field[1], _offset + 2, _mask, _shift); \ ++ SPEX(_field[2], _offset + 4, _mask, _shift); \ ++ SPEX(_field[3], _offset + 6, _mask, _shift); \ ++ SPEX(_field[4], _offset + 8, _mask, _shift); \ ++ SPEX(_field[5], _offset + 10, _mask, _shift); \ ++ SPEX(_field[6], _offset + 12, _mask, _shift); \ ++ SPEX(_field[7], _offset + 14, _mask, _shift); \ ++ } while (0) ++ ++struct bcma_fbs { ++ struct device *dev; ++ struct list_head list; ++ struct ssb_sprom sprom; ++ u32 pci_bus; ++ u32 pci_dev; ++ bool devid_override; ++}; ++ ++static DEFINE_SPINLOCK(bcma_fbs_lock); ++static struct list_head bcma_fbs_list = LIST_HEAD_INIT(bcma_fbs_list); ++ ++int bcma_get_fallback_sprom(struct bcma_bus *bus, struct ssb_sprom *out) ++{ ++ struct bcma_fbs *pos; ++ u32 pci_bus, pci_dev; ++ ++ if (bus->hosttype != BCMA_HOSTTYPE_PCI) ++ return -ENOENT; ++ ++ pci_bus = bus->host_pci->bus->number; ++ pci_dev = PCI_SLOT(bus->host_pci->devfn); ++ ++ list_for_each_entry(pos, &bcma_fbs_list, list) { ++ if (pos->pci_bus != pci_bus || ++ pos->pci_dev != pci_dev) ++ continue; ++ ++ if (pos->devid_override) ++ bus->host_pci->device = pos->sprom.dev_id; ++ ++ memcpy(out, &pos->sprom, sizeof(struct ssb_sprom)); ++ dev_info(pos->dev, "requested by [%x:%x]", ++ pos->pci_bus, pos->pci_dev); ++ ++ return 0; ++ } ++ ++ pr_err("unable to fill SPROM for [%x:%x]\n", pci_bus, pci_dev); ++ ++ return -EINVAL; ++} ++ ++static s8 sprom_extract_antgain(const u16 *in, u16 offset, u16 mask, u16 shift) ++{ ++ u16 v; ++ u8 gain; ++ ++ v = in[SPOFF(offset)]; ++ gain = (v & mask) >> shift; ++ if (gain == 0xFF) { ++ gain = 8; /* If unset use 2dBm */ ++ } else { ++ /* Q5.2 Fractional part is stored in 0xC0 */ ++ gain = ((gain & 0xC0) >> 6) | ((gain & 0x3F) << 2); ++ } ++ ++ return (s8)gain; ++} ++ ++static void sprom_extract_r8(struct ssb_sprom *out, const u16 *in) ++{ ++ static const u16 pwr_info_offset[] = { ++ SSB_SROM8_PWR_INFO_CORE0, SSB_SROM8_PWR_INFO_CORE1, ++ SSB_SROM8_PWR_INFO_CORE2, SSB_SROM8_PWR_INFO_CORE3 ++ }; ++ u16 o; ++ int i; ++ ++ BUILD_BUG_ON(ARRAY_SIZE(pwr_info_offset) != ++ ARRAY_SIZE(out->core_pwr_info)); ++ ++ SPEX(board_rev, SSB_SPROM8_BOARDREV, ~0, 0); ++ SPEX(board_type, SSB_SPROM1_SPID, ~0, 0); ++ ++ SPEX(txpid2g[0], SSB_SPROM4_TXPID2G01, SSB_SPROM4_TXPID2G0, ++ SSB_SPROM4_TXPID2G0_SHIFT); ++ SPEX(txpid2g[1], SSB_SPROM4_TXPID2G01, SSB_SPROM4_TXPID2G1, ++ SSB_SPROM4_TXPID2G1_SHIFT); ++ SPEX(txpid2g[2], SSB_SPROM4_TXPID2G23, SSB_SPROM4_TXPID2G2, ++ SSB_SPROM4_TXPID2G2_SHIFT); ++ SPEX(txpid2g[3], SSB_SPROM4_TXPID2G23, SSB_SPROM4_TXPID2G3, ++ SSB_SPROM4_TXPID2G3_SHIFT); ++ ++ SPEX(txpid5gl[0], SSB_SPROM4_TXPID5GL01, SSB_SPROM4_TXPID5GL0, ++ SSB_SPROM4_TXPID5GL0_SHIFT); ++ SPEX(txpid5gl[1], SSB_SPROM4_TXPID5GL01, SSB_SPROM4_TXPID5GL1, ++ SSB_SPROM4_TXPID5GL1_SHIFT); ++ SPEX(txpid5gl[2], SSB_SPROM4_TXPID5GL23, SSB_SPROM4_TXPID5GL2, ++ SSB_SPROM4_TXPID5GL2_SHIFT); ++ SPEX(txpid5gl[3], SSB_SPROM4_TXPID5GL23, SSB_SPROM4_TXPID5GL3, ++ SSB_SPROM4_TXPID5GL3_SHIFT); ++ ++ SPEX(txpid5g[0], SSB_SPROM4_TXPID5G01, SSB_SPROM4_TXPID5G0, ++ SSB_SPROM4_TXPID5G0_SHIFT); ++ SPEX(txpid5g[1], SSB_SPROM4_TXPID5G01, SSB_SPROM4_TXPID5G1, ++ SSB_SPROM4_TXPID5G1_SHIFT); ++ SPEX(txpid5g[2], SSB_SPROM4_TXPID5G23, SSB_SPROM4_TXPID5G2, ++ SSB_SPROM4_TXPID5G2_SHIFT); ++ SPEX(txpid5g[3], SSB_SPROM4_TXPID5G23, SSB_SPROM4_TXPID5G3, ++ SSB_SPROM4_TXPID5G3_SHIFT); ++ ++ SPEX(txpid5gh[0], SSB_SPROM4_TXPID5GH01, SSB_SPROM4_TXPID5GH0, ++ SSB_SPROM4_TXPID5GH0_SHIFT); ++ SPEX(txpid5gh[1], SSB_SPROM4_TXPID5GH01, SSB_SPROM4_TXPID5GH1, ++ SSB_SPROM4_TXPID5GH1_SHIFT); ++ SPEX(txpid5gh[2], SSB_SPROM4_TXPID5GH23, SSB_SPROM4_TXPID5GH2, ++ SSB_SPROM4_TXPID5GH2_SHIFT); ++ SPEX(txpid5gh[3], SSB_SPROM4_TXPID5GH23, SSB_SPROM4_TXPID5GH3, ++ SSB_SPROM4_TXPID5GH3_SHIFT); ++ ++ SPEX(boardflags_lo, SSB_SPROM8_BFLLO, ~0, 0); ++ SPEX(boardflags_hi, SSB_SPROM8_BFLHI, ~0, 0); ++ SPEX(boardflags2_lo, SSB_SPROM8_BFL2LO, ~0, 0); ++ SPEX(boardflags2_hi, SSB_SPROM8_BFL2HI, ~0, 0); ++ ++ SPEX(alpha2[0], SSB_SPROM8_CCODE, 0xff00, 8); ++ SPEX(alpha2[1], SSB_SPROM8_CCODE, 0x00ff, 0); ++ ++ /* Extract core's power info */ ++ for (i = 0; i < ARRAY_SIZE(pwr_info_offset); i++) { ++ o = pwr_info_offset[i]; ++ SPEX(core_pwr_info[i].itssi_2g, o + SSB_SROM8_2G_MAXP_ITSSI, ++ SSB_SPROM8_2G_ITSSI, SSB_SPROM8_2G_ITSSI_SHIFT); ++ SPEX(core_pwr_info[i].maxpwr_2g, o + SSB_SROM8_2G_MAXP_ITSSI, ++ SSB_SPROM8_2G_MAXP, 0); ++ ++ SPEX(core_pwr_info[i].pa_2g[0], o + SSB_SROM8_2G_PA_0, ~0, 0); ++ SPEX(core_pwr_info[i].pa_2g[1], o + SSB_SROM8_2G_PA_1, ~0, 0); ++ SPEX(core_pwr_info[i].pa_2g[2], o + SSB_SROM8_2G_PA_2, ~0, 0); ++ ++ SPEX(core_pwr_info[i].itssi_5g, o + SSB_SROM8_5G_MAXP_ITSSI, ++ SSB_SPROM8_5G_ITSSI, SSB_SPROM8_5G_ITSSI_SHIFT); ++ SPEX(core_pwr_info[i].maxpwr_5g, o + SSB_SROM8_5G_MAXP_ITSSI, ++ SSB_SPROM8_5G_MAXP, 0); ++ SPEX(core_pwr_info[i].maxpwr_5gh, o + SSB_SPROM8_5GHL_MAXP, ++ SSB_SPROM8_5GH_MAXP, 0); ++ SPEX(core_pwr_info[i].maxpwr_5gl, o + SSB_SPROM8_5GHL_MAXP, ++ SSB_SPROM8_5GL_MAXP, SSB_SPROM8_5GL_MAXP_SHIFT); ++ ++ SPEX(core_pwr_info[i].pa_5gl[0], o + SSB_SROM8_5GL_PA_0, ~0, 0); ++ SPEX(core_pwr_info[i].pa_5gl[1], o + SSB_SROM8_5GL_PA_1, ~0, 0); ++ SPEX(core_pwr_info[i].pa_5gl[2], o + SSB_SROM8_5GL_PA_2, ~0, 0); ++ SPEX(core_pwr_info[i].pa_5g[0], o + SSB_SROM8_5G_PA_0, ~0, 0); ++ SPEX(core_pwr_info[i].pa_5g[1], o + SSB_SROM8_5G_PA_1, ~0, 0); ++ SPEX(core_pwr_info[i].pa_5g[2], o + SSB_SROM8_5G_PA_2, ~0, 0); ++ SPEX(core_pwr_info[i].pa_5gh[0], o + SSB_SROM8_5GH_PA_0, ~0, 0); ++ SPEX(core_pwr_info[i].pa_5gh[1], o + SSB_SROM8_5GH_PA_1, ~0, 0); ++ SPEX(core_pwr_info[i].pa_5gh[2], o + SSB_SROM8_5GH_PA_2, ~0, 0); ++ } ++ ++ SPEX(fem.ghz2.tssipos, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_TSSIPOS, ++ SSB_SROM8_FEM_TSSIPOS_SHIFT); ++ SPEX(fem.ghz2.extpa_gain, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_EXTPA_GAIN, ++ SSB_SROM8_FEM_EXTPA_GAIN_SHIFT); ++ SPEX(fem.ghz2.pdet_range, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_PDET_RANGE, ++ SSB_SROM8_FEM_PDET_RANGE_SHIFT); ++ SPEX(fem.ghz2.tr_iso, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_TR_ISO, ++ SSB_SROM8_FEM_TR_ISO_SHIFT); ++ SPEX(fem.ghz2.antswlut, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_ANTSWLUT, ++ SSB_SROM8_FEM_ANTSWLUT_SHIFT); ++ ++ SPEX(fem.ghz5.tssipos, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_TSSIPOS, ++ SSB_SROM8_FEM_TSSIPOS_SHIFT); ++ SPEX(fem.ghz5.extpa_gain, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_EXTPA_GAIN, ++ SSB_SROM8_FEM_EXTPA_GAIN_SHIFT); ++ SPEX(fem.ghz5.pdet_range, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_PDET_RANGE, ++ SSB_SROM8_FEM_PDET_RANGE_SHIFT); ++ SPEX(fem.ghz5.tr_iso, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_TR_ISO, ++ SSB_SROM8_FEM_TR_ISO_SHIFT); ++ SPEX(fem.ghz5.antswlut, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_ANTSWLUT, ++ SSB_SROM8_FEM_ANTSWLUT_SHIFT); ++ ++ SPEX(ant_available_a, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_A, ++ SSB_SPROM8_ANTAVAIL_A_SHIFT); ++ SPEX(ant_available_bg, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_BG, ++ SSB_SPROM8_ANTAVAIL_BG_SHIFT); ++ SPEX(maxpwr_bg, SSB_SPROM8_MAXP_BG, SSB_SPROM8_MAXP_BG_MASK, 0); ++ SPEX(itssi_bg, SSB_SPROM8_MAXP_BG, SSB_SPROM8_ITSSI_BG, ++ SSB_SPROM8_ITSSI_BG_SHIFT); ++ SPEX(maxpwr_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_MAXP_A_MASK, 0); ++ SPEX(itssi_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_ITSSI_A, ++ SSB_SPROM8_ITSSI_A_SHIFT); ++ SPEX(maxpwr_ah, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AH_MASK, 0); ++ SPEX(maxpwr_al, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AL_MASK, ++ SSB_SPROM8_MAXP_AL_SHIFT); ++ SPEX(gpio0, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P0, 0); ++ SPEX(gpio1, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P1, ++ SSB_SPROM8_GPIOA_P1_SHIFT); ++ SPEX(gpio2, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P2, 0); ++ SPEX(gpio3, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P3, ++ SSB_SPROM8_GPIOB_P3_SHIFT); ++ SPEX(tri2g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI2G, 0); ++ SPEX(tri5g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI5G, ++ SSB_SPROM8_TRI5G_SHIFT); ++ SPEX(tri5gl, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GL, 0); ++ SPEX(tri5gh, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GH, ++ SSB_SPROM8_TRI5GH_SHIFT); ++ SPEX(rxpo2g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO2G, ++ SSB_SPROM8_RXPO2G_SHIFT); ++ SPEX(rxpo5g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO5G, ++ SSB_SPROM8_RXPO5G_SHIFT); ++ SPEX(rssismf2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMF2G, 0); ++ SPEX(rssismc2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMC2G, ++ SSB_SPROM8_RSSISMC2G_SHIFT); ++ SPEX(rssisav2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISAV2G, ++ SSB_SPROM8_RSSISAV2G_SHIFT); ++ SPEX(bxa2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_BXA2G, ++ SSB_SPROM8_BXA2G_SHIFT); ++ SPEX(rssismf5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMF5G, 0); ++ SPEX(rssismc5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMC5G, ++ SSB_SPROM8_RSSISMC5G_SHIFT); ++ SPEX(rssisav5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISAV5G, ++ SSB_SPROM8_RSSISAV5G_SHIFT); ++ SPEX(bxa5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_BXA5G, ++ SSB_SPROM8_BXA5G_SHIFT); ++ ++ SPEX(pa0b0, SSB_SPROM8_PA0B0, ~0, 0); ++ SPEX(pa0b1, SSB_SPROM8_PA0B1, ~0, 0); ++ SPEX(pa0b2, SSB_SPROM8_PA0B2, ~0, 0); ++ SPEX(pa1b0, SSB_SPROM8_PA1B0, ~0, 0); ++ SPEX(pa1b1, SSB_SPROM8_PA1B1, ~0, 0); ++ SPEX(pa1b2, SSB_SPROM8_PA1B2, ~0, 0); ++ SPEX(pa1lob0, SSB_SPROM8_PA1LOB0, ~0, 0); ++ SPEX(pa1lob1, SSB_SPROM8_PA1LOB1, ~0, 0); ++ SPEX(pa1lob2, SSB_SPROM8_PA1LOB2, ~0, 0); ++ SPEX(pa1hib0, SSB_SPROM8_PA1HIB0, ~0, 0); ++ SPEX(pa1hib1, SSB_SPROM8_PA1HIB1, ~0, 0); ++ SPEX(pa1hib2, SSB_SPROM8_PA1HIB2, ~0, 0); ++ SPEX(cck2gpo, SSB_SPROM8_CCK2GPO, ~0, 0); ++ SPEX32(ofdm2gpo, SSB_SPROM8_OFDM2GPO, ~0, 0); ++ SPEX32(ofdm5glpo, SSB_SPROM8_OFDM5GLPO, ~0, 0); ++ SPEX32(ofdm5gpo, SSB_SPROM8_OFDM5GPO, ~0, 0); ++ SPEX32(ofdm5ghpo, SSB_SPROM8_OFDM5GHPO, ~0, 0); ++ ++ /* Extract the antenna gain values. */ ++ out->antenna_gain.a0 = sprom_extract_antgain(in, ++ SSB_SPROM8_AGAIN01, ++ SSB_SPROM8_AGAIN0, ++ SSB_SPROM8_AGAIN0_SHIFT); ++ out->antenna_gain.a1 = sprom_extract_antgain(in, ++ SSB_SPROM8_AGAIN01, ++ SSB_SPROM8_AGAIN1, ++ SSB_SPROM8_AGAIN1_SHIFT); ++ out->antenna_gain.a2 = sprom_extract_antgain(in, ++ SSB_SPROM8_AGAIN23, ++ SSB_SPROM8_AGAIN2, ++ SSB_SPROM8_AGAIN2_SHIFT); ++ out->antenna_gain.a3 = sprom_extract_antgain(in, ++ SSB_SPROM8_AGAIN23, ++ SSB_SPROM8_AGAIN3, ++ SSB_SPROM8_AGAIN3_SHIFT); ++ ++ SPEX(leddc_on_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_ON, ++ SSB_SPROM8_LEDDC_ON_SHIFT); ++ SPEX(leddc_off_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_OFF, ++ SSB_SPROM8_LEDDC_OFF_SHIFT); ++ ++ SPEX(txchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_TXCHAIN, ++ SSB_SPROM8_TXRXC_TXCHAIN_SHIFT); ++ SPEX(rxchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_RXCHAIN, ++ SSB_SPROM8_TXRXC_RXCHAIN_SHIFT); ++ SPEX(antswitch, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_SWITCH, ++ SSB_SPROM8_TXRXC_SWITCH_SHIFT); ++ ++ SPEX(opo, SSB_SPROM8_OFDM2GPO, 0x00ff, 0); ++ ++ SPEX_ARRAY8(mcs2gpo, SSB_SPROM8_2G_MCSPO, ~0, 0); ++ SPEX_ARRAY8(mcs5gpo, SSB_SPROM8_5G_MCSPO, ~0, 0); ++ SPEX_ARRAY8(mcs5glpo, SSB_SPROM8_5GL_MCSPO, ~0, 0); ++ SPEX_ARRAY8(mcs5ghpo, SSB_SPROM8_5GH_MCSPO, ~0, 0); ++ ++ SPEX(rawtempsense, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_RAWTEMP, ++ SSB_SPROM8_RAWTS_RAWTEMP_SHIFT); ++ SPEX(measpower, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_MEASPOWER, ++ SSB_SPROM8_RAWTS_MEASPOWER_SHIFT); ++ SPEX(tempsense_slope, SSB_SPROM8_OPT_CORRX, ++ SSB_SPROM8_OPT_CORRX_TEMP_SLOPE, ++ SSB_SPROM8_OPT_CORRX_TEMP_SLOPE_SHIFT); ++ SPEX(tempcorrx, SSB_SPROM8_OPT_CORRX, SSB_SPROM8_OPT_CORRX_TEMPCORRX, ++ SSB_SPROM8_OPT_CORRX_TEMPCORRX_SHIFT); ++ SPEX(tempsense_option, SSB_SPROM8_OPT_CORRX, ++ SSB_SPROM8_OPT_CORRX_TEMP_OPTION, ++ SSB_SPROM8_OPT_CORRX_TEMP_OPTION_SHIFT); ++ SPEX(freqoffset_corr, SSB_SPROM8_HWIQ_IQSWP, ++ SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR, ++ SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR_SHIFT); ++ SPEX(iqcal_swp_dis, SSB_SPROM8_HWIQ_IQSWP, ++ SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP, ++ SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP_SHIFT); ++ SPEX(hw_iqcal_en, SSB_SPROM8_HWIQ_IQSWP, SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL, ++ SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL_SHIFT); ++ ++ SPEX(bw40po, SSB_SPROM8_BW40PO, ~0, 0); ++ SPEX(cddpo, SSB_SPROM8_CDDPO, ~0, 0); ++ SPEX(stbcpo, SSB_SPROM8_STBCPO, ~0, 0); ++ SPEX(bwduppo, SSB_SPROM8_BWDUPPO, ~0, 0); ++ ++ SPEX(tempthresh, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_TRESH, ++ SSB_SPROM8_THERMAL_TRESH_SHIFT); ++ SPEX(tempoffset, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_OFFSET, ++ SSB_SPROM8_THERMAL_OFFSET_SHIFT); ++ SPEX(phycal_tempdelta, SSB_SPROM8_TEMPDELTA, ++ SSB_SPROM8_TEMPDELTA_PHYCAL, ++ SSB_SPROM8_TEMPDELTA_PHYCAL_SHIFT); ++ SPEX(temps_period, SSB_SPROM8_TEMPDELTA, SSB_SPROM8_TEMPDELTA_PERIOD, ++ SSB_SPROM8_TEMPDELTA_PERIOD_SHIFT); ++ SPEX(temps_hysteresis, SSB_SPROM8_TEMPDELTA, ++ SSB_SPROM8_TEMPDELTA_HYSTERESIS, ++ SSB_SPROM8_TEMPDELTA_HYSTERESIS_SHIFT); ++} ++ ++static int sprom_extract(struct bcma_fbs *priv, const u16 *in, u16 size) ++{ ++ struct ssb_sprom *out = &priv->sprom; ++ ++ memset(out, 0, sizeof(*out)); ++ ++ out->revision = in[size - 1] & 0x00FF; ++ if (out->revision < 8 || out->revision > 11) { ++ dev_warn(priv->dev, ++ "Unsupported SPROM revision %d detected." ++ " Will extract v8\n", ++ out->revision); ++ out->revision = 8; ++ } ++ ++ sprom_extract_r8(out, in); ++ ++ return 0; ++} ++ ++static void bcma_fbs_fixup(struct bcma_fbs *priv, u16 *sprom) ++{ ++ struct device_node *node = priv->dev->of_node; ++ u32 fixups, off, val; ++ int i = 0; ++ ++ if (!of_get_property(node, "brcm,sprom-fixups", &fixups)) ++ return; ++ ++ fixups /= sizeof(u32); ++ ++ dev_info(priv->dev, "patching SPROM with %u fixups...\n", fixups >> 1); ++ ++ while (i < fixups) { ++ if (of_property_read_u32_index(node, "brcm,sprom-fixups", ++ i++, &off)) { ++ dev_err(priv->dev, "error reading fixup[%u] offset\n", ++ i - 1); ++ return; ++ } ++ ++ if (of_property_read_u32_index(node, "brcm,sprom-fixups", ++ i++, &val)) { ++ dev_err(priv->dev, "error reading fixup[%u] value\n", ++ i - 1); ++ return; ++ } ++ ++ dev_dbg(priv->dev, "fixup[%d]=0x%04x\n", off, val); ++ ++ sprom[off] = val; ++ } ++} ++ ++static bool sprom_override_devid(struct bcma_fbs *priv, struct ssb_sprom *out, ++ const u16 *in) ++{ ++ SPEX(dev_id, 0x0060, 0xFFFF, 0); ++ return !!out->dev_id; ++} ++ ++static void bcma_fbs_set(struct bcma_fbs *priv, struct device_node *node) ++{ ++ struct ssb_sprom *sprom = &priv->sprom; ++ const struct firmware *fw; ++ const char *sprom_name; ++ int err; ++ ++ if (of_property_read_string(node, "brcm,sprom", &sprom_name)) ++ sprom_name = NULL; ++ ++ if (sprom_name) { ++ err = request_firmware_direct(&fw, sprom_name, priv->dev); ++ if (err) ++ dev_err(priv->dev, "%s load error\n", sprom_name); ++ } else { ++ err = -ENOENT; ++ } ++ ++ if (err) { ++ sprom->revision = 0x02; ++ sprom->board_rev = 0x0017; ++ sprom->country_code = 0x00; ++ sprom->ant_available_bg = 0x03; ++ sprom->pa0b0 = 0x15ae; ++ sprom->pa0b1 = 0xfa85; ++ sprom->pa0b2 = 0xfe8d; ++ sprom->pa1b0 = 0xffff; ++ sprom->pa1b1 = 0xffff; ++ sprom->pa1b2 = 0xffff; ++ sprom->gpio0 = 0xff; ++ sprom->gpio1 = 0xff; ++ sprom->gpio2 = 0xff; ++ sprom->gpio3 = 0xff; ++ sprom->maxpwr_bg = 0x4c; ++ sprom->itssi_bg = 0x00; ++ sprom->boardflags_lo = 0x2848; ++ sprom->boardflags_hi = 0x0000; ++ priv->devid_override = false; ++ ++ dev_warn(priv->dev, "using basic SPROM\n"); ++ } else { ++ size_t size = min(fw->size, (size_t) BCMA_FBS_MAX_SIZE); ++ u16 tmp_sprom[BCMA_FBS_MAX_SIZE >> 1]; ++ u32 i, j; ++ ++ for (i = 0, j = 0; i < size; i += 2, j++) ++ tmp_sprom[j] = (fw->data[i] << 8) | fw->data[i + 1]; ++ ++ release_firmware(fw); ++ bcma_fbs_fixup(priv, tmp_sprom); ++ sprom_extract(priv, tmp_sprom, size >> 1); ++ ++ priv->devid_override = sprom_override_devid(priv, sprom, ++ tmp_sprom); ++ } ++} ++ ++static int bcma_fbs_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct device_node *node = dev->of_node; ++ struct bcma_fbs *priv; ++ unsigned long flags; ++ u8 mac[ETH_ALEN]; ++ ++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ priv->dev = dev; ++ ++ bcma_fbs_set(priv, node); ++ ++ of_property_read_u32(node, "pci-bus", &priv->pci_bus); ++ of_property_read_u32(node, "pci-dev", &priv->pci_dev); ++ ++ of_get_mac_address(node, mac); ++ if (is_valid_ether_addr(mac)) { ++ dev_info(dev, "mtd mac %pM\n", mac); ++ } else { ++ eth_random_addr(mac); ++ dev_info(dev, "random mac %pM\n", mac); ++ } ++ ++ memcpy(priv->sprom.il0mac, mac, ETH_ALEN); ++ memcpy(priv->sprom.et0mac, mac, ETH_ALEN); ++ memcpy(priv->sprom.et1mac, mac, ETH_ALEN); ++ memcpy(priv->sprom.et2mac, mac, ETH_ALEN); ++ ++ spin_lock_irqsave(&bcma_fbs_lock, flags); ++ list_add(&priv->list, &bcma_fbs_list); ++ spin_unlock_irqrestore(&bcma_fbs_lock, flags); ++ ++ dev_info(dev, "registered SPROM for [%x:%x]\n", ++ priv->pci_bus, priv->pci_dev); ++ ++ return 0; ++} ++ ++static const struct of_device_id bcma_fbs_of_match[] = { ++ { .compatible = "brcm,bcma-sprom", }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, bcma_fbs_of_match); ++ ++static struct platform_driver bcma_fbs_driver = { ++ .probe = bcma_fbs_probe, ++ .driver = { ++ .name = "bcma-sprom", ++ .of_match_table = bcma_fbs_of_match, ++ }, ++}; ++ ++int __init bcma_fbs_register(void) ++{ ++ return platform_driver_register(&bcma_fbs_driver); ++} +diff --git a/drivers/bcma/fallback-sprom.h b/drivers/bcma/fallback-sprom.h +new file mode 100644 +index 000000000000..363663413dc4 +--- /dev/null ++++ b/drivers/bcma/fallback-sprom.h +@@ -0,0 +1,7 @@ ++#ifndef _FALLBACK_SPROM_H ++#define _FALLBACK_SPROM_H ++ ++int __init bcma_fbs_register(void); ++int bcma_get_fallback_sprom(struct bcma_bus *dev, struct ssb_sprom *out); ++ ++#endif /* _FALLBACK_SPROM_H */ +diff --git a/drivers/leds/leds-smartrg-system.c b/drivers/leds/leds-smartrg-system.c +new file mode 100644 +index 000000000000..c1770aa81b59 +--- /dev/null ++++ b/drivers/leds/leds-smartrg-system.c +@@ -0,0 +1,225 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/** ++ * Driver for SmartRG RGBW LED microcontroller. ++ * RGBW LED is connected to a Holtek HT45F0062 that is on the I2C bus. ++ * ++ */ ++ ++struct srg_led_ctrl; ++struct srg_led { ++ u8 index; ++ struct led_classdev led; ++ struct srg_led_ctrl *ctrl; ++}; ++ ++struct srg_led_ctrl { ++ struct mutex lock; ++ struct i2c_client *client; ++ struct srg_led channel[4]; ++ u8 control[5]; ++}; ++ ++static int ++srg_led_i2c_write(struct srg_led_ctrl *sysled_ctrl, u8 reg, u8 value) ++{ ++ return i2c_smbus_write_byte_data(sysled_ctrl->client, reg, value); ++} ++ ++/* ++ * MC LED Command: 0 = OFF, 1 = ON, 2 = Flash, 3 = Pulse, 4 = Blink ++ * */ ++static int ++srg_led_control_sync(struct srg_led_ctrl *sysled_ctrl) ++{ ++ int i, ret; ++ ++ for (i = 1; i < 5; i++) { ++ ret = srg_led_i2c_write(sysled_ctrl, i, sysled_ctrl->control[i]); ++ if (ret) ++ break; ++ } ++ return ret; ++} ++ ++/* ++ * This function overrides the led driver timer trigger to offload ++ * flashing to the micro-controller. The negative effect of this ++ * is the inability to configure the delay_on and delay_off periods. ++ * ++ * */ ++static int ++srg_led_set_pulse(struct led_classdev *led_cdev, ++ unsigned long *delay_on, ++ unsigned long *delay_off) ++{ ++ struct srg_led *sysled = container_of(led_cdev, struct srg_led, led); ++ struct srg_led_ctrl *sysled_ctrl = sysled->ctrl; ++ bool blinking = false, pulsing = false; ++ u8 cbyte; ++ int ret; ++ ++ if (delay_on && delay_off && (*delay_on > 100) && (*delay_on <= 500)) { ++ pulsing = true; ++ *delay_on = 500; ++ *delay_off = 500; ++ } else if (delay_on && delay_off && (*delay_on >= 50) && (*delay_on <= 100)) { ++ blinking = true; ++ *delay_on = 50; ++ *delay_off = 50; ++ } ++ ++ cbyte = pulsing ? 3 : blinking ? 2 : 0; ++ mutex_lock(&sysled_ctrl->lock); ++ ret = srg_led_i2c_write(sysled_ctrl, sysled->index + 4, ++ (blinking || pulsing) ? 255 : 0); ++ if (!ret) { ++ sysled_ctrl->control[sysled->index] = cbyte; ++ ret = srg_led_control_sync(sysled_ctrl); ++ } ++ mutex_unlock(&sysled_ctrl->lock); ++ ++ return !cbyte; ++} ++ ++static int ++srg_led_set_brightness(struct led_classdev *led_cdev, ++ enum led_brightness value) ++{ ++ struct srg_led *sysled = container_of(led_cdev, struct srg_led, led); ++ struct srg_led_ctrl *sysled_ctrl = sysled->ctrl; ++ int ret; ++ ++ mutex_lock(&sysled_ctrl->lock); ++ ret = srg_led_i2c_write(sysled_ctrl, sysled->index + 4, value); ++ if (!ret) { ++ sysled_ctrl->control[sysled->index] = !!value; ++ ret = srg_led_control_sync(sysled_ctrl); ++ } ++ mutex_unlock(&sysled_ctrl->lock); ++ return ret; ++} ++ ++static int ++srg_led_init_led(struct srg_led_ctrl *sysled_ctrl, struct device_node *np) ++{ ++ struct led_init_data init_data = {}; ++ struct led_classdev *led_cdev; ++ struct srg_led *sysled; ++ int index, ret; ++ ++ if (!np) ++ return -ENOENT; ++ ++ ret = of_property_read_u32(np, "reg", &index); ++ if (ret) { ++ dev_err(&sysled_ctrl->client->dev, ++ "srg_led_init_led: no reg defined in np!\n"); ++ return ret; ++ } ++ ++ if (index < 1 || index > 4) ++ return -EINVAL; ++ ++ sysled = &sysled_ctrl->channel[index - 1]; ++ led_cdev = &sysled->led; ++ ++ sysled->index = index; ++ sysled->ctrl = sysled_ctrl; ++ ++ init_data.fwnode = of_fwnode_handle(np); ++ ++ led_cdev->name = of_get_property(np, "label", NULL) ? : np->name; ++ led_cdev->brightness = LED_OFF; ++ led_cdev->max_brightness = LED_FULL; ++ led_cdev->brightness_set_blocking = srg_led_set_brightness; ++ led_cdev->blink_set = srg_led_set_pulse; ++ ++ srg_led_i2c_write(sysled_ctrl, index + 4, 0); ++ ++ ret = devm_led_classdev_register_ext(&sysled_ctrl->client->dev, ++ led_cdev, &init_data); ++ if (ret) { ++ dev_err(&sysled_ctrl->client->dev, ++ "srg_led_init_led: led register %s error ret %d!n", ++ led_cdev->name, ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int ++ ++srg_led_probe(struct i2c_client *client) ++{ ++ struct device_node *np = client->dev.of_node, *child; ++ struct srg_led_ctrl *sysled_ctrl; ++ int err; ++ ++ sysled_ctrl = devm_kzalloc(&client->dev, sizeof(*sysled_ctrl), GFP_KERNEL); ++ if (!sysled_ctrl) ++ return -ENOMEM; ++ ++ sysled_ctrl->client = client; ++ ++ err = devm_mutex_init(&client->dev, &sysled_ctrl->lock); ++ if (err) ++ return err; ++ ++ i2c_set_clientdata(client, sysled_ctrl); ++ ++ for_each_available_child_of_node(np, child) { ++ if (srg_led_init_led(sysled_ctrl, child)) ++ continue; ++ ++ msleep(5); ++ } ++ ++ return srg_led_control_sync(sysled_ctrl);; ++} ++ ++static void srg_led_disable(struct i2c_client *client) ++{ ++ struct srg_led_ctrl *sysled_ctrl = i2c_get_clientdata(client); ++ int i; ++ ++ for (i = 1; i < 10; i++) ++ srg_led_i2c_write(sysled_ctrl, i, 0); ++} ++ ++static const struct i2c_device_id srg_led_id[] = { ++ { "srg-sysled", 0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, srg_led_id); ++ ++static const struct of_device_id of_srg_led_match[] = { ++ { .compatible = "srg,sysled", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, of_srg_led_match); ++ ++static struct i2c_driver srg_sysled_driver = { ++ .driver = { ++ .name = "srg-sysled", ++ .of_match_table = of_srg_led_match, ++ }, ++ .probe = srg_led_probe, ++ .remove = srg_led_disable, ++ .id_table = srg_led_id, ++}; ++module_i2c_driver(srg_sysled_driver); ++ ++MODULE_DESCRIPTION("SmartRG system LED driver"); ++MODULE_AUTHOR("Shen Loh "); ++MODULE_AUTHOR("Daniel Golle "); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/mfd/airoha-an8855.c b/drivers/mfd/airoha-an8855.c +new file mode 100644 +index 000000000000..eeaea348aa41 +--- /dev/null ++++ b/drivers/mfd/airoha-an8855.c +@@ -0,0 +1,278 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * MFD driver for Airoha AN8855 Switch ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static const struct mfd_cell an8855_mfd_devs[] = { ++ { ++ .name = "an8855-efuse", ++ .of_compatible = "airoha,an8855-efuse", ++ }, { ++ .name = "an8855-switch", ++ .of_compatible = "airoha,an8855-switch", ++ }, { ++ .name = "an8855-mdio", ++ .of_compatible = "airoha,an8855-mdio", ++ } ++}; ++ ++int an8855_mii_set_page(struct an8855_mfd_priv *priv, u8 phy_id, ++ u8 page) __must_hold(&priv->bus->mdio_lock) ++{ ++ struct mii_bus *bus = priv->bus; ++ int ret; ++ ++ ret = __mdiobus_write(bus, phy_id, AN8855_PHY_SELECT_PAGE, page); ++ if (ret < 0) ++ dev_err_ratelimited(&bus->dev, ++ "failed to set an8855 mii page\n"); ++ ++ /* Cache current page if next mii read/write is for switch */ ++ priv->current_page = page; ++ return ret < 0 ? ret : 0; ++} ++EXPORT_SYMBOL_GPL(an8855_mii_set_page); ++ ++static int an8855_mii_read32(struct mii_bus *bus, u8 phy_id, u32 reg, ++ u32 *val) __must_hold(&bus->mdio_lock) ++{ ++ int lo, hi, ret; ++ ++ ret = __mdiobus_write(bus, phy_id, AN8855_PBUS_MODE, ++ AN8855_PBUS_MODE_ADDR_FIXED); ++ if (ret < 0) ++ goto err; ++ ++ ret = __mdiobus_write(bus, phy_id, AN8855_PBUS_RD_ADDR_HIGH, ++ upper_16_bits(reg)); ++ if (ret < 0) ++ goto err; ++ ret = __mdiobus_write(bus, phy_id, AN8855_PBUS_RD_ADDR_LOW, ++ lower_16_bits(reg)); ++ if (ret < 0) ++ goto err; ++ ++ hi = __mdiobus_read(bus, phy_id, AN8855_PBUS_RD_DATA_HIGH); ++ if (hi < 0) { ++ ret = hi; ++ goto err; ++ } ++ lo = __mdiobus_read(bus, phy_id, AN8855_PBUS_RD_DATA_LOW); ++ if (lo < 0) { ++ ret = lo; ++ goto err; ++ } ++ ++ *val = ((u16)hi << 16) | ((u16)lo & 0xffff); ++ ++ return 0; ++err: ++ dev_err_ratelimited(&bus->dev, ++ "failed to read an8855 register\n"); ++ return ret; ++} ++ ++static int an8855_regmap_read(void *ctx, uint32_t reg, uint32_t *val) ++{ ++ struct an8855_mfd_priv *priv = ctx; ++ struct mii_bus *bus = priv->bus; ++ u16 addr = priv->switch_addr; ++ int ret; ++ ++ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); ++ ret = an8855_mii_set_page(priv, addr, AN8855_PHY_PAGE_EXTENDED_4); ++ if (ret < 0) ++ goto exit; ++ ++ ret = an8855_mii_read32(bus, addr, reg, val); ++ ++exit: ++ mutex_unlock(&bus->mdio_lock); ++ ++ return ret < 0 ? ret : 0; ++} ++ ++static int an8855_mii_write32(struct mii_bus *bus, u8 phy_id, u32 reg, ++ u32 val) __must_hold(&bus->mdio_lock) ++{ ++ int ret; ++ ++ ret = __mdiobus_write(bus, phy_id, AN8855_PBUS_MODE, ++ AN8855_PBUS_MODE_ADDR_FIXED); ++ if (ret < 0) ++ goto err; ++ ++ ret = __mdiobus_write(bus, phy_id, AN8855_PBUS_WR_ADDR_HIGH, ++ upper_16_bits(reg)); ++ if (ret < 0) ++ goto err; ++ ret = __mdiobus_write(bus, phy_id, AN8855_PBUS_WR_ADDR_LOW, ++ lower_16_bits(reg)); ++ if (ret < 0) ++ goto err; ++ ++ ret = __mdiobus_write(bus, phy_id, AN8855_PBUS_WR_DATA_HIGH, ++ upper_16_bits(val)); ++ if (ret < 0) ++ goto err; ++ ret = __mdiobus_write(bus, phy_id, AN8855_PBUS_WR_DATA_LOW, ++ lower_16_bits(val)); ++ if (ret < 0) ++ goto err; ++ ++ return 0; ++err: ++ dev_err_ratelimited(&bus->dev, ++ "failed to write an8855 register\n"); ++ return ret; ++} ++ ++static int ++an8855_regmap_write(void *ctx, uint32_t reg, uint32_t val) ++{ ++ struct an8855_mfd_priv *priv = ctx; ++ struct mii_bus *bus = priv->bus; ++ u16 addr = priv->switch_addr; ++ int ret; ++ ++ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); ++ ret = an8855_mii_set_page(priv, addr, AN8855_PHY_PAGE_EXTENDED_4); ++ if (ret < 0) ++ goto exit; ++ ++ ret = an8855_mii_write32(bus, addr, reg, val); ++ ++exit: ++ mutex_unlock(&bus->mdio_lock); ++ ++ return ret < 0 ? ret : 0; ++} ++ ++static int an8855_regmap_update_bits(void *ctx, uint32_t reg, uint32_t mask, ++ uint32_t write_val) ++{ ++ struct an8855_mfd_priv *priv = ctx; ++ struct mii_bus *bus = priv->bus; ++ u16 addr = priv->switch_addr; ++ u32 val; ++ int ret; ++ ++ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); ++ ret = an8855_mii_set_page(priv, addr, AN8855_PHY_PAGE_EXTENDED_4); ++ if (ret < 0) ++ goto exit; ++ ++ ret = an8855_mii_read32(bus, addr, reg, &val); ++ if (ret < 0) ++ goto exit; ++ ++ val &= ~mask; ++ val |= write_val; ++ ret = an8855_mii_write32(bus, addr, reg, val); ++ ++exit: ++ mutex_unlock(&bus->mdio_lock); ++ ++ return ret < 0 ? ret : 0; ++} ++ ++static const struct regmap_range an8855_readable_ranges[] = { ++ regmap_reg_range(0x10000000, 0x10000fff), /* SCU */ ++ regmap_reg_range(0x10001000, 0x10001fff), /* RBUS */ ++ regmap_reg_range(0x10002000, 0x10002fff), /* MCU */ ++ regmap_reg_range(0x10005000, 0x10005fff), /* SYS SCU */ ++ regmap_reg_range(0x10007000, 0x10007fff), /* I2C Slave */ ++ regmap_reg_range(0x10008000, 0x10008fff), /* I2C Master */ ++ regmap_reg_range(0x10009000, 0x10009fff), /* PDMA */ ++ regmap_reg_range(0x1000a100, 0x1000a2ff), /* General Purpose Timer */ ++ regmap_reg_range(0x1000a200, 0x1000a2ff), /* GPU timer */ ++ regmap_reg_range(0x1000a300, 0x1000a3ff), /* GPIO */ ++ regmap_reg_range(0x1000a400, 0x1000a5ff), /* EFUSE */ ++ regmap_reg_range(0x1000c000, 0x1000cfff), /* GDMP CSR */ ++ regmap_reg_range(0x10010000, 0x1001ffff), /* GDMP SRAM */ ++ regmap_reg_range(0x10200000, 0x10203fff), /* Switch - ARL Global */ ++ regmap_reg_range(0x10204000, 0x10207fff), /* Switch - BMU */ ++ regmap_reg_range(0x10208000, 0x1020bfff), /* Switch - ARL Port */ ++ regmap_reg_range(0x1020c000, 0x1020cfff), /* Switch - SCH */ ++ regmap_reg_range(0x10210000, 0x10213fff), /* Switch - MAC */ ++ regmap_reg_range(0x10214000, 0x10217fff), /* Switch - MIB */ ++ regmap_reg_range(0x10218000, 0x1021bfff), /* Switch - Port Control */ ++ regmap_reg_range(0x1021c000, 0x1021ffff), /* Switch - TOP */ ++ regmap_reg_range(0x10220000, 0x1022ffff), /* SerDes */ ++ regmap_reg_range(0x10286000, 0x10286fff), /* RG Batcher */ ++ regmap_reg_range(0x1028c000, 0x1028ffff), /* ETHER_SYS */ ++ regmap_reg_range(0x30000000, 0x37ffffff), /* I2C EEPROM */ ++ regmap_reg_range(0x38000000, 0x3fffffff), /* BOOT_ROM */ ++ regmap_reg_range(0xa0000000, 0xbfffffff), /* GPHY */ ++}; ++ ++static const struct regmap_access_table an8855_readable_table = { ++ .yes_ranges = an8855_readable_ranges, ++ .n_yes_ranges = ARRAY_SIZE(an8855_readable_ranges), ++}; ++ ++static const struct regmap_config an8855_regmap_config = { ++ .reg_bits = 32, ++ .val_bits = 32, ++ .reg_stride = 4, ++ .max_register = 0xbfffffff, ++ .reg_read = an8855_regmap_read, ++ .reg_write = an8855_regmap_write, ++ .reg_update_bits = an8855_regmap_update_bits, ++ .disable_locking = true, ++ .rd_table = &an8855_readable_table, ++}; ++ ++static int an8855_mfd_probe(struct mdio_device *mdiodev) ++{ ++ struct an8855_mfd_priv *priv; ++ struct regmap *regmap; ++ ++ priv = devm_kzalloc(&mdiodev->dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ priv->bus = mdiodev->bus; ++ priv->dev = &mdiodev->dev; ++ priv->switch_addr = mdiodev->addr; ++ /* no DMA for mdiobus, mute warning for DMA mask not set */ ++ priv->dev->dma_mask = &priv->dev->coherent_dma_mask; ++ ++ regmap = devm_regmap_init(priv->dev, NULL, priv, ++ &an8855_regmap_config); ++ if (IS_ERR(regmap)) ++ dev_err_probe(priv->dev, PTR_ERR(priv->dev), ++ "regmap initialization failed\n"); ++ ++ dev_set_drvdata(&mdiodev->dev, priv); ++ ++ return devm_mfd_add_devices(priv->dev, PLATFORM_DEVID_AUTO, an8855_mfd_devs, ++ ARRAY_SIZE(an8855_mfd_devs), NULL, 0, ++ NULL); ++} ++ ++static const struct of_device_id an8855_mfd_of_match[] = { ++ { .compatible = "airoha,an8855-mfd" }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, an8855_mfd_of_match); ++ ++static struct mdio_driver an8855_mfd_driver = { ++ .probe = an8855_mfd_probe, ++ .mdiodrv.driver = { ++ .name = "an8855", ++ .of_match_table = an8855_mfd_of_match, ++ }, ++}; ++mdio_module_driver(an8855_mfd_driver); ++ ++MODULE_AUTHOR("Christian Marangi "); ++MODULE_DESCRIPTION("Driver for Airoha AN8855 MFD"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/mtd/mtdsplit/Kconfig b/drivers/mtd/mtdsplit/Kconfig +new file mode 100644 +index 000000000000..396becf160cf +--- /dev/null ++++ b/drivers/mtd/mtdsplit/Kconfig +@@ -0,0 +1,117 @@ ++config MTD_SPLIT ++ def_bool n ++ help ++ Generic MTD split support. ++ ++config MTD_SPLIT_SUPPORT ++ def_bool MTD = y ++ ++comment "Rootfs partition parsers" ++ ++config MTD_SPLIT_SQUASHFS_ROOT ++ bool "Squashfs based root partition parser" ++ depends on MTD_SPLIT_SUPPORT ++ select MTD_SPLIT ++ help ++ This provides a parsing function which allows to detect the ++ offset and size of the unused portion of a rootfs partition ++ containing a squashfs. ++ ++comment "Firmware partition parsers" ++ ++config MTD_SPLIT_BCM63XX_FW ++ bool "BCM63xx firmware parser" ++ depends on MTD_SPLIT_SUPPORT ++ select MTD_SPLIT ++ ++config MTD_SPLIT_BCM_WFI_FW ++ bool "Broadcom Whole Flash Image parser" ++ depends on MTD_SPLIT_SUPPORT ++ select MTD_SPLIT ++ ++config MTD_SPLIT_CFE_BOOTFS ++ bool "Parser finding rootfs appended to the CFE bootfs" ++ depends on MTD_SPLIT_SUPPORT && (ARCH_BCM4908 || ARCH_BCMBCA) ++ select MTD_SPLIT ++ help ++ cferom on BCM4908 (and bcm63xx) uses JFFS2 bootfs partition ++ for storing kernel, cferam and some device specific files. ++ There isn't any straight way of storing rootfs so it gets ++ appended to the JFFS2 bootfs partition. Kernel needs to find ++ it and run init from it. This parser is responsible for ++ finding appended rootfs. ++ ++config MTD_SPLIT_SEAMA_FW ++ bool "Seama firmware parser" ++ depends on MTD_SPLIT_SUPPORT ++ select MTD_SPLIT ++ ++config MTD_SPLIT_WRGG_FW ++ bool "WRGG firmware parser" ++ depends on MTD_SPLIT_SUPPORT ++ select MTD_SPLIT ++ ++config MTD_SPLIT_UIMAGE_FW ++ bool "uImage based firmware partition parser" ++ depends on MTD_SPLIT_SUPPORT ++ select MTD_SPLIT ++ ++config MTD_SPLIT_FIT_FW ++ bool "FIT based firmware partition parser" ++ depends on MTD_SPLIT_SUPPORT ++ select MTD_SPLIT ++ ++config MTD_SPLIT_LZMA_FW ++ bool "LZMA compressed kernel based firmware partition parser" ++ depends on MTD_SPLIT_SUPPORT ++ select MTD_SPLIT ++ ++config MTD_SPLIT_TPLINK_FW ++ bool "TP-Link firmware parser" ++ depends on MTD_SPLIT_SUPPORT ++ select MTD_SPLIT ++ ++config MTD_SPLIT_TRX_FW ++ bool "TRX image based firmware partition parser" ++ depends on MTD_SPLIT_SUPPORT ++ select MTD_SPLIT ++ ++config MTD_SPLIT_BRNIMAGE_FW ++ bool "brnImage (brnboot image) firmware parser" ++ depends on MTD_SPLIT_SUPPORT ++ select MTD_SPLIT ++ ++config MTD_SPLIT_EVA_FW ++ bool "EVA image based firmware partition parser" ++ depends on MTD_SPLIT_SUPPORT ++ select MTD_SPLIT ++ ++config MTD_SPLIT_MINOR_FW ++ bool "Mikrotik NOR image based firmware partition parser" ++ depends on MTD_SPLIT_SUPPORT ++ select MTD_SPLIT ++ ++config MTD_SPLIT_JIMAGE_FW ++ bool "JBOOT Image based firmware partition parser" ++ depends on MTD_SPLIT_SUPPORT ++ select MTD_SPLIT ++ ++config MTD_SPLIT_ELF_FW ++ bool "ELF loader firmware partition parser" ++ depends on MTD_SPLIT_SUPPORT ++ select MTD_SPLIT ++ ++config MTD_SPLIT_H3C_VFS ++ bool "Parser finding rootfs appended to H3C VFS" ++ depends on MTD_SPLIT_SUPPORT ++ select MTD_SPLIT ++ ++config MTD_SPLIT_SEIL_FW ++ bool "IIJ SEIL firmware parser" ++ depends on MTD_SPLIT_SUPPORT ++ select MTD_SPLIT ++ ++config MTD_SPLIT_MSTC_BOOT ++ bool "MSTC bootnum-based parser" ++ depends on MTD_SPLIT_SUPPORT ++ select MTD_SPLIT +diff --git a/drivers/mtd/mtdsplit/Makefile b/drivers/mtd/mtdsplit/Makefile +new file mode 100644 +index 000000000000..b85ce5d21f3b +--- /dev/null ++++ b/drivers/mtd/mtdsplit/Makefile +@@ -0,0 +1,20 @@ ++obj-$(CONFIG_MTD_SPLIT) += mtdsplit.o ++obj-$(CONFIG_MTD_SPLIT_BCM63XX_FW) += mtdsplit_bcm63xx.o ++obj-$(CONFIG_MTD_SPLIT_BCM_WFI_FW) += mtdsplit_bcm_wfi.o ++obj-$(CONFIG_MTD_SPLIT_CFE_BOOTFS) += mtdsplit_cfe_bootfs.o ++obj-$(CONFIG_MTD_SPLIT_SEAMA_FW) += mtdsplit_seama.o ++obj-$(CONFIG_MTD_SPLIT_SEIL_FW) += mtdsplit_seil.o ++obj-$(CONFIG_MTD_SPLIT_SQUASHFS_ROOT) += mtdsplit_squashfs.o ++obj-$(CONFIG_MTD_SPLIT_UIMAGE_FW) += mtdsplit_uimage.o ++obj-$(CONFIG_MTD_SPLIT_FIT_FW) += mtdsplit_fit.o ++obj-$(CONFIG_MTD_SPLIT_LZMA_FW) += mtdsplit_lzma.o ++obj-$(CONFIG_MTD_SPLIT_TPLINK_FW) += mtdsplit_tplink.o ++obj-$(CONFIG_MTD_SPLIT_TRX_FW) += mtdsplit_trx.o ++obj-$(CONFIG_MTD_SPLIT_BRNIMAGE_FW) += mtdsplit_brnimage.o ++obj-$(CONFIG_MTD_SPLIT_EVA_FW) += mtdsplit_eva.o ++obj-$(CONFIG_MTD_SPLIT_WRGG_FW) += mtdsplit_wrgg.o ++obj-$(CONFIG_MTD_SPLIT_MINOR_FW) += mtdsplit_minor.o ++obj-$(CONFIG_MTD_SPLIT_JIMAGE_FW) += mtdsplit_jimage.o ++obj-$(CONFIG_MTD_SPLIT_ELF_FW) += mtdsplit_elf.o ++obj-$(CONFIG_MTD_SPLIT_H3C_VFS) += mtdsplit_h3c_vfs.o ++obj-$(CONFIG_MTD_SPLIT_MSTC_BOOT) += mtdsplit_mstc_boot.o +diff --git a/drivers/mtd/mtdsplit/mtdsplit.c b/drivers/mtd/mtdsplit/mtdsplit.c +new file mode 100644 +index 000000000000..b2e51dcfc66b +--- /dev/null ++++ b/drivers/mtd/mtdsplit/mtdsplit.c +@@ -0,0 +1,130 @@ ++/* ++ * Copyright (C) 2009-2013 Felix Fietkau ++ * Copyright (C) 2009-2013 Gabor Juhos ++ * Copyright (C) 2012 Jonas Gorski ++ * Copyright (C) 2013 Hauke Mehrtens ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation. ++ * ++ */ ++ ++#define pr_fmt(fmt) "mtdsplit: " fmt ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mtdsplit.h" ++ ++#define UBI_EC_MAGIC 0x55424923 /* UBI# */ ++ ++struct squashfs_super_block { ++ __le32 s_magic; ++ __le32 pad0[9]; ++ __le64 bytes_used; ++}; ++ ++int mtd_get_squashfs_len(struct mtd_info *master, ++ size_t offset, ++ size_t *squashfs_len) ++{ ++ struct squashfs_super_block sb; ++ size_t retlen; ++ int err; ++ ++ err = mtd_read(master, offset, sizeof(sb), &retlen, (void *)&sb); ++ if (err || (retlen != sizeof(sb))) { ++ pr_alert("error occured while reading from \"%s\"\n", ++ master->name); ++ return -EIO; ++ } ++ ++ if (le32_to_cpu(sb.s_magic) != SQUASHFS_MAGIC) { ++ pr_alert("no squashfs found in \"%s\"\n", master->name); ++ return -EINVAL; ++ } ++ ++ retlen = le64_to_cpu(sb.bytes_used); ++ if (retlen <= 0) { ++ pr_alert("squashfs is empty in \"%s\"\n", master->name); ++ return -ENODEV; ++ } ++ ++ if (offset + retlen > master->size) { ++ pr_alert("squashfs has invalid size in \"%s\"\n", ++ master->name); ++ return -EINVAL; ++ } ++ ++ *squashfs_len = retlen; ++ return 0; ++} ++EXPORT_SYMBOL_GPL(mtd_get_squashfs_len); ++ ++static ssize_t mtd_next_eb(struct mtd_info *mtd, size_t offset) ++{ ++ return mtd_rounddown_to_eb(offset, mtd) + mtd->erasesize; ++} ++ ++int mtd_check_rootfs_magic(struct mtd_info *mtd, size_t offset, ++ enum mtdsplit_part_type *type) ++{ ++ u32 magic; ++ size_t retlen; ++ int ret; ++ ++ ret = mtd_read(mtd, offset, sizeof(magic), &retlen, ++ (unsigned char *) &magic); ++ if (ret) ++ return ret; ++ ++ if (retlen != sizeof(magic)) ++ return -EIO; ++ ++ if (le32_to_cpu(magic) == SQUASHFS_MAGIC) { ++ if (type) ++ *type = MTDSPLIT_PART_TYPE_SQUASHFS; ++ return 0; ++ } else if (magic == 0x19852003) { ++ if (type) ++ *type = MTDSPLIT_PART_TYPE_JFFS2; ++ return 0; ++ } else if (be32_to_cpu(magic) == UBI_EC_MAGIC) { ++ if (type) ++ *type = MTDSPLIT_PART_TYPE_UBI; ++ return 0; ++ } ++ ++ return -EINVAL; ++} ++EXPORT_SYMBOL_GPL(mtd_check_rootfs_magic); ++ ++int mtd_find_rootfs_from(struct mtd_info *mtd, ++ size_t from, ++ size_t limit, ++ size_t *ret_offset, ++ enum mtdsplit_part_type *type) ++{ ++ size_t offset; ++ int err; ++ ++ for (offset = from; offset < limit; ++ offset = mtd_next_eb(mtd, offset)) { ++ err = mtd_check_rootfs_magic(mtd, offset, type); ++ if (err) ++ continue; ++ ++ *ret_offset = offset; ++ return 0; ++ } ++ ++ return -ENODEV; ++} ++EXPORT_SYMBOL_GPL(mtd_find_rootfs_from); ++ +diff --git a/drivers/mtd/mtdsplit/mtdsplit.h b/drivers/mtd/mtdsplit/mtdsplit.h +new file mode 100644 +index 000000000000..71d62a8956b2 +--- /dev/null ++++ b/drivers/mtd/mtdsplit/mtdsplit.h +@@ -0,0 +1,67 @@ ++/* ++ * Copyright (C) 2009-2013 Felix Fietkau ++ * Copyright (C) 2009-2013 Gabor Juhos ++ * Copyright (C) 2012 Jonas Gorski ++ * Copyright (C) 2013 Hauke Mehrtens ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation. ++ * ++ */ ++ ++#ifndef _MTDSPLIT_H ++#define _MTDSPLIT_H ++ ++#define KERNEL_PART_NAME "kernel" ++#define ROOTFS_PART_NAME "rootfs" ++#define UBI_PART_NAME "ubi" ++ ++#define ROOTFS_SPLIT_NAME "rootfs_data" ++ ++enum mtdsplit_part_type { ++ MTDSPLIT_PART_TYPE_UNK = 0, ++ MTDSPLIT_PART_TYPE_SQUASHFS, ++ MTDSPLIT_PART_TYPE_JFFS2, ++ MTDSPLIT_PART_TYPE_UBI, ++}; ++ ++#ifdef CONFIG_MTD_SPLIT ++int mtd_get_squashfs_len(struct mtd_info *master, ++ size_t offset, ++ size_t *squashfs_len); ++ ++int mtd_check_rootfs_magic(struct mtd_info *mtd, size_t offset, ++ enum mtdsplit_part_type *type); ++ ++int mtd_find_rootfs_from(struct mtd_info *mtd, ++ size_t from, ++ size_t limit, ++ size_t *ret_offset, ++ enum mtdsplit_part_type *type); ++ ++#else ++static inline int mtd_get_squashfs_len(struct mtd_info *master, ++ size_t offset, ++ size_t *squashfs_len) ++{ ++ return -ENODEV; ++} ++ ++static inline int mtd_check_rootfs_magic(struct mtd_info *mtd, size_t offset, ++ enum mtdsplit_part_type *type) ++{ ++ return -EINVAL; ++} ++ ++static inline int mtd_find_rootfs_from(struct mtd_info *mtd, ++ size_t from, ++ size_t limit, ++ size_t *ret_offset, ++ enum mtdsplit_part_type *type) ++{ ++ return -ENODEV; ++} ++#endif /* CONFIG_MTD_SPLIT */ ++ ++#endif /* _MTDSPLIT_H */ +diff --git a/drivers/mtd/mtdsplit/mtdsplit_bcm63xx.c b/drivers/mtd/mtdsplit/mtdsplit_bcm63xx.c +new file mode 100644 +index 000000000000..3a4b8a754fde +--- /dev/null ++++ b/drivers/mtd/mtdsplit/mtdsplit_bcm63xx.c +@@ -0,0 +1,186 @@ ++/* ++ * Firmware MTD split for BCM63XX, based on bcm63xxpart.c ++ * ++ * Copyright (C) 2006-2008 Florian Fainelli ++ * Copyright (C) 2006-2008 Mike Albon ++ * Copyright (C) 2009-2010 Daniel Dickinson ++ * Copyright (C) 2011-2013 Jonas Gorski ++ * Copyright (C) 2015 Simon Arlott ++ * Copyright (C) 2017 Ãlvaro Fernández Rojas ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation. ++ * ++ */ ++ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mtdsplit.h" ++ ++/* Ensure strings read from flash structs are null terminated */ ++#define STR_NULL_TERMINATE(x) \ ++ do { char *_str = (x); _str[sizeof(x) - 1] = 0; } while (0) ++ ++#define BCM63XX_NR_PARTS 2 ++ ++static int bcm63xx_read_image_tag(struct mtd_info *master, loff_t offset, ++ struct bcm_tag *hdr) ++{ ++ int ret; ++ size_t retlen; ++ u32 computed_crc; ++ ++ ret = mtd_read(master, offset, sizeof(*hdr), &retlen, (void *) hdr); ++ if (ret) ++ return ret; ++ ++ if (retlen != sizeof(*hdr)) ++ return -EIO; ++ ++ computed_crc = crc32_le(IMAGETAG_CRC_START, (u8 *)hdr, ++ offsetof(struct bcm_tag, header_crc)); ++ if (computed_crc == hdr->header_crc) { ++ STR_NULL_TERMINATE(hdr->board_id); ++ STR_NULL_TERMINATE(hdr->tag_version); ++ ++ pr_info("CFE image tag found at 0x%llx with version %s, " ++ "board type %s\n", offset, hdr->tag_version, ++ hdr->board_id); ++ ++ return 0; ++ } else { ++ pr_err("CFE image tag at 0x%llx CRC invalid " ++ "(expected %08x, actual %08x)\n", ++ offset, hdr->header_crc, computed_crc); ++ ++ return 1; ++ } ++} ++ ++static int bcm63xx_parse_partitions(struct mtd_info *master, ++ const struct mtd_partition **pparts, ++ struct bcm_tag *hdr) ++{ ++ struct mtd_partition *parts; ++ unsigned int flash_image_start; ++ unsigned int kernel_address; ++ unsigned int kernel_length; ++ size_t kernel_offset = 0, kernel_size = 0; ++ size_t rootfs_offset = 0, rootfs_size = 0; ++ int kernel_part, rootfs_part; ++ ++ STR_NULL_TERMINATE(hdr->flash_image_start); ++ if (kstrtouint(hdr->flash_image_start, 10, &flash_image_start) || ++ flash_image_start < BCM963XX_EXTENDED_SIZE) { ++ pr_err("invalid rootfs address: %*ph\n", ++ (int) sizeof(hdr->flash_image_start), ++ hdr->flash_image_start); ++ return -EINVAL; ++ } ++ ++ STR_NULL_TERMINATE(hdr->kernel_address); ++ if (kstrtouint(hdr->kernel_address, 10, &kernel_address) || ++ kernel_address < BCM963XX_EXTENDED_SIZE) { ++ pr_err("invalid kernel address: %*ph\n", ++ (int) sizeof(hdr->kernel_address), hdr->kernel_address); ++ return -EINVAL; ++ } ++ ++ STR_NULL_TERMINATE(hdr->kernel_length); ++ if (kstrtouint(hdr->kernel_length, 10, &kernel_length) || ++ !kernel_length) { ++ pr_err("invalid kernel length: %*ph\n", ++ (int) sizeof(hdr->kernel_length), hdr->kernel_length); ++ return -EINVAL; ++ } ++ ++ kernel_offset = kernel_address - BCM963XX_EXTENDED_SIZE - ++ mtdpart_get_offset(master); ++ kernel_size = kernel_length; ++ ++ if (flash_image_start < kernel_address) { ++ /* rootfs first */ ++ rootfs_part = 0; ++ kernel_part = 1; ++ rootfs_offset = flash_image_start - BCM963XX_EXTENDED_SIZE - ++ mtdpart_get_offset(master); ++ rootfs_size = kernel_offset - rootfs_offset; ++ } else { ++ /* kernel first */ ++ kernel_part = 0; ++ rootfs_part = 1; ++ rootfs_offset = kernel_offset + kernel_size; ++ rootfs_size = master->size - rootfs_offset; ++ } ++ ++ if (mtd_check_rootfs_magic(master, rootfs_offset, NULL)) ++ pr_warn("rootfs magic not found\n"); ++ ++ parts = kzalloc(BCM63XX_NR_PARTS * sizeof(*parts), GFP_KERNEL); ++ if (!parts) ++ return -ENOMEM; ++ ++ parts[kernel_part].name = KERNEL_PART_NAME; ++ parts[kernel_part].offset = kernel_offset; ++ parts[kernel_part].size = kernel_size; ++ ++ parts[rootfs_part].name = ROOTFS_PART_NAME; ++ parts[rootfs_part].offset = rootfs_offset; ++ parts[rootfs_part].size = rootfs_size; ++ ++ *pparts = parts; ++ return BCM63XX_NR_PARTS; ++} ++ ++static int mtdsplit_parse_bcm63xx(struct mtd_info *master, ++ const struct mtd_partition **pparts, ++ struct mtd_part_parser_data *data) ++{ ++ struct bcm_tag hdr; ++ loff_t offset; ++ ++ if (mtd_type_is_nand(master)) ++ return -EINVAL; ++ ++ /* find bcm63xx_cfe image on erase block boundaries */ ++ for (offset = 0; offset < master->size; offset += master->erasesize) { ++ if (!bcm63xx_read_image_tag(master, offset, (void *) &hdr)) ++ return bcm63xx_parse_partitions(master, pparts, ++ (void *) &hdr); ++ } ++ ++ return -EINVAL; ++} ++ ++static const struct of_device_id mtdsplit_fit_of_match_table[] = { ++ { .compatible = "brcm,bcm963xx-imagetag" }, ++ { }, ++}; ++ ++static struct mtd_part_parser mtdsplit_bcm63xx_parser = { ++ .owner = THIS_MODULE, ++ .name = "bcm63xx-fw", ++ .of_match_table = mtdsplit_fit_of_match_table, ++ .parse_fn = mtdsplit_parse_bcm63xx, ++ .type = MTD_PARSER_TYPE_FIRMWARE, ++}; ++ ++static int __init mtdsplit_bcm63xx_init(void) ++{ ++ register_mtd_parser(&mtdsplit_bcm63xx_parser); ++ ++ return 0; ++} ++ ++module_init(mtdsplit_bcm63xx_init); +diff --git a/drivers/mtd/mtdsplit/mtdsplit_bcm_wfi.c b/drivers/mtd/mtdsplit/mtdsplit_bcm_wfi.c +new file mode 100644 +index 000000000000..1cafc91fded3 +--- /dev/null ++++ b/drivers/mtd/mtdsplit/mtdsplit_bcm_wfi.c +@@ -0,0 +1,535 @@ ++/* ++ * MTD split for Broadcom Whole Flash Image ++ * ++ * Copyright (C) 2020 Ãlvaro Fernández Rojas ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation. ++ * ++ */ ++ ++#define je16_to_cpu(x) ((x).v16) ++#define je32_to_cpu(x) ((x).v32) ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mtdsplit.h" ++ ++#define char_to_num(c) ((c >= '0' && c <= '9') ? (c - '0') : (0)) ++ ++#define BCM_WFI_PARTS 3 ++#define BCM_WFI_SPLIT_PARTS 2 ++ ++#define CFERAM_NAME "cferam" ++#define CFERAM_NAME_LEN (sizeof(CFERAM_NAME) - 1) ++#define CFERAM_NAME_MAX_LEN 32 ++#define KERNEL_NAME "vmlinux.lz" ++#define KERNEL_NAME_LEN (sizeof(KERNEL_NAME) - 1) ++#define OPENWRT_NAME "1-openwrt" ++#define OPENWRT_NAME_LEN (sizeof(OPENWRT_NAME) - 1) ++ ++#define UBI_MAGIC 0x55424923 ++ ++#define CFE_MAGIC_PFX "cferam." ++#define CFE_MAGIC_PFX_LEN (sizeof(CFE_MAGIC_PFX) - 1) ++#define CFE_MAGIC "cferam.000" ++#define CFE_MAGIC_LEN (sizeof(CFE_MAGIC) - 1) ++#define SERCOMM_MAGIC_PFX "eRcOmM." ++#define SERCOMM_MAGIC_PFX_LEN (sizeof(SERCOMM_MAGIC_PFX) - 1) ++#define SERCOMM_MAGIC "eRcOmM.000" ++#define SERCOMM_MAGIC_LEN (sizeof(SERCOMM_MAGIC) - 1) ++ ++#define PART_CFERAM "cferam" ++#define PART_FIRMWARE "firmware" ++#define PART_IMAGE_1 "img1" ++#define PART_IMAGE_2 "img2" ++ ++static u32 jffs2_dirent_crc(struct jffs2_raw_dirent *node) ++{ ++ return crc32(0, node, sizeof(struct jffs2_raw_dirent) - 8); ++} ++ ++static bool jffs2_dirent_valid(struct jffs2_raw_dirent *node) ++{ ++ return ((je16_to_cpu(node->magic) == JFFS2_MAGIC_BITMASK) && ++ (je16_to_cpu(node->nodetype) == JFFS2_NODETYPE_DIRENT) && ++ je32_to_cpu(node->ino) && ++ je32_to_cpu(node->node_crc) == jffs2_dirent_crc(node)); ++} ++ ++static int jffs2_find_file(struct mtd_info *mtd, uint8_t *buf, ++ const char *name, size_t name_len, ++ loff_t *offs, loff_t size, ++ char **out_name, size_t *out_name_len) ++{ ++ const loff_t end = *offs + size; ++ struct jffs2_raw_dirent *node; ++ bool valid = false; ++ size_t retlen; ++ uint16_t magic; ++ int rc; ++ ++ for (; *offs < end; *offs += mtd->erasesize) { ++ unsigned int block_offs = 0; ++ ++ /* Skip CFE erased blocks */ ++ rc = mtd_read(mtd, *offs, sizeof(magic), &retlen, ++ (void *) &magic); ++ if (rc || retlen != sizeof(magic)) { ++ continue; ++ } ++ ++ /* Skip blocks not starting with JFFS2 magic */ ++ if (magic != JFFS2_MAGIC_BITMASK) ++ continue; ++ ++ /* Read full block */ ++ rc = mtd_read(mtd, *offs, mtd->erasesize, &retlen, ++ (void *) buf); ++ if (rc) ++ return rc; ++ if (retlen != mtd->erasesize) ++ return -EINVAL; ++ ++ while (block_offs < mtd->erasesize) { ++ node = (struct jffs2_raw_dirent *) &buf[block_offs]; ++ ++ if (!jffs2_dirent_valid(node)) { ++ block_offs += 4; ++ continue; ++ } ++ ++ if (!memcmp(node->name, OPENWRT_NAME, ++ OPENWRT_NAME_LEN)) { ++ valid = true; ++ } else if (!memcmp(node->name, name, name_len)) { ++ if (!valid) ++ return -EINVAL; ++ ++ if (out_name) ++ *out_name = kstrndup(node->name, ++ node->nsize, ++ GFP_KERNEL); ++ ++ if (out_name_len) ++ *out_name_len = node->nsize; ++ ++ return 0; ++ } ++ ++ block_offs += je32_to_cpu(node->totlen); ++ block_offs = (block_offs + 0x3) & ~0x3; ++ } ++ } ++ ++ return -ENOENT; ++} ++ ++static int ubifs_find(struct mtd_info *mtd, loff_t *offs, loff_t size) ++{ ++ const loff_t end = *offs + size; ++ uint32_t magic; ++ size_t retlen; ++ int rc; ++ ++ for (; *offs < end; *offs += mtd->erasesize) { ++ rc = mtd_read(mtd, *offs, sizeof(magic), &retlen, ++ (unsigned char *) &magic); ++ if (rc || retlen != sizeof(magic)) ++ continue; ++ ++ if (be32_to_cpu(magic) == UBI_MAGIC) ++ return 0; ++ } ++ ++ return -ENOENT; ++} ++ ++static int parse_bcm_wfi(struct mtd_info *master, ++ const struct mtd_partition **pparts, ++ uint8_t *buf, loff_t off, loff_t size, bool cfe_part) ++{ ++ struct device_node *mtd_node; ++ struct mtd_partition *parts; ++ loff_t cfe_off, kernel_off, rootfs_off; ++ unsigned int num_parts = BCM_WFI_PARTS, cur_part = 0; ++ const char *cferam_name = CFERAM_NAME; ++ size_t cferam_name_len; ++ int ret; ++ ++ mtd_node = mtd_get_of_node(master); ++ if (mtd_node) ++ of_property_read_string(mtd_node, "brcm,cferam", &cferam_name); ++ ++ cferam_name_len = strnlen(cferam_name, CFERAM_NAME_MAX_LEN); ++ if (cferam_name_len > 0) ++ cferam_name_len--; ++ ++ if (cfe_part) { ++ num_parts++; ++ cfe_off = off; ++ ++ ret = jffs2_find_file(master, buf, cferam_name, ++ cferam_name_len, &cfe_off, ++ size - (cfe_off - off), NULL, NULL); ++ if (ret) ++ return ret; ++ ++ kernel_off = cfe_off + master->erasesize; ++ } else { ++ kernel_off = off; ++ } ++ ++ ret = jffs2_find_file(master, buf, KERNEL_NAME, KERNEL_NAME_LEN, ++ &kernel_off, size - (kernel_off - off), ++ NULL, NULL); ++ if (ret) ++ return ret; ++ ++ rootfs_off = kernel_off + master->erasesize; ++ ret = ubifs_find(master, &rootfs_off, size - (rootfs_off - off)); ++ if (ret) ++ return ret; ++ ++ parts = kzalloc(num_parts * sizeof(*parts), GFP_KERNEL); ++ if (!parts) ++ return -ENOMEM; ++ ++ if (cfe_part) { ++ parts[cur_part].name = PART_CFERAM; ++ parts[cur_part].mask_flags = MTD_WRITEABLE; ++ parts[cur_part].offset = cfe_off; ++ parts[cur_part].size = kernel_off - cfe_off; ++ cur_part++; ++ } ++ ++ parts[cur_part].name = PART_FIRMWARE; ++ parts[cur_part].offset = kernel_off; ++ parts[cur_part].size = size - (kernel_off - off); ++ cur_part++; ++ ++ parts[cur_part].name = KERNEL_PART_NAME; ++ parts[cur_part].offset = kernel_off; ++ parts[cur_part].size = rootfs_off - kernel_off; ++ cur_part++; ++ ++ parts[cur_part].name = UBI_PART_NAME; ++ parts[cur_part].offset = rootfs_off; ++ parts[cur_part].size = size - (rootfs_off - off); ++ cur_part++; ++ ++ *pparts = parts; ++ ++ return num_parts; ++} ++ ++static int mtdsplit_parse_bcm_wfi(struct mtd_info *master, ++ const struct mtd_partition **pparts, ++ struct mtd_part_parser_data *data) ++{ ++ struct device_node *mtd_node; ++ bool cfe_part = true; ++ uint8_t *buf; ++ int ret; ++ ++ mtd_node = mtd_get_of_node(master); ++ if (!mtd_node) ++ return -EINVAL; ++ ++ buf = kzalloc(master->erasesize, GFP_KERNEL); ++ if (!buf) ++ return -ENOMEM; ++ ++ if (of_property_read_bool(mtd_node, "brcm,no-cferam")) ++ cfe_part = false; ++ ++ ret = parse_bcm_wfi(master, pparts, buf, 0, master->size, cfe_part); ++ ++ kfree(buf); ++ ++ return ret; ++} ++ ++static const struct of_device_id mtdsplit_bcm_wfi_of_match[] = { ++ { .compatible = "brcm,wfi" }, ++ { }, ++}; ++ ++static struct mtd_part_parser mtdsplit_bcm_wfi_parser = { ++ .owner = THIS_MODULE, ++ .name = "bcm-wfi-fw", ++ .of_match_table = mtdsplit_bcm_wfi_of_match, ++ .parse_fn = mtdsplit_parse_bcm_wfi, ++ .type = MTD_PARSER_TYPE_FIRMWARE, ++}; ++ ++static int cferam_bootflag_value(const char *name, size_t name_len) ++{ ++ int rc = -ENOENT; ++ ++ if (name && ++ (name_len >= CFE_MAGIC_LEN) && ++ !memcmp(name, CFE_MAGIC_PFX, CFE_MAGIC_PFX_LEN)) { ++ rc = char_to_num(name[CFE_MAGIC_PFX_LEN + 0]) * 100; ++ rc += char_to_num(name[CFE_MAGIC_PFX_LEN + 1]) * 10; ++ rc += char_to_num(name[CFE_MAGIC_PFX_LEN + 2]) * 1; ++ } ++ ++ return rc; ++} ++ ++static int mtdsplit_parse_bcm_wfi_split(struct mtd_info *master, ++ const struct mtd_partition **pparts, ++ struct mtd_part_parser_data *data) ++{ ++ struct mtd_partition *parts; ++ loff_t cfe_off; ++ loff_t img1_off = 0; ++ loff_t img2_off = master->size / 2; ++ loff_t img1_size = (img2_off - img1_off); ++ loff_t img2_size = (master->size - img2_off); ++ loff_t active_off, inactive_off; ++ loff_t active_size, inactive_size; ++ const char *inactive_name; ++ uint8_t *buf; ++ char *cfe1_name = NULL, *cfe2_name = NULL; ++ size_t cfe1_size = 0, cfe2_size = 0; ++ int ret; ++ int bf1, bf2; ++ ++ buf = kzalloc(master->erasesize, GFP_KERNEL); ++ if (!buf) ++ return -ENOMEM; ++ ++ cfe_off = img1_off; ++ ret = jffs2_find_file(master, buf, CFERAM_NAME, CFERAM_NAME_LEN, ++ &cfe_off, img1_size, &cfe1_name, &cfe1_size); ++ ++ cfe_off = img2_off; ++ ret = jffs2_find_file(master, buf, CFERAM_NAME, CFERAM_NAME_LEN, ++ &cfe_off, img2_size, &cfe2_name, &cfe2_size); ++ ++ bf1 = cferam_bootflag_value(cfe1_name, cfe1_size); ++ if (bf1 >= 0) ++ printk("cferam: bootflag1=%d\n", bf1); ++ ++ bf2 = cferam_bootflag_value(cfe2_name, cfe2_size); ++ if (bf2 >= 0) ++ printk("cferam: bootflag2=%d\n", bf2); ++ ++ kfree(cfe1_name); ++ kfree(cfe2_name); ++ ++ if (bf1 >= bf2) { ++ active_off = img1_off; ++ active_size = img1_size; ++ inactive_off = img2_off; ++ inactive_size = img2_size; ++ inactive_name = PART_IMAGE_2; ++ } else { ++ active_off = img2_off; ++ active_size = img2_size; ++ inactive_off = img1_off; ++ inactive_size = img1_size; ++ inactive_name = PART_IMAGE_1; ++ } ++ ++ ret = parse_bcm_wfi(master, pparts, buf, active_off, active_size, true); ++ ++ kfree(buf); ++ ++ if (ret > 0) { ++ parts = kzalloc((ret + 1) * sizeof(*parts), GFP_KERNEL); ++ if (!parts) ++ return -ENOMEM; ++ ++ memcpy(parts, *pparts, ret * sizeof(*parts)); ++ kfree(*pparts); ++ ++ parts[ret].name = inactive_name; ++ parts[ret].offset = inactive_off; ++ parts[ret].size = inactive_size; ++ ret++; ++ ++ *pparts = parts; ++ } else { ++ parts = kzalloc(BCM_WFI_SPLIT_PARTS * sizeof(*parts), GFP_KERNEL); ++ ++ parts[0].name = PART_IMAGE_1; ++ parts[0].offset = img1_off; ++ parts[0].size = img1_size; ++ ++ parts[1].name = PART_IMAGE_2; ++ parts[1].offset = img2_off; ++ parts[1].size = img2_size; ++ ++ *pparts = parts; ++ } ++ ++ return ret; ++} ++ ++static const struct of_device_id mtdsplit_bcm_wfi_split_of_match[] = { ++ { .compatible = "brcm,wfi-split" }, ++ { }, ++}; ++ ++static struct mtd_part_parser mtdsplit_bcm_wfi_split_parser = { ++ .owner = THIS_MODULE, ++ .name = "bcm-wfi-split-fw", ++ .of_match_table = mtdsplit_bcm_wfi_split_of_match, ++ .parse_fn = mtdsplit_parse_bcm_wfi_split, ++ .type = MTD_PARSER_TYPE_FIRMWARE, ++}; ++ ++static int sercomm_bootflag_value(struct mtd_info *mtd, uint8_t *buf) ++{ ++ size_t retlen; ++ loff_t offs; ++ int rc; ++ ++ for (offs = 0; offs < mtd->size; offs += mtd->erasesize) { ++ rc = mtd_read(mtd, offs, SERCOMM_MAGIC_LEN, &retlen, buf); ++ if (rc || retlen != SERCOMM_MAGIC_LEN) ++ continue; ++ ++ if (memcmp(buf, SERCOMM_MAGIC_PFX, SERCOMM_MAGIC_PFX_LEN)) ++ continue; ++ ++ rc = char_to_num(buf[SERCOMM_MAGIC_PFX_LEN + 0]) * 100; ++ rc += char_to_num(buf[SERCOMM_MAGIC_PFX_LEN + 1]) * 10; ++ rc += char_to_num(buf[SERCOMM_MAGIC_PFX_LEN + 2]) * 1; ++ ++ return rc; ++ } ++ ++ return -ENOENT; ++} ++ ++static int mtdsplit_parse_ser_wfi(struct mtd_info *master, ++ const struct mtd_partition **pparts, ++ struct mtd_part_parser_data *data) ++{ ++ struct mtd_partition *parts; ++ struct mtd_info *mtd_bf1, *mtd_bf2; ++ loff_t img1_off = 0; ++ loff_t img2_off = master->size / 2; ++ loff_t img1_size = (img2_off - img1_off); ++ loff_t img2_size = (master->size - img2_off); ++ loff_t active_off, inactive_off; ++ loff_t active_size, inactive_size; ++ const char *inactive_name; ++ uint8_t *buf; ++ int bf1, bf2; ++ int ret; ++ ++ mtd_bf1 = get_mtd_device_nm("bootflag1"); ++ if (IS_ERR(mtd_bf1)) ++ return -ENOENT; ++ ++ mtd_bf2 = get_mtd_device_nm("bootflag2"); ++ if (IS_ERR(mtd_bf2)) ++ return -ENOENT; ++ ++ buf = kzalloc(master->erasesize, GFP_KERNEL); ++ if (!buf) ++ return -ENOMEM; ++ ++ bf1 = sercomm_bootflag_value(mtd_bf1, buf); ++ if (bf1 >= 0) ++ printk("sercomm: bootflag1=%d\n", bf1); ++ ++ bf2 = sercomm_bootflag_value(mtd_bf2, buf); ++ if (bf2 >= 0) ++ printk("sercomm: bootflag2=%d\n", bf2); ++ ++ if (bf1 == bf2 && bf2 >= 0) { ++ struct erase_info bf_erase; ++ ++ bf2 = -ENOENT; ++ bf_erase.addr = 0; ++ bf_erase.len = mtd_bf2->size; ++ mtd_erase(mtd_bf2, &bf_erase); ++ } ++ ++ if (bf1 >= bf2) { ++ active_off = img1_off; ++ active_size = img1_size; ++ inactive_off = img2_off; ++ inactive_size = img2_size; ++ inactive_name = PART_IMAGE_2; ++ } else { ++ active_off = img2_off; ++ active_size = img2_size; ++ inactive_off = img1_off; ++ inactive_size = img1_size; ++ inactive_name = PART_IMAGE_1; ++ } ++ ++ ret = parse_bcm_wfi(master, pparts, buf, active_off, active_size, false); ++ ++ kfree(buf); ++ ++ if (ret > 0) { ++ parts = kzalloc((ret + 1) * sizeof(*parts), GFP_KERNEL); ++ if (!parts) ++ return -ENOMEM; ++ ++ memcpy(parts, *pparts, ret * sizeof(*parts)); ++ kfree(*pparts); ++ ++ parts[ret].name = inactive_name; ++ parts[ret].offset = inactive_off; ++ parts[ret].size = inactive_size; ++ ret++; ++ ++ *pparts = parts; ++ } else { ++ parts = kzalloc(BCM_WFI_SPLIT_PARTS * sizeof(*parts), GFP_KERNEL); ++ ++ parts[0].name = PART_IMAGE_1; ++ parts[0].offset = img1_off; ++ parts[0].size = img1_size; ++ ++ parts[1].name = PART_IMAGE_2; ++ parts[1].offset = img2_off; ++ parts[1].size = img2_size; ++ ++ *pparts = parts; ++ } ++ ++ return ret; ++} ++ ++static const struct of_device_id mtdsplit_ser_wfi_of_match[] = { ++ { .compatible = "sercomm,wfi" }, ++ { }, ++}; ++ ++static struct mtd_part_parser mtdsplit_ser_wfi_parser = { ++ .owner = THIS_MODULE, ++ .name = "ser-wfi-fw", ++ .of_match_table = mtdsplit_ser_wfi_of_match, ++ .parse_fn = mtdsplit_parse_ser_wfi, ++ .type = MTD_PARSER_TYPE_FIRMWARE, ++}; ++ ++static int __init mtdsplit_bcm_wfi_init(void) ++{ ++ register_mtd_parser(&mtdsplit_bcm_wfi_parser); ++ register_mtd_parser(&mtdsplit_bcm_wfi_split_parser); ++ register_mtd_parser(&mtdsplit_ser_wfi_parser); ++ ++ return 0; ++} ++ ++module_init(mtdsplit_bcm_wfi_init); +diff --git a/drivers/mtd/mtdsplit/mtdsplit_brnimage.c b/drivers/mtd/mtdsplit/mtdsplit_brnimage.c +new file mode 100644 +index 000000000000..3f2d79601a14 +--- /dev/null ++++ b/drivers/mtd/mtdsplit/mtdsplit_brnimage.c +@@ -0,0 +1,104 @@ ++/* ++ * Copyright (C) 2012 John Crispin ++ * Copyright (C) 2015 Martin Blumenstingl ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mtdsplit.h" ++ ++#define BRNIMAGE_NR_PARTS 2 ++ ++#define BRNIMAGE_ALIGN_BYTES 0x400 ++#define BRNIMAGE_FOOTER_SIZE 12 ++ ++#define BRNIMAGE_MIN_OVERHEAD (BRNIMAGE_FOOTER_SIZE) ++#define BRNIMAGE_MAX_OVERHEAD (BRNIMAGE_ALIGN_BYTES + BRNIMAGE_FOOTER_SIZE) ++ ++static int mtdsplit_parse_brnimage(struct mtd_info *master, ++ const struct mtd_partition **pparts, ++ struct mtd_part_parser_data *data) ++{ ++ struct mtd_partition *parts; ++ uint32_t buf; ++ unsigned long rootfs_offset, rootfs_size, kernel_size; ++ size_t len; ++ int ret = 0; ++ ++ for (rootfs_offset = 0; rootfs_offset < master->size; ++ rootfs_offset += BRNIMAGE_ALIGN_BYTES) { ++ ret = mtd_check_rootfs_magic(master, rootfs_offset, NULL); ++ if (!ret) ++ break; ++ } ++ ++ if (ret) ++ return ret; ++ ++ if (rootfs_offset >= master->size) ++ return -EINVAL; ++ ++ ret = mtd_read(master, rootfs_offset - BRNIMAGE_FOOTER_SIZE, 4, &len, ++ (void *)&buf); ++ if (ret) ++ return ret; ++ ++ if (len != 4) ++ return -EIO; ++ ++ kernel_size = le32_to_cpu(buf); ++ ++ if (kernel_size > (rootfs_offset - BRNIMAGE_MIN_OVERHEAD)) ++ return -EINVAL; ++ ++ if (kernel_size < (rootfs_offset - BRNIMAGE_MAX_OVERHEAD)) ++ return -EINVAL; ++ ++ /* ++ * The footer must be untouched as it contains the checksum of the ++ * original brnImage (kernel + squashfs)! ++ */ ++ rootfs_size = master->size - rootfs_offset - BRNIMAGE_FOOTER_SIZE; ++ ++ parts = kzalloc(BRNIMAGE_NR_PARTS * sizeof(*parts), GFP_KERNEL); ++ if (!parts) ++ return -ENOMEM; ++ ++ parts[0].name = KERNEL_PART_NAME; ++ parts[0].offset = 0; ++ parts[0].size = kernel_size; ++ ++ parts[1].name = ROOTFS_PART_NAME; ++ parts[1].offset = rootfs_offset; ++ parts[1].size = rootfs_size; ++ ++ *pparts = parts; ++ return BRNIMAGE_NR_PARTS; ++} ++ ++static struct mtd_part_parser mtdsplit_brnimage_parser = { ++ .owner = THIS_MODULE, ++ .name = "brnimage-fw", ++ .parse_fn = mtdsplit_parse_brnimage, ++ .type = MTD_PARSER_TYPE_FIRMWARE, ++}; ++ ++static int __init mtdsplit_brnimage_init(void) ++{ ++ register_mtd_parser(&mtdsplit_brnimage_parser); ++ ++ return 0; ++} ++ ++subsys_initcall(mtdsplit_brnimage_init); +diff --git a/drivers/mtd/mtdsplit/mtdsplit_cfe_bootfs.c b/drivers/mtd/mtdsplit/mtdsplit_cfe_bootfs.c +new file mode 100644 +index 000000000000..a3474c9dc274 +--- /dev/null ++++ b/drivers/mtd/mtdsplit/mtdsplit_cfe_bootfs.c +@@ -0,0 +1,90 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Copyright (C) 2021 RafaÅ‚ MiÅ‚ecki ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mtdsplit.h" ++ ++#define je16_to_cpu(x) ((x).v16) ++#define je32_to_cpu(x) ((x).v32) ++ ++#define NR_PARTS 2 ++ ++static int mtdsplit_cfe_bootfs_parse(struct mtd_info *mtd, ++ const struct mtd_partition **pparts, ++ struct mtd_part_parser_data *data) ++{ ++ struct jffs2_raw_dirent node; ++ enum mtdsplit_part_type type; ++ struct mtd_partition *parts; ++ size_t rootfs_offset; ++ size_t retlen; ++ size_t offset; ++ int err; ++ ++ /* Don't parse backup partitions */ ++ if (strcmp(mtd->name, "firmware")) ++ return -EINVAL; ++ ++ /* Find the end of JFFS2 bootfs partition */ ++ offset = 0; ++ do { ++ err = mtd_read(mtd, offset, sizeof(node), &retlen, (void *)&node); ++ if (err || retlen != sizeof(node)) ++ break; ++ ++ if (je16_to_cpu(node.magic) != JFFS2_MAGIC_BITMASK) ++ break; ++ ++ offset += je32_to_cpu(node.totlen); ++ offset = (offset + 0x3) & ~0x3; ++ } while (offset < mtd->size); ++ ++ /* Find rootfs partition that follows the bootfs */ ++ err = mtd_find_rootfs_from(mtd, mtd->erasesize, mtd->size, &rootfs_offset, &type); ++ if (err) ++ return err; ++ ++ parts = kzalloc(NR_PARTS * sizeof(*parts), GFP_KERNEL); ++ if (!parts) ++ return -ENOMEM; ++ ++ parts[0].name = "bootfs"; ++ parts[0].offset = 0; ++ parts[0].size = rootfs_offset; ++ ++ if (type == MTDSPLIT_PART_TYPE_UBI) ++ parts[1].name = UBI_PART_NAME; ++ else ++ parts[1].name = ROOTFS_PART_NAME; ++ parts[1].offset = rootfs_offset; ++ parts[1].size = mtd->size - rootfs_offset; ++ ++ *pparts = parts; ++ ++ return NR_PARTS; ++} ++ ++static const struct of_device_id mtdsplit_cfe_bootfs_of_match_table[] = { ++ { .compatible = "brcm,bcm4908-firmware" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, mtdsplit_cfe_bootfs_of_match_table); ++ ++static struct mtd_part_parser mtdsplit_cfe_bootfs_parser = { ++ .owner = THIS_MODULE, ++ .name = "cfe-bootfs", ++ .of_match_table = mtdsplit_cfe_bootfs_of_match_table, ++ .parse_fn = mtdsplit_cfe_bootfs_parse, ++}; ++ ++module_mtd_part_parser(mtdsplit_cfe_bootfs_parser); +diff --git a/drivers/mtd/mtdsplit/mtdsplit_elf.c b/drivers/mtd/mtdsplit/mtdsplit_elf.c +new file mode 100644 +index 000000000000..47818416f61c +--- /dev/null ++++ b/drivers/mtd/mtdsplit/mtdsplit_elf.c +@@ -0,0 +1,287 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* ++ * MTD splitter for ELF loader firmware partitions ++ * ++ * Copyright (C) 2020 Sander Vanheule ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the Free ++ * Software Foundation; version 2. ++ * ++ * To parse the ELF kernel loader, a small ELF parser is used that can ++ * handle both ELF32 or ELF64 class loaders. The splitter assumes that the ++ * kernel is always located before the rootfs, whether it is embedded in the ++ * loader or not. ++ * ++ * The kernel image is preferably embedded inside the ELF loader, so the end ++ * of the loader equals the end of the kernel partition. This is due to the ++ * way mtd_find_rootfs_from searches for the the rootfs: ++ * - if the kernel image is embedded in the loader, the appended rootfs may ++ * follow the loader immediately, within the same erase block. ++ * - if the kernel image is not embedded in the loader, but placed at some ++ * offset behind the loader (OKLI-style loader), the rootfs must be ++ * aligned to an erase-block after the loader and kernel image. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mtdsplit.h" ++ ++#define ELF_NR_PARTS 2 ++ ++#define ELF_MAGIC 0x7f454c46 /* 0x7f E L F */ ++#define ELF_CLASS_32 1 ++#define ELF_CLASS_64 2 ++ ++struct elf_header_ident { ++ uint32_t magic; ++ uint8_t class; ++ uint8_t data; ++ uint8_t version; ++ uint8_t osabi; ++ uint8_t abiversion; ++ uint8_t pad[7]; ++}; ++ ++struct elf_header_32 { ++ uint16_t type; ++ uint16_t machine; ++ uint32_t version; ++ uint32_t entry; ++ uint32_t phoff; ++ uint32_t shoff; ++ uint32_t flags; ++ uint16_t ehsize; ++ uint16_t phentsize; ++ uint16_t phnum; ++ uint16_t shentsize; ++ uint16_t shnum; ++ uint16_t shstrndx; ++}; ++ ++struct elf_header_64 { ++ uint16_t type; ++ uint16_t machine; ++ uint32_t version; ++ uint64_t entry; ++ uint64_t phoff; ++ uint64_t shoff; ++ uint32_t flags; ++ uint16_t ehsize; ++ uint16_t phentsize; ++ uint16_t phnum; ++ uint16_t shentsize; ++ uint16_t shnum; ++ uint16_t shstrndx; ++}; ++ ++struct elf_header { ++ struct elf_header_ident ident; ++ union { ++ struct elf_header_32 elf32; ++ struct elf_header_64 elf64; ++ }; ++}; ++ ++struct elf_program_header_32 { ++ uint32_t type; ++ uint32_t offset; ++ uint32_t vaddr; ++ uint32_t paddr; ++ uint32_t filesize; ++ uint32_t memsize; ++ uint32_t flags; ++}; ++ ++struct elf_program_header_64 { ++ uint32_t type; ++ uint32_t flags; ++ uint64_t offset; ++ uint64_t vaddr; ++ uint64_t paddr; ++ uint64_t filesize; ++ uint64_t memsize; ++}; ++ ++ ++static int mtdsplit_elf_read_mtd(struct mtd_info *mtd, size_t offset, ++ uint8_t *dst, size_t len) ++{ ++ size_t retlen; ++ int ret; ++ ++ ret = mtd_read(mtd, offset, len, &retlen, dst); ++ if (ret) { ++ pr_debug("read error in \"%s\"\n", mtd->name); ++ return ret; ++ } ++ ++ if (retlen != len) { ++ pr_debug("short read in \"%s\"\n", mtd->name); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++static int elf32_determine_size(struct mtd_info *mtd, struct elf_header *hdr, ++ size_t *size) ++{ ++ struct elf_header_32 *hdr32 = &(hdr->elf32); ++ int err; ++ size_t section_end, ph_table_end, ph_entry; ++ struct elf_program_header_32 ph; ++ ++ *size = 0; ++ ++ if (hdr32->shoff > 0) { ++ *size = hdr32->shoff + hdr32->shentsize * hdr32->shnum; ++ return 0; ++ } ++ ++ ph_entry = hdr32->phoff; ++ ph_table_end = hdr32->phoff + hdr32->phentsize * hdr32->phnum; ++ ++ while (ph_entry < ph_table_end) { ++ err = mtdsplit_elf_read_mtd(mtd, ph_entry, (uint8_t *)(&ph), ++ sizeof(ph)); ++ if (err) ++ return err; ++ ++ section_end = ph.offset + ph.filesize; ++ if (section_end > *size) ++ *size = section_end; ++ ++ ph_entry += hdr32->phentsize; ++ } ++ ++ return 0; ++} ++ ++static int elf64_determine_size(struct mtd_info *mtd, struct elf_header *hdr, ++ size_t *size) ++{ ++ struct elf_header_64 *hdr64 = &(hdr->elf64); ++ int err; ++ size_t section_end, ph_table_end, ph_entry; ++ struct elf_program_header_64 ph; ++ ++ *size = 0; ++ ++ if (hdr64->shoff > 0) { ++ *size = hdr64->shoff + hdr64->shentsize * hdr64->shnum; ++ return 0; ++ } ++ ++ ph_entry = hdr64->phoff; ++ ph_table_end = hdr64->phoff + hdr64->phentsize * hdr64->phnum; ++ ++ while (ph_entry < ph_table_end) { ++ err = mtdsplit_elf_read_mtd(mtd, ph_entry, (uint8_t *)(&ph), ++ sizeof(ph)); ++ if (err) ++ return err; ++ ++ section_end = ph.offset + ph.filesize; ++ if (section_end > *size) ++ *size = section_end; ++ ++ ph_entry += hdr64->phentsize; ++ } ++ ++ return 0; ++} ++ ++static int mtdsplit_parse_elf(struct mtd_info *mtd, ++ const struct mtd_partition **pparts, ++ struct mtd_part_parser_data *data) ++{ ++ struct elf_header hdr; ++ size_t loader_size, rootfs_offset; ++ enum mtdsplit_part_type type; ++ struct mtd_partition *parts; ++ int err; ++ ++ err = mtdsplit_elf_read_mtd(mtd, 0, (uint8_t *)&hdr, sizeof(hdr)); ++ if (err) ++ return err; ++ ++ if (be32_to_cpu(hdr.ident.magic) != ELF_MAGIC) { ++ pr_debug("invalid ELF magic %08x\n", ++ be32_to_cpu(hdr.ident.magic)); ++ return -EINVAL; ++ } ++ ++ switch (hdr.ident.class) { ++ case ELF_CLASS_32: ++ err = elf32_determine_size(mtd, &hdr, &loader_size); ++ break; ++ case ELF_CLASS_64: ++ err = elf64_determine_size(mtd, &hdr, &loader_size); ++ break; ++ default: ++ pr_debug("invalid ELF class %i\n", hdr.ident.class); ++ err = -EINVAL; ++ } ++ ++ if (err) ++ return err; ++ ++ err = mtd_find_rootfs_from(mtd, loader_size, mtd->size, ++ &rootfs_offset, &type); ++ if (err) ++ return err; ++ ++ if (rootfs_offset == mtd->size) { ++ pr_debug("no rootfs found in \"%s\"\n", mtd->name); ++ return -ENODEV; ++ } ++ ++ parts = kzalloc(ELF_NR_PARTS * sizeof(*parts), GFP_KERNEL); ++ if (!parts) ++ return -ENOMEM; ++ ++ parts[0].name = KERNEL_PART_NAME; ++ parts[0].offset = 0; ++ parts[0].size = rootfs_offset; ++ ++ if (type == MTDSPLIT_PART_TYPE_UBI) ++ parts[1].name = UBI_PART_NAME; ++ else ++ parts[1].name = ROOTFS_PART_NAME; ++ parts[1].offset = rootfs_offset; ++ parts[1].size = mtd->size - rootfs_offset; ++ ++ *pparts = parts; ++ return ELF_NR_PARTS; ++} ++ ++static const struct of_device_id mtdsplit_elf_of_match_table[] = { ++ { .compatible = "openwrt,elf" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, mtdsplit_elf_of_match_table); ++ ++static struct mtd_part_parser mtdsplit_elf_parser = { ++ .owner = THIS_MODULE, ++ .name = "elf-loader-fw", ++ .of_match_table = mtdsplit_elf_of_match_table, ++ .parse_fn = mtdsplit_parse_elf, ++ .type = MTD_PARSER_TYPE_FIRMWARE, ++}; ++ ++static int __init mtdsplit_elf_init(void) ++{ ++ register_mtd_parser(&mtdsplit_elf_parser); ++ ++ return 0; ++} ++ ++subsys_initcall(mtdsplit_elf_init); +diff --git a/drivers/mtd/mtdsplit/mtdsplit_eva.c b/drivers/mtd/mtdsplit/mtdsplit_eva.c +new file mode 100644 +index 000000000000..55004a6d36d7 +--- /dev/null ++++ b/drivers/mtd/mtdsplit/mtdsplit_eva.c +@@ -0,0 +1,103 @@ ++/* ++ * Copyright (C) 2012 John Crispin ++ * Copyright (C) 2015 Martin Blumenstingl ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mtdsplit.h" ++ ++#define EVA_NR_PARTS 2 ++#define EVA_MAGIC 0xfeed1281 ++#define EVA_FOOTER_SIZE 0x18 ++#define EVA_DUMMY_SQUASHFS_SIZE 0x100 ++ ++struct eva_image_header { ++ uint32_t magic; ++ uint32_t size; ++}; ++ ++static int mtdsplit_parse_eva(struct mtd_info *master, ++ const struct mtd_partition **pparts, ++ struct mtd_part_parser_data *data) ++{ ++ struct mtd_partition *parts; ++ struct eva_image_header hdr; ++ size_t retlen; ++ unsigned long kernel_size, rootfs_offset; ++ int err; ++ ++ err = mtd_read(master, 0, sizeof(hdr), &retlen, (void *) &hdr); ++ if (err) ++ return err; ++ ++ if (retlen != sizeof(hdr)) ++ return -EIO; ++ ++ if (le32_to_cpu(hdr.magic) != EVA_MAGIC) ++ return -EINVAL; ++ ++ kernel_size = le32_to_cpu(hdr.size) + EVA_FOOTER_SIZE; ++ ++ /* rootfs starts at the next 0x10000 boundary: */ ++ rootfs_offset = round_up(kernel_size, 0x10000); ++ ++ /* skip the dummy EVA squashfs partition (with wrong endianness): */ ++ rootfs_offset += EVA_DUMMY_SQUASHFS_SIZE; ++ ++ if (rootfs_offset >= master->size) ++ return -EINVAL; ++ ++ err = mtd_check_rootfs_magic(master, rootfs_offset, NULL); ++ if (err) ++ return err; ++ ++ parts = kzalloc(EVA_NR_PARTS * sizeof(*parts), GFP_KERNEL); ++ if (!parts) ++ return -ENOMEM; ++ ++ parts[0].name = KERNEL_PART_NAME; ++ parts[0].offset = 0; ++ parts[0].size = kernel_size; ++ ++ parts[1].name = ROOTFS_PART_NAME; ++ parts[1].offset = rootfs_offset; ++ parts[1].size = master->size - rootfs_offset; ++ ++ *pparts = parts; ++ return EVA_NR_PARTS; ++} ++ ++static const struct of_device_id mtdsplit_eva_of_match_table[] = { ++ { .compatible = "avm,eva-firmware" }, ++ {}, ++}; ++ ++static struct mtd_part_parser mtdsplit_eva_parser = { ++ .owner = THIS_MODULE, ++ .name = "eva-fw", ++ .of_match_table = mtdsplit_eva_of_match_table, ++ .parse_fn = mtdsplit_parse_eva, ++ .type = MTD_PARSER_TYPE_FIRMWARE, ++}; ++ ++static int __init mtdsplit_eva_init(void) ++{ ++ register_mtd_parser(&mtdsplit_eva_parser); ++ ++ return 0; ++} ++ ++subsys_initcall(mtdsplit_eva_init); +diff --git a/drivers/mtd/mtdsplit/mtdsplit_fit.c b/drivers/mtd/mtdsplit/mtdsplit_fit.c +new file mode 100644 +index 000000000000..a271a676e10e +--- /dev/null ++++ b/drivers/mtd/mtdsplit/mtdsplit_fit.c +@@ -0,0 +1,365 @@ ++/* ++ * Copyright (c) 2015 The Linux Foundation ++ * Copyright (C) 2014 Gabor Juhos ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mtdsplit.h" ++ ++// string macros from git://git.denx.de/u-boot.git/include/image.h ++ ++#define FIT_IMAGES_PATH "/images" ++#define FIT_DATA_PROP "data" ++#define FIT_DATA_POSITION_PROP "data-position" ++#define FIT_DATA_OFFSET_PROP "data-offset" ++#define FIT_DATA_SIZE_PROP "data-size" ++ ++// functions from git://git.denx.de/u-boot.git/common/image-fit.c ++ ++/** ++ * fit_image_get_data - get data property and its size for a given component image node ++ * @fit: pointer to the FIT format image header ++ * @noffset: component image node offset ++ * @data: double pointer to void, will hold data property's data address ++ * @size: pointer to size_t, will hold data property's data size ++ * ++ * fit_image_get_data() finds data property in a given component image node. ++ * If the property is found its data start address and size are returned to ++ * the caller. ++ * ++ * returns: ++ * 0, on success ++ * -1, on failure ++ */ ++static int fit_image_get_data(const void *fit, int noffset, ++ const void **data, size_t *size) ++{ ++ int len; ++ ++ *data = fdt_getprop(fit, noffset, FIT_DATA_PROP, &len); ++ if (*data == NULL) { ++ *size = 0; ++ return -1; ++ } ++ ++ *size = len; ++ return 0; ++} ++ ++ ++/** ++ * Get 'data-offset' property from a given image node. ++ * ++ * @fit: pointer to the FIT image header ++ * @noffset: component image node offset ++ * @data_offset: holds the data-offset property ++ * ++ * returns: ++ * 0, on success ++ * -ENOENT if the property could not be found ++ */ ++static int fit_image_get_data_offset(const void *fit, int noffset, int *data_offset) ++{ ++ const fdt32_t *val; ++ ++ val = fdt_getprop(fit, noffset, FIT_DATA_OFFSET_PROP, NULL); ++ if (!val) ++ return -ENOENT; ++ ++ *data_offset = fdt32_to_cpu(*val); ++ ++ return 0; ++} ++ ++/** ++ * Get 'data-position' property from a given image node. ++ * ++ * @fit: pointer to the FIT image header ++ * @noffset: component image node offset ++ * @data_position: holds the data-position property ++ * ++ * returns: ++ * 0, on success ++ * -ENOENT if the property could not be found ++ */ ++static int fit_image_get_data_position(const void *fit, int noffset, ++ int *data_position) ++{ ++ const fdt32_t *val; ++ ++ val = fdt_getprop(fit, noffset, FIT_DATA_POSITION_PROP, NULL); ++ if (!val) ++ return -ENOENT; ++ ++ *data_position = fdt32_to_cpu(*val); ++ ++ return 0; ++} ++ ++/** ++ * Get 'data-size' property from a given image node. ++ * ++ * @fit: pointer to the FIT image header ++ * @noffset: component image node offset ++ * @data_size: holds the data-size property ++ * ++ * returns: ++ * 0, on success ++ * -ENOENT if the property could not be found ++ */ ++static int fit_image_get_data_size(const void *fit, int noffset, int *data_size) ++{ ++ const fdt32_t *val; ++ ++ val = fdt_getprop(fit, noffset, FIT_DATA_SIZE_PROP, NULL); ++ if (!val) ++ return -ENOENT; ++ ++ *data_size = fdt32_to_cpu(*val); ++ ++ return 0; ++} ++ ++/** ++ * fit_image_get_data_and_size - get data and its size including ++ * both embedded and external data ++ * @fit: pointer to the FIT format image header ++ * @noffset: component image node offset ++ * @data: double pointer to void, will hold data property's data address ++ * @size: pointer to size_t, will hold data property's data size ++ * ++ * fit_image_get_data_and_size() finds data and its size including ++ * both embedded and external data. If the property is found ++ * its data start address and size are returned to the caller. ++ * ++ * returns: ++ * 0, on success ++ * otherwise, on failure ++ */ ++static int fit_image_get_data_and_size(const void *fit, int noffset, ++ const void **data, size_t *size) ++{ ++ bool external_data = false; ++ int offset; ++ int len; ++ int ret; ++ ++ if (!fit_image_get_data_position(fit, noffset, &offset)) { ++ external_data = true; ++ } else if (!fit_image_get_data_offset(fit, noffset, &offset)) { ++ external_data = true; ++ /* ++ * For FIT with external data, figure out where ++ * the external images start. This is the base ++ * for the data-offset properties in each image. ++ */ ++ offset += ((fdt_totalsize(fit) + 3) & ~3); ++ } ++ ++ if (external_data) { ++ ret = fit_image_get_data_size(fit, noffset, &len); ++ if (!ret) { ++ *data = fit + offset; ++ *size = len; ++ } ++ } else { ++ ret = fit_image_get_data(fit, noffset, data, size); ++ } ++ ++ return ret; ++} ++ ++static int ++mtdsplit_fit_parse(struct mtd_info *mtd, ++ const struct mtd_partition **pparts, ++ struct mtd_part_parser_data *data) ++{ ++ struct device_node *np = mtd_get_of_node(mtd); ++ const char *cmdline_match = NULL; ++ struct fdt_header hdr; ++ size_t hdr_len, retlen; ++ size_t offset; ++ u32 offset_start = 0; ++ size_t fit_offset, fit_size; ++ size_t rootfs_offset, rootfs_size; ++ size_t data_size, img_total, max_size = 0; ++ struct mtd_partition *parts; ++ int ret, ndepth, noffset, images_noffset; ++ const void *img_data; ++ void *fit; ++ ++ of_property_read_string(np, "openwrt,cmdline-match", &cmdline_match); ++ if (cmdline_match && !strstr(saved_command_line, cmdline_match)) ++ return -ENODEV; ++ ++ of_property_read_u32(np, "openwrt,fit-offset", &offset_start); ++ ++ hdr_len = sizeof(struct fdt_header); ++ ++ /* Parse the MTD device & search for the FIT image location */ ++ for(offset = 0; offset + hdr_len <= mtd->size; offset += mtd->erasesize) { ++ ret = mtd_read(mtd, offset + offset_start, hdr_len, &retlen, (void*) &hdr); ++ if (ret) { ++ pr_err("read error in \"%s\" at offset 0x%llx\n", ++ mtd->name, (unsigned long long) offset); ++ return ret; ++ } ++ ++ if (retlen != hdr_len) { ++ pr_err("short read in \"%s\"\n", mtd->name); ++ return -EIO; ++ } ++ ++ /* Check the magic - see if this is a FIT image */ ++ if (be32_to_cpu(hdr.magic) != OF_DT_HEADER) { ++ pr_debug("no valid FIT image found in \"%s\" at offset %llx\n", ++ mtd->name, (unsigned long long) offset); ++ continue; ++ } ++ ++ /* We found a FIT image. Let's keep going */ ++ break; ++ } ++ ++ fit_offset = offset; ++ fit_size = be32_to_cpu(hdr.totalsize); ++ ++ if (fit_size == 0) { ++ pr_err("FIT image in \"%s\" at offset %llx has null size\n", ++ mtd->name, (unsigned long long) fit_offset); ++ return -ENODEV; ++ } ++ ++ /* ++ * Classic uImage.FIT has all data embedded into the FDT ++ * data structure. Hence the total size of the image equals ++ * the total size of the FDT structure. ++ * Modern uImage.FIT may have only references to data in FDT, ++ * hence we need to parse FDT structure to find the end of the ++ * last external data refernced. ++ */ ++ if (fit_size > 0x1000) { ++ enum mtdsplit_part_type type; ++ ++ /* Search for the rootfs partition after the FIT image */ ++ ret = mtd_find_rootfs_from(mtd, fit_offset + fit_size + offset_start, mtd->size, ++ &rootfs_offset, &type); ++ if (ret) { ++ pr_info("no rootfs found after FIT image in \"%s\"\n", ++ mtd->name); ++ return ret; ++ } ++ ++ rootfs_size = mtd->size - rootfs_offset; ++ ++ parts = kzalloc(2 * sizeof(*parts), GFP_KERNEL); ++ if (!parts) ++ return -ENOMEM; ++ ++ parts[0].name = KERNEL_PART_NAME; ++ parts[0].offset = fit_offset; ++ parts[0].size = mtd_roundup_to_eb(fit_size + offset_start, mtd); ++ ++ if (type == MTDSPLIT_PART_TYPE_UBI) ++ parts[1].name = UBI_PART_NAME; ++ else ++ parts[1].name = ROOTFS_PART_NAME; ++ parts[1].offset = rootfs_offset; ++ parts[1].size = rootfs_size; ++ ++ *pparts = parts; ++ ++ return 2; ++ } else { ++ /* Search for rootfs_data after FIT external data */ ++ fit = kzalloc(fit_size, GFP_KERNEL); ++ ret = mtd_read(mtd, offset, fit_size + offset_start, &retlen, fit); ++ if (ret) { ++ pr_err("read error in \"%s\" at offset 0x%llx\n", ++ mtd->name, (unsigned long long) offset); ++ return ret; ++ } ++ ++ images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH); ++ if (images_noffset < 0) { ++ pr_err("Can't find images parent node '%s' (%s)\n", ++ FIT_IMAGES_PATH, fdt_strerror(images_noffset)); ++ return -ENODEV; ++ } ++ ++ for (ndepth = 0, ++ noffset = fdt_next_node(fit, images_noffset, &ndepth); ++ (noffset >= 0) && (ndepth > 0); ++ noffset = fdt_next_node(fit, noffset, &ndepth)) { ++ if (ndepth == 1) { ++ ret = fit_image_get_data_and_size(fit, noffset, &img_data, &data_size); ++ if (ret) ++ return 0; ++ ++ img_total = data_size + (img_data - fit); ++ ++ max_size = (max_size > img_total) ? max_size : img_total; ++ } ++ } ++ ++ parts = kzalloc(sizeof(*parts), GFP_KERNEL); ++ if (!parts) ++ return -ENOMEM; ++ ++ parts[0].name = ROOTFS_SPLIT_NAME; ++ parts[0].offset = fit_offset + mtd_roundup_to_eb(max_size, mtd); ++ parts[0].size = mtd->size - parts[0].offset; ++ ++ *pparts = parts; ++ ++ kfree(fit); ++ ++ return 1; ++ } ++} ++ ++static const struct of_device_id mtdsplit_fit_of_match_table[] = { ++ { .compatible = "denx,fit" }, ++ {}, ++}; ++ ++static struct mtd_part_parser uimage_parser = { ++ .owner = THIS_MODULE, ++ .name = "fit-fw", ++ .of_match_table = mtdsplit_fit_of_match_table, ++ .parse_fn = mtdsplit_fit_parse, ++ .type = MTD_PARSER_TYPE_FIRMWARE, ++}; ++ ++/************************************************** ++ * Init ++ **************************************************/ ++ ++static int __init mtdsplit_fit_init(void) ++{ ++ register_mtd_parser(&uimage_parser); ++ ++ return 0; ++} ++ ++module_init(mtdsplit_fit_init); +diff --git a/drivers/mtd/mtdsplit/mtdsplit_h3c_vfs.c b/drivers/mtd/mtdsplit/mtdsplit_h3c_vfs.c +new file mode 100644 +index 000000000000..25993e762bf9 +--- /dev/null ++++ b/drivers/mtd/mtdsplit/mtdsplit_h3c_vfs.c +@@ -0,0 +1,167 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Some devices made by H3C use a "VFS" filesystem to store firmware images. ++ * This parses the start of the filesystem to read the length of the first ++ * file (the kernel image). It then searches for the rootfs after the end of ++ * the file data. This driver assumes that the filesystem was generated by ++ * mkh3cvfs, and only works if the filesystem matches the expected layout, ++ * which includes the file name of the kernel image. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mtdsplit.h" ++ ++#define VFS_ERASEBLOCK_SIZE 0x10000 ++#define VFS_BLOCK_SIZE 0x400 ++#define VFS_BLOCKS_PER_ERASEBLOCK (VFS_ERASEBLOCK_SIZE / VFS_BLOCK_SIZE) ++ ++#define FORMAT_FLAG_OFFSET 0x0 ++ ++#define FORMAT_FLAG (VFS_ERASEBLOCK_SIZE << 12 | VFS_BLOCK_SIZE) ++ ++#define FILE_ENTRY_OFFSET 0x800 ++ ++#define FILE_ENTRY_FLAGS 0x3f ++#define FILE_ENTRY_PARENT_BLOCK 0 ++#define FILE_ENTRY_PARENT_INDEX 0 ++#define FILE_ENTRY_DATA_BLOCK 2 ++#define FILE_ENTRY_NAME "openwrt-kernel.bin" ++ ++#define NR_PARTS 2 ++ ++struct file_entry { ++ uint8_t flags; ++ ++ uint8_t res0[5]; ++ ++ uint16_t year; ++ uint8_t month; ++ uint8_t day; ++ uint8_t hour; ++ uint8_t minute; ++ uint8_t second; ++ ++ uint8_t res1[3]; ++ ++ uint32_t length; ++ ++ uint32_t parent_block; ++ uint16_t parent_index; ++ ++ uint8_t res2[2]; ++ ++ uint32_t data_block; ++ ++ char name[96]; ++} __attribute__ ((packed)); ++ ++static inline size_t block_offset(int block) ++{ ++ return VFS_ERASEBLOCK_SIZE * (block / (VFS_BLOCKS_PER_ERASEBLOCK-1)) ++ + VFS_BLOCK_SIZE * (1 + (block % (VFS_BLOCKS_PER_ERASEBLOCK-1))); ++} ++ ++static inline int block_count(size_t size) ++{ ++ return (size + VFS_BLOCK_SIZE - 1) / VFS_BLOCK_SIZE; ++} ++ ++static int mtdsplit_h3c_vfs_parse(struct mtd_info *mtd, ++ const struct mtd_partition **pparts, ++ struct mtd_part_parser_data *data) ++{ ++ struct mtd_partition *parts; ++ uint32_t format_flag; ++ struct file_entry file_entry; ++ size_t retlen; ++ int err; ++ size_t kernel_size; ++ size_t expected_offset; ++ size_t rootfs_offset; ++ ++ if (mtd->erasesize != VFS_ERASEBLOCK_SIZE) ++ return -EINVAL; ++ ++ /* Check format flag */ ++ err = mtd_read(mtd, FORMAT_FLAG_OFFSET, sizeof(format_flag), &retlen, ++ (void *) &format_flag); ++ if (err) ++ return err; ++ ++ if (retlen != sizeof(format_flag)) ++ return -EIO; ++ ++ if (format_flag != FORMAT_FLAG) { ++ pr_info("mtdsplit_h3c_vfs: unexpected format flag %08x\n", ++ format_flag); ++ return 0; ++ } ++ ++ /* Check file entry */ ++ err = mtd_read(mtd, FILE_ENTRY_OFFSET, sizeof(file_entry), &retlen, ++ (void *) &file_entry); ++ if (err) ++ return err; ++ ++ if (retlen != sizeof(file_entry)) ++ return -EIO; ++ ++ if (file_entry.flags != FILE_ENTRY_FLAGS || ++ file_entry.parent_block != FILE_ENTRY_PARENT_BLOCK || ++ file_entry.parent_index != FILE_ENTRY_PARENT_INDEX || ++ file_entry.data_block != FILE_ENTRY_DATA_BLOCK || ++ strncmp(file_entry.name, FILE_ENTRY_NAME, sizeof(file_entry.name)) != 0) { ++ pr_info("mtdsplit_h3c_vfs: unexpected file entry - OpenWrt probably not installed\n"); ++ return 0; ++ } ++ ++ /* Find rootfs offset */ ++ kernel_size = block_offset(file_entry.data_block + ++ block_count(file_entry.length) - 1) + ++ VFS_BLOCK_SIZE; ++ ++ expected_offset = mtd_roundup_to_eb(kernel_size, mtd); ++ ++ err = mtd_find_rootfs_from(mtd, expected_offset, mtd->size, ++ &rootfs_offset, NULL); ++ if (err) ++ return err; ++ ++ parts = kzalloc(NR_PARTS * sizeof(*parts), GFP_KERNEL); ++ if (!parts) ++ return -ENOMEM; ++ ++ parts[0].name = KERNEL_PART_NAME; ++ parts[0].offset = 0; ++ parts[0].size = rootfs_offset; ++ ++ parts[1].name = ROOTFS_PART_NAME; ++ parts[1].offset = rootfs_offset; ++ parts[1].size = mtd->size - rootfs_offset; ++ ++ *pparts = parts; ++ return NR_PARTS; ++} ++ ++static const struct of_device_id mtdsplit_h3c_vfs_of_match_table[] = { ++ { .compatible = "h3c,vfs-firmware" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, mtdsplit_h3c_vfs_of_match_table); ++ ++static struct mtd_part_parser mtdsplit_h3c_vfs_parser = { ++ .owner = THIS_MODULE, ++ .name = "h3c-vfs", ++ .of_match_table = mtdsplit_h3c_vfs_of_match_table, ++ .parse_fn = mtdsplit_h3c_vfs_parse, ++ .type = MTD_PARSER_TYPE_FIRMWARE, ++}; ++ ++module_mtd_part_parser(mtdsplit_h3c_vfs_parser); +diff --git a/drivers/mtd/mtdsplit/mtdsplit_jimage.c b/drivers/mtd/mtdsplit/mtdsplit_jimage.c +new file mode 100644 +index 000000000000..1244bbdb06e5 +--- /dev/null ++++ b/drivers/mtd/mtdsplit/mtdsplit_jimage.c +@@ -0,0 +1,284 @@ ++/* ++ * Copyright (C) 2018 PaweÅ‚ Dembicki ++ * ++ * Based on: mtdsplit_uimage.c ++ * Copyright (C) 2013 Gabor Juhos ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation. ++ * ++ */ ++ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mtdsplit.h" ++ ++#define MAX_HEADER_LEN ( STAG_SIZE + SCH2_SIZE ) ++ ++#define STAG_SIZE 16 ++#define STAG_ID 0x04 ++#define STAG_MAGIC 0x2B24 ++ ++#define SCH2_SIZE 40 ++#define SCH2_MAGIC 0x2124 ++#define SCH2_VER 0x02 ++ ++/* ++ * Jboot image header, ++ * all data in little endian. ++ */ ++ ++struct jimage_header //stag + sch2 jboot joined headers ++{ ++ uint8_t stag_cmark; // in factory 0xFF , in sysupgrade must be the same as stag_id ++ uint8_t stag_id; // 0x04 ++ uint16_t stag_magic; //magic 0x2B24 ++ uint32_t stag_time_stamp; // timestamp calculated in jboot way ++ uint32_t stag_image_length; // lentgh of kernel + sch2 header ++ uint16_t stag_image_checksum; // negated jboot_checksum of sch2 + kernel ++ uint16_t stag_tag_checksum; // negated jboot_checksum of stag header data ++ uint16_t sch2_magic; // magic 0x2124 ++ uint8_t sch2_cp_type; // 0x00 for flat, 0x01 for jz, 0x02 for gzip, 0x03 for lzma ++ uint8_t sch2_version; // 0x02 for sch2 ++ uint32_t sch2_ram_addr; // ram entry address ++ uint32_t sch2_image_len; // kernel image length ++ uint32_t sch2_image_crc32; // kernel image crc ++ uint32_t sch2_start_addr; // ram start address ++ uint32_t sch2_rootfs_addr; // rootfs flash address ++ uint32_t sch2_rootfs_len; // rootfls length ++ uint32_t sch2_rootfs_crc32; // rootfs crc32 ++ uint32_t sch2_header_crc32; // sch2 header crc32, durring calculation this area is replaced by zero ++ uint16_t sch2_header_length; // sch2 header length: 0x28 ++ uint16_t sch2_cmd_line_length; // cmd line length, known zeros ++}; ++ ++static int ++read_jimage_header(struct mtd_info *mtd, size_t offset, u_char *buf, ++ size_t header_len) ++{ ++ size_t retlen; ++ int ret; ++ ++ ret = mtd_read(mtd, offset, header_len, &retlen, buf); ++ if (ret) { ++ pr_debug("read error in \"%s\"\n", mtd->name); ++ return ret; ++ } ++ ++ if (retlen != header_len) { ++ pr_debug("short read in \"%s\"\n", mtd->name); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++/** ++ * __mtdsplit_parse_jimage - scan partition and create kernel + rootfs parts ++ * ++ * @find_header: function to call for a block of data that will return offset ++ * of a valid jImage header if found ++ */ ++static int __mtdsplit_parse_jimage(struct mtd_info *master, ++ const struct mtd_partition **pparts, ++ struct mtd_part_parser_data *data, ++ ssize_t (*find_header)(u_char *buf, size_t len)) ++{ ++ struct mtd_partition *parts; ++ u_char *buf; ++ int nr_parts; ++ size_t offset; ++ size_t jimage_offset; ++ size_t jimage_size = 0; ++ size_t rootfs_offset; ++ size_t rootfs_size = 0; ++ int jimage_part, rf_part; ++ int ret; ++ enum mtdsplit_part_type type; ++ ++ nr_parts = 2; ++ parts = kzalloc(nr_parts * sizeof(*parts), GFP_KERNEL); ++ if (!parts) ++ return -ENOMEM; ++ ++ buf = vmalloc(MAX_HEADER_LEN); ++ if (!buf) { ++ ret = -ENOMEM; ++ goto err_free_parts; ++ } ++ ++ /* find jImage on erase block boundaries */ ++ for (offset = 0; offset < master->size; offset += master->erasesize) { ++ struct jimage_header *header; ++ ++ jimage_size = 0; ++ ++ ret = read_jimage_header(master, offset, buf, MAX_HEADER_LEN); ++ if (ret) ++ continue; ++ ++ ret = find_header(buf, MAX_HEADER_LEN); ++ if (ret < 0) { ++ pr_debug("no valid jImage found in \"%s\" at offset %llx\n", ++ master->name, (unsigned long long) offset); ++ continue; ++ } ++ header = (struct jimage_header *)(buf + ret); ++ ++ jimage_size = sizeof(*header) + header->sch2_image_len + ret; ++ if ((offset + jimage_size) > master->size) { ++ pr_debug("jImage exceeds MTD device \"%s\"\n", ++ master->name); ++ continue; ++ } ++ break; ++ } ++ ++ if (jimage_size == 0) { ++ pr_debug("no jImage found in \"%s\"\n", master->name); ++ ret = -ENODEV; ++ goto err_free_buf; ++ } ++ ++ jimage_offset = offset; ++ ++ if (jimage_offset == 0) { ++ jimage_part = 0; ++ rf_part = 1; ++ ++ /* find the roots after the jImage */ ++ ret = mtd_find_rootfs_from(master, jimage_offset + jimage_size, ++ master->size, &rootfs_offset, &type); ++ if (ret) { ++ pr_debug("no rootfs after jImage in \"%s\"\n", ++ master->name); ++ goto err_free_buf; ++ } ++ ++ rootfs_size = master->size - rootfs_offset; ++ jimage_size = rootfs_offset - jimage_offset; ++ } else { ++ rf_part = 0; ++ jimage_part = 1; ++ ++ /* check rootfs presence at offset 0 */ ++ ret = mtd_check_rootfs_magic(master, 0, &type); ++ if (ret) { ++ pr_debug("no rootfs before jImage in \"%s\"\n", ++ master->name); ++ goto err_free_buf; ++ } ++ ++ rootfs_offset = 0; ++ rootfs_size = jimage_offset; ++ } ++ ++ if (rootfs_size == 0) { ++ pr_debug("no rootfs found in \"%s\"\n", master->name); ++ ret = -ENODEV; ++ goto err_free_buf; ++ } ++ ++ parts[jimage_part].name = KERNEL_PART_NAME; ++ parts[jimage_part].offset = jimage_offset; ++ parts[jimage_part].size = jimage_size; ++ ++ if (type == MTDSPLIT_PART_TYPE_UBI) ++ parts[rf_part].name = UBI_PART_NAME; ++ else ++ parts[rf_part].name = ROOTFS_PART_NAME; ++ parts[rf_part].offset = rootfs_offset; ++ parts[rf_part].size = rootfs_size; ++ ++ vfree(buf); ++ ++ *pparts = parts; ++ return nr_parts; ++ ++err_free_buf: ++ vfree(buf); ++ ++err_free_parts: ++ kfree(parts); ++ return ret; ++} ++ ++static ssize_t jimage_verify_default(u_char *buf, size_t len) ++{ ++ struct jimage_header *header = (struct jimage_header *)buf; ++ ++ /* default sanity checks */ ++ if (header->stag_magic != STAG_MAGIC) { ++ pr_debug("invalid jImage stag header magic: %04x\n", ++ header->stag_magic); ++ return -EINVAL; ++ } ++ if (header->sch2_magic != SCH2_MAGIC) { ++ pr_debug("invalid jImage sch2 header magic: %04x\n", ++ header->stag_magic); ++ return -EINVAL; ++ } ++ if (header->stag_cmark != header->stag_id) { ++ pr_debug("invalid jImage stag header cmark: %02x\n", ++ header->stag_magic); ++ return -EINVAL; ++ } ++ if (header->stag_id != STAG_ID) { ++ pr_debug("invalid jImage stag header id: %02x\n", ++ header->stag_magic); ++ return -EINVAL; ++ } ++ if (header->sch2_version != SCH2_VER) { ++ pr_debug("invalid jImage sch2 header version: %02x\n", ++ header->stag_magic); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int ++mtdsplit_jimage_parse_generic(struct mtd_info *master, ++ const struct mtd_partition **pparts, ++ struct mtd_part_parser_data *data) ++{ ++ return __mtdsplit_parse_jimage(master, pparts, data, ++ jimage_verify_default); ++} ++ ++static const struct of_device_id mtdsplit_jimage_of_match_table[] = { ++ { .compatible = "amit,jimage" }, ++ {}, ++}; ++ ++static struct mtd_part_parser jimage_generic_parser = { ++ .owner = THIS_MODULE, ++ .name = "jimage-fw", ++ .of_match_table = mtdsplit_jimage_of_match_table, ++ .parse_fn = mtdsplit_jimage_parse_generic, ++ .type = MTD_PARSER_TYPE_FIRMWARE, ++}; ++ ++/************************************************** ++ * Init ++ **************************************************/ ++ ++static int __init mtdsplit_jimage_init(void) ++{ ++ register_mtd_parser(&jimage_generic_parser); ++ ++ return 0; ++} ++ ++module_init(mtdsplit_jimage_init); +diff --git a/drivers/mtd/mtdsplit/mtdsplit_lzma.c b/drivers/mtd/mtdsplit/mtdsplit_lzma.c +new file mode 100644 +index 000000000000..6dcffd04203d +--- /dev/null ++++ b/drivers/mtd/mtdsplit/mtdsplit_lzma.c +@@ -0,0 +1,109 @@ ++/* ++ * Copyright (C) 2014 Gabor Juhos ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(6,12,0) ++#include ++#else ++#include ++#endif ++ ++#include "mtdsplit.h" ++ ++#define LZMA_NR_PARTS 2 ++#define LZMA_PROPERTIES_SIZE 5 ++ ++struct lzma_header { ++ u8 props[LZMA_PROPERTIES_SIZE]; ++ u8 size_low[4]; ++ u8 size_high[4]; ++}; ++ ++static int mtdsplit_parse_lzma(struct mtd_info *master, ++ const struct mtd_partition **pparts, ++ struct mtd_part_parser_data *data) ++{ ++ struct lzma_header hdr; ++ size_t hdr_len, retlen; ++ size_t rootfs_offset; ++ u32 t; ++ struct mtd_partition *parts; ++ int err; ++ ++ hdr_len = sizeof(hdr); ++ err = mtd_read(master, 0, hdr_len, &retlen, (void *) &hdr); ++ if (err) ++ return err; ++ ++ if (retlen != hdr_len) ++ return -EIO; ++ ++ /* verify LZMA properties */ ++ if (hdr.props[0] >= (9 * 5 * 5)) ++ return -EINVAL; ++ ++ t = get_unaligned_le32(&hdr.props[1]); ++ if (!is_power_of_2(t)) ++ return -EINVAL; ++ ++ t = get_unaligned_le32(&hdr.size_high); ++ if (t) ++ return -EINVAL; ++ ++ err = mtd_find_rootfs_from(master, master->erasesize, master->size, ++ &rootfs_offset, NULL); ++ if (err) ++ return err; ++ ++ parts = kzalloc(LZMA_NR_PARTS * sizeof(*parts), GFP_KERNEL); ++ if (!parts) ++ return -ENOMEM; ++ ++ parts[0].name = KERNEL_PART_NAME; ++ parts[0].offset = 0; ++ parts[0].size = rootfs_offset; ++ ++ parts[1].name = ROOTFS_PART_NAME; ++ parts[1].offset = rootfs_offset; ++ parts[1].size = master->size - rootfs_offset; ++ ++ *pparts = parts; ++ return LZMA_NR_PARTS; ++} ++ ++static const struct of_device_id mtdsplit_lzma_of_match_table[] = { ++ { .compatible = "lzma" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, mtdsplit_lzma_of_match_table); ++ ++static struct mtd_part_parser mtdsplit_lzma_parser = { ++ .owner = THIS_MODULE, ++ .name = "lzma-fw", ++ .of_match_table = mtdsplit_lzma_of_match_table, ++ .parse_fn = mtdsplit_parse_lzma, ++ .type = MTD_PARSER_TYPE_FIRMWARE, ++}; ++ ++static int __init mtdsplit_lzma_init(void) ++{ ++ register_mtd_parser(&mtdsplit_lzma_parser); ++ ++ return 0; ++} ++ ++subsys_initcall(mtdsplit_lzma_init); +diff --git a/drivers/mtd/mtdsplit/mtdsplit_minor.c b/drivers/mtd/mtdsplit/mtdsplit_minor.c +new file mode 100644 +index 000000000000..053cba6272da +--- /dev/null ++++ b/drivers/mtd/mtdsplit/mtdsplit_minor.c +@@ -0,0 +1,142 @@ ++/* ++ * MTD splitter for MikroTik NOR devices ++ * ++ * Copyright (C) 2017 Thibaut VARENE ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation. ++ * ++ * The rootfs is expected at erase-block boundary due to the use of ++ * mtd_find_rootfs_from(). We use a trimmed down version of the yaffs header ++ * for two main reasons: ++ * - the original header uses weakly defined types (int, enum...) which can ++ * vary in length depending on build host (and the struct is not packed), ++ * and the name field can have a different total length depending on ++ * whether or not the yaffs code was _built_ with unicode support. ++ * - the only field that could be of real use here (file_size_low) contains ++ * invalid data in the header generated by kernel2minor, so we cannot use ++ * it to infer the exact position of the rootfs and do away with ++ * mtd_find_rootfs_from() (and thus have non-EB-aligned rootfs). ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mtdsplit.h" ++ ++#define YAFFS_OBJECT_TYPE_FILE 0x1 ++#define YAFFS_OBJECTID_ROOT 0x1 ++#define YAFFS_SUM_UNUSED 0xFFFF ++#define YAFFS_MAX_NAME_LENGTH 127 ++#define YAFFS_NAME_KERNEL "kernel" ++#define YAFFS_NAME_BOOTIMAGE "bootimage" ++ ++#define MINOR_NR_PARTS 2 ++ ++/* ++ * This structure is based on yaffs_obj_hdr from yaffs_guts.h ++ * The weak types match upstream. The fields have cpu-endianness ++ */ ++struct minor_header { ++ int yaffs_type; ++ int yaffs_obj_id; ++ u16 yaffs_sum_unused; ++ char yaffs_name[YAFFS_MAX_NAME_LENGTH]; ++}; ++ ++static int mtdsplit_parse_minor(struct mtd_info *master, ++ const struct mtd_partition **pparts, ++ struct mtd_part_parser_data *data) ++{ ++ struct minor_header hdr; ++ size_t hdr_len, retlen; ++ size_t rootfs_offset; ++ struct mtd_partition *parts; ++ int err; ++ ++ hdr_len = sizeof(hdr); ++ err = mtd_read(master, 0, hdr_len, &retlen, (void *) &hdr); ++ if (err) { ++ pr_err("MiNOR mtd_read error: %d\n", err); ++ return err; ++ } ++ ++ if (retlen != hdr_len) { ++ pr_err("MiNOR mtd_read too short\n"); ++ return -EIO; ++ } ++ ++ /* match header */ ++ if (hdr.yaffs_type != YAFFS_OBJECT_TYPE_FILE) { ++ pr_info("MiNOR YAFFS first type not matched\n"); ++ return 0; ++ } ++ ++ if (hdr.yaffs_obj_id != YAFFS_OBJECTID_ROOT) { ++ pr_info("MiNOR YAFFS first objectid not matched\n"); ++ return 0; ++ } ++ ++ if (hdr.yaffs_sum_unused != YAFFS_SUM_UNUSED) { ++ pr_info("MiNOR YAFFS first sum not matched\n"); ++ return 0; ++ } ++ ++ if ((memcmp(hdr.yaffs_name, YAFFS_NAME_KERNEL, sizeof(YAFFS_NAME_KERNEL))) && ++ (memcmp(hdr.yaffs_name, YAFFS_NAME_BOOTIMAGE, sizeof(YAFFS_NAME_BOOTIMAGE)))) { ++ pr_info("MiNOR YAFFS first name not matched\n"); ++ return 0; ++ } ++ ++ err = mtd_find_rootfs_from(master, master->erasesize, master->size, ++ &rootfs_offset, NULL); ++ if (err) { ++ pr_info("MiNOR mtd_find_rootfs_from error: %d\n", err); ++ return 0; ++ } ++ ++ parts = kzalloc(MINOR_NR_PARTS * sizeof(*parts), GFP_KERNEL); ++ if (!parts) ++ return -ENOMEM; ++ ++ parts[0].name = KERNEL_PART_NAME; ++ parts[0].offset = 0; ++ parts[0].size = rootfs_offset; ++ ++ parts[1].name = ROOTFS_PART_NAME; ++ parts[1].offset = rootfs_offset; ++ parts[1].size = master->size - rootfs_offset; ++ ++ *pparts = parts; ++ return MINOR_NR_PARTS; ++} ++ ++static const struct of_device_id mtdsplit_minor_of_match_table[] = { ++ { .compatible = "mikrotik,minor" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, mtdsplit_minor_of_match_table); ++ ++static struct mtd_part_parser mtdsplit_minor_parser = { ++ .owner = THIS_MODULE, ++ .name = "minor-fw", ++ .of_match_table = mtdsplit_minor_of_match_table, ++ .parse_fn = mtdsplit_parse_minor, ++ .type = MTD_PARSER_TYPE_FIRMWARE, ++}; ++ ++static int __init mtdsplit_minor_init(void) ++{ ++ register_mtd_parser(&mtdsplit_minor_parser); ++ ++ return 0; ++} ++ ++subsys_initcall(mtdsplit_minor_init); +diff --git a/drivers/mtd/mtdsplit/mtdsplit_mstc_boot.c b/drivers/mtd/mtdsplit/mtdsplit_mstc_boot.c +new file mode 100644 +index 000000000000..6d7980792aed +--- /dev/null ++++ b/drivers/mtd/mtdsplit/mtdsplit_mstc_boot.c +@@ -0,0 +1,270 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * a mtdsplit parser using "bootnum" value in the "persist" partition ++ * for the devices manufactured by MSTC (MitraStar Technology Corp.) ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mtdsplit.h" ++ ++#define PERSIST_BOOTNUM_OFFSET 0x4 ++#define NR_PARTS_MAX 2 ++ ++/* ++ * Legacy format image header, ++ * all data in network byte order (aka natural aka bigendian). ++ */ ++ struct uimage_header { ++ uint32_t ih_magic; /* Image Header Magic Number */ ++ uint32_t ih_hcrc; /* Image Header CRC Checksum */ ++ uint32_t ih_time; /* Image Creation Timestamp */ ++ uint32_t ih_size; /* Image Data Size */ ++ uint32_t ih_load; /* Data Load Address */ ++ uint32_t ih_ep; /* Entry Point Address */ ++ uint32_t ih_dcrc; /* Image Data CRC Checksum */ ++ uint8_t ih_os; /* Operating System */ ++ uint8_t ih_arch; /* CPU architecture */ ++ uint8_t ih_type; /* Image Type */ ++ uint8_t ih_comp; /* Compression Type */ ++ uint8_t ih_name[IH_NMLEN]; /* Image Name */ ++}; ++ ++/* check whether the current mtd device is active or not */ ++static int ++mstcboot_is_active(struct mtd_info *mtd, u32 *bootnum_dt) ++{ ++ struct device_node *np = mtd_get_of_node(mtd); ++ struct device_node *persist_np; ++ size_t retlen; ++ u32 persist_offset; ++ u_char bootnum; ++ int ret; ++ ++ ret = of_property_read_u32(np, "mstc,bootnum", bootnum_dt); ++ if (ret) ++ return ret; ++ ++ persist_np = of_parse_phandle(np, "mstc,persist", 0); ++ if (!persist_np) ++ return -ENODATA; ++ /* is "persist" under the same node? */ ++ if (persist_np->parent != np->parent) { ++ of_node_put(persist_np); ++ return -EINVAL; ++ } ++ ++ ret = of_property_read_u32(persist_np, "reg", &persist_offset); ++ of_node_put(persist_np); ++ if (ret) ++ return ret; ++ ret = mtd_read(mtd->parent, persist_offset + PERSIST_BOOTNUM_OFFSET, ++ 1, &retlen, &bootnum); ++ if (ret) ++ return ret; ++ if (retlen != 1) ++ return -EIO; ++ ++ return (bootnum == *bootnum_dt) ? 1 : 0; ++} ++ ++/* ++ * mainly for NOR devices that uses raw kernel and squashfs ++ * ++ * example: ++ * ++ * partition@5a0000 { ++ * compatible = "mstc,boot"; ++ * label = "firmware1"; ++ * reg = <0x5a0000 0x3200000>; ++ * mstc,bootnum = <1>; ++ * mstc,persist = <&mtd_persist>; ++ * }; ++ */ ++static int ++mstcboot_parse_image_parts(struct mtd_info *mtd, ++ const struct mtd_partition **pparts) ++{ ++ struct mtd_partition *parts; ++ size_t retlen, kern_len = 0; ++ size_t rootfs_offset; ++ enum mtdsplit_part_type type; ++ u_char buf[0x40]; ++ int ret, nr_parts = 1, index = 0; ++ ++ ret = mtd_read(mtd, 0, sizeof(struct uimage_header), &retlen, buf); ++ if (ret) ++ return ret; ++ if (retlen != sizeof(struct uimage_header)) ++ return -EIO; ++ ++ if (be32_to_cpu(*(u32 *)buf) == OF_DT_HEADER) { ++ /* Flattened Image Tree (FIT) */ ++ struct fdt_header *fdthdr = (void *)buf; ++ kern_len = be32_to_cpu(fdthdr->totalsize); ++ } else if (be32_to_cpu(*(u32 *)buf) == IH_MAGIC) { ++ /* Legacy uImage */ ++ struct uimage_header *uimghdr = (void *)buf; ++ kern_len = sizeof(*uimghdr) + be32_to_cpu(uimghdr->ih_size); ++ } ++ ++ ret = mtd_find_rootfs_from(mtd, kern_len, mtd->size, &rootfs_offset, &type); ++ if (ret) { ++ pr_debug("no rootfs in \"%s\"\n", mtd->name); ++ return ret; ++ } ++ ++ if (kern_len > 0) ++ nr_parts++; ++ ++ parts = kcalloc(nr_parts, sizeof(*parts), GFP_KERNEL); ++ if (!parts) ++ return -ENOMEM; ++ ++ if (kern_len) { ++ parts[index].name = KERNEL_PART_NAME; ++ parts[index].offset = 0; ++ parts[index++].size = rootfs_offset; ++ } ++ ++ parts[index].name = (type == MTDSPLIT_PART_TYPE_UBI) ++ ? UBI_PART_NAME : ROOTFS_PART_NAME; ++ parts[index].offset = rootfs_offset; ++ parts[index].size = mtd->size - rootfs_offset; ++ ++ *pparts = parts; ++ return nr_parts; ++} ++ ++/* ++ * mainly for NAND devices that uses raw-kernel and UBI and needs ++ * splitted kernel/ubi partitions when sysupgrade ++ * ++ * example: ++ * ++ * partition@3c0000 { ++ * compatible = "mstc,boot"; ++ * reg = <0x3c0000 0x3240000>; ++ * label = "firmware1"; ++ * mstc,bootnum = <1>; ++ * mstc,persist = <&mtd_persist>; ++ * #address-cells = <1>; ++ * #size-cells = <1>; ++ * ++ * partition@0 { ++ * reg = <0x0 0x800000>; ++ * label-base = "kernel"; ++ * }; ++ * ++ * partition@800000 { ++ * reg = <0x800000 0x2a40000>; ++ * label-base = "ubi"; ++ * }; ++}; ++ */ ++static int ++mstcboot_parse_fixed_parts(struct mtd_info *mtd, ++ const struct mtd_partition **pparts, ++ int active, u32 bootnum_dt) ++{ ++ struct device_node *np = mtd_get_of_node(mtd); ++ struct device_node *child; ++ struct mtd_partition *parts; ++ int ret, nr_parts, index = 0; ++ ++ nr_parts = of_get_child_count(np); ++ if (nr_parts > NR_PARTS_MAX) { ++ pr_err("too many partitions found!\n"); ++ return -EINVAL; ++ } ++ ++ parts = kcalloc(nr_parts, sizeof(*parts), GFP_KERNEL); ++ if (!parts) ++ return -ENOMEM; ++ ++ for_each_child_of_node(np, child) { ++ u32 reg[2]; ++ if (of_n_addr_cells(child) != 1 || ++ of_n_size_cells(child) != 1) ++ { ++ ret = -EINVAL; ++ break; ++ } ++ ++ ret = of_property_read_u32_array(child, "reg", reg, 2); ++ if (ret) ++ break; ++ ret = of_property_read_string(child, "label-base", ++ &parts[index].name); ++ if (ret) ++ break; ++ ++ if (!active) { ++ parts[index].name = devm_kasprintf(&mtd->dev, GFP_KERNEL, ++ "%s%u", ++ parts[index].name, bootnum_dt); ++ if (!parts[index].name) { ++ ret = -ENOMEM; ++ break; ++ } ++ } ++ parts[index].offset = reg[0]; ++ parts[index].size = reg[1]; ++ index++; ++ } ++ of_node_put(child); ++ ++ if (ret) ++ kfree(parts); ++ else ++ *pparts = parts; ++ return ret ? ret : nr_parts; ++} ++ ++static int ++mtdsplit_mstcboot_parse(struct mtd_info *mtd, ++ const struct mtd_partition **pparts, ++ struct mtd_part_parser_data *data) ++{ ++ struct device_node *np = mtd_get_of_node(mtd); ++ u32 bootnum_dt; ++ int ret; ++ ++ ret = mstcboot_is_active(mtd, &bootnum_dt); ++ if (ret < 0) ++ goto exit; ++ ++ if (of_get_child_count(np)) ++ ret = mstcboot_parse_fixed_parts(mtd, pparts, ret, bootnum_dt); ++ else if (ret != 0) ++ ret = mstcboot_parse_image_parts(mtd, pparts); ++ ++exit: ++ /* ++ * return 0 when ret=-ENODEV, to prevent deletion of ++ * parent mtd partitions on Linux 6.7 and later ++ */ ++ return ret == -ENODEV ? 0 : ret; ++} ++ ++static const struct of_device_id mtdsplit_mstcboot_of_match_table[] = { ++ { .compatible = "mstc,boot" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, mtdsplit_mstcboot_of_match_table); ++ ++static struct mtd_part_parser mtdsplit_mstcboot_parser = { ++ .owner = THIS_MODULE, ++ .name = "mstc-boot", ++ .of_match_table = mtdsplit_mstcboot_of_match_table, ++ .parse_fn = mtdsplit_mstcboot_parse, ++ .type = MTD_PARSER_TYPE_FIRMWARE, ++}; ++module_mtd_part_parser(mtdsplit_mstcboot_parser) +diff --git a/drivers/mtd/mtdsplit/mtdsplit_seama.c b/drivers/mtd/mtdsplit/mtdsplit_seama.c +new file mode 100644 +index 000000000000..5d49171b1f74 +--- /dev/null ++++ b/drivers/mtd/mtdsplit/mtdsplit_seama.c +@@ -0,0 +1,118 @@ ++/* ++ * Copyright (C) 2013 Gabor Juhos ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mtdsplit.h" ++ ++#define SEAMA_MAGIC 0x5EA3A417 ++#define SEAMA_NR_PARTS 2 ++#define SEAMA_MIN_ROOTFS_OFFS 0x80000 /* 512KiB */ ++ ++struct seama_header { ++ __be32 magic; /* should always be SEAMA_MAGIC. */ ++ __be16 reserved; /* reserved for */ ++ __be16 metasize; /* size of the META data */ ++ __be32 size; /* size of the image */ ++ u8 md5[16]; /* digest */ ++}; ++ ++static int mtdsplit_parse_seama(struct mtd_info *master, ++ const struct mtd_partition **pparts, ++ struct mtd_part_parser_data *data) ++{ ++ struct seama_header hdr; ++ size_t hdr_len, retlen, kernel_ent_size; ++ size_t rootfs_offset; ++ struct mtd_partition *parts; ++ enum mtdsplit_part_type type; ++ int err; ++ ++ hdr_len = sizeof(hdr); ++ err = mtd_read(master, 0, hdr_len, &retlen, (void *) &hdr); ++ if (err) ++ return err; ++ ++ if (retlen != hdr_len) ++ return -EIO; ++ ++ /* sanity checks */ ++ if (be32_to_cpu(hdr.magic) != SEAMA_MAGIC) ++ return -EINVAL; ++ ++ kernel_ent_size = hdr_len + be32_to_cpu(hdr.size) + ++ be16_to_cpu(hdr.metasize); ++ if (kernel_ent_size > master->size) ++ return -EINVAL; ++ ++ /* Check for the rootfs right after Seama entity with a kernel. */ ++ err = mtd_check_rootfs_magic(master, kernel_ent_size, &type); ++ if (!err) { ++ rootfs_offset = kernel_ent_size; ++ } else { ++ /* ++ * On some devices firmware entity might contain both: kernel ++ * and rootfs. We can't determine kernel size so we just have to ++ * look for rootfs magic. ++ * Start the search from an arbitrary offset. ++ */ ++ err = mtd_find_rootfs_from(master, SEAMA_MIN_ROOTFS_OFFS, ++ master->size, &rootfs_offset, &type); ++ if (err) ++ return err; ++ } ++ ++ parts = kzalloc(SEAMA_NR_PARTS * sizeof(*parts), GFP_KERNEL); ++ if (!parts) ++ return -ENOMEM; ++ ++ parts[0].name = KERNEL_PART_NAME; ++ parts[0].offset = sizeof hdr + be16_to_cpu(hdr.metasize); ++ parts[0].size = rootfs_offset - parts[0].offset; ++ ++ if (type == MTDSPLIT_PART_TYPE_UBI) ++ parts[1].name = UBI_PART_NAME; ++ else ++ parts[1].name = ROOTFS_PART_NAME; ++ parts[1].offset = rootfs_offset; ++ parts[1].size = master->size - rootfs_offset; ++ ++ *pparts = parts; ++ return SEAMA_NR_PARTS; ++} ++ ++static const struct of_device_id mtdsplit_seama_of_match_table[] = { ++ { .compatible = "seama" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, mtdsplit_seama_of_match_table); ++ ++static struct mtd_part_parser mtdsplit_seama_parser = { ++ .owner = THIS_MODULE, ++ .name = "seama-fw", ++ .of_match_table = mtdsplit_seama_of_match_table, ++ .parse_fn = mtdsplit_parse_seama, ++ .type = MTD_PARSER_TYPE_FIRMWARE, ++}; ++ ++static int __init mtdsplit_seama_init(void) ++{ ++ register_mtd_parser(&mtdsplit_seama_parser); ++ ++ return 0; ++} ++ ++subsys_initcall(mtdsplit_seama_init); +diff --git a/drivers/mtd/mtdsplit/mtdsplit_seil.c b/drivers/mtd/mtdsplit/mtdsplit_seil.c +new file mode 100644 +index 000000000000..e58bb49b23fc +--- /dev/null ++++ b/drivers/mtd/mtdsplit/mtdsplit_seil.c +@@ -0,0 +1,191 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* a mtdsplit driver for IIJ SEIL devices */ ++ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mtdsplit.h" ++ ++#define NR_PARTS 2 ++#define SEIL_VFMT 1 ++#define LDR_ENV_PART_NAME "bootloader-env" ++#define LDR_ENV_KEY_BOOTDEV "BOOTDEV" ++ ++struct seil_header { ++ uint64_t id; /* Identifier */ ++ uint8_t copy[80]; /* Copyright */ ++ uint32_t dcrc; /* Data CRC Checksum */ ++ uint32_t vfmt; /* Image Version Format */ ++ uint32_t vmjr; /* Image Version Major */ ++ uint32_t vmnr; /* Image Version Minor */ ++ uint8_t vrel[32]; /* Image Version Release */ ++ uint32_t dxor; /* xor value for Data? */ ++ uint32_t dlen; /* Data Length */ ++}; ++ ++/* ++ * check whether the current mtd device is active or not ++ * ++ * example of BOOTDEV value (IIJ SA-W2): ++ * - "flash" : primary image on flash ++ * - "rescue" : secondary image on flash ++ * - "usb" : usb storage ++ * - "lan0/1" : network ++ */ ++static bool seil_bootdev_is_active(struct device_node *np) ++{ ++ struct mtd_info *env_mtd; ++ char *buf, *var, *value, *eq; ++ const char *devnm; ++ size_t rdlen; ++ int ret; ++ ++ /* ++ * read bootdev name of the partition ++ * if doesn't exist, return true and skip checking of active device ++ */ ++ ret = of_property_read_string(np, "iij,bootdev-name", &devnm); ++ if (ret == -EINVAL) ++ return true; ++ else if (ret < 0) ++ return false; ++ ++ env_mtd = get_mtd_device_nm(LDR_ENV_PART_NAME); ++ if (IS_ERR(env_mtd)) { ++ pr_err("failed to get mtd device \"%s\"", LDR_ENV_PART_NAME); ++ return false; ++ } ++ ++ buf = vmalloc(env_mtd->size); ++ if (!buf) ++ return false; ++ ++ ret = mtd_read(env_mtd, 0, env_mtd->size, &rdlen, buf); ++ if (ret || rdlen != env_mtd->size) { ++ pr_err("failed to read from mtd (%d)\n", ret); ++ ret = 0; ++ goto exit_vfree; ++ } ++ ++ for (var = buf, ret = false; ++ var < buf + env_mtd->size && *var; ++ var = value + strlen(value) + 1) { ++ eq = strchr(var, '='); ++ if (!eq) ++ break; ++ *eq = '\0'; ++ value = eq + 1; ++ ++ pr_debug("ENV: %s=%s\n", var, value); ++ if (!strcmp(var, LDR_ENV_KEY_BOOTDEV)) { ++ ret = !strcmp(devnm, value); ++ break; ++ } ++ } ++ ++exit_vfree: ++ vfree(buf); ++ ++ return ret; ++} ++ ++static int mtdsplit_parse_seil_fw(struct mtd_info *master, ++ const struct mtd_partition **pparts, ++ struct mtd_part_parser_data *data) ++{ ++ struct device_node *np = mtd_get_of_node(master); ++ struct mtd_partition *parts; ++ struct seil_header header; ++ size_t image_size = 0; ++ size_t rootfs_offset; ++ size_t hdrlen = sizeof(header); ++ size_t retlen; ++ int ret; ++ u64 id; ++ ++ if (!seil_bootdev_is_active(np)) ++ return -ENODEV; ++ ++ ret = of_property_read_u64(np, "iij,seil-id", &id); ++ if (ret) { ++ pr_err("failed to get iij,seil-id from dt\n"); ++ return ret; ++ } ++ pr_debug("got seil-id=0x%016llx from dt\n", id); ++ ++ parts = kcalloc(NR_PARTS, sizeof(*parts), GFP_KERNEL); ++ if (!parts) ++ return -ENOMEM; ++ ++ ret = mtd_read(master, 0, hdrlen, &retlen, (void *)&header); ++ if (ret) ++ goto err_free_parts; ++ ++ if (retlen != hdrlen) { ++ ret = -EIO; ++ goto err_free_parts; ++ } ++ ++ if (be64_to_cpu(header.id) != id || ++ be32_to_cpu(header.vfmt) != SEIL_VFMT) { ++ pr_debug("no valid seil image found in \"%s\"\n", master->name); ++ ret = -ENODEV; ++ goto err_free_parts; ++ } ++ ++ image_size = hdrlen + be32_to_cpu(header.dlen); ++ if (image_size > master->size) { ++ pr_err("seil image exceeds MTD device \"%s\"\n", master->name); ++ ret = -EINVAL; ++ goto err_free_parts; ++ } ++ ++ /* find the roots after the seil image */ ++ ret = mtd_find_rootfs_from(master, image_size, ++ master->size, &rootfs_offset, NULL); ++ if (ret || (master->size - rootfs_offset) == 0) { ++ pr_debug("no rootfs after seil image in \"%s\"\n", ++ master->name); ++ ret = -ENODEV; ++ goto err_free_parts; ++ } ++ ++ parts[0].name = KERNEL_PART_NAME; ++ parts[0].offset = 0; ++ parts[0].size = rootfs_offset; ++ ++ parts[1].name = ROOTFS_PART_NAME; ++ parts[1].offset = rootfs_offset; ++ parts[1].size = master->size - rootfs_offset; ++ ++ *pparts = parts; ++ return NR_PARTS; ++ ++err_free_parts: ++ kfree(parts); ++ return ret; ++} ++ ++static const struct of_device_id mtdsplit_seil_fw_of_match_table[] = { ++ { .compatible = "iij,seil-firmware" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, mtdsplit_seil_fw_of_match_table); ++ ++static struct mtd_part_parser mtdsplit_seil_fw_parser = { ++ .owner = THIS_MODULE, ++ .name = "seil-fw", ++ .of_match_table = mtdsplit_seil_fw_of_match_table, ++ .parse_fn = mtdsplit_parse_seil_fw, ++ .type = MTD_PARSER_TYPE_FIRMWARE, ++}; ++ ++module_mtd_part_parser(mtdsplit_seil_fw_parser); +diff --git a/drivers/mtd/mtdsplit/mtdsplit_squashfs.c b/drivers/mtd/mtdsplit/mtdsplit_squashfs.c +new file mode 100644 +index 000000000000..f6353da65b0e +--- /dev/null ++++ b/drivers/mtd/mtdsplit/mtdsplit_squashfs.c +@@ -0,0 +1,72 @@ ++/* ++ * Copyright (C) 2013 Felix Fietkau ++ * Copyright (C) 2013 Gabor Juhos ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation. ++ * ++ */ ++ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mtdsplit.h" ++ ++static int ++mtdsplit_parse_squashfs(struct mtd_info *master, ++ const struct mtd_partition **pparts, ++ struct mtd_part_parser_data *data) ++{ ++ struct mtd_partition *part; ++ struct mtd_info *parent_mtd; ++ size_t part_offset; ++ size_t squashfs_len; ++ int err; ++ ++ err = mtd_get_squashfs_len(master, 0, &squashfs_len); ++ if (err) ++ return err; ++ ++ parent_mtd = mtd_get_master(master); ++ part_offset = mtdpart_get_offset(master); ++ ++ part = kzalloc(sizeof(*part), GFP_KERNEL); ++ if (!part) { ++ pr_alert("unable to allocate memory for \"%s\" partition\n", ++ ROOTFS_SPLIT_NAME); ++ return -ENOMEM; ++ } ++ ++ part->name = ROOTFS_SPLIT_NAME; ++ part->offset = mtd_roundup_to_eb(part_offset + squashfs_len, ++ parent_mtd) - part_offset; ++ part->size = mtd_rounddown_to_eb(master->size - part->offset, master); ++ ++ *pparts = part; ++ return 1; ++} ++ ++static struct mtd_part_parser mtdsplit_squashfs_parser = { ++ .owner = THIS_MODULE, ++ .name = "squashfs-split", ++ .parse_fn = mtdsplit_parse_squashfs, ++ .type = MTD_PARSER_TYPE_ROOTFS, ++}; ++ ++static int __init mtdsplit_squashfs_init(void) ++{ ++ register_mtd_parser(&mtdsplit_squashfs_parser); ++ ++ return 0; ++} ++ ++subsys_initcall(mtdsplit_squashfs_init); +diff --git a/drivers/mtd/mtdsplit/mtdsplit_tplink.c b/drivers/mtd/mtdsplit/mtdsplit_tplink.c +new file mode 100644 +index 000000000000..8909c107a094 +--- /dev/null ++++ b/drivers/mtd/mtdsplit/mtdsplit_tplink.c +@@ -0,0 +1,176 @@ ++/* ++ * Copyright (C) 2013 Gabor Juhos ++ * Copyright (C) 2014 Felix Fietkau ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mtdsplit.h" ++ ++#define TPLINK_NR_PARTS 2 ++#define TPLINK_MIN_ROOTFS_OFFS 0x80000 /* 512KiB */ ++ ++#define MD5SUM_LEN 16 ++ ++struct fw_v1 { ++ char vendor_name[24]; ++ char fw_version[36]; ++ uint32_t hw_id; /* hardware id */ ++ uint32_t hw_rev; /* hardware revision */ ++ uint32_t unk1; ++ uint8_t md5sum1[MD5SUM_LEN]; ++ uint32_t unk2; ++ uint8_t md5sum2[MD5SUM_LEN]; ++ uint32_t unk3; ++ uint32_t kernel_la; /* kernel load address */ ++ uint32_t kernel_ep; /* kernel entry point */ ++ uint32_t fw_length; /* total length of the firmware */ ++ uint32_t kernel_ofs; /* kernel data offset */ ++ uint32_t kernel_len; /* kernel data length */ ++ uint32_t rootfs_ofs; /* rootfs data offset */ ++ uint32_t rootfs_len; /* rootfs data length */ ++ uint32_t boot_ofs; /* bootloader data offset */ ++ uint32_t boot_len; /* bootloader data length */ ++ uint8_t pad[360]; ++} __attribute__ ((packed)); ++ ++struct fw_v2 { ++ char fw_version[48]; /* 0x04: fw version string */ ++ uint32_t hw_id; /* 0x34: hardware id */ ++ uint32_t hw_rev; /* 0x38: FIXME: hardware revision? */ ++ uint32_t unk1; /* 0x3c: 0x00000000 */ ++ uint8_t md5sum1[MD5SUM_LEN]; /* 0x40 */ ++ uint32_t unk2; /* 0x50: 0x00000000 */ ++ uint8_t md5sum2[MD5SUM_LEN]; /* 0x54 */ ++ uint32_t unk3; /* 0x64: 0xffffffff */ ++ ++ uint32_t kernel_la; /* 0x68: kernel load address */ ++ uint32_t kernel_ep; /* 0x6c: kernel entry point */ ++ uint32_t fw_length; /* 0x70: total length of the image */ ++ uint32_t kernel_ofs; /* 0x74: kernel data offset */ ++ uint32_t kernel_len; /* 0x78: kernel data length */ ++ uint32_t rootfs_ofs; /* 0x7c: rootfs data offset */ ++ uint32_t rootfs_len; /* 0x80: rootfs data length */ ++ uint32_t boot_ofs; /* 0x84: FIXME: seems to be unused */ ++ uint32_t boot_len; /* 0x88: FIXME: seems to be unused */ ++ uint16_t unk4; /* 0x8c: 0x55aa */ ++ uint8_t sver_hi; /* 0x8e */ ++ uint8_t sver_lo; /* 0x8f */ ++ uint8_t unk5; /* 0x90: magic: 0xa5 */ ++ uint8_t ver_hi; /* 0x91 */ ++ uint8_t ver_mid; /* 0x92 */ ++ uint8_t ver_lo; /* 0x93 */ ++ uint8_t pad[364]; ++} __attribute__ ((packed)); ++ ++struct tplink_fw_header { ++ uint32_t version; ++ union { ++ struct fw_v1 v1; ++ struct fw_v2 v2; ++ }; ++}; ++ ++static int mtdsplit_parse_tplink(struct mtd_info *master, ++ const struct mtd_partition **pparts, ++ struct mtd_part_parser_data *data) ++{ ++ struct tplink_fw_header hdr; ++ size_t hdr_len, retlen, kernel_size; ++ size_t rootfs_offset; ++ struct mtd_partition *parts; ++ int err; ++ ++ hdr_len = sizeof(hdr); ++ err = mtd_read(master, 0, hdr_len, &retlen, (void *) &hdr); ++ if (err) ++ return err; ++ ++ if (retlen != hdr_len) ++ return -EIO; ++ ++ switch (le32_to_cpu(hdr.version)) { ++ case 1: ++ if (be32_to_cpu(hdr.v1.kernel_ofs) != sizeof(hdr)) ++ return -EINVAL; ++ ++ kernel_size = sizeof(hdr) + be32_to_cpu(hdr.v1.kernel_len); ++ rootfs_offset = be32_to_cpu(hdr.v1.rootfs_ofs); ++ break; ++ case 2: ++ case 3: ++ if (be32_to_cpu(hdr.v2.kernel_ofs) != sizeof(hdr)) ++ return -EINVAL; ++ ++ kernel_size = sizeof(hdr) + be32_to_cpu(hdr.v2.kernel_len); ++ rootfs_offset = be32_to_cpu(hdr.v2.rootfs_ofs); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ if (kernel_size > master->size) ++ return -EINVAL; ++ ++ /* Find the rootfs */ ++ err = mtd_check_rootfs_magic(master, rootfs_offset, NULL); ++ if (err) { ++ /* ++ * The size in the header might cover the rootfs as well. ++ * Start the search from an arbitrary offset. ++ */ ++ err = mtd_find_rootfs_from(master, TPLINK_MIN_ROOTFS_OFFS, ++ master->size, &rootfs_offset, NULL); ++ if (err) ++ return err; ++ } ++ ++ parts = kzalloc(TPLINK_NR_PARTS * sizeof(*parts), GFP_KERNEL); ++ if (!parts) ++ return -ENOMEM; ++ ++ parts[0].name = KERNEL_PART_NAME; ++ parts[0].offset = 0; ++ parts[0].size = kernel_size; ++ ++ parts[1].name = ROOTFS_PART_NAME; ++ parts[1].offset = rootfs_offset; ++ parts[1].size = master->size - rootfs_offset; ++ ++ *pparts = parts; ++ return TPLINK_NR_PARTS; ++} ++ ++static const struct of_device_id mtdsplit_tplink_of_match_table[] = { ++ { .compatible = "tplink,firmware" }, ++ {}, ++}; ++ ++static struct mtd_part_parser mtdsplit_tplink_parser = { ++ .owner = THIS_MODULE, ++ .name = "tplink-fw", ++ .of_match_table = mtdsplit_tplink_of_match_table, ++ .parse_fn = mtdsplit_parse_tplink, ++ .type = MTD_PARSER_TYPE_FIRMWARE, ++}; ++ ++static int __init mtdsplit_tplink_init(void) ++{ ++ register_mtd_parser(&mtdsplit_tplink_parser); ++ ++ return 0; ++} ++ ++subsys_initcall(mtdsplit_tplink_init); +diff --git a/drivers/mtd/mtdsplit/mtdsplit_trx.c b/drivers/mtd/mtdsplit/mtdsplit_trx.c +new file mode 100644 +index 000000000000..b853ec9e5283 +--- /dev/null ++++ b/drivers/mtd/mtdsplit/mtdsplit_trx.c +@@ -0,0 +1,155 @@ ++/* ++ * Copyright (C) 2013 Gabor Juhos ++ * Copyright (C) 2014 Felix Fietkau ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation. ++ * ++ */ ++ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mtdsplit.h" ++ ++#define TRX_MAGIC 0x30524448 /* "HDR0" */ ++ ++struct trx_header { ++ __le32 magic; ++ __le32 len; ++ __le32 crc32; ++ __le32 flag_version; ++ __le32 offset[4]; ++}; ++ ++static int ++read_trx_header(struct mtd_info *mtd, size_t offset, ++ struct trx_header *header) ++{ ++ size_t header_len; ++ size_t retlen; ++ int ret; ++ ++ header_len = sizeof(*header); ++ ret = mtd_read(mtd, offset, header_len, &retlen, ++ (unsigned char *) header); ++ if (ret) { ++ pr_debug("read error in \"%s\"\n", mtd->name); ++ return ret; ++ } ++ ++ if (retlen != header_len) { ++ pr_debug("short read in \"%s\"\n", mtd->name); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++static int ++mtdsplit_parse_trx(struct mtd_info *master, ++ const struct mtd_partition **pparts, ++ struct mtd_part_parser_data *data) ++{ ++ struct mtd_partition *parts; ++ struct trx_header hdr; ++ int nr_parts; ++ size_t offset; ++ size_t trx_offset; ++ size_t trx_size = 0; ++ size_t rootfs_offset; ++ size_t rootfs_size = 0; ++ int ret; ++ ++ nr_parts = 2; ++ parts = kzalloc(nr_parts * sizeof(*parts), GFP_KERNEL); ++ if (!parts) ++ return -ENOMEM; ++ ++ /* find trx image on erase block boundaries */ ++ for (offset = 0; offset < master->size; offset += master->erasesize) { ++ trx_size = 0; ++ ++ ret = read_trx_header(master, offset, &hdr); ++ if (ret) ++ continue; ++ ++ if (hdr.magic != cpu_to_le32(TRX_MAGIC)) { ++ pr_debug("no valid trx header found in \"%s\" at offset %llx\n", ++ master->name, (unsigned long long) offset); ++ continue; ++ } ++ ++ trx_size = le32_to_cpu(hdr.len); ++ if ((offset + trx_size) > master->size) { ++ pr_debug("trx image exceeds MTD device \"%s\"\n", ++ master->name); ++ continue; ++ } ++ break; ++ } ++ ++ if (trx_size == 0) { ++ pr_debug("no trx header found in \"%s\"\n", master->name); ++ ret = -ENODEV; ++ goto err; ++ } ++ ++ trx_offset = offset + hdr.offset[0]; ++ rootfs_offset = offset + hdr.offset[1]; ++ rootfs_size = master->size - rootfs_offset; ++ trx_size = rootfs_offset - trx_offset; ++ ++ if (rootfs_size == 0) { ++ pr_debug("no rootfs found in \"%s\"\n", master->name); ++ ret = -ENODEV; ++ goto err; ++ } ++ ++ parts[0].name = KERNEL_PART_NAME; ++ parts[0].offset = trx_offset; ++ parts[0].size = trx_size; ++ ++ parts[1].name = ROOTFS_PART_NAME; ++ parts[1].offset = rootfs_offset; ++ parts[1].size = rootfs_size; ++ ++ *pparts = parts; ++ return nr_parts; ++ ++err: ++ kfree(parts); ++ return ret; ++} ++ ++static const struct of_device_id trx_parser_of_match_table[] = { ++ { .compatible = "openwrt,trx" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, trx_parser_of_match_table); ++ ++static struct mtd_part_parser trx_parser = { ++ .owner = THIS_MODULE, ++ .name = "trx-fw", ++ .of_match_table = trx_parser_of_match_table, ++ .parse_fn = mtdsplit_parse_trx, ++ .type = MTD_PARSER_TYPE_FIRMWARE, ++}; ++ ++static int __init mtdsplit_trx_init(void) ++{ ++ register_mtd_parser(&trx_parser); ++ ++ return 0; ++} ++ ++module_init(mtdsplit_trx_init); +diff --git a/drivers/mtd/mtdsplit/mtdsplit_uimage.c b/drivers/mtd/mtdsplit/mtdsplit_uimage.c +new file mode 100644 +index 000000000000..0d9685490030 +--- /dev/null ++++ b/drivers/mtd/mtdsplit/mtdsplit_uimage.c +@@ -0,0 +1,282 @@ ++/* ++ * Copyright (C) 2013 Gabor Juhos ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation. ++ * ++ */ ++ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mtdsplit.h" ++ ++/* ++ * Legacy format image header, ++ * all data in network byte order (aka natural aka bigendian). ++ */ ++struct uimage_header { ++ uint32_t ih_magic; /* Image Header Magic Number */ ++ uint32_t ih_hcrc; /* Image Header CRC Checksum */ ++ uint32_t ih_time; /* Image Creation Timestamp */ ++ uint32_t ih_size; /* Image Data Size */ ++ uint32_t ih_load; /* Data Load Address */ ++ uint32_t ih_ep; /* Entry Point Address */ ++ uint32_t ih_dcrc; /* Image Data CRC Checksum */ ++ uint8_t ih_os; /* Operating System */ ++ uint8_t ih_arch; /* CPU architecture */ ++ uint8_t ih_type; /* Image Type */ ++ uint8_t ih_comp; /* Compression Type */ ++ uint8_t ih_name[IH_NMLEN]; /* Image Name */ ++}; ++ ++static int ++read_uimage_header(struct mtd_info *mtd, size_t offset, u_char *buf, ++ size_t header_len) ++{ ++ size_t retlen; ++ int ret; ++ ++ ret = mtd_read(mtd, offset, header_len, &retlen, buf); ++ if (ret) { ++ pr_debug("read error in \"%s\"\n", mtd->name); ++ return ret; ++ } ++ ++ if (retlen != header_len) { ++ pr_debug("short read in \"%s\"\n", mtd->name); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++static void uimage_parse_dt(struct mtd_info *master, int *extralen, ++ u32 *ih_magic, u32 *ih_type, ++ u32 *header_offset, u32 *part_magic) ++{ ++ struct device_node *np = mtd_get_of_node(master); ++ ++ if (!np || !of_device_is_compatible(np, "openwrt,uimage")) ++ return; ++ ++ if (!of_property_read_u32(np, "openwrt,padding", extralen)) ++ pr_debug("got openwrt,padding=%d from device-tree\n", *extralen); ++ if (!of_property_read_u32(np, "openwrt,ih-magic", ih_magic)) ++ pr_debug("got openwrt,ih-magic=%08x from device-tree\n", *ih_magic); ++ if (!of_property_read_u32(np, "openwrt,ih-type", ih_type)) ++ pr_debug("got openwrt,ih-type=%08x from device-tree\n", *ih_type); ++ if (!of_property_read_u32(np, "openwrt,offset", header_offset)) ++ pr_debug("got ih-start=%u from device-tree\n", *header_offset); ++ if (!of_property_read_u32(np, "openwrt,partition-magic", part_magic)) ++ pr_debug("got openwrt,partition-magic=%08x from device-tree\n", *part_magic); ++} ++ ++static ssize_t uimage_verify_default(u_char *buf, u32 ih_magic, u32 ih_type) ++{ ++ struct uimage_header *header = (struct uimage_header *)buf; ++ ++ /* default sanity checks */ ++ if (be32_to_cpu(header->ih_magic) != ih_magic) { ++ pr_debug("invalid uImage magic: %08x != %08x\n", ++ be32_to_cpu(header->ih_magic), ih_magic); ++ return -EINVAL; ++ } ++ ++ if (header->ih_os != IH_OS_LINUX) { ++ pr_debug("invalid uImage OS: %08x != %08x\n", ++ be32_to_cpu(header->ih_os), IH_OS_LINUX); ++ return -EINVAL; ++ } ++ ++ if (header->ih_type != ih_type) { ++ pr_debug("invalid uImage type: %08x != %08x\n", ++ be32_to_cpu(header->ih_type), ih_type); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++/** ++ * __mtdsplit_parse_uimage - scan partition and create kernel + rootfs parts ++ * ++ * @find_header: function to call for a block of data that will return offset ++ * and tail padding length of a valid uImage header if found ++ */ ++static int __mtdsplit_parse_uimage(struct mtd_info *master, ++ const struct mtd_partition **pparts, ++ struct mtd_part_parser_data *data) ++{ ++ struct mtd_partition *parts; ++ u_char *buf; ++ int nr_parts; ++ size_t offset; ++ size_t uimage_offset; ++ size_t uimage_size = 0; ++ size_t rootfs_offset; ++ size_t rootfs_size = 0; ++ size_t buflen; ++ int uimage_part, rf_part; ++ int ret; ++ int extralen = 0; ++ u32 ih_magic = IH_MAGIC; ++ u32 ih_type = IH_TYPE_KERNEL; ++ u32 header_offset = 0; ++ u32 part_magic = 0; ++ enum mtdsplit_part_type type; ++ ++ nr_parts = 2; ++ parts = kzalloc(nr_parts * sizeof(*parts), GFP_KERNEL); ++ if (!parts) ++ return -ENOMEM; ++ ++ uimage_parse_dt(master, &extralen, &ih_magic, &ih_type, &header_offset, &part_magic); ++ buflen = sizeof(struct uimage_header) + header_offset; ++ buf = vmalloc(buflen); ++ if (!buf) { ++ ret = -ENOMEM; ++ goto err_free_parts; ++ } ++ ++ /* find uImage on erase block boundaries */ ++ for (offset = 0; offset < master->size; offset += master->erasesize) { ++ struct uimage_header *header; ++ ++ uimage_size = 0; ++ ++ ret = read_uimage_header(master, offset, buf, buflen); ++ if (ret) ++ continue; ++ ++ /* verify optional partition magic before uimage header */ ++ if (header_offset && part_magic && (be32_to_cpu(*(u32 *)buf) != part_magic)) ++ continue; ++ ++ ret = uimage_verify_default(buf + header_offset, ih_magic, ih_type); ++ if (ret < 0) { ++ pr_debug("no valid uImage found in \"%s\" at offset %llx\n", ++ master->name, (unsigned long long) offset); ++ continue; ++ } ++ ++ header = (struct uimage_header *)(buf + header_offset); ++ ++ uimage_size = sizeof(*header) + ++ be32_to_cpu(header->ih_size) + header_offset + extralen; ++ ++ if ((offset + uimage_size) > master->size) { ++ pr_debug("uImage exceeds MTD device \"%s\"\n", ++ master->name); ++ continue; ++ } ++ break; ++ } ++ ++ if (uimage_size == 0) { ++ pr_info("no uImage found in \"%s\"\n", master->name); ++ ret = 0; ++ goto err_free_buf; ++ } ++ ++ uimage_offset = offset; ++ ++ if (uimage_offset == 0) { ++ uimage_part = 0; ++ rf_part = 1; ++ ++ /* find the roots after the uImage */ ++ ret = mtd_find_rootfs_from(master, uimage_offset + uimage_size, ++ master->size, &rootfs_offset, &type); ++ if (ret) { ++ pr_info("no rootfs after uImage in \"%s\"\n", master->name); ++ ret = 0; ++ goto err_free_buf; ++ } ++ ++ rootfs_size = master->size - rootfs_offset; ++ uimage_size = rootfs_offset - uimage_offset; ++ } else { ++ rf_part = 0; ++ uimage_part = 1; ++ ++ /* check rootfs presence at offset 0 */ ++ ret = mtd_check_rootfs_magic(master, 0, &type); ++ if (ret) { ++ pr_info("no rootfs before uImage in \"%s\"\n", master->name); ++ ret = 0; ++ goto err_free_buf; ++ } ++ ++ rootfs_offset = 0; ++ rootfs_size = uimage_offset; ++ } ++ ++ if (rootfs_size == 0) { ++ pr_debug("no rootfs found in \"%s\"\n", master->name); ++ ret = -ENODEV; ++ goto err_free_buf; ++ } ++ ++ parts[uimage_part].name = KERNEL_PART_NAME; ++ parts[uimage_part].offset = uimage_offset; ++ parts[uimage_part].size = uimage_size; ++ ++ if (type == MTDSPLIT_PART_TYPE_UBI) ++ parts[rf_part].name = UBI_PART_NAME; ++ else ++ parts[rf_part].name = ROOTFS_PART_NAME; ++ parts[rf_part].offset = rootfs_offset; ++ parts[rf_part].size = rootfs_size; ++ ++ vfree(buf); ++ ++ *pparts = parts; ++ return nr_parts; ++ ++err_free_buf: ++ vfree(buf); ++ ++err_free_parts: ++ kfree(parts); ++ return ret; ++} ++ ++static const struct of_device_id mtdsplit_uimage_of_match_table[] = { ++ { .compatible = "denx,uimage" }, ++ { .compatible = "openwrt,uimage" }, ++ {}, ++}; ++ ++static struct mtd_part_parser uimage_generic_parser = { ++ .owner = THIS_MODULE, ++ .name = "uimage-fw", ++ .of_match_table = mtdsplit_uimage_of_match_table, ++ .parse_fn = __mtdsplit_parse_uimage, ++ .type = MTD_PARSER_TYPE_FIRMWARE, ++}; ++ ++/************************************************** ++ * Init ++ **************************************************/ ++ ++static int __init mtdsplit_uimage_init(void) ++{ ++ register_mtd_parser(&uimage_generic_parser); ++ ++ return 0; ++} ++ ++module_init(mtdsplit_uimage_init); +diff --git a/drivers/mtd/mtdsplit/mtdsplit_wrgg.c b/drivers/mtd/mtdsplit/mtdsplit_wrgg.c +new file mode 100644 +index 000000000000..dfd6058ae7e4 +--- /dev/null ++++ b/drivers/mtd/mtdsplit/mtdsplit_wrgg.c +@@ -0,0 +1,142 @@ ++/* ++ * Copyright (C) 2013 Gabor Juhos ++ * Copyright (C) 2014 Felix Fietkau ++ * Copyright (C) 2016 Stijn Tintel ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mtdsplit.h" ++ ++#define WRGG_NR_PARTS 2 ++#define WRGG_MIN_ROOTFS_OFFS 0x80000 /* 512KiB */ ++#define WRGG03_MAGIC 0x20080321 ++#define WRG_MAGIC 0x20040220 ++ ++struct wrgg03_header { ++ char signature[32]; ++ uint32_t magic1; ++ uint32_t magic2; ++ char version[16]; ++ char model[16]; ++ uint32_t flag[2]; ++ uint32_t reserve[2]; ++ char buildno[16]; ++ uint32_t size; ++ uint32_t offset; ++ char devname[32]; ++ char digest[16]; ++} __attribute__ ((packed)); ++ ++struct wrg_header { ++ char signature[32]; ++ uint32_t magic1; ++ uint32_t magic2; ++ uint32_t size; ++ uint32_t offset; ++ char devname[32]; ++ char digest[16]; ++} __attribute__ ((packed)); ++ ++ ++static int mtdsplit_parse_wrgg(struct mtd_info *master, ++ const struct mtd_partition **pparts, ++ struct mtd_part_parser_data *data) ++{ ++ struct wrgg03_header hdr; ++ size_t hdr_len, retlen, kernel_ent_size; ++ size_t rootfs_offset; ++ struct mtd_partition *parts; ++ enum mtdsplit_part_type type; ++ int err; ++ ++ hdr_len = sizeof(hdr); ++ err = mtd_read(master, 0, hdr_len, &retlen, (void *) &hdr); ++ if (err) ++ return err; ++ ++ if (retlen != hdr_len) ++ return -EIO; ++ ++ /* sanity checks */ ++ if (le32_to_cpu(hdr.magic1) == WRGG03_MAGIC) { ++ kernel_ent_size = hdr_len + be32_to_cpu(hdr.size); ++ /* ++ * If this becomes silly big it's probably because the ++ * WRGG image is little-endian. ++ */ ++ if (kernel_ent_size > master->size) ++ kernel_ent_size = hdr_len + le32_to_cpu(hdr.size); ++ ++ /* Now what ?! It's neither */ ++ if (kernel_ent_size > master->size) ++ return -EINVAL; ++ } else if (le32_to_cpu(hdr.magic1) == WRG_MAGIC) { ++ kernel_ent_size = sizeof(struct wrg_header) + le32_to_cpu( ++ ((struct wrg_header*)&hdr)->size); ++ } else { ++ return -EINVAL; ++ } ++ ++ if (kernel_ent_size > master->size) ++ return -EINVAL; ++ ++ /* ++ * The size in the header covers the rootfs as well. ++ * Start the search from an arbitrary offset. ++ */ ++ err = mtd_find_rootfs_from(master, WRGG_MIN_ROOTFS_OFFS, ++ master->size, &rootfs_offset, &type); ++ if (err) ++ return err; ++ ++ parts = kzalloc(WRGG_NR_PARTS * sizeof(*parts), GFP_KERNEL); ++ if (!parts) ++ return -ENOMEM; ++ ++ parts[0].name = KERNEL_PART_NAME; ++ parts[0].offset = 0; ++ parts[0].size = rootfs_offset; ++ ++ parts[1].name = ROOTFS_PART_NAME; ++ parts[1].offset = rootfs_offset; ++ parts[1].size = master->size - rootfs_offset; ++ ++ *pparts = parts; ++ return WRGG_NR_PARTS; ++} ++ ++static const struct of_device_id mtdsplit_wrgg_of_match_table[] = { ++ { .compatible = "wrg" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, mtdsplit_wrgg_of_match_table); ++ ++static struct mtd_part_parser mtdsplit_wrgg_parser = { ++ .owner = THIS_MODULE, ++ .name = "wrgg-fw", ++ .of_match_table = mtdsplit_wrgg_of_match_table, ++ .parse_fn = mtdsplit_parse_wrgg, ++ .type = MTD_PARSER_TYPE_FIRMWARE, ++}; ++ ++static int __init mtdsplit_wrgg_init(void) ++{ ++ register_mtd_parser(&mtdsplit_wrgg_parser); ++ ++ return 0; ++} ++ ++subsys_initcall(mtdsplit_wrgg_init); +diff --git a/drivers/mtd/nand/mtk_bmt.c b/drivers/mtd/nand/mtk_bmt.c +new file mode 100644 +index 000000000000..063adb50fb60 +--- /dev/null ++++ b/drivers/mtd/nand/mtk_bmt.c +@@ -0,0 +1,474 @@ ++/* ++ * Copyright (c) 2017 MediaTek Inc. ++ * Author: Xiangsheng Hou ++ * Copyright (c) 2020-2022 Felix Fietkau ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#include ++#include ++#include ++#include ++#include "mtk_bmt.h" ++ ++struct bmt_desc bmtd = {}; ++ ++/* -------- Nand operations wrapper -------- */ ++int bbt_nand_copy(u16 dest_blk, u16 src_blk, loff_t max_offset) ++{ ++ int pages = bmtd.blk_size >> bmtd.pg_shift; ++ loff_t src = (loff_t)src_blk << bmtd.blk_shift; ++ loff_t dest = (loff_t)dest_blk << bmtd.blk_shift; ++ loff_t offset = 0; ++ uint8_t oob[64]; ++ int i, ret; ++ ++ for (i = 0; i < pages; i++) { ++ struct mtd_oob_ops rd_ops = { ++ .mode = MTD_OPS_PLACE_OOB, ++ .oobbuf = oob, ++ .ooblen = min_t(int, bmtd.mtd->oobsize / pages, sizeof(oob)), ++ .datbuf = bmtd.data_buf, ++ .len = bmtd.pg_size, ++ }; ++ struct mtd_oob_ops wr_ops = { ++ .mode = MTD_OPS_PLACE_OOB, ++ .oobbuf = oob, ++ .datbuf = bmtd.data_buf, ++ .len = bmtd.pg_size, ++ }; ++ ++ if (offset >= max_offset) ++ break; ++ ++ ret = bmtd._read_oob(bmtd.mtd, src + offset, &rd_ops); ++ if (ret < 0 && !mtd_is_bitflip(ret)) ++ return ret; ++ ++ if (!rd_ops.retlen) ++ break; ++ ++ ret = bmtd._write_oob(bmtd.mtd, dest + offset, &wr_ops); ++ if (ret < 0) ++ return ret; ++ ++ wr_ops.ooblen = rd_ops.oobretlen; ++ offset += rd_ops.retlen; ++ } ++ ++ return 0; ++} ++ ++/* -------- Bad Blocks Management -------- */ ++bool mapping_block_in_range(int block, int *start, int *end) ++{ ++ const __be32 *cur = bmtd.remap_range; ++ u32 addr = block << bmtd.blk_shift; ++ int i; ++ ++ if (!cur || !bmtd.remap_range_len) { ++ *start = 0; ++ *end = bmtd.total_blks; ++ return true; ++ } ++ ++ for (i = 0; i < bmtd.remap_range_len; i++, cur += 2) { ++ if (addr < be32_to_cpu(cur[0]) || addr >= be32_to_cpu(cur[1])) ++ continue; ++ ++ *start = be32_to_cpu(cur[0]); ++ *end = be32_to_cpu(cur[1]); ++ return true; ++ } ++ ++ return false; ++} ++ ++static bool ++mtk_bmt_remap_block(u32 block, u32 mapped_block, int copy_len) ++{ ++ int start, end; ++ ++ if (!mapping_block_in_range(block, &start, &end)) ++ return false; ++ ++ return bmtd.ops->remap_block(block, mapped_block, copy_len); ++} ++ ++static int ++mtk_bmt_read(struct mtd_info *mtd, loff_t from, ++ struct mtd_oob_ops *ops) ++{ ++ struct mtd_oob_ops cur_ops = *ops; ++ int retry_count = 0; ++ loff_t cur_from; ++ int ret = 0; ++ int max_bitflips = 0; ++ ++ ops->retlen = 0; ++ ops->oobretlen = 0; ++ ++ while (ops->retlen < ops->len || ops->oobretlen < ops->ooblen) { ++ int cur_ret; ++ ++ u32 offset = from & (bmtd.blk_size - 1); ++ u32 block = from >> bmtd.blk_shift; ++ int cur_block; ++ ++ cur_block = bmtd.ops->get_mapping_block(block); ++ if (cur_block < 0) ++ return -EIO; ++ ++ cur_from = ((loff_t)cur_block << bmtd.blk_shift) + offset; ++ ++ cur_ops.oobretlen = 0; ++ cur_ops.retlen = 0; ++ cur_ops.len = min_t(u32, mtd->erasesize - offset, ++ ops->len - ops->retlen); ++ cur_ret = bmtd._read_oob(mtd, cur_from, &cur_ops); ++ if (cur_ret < 0) ++ ret = cur_ret; ++ else ++ max_bitflips = max_t(int, max_bitflips, cur_ret); ++ if (cur_ret < 0 && !mtd_is_bitflip(cur_ret)) { ++ if (mtk_bmt_remap_block(block, cur_block, mtd->erasesize) && ++ retry_count++ < 10) ++ continue; ++ ++ goto out; ++ } ++ ++ if (mtd->bitflip_threshold && cur_ret >= mtd->bitflip_threshold) ++ mtk_bmt_remap_block(block, cur_block, mtd->erasesize); ++ ++ ops->retlen += cur_ops.retlen; ++ ops->oobretlen += cur_ops.oobretlen; ++ ++ cur_ops.ooboffs = 0; ++ cur_ops.datbuf += cur_ops.retlen; ++ cur_ops.oobbuf += cur_ops.oobretlen; ++ cur_ops.ooblen -= cur_ops.oobretlen; ++ ++ if (!cur_ops.len) ++ cur_ops.len = mtd->erasesize - offset; ++ ++ from += cur_ops.len; ++ retry_count = 0; ++ } ++ ++out: ++ if (ret < 0) ++ return ret; ++ ++ return max_bitflips; ++} ++ ++static int ++mtk_bmt_write(struct mtd_info *mtd, loff_t to, ++ struct mtd_oob_ops *ops) ++{ ++ struct mtd_oob_ops cur_ops = *ops; ++ int retry_count = 0; ++ loff_t cur_to; ++ int ret; ++ ++ ops->retlen = 0; ++ ops->oobretlen = 0; ++ ++ while (ops->retlen < ops->len || ops->oobretlen < ops->ooblen) { ++ u32 offset = to & (bmtd.blk_size - 1); ++ u32 block = to >> bmtd.blk_shift; ++ int cur_block; ++ ++ cur_block = bmtd.ops->get_mapping_block(block); ++ if (cur_block < 0) ++ return -EIO; ++ ++ cur_to = ((loff_t)cur_block << bmtd.blk_shift) + offset; ++ ++ cur_ops.oobretlen = 0; ++ cur_ops.retlen = 0; ++ cur_ops.len = min_t(u32, bmtd.blk_size - offset, ++ ops->len - ops->retlen); ++ ret = bmtd._write_oob(mtd, cur_to, &cur_ops); ++ if (ret < 0) { ++ if (mtk_bmt_remap_block(block, cur_block, offset) && ++ retry_count++ < 10) ++ continue; ++ ++ return ret; ++ } ++ ++ ops->retlen += cur_ops.retlen; ++ ops->oobretlen += cur_ops.oobretlen; ++ ++ cur_ops.ooboffs = 0; ++ cur_ops.datbuf += cur_ops.retlen; ++ cur_ops.oobbuf += cur_ops.oobretlen; ++ cur_ops.ooblen -= cur_ops.oobretlen; ++ ++ if (!cur_ops.len) ++ cur_ops.len = mtd->erasesize - offset; ++ ++ to += cur_ops.len; ++ retry_count = 0; ++ } ++ ++ return 0; ++} ++ ++static int ++mtk_bmt_mtd_erase(struct mtd_info *mtd, struct erase_info *instr) ++{ ++ struct erase_info mapped_instr = { ++ .len = bmtd.blk_size, ++ }; ++ int retry_count = 0; ++ u64 start_addr, end_addr; ++ int ret; ++ u16 orig_block; ++ int block; ++ ++ start_addr = instr->addr & (~mtd->erasesize_mask); ++ end_addr = instr->addr + instr->len; ++ ++ while (start_addr < end_addr) { ++ orig_block = start_addr >> bmtd.blk_shift; ++ block = bmtd.ops->get_mapping_block(orig_block); ++ if (block < 0) ++ return -EIO; ++ mapped_instr.addr = (loff_t)block << bmtd.blk_shift; ++ ret = bmtd._erase(mtd, &mapped_instr); ++ if (ret) { ++ if (mtk_bmt_remap_block(orig_block, block, 0) && ++ retry_count++ < 10) ++ continue; ++ instr->fail_addr = start_addr; ++ break; ++ } ++ start_addr += mtd->erasesize; ++ retry_count = 0; ++ } ++ ++ return ret; ++} ++static int ++mtk_bmt_block_isbad(struct mtd_info *mtd, loff_t ofs) ++{ ++ int retry_count = 0; ++ u16 orig_block = ofs >> bmtd.blk_shift; ++ u16 block; ++ int ret; ++ ++retry: ++ block = bmtd.ops->get_mapping_block(orig_block); ++ ret = bmtd._block_isbad(mtd, (loff_t)block << bmtd.blk_shift); ++ if (ret) { ++ if (mtk_bmt_remap_block(orig_block, block, bmtd.blk_size) && ++ retry_count++ < 10) ++ goto retry; ++ } ++ return ret; ++} ++ ++static int ++mtk_bmt_block_markbad(struct mtd_info *mtd, loff_t ofs) ++{ ++ u16 orig_block = ofs >> bmtd.blk_shift; ++ int block; ++ ++ block = bmtd.ops->get_mapping_block(orig_block); ++ if (block < 0) ++ return -EIO; ++ ++ mtk_bmt_remap_block(orig_block, block, bmtd.blk_size); ++ ++ return bmtd._block_markbad(mtd, (loff_t)block << bmtd.blk_shift); ++} ++ ++static void ++mtk_bmt_replace_ops(struct mtd_info *mtd) ++{ ++ bmtd._read_oob = mtd->_read_oob; ++ bmtd._write_oob = mtd->_write_oob; ++ bmtd._erase = mtd->_erase; ++ bmtd._block_isbad = mtd->_block_isbad; ++ bmtd._block_markbad = mtd->_block_markbad; ++ ++ mtd->_read_oob = mtk_bmt_read; ++ mtd->_write_oob = mtk_bmt_write; ++ mtd->_erase = mtk_bmt_mtd_erase; ++ mtd->_block_isbad = mtk_bmt_block_isbad; ++ mtd->_block_markbad = mtk_bmt_block_markbad; ++} ++ ++static int mtk_bmt_debug_repair(void *data, u64 val) ++{ ++ int block = val >> bmtd.blk_shift; ++ int prev_block, new_block; ++ ++ prev_block = bmtd.ops->get_mapping_block(block); ++ if (prev_block < 0) ++ return -EIO; ++ ++ bmtd.ops->unmap_block(block); ++ new_block = bmtd.ops->get_mapping_block(block); ++ if (new_block < 0) ++ return -EIO; ++ ++ if (prev_block == new_block) ++ return 0; ++ ++ bbt_nand_erase(new_block); ++ bbt_nand_copy(new_block, prev_block, bmtd.blk_size); ++ ++ return 0; ++} ++ ++static int mtk_bmt_debug_mark_good(void *data, u64 val) ++{ ++ bmtd.ops->unmap_block(val >> bmtd.blk_shift); ++ ++ return 0; ++} ++ ++static int mtk_bmt_debug_mark_bad(void *data, u64 val) ++{ ++ u32 block = val >> bmtd.blk_shift; ++ int cur_block; ++ ++ cur_block = bmtd.ops->get_mapping_block(block); ++ if (cur_block < 0) ++ return -EIO; ++ ++ mtk_bmt_remap_block(block, cur_block, bmtd.blk_size); ++ ++ return 0; ++} ++ ++static int mtk_bmt_debug(void *data, u64 val) ++{ ++ return bmtd.ops->debug(data, val); ++} ++ ++ ++DEFINE_DEBUGFS_ATTRIBUTE(fops_repair, NULL, mtk_bmt_debug_repair, "%llu\n"); ++DEFINE_DEBUGFS_ATTRIBUTE(fops_mark_good, NULL, mtk_bmt_debug_mark_good, "%llu\n"); ++DEFINE_DEBUGFS_ATTRIBUTE(fops_mark_bad, NULL, mtk_bmt_debug_mark_bad, "%llu\n"); ++DEFINE_DEBUGFS_ATTRIBUTE(fops_debug, NULL, mtk_bmt_debug, "%llu\n"); ++ ++static void ++mtk_bmt_add_debugfs(void) ++{ ++ struct dentry *dir; ++ ++ dir = bmtd.debugfs_dir = debugfs_create_dir("mtk-bmt", NULL); ++ if (!dir) ++ return; ++ ++ debugfs_create_file_unsafe("repair", S_IWUSR, dir, NULL, &fops_repair); ++ debugfs_create_file_unsafe("mark_good", S_IWUSR, dir, NULL, &fops_mark_good); ++ debugfs_create_file_unsafe("mark_bad", S_IWUSR, dir, NULL, &fops_mark_bad); ++ debugfs_create_file_unsafe("debug", S_IWUSR, dir, NULL, &fops_debug); ++} ++ ++void mtk_bmt_detach(struct mtd_info *mtd) ++{ ++ if (bmtd.mtd != mtd) ++ return; ++ ++ if (bmtd.debugfs_dir) ++ debugfs_remove_recursive(bmtd.debugfs_dir); ++ bmtd.debugfs_dir = NULL; ++ ++ kfree(bmtd.bbt_buf); ++ kfree(bmtd.data_buf); ++ ++ mtd->_read_oob = bmtd._read_oob; ++ mtd->_write_oob = bmtd._write_oob; ++ mtd->_erase = bmtd._erase; ++ mtd->_block_isbad = bmtd._block_isbad; ++ mtd->_block_markbad = bmtd._block_markbad; ++ mtd->size = bmtd.total_blks << bmtd.blk_shift; ++ ++ memset(&bmtd, 0, sizeof(bmtd)); ++} ++ ++ ++int mtk_bmt_attach(struct mtd_info *mtd) ++{ ++ struct device_node *np; ++ int ret = 0; ++ u32 overridden_oobsize = 0; ++ ++ if (bmtd.mtd) ++ return -ENOSPC; ++ ++ np = mtd_get_of_node(mtd); ++ if (!np) ++ return 0; ++ ++ if (of_property_read_bool(np, "mediatek,bmt-v2")) ++ bmtd.ops = &mtk_bmt_v2_ops; ++ else if (of_property_read_bool(np, "mediatek,nmbm")) ++ bmtd.ops = &mtk_bmt_nmbm_ops; ++ else if (of_property_read_bool(np, "mediatek,bbt")) ++ bmtd.ops = &mtk_bmt_bbt_ops; ++ else ++ return 0; ++ ++ bmtd.remap_range = of_get_property(np, "mediatek,bmt-remap-range", ++ &bmtd.remap_range_len); ++ bmtd.remap_range_len /= 8; ++ ++ bmtd.mtd = mtd; ++ mtk_bmt_replace_ops(mtd); ++ ++ if (!of_property_read_u32(np, "mediatek,bmt-mtd-overridden-oobsize", ++ &overridden_oobsize)) ++ if (overridden_oobsize < bmtd.mtd->oobsize) { ++ bmtd.mtd->oobsize = overridden_oobsize; ++ pr_info("NMBM: mtd OOB size has been overridden to %luB\n", ++ (long unsigned int)bmtd.mtd->oobsize); ++ } ++ ++ bmtd.blk_size = mtd->erasesize; ++ bmtd.blk_shift = ffs(bmtd.blk_size) - 1; ++ bmtd.pg_size = mtd->writesize; ++ bmtd.pg_shift = ffs(bmtd.pg_size) - 1; ++ bmtd.total_blks = mtd->size >> bmtd.blk_shift; ++ ++ bmtd.data_buf = kzalloc(bmtd.pg_size + bmtd.mtd->oobsize, GFP_KERNEL); ++ if (!bmtd.data_buf) { ++ pr_info("nand: FATAL ERR: allocate buffer failed!\n"); ++ ret = -1; ++ goto error; ++ } ++ ++ memset(bmtd.data_buf, 0xff, bmtd.pg_size + bmtd.mtd->oobsize); ++ ++ ret = bmtd.ops->init(np); ++ if (ret) ++ goto error; ++ ++ mtk_bmt_add_debugfs(); ++ return 0; ++ ++error: ++ mtk_bmt_detach(mtd); ++ return ret; ++} ++ ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Xiangsheng Hou , Felix Fietkau "); ++MODULE_DESCRIPTION("Bad Block mapping management v2 for MediaTek NAND Flash Driver"); ++ +diff --git a/drivers/mtd/nand/mtk_bmt.h b/drivers/mtd/nand/mtk_bmt.h +new file mode 100644 +index 000000000000..517ff7414f34 +--- /dev/null ++++ b/drivers/mtd/nand/mtk_bmt.h +@@ -0,0 +1,137 @@ ++#ifndef __MTK_BMT_PRIV_H ++#define __MTK_BMT_PRIV_H ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define MAIN_SIGNATURE_OFFSET 0 ++#define OOB_SIGNATURE_OFFSET 1 ++ ++#define BBT_LOG(fmt, ...) pr_debug("[BBT][%s|%d] "fmt"\n", __func__, __LINE__, ##__VA_ARGS__) ++ ++struct mtk_bmt_ops { ++ char *sig; ++ unsigned int sig_len; ++ int (*init)(struct device_node *np); ++ bool (*remap_block)(u16 block, u16 mapped_block, int copy_len); ++ void (*unmap_block)(u16 block); ++ int (*get_mapping_block)(int block); ++ int (*debug)(void *data, u64 val); ++}; ++ ++struct bbbt; ++struct nmbm_instance; ++ ++struct bmt_desc { ++ struct mtd_info *mtd; ++ unsigned char *bbt_buf; ++ unsigned char *data_buf; ++ ++ int (*_read_oob) (struct mtd_info *mtd, loff_t from, ++ struct mtd_oob_ops *ops); ++ int (*_write_oob) (struct mtd_info *mtd, loff_t to, ++ struct mtd_oob_ops *ops); ++ int (*_erase) (struct mtd_info *mtd, struct erase_info *instr); ++ int (*_block_isbad) (struct mtd_info *mtd, loff_t ofs); ++ int (*_block_markbad) (struct mtd_info *mtd, loff_t ofs); ++ ++ const struct mtk_bmt_ops *ops; ++ ++ union { ++ struct bbbt *bbt; ++ struct nmbm_instance *ni; ++ }; ++ ++ struct dentry *debugfs_dir; ++ ++ u32 table_size; ++ u32 pg_size; ++ u32 blk_size; ++ u16 pg_shift; ++ u16 blk_shift; ++ /* bbt logical address */ ++ u16 pool_lba; ++ /* bbt physical address */ ++ u16 pool_pba; ++ /* Maximum count of bad blocks that the vendor guaranteed */ ++ u16 bb_max; ++ /* Total blocks of the Nand Chip */ ++ u16 total_blks; ++ /* The block(n) BMT is located at (bmt_tbl[n]) */ ++ u16 bmt_blk_idx; ++ /* How many pages needs to store 'struct bbbt' */ ++ u32 bmt_pgs; ++ ++ const __be32 *remap_range; ++ int remap_range_len; ++ ++ /* to compensate for driver level remapping */ ++ u8 oob_offset; ++}; ++ ++extern struct bmt_desc bmtd; ++extern const struct mtk_bmt_ops mtk_bmt_v2_ops; ++extern const struct mtk_bmt_ops mtk_bmt_bbt_ops; ++extern const struct mtk_bmt_ops mtk_bmt_nmbm_ops; ++ ++static inline u32 blk_pg(u16 block) ++{ ++ return (u32)(block << (bmtd.blk_shift - bmtd.pg_shift)); ++} ++ ++static inline int ++bbt_nand_read(u32 page, unsigned char *dat, int dat_len, ++ unsigned char *fdm, int fdm_len) ++{ ++ struct mtd_oob_ops ops = { ++ .mode = MTD_OPS_PLACE_OOB, ++ .ooboffs = bmtd.oob_offset, ++ .oobbuf = fdm, ++ .ooblen = fdm_len, ++ .datbuf = dat, ++ .len = dat_len, ++ }; ++ int ret; ++ ++ ret = bmtd._read_oob(bmtd.mtd, page << bmtd.pg_shift, &ops); ++ if (ret < 0) ++ return ret; ++ if (ret) ++ pr_info("%s: %d bitflips\n", __func__, ret); ++ return 0; ++} ++ ++static inline int bbt_nand_erase(u16 block) ++{ ++ struct mtd_info *mtd = bmtd.mtd; ++ struct erase_info instr = { ++ .addr = (loff_t)block << bmtd.blk_shift, ++ .len = bmtd.blk_size, ++ }; ++ ++ return bmtd._erase(mtd, &instr); ++} ++ ++static inline int write_bmt(u16 block, unsigned char *dat) ++{ ++ struct mtd_oob_ops ops = { ++ .mode = MTD_OPS_PLACE_OOB, ++ .ooboffs = OOB_SIGNATURE_OFFSET + bmtd.oob_offset, ++ .oobbuf = bmtd.ops->sig, ++ .ooblen = bmtd.ops->sig_len, ++ .datbuf = dat, ++ .len = bmtd.bmt_pgs << bmtd.pg_shift, ++ }; ++ loff_t addr = (loff_t)block << bmtd.blk_shift; ++ ++ return bmtd._write_oob(bmtd.mtd, addr, &ops); ++} ++ ++int bbt_nand_copy(u16 dest_blk, u16 src_blk, loff_t max_offset); ++bool mapping_block_in_range(int block, int *start, int *end); ++ ++#endif +diff --git a/drivers/mtd/nand/mtk_bmt_bbt.c b/drivers/mtd/nand/mtk_bmt_bbt.c +new file mode 100644 +index 000000000000..519e1ed70c7b +--- /dev/null ++++ b/drivers/mtd/nand/mtk_bmt_bbt.c +@@ -0,0 +1,203 @@ ++/* ++ * Copyright (c) 2017 MediaTek Inc. ++ * Author: Xiangsheng Hou ++ * Copyright (c) 2020-2022 Felix Fietkau ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#include ++#include ++#include "mtk_bmt.h" ++ ++static bool ++bbt_block_is_bad(u16 block) ++{ ++ u8 cur = bmtd.bbt_buf[block / 4]; ++ ++ return cur & (3 << ((block % 4) * 2)); ++} ++ ++static void ++bbt_set_block_state(u16 block, bool bad) ++{ ++ u8 mask = (3 << ((block % 4) * 2)); ++ ++ if (bad) ++ bmtd.bbt_buf[block / 4] |= mask; ++ else ++ bmtd.bbt_buf[block / 4] &= ~mask; ++ ++ bbt_nand_erase(bmtd.bmt_blk_idx); ++ write_bmt(bmtd.bmt_blk_idx, bmtd.bbt_buf); ++} ++ ++static int ++get_mapping_block_index_bbt(int block) ++{ ++ int start, end, ofs; ++ int bad_blocks = 0; ++ int i; ++ ++ if (!mapping_block_in_range(block, &start, &end)) ++ return block; ++ ++ start >>= bmtd.blk_shift; ++ end >>= bmtd.blk_shift; ++ /* skip bad blocks within the mapping range */ ++ ofs = block - start; ++ for (i = start; i < end; i++) { ++ if (bbt_block_is_bad(i)) ++ bad_blocks++; ++ else if (ofs) ++ ofs--; ++ else ++ break; ++ } ++ ++ if (i < end) ++ return i; ++ ++ /* when overflowing, remap remaining blocks to bad ones */ ++ for (i = end - 1; bad_blocks > 0; i--) { ++ if (!bbt_block_is_bad(i)) ++ continue; ++ ++ bad_blocks--; ++ if (bad_blocks <= ofs) ++ return i; ++ } ++ ++ return block; ++} ++ ++static bool remap_block_bbt(u16 block, u16 mapped_blk, int copy_len) ++{ ++ int start, end; ++ u16 new_blk; ++ ++ if (!mapping_block_in_range(block, &start, &end)) ++ return false; ++ ++ bbt_set_block_state(mapped_blk, true); ++ ++ new_blk = get_mapping_block_index_bbt(block); ++ bbt_nand_erase(new_blk); ++ if (copy_len > 0) ++ bbt_nand_copy(new_blk, mapped_blk, copy_len); ++ ++ return true; ++} ++ ++static void ++unmap_block_bbt(u16 block) ++{ ++ bbt_set_block_state(block, false); ++} ++ ++static int ++mtk_bmt_read_bbt(void) ++{ ++ u8 oob_buf[8]; ++ int i; ++ ++ for (i = bmtd.total_blks - 1; i >= bmtd.total_blks - 5; i--) { ++ u32 page = i << (bmtd.blk_shift - bmtd.pg_shift); ++ ++ if (bbt_nand_read(page, bmtd.bbt_buf, bmtd.pg_size, ++ oob_buf, sizeof(oob_buf))) { ++ pr_info("read_bbt: could not read block %d\n", i); ++ continue; ++ } ++ ++ if (oob_buf[0] != 0xff) { ++ pr_info("read_bbt: bad block at %d\n", i); ++ continue; ++ } ++ ++ if (memcmp(&oob_buf[1], "mtknand", 7) != 0) { ++ pr_info("read_bbt: signature mismatch in block %d\n", i); ++ print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 1, oob_buf, 8, 1); ++ continue; ++ } ++ ++ pr_info("read_bbt: found bbt at block %d\n", i); ++ bmtd.bmt_blk_idx = i; ++ return 0; ++ } ++ ++ return -EIO; ++} ++ ++ ++static int ++mtk_bmt_init_bbt(struct device_node *np) ++{ ++ int buf_size = round_up(bmtd.total_blks >> 2, bmtd.blk_size); ++ int ret; ++ ++ bmtd.bbt_buf = kmalloc(buf_size, GFP_KERNEL); ++ if (!bmtd.bbt_buf) ++ return -ENOMEM; ++ ++ memset(bmtd.bbt_buf, 0xff, buf_size); ++ bmtd.mtd->size -= 4 * bmtd.mtd->erasesize; ++ ++ ret = mtk_bmt_read_bbt(); ++ if (ret) ++ return ret; ++ ++ bmtd.bmt_pgs = buf_size / bmtd.pg_size; ++ ++ return 0; ++} ++ ++static int mtk_bmt_debug_bbt(void *data, u64 val) ++{ ++ char buf[5]; ++ int i, k; ++ ++ switch (val) { ++ case 0: ++ for (i = 0; i < bmtd.total_blks; i += 4) { ++ u8 cur = bmtd.bbt_buf[i / 4]; ++ ++ for (k = 0; k < 4; k++, cur >>= 2) ++ buf[k] = (cur & 3) ? 'B' : '.'; ++ ++ buf[4] = 0; ++ printk("[%06x] %s\n", i * bmtd.blk_size, buf); ++ } ++ break; ++ case 100: ++#if 0 ++ for (i = bmtd.bmt_blk_idx; i < bmtd.total_blks - 1; i++) ++ bbt_nand_erase(bmtd.bmt_blk_idx); ++#endif ++ ++ bmtd.bmt_blk_idx = bmtd.total_blks - 1; ++ bbt_nand_erase(bmtd.bmt_blk_idx); ++ write_bmt(bmtd.bmt_blk_idx, bmtd.bbt_buf); ++ break; ++ default: ++ break; ++ } ++ return 0; ++} ++ ++const struct mtk_bmt_ops mtk_bmt_bbt_ops = { ++ .sig = "mtknand", ++ .sig_len = 7, ++ .init = mtk_bmt_init_bbt, ++ .remap_block = remap_block_bbt, ++ .unmap_block = unmap_block_bbt, ++ .get_mapping_block = get_mapping_block_index_bbt, ++ .debug = mtk_bmt_debug_bbt, ++}; +diff --git a/drivers/mtd/nand/mtk_bmt_nmbm.c b/drivers/mtd/nand/mtk_bmt_nmbm.c +new file mode 100644 +index 000000000000..a896e49ec047 +--- /dev/null ++++ b/drivers/mtd/nand/mtk_bmt_nmbm.c +@@ -0,0 +1,2348 @@ ++#include ++#include ++#include "mtk_bmt.h" ++ ++#define nlog_err(ni, ...) printk(KERN_ERR __VA_ARGS__) ++#define nlog_info(ni, ...) printk(KERN_INFO __VA_ARGS__) ++#define nlog_debug(ni, ...) printk(KERN_INFO __VA_ARGS__) ++#define nlog_warn(ni, ...) printk(KERN_WARNING __VA_ARGS__) ++ ++#define NMBM_MAGIC_SIGNATURE 0x304d4d4e /* NMM0 */ ++#define NMBM_MAGIC_INFO_TABLE 0x314d4d4e /* NMM1 */ ++ ++#define NMBM_VERSION_MAJOR_S 0 ++#define NMBM_VERSION_MAJOR_M 0xffff ++#define NMBM_VERSION_MINOR_S 16 ++#define NMBM_VERSION_MINOR_M 0xffff ++#define NMBM_VERSION_MAKE(major, minor) (((major) & NMBM_VERSION_MAJOR_M) | \ ++ (((minor) & NMBM_VERSION_MINOR_M) << \ ++ NMBM_VERSION_MINOR_S)) ++#define NMBM_VERSION_MAJOR_GET(ver) (((ver) >> NMBM_VERSION_MAJOR_S) & \ ++ NMBM_VERSION_MAJOR_M) ++#define NMBM_VERSION_MINOR_GET(ver) (((ver) >> NMBM_VERSION_MINOR_S) & \ ++ NMBM_VERSION_MINOR_M) ++ ++#define NMBM_BITMAP_UNIT_SIZE (sizeof(u32)) ++#define NMBM_BITMAP_BITS_PER_BLOCK 2 ++#define NMBM_BITMAP_BITS_PER_UNIT (8 * sizeof(u32)) ++#define NMBM_BITMAP_BLOCKS_PER_UNIT (NMBM_BITMAP_BITS_PER_UNIT / \ ++ NMBM_BITMAP_BITS_PER_BLOCK) ++ ++#define NMBM_SPARE_BLOCK_MULTI 1 ++#define NMBM_SPARE_BLOCK_DIV 2 ++#define NMBM_SPARE_BLOCK_MIN 2 ++ ++#define NMBM_MGMT_DIV 16 ++#define NMBM_MGMT_BLOCKS_MIN 32 ++ ++#define NMBM_TRY_COUNT 3 ++ ++#define BLOCK_ST_BAD 0 ++#define BLOCK_ST_NEED_REMAP 2 ++#define BLOCK_ST_GOOD 3 ++#define BLOCK_ST_MASK 3 ++ ++#define NMBM_VER_MAJOR 1 ++#define NMBM_VER_MINOR 0 ++#define NMBM_VER NMBM_VERSION_MAKE(NMBM_VER_MAJOR, \ ++ NMBM_VER_MINOR) ++ ++struct nmbm_header { ++ u32 magic; ++ u32 version; ++ u32 size; ++ u32 checksum; ++}; ++ ++struct nmbm_signature { ++ struct nmbm_header header; ++ uint64_t nand_size; ++ u32 block_size; ++ u32 page_size; ++ u32 spare_size; ++ u32 mgmt_start_pb; ++ u8 max_try_count; ++ u8 padding[3]; ++}; ++ ++struct nmbm_info_table_header { ++ struct nmbm_header header; ++ u32 write_count; ++ u32 state_table_off; ++ u32 mapping_table_off; ++ u32 padding; ++}; ++ ++struct nmbm_instance { ++ u32 rawpage_size; ++ u32 rawblock_size; ++ u32 rawchip_size; ++ ++ struct nmbm_signature signature; ++ ++ u8 *info_table_cache; ++ u32 info_table_size; ++ u32 info_table_spare_blocks; ++ struct nmbm_info_table_header info_table; ++ ++ u32 *block_state; ++ u32 block_state_changed; ++ u32 state_table_size; ++ ++ int32_t *block_mapping; ++ u32 block_mapping_changed; ++ u32 mapping_table_size; ++ ++ u8 *page_cache; ++ ++ int protected; ++ ++ u32 block_count; ++ u32 data_block_count; ++ ++ u32 mgmt_start_ba; ++ u32 main_table_ba; ++ u32 backup_table_ba; ++ u32 mapping_blocks_ba; ++ u32 mapping_blocks_top_ba; ++ u32 signature_ba; ++ ++ u32 max_ratio; ++ u32 max_reserved_blocks; ++ bool empty_page_ecc_ok; ++ bool force_create; ++}; ++ ++static inline u32 nmbm_crc32(u32 crcval, const void *buf, size_t size) ++{ ++ unsigned int chksz; ++ const unsigned char *p = buf; ++ ++ while (size) { ++ if (size > UINT_MAX) ++ chksz = UINT_MAX; ++ else ++ chksz = (uint)size; ++ ++ crcval = crc32_le(crcval, p, chksz); ++ size -= chksz; ++ p += chksz; ++ } ++ ++ return crcval; ++} ++/* ++ * nlog_table_creation - Print log of table creation event ++ * @ni: NMBM instance structure ++ * @main_table: whether the table is main info table ++ * @start_ba: start block address of the table ++ * @end_ba: block address after the end of the table ++ */ ++static void nlog_table_creation(struct nmbm_instance *ni, bool main_table, ++ uint32_t start_ba, uint32_t end_ba) ++{ ++ if (start_ba == end_ba - 1) ++ nlog_info(ni, "%s info table has been written to block %u\n", ++ main_table ? "Main" : "Backup", start_ba); ++ else ++ nlog_info(ni, "%s info table has been written to block %u-%u\n", ++ main_table ? "Main" : "Backup", start_ba, end_ba - 1); ++} ++ ++/* ++ * nlog_table_update - Print log of table update event ++ * @ni: NMBM instance structure ++ * @main_table: whether the table is main info table ++ * @start_ba: start block address of the table ++ * @end_ba: block address after the end of the table ++ */ ++static void nlog_table_update(struct nmbm_instance *ni, bool main_table, ++ uint32_t start_ba, uint32_t end_ba) ++{ ++ if (start_ba == end_ba - 1) ++ nlog_debug(ni, "%s info table has been updated in block %u\n", ++ main_table ? "Main" : "Backup", start_ba); ++ else ++ nlog_debug(ni, "%s info table has been updated in block %u-%u\n", ++ main_table ? "Main" : "Backup", start_ba, end_ba - 1); ++} ++ ++/* ++ * nlog_table_found - Print log of table found event ++ * @ni: NMBM instance structure ++ * @first_table: whether the table is first found info table ++ * @write_count: write count of the info table ++ * @start_ba: start block address of the table ++ * @end_ba: block address after the end of the table ++ */ ++static void nlog_table_found(struct nmbm_instance *ni, bool first_table, ++ uint32_t write_count, uint32_t start_ba, ++ uint32_t end_ba) ++{ ++ if (start_ba == end_ba - 1) ++ nlog_info(ni, "%s info table with writecount %u found in block %u\n", ++ first_table ? "First" : "Second", write_count, ++ start_ba); ++ else ++ nlog_info(ni, "%s info table with writecount %u found in block %u-%u\n", ++ first_table ? "First" : "Second", write_count, ++ start_ba, end_ba - 1); ++} ++ ++/*****************************************************************************/ ++/* Address conversion functions */ ++/*****************************************************************************/ ++ ++/* ++ * ba2addr - Convert a block address to linear address ++ * @ni: NMBM instance structure ++ * @ba: Block address ++ */ ++static uint64_t ba2addr(struct nmbm_instance *ni, uint32_t ba) ++{ ++ return (uint64_t)ba << bmtd.blk_shift; ++} ++/* ++ * size2blk - Get minimum required blocks for storing specific size of data ++ * @ni: NMBM instance structure ++ * @size: size for storing ++ */ ++static uint32_t size2blk(struct nmbm_instance *ni, uint64_t size) ++{ ++ return (size + bmtd.blk_size - 1) >> bmtd.blk_shift; ++} ++ ++/*****************************************************************************/ ++/* High level NAND chip APIs */ ++/*****************************************************************************/ ++ ++/* ++ * nmbm_read_phys_page - Read page with retry ++ * @ni: NMBM instance structure ++ * @addr: linear address where the data will be read from ++ * @data: the main data to be read ++ * @oob: the oob data to be read ++ * ++ * Read a page for at most NMBM_TRY_COUNT times. ++ * ++ * Return 0 for success, positive value for corrected bitflip count, ++ * -EBADMSG for ecc error, other negative values for other errors ++ */ ++static int nmbm_read_phys_page(struct nmbm_instance *ni, uint64_t addr, ++ void *data, void *oob) ++{ ++ int tries, ret; ++ ++ for (tries = 0; tries < NMBM_TRY_COUNT; tries++) { ++ struct mtd_oob_ops ops = { ++ .mode = MTD_OPS_PLACE_OOB, ++ .oobbuf = oob, ++ .datbuf = data, ++ }; ++ ++ if (data) ++ ops.len = bmtd.pg_size; ++ if (oob) ++ ops.ooblen = mtd_oobavail(bmtd.mtd, &ops); ++ ++ ret = bmtd._read_oob(bmtd.mtd, addr, &ops); ++ if (ret == -EUCLEAN) ++ return min_t(u32, bmtd.mtd->bitflip_threshold + 1, ++ bmtd.mtd->ecc_strength); ++ if (ret >= 0) ++ return 0; ++ } ++ ++ if (ret != -EBADMSG) ++ nlog_err(ni, "Page read failed at address 0x%08llx\n", addr); ++ ++ return ret; ++} ++ ++/* ++ * nmbm_write_phys_page - Write page with retry ++ * @ni: NMBM instance structure ++ * @addr: linear address where the data will be written to ++ * @data: the main data to be written ++ * @oob: the oob data to be written ++ * ++ * Write a page for at most NMBM_TRY_COUNT times. ++ */ ++static bool nmbm_write_phys_page(struct nmbm_instance *ni, uint64_t addr, ++ const void *data, const void *oob) ++{ ++ int tries, ret; ++ ++ for (tries = 0; tries < NMBM_TRY_COUNT; tries++) { ++ struct mtd_oob_ops ops = { ++ .mode = MTD_OPS_PLACE_OOB, ++ .oobbuf = (void *)oob, ++ .datbuf = (void *)data, ++ }; ++ ++ if (data) ++ ops.len = bmtd.pg_size; ++ if (oob) ++ ops.ooblen = mtd_oobavail(bmtd.mtd, &ops); ++ ++ ret = bmtd._write_oob(bmtd.mtd, addr, &ops); ++ if (!ret) ++ return true; ++ } ++ ++ nlog_err(ni, "Page write failed at address 0x%08llx\n", addr); ++ ++ return false; ++} ++ ++/* ++ * nmbm_erase_phys_block - Erase a block with retry ++ * @ni: NMBM instance structure ++ * @addr: Linear address ++ * ++ * Erase a block for at most NMBM_TRY_COUNT times. ++ */ ++static bool nmbm_erase_phys_block(struct nmbm_instance *ni, uint64_t addr) ++{ ++ int tries, ret; ++ ++ for (tries = 0; tries < NMBM_TRY_COUNT; tries++) { ++ struct erase_info ei = { ++ .addr = addr, ++ .len = bmtd.mtd->erasesize, ++ }; ++ ++ ret = bmtd._erase(bmtd.mtd, &ei); ++ if (!ret) ++ return true; ++ } ++ ++ nlog_err(ni, "Block erasure failed at address 0x%08llx\n", addr); ++ ++ return false; ++} ++ ++/* ++ * nmbm_check_bad_phys_block - Check whether a block is marked bad in OOB ++ * @ni: NMBM instance structure ++ * @ba: block address ++ */ ++static bool nmbm_check_bad_phys_block(struct nmbm_instance *ni, uint32_t ba) ++{ ++ uint64_t addr = ba2addr(ni, ba); ++ ++ return bmtd._block_isbad(bmtd.mtd, addr); ++} ++ ++/* ++ * nmbm_mark_phys_bad_block - Mark a block bad ++ * @ni: NMBM instance structure ++ * @addr: Linear address ++ */ ++static int nmbm_mark_phys_bad_block(struct nmbm_instance *ni, uint32_t ba) ++{ ++ uint64_t addr = ba2addr(ni, ba); ++ ++ nlog_info(ni, "Block %u [0x%08llx] will be marked bad\n", ba, addr); ++ ++ return bmtd._block_markbad(bmtd.mtd, addr); ++} ++ ++/*****************************************************************************/ ++/* NMBM related functions */ ++/*****************************************************************************/ ++ ++/* ++ * nmbm_check_header - Check whether a NMBM structure is valid ++ * @data: pointer to a NMBM structure with a NMBM header at beginning ++ * @size: Size of the buffer pointed by @header ++ * ++ * The size of the NMBM structure may be larger than NMBM header, ++ * e.g. block mapping table and block state table. ++ */ ++static bool nmbm_check_header(const void *data, uint32_t size) ++{ ++ const struct nmbm_header *header = data; ++ struct nmbm_header nhdr; ++ uint32_t new_checksum; ++ ++ /* ++ * Make sure expected structure size is equal or smaller than ++ * buffer size. ++ */ ++ if (header->size > size) ++ return false; ++ ++ memcpy(&nhdr, data, sizeof(nhdr)); ++ ++ nhdr.checksum = 0; ++ new_checksum = nmbm_crc32(0, &nhdr, sizeof(nhdr)); ++ if (header->size > sizeof(nhdr)) ++ new_checksum = nmbm_crc32(new_checksum, ++ (const uint8_t *)data + sizeof(nhdr), ++ header->size - sizeof(nhdr)); ++ ++ if (header->checksum != new_checksum) ++ return false; ++ ++ return true; ++} ++ ++/* ++ * nmbm_update_checksum - Update checksum of a NMBM structure ++ * @header: pointer to a NMBM structure with a NMBM header at beginning ++ * ++ * The size of the NMBM structure must be specified by @header->size ++ */ ++static void nmbm_update_checksum(struct nmbm_header *header) ++{ ++ header->checksum = 0; ++ header->checksum = nmbm_crc32(0, header, header->size); ++} ++ ++/* ++ * nmbm_get_spare_block_count - Calculate number of blocks should be reserved ++ * @block_count: number of blocks of data ++ * ++ * Calculate number of blocks should be reserved for data ++ */ ++static uint32_t nmbm_get_spare_block_count(uint32_t block_count) ++{ ++ uint32_t val; ++ ++ val = (block_count + NMBM_SPARE_BLOCK_DIV / 2) / NMBM_SPARE_BLOCK_DIV; ++ val *= NMBM_SPARE_BLOCK_MULTI; ++ ++ if (val < NMBM_SPARE_BLOCK_MIN) ++ val = NMBM_SPARE_BLOCK_MIN; ++ ++ return val; ++} ++ ++/* ++ * nmbm_get_block_state_raw - Get state of a block from raw block state table ++ * @block_state: pointer to raw block state table (bitmap) ++ * @ba: block address ++ */ ++static uint32_t nmbm_get_block_state_raw(u32 *block_state, ++ uint32_t ba) ++{ ++ uint32_t unit, shift; ++ ++ unit = ba / NMBM_BITMAP_BLOCKS_PER_UNIT; ++ shift = (ba % NMBM_BITMAP_BLOCKS_PER_UNIT) * NMBM_BITMAP_BITS_PER_BLOCK; ++ ++ return (block_state[unit] >> shift) & BLOCK_ST_MASK; ++} ++ ++/* ++ * nmbm_get_block_state - Get state of a block from block state table ++ * @ni: NMBM instance structure ++ * @ba: block address ++ */ ++static uint32_t nmbm_get_block_state(struct nmbm_instance *ni, uint32_t ba) ++{ ++ return nmbm_get_block_state_raw(ni->block_state, ba); ++} ++ ++/* ++ * nmbm_set_block_state - Set state of a block to block state table ++ * @ni: NMBM instance structure ++ * @ba: block address ++ * @state: block state ++ * ++ * Set state of a block. If the block state changed, ni->block_state_changed ++ * will be increased. ++ */ ++static bool nmbm_set_block_state(struct nmbm_instance *ni, uint32_t ba, ++ uint32_t state) ++{ ++ uint32_t unit, shift, orig; ++ u32 uv; ++ ++ unit = ba / NMBM_BITMAP_BLOCKS_PER_UNIT; ++ shift = (ba % NMBM_BITMAP_BLOCKS_PER_UNIT) * NMBM_BITMAP_BITS_PER_BLOCK; ++ ++ orig = (ni->block_state[unit] >> shift) & BLOCK_ST_MASK; ++ state &= BLOCK_ST_MASK; ++ ++ uv = ni->block_state[unit] & (~(BLOCK_ST_MASK << shift)); ++ uv |= state << shift; ++ ni->block_state[unit] = uv; ++ ++ if (orig != state) { ++ ni->block_state_changed++; ++ return true; ++ } ++ ++ return false; ++} ++ ++/* ++ * nmbm_block_walk_asc - Skip specified number of good blocks, ascending addr. ++ * @ni: NMBM instance structure ++ * @ba: start physical block address ++ * @nba: return physical block address after walk ++ * @count: number of good blocks to be skipped ++ * @limit: highest block address allowed for walking ++ * ++ * Start from @ba, skipping any bad blocks, counting @count good blocks, and ++ * return the next good block address. ++ * ++ * If no enough good blocks counted while @limit reached, false will be returned. ++ * ++ * If @count == 0, nearest good block address will be returned. ++ * @limit is not counted in walking. ++ */ ++static bool nmbm_block_walk_asc(struct nmbm_instance *ni, uint32_t ba, ++ uint32_t *nba, uint32_t count, ++ uint32_t limit) ++{ ++ int32_t nblock = count; ++ ++ if (limit >= ni->block_count) ++ limit = ni->block_count - 1; ++ ++ while (ba < limit) { ++ if (nmbm_get_block_state(ni, ba) == BLOCK_ST_GOOD) ++ nblock--; ++ ++ if (nblock < 0) { ++ *nba = ba; ++ return true; ++ } ++ ++ ba++; ++ } ++ ++ return false; ++} ++ ++/* ++ * nmbm_block_walk_desc - Skip specified number of good blocks, descending addr ++ * @ni: NMBM instance structure ++ * @ba: start physical block address ++ * @nba: return physical block address after walk ++ * @count: number of good blocks to be skipped ++ * @limit: lowest block address allowed for walking ++ * ++ * Start from @ba, skipping any bad blocks, counting @count good blocks, and ++ * return the next good block address. ++ * ++ * If no enough good blocks counted while @limit reached, false will be returned. ++ * ++ * If @count == 0, nearest good block address will be returned. ++ * @limit is not counted in walking. ++ */ ++static bool nmbm_block_walk_desc(struct nmbm_instance *ni, uint32_t ba, ++ uint32_t *nba, uint32_t count, uint32_t limit) ++{ ++ int32_t nblock = count; ++ ++ if (limit >= ni->block_count) ++ limit = ni->block_count - 1; ++ ++ while (ba > limit) { ++ if (nmbm_get_block_state(ni, ba) == BLOCK_ST_GOOD) ++ nblock--; ++ ++ if (nblock < 0) { ++ *nba = ba; ++ return true; ++ } ++ ++ ba--; ++ } ++ ++ return false; ++} ++ ++/* ++ * nmbm_block_walk - Skip specified number of good blocks from curr. block addr ++ * @ni: NMBM instance structure ++ * @ascending: whether to walk ascending ++ * @ba: start physical block address ++ * @nba: return physical block address after walk ++ * @count: number of good blocks to be skipped ++ * @limit: highest/lowest block address allowed for walking ++ * ++ * Start from @ba, skipping any bad blocks, counting @count good blocks, and ++ * return the next good block address. ++ * ++ * If no enough good blocks counted while @limit reached, false will be returned. ++ * ++ * If @count == 0, nearest good block address will be returned. ++ * @limit can be set to negative if no limit required. ++ * @limit is not counted in walking. ++ */ ++static bool nmbm_block_walk(struct nmbm_instance *ni, bool ascending, ++ uint32_t ba, uint32_t *nba, int32_t count, ++ int32_t limit) ++{ ++ if (ascending) ++ return nmbm_block_walk_asc(ni, ba, nba, count, limit); ++ ++ return nmbm_block_walk_desc(ni, ba, nba, count, limit); ++} ++ ++/* ++ * nmbm_scan_badblocks - Scan and record all bad blocks ++ * @ni: NMBM instance structure ++ * ++ * Scan the entire lower NAND chip and record all bad blocks in to block state ++ * table. ++ */ ++static void nmbm_scan_badblocks(struct nmbm_instance *ni) ++{ ++ uint32_t ba; ++ ++ for (ba = 0; ba < ni->block_count; ba++) { ++ if (nmbm_check_bad_phys_block(ni, ba)) { ++ nmbm_set_block_state(ni, ba, BLOCK_ST_BAD); ++ nlog_info(ni, "Bad block %u [0x%08llx]\n", ba, ++ ba2addr(ni, ba)); ++ } ++ } ++} ++ ++/* ++ * nmbm_build_mapping_table - Build initial block mapping table ++ * @ni: NMBM instance structure ++ * ++ * The initial mapping table will be compatible with the stratage of ++ * factory production. ++ */ ++static void nmbm_build_mapping_table(struct nmbm_instance *ni) ++{ ++ uint32_t pb, lb; ++ ++ for (pb = 0, lb = 0; pb < ni->mgmt_start_ba; pb++) { ++ if (nmbm_get_block_state(ni, pb) == BLOCK_ST_BAD) ++ continue; ++ ++ /* Always map to the next good block */ ++ ni->block_mapping[lb++] = pb; ++ } ++ ++ ni->data_block_count = lb; ++ ++ /* Unusable/Management blocks */ ++ for (pb = lb; pb < ni->block_count; pb++) ++ ni->block_mapping[pb] = -1; ++} ++ ++/* ++ * nmbm_erase_block_and_check - Erase a block and check its usability ++ * @ni: NMBM instance structure ++ * @ba: block address to be erased ++ * ++ * Erase a block anc check its usability ++ * ++ * Return true if the block is usable, false if erasure failure or the block ++ * has too many bitflips. ++ */ ++static bool nmbm_erase_block_and_check(struct nmbm_instance *ni, uint32_t ba) ++{ ++ uint64_t addr, off; ++ bool success; ++ int ret; ++ ++ success = nmbm_erase_phys_block(ni, ba2addr(ni, ba)); ++ if (!success) ++ return false; ++ ++ if (!ni->empty_page_ecc_ok) ++ return true; ++ ++ /* Check every page to make sure there aren't too many bitflips */ ++ ++ addr = ba2addr(ni, ba); ++ ++ for (off = 0; off < bmtd.blk_size; off += bmtd.pg_size) { ++ ret = nmbm_read_phys_page(ni, addr + off, ni->page_cache, NULL); ++ if (ret == -EBADMSG) { ++ /* ++ * empty_page_ecc_ok means the empty page is ++ * still protected by ECC. So reading pages with ECC ++ * enabled and -EBADMSG means there are too many ++ * bitflips that can't be recovered, and the block ++ * containing the page should be marked bad. ++ */ ++ nlog_err(ni, ++ "Too many bitflips in empty page at 0x%llx\n", ++ addr + off); ++ return false; ++ } ++ } ++ ++ return true; ++} ++ ++/* ++ * nmbm_erase_range - Erase a range of blocks ++ * @ni: NMBM instance structure ++ * @ba: block address where the erasure will start ++ * @limit: top block address allowed for erasure ++ * ++ * Erase blocks within the specific range. Newly-found bad blocks will be ++ * marked. ++ * ++ * @limit is not counted into the allowed erasure address. ++ */ ++static void nmbm_erase_range(struct nmbm_instance *ni, uint32_t ba, ++ uint32_t limit) ++{ ++ bool success; ++ ++ while (ba < limit) { ++ if (nmbm_get_block_state(ni, ba) != BLOCK_ST_GOOD) ++ goto next_block; ++ ++ /* Insurance to detect unexpected bad block marked by user */ ++ if (nmbm_check_bad_phys_block(ni, ba)) { ++ nmbm_set_block_state(ni, ba, BLOCK_ST_BAD); ++ goto next_block; ++ } ++ ++ success = nmbm_erase_block_and_check(ni, ba); ++ if (success) ++ goto next_block; ++ ++ nmbm_mark_phys_bad_block(ni, ba); ++ nmbm_set_block_state(ni, ba, BLOCK_ST_BAD); ++ ++ next_block: ++ ba++; ++ } ++} ++ ++/* ++ * nmbm_write_repeated_data - Write critical data to a block with retry ++ * @ni: NMBM instance structure ++ * @ba: block address where the data will be written to ++ * @data: the data to be written ++ * @size: size of the data ++ * ++ * Write data to every page of the block. Success only if all pages within ++ * this block have been successfully written. ++ * ++ * Make sure data size is not bigger than one page. ++ * ++ * This function will write and verify every page for at most ++ * NMBM_TRY_COUNT times. ++ */ ++static bool nmbm_write_repeated_data(struct nmbm_instance *ni, uint32_t ba, ++ const void *data, uint32_t size) ++{ ++ uint64_t addr, off; ++ bool success; ++ int ret; ++ ++ if (size > bmtd.pg_size) ++ return false; ++ ++ addr = ba2addr(ni, ba); ++ ++ for (off = 0; off < bmtd.blk_size; off += bmtd.pg_size) { ++ /* Prepare page data. fill 0xff to unused region */ ++ memcpy(ni->page_cache, data, size); ++ memset(ni->page_cache + size, 0xff, ni->rawpage_size - size); ++ ++ success = nmbm_write_phys_page(ni, addr + off, ni->page_cache, NULL); ++ if (!success) ++ return false; ++ ++ /* Verify the data just written. ECC error indicates failure */ ++ ret = nmbm_read_phys_page(ni, addr + off, ni->page_cache, NULL); ++ if (ret < 0) ++ return false; ++ ++ if (memcmp(ni->page_cache, data, size)) ++ return false; ++ } ++ ++ return true; ++} ++ ++/* ++ * nmbm_write_signature - Write signature to NAND chip ++ * @ni: NMBM instance structure ++ * @limit: top block address allowed for writing ++ * @signature: the signature to be written ++ * @signature_ba: the actual block address where signature is written to ++ * ++ * Write signature within a specific range, from chip bottom to limit. ++ * At most one block will be written. ++ * ++ * @limit is not counted into the allowed write address. ++ */ ++static bool nmbm_write_signature(struct nmbm_instance *ni, uint32_t limit, ++ const struct nmbm_signature *signature, ++ uint32_t *signature_ba) ++{ ++ uint32_t ba = ni->block_count - 1; ++ bool success; ++ ++ while (ba > limit) { ++ if (nmbm_get_block_state(ni, ba) != BLOCK_ST_GOOD) ++ goto next_block; ++ ++ /* Insurance to detect unexpected bad block marked by user */ ++ if (nmbm_check_bad_phys_block(ni, ba)) { ++ nmbm_set_block_state(ni, ba, BLOCK_ST_BAD); ++ goto next_block; ++ } ++ ++ success = nmbm_erase_block_and_check(ni, ba); ++ if (!success) ++ goto skip_bad_block; ++ ++ success = nmbm_write_repeated_data(ni, ba, signature, ++ sizeof(*signature)); ++ if (success) { ++ *signature_ba = ba; ++ return true; ++ } ++ ++ skip_bad_block: ++ nmbm_mark_phys_bad_block(ni, ba); ++ nmbm_set_block_state(ni, ba, BLOCK_ST_BAD); ++ ++ next_block: ++ ba--; ++ }; ++ ++ return false; ++} ++ ++/* ++ * nmbn_read_data - Read data ++ * @ni: NMBM instance structure ++ * @addr: linear address where the data will be read from ++ * @data: the data to be read ++ * @size: the size of data ++ * ++ * Read data range. ++ * Every page will be tried for at most NMBM_TRY_COUNT times. ++ * ++ * Return 0 for success, positive value for corrected bitflip count, ++ * -EBADMSG for ecc error, other negative values for other errors ++ */ ++static int nmbn_read_data(struct nmbm_instance *ni, uint64_t addr, void *data, ++ uint32_t size) ++{ ++ uint64_t off = addr; ++ uint8_t *ptr = data; ++ uint32_t sizeremain = size, chunksize, leading; ++ int ret; ++ ++ while (sizeremain) { ++ leading = off & (bmtd.pg_size - 1); ++ chunksize = bmtd.pg_size - leading; ++ if (chunksize > sizeremain) ++ chunksize = sizeremain; ++ ++ if (chunksize == bmtd.pg_size) { ++ ret = nmbm_read_phys_page(ni, off - leading, ptr, NULL); ++ if (ret < 0) ++ return ret; ++ } else { ++ ret = nmbm_read_phys_page(ni, off - leading, ++ ni->page_cache, NULL); ++ if (ret < 0) ++ return ret; ++ ++ memcpy(ptr, ni->page_cache + leading, chunksize); ++ } ++ ++ off += chunksize; ++ ptr += chunksize; ++ sizeremain -= chunksize; ++ } ++ ++ return 0; ++} ++ ++/* ++ * nmbn_write_verify_data - Write data with validation ++ * @ni: NMBM instance structure ++ * @addr: linear address where the data will be written to ++ * @data: the data to be written ++ * @size: the size of data ++ * ++ * Write data and verify. ++ * Every page will be tried for at most NMBM_TRY_COUNT times. ++ */ ++static bool nmbn_write_verify_data(struct nmbm_instance *ni, uint64_t addr, ++ const void *data, uint32_t size) ++{ ++ uint64_t off = addr; ++ const uint8_t *ptr = data; ++ uint32_t sizeremain = size, chunksize, leading; ++ bool success; ++ int ret; ++ ++ while (sizeremain) { ++ leading = off & (bmtd.pg_size - 1); ++ chunksize = bmtd.pg_size - leading; ++ if (chunksize > sizeremain) ++ chunksize = sizeremain; ++ ++ /* Prepare page data. fill 0xff to unused region */ ++ memset(ni->page_cache, 0xff, ni->rawpage_size); ++ memcpy(ni->page_cache + leading, ptr, chunksize); ++ ++ success = nmbm_write_phys_page(ni, off - leading, ++ ni->page_cache, NULL); ++ if (!success) ++ return false; ++ ++ /* Verify the data just written. ECC error indicates failure */ ++ ret = nmbm_read_phys_page(ni, off - leading, ni->page_cache, NULL); ++ if (ret < 0) ++ return false; ++ ++ if (memcmp(ni->page_cache + leading, ptr, chunksize)) ++ return false; ++ ++ off += chunksize; ++ ptr += chunksize; ++ sizeremain -= chunksize; ++ } ++ ++ return true; ++} ++ ++/* ++ * nmbm_write_mgmt_range - Write management data into NAND within a range ++ * @ni: NMBM instance structure ++ * @addr: preferred start block address for writing ++ * @limit: highest block address allowed for writing ++ * @data: the data to be written ++ * @size: the size of data ++ * @actual_start_ba: actual start block address of data ++ * @actual_end_ba: block address after the end of data ++ * ++ * @limit is not counted into the allowed write address. ++ */ ++static bool nmbm_write_mgmt_range(struct nmbm_instance *ni, uint32_t ba, ++ uint32_t limit, const void *data, ++ uint32_t size, uint32_t *actual_start_ba, ++ uint32_t *actual_end_ba) ++{ ++ const uint8_t *ptr = data; ++ uint32_t sizeremain = size, chunksize; ++ bool success; ++ ++ while (sizeremain && ba < limit) { ++ chunksize = sizeremain; ++ if (chunksize > bmtd.blk_size) ++ chunksize = bmtd.blk_size; ++ ++ if (nmbm_get_block_state(ni, ba) != BLOCK_ST_GOOD) ++ goto next_block; ++ ++ /* Insurance to detect unexpected bad block marked by user */ ++ if (nmbm_check_bad_phys_block(ni, ba)) { ++ nmbm_set_block_state(ni, ba, BLOCK_ST_BAD); ++ goto next_block; ++ } ++ ++ success = nmbm_erase_block_and_check(ni, ba); ++ if (!success) ++ goto skip_bad_block; ++ ++ success = nmbn_write_verify_data(ni, ba2addr(ni, ba), ptr, ++ chunksize); ++ if (!success) ++ goto skip_bad_block; ++ ++ if (sizeremain == size) ++ *actual_start_ba = ba; ++ ++ ptr += chunksize; ++ sizeremain -= chunksize; ++ ++ goto next_block; ++ ++ skip_bad_block: ++ nmbm_mark_phys_bad_block(ni, ba); ++ nmbm_set_block_state(ni, ba, BLOCK_ST_BAD); ++ ++ next_block: ++ ba++; ++ } ++ ++ if (sizeremain) ++ return false; ++ ++ *actual_end_ba = ba; ++ ++ return true; ++} ++ ++/* ++ * nmbm_generate_info_table_cache - Generate info table cache data ++ * @ni: NMBM instance structure ++ * ++ * Generate info table cache data to be written into flash. ++ */ ++static bool nmbm_generate_info_table_cache(struct nmbm_instance *ni) ++{ ++ bool changed = false; ++ ++ memset(ni->info_table_cache, 0xff, ni->info_table_size); ++ ++ memcpy(ni->info_table_cache + ni->info_table.state_table_off, ++ ni->block_state, ni->state_table_size); ++ ++ memcpy(ni->info_table_cache + ni->info_table.mapping_table_off, ++ ni->block_mapping, ni->mapping_table_size); ++ ++ ni->info_table.header.magic = NMBM_MAGIC_INFO_TABLE; ++ ni->info_table.header.version = NMBM_VER; ++ ni->info_table.header.size = ni->info_table_size; ++ ++ if (ni->block_state_changed || ni->block_mapping_changed) { ++ ni->info_table.write_count++; ++ changed = true; ++ } ++ ++ memcpy(ni->info_table_cache, &ni->info_table, sizeof(ni->info_table)); ++ ++ nmbm_update_checksum((struct nmbm_header *)ni->info_table_cache); ++ ++ return changed; ++} ++ ++/* ++ * nmbm_write_info_table - Write info table into NAND within a range ++ * @ni: NMBM instance structure ++ * @ba: preferred start block address for writing ++ * @limit: highest block address allowed for writing ++ * @actual_start_ba: actual start block address of info table ++ * @actual_end_ba: block address after the end of info table ++ * ++ * @limit is counted into the allowed write address. ++ */ ++static bool nmbm_write_info_table(struct nmbm_instance *ni, uint32_t ba, ++ uint32_t limit, uint32_t *actual_start_ba, ++ uint32_t *actual_end_ba) ++{ ++ return nmbm_write_mgmt_range(ni, ba, limit, ni->info_table_cache, ++ ni->info_table_size, actual_start_ba, ++ actual_end_ba); ++} ++ ++/* ++ * nmbm_mark_tables_clean - Mark info table `clean' ++ * @ni: NMBM instance structure ++ */ ++static void nmbm_mark_tables_clean(struct nmbm_instance *ni) ++{ ++ ni->block_state_changed = 0; ++ ni->block_mapping_changed = 0; ++} ++ ++/* ++ * nmbm_try_reserve_blocks - Reserve blocks with compromisation ++ * @ni: NMBM instance structure ++ * @ba: start physical block address ++ * @nba: return physical block address after reservation ++ * @count: number of good blocks to be skipped ++ * @min_count: minimum number of good blocks to be skipped ++ * @limit: highest/lowest block address allowed for walking ++ * ++ * Reserve specific blocks. If failed, try to reserve as many as possible. ++ */ ++static bool nmbm_try_reserve_blocks(struct nmbm_instance *ni, uint32_t ba, ++ uint32_t *nba, uint32_t count, ++ int32_t min_count, int32_t limit) ++{ ++ int32_t nblocks = count; ++ bool success; ++ ++ while (nblocks >= min_count) { ++ success = nmbm_block_walk(ni, true, ba, nba, nblocks, limit); ++ if (success) ++ return true; ++ ++ nblocks--; ++ } ++ ++ return false; ++} ++ ++/* ++ * nmbm_rebuild_info_table - Build main & backup info table from scratch ++ * @ni: NMBM instance structure ++ * @allow_no_gap: allow no spare blocks between two tables ++ */ ++static bool nmbm_rebuild_info_table(struct nmbm_instance *ni) ++{ ++ uint32_t table_start_ba, table_end_ba, next_start_ba; ++ uint32_t main_table_end_ba; ++ bool success; ++ ++ /* Set initial value */ ++ ni->main_table_ba = 0; ++ ni->backup_table_ba = 0; ++ ni->mapping_blocks_ba = ni->mapping_blocks_top_ba; ++ ++ /* Write main table */ ++ success = nmbm_write_info_table(ni, ni->mgmt_start_ba, ++ ni->mapping_blocks_top_ba, ++ &table_start_ba, &table_end_ba); ++ if (!success) { ++ /* Failed to write main table, data will be lost */ ++ nlog_err(ni, "Unable to write at least one info table!\n"); ++ nlog_err(ni, "Please save your data before power off!\n"); ++ ni->protected = 1; ++ return false; ++ } ++ ++ /* Main info table is successfully written, record its offset */ ++ ni->main_table_ba = table_start_ba; ++ main_table_end_ba = table_end_ba; ++ ++ /* Adjust mapping_blocks_ba */ ++ ni->mapping_blocks_ba = table_end_ba; ++ ++ nmbm_mark_tables_clean(ni); ++ ++ nlog_table_creation(ni, true, table_start_ba, table_end_ba); ++ ++ /* Reserve spare blocks for main info table. */ ++ success = nmbm_try_reserve_blocks(ni, table_end_ba, ++ &next_start_ba, ++ ni->info_table_spare_blocks, 0, ++ ni->mapping_blocks_top_ba - ++ size2blk(ni, ni->info_table_size)); ++ if (!success) { ++ /* There is no spare block. */ ++ nlog_debug(ni, "No room for backup info table\n"); ++ return true; ++ } ++ ++ /* Write backup info table. */ ++ success = nmbm_write_info_table(ni, next_start_ba, ++ ni->mapping_blocks_top_ba, ++ &table_start_ba, &table_end_ba); ++ if (!success) { ++ /* There is no enough blocks for backup table. */ ++ nlog_debug(ni, "No room for backup info table\n"); ++ return true; ++ } ++ ++ /* Backup table is successfully written, record its offset */ ++ ni->backup_table_ba = table_start_ba; ++ ++ /* Adjust mapping_blocks_off */ ++ ni->mapping_blocks_ba = table_end_ba; ++ ++ /* Erase spare blocks of main table to clean possible interference data */ ++ nmbm_erase_range(ni, main_table_end_ba, ni->backup_table_ba); ++ ++ nlog_table_creation(ni, false, table_start_ba, table_end_ba); ++ ++ return true; ++} ++ ++/* ++ * nmbm_rescue_single_info_table - Rescue when there is only one info table ++ * @ni: NMBM instance structure ++ * ++ * This function is called when there is only one info table exists. ++ * This function may fail if we can't write new info table ++ */ ++static bool nmbm_rescue_single_info_table(struct nmbm_instance *ni) ++{ ++ uint32_t table_start_ba, table_end_ba, write_ba; ++ bool success; ++ ++ /* Try to write new info table in front of existing table */ ++ success = nmbm_write_info_table(ni, ni->mgmt_start_ba, ++ ni->main_table_ba, ++ &table_start_ba, ++ &table_end_ba); ++ if (success) { ++ /* ++ * New table becomes the main table, existing table becomes ++ * the backup table. ++ */ ++ ni->backup_table_ba = ni->main_table_ba; ++ ni->main_table_ba = table_start_ba; ++ ++ nmbm_mark_tables_clean(ni); ++ ++ /* Erase spare blocks of main table to clean possible interference data */ ++ nmbm_erase_range(ni, table_end_ba, ni->backup_table_ba); ++ ++ nlog_table_creation(ni, true, table_start_ba, table_end_ba); ++ ++ return true; ++ } ++ ++ /* Try to reserve spare blocks for existing table */ ++ success = nmbm_try_reserve_blocks(ni, ni->mapping_blocks_ba, &write_ba, ++ ni->info_table_spare_blocks, 0, ++ ni->mapping_blocks_top_ba - ++ size2blk(ni, ni->info_table_size)); ++ if (!success) { ++ nlog_warn(ni, "Failed to rescue single info table\n"); ++ return false; ++ } ++ ++ /* Try to write new info table next to the existing table */ ++ while (write_ba >= ni->mapping_blocks_ba) { ++ success = nmbm_write_info_table(ni, write_ba, ++ ni->mapping_blocks_top_ba, ++ &table_start_ba, ++ &table_end_ba); ++ if (success) ++ break; ++ ++ write_ba--; ++ } ++ ++ if (success) { ++ /* Erase spare blocks of main table to clean possible interference data */ ++ nmbm_erase_range(ni, ni->mapping_blocks_ba, table_start_ba); ++ ++ /* New table becomes the backup table */ ++ ni->backup_table_ba = table_start_ba; ++ ni->mapping_blocks_ba = table_end_ba; ++ ++ nmbm_mark_tables_clean(ni); ++ ++ nlog_table_creation(ni, false, table_start_ba, table_end_ba); ++ ++ return true; ++ } ++ ++ nlog_warn(ni, "Failed to rescue single info table\n"); ++ return false; ++} ++ ++/* ++ * nmbm_update_single_info_table - Update specific one info table ++ * @ni: NMBM instance structure ++ */ ++static bool nmbm_update_single_info_table(struct nmbm_instance *ni, ++ bool update_main_table) ++{ ++ uint32_t write_start_ba, write_limit, table_start_ba, table_end_ba; ++ bool success; ++ ++ /* Determine the write range */ ++ if (update_main_table) { ++ write_start_ba = ni->main_table_ba; ++ write_limit = ni->backup_table_ba; ++ } else { ++ write_start_ba = ni->backup_table_ba; ++ write_limit = ni->mapping_blocks_top_ba; ++ } ++ ++ success = nmbm_write_info_table(ni, write_start_ba, write_limit, ++ &table_start_ba, &table_end_ba); ++ if (success) { ++ if (update_main_table) { ++ ni->main_table_ba = table_start_ba; ++ } else { ++ ni->backup_table_ba = table_start_ba; ++ ni->mapping_blocks_ba = table_end_ba; ++ } ++ ++ nmbm_mark_tables_clean(ni); ++ ++ nlog_table_update(ni, update_main_table, table_start_ba, ++ table_end_ba); ++ ++ return true; ++ } ++ ++ if (update_main_table) { ++ /* ++ * If failed to update main table, make backup table the new ++ * main table, and call nmbm_rescue_single_info_table() ++ */ ++ nlog_warn(ni, "Unable to update %s info table\n", ++ update_main_table ? "Main" : "Backup"); ++ ++ ni->main_table_ba = ni->backup_table_ba; ++ ni->backup_table_ba = 0; ++ return nmbm_rescue_single_info_table(ni); ++ } ++ ++ /* Only one table left */ ++ ni->mapping_blocks_ba = ni->backup_table_ba; ++ ni->backup_table_ba = 0; ++ ++ return false; ++} ++ ++/* ++ * nmbm_rescue_main_info_table - Rescue when failed to write main info table ++ * @ni: NMBM instance structure ++ * ++ * This function is called when main info table failed to be written, and ++ * backup info table exists. ++ */ ++static bool nmbm_rescue_main_info_table(struct nmbm_instance *ni) ++{ ++ uint32_t tmp_table_start_ba, tmp_table_end_ba, main_table_start_ba; ++ uint32_t main_table_end_ba, write_ba; ++ uint32_t info_table_erasesize = size2blk(ni, ni->info_table_size); ++ bool success; ++ ++ /* Try to reserve spare blocks for existing backup info table */ ++ success = nmbm_try_reserve_blocks(ni, ni->mapping_blocks_ba, &write_ba, ++ ni->info_table_spare_blocks, 0, ++ ni->mapping_blocks_top_ba - ++ info_table_erasesize); ++ if (!success) { ++ /* There is no spare block. Backup info table becomes the main table. */ ++ nlog_err(ni, "No room for temporary info table\n"); ++ ni->main_table_ba = ni->backup_table_ba; ++ ni->backup_table_ba = 0; ++ return true; ++ } ++ ++ /* Try to write temporary info table into spare unmapped blocks */ ++ while (write_ba >= ni->mapping_blocks_ba) { ++ success = nmbm_write_info_table(ni, write_ba, ++ ni->mapping_blocks_top_ba, ++ &tmp_table_start_ba, ++ &tmp_table_end_ba); ++ if (success) ++ break; ++ ++ write_ba--; ++ } ++ ++ if (!success) { ++ /* Backup info table becomes the main table */ ++ nlog_err(ni, "Failed to update main info table\n"); ++ ni->main_table_ba = ni->backup_table_ba; ++ ni->backup_table_ba = 0; ++ return true; ++ } ++ ++ /* Adjust mapping_blocks_off */ ++ ni->mapping_blocks_ba = tmp_table_end_ba; ++ ++ /* ++ * Now write main info table at the beginning of management area. ++ * This operation will generally destroy the original backup info ++ * table. ++ */ ++ success = nmbm_write_info_table(ni, ni->mgmt_start_ba, ++ tmp_table_start_ba, ++ &main_table_start_ba, ++ &main_table_end_ba); ++ if (!success) { ++ /* Temporary info table becomes the main table */ ++ ni->main_table_ba = tmp_table_start_ba; ++ ni->backup_table_ba = 0; ++ ++ nmbm_mark_tables_clean(ni); ++ ++ nlog_err(ni, "Failed to update main info table\n"); ++ ++ return true; ++ } ++ ++ /* Main info table has been successfully written, record its offset */ ++ ni->main_table_ba = main_table_start_ba; ++ ++ nmbm_mark_tables_clean(ni); ++ ++ nlog_table_creation(ni, true, main_table_start_ba, main_table_end_ba); ++ ++ /* ++ * Temporary info table becomes the new backup info table if it's ++ * not overwritten. ++ */ ++ if (main_table_end_ba <= tmp_table_start_ba) { ++ ni->backup_table_ba = tmp_table_start_ba; ++ ++ nlog_table_creation(ni, false, tmp_table_start_ba, ++ tmp_table_end_ba); ++ ++ return true; ++ } ++ ++ /* Adjust mapping_blocks_off */ ++ ni->mapping_blocks_ba = main_table_end_ba; ++ ++ /* Try to reserve spare blocks for new main info table */ ++ success = nmbm_try_reserve_blocks(ni, main_table_end_ba, &write_ba, ++ ni->info_table_spare_blocks, 0, ++ ni->mapping_blocks_top_ba - ++ info_table_erasesize); ++ if (!success) { ++ /* There is no spare block. Only main table exists. */ ++ nlog_err(ni, "No room for backup info table\n"); ++ ni->backup_table_ba = 0; ++ return true; ++ } ++ ++ /* Write new backup info table. */ ++ while (write_ba >= main_table_end_ba) { ++ success = nmbm_write_info_table(ni, write_ba, ++ ni->mapping_blocks_top_ba, ++ &tmp_table_start_ba, ++ &tmp_table_end_ba); ++ if (success) ++ break; ++ ++ write_ba--; ++ } ++ ++ if (!success) { ++ nlog_err(ni, "No room for backup info table\n"); ++ ni->backup_table_ba = 0; ++ return true; ++ } ++ ++ /* Backup info table has been successfully written, record its offset */ ++ ni->backup_table_ba = tmp_table_start_ba; ++ ++ /* Adjust mapping_blocks_off */ ++ ni->mapping_blocks_ba = tmp_table_end_ba; ++ ++ /* Erase spare blocks of main table to clean possible interference data */ ++ nmbm_erase_range(ni, main_table_end_ba, ni->backup_table_ba); ++ ++ nlog_table_creation(ni, false, tmp_table_start_ba, tmp_table_end_ba); ++ ++ return true; ++} ++ ++/* ++ * nmbm_update_info_table_once - Update info table once ++ * @ni: NMBM instance structure ++ * @force: force update ++ * ++ * Update both main and backup info table. Return true if at least one info ++ * table has been successfully written. ++ * This function only try to update info table once regard less of the result. ++ */ ++static bool nmbm_update_info_table_once(struct nmbm_instance *ni, bool force) ++{ ++ uint32_t table_start_ba, table_end_ba; ++ uint32_t main_table_limit; ++ bool success; ++ ++ /* Do nothing if there is no change */ ++ if (!nmbm_generate_info_table_cache(ni) && !force) ++ return true; ++ ++ /* Check whether both two tables exist */ ++ if (!ni->backup_table_ba) { ++ main_table_limit = ni->mapping_blocks_top_ba; ++ goto write_main_table; ++ } ++ ++ /* ++ * Write backup info table in its current range. ++ * Note that limit is set to mapping_blocks_top_off to provide as many ++ * spare blocks as possible for the backup table. If at last ++ * unmapped blocks are used by backup table, mapping_blocks_off will ++ * be adjusted. ++ */ ++ success = nmbm_write_info_table(ni, ni->backup_table_ba, ++ ni->mapping_blocks_top_ba, ++ &table_start_ba, &table_end_ba); ++ if (!success) { ++ /* ++ * There is nothing to do if failed to write backup table. ++ * Write the main table now. ++ */ ++ nlog_err(ni, "No room for backup table\n"); ++ ni->mapping_blocks_ba = ni->backup_table_ba; ++ ni->backup_table_ba = 0; ++ main_table_limit = ni->mapping_blocks_top_ba; ++ goto write_main_table; ++ } ++ ++ /* Backup table is successfully written, record its offset */ ++ ni->backup_table_ba = table_start_ba; ++ ++ /* Adjust mapping_blocks_off */ ++ ni->mapping_blocks_ba = table_end_ba; ++ ++ nmbm_mark_tables_clean(ni); ++ ++ /* The normal limit of main table */ ++ main_table_limit = ni->backup_table_ba; ++ ++ nlog_table_update(ni, false, table_start_ba, table_end_ba); ++ ++write_main_table: ++ if (!ni->main_table_ba) ++ goto rebuild_tables; ++ ++ /* Write main info table in its current range */ ++ success = nmbm_write_info_table(ni, ni->main_table_ba, ++ main_table_limit, &table_start_ba, ++ &table_end_ba); ++ if (!success) { ++ /* If failed to write main table, go rescue procedure */ ++ if (!ni->backup_table_ba) ++ goto rebuild_tables; ++ ++ return nmbm_rescue_main_info_table(ni); ++ } ++ ++ /* Main info table is successfully written, record its offset */ ++ ni->main_table_ba = table_start_ba; ++ ++ /* Adjust mapping_blocks_off */ ++ if (!ni->backup_table_ba) ++ ni->mapping_blocks_ba = table_end_ba; ++ ++ nmbm_mark_tables_clean(ni); ++ ++ nlog_table_update(ni, true, table_start_ba, table_end_ba); ++ ++ return true; ++ ++rebuild_tables: ++ return nmbm_rebuild_info_table(ni); ++} ++ ++/* ++ * nmbm_update_info_table - Update info table ++ * @ni: NMBM instance structure ++ * ++ * Update both main and backup info table. Return true if at least one table ++ * has been successfully written. ++ * This function will try to update info table repeatedly until no new bad ++ * block found during updating. ++ */ ++static bool nmbm_update_info_table(struct nmbm_instance *ni) ++{ ++ bool success; ++ ++ if (ni->protected) ++ return true; ++ ++ while (ni->block_state_changed || ni->block_mapping_changed) { ++ success = nmbm_update_info_table_once(ni, false); ++ if (!success) { ++ nlog_err(ni, "Failed to update info table\n"); ++ return false; ++ } ++ } ++ ++ return true; ++} ++ ++/* ++ * nmbm_map_block - Map a bad block to a unused spare block ++ * @ni: NMBM instance structure ++ * @lb: logic block addr to map ++ */ ++static bool nmbm_map_block(struct nmbm_instance *ni, uint32_t lb) ++{ ++ uint32_t pb; ++ bool success; ++ ++ if (ni->mapping_blocks_ba == ni->mapping_blocks_top_ba) { ++ nlog_warn(ni, "No spare unmapped blocks.\n"); ++ return false; ++ } ++ ++ success = nmbm_block_walk(ni, false, ni->mapping_blocks_top_ba, &pb, 0, ++ ni->mapping_blocks_ba); ++ if (!success) { ++ nlog_warn(ni, "No spare unmapped blocks.\n"); ++ nmbm_update_info_table(ni); ++ ni->mapping_blocks_top_ba = ni->mapping_blocks_ba; ++ return false; ++ } ++ ++ ni->block_mapping[lb] = pb; ++ ni->mapping_blocks_top_ba--; ++ ni->block_mapping_changed++; ++ ++ nlog_info(ni, "Logic block %u mapped to physical block %u\n", lb, pb); ++ ++ return true; ++} ++ ++/* ++ * nmbm_create_info_table - Create info table(s) ++ * @ni: NMBM instance structure ++ * ++ * This function assumes that the chip has no existing info table(s) ++ */ ++static bool nmbm_create_info_table(struct nmbm_instance *ni) ++{ ++ uint32_t lb; ++ bool success; ++ ++ /* Set initial mapping_blocks_top_off */ ++ success = nmbm_block_walk(ni, false, ni->signature_ba, ++ &ni->mapping_blocks_top_ba, 1, ++ ni->mgmt_start_ba); ++ if (!success) { ++ nlog_err(ni, "No room for spare blocks\n"); ++ return false; ++ } ++ ++ /* Generate info table cache */ ++ nmbm_generate_info_table_cache(ni); ++ ++ /* Write info table */ ++ success = nmbm_rebuild_info_table(ni); ++ if (!success) { ++ nlog_err(ni, "Failed to build info tables\n"); ++ return false; ++ } ++ ++ /* Remap bad block(s) at end of data area */ ++ for (lb = ni->data_block_count; lb < ni->mgmt_start_ba; lb++) { ++ success = nmbm_map_block(ni, lb); ++ if (!success) ++ break; ++ ++ ni->data_block_count++; ++ } ++ ++ /* If state table and/or mapping table changed, update info table. */ ++ success = nmbm_update_info_table(ni); ++ if (!success) ++ return false; ++ ++ return true; ++} ++ ++/* ++ * nmbm_create_new - Create NMBM on a new chip ++ * @ni: NMBM instance structure ++ */ ++static bool nmbm_create_new(struct nmbm_instance *ni) ++{ ++ bool success; ++ ++ /* Determine the boundary of management blocks */ ++ ni->mgmt_start_ba = ni->block_count * (NMBM_MGMT_DIV - ni->max_ratio) / NMBM_MGMT_DIV; ++ ++ if (ni->max_reserved_blocks && ni->block_count - ni->mgmt_start_ba > ni->max_reserved_blocks) ++ ni->mgmt_start_ba = ni->block_count - ni->max_reserved_blocks; ++ ++ nlog_info(ni, "NMBM management region starts at block %u [0x%08llx]\n", ++ ni->mgmt_start_ba, ba2addr(ni, ni->mgmt_start_ba)); ++ ++ /* Fill block state table & mapping table */ ++ nmbm_scan_badblocks(ni); ++ nmbm_build_mapping_table(ni); ++ ++ /* Write signature */ ++ ni->signature.header.magic = NMBM_MAGIC_SIGNATURE; ++ ni->signature.header.version = NMBM_VER; ++ ni->signature.header.size = sizeof(ni->signature); ++ ni->signature.nand_size = bmtd.total_blks << bmtd.blk_shift; ++ ni->signature.block_size = bmtd.blk_size; ++ ni->signature.page_size = bmtd.pg_size; ++ ni->signature.spare_size = bmtd.mtd->oobsize; ++ ni->signature.mgmt_start_pb = ni->mgmt_start_ba; ++ ni->signature.max_try_count = NMBM_TRY_COUNT; ++ nmbm_update_checksum(&ni->signature.header); ++ ++ success = nmbm_write_signature(ni, ni->mgmt_start_ba, ++ &ni->signature, &ni->signature_ba); ++ if (!success) { ++ nlog_err(ni, "Failed to write signature to a proper offset\n"); ++ return false; ++ } ++ ++ nlog_info(ni, "Signature has been written to block %u [0x%08llx]\n", ++ ni->signature_ba, ba2addr(ni, ni->signature_ba)); ++ ++ /* Write info table(s) */ ++ success = nmbm_create_info_table(ni); ++ if (success) { ++ nlog_info(ni, "NMBM has been successfully created\n"); ++ return true; ++ } ++ ++ return false; ++} ++ ++/* ++ * nmbm_check_info_table_header - Check if a info table header is valid ++ * @ni: NMBM instance structure ++ * @data: pointer to the info table header ++ */ ++static bool nmbm_check_info_table_header(struct nmbm_instance *ni, void *data) ++{ ++ struct nmbm_info_table_header *ifthdr = data; ++ ++ if (ifthdr->header.magic != NMBM_MAGIC_INFO_TABLE) ++ return false; ++ ++ if (ifthdr->header.size != ni->info_table_size) ++ return false; ++ ++ if (ifthdr->mapping_table_off - ifthdr->state_table_off < ni->state_table_size) ++ return false; ++ ++ if (ni->info_table_size - ifthdr->mapping_table_off < ni->mapping_table_size) ++ return false; ++ ++ return true; ++} ++ ++/* ++ * nmbm_check_info_table - Check if a whole info table is valid ++ * @ni: NMBM instance structure ++ * @start_ba: start block address of this table ++ * @end_ba: end block address of this table ++ * @data: pointer to the info table header ++ * @mapping_blocks_top_ba: return the block address of top remapped block ++ */ ++static bool nmbm_check_info_table(struct nmbm_instance *ni, uint32_t start_ba, ++ uint32_t end_ba, void *data, ++ uint32_t *mapping_blocks_top_ba) ++{ ++ struct nmbm_info_table_header *ifthdr = data; ++ int32_t *block_mapping = (int32_t *)((uintptr_t)data + ifthdr->mapping_table_off); ++ u32 *block_state = (u32 *)((uintptr_t)data + ifthdr->state_table_off); ++ uint32_t minimum_mapping_pb = ni->signature_ba; ++ uint32_t ba; ++ ++ for (ba = 0; ba < ni->data_block_count; ba++) { ++ if ((block_mapping[ba] >= ni->data_block_count && block_mapping[ba] < end_ba) || ++ block_mapping[ba] == ni->signature_ba) ++ return false; ++ ++ if (block_mapping[ba] >= end_ba && block_mapping[ba] < minimum_mapping_pb) ++ minimum_mapping_pb = block_mapping[ba]; ++ } ++ ++ for (ba = start_ba; ba < end_ba; ba++) { ++ if (nmbm_get_block_state(ni, ba) != BLOCK_ST_GOOD) ++ continue; ++ ++ if (nmbm_get_block_state_raw(block_state, ba) != BLOCK_ST_GOOD) ++ return false; ++ } ++ ++ *mapping_blocks_top_ba = minimum_mapping_pb - 1; ++ ++ return true; ++} ++ ++/* ++ * nmbm_try_load_info_table - Try to load info table from a address ++ * @ni: NMBM instance structure ++ * @ba: start block address of the info table ++ * @eba: return the block address after end of the table ++ * @write_count: return the write count of this table ++ * @mapping_blocks_top_ba: return the block address of top remapped block ++ * @table_loaded: used to record whether ni->info_table has valid data ++ */ ++static bool nmbm_try_load_info_table(struct nmbm_instance *ni, uint32_t ba, ++ uint32_t *eba, uint32_t *write_count, ++ uint32_t *mapping_blocks_top_ba, ++ bool table_loaded) ++{ ++ struct nmbm_info_table_header *ifthdr = (void *)ni->info_table_cache; ++ uint8_t *off = ni->info_table_cache; ++ uint32_t limit = ba + size2blk(ni, ni->info_table_size); ++ uint32_t start_ba = 0, chunksize, sizeremain = ni->info_table_size; ++ bool success, checkhdr = true; ++ int ret; ++ ++ while (sizeremain && ba < limit) { ++ if (nmbm_get_block_state(ni, ba) != BLOCK_ST_GOOD) ++ goto next_block; ++ ++ if (nmbm_check_bad_phys_block(ni, ba)) { ++ nmbm_set_block_state(ni, ba, BLOCK_ST_BAD); ++ goto next_block; ++ } ++ ++ chunksize = sizeremain; ++ if (chunksize > bmtd.blk_size) ++ chunksize = bmtd.blk_size; ++ ++ /* Assume block with ECC error has no info table data */ ++ ret = nmbn_read_data(ni, ba2addr(ni, ba), off, chunksize); ++ if (ret < 0) ++ goto skip_bad_block; ++ else if (ret > 0) ++ return false; ++ ++ if (checkhdr) { ++ success = nmbm_check_info_table_header(ni, off); ++ if (!success) ++ return false; ++ ++ start_ba = ba; ++ checkhdr = false; ++ } ++ ++ off += chunksize; ++ sizeremain -= chunksize; ++ ++ goto next_block; ++ ++ skip_bad_block: ++ /* Only mark bad in memory */ ++ nmbm_set_block_state(ni, ba, BLOCK_ST_BAD); ++ ++ next_block: ++ ba++; ++ } ++ ++ if (sizeremain) ++ return false; ++ ++ success = nmbm_check_header(ni->info_table_cache, ni->info_table_size); ++ if (!success) ++ return false; ++ ++ *eba = ba; ++ *write_count = ifthdr->write_count; ++ ++ success = nmbm_check_info_table(ni, start_ba, ba, ni->info_table_cache, ++ mapping_blocks_top_ba); ++ if (!success) ++ return false; ++ ++ if (!table_loaded || ifthdr->write_count > ni->info_table.write_count) { ++ memcpy(&ni->info_table, ifthdr, sizeof(ni->info_table)); ++ memcpy(ni->block_state, ++ (uint8_t *)ifthdr + ifthdr->state_table_off, ++ ni->state_table_size); ++ memcpy(ni->block_mapping, ++ (uint8_t *)ifthdr + ifthdr->mapping_table_off, ++ ni->mapping_table_size); ++ ni->info_table.write_count = ifthdr->write_count; ++ } ++ ++ return true; ++} ++ ++/* ++ * nmbm_search_info_table - Search info table from specific address ++ * @ni: NMBM instance structure ++ * @ba: start block address to search ++ * @limit: highest block address allowed for searching ++ * @table_start_ba: return the start block address of this table ++ * @table_end_ba: return the block address after end of this table ++ * @write_count: return the write count of this table ++ * @mapping_blocks_top_ba: return the block address of top remapped block ++ * @table_loaded: used to record whether ni->info_table has valid data ++ */ ++static bool nmbm_search_info_table(struct nmbm_instance *ni, uint32_t ba, ++ uint32_t limit, uint32_t *table_start_ba, ++ uint32_t *table_end_ba, ++ uint32_t *write_count, ++ uint32_t *mapping_blocks_top_ba, ++ bool table_loaded) ++{ ++ bool success; ++ ++ while (ba < limit - size2blk(ni, ni->info_table_size)) { ++ success = nmbm_try_load_info_table(ni, ba, table_end_ba, ++ write_count, ++ mapping_blocks_top_ba, ++ table_loaded); ++ if (success) { ++ *table_start_ba = ba; ++ return true; ++ } ++ ++ ba++; ++ } ++ ++ return false; ++} ++ ++/* ++ * nmbm_load_info_table - Load info table(s) from a chip ++ * @ni: NMBM instance structure ++ * @ba: start block address to search info table ++ * @limit: highest block address allowed for searching ++ */ ++static bool nmbm_load_info_table(struct nmbm_instance *ni, uint32_t ba, ++ uint32_t limit) ++{ ++ uint32_t main_table_end_ba, backup_table_end_ba, table_end_ba; ++ uint32_t main_mapping_blocks_top_ba, backup_mapping_blocks_top_ba; ++ uint32_t main_table_write_count, backup_table_write_count; ++ uint32_t i; ++ bool success; ++ ++ /* Set initial value */ ++ ni->main_table_ba = 0; ++ ni->backup_table_ba = 0; ++ ni->info_table.write_count = 0; ++ ni->mapping_blocks_top_ba = ni->signature_ba - 1; ++ ni->data_block_count = ni->signature.mgmt_start_pb; ++ ++ /* Find first info table */ ++ success = nmbm_search_info_table(ni, ba, limit, &ni->main_table_ba, ++ &main_table_end_ba, &main_table_write_count, ++ &main_mapping_blocks_top_ba, false); ++ if (!success) { ++ nlog_warn(ni, "No valid info table found\n"); ++ return false; ++ } ++ ++ table_end_ba = main_table_end_ba; ++ ++ nlog_table_found(ni, true, main_table_write_count, ni->main_table_ba, ++ main_table_end_ba); ++ ++ /* Find second info table */ ++ success = nmbm_search_info_table(ni, main_table_end_ba, limit, ++ &ni->backup_table_ba, &backup_table_end_ba, ++ &backup_table_write_count, &backup_mapping_blocks_top_ba, true); ++ if (!success) { ++ nlog_warn(ni, "Second info table not found\n"); ++ } else { ++ table_end_ba = backup_table_end_ba; ++ ++ nlog_table_found(ni, false, backup_table_write_count, ++ ni->backup_table_ba, backup_table_end_ba); ++ } ++ ++ /* Pick mapping_blocks_top_ba */ ++ if (!ni->backup_table_ba) { ++ ni->mapping_blocks_top_ba= main_mapping_blocks_top_ba; ++ } else { ++ if (main_table_write_count >= backup_table_write_count) ++ ni->mapping_blocks_top_ba = main_mapping_blocks_top_ba; ++ else ++ ni->mapping_blocks_top_ba = backup_mapping_blocks_top_ba; ++ } ++ ++ /* Set final mapping_blocks_ba */ ++ ni->mapping_blocks_ba = table_end_ba; ++ ++ /* Set final data_block_count */ ++ for (i = ni->signature.mgmt_start_pb; i > 0; i--) { ++ if (ni->block_mapping[i - 1] >= 0) { ++ ni->data_block_count = i; ++ break; ++ } ++ } ++ ++ /* Regenerate the info table cache from the final selected info table */ ++ nmbm_generate_info_table_cache(ni); ++ ++ /* ++ * If only one table exists, try to write another table. ++ * If two tables have different write count, try to update info table ++ */ ++ if (!ni->backup_table_ba) { ++ success = nmbm_rescue_single_info_table(ni); ++ } else if (main_table_write_count != backup_table_write_count) { ++ /* Mark state & mapping tables changed */ ++ ni->block_state_changed = 1; ++ ni->block_mapping_changed = 1; ++ ++ success = nmbm_update_single_info_table(ni, ++ main_table_write_count < backup_table_write_count); ++ } else { ++ success = true; ++ } ++ ++ /* ++ * If there is no spare unmapped blocks, or still only one table ++ * exists, set the chip to read-only ++ */ ++ if (ni->mapping_blocks_ba == ni->mapping_blocks_top_ba) { ++ nlog_warn(ni, "No spare unmapped blocks. Device is now read-only\n"); ++ ni->protected = 1; ++ } else if (!success) { ++ nlog_warn(ni, "Only one info table found. Device is now read-only\n"); ++ ni->protected = 1; ++ } ++ ++ return true; ++} ++ ++/* ++ * nmbm_load_existing - Load NMBM from a new chip ++ * @ni: NMBM instance structure ++ */ ++static bool nmbm_load_existing(struct nmbm_instance *ni) ++{ ++ bool success; ++ ++ /* Calculate the boundary of management blocks */ ++ ni->mgmt_start_ba = ni->signature.mgmt_start_pb; ++ ++ nlog_debug(ni, "NMBM management region starts at block %u [0x%08llx]\n", ++ ni->mgmt_start_ba, ba2addr(ni, ni->mgmt_start_ba)); ++ ++ /* Look for info table(s) */ ++ success = nmbm_load_info_table(ni, ni->mgmt_start_ba, ++ ni->signature_ba); ++ if (success) { ++ nlog_info(ni, "NMBM has been successfully attached\n"); ++ return true; ++ } ++ ++ if (!ni->force_create) { ++ printk("not creating NMBM table\n"); ++ return false; ++ } ++ ++ /* Fill block state table & mapping table */ ++ nmbm_scan_badblocks(ni); ++ nmbm_build_mapping_table(ni); ++ ++ /* Write info table(s) */ ++ success = nmbm_create_info_table(ni); ++ if (success) { ++ nlog_info(ni, "NMBM has been successfully created\n"); ++ return true; ++ } ++ ++ return false; ++} ++ ++/* ++ * nmbm_find_signature - Find signature in the lower NAND chip ++ * @ni: NMBM instance structure ++ * @signature_ba: used for storing block address of the signature ++ * @signature_ba: return the actual block address of signature block ++ * ++ * Find a valid signature from a specific range in the lower NAND chip, ++ * from bottom (highest address) to top (lowest address) ++ * ++ * Return true if found. ++ */ ++static bool nmbm_find_signature(struct nmbm_instance *ni, ++ struct nmbm_signature *signature, ++ uint32_t *signature_ba) ++{ ++ struct nmbm_signature sig; ++ uint64_t off, addr; ++ uint32_t block_count, ba, limit; ++ bool success; ++ int ret; ++ ++ /* Calculate top and bottom block address */ ++ block_count = bmtd.total_blks; ++ ba = block_count; ++ limit = (block_count / NMBM_MGMT_DIV) * (NMBM_MGMT_DIV - ni->max_ratio); ++ if (ni->max_reserved_blocks && block_count - limit > ni->max_reserved_blocks) ++ limit = block_count - ni->max_reserved_blocks; ++ ++ while (ba >= limit) { ++ ba--; ++ addr = ba2addr(ni, ba); ++ ++ if (nmbm_check_bad_phys_block(ni, ba)) ++ continue; ++ ++ /* Check every page. ++ * As long as at leaset one page contains valid signature, ++ * the block is treated as a valid signature block. ++ */ ++ for (off = 0; off < bmtd.blk_size; ++ off += bmtd.pg_size) { ++ ret = nmbn_read_data(ni, addr + off, &sig, ++ sizeof(sig)); ++ if (ret) ++ continue; ++ ++ /* Check for header size and checksum */ ++ success = nmbm_check_header(&sig, sizeof(sig)); ++ if (!success) ++ continue; ++ ++ /* Check for header magic */ ++ if (sig.header.magic == NMBM_MAGIC_SIGNATURE) { ++ /* Found it */ ++ memcpy(signature, &sig, sizeof(sig)); ++ *signature_ba = ba; ++ return true; ++ } ++ } ++ }; ++ ++ return false; ++} ++ ++/* ++ * nmbm_calc_structure_size - Calculate the instance structure size ++ * @nld: NMBM lower device structure ++ */ ++static size_t nmbm_calc_structure_size(void) ++{ ++ uint32_t state_table_size, mapping_table_size, info_table_size; ++ uint32_t block_count; ++ ++ block_count = bmtd.total_blks; ++ ++ /* Calculate info table size */ ++ state_table_size = ((block_count + NMBM_BITMAP_BLOCKS_PER_UNIT - 1) / ++ NMBM_BITMAP_BLOCKS_PER_UNIT) * NMBM_BITMAP_UNIT_SIZE; ++ mapping_table_size = block_count * sizeof(int32_t); ++ ++ info_table_size = ALIGN(sizeof(struct nmbm_info_table_header), ++ bmtd.pg_size); ++ info_table_size += ALIGN(state_table_size, bmtd.pg_size); ++ info_table_size += ALIGN(mapping_table_size, bmtd.pg_size); ++ ++ return info_table_size + state_table_size + mapping_table_size + ++ sizeof(struct nmbm_instance); ++} ++ ++/* ++ * nmbm_init_structure - Initialize members of instance structure ++ * @ni: NMBM instance structure ++ */ ++static void nmbm_init_structure(struct nmbm_instance *ni) ++{ ++ uint32_t pages_per_block, blocks_per_chip; ++ uintptr_t ptr; ++ ++ pages_per_block = bmtd.blk_size / bmtd.pg_size; ++ blocks_per_chip = bmtd.total_blks; ++ ++ ni->rawpage_size = bmtd.pg_size + bmtd.mtd->oobsize; ++ ni->rawblock_size = pages_per_block * ni->rawpage_size; ++ ni->rawchip_size = blocks_per_chip * ni->rawblock_size; ++ ++ /* Calculate number of block this chip */ ++ ni->block_count = blocks_per_chip; ++ ++ /* Calculate info table size */ ++ ni->state_table_size = ((ni->block_count + NMBM_BITMAP_BLOCKS_PER_UNIT - 1) / ++ NMBM_BITMAP_BLOCKS_PER_UNIT) * NMBM_BITMAP_UNIT_SIZE; ++ ni->mapping_table_size = ni->block_count * sizeof(*ni->block_mapping); ++ ++ ni->info_table_size = ALIGN(sizeof(ni->info_table), ++ bmtd.pg_size); ++ ni->info_table.state_table_off = ni->info_table_size; ++ ++ ni->info_table_size += ALIGN(ni->state_table_size, ++ bmtd.pg_size); ++ ni->info_table.mapping_table_off = ni->info_table_size; ++ ++ ni->info_table_size += ALIGN(ni->mapping_table_size, ++ bmtd.pg_size); ++ ++ ni->info_table_spare_blocks = nmbm_get_spare_block_count( ++ size2blk(ni, ni->info_table_size)); ++ ++ /* Assign memory to members */ ++ ptr = (uintptr_t)ni + sizeof(*ni); ++ ++ ni->info_table_cache = (void *)ptr; ++ ptr += ni->info_table_size; ++ ++ ni->block_state = (void *)ptr; ++ ptr += ni->state_table_size; ++ ++ ni->block_mapping = (void *)ptr; ++ ptr += ni->mapping_table_size; ++ ++ ni->page_cache = bmtd.data_buf; ++ ++ /* Initialize block state table */ ++ ni->block_state_changed = 0; ++ memset(ni->block_state, 0xff, ni->state_table_size); ++ ++ /* Initialize block mapping table */ ++ ni->block_mapping_changed = 0; ++} ++ ++/* ++ * nmbm_attach - Attach to a lower device ++ * @ni: NMBM instance structure ++ */ ++static int nmbm_attach(struct nmbm_instance *ni) ++{ ++ bool success; ++ ++ if (!ni) ++ return -EINVAL; ++ ++ /* Initialize NMBM instance */ ++ nmbm_init_structure(ni); ++ ++ success = nmbm_find_signature(ni, &ni->signature, &ni->signature_ba); ++ if (!success) { ++ if (!ni->force_create) { ++ nlog_err(ni, "Signature not found\n"); ++ return -ENODEV; ++ } ++ ++ success = nmbm_create_new(ni); ++ if (!success) ++ return -ENODEV; ++ ++ return 0; ++ } ++ ++ nlog_info(ni, "Signature found at block %u [0x%08llx]\n", ++ ni->signature_ba, ba2addr(ni, ni->signature_ba)); ++ ++ if (ni->signature.header.version != NMBM_VER) { ++ nlog_err(ni, "NMBM version %u.%u is not supported\n", ++ NMBM_VERSION_MAJOR_GET(ni->signature.header.version), ++ NMBM_VERSION_MINOR_GET(ni->signature.header.version)); ++ return -EINVAL; ++ } ++ ++ if (ni->signature.nand_size != bmtd.total_blks << bmtd.blk_shift || ++ ni->signature.block_size != bmtd.blk_size || ++ ni->signature.page_size != bmtd.pg_size || ++ ni->signature.spare_size != bmtd.mtd->oobsize) { ++ nlog_err(ni, "NMBM configuration mismatch\n"); ++ return -EINVAL; ++ } ++ ++ success = nmbm_load_existing(ni); ++ if (!success) ++ return -ENODEV; ++ ++ return 0; ++} ++ ++static bool remap_block_nmbm(u16 block, u16 mapped_block, int copy_len) ++{ ++ struct nmbm_instance *ni = bmtd.ni; ++ int new_block; ++ ++ if (block >= ni->data_block_count) ++ return false; ++ ++ nmbm_set_block_state(ni, mapped_block, BLOCK_ST_BAD); ++ if (!nmbm_map_block(ni, block)) ++ return false; ++ ++ new_block = ni->block_mapping[block]; ++ bbt_nand_erase(new_block); ++ if (copy_len > 0) ++ bbt_nand_copy(new_block, mapped_block, copy_len); ++ nmbm_update_info_table(ni); ++ ++ return true; ++} ++ ++static int get_mapping_block_index_nmbm(int block) ++{ ++ struct nmbm_instance *ni = bmtd.ni; ++ ++ if (block >= ni->data_block_count) ++ return -1; ++ ++ return ni->block_mapping[block]; ++} ++ ++static int mtk_bmt_init_nmbm(struct device_node *np) ++{ ++ struct nmbm_instance *ni; ++ int ret; ++ ++ ni = kzalloc(nmbm_calc_structure_size(), GFP_KERNEL); ++ if (!ni) ++ return -ENOMEM; ++ ++ bmtd.ni = ni; ++ ++ if (of_property_read_u32(np, "mediatek,bmt-max-ratio", &ni->max_ratio)) ++ ni->max_ratio = 1; ++ if (of_property_read_u32(np, "mediatek,bmt-max-reserved-blocks", ++ &ni->max_reserved_blocks)) ++ ni->max_reserved_blocks = 256; ++ if (of_property_read_bool(np, "mediatek,empty-page-ecc-protected")) ++ ni->empty_page_ecc_ok = true; ++ if (of_property_read_bool(np, "mediatek,bmt-force-create")) ++ ni->force_create = true; ++ ++ ret = nmbm_attach(ni); ++ if (ret) ++ goto out; ++ ++ bmtd.mtd->size = ni->data_block_count << bmtd.blk_shift; ++ ++ return 0; ++ ++out: ++ kfree(ni); ++ bmtd.ni = NULL; ++ ++ return ret; ++} ++ ++static int mtk_bmt_debug_nmbm(void *data, u64 val) ++{ ++ struct nmbm_instance *ni = bmtd.ni; ++ int i; ++ ++ switch (val) { ++ case 0: ++ for (i = 1; i < ni->data_block_count; i++) { ++ if (ni->block_mapping[i] < ni->mapping_blocks_ba) ++ continue; ++ ++ printk("remap [%x->%x]\n", i, ni->block_mapping[i]); ++ } ++ } ++ ++ return 0; ++} ++ ++static void unmap_block_nmbm(u16 block) ++{ ++ struct nmbm_instance *ni = bmtd.ni; ++ int start, offset; ++ int new_block; ++ ++ if (block >= ni->data_block_count) ++ return; ++ ++ start = block; ++ offset = 0; ++ while (ni->block_mapping[start] >= ni->mapping_blocks_ba) { ++ start--; ++ offset++; ++ if (start < 0) ++ return; ++ } ++ ++ if (!offset) ++ return; ++ ++ new_block = ni->block_mapping[start] + offset; ++ nmbm_set_block_state(ni, new_block, BLOCK_ST_GOOD); ++ ni->block_mapping[block] = new_block; ++ ni->block_mapping_changed++; ++ ++ new_block = ni->signature_ba - 1; ++ for (block = 0; block < ni->data_block_count; block++) { ++ int cur = ni->block_mapping[block]; ++ ++ if (cur < ni->mapping_blocks_ba) ++ continue; ++ ++ if (cur <= new_block) ++ new_block = cur - 1; ++ } ++ ++ ni->mapping_blocks_top_ba = new_block; ++ ++ nmbm_update_info_table(ni); ++} ++ ++const struct mtk_bmt_ops mtk_bmt_nmbm_ops = { ++ .init = mtk_bmt_init_nmbm, ++ .remap_block = remap_block_nmbm, ++ .unmap_block = unmap_block_nmbm, ++ .get_mapping_block = get_mapping_block_index_nmbm, ++ .debug = mtk_bmt_debug_nmbm, ++}; +diff --git a/drivers/mtd/nand/mtk_bmt_v2.c b/drivers/mtd/nand/mtk_bmt_v2.c +new file mode 100644 +index 000000000000..a17b7290260b +--- /dev/null ++++ b/drivers/mtd/nand/mtk_bmt_v2.c +@@ -0,0 +1,506 @@ ++/* ++ * Copyright (c) 2017 MediaTek Inc. ++ * Author: Xiangsheng Hou ++ * Copyright (c) 2020-2022 Felix Fietkau ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#include ++#include ++#include "mtk_bmt.h" ++ ++struct bbbt { ++ char signature[3]; ++ /* This version is used to distinguish the legacy and new algorithm */ ++#define BBMT_VERSION 2 ++ unsigned char version; ++ /* Below 2 tables will be written in SLC */ ++ u16 bb_tbl[]; ++}; ++ ++struct bbmt { ++ u16 block; ++#define NO_MAPPED 0 ++#define NORMAL_MAPPED 1 ++#define BMT_MAPPED 2 ++ u16 mapped; ++}; ++ ++/* Maximum 8k blocks */ ++#define BBPOOL_RATIO 2 ++#define BB_TABLE_MAX bmtd.table_size ++#define BMT_TABLE_MAX (BB_TABLE_MAX * BBPOOL_RATIO / 100) ++#define BMT_TBL_DEF_VAL 0x0 ++ ++static inline struct bbmt *bmt_tbl(struct bbbt *bbbt) ++{ ++ return (struct bbmt *)&bbbt->bb_tbl[bmtd.table_size]; ++} ++ ++static u16 find_valid_block(u16 block) ++{ ++ u8 fdm[4]; ++ int ret; ++ int loop = 0; ++ ++retry: ++ if (block >= bmtd.total_blks) ++ return 0; ++ ++ ret = bbt_nand_read(blk_pg(block), bmtd.data_buf, bmtd.pg_size, ++ fdm, sizeof(fdm)); ++ /* Read the 1st byte of FDM to judge whether it's a bad ++ * or not ++ */ ++ if (ret || fdm[0] != 0xff) { ++ pr_info("nand: found bad block 0x%x\n", block); ++ if (loop >= bmtd.bb_max) { ++ pr_info("nand: FATAL ERR: too many bad blocks!!\n"); ++ return 0; ++ } ++ ++ loop++; ++ block++; ++ goto retry; ++ } ++ ++ return block; ++} ++ ++/* Find out all bad blocks, and fill in the mapping table */ ++static int scan_bad_blocks(struct bbbt *bbt) ++{ ++ int i; ++ u16 block = 0; ++ ++ /* First time download, the block0 MUST NOT be a bad block, ++ * this is guaranteed by vendor ++ */ ++ bbt->bb_tbl[0] = 0; ++ ++ /* ++ * Construct the mapping table of Normal data area(non-PMT/BMTPOOL) ++ * G - Good block; B - Bad block ++ * --------------------------- ++ * physical |G|G|B|G|B|B|G|G|G|G|B|G|B| ++ * --------------------------- ++ * What bb_tbl[i] looks like: ++ * physical block(i): ++ * 0 1 2 3 4 5 6 7 8 9 a b c ++ * mapped block(bb_tbl[i]): ++ * 0 1 3 6 7 8 9 b ...... ++ * ATTENTION: ++ * If new bad block ocurred(n), search bmt_tbl to find ++ * a available block(x), and fill in the bb_tbl[n] = x; ++ */ ++ for (i = 1; i < bmtd.pool_lba; i++) { ++ bbt->bb_tbl[i] = find_valid_block(bbt->bb_tbl[i - 1] + 1); ++ BBT_LOG("bb_tbl[0x%x] = 0x%x", i, bbt->bb_tbl[i]); ++ if (bbt->bb_tbl[i] == 0) ++ return -1; ++ } ++ ++ /* Physical Block start Address of BMT pool */ ++ bmtd.pool_pba = bbt->bb_tbl[i - 1] + 1; ++ if (bmtd.pool_pba >= bmtd.total_blks - 2) { ++ pr_info("nand: FATAL ERR: Too many bad blocks!!\n"); ++ return -1; ++ } ++ ++ BBT_LOG("pool_pba=0x%x", bmtd.pool_pba); ++ i = 0; ++ block = bmtd.pool_pba; ++ /* ++ * The bmt table is used for runtime bad block mapping ++ * G - Good block; B - Bad block ++ * --------------------------- ++ * physical |G|G|B|G|B|B|G|G|G|G|B|G|B| ++ * --------------------------- ++ * block: 0 1 2 3 4 5 6 7 8 9 a b c ++ * What bmt_tbl[i] looks like in initial state: ++ * i: ++ * 0 1 2 3 4 5 6 7 ++ * bmt_tbl[i].block: ++ * 0 1 3 6 7 8 9 b ++ * bmt_tbl[i].mapped: ++ * N N N N N N N B ++ * N - Not mapped(Available) ++ * M - Mapped ++ * B - BMT ++ * ATTENTION: ++ * BMT always in the last valid block in pool ++ */ ++ while ((block = find_valid_block(block)) != 0) { ++ bmt_tbl(bbt)[i].block = block; ++ bmt_tbl(bbt)[i].mapped = NO_MAPPED; ++ BBT_LOG("bmt_tbl[%d].block = 0x%x", i, block); ++ block++; ++ i++; ++ } ++ ++ /* i - How many available blocks in pool, which is the length of bmt_tbl[] ++ * bmtd.bmt_blk_idx - bmt_tbl[bmtd.bmt_blk_idx].block => the BMT block ++ */ ++ bmtd.bmt_blk_idx = i - 1; ++ bmt_tbl(bbt)[bmtd.bmt_blk_idx].mapped = BMT_MAPPED; ++ ++ if (i < 1) { ++ pr_info("nand: FATAL ERR: no space to store BMT!!\n"); ++ return -1; ++ } ++ ++ pr_info("[BBT] %d available blocks in BMT pool\n", i); ++ ++ return 0; ++} ++ ++static bool is_valid_bmt(unsigned char *buf, unsigned char *fdm) ++{ ++ struct bbbt *bbt = (struct bbbt *)buf; ++ u8 *sig = (u8*)bbt->signature + MAIN_SIGNATURE_OFFSET; ++ ++ ++ if (memcmp(bbt->signature + MAIN_SIGNATURE_OFFSET, "BMT", 3) == 0 && ++ memcmp(fdm + OOB_SIGNATURE_OFFSET, "bmt", 3) == 0) { ++ if (bbt->version == BBMT_VERSION) ++ return true; ++ } ++ BBT_LOG("[BBT] BMT Version not match,upgrage preloader and uboot please! sig=%02x%02x%02x, fdm=%02x%02x%02x", ++ sig[0], sig[1], sig[2], ++ fdm[1], fdm[2], fdm[3]); ++ return false; ++} ++ ++static u16 get_bmt_index(struct bbmt *bmt) ++{ ++ int i = 0; ++ ++ while (bmt[i].block != BMT_TBL_DEF_VAL) { ++ if (bmt[i].mapped == BMT_MAPPED) ++ return i; ++ i++; ++ } ++ return 0; ++} ++ ++/* Write the Burner Bad Block Table to Nand Flash ++ * n - write BMT to bmt_tbl[n] ++ */ ++static u16 upload_bmt(struct bbbt *bbt, int n) ++{ ++ u16 block; ++ ++retry: ++ if (n < 0 || bmt_tbl(bbt)[n].mapped == NORMAL_MAPPED) { ++ pr_info("nand: FATAL ERR: no space to store BMT!\n"); ++ return (u16)-1; ++ } ++ ++ block = bmt_tbl(bbt)[n].block; ++ BBT_LOG("n = 0x%x, block = 0x%x", n, block); ++ if (bbt_nand_erase(block)) { ++ bmt_tbl(bbt)[n].block = 0; ++ /* erase failed, try the previous block: bmt_tbl[n - 1].block */ ++ n--; ++ goto retry; ++ } ++ ++ /* The signature offset is fixed set to 0, ++ * oob signature offset is fixed set to 1 ++ */ ++ memcpy(bbt->signature + MAIN_SIGNATURE_OFFSET, "BMT", 3); ++ bbt->version = BBMT_VERSION; ++ ++ if (write_bmt(block, (unsigned char *)bbt)) { ++ bmt_tbl(bbt)[n].block = 0; ++ ++ /* write failed, try the previous block in bmt_tbl[n - 1] */ ++ n--; ++ goto retry; ++ } ++ ++ /* Return the current index(n) of BMT pool (bmt_tbl[n]) */ ++ return n; ++} ++ ++static u16 find_valid_block_in_pool(struct bbbt *bbt) ++{ ++ int i; ++ ++ if (bmtd.bmt_blk_idx == 0) ++ goto error; ++ ++ for (i = 0; i < bmtd.bmt_blk_idx; i++) { ++ if (bmt_tbl(bbt)[i].block != 0 && bmt_tbl(bbt)[i].mapped == NO_MAPPED) { ++ bmt_tbl(bbt)[i].mapped = NORMAL_MAPPED; ++ return bmt_tbl(bbt)[i].block; ++ } ++ } ++ ++error: ++ pr_info("nand: FATAL ERR: BMT pool is run out!\n"); ++ return 0; ++} ++ ++/* We met a bad block, mark it as bad and map it to a valid block in pool, ++ * if it's a write failure, we need to write the data to mapped block ++ */ ++static bool remap_block_v2(u16 block, u16 mapped_block, int copy_len) ++{ ++ u16 new_block; ++ struct bbbt *bbt; ++ ++ bbt = bmtd.bbt; ++ new_block = find_valid_block_in_pool(bbt); ++ if (new_block == 0) ++ return false; ++ ++ /* Map new bad block to available block in pool */ ++ bbt->bb_tbl[block] = new_block; ++ ++ /* Erase new block */ ++ bbt_nand_erase(new_block); ++ if (copy_len > 0) ++ bbt_nand_copy(new_block, mapped_block, copy_len); ++ ++ bmtd.bmt_blk_idx = upload_bmt(bbt, bmtd.bmt_blk_idx); ++ ++ return true; ++} ++ ++static int get_mapping_block_index_v2(int block) ++{ ++ int start, end; ++ ++ if (block >= bmtd.pool_lba) ++ return block; ++ ++ if (!mapping_block_in_range(block, &start, &end)) ++ return block; ++ ++ return bmtd.bbt->bb_tbl[block]; ++} ++ ++static void ++unmap_block_v2(u16 block) ++{ ++ bmtd.bbt->bb_tbl[block] = block; ++ bmtd.bmt_blk_idx = upload_bmt(bmtd.bbt, bmtd.bmt_blk_idx); ++} ++ ++static unsigned long * ++mtk_bmt_get_mapping_mask(void) ++{ ++ struct bbmt *bbmt = bmt_tbl(bmtd.bbt); ++ int main_blocks = bmtd.mtd->size >> bmtd.blk_shift; ++ unsigned long *used; ++ int i, k; ++ ++ used = kcalloc(BIT_WORD(bmtd.bmt_blk_idx) + 1, sizeof(unsigned long), GFP_KERNEL); ++ if (!used) ++ return NULL; ++ ++ for (i = 1; i < main_blocks; i++) { ++ if (bmtd.bbt->bb_tbl[i] == i) ++ continue; ++ ++ for (k = 0; k < bmtd.bmt_blk_idx; k++) { ++ if (bmtd.bbt->bb_tbl[i] != bbmt[k].block) ++ continue; ++ ++ set_bit(k, used); ++ break; ++ } ++ } ++ ++ return used; ++} ++ ++static int mtk_bmt_debug_v2(void *data, u64 val) ++{ ++ struct bbmt *bbmt = bmt_tbl(bmtd.bbt); ++ struct mtd_info *mtd = bmtd.mtd; ++ unsigned long *used; ++ int main_blocks = mtd->size >> bmtd.blk_shift; ++ int n_remap = 0; ++ int i; ++ ++ used = mtk_bmt_get_mapping_mask(); ++ if (!used) ++ return -ENOMEM; ++ ++ switch (val) { ++ case 0: ++ for (i = 1; i < main_blocks; i++) { ++ if (bmtd.bbt->bb_tbl[i] == i) ++ continue; ++ ++ printk("remap [%x->%x]\n", i, bmtd.bbt->bb_tbl[i]); ++ n_remap++; ++ } ++ for (i = 0; i <= bmtd.bmt_blk_idx; i++) { ++ char c; ++ ++ switch (bbmt[i].mapped) { ++ case NO_MAPPED: ++ continue; ++ case NORMAL_MAPPED: ++ c = 'm'; ++ if (test_bit(i, used)) ++ c = 'M'; ++ break; ++ case BMT_MAPPED: ++ c = 'B'; ++ break; ++ default: ++ c = 'X'; ++ break; ++ } ++ printk("[%x:%c] = 0x%x\n", i, c, bbmt[i].block); ++ } ++ break; ++ case 100: ++ for (i = 0; i <= bmtd.bmt_blk_idx; i++) { ++ if (bbmt[i].mapped != NORMAL_MAPPED) ++ continue; ++ ++ if (test_bit(i, used)) ++ continue; ++ ++ n_remap++; ++ bbmt[i].mapped = NO_MAPPED; ++ printk("free block [%d:%x]\n", i, bbmt[i].block); ++ } ++ if (n_remap) ++ bmtd.bmt_blk_idx = upload_bmt(bmtd.bbt, bmtd.bmt_blk_idx); ++ break; ++ } ++ ++ kfree(used); ++ ++ return 0; ++} ++ ++static int mtk_bmt_init_v2(struct device_node *np) ++{ ++ u32 bmt_pool_size, bmt_table_size; ++ u32 bufsz, block; ++ u16 pmt_block; ++ ++ if (of_property_read_u32(np, "mediatek,bmt-pool-size", ++ &bmt_pool_size) != 0) ++ bmt_pool_size = 80; ++ ++ if (of_property_read_u8(np, "mediatek,bmt-oob-offset", ++ &bmtd.oob_offset) != 0) ++ bmtd.oob_offset = 0; ++ ++ if (of_property_read_u32(np, "mediatek,bmt-table-size", ++ &bmt_table_size) != 0) ++ bmt_table_size = 0x2000U; ++ ++ bmtd.table_size = bmt_table_size; ++ ++ pmt_block = bmtd.total_blks - bmt_pool_size - 2; ++ ++ bmtd.mtd->size = pmt_block << bmtd.blk_shift; ++ ++ /* ++ * --------------------------------------- ++ * | PMT(2blks) | BMT POOL(totalblks * 2%) | ++ * --------------------------------------- ++ * ^ ^ ++ * | | ++ * pmt_block pmt_block + 2blocks(pool_lba) ++ * ++ * ATTETION!!!!!! ++ * The blocks ahead of the boundary block are stored in bb_tbl ++ * and blocks behind are stored in bmt_tbl ++ */ ++ ++ bmtd.pool_lba = (u16)(pmt_block + 2); ++ bmtd.bb_max = bmtd.total_blks * BBPOOL_RATIO / 100; ++ ++ bufsz = round_up(sizeof(struct bbbt) + ++ bmt_table_size * sizeof(struct bbmt), bmtd.pg_size); ++ bmtd.bmt_pgs = bufsz >> bmtd.pg_shift; ++ ++ bmtd.bbt_buf = kzalloc(bufsz, GFP_KERNEL); ++ if (!bmtd.bbt_buf) ++ return -ENOMEM; ++ ++ memset(bmtd.bbt_buf, 0xff, bufsz); ++ ++ /* Scanning start from the first page of the last block ++ * of whole flash ++ */ ++ bmtd.bbt = NULL; ++ for (u16 block = bmtd.total_blks - 1; !bmtd.bbt && block >= bmtd.pool_lba; block--) { ++ u8 fdm[4]; ++ ++ if (bbt_nand_read(blk_pg(block), bmtd.bbt_buf, bufsz, fdm, sizeof(fdm))) { ++ /* Read failed, try the previous block */ ++ continue; ++ } ++ ++ if (!is_valid_bmt(bmtd.bbt_buf, fdm)) { ++ /* No valid BMT found, try the previous block */ ++ continue; ++ } ++ ++ bmtd.bmt_blk_idx = get_bmt_index(bmt_tbl((struct bbbt *)bmtd.bbt_buf)); ++ if (bmtd.bmt_blk_idx == 0) { ++ pr_info("[BBT] FATAL ERR: bmt block index is wrong!\n"); ++ break; ++ } ++ ++ pr_info("[BBT] BMT.v2 is found at 0x%x\n", block); ++ bmtd.bbt = (struct bbbt *)bmtd.bbt_buf; ++ } ++ ++ if (!bmtd.bbt) { ++ /* BMT not found */ ++ if (bmtd.total_blks > BB_TABLE_MAX + BMT_TABLE_MAX) { ++ pr_info("nand: FATAL: Too many blocks, can not support!\n"); ++ return -1; ++ } ++ ++ bmtd.bbt = (struct bbbt *)bmtd.bbt_buf; ++ memset(bmt_tbl(bmtd.bbt), BMT_TBL_DEF_VAL, ++ bmtd.table_size * sizeof(struct bbmt)); ++ ++ if (scan_bad_blocks(bmtd.bbt)) ++ return -1; ++ ++ /* BMT always in the last valid block in pool */ ++ bmtd.bmt_blk_idx = upload_bmt(bmtd.bbt, bmtd.bmt_blk_idx); ++ block = bmt_tbl(bmtd.bbt)[bmtd.bmt_blk_idx].block; ++ pr_notice("[BBT] BMT.v2 is written into PBA:0x%x\n", block); ++ ++ if (bmtd.bmt_blk_idx == 0) ++ pr_info("nand: Warning: no available block in BMT pool!\n"); ++ else if (bmtd.bmt_blk_idx == (u16)-1) ++ return -1; ++ } ++ ++ return 0; ++} ++ ++ ++const struct mtk_bmt_ops mtk_bmt_v2_ops = { ++ .sig = "bmt", ++ .sig_len = 3, ++ .init = mtk_bmt_init_v2, ++ .remap_block = remap_block_v2, ++ .unmap_block = unmap_block_v2, ++ .get_mapping_block = get_mapping_block_index_v2, ++ .debug = mtk_bmt_debug_v2, ++}; +diff --git a/drivers/mtd/parsers/routerbootpart.c b/drivers/mtd/parsers/routerbootpart.c +new file mode 100644 +index 000000000000..aa786cd895e5 +--- /dev/null ++++ b/drivers/mtd/parsers/routerbootpart.c +@@ -0,0 +1,365 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Parser for MikroTik RouterBoot partitions. ++ * ++ * Copyright (C) 2020 Thibaut VARÈNE ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation. ++ * ++ * This parser builds from the "fixed-partitions" one (see ofpart.c), but it can ++ * handle dynamic partitions as found on routerboot devices. ++ * ++ * DTS nodes are defined as follows: ++ * For fixed partitions: ++ * node-name@unit-address { ++ * reg = ; ++ * label = ; ++ * read-only; ++ * lock; ++ * }; ++ * ++ * reg property is mandatory; other properties are optional. ++ * reg format is
. length can be 0 if the next partition is ++ * another fixed partition or a "well-known" partition as defined below: in that ++ * case the partition will extend up to the next one. ++ * ++ * For dynamic partitions: ++ * node-name { ++ * size = ; ++ * label = ; ++ * read-only; ++ * lock; ++ * }; ++ * ++ * size property is normally mandatory. It can only be omitted (or set to 0) if: ++ * - the partition is a "well-known" one (as defined below), in which case ++ * the partition size will be automatically adjusted; or ++ * - the next partition is a fixed one or a "well-known" one, in which case ++ * the current partition will extend up to the next one. ++ * Other properties are optional. ++ * size format is . ++ * By default dynamic partitions are appended after the preceding one, except ++ * for "well-known" ones which are automatically located on flash. ++ * ++ * Well-known partitions (matched via label or node-name): ++ * - "hard_config" ++ * - "soft_config" ++ * - "dtb_config" ++ * ++ * Note: this parser will happily register 0-sized partitions if misused. ++ * ++ * This parser requires the DTS to list partitions in ascending order as ++ * expected on the MTD device. ++ * ++ * Since only the "hard_config" and "soft_config" partitions are used in OpenWRT, ++ * a minimal working DTS could define only these two partitions dynamically (in ++ * the right order, usually hard_config then soft_config). ++ * ++ * Note: some mips RB devices encode the hard_config offset and length in two ++ * consecutive u32 located at offset 0x14 (for ramips) or 0x24 (for ath79) on ++ * the SPI NOR flash. Unfortunately this seems inconsistent across machines and ++ * does not apply to e.g. ipq-based ones, so we ignore that information. ++ * ++ * Note: To find well-known partitions, this parser will go through the entire ++ * top mtd partition parsed, _before_ the DTS nodes are processed. This works ++ * well in the current state of affairs, and is a simpler implementation than ++ * searching for known partitions in the "holes" left between fixed-partition, ++ * _after_ processing DTS nodes. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define RB_MAGIC_HARD (('H') | ('a' << 8) | ('r' << 16) | ('d' << 24)) ++#define RB_MAGIC_SOFT (('S') | ('o' << 8) | ('f' << 16) | ('t' << 24)) ++#define RB_BLOCK_SIZE 0x1000 ++ ++struct routerboot_dynpart { ++ const char * const name; ++ const u32 magic; ++ int (* const size_fixup)(struct mtd_info *, struct routerboot_dynpart *); ++ size_t offset; ++ size_t size; ++ bool found; ++}; ++ ++static int routerboot_dtbsfixup(struct mtd_info *, struct routerboot_dynpart *); ++ ++static struct routerboot_dynpart rb_dynparts[] = { ++ { ++ .name = "hard_config", ++ .magic = RB_MAGIC_HARD, // stored in CPU-endianness on flash ++ .size_fixup = NULL, ++ .offset = 0x0, ++ .size = RB_BLOCK_SIZE, ++ .found = false, ++ }, { ++ .name = "soft_config", ++ .magic = RB_MAGIC_SOFT, // stored in CPU-endianness on flash ++ .size_fixup = NULL, ++ .offset = 0x0, ++ .size = RB_BLOCK_SIZE, ++ .found = false, ++ }, { ++ .name = "dtb_config", ++ .magic = fdt32_to_cpu(OF_DT_HEADER), // stored BE on flash ++ .size_fixup = routerboot_dtbsfixup, ++ .offset = 0x0, ++ .size = 0x0, ++ .found = false, ++ } ++}; ++ ++static int routerboot_dtbsfixup(struct mtd_info *master, struct routerboot_dynpart *rbdpart) ++{ ++ int err; ++ size_t bytes_read, psize; ++ struct { ++ fdt32_t magic; ++ fdt32_t totalsize; ++ fdt32_t off_dt_struct; ++ fdt32_t off_dt_strings; ++ fdt32_t off_mem_rsvmap; ++ fdt32_t version; ++ fdt32_t last_comp_version; ++ fdt32_t boot_cpuid_phys; ++ fdt32_t size_dt_strings; ++ fdt32_t size_dt_struct; ++ } fdt_header; ++ ++ err = mtd_read(master, rbdpart->offset, sizeof(fdt_header), ++ &bytes_read, (u8 *)&fdt_header); ++ if (err) ++ return err; ++ ++ if (bytes_read != sizeof(fdt_header)) ++ return -EIO; ++ ++ psize = fdt32_to_cpu(fdt_header.totalsize); ++ if (!psize) ++ return -EINVAL; ++ ++ rbdpart->size = psize; ++ return 0; ++} ++ ++static void routerboot_find_dynparts(struct mtd_info *master) ++{ ++ size_t bytes_read, offset; ++ bool allfound; ++ int err, i; ++ u32 buf; ++ ++ /* ++ * Dynamic RouterBoot partitions offsets are aligned to RB_BLOCK_SIZE: ++ * read the whole partition at RB_BLOCK_SIZE intervals to find sigs. ++ * Skip partition content when possible. ++ */ ++ offset = 0; ++ while (offset < master->size) { ++ err = mtd_read(master, offset, sizeof(buf), &bytes_read, (u8 *)&buf); ++ if (err) { ++ pr_err("%s: mtd_read error while parsing (offset: 0x%zX): %d\n", ++ master->name, offset, err); ++ continue; ++ } ++ ++ allfound = true; ++ ++ for (i = 0; i < ARRAY_SIZE(rb_dynparts); i++) { ++ if (rb_dynparts[i].found) ++ continue; ++ ++ allfound = false; ++ ++ if (rb_dynparts[i].magic == buf) { ++ rb_dynparts[i].offset = offset; ++ ++ if (rb_dynparts[i].size_fixup) { ++ err = rb_dynparts[i].size_fixup(master, &rb_dynparts[i]); ++ if (err) { ++ pr_err("%s: size fixup error while parsing \"%s\": %d\n", ++ master->name, rb_dynparts[i].name, err); ++ continue; ++ } ++ } ++ ++ rb_dynparts[i].found = true; ++ ++ /* ++ * move offset to skip the whole partition on ++ * next iteration if size > RB_BLOCK_SIZE. ++ */ ++ if (rb_dynparts[i].size > RB_BLOCK_SIZE) ++ offset += ALIGN_DOWN((rb_dynparts[i].size - RB_BLOCK_SIZE), RB_BLOCK_SIZE); ++ ++ break; ++ } ++ } ++ ++ offset += RB_BLOCK_SIZE; ++ ++ if (allfound) ++ break; ++ } ++} ++ ++static int routerboot_partitions_parse(struct mtd_info *master, ++ const struct mtd_partition **pparts, ++ struct mtd_part_parser_data *data) ++{ ++ struct device_node *rbpart_node, *pp; ++ struct mtd_partition *parts; ++ const char *partname; ++ size_t master_ofs; ++ int np; ++ ++ /* Pull of_node from the master device node */ ++ rbpart_node = mtd_get_of_node(master); ++ if (!rbpart_node) ++ return 0; ++ ++ /* First count the subnodes */ ++ np = 0; ++ for_each_child_of_node(rbpart_node, pp) ++ np++; ++ ++ if (!np) ++ return 0; ++ ++ parts = kcalloc(np, sizeof(*parts), GFP_KERNEL); ++ if (!parts) ++ return -ENOMEM; ++ ++ /* Preemptively look for known parts in flash */ ++ routerboot_find_dynparts(master); ++ ++ np = 0; ++ master_ofs = 0; ++ for_each_child_of_node(rbpart_node, pp) { ++ const __be32 *reg, *sz; ++ size_t offset, size; ++ int i, len, a_cells, s_cells; ++ ++ partname = of_get_property(pp, "label", &len); ++ /* Allow deprecated use of "name" instead of "label" */ ++ if (!partname) ++ partname = of_get_property(pp, "name", &len); ++ /* Fallback to node name per spec if all else fails: partname is always set */ ++ if (!partname) ++ partname = pp->name; ++ parts[np].name = partname; ++ ++ reg = of_get_property(pp, "reg", &len); ++ if (reg) { ++ /* Fixed partition */ ++ a_cells = of_n_addr_cells(pp); ++ s_cells = of_n_size_cells(pp); ++ ++ if ((len / 4) != (a_cells + s_cells)) { ++ pr_debug("%s: routerboot partition %pOF (%pOF) error parsing reg property.\n", ++ master->name, pp, rbpart_node); ++ goto rbpart_fail; ++ } ++ ++ offset = of_read_number(reg, a_cells); ++ size = of_read_number(reg + a_cells, s_cells); ++ } else { ++ /* Dynamic partition */ ++ /* Default: part starts at current offset, 0 size */ ++ offset = master_ofs; ++ size = 0; ++ ++ /* Check if well-known partition */ ++ for (i = 0; i < ARRAY_SIZE(rb_dynparts); i++) { ++ if (!strcmp(partname, rb_dynparts[i].name) && rb_dynparts[i].found) { ++ offset = rb_dynparts[i].offset; ++ size = rb_dynparts[i].size; ++ break; ++ } ++ } ++ ++ /* Standalone 'size' property? Override size */ ++ sz = of_get_property(pp, "size", &len); ++ if (sz) { ++ s_cells = of_n_size_cells(pp); ++ if ((len / 4) != s_cells) { ++ pr_debug("%s: routerboot partition %pOF (%pOF) error parsing size property.\n", ++ master->name, pp, rbpart_node); ++ goto rbpart_fail; ++ } ++ ++ size = of_read_number(sz, s_cells); ++ } ++ } ++ ++ if (np > 0) { ++ /* Minor sanity check for overlaps */ ++ if (offset < (parts[np-1].offset + parts[np-1].size)) { ++ pr_err("%s: routerboot partition %pOF (%pOF) \"%s\" overlaps with previous partition \"%s\".\n", ++ master->name, pp, rbpart_node, ++ partname, parts[np-1].name); ++ goto rbpart_fail; ++ } ++ ++ /* Fixup end of previous partition if necessary */ ++ if (!parts[np-1].size) ++ parts[np-1].size = (offset - parts[np-1].offset); ++ } ++ ++ if ((offset + size) > master->size) { ++ pr_err("%s: routerboot partition %pOF (%pOF) \"%s\" extends past end of segment.\n", ++ master->name, pp, rbpart_node, partname); ++ goto rbpart_fail; ++ } ++ ++ parts[np].offset = offset; ++ parts[np].size = size; ++ parts[np].of_node = pp; ++ ++ if (of_get_property(pp, "read-only", &len)) ++ parts[np].mask_flags |= MTD_WRITEABLE; ++ ++ if (of_get_property(pp, "lock", &len)) ++ parts[np].mask_flags |= MTD_POWERUP_LOCK; ++ ++ /* Keep master offset aligned to RB_BLOCK_SIZE */ ++ master_ofs = ALIGN(offset + size, RB_BLOCK_SIZE); ++ np++; ++ } ++ ++ *pparts = parts; ++ return np; ++ ++rbpart_fail: ++ pr_err("%s: error parsing routerboot partition %pOF (%pOF)\n", ++ master->name, pp, rbpart_node); ++ of_node_put(pp); ++ kfree(parts); ++ return -EINVAL; ++} ++ ++static const struct of_device_id parse_routerbootpart_match_table[] = { ++ { .compatible = "mikrotik,routerboot-partitions" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, parse_routerbootpart_match_table); ++ ++static struct mtd_part_parser routerbootpart_parser = { ++ .parse_fn = routerboot_partitions_parse, ++ .name = "routerbootpart", ++ .of_match_table = parse_routerbootpart_match_table, ++}; ++module_mtd_part_parser(routerbootpart_parser); ++ ++MODULE_LICENSE("GPL v2"); ++MODULE_DESCRIPTION("MTD partitioning for RouterBoot"); ++MODULE_AUTHOR("Thibaut VARENE"); +diff --git a/drivers/net/dsa/an8855.c b/drivers/net/dsa/an8855.c +new file mode 100644 +index 000000000000..e6666d2011c9 +--- /dev/null ++++ b/drivers/net/dsa/an8855.c +@@ -0,0 +1,2308 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Airoha AN8855 DSA Switch driver ++ * Copyright (C) 2023 Min Yao ++ * Copyright (C) 2024 Christian Marangi ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "an8855.h" ++ ++static const struct an8855_mib_desc an8855_mib[] = { ++ MIB_DESC(1, AN8855_PORT_MIB_TX_DROP, "TxDrop"), ++ MIB_DESC(1, AN8855_PORT_MIB_TX_CRC_ERR, "TxCrcErr"), ++ MIB_DESC(1, AN8855_PORT_MIB_TX_COLLISION, "TxCollision"), ++ MIB_DESC(1, AN8855_PORT_MIB_TX_OVERSIZE_DROP, "TxOversizeDrop"), ++ MIB_DESC(2, AN8855_PORT_MIB_TX_BAD_PKT_BYTES, "TxBadPktBytes"), ++ MIB_DESC(1, AN8855_PORT_MIB_RX_DROP, "RxDrop"), ++ MIB_DESC(1, AN8855_PORT_MIB_RX_FILTERING, "RxFiltering"), ++ MIB_DESC(1, AN8855_PORT_MIB_RX_CRC_ERR, "RxCrcErr"), ++ MIB_DESC(1, AN8855_PORT_MIB_RX_CTRL_DROP, "RxCtrlDrop"), ++ MIB_DESC(1, AN8855_PORT_MIB_RX_INGRESS_DROP, "RxIngressDrop"), ++ MIB_DESC(1, AN8855_PORT_MIB_RX_ARL_DROP, "RxArlDrop"), ++ MIB_DESC(1, AN8855_PORT_MIB_FLOW_CONTROL_DROP, "FlowControlDrop"), ++ MIB_DESC(1, AN8855_PORT_MIB_WRED_DROP, "WredDrop"), ++ MIB_DESC(1, AN8855_PORT_MIB_MIRROR_DROP, "MirrorDrop"), ++ MIB_DESC(2, AN8855_PORT_MIB_RX_BAD_PKT_BYTES, "RxBadPktBytes"), ++ MIB_DESC(1, AN8855_PORT_MIB_RXS_FLOW_SAMPLING_PKT_DROP, "RxsFlowSamplingPktDrop"), ++ MIB_DESC(1, AN8855_PORT_MIB_RXS_FLOW_TOTAL_PKT_DROP, "RxsFlowTotalPktDrop"), ++ MIB_DESC(1, AN8855_PORT_MIB_PORT_CONTROL_DROP, "PortControlDrop"), ++}; ++ ++static int ++an8855_mib_init(struct an8855_priv *priv) ++{ ++ int ret; ++ ++ ret = regmap_write(priv->regmap, AN8855_MIB_CCR, ++ AN8855_CCR_MIB_ENABLE); ++ if (ret) ++ return ret; ++ ++ return regmap_write(priv->regmap, AN8855_MIB_CCR, ++ AN8855_CCR_MIB_ACTIVATE); ++} ++ ++static void an8855_fdb_write(struct an8855_priv *priv, u16 vid, ++ u8 port_mask, const u8 *mac, ++ bool add) __must_hold(&priv->reg_mutex) ++{ ++ u32 mac_reg[2] = { }; ++ u32 reg; ++ ++ mac_reg[0] |= FIELD_PREP(AN8855_ATA1_MAC0, mac[0]); ++ mac_reg[0] |= FIELD_PREP(AN8855_ATA1_MAC1, mac[1]); ++ mac_reg[0] |= FIELD_PREP(AN8855_ATA1_MAC2, mac[2]); ++ mac_reg[0] |= FIELD_PREP(AN8855_ATA1_MAC3, mac[3]); ++ mac_reg[1] |= FIELD_PREP(AN8855_ATA2_MAC4, mac[4]); ++ mac_reg[1] |= FIELD_PREP(AN8855_ATA2_MAC5, mac[5]); ++ ++ regmap_bulk_write(priv->regmap, AN8855_ATA1, mac_reg, ++ ARRAY_SIZE(mac_reg)); ++ ++ reg = AN8855_ATWD_IVL; ++ if (add) ++ reg |= AN8855_ATWD_VLD; ++ reg |= FIELD_PREP(AN8855_ATWD_VID, vid); ++ reg |= FIELD_PREP(AN8855_ATWD_FID, AN8855_FID_BRIDGED); ++ regmap_write(priv->regmap, AN8855_ATWD, reg); ++ regmap_write(priv->regmap, AN8855_ATWD2, ++ FIELD_PREP(AN8855_ATWD2_PORT, port_mask)); ++} ++ ++static void an8855_fdb_read(struct an8855_priv *priv, struct an8855_fdb *fdb) ++{ ++ u32 reg[4]; ++ ++ regmap_bulk_read(priv->regmap, AN8855_ATRD0, reg, ++ ARRAY_SIZE(reg)); ++ ++ fdb->live = FIELD_GET(AN8855_ATRD0_LIVE, reg[0]); ++ fdb->type = FIELD_GET(AN8855_ATRD0_TYPE, reg[0]); ++ fdb->ivl = FIELD_GET(AN8855_ATRD0_IVL, reg[0]); ++ fdb->vid = FIELD_GET(AN8855_ATRD0_VID, reg[0]); ++ fdb->fid = FIELD_GET(AN8855_ATRD0_FID, reg[0]); ++ fdb->aging = FIELD_GET(AN8855_ATRD1_AGING, reg[1]); ++ fdb->port_mask = FIELD_GET(AN8855_ATRD3_PORTMASK, reg[3]); ++ fdb->mac[0] = FIELD_GET(AN8855_ATRD2_MAC0, reg[2]); ++ fdb->mac[1] = FIELD_GET(AN8855_ATRD2_MAC1, reg[2]); ++ fdb->mac[2] = FIELD_GET(AN8855_ATRD2_MAC2, reg[2]); ++ fdb->mac[3] = FIELD_GET(AN8855_ATRD2_MAC3, reg[2]); ++ fdb->mac[4] = FIELD_GET(AN8855_ATRD1_MAC4, reg[1]); ++ fdb->mac[5] = FIELD_GET(AN8855_ATRD1_MAC5, reg[1]); ++ fdb->noarp = !!FIELD_GET(AN8855_ATRD0_ARP, reg[0]); ++} ++ ++static int an8855_fdb_cmd(struct an8855_priv *priv, u32 cmd, ++ u32 *rsp) __must_hold(&priv->reg_mutex) ++{ ++ u32 val; ++ int ret; ++ ++ /* Set the command operating upon the MAC address entries */ ++ val = AN8855_ATC_BUSY | cmd; ++ ret = regmap_write(priv->regmap, AN8855_ATC, val); ++ if (ret) ++ return ret; ++ ++ ret = regmap_read_poll_timeout(priv->regmap, AN8855_ATC, val, ++ !(val & AN8855_ATC_BUSY), 20, 200000); ++ if (ret) ++ return ret; ++ ++ if (rsp) ++ *rsp = val; ++ ++ return 0; ++} ++ ++static void ++an8855_port_stp_state_set(struct dsa_switch *ds, int port, u8 state) ++{ ++ struct dsa_port *dp = dsa_to_port(ds, port); ++ struct an8855_priv *priv = ds->priv; ++ bool learning = false; ++ u32 stp_state; ++ ++ switch (state) { ++ case BR_STATE_DISABLED: ++ stp_state = AN8855_STP_DISABLED; ++ break; ++ case BR_STATE_BLOCKING: ++ stp_state = AN8855_STP_BLOCKING; ++ break; ++ case BR_STATE_LISTENING: ++ stp_state = AN8855_STP_LISTENING; ++ break; ++ case BR_STATE_LEARNING: ++ stp_state = AN8855_STP_LEARNING; ++ learning = dp->learning; ++ break; ++ case BR_STATE_FORWARDING: ++ learning = dp->learning; ++ fallthrough; ++ default: ++ stp_state = AN8855_STP_FORWARDING; ++ break; ++ } ++ ++ regmap_update_bits(priv->regmap, AN8855_SSP_P(port), ++ AN8855_FID_PST_MASK(AN8855_FID_BRIDGED), ++ AN8855_FID_PST_VAL(AN8855_FID_BRIDGED, stp_state)); ++ ++ regmap_update_bits(priv->regmap, AN8855_PSC_P(port), AN8855_SA_DIS, ++ learning ? 0 : AN8855_SA_DIS); ++} ++ ++static void an8855_port_fast_age(struct dsa_switch *ds, int port) ++{ ++ struct an8855_priv *priv = ds->priv; ++ int ret; ++ ++ /* Set to clean Dynamic entry */ ++ ret = regmap_write(priv->regmap, AN8855_ATA2, AN8855_ATA2_TYPE); ++ if (ret) ++ return; ++ ++ /* Set Port */ ++ ret = regmap_write(priv->regmap, AN8855_ATWD2, ++ FIELD_PREP(AN8855_ATWD2_PORT, BIT(port))); ++ if (ret) ++ return; ++ ++ /* Flush Dynamic entry at port */ ++ an8855_fdb_cmd(priv, AN8855_ATC_MAT(AND8855_FDB_MAT_MAC_TYPE_PORT) | ++ AN8855_FDB_FLUSH, NULL); ++} ++ ++static int an8855_update_port_member(struct dsa_switch *ds, int port, ++ const struct net_device *bridge_dev, ++ bool join) ++{ ++ struct an8855_priv *priv = ds->priv; ++ bool isolated, other_isolated; ++ struct dsa_port *dp; ++ u32 port_mask = 0; ++ int ret; ++ ++ isolated = !!(priv->port_isolated_map & BIT(port)); ++ ++ dsa_switch_for_each_user_port(dp, ds) { ++ if (dp->index == port) ++ continue; ++ ++ if (!dsa_port_offloads_bridge_dev(dp, bridge_dev)) ++ continue; ++ ++ other_isolated = !!(priv->port_isolated_map & BIT(dp->index)); ++ port_mask |= BIT(dp->index); ++ /* Add/remove this port to the portvlan mask of the other ++ * ports in the bridge ++ */ ++ if (join && !(isolated && other_isolated)) ++ ret = regmap_set_bits(priv->regmap, ++ AN8855_PORTMATRIX_P(dp->index), ++ FIELD_PREP(AN8855_USER_PORTMATRIX, ++ BIT(port))); ++ else ++ ret = regmap_clear_bits(priv->regmap, ++ AN8855_PORTMATRIX_P(dp->index), ++ FIELD_PREP(AN8855_USER_PORTMATRIX, ++ BIT(port))); ++ if (ret) ++ return ret; ++ } ++ ++ /* Add/remove all other ports to this port's portvlan mask */ ++ return regmap_update_bits(priv->regmap, AN8855_PORTMATRIX_P(port), ++ AN8855_USER_PORTMATRIX, ++ join ? port_mask : ~port_mask); ++} ++ ++static int an8855_port_pre_bridge_flags(struct dsa_switch *ds, int port, ++ struct switchdev_brport_flags flags, ++ struct netlink_ext_ack *extack) ++{ ++ if (flags.mask & ~(BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | ++ BR_BCAST_FLOOD | BR_ISOLATED)) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static int an8855_port_bridge_flags(struct dsa_switch *ds, int port, ++ struct switchdev_brport_flags flags, ++ struct netlink_ext_ack *extack) ++{ ++ struct an8855_priv *priv = ds->priv; ++ int ret; ++ ++ if (flags.mask & BR_LEARNING) { ++ ret = regmap_update_bits(priv->regmap, AN8855_PSC_P(port), AN8855_SA_DIS, ++ flags.val & BR_LEARNING ? 0 : AN8855_SA_DIS); ++ if (ret) ++ return ret; ++ } ++ ++ if (flags.mask & BR_FLOOD) { ++ ret = regmap_update_bits(priv->regmap, AN8855_UNUF, BIT(port), ++ flags.val & BR_FLOOD ? BIT(port) : 0); ++ if (ret) ++ return ret; ++ } ++ ++ if (flags.mask & BR_MCAST_FLOOD) { ++ ret = regmap_update_bits(priv->regmap, AN8855_UNMF, BIT(port), ++ flags.val & BR_MCAST_FLOOD ? BIT(port) : 0); ++ if (ret) ++ return ret; ++ ++ ret = regmap_update_bits(priv->regmap, AN8855_UNIPMF, BIT(port), ++ flags.val & BR_MCAST_FLOOD ? BIT(port) : 0); ++ if (ret) ++ return ret; ++ } ++ ++ if (flags.mask & BR_BCAST_FLOOD) { ++ ret = regmap_update_bits(priv->regmap, AN8855_BCF, BIT(port), ++ flags.val & BR_BCAST_FLOOD ? BIT(port) : 0); ++ if (ret) ++ return ret; ++ } ++ ++ if (flags.mask & BR_ISOLATED) { ++ struct dsa_port *dp = dsa_to_port(ds, port); ++ struct net_device *bridge_dev = dsa_port_bridge_dev_get(dp); ++ ++ if (flags.val & BR_ISOLATED) ++ priv->port_isolated_map |= BIT(port); ++ else ++ priv->port_isolated_map &= ~BIT(port); ++ ++ ret = an8855_update_port_member(ds, port, bridge_dev, true); ++ if (ret) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int an8855_set_ageing_time(struct dsa_switch *ds, unsigned int msecs) ++{ ++ struct an8855_priv *priv = ds->priv; ++ u32 age_count, age_unit, val; ++ ++ /* Convert msec in AN8855_L2_AGING_MS_CONSTANT counter */ ++ val = msecs / AN8855_L2_AGING_MS_CONSTANT; ++ /* Derive the count unit */ ++ age_unit = val / FIELD_MAX(AN8855_AGE_UNIT); ++ /* Get the count in unit, age_unit is always incremented by 1 internally */ ++ age_count = val / (age_unit + 1); ++ ++ return regmap_update_bits(priv->regmap, AN8855_AAC, ++ AN8855_AGE_CNT | AN8855_AGE_UNIT, ++ FIELD_PREP(AN8855_AGE_CNT, age_count) | ++ FIELD_PREP(AN8855_AGE_UNIT, age_unit)); ++} ++ ++static int an8855_port_bridge_join(struct dsa_switch *ds, int port, ++ struct dsa_bridge bridge, ++ bool *tx_fwd_offload, ++ struct netlink_ext_ack *extack) ++{ ++ struct an8855_priv *priv = ds->priv; ++ int ret; ++ ++ ret = an8855_update_port_member(ds, port, bridge.dev, true); ++ if (ret) ++ return ret; ++ ++ /* Set to fallback mode for independent VLAN learning if in a bridge */ ++ return regmap_update_bits(priv->regmap, AN8855_PCR_P(port), ++ AN8855_PORT_VLAN, ++ FIELD_PREP(AN8855_PORT_VLAN, ++ AN8855_PORT_FALLBACK_MODE)); ++} ++ ++static void an8855_port_bridge_leave(struct dsa_switch *ds, int port, ++ struct dsa_bridge bridge) ++{ ++ struct an8855_priv *priv = ds->priv; ++ ++ an8855_update_port_member(ds, port, bridge.dev, false); ++ ++ /* When a port is removed from the bridge, the port would be set up ++ * back to the default as is at initial boot which is a VLAN-unaware ++ * port. ++ */ ++ regmap_update_bits(priv->regmap, AN8855_PCR_P(port), ++ AN8855_PORT_VLAN, ++ FIELD_PREP(AN8855_PORT_VLAN, ++ AN8855_PORT_MATRIX_MODE)); ++} ++ ++static int an8855_port_fdb_add(struct dsa_switch *ds, int port, ++ const unsigned char *addr, u16 vid, ++ struct dsa_db db) ++{ ++ struct an8855_priv *priv = ds->priv; ++ u8 port_mask = BIT(port); ++ int ret; ++ ++ /* Set the vid to the port vlan id if no vid is set */ ++ if (!vid) ++ vid = AN8855_PORT_VID_DEFAULT; ++ ++ mutex_lock(&priv->reg_mutex); ++ an8855_fdb_write(priv, vid, port_mask, addr, true); ++ ret = an8855_fdb_cmd(priv, AN8855_FDB_WRITE, NULL); ++ mutex_unlock(&priv->reg_mutex); ++ ++ return ret; ++} ++ ++static int an8855_port_fdb_del(struct dsa_switch *ds, int port, ++ const unsigned char *addr, u16 vid, ++ struct dsa_db db) ++{ ++ struct an8855_priv *priv = ds->priv; ++ u8 port_mask = BIT(port); ++ int ret; ++ ++ /* Set the vid to the port vlan id if no vid is set */ ++ if (!vid) ++ vid = AN8855_PORT_VID_DEFAULT; ++ ++ mutex_lock(&priv->reg_mutex); ++ an8855_fdb_write(priv, vid, port_mask, addr, false); ++ ret = an8855_fdb_cmd(priv, AN8855_FDB_WRITE, NULL); ++ mutex_unlock(&priv->reg_mutex); ++ ++ return ret; ++} ++ ++static int an8855_port_fdb_dump(struct dsa_switch *ds, int port, ++ dsa_fdb_dump_cb_t *cb, void *data) ++{ ++ struct an8855_priv *priv = ds->priv; ++ int banks, count = 0; ++ u32 rsp; ++ int ret; ++ int i; ++ ++ mutex_lock(&priv->reg_mutex); ++ ++ /* Load search port */ ++ ret = regmap_write(priv->regmap, AN8855_ATWD2, ++ FIELD_PREP(AN8855_ATWD2_PORT, BIT(port))); ++ if (ret) ++ goto exit; ++ ret = an8855_fdb_cmd(priv, AN8855_ATC_MAT(AND8855_FDB_MAT_MAC_PORT) | ++ AN8855_FDB_START, &rsp); ++ if (ret < 0) ++ goto exit; ++ ++ do { ++ /* From response get the number of banks to read, exit if 0 */ ++ banks = FIELD_GET(AN8855_ATC_HIT, rsp); ++ if (!banks) ++ break; ++ ++ /* Each banks have 4 entry */ ++ for (i = 0; i < 4; i++) { ++ struct an8855_fdb _fdb = { }; ++ ++ count++; ++ ++ /* Check if bank is present */ ++ if (!(banks & BIT(i))) ++ continue; ++ ++ /* Select bank entry index */ ++ ret = regmap_write(priv->regmap, AN8855_ATRDS, ++ FIELD_PREP(AN8855_ATRD_SEL, i)); ++ if (ret) ++ break; ++ /* wait 1ms for the bank entry to be filled */ ++ usleep_range(1000, 1500); ++ an8855_fdb_read(priv, &_fdb); ++ ++ if (!_fdb.live) ++ continue; ++ ret = cb(_fdb.mac, _fdb.vid, _fdb.noarp, data); ++ if (ret < 0) ++ break; ++ } ++ ++ /* Stop if reached max FDB number */ ++ if (count >= AN8855_NUM_FDB_RECORDS) ++ break; ++ ++ /* Read next bank */ ++ ret = an8855_fdb_cmd(priv, AN8855_ATC_MAT(AND8855_FDB_MAT_MAC_PORT) | ++ AN8855_FDB_NEXT, &rsp); ++ if (ret < 0) ++ break; ++ } while (true); ++ ++exit: ++ mutex_unlock(&priv->reg_mutex); ++ return ret; ++} ++ ++static int an8855_vlan_cmd(struct an8855_priv *priv, enum an8855_vlan_cmd cmd, ++ u16 vid) __must_hold(&priv->reg_mutex) ++{ ++ u32 val; ++ int ret; ++ ++ val = AN8855_VTCR_BUSY | FIELD_PREP(AN8855_VTCR_FUNC, cmd) | ++ FIELD_PREP(AN8855_VTCR_VID, vid); ++ ret = regmap_write(priv->regmap, AN8855_VTCR, val); ++ if (ret) ++ return ret; ++ ++ return regmap_read_poll_timeout(priv->regmap, AN8855_VTCR, val, ++ !(val & AN8855_VTCR_BUSY), 20, 200000); ++} ++ ++static int an8855_vlan_add(struct an8855_priv *priv, u8 port, u16 vid, ++ bool untagged) __must_hold(&priv->reg_mutex) ++{ ++ u32 port_mask; ++ u32 val; ++ int ret; ++ ++ /* Fetch entry */ ++ ret = an8855_vlan_cmd(priv, AN8855_VTCR_RD_VID, vid); ++ if (ret) ++ return ret; ++ ++ ret = regmap_read(priv->regmap, AN8855_VARD0, &val); ++ if (ret) ++ return ret; ++ port_mask = FIELD_GET(AN8855_VA0_PORT, val) | BIT(port); ++ ++ /* Validate the entry with independent learning, create egress tag per ++ * VLAN and joining the port as one of the port members. ++ */ ++ val = (val & AN8855_VA0_ETAG) | AN8855_VA0_IVL_MAC | ++ AN8855_VA0_VTAG_EN | AN8855_VA0_VLAN_VALID | ++ FIELD_PREP(AN8855_VA0_PORT, port_mask) | ++ FIELD_PREP(AN8855_VA0_FID, AN8855_FID_BRIDGED); ++ ret = regmap_write(priv->regmap, AN8855_VAWD0, val); ++ if (ret) ++ return ret; ++ ret = regmap_write(priv->regmap, AN8855_VAWD1, 0); ++ if (ret) ++ return ret; ++ ++ /* CPU port is always taken as a tagged port for serving more than one ++ * VLANs across and also being applied with egress type stack mode for ++ * that VLAN tags would be appended after hardware special tag used as ++ * DSA tag. ++ */ ++ if (port == AN8855_CPU_PORT) ++ val = AN8855_VLAN_EGRESS_STACK; ++ /* Decide whether adding tag or not for those outgoing packets from the ++ * port inside the VLAN. ++ */ ++ else ++ val = untagged ? AN8855_VLAN_EGRESS_UNTAG : AN8855_VLAN_EGRESS_TAG; ++ ret = regmap_update_bits(priv->regmap, AN8855_VAWD0, ++ AN8855_VA0_ETAG_PORT_MASK(port), ++ AN8855_VA0_ETAG_PORT_VAL(port, val)); ++ if (ret) ++ return ret; ++ ++ /* Flush result to hardware */ ++ return an8855_vlan_cmd(priv, AN8855_VTCR_WR_VID, vid); ++} ++ ++static int an8855_vlan_del(struct an8855_priv *priv, u8 port, ++ u16 vid) __must_hold(&priv->reg_mutex) ++{ ++ u32 port_mask; ++ u32 val; ++ int ret; ++ ++ /* Fetch entry */ ++ ret = an8855_vlan_cmd(priv, AN8855_VTCR_RD_VID, vid); ++ if (ret) ++ return ret; ++ ++ ret = regmap_read(priv->regmap, AN8855_VARD0, &val); ++ if (ret) ++ return ret; ++ port_mask = FIELD_GET(AN8855_VA0_PORT, val) & ~BIT(port); ++ ++ if (!(val & AN8855_VA0_VLAN_VALID)) { ++ dev_err(priv->dev, "Cannot be deleted due to invalid entry\n"); ++ return -EINVAL; ++ } ++ ++ if (port_mask) { ++ val = (val & AN8855_VA0_ETAG) | AN8855_VA0_IVL_MAC | ++ AN8855_VA0_VTAG_EN | AN8855_VA0_VLAN_VALID | ++ FIELD_PREP(AN8855_VA0_PORT, port_mask); ++ ret = regmap_write(priv->regmap, AN8855_VAWD0, val); ++ if (ret) ++ return ret; ++ } else { ++ ret = regmap_write(priv->regmap, AN8855_VAWD0, 0); ++ if (ret) ++ return ret; ++ } ++ ret = regmap_write(priv->regmap, AN8855_VAWD1, 0); ++ if (ret) ++ return ret; ++ ++ /* Flush result to hardware */ ++ return an8855_vlan_cmd(priv, AN8855_VTCR_WR_VID, vid); ++} ++ ++static int an8855_port_set_vlan_mode(struct an8855_priv *priv, int port, ++ enum an8855_port_mode port_mode, ++ enum an8855_vlan_port_eg_tag eg_tag, ++ enum an8855_vlan_port_attr vlan_attr, ++ enum an8855_vlan_port_acc_frm acc_frm) ++{ ++ int ret; ++ ++ ret = regmap_update_bits(priv->regmap, AN8855_PCR_P(port), ++ AN8855_PORT_VLAN, ++ FIELD_PREP(AN8855_PORT_VLAN, port_mode)); ++ if (ret) ++ return ret; ++ ++ return regmap_update_bits(priv->regmap, AN8855_PVC_P(port), ++ AN8855_PVC_EG_TAG | AN8855_VLAN_ATTR | AN8855_ACC_FRM, ++ FIELD_PREP(AN8855_PVC_EG_TAG, eg_tag) | ++ FIELD_PREP(AN8855_VLAN_ATTR, vlan_attr) | ++ FIELD_PREP(AN8855_ACC_FRM, acc_frm)); ++} ++ ++static int an8855_port_set_pid(struct an8855_priv *priv, int port, ++ u16 pid) ++{ ++ int ret; ++ ++ ret = regmap_update_bits(priv->regmap, AN8855_PPBV1_P(port), ++ AN8855_PPBV_G0_PORT_VID, ++ FIELD_PREP(AN8855_PPBV_G0_PORT_VID, pid)); ++ if (ret) ++ return ret; ++ ++ return regmap_update_bits(priv->regmap, AN8855_PVID_P(port), ++ AN8855_G0_PORT_VID, ++ FIELD_PREP(AN8855_G0_PORT_VID, pid)); ++} ++ ++static int an8855_port_vlan_filtering(struct dsa_switch *ds, int port, ++ bool vlan_filtering, ++ struct netlink_ext_ack *extack) ++{ ++ struct an8855_priv *priv = ds->priv; ++ u32 val; ++ int ret; ++ ++ /* The port is being kept as VLAN-unaware port when bridge is ++ * set up with vlan_filtering not being set, Otherwise, the ++ * port and the corresponding CPU port is required the setup ++ * for becoming a VLAN-aware port. ++ */ ++ if (vlan_filtering) { ++ u32 acc_frm; ++ /* CPU port is set to fallback mode to let untagged ++ * frames pass through. ++ */ ++ ret = an8855_port_set_vlan_mode(priv, AN8855_CPU_PORT, ++ AN8855_PORT_FALLBACK_MODE, ++ AN8855_VLAN_EG_CONSISTENT, ++ AN8855_VLAN_USER, ++ AN8855_VLAN_ACC_ALL); ++ if (ret) ++ return ret; ++ ++ ret = regmap_read(priv->regmap, AN8855_PVID_P(port), &val); ++ if (ret) ++ return ret; ++ ++ /* Only accept tagged frames if PVID is not set */ ++ if (FIELD_GET(AN8855_G0_PORT_VID, val) != AN8855_PORT_VID_DEFAULT) ++ acc_frm = AN8855_VLAN_ACC_TAGGED; ++ else ++ acc_frm = AN8855_VLAN_ACC_ALL; ++ ++ /* Trapped into security mode allows packet forwarding through VLAN ++ * table lookup. ++ * Set the port as a user port which is to be able to recognize VID ++ * from incoming packets before fetching entry within the VLAN table. ++ */ ++ ret = an8855_port_set_vlan_mode(priv, port, ++ AN8855_PORT_SECURITY_MODE, ++ AN8855_VLAN_EG_DISABLED, ++ AN8855_VLAN_USER, ++ acc_frm); ++ if (ret) ++ return ret; ++ } else { ++ bool disable_cpu_vlan = true; ++ struct dsa_port *dp; ++ u32 port_mode; ++ ++ /* This is called after .port_bridge_leave when leaving a VLAN-aware ++ * bridge. Don't set standalone ports to fallback mode. ++ */ ++ if (dsa_port_bridge_dev_get(dsa_to_port(ds, port))) ++ port_mode = AN8855_PORT_FALLBACK_MODE; ++ else ++ port_mode = AN8855_PORT_MATRIX_MODE; ++ ++ /* When a port is removed from the bridge, the port would be set up ++ * back to the default as is at initial boot which is a VLAN-unaware ++ * port. ++ */ ++ ret = an8855_port_set_vlan_mode(priv, port, port_mode, ++ AN8855_VLAN_EG_CONSISTENT, ++ AN8855_VLAN_TRANSPARENT, ++ AN8855_VLAN_ACC_ALL); ++ if (ret) ++ return ret; ++ ++ /* Restore default PVID */ ++ ret = an8855_port_set_pid(priv, port, AN8855_PORT_VID_DEFAULT); ++ if (ret) ++ return ret; ++ ++ dsa_switch_for_each_user_port(dp, ds) { ++ if (dsa_port_is_vlan_filtering(dp)) { ++ disable_cpu_vlan = false; ++ break; ++ } ++ } ++ ++ if (disable_cpu_vlan) { ++ ret = an8855_port_set_vlan_mode(priv, AN8855_CPU_PORT, ++ AN8855_PORT_MATRIX_MODE, ++ AN8855_VLAN_EG_CONSISTENT, ++ AN8855_VLAN_USER, ++ AN8855_VLAN_ACC_ALL); ++ if (ret) ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ ++static int an8855_port_vlan_add(struct dsa_switch *ds, int port, ++ const struct switchdev_obj_port_vlan *vlan, ++ struct netlink_ext_ack *extack) ++{ ++ bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; ++ bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID; ++ struct an8855_priv *priv = ds->priv; ++ u32 val; ++ int ret; ++ ++ mutex_lock(&priv->reg_mutex); ++ ret = an8855_vlan_add(priv, port, vlan->vid, untagged); ++ mutex_unlock(&priv->reg_mutex); ++ if (ret) ++ return ret; ++ ++ if (pvid) { ++ /* Accept all frames if PVID is set */ ++ regmap_update_bits(priv->regmap, AN8855_PVC_P(port), AN8855_ACC_FRM, ++ FIELD_PREP(AN8855_ACC_FRM, AN8855_VLAN_ACC_ALL)); ++ ++ /* Only configure PVID if VLAN filtering is enabled */ ++ if (dsa_port_is_vlan_filtering(dsa_to_port(ds, port))) { ++ ret = an8855_port_set_pid(priv, port, vlan->vid); ++ if (ret) ++ return ret; ++ } ++ } else if (vlan->vid) { ++ ret = regmap_read(priv->regmap, AN8855_PVID_P(port), &val); ++ if (ret) ++ return ret; ++ ++ if (FIELD_GET(AN8855_G0_PORT_VID, val) != vlan->vid) ++ return 0; ++ ++ /* This VLAN is overwritten without PVID, so unset it */ ++ if (dsa_port_is_vlan_filtering(dsa_to_port(ds, port))) { ++ ret = regmap_update_bits(priv->regmap, AN8855_PVC_P(port), ++ AN8855_ACC_FRM, ++ FIELD_PREP(AN8855_ACC_FRM, ++ AN8855_VLAN_ACC_TAGGED)); ++ if (ret) ++ return ret; ++ } ++ ++ ret = an8855_port_set_pid(priv, port, AN8855_PORT_VID_DEFAULT); ++ if (ret) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int an8855_port_vlan_del(struct dsa_switch *ds, int port, ++ const struct switchdev_obj_port_vlan *vlan) ++{ ++ struct an8855_priv *priv = ds->priv; ++ u32 val; ++ int ret; ++ ++ mutex_lock(&priv->reg_mutex); ++ ret = an8855_vlan_del(priv, port, vlan->vid); ++ mutex_unlock(&priv->reg_mutex); ++ if (ret) ++ return ret; ++ ++ ret = regmap_read(priv->regmap, AN8855_PVID_P(port), &val); ++ if (ret) ++ return ret; ++ ++ /* PVID is being restored to the default whenever the PVID port ++ * is being removed from the VLAN. ++ */ ++ if (FIELD_GET(AN8855_G0_PORT_VID, val) == vlan->vid) { ++ /* Only accept tagged frames if the port is VLAN-aware */ ++ if (dsa_port_is_vlan_filtering(dsa_to_port(ds, port))) { ++ ret = regmap_update_bits(priv->regmap, AN8855_PVC_P(port), ++ AN8855_ACC_FRM, ++ FIELD_PREP(AN8855_ACC_FRM, ++ AN8855_VLAN_ACC_TAGGED)); ++ if (ret) ++ return ret; ++ } ++ ++ ret = an8855_port_set_pid(priv, port, AN8855_PORT_VID_DEFAULT); ++ if (ret) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int ++an8855_port_mdb_add(struct dsa_switch *ds, int port, ++ const struct switchdev_obj_port_mdb *mdb, ++ struct dsa_db db) ++{ ++ struct an8855_priv *priv = ds->priv; ++ const u8 *addr = mdb->addr; ++ u16 vid = mdb->vid; ++ u8 port_mask = 0; ++ u32 val; ++ int ret; ++ ++ /* Set the vid to the port vlan id if no vid is set */ ++ if (!vid) ++ vid = AN8855_PORT_VID_DEFAULT; ++ ++ mutex_lock(&priv->reg_mutex); ++ ++ an8855_fdb_write(priv, vid, 0, addr, false); ++ if (!an8855_fdb_cmd(priv, AN8855_FDB_READ, NULL)) { ++ ret = regmap_read(priv->regmap, AN8855_ATRD3, &val); ++ if (ret) ++ goto exit; ++ ++ port_mask = FIELD_GET(AN8855_ATRD3_PORTMASK, val); ++ } ++ ++ port_mask |= BIT(port); ++ an8855_fdb_write(priv, vid, port_mask, addr, true); ++ ret = an8855_fdb_cmd(priv, AN8855_FDB_WRITE, NULL); ++ ++exit: ++ mutex_unlock(&priv->reg_mutex); ++ ++ return ret; ++} ++ ++static int ++an8855_port_mdb_del(struct dsa_switch *ds, int port, ++ const struct switchdev_obj_port_mdb *mdb, ++ struct dsa_db db) ++{ ++ struct an8855_priv *priv = ds->priv; ++ const u8 *addr = mdb->addr; ++ u16 vid = mdb->vid; ++ u8 port_mask = 0; ++ u32 val; ++ int ret; ++ ++ /* Set the vid to the port vlan id if no vid is set */ ++ if (!vid) ++ vid = AN8855_PORT_VID_DEFAULT; ++ ++ mutex_lock(&priv->reg_mutex); ++ ++ an8855_fdb_write(priv, vid, 0, addr, 0); ++ if (!an8855_fdb_cmd(priv, AN8855_FDB_READ, NULL)) { ++ ret = regmap_read(priv->regmap, AN8855_ATRD3, &val); ++ if (ret) ++ goto exit; ++ ++ port_mask = FIELD_GET(AN8855_ATRD3_PORTMASK, val); ++ } ++ ++ port_mask &= ~BIT(port); ++ an8855_fdb_write(priv, vid, port_mask, addr, port_mask ? true : false); ++ ret = an8855_fdb_cmd(priv, AN8855_FDB_WRITE, NULL); ++ ++exit: ++ mutex_unlock(&priv->reg_mutex); ++ ++ return ret; ++} ++ ++static int ++an8855_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu) ++{ ++ struct an8855_priv *priv = ds->priv; ++ int length; ++ u32 val; ++ ++ /* When a new MTU is set, DSA always set the CPU port's MTU to the ++ * largest MTU of the slave ports. Because the switch only has a global ++ * RX length register, only allowing CPU port here is enough. ++ */ ++ if (!dsa_is_cpu_port(ds, port)) ++ return 0; ++ ++ /* RX length also includes Ethernet header, MTK tag, and FCS length */ ++ length = new_mtu + ETH_HLEN + MTK_TAG_LEN + ETH_FCS_LEN; ++ if (length <= 1522) ++ val = AN8855_MAX_RX_PKT_1518_1522; ++ else if (length <= 1536) ++ val = AN8855_MAX_RX_PKT_1536; ++ else if (length <= 1552) ++ val = AN8855_MAX_RX_PKT_1552; ++ else if (length <= 3072) ++ val = AN8855_MAX_RX_JUMBO_3K; ++ else if (length <= 4096) ++ val = AN8855_MAX_RX_JUMBO_4K; ++ else if (length <= 5120) ++ val = AN8855_MAX_RX_JUMBO_5K; ++ else if (length <= 6144) ++ val = AN8855_MAX_RX_JUMBO_6K; ++ else if (length <= 7168) ++ val = AN8855_MAX_RX_JUMBO_7K; ++ else if (length <= 8192) ++ val = AN8855_MAX_RX_JUMBO_8K; ++ else if (length <= 9216) ++ val = AN8855_MAX_RX_JUMBO_9K; ++ else if (length <= 12288) ++ val = AN8855_MAX_RX_JUMBO_12K; ++ else if (length <= 15360) ++ val = AN8855_MAX_RX_JUMBO_15K; ++ else ++ val = AN8855_MAX_RX_JUMBO_16K; ++ ++ /* Enable JUMBO packet */ ++ if (length > 1552) ++ val |= AN8855_MAX_RX_PKT_JUMBO; ++ ++ return regmap_update_bits(priv->regmap, AN8855_GMACCR, ++ AN8855_MAX_RX_JUMBO | AN8855_MAX_RX_PKT_LEN, ++ val); ++} ++ ++static int ++an8855_port_max_mtu(struct dsa_switch *ds, int port) ++{ ++ return AN8855_MAX_MTU; ++} ++ ++static void ++an8855_get_strings(struct dsa_switch *ds, int port, u32 stringset, ++ uint8_t *data) ++{ ++ int i; ++ ++ if (stringset != ETH_SS_STATS) ++ return; ++ ++ for (i = 0; i < ARRAY_SIZE(an8855_mib); i++) ++ ethtool_puts(&data, an8855_mib[i].name); ++} ++ ++static void ++an8855_read_port_stats(struct an8855_priv *priv, int port, u32 offset, u8 size, ++ uint64_t *data) ++{ ++ u32 val, reg = AN8855_PORT_MIB_COUNTER(port) + offset; ++ ++ regmap_read(priv->regmap, reg, &val); ++ *data = val; ++ ++ if (size == 2) { ++ regmap_read(priv->regmap, reg + 4, &val); ++ *data |= (u64)val << 32; ++ } ++} ++ ++static void ++an8855_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *data) ++{ ++ struct an8855_priv *priv = ds->priv; ++ const struct an8855_mib_desc *mib; ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(an8855_mib); i++) { ++ mib = &an8855_mib[i]; ++ ++ an8855_read_port_stats(priv, port, mib->offset, mib->size, ++ data + i); ++ } ++} ++ ++static int ++an8855_get_sset_count(struct dsa_switch *ds, int port, int sset) ++{ ++ if (sset != ETH_SS_STATS) ++ return 0; ++ ++ return ARRAY_SIZE(an8855_mib); ++} ++ ++static void ++an8855_get_eth_mac_stats(struct dsa_switch *ds, int port, ++ struct ethtool_eth_mac_stats *mac_stats) ++{ ++ struct an8855_priv *priv = ds->priv; ++ ++ /* MIB counter doesn't provide a FramesTransmittedOK but instead ++ * provide stats for Unicast, Broadcast and Multicast frames separately. ++ * To simulate a global frame counter, read Unicast and addition Multicast ++ * and Broadcast later ++ */ ++ an8855_read_port_stats(priv, port, AN8855_PORT_MIB_TX_UNICAST, 1, ++ &mac_stats->FramesTransmittedOK); ++ ++ an8855_read_port_stats(priv, port, AN8855_PORT_MIB_TX_SINGLE_COLLISION, 1, ++ &mac_stats->SingleCollisionFrames); ++ ++ an8855_read_port_stats(priv, port, AN8855_PORT_MIB_TX_MULTIPLE_COLLISION, 1, ++ &mac_stats->MultipleCollisionFrames); ++ ++ an8855_read_port_stats(priv, port, AN8855_PORT_MIB_RX_UNICAST, 1, ++ &mac_stats->FramesReceivedOK); ++ ++ an8855_read_port_stats(priv, port, AN8855_PORT_MIB_TX_BYTES, 2, ++ &mac_stats->OctetsTransmittedOK); ++ ++ an8855_read_port_stats(priv, port, AN8855_PORT_MIB_RX_ALIGN_ERR, 1, ++ &mac_stats->AlignmentErrors); ++ ++ an8855_read_port_stats(priv, port, AN8855_PORT_MIB_TX_DEFERRED, 1, ++ &mac_stats->FramesWithDeferredXmissions); ++ ++ an8855_read_port_stats(priv, port, AN8855_PORT_MIB_TX_LATE_COLLISION, 1, ++ &mac_stats->LateCollisions); ++ ++ an8855_read_port_stats(priv, port, AN8855_PORT_MIB_TX_EXCESSIVE_COLLISION, 1, ++ &mac_stats->FramesAbortedDueToXSColls); ++ ++ an8855_read_port_stats(priv, port, AN8855_PORT_MIB_RX_BYTES, 2, ++ &mac_stats->OctetsReceivedOK); ++ ++ an8855_read_port_stats(priv, port, AN8855_PORT_MIB_TX_MULTICAST, 1, ++ &mac_stats->MulticastFramesXmittedOK); ++ mac_stats->FramesTransmittedOK += mac_stats->MulticastFramesXmittedOK; ++ an8855_read_port_stats(priv, port, AN8855_PORT_MIB_TX_BROADCAST, 1, ++ &mac_stats->BroadcastFramesXmittedOK); ++ mac_stats->FramesTransmittedOK += mac_stats->BroadcastFramesXmittedOK; ++ ++ an8855_read_port_stats(priv, port, AN8855_PORT_MIB_RX_MULTICAST, 1, ++ &mac_stats->MulticastFramesReceivedOK); ++ mac_stats->FramesReceivedOK += mac_stats->MulticastFramesReceivedOK; ++ an8855_read_port_stats(priv, port, AN8855_PORT_MIB_RX_BROADCAST, 1, ++ &mac_stats->BroadcastFramesReceivedOK); ++ mac_stats->FramesReceivedOK += mac_stats->BroadcastFramesReceivedOK; ++} ++ ++static const struct ethtool_rmon_hist_range an8855_rmon_ranges[] = { ++ { 0, 64 }, ++ { 65, 127 }, ++ { 128, 255 }, ++ { 256, 511 }, ++ { 512, 1023 }, ++ { 1024, 1518 }, ++ { 1519, AN8855_MAX_MTU }, ++ {} ++}; ++ ++static void an8855_get_rmon_stats(struct dsa_switch *ds, int port, ++ struct ethtool_rmon_stats *rmon_stats, ++ const struct ethtool_rmon_hist_range **ranges) ++{ ++ struct an8855_priv *priv = ds->priv; ++ ++ an8855_read_port_stats(priv, port, AN8855_PORT_MIB_RX_UNDER_SIZE_ERR, 1, ++ &rmon_stats->undersize_pkts); ++ an8855_read_port_stats(priv, port, AN8855_PORT_MIB_RX_OVER_SZ_ERR, 1, ++ &rmon_stats->oversize_pkts); ++ an8855_read_port_stats(priv, port, AN8855_PORT_MIB_RX_FRAG_ERR, 1, ++ &rmon_stats->fragments); ++ an8855_read_port_stats(priv, port, AN8855_PORT_MIB_RX_JABBER_ERR, 1, ++ &rmon_stats->jabbers); ++ ++ an8855_read_port_stats(priv, port, AN8855_PORT_MIB_RX_PKT_SZ_64, 1, ++ &rmon_stats->hist[0]); ++ an8855_read_port_stats(priv, port, AN8855_PORT_MIB_RX_PKT_SZ_65_TO_127, 1, ++ &rmon_stats->hist[1]); ++ an8855_read_port_stats(priv, port, AN8855_PORT_MIB_RX_PKT_SZ_128_TO_255, 1, ++ &rmon_stats->hist[2]); ++ an8855_read_port_stats(priv, port, AN8855_PORT_MIB_RX_PKT_SZ_256_TO_511, 1, ++ &rmon_stats->hist[3]); ++ an8855_read_port_stats(priv, port, AN8855_PORT_MIB_RX_PKT_SZ_512_TO_1023, 1, ++ &rmon_stats->hist[4]); ++ an8855_read_port_stats(priv, port, AN8855_PORT_MIB_RX_PKT_SZ_1024_TO_1518, 1, ++ &rmon_stats->hist[5]); ++ an8855_read_port_stats(priv, port, AN8855_PORT_MIB_RX_PKT_SZ_1519_TO_MAX, 1, ++ &rmon_stats->hist[6]); ++ ++ an8855_read_port_stats(priv, port, AN8855_PORT_MIB_TX_PKT_SZ_64, 1, ++ &rmon_stats->hist_tx[0]); ++ an8855_read_port_stats(priv, port, AN8855_PORT_MIB_TX_PKT_SZ_65_TO_127, 1, ++ &rmon_stats->hist_tx[1]); ++ an8855_read_port_stats(priv, port, AN8855_PORT_MIB_TX_PKT_SZ_128_TO_255, 1, ++ &rmon_stats->hist_tx[2]); ++ an8855_read_port_stats(priv, port, AN8855_PORT_MIB_TX_PKT_SZ_256_TO_511, 1, ++ &rmon_stats->hist_tx[3]); ++ an8855_read_port_stats(priv, port, AN8855_PORT_MIB_TX_PKT_SZ_512_TO_1023, 1, ++ &rmon_stats->hist_tx[4]); ++ an8855_read_port_stats(priv, port, AN8855_PORT_MIB_TX_PKT_SZ_1024_TO_1518, 1, ++ &rmon_stats->hist_tx[5]); ++ an8855_read_port_stats(priv, port, AN8855_PORT_MIB_TX_PKT_SZ_1519_TO_MAX, 1, ++ &rmon_stats->hist_tx[6]); ++ ++ *ranges = an8855_rmon_ranges; ++} ++ ++static void an8855_get_eth_ctrl_stats(struct dsa_switch *ds, int port, ++ struct ethtool_eth_ctrl_stats *ctrl_stats) ++{ ++ struct an8855_priv *priv = ds->priv; ++ ++ an8855_read_port_stats(priv, port, AN8855_PORT_MIB_TX_PAUSE, 1, ++ &ctrl_stats->MACControlFramesTransmitted); ++ ++ an8855_read_port_stats(priv, port, AN8855_PORT_MIB_RX_PAUSE, 1, ++ &ctrl_stats->MACControlFramesReceived); ++} ++ ++static int an8855_port_mirror_add(struct dsa_switch *ds, int port, ++ struct dsa_mall_mirror_tc_entry *mirror, ++ bool ingress, ++ struct netlink_ext_ack *extack) ++{ ++ struct an8855_priv *priv = ds->priv; ++ int monitor_port; ++ u32 val; ++ int ret; ++ ++ /* Check for existent entry */ ++ if ((ingress ? priv->mirror_rx : priv->mirror_tx) & BIT(port)) ++ return -EEXIST; ++ ++ ret = regmap_read(priv->regmap, AN8855_MIR, &val); ++ if (ret) ++ return ret; ++ ++ /* AN8855 supports 4 monitor port, but only use first group */ ++ monitor_port = FIELD_GET(AN8855_MIRROR_PORT, val); ++ if (val & AN8855_MIRROR_EN && monitor_port != mirror->to_local_port) ++ return -EEXIST; ++ ++ val = AN8855_MIRROR_EN; ++ val |= FIELD_PREP(AN8855_MIRROR_PORT, mirror->to_local_port); ++ ret = regmap_update_bits(priv->regmap, AN8855_MIR, ++ AN8855_MIRROR_EN | AN8855_MIRROR_PORT, ++ val); ++ if (ret) ++ return ret; ++ ++ ret = regmap_set_bits(priv->regmap, AN8855_PCR_P(port), ++ ingress ? AN8855_PORT_RX_MIR : AN8855_PORT_TX_MIR); ++ if (ret) ++ return ret; ++ ++ if (ingress) ++ priv->mirror_rx |= BIT(port); ++ else ++ priv->mirror_tx |= BIT(port); ++ ++ return 0; ++} ++ ++static void an8855_port_mirror_del(struct dsa_switch *ds, int port, ++ struct dsa_mall_mirror_tc_entry *mirror) ++{ ++ struct an8855_priv *priv = ds->priv; ++ ++ if (mirror->ingress) ++ priv->mirror_rx &= ~BIT(port); ++ else ++ priv->mirror_tx &= ~BIT(port); ++ ++ regmap_clear_bits(priv->regmap, AN8855_PCR_P(port), ++ mirror->ingress ? AN8855_PORT_RX_MIR : ++ AN8855_PORT_TX_MIR); ++ ++ if (!priv->mirror_rx && !priv->mirror_tx) ++ regmap_clear_bits(priv->regmap, AN8855_MIR, AN8855_MIRROR_EN); ++} ++ ++static int an8855_port_set_status(struct an8855_priv *priv, int port, ++ bool enable) ++{ ++ if (enable) ++ return regmap_set_bits(priv->regmap, AN8855_PMCR_P(port), ++ AN8855_PMCR_TX_EN | AN8855_PMCR_RX_EN); ++ else ++ return regmap_clear_bits(priv->regmap, AN8855_PMCR_P(port), ++ AN8855_PMCR_TX_EN | AN8855_PMCR_RX_EN); ++} ++ ++static int an8855_port_enable(struct dsa_switch *ds, int port, ++ struct phy_device *phy) ++{ ++ return an8855_port_set_status(ds->priv, port, true); ++} ++ ++static void an8855_port_disable(struct dsa_switch *ds, int port) ++{ ++ an8855_port_set_status(ds->priv, port, false); ++} ++ ++static u32 en8855_get_phy_flags(struct dsa_switch *ds, int port) ++{ ++ struct an8855_priv *priv = ds->priv; ++ ++ /* PHY doesn't need calibration */ ++ if (!priv->phy_require_calib) ++ return 0; ++ ++ /* Use AN8855_PHY_FLAGS_EN_CALIBRATION to signal ++ * calibration needed. ++ */ ++ return AN8855_PHY_FLAGS_EN_CALIBRATION; ++} ++ ++static enum dsa_tag_protocol ++an8855_get_tag_protocol(struct dsa_switch *ds, int port, ++ enum dsa_tag_protocol mp) ++{ ++ return DSA_TAG_PROTO_MTK; ++} ++ ++/* Similar to MT7530 also trap link local frame and special frame to CPU */ ++static int an8855_trap_special_frames(struct an8855_priv *priv) ++{ ++ int ret; ++ ++ /* Trap BPDUs to the CPU port(s) and egress them ++ * VLAN-untagged. ++ */ ++ ret = regmap_update_bits(priv->regmap, AN8855_BPC, ++ AN8855_BPDU_BPDU_FR | AN8855_BPDU_EG_TAG | ++ AN8855_BPDU_PORT_FW, ++ AN8855_BPDU_BPDU_FR | ++ FIELD_PREP(AN8855_BPDU_EG_TAG, AN8855_VLAN_EG_UNTAGGED) | ++ FIELD_PREP(AN8855_BPDU_PORT_FW, AN8855_BPDU_CPU_ONLY)); ++ if (ret) ++ return ret; ++ ++ /* Trap 802.1X PAE frames to the CPU port(s) and egress them ++ * VLAN-untagged. ++ */ ++ ret = regmap_update_bits(priv->regmap, AN8855_PAC, ++ AN8855_PAE_BPDU_FR | AN8855_PAE_EG_TAG | ++ AN8855_PAE_PORT_FW, ++ AN8855_PAE_BPDU_FR | ++ FIELD_PREP(AN8855_PAE_EG_TAG, AN8855_VLAN_EG_UNTAGGED) | ++ FIELD_PREP(AN8855_PAE_PORT_FW, AN8855_BPDU_CPU_ONLY)); ++ if (ret) ++ return ret; ++ ++ /* Trap frames with :01 MAC DAs to the CPU port(s) and egress ++ * them VLAN-untagged. ++ */ ++ ret = regmap_update_bits(priv->regmap, AN8855_RGAC1, ++ AN8855_R01_BPDU_FR | AN8855_R01_EG_TAG | ++ AN8855_R01_PORT_FW, ++ AN8855_R01_BPDU_FR | ++ FIELD_PREP(AN8855_R01_EG_TAG, AN8855_VLAN_EG_UNTAGGED) | ++ FIELD_PREP(AN8855_R01_PORT_FW, AN8855_BPDU_CPU_ONLY)); ++ if (ret) ++ return ret; ++ ++ /* Trap frames with :02 MAC DAs to the CPU port(s) and egress ++ * them VLAN-untagged. ++ */ ++ ret = regmap_update_bits(priv->regmap, AN8855_RGAC1, ++ AN8855_R02_BPDU_FR | AN8855_R02_EG_TAG | ++ AN8855_R02_PORT_FW, ++ AN8855_R02_BPDU_FR | ++ FIELD_PREP(AN8855_R02_EG_TAG, AN8855_VLAN_EG_UNTAGGED) | ++ FIELD_PREP(AN8855_R02_PORT_FW, AN8855_BPDU_CPU_ONLY)); ++ if (ret) ++ return ret; ++ ++ /* Trap frames with :03 MAC DAs to the CPU port(s) and egress ++ * them VLAN-untagged. ++ */ ++ ret = regmap_update_bits(priv->regmap, AN8855_RGAC1, ++ AN8855_R03_BPDU_FR | AN8855_R03_EG_TAG | ++ AN8855_R03_PORT_FW, ++ AN8855_R03_BPDU_FR | ++ FIELD_PREP(AN8855_R03_EG_TAG, AN8855_VLAN_EG_UNTAGGED) | ++ FIELD_PREP(AN8855_R03_PORT_FW, AN8855_BPDU_CPU_ONLY)); ++ if (ret) ++ return ret; ++ ++ /* Trap frames with :0E MAC DAs to the CPU port(s) and egress ++ * them VLAN-untagged. ++ */ ++ return regmap_update_bits(priv->regmap, AN8855_RGAC1, ++ AN8855_R0E_BPDU_FR | AN8855_R0E_EG_TAG | ++ AN8855_R0E_PORT_FW, ++ AN8855_R0E_BPDU_FR | ++ FIELD_PREP(AN8855_R0E_EG_TAG, AN8855_VLAN_EG_UNTAGGED) | ++ FIELD_PREP(AN8855_R0E_PORT_FW, AN8855_BPDU_CPU_ONLY)); ++} ++ ++static int ++an8855_setup_pvid_vlan(struct an8855_priv *priv) ++{ ++ u32 val; ++ int ret; ++ ++ /* Validate the entry with independent learning, keep the original ++ * ingress tag attribute. ++ */ ++ val = AN8855_VA0_IVL_MAC | AN8855_VA0_EG_CON | ++ FIELD_PREP(AN8855_VA0_FID, AN8855_FID_BRIDGED) | ++ AN8855_VA0_PORT | AN8855_VA0_VLAN_VALID; ++ ret = regmap_write(priv->regmap, AN8855_VAWD0, val); ++ if (ret) ++ return ret; ++ ++ return an8855_vlan_cmd(priv, AN8855_VTCR_WR_VID, ++ AN8855_PORT_VID_DEFAULT); ++} ++ ++static int an8855_setup(struct dsa_switch *ds) ++{ ++ struct an8855_priv *priv = ds->priv; ++ struct dsa_port *dp; ++ int ret; ++ ++ /* Enable and reset MIB counters */ ++ ret = an8855_mib_init(priv); ++ if (ret) ++ return ret; ++ ++ dsa_switch_for_each_user_port(dp, ds) { ++ /* Disable MAC by default on all user ports */ ++ ret = an8855_port_set_status(priv, dp->index, false); ++ if (ret) ++ return ret; ++ ++ /* Individual user ports get connected to CPU port only */ ++ ret = regmap_write(priv->regmap, AN8855_PORTMATRIX_P(dp->index), ++ FIELD_PREP(AN8855_PORTMATRIX, BIT(AN8855_CPU_PORT))); ++ if (ret) ++ return ret; ++ ++ /* Disable Broadcast Forward on user ports */ ++ ret = regmap_clear_bits(priv->regmap, AN8855_BCF, BIT(dp->index)); ++ if (ret) ++ return ret; ++ ++ /* Disable Unknown Unicast Forward on user ports */ ++ ret = regmap_clear_bits(priv->regmap, AN8855_UNUF, BIT(dp->index)); ++ if (ret) ++ return ret; ++ ++ /* Disable Unknown Multicast Forward on user ports */ ++ ret = regmap_clear_bits(priv->regmap, AN8855_UNMF, BIT(dp->index)); ++ if (ret) ++ return ret; ++ ++ ret = regmap_clear_bits(priv->regmap, AN8855_UNIPMF, BIT(dp->index)); ++ if (ret) ++ return ret; ++ ++ /* Set default PVID to on all user ports */ ++ ret = an8855_port_set_pid(priv, dp->index, AN8855_PORT_VID_DEFAULT); ++ if (ret) ++ return ret; ++ } ++ ++ /* Enable Airoha header mode on the cpu port */ ++ ret = regmap_write(priv->regmap, AN8855_PVC_P(AN8855_CPU_PORT), ++ AN8855_PORT_SPEC_REPLACE_MODE | AN8855_PORT_SPEC_TAG); ++ if (ret) ++ return ret; ++ ++ /* Unknown multicast frame forwarding to the cpu port */ ++ ret = regmap_write(priv->regmap, AN8855_UNMF, BIT(AN8855_CPU_PORT)); ++ if (ret) ++ return ret; ++ ++ /* Set CPU port number */ ++ ret = regmap_update_bits(priv->regmap, AN8855_MFC, ++ AN8855_CPU_EN | AN8855_CPU_PORT_IDX, ++ AN8855_CPU_EN | ++ FIELD_PREP(AN8855_CPU_PORT_IDX, AN8855_CPU_PORT)); ++ if (ret) ++ return ret; ++ ++ /* CPU port gets connected to all user ports of ++ * the switch. ++ */ ++ ret = regmap_write(priv->regmap, AN8855_PORTMATRIX_P(AN8855_CPU_PORT), ++ FIELD_PREP(AN8855_PORTMATRIX, dsa_user_ports(ds))); ++ if (ret) ++ return ret; ++ ++ /* CPU port is set to fallback mode to let untagged ++ * frames pass through. ++ */ ++ ret = regmap_update_bits(priv->regmap, AN8855_PCR_P(AN8855_CPU_PORT), ++ AN8855_PORT_VLAN, ++ FIELD_PREP(AN8855_PORT_VLAN, AN8855_PORT_FALLBACK_MODE)); ++ if (ret) ++ return ret; ++ ++ /* Enable Broadcast Forward on CPU port */ ++ ret = regmap_set_bits(priv->regmap, AN8855_BCF, BIT(AN8855_CPU_PORT)); ++ if (ret) ++ return ret; ++ ++ /* Enable Unknown Unicast Forward on CPU port */ ++ ret = regmap_set_bits(priv->regmap, AN8855_UNUF, BIT(AN8855_CPU_PORT)); ++ if (ret) ++ return ret; ++ ++ /* Enable Unknown Multicast Forward on CPU port */ ++ ret = regmap_set_bits(priv->regmap, AN8855_UNMF, BIT(AN8855_CPU_PORT)); ++ if (ret) ++ return ret; ++ ++ ret = regmap_set_bits(priv->regmap, AN8855_UNIPMF, BIT(AN8855_CPU_PORT)); ++ if (ret) ++ return ret; ++ ++ /* Setup Trap special frame to CPU rules */ ++ ret = an8855_trap_special_frames(priv); ++ if (ret) ++ return ret; ++ ++ dsa_switch_for_each_port(dp, ds) { ++ /* Disable Learning on all ports. ++ * Learning on CPU is disabled for fdb isolation and handled by ++ * assisted_learning_on_cpu_port. ++ */ ++ ret = regmap_set_bits(priv->regmap, AN8855_PSC_P(dp->index), ++ AN8855_SA_DIS); ++ if (ret) ++ return ret; ++ ++ /* Enable consistent egress tag (for VLAN unware VLAN-passtrough) */ ++ ret = regmap_update_bits(priv->regmap, AN8855_PVC_P(dp->index), ++ AN8855_PVC_EG_TAG, ++ FIELD_PREP(AN8855_PVC_EG_TAG, AN8855_VLAN_EG_CONSISTENT)); ++ if (ret) ++ return ret; ++ } ++ ++ /* Setup VLAN for Default PVID */ ++ ret = an8855_setup_pvid_vlan(priv); ++ if (ret) ++ return ret; ++ ++ ret = regmap_clear_bits(priv->regmap, AN8855_CKGCR, ++ AN8855_CKG_LNKDN_GLB_STOP | AN8855_CKG_LNKDN_PORT_STOP); ++ if (ret) ++ return ret; ++ ++ /* Release global PHY power down */ ++ ret = regmap_write(priv->regmap, AN8855_RG_GPHY_AFE_PWD, 0x0); ++ if (ret) ++ return ret; ++ ++ ds->configure_vlan_while_not_filtering = true; ++ ++ /* Flush the FDB table */ ++ ret = an8855_fdb_cmd(priv, AN8855_FDB_FLUSH, NULL); ++ if (ret < 0) ++ return ret; ++ ++ /* Set min a max ageing value supported */ ++ ds->ageing_time_min = AN8855_L2_AGING_MS_CONSTANT; ++ ds->ageing_time_max = FIELD_MAX(AN8855_AGE_CNT) * ++ FIELD_MAX(AN8855_AGE_UNIT) * ++ AN8855_L2_AGING_MS_CONSTANT; ++ ++ /* Enable assisted learning for fdb isolation */ ++ ds->assisted_learning_on_cpu_port = true; ++ ++ return 0; ++} ++ ++static struct phylink_pcs *an8855_phylink_mac_select_pcs(struct phylink_config *config, ++ phy_interface_t interface) ++{ ++ struct dsa_port *dp = dsa_phylink_to_port(config); ++ struct an8855_priv *priv = dp->ds->priv; ++ ++ switch (interface) { ++ case PHY_INTERFACE_MODE_SGMII: ++ case PHY_INTERFACE_MODE_2500BASEX: ++ return &priv->pcs; ++ default: ++ return NULL; ++ } ++} ++ ++static void an8855_phylink_mac_config(struct phylink_config *config, ++ unsigned int mode, ++ const struct phylink_link_state *state) ++{ ++ struct dsa_port *dp = dsa_phylink_to_port(config); ++ struct dsa_switch *ds = dp->ds; ++ struct an8855_priv *priv; ++ int port = dp->index; ++ ++ priv = ds->priv; ++ ++ /* Nothing to configure for internal ports */ ++ if (port != 5) ++ return; ++ ++ regmap_update_bits(priv->regmap, AN8855_PMCR_P(port), ++ AN8855_PMCR_IFG_XMIT | AN8855_PMCR_MAC_MODE | ++ AN8855_PMCR_BACKOFF_EN | AN8855_PMCR_BACKPR_EN, ++ FIELD_PREP(AN8855_PMCR_IFG_XMIT, 0x1) | ++ AN8855_PMCR_MAC_MODE | AN8855_PMCR_BACKOFF_EN | ++ AN8855_PMCR_BACKPR_EN); ++} ++ ++static void an8855_phylink_get_caps(struct dsa_switch *ds, int port, ++ struct phylink_config *config) ++{ ++ switch (port) { ++ case 0: ++ case 1: ++ case 2: ++ case 3: ++ case 4: ++ __set_bit(PHY_INTERFACE_MODE_GMII, ++ config->supported_interfaces); ++ __set_bit(PHY_INTERFACE_MODE_INTERNAL, ++ config->supported_interfaces); ++ break; ++ case 5: ++ phy_interface_set_rgmii(config->supported_interfaces); ++ __set_bit(PHY_INTERFACE_MODE_SGMII, ++ config->supported_interfaces); ++ __set_bit(PHY_INTERFACE_MODE_2500BASEX, ++ config->supported_interfaces); ++ break; ++ } ++ ++ config->mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE | ++ MAC_10 | MAC_100 | MAC_1000FD | MAC_2500FD; ++} ++ ++static void an8855_phylink_mac_link_down(struct phylink_config *config, ++ unsigned int mode, ++ phy_interface_t interface) ++{ ++ struct dsa_port *dp = dsa_phylink_to_port(config); ++ struct an8855_priv *priv = dp->ds->priv; ++ ++ /* With autoneg just disable TX/RX else also force link down */ ++ if (phylink_autoneg_inband(mode)) { ++ regmap_clear_bits(priv->regmap, AN8855_PMCR_P(dp->index), ++ AN8855_PMCR_TX_EN | AN8855_PMCR_RX_EN); ++ } else { ++ regmap_update_bits(priv->regmap, AN8855_PMCR_P(dp->index), ++ AN8855_PMCR_TX_EN | AN8855_PMCR_RX_EN | ++ AN8855_PMCR_FORCE_MODE | AN8855_PMCR_FORCE_LNK, ++ AN8855_PMCR_FORCE_MODE); ++ } ++} ++ ++static void an8855_phylink_mac_link_up(struct phylink_config *config, ++ struct phy_device *phydev, unsigned int mode, ++ phy_interface_t interface, int speed, ++ int duplex, bool tx_pause, bool rx_pause) ++{ ++ struct dsa_port *dp = dsa_phylink_to_port(config); ++ struct an8855_priv *priv = dp->ds->priv; ++ int port = dp->index; ++ u32 reg; ++ ++ reg = regmap_read(priv->regmap, AN8855_PMCR_P(port), ®); ++ if (phylink_autoneg_inband(mode)) { ++ reg &= ~AN8855_PMCR_FORCE_MODE; ++ } else { ++ reg |= AN8855_PMCR_FORCE_MODE | AN8855_PMCR_FORCE_LNK; ++ ++ reg &= ~AN8855_PMCR_FORCE_SPEED; ++ switch (speed) { ++ case SPEED_10: ++ reg |= AN8855_PMCR_FORCE_SPEED_10; ++ break; ++ case SPEED_100: ++ reg |= AN8855_PMCR_FORCE_SPEED_100; ++ break; ++ case SPEED_1000: ++ reg |= AN8855_PMCR_FORCE_SPEED_1000; ++ break; ++ case SPEED_2500: ++ reg |= AN8855_PMCR_FORCE_SPEED_2500; ++ break; ++ case SPEED_5000: ++ dev_err(priv->dev, "Missing support for 5G speed. Aborting...\n"); ++ return; ++ } ++ ++ reg &= ~AN8855_PMCR_FORCE_FDX; ++ if (duplex == DUPLEX_FULL) ++ reg |= AN8855_PMCR_FORCE_FDX; ++ ++ reg &= ~AN8855_PMCR_RX_FC_EN; ++ if (rx_pause || dsa_port_is_cpu(dp)) ++ reg |= AN8855_PMCR_RX_FC_EN; ++ ++ reg &= ~AN8855_PMCR_TX_FC_EN; ++ if (rx_pause || dsa_port_is_cpu(dp)) ++ reg |= AN8855_PMCR_TX_FC_EN; ++ ++ /* Disable any EEE options */ ++ reg &= ~(AN8855_PMCR_FORCE_EEE5G | AN8855_PMCR_FORCE_EEE2P5G | ++ AN8855_PMCR_FORCE_EEE1G | AN8855_PMCR_FORCE_EEE100); ++ } ++ ++ reg |= AN8855_PMCR_TX_EN | AN8855_PMCR_RX_EN; ++ ++ regmap_write(priv->regmap, AN8855_PMCR_P(port), reg); ++} ++ ++static unsigned int an8855_pcs_inband_caps(struct phylink_pcs *pcs, ++ phy_interface_t interface) ++{ ++ /* SGMII can be configured to use inband with AN result */ ++ if (interface == PHY_INTERFACE_MODE_SGMII) ++ return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE; ++ ++ /* inband is not supported in 2500-baseX and must be disabled */ ++ return LINK_INBAND_DISABLE; ++} ++ ++static void an8855_pcs_get_state(struct phylink_pcs *pcs, ++ struct phylink_link_state *state) ++{ ++ struct an8855_priv *priv = container_of(pcs, struct an8855_priv, pcs); ++ u32 val; ++ int ret; ++ ++ ret = regmap_read(priv->regmap, AN8855_PMSR_P(AN8855_CPU_PORT), &val); ++ if (ret < 0) { ++ state->link = false; ++ return; ++ } ++ ++ state->link = !!(val & AN8855_PMSR_LNK); ++ state->an_complete = state->link; ++ state->duplex = (val & AN8855_PMSR_DPX) ? DUPLEX_FULL : ++ DUPLEX_HALF; ++ ++ switch (val & AN8855_PMSR_SPEED) { ++ case AN8855_PMSR_SPEED_10: ++ state->speed = SPEED_10; ++ break; ++ case AN8855_PMSR_SPEED_100: ++ state->speed = SPEED_100; ++ break; ++ case AN8855_PMSR_SPEED_1000: ++ state->speed = SPEED_1000; ++ break; ++ case AN8855_PMSR_SPEED_2500: ++ state->speed = SPEED_2500; ++ break; ++ case AN8855_PMSR_SPEED_5000: ++ dev_err(priv->dev, "Missing support for 5G speed. Setting Unknown.\n"); ++ fallthrough; ++ default: ++ state->speed = SPEED_UNKNOWN; ++ break; ++ } ++ ++ if (val & AN8855_PMSR_RX_FC) ++ state->pause |= MLO_PAUSE_RX; ++ if (val & AN8855_PMSR_TX_FC) ++ state->pause |= MLO_PAUSE_TX; ++} ++ ++static int an8855_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode, ++ phy_interface_t interface, ++ const unsigned long *advertising, ++ bool permit_pause_to_mac) ++{ ++ struct an8855_priv *priv = container_of(pcs, struct an8855_priv, pcs); ++ u32 val; ++ int ret; ++ ++ /* !!! WELCOME TO HELL !!! */ ++ ++ /* TX FIR - improve TX EYE */ ++ ret = regmap_update_bits(priv->regmap, AN8855_INTF_CTRL_10, ++ AN8855_RG_DA_QP_TX_FIR_C2_SEL | ++ AN8855_RG_DA_QP_TX_FIR_C2_FORCE | ++ AN8855_RG_DA_QP_TX_FIR_C1_SEL | ++ AN8855_RG_DA_QP_TX_FIR_C1_FORCE, ++ AN8855_RG_DA_QP_TX_FIR_C2_SEL | ++ FIELD_PREP(AN8855_RG_DA_QP_TX_FIR_C2_FORCE, 0x4) | ++ AN8855_RG_DA_QP_TX_FIR_C1_SEL | ++ FIELD_PREP(AN8855_RG_DA_QP_TX_FIR_C1_FORCE, 0x0)); ++ if (ret) ++ return ret; ++ ++ if (interface == PHY_INTERFACE_MODE_2500BASEX) ++ val = 0x0; ++ else ++ val = 0xd; ++ ret = regmap_update_bits(priv->regmap, AN8855_INTF_CTRL_11, ++ AN8855_RG_DA_QP_TX_FIR_C0B_SEL | ++ AN8855_RG_DA_QP_TX_FIR_C0B_FORCE, ++ AN8855_RG_DA_QP_TX_FIR_C0B_SEL | ++ FIELD_PREP(AN8855_RG_DA_QP_TX_FIR_C0B_FORCE, val)); ++ if (ret) ++ return ret; ++ ++ /* RX CDR - improve RX Jitter Tolerance */ ++ if (interface == PHY_INTERFACE_MODE_2500BASEX) ++ val = 0x5; ++ else ++ val = 0x6; ++ ret = regmap_update_bits(priv->regmap, AN8855_RG_QP_CDR_LPF_BOT_LIM, ++ AN8855_RG_QP_CDR_LPF_KP_GAIN | ++ AN8855_RG_QP_CDR_LPF_KI_GAIN, ++ FIELD_PREP(AN8855_RG_QP_CDR_LPF_KP_GAIN, val) | ++ FIELD_PREP(AN8855_RG_QP_CDR_LPF_KI_GAIN, val)); ++ if (ret) ++ return ret; ++ ++ /* PLL */ ++ if (interface == PHY_INTERFACE_MODE_2500BASEX) ++ val = 0x1; ++ else ++ val = 0x0; ++ ret = regmap_update_bits(priv->regmap, AN8855_QP_DIG_MODE_CTRL_1, ++ AN8855_RG_TPHY_SPEED, ++ FIELD_PREP(AN8855_RG_TPHY_SPEED, val)); ++ if (ret) ++ return ret; ++ ++ /* PLL - LPF */ ++ ret = regmap_update_bits(priv->regmap, AN8855_PLL_CTRL_2, ++ AN8855_RG_DA_QP_PLL_RICO_SEL_INTF | ++ AN8855_RG_DA_QP_PLL_FBKSEL_INTF | ++ AN8855_RG_DA_QP_PLL_BR_INTF | ++ AN8855_RG_DA_QP_PLL_BPD_INTF | ++ AN8855_RG_DA_QP_PLL_BPA_INTF | ++ AN8855_RG_DA_QP_PLL_BC_INTF, ++ AN8855_RG_DA_QP_PLL_RICO_SEL_INTF | ++ FIELD_PREP(AN8855_RG_DA_QP_PLL_FBKSEL_INTF, 0x0) | ++ FIELD_PREP(AN8855_RG_DA_QP_PLL_BR_INTF, 0x3) | ++ FIELD_PREP(AN8855_RG_DA_QP_PLL_BPD_INTF, 0x0) | ++ FIELD_PREP(AN8855_RG_DA_QP_PLL_BPA_INTF, 0x5) | ++ FIELD_PREP(AN8855_RG_DA_QP_PLL_BC_INTF, 0x1)); ++ if (ret) ++ return ret; ++ ++ /* PLL - ICO */ ++ ret = regmap_set_bits(priv->regmap, AN8855_PLL_CTRL_4, ++ AN8855_RG_DA_QP_PLL_ICOLP_EN_INTF); ++ if (ret) ++ return ret; ++ ret = regmap_clear_bits(priv->regmap, AN8855_PLL_CTRL_2, ++ AN8855_RG_DA_QP_PLL_ICOIQ_EN_INTF); ++ if (ret) ++ return ret; ++ ++ /* PLL - CHP */ ++ if (interface == PHY_INTERFACE_MODE_2500BASEX) ++ val = 0x6; ++ else ++ val = 0x4; ++ ret = regmap_update_bits(priv->regmap, AN8855_PLL_CTRL_2, ++ AN8855_RG_DA_QP_PLL_IR_INTF, ++ FIELD_PREP(AN8855_RG_DA_QP_PLL_IR_INTF, val)); ++ if (ret) ++ return ret; ++ ++ /* PLL - PFD */ ++ ret = regmap_update_bits(priv->regmap, AN8855_PLL_CTRL_2, ++ AN8855_RG_DA_QP_PLL_PFD_OFFSET_EN_INTRF | ++ AN8855_RG_DA_QP_PLL_PFD_OFFSET_INTF | ++ AN8855_RG_DA_QP_PLL_KBAND_PREDIV_INTF, ++ FIELD_PREP(AN8855_RG_DA_QP_PLL_PFD_OFFSET_INTF, 0x1) | ++ FIELD_PREP(AN8855_RG_DA_QP_PLL_KBAND_PREDIV_INTF, 0x1)); ++ if (ret) ++ return ret; ++ ++ /* PLL - POSTDIV */ ++ ret = regmap_update_bits(priv->regmap, AN8855_PLL_CTRL_2, ++ AN8855_RG_DA_QP_PLL_POSTDIV_EN_INTF | ++ AN8855_RG_DA_QP_PLL_PHY_CK_EN_INTF | ++ AN8855_RG_DA_QP_PLL_PCK_SEL_INTF, ++ AN8855_RG_DA_QP_PLL_PCK_SEL_INTF); ++ if (ret) ++ return ret; ++ ++ /* PLL - SDM */ ++ ret = regmap_update_bits(priv->regmap, AN8855_PLL_CTRL_2, ++ AN8855_RG_DA_QP_PLL_SDM_HREN_INTF, ++ FIELD_PREP(AN8855_RG_DA_QP_PLL_SDM_HREN_INTF, 0x0)); ++ if (ret) ++ return ret; ++ ret = regmap_clear_bits(priv->regmap, AN8855_PLL_CTRL_2, ++ AN8855_RG_DA_QP_PLL_SDM_IFM_INTF); ++ if (ret) ++ return ret; ++ ++ ret = regmap_update_bits(priv->regmap, AN8855_SS_LCPLL_PWCTL_SETTING_2, ++ AN8855_RG_NCPO_ANA_MSB, ++ FIELD_PREP(AN8855_RG_NCPO_ANA_MSB, 0x1)); ++ if (ret) ++ return ret; ++ ++ if (interface == PHY_INTERFACE_MODE_2500BASEX) ++ val = 0x7a000000; ++ else ++ val = 0x48000000; ++ ret = regmap_write(priv->regmap, AN8855_SS_LCPLL_TDC_FLT_2, ++ FIELD_PREP(AN8855_RG_LCPLL_NCPO_VALUE, val)); ++ if (ret) ++ return ret; ++ ret = regmap_write(priv->regmap, AN8855_SS_LCPLL_TDC_PCW_1, ++ FIELD_PREP(AN8855_RG_LCPLL_PON_HRDDS_PCW_NCPO_GPON, val)); ++ if (ret) ++ return ret; ++ ++ ret = regmap_clear_bits(priv->regmap, AN8855_SS_LCPLL_TDC_FLT_5, ++ AN8855_RG_LCPLL_NCPO_CHG); ++ if (ret) ++ return ret; ++ ret = regmap_clear_bits(priv->regmap, AN8855_PLL_CK_CTRL_0, ++ AN8855_RG_DA_QP_PLL_SDM_DI_EN_INTF); ++ if (ret) ++ return ret; ++ ++ /* PLL - SS */ ++ ret = regmap_update_bits(priv->regmap, AN8855_PLL_CTRL_3, ++ AN8855_RG_DA_QP_PLL_SSC_DELTA_INTF, ++ FIELD_PREP(AN8855_RG_DA_QP_PLL_SSC_DELTA_INTF, 0x0)); ++ if (ret) ++ return ret; ++ ret = regmap_update_bits(priv->regmap, AN8855_PLL_CTRL_4, ++ AN8855_RG_DA_QP_PLL_SSC_DIR_DLY_INTF, ++ FIELD_PREP(AN8855_RG_DA_QP_PLL_SSC_DIR_DLY_INTF, 0x0)); ++ if (ret) ++ return ret; ++ ret = regmap_update_bits(priv->regmap, AN8855_PLL_CTRL_3, ++ AN8855_RG_DA_QP_PLL_SSC_PERIOD_INTF, ++ FIELD_PREP(AN8855_RG_DA_QP_PLL_SSC_PERIOD_INTF, 0x0)); ++ if (ret) ++ return ret; ++ ++ /* PLL - TDC */ ++ ret = regmap_clear_bits(priv->regmap, AN8855_PLL_CK_CTRL_0, ++ AN8855_RG_DA_QP_PLL_TDC_TXCK_SEL_INTF); ++ if (ret) ++ return ret; ++ ++ ret = regmap_set_bits(priv->regmap, AN8855_RG_QP_PLL_SDM_ORD, ++ AN8855_RG_QP_PLL_SSC_TRI_EN); ++ if (ret) ++ return ret; ++ ret = regmap_set_bits(priv->regmap, AN8855_RG_QP_PLL_SDM_ORD, ++ AN8855_RG_QP_PLL_SSC_PHASE_INI); ++ if (ret) ++ return ret; ++ ++ ret = regmap_update_bits(priv->regmap, AN8855_RG_QP_RX_DAC_EN, ++ AN8855_RG_QP_SIGDET_HF, ++ FIELD_PREP(AN8855_RG_QP_SIGDET_HF, 0x2)); ++ if (ret) ++ return ret; ++ ++ /* TCL Disable (only for Co-SIM) */ ++ ret = regmap_clear_bits(priv->regmap, AN8855_PON_RXFEDIG_CTRL_0, ++ AN8855_RG_QP_EQ_RX500M_CK_SEL); ++ if (ret) ++ return ret; ++ ++ /* TX Init */ ++ if (interface == PHY_INTERFACE_MODE_2500BASEX) ++ val = 0x4; ++ else ++ val = 0x0; ++ ret = regmap_update_bits(priv->regmap, AN8855_RG_QP_TX_MODE, ++ AN8855_RG_QP_TX_RESERVE | ++ AN8855_RG_QP_TX_MODE_16B_EN, ++ FIELD_PREP(AN8855_RG_QP_TX_RESERVE, val)); ++ if (ret) ++ return ret; ++ ++ /* RX Control/Init */ ++ ret = regmap_set_bits(priv->regmap, AN8855_RG_QP_RXAFE_RESERVE, ++ AN8855_RG_QP_CDR_PD_10B_EN); ++ if (ret) ++ return ret; ++ ++ if (interface == PHY_INTERFACE_MODE_2500BASEX) ++ val = 0x1; ++ else ++ val = 0x2; ++ ret = regmap_update_bits(priv->regmap, AN8855_RG_QP_CDR_LPF_MJV_LIM, ++ AN8855_RG_QP_CDR_LPF_RATIO, ++ FIELD_PREP(AN8855_RG_QP_CDR_LPF_RATIO, val)); ++ if (ret) ++ return ret; ++ ++ ret = regmap_update_bits(priv->regmap, AN8855_RG_QP_CDR_LPF_SETVALUE, ++ AN8855_RG_QP_CDR_PR_BUF_IN_SR | ++ AN8855_RG_QP_CDR_PR_BETA_SEL, ++ FIELD_PREP(AN8855_RG_QP_CDR_PR_BUF_IN_SR, 0x6) | ++ FIELD_PREP(AN8855_RG_QP_CDR_PR_BETA_SEL, 0x1)); ++ if (ret) ++ return ret; ++ ++ if (interface == PHY_INTERFACE_MODE_2500BASEX) ++ val = 0xf; ++ else ++ val = 0xc; ++ ret = regmap_update_bits(priv->regmap, AN8855_RG_QP_CDR_PR_CKREF_DIV1, ++ AN8855_RG_QP_CDR_PR_DAC_BAND, ++ FIELD_PREP(AN8855_RG_QP_CDR_PR_DAC_BAND, val)); ++ if (ret) ++ return ret; ++ ++ ret = regmap_update_bits(priv->regmap, AN8855_RG_QP_CDR_PR_KBAND_DIV_PCIE, ++ AN8855_RG_QP_CDR_PR_KBAND_PCIE_MODE | ++ AN8855_RG_QP_CDR_PR_KBAND_DIV_PCIE_MASK, ++ FIELD_PREP(AN8855_RG_QP_CDR_PR_KBAND_DIV_PCIE_MASK, 0x19)); ++ if (ret) ++ return ret; ++ ++ ret = regmap_update_bits(priv->regmap, AN8855_RG_QP_CDR_FORCE_IBANDLPF_R_OFF, ++ AN8855_RG_QP_CDR_PHYCK_SEL | ++ AN8855_RG_QP_CDR_PHYCK_RSTB | ++ AN8855_RG_QP_CDR_PHYCK_DIV, ++ FIELD_PREP(AN8855_RG_QP_CDR_PHYCK_SEL, 0x2) | ++ FIELD_PREP(AN8855_RG_QP_CDR_PHYCK_DIV, 0x21)); ++ if (ret) ++ return ret; ++ ++ ret = regmap_clear_bits(priv->regmap, AN8855_RG_QP_CDR_PR_KBAND_DIV_PCIE, ++ AN8855_RG_QP_CDR_PR_XFICK_EN); ++ if (ret) ++ return ret; ++ ++ ret = regmap_update_bits(priv->regmap, AN8855_RG_QP_CDR_PR_CKREF_DIV1, ++ AN8855_RG_QP_CDR_PR_KBAND_DIV, ++ FIELD_PREP(AN8855_RG_QP_CDR_PR_KBAND_DIV, 0x4)); ++ if (ret) ++ return ret; ++ ++ ret = regmap_update_bits(priv->regmap, AN8855_RX_CTRL_26, ++ AN8855_RG_QP_EQ_RETRAIN_ONLY_EN | ++ AN8855_RG_LINK_NE_EN | ++ AN8855_RG_LINK_ERRO_EN, ++ AN8855_RG_QP_EQ_RETRAIN_ONLY_EN | ++ AN8855_RG_LINK_ERRO_EN); ++ if (ret) ++ return ret; ++ ++ ret = regmap_update_bits(priv->regmap, AN8855_RX_DLY_0, ++ AN8855_RG_QP_RX_SAOSC_EN_H_DLY | ++ AN8855_RG_QP_RX_PI_CAL_EN_H_DLY, ++ FIELD_PREP(AN8855_RG_QP_RX_SAOSC_EN_H_DLY, 0x3f) | ++ FIELD_PREP(AN8855_RG_QP_RX_PI_CAL_EN_H_DLY, 0x6f)); ++ if (ret) ++ return ret; ++ ++ ret = regmap_update_bits(priv->regmap, AN8855_RX_CTRL_42, ++ AN8855_RG_QP_EQ_EN_DLY, ++ FIELD_PREP(AN8855_RG_QP_EQ_EN_DLY, 0x150)); ++ if (ret) ++ return ret; ++ ++ ret = regmap_update_bits(priv->regmap, AN8855_RX_CTRL_2, ++ AN8855_RG_QP_RX_EQ_EN_H_DLY, ++ FIELD_PREP(AN8855_RG_QP_RX_EQ_EN_H_DLY, 0x150)); ++ if (ret) ++ return ret; ++ ++ ret = regmap_update_bits(priv->regmap, AN8855_PON_RXFEDIG_CTRL_9, ++ AN8855_RG_QP_EQ_LEQOSC_DLYCNT, ++ FIELD_PREP(AN8855_RG_QP_EQ_LEQOSC_DLYCNT, 0x1)); ++ if (ret) ++ return ret; ++ ++ ret = regmap_update_bits(priv->regmap, AN8855_RX_CTRL_8, ++ AN8855_RG_DA_QP_SAOSC_DONE_TIME | ++ AN8855_RG_DA_QP_LEQOS_EN_TIME, ++ FIELD_PREP(AN8855_RG_DA_QP_SAOSC_DONE_TIME, 0x200) | ++ FIELD_PREP(AN8855_RG_DA_QP_LEQOS_EN_TIME, 0xfff)); ++ if (ret) ++ return ret; ++ ++ /* Frequency meter */ ++ if (interface == PHY_INTERFACE_MODE_2500BASEX) ++ val = 0x10; ++ else ++ val = 0x28; ++ ret = regmap_update_bits(priv->regmap, AN8855_RX_CTRL_5, ++ AN8855_RG_FREDET_CHK_CYCLE, ++ FIELD_PREP(AN8855_RG_FREDET_CHK_CYCLE, val)); ++ if (ret) ++ return ret; ++ ++ ret = regmap_update_bits(priv->regmap, AN8855_RX_CTRL_6, ++ AN8855_RG_FREDET_GOLDEN_CYCLE, ++ FIELD_PREP(AN8855_RG_FREDET_GOLDEN_CYCLE, 0x64)); ++ if (ret) ++ return ret; ++ ++ ret = regmap_update_bits(priv->regmap, AN8855_RX_CTRL_7, ++ AN8855_RG_FREDET_TOLERATE_CYCLE, ++ FIELD_PREP(AN8855_RG_FREDET_TOLERATE_CYCLE, 0x2710)); ++ if (ret) ++ return ret; ++ ++ ret = regmap_set_bits(priv->regmap, AN8855_PLL_CTRL_0, ++ AN8855_RG_PHYA_AUTO_INIT); ++ if (ret) ++ return ret; ++ ++ /* PCS Init */ ++ if (interface == PHY_INTERFACE_MODE_SGMII && ++ neg_mode == PHYLINK_PCS_NEG_INBAND_DISABLED) { ++ ret = regmap_clear_bits(priv->regmap, AN8855_QP_DIG_MODE_CTRL_0, ++ AN8855_RG_SGMII_MODE | AN8855_RG_SGMII_AN_EN); ++ if (ret) ++ return ret; ++ } ++ ++ ret = regmap_clear_bits(priv->regmap, AN8855_RG_HSGMII_PCS_CTROL_1, ++ AN8855_RG_TBI_10B_MODE); ++ if (ret) ++ return ret; ++ ++ if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED) { ++ /* Set AN Ability - Interrupt */ ++ ret = regmap_set_bits(priv->regmap, AN8855_SGMII_REG_AN_FORCE_CL37, ++ AN8855_RG_FORCE_AN_DONE); ++ if (ret) ++ return ret; ++ ++ ret = regmap_update_bits(priv->regmap, AN8855_SGMII_REG_AN_13, ++ AN8855_SGMII_REMOTE_FAULT_DIS | ++ AN8855_SGMII_IF_MODE, ++ AN8855_SGMII_REMOTE_FAULT_DIS | ++ FIELD_PREP(AN8855_SGMII_IF_MODE, 0xb)); ++ if (ret) ++ return ret; ++ } ++ ++ /* Rate Adaption - GMII path config. */ ++ if (interface == PHY_INTERFACE_MODE_2500BASEX) { ++ ret = regmap_clear_bits(priv->regmap, AN8855_RATE_ADP_P0_CTRL_0, ++ AN8855_RG_P0_DIS_MII_MODE); ++ if (ret) ++ return ret; ++ } else { ++ if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED) { ++ ret = regmap_set_bits(priv->regmap, AN8855_MII_RA_AN_ENABLE, ++ AN8855_RG_P0_RA_AN_EN); ++ if (ret) ++ return ret; ++ } else { ++ ret = regmap_update_bits(priv->regmap, AN8855_RG_AN_SGMII_MODE_FORCE, ++ AN8855_RG_FORCE_CUR_SGMII_MODE | ++ AN8855_RG_FORCE_CUR_SGMII_SEL, ++ AN8855_RG_FORCE_CUR_SGMII_SEL); ++ if (ret) ++ return ret; ++ ++ ret = regmap_clear_bits(priv->regmap, AN8855_RATE_ADP_P0_CTRL_0, ++ AN8855_RG_P0_MII_RA_RX_EN | ++ AN8855_RG_P0_MII_RA_TX_EN | ++ AN8855_RG_P0_MII_RA_RX_MODE | ++ AN8855_RG_P0_MII_RA_TX_MODE); ++ if (ret) ++ return ret; ++ } ++ ++ ret = regmap_set_bits(priv->regmap, AN8855_RATE_ADP_P0_CTRL_0, ++ AN8855_RG_P0_MII_MODE); ++ if (ret) ++ return ret; ++ } ++ ++ ret = regmap_set_bits(priv->regmap, AN8855_RG_RATE_ADAPT_CTRL_0, ++ AN8855_RG_RATE_ADAPT_RX_BYPASS | ++ AN8855_RG_RATE_ADAPT_TX_BYPASS | ++ AN8855_RG_RATE_ADAPT_RX_EN | ++ AN8855_RG_RATE_ADAPT_TX_EN); ++ if (ret) ++ return ret; ++ ++ /* Disable AN if not in autoneg */ ++ ret = regmap_update_bits(priv->regmap, AN8855_SGMII_REG_AN0, BMCR_ANENABLE, ++ neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED ? BMCR_ANENABLE : ++ 0); ++ if (ret) ++ return ret; ++ ++ if (interface == PHY_INTERFACE_MODE_SGMII) { ++ /* Follow SDK init flow with restarting AN after AN enable */ ++ if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED) { ++ ret = regmap_set_bits(priv->regmap, AN8855_SGMII_REG_AN0, ++ BMCR_ANRESTART); ++ if (ret) ++ return ret; ++ } else { ++ ret = regmap_set_bits(priv->regmap, AN8855_PHY_RX_FORCE_CTRL_0, ++ AN8855_RG_FORCE_TXC_SEL); ++ if (ret) ++ return ret; ++ } ++ } ++ ++ /* Force Speed with fixed-link or 2500base-x as doesn't support aneg */ ++ if (interface == PHY_INTERFACE_MODE_2500BASEX || ++ neg_mode != PHYLINK_PCS_NEG_INBAND_ENABLED) { ++ if (interface == PHY_INTERFACE_MODE_2500BASEX) ++ val = AN8855_RG_LINK_MODE_P0_SPEED_2500; ++ else ++ val = AN8855_RG_LINK_MODE_P0_SPEED_1000; ++ ret = regmap_update_bits(priv->regmap, AN8855_SGMII_STS_CTRL_0, ++ AN8855_RG_LINK_MODE_P0 | ++ AN8855_RG_FORCE_SPD_MODE_P0, ++ val | AN8855_RG_FORCE_SPD_MODE_P0); ++ if (ret) ++ return ret; ++ } ++ ++ /* bypass flow control to MAC */ ++ ret = regmap_write(priv->regmap, AN8855_MSG_RX_LIK_STS_0, ++ AN8855_RG_DPX_STS_P3 | AN8855_RG_DPX_STS_P2 | ++ AN8855_RG_DPX_STS_P1 | AN8855_RG_TXFC_STS_P0 | ++ AN8855_RG_RXFC_STS_P0 | AN8855_RG_DPX_STS_P0); ++ if (ret) ++ return ret; ++ ret = regmap_write(priv->regmap, AN8855_MSG_RX_LIK_STS_2, ++ AN8855_RG_RXFC_AN_BYPASS_P3 | ++ AN8855_RG_RXFC_AN_BYPASS_P2 | ++ AN8855_RG_RXFC_AN_BYPASS_P1 | ++ AN8855_RG_TXFC_AN_BYPASS_P3 | ++ AN8855_RG_TXFC_AN_BYPASS_P2 | ++ AN8855_RG_TXFC_AN_BYPASS_P1 | ++ AN8855_RG_DPX_AN_BYPASS_P3 | ++ AN8855_RG_DPX_AN_BYPASS_P2 | ++ AN8855_RG_DPX_AN_BYPASS_P1 | ++ AN8855_RG_DPX_AN_BYPASS_P0); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static void an8855_pcs_an_restart(struct phylink_pcs *pcs) ++{ ++ return; ++} ++ ++static const struct phylink_pcs_ops an8855_pcs_ops = { ++ .pcs_inband_caps = an8855_pcs_inband_caps, ++ .pcs_get_state = an8855_pcs_get_state, ++ .pcs_config = an8855_pcs_config, ++ .pcs_an_restart = an8855_pcs_an_restart, ++}; ++ ++static const struct phylink_mac_ops an8855_phylink_mac_ops = { ++ .mac_select_pcs = an8855_phylink_mac_select_pcs, ++ .mac_config = an8855_phylink_mac_config, ++ .mac_link_down = an8855_phylink_mac_link_down, ++ .mac_link_up = an8855_phylink_mac_link_up, ++}; ++ ++static const struct dsa_switch_ops an8855_switch_ops = { ++ .get_tag_protocol = an8855_get_tag_protocol, ++ .setup = an8855_setup, ++ .get_phy_flags = en8855_get_phy_flags, ++ .phylink_get_caps = an8855_phylink_get_caps, ++ .get_strings = an8855_get_strings, ++ .get_ethtool_stats = an8855_get_ethtool_stats, ++ .get_sset_count = an8855_get_sset_count, ++ .get_eth_mac_stats = an8855_get_eth_mac_stats, ++ .get_eth_ctrl_stats = an8855_get_eth_ctrl_stats, ++ .get_rmon_stats = an8855_get_rmon_stats, ++ .port_enable = an8855_port_enable, ++ .port_disable = an8855_port_disable, ++ .set_ageing_time = an8855_set_ageing_time, ++ .port_bridge_join = an8855_port_bridge_join, ++ .port_bridge_leave = an8855_port_bridge_leave, ++ .port_fast_age = an8855_port_fast_age, ++ .port_stp_state_set = an8855_port_stp_state_set, ++ .port_pre_bridge_flags = an8855_port_pre_bridge_flags, ++ .port_bridge_flags = an8855_port_bridge_flags, ++ .port_vlan_filtering = an8855_port_vlan_filtering, ++ .port_vlan_add = an8855_port_vlan_add, ++ .port_vlan_del = an8855_port_vlan_del, ++ .port_fdb_add = an8855_port_fdb_add, ++ .port_fdb_del = an8855_port_fdb_del, ++ .port_fdb_dump = an8855_port_fdb_dump, ++ .port_mdb_add = an8855_port_mdb_add, ++ .port_mdb_del = an8855_port_mdb_del, ++ .port_change_mtu = an8855_port_change_mtu, ++ .port_max_mtu = an8855_port_max_mtu, ++ .port_mirror_add = an8855_port_mirror_add, ++ .port_mirror_del = an8855_port_mirror_del, ++}; ++ ++static int an8855_read_switch_id(struct an8855_priv *priv) ++{ ++ u32 id; ++ int ret; ++ ++ ret = regmap_read(priv->regmap, AN8855_CREV, &id); ++ if (ret) ++ return ret; ++ ++ if (id != AN8855_ID) { ++ dev_err(priv->dev, ++ "Switch id detected %x but expected %x\n", ++ id, AN8855_ID); ++ return -ENODEV; ++ } ++ ++ return 0; ++} ++ ++static int an8855_switch_probe(struct platform_device *pdev) ++{ ++ struct an8855_priv *priv; ++ u32 val; ++ int ret; ++ ++ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ priv->dev = &pdev->dev; ++ priv->phy_require_calib = of_property_read_bool(priv->dev->of_node, ++ "airoha,ext-surge"); ++ ++ priv->reset_gpio = devm_gpiod_get_optional(priv->dev, "reset", ++ GPIOD_OUT_LOW); ++ if (IS_ERR(priv->reset_gpio)) ++ return PTR_ERR(priv->reset_gpio); ++ ++ /* Get regmap from MFD */ ++ priv->regmap = dev_get_regmap(priv->dev->parent, NULL); ++ ++ if (priv->reset_gpio) { ++ usleep_range(100000, 150000); ++ gpiod_set_value_cansleep(priv->reset_gpio, 0); ++ usleep_range(100000, 150000); ++ gpiod_set_value_cansleep(priv->reset_gpio, 1); ++ ++ /* Poll HWTRAP reg to wait for Switch to fully Init */ ++ ret = regmap_read_poll_timeout(priv->regmap, AN8855_HWTRAP, val, ++ val, 20, 200000); ++ if (ret) ++ return ret; ++ } ++ ++ ret = an8855_read_switch_id(priv); ++ if (ret) ++ return ret; ++ ++ priv->ds = devm_kzalloc(priv->dev, sizeof(*priv->ds), GFP_KERNEL); ++ if (!priv->ds) ++ return -ENOMEM; ++ ++ priv->ds->dev = priv->dev; ++ priv->ds->num_ports = AN8855_NUM_PORTS; ++ priv->ds->priv = priv; ++ priv->ds->ops = &an8855_switch_ops; ++ devm_mutex_init(priv->dev, &priv->reg_mutex); ++ priv->ds->phylink_mac_ops = &an8855_phylink_mac_ops; ++ ++ priv->pcs.ops = &an8855_pcs_ops; ++ priv->pcs.neg_mode = true; ++ priv->pcs.poll = true; ++ ++ dev_set_drvdata(priv->dev, priv); ++ ++ return dsa_register_switch(priv->ds); ++} ++ ++static void an8855_switch_remove(struct platform_device *pdev) ++{ ++ struct an8855_priv *priv = dev_get_drvdata(&pdev->dev); ++ ++ if (priv) ++ dsa_unregister_switch(priv->ds); ++} ++ ++static const struct of_device_id an8855_switch_of_match[] = { ++ { .compatible = "airoha,an8855-switch" }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, an8855_switch_of_match); ++ ++static struct platform_driver an8855_switch_driver = { ++ .probe = an8855_switch_probe, ++ .remove_new = an8855_switch_remove, ++ .driver = { ++ .name = "an8855-switch", ++ .of_match_table = an8855_switch_of_match, ++ }, ++}; ++module_platform_driver(an8855_switch_driver); ++ ++MODULE_AUTHOR("Min Yao "); ++MODULE_AUTHOR("Christian Marangi "); ++MODULE_DESCRIPTION("Driver for Airoha AN8855 Switch"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/net/dsa/an8855.h b/drivers/net/dsa/an8855.h +new file mode 100644 +index 000000000000..2462b9d33752 +--- /dev/null ++++ b/drivers/net/dsa/an8855.h +@@ -0,0 +1,783 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* ++ * Copyright (C) 2023 Min Yao ++ * Copyright (C) 2024 Christian Marangi ++ */ ++ ++#ifndef __AN8855_H ++#define __AN8855_H ++ ++#include ++ ++#define AN8855_NUM_PORTS 6 ++#define AN8855_CPU_PORT 5 ++#define AN8855_NUM_FDB_RECORDS 2048 ++#define AN8855_GPHY_SMI_ADDR_DEFAULT 1 ++#define AN8855_PORT_VID_DEFAULT 0 ++ ++#define MTK_TAG_LEN 4 ++#define AN8855_MAX_MTU (15360 - ETH_HLEN - ETH_FCS_LEN - MTK_TAG_LEN) ++ ++#define AN8855_L2_AGING_MS_CONSTANT 1024 ++ ++#define AN8855_PHY_FLAGS_EN_CALIBRATION BIT(0) ++ ++/* AN8855_SCU 0x10000000 */ ++#define AN8855_RG_GPIO_LED_MODE 0x10000054 ++#define AN8855_RG_GPIO_LED_SEL(i) (0x10000000 + (0x0058 + ((i) * 4))) ++#define AN8855_RG_INTB_MODE 0x10000080 ++#define AN8855_RG_RGMII_TXCK_C 0x100001d0 ++ ++#define AN8855_PKG_SEL 0x10000094 ++#define AN8855_PAG_SEL_AN8855H 0x2 ++ ++/* Register for hw trap status */ ++#define AN8855_HWTRAP 0x1000009c ++ ++#define AN8855_RG_GPIO_L_INV 0x10000010 ++#define AN8855_RG_GPIO_CTRL 0x1000a300 ++#define AN8855_RG_GPIO_DATA 0x1000a304 ++#define AN8855_RG_GPIO_OE 0x1000a314 ++ ++#define AN8855_CREV 0x10005000 ++#define AN8855_ID 0x8855 ++ ++/* Register for system reset */ ++#define AN8855_RST_CTRL 0x100050c0 ++#define AN8855_SYS_CTRL_SYS_RST BIT(31) ++ ++#define AN8855_INT_MASK 0x100050f0 ++#define AN8855_INT_SYS BIT(15) ++ ++#define AN8855_RG_CLK_CPU_ICG 0x10005034 ++#define AN8855_MCU_ENABLE BIT(3) ++ ++#define AN8855_RG_TIMER_CTL 0x1000a100 ++#define AN8855_WDOG_ENABLE BIT(25) ++ ++#define AN8855_RG_GDMP_RAM 0x10010000 ++ ++/* Registers to mac forward control for unknown frames */ ++#define AN8855_MFC 0x10200010 ++#define AN8855_CPU_EN BIT(15) ++#define AN8855_CPU_PORT_IDX GENMASK(12, 8) ++ ++#define AN8855_PAC 0x10200024 ++#define AN8855_TAG_PAE_MANG_FR BIT(30) ++#define AN8855_TAG_PAE_BPDU_FR BIT(28) ++#define AN8855_TAG_PAE_EG_TAG GENMASK(27, 25) ++#define AN8855_TAG_PAE_LKY_VLAN BIT(24) ++#define AN8855_TAG_PAE_PRI_HIGH BIT(23) ++#define AN8855_TAG_PAE_MIR GENMASK(20, 19) ++#define AN8855_TAG_PAE_PORT_FW GENMASK(18, 16) ++#define AN8855_PAE_MANG_FR BIT(14) ++#define AN8855_PAE_BPDU_FR BIT(12) ++#define AN8855_PAE_EG_TAG GENMASK(11, 9) ++#define AN8855_PAE_LKY_VLAN BIT(8) ++#define AN8855_PAE_PRI_HIGH BIT(7) ++#define AN8855_PAE_MIR GENMASK(4, 3) ++#define AN8855_PAE_PORT_FW GENMASK(2, 0) ++ ++#define AN8855_RGAC1 0x10200028 ++#define AN8855_R02_MANG_FR BIT(30) ++#define AN8855_R02_BPDU_FR BIT(28) ++#define AN8855_R02_EG_TAG GENMASK(27, 25) ++#define AN8855_R02_LKY_VLAN BIT(24) ++#define AN8855_R02_PRI_HIGH BIT(23) ++#define AN8855_R02_MIR GENMASK(20, 19) ++#define AN8855_R02_PORT_FW GENMASK(18, 16) ++#define AN8855_R01_MANG_FR BIT(14) ++#define AN8855_R01_BPDU_FR BIT(12) ++#define AN8855_R01_EG_TAG GENMASK(11, 9) ++#define AN8855_R01_LKY_VLAN BIT(8) ++#define AN8855_R01_PRI_HIGH BIT(7) ++#define AN8855_R01_MIR GENMASK(4, 3) ++#define AN8855_R01_PORT_FW GENMASK(2, 0) ++ ++#define AN8855_RGAC2 0x1020002c ++#define AN8855_R0E_MANG_FR BIT(30) ++#define AN8855_R0E_BPDU_FR BIT(28) ++#define AN8855_R0E_EG_TAG GENMASK(27, 25) ++#define AN8855_R0E_LKY_VLAN BIT(24) ++#define AN8855_R0E_PRI_HIGH BIT(23) ++#define AN8855_R0E_MIR GENMASK(20, 19) ++#define AN8855_R0E_PORT_FW GENMASK(18, 16) ++#define AN8855_R03_MANG_FR BIT(14) ++#define AN8855_R03_BPDU_FR BIT(12) ++#define AN8855_R03_EG_TAG GENMASK(11, 9) ++#define AN8855_R03_LKY_VLAN BIT(8) ++#define AN8855_R03_PRI_HIGH BIT(7) ++#define AN8855_R03_MIR GENMASK(4, 3) ++#define AN8855_R03_PORT_FW GENMASK(2, 0) ++ ++#define AN8855_AAC 0x102000a0 ++#define AN8855_MAC_AUTO_FLUSH BIT(28) ++/* Control Address Table Age time. ++ * (AN8855_AGE_CNT + 1) * ( AN8855_AGE_UNIT + 1 ) * AN8855_L2_AGING_MS_CONSTANT ++ */ ++#define AN8855_AGE_CNT GENMASK(20, 12) ++/* Value in seconds. Value is always incremented of 1 */ ++#define AN8855_AGE_UNIT GENMASK(10, 0) ++ ++/* Registers for ARL Unknown Unicast Forward control */ ++#define AN8855_UNUF 0x102000b4 ++ ++/* Registers for ARL Unknown Multicast Forward control */ ++#define AN8855_UNMF 0x102000b8 ++ ++/* Registers for ARL Broadcast forward control */ ++#define AN8855_BCF 0x102000bc ++ ++/* Registers for port address age disable */ ++#define AN8855_AGDIS 0x102000c0 ++ ++/* Registers for mirror port control */ ++#define AN8855_MIR 0x102000cc ++#define AN8855_MIRROR_EN BIT(7) ++#define AN8855_MIRROR_PORT GENMASK(4, 0) ++ ++/* Registers for BPDU and PAE frame control*/ ++#define AN8855_BPC 0x102000d0 ++#define AN8855_BPDU_MANG_FR BIT(14) ++#define AN8855_BPDU_BPDU_FR BIT(12) ++#define AN8855_BPDU_EG_TAG GENMASK(11, 9) ++#define AN8855_BPDU_LKY_VLAN BIT(8) ++#define AN8855_BPDU_PRI_HIGH BIT(7) ++#define AN8855_BPDU_MIR GENMASK(4, 3) ++#define AN8855_BPDU_PORT_FW GENMASK(2, 0) ++ ++/* Registers for IP Unknown Multicast Forward control */ ++#define AN8855_UNIPMF 0x102000dc ++ ++enum an8855_bpdu_port_fw { ++ AN8855_BPDU_FOLLOW_MFC = 0, ++ AN8855_BPDU_CPU_EXCLUDE = 4, ++ AN8855_BPDU_CPU_INCLUDE = 5, ++ AN8855_BPDU_CPU_ONLY = 6, ++ AN8855_BPDU_DROP = 7, ++}; ++ ++/* Register for address table control */ ++#define AN8855_ATC 0x10200300 ++#define AN8855_ATC_BUSY BIT(31) ++#define AN8855_ATC_HASH GENMASK(24, 16) ++#define AN8855_ATC_HIT GENMASK(15, 12) ++#define AN8855_ATC_MAT_MASK GENMASK(11, 7) ++#define AN8855_ATC_MAT(x) FIELD_PREP(AN8855_ATC_MAT_MASK, x) ++#define AN8855_ATC_SAT GENMASK(5, 4) ++#define AN8855_ATC_CMD GENMASK(2, 0) ++ ++enum an8855_fdb_mat_cmds { ++ AND8855_FDB_MAT_ALL = 0, ++ AND8855_FDB_MAT_MAC, /* All MAC address */ ++ AND8855_FDB_MAT_DYNAMIC_MAC, /* All Dynamic MAC address */ ++ AND8855_FDB_MAT_STATIC_MAC, /* All Static Mac Address */ ++ AND8855_FDB_MAT_DIP, /* All DIP/GA address */ ++ AND8855_FDB_MAT_DIP_IPV4, /* All DIP/GA IPv4 address */ ++ AND8855_FDB_MAT_DIP_IPV6, /* All DIP/GA IPv6 address */ ++ AND8855_FDB_MAT_DIP_SIP, /* All DIP_SIP address */ ++ AND8855_FDB_MAT_DIP_SIP_IPV4, /* All DIP_SIP IPv4 address */ ++ AND8855_FDB_MAT_DIP_SIP_IPV6, /* All DIP_SIP IPv6 address */ ++ AND8855_FDB_MAT_MAC_CVID, /* All MAC address with CVID */ ++ AND8855_FDB_MAT_MAC_FID, /* All MAC address with Filter ID */ ++ AND8855_FDB_MAT_MAC_PORT, /* All MAC address with port */ ++ AND8855_FDB_MAT_DIP_SIP_DIP_IPV4, /* All DIP_SIP address with DIP_IPV4 */ ++ AND8855_FDB_MAT_DIP_SIP_SIP_IPV4, /* All DIP_SIP address with SIP_IPV4 */ ++ AND8855_FDB_MAT_DIP_SIP_DIP_IPV6, /* All DIP_SIP address with DIP_IPV6 */ ++ AND8855_FDB_MAT_DIP_SIP_SIP_IPV6, /* All DIP_SIP address with SIP_IPV6 */ ++ /* All MAC address with MAC type (dynamic or static) with CVID */ ++ AND8855_FDB_MAT_MAC_TYPE_CVID, ++ /* All MAC address with MAC type (dynamic or static) with Filter ID */ ++ AND8855_FDB_MAT_MAC_TYPE_FID, ++ /* All MAC address with MAC type (dynamic or static) with port */ ++ AND8855_FDB_MAT_MAC_TYPE_PORT, ++}; ++ ++enum an8855_fdb_cmds { ++ AN8855_FDB_READ = 0, ++ AN8855_FDB_WRITE = 1, ++ AN8855_FDB_FLUSH = 2, ++ AN8855_FDB_START = 4, ++ AN8855_FDB_NEXT = 5, ++}; ++ ++/* Registers for address table access */ ++#define AN8855_ATA1 0x10200304 ++#define AN8855_ATA1_MAC0 GENMASK(31, 24) ++#define AN8855_ATA1_MAC1 GENMASK(23, 16) ++#define AN8855_ATA1_MAC2 GENMASK(15, 8) ++#define AN8855_ATA1_MAC3 GENMASK(7, 0) ++#define AN8855_ATA2 0x10200308 ++#define AN8855_ATA2_MAC4 GENMASK(31, 24) ++#define AN8855_ATA2_MAC5 GENMASK(23, 16) ++#define AN8855_ATA2_UNAUTH BIT(10) ++#define AN8855_ATA2_TYPE BIT(9) /* 1: dynamic, 0: static */ ++#define AN8855_ATA2_AGE GENMASK(8, 0) ++ ++/* Register for address table write data */ ++#define AN8855_ATWD 0x10200324 ++#define AN8855_ATWD_FID GENMASK(31, 28) ++#define AN8855_ATWD_VID GENMASK(27, 16) ++#define AN8855_ATWD_IVL BIT(15) ++#define AN8855_ATWD_EG_TAG GENMASK(14, 12) ++#define AN8855_ATWD_SA_MIR GENMASK(9, 8) ++#define AN8855_ATWD_SA_FWD GENMASK(7, 5) ++#define AN8855_ATWD_UPRI GENMASK(4, 2) ++#define AN8855_ATWD_LEAKY BIT(1) ++#define AN8855_ATWD_VLD BIT(0) /* vid LOAD */ ++#define AN8855_ATWD2 0x10200328 ++#define AN8855_ATWD2_PORT GENMASK(7, 0) ++ ++/* Registers for table search read address */ ++#define AN8855_ATRDS 0x10200330 ++#define AN8855_ATRD_SEL GENMASK(1, 0) ++#define AN8855_ATRD0 0x10200334 ++#define AN8855_ATRD0_FID GENMASK(28, 25) ++#define AN8855_ATRD0_VID GENMASK(21, 10) ++#define AN8855_ATRD0_IVL BIT(9) ++#define AN8855_ATRD0_TYPE GENMASK(4, 3) ++#define AN8855_ATRD0_ARP GENMASK(2, 1) ++#define AN8855_ATRD0_LIVE BIT(0) ++#define AN8855_ATRD1 0x10200338 ++#define AN8855_ATRD1_MAC4 GENMASK(31, 24) ++#define AN8855_ATRD1_MAC5 GENMASK(23, 16) ++#define AN8855_ATRD1_AGING GENMASK(11, 3) ++#define AN8855_ATRD2 0x1020033c ++#define AN8855_ATRD2_MAC0 GENMASK(31, 24) ++#define AN8855_ATRD2_MAC1 GENMASK(23, 16) ++#define AN8855_ATRD2_MAC2 GENMASK(15, 8) ++#define AN8855_ATRD2_MAC3 GENMASK(7, 0) ++#define AN8855_ATRD3 0x10200340 ++#define AN8855_ATRD3_PORTMASK GENMASK(7, 0) ++ ++enum an8855_fdb_type { ++ AN8855_MAC_TB_TY_MAC = 0, ++ AN8855_MAC_TB_TY_DIP = 1, ++ AN8855_MAC_TB_TY_DIP_SIP = 2, ++}; ++ ++/* Register for vlan table control */ ++#define AN8855_VTCR 0x10200600 ++#define AN8855_VTCR_BUSY BIT(31) ++#define AN8855_VTCR_FUNC GENMASK(15, 12) ++#define AN8855_VTCR_VID GENMASK(11, 0) ++ ++enum an8855_vlan_cmd { ++ /* Read/Write the specified VID entry from VAWD register based ++ * on VID. ++ */ ++ AN8855_VTCR_RD_VID = 0, ++ AN8855_VTCR_WR_VID = 1, ++}; ++ ++/* Register for setup vlan write data */ ++#define AN8855_VAWD0 0x10200604 ++/* VLAN Member Control */ ++#define AN8855_VA0_PORT GENMASK(31, 26) ++/* Egress Tag Control */ ++#define AN8855_VA0_ETAG GENMASK(23, 12) ++#define AN8855_VA0_ETAG_PORT GENMASK(13, 12) ++#define AN8855_VA0_ETAG_PORT_SHIFT(port) ((port) * 2) ++#define AN8855_VA0_ETAG_PORT_MASK(port) (AN8855_VA0_ETAG_PORT << \ ++ AN8855_VA0_ETAG_PORT_SHIFT(port)) ++#define AN8855_VA0_ETAG_PORT_VAL(port, val) (FIELD_PREP(AN8855_VA0_ETAG_PORT, (val)) << \ ++ AN8855_VA0_ETAG_PORT_SHIFT(port)) ++#define AN8855_VA0_EG_CON BIT(11) ++#define AN8855_VA0_VTAG_EN BIT(10) /* Per VLAN Egress Tag Control */ ++#define AN8855_VA0_IVL_MAC BIT(5) /* Independent VLAN Learning */ ++#define AN8855_VA0_FID GENMASK(4, 1) ++#define AN8855_VA0_VLAN_VALID BIT(0) /* VLAN Entry Valid */ ++#define AN8855_VAWD1 0x10200608 ++#define AN8855_VA1_PORT_STAG BIT(1) ++ ++enum an8855_fid { ++ AN8855_FID_STANDALONE = 0, ++ AN8855_FID_BRIDGED = 1, ++}; ++ ++/* Same register field of VAWD0 */ ++#define AN8855_VARD0 0x10200618 ++ ++enum an8855_vlan_egress_attr { ++ AN8855_VLAN_EGRESS_UNTAG = 0, ++ AN8855_VLAN_EGRESS_TAG = 2, ++ AN8855_VLAN_EGRESS_STACK = 3, ++}; ++ ++/* Register for port STP state control */ ++#define AN8855_SSP_P(x) (0x10208000 + ((x) * 0x200)) ++/* Up to 16 FID supported, each with the same mask */ ++#define AN8855_FID_PST GENMASK(1, 0) ++#define AN8855_FID_PST_SHIFT(fid) (2 * (fid)) ++#define AN8855_FID_PST_MASK(fid) (AN8855_FID_PST << \ ++ AN8855_FID_PST_SHIFT(fid)) ++#define AN8855_FID_PST_VAL(fid, val) (FIELD_PREP(AN8855_FID_PST, (val)) << \ ++ AN8855_FID_PST_SHIFT(fid)) ++ ++enum an8855_stp_state { ++ AN8855_STP_DISABLED = 0, ++ AN8855_STP_BLOCKING = 1, ++ AN8855_STP_LISTENING = AN8855_STP_BLOCKING, ++ AN8855_STP_LEARNING = 2, ++ AN8855_STP_FORWARDING = 3 ++}; ++ ++/* Register for port control */ ++#define AN8855_PCR_P(x) (0x10208004 + ((x) * 0x200)) ++#define AN8855_EG_TAG GENMASK(29, 28) ++#define AN8855_PORT_PRI GENMASK(26, 24) ++#define AN8855_PORT_TX_MIR BIT(20) ++#define AN8855_PORT_RX_MIR BIT(16) ++#define AN8855_PORT_VLAN GENMASK(1, 0) ++ ++enum an8855_port_mode { ++ /* Port Matrix Mode: Frames are forwarded by the PCR_MATRIX members. */ ++ AN8855_PORT_MATRIX_MODE = 0, ++ ++ /* Fallback Mode: Forward received frames with ingress ports that do ++ * not belong to the VLAN member. Frames whose VID is not listed on ++ * the VLAN table are forwarded by the PCR_MATRIX members. ++ */ ++ AN8855_PORT_FALLBACK_MODE = 1, ++ ++ /* Check Mode: Forward received frames whose ingress do not ++ * belong to the VLAN member. Discard frames if VID ismiddes on the ++ * VLAN table. ++ */ ++ AN8855_PORT_CHECK_MODE = 2, ++ ++ /* Security Mode: Discard any frame due to ingress membership ++ * violation or VID missed on the VLAN table. ++ */ ++ AN8855_PORT_SECURITY_MODE = 3, ++}; ++ ++/* Register for port security control */ ++#define AN8855_PSC_P(x) (0x1020800c + ((x) * 0x200)) ++#define AN8855_SA_DIS BIT(4) ++ ++/* Register for port vlan control */ ++#define AN8855_PVC_P(x) (0x10208010 + ((x) * 0x200)) ++#define AN8855_PORT_SPEC_REPLACE_MODE BIT(11) ++#define AN8855_PVC_EG_TAG GENMASK(10, 8) ++#define AN8855_VLAN_ATTR GENMASK(7, 6) ++#define AN8855_PORT_SPEC_TAG BIT(5) ++#define AN8855_ACC_FRM GENMASK(1, 0) ++ ++enum an8855_vlan_port_eg_tag { ++ AN8855_VLAN_EG_DISABLED = 0, ++ AN8855_VLAN_EG_CONSISTENT = 1, ++ AN8855_VLAN_EG_UNTAGGED = 4, ++ AN8855_VLAN_EG_SWAP = 5, ++ AN8855_VLAN_EG_TAGGED = 6, ++ AN8855_VLAN_EG_STACK = 7, ++}; ++ ++enum an8855_vlan_port_attr { ++ AN8855_VLAN_USER = 0, ++ AN8855_VLAN_STACK = 1, ++ AN8855_VLAN_TRANSPARENT = 3, ++}; ++ ++enum an8855_vlan_port_acc_frm { ++ AN8855_VLAN_ACC_ALL = 0, ++ AN8855_VLAN_ACC_TAGGED = 1, ++ AN8855_VLAN_ACC_UNTAGGED = 2, ++}; ++ ++#define AN8855_PPBV1_P(x) (0x10208014 + ((x) * 0x200)) ++#define AN8855_PPBV_G0_PORT_VID GENMASK(11, 0) ++ ++#define AN8855_PORTMATRIX_P(x) (0x10208044 + ((x) * 0x200)) ++#define AN8855_PORTMATRIX GENMASK(5, 0) ++/* Port matrix without the CPU port that should never be removed */ ++#define AN8855_USER_PORTMATRIX GENMASK(4, 0) ++ ++/* Register for port PVID */ ++#define AN8855_PVID_P(x) (0x10208048 + ((x) * 0x200)) ++#define AN8855_G0_PORT_VID GENMASK(11, 0) ++ ++/* Register for port MAC control register */ ++#define AN8855_PMCR_P(x) (0x10210000 + ((x) * 0x200)) ++#define AN8855_PMCR_FORCE_MODE BIT(31) ++#define AN8855_PMCR_FORCE_SPEED GENMASK(30, 28) ++#define AN8855_PMCR_FORCE_SPEED_5000 FIELD_PREP_CONST(AN8855_PMCR_FORCE_SPEED, 0x4) ++#define AN8855_PMCR_FORCE_SPEED_2500 FIELD_PREP_CONST(AN8855_PMCR_FORCE_SPEED, 0x3) ++#define AN8855_PMCR_FORCE_SPEED_1000 FIELD_PREP_CONST(AN8855_PMCR_FORCE_SPEED, 0x2) ++#define AN8855_PMCR_FORCE_SPEED_100 FIELD_PREP_CONST(AN8855_PMCR_FORCE_SPEED, 0x1) ++#define AN8855_PMCR_FORCE_SPEED_10 FIELD_PREP_CONST(AN8855_PMCR_FORCE_SPEED, 0x1) ++#define AN8855_PMCR_FORCE_FDX BIT(25) ++#define AN8855_PMCR_FORCE_LNK BIT(24) ++#define AN8855_PMCR_IFG_XMIT GENMASK(21, 20) ++#define AN8855_PMCR_EXT_PHY BIT(19) ++#define AN8855_PMCR_MAC_MODE BIT(18) ++#define AN8855_PMCR_TX_EN BIT(16) ++#define AN8855_PMCR_RX_EN BIT(15) ++#define AN8855_PMCR_BACKOFF_EN BIT(12) ++#define AN8855_PMCR_BACKPR_EN BIT(11) ++#define AN8855_PMCR_FORCE_EEE5G BIT(9) ++#define AN8855_PMCR_FORCE_EEE2P5G BIT(8) ++#define AN8855_PMCR_FORCE_EEE1G BIT(7) ++#define AN8855_PMCR_FORCE_EEE100 BIT(6) ++#define AN8855_PMCR_TX_FC_EN BIT(5) ++#define AN8855_PMCR_RX_FC_EN BIT(4) ++ ++#define AN8855_PMSR_P(x) (0x10210010 + (x) * 0x200) ++#define AN8855_PMSR_SPEED GENMASK(30, 28) ++#define AN8855_PMSR_SPEED_5000 FIELD_PREP_CONST(AN8855_PMSR_SPEED, 0x4) ++#define AN8855_PMSR_SPEED_2500 FIELD_PREP_CONST(AN8855_PMSR_SPEED, 0x3) ++#define AN8855_PMSR_SPEED_1000 FIELD_PREP_CONST(AN8855_PMSR_SPEED, 0x2) ++#define AN8855_PMSR_SPEED_100 FIELD_PREP_CONST(AN8855_PMSR_SPEED, 0x1) ++#define AN8855_PMSR_SPEED_10 FIELD_PREP_CONST(AN8855_PMSR_SPEED, 0x0) ++#define AN8855_PMSR_DPX BIT(25) ++#define AN8855_PMSR_LNK BIT(24) ++#define AN8855_PMSR_EEE1G BIT(7) ++#define AN8855_PMSR_EEE100M BIT(6) ++#define AN8855_PMSR_RX_FC BIT(5) ++#define AN8855_PMSR_TX_FC BIT(4) ++ ++#define AN8855_PMEEECR_P(x) (0x10210004 + (x) * 0x200) ++#define AN8855_LPI_MODE_EN BIT(31) ++#define AN8855_WAKEUP_TIME_2500 GENMASK(23, 16) ++#define AN8855_WAKEUP_TIME_1000 GENMASK(15, 8) ++#define AN8855_WAKEUP_TIME_100 GENMASK(7, 0) ++#define AN8855_PMEEECR2_P(x) (0x10210008 + (x) * 0x200) ++#define AN8855_WAKEUP_TIME_5000 GENMASK(7, 0) ++ ++#define AN8855_GMACCR 0x10213e00 ++#define AN8855_MAX_RX_JUMBO GENMASK(7, 4) ++/* 2K for 0x0, 0x1, 0x2 */ ++#define AN8855_MAX_RX_JUMBO_2K FIELD_PREP_CONST(AN8855_MAX_RX_JUMBO, 0x0) ++#define AN8855_MAX_RX_JUMBO_3K FIELD_PREP_CONST(AN8855_MAX_RX_JUMBO, 0x3) ++#define AN8855_MAX_RX_JUMBO_4K FIELD_PREP_CONST(AN8855_MAX_RX_JUMBO, 0x4) ++#define AN8855_MAX_RX_JUMBO_5K FIELD_PREP_CONST(AN8855_MAX_RX_JUMBO, 0x5) ++#define AN8855_MAX_RX_JUMBO_6K FIELD_PREP_CONST(AN8855_MAX_RX_JUMBO, 0x6) ++#define AN8855_MAX_RX_JUMBO_7K FIELD_PREP_CONST(AN8855_MAX_RX_JUMBO, 0x7) ++#define AN8855_MAX_RX_JUMBO_8K FIELD_PREP_CONST(AN8855_MAX_RX_JUMBO, 0x8) ++#define AN8855_MAX_RX_JUMBO_9K FIELD_PREP_CONST(AN8855_MAX_RX_JUMBO, 0x9) ++#define AN8855_MAX_RX_JUMBO_12K FIELD_PREP_CONST(AN8855_MAX_RX_JUMBO, 0xa) ++#define AN8855_MAX_RX_JUMBO_15K FIELD_PREP_CONST(AN8855_MAX_RX_JUMBO, 0xb) ++#define AN8855_MAX_RX_JUMBO_16K FIELD_PREP_CONST(AN8855_MAX_RX_JUMBO, 0xc) ++#define AN8855_MAX_RX_PKT_LEN GENMASK(1, 0) ++#define AN8855_MAX_RX_PKT_1518_1522 FIELD_PREP_CONST(AN8855_MAX_RX_PKT_LEN, 0x0) ++#define AN8855_MAX_RX_PKT_1536 FIELD_PREP_CONST(AN8855_MAX_RX_PKT_LEN, 0x1) ++#define AN8855_MAX_RX_PKT_1552 FIELD_PREP_CONST(AN8855_MAX_RX_PKT_LEN, 0x2) ++#define AN8855_MAX_RX_PKT_JUMBO FIELD_PREP_CONST(AN8855_MAX_RX_PKT_LEN, 0x3) ++ ++#define AN8855_CKGCR 0x10213e1c ++#define AN8855_LPI_TXIDLE_THD_MASK GENMASK(31, 14) ++#define AN8855_CKG_LNKDN_PORT_STOP BIT(1) ++#define AN8855_CKG_LNKDN_GLB_STOP BIT(0) ++ ++/* Register for MIB */ ++#define AN8855_PORT_MIB_COUNTER(x) (0x10214000 + (x) * 0x200) ++/* Each define is an offset of AN8855_PORT_MIB_COUNTER */ ++#define AN8855_PORT_MIB_TX_DROP 0x00 ++#define AN8855_PORT_MIB_TX_CRC_ERR 0x04 ++#define AN8855_PORT_MIB_TX_UNICAST 0x08 ++#define AN8855_PORT_MIB_TX_MULTICAST 0x0c ++#define AN8855_PORT_MIB_TX_BROADCAST 0x10 ++#define AN8855_PORT_MIB_TX_COLLISION 0x14 ++#define AN8855_PORT_MIB_TX_SINGLE_COLLISION 0x18 ++#define AN8855_PORT_MIB_TX_MULTIPLE_COLLISION 0x1c ++#define AN8855_PORT_MIB_TX_DEFERRED 0x20 ++#define AN8855_PORT_MIB_TX_LATE_COLLISION 0x24 ++#define AN8855_PORT_MIB_TX_EXCESSIVE_COLLISION 0x28 ++#define AN8855_PORT_MIB_TX_PAUSE 0x2c ++#define AN8855_PORT_MIB_TX_PKT_SZ_64 0x30 ++#define AN8855_PORT_MIB_TX_PKT_SZ_65_TO_127 0x34 ++#define AN8855_PORT_MIB_TX_PKT_SZ_128_TO_255 0x38 ++#define AN8855_PORT_MIB_TX_PKT_SZ_256_TO_511 0x3 ++#define AN8855_PORT_MIB_TX_PKT_SZ_512_TO_1023 0x40 ++#define AN8855_PORT_MIB_TX_PKT_SZ_1024_TO_1518 0x44 ++#define AN8855_PORT_MIB_TX_PKT_SZ_1519_TO_MAX 0x48 ++#define AN8855_PORT_MIB_TX_BYTES 0x4c /* 64 bytes */ ++#define AN8855_PORT_MIB_TX_OVERSIZE_DROP 0x54 ++#define AN8855_PORT_MIB_TX_BAD_PKT_BYTES 0x58 /* 64 bytes */ ++#define AN8855_PORT_MIB_RX_DROP 0x80 ++#define AN8855_PORT_MIB_RX_FILTERING 0x84 ++#define AN8855_PORT_MIB_RX_UNICAST 0x88 ++#define AN8855_PORT_MIB_RX_MULTICAST 0x8c ++#define AN8855_PORT_MIB_RX_BROADCAST 0x90 ++#define AN8855_PORT_MIB_RX_ALIGN_ERR 0x94 ++#define AN8855_PORT_MIB_RX_CRC_ERR 0x98 ++#define AN8855_PORT_MIB_RX_UNDER_SIZE_ERR 0x9c ++#define AN8855_PORT_MIB_RX_FRAG_ERR 0xa0 ++#define AN8855_PORT_MIB_RX_OVER_SZ_ERR 0xa4 ++#define AN8855_PORT_MIB_RX_JABBER_ERR 0xa8 ++#define AN8855_PORT_MIB_RX_PAUSE 0xac ++#define AN8855_PORT_MIB_RX_PKT_SZ_64 0xb0 ++#define AN8855_PORT_MIB_RX_PKT_SZ_65_TO_127 0xb4 ++#define AN8855_PORT_MIB_RX_PKT_SZ_128_TO_255 0xb8 ++#define AN8855_PORT_MIB_RX_PKT_SZ_256_TO_511 0xbc ++#define AN8855_PORT_MIB_RX_PKT_SZ_512_TO_1023 0xc0 ++#define AN8855_PORT_MIB_RX_PKT_SZ_1024_TO_1518 0xc4 ++#define AN8855_PORT_MIB_RX_PKT_SZ_1519_TO_MAX 0xc8 ++#define AN8855_PORT_MIB_RX_BYTES 0xcc /* 64 bytes */ ++#define AN8855_PORT_MIB_RX_CTRL_DROP 0xd4 ++#define AN8855_PORT_MIB_RX_INGRESS_DROP 0xd8 ++#define AN8855_PORT_MIB_RX_ARL_DROP 0xdc ++#define AN8855_PORT_MIB_FLOW_CONTROL_DROP 0xe0 ++#define AN8855_PORT_MIB_WRED_DROP 0xe4 ++#define AN8855_PORT_MIB_MIRROR_DROP 0xe8 ++#define AN8855_PORT_MIB_RX_BAD_PKT_BYTES 0xec /* 64 bytes */ ++#define AN8855_PORT_MIB_RXS_FLOW_SAMPLING_PKT_DROP 0xf4 ++#define AN8855_PORT_MIB_RXS_FLOW_TOTAL_PKT_DROP 0xf8 ++#define AN8855_PORT_MIB_PORT_CONTROL_DROP 0xfc ++#define AN8855_MIB_CCR 0x10213e30 ++#define AN8855_CCR_MIB_ENABLE BIT(31) ++#define AN8855_CCR_RX_OCT_CNT_GOOD BIT(7) ++#define AN8855_CCR_RX_OCT_CNT_BAD BIT(6) ++#define AN8855_CCR_TX_OCT_CNT_GOOD BIT(5) ++#define AN8855_CCR_TX_OCT_CNT_BAD BIT(4) ++#define AN8855_CCR_RX_OCT_CNT_GOOD_2 BIT(3) ++#define AN8855_CCR_RX_OCT_CNT_BAD_2 BIT(2) ++#define AN8855_CCR_TX_OCT_CNT_GOOD_2 BIT(1) ++#define AN8855_CCR_TX_OCT_CNT_BAD_2 BIT(0) ++#define AN8855_CCR_MIB_ACTIVATE (AN8855_CCR_MIB_ENABLE | \ ++ AN8855_CCR_RX_OCT_CNT_GOOD | \ ++ AN8855_CCR_RX_OCT_CNT_BAD | \ ++ AN8855_CCR_TX_OCT_CNT_GOOD | \ ++ AN8855_CCR_TX_OCT_CNT_BAD | \ ++ AN8855_CCR_RX_OCT_CNT_BAD_2 | \ ++ AN8855_CCR_TX_OCT_CNT_BAD_2) ++#define AN8855_MIB_CLR 0x10213e34 ++#define AN8855_MIB_PORT6_CLR BIT(6) ++#define AN8855_MIB_PORT5_CLR BIT(5) ++#define AN8855_MIB_PORT4_CLR BIT(4) ++#define AN8855_MIB_PORT3_CLR BIT(3) ++#define AN8855_MIB_PORT2_CLR BIT(2) ++#define AN8855_MIB_PORT1_CLR BIT(1) ++#define AN8855_MIB_PORT0_CLR BIT(0) ++ ++/* HSGMII/SGMII Configuration register */ ++/* AN8855_HSGMII_AN_CSR_BASE 0x10220000 */ ++#define AN8855_SGMII_REG_AN0 0x10220000 ++/* AN8855_SGMII_AN_ENABLE BMCR_ANENABLE */ ++/* AN8855_SGMII_AN_RESTART BMCR_ANRESTART */ ++#define AN8855_SGMII_REG_AN_13 0x10220034 ++#define AN8855_SGMII_REMOTE_FAULT_DIS BIT(8) ++#define AN8855_SGMII_IF_MODE GENMASK(5, 0) ++#define AN8855_SGMII_REG_AN_FORCE_CL37 0x10220060 ++#define AN8855_RG_FORCE_AN_DONE BIT(0) ++ ++/* AN8855_HSGMII_CSR_PCS_BASE 0x10220000 */ ++#define AN8855_RG_HSGMII_PCS_CTROL_1 0x10220a00 ++#define AN8855_RG_TBI_10B_MODE BIT(30) ++#define AN8855_RG_AN_SGMII_MODE_FORCE 0x10220a24 ++#define AN8855_RG_FORCE_CUR_SGMII_MODE GENMASK(5, 4) ++#define AN8855_RG_FORCE_CUR_SGMII_SEL BIT(0) ++ ++/* AN8855_MULTI_SGMII_CSR_BASE 0x10224000 */ ++#define AN8855_SGMII_STS_CTRL_0 0x10224018 ++#define AN8855_RG_LINK_MODE_P0 GENMASK(5, 4) ++#define AN8855_RG_LINK_MODE_P0_SPEED_2500 FIELD_PREP_CONST(AN8855_RG_LINK_MODE_P0, 0x3) ++#define AN8855_RG_LINK_MODE_P0_SPEED_1000 FIELD_PREP_CONST(AN8855_RG_LINK_MODE_P0, 0x2) ++#define AN8855_RG_LINK_MODE_P0_SPEED_100 FIELD_PREP_CONST(AN8855_RG_LINK_MODE_P0, 0x1) ++#define AN8855_RG_LINK_MODE_P0_SPEED_10 FIELD_PREP_CONST(AN8855_RG_LINK_MODE_P0, 0x0) ++#define AN8855_RG_FORCE_SPD_MODE_P0 BIT(2) ++#define AN8855_MSG_RX_CTRL_0 0x10224100 ++#define AN8855_MSG_RX_LIK_STS_0 0x10224514 ++#define AN8855_RG_DPX_STS_P3 BIT(24) ++#define AN8855_RG_DPX_STS_P2 BIT(16) ++#define AN8855_RG_EEE1G_STS_P1 BIT(12) ++#define AN8855_RG_DPX_STS_P1 BIT(8) ++#define AN8855_RG_TXFC_STS_P0 BIT(2) ++#define AN8855_RG_RXFC_STS_P0 BIT(1) ++#define AN8855_RG_DPX_STS_P0 BIT(0) ++#define AN8855_MSG_RX_LIK_STS_2 0x1022451c ++#define AN8855_RG_RXFC_AN_BYPASS_P3 BIT(11) ++#define AN8855_RG_RXFC_AN_BYPASS_P2 BIT(10) ++#define AN8855_RG_RXFC_AN_BYPASS_P1 BIT(9) ++#define AN8855_RG_TXFC_AN_BYPASS_P3 BIT(7) ++#define AN8855_RG_TXFC_AN_BYPASS_P2 BIT(6) ++#define AN8855_RG_TXFC_AN_BYPASS_P1 BIT(5) ++#define AN8855_RG_DPX_AN_BYPASS_P3 BIT(3) ++#define AN8855_RG_DPX_AN_BYPASS_P2 BIT(2) ++#define AN8855_RG_DPX_AN_BYPASS_P1 BIT(1) ++#define AN8855_RG_DPX_AN_BYPASS_P0 BIT(0) ++#define AN8855_PHY_RX_FORCE_CTRL_0 0x10224520 ++#define AN8855_RG_FORCE_TXC_SEL BIT(4) ++ ++/* AN8855_XFI_CSR_PCS_BASE 0x10225000 */ ++#define AN8855_RG_USXGMII_AN_CONTROL_0 0x10225bf8 ++ ++/* AN8855_MULTI_PHY_RA_CSR_BASE 0x10226000 */ ++#define AN8855_RG_RATE_ADAPT_CTRL_0 0x10226000 ++#define AN8855_RG_RATE_ADAPT_RX_BYPASS BIT(27) ++#define AN8855_RG_RATE_ADAPT_TX_BYPASS BIT(26) ++#define AN8855_RG_RATE_ADAPT_RX_EN BIT(4) ++#define AN8855_RG_RATE_ADAPT_TX_EN BIT(0) ++#define AN8855_RATE_ADP_P0_CTRL_0 0x10226100 ++#define AN8855_RG_P0_DIS_MII_MODE BIT(31) ++#define AN8855_RG_P0_MII_MODE BIT(28) ++#define AN8855_RG_P0_MII_RA_RX_EN BIT(3) ++#define AN8855_RG_P0_MII_RA_TX_EN BIT(2) ++#define AN8855_RG_P0_MII_RA_RX_MODE BIT(1) ++#define AN8855_RG_P0_MII_RA_TX_MODE BIT(0) ++#define AN8855_MII_RA_AN_ENABLE 0x10226300 ++#define AN8855_RG_P0_RA_AN_EN BIT(0) ++ ++/* AN8855_QP_DIG_CSR_BASE 0x1022a000 */ ++#define AN8855_QP_CK_RST_CTRL_4 0x1022a310 ++#define AN8855_QP_DIG_MODE_CTRL_0 0x1022a324 ++#define AN8855_RG_SGMII_MODE GENMASK(5, 4) ++#define AN8855_RG_SGMII_AN_EN BIT(0) ++#define AN8855_QP_DIG_MODE_CTRL_1 0x1022a330 ++#define AN8855_RG_TPHY_SPEED GENMASK(3, 2) ++ ++/* AN8855_SERDES_WRAPPER_BASE 0x1022c000 */ ++#define AN8855_USGMII_CTRL_0 0x1022c000 ++ ++/* AN8855_QP_PMA_TOP_BASE 0x1022e000 */ ++#define AN8855_PON_RXFEDIG_CTRL_0 0x1022e100 ++#define AN8855_RG_QP_EQ_RX500M_CK_SEL BIT(12) ++#define AN8855_PON_RXFEDIG_CTRL_9 0x1022e124 ++#define AN8855_RG_QP_EQ_LEQOSC_DLYCNT GENMASK(2, 0) ++ ++#define AN8855_SS_LCPLL_PWCTL_SETTING_2 0x1022e208 ++#define AN8855_RG_NCPO_ANA_MSB GENMASK(17, 16) ++#define AN8855_SS_LCPLL_TDC_FLT_2 0x1022e230 ++#define AN8855_RG_LCPLL_NCPO_VALUE GENMASK(30, 0) ++#define AN8855_SS_LCPLL_TDC_FLT_5 0x1022e23c ++#define AN8855_RG_LCPLL_NCPO_CHG BIT(24) ++#define AN8855_SS_LCPLL_TDC_PCW_1 0x1022e248 ++#define AN8855_RG_LCPLL_PON_HRDDS_PCW_NCPO_GPON GENMASK(30, 0) ++#define AN8855_INTF_CTRL_8 0x1022e320 ++#define AN8855_INTF_CTRL_9 0x1022e324 ++#define AN8855_INTF_CTRL_10 0x1022e328 ++#define AN8855_RG_DA_QP_TX_FIR_C2_SEL BIT(29) ++#define AN8855_RG_DA_QP_TX_FIR_C2_FORCE GENMASK(28, 24) ++#define AN8855_RG_DA_QP_TX_FIR_C1_SEL BIT(21) ++#define AN8855_RG_DA_QP_TX_FIR_C1_FORCE GENMASK(20, 16) ++#define AN8855_INTF_CTRL_11 0x1022e32c ++#define AN8855_RG_DA_QP_TX_FIR_C0B_SEL BIT(6) ++#define AN8855_RG_DA_QP_TX_FIR_C0B_FORCE GENMASK(5, 0) ++#define AN8855_PLL_CTRL_0 0x1022e400 ++#define AN8855_RG_PHYA_AUTO_INIT BIT(0) ++#define AN8855_PLL_CTRL_2 0x1022e408 ++#define AN8855_RG_DA_QP_PLL_SDM_IFM_INTF BIT(30) ++#define AN8855_RG_DA_QP_PLL_RICO_SEL_INTF BIT(29) ++#define AN8855_RG_DA_QP_PLL_POSTDIV_EN_INTF BIT(28) ++#define AN8855_RG_DA_QP_PLL_PHY_CK_EN_INTF BIT(27) ++#define AN8855_RG_DA_QP_PLL_PFD_OFFSET_EN_INTRF BIT(26) ++#define AN8855_RG_DA_QP_PLL_PFD_OFFSET_INTF GENMASK(25, 24) ++#define AN8855_RG_DA_QP_PLL_PCK_SEL_INTF BIT(22) ++#define AN8855_RG_DA_QP_PLL_KBAND_PREDIV_INTF GENMASK(21, 20) ++#define AN8855_RG_DA_QP_PLL_IR_INTF GENMASK(19, 16) ++#define AN8855_RG_DA_QP_PLL_ICOIQ_EN_INTF BIT(14) ++#define AN8855_RG_DA_QP_PLL_FBKSEL_INTF GENMASK(13, 12) ++#define AN8855_RG_DA_QP_PLL_BR_INTF GENMASK(10, 8) ++#define AN8855_RG_DA_QP_PLL_BPD_INTF GENMASK(7, 6) ++#define AN8855_RG_DA_QP_PLL_BPA_INTF GENMASK(4, 2) ++#define AN8855_RG_DA_QP_PLL_BC_INTF GENMASK(1, 0) ++#define AN8855_PLL_CTRL_3 0x1022e40c ++#define AN8855_RG_DA_QP_PLL_SSC_PERIOD_INTF GENMASK(31, 16) ++#define AN8855_RG_DA_QP_PLL_SSC_DELTA_INTF GENMASK(15, 0) ++#define AN8855_PLL_CTRL_4 0x1022e410 ++#define AN8855_RG_DA_QP_PLL_SDM_HREN_INTF GENMASK(4, 3) ++#define AN8855_RG_DA_QP_PLL_ICOLP_EN_INTF BIT(2) ++#define AN8855_RG_DA_QP_PLL_SSC_DIR_DLY_INTF GENMASK(1, 0) ++#define AN8855_PLL_CK_CTRL_0 0x1022e414 ++#define AN8855_RG_DA_QP_PLL_TDC_TXCK_SEL_INTF BIT(9) ++#define AN8855_RG_DA_QP_PLL_SDM_DI_EN_INTF BIT(8) ++#define AN8855_RX_DLY_0 0x1022e614 ++#define AN8855_RG_QP_RX_SAOSC_EN_H_DLY GENMASK(13, 8) ++#define AN8855_RG_QP_RX_PI_CAL_EN_H_DLY GENMASK(7, 0) ++#define AN8855_RX_CTRL_2 0x1022e630 ++#define AN8855_RG_QP_RX_EQ_EN_H_DLY GENMASK(28, 16) ++#define AN8855_RX_CTRL_5 0x1022e63c ++#define AN8855_RG_FREDET_CHK_CYCLE GENMASK(29, 10) ++#define AN8855_RX_CTRL_6 0x1022e640 ++#define AN8855_RG_FREDET_GOLDEN_CYCLE GENMASK(19, 0) ++#define AN8855_RX_CTRL_7 0x1022e644 ++#define AN8855_RG_FREDET_TOLERATE_CYCLE GENMASK(19, 0) ++#define AN8855_RX_CTRL_8 0x1022e648 ++#define AN8855_RG_DA_QP_SAOSC_DONE_TIME GENMASK(27, 16) ++#define AN8855_RG_DA_QP_LEQOS_EN_TIME GENMASK(14, 0) ++#define AN8855_RX_CTRL_26 0x1022e690 ++#define AN8855_RG_QP_EQ_RETRAIN_ONLY_EN BIT(26) ++#define AN8855_RG_LINK_NE_EN BIT(24) ++#define AN8855_RG_LINK_ERRO_EN BIT(23) ++#define AN8855_RX_CTRL_42 0x1022e6d0 ++#define AN8855_RG_QP_EQ_EN_DLY GENMASK(12, 0) ++ ++/* AN8855_QP_ANA_CSR_BASE 0x1022f000 */ ++#define AN8855_RG_QP_RX_DAC_EN 0x1022f000 ++#define AN8855_RG_QP_SIGDET_HF GENMASK(17, 16) ++#define AN8855_RG_QP_RXAFE_RESERVE 0x1022f004 ++#define AN8855_RG_QP_CDR_PD_10B_EN BIT(11) ++#define AN8855_RG_QP_CDR_LPF_BOT_LIM 0x1022f008 ++#define AN8855_RG_QP_CDR_LPF_KP_GAIN GENMASK(26, 24) ++#define AN8855_RG_QP_CDR_LPF_KI_GAIN GENMASK(22, 20) ++#define AN8855_RG_QP_CDR_LPF_MJV_LIM 0x1022f00c ++#define AN8855_RG_QP_CDR_LPF_RATIO GENMASK(5, 4) ++#define AN8855_RG_QP_CDR_LPF_SETVALUE 0x1022f014 ++#define AN8855_RG_QP_CDR_PR_BUF_IN_SR GENMASK(31, 29) ++#define AN8855_RG_QP_CDR_PR_BETA_SEL GENMASK(28, 25) ++#define AN8855_RG_QP_CDR_PR_CKREF_DIV1 0x1022f018 ++#define AN8855_RG_QP_CDR_PR_KBAND_DIV GENMASK(26, 24) ++#define AN8855_RG_QP_CDR_PR_DAC_BAND GENMASK(12, 8) ++#define AN8855_RG_QP_CDR_PR_KBAND_DIV_PCIE 0x1022f01c ++#define AN8855_RG_QP_CDR_PR_XFICK_EN BIT(30) ++#define AN8855_RG_QP_CDR_PR_KBAND_PCIE_MODE BIT(6) ++#define AN8855_RG_QP_CDR_PR_KBAND_DIV_PCIE_MASK GENMASK(5, 0) ++#define AN8855_RG_QP_CDR_FORCE_IBANDLPF_R_OFF 0x1022f020 ++#define AN8855_RG_QP_CDR_PHYCK_SEL GENMASK(17, 16) ++#define AN8855_RG_QP_CDR_PHYCK_RSTB BIT(13) ++#define AN8855_RG_QP_CDR_PHYCK_DIV GENMASK(12, 6) ++#define AN8855_RG_QP_TX_MODE 0x1022f028 ++#define AN8855_RG_QP_TX_RESERVE GENMASK(31, 16) ++#define AN8855_RG_QP_TX_MODE_16B_EN BIT(0) ++#define AN8855_RG_QP_PLL_IPLL_DIG_PWR_SEL 0x1022f03c ++#define AN8855_RG_QP_PLL_SDM_ORD 0x1022f040 ++#define AN8855_RG_QP_PLL_SSC_PHASE_INI BIT(4) ++#define AN8855_RG_QP_PLL_SSC_TRI_EN BIT(3) ++ ++/* AN8855_ETHER_SYS_BASE 0x1028c800 */ ++#define AN8855_RG_GPHY_AFE_PWD 0x1028c840 ++#define AN8855_RG_GPHY_SMI_ADDR 0x1028c848 ++ ++#define MIB_DESC(_s, _o, _n) \ ++ { \ ++ .size = (_s), \ ++ .offset = (_o), \ ++ .name = (_n), \ ++ } ++ ++struct an8855_mib_desc { ++ unsigned int size; ++ unsigned int offset; ++ const char *name; ++}; ++ ++struct an8855_fdb { ++ u16 vid; ++ u8 port_mask; ++ u16 aging; ++ u8 mac[6]; ++ bool noarp; ++ u8 live; ++ u8 type; ++ u8 fid; ++ u8 ivl; ++}; ++ ++struct an8855_priv { ++ struct device *dev; ++ struct dsa_switch *ds; ++ struct regmap *regmap; ++ struct gpio_desc *reset_gpio; ++ /* Protect ATU or VLAN table access */ ++ struct mutex reg_mutex; ++ ++ struct phylink_pcs pcs; ++ ++ u8 mirror_rx; ++ u8 mirror_tx; ++ u8 port_isolated_map; ++ ++ bool phy_require_calib; ++}; ++ ++#endif /* __AN8855_H */ +diff --git a/drivers/net/mdio/mdio-an8855.c b/drivers/net/mdio/mdio-an8855.c +new file mode 100644 +index 000000000000..5feba72c021b +--- /dev/null ++++ b/drivers/net/mdio/mdio-an8855.c +@@ -0,0 +1,113 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * MDIO passthrough driver for Airoha AN8855 Switch ++ */ ++ ++#include ++#include ++#include ++#include ++ ++static int an855_phy_restore_page(struct an8855_mfd_priv *priv, ++ int phy) __must_hold(&priv->bus->mdio_lock) ++{ ++ /* Check PHY page only for addr shared with switch */ ++ if (phy != priv->switch_addr) ++ return 0; ++ ++ /* Don't restore page if it's not set to switch page */ ++ if (priv->current_page != FIELD_GET(AN8855_PHY_PAGE, ++ AN8855_PHY_PAGE_EXTENDED_4)) ++ return 0; ++ ++ /* Restore page to 0, PHY might change page right after but that ++ * will be ignored as it won't be a switch page. ++ */ ++ return an8855_mii_set_page(priv, phy, AN8855_PHY_PAGE_STANDARD); ++} ++ ++static int an8855_phy_read(struct mii_bus *bus, int phy, int regnum) ++{ ++ struct an8855_mfd_priv *priv = bus->priv; ++ struct mii_bus *real_bus = priv->bus; ++ int ret; ++ ++ mutex_lock_nested(&real_bus->mdio_lock, MDIO_MUTEX_NESTED); ++ ++ ret = an855_phy_restore_page(priv, phy); ++ if (ret) ++ goto exit; ++ ++ ret = __mdiobus_read(real_bus, phy, regnum); ++exit: ++ mutex_unlock(&real_bus->mdio_lock); ++ ++ return ret; ++} ++ ++static int an8855_phy_write(struct mii_bus *bus, int phy, int regnum, u16 val) ++{ ++ struct an8855_mfd_priv *priv = bus->priv; ++ struct mii_bus *real_bus = priv->bus; ++ int ret; ++ ++ mutex_lock_nested(&real_bus->mdio_lock, MDIO_MUTEX_NESTED); ++ ++ ret = an855_phy_restore_page(priv, phy); ++ if (ret) ++ goto exit; ++ ++ ret = __mdiobus_write(real_bus, phy, regnum, val); ++exit: ++ mutex_unlock(&real_bus->mdio_lock); ++ ++ return ret; ++} ++ ++static int an8855_mdio_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct an8855_mfd_priv *priv; ++ struct mii_bus *bus; ++ int ret; ++ ++ /* Get priv of MFD */ ++ priv = dev_get_drvdata(dev->parent); ++ ++ bus = devm_mdiobus_alloc(dev); ++ if (!bus) ++ return -ENOMEM; ++ ++ bus->priv = priv; ++ bus->name = KBUILD_MODNAME "-mii"; ++ snprintf(bus->id, MII_BUS_ID_SIZE, KBUILD_MODNAME "-%d", ++ priv->switch_addr); ++ bus->parent = dev; ++ bus->read = an8855_phy_read; ++ bus->write = an8855_phy_write; ++ ++ ret = devm_of_mdiobus_register(dev, bus, dev->of_node); ++ if (ret) ++ return dev_err_probe(dev, ret, "failed to register MDIO bus\n"); ++ ++ return ret; ++} ++ ++static const struct of_device_id an8855_mdio_of_match[] = { ++ { .compatible = "airoha,an8855-mdio", }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, an8855_mdio_of_match); ++ ++static struct platform_driver an8855_mdio_driver = { ++ .probe = an8855_mdio_probe, ++ .driver = { ++ .name = "an8855-mdio", ++ .of_match_table = an8855_mdio_of_match, ++ }, ++}; ++module_platform_driver(an8855_mdio_driver); ++ ++MODULE_AUTHOR("Christian Marangi "); ++MODULE_DESCRIPTION("Driver for AN8855 MDIO passthrough"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/net/phy/adm6996.c b/drivers/net/phy/adm6996.c +new file mode 100644 +index 000000000000..d917427419ad +--- /dev/null ++++ b/drivers/net/phy/adm6996.c +@@ -0,0 +1,1241 @@ ++/* ++ * ADM6996 switch driver ++ * ++ * swconfig interface based on ar8216.c ++ * ++ * Copyright (c) 2008 Felix Fietkau ++ * VLAN support Copyright (c) 2010, 2011 Peter Lebbing ++ * Copyright (c) 2013 Hauke Mehrtens ++ * Copyright (c) 2014 Matti Laakso ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License v2 as published by the ++ * Free Software Foundation ++ */ ++ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++/*#define DEBUG 1*/ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include "adm6996.h" ++ ++MODULE_DESCRIPTION("Infineon ADM6996 Switch"); ++MODULE_AUTHOR("Felix Fietkau, Peter Lebbing "); ++MODULE_LICENSE("GPL"); ++ ++static const char * const adm6996_model_name[] = ++{ ++ NULL, ++ "ADM6996FC", ++ "ADM6996M", ++ "ADM6996L" ++}; ++ ++struct adm6996_mib_desc { ++ unsigned int offset; ++ const char *name; ++}; ++ ++struct adm6996_priv { ++ struct switch_dev dev; ++ void *priv; ++ ++ u8 eecs; ++ u8 eesk; ++ u8 eedi; ++ ++ enum adm6996_model model; ++ ++ bool enable_vlan; ++ bool vlan_enabled; /* Current hardware state */ ++ ++#ifdef DEBUG ++ u16 addr; /* Debugging: register address to operate on */ ++#endif ++ ++ u16 pvid[ADM_NUM_PORTS]; /* Primary VLAN ID */ ++ u8 tagged_ports; ++ ++ u16 vlan_id[ADM_NUM_VLANS]; ++ u8 vlan_table[ADM_NUM_VLANS]; /* bitmap, 1 = port is member */ ++ u8 vlan_tagged[ADM_NUM_VLANS]; /* bitmap, 1 = tagged member */ ++ ++ struct mutex mib_lock; ++ char buf[2048]; ++ ++ struct mutex reg_mutex; ++ ++ /* use abstraction for regops, we want to add gpio support in the future */ ++ u16 (*read)(struct adm6996_priv *priv, enum admreg reg); ++ void (*write)(struct adm6996_priv *priv, enum admreg reg, u16 val); ++}; ++ ++#define to_adm(_dev) container_of(_dev, struct adm6996_priv, dev) ++#define phy_to_adm(_phy) ((struct adm6996_priv *) (_phy)->priv) ++ ++#define MIB_DESC(_o, _n) \ ++ { \ ++ .offset = (_o), \ ++ .name = (_n), \ ++ } ++ ++static const struct adm6996_mib_desc adm6996_mibs[] = { ++ MIB_DESC(ADM_CL0, "RxPacket"), ++ MIB_DESC(ADM_CL6, "RxByte"), ++ MIB_DESC(ADM_CL12, "TxPacket"), ++ MIB_DESC(ADM_CL18, "TxByte"), ++ MIB_DESC(ADM_CL24, "Collision"), ++ MIB_DESC(ADM_CL30, "Error"), ++}; ++ ++#define ADM6996_MIB_RXB_ID 1 ++#define ADM6996_MIB_TXB_ID 3 ++ ++static inline u16 ++r16(struct adm6996_priv *priv, enum admreg reg) ++{ ++ return priv->read(priv, reg); ++} ++ ++static inline void ++w16(struct adm6996_priv *priv, enum admreg reg, u16 val) ++{ ++ priv->write(priv, reg, val); ++} ++ ++/* Minimum timing constants */ ++#define EECK_EDGE_TIME 3 /* 3us - max(adm 2.5us, 93c 1us) */ ++#define EEDI_SETUP_TIME 1 /* 1us - max(adm 10ns, 93c 400ns) */ ++#define EECS_SETUP_TIME 1 /* 1us - max(adm no, 93c 200ns) */ ++ ++static void adm6996_gpio_write(struct adm6996_priv *priv, int cs, char *buf, unsigned int bits) ++{ ++ int i, len = (bits + 7) / 8; ++ u8 mask; ++ ++ gpio_set_value(priv->eecs, cs); ++ udelay(EECK_EDGE_TIME); ++ ++ /* Byte assemble from MSB to LSB */ ++ for (i = 0; i < len; i++) { ++ /* Bit bang from MSB to LSB */ ++ for (mask = 0x80; mask && bits > 0; mask >>= 1, bits --) { ++ /* Clock low */ ++ gpio_set_value(priv->eesk, 0); ++ udelay(EECK_EDGE_TIME); ++ ++ /* Output on rising edge */ ++ gpio_set_value(priv->eedi, (mask & buf[i])); ++ udelay(EEDI_SETUP_TIME); ++ ++ /* Clock high */ ++ gpio_set_value(priv->eesk, 1); ++ udelay(EECK_EDGE_TIME); ++ } ++ } ++ ++ /* Clock low */ ++ gpio_set_value(priv->eesk, 0); ++ udelay(EECK_EDGE_TIME); ++ ++ if (cs) ++ gpio_set_value(priv->eecs, 0); ++} ++ ++static void adm6996_gpio_read(struct adm6996_priv *priv, int cs, char *buf, unsigned int bits) ++{ ++ int i, len = (bits + 7) / 8; ++ u8 mask; ++ ++ gpio_set_value(priv->eecs, cs); ++ udelay(EECK_EDGE_TIME); ++ ++ /* Byte assemble from MSB to LSB */ ++ for (i = 0; i < len; i++) { ++ u8 byte; ++ ++ /* Bit bang from MSB to LSB */ ++ for (mask = 0x80, byte = 0; mask && bits > 0; mask >>= 1, bits --) { ++ u8 gp; ++ ++ /* Clock low */ ++ gpio_set_value(priv->eesk, 0); ++ udelay(EECK_EDGE_TIME); ++ ++ /* Input on rising edge */ ++ gp = gpio_get_value(priv->eedi); ++ if (gp) ++ byte |= mask; ++ ++ /* Clock high */ ++ gpio_set_value(priv->eesk, 1); ++ udelay(EECK_EDGE_TIME); ++ } ++ ++ *buf++ = byte; ++ } ++ ++ /* Clock low */ ++ gpio_set_value(priv->eesk, 0); ++ udelay(EECK_EDGE_TIME); ++ ++ if (cs) ++ gpio_set_value(priv->eecs, 0); ++} ++ ++/* Advance clock(s) */ ++static void adm6996_gpio_adclk(struct adm6996_priv *priv, int clocks) ++{ ++ int i; ++ for (i = 0; i < clocks; i++) { ++ /* Clock high */ ++ gpio_set_value(priv->eesk, 1); ++ udelay(EECK_EDGE_TIME); ++ ++ /* Clock low */ ++ gpio_set_value(priv->eesk, 0); ++ udelay(EECK_EDGE_TIME); ++ } ++} ++ ++static u16 ++adm6996_read_gpio_reg(struct adm6996_priv *priv, enum admreg reg) ++{ ++ /* cmd: 01 10 T DD R RRRRRR */ ++ u8 bits[6] = { ++ 0xFF, 0xFF, 0xFF, 0xFF, ++ (0x06 << 4) | ((0 & 0x01) << 3 | (reg&64)>>6), ++ ((reg&63)<<2) ++ }; ++ ++ u8 rbits[4]; ++ ++ /* Enable GPIO outputs with all pins to 0 */ ++ gpio_direction_output(priv->eecs, 0); ++ gpio_direction_output(priv->eesk, 0); ++ gpio_direction_output(priv->eedi, 0); ++ ++ adm6996_gpio_write(priv, 0, bits, 46); ++ gpio_direction_input(priv->eedi); ++ adm6996_gpio_adclk(priv, 2); ++ adm6996_gpio_read(priv, 0, rbits, 32); ++ ++ /* Extra clock(s) required per datasheet */ ++ adm6996_gpio_adclk(priv, 2); ++ ++ /* Disable GPIO outputs */ ++ gpio_direction_input(priv->eecs); ++ gpio_direction_input(priv->eesk); ++ ++ /* EEPROM has 16-bit registers, but pumps out two registers in one request */ ++ return (reg & 0x01 ? (rbits[0]<<8) | rbits[1] : (rbits[2]<<8) | (rbits[3])); ++} ++ ++/* Write chip configuration register */ ++/* Follow 93c66 timing and chip's min EEPROM timing requirement */ ++static void ++adm6996_write_gpio_reg(struct adm6996_priv *priv, enum admreg reg, u16 val) ++{ ++ /* cmd(27bits): sb(1) + opc(01) + addr(bbbbbbbb) + data(bbbbbbbbbbbbbbbb) */ ++ u8 bits[4] = { ++ (0x05 << 5) | (reg >> 3), ++ (reg << 5) | (u8)(val >> 11), ++ (u8)(val >> 3), ++ (u8)(val << 5) ++ }; ++ ++ /* Enable GPIO outputs with all pins to 0 */ ++ gpio_direction_output(priv->eecs, 0); ++ gpio_direction_output(priv->eesk, 0); ++ gpio_direction_output(priv->eedi, 0); ++ ++ /* Write cmd. Total 27 bits */ ++ adm6996_gpio_write(priv, 1, bits, 27); ++ ++ /* Extra clock(s) required per datasheet */ ++ adm6996_gpio_adclk(priv, 2); ++ ++ /* Disable GPIO outputs */ ++ gpio_direction_input(priv->eecs); ++ gpio_direction_input(priv->eesk); ++ gpio_direction_input(priv->eedi); ++} ++ ++static u16 ++adm6996_read_mii_reg(struct adm6996_priv *priv, enum admreg reg) ++{ ++ struct phy_device *phydev = priv->priv; ++ struct mii_bus *bus = phydev->mdio.bus; ++ ++ return bus->read(bus, PHYADDR(reg)); ++} ++ ++static void ++adm6996_write_mii_reg(struct adm6996_priv *priv, enum admreg reg, u16 val) ++{ ++ struct phy_device *phydev = priv->priv; ++ struct mii_bus *bus = phydev->mdio.bus; ++ ++ bus->write(bus, PHYADDR(reg), val); ++} ++ ++static int ++adm6996_set_enable_vlan(struct switch_dev *dev, const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct adm6996_priv *priv = to_adm(dev); ++ ++ if (val->value.i > 1) ++ return -EINVAL; ++ ++ priv->enable_vlan = val->value.i; ++ ++ return 0; ++}; ++ ++static int ++adm6996_get_enable_vlan(struct switch_dev *dev, const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct adm6996_priv *priv = to_adm(dev); ++ ++ val->value.i = priv->enable_vlan; ++ ++ return 0; ++}; ++ ++#ifdef DEBUG ++ ++static int ++adm6996_set_addr(struct switch_dev *dev, const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct adm6996_priv *priv = to_adm(dev); ++ ++ if (val->value.i > 1023) ++ return -EINVAL; ++ ++ priv->addr = val->value.i; ++ ++ return 0; ++}; ++ ++static int ++adm6996_get_addr(struct switch_dev *dev, const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct adm6996_priv *priv = to_adm(dev); ++ ++ val->value.i = priv->addr; ++ ++ return 0; ++}; ++ ++static int ++adm6996_set_data(struct switch_dev *dev, const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct adm6996_priv *priv = to_adm(dev); ++ ++ if (val->value.i > 65535) ++ return -EINVAL; ++ ++ w16(priv, priv->addr, val->value.i); ++ ++ return 0; ++}; ++ ++static int ++adm6996_get_data(struct switch_dev *dev, const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct adm6996_priv *priv = to_adm(dev); ++ ++ val->value.i = r16(priv, priv->addr); ++ ++ return 0; ++}; ++ ++#endif /* def DEBUG */ ++ ++static int ++adm6996_set_pvid(struct switch_dev *dev, int port, int vlan) ++{ ++ struct adm6996_priv *priv = to_adm(dev); ++ ++ pr_devel("set_pvid port %d vlan %d\n", port, vlan); ++ ++ if (vlan > ADM_VLAN_MAX_ID) ++ return -EINVAL; ++ ++ priv->pvid[port] = vlan; ++ ++ return 0; ++} ++ ++static int ++adm6996_get_pvid(struct switch_dev *dev, int port, int *vlan) ++{ ++ struct adm6996_priv *priv = to_adm(dev); ++ ++ pr_devel("get_pvid port %d\n", port); ++ *vlan = priv->pvid[port]; ++ ++ return 0; ++} ++ ++static int ++adm6996_set_vid(struct switch_dev *dev, const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct adm6996_priv *priv = to_adm(dev); ++ ++ pr_devel("set_vid port %d vid %d\n", val->port_vlan, val->value.i); ++ ++ if (val->value.i > ADM_VLAN_MAX_ID) ++ return -EINVAL; ++ ++ priv->vlan_id[val->port_vlan] = val->value.i; ++ ++ return 0; ++}; ++ ++static int ++adm6996_get_vid(struct switch_dev *dev, const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct adm6996_priv *priv = to_adm(dev); ++ ++ pr_devel("get_vid port %d\n", val->port_vlan); ++ ++ val->value.i = priv->vlan_id[val->port_vlan]; ++ ++ return 0; ++}; ++ ++static int ++adm6996_get_ports(struct switch_dev *dev, struct switch_val *val) ++{ ++ struct adm6996_priv *priv = to_adm(dev); ++ u8 ports = priv->vlan_table[val->port_vlan]; ++ u8 tagged = priv->vlan_tagged[val->port_vlan]; ++ int i; ++ ++ pr_devel("get_ports port_vlan %d\n", val->port_vlan); ++ ++ val->len = 0; ++ ++ for (i = 0; i < ADM_NUM_PORTS; i++) { ++ struct switch_port *p; ++ ++ if (!(ports & (1 << i))) ++ continue; ++ ++ p = &val->value.ports[val->len++]; ++ p->id = i; ++ if (tagged & (1 << i)) ++ p->flags = (1 << SWITCH_PORT_FLAG_TAGGED); ++ else ++ p->flags = 0; ++ } ++ ++ return 0; ++}; ++ ++static int ++adm6996_set_ports(struct switch_dev *dev, struct switch_val *val) ++{ ++ struct adm6996_priv *priv = to_adm(dev); ++ u8 *ports = &priv->vlan_table[val->port_vlan]; ++ u8 *tagged = &priv->vlan_tagged[val->port_vlan]; ++ int i; ++ ++ pr_devel("set_ports port_vlan %d ports", val->port_vlan); ++ ++ *ports = 0; ++ *tagged = 0; ++ ++ for (i = 0; i < val->len; i++) { ++ struct switch_port *p = &val->value.ports[i]; ++ ++#ifdef DEBUG ++ pr_cont(" %d%s", p->id, ++ ((p->flags & (1 << SWITCH_PORT_FLAG_TAGGED)) ? "T" : ++ "")); ++#endif ++ ++ if (p->flags & (1 << SWITCH_PORT_FLAG_TAGGED)) { ++ *tagged |= (1 << p->id); ++ priv->tagged_ports |= (1 << p->id); ++ } ++ ++ *ports |= (1 << p->id); ++ } ++ ++#ifdef DEBUG ++ pr_cont("\n"); ++#endif ++ ++ return 0; ++}; ++ ++/* ++ * Precondition: reg_mutex must be held ++ */ ++static void ++adm6996_enable_vlan(struct adm6996_priv *priv) ++{ ++ u16 reg; ++ ++ reg = r16(priv, ADM_OTBE_P2_PVID); ++ reg &= ~(ADM_OTBE_MASK); ++ w16(priv, ADM_OTBE_P2_PVID, reg); ++ reg = r16(priv, ADM_IFNTE); ++ reg &= ~(ADM_IFNTE_MASK); ++ w16(priv, ADM_IFNTE, reg); ++ reg = r16(priv, ADM_VID_CHECK); ++ reg |= ADM_VID_CHECK_MASK; ++ w16(priv, ADM_VID_CHECK, reg); ++ reg = r16(priv, ADM_SYSC0); ++ reg |= ADM_NTTE; ++ reg &= ~(ADM_RVID1); ++ w16(priv, ADM_SYSC0, reg); ++ reg = r16(priv, ADM_SYSC3); ++ reg |= ADM_TBV; ++ w16(priv, ADM_SYSC3, reg); ++} ++ ++static void ++adm6996_enable_vlan_6996l(struct adm6996_priv *priv) ++{ ++ u16 reg; ++ ++ reg = r16(priv, ADM_SYSC3); ++ reg |= ADM_TBV; ++ reg |= ADM_MAC_CLONE; ++ w16(priv, ADM_SYSC3, reg); ++} ++ ++/* ++ * Disable VLANs ++ * ++ * Sets VLAN mapping for port-based VLAN with all ports connected to ++ * eachother (this is also the power-on default). ++ * ++ * Precondition: reg_mutex must be held ++ */ ++static void ++adm6996_disable_vlan(struct adm6996_priv *priv) ++{ ++ u16 reg; ++ int i; ++ ++ for (i = 0; i < ADM_NUM_VLANS; i++) { ++ reg = ADM_VLAN_FILT_MEMBER_MASK; ++ w16(priv, ADM_VLAN_FILT_L(i), reg); ++ reg = ADM_VLAN_FILT_VALID | ADM_VLAN_FILT_VID(1); ++ w16(priv, ADM_VLAN_FILT_H(i), reg); ++ } ++ ++ reg = r16(priv, ADM_OTBE_P2_PVID); ++ reg |= ADM_OTBE_MASK; ++ w16(priv, ADM_OTBE_P2_PVID, reg); ++ reg = r16(priv, ADM_IFNTE); ++ reg |= ADM_IFNTE_MASK; ++ w16(priv, ADM_IFNTE, reg); ++ reg = r16(priv, ADM_VID_CHECK); ++ reg &= ~(ADM_VID_CHECK_MASK); ++ w16(priv, ADM_VID_CHECK, reg); ++ reg = r16(priv, ADM_SYSC0); ++ reg &= ~(ADM_NTTE); ++ reg |= ADM_RVID1; ++ w16(priv, ADM_SYSC0, reg); ++ reg = r16(priv, ADM_SYSC3); ++ reg &= ~(ADM_TBV); ++ w16(priv, ADM_SYSC3, reg); ++} ++ ++/* ++ * Disable VLANs ++ * ++ * Sets VLAN mapping for port-based VLAN with all ports connected to ++ * eachother (this is also the power-on default). ++ * ++ * Precondition: reg_mutex must be held ++ */ ++static void ++adm6996_disable_vlan_6996l(struct adm6996_priv *priv) ++{ ++ u16 reg; ++ int i; ++ ++ for (i = 0; i < ADM_NUM_VLANS; i++) { ++ w16(priv, ADM_VLAN_MAP(i), 0); ++ } ++ ++ reg = r16(priv, ADM_SYSC3); ++ reg &= ~(ADM_TBV); ++ reg &= ~(ADM_MAC_CLONE); ++ w16(priv, ADM_SYSC3, reg); ++} ++ ++/* ++ * Precondition: reg_mutex must be held ++ */ ++static void ++adm6996_apply_port_pvids(struct adm6996_priv *priv) ++{ ++ u16 reg; ++ int i; ++ ++ for (i = 0; i < ADM_NUM_PORTS; i++) { ++ reg = r16(priv, adm_portcfg[i]); ++ reg &= ~(ADM_PORTCFG_PVID_MASK); ++ reg |= ADM_PORTCFG_PVID(priv->pvid[i]); ++ if (priv->model == ADM6996L) { ++ if (priv->tagged_ports & (1 << i)) ++ reg |= (1 << 4); ++ else ++ reg &= ~(1 << 4); ++ } ++ w16(priv, adm_portcfg[i], reg); ++ } ++ ++ w16(priv, ADM_P0_PVID, ADM_P0_PVID_VAL(priv->pvid[0])); ++ w16(priv, ADM_P1_PVID, ADM_P1_PVID_VAL(priv->pvid[1])); ++ reg = r16(priv, ADM_OTBE_P2_PVID); ++ reg &= ~(ADM_P2_PVID_MASK); ++ reg |= ADM_P2_PVID_VAL(priv->pvid[2]); ++ w16(priv, ADM_OTBE_P2_PVID, reg); ++ reg = ADM_P3_PVID_VAL(priv->pvid[3]); ++ reg |= ADM_P4_PVID_VAL(priv->pvid[4]); ++ w16(priv, ADM_P3_P4_PVID, reg); ++ reg = r16(priv, ADM_P5_PVID); ++ reg &= ~(ADM_P2_PVID_MASK); ++ reg |= ADM_P5_PVID_VAL(priv->pvid[5]); ++ w16(priv, ADM_P5_PVID, reg); ++} ++ ++/* ++ * Precondition: reg_mutex must be held ++ */ ++static void ++adm6996_apply_vlan_filters(struct adm6996_priv *priv) ++{ ++ u8 ports, tagged; ++ u16 vid, reg; ++ int i; ++ ++ for (i = 0; i < ADM_NUM_VLANS; i++) { ++ vid = priv->vlan_id[i]; ++ ports = priv->vlan_table[i]; ++ tagged = priv->vlan_tagged[i]; ++ ++ if (ports == 0) { ++ /* Disable VLAN entry */ ++ w16(priv, ADM_VLAN_FILT_H(i), 0); ++ w16(priv, ADM_VLAN_FILT_L(i), 0); ++ continue; ++ } ++ ++ reg = ADM_VLAN_FILT_MEMBER(ports); ++ reg |= ADM_VLAN_FILT_TAGGED(tagged); ++ w16(priv, ADM_VLAN_FILT_L(i), reg); ++ reg = ADM_VLAN_FILT_VALID | ADM_VLAN_FILT_VID(vid); ++ w16(priv, ADM_VLAN_FILT_H(i), reg); ++ } ++} ++ ++static void ++adm6996_apply_vlan_filters_6996l(struct adm6996_priv *priv) ++{ ++ u8 ports; ++ u16 reg; ++ int i; ++ ++ for (i = 0; i < ADM_NUM_VLANS; i++) { ++ ports = priv->vlan_table[i]; ++ ++ if (ports == 0) { ++ /* Disable VLAN entry */ ++ w16(priv, ADM_VLAN_MAP(i), 0); ++ continue; ++ } else { ++ reg = ADM_VLAN_FILT(ports); ++ w16(priv, ADM_VLAN_MAP(i), reg); ++ } ++ } ++} ++ ++static int ++adm6996_hw_apply(struct switch_dev *dev) ++{ ++ struct adm6996_priv *priv = to_adm(dev); ++ ++ pr_devel("hw_apply\n"); ++ ++ mutex_lock(&priv->reg_mutex); ++ ++ if (!priv->enable_vlan) { ++ if (priv->vlan_enabled) { ++ if (priv->model == ADM6996L) ++ adm6996_disable_vlan_6996l(priv); ++ else ++ adm6996_disable_vlan(priv); ++ priv->vlan_enabled = 0; ++ } ++ goto out; ++ } ++ ++ if (!priv->vlan_enabled) { ++ if (priv->model == ADM6996L) ++ adm6996_enable_vlan_6996l(priv); ++ else ++ adm6996_enable_vlan(priv); ++ priv->vlan_enabled = 1; ++ } ++ ++ adm6996_apply_port_pvids(priv); ++ if (priv->model == ADM6996L) ++ adm6996_apply_vlan_filters_6996l(priv); ++ else ++ adm6996_apply_vlan_filters(priv); ++ ++out: ++ mutex_unlock(&priv->reg_mutex); ++ ++ return 0; ++} ++ ++/* ++ * Reset the switch ++ * ++ * The ADM6996 can't do a software-initiated reset, so we just initialise the ++ * registers we support in this driver. ++ * ++ * Precondition: reg_mutex must be held ++ */ ++static void ++adm6996_perform_reset (struct adm6996_priv *priv) ++{ ++ int i; ++ ++ /* initialize port and vlan settings */ ++ for (i = 0; i < ADM_NUM_PORTS - 1; i++) { ++ w16(priv, adm_portcfg[i], ADM_PORTCFG_INIT | ++ ADM_PORTCFG_PVID(0)); ++ } ++ w16(priv, adm_portcfg[5], ADM_PORTCFG_CPU); ++ ++ if (priv->model == ADM6996M || priv->model == ADM6996FC) { ++ /* reset all PHY ports */ ++ for (i = 0; i < ADM_PHY_PORTS; i++) { ++ w16(priv, ADM_PHY_PORT(i), ADM_PHYCFG_INIT); ++ } ++ } ++ ++ priv->enable_vlan = 0; ++ priv->vlan_enabled = 0; ++ ++ for (i = 0; i < ADM_NUM_PORTS; i++) { ++ priv->pvid[i] = 0; ++ } ++ ++ for (i = 0; i < ADM_NUM_VLANS; i++) { ++ priv->vlan_id[i] = i; ++ priv->vlan_table[i] = 0; ++ priv->vlan_tagged[i] = 0; ++ } ++ ++ if (priv->model == ADM6996M) { ++ /* Clear VLAN priority map so prio's are unused */ ++ w16 (priv, ADM_VLAN_PRIOMAP, 0); ++ ++ adm6996_disable_vlan(priv); ++ adm6996_apply_port_pvids(priv); ++ } else if (priv->model == ADM6996L) { ++ /* Clear VLAN priority map so prio's are unused */ ++ w16 (priv, ADM_VLAN_PRIOMAP, 0); ++ ++ adm6996_disable_vlan_6996l(priv); ++ adm6996_apply_port_pvids(priv); ++ } ++} ++ ++static int ++adm6996_reset_switch(struct switch_dev *dev) ++{ ++ struct adm6996_priv *priv = to_adm(dev); ++ ++ pr_devel("reset\n"); ++ ++ mutex_lock(&priv->reg_mutex); ++ adm6996_perform_reset (priv); ++ mutex_unlock(&priv->reg_mutex); ++ return 0; ++} ++ ++static int ++adm6996_get_port_link(struct switch_dev *dev, int port, ++ struct switch_port_link *link) ++{ ++ struct adm6996_priv *priv = to_adm(dev); ++ ++ u16 reg = 0; ++ ++ if (port >= ADM_NUM_PORTS) ++ return -EINVAL; ++ ++ switch (port) { ++ case 0: ++ reg = r16(priv, ADM_PS0); ++ break; ++ case 1: ++ reg = r16(priv, ADM_PS0); ++ reg = reg >> 8; ++ break; ++ case 2: ++ reg = r16(priv, ADM_PS1); ++ break; ++ case 3: ++ reg = r16(priv, ADM_PS1); ++ reg = reg >> 8; ++ break; ++ case 4: ++ reg = r16(priv, ADM_PS1); ++ reg = reg >> 12; ++ break; ++ case 5: ++ reg = r16(priv, ADM_PS2); ++ /* Bits 0, 1, 3 and 4. */ ++ reg = (reg & 3) | ((reg & 24) >> 1); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ link->link = reg & ADM_PS_LS; ++ if (!link->link) ++ return 0; ++ link->aneg = true; ++ link->duplex = reg & ADM_PS_DS; ++ link->tx_flow = reg & ADM_PS_FCS; ++ link->rx_flow = reg & ADM_PS_FCS; ++ if (reg & ADM_PS_SS) ++ link->speed = SWITCH_PORT_SPEED_100; ++ else ++ link->speed = SWITCH_PORT_SPEED_10; ++ ++ return 0; ++} ++ ++static int ++adm6996_sw_get_port_mib(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct adm6996_priv *priv = to_adm(dev); ++ int port; ++ char *buf = priv->buf; ++ int i, len = 0; ++ u32 reg = 0; ++ ++ port = val->port_vlan; ++ if (port >= ADM_NUM_PORTS) ++ return -EINVAL; ++ ++ mutex_lock(&priv->mib_lock); ++ ++ len += snprintf(buf + len, sizeof(priv->buf) - len, ++ "Port %d MIB counters\n", ++ port); ++ ++ for (i = 0; i < ARRAY_SIZE(adm6996_mibs); i++) { ++ reg = r16(priv, adm6996_mibs[i].offset + ADM_OFFSET_PORT(port)); ++ reg += r16(priv, adm6996_mibs[i].offset + ADM_OFFSET_PORT(port) + 1) << 16; ++ len += snprintf(buf + len, sizeof(priv->buf) - len, ++ "%-12s: %u\n", ++ adm6996_mibs[i].name, ++ reg); ++ } ++ ++ mutex_unlock(&priv->mib_lock); ++ ++ val->value.s = buf; ++ val->len = len; ++ ++ return 0; ++} ++ ++static int ++adm6996_get_port_stats(struct switch_dev *dev, int port, ++ struct switch_port_stats *stats) ++{ ++ struct adm6996_priv *priv = to_adm(dev); ++ int id; ++ u32 reg = 0; ++ ++ if (port >= ADM_NUM_PORTS) ++ return -EINVAL; ++ ++ mutex_lock(&priv->mib_lock); ++ ++ id = ADM6996_MIB_TXB_ID; ++ reg = r16(priv, adm6996_mibs[id].offset + ADM_OFFSET_PORT(port)); ++ reg += r16(priv, adm6996_mibs[id].offset + ADM_OFFSET_PORT(port) + 1) << 16; ++ stats->tx_bytes = reg; ++ ++ id = ADM6996_MIB_RXB_ID; ++ reg = r16(priv, adm6996_mibs[id].offset + ADM_OFFSET_PORT(port)); ++ reg += r16(priv, adm6996_mibs[id].offset + ADM_OFFSET_PORT(port) + 1) << 16; ++ stats->rx_bytes = reg; ++ ++ mutex_unlock(&priv->mib_lock); ++ ++ return 0; ++} ++ ++static struct switch_attr adm6996_globals[] = { ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "enable_vlan", ++ .description = "Enable VLANs", ++ .set = adm6996_set_enable_vlan, ++ .get = adm6996_get_enable_vlan, ++ }, ++#ifdef DEBUG ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "addr", ++ .description = ++ "Direct register access: set register address (0 - 1023)", ++ .set = adm6996_set_addr, ++ .get = adm6996_get_addr, ++ }, ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "data", ++ .description = ++ "Direct register access: read/write to register (0 - 65535)", ++ .set = adm6996_set_data, ++ .get = adm6996_get_data, ++ }, ++#endif /* def DEBUG */ ++}; ++ ++static struct switch_attr adm6996_port[] = { ++ { ++ .type = SWITCH_TYPE_STRING, ++ .name = "mib", ++ .description = "Get port's MIB counters", ++ .set = NULL, ++ .get = adm6996_sw_get_port_mib, ++ }, ++}; ++ ++static struct switch_attr adm6996_vlan[] = { ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "vid", ++ .description = "VLAN ID", ++ .set = adm6996_set_vid, ++ .get = adm6996_get_vid, ++ }, ++}; ++ ++static struct switch_dev_ops adm6996_ops = { ++ .attr_global = { ++ .attr = adm6996_globals, ++ .n_attr = ARRAY_SIZE(adm6996_globals), ++ }, ++ .attr_port = { ++ .attr = adm6996_port, ++ .n_attr = ARRAY_SIZE(adm6996_port), ++ }, ++ .attr_vlan = { ++ .attr = adm6996_vlan, ++ .n_attr = ARRAY_SIZE(adm6996_vlan), ++ }, ++ .get_port_pvid = adm6996_get_pvid, ++ .set_port_pvid = adm6996_set_pvid, ++ .get_vlan_ports = adm6996_get_ports, ++ .set_vlan_ports = adm6996_set_ports, ++ .apply_config = adm6996_hw_apply, ++ .reset_switch = adm6996_reset_switch, ++ .get_port_link = adm6996_get_port_link, ++ .get_port_stats = adm6996_get_port_stats, ++}; ++ ++static int adm6996_switch_init(struct adm6996_priv *priv, const char *alias, struct net_device *netdev) ++{ ++ struct switch_dev *swdev; ++ u16 test, old; ++ ++ if (!priv->model) { ++ /* Detect type of chip */ ++ old = r16(priv, ADM_VID_CHECK); ++ test = old ^ (1 << 12); ++ w16(priv, ADM_VID_CHECK, test); ++ test ^= r16(priv, ADM_VID_CHECK); ++ if (test & (1 << 12)) { ++ /* ++ * Bit 12 of this register is read-only. ++ * This is the FC model. ++ */ ++ priv->model = ADM6996FC; ++ } else { ++ /* Bit 12 is read-write. This is the M model. */ ++ priv->model = ADM6996M; ++ w16(priv, ADM_VID_CHECK, old); ++ } ++ } ++ ++ swdev = &priv->dev; ++ swdev->name = (adm6996_model_name[priv->model]); ++ swdev->cpu_port = ADM_CPU_PORT; ++ swdev->ports = ADM_NUM_PORTS; ++ swdev->vlans = ADM_NUM_VLANS; ++ swdev->ops = &adm6996_ops; ++ swdev->alias = alias; ++ ++ /* The ADM6996L connected through GPIOs does not support any switch ++ status calls */ ++ if (priv->model == ADM6996L) { ++ adm6996_ops.attr_port.n_attr = 0; ++ adm6996_ops.get_port_link = NULL; ++ } ++ ++ pr_info ("%s: %s model PHY found.\n", alias, swdev->name); ++ ++ mutex_lock(&priv->reg_mutex); ++ adm6996_perform_reset (priv); ++ mutex_unlock(&priv->reg_mutex); ++ ++ if (priv->model == ADM6996M || priv->model == ADM6996L) { ++ return register_switch(swdev, netdev); ++ } ++ ++ return -ENODEV; ++} ++ ++static int adm6996_config_init(struct phy_device *pdev) ++{ ++ struct adm6996_priv *priv; ++ int ret; ++ ++ linkmode_zero(pdev->supported); ++ linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, pdev->supported); ++ linkmode_copy(pdev->advertising, pdev->supported); ++ ++ if (pdev->mdio.addr != 0) { ++ pr_info ("%s: PHY overlaps ADM6996, providing fixed PHY 0x%x.\n" ++ , pdev->attached_dev->name, pdev->mdio.addr); ++ return 0; ++ } ++ ++ priv = devm_kzalloc(&pdev->mdio.dev, sizeof(struct adm6996_priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ mutex_init(&priv->reg_mutex); ++ mutex_init(&priv->mib_lock); ++ priv->priv = pdev; ++ priv->read = adm6996_read_mii_reg; ++ priv->write = adm6996_write_mii_reg; ++ ++ ret = adm6996_switch_init(priv, pdev->attached_dev->name, pdev->attached_dev); ++ if (ret < 0) ++ return ret; ++ ++ pdev->priv = priv; ++ ++ return 0; ++} ++ ++/* ++ * Warning: phydev->priv is NULL if phydev->mdio.addr != 0 ++ */ ++static int adm6996_read_status(struct phy_device *phydev) ++{ ++ phydev->speed = SPEED_100; ++ phydev->duplex = DUPLEX_FULL; ++ phydev->link = 1; ++ ++ phydev->state = PHY_RUNNING; ++ netif_carrier_on(phydev->attached_dev); ++ phydev->adjust_link(phydev->attached_dev); ++ ++ return 0; ++} ++ ++/* ++ * Warning: phydev->priv is NULL if phydev->mdio.addr != 0 ++ */ ++static int adm6996_config_aneg(struct phy_device *phydev) ++{ ++ return 0; ++} ++ ++static int adm6996_fixup(struct phy_device *dev) ++{ ++ struct mii_bus *bus = dev->mdio.bus; ++ u16 reg; ++ ++ /* Our custom registers are at PHY addresses 0-10. Claim those. */ ++ if (dev->mdio.addr > 10) ++ return 0; ++ ++ /* look for the switch on the bus */ ++ reg = bus->read(bus, PHYADDR(ADM_SIG0)) & ADM_SIG0_MASK; ++ if (reg != ADM_SIG0_VAL) ++ return 0; ++ ++ reg = bus->read(bus, PHYADDR(ADM_SIG1)) & ADM_SIG1_MASK; ++ if (reg != ADM_SIG1_VAL) ++ return 0; ++ ++ dev->phy_id = (ADM_SIG0_VAL << 16) | ADM_SIG1_VAL; ++ ++ return 0; ++} ++ ++static int adm6996_probe(struct phy_device *pdev) ++{ ++ return 0; ++} ++ ++static void adm6996_remove(struct phy_device *pdev) ++{ ++ struct adm6996_priv *priv = phy_to_adm(pdev); ++ ++ if (priv && (priv->model == ADM6996M || priv->model == ADM6996L)) ++ unregister_switch(&priv->dev); ++} ++ ++static int adm6996_soft_reset(struct phy_device *phydev) ++{ ++ /* we don't need an extra reset */ ++ return 0; ++} ++ ++static struct phy_driver adm6996_phy_driver = { ++ .name = "Infineon ADM6996", ++ .phy_id = (ADM_SIG0_VAL << 16) | ADM_SIG1_VAL, ++ .phy_id_mask = 0xffffffff, ++ .features = PHY_BASIC_FEATURES, ++ .probe = adm6996_probe, ++ .remove = adm6996_remove, ++ .config_init = &adm6996_config_init, ++ .config_aneg = &adm6996_config_aneg, ++ .read_status = &adm6996_read_status, ++ .soft_reset = adm6996_soft_reset, ++}; ++ ++static int adm6996_gpio_probe(struct platform_device *pdev) ++{ ++ struct adm6996_gpio_platform_data *pdata = pdev->dev.platform_data; ++ struct adm6996_priv *priv; ++ int ret; ++ ++ if (!pdata) ++ return -EINVAL; ++ ++ priv = devm_kzalloc(&pdev->dev, sizeof(struct adm6996_priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ mutex_init(&priv->reg_mutex); ++ mutex_init(&priv->mib_lock); ++ ++ priv->eecs = pdata->eecs; ++ priv->eedi = pdata->eedi; ++ priv->eesk = pdata->eesk; ++ ++ priv->model = pdata->model; ++ priv->read = adm6996_read_gpio_reg; ++ priv->write = adm6996_write_gpio_reg; ++ ++ ret = devm_gpio_request(&pdev->dev, priv->eecs, "adm_eecs"); ++ if (ret) ++ return ret; ++ ret = devm_gpio_request(&pdev->dev, priv->eedi, "adm_eedi"); ++ if (ret) ++ return ret; ++ ret = devm_gpio_request(&pdev->dev, priv->eesk, "adm_eesk"); ++ if (ret) ++ return ret; ++ ++ ret = adm6996_switch_init(priv, dev_name(&pdev->dev), NULL); ++ if (ret < 0) ++ return ret; ++ ++ platform_set_drvdata(pdev, priv); ++ ++ return 0; ++} ++ ++static void adm6996_gpio_remove(struct platform_device *pdev) ++{ ++ struct adm6996_priv *priv = platform_get_drvdata(pdev); ++ ++ if (priv && (priv->model == ADM6996M || priv->model == ADM6996L)) ++ unregister_switch(&priv->dev); ++} ++ ++static struct platform_driver adm6996_gpio_driver = { ++ .probe = adm6996_gpio_probe, ++ .remove_new = adm6996_gpio_remove, ++ .driver = { ++ .name = "adm6996_gpio", ++ }, ++}; ++ ++static int __init adm6996_init(void) ++{ ++ int err; ++ ++ phy_register_fixup_for_id(PHY_ANY_ID, adm6996_fixup); ++ err = phy_driver_register(&adm6996_phy_driver, THIS_MODULE); ++ if (err) ++ return err; ++ ++ err = platform_driver_register(&adm6996_gpio_driver); ++ if (err) ++ phy_driver_unregister(&adm6996_phy_driver); ++ ++ return err; ++} ++ ++static void __exit adm6996_exit(void) ++{ ++ platform_driver_unregister(&adm6996_gpio_driver); ++ phy_driver_unregister(&adm6996_phy_driver); ++} ++ ++module_init(adm6996_init); ++module_exit(adm6996_exit); +diff --git a/drivers/net/phy/adm6996.h b/drivers/net/phy/adm6996.h +new file mode 100644 +index 000000000000..6fd460a46594 +--- /dev/null ++++ b/drivers/net/phy/adm6996.h +@@ -0,0 +1,186 @@ ++/* ++ * ADM6996 switch driver ++ * ++ * Copyright (c) 2008 Felix Fietkau ++ * Copyright (c) 2010,2011 Peter Lebbing ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License v2 as published by the ++ * Free Software Foundation ++ */ ++#ifndef __ADM6996_H ++#define __ADM6996_H ++ ++/* ++ * ADM_PHY_PORTS: Number of ports with a PHY. ++ * We only control ports 0 to 3, because if 4 is connected, it is most likely ++ * not connected to the switch but to a separate MII and MAC for the WAN port. ++ */ ++#define ADM_PHY_PORTS 4 ++#define ADM_NUM_PORTS 6 ++#define ADM_CPU_PORT 5 ++ ++#define ADM_NUM_VLANS 16 ++#define ADM_VLAN_MAX_ID 4094 ++ ++enum admreg { ++ ADM_EEPROM_BASE = 0x0, ++ ADM_P0_CFG = ADM_EEPROM_BASE + 1, ++ ADM_P1_CFG = ADM_EEPROM_BASE + 3, ++ ADM_P2_CFG = ADM_EEPROM_BASE + 5, ++ ADM_P3_CFG = ADM_EEPROM_BASE + 7, ++ ADM_P4_CFG = ADM_EEPROM_BASE + 8, ++ ADM_P5_CFG = ADM_EEPROM_BASE + 9, ++ ADM_SYSC0 = ADM_EEPROM_BASE + 0xa, ++ ADM_VLAN_PRIOMAP = ADM_EEPROM_BASE + 0xe, ++ ADM_SYSC3 = ADM_EEPROM_BASE + 0x11, ++ /* Input Force No Tag Enable */ ++ ADM_IFNTE = ADM_EEPROM_BASE + 0x20, ++ ADM_VID_CHECK = ADM_EEPROM_BASE + 0x26, ++ ADM_P0_PVID = ADM_EEPROM_BASE + 0x28, ++ ADM_P1_PVID = ADM_EEPROM_BASE + 0x29, ++ /* Output Tag Bypass Enable and P2 PVID */ ++ ADM_OTBE_P2_PVID = ADM_EEPROM_BASE + 0x2a, ++ ADM_P3_P4_PVID = ADM_EEPROM_BASE + 0x2b, ++ ADM_P5_PVID = ADM_EEPROM_BASE + 0x2c, ++ ADM_EEPROM_EXT_BASE = 0x40, ++#define ADM_VLAN_FILT_L(n) (ADM_EEPROM_EXT_BASE + 2 * (n)) ++#define ADM_VLAN_FILT_H(n) (ADM_EEPROM_EXT_BASE + 1 + 2 * (n)) ++#define ADM_VLAN_MAP(n) (ADM_EEPROM_BASE + 0x13 + n) ++ ADM_COUNTER_BASE = 0xa0, ++ ADM_SIG0 = ADM_COUNTER_BASE + 0, ++ ADM_SIG1 = ADM_COUNTER_BASE + 1, ++ ADM_PS0 = ADM_COUNTER_BASE + 2, ++ ADM_PS1 = ADM_COUNTER_BASE + 3, ++ ADM_PS2 = ADM_COUNTER_BASE + 4, ++ ADM_CL0 = ADM_COUNTER_BASE + 8, /* RxPacket */ ++ ADM_CL6 = ADM_COUNTER_BASE + 0x1a, /* RxByte */ ++ ADM_CL12 = ADM_COUNTER_BASE + 0x2c, /* TxPacket */ ++ ADM_CL18 = ADM_COUNTER_BASE + 0x3e, /* TxByte */ ++ ADM_CL24 = ADM_COUNTER_BASE + 0x50, /* Coll */ ++ ADM_CL30 = ADM_COUNTER_BASE + 0x62, /* Err */ ++#define ADM_OFFSET_PORT(n) ((n * 4) - (n / 4) * 2 - (n / 5) * 2) ++ ADM_PHY_BASE = 0x200, ++#define ADM_PHY_PORT(n) (ADM_PHY_BASE + (0x20 * n)) ++}; ++ ++/* Chip identification patterns */ ++#define ADM_SIG0_MASK 0xffff ++#define ADM_SIG0_VAL 0x1023 ++#define ADM_SIG1_MASK 0xffff ++#define ADM_SIG1_VAL 0x0007 ++ ++enum { ++ ADM_PHYCFG_COLTST = (1 << 7), /* Enable collision test */ ++ ADM_PHYCFG_DPLX = (1 << 8), /* Enable full duplex */ ++ ADM_PHYCFG_ANEN_RST = (1 << 9), /* Restart auto negotiation (self clear) */ ++ ADM_PHYCFG_ISO = (1 << 10), /* Isolate PHY */ ++ ADM_PHYCFG_PDN = (1 << 11), /* Power down PHY */ ++ ADM_PHYCFG_ANEN = (1 << 12), /* Enable auto negotiation */ ++ ADM_PHYCFG_SPEED_100 = (1 << 13), /* Enable 100 Mbit/s */ ++ ADM_PHYCFG_LPBK = (1 << 14), /* Enable loopback operation */ ++ ADM_PHYCFG_RST = (1 << 15), /* Reset the port (self clear) */ ++ ADM_PHYCFG_INIT = ( ++ ADM_PHYCFG_RST | ++ ADM_PHYCFG_SPEED_100 | ++ ADM_PHYCFG_ANEN | ++ ADM_PHYCFG_ANEN_RST ++ ) ++}; ++ ++enum { ++ ADM_PORTCFG_FC = (1 << 0), /* Enable 802.x flow control */ ++ ADM_PORTCFG_AN = (1 << 1), /* Enable auto-negotiation */ ++ ADM_PORTCFG_SPEED_100 = (1 << 2), /* Enable 100 Mbit/s */ ++ ADM_PORTCFG_DPLX = (1 << 3), /* Enable full duplex */ ++ ADM_PORTCFG_OT = (1 << 4), /* Output tagged packets */ ++ ADM_PORTCFG_PD = (1 << 5), /* Port disable */ ++ ADM_PORTCFG_TV_PRIO = (1 << 6), /* 0 = VLAN based priority ++ * 1 = TOS based priority */ ++ ADM_PORTCFG_PPE = (1 << 7), /* Port based priority enable */ ++ ADM_PORTCFG_PP_S = (1 << 8), /* Port based priority, 2 bits */ ++ ADM_PORTCFG_PVID_BASE = (1 << 10), /* Primary VLAN id, 4 bits */ ++ ADM_PORTCFG_FSE = (1 << 14), /* Fx select enable */ ++ ADM_PORTCFG_CAM = (1 << 15), /* Crossover Auto MDIX */ ++ ++ ADM_PORTCFG_INIT = ( ++ ADM_PORTCFG_FC | ++ ADM_PORTCFG_AN | ++ ADM_PORTCFG_SPEED_100 | ++ ADM_PORTCFG_DPLX | ++ ADM_PORTCFG_CAM ++ ), ++ ADM_PORTCFG_CPU = ( ++ ADM_PORTCFG_FC | ++ ADM_PORTCFG_SPEED_100 | ++ ADM_PORTCFG_OT | ++ ADM_PORTCFG_DPLX ++ ), ++}; ++ ++#define ADM_PORTCFG_PPID(n) ((n & 0x3) << 8) ++#define ADM_PORTCFG_PVID(n) ((n & 0xf) << 10) ++#define ADM_PORTCFG_PVID_MASK (0xf << 10) ++ ++#define ADM_IFNTE_MASK (0x3f << 9) ++#define ADM_VID_CHECK_MASK (0x3f << 6) ++ ++#define ADM_P0_PVID_VAL(n) ((((n) & 0xff0) >> 4) << 0) ++#define ADM_P1_PVID_VAL(n) ((((n) & 0xff0) >> 4) << 0) ++#define ADM_P2_PVID_VAL(n) ((((n) & 0xff0) >> 4) << 0) ++#define ADM_P3_PVID_VAL(n) ((((n) & 0xff0) >> 4) << 0) ++#define ADM_P4_PVID_VAL(n) ((((n) & 0xff0) >> 4) << 8) ++#define ADM_P5_PVID_VAL(n) ((((n) & 0xff0) >> 4) << 0) ++#define ADM_P2_PVID_MASK 0xff ++ ++#define ADM_OTBE(n) (((n) & 0x3f) << 8) ++#define ADM_OTBE_MASK (0x3f << 8) ++ ++/* ADM_SYSC0 */ ++enum { ++ ADM_NTTE = (1 << 2), /* New Tag Transmit Enable */ ++ ADM_RVID1 = (1 << 8) /* Replace VLAN ID 1 */ ++}; ++ ++/* Tag Based VLAN in ADM_SYSC3 */ ++#define ADM_MAC_CLONE BIT(4) ++#define ADM_TBV BIT(5) ++ ++static const u8 adm_portcfg[] = { ++ [0] = ADM_P0_CFG, ++ [1] = ADM_P1_CFG, ++ [2] = ADM_P2_CFG, ++ [3] = ADM_P3_CFG, ++ [4] = ADM_P4_CFG, ++ [5] = ADM_P5_CFG, ++}; ++ ++/* Fields in ADM_VLAN_FILT_L(x) */ ++#define ADM_VLAN_FILT_FID(n) (((n) & 0xf) << 12) ++#define ADM_VLAN_FILT_TAGGED(n) (((n) & 0x3f) << 6) ++#define ADM_VLAN_FILT_MEMBER(n) (((n) & 0x3f) << 0) ++#define ADM_VLAN_FILT_MEMBER_MASK 0x3f ++/* Fields in ADM_VLAN_FILT_H(x) */ ++#define ADM_VLAN_FILT_VALID (1 << 15) ++#define ADM_VLAN_FILT_VID(n) (((n) & 0xfff) << 0) ++ ++/* Convert ports to a form for ADM6996L VLAN map */ ++#define ADM_VLAN_FILT(ports) ((ports & 0x01) | ((ports & 0x02) << 1) | \ ++ ((ports & 0x04) << 2) | ((ports & 0x08) << 3) | \ ++ ((ports & 0x10) << 3) | ((ports & 0x20) << 3)) ++ ++/* Port status register */ ++enum { ++ ADM_PS_LS = (1 << 0), /* Link status */ ++ ADM_PS_SS = (1 << 1), /* Speed status */ ++ ADM_PS_DS = (1 << 2), /* Duplex status */ ++ ADM_PS_FCS = (1 << 3) /* Flow control status */ ++}; ++ ++/* ++ * Split the register address in phy id and register ++ * it will get combined again by the mdio bus op ++ */ ++#define PHYADDR(_reg) ((_reg >> 5) & 0xff), (_reg & 0x1f) ++ ++#endif +diff --git a/drivers/net/phy/air_an8855.c b/drivers/net/phy/air_an8855.c +new file mode 100644 +index 000000000000..7fab0854ef78 +--- /dev/null ++++ b/drivers/net/phy/air_an8855.c +@@ -0,0 +1,267 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Copyright (C) 2024 Christian Marangi ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#define AN8855_PHY_SELECT_PAGE 0x1f ++#define AN8855_PHY_PAGE GENMASK(2, 0) ++#define AN8855_PHY_PAGE_STANDARD FIELD_PREP_CONST(AN8855_PHY_PAGE, 0x0) ++#define AN8855_PHY_PAGE_EXTENDED_1 FIELD_PREP_CONST(AN8855_PHY_PAGE, 0x1) ++ ++/* MII Registers Page 1 */ ++#define AN8855_PHY_EXT_REG_14 0x14 ++#define AN8855_PHY_EN_DOWN_SHIFT BIT(4) ++ ++/* R50 Calibration regs in MDIO_MMD_VEND1 */ ++#define AN8855_PHY_R500HM_RSEL_TX_AB 0x174 ++#define AN8855_PHY_R50OHM_RSEL_TX_A_EN BIT(15) ++#define AN8855_PHY_R50OHM_RSEL_TX_A GENMASK(14, 8) ++#define AN8855_PHY_R50OHM_RSEL_TX_B_EN BIT(7) ++#define AN8855_PHY_R50OHM_RSEL_TX_B GENMASK(6, 0) ++#define AN8855_PHY_R500HM_RSEL_TX_CD 0x175 ++#define AN8855_PHY_R50OHM_RSEL_TX_C_EN BIT(15) ++#define AN8855_PHY_R50OHM_RSEL_TX_C GENMASK(14, 8) ++#define AN8855_PHY_R50OHM_RSEL_TX_D_EN BIT(7) ++#define AN8855_PHY_R50OHM_RSEL_TX_D GENMASK(6, 0) ++ ++#define AN8855_SWITCH_EFUSE_R50O GENMASK(30, 24) ++ ++/* PHY TX PAIR DELAY SELECT Register */ ++#define AN8855_PHY_TX_PAIR_DLY_SEL_GBE 0x013 ++#define AN8855_PHY_CR_DA_TX_PAIR_DELKAY_SEL_A_GBE GENMASK(14, 12) ++#define AN8855_PHY_CR_DA_TX_PAIR_DELKAY_SEL_B_GBE GENMASK(10, 8) ++#define AN8855_PHY_CR_DA_TX_PAIR_DELKAY_SEL_C_GBE GENMASK(6, 4) ++#define AN8855_PHY_CR_DA_TX_PAIR_DELKAY_SEL_D_GBE GENMASK(2, 0) ++/* PHY ADC Register */ ++#define AN8855_PHY_RXADC_CTRL 0x0d8 ++#define AN8855_PHY_RG_AD_SAMNPLE_PHSEL_A BIT(12) ++#define AN8855_PHY_RG_AD_SAMNPLE_PHSEL_B BIT(8) ++#define AN8855_PHY_RG_AD_SAMNPLE_PHSEL_C BIT(4) ++#define AN8855_PHY_RG_AD_SAMNPLE_PHSEL_D BIT(0) ++#define AN8855_PHY_RXADC_REV_0 0x0d9 ++#define AN8855_PHY_RG_AD_RESERVE0_A GENMASK(15, 8) ++#define AN8855_PHY_RG_AD_RESERVE0_B GENMASK(7, 0) ++#define AN8855_PHY_RXADC_REV_1 0x0da ++#define AN8855_PHY_RG_AD_RESERVE0_C GENMASK(15, 8) ++#define AN8855_PHY_RG_AD_RESERVE0_D GENMASK(7, 0) ++ ++#define AN8855_PHY_ID 0xc0ff0410 ++ ++#define AN8855_PHY_FLAGS_EN_CALIBRATION BIT(0) ++ ++struct air_an8855_priv { ++ u8 calibration_data[4]; ++}; ++ ++static const u8 dsa_r50ohm_table[] = { ++ 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, ++ 127, 127, 127, 127, 127, 127, 127, 126, 122, 117, ++ 112, 109, 104, 101, 97, 94, 90, 88, 84, 80, ++ 78, 74, 72, 68, 66, 64, 61, 58, 56, 53, ++ 51, 48, 47, 44, 42, 40, 38, 36, 34, 32, ++ 31, 28, 27, 24, 24, 22, 20, 18, 16, 16, ++ 14, 12, 11, 9 ++}; ++ ++static int en8855_get_r50ohm_val(struct device *dev, const char *calib_name, ++ u8 *dest) ++{ ++ u32 shift_sel, val; ++ int ret; ++ int i; ++ ++ ret = nvmem_cell_read_u32(dev, calib_name, &val); ++ if (ret) ++ return ret; ++ ++ shift_sel = FIELD_GET(AN8855_SWITCH_EFUSE_R50O, val); ++ for (i = 0; i < ARRAY_SIZE(dsa_r50ohm_table); i++) ++ if (dsa_r50ohm_table[i] == shift_sel) ++ break; ++ ++ if (i < 8 || i >= ARRAY_SIZE(dsa_r50ohm_table)) ++ *dest = dsa_r50ohm_table[25]; ++ else ++ *dest = dsa_r50ohm_table[i - 8]; ++ ++ return 0; ++} ++ ++static int an8855_probe(struct phy_device *phydev) ++{ ++ struct device *dev = &phydev->mdio.dev; ++ struct device_node *node = dev->of_node; ++ struct air_an8855_priv *priv; ++ ++ /* If we don't have a node, skip calib */ ++ if (!node) ++ return 0; ++ ++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ phydev->priv = priv; ++ ++ return 0; ++} ++ ++static int an8855_get_downshift(struct phy_device *phydev, u8 *data) ++{ ++ int val; ++ ++ val = phy_read_paged(phydev, AN8855_PHY_PAGE_EXTENDED_1, AN8855_PHY_EXT_REG_14); ++ if (val < 0) ++ return val; ++ ++ *data = val & AN8855_PHY_EN_DOWN_SHIFT ? DOWNSHIFT_DEV_DEFAULT_COUNT : ++ DOWNSHIFT_DEV_DISABLE; ++ ++ return 0; ++} ++ ++static int an8855_set_downshift(struct phy_device *phydev, u8 cnt) ++{ ++ u16 ds = cnt != DOWNSHIFT_DEV_DISABLE ? AN8855_PHY_EN_DOWN_SHIFT : 0; ++ ++ return phy_modify_paged(phydev, AN8855_PHY_PAGE_EXTENDED_1, ++ AN8855_PHY_EXT_REG_14, AN8855_PHY_EN_DOWN_SHIFT, ++ ds); ++} ++ ++static int an8855_config_init(struct phy_device *phydev) ++{ ++ struct air_an8855_priv *priv = phydev->priv; ++ struct device *dev = &phydev->mdio.dev; ++ int ret; ++ ++ /* Enable HW auto downshift */ ++ ret = an8855_set_downshift(phydev, DOWNSHIFT_DEV_DEFAULT_COUNT); ++ if (ret) ++ return ret; ++ ++ /* Apply calibration values, if needed. ++ * AN8855_PHY_FLAGS_EN_CALIBRATION signal this. ++ */ ++ if (priv && phydev->dev_flags & AN8855_PHY_FLAGS_EN_CALIBRATION) { ++ u8 *calibration_data = priv->calibration_data; ++ ++ ret = en8855_get_r50ohm_val(dev, "tx_a", &calibration_data[0]); ++ if (ret) ++ return ret; ++ ++ ret = en8855_get_r50ohm_val(dev, "tx_b", &calibration_data[1]); ++ if (ret) ++ return ret; ++ ++ ret = en8855_get_r50ohm_val(dev, "tx_c", &calibration_data[2]); ++ if (ret) ++ return ret; ++ ++ ret = en8855_get_r50ohm_val(dev, "tx_d", &calibration_data[3]); ++ if (ret) ++ return ret; ++ ++ ret = phy_modify_mmd(phydev, MDIO_MMD_VEND1, AN8855_PHY_R500HM_RSEL_TX_AB, ++ AN8855_PHY_R50OHM_RSEL_TX_A | AN8855_PHY_R50OHM_RSEL_TX_B, ++ FIELD_PREP(AN8855_PHY_R50OHM_RSEL_TX_A, calibration_data[0]) | ++ FIELD_PREP(AN8855_PHY_R50OHM_RSEL_TX_B, calibration_data[1])); ++ if (ret) ++ return ret; ++ ret = phy_modify_mmd(phydev, MDIO_MMD_VEND1, AN8855_PHY_R500HM_RSEL_TX_CD, ++ AN8855_PHY_R50OHM_RSEL_TX_C | AN8855_PHY_R50OHM_RSEL_TX_D, ++ FIELD_PREP(AN8855_PHY_R50OHM_RSEL_TX_C, calibration_data[2]) | ++ FIELD_PREP(AN8855_PHY_R50OHM_RSEL_TX_D, calibration_data[3])); ++ if (ret) ++ return ret; ++ } ++ ++ /* Apply values to reduce signal noise */ ++ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AN8855_PHY_TX_PAIR_DLY_SEL_GBE, ++ FIELD_PREP(AN8855_PHY_CR_DA_TX_PAIR_DELKAY_SEL_A_GBE, 0x4) | ++ FIELD_PREP(AN8855_PHY_CR_DA_TX_PAIR_DELKAY_SEL_C_GBE, 0x4)); ++ if (ret) ++ return ret; ++ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AN8855_PHY_RXADC_CTRL, ++ AN8855_PHY_RG_AD_SAMNPLE_PHSEL_A | ++ AN8855_PHY_RG_AD_SAMNPLE_PHSEL_C); ++ if (ret) ++ return ret; ++ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AN8855_PHY_RXADC_REV_0, ++ FIELD_PREP(AN8855_PHY_RG_AD_RESERVE0_A, 0x1)); ++ if (ret) ++ return ret; ++ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AN8855_PHY_RXADC_REV_1, ++ FIELD_PREP(AN8855_PHY_RG_AD_RESERVE0_C, 0x1)); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static int an8855_get_tunable(struct phy_device *phydev, ++ struct ethtool_tunable *tuna, void *data) ++{ ++ switch (tuna->id) { ++ case ETHTOOL_PHY_DOWNSHIFT: ++ return an8855_get_downshift(phydev, data); ++ default: ++ return -EOPNOTSUPP; ++ } ++} ++ ++static int an8855_set_tunable(struct phy_device *phydev, ++ struct ethtool_tunable *tuna, const void *data) ++{ ++ switch (tuna->id) { ++ case ETHTOOL_PHY_DOWNSHIFT: ++ return an8855_set_downshift(phydev, *(const u8 *)data); ++ default: ++ return -EOPNOTSUPP; ++ } ++} ++ ++static int an8855_read_page(struct phy_device *phydev) ++{ ++ return __phy_read(phydev, AN8855_PHY_SELECT_PAGE); ++} ++ ++static int an8855_write_page(struct phy_device *phydev, int page) ++{ ++ return __phy_write(phydev, AN8855_PHY_SELECT_PAGE, page); ++} ++ ++static struct phy_driver an8855_driver[] = { ++{ ++ PHY_ID_MATCH_EXACT(AN8855_PHY_ID), ++ .name = "Airoha AN8855 internal PHY", ++ /* PHY_GBIT_FEATURES */ ++ .flags = PHY_IS_INTERNAL, ++ .probe = an8855_probe, ++ .config_init = an8855_config_init, ++ .soft_reset = genphy_soft_reset, ++ .get_tunable = an8855_get_tunable, ++ .set_tunable = an8855_set_tunable, ++ .suspend = genphy_suspend, ++ .resume = genphy_resume, ++ .read_page = an8855_read_page, ++ .write_page = an8855_write_page, ++}, }; ++ ++module_phy_driver(an8855_driver); ++ ++static struct mdio_device_id __maybe_unused an8855_tbl[] = { ++ { PHY_ID_MATCH_EXACT(AN8855_PHY_ID) }, ++ { } ++}; ++ ++MODULE_DEVICE_TABLE(mdio, an8855_tbl); ++ ++MODULE_DESCRIPTION("Airoha AN8855 PHY driver"); ++MODULE_AUTHOR("Christian Marangi "); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/net/phy/ar8216.c b/drivers/net/phy/ar8216.c +new file mode 100644 +index 000000000000..84b923ffc125 +--- /dev/null ++++ b/drivers/net/phy/ar8216.c +@@ -0,0 +1,2909 @@ ++/* ++ * ar8216.c: AR8216 switch driver ++ * ++ * Copyright (C) 2009 Felix Fietkau ++ * Copyright (C) 2011-2012 Gabor Juhos ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version 2 ++ * of the License, or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "ar8216.h" ++ ++extern const struct ar8xxx_chip ar8327_chip; ++extern const struct ar8xxx_chip ar8337_chip; ++ ++#define MIB_DESC_BASIC(_s , _o, _n) \ ++ { \ ++ .size = (_s), \ ++ .offset = (_o), \ ++ .name = (_n), \ ++ .type = AR8XXX_MIB_BASIC, \ ++ } ++ ++#define MIB_DESC_EXT(_s , _o, _n) \ ++ { \ ++ .size = (_s), \ ++ .offset = (_o), \ ++ .name = (_n), \ ++ .type = AR8XXX_MIB_EXTENDED, \ ++ } ++ ++static const struct ar8xxx_mib_desc ar8216_mibs[] = { ++ MIB_DESC_EXT(1, AR8216_STATS_RXBROAD, "RxBroad"), ++ MIB_DESC_EXT(1, AR8216_STATS_RXPAUSE, "RxPause"), ++ MIB_DESC_EXT(1, AR8216_STATS_RXMULTI, "RxMulti"), ++ MIB_DESC_EXT(1, AR8216_STATS_RXFCSERR, "RxFcsErr"), ++ MIB_DESC_EXT(1, AR8216_STATS_RXALIGNERR, "RxAlignErr"), ++ MIB_DESC_EXT(1, AR8216_STATS_RXRUNT, "RxRunt"), ++ MIB_DESC_EXT(1, AR8216_STATS_RXFRAGMENT, "RxFragment"), ++ MIB_DESC_EXT(1, AR8216_STATS_RX64BYTE, "Rx64Byte"), ++ MIB_DESC_EXT(1, AR8216_STATS_RX128BYTE, "Rx128Byte"), ++ MIB_DESC_EXT(1, AR8216_STATS_RX256BYTE, "Rx256Byte"), ++ MIB_DESC_EXT(1, AR8216_STATS_RX512BYTE, "Rx512Byte"), ++ MIB_DESC_EXT(1, AR8216_STATS_RX1024BYTE, "Rx1024Byte"), ++ MIB_DESC_EXT(1, AR8216_STATS_RXMAXBYTE, "RxMaxByte"), ++ MIB_DESC_EXT(1, AR8216_STATS_RXTOOLONG, "RxTooLong"), ++ MIB_DESC_BASIC(2, AR8216_STATS_RXGOODBYTE, "RxGoodByte"), ++ MIB_DESC_EXT(2, AR8216_STATS_RXBADBYTE, "RxBadByte"), ++ MIB_DESC_EXT(1, AR8216_STATS_RXOVERFLOW, "RxOverFlow"), ++ MIB_DESC_EXT(1, AR8216_STATS_FILTERED, "Filtered"), ++ MIB_DESC_EXT(1, AR8216_STATS_TXBROAD, "TxBroad"), ++ MIB_DESC_EXT(1, AR8216_STATS_TXPAUSE, "TxPause"), ++ MIB_DESC_EXT(1, AR8216_STATS_TXMULTI, "TxMulti"), ++ MIB_DESC_EXT(1, AR8216_STATS_TXUNDERRUN, "TxUnderRun"), ++ MIB_DESC_EXT(1, AR8216_STATS_TX64BYTE, "Tx64Byte"), ++ MIB_DESC_EXT(1, AR8216_STATS_TX128BYTE, "Tx128Byte"), ++ MIB_DESC_EXT(1, AR8216_STATS_TX256BYTE, "Tx256Byte"), ++ MIB_DESC_EXT(1, AR8216_STATS_TX512BYTE, "Tx512Byte"), ++ MIB_DESC_EXT(1, AR8216_STATS_TX1024BYTE, "Tx1024Byte"), ++ MIB_DESC_EXT(1, AR8216_STATS_TXMAXBYTE, "TxMaxByte"), ++ MIB_DESC_EXT(1, AR8216_STATS_TXOVERSIZE, "TxOverSize"), ++ MIB_DESC_BASIC(2, AR8216_STATS_TXBYTE, "TxByte"), ++ MIB_DESC_EXT(1, AR8216_STATS_TXCOLLISION, "TxCollision"), ++ MIB_DESC_EXT(1, AR8216_STATS_TXABORTCOL, "TxAbortCol"), ++ MIB_DESC_EXT(1, AR8216_STATS_TXMULTICOL, "TxMultiCol"), ++ MIB_DESC_EXT(1, AR8216_STATS_TXSINGLECOL, "TxSingleCol"), ++ MIB_DESC_EXT(1, AR8216_STATS_TXEXCDEFER, "TxExcDefer"), ++ MIB_DESC_EXT(1, AR8216_STATS_TXDEFER, "TxDefer"), ++ MIB_DESC_EXT(1, AR8216_STATS_TXLATECOL, "TxLateCol"), ++}; ++ ++const struct ar8xxx_mib_desc ar8236_mibs[39] = { ++ MIB_DESC_EXT(1, AR8236_STATS_RXBROAD, "RxBroad"), ++ MIB_DESC_EXT(1, AR8236_STATS_RXPAUSE, "RxPause"), ++ MIB_DESC_EXT(1, AR8236_STATS_RXMULTI, "RxMulti"), ++ MIB_DESC_EXT(1, AR8236_STATS_RXFCSERR, "RxFcsErr"), ++ MIB_DESC_EXT(1, AR8236_STATS_RXALIGNERR, "RxAlignErr"), ++ MIB_DESC_EXT(1, AR8236_STATS_RXRUNT, "RxRunt"), ++ MIB_DESC_EXT(1, AR8236_STATS_RXFRAGMENT, "RxFragment"), ++ MIB_DESC_EXT(1, AR8236_STATS_RX64BYTE, "Rx64Byte"), ++ MIB_DESC_EXT(1, AR8236_STATS_RX128BYTE, "Rx128Byte"), ++ MIB_DESC_EXT(1, AR8236_STATS_RX256BYTE, "Rx256Byte"), ++ MIB_DESC_EXT(1, AR8236_STATS_RX512BYTE, "Rx512Byte"), ++ MIB_DESC_EXT(1, AR8236_STATS_RX1024BYTE, "Rx1024Byte"), ++ MIB_DESC_EXT(1, AR8236_STATS_RX1518BYTE, "Rx1518Byte"), ++ MIB_DESC_EXT(1, AR8236_STATS_RXMAXBYTE, "RxMaxByte"), ++ MIB_DESC_EXT(1, AR8236_STATS_RXTOOLONG, "RxTooLong"), ++ MIB_DESC_BASIC(2, AR8236_STATS_RXGOODBYTE, "RxGoodByte"), ++ MIB_DESC_EXT(2, AR8236_STATS_RXBADBYTE, "RxBadByte"), ++ MIB_DESC_EXT(1, AR8236_STATS_RXOVERFLOW, "RxOverFlow"), ++ MIB_DESC_EXT(1, AR8236_STATS_FILTERED, "Filtered"), ++ MIB_DESC_EXT(1, AR8236_STATS_TXBROAD, "TxBroad"), ++ MIB_DESC_EXT(1, AR8236_STATS_TXPAUSE, "TxPause"), ++ MIB_DESC_EXT(1, AR8236_STATS_TXMULTI, "TxMulti"), ++ MIB_DESC_EXT(1, AR8236_STATS_TXUNDERRUN, "TxUnderRun"), ++ MIB_DESC_EXT(1, AR8236_STATS_TX64BYTE, "Tx64Byte"), ++ MIB_DESC_EXT(1, AR8236_STATS_TX128BYTE, "Tx128Byte"), ++ MIB_DESC_EXT(1, AR8236_STATS_TX256BYTE, "Tx256Byte"), ++ MIB_DESC_EXT(1, AR8236_STATS_TX512BYTE, "Tx512Byte"), ++ MIB_DESC_EXT(1, AR8236_STATS_TX1024BYTE, "Tx1024Byte"), ++ MIB_DESC_EXT(1, AR8236_STATS_TX1518BYTE, "Tx1518Byte"), ++ MIB_DESC_EXT(1, AR8236_STATS_TXMAXBYTE, "TxMaxByte"), ++ MIB_DESC_EXT(1, AR8236_STATS_TXOVERSIZE, "TxOverSize"), ++ MIB_DESC_BASIC(2, AR8236_STATS_TXBYTE, "TxByte"), ++ MIB_DESC_EXT(1, AR8236_STATS_TXCOLLISION, "TxCollision"), ++ MIB_DESC_EXT(1, AR8236_STATS_TXABORTCOL, "TxAbortCol"), ++ MIB_DESC_EXT(1, AR8236_STATS_TXMULTICOL, "TxMultiCol"), ++ MIB_DESC_EXT(1, AR8236_STATS_TXSINGLECOL, "TxSingleCol"), ++ MIB_DESC_EXT(1, AR8236_STATS_TXEXCDEFER, "TxExcDefer"), ++ MIB_DESC_EXT(1, AR8236_STATS_TXDEFER, "TxDefer"), ++ MIB_DESC_EXT(1, AR8236_STATS_TXLATECOL, "TxLateCol"), ++}; ++ ++static DEFINE_MUTEX(ar8xxx_dev_list_lock); ++static LIST_HEAD(ar8xxx_dev_list); ++ ++static void ++ar8xxx_mib_start(struct ar8xxx_priv *priv); ++static void ++ar8xxx_mib_stop(struct ar8xxx_priv *priv); ++ ++/* inspired by phy_poll_reset in drivers/net/phy/phy_device.c */ ++static int ++ar8xxx_phy_poll_reset(struct mii_bus *bus) ++{ ++ unsigned int sleep_msecs = 20; ++ int ret, elapsed, i; ++ ++ for (elapsed = sleep_msecs; elapsed <= 600; ++ elapsed += sleep_msecs) { ++ msleep(sleep_msecs); ++ for (i = 0; i < AR8XXX_NUM_PHYS; i++) { ++ ret = mdiobus_read(bus, i, MII_BMCR); ++ if (ret < 0) ++ return ret; ++ if (ret & BMCR_RESET) ++ break; ++ if (i == AR8XXX_NUM_PHYS - 1) { ++ usleep_range(1000, 2000); ++ return 0; ++ } ++ } ++ } ++ return -ETIMEDOUT; ++} ++ ++static int ++ar8xxx_phy_check_aneg(struct phy_device *phydev) ++{ ++ int ret; ++ ++ if (phydev->autoneg != AUTONEG_ENABLE) ++ return 0; ++ /* ++ * BMCR_ANENABLE might have been cleared ++ * by phy_init_hw in certain kernel versions ++ * therefore check for it ++ */ ++ ret = phy_read(phydev, MII_BMCR); ++ if (ret < 0) ++ return ret; ++ if (ret & BMCR_ANENABLE) ++ return 0; ++ ++ dev_info(&phydev->mdio.dev, "ANEG disabled, re-enabling ...\n"); ++ ret |= BMCR_ANENABLE | BMCR_ANRESTART; ++ return phy_write(phydev, MII_BMCR, ret); ++} ++ ++void ++ar8xxx_phy_init(struct ar8xxx_priv *priv) ++{ ++ int i; ++ struct mii_bus *bus; ++ ++ bus = priv->sw_mii_bus ?: priv->mii_bus; ++ for (i = 0; i < AR8XXX_NUM_PHYS; i++) { ++ if (priv->chip->phy_fixup) ++ priv->chip->phy_fixup(priv, i); ++ ++ /* initialize the port itself */ ++ mdiobus_write(bus, i, MII_ADVERTISE, ++ ADVERTISE_ALL | ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM); ++ if (ar8xxx_has_gige(priv)) ++ mdiobus_write(bus, i, MII_CTRL1000, ADVERTISE_1000FULL); ++ mdiobus_write(bus, i, MII_BMCR, BMCR_RESET | BMCR_ANENABLE); ++ } ++ ++ ar8xxx_phy_poll_reset(bus); ++} ++ ++u32 ++ar8xxx_mii_read32(struct ar8xxx_priv *priv, int phy_id, int regnum) ++{ ++ struct mii_bus *bus = priv->mii_bus; ++ u16 lo, hi; ++ ++ lo = bus->read(bus, phy_id, regnum); ++ hi = bus->read(bus, phy_id, regnum + 1); ++ ++ return (hi << 16) | lo; ++} ++ ++void ++ar8xxx_mii_write32(struct ar8xxx_priv *priv, int phy_id, int regnum, u32 val) ++{ ++ struct mii_bus *bus = priv->mii_bus; ++ u16 lo, hi; ++ ++ lo = val & 0xffff; ++ hi = (u16) (val >> 16); ++ ++ if (priv->chip->mii_lo_first) ++ { ++ bus->write(bus, phy_id, regnum, lo); ++ bus->write(bus, phy_id, regnum + 1, hi); ++ } else { ++ bus->write(bus, phy_id, regnum + 1, hi); ++ bus->write(bus, phy_id, regnum, lo); ++ } ++} ++ ++u32 ++ar8xxx_read(struct ar8xxx_priv *priv, int reg) ++{ ++ struct mii_bus *bus = priv->mii_bus; ++ u16 r1, r2, page; ++ u32 val; ++ ++ split_addr((u32) reg, &r1, &r2, &page); ++ ++ mutex_lock(&bus->mdio_lock); ++ ++ bus->write(bus, 0x18, 0, page); ++ wait_for_page_switch(); ++ val = ar8xxx_mii_read32(priv, 0x10 | r2, r1); ++ ++ mutex_unlock(&bus->mdio_lock); ++ ++ return val; ++} ++ ++void ++ar8xxx_write(struct ar8xxx_priv *priv, int reg, u32 val) ++{ ++ struct mii_bus *bus = priv->mii_bus; ++ u16 r1, r2, page; ++ ++ split_addr((u32) reg, &r1, &r2, &page); ++ ++ mutex_lock(&bus->mdio_lock); ++ ++ bus->write(bus, 0x18, 0, page); ++ wait_for_page_switch(); ++ ar8xxx_mii_write32(priv, 0x10 | r2, r1, val); ++ ++ mutex_unlock(&bus->mdio_lock); ++} ++ ++u32 ++ar8xxx_rmw(struct ar8xxx_priv *priv, int reg, u32 mask, u32 val) ++{ ++ struct mii_bus *bus = priv->mii_bus; ++ u16 r1, r2, page; ++ u32 ret; ++ ++ split_addr((u32) reg, &r1, &r2, &page); ++ ++ mutex_lock(&bus->mdio_lock); ++ ++ bus->write(bus, 0x18, 0, page); ++ wait_for_page_switch(); ++ ++ ret = ar8xxx_mii_read32(priv, 0x10 | r2, r1); ++ ret &= ~mask; ++ ret |= val; ++ ar8xxx_mii_write32(priv, 0x10 | r2, r1, ret); ++ ++ mutex_unlock(&bus->mdio_lock); ++ ++ return ret; ++} ++void ++ar8xxx_phy_dbg_read(struct ar8xxx_priv *priv, int phy_addr, ++ u16 dbg_addr, u16 *dbg_data) ++{ ++ struct mii_bus *bus = priv->mii_bus; ++ ++ mutex_lock(&bus->mdio_lock); ++ bus->write(bus, phy_addr, MII_ATH_DBG_ADDR, dbg_addr); ++ *dbg_data = bus->read(bus, phy_addr, MII_ATH_DBG_DATA); ++ mutex_unlock(&bus->mdio_lock); ++} ++ ++void ++ar8xxx_phy_dbg_write(struct ar8xxx_priv *priv, int phy_addr, ++ u16 dbg_addr, u16 dbg_data) ++{ ++ struct mii_bus *bus = priv->mii_bus; ++ ++ mutex_lock(&bus->mdio_lock); ++ bus->write(bus, phy_addr, MII_ATH_DBG_ADDR, dbg_addr); ++ bus->write(bus, phy_addr, MII_ATH_DBG_DATA, dbg_data); ++ mutex_unlock(&bus->mdio_lock); ++} ++ ++static inline void ++ar8xxx_phy_mmd_prep(struct mii_bus *bus, int phy_addr, u16 addr, u16 reg) ++{ ++ bus->write(bus, phy_addr, MII_ATH_MMD_ADDR, addr); ++ bus->write(bus, phy_addr, MII_ATH_MMD_DATA, reg); ++ bus->write(bus, phy_addr, MII_ATH_MMD_ADDR, addr | 0x4000); ++} ++ ++void ++ar8xxx_phy_mmd_write(struct ar8xxx_priv *priv, int phy_addr, u16 addr, u16 reg, u16 data) ++{ ++ struct mii_bus *bus = priv->mii_bus; ++ ++ mutex_lock(&bus->mdio_lock); ++ ar8xxx_phy_mmd_prep(bus, phy_addr, addr, reg); ++ bus->write(bus, phy_addr, MII_ATH_MMD_DATA, data); ++ mutex_unlock(&bus->mdio_lock); ++} ++ ++u16 ++ar8xxx_phy_mmd_read(struct ar8xxx_priv *priv, int phy_addr, u16 addr, u16 reg) ++{ ++ struct mii_bus *bus = priv->mii_bus; ++ u16 data; ++ ++ mutex_lock(&bus->mdio_lock); ++ ar8xxx_phy_mmd_prep(bus, phy_addr, addr, reg); ++ data = bus->read(bus, phy_addr, MII_ATH_MMD_DATA); ++ mutex_unlock(&bus->mdio_lock); ++ ++ return data; ++} ++ ++static int ++ar8xxx_reg_wait(struct ar8xxx_priv *priv, u32 reg, u32 mask, u32 val, ++ unsigned timeout) ++{ ++ int i; ++ ++ for (i = 0; i < timeout; i++) { ++ u32 t; ++ ++ t = ar8xxx_read(priv, reg); ++ if ((t & mask) == val) ++ return 0; ++ ++ usleep_range(1000, 2000); ++ cond_resched(); ++ } ++ ++ return -ETIMEDOUT; ++} ++ ++static int ++ar8xxx_mib_op(struct ar8xxx_priv *priv, u32 op) ++{ ++ unsigned mib_func = priv->chip->mib_func; ++ int ret; ++ ++ lockdep_assert_held(&priv->mib_lock); ++ ++ /* Capture the hardware statistics for all ports */ ++ ar8xxx_rmw(priv, mib_func, AR8216_MIB_FUNC, (op << AR8216_MIB_FUNC_S)); ++ ++ /* Wait for the capturing to complete. */ ++ ret = ar8xxx_reg_wait(priv, mib_func, AR8216_MIB_BUSY, 0, 10); ++ if (ret) ++ goto out; ++ ++ ret = 0; ++ ++out: ++ return ret; ++} ++ ++static int ++ar8xxx_mib_capture(struct ar8xxx_priv *priv) ++{ ++ return ar8xxx_mib_op(priv, AR8216_MIB_FUNC_CAPTURE); ++} ++ ++static int ++ar8xxx_mib_flush(struct ar8xxx_priv *priv) ++{ ++ return ar8xxx_mib_op(priv, AR8216_MIB_FUNC_FLUSH); ++} ++ ++static void ++ar8xxx_mib_fetch_port_stat(struct ar8xxx_priv *priv, int port, bool flush) ++{ ++ unsigned int base; ++ u64 *mib_stats; ++ int i; ++ ++ WARN_ON(port >= priv->dev.ports); ++ ++ lockdep_assert_held(&priv->mib_lock); ++ ++ base = priv->chip->reg_port_stats_start + ++ priv->chip->reg_port_stats_length * port; ++ ++ mib_stats = &priv->mib_stats[port * priv->chip->num_mibs]; ++ for (i = 0; i < priv->chip->num_mibs; i++) { ++ const struct ar8xxx_mib_desc *mib; ++ u64 t; ++ ++ mib = &priv->chip->mib_decs[i]; ++ if (mib->type > priv->mib_type) ++ continue; ++ t = ar8xxx_read(priv, base + mib->offset); ++ if (mib->size == 2) { ++ u64 hi; ++ ++ hi = ar8xxx_read(priv, base + mib->offset + 4); ++ t |= hi << 32; ++ } ++ ++ if (flush) ++ mib_stats[i] = 0; ++ else ++ mib_stats[i] += t; ++ cond_resched(); ++ } ++} ++ ++static void ++ar8216_read_port_link(struct ar8xxx_priv *priv, int port, ++ struct switch_port_link *link) ++{ ++ u32 status; ++ u32 speed; ++ ++ memset(link, '\0', sizeof(*link)); ++ ++ status = priv->chip->read_port_status(priv, port); ++ ++ link->aneg = !!(status & AR8216_PORT_STATUS_LINK_AUTO); ++ if (link->aneg) { ++ link->link = !!(status & AR8216_PORT_STATUS_LINK_UP); ++ } else { ++ link->link = true; ++ ++ if (priv->get_port_link) { ++ int err; ++ ++ err = priv->get_port_link(port); ++ if (err >= 0) ++ link->link = !!err; ++ } ++ } ++ ++ if (!link->link) ++ return; ++ ++ link->duplex = !!(status & AR8216_PORT_STATUS_DUPLEX); ++ link->tx_flow = !!(status & AR8216_PORT_STATUS_TXFLOW); ++ link->rx_flow = !!(status & AR8216_PORT_STATUS_RXFLOW); ++ ++ if (link->aneg && link->duplex && priv->chip->read_port_eee_status) ++ link->eee = priv->chip->read_port_eee_status(priv, port); ++ ++ speed = (status & AR8216_PORT_STATUS_SPEED) >> ++ AR8216_PORT_STATUS_SPEED_S; ++ ++ switch (speed) { ++ case AR8216_PORT_SPEED_10M: ++ link->speed = SWITCH_PORT_SPEED_10; ++ break; ++ case AR8216_PORT_SPEED_100M: ++ link->speed = SWITCH_PORT_SPEED_100; ++ break; ++ case AR8216_PORT_SPEED_1000M: ++ link->speed = SWITCH_PORT_SPEED_1000; ++ break; ++ default: ++ link->speed = SWITCH_PORT_SPEED_UNKNOWN; ++ break; ++ } ++} ++ ++#ifdef CONFIG_ETHERNET_PACKET_MANGLE ++ ++static struct sk_buff * ++ar8216_mangle_tx(struct net_device *dev, struct sk_buff *skb) ++{ ++ struct ar8xxx_priv *priv = dev->phy_ptr; ++ unsigned char *buf; ++ ++ if (unlikely(!priv)) ++ goto error; ++ ++ if (!priv->vlan) ++ goto send; ++ ++ if (unlikely(skb_headroom(skb) < 2)) { ++ if (pskb_expand_head(skb, 2, 0, GFP_ATOMIC) < 0) ++ goto error; ++ } ++ ++ buf = skb_push(skb, 2); ++ buf[0] = 0x10; ++ buf[1] = 0x80; ++ ++send: ++ return skb; ++ ++error: ++ dev_kfree_skb_any(skb); ++ return NULL; ++} ++ ++static void ++ar8216_mangle_rx(struct net_device *dev, struct sk_buff *skb) ++{ ++ struct ar8xxx_priv *priv; ++ unsigned char *buf; ++ int port, vlan; ++ ++ priv = dev->phy_ptr; ++ if (!priv) ++ return; ++ ++ /* don't strip the header if vlan mode is disabled */ ++ if (!priv->vlan) ++ return; ++ ++ /* strip header, get vlan id */ ++ buf = skb->data; ++ skb_pull(skb, 2); ++ ++ /* check for vlan header presence */ ++ if ((buf[12 + 2] != 0x81) || (buf[13 + 2] != 0x00)) ++ return; ++ ++ port = buf[0] & 0x7; ++ ++ /* no need to fix up packets coming from a tagged source */ ++ if (priv->vlan_tagged & (1 << port)) ++ return; ++ ++ /* lookup port vid from local table, the switch passes an invalid vlan id */ ++ vlan = priv->vlan_id[priv->pvid[port]]; ++ ++ buf[14 + 2] &= 0xf0; ++ buf[14 + 2] |= vlan >> 8; ++ buf[15 + 2] = vlan & 0xff; ++} ++ ++#endif ++ ++int ++ar8216_wait_bit(struct ar8xxx_priv *priv, int reg, u32 mask, u32 val) ++{ ++ int timeout = 20; ++ u32 t = 0; ++ ++ while (1) { ++ t = ar8xxx_read(priv, reg); ++ if ((t & mask) == val) ++ return 0; ++ ++ if (timeout-- <= 0) ++ break; ++ ++ udelay(10); ++ cond_resched(); ++ } ++ ++ pr_err("ar8216: timeout on reg %08x: %08x & %08x != %08x\n", ++ (unsigned int) reg, t, mask, val); ++ return -ETIMEDOUT; ++} ++ ++static void ++ar8216_vtu_op(struct ar8xxx_priv *priv, u32 op, u32 val) ++{ ++ if (ar8216_wait_bit(priv, AR8216_REG_VTU, AR8216_VTU_ACTIVE, 0)) ++ return; ++ if ((op & AR8216_VTU_OP) == AR8216_VTU_OP_LOAD) { ++ val &= AR8216_VTUDATA_MEMBER; ++ val |= AR8216_VTUDATA_VALID; ++ ar8xxx_write(priv, AR8216_REG_VTU_DATA, val); ++ } ++ op |= AR8216_VTU_ACTIVE; ++ ar8xxx_write(priv, AR8216_REG_VTU, op); ++} ++ ++static void ++ar8216_vtu_flush(struct ar8xxx_priv *priv) ++{ ++ ar8216_vtu_op(priv, AR8216_VTU_OP_FLUSH, 0); ++} ++ ++static void ++ar8216_vtu_load_vlan(struct ar8xxx_priv *priv, u32 vid, u32 port_mask) ++{ ++ u32 op; ++ ++ op = AR8216_VTU_OP_LOAD | (vid << AR8216_VTU_VID_S); ++ ar8216_vtu_op(priv, op, port_mask); ++} ++ ++static int ++ar8216_atu_flush(struct ar8xxx_priv *priv) ++{ ++ int ret; ++ ++ ret = ar8216_wait_bit(priv, AR8216_REG_ATU_FUNC0, AR8216_ATU_ACTIVE, 0); ++ if (!ret) ++ ar8xxx_write(priv, AR8216_REG_ATU_FUNC0, AR8216_ATU_OP_FLUSH | ++ AR8216_ATU_ACTIVE); ++ ++ return ret; ++} ++ ++static int ++ar8216_atu_flush_port(struct ar8xxx_priv *priv, int port) ++{ ++ u32 t; ++ int ret; ++ ++ ret = ar8216_wait_bit(priv, AR8216_REG_ATU_FUNC0, AR8216_ATU_ACTIVE, 0); ++ if (!ret) { ++ t = (port << AR8216_ATU_PORT_NUM_S) | AR8216_ATU_OP_FLUSH_PORT; ++ t |= AR8216_ATU_ACTIVE; ++ ar8xxx_write(priv, AR8216_REG_ATU_FUNC0, t); ++ } ++ ++ return ret; ++} ++ ++static u32 ++ar8216_read_port_status(struct ar8xxx_priv *priv, int port) ++{ ++ return ar8xxx_read(priv, AR8216_REG_PORT_STATUS(port)); ++} ++ ++static void ++__ar8216_setup_port(struct ar8xxx_priv *priv, int port, u32 members, ++ bool ath_hdr_en) ++{ ++ u32 header; ++ u32 egress, ingress; ++ u32 pvid; ++ ++ if (priv->vlan) { ++ pvid = priv->vlan_id[priv->pvid[port]]; ++ if (priv->vlan_tagged & (1 << port)) ++ egress = AR8216_OUT_ADD_VLAN; ++ else ++ egress = AR8216_OUT_STRIP_VLAN; ++ ingress = AR8216_IN_SECURE; ++ } else { ++ pvid = port; ++ egress = AR8216_OUT_KEEP; ++ ingress = AR8216_IN_PORT_ONLY; ++ } ++ ++ header = ath_hdr_en ? AR8216_PORT_CTRL_HEADER : 0; ++ ++ ar8xxx_rmw(priv, AR8216_REG_PORT_CTRL(port), ++ AR8216_PORT_CTRL_LEARN | AR8216_PORT_CTRL_VLAN_MODE | ++ AR8216_PORT_CTRL_SINGLE_VLAN | AR8216_PORT_CTRL_STATE | ++ AR8216_PORT_CTRL_HEADER | AR8216_PORT_CTRL_LEARN_LOCK, ++ AR8216_PORT_CTRL_LEARN | header | ++ (egress << AR8216_PORT_CTRL_VLAN_MODE_S) | ++ (AR8216_PORT_STATE_FORWARD << AR8216_PORT_CTRL_STATE_S)); ++ ++ ar8xxx_rmw(priv, AR8216_REG_PORT_VLAN(port), ++ AR8216_PORT_VLAN_DEST_PORTS | AR8216_PORT_VLAN_MODE | ++ AR8216_PORT_VLAN_DEFAULT_ID, ++ (members << AR8216_PORT_VLAN_DEST_PORTS_S) | ++ (ingress << AR8216_PORT_VLAN_MODE_S) | ++ (pvid << AR8216_PORT_VLAN_DEFAULT_ID_S)); ++} ++ ++static void ++ar8216_setup_port(struct ar8xxx_priv *priv, int port, u32 members) ++{ ++ return __ar8216_setup_port(priv, port, members, ++ chip_is_ar8216(priv) && priv->vlan && ++ port == AR8216_PORT_CPU); ++} ++ ++static int ++ar8216_hw_init(struct ar8xxx_priv *priv) ++{ ++ if (priv->initialized) ++ return 0; ++ ++ ar8xxx_write(priv, AR8216_REG_CTRL, AR8216_CTRL_RESET); ++ ar8xxx_reg_wait(priv, AR8216_REG_CTRL, AR8216_CTRL_RESET, 0, 1000); ++ ++ ar8xxx_phy_init(priv); ++ ++ priv->initialized = true; ++ return 0; ++} ++ ++static void ++ar8216_init_globals(struct ar8xxx_priv *priv) ++{ ++ /* standard atheros magic */ ++ ar8xxx_write(priv, 0x38, 0xc000050e); ++ ++ ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CTRL, ++ AR8216_GCTRL_MTU, 1518 + 8 + 2); ++} ++ ++static void ++__ar8216_init_port(struct ar8xxx_priv *priv, int port, ++ bool cpu_ge, bool flow_en) ++{ ++ /* Enable port learning and tx */ ++ ar8xxx_write(priv, AR8216_REG_PORT_CTRL(port), ++ AR8216_PORT_CTRL_LEARN | ++ (4 << AR8216_PORT_CTRL_STATE_S)); ++ ++ ar8xxx_write(priv, AR8216_REG_PORT_VLAN(port), 0); ++ ++ if (port == AR8216_PORT_CPU) { ++ ar8xxx_write(priv, AR8216_REG_PORT_STATUS(port), ++ AR8216_PORT_STATUS_LINK_UP | ++ (cpu_ge ? AR8216_PORT_SPEED_1000M : AR8216_PORT_SPEED_100M) | ++ AR8216_PORT_STATUS_TXMAC | ++ AR8216_PORT_STATUS_RXMAC | ++ (flow_en ? AR8216_PORT_STATUS_RXFLOW : 0) | ++ (flow_en ? AR8216_PORT_STATUS_TXFLOW : 0) | ++ AR8216_PORT_STATUS_DUPLEX); ++ } else { ++ ar8xxx_write(priv, AR8216_REG_PORT_STATUS(port), ++ AR8216_PORT_STATUS_LINK_AUTO); ++ } ++} ++ ++static void ++ar8216_init_port(struct ar8xxx_priv *priv, int port) ++{ ++ __ar8216_init_port(priv, port, ar8xxx_has_gige(priv), ++ chip_is_ar8316(priv)); ++} ++ ++static void ++ar8216_wait_atu_ready(struct ar8xxx_priv *priv, u16 r2, u16 r1) ++{ ++ int timeout = 20; ++ ++ while (ar8xxx_mii_read32(priv, r2, r1) & AR8216_ATU_ACTIVE && --timeout) { ++ udelay(10); ++ cond_resched(); ++ } ++ ++ if (!timeout) ++ pr_err("ar8216: timeout waiting for atu to become ready\n"); ++} ++ ++static void ar8216_get_arl_entry(struct ar8xxx_priv *priv, ++ struct arl_entry *a, u32 *status, enum arl_op op) ++{ ++ struct mii_bus *bus = priv->mii_bus; ++ u16 r2, page; ++ u16 r1_func0, r1_func1, r1_func2; ++ u32 t, val0, val1, val2; ++ ++ split_addr(AR8216_REG_ATU_FUNC0, &r1_func0, &r2, &page); ++ r2 |= 0x10; ++ ++ r1_func1 = (AR8216_REG_ATU_FUNC1 >> 1) & 0x1e; ++ r1_func2 = (AR8216_REG_ATU_FUNC2 >> 1) & 0x1e; ++ ++ switch (op) { ++ case AR8XXX_ARL_INITIALIZE: ++ /* all ATU registers are on the same page ++ * therefore set page only once ++ */ ++ bus->write(bus, 0x18, 0, page); ++ wait_for_page_switch(); ++ ++ ar8216_wait_atu_ready(priv, r2, r1_func0); ++ ++ ar8xxx_mii_write32(priv, r2, r1_func0, AR8216_ATU_OP_GET_NEXT); ++ ar8xxx_mii_write32(priv, r2, r1_func1, 0); ++ ar8xxx_mii_write32(priv, r2, r1_func2, 0); ++ break; ++ case AR8XXX_ARL_GET_NEXT: ++ t = ar8xxx_mii_read32(priv, r2, r1_func0); ++ t |= AR8216_ATU_ACTIVE; ++ ar8xxx_mii_write32(priv, r2, r1_func0, t); ++ ar8216_wait_atu_ready(priv, r2, r1_func0); ++ ++ val0 = ar8xxx_mii_read32(priv, r2, r1_func0); ++ val1 = ar8xxx_mii_read32(priv, r2, r1_func1); ++ val2 = ar8xxx_mii_read32(priv, r2, r1_func2); ++ ++ *status = (val2 & AR8216_ATU_STATUS) >> AR8216_ATU_STATUS_S; ++ if (!*status) ++ break; ++ ++ a->portmap = (val2 & AR8216_ATU_PORTS) >> AR8216_ATU_PORTS_S; ++ a->mac[0] = (val0 & AR8216_ATU_ADDR5) >> AR8216_ATU_ADDR5_S; ++ a->mac[1] = (val0 & AR8216_ATU_ADDR4) >> AR8216_ATU_ADDR4_S; ++ a->mac[2] = (val1 & AR8216_ATU_ADDR3) >> AR8216_ATU_ADDR3_S; ++ a->mac[3] = (val1 & AR8216_ATU_ADDR2) >> AR8216_ATU_ADDR2_S; ++ a->mac[4] = (val1 & AR8216_ATU_ADDR1) >> AR8216_ATU_ADDR1_S; ++ a->mac[5] = (val1 & AR8216_ATU_ADDR0) >> AR8216_ATU_ADDR0_S; ++ break; ++ } ++} ++ ++static int ++ar8216_phy_read(struct ar8xxx_priv *priv, int addr, int regnum) ++{ ++ u32 t, val = 0xffff; ++ int err; ++ ++ if (addr >= AR8216_NUM_PORTS) ++ return 0xffff; ++ t = (regnum << AR8216_MDIO_CTRL_REG_ADDR_S) | ++ (addr << AR8216_MDIO_CTRL_PHY_ADDR_S) | ++ AR8216_MDIO_CTRL_MASTER_EN | ++ AR8216_MDIO_CTRL_BUSY | ++ AR8216_MDIO_CTRL_CMD_READ; ++ ++ ar8xxx_write(priv, AR8216_REG_MDIO_CTRL, t); ++ err = ar8xxx_reg_wait(priv, AR8216_REG_MDIO_CTRL, ++ AR8216_MDIO_CTRL_BUSY, 0, 5); ++ if (!err) ++ val = ar8xxx_read(priv, AR8216_REG_MDIO_CTRL); ++ ++ return val & AR8216_MDIO_CTRL_DATA_M; ++} ++ ++static int ++ar8216_phy_write(struct ar8xxx_priv *priv, int addr, int regnum, u16 val) ++{ ++ u32 t; ++ int ret; ++ ++ if (addr >= AR8216_NUM_PORTS) ++ return -EINVAL; ++ ++ t = (addr << AR8216_MDIO_CTRL_PHY_ADDR_S) | ++ (regnum << AR8216_MDIO_CTRL_REG_ADDR_S) | ++ AR8216_MDIO_CTRL_MASTER_EN | ++ AR8216_MDIO_CTRL_BUSY | ++ AR8216_MDIO_CTRL_CMD_WRITE | ++ val; ++ ++ ar8xxx_write(priv, AR8216_REG_MDIO_CTRL, t); ++ ret = ar8xxx_reg_wait(priv, AR8216_REG_MDIO_CTRL, ++ AR8216_MDIO_CTRL_BUSY, 0, 5); ++ ++ return ret; ++} ++ ++static int ++ar8229_hw_init(struct ar8xxx_priv *priv) ++{ ++ phy_interface_t phy_if_mode; ++ ++ if (priv->initialized) ++ return 0; ++ ++ ar8xxx_write(priv, AR8216_REG_CTRL, AR8216_CTRL_RESET); ++ ar8xxx_reg_wait(priv, AR8216_REG_CTRL, AR8216_CTRL_RESET, 0, 1000); ++ ++ of_get_phy_mode(priv->pdev->of_node, &phy_if_mode); ++ ++ if (phy_if_mode == PHY_INTERFACE_MODE_GMII) { ++ ar8xxx_write(priv, AR8229_REG_OPER_MODE0, ++ AR8229_OPER_MODE0_MAC_GMII_EN); ++ } else if (phy_if_mode == PHY_INTERFACE_MODE_MII) { ++ ar8xxx_write(priv, AR8229_REG_OPER_MODE0, ++ AR8229_OPER_MODE0_PHY_MII_EN); ++ } else { ++ pr_err("ar8229: unsupported mii mode\n"); ++ return -EINVAL; ++ } ++ ++ if (priv->port4_phy) { ++ ar8xxx_write(priv, AR8229_REG_OPER_MODE1, ++ AR8229_REG_OPER_MODE1_PHY4_MII_EN); ++ /* disable port5 to prevent mii conflict */ ++ ar8xxx_write(priv, AR8216_REG_PORT_STATUS(5), 0); ++ } ++ ++ ar8xxx_phy_init(priv); ++ ++ priv->initialized = true; ++ return 0; ++} ++ ++static void ++ar8229_init_globals(struct ar8xxx_priv *priv) ++{ ++ ++ /* Enable CPU port, and disable mirror port */ ++ ar8xxx_write(priv, AR8216_REG_GLOBAL_CPUPORT, ++ AR8216_GLOBAL_CPUPORT_EN | ++ (15 << AR8216_GLOBAL_CPUPORT_MIRROR_PORT_S)); ++ ++ /* Setup TAG priority mapping */ ++ ar8xxx_write(priv, AR8216_REG_TAG_PRIORITY, 0xfa50); ++ ++ /* Enable aging, MAC replacing */ ++ ar8xxx_write(priv, AR8216_REG_ATU_CTRL, ++ 0x2b /* 5 min age time */ | ++ AR8216_ATU_CTRL_AGE_EN | ++ AR8216_ATU_CTRL_LEARN_CHANGE); ++ ++ /* Enable ARP frame acknowledge */ ++ ar8xxx_reg_set(priv, AR8229_REG_QM_CTRL, ++ AR8229_QM_CTRL_ARP_EN); ++ ++ /* ++ * Enable Broadcast/unknown multicast and unicast frames ++ * transmitted to the CPU port. ++ */ ++ ar8xxx_reg_set(priv, AR8216_REG_FLOOD_MASK, ++ AR8229_FLOOD_MASK_BC_DP(0) | ++ AR8229_FLOOD_MASK_MC_DP(0) | ++ AR8229_FLOOD_MASK_UC_DP(0)); ++ ++ /* setup MTU */ ++ ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CTRL, ++ AR8236_GCTRL_MTU, AR8236_GCTRL_MTU); ++ ++ /* Enable MIB counters */ ++ ar8xxx_reg_set(priv, AR8216_REG_MIB_FUNC, ++ AR8236_MIB_EN); ++ ++ /* setup Service TAG */ ++ ar8xxx_rmw(priv, AR8216_REG_SERVICE_TAG, AR8216_SERVICE_TAG_M, 0); ++} ++ ++static void ++ar8229_init_port(struct ar8xxx_priv *priv, int port) ++{ ++ __ar8216_init_port(priv, port, true, true); ++} ++ ++ ++static int ++ar7240sw_hw_init(struct ar8xxx_priv *priv) ++{ ++ if (priv->initialized) ++ return 0; ++ ++ ar8xxx_write(priv, AR8216_REG_CTRL, AR8216_CTRL_RESET); ++ ar8xxx_reg_wait(priv, AR8216_REG_CTRL, AR8216_CTRL_RESET, 0, 1000); ++ ++ priv->port4_phy = 1; ++ /* disable port5 to prevent mii conflict */ ++ ar8xxx_write(priv, AR8216_REG_PORT_STATUS(5), 0); ++ ++ ar8xxx_phy_init(priv); ++ ++ priv->initialized = true; ++ return 0; ++} ++ ++static void ++ar7240sw_init_globals(struct ar8xxx_priv *priv) ++{ ++ ++ /* Enable CPU port, and disable mirror port */ ++ ar8xxx_write(priv, AR8216_REG_GLOBAL_CPUPORT, ++ AR8216_GLOBAL_CPUPORT_EN | ++ (15 << AR8216_GLOBAL_CPUPORT_MIRROR_PORT_S)); ++ ++ /* Setup TAG priority mapping */ ++ ar8xxx_write(priv, AR8216_REG_TAG_PRIORITY, 0xfa50); ++ ++ /* Enable ARP frame acknowledge, aging, MAC replacing */ ++ ar8xxx_write(priv, AR8216_REG_ATU_CTRL, ++ AR8216_ATU_CTRL_RESERVED | ++ 0x2b /* 5 min age time */ | ++ AR8216_ATU_CTRL_AGE_EN | ++ AR8216_ATU_CTRL_ARP_EN | ++ AR8216_ATU_CTRL_LEARN_CHANGE); ++ ++ /* Enable Broadcast frames transmitted to the CPU */ ++ ar8xxx_reg_set(priv, AR8216_REG_FLOOD_MASK, ++ AR8216_FM_CPU_BROADCAST_EN); ++ ++ /* setup MTU */ ++ ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CTRL, ++ AR8216_GCTRL_MTU, ++ AR8216_GCTRL_MTU); ++ ++ /* setup Service TAG */ ++ ar8xxx_rmw(priv, AR8216_REG_SERVICE_TAG, AR8216_SERVICE_TAG_M, 0); ++} ++ ++static void ++ar7240sw_setup_port(struct ar8xxx_priv *priv, int port, u32 members) ++{ ++ return __ar8216_setup_port(priv, port, members, false); ++} ++ ++static void ++ar8236_setup_port(struct ar8xxx_priv *priv, int port, u32 members) ++{ ++ u32 egress, ingress; ++ u32 pvid; ++ ++ if (priv->vlan) { ++ pvid = priv->vlan_id[priv->pvid[port]]; ++ if (priv->vlan_tagged & (1 << port)) ++ egress = AR8216_OUT_ADD_VLAN; ++ else ++ egress = AR8216_OUT_STRIP_VLAN; ++ ingress = AR8216_IN_SECURE; ++ } else { ++ pvid = port; ++ egress = AR8216_OUT_KEEP; ++ ingress = AR8216_IN_PORT_ONLY; ++ } ++ ++ ar8xxx_rmw(priv, AR8216_REG_PORT_CTRL(port), ++ AR8216_PORT_CTRL_LEARN | AR8216_PORT_CTRL_VLAN_MODE | ++ AR8216_PORT_CTRL_SINGLE_VLAN | AR8216_PORT_CTRL_STATE | ++ AR8216_PORT_CTRL_HEADER | AR8216_PORT_CTRL_LEARN_LOCK, ++ AR8216_PORT_CTRL_LEARN | ++ (egress << AR8216_PORT_CTRL_VLAN_MODE_S) | ++ (AR8216_PORT_STATE_FORWARD << AR8216_PORT_CTRL_STATE_S)); ++ ++ ar8xxx_rmw(priv, AR8236_REG_PORT_VLAN(port), ++ AR8236_PORT_VLAN_DEFAULT_ID, ++ (pvid << AR8236_PORT_VLAN_DEFAULT_ID_S)); ++ ++ ar8xxx_rmw(priv, AR8236_REG_PORT_VLAN2(port), ++ AR8236_PORT_VLAN2_VLAN_MODE | ++ AR8236_PORT_VLAN2_MEMBER, ++ (ingress << AR8236_PORT_VLAN2_VLAN_MODE_S) | ++ (members << AR8236_PORT_VLAN2_MEMBER_S)); ++} ++ ++static void ++ar8236_init_globals(struct ar8xxx_priv *priv) ++{ ++ /* enable jumbo frames */ ++ ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CTRL, ++ AR8316_GCTRL_MTU, 9018 + 8 + 2); ++ ++ /* enable cpu port to receive arp frames */ ++ ar8xxx_reg_set(priv, AR8216_REG_ATU_CTRL, ++ AR8236_ATU_CTRL_RES); ++ ++ /* ++ * Enable Broadcast/unknown multicast and unicast frames ++ * transmitted to the CPU port. ++ */ ++ ar8xxx_reg_set(priv, AR8216_REG_FLOOD_MASK, ++ AR8229_FLOOD_MASK_BC_DP(0) | ++ AR8229_FLOOD_MASK_MC_DP(0) | ++ AR8229_FLOOD_MASK_UC_DP(0)); ++ ++ /* Enable MIB counters */ ++ ar8xxx_rmw(priv, AR8216_REG_MIB_FUNC, AR8216_MIB_FUNC | AR8236_MIB_EN, ++ (AR8216_MIB_FUNC_NO_OP << AR8216_MIB_FUNC_S) | ++ AR8236_MIB_EN); ++} ++ ++static int ++ar8316_hw_init(struct ar8xxx_priv *priv) ++{ ++ u32 val, newval; ++ ++ val = ar8xxx_read(priv, AR8316_REG_POSTRIP); ++ ++ if (priv->phy->interface == PHY_INTERFACE_MODE_RGMII) { ++ if (priv->port4_phy) { ++ /* value taken from Ubiquiti RouterStation Pro */ ++ newval = 0x81461bea; ++ pr_info("ar8316: Using port 4 as PHY\n"); ++ } else { ++ newval = 0x01261be2; ++ pr_info("ar8316: Using port 4 as switch port\n"); ++ } ++ } else if (priv->phy->interface == PHY_INTERFACE_MODE_GMII) { ++ /* value taken from AVM Fritz!Box 7390 sources */ ++ newval = 0x010e5b71; ++ } else { ++ /* no known value for phy interface */ ++ pr_err("ar8316: unsupported mii mode: %d.\n", ++ priv->phy->interface); ++ return -EINVAL; ++ } ++ ++ if (val == newval) ++ goto out; ++ ++ ar8xxx_write(priv, AR8316_REG_POSTRIP, newval); ++ ++ if (priv->port4_phy && ++ priv->phy->interface == PHY_INTERFACE_MODE_RGMII) { ++ /* work around for phy4 rgmii mode */ ++ ar8xxx_phy_dbg_write(priv, 4, 0x12, 0x480c); ++ /* rx delay */ ++ ar8xxx_phy_dbg_write(priv, 4, 0x0, 0x824e); ++ /* tx delay */ ++ ar8xxx_phy_dbg_write(priv, 4, 0x5, 0x3d47); ++ msleep(1000); ++ } ++ ++ ar8xxx_phy_init(priv); ++ ++out: ++ priv->initialized = true; ++ return 0; ++} ++ ++static void ++ar8316_init_globals(struct ar8xxx_priv *priv) ++{ ++ /* standard atheros magic */ ++ ar8xxx_write(priv, 0x38, 0xc000050e); ++ ++ /* enable cpu port to receive multicast and broadcast frames */ ++ ar8xxx_write(priv, AR8216_REG_FLOOD_MASK, 0x003f003f); ++ ++ /* enable jumbo frames */ ++ ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CTRL, ++ AR8316_GCTRL_MTU, 9018 + 8 + 2); ++ ++ /* Enable MIB counters */ ++ ar8xxx_rmw(priv, AR8216_REG_MIB_FUNC, AR8216_MIB_FUNC | AR8236_MIB_EN, ++ (AR8216_MIB_FUNC_NO_OP << AR8216_MIB_FUNC_S) | ++ AR8236_MIB_EN); ++} ++ ++int ++ar8xxx_sw_set_vlan(struct switch_dev *dev, const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); ++ priv->vlan = !!val->value.i; ++ return 0; ++} ++ ++int ++ar8xxx_sw_get_vlan(struct switch_dev *dev, const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); ++ val->value.i = priv->vlan; ++ return 0; ++} ++ ++ ++int ++ar8xxx_sw_set_pvid(struct switch_dev *dev, int port, int vlan) ++{ ++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); ++ ++ /* make sure no invalid PVIDs get set */ ++ ++ if (vlan < 0 || vlan >= dev->vlans || ++ port < 0 || port >= AR8X16_MAX_PORTS) ++ return -EINVAL; ++ ++ priv->pvid[port] = vlan; ++ return 0; ++} ++ ++int ++ar8xxx_sw_get_pvid(struct switch_dev *dev, int port, int *vlan) ++{ ++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); ++ ++ if (port < 0 || port >= AR8X16_MAX_PORTS) ++ return -EINVAL; ++ ++ *vlan = priv->pvid[port]; ++ return 0; ++} ++ ++static int ++ar8xxx_sw_set_vid(struct switch_dev *dev, const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); ++ ++ if (val->port_vlan >= dev->vlans) ++ return -EINVAL; ++ ++ priv->vlan_id[val->port_vlan] = val->value.i; ++ return 0; ++} ++ ++static int ++ar8xxx_sw_get_vid(struct switch_dev *dev, const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); ++ val->value.i = priv->vlan_id[val->port_vlan]; ++ return 0; ++} ++ ++int ++ar8xxx_sw_get_port_link(struct switch_dev *dev, int port, ++ struct switch_port_link *link) ++{ ++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); ++ ++ ar8216_read_port_link(priv, port, link); ++ return 0; ++} ++ ++static int ++ar8xxx_sw_get_ports(struct switch_dev *dev, struct switch_val *val) ++{ ++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); ++ u8 ports; ++ int i; ++ ++ if (val->port_vlan >= dev->vlans) ++ return -EINVAL; ++ ++ ports = priv->vlan_table[val->port_vlan]; ++ val->len = 0; ++ for (i = 0; i < dev->ports; i++) { ++ struct switch_port *p; ++ ++ if (!(ports & (1 << i))) ++ continue; ++ ++ p = &val->value.ports[val->len++]; ++ p->id = i; ++ if (priv->vlan_tagged & (1 << i)) ++ p->flags = (1 << SWITCH_PORT_FLAG_TAGGED); ++ else ++ p->flags = 0; ++ } ++ return 0; ++} ++ ++static int ++ar8xxx_sw_set_ports(struct switch_dev *dev, struct switch_val *val) ++{ ++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); ++ u8 *vt = &priv->vlan_table[val->port_vlan]; ++ int i, j; ++ ++ *vt = 0; ++ for (i = 0; i < val->len; i++) { ++ struct switch_port *p = &val->value.ports[i]; ++ ++ if (p->flags & (1 << SWITCH_PORT_FLAG_TAGGED)) { ++ priv->vlan_tagged |= (1 << p->id); ++ } else { ++ priv->vlan_tagged &= ~(1 << p->id); ++ priv->pvid[p->id] = val->port_vlan; ++ ++ /* make sure that an untagged port does not ++ * appear in other vlans */ ++ for (j = 0; j < dev->vlans; j++) { ++ if (j == val->port_vlan) ++ continue; ++ priv->vlan_table[j] &= ~(1 << p->id); ++ } ++ } ++ ++ *vt |= 1 << p->id; ++ } ++ return 0; ++} ++ ++static void ++ar8216_set_mirror_regs(struct ar8xxx_priv *priv) ++{ ++ int port; ++ ++ /* reset all mirror registers */ ++ ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CPUPORT, ++ AR8216_GLOBAL_CPUPORT_MIRROR_PORT, ++ (0xF << AR8216_GLOBAL_CPUPORT_MIRROR_PORT_S)); ++ for (port = 0; port < AR8216_NUM_PORTS; port++) { ++ ar8xxx_reg_clear(priv, AR8216_REG_PORT_CTRL(port), ++ AR8216_PORT_CTRL_MIRROR_RX); ++ ++ ar8xxx_reg_clear(priv, AR8216_REG_PORT_CTRL(port), ++ AR8216_PORT_CTRL_MIRROR_TX); ++ } ++ ++ /* now enable mirroring if necessary */ ++ if (priv->source_port >= AR8216_NUM_PORTS || ++ priv->monitor_port >= AR8216_NUM_PORTS || ++ priv->source_port == priv->monitor_port) { ++ return; ++ } ++ ++ ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CPUPORT, ++ AR8216_GLOBAL_CPUPORT_MIRROR_PORT, ++ (priv->monitor_port << AR8216_GLOBAL_CPUPORT_MIRROR_PORT_S)); ++ ++ if (priv->mirror_rx) ++ ar8xxx_reg_set(priv, AR8216_REG_PORT_CTRL(priv->source_port), ++ AR8216_PORT_CTRL_MIRROR_RX); ++ ++ if (priv->mirror_tx) ++ ar8xxx_reg_set(priv, AR8216_REG_PORT_CTRL(priv->source_port), ++ AR8216_PORT_CTRL_MIRROR_TX); ++} ++ ++static inline u32 ++ar8xxx_age_time_val(int age_time) ++{ ++ return (age_time + AR8XXX_REG_ARL_CTRL_AGE_TIME_SECS / 2) / ++ AR8XXX_REG_ARL_CTRL_AGE_TIME_SECS; ++} ++ ++static inline void ++ar8xxx_set_age_time(struct ar8xxx_priv *priv, int reg) ++{ ++ u32 age_time = ar8xxx_age_time_val(priv->arl_age_time); ++ ar8xxx_rmw(priv, reg, AR8216_ATU_CTRL_AGE_TIME, age_time << AR8216_ATU_CTRL_AGE_TIME_S); ++} ++ ++int ++ar8xxx_sw_hw_apply(struct switch_dev *dev) ++{ ++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); ++ const struct ar8xxx_chip *chip = priv->chip; ++ u8 portmask[AR8X16_MAX_PORTS]; ++ int i, j; ++ ++ mutex_lock(&priv->reg_mutex); ++ /* flush all vlan translation unit entries */ ++ priv->chip->vtu_flush(priv); ++ ++ memset(portmask, 0, sizeof(portmask)); ++ if (!priv->init) { ++ /* calculate the port destination masks and load vlans ++ * into the vlan translation unit */ ++ for (j = 0; j < dev->vlans; j++) { ++ u8 vp = priv->vlan_table[j]; ++ ++ if (!vp) ++ continue; ++ ++ for (i = 0; i < dev->ports; i++) { ++ u8 mask = (1 << i); ++ if (vp & mask) ++ portmask[i] |= vp & ~mask; ++ } ++ ++ chip->vtu_load_vlan(priv, priv->vlan_id[j], ++ priv->vlan_table[j]); ++ } ++ } else { ++ /* vlan disabled: ++ * isolate all ports, but connect them to the cpu port */ ++ for (i = 0; i < dev->ports; i++) { ++ if (i == AR8216_PORT_CPU) ++ continue; ++ ++ portmask[i] = 1 << AR8216_PORT_CPU; ++ portmask[AR8216_PORT_CPU] |= (1 << i); ++ } ++ } ++ ++ /* update the port destination mask registers and tag settings */ ++ for (i = 0; i < dev->ports; i++) { ++ chip->setup_port(priv, i, portmask[i]); ++ } ++ ++ chip->set_mirror_regs(priv); ++ ++ /* set age time */ ++ if (chip->reg_arl_ctrl) ++ ar8xxx_set_age_time(priv, chip->reg_arl_ctrl); ++ ++ mutex_unlock(&priv->reg_mutex); ++ return 0; ++} ++ ++int ++ar8xxx_sw_reset_switch(struct switch_dev *dev) ++{ ++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); ++ const struct ar8xxx_chip *chip = priv->chip; ++ int i; ++ ++ mutex_lock(&priv->reg_mutex); ++ memset(&priv->ar8xxx_priv_volatile, 0, sizeof(priv->ar8xxx_priv_volatile)); ++ ++ for (i = 0; i < dev->vlans; i++) ++ priv->vlan_id[i] = i; ++ ++ /* Configure all ports */ ++ for (i = 0; i < dev->ports; i++) ++ chip->init_port(priv, i); ++ ++ priv->mirror_rx = false; ++ priv->mirror_tx = false; ++ priv->source_port = 0; ++ priv->monitor_port = 0; ++ priv->arl_age_time = AR8XXX_DEFAULT_ARL_AGE_TIME; ++ ++ chip->init_globals(priv); ++ chip->atu_flush(priv); ++ ++ mutex_unlock(&priv->reg_mutex); ++ ++ return chip->sw_hw_apply(dev); ++} ++ ++int ++ar8xxx_sw_set_reset_mibs(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); ++ unsigned int len; ++ int ret; ++ ++ if (!ar8xxx_has_mib_counters(priv)) ++ return -EOPNOTSUPP; ++ ++ mutex_lock(&priv->mib_lock); ++ ++ len = priv->dev.ports * priv->chip->num_mibs * ++ sizeof(*priv->mib_stats); ++ memset(priv->mib_stats, '\0', len); ++ ret = ar8xxx_mib_flush(priv); ++ if (ret) ++ goto unlock; ++ ++ ret = 0; ++ ++unlock: ++ mutex_unlock(&priv->mib_lock); ++ return ret; ++} ++ ++int ++ar8xxx_sw_set_mib_poll_interval(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); ++ ++ if (!ar8xxx_has_mib_counters(priv)) ++ return -EOPNOTSUPP; ++ ++ ar8xxx_mib_stop(priv); ++ priv->mib_poll_interval = val->value.i; ++ ar8xxx_mib_start(priv); ++ ++ return 0; ++} ++ ++int ++ar8xxx_sw_get_mib_poll_interval(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); ++ ++ if (!ar8xxx_has_mib_counters(priv)) ++ return -EOPNOTSUPP; ++ val->value.i = priv->mib_poll_interval; ++ return 0; ++} ++ ++int ++ar8xxx_sw_set_mib_type(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); ++ ++ if (!ar8xxx_has_mib_counters(priv)) ++ return -EOPNOTSUPP; ++ priv->mib_type = val->value.i; ++ return 0; ++} ++ ++int ++ar8xxx_sw_get_mib_type(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); ++ ++ if (!ar8xxx_has_mib_counters(priv)) ++ return -EOPNOTSUPP; ++ val->value.i = priv->mib_type; ++ return 0; ++} ++ ++int ++ar8xxx_sw_set_mirror_rx_enable(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); ++ ++ mutex_lock(&priv->reg_mutex); ++ priv->mirror_rx = !!val->value.i; ++ priv->chip->set_mirror_regs(priv); ++ mutex_unlock(&priv->reg_mutex); ++ ++ return 0; ++} ++ ++int ++ar8xxx_sw_get_mirror_rx_enable(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); ++ val->value.i = priv->mirror_rx; ++ return 0; ++} ++ ++int ++ar8xxx_sw_set_mirror_tx_enable(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); ++ ++ mutex_lock(&priv->reg_mutex); ++ priv->mirror_tx = !!val->value.i; ++ priv->chip->set_mirror_regs(priv); ++ mutex_unlock(&priv->reg_mutex); ++ ++ return 0; ++} ++ ++int ++ar8xxx_sw_get_mirror_tx_enable(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); ++ val->value.i = priv->mirror_tx; ++ return 0; ++} ++ ++int ++ar8xxx_sw_set_mirror_monitor_port(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); ++ ++ mutex_lock(&priv->reg_mutex); ++ priv->monitor_port = val->value.i; ++ priv->chip->set_mirror_regs(priv); ++ mutex_unlock(&priv->reg_mutex); ++ ++ return 0; ++} ++ ++int ++ar8xxx_sw_get_mirror_monitor_port(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); ++ val->value.i = priv->monitor_port; ++ return 0; ++} ++ ++int ++ar8xxx_sw_set_mirror_source_port(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); ++ ++ mutex_lock(&priv->reg_mutex); ++ priv->source_port = val->value.i; ++ priv->chip->set_mirror_regs(priv); ++ mutex_unlock(&priv->reg_mutex); ++ ++ return 0; ++} ++ ++int ++ar8xxx_sw_get_mirror_source_port(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); ++ val->value.i = priv->source_port; ++ return 0; ++} ++ ++int ++ar8xxx_sw_set_port_reset_mib(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); ++ int port; ++ int ret; ++ ++ if (!ar8xxx_has_mib_counters(priv)) ++ return -EOPNOTSUPP; ++ ++ port = val->port_vlan; ++ if (port >= dev->ports) ++ return -EINVAL; ++ ++ mutex_lock(&priv->mib_lock); ++ ret = ar8xxx_mib_capture(priv); ++ if (ret) ++ goto unlock; ++ ++ ar8xxx_mib_fetch_port_stat(priv, port, true); ++ ++ ret = 0; ++ ++unlock: ++ mutex_unlock(&priv->mib_lock); ++ return ret; ++} ++ ++static void ++ar8xxx_byte_to_str(char *buf, int len, u64 byte) ++{ ++ unsigned long b; ++ const char *unit; ++ ++ if (byte >= 0x40000000) { /* 1 GiB */ ++ b = byte * 10 / 0x40000000; ++ unit = "GiB"; ++ } else if (byte >= 0x100000) { /* 1 MiB */ ++ b = byte * 10 / 0x100000; ++ unit = "MiB"; ++ } else if (byte >= 0x400) { /* 1 KiB */ ++ b = byte * 10 / 0x400; ++ unit = "KiB"; ++ } else { ++ b = byte; ++ unit = "Byte"; ++ } ++ if (strcmp(unit, "Byte")) ++ snprintf(buf, len, "%lu.%lu %s", b / 10, b % 10, unit); ++ else ++ snprintf(buf, len, "%lu %s", b, unit); ++} ++ ++int ++ar8xxx_sw_get_port_mib(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); ++ const struct ar8xxx_chip *chip = priv->chip; ++ u64 *mib_stats, mib_data; ++ unsigned int port; ++ int ret; ++ char *buf = priv->buf; ++ char buf1[64]; ++ const char *mib_name; ++ int i, len = 0; ++ bool mib_stats_empty = true; ++ ++ if (!ar8xxx_has_mib_counters(priv) || !priv->mib_poll_interval) ++ return -EOPNOTSUPP; ++ ++ port = val->port_vlan; ++ if (port >= dev->ports) ++ return -EINVAL; ++ ++ mutex_lock(&priv->mib_lock); ++ ret = ar8xxx_mib_capture(priv); ++ if (ret) ++ goto unlock; ++ ++ ar8xxx_mib_fetch_port_stat(priv, port, false); ++ ++ len += snprintf(buf + len, sizeof(priv->buf) - len, ++ "MIB counters\n"); ++ ++ mib_stats = &priv->mib_stats[port * chip->num_mibs]; ++ for (i = 0; i < chip->num_mibs; i++) { ++ if (chip->mib_decs[i].type > priv->mib_type) ++ continue; ++ mib_name = chip->mib_decs[i].name; ++ mib_data = mib_stats[i]; ++ len += snprintf(buf + len, sizeof(priv->buf) - len, ++ "%-12s: %llu\n", mib_name, mib_data); ++ if ((!strcmp(mib_name, "TxByte") || ++ !strcmp(mib_name, "RxGoodByte")) && ++ mib_data >= 1024) { ++ ar8xxx_byte_to_str(buf1, sizeof(buf1), mib_data); ++ --len; /* discard newline at the end of buf */ ++ len += snprintf(buf + len, sizeof(priv->buf) - len, ++ " (%s)\n", buf1); ++ } ++ if (mib_stats_empty && mib_data) ++ mib_stats_empty = false; ++ } ++ ++ if (mib_stats_empty) ++ len = snprintf(buf, sizeof(priv->buf), "No MIB data"); ++ ++ val->value.s = buf; ++ val->len = len; ++ ++ ret = 0; ++ ++unlock: ++ mutex_unlock(&priv->mib_lock); ++ return ret; ++} ++ ++int ++ar8xxx_sw_set_arl_age_time(struct switch_dev *dev, const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); ++ int age_time = val->value.i; ++ u32 age_time_val; ++ ++ if (age_time < 0) ++ return -EINVAL; ++ ++ age_time_val = ar8xxx_age_time_val(age_time); ++ if (age_time_val == 0 || age_time_val > 0xffff) ++ return -EINVAL; ++ ++ priv->arl_age_time = age_time; ++ return 0; ++} ++ ++int ++ar8xxx_sw_get_arl_age_time(struct switch_dev *dev, const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); ++ val->value.i = priv->arl_age_time; ++ return 0; ++} ++ ++int ++ar8xxx_sw_get_arl_table(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); ++ struct mii_bus *bus = priv->mii_bus; ++ const struct ar8xxx_chip *chip = priv->chip; ++ char *buf = priv->arl_buf; ++ int i, j, k, len = 0; ++ struct arl_entry *a, *a1; ++ u32 status; ++ ++ if (!chip->get_arl_entry) ++ return -EOPNOTSUPP; ++ ++ mutex_lock(&priv->reg_mutex); ++ mutex_lock(&bus->mdio_lock); ++ ++ chip->get_arl_entry(priv, NULL, NULL, AR8XXX_ARL_INITIALIZE); ++ ++ for(i = 0; i < AR8XXX_NUM_ARL_RECORDS; ++i) { ++ a = &priv->arl_table[i]; ++ duplicate: ++ chip->get_arl_entry(priv, a, &status, AR8XXX_ARL_GET_NEXT); ++ ++ if (!status) ++ break; ++ ++ /* avoid duplicates ++ * ARL table can include multiple valid entries ++ * per MAC, just with differing status codes ++ */ ++ for (j = 0; j < i; ++j) { ++ a1 = &priv->arl_table[j]; ++ if (!memcmp(a->mac, a1->mac, sizeof(a->mac))) { ++ /* ignore ports already seen in former entry */ ++ a->portmap &= ~a1->portmap; ++ if (!a->portmap) ++ goto duplicate; ++ } ++ } ++ } ++ ++ mutex_unlock(&bus->mdio_lock); ++ ++ len += snprintf(buf + len, sizeof(priv->arl_buf) - len, ++ "address resolution table\n"); ++ ++ if (i == AR8XXX_NUM_ARL_RECORDS) ++ len += snprintf(buf + len, sizeof(priv->arl_buf) - len, ++ "Too many entries found, displaying the first %d only!\n", ++ AR8XXX_NUM_ARL_RECORDS); ++ ++ for (j = 0; j < priv->dev.ports; ++j) { ++ for (k = 0; k < i; ++k) { ++ a = &priv->arl_table[k]; ++ if (!(a->portmap & BIT(j))) ++ continue; ++ len += snprintf(buf + len, sizeof(priv->arl_buf) - len, ++ "Port %d: MAC %02x:%02x:%02x:%02x:%02x:%02x\n", ++ j, ++ a->mac[5], a->mac[4], a->mac[3], ++ a->mac[2], a->mac[1], a->mac[0]); ++ } ++ } ++ ++ val->value.s = buf; ++ val->len = len; ++ ++ mutex_unlock(&priv->reg_mutex); ++ ++ return 0; ++} ++ ++int ++ar8xxx_sw_set_flush_arl_table(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); ++ int ret; ++ ++ mutex_lock(&priv->reg_mutex); ++ ret = priv->chip->atu_flush(priv); ++ mutex_unlock(&priv->reg_mutex); ++ ++ return ret; ++} ++ ++int ++ar8xxx_sw_set_flush_port_arl_table(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); ++ int port, ret; ++ ++ port = val->port_vlan; ++ if (port >= dev->ports) ++ return -EINVAL; ++ ++ mutex_lock(&priv->reg_mutex); ++ ret = priv->chip->atu_flush_port(priv, port); ++ mutex_unlock(&priv->reg_mutex); ++ ++ return ret; ++} ++ ++int ++ar8xxx_sw_get_port_stats(struct switch_dev *dev, int port, ++ struct switch_port_stats *stats) ++{ ++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); ++ u64 *mib_stats; ++ ++ if (!ar8xxx_has_mib_counters(priv) || !priv->mib_poll_interval) ++ return -EOPNOTSUPP; ++ ++ if (!(priv->chip->mib_rxb_id || priv->chip->mib_txb_id)) ++ return -EOPNOTSUPP; ++ ++ if (port >= dev->ports) ++ return -EINVAL; ++ ++ mutex_lock(&priv->mib_lock); ++ ++ mib_stats = &priv->mib_stats[port * priv->chip->num_mibs]; ++ ++ stats->tx_bytes = mib_stats[priv->chip->mib_txb_id]; ++ stats->rx_bytes = mib_stats[priv->chip->mib_rxb_id]; ++ ++ mutex_unlock(&priv->mib_lock); ++ return 0; ++} ++ ++static int ++ar8xxx_phy_read(struct mii_bus *bus, int phy_addr, int reg_addr) ++{ ++ struct ar8xxx_priv *priv = bus->priv; ++ return priv->chip->phy_read(priv, phy_addr, reg_addr); ++} ++ ++static int ++ar8xxx_phy_write(struct mii_bus *bus, int phy_addr, int reg_addr, ++ u16 reg_val) ++{ ++ struct ar8xxx_priv *priv = bus->priv; ++ return priv->chip->phy_write(priv, phy_addr, reg_addr, reg_val); ++} ++ ++static const struct switch_attr ar8xxx_sw_attr_globals[] = { ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "enable_vlan", ++ .description = "Enable VLAN mode", ++ .set = ar8xxx_sw_set_vlan, ++ .get = ar8xxx_sw_get_vlan, ++ .max = 1 ++ }, ++ { ++ .type = SWITCH_TYPE_NOVAL, ++ .name = "reset_mibs", ++ .description = "Reset all MIB counters", ++ .set = ar8xxx_sw_set_reset_mibs, ++ }, ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "ar8xxx_mib_poll_interval", ++ .description = "MIB polling interval in msecs (0 to disable)", ++ .set = ar8xxx_sw_set_mib_poll_interval, ++ .get = ar8xxx_sw_get_mib_poll_interval ++ }, ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "ar8xxx_mib_type", ++ .description = "MIB type (0=basic 1=extended)", ++ .set = ar8xxx_sw_set_mib_type, ++ .get = ar8xxx_sw_get_mib_type ++ }, ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "enable_mirror_rx", ++ .description = "Enable mirroring of RX packets", ++ .set = ar8xxx_sw_set_mirror_rx_enable, ++ .get = ar8xxx_sw_get_mirror_rx_enable, ++ .max = 1 ++ }, ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "enable_mirror_tx", ++ .description = "Enable mirroring of TX packets", ++ .set = ar8xxx_sw_set_mirror_tx_enable, ++ .get = ar8xxx_sw_get_mirror_tx_enable, ++ .max = 1 ++ }, ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "mirror_monitor_port", ++ .description = "Mirror monitor port", ++ .set = ar8xxx_sw_set_mirror_monitor_port, ++ .get = ar8xxx_sw_get_mirror_monitor_port, ++ .max = AR8216_NUM_PORTS - 1 ++ }, ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "mirror_source_port", ++ .description = "Mirror source port", ++ .set = ar8xxx_sw_set_mirror_source_port, ++ .get = ar8xxx_sw_get_mirror_source_port, ++ .max = AR8216_NUM_PORTS - 1 ++ }, ++ { ++ .type = SWITCH_TYPE_STRING, ++ .name = "arl_table", ++ .description = "Get ARL table", ++ .set = NULL, ++ .get = ar8xxx_sw_get_arl_table, ++ }, ++ { ++ .type = SWITCH_TYPE_NOVAL, ++ .name = "flush_arl_table", ++ .description = "Flush ARL table", ++ .set = ar8xxx_sw_set_flush_arl_table, ++ }, ++}; ++ ++const struct switch_attr ar8xxx_sw_attr_port[] = { ++ { ++ .type = SWITCH_TYPE_NOVAL, ++ .name = "reset_mib", ++ .description = "Reset single port MIB counters", ++ .set = ar8xxx_sw_set_port_reset_mib, ++ }, ++ { ++ .type = SWITCH_TYPE_STRING, ++ .name = "mib", ++ .description = "Get port's MIB counters", ++ .set = NULL, ++ .get = ar8xxx_sw_get_port_mib, ++ }, ++ { ++ .type = SWITCH_TYPE_NOVAL, ++ .name = "flush_arl_table", ++ .description = "Flush port's ARL table entries", ++ .set = ar8xxx_sw_set_flush_port_arl_table, ++ }, ++}; ++ ++const struct switch_attr ar8xxx_sw_attr_vlan[1] = { ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "vid", ++ .description = "VLAN ID (0-4094)", ++ .set = ar8xxx_sw_set_vid, ++ .get = ar8xxx_sw_get_vid, ++ .max = 4094, ++ }, ++}; ++ ++static const struct switch_dev_ops ar8xxx_sw_ops = { ++ .attr_global = { ++ .attr = ar8xxx_sw_attr_globals, ++ .n_attr = ARRAY_SIZE(ar8xxx_sw_attr_globals), ++ }, ++ .attr_port = { ++ .attr = ar8xxx_sw_attr_port, ++ .n_attr = ARRAY_SIZE(ar8xxx_sw_attr_port), ++ }, ++ .attr_vlan = { ++ .attr = ar8xxx_sw_attr_vlan, ++ .n_attr = ARRAY_SIZE(ar8xxx_sw_attr_vlan), ++ }, ++ .get_port_pvid = ar8xxx_sw_get_pvid, ++ .set_port_pvid = ar8xxx_sw_set_pvid, ++ .get_vlan_ports = ar8xxx_sw_get_ports, ++ .set_vlan_ports = ar8xxx_sw_set_ports, ++ .apply_config = ar8xxx_sw_hw_apply, ++ .reset_switch = ar8xxx_sw_reset_switch, ++ .get_port_link = ar8xxx_sw_get_port_link, ++ .get_port_stats = ar8xxx_sw_get_port_stats, ++}; ++ ++static const struct ar8xxx_chip ar7240sw_chip = { ++ .caps = AR8XXX_CAP_MIB_COUNTERS, ++ ++ .reg_port_stats_start = 0x20000, ++ .reg_port_stats_length = 0x100, ++ .reg_arl_ctrl = AR8216_REG_ATU_CTRL, ++ ++ .name = "Atheros AR724X/AR933X built-in", ++ .ports = AR7240SW_NUM_PORTS, ++ .vlans = AR8216_NUM_VLANS, ++ .swops = &ar8xxx_sw_ops, ++ ++ .hw_init = ar7240sw_hw_init, ++ .init_globals = ar7240sw_init_globals, ++ .init_port = ar8229_init_port, ++ .phy_read = ar8216_phy_read, ++ .phy_write = ar8216_phy_write, ++ .setup_port = ar7240sw_setup_port, ++ .read_port_status = ar8216_read_port_status, ++ .atu_flush = ar8216_atu_flush, ++ .atu_flush_port = ar8216_atu_flush_port, ++ .vtu_flush = ar8216_vtu_flush, ++ .vtu_load_vlan = ar8216_vtu_load_vlan, ++ .set_mirror_regs = ar8216_set_mirror_regs, ++ .get_arl_entry = ar8216_get_arl_entry, ++ .sw_hw_apply = ar8xxx_sw_hw_apply, ++ ++ .num_mibs = ARRAY_SIZE(ar8236_mibs), ++ .mib_decs = ar8236_mibs, ++ .mib_func = AR8216_REG_MIB_FUNC, ++ .mib_rxb_id = AR8236_MIB_RXB_ID, ++ .mib_txb_id = AR8236_MIB_TXB_ID, ++}; ++ ++static const struct ar8xxx_chip ar8216_chip = { ++ .caps = AR8XXX_CAP_MIB_COUNTERS, ++ ++ .reg_port_stats_start = 0x19000, ++ .reg_port_stats_length = 0xa0, ++ .reg_arl_ctrl = AR8216_REG_ATU_CTRL, ++ ++ .name = "Atheros AR8216", ++ .ports = AR8216_NUM_PORTS, ++ .vlans = AR8216_NUM_VLANS, ++ .swops = &ar8xxx_sw_ops, ++ ++ .hw_init = ar8216_hw_init, ++ .init_globals = ar8216_init_globals, ++ .init_port = ar8216_init_port, ++ .setup_port = ar8216_setup_port, ++ .read_port_status = ar8216_read_port_status, ++ .atu_flush = ar8216_atu_flush, ++ .atu_flush_port = ar8216_atu_flush_port, ++ .vtu_flush = ar8216_vtu_flush, ++ .vtu_load_vlan = ar8216_vtu_load_vlan, ++ .set_mirror_regs = ar8216_set_mirror_regs, ++ .get_arl_entry = ar8216_get_arl_entry, ++ .sw_hw_apply = ar8xxx_sw_hw_apply, ++ ++ .num_mibs = ARRAY_SIZE(ar8216_mibs), ++ .mib_decs = ar8216_mibs, ++ .mib_func = AR8216_REG_MIB_FUNC, ++ .mib_rxb_id = AR8216_MIB_RXB_ID, ++ .mib_txb_id = AR8216_MIB_TXB_ID, ++}; ++ ++static const struct ar8xxx_chip ar8229_chip = { ++ .caps = AR8XXX_CAP_MIB_COUNTERS, ++ ++ .reg_port_stats_start = 0x20000, ++ .reg_port_stats_length = 0x100, ++ .reg_arl_ctrl = AR8216_REG_ATU_CTRL, ++ ++ .name = "Atheros AR8229", ++ .ports = AR8216_NUM_PORTS, ++ .vlans = AR8216_NUM_VLANS, ++ .swops = &ar8xxx_sw_ops, ++ ++ .hw_init = ar8229_hw_init, ++ .init_globals = ar8229_init_globals, ++ .init_port = ar8229_init_port, ++ .phy_read = ar8216_phy_read, ++ .phy_write = ar8216_phy_write, ++ .setup_port = ar8236_setup_port, ++ .read_port_status = ar8216_read_port_status, ++ .atu_flush = ar8216_atu_flush, ++ .atu_flush_port = ar8216_atu_flush_port, ++ .vtu_flush = ar8216_vtu_flush, ++ .vtu_load_vlan = ar8216_vtu_load_vlan, ++ .set_mirror_regs = ar8216_set_mirror_regs, ++ .get_arl_entry = ar8216_get_arl_entry, ++ .sw_hw_apply = ar8xxx_sw_hw_apply, ++ ++ .num_mibs = ARRAY_SIZE(ar8236_mibs), ++ .mib_decs = ar8236_mibs, ++ .mib_func = AR8216_REG_MIB_FUNC, ++ .mib_rxb_id = AR8236_MIB_RXB_ID, ++ .mib_txb_id = AR8236_MIB_TXB_ID, ++}; ++ ++static const struct ar8xxx_chip ar8236_chip = { ++ .caps = AR8XXX_CAP_MIB_COUNTERS, ++ ++ .reg_port_stats_start = 0x20000, ++ .reg_port_stats_length = 0x100, ++ .reg_arl_ctrl = AR8216_REG_ATU_CTRL, ++ ++ .name = "Atheros AR8236", ++ .ports = AR8216_NUM_PORTS, ++ .vlans = AR8216_NUM_VLANS, ++ .swops = &ar8xxx_sw_ops, ++ ++ .hw_init = ar8216_hw_init, ++ .init_globals = ar8236_init_globals, ++ .init_port = ar8216_init_port, ++ .setup_port = ar8236_setup_port, ++ .read_port_status = ar8216_read_port_status, ++ .atu_flush = ar8216_atu_flush, ++ .atu_flush_port = ar8216_atu_flush_port, ++ .vtu_flush = ar8216_vtu_flush, ++ .vtu_load_vlan = ar8216_vtu_load_vlan, ++ .set_mirror_regs = ar8216_set_mirror_regs, ++ .get_arl_entry = ar8216_get_arl_entry, ++ .sw_hw_apply = ar8xxx_sw_hw_apply, ++ ++ .num_mibs = ARRAY_SIZE(ar8236_mibs), ++ .mib_decs = ar8236_mibs, ++ .mib_func = AR8216_REG_MIB_FUNC, ++ .mib_rxb_id = AR8236_MIB_RXB_ID, ++ .mib_txb_id = AR8236_MIB_TXB_ID, ++}; ++ ++static const struct ar8xxx_chip ar8316_chip = { ++ .caps = AR8XXX_CAP_GIGE | AR8XXX_CAP_MIB_COUNTERS, ++ ++ .reg_port_stats_start = 0x20000, ++ .reg_port_stats_length = 0x100, ++ .reg_arl_ctrl = AR8216_REG_ATU_CTRL, ++ ++ .name = "Atheros AR8316", ++ .ports = AR8216_NUM_PORTS, ++ .vlans = AR8X16_MAX_VLANS, ++ .swops = &ar8xxx_sw_ops, ++ ++ .hw_init = ar8316_hw_init, ++ .init_globals = ar8316_init_globals, ++ .init_port = ar8216_init_port, ++ .setup_port = ar8216_setup_port, ++ .read_port_status = ar8216_read_port_status, ++ .atu_flush = ar8216_atu_flush, ++ .atu_flush_port = ar8216_atu_flush_port, ++ .vtu_flush = ar8216_vtu_flush, ++ .vtu_load_vlan = ar8216_vtu_load_vlan, ++ .set_mirror_regs = ar8216_set_mirror_regs, ++ .get_arl_entry = ar8216_get_arl_entry, ++ .sw_hw_apply = ar8xxx_sw_hw_apply, ++ ++ .num_mibs = ARRAY_SIZE(ar8236_mibs), ++ .mib_decs = ar8236_mibs, ++ .mib_func = AR8216_REG_MIB_FUNC, ++ .mib_rxb_id = AR8236_MIB_RXB_ID, ++ .mib_txb_id = AR8236_MIB_TXB_ID, ++}; ++ ++static int ++ar8xxx_read_id(struct ar8xxx_priv *priv) ++{ ++ u32 val; ++ u16 id; ++ int i; ++ ++ val = ar8xxx_read(priv, AR8216_REG_CTRL); ++ if (val == ~0) ++ return -ENODEV; ++ ++ id = val & (AR8216_CTRL_REVISION | AR8216_CTRL_VERSION); ++ for (i = 0; i < AR8X16_PROBE_RETRIES; i++) { ++ u16 t; ++ ++ val = ar8xxx_read(priv, AR8216_REG_CTRL); ++ if (val == ~0) ++ return -ENODEV; ++ ++ t = val & (AR8216_CTRL_REVISION | AR8216_CTRL_VERSION); ++ if (t != id) ++ return -ENODEV; ++ } ++ ++ priv->chip_ver = (id & AR8216_CTRL_VERSION) >> AR8216_CTRL_VERSION_S; ++ priv->chip_rev = (id & AR8216_CTRL_REVISION); ++ return 0; ++} ++ ++static int ++ar8xxx_id_chip(struct ar8xxx_priv *priv) ++{ ++ int ret; ++ ++ ret = ar8xxx_read_id(priv); ++ if(ret) ++ return ret; ++ ++ switch (priv->chip_ver) { ++ case AR8XXX_VER_AR8216: ++ priv->chip = &ar8216_chip; ++ break; ++ case AR8XXX_VER_AR8236: ++ priv->chip = &ar8236_chip; ++ break; ++ case AR8XXX_VER_AR8316: ++ priv->chip = &ar8316_chip; ++ break; ++ case AR8XXX_VER_AR8327: ++ priv->chip = &ar8327_chip; ++ break; ++ case AR8XXX_VER_AR8337: ++ priv->chip = &ar8337_chip; ++ break; ++ default: ++ pr_err("ar8216: Unknown Atheros device [ver=%d, rev=%d]\n", ++ priv->chip_ver, priv->chip_rev); ++ ++ return -ENODEV; ++ } ++ ++ return 0; ++} ++ ++static void ++ar8xxx_mib_work_func(struct work_struct *work) ++{ ++ struct ar8xxx_priv *priv; ++ int err, i; ++ ++ priv = container_of(work, struct ar8xxx_priv, mib_work.work); ++ ++ mutex_lock(&priv->mib_lock); ++ ++ err = ar8xxx_mib_capture(priv); ++ if (err) ++ goto next_attempt; ++ ++ for (i = 0; i < priv->dev.ports; i++) ++ ar8xxx_mib_fetch_port_stat(priv, i, false); ++ ++next_attempt: ++ mutex_unlock(&priv->mib_lock); ++ schedule_delayed_work(&priv->mib_work, ++ msecs_to_jiffies(priv->mib_poll_interval)); ++} ++ ++static int ++ar8xxx_mib_init(struct ar8xxx_priv *priv) ++{ ++ unsigned int len; ++ ++ if (!ar8xxx_has_mib_counters(priv)) ++ return 0; ++ ++ BUG_ON(!priv->chip->mib_decs || !priv->chip->num_mibs); ++ ++ len = priv->dev.ports * priv->chip->num_mibs * ++ sizeof(*priv->mib_stats); ++ priv->mib_stats = kzalloc(len, GFP_KERNEL); ++ ++ if (!priv->mib_stats) ++ return -ENOMEM; ++ ++ return 0; ++} ++ ++static void ++ar8xxx_mib_start(struct ar8xxx_priv *priv) ++{ ++ if (!ar8xxx_has_mib_counters(priv) || !priv->mib_poll_interval) ++ return; ++ ++ schedule_delayed_work(&priv->mib_work, ++ msecs_to_jiffies(priv->mib_poll_interval)); ++} ++ ++static void ++ar8xxx_mib_stop(struct ar8xxx_priv *priv) ++{ ++ if (!ar8xxx_has_mib_counters(priv) || !priv->mib_poll_interval) ++ return; ++ ++ cancel_delayed_work_sync(&priv->mib_work); ++} ++ ++static struct ar8xxx_priv * ++ar8xxx_create(void) ++{ ++ struct ar8xxx_priv *priv; ++ ++ priv = kzalloc(sizeof(struct ar8xxx_priv), GFP_KERNEL); ++ if (priv == NULL) ++ return NULL; ++ ++ mutex_init(&priv->reg_mutex); ++ mutex_init(&priv->mib_lock); ++ INIT_DELAYED_WORK(&priv->mib_work, ar8xxx_mib_work_func); ++ ++ return priv; ++} ++ ++static void ++ar8xxx_free(struct ar8xxx_priv *priv) ++{ ++ if (priv->chip && priv->chip->cleanup) ++ priv->chip->cleanup(priv); ++ ++ kfree(priv->chip_data); ++ kfree(priv->mib_stats); ++ kfree(priv); ++} ++ ++static int ++ar8xxx_probe_switch(struct ar8xxx_priv *priv) ++{ ++ const struct ar8xxx_chip *chip; ++ struct switch_dev *swdev; ++ int ret; ++ ++ chip = priv->chip; ++ ++ swdev = &priv->dev; ++ swdev->cpu_port = AR8216_PORT_CPU; ++ swdev->name = chip->name; ++ swdev->vlans = chip->vlans; ++ swdev->ports = chip->ports; ++ swdev->ops = chip->swops; ++ ++ ret = ar8xxx_mib_init(priv); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static int ++ar8xxx_start(struct ar8xxx_priv *priv) ++{ ++ int ret; ++ ++ priv->init = true; ++ ++ ret = priv->chip->hw_init(priv); ++ if (ret) ++ return ret; ++ ++ ret = ar8xxx_sw_reset_switch(&priv->dev); ++ if (ret) ++ return ret; ++ ++ priv->init = false; ++ ++ ar8xxx_mib_start(priv); ++ ++ return 0; ++} ++ ++static int ++ar8xxx_phy_config_init(struct phy_device *phydev) ++{ ++ struct ar8xxx_priv *priv = phydev->priv; ++#ifdef CONFIG_ETHERNET_PACKET_MANGLE ++ struct net_device *dev = phydev->attached_dev; ++#endif ++ int ret; ++ ++ if (WARN_ON(!priv)) ++ return -ENODEV; ++ ++ if (priv->chip->config_at_probe) ++ return ar8xxx_phy_check_aneg(phydev); ++ ++ priv->phy = phydev; ++ ++ if (phydev->mdio.addr != 0) { ++ if (chip_is_ar8316(priv)) { ++ /* switch device has been initialized, reinit */ ++ priv->dev.ports = (AR8216_NUM_PORTS - 1); ++ priv->initialized = false; ++ priv->port4_phy = true; ++ ar8316_hw_init(priv); ++ return 0; ++ } ++ ++ return 0; ++ } ++ ++ ret = ar8xxx_start(priv); ++ if (ret) ++ return ret; ++ ++#ifdef CONFIG_ETHERNET_PACKET_MANGLE ++ /* VID fixup only needed on ar8216 */ ++ if (chip_is_ar8216(priv)) { ++ dev->phy_ptr = priv; ++ dev->priv_flags |= IFF_NO_IP_ALIGN; ++ dev->eth_mangle_rx = ar8216_mangle_rx; ++ dev->eth_mangle_tx = ar8216_mangle_tx; ++ } ++#endif ++ ++ return 0; ++} ++ ++static bool ++ar8xxx_check_link_states(struct ar8xxx_priv *priv) ++{ ++ bool link_new, changed = false; ++ u32 status; ++ int i; ++ ++ mutex_lock(&priv->reg_mutex); ++ ++ for (i = 0; i < priv->dev.ports; i++) { ++ status = priv->chip->read_port_status(priv, i); ++ link_new = !!(status & AR8216_PORT_STATUS_LINK_UP); ++ if (link_new == priv->link_up[i]) ++ continue; ++ ++ priv->link_up[i] = link_new; ++ changed = true; ++ /* flush ARL entries for this port if it went down*/ ++ if (!link_new) ++ priv->chip->atu_flush_port(priv, i); ++ dev_info(&priv->phy->mdio.dev, "Port %d is %s\n", ++ i, link_new ? "up" : "down"); ++ } ++ ++ mutex_unlock(&priv->reg_mutex); ++ ++ return changed; ++} ++ ++static int ++ar8xxx_phy_read_status(struct phy_device *phydev) ++{ ++ struct ar8xxx_priv *priv = phydev->priv; ++ struct switch_port_link link; ++ ++ /* check for switch port link changes */ ++ ar8xxx_check_link_states(priv); ++ ++ if (phydev->mdio.addr != 0) ++ return genphy_read_status(phydev); ++ ++ ar8216_read_port_link(priv, phydev->mdio.addr, &link); ++ phydev->link = !!link.link; ++ if (!phydev->link) ++ return 0; ++ ++ switch (link.speed) { ++ case SWITCH_PORT_SPEED_10: ++ phydev->speed = SPEED_10; ++ break; ++ case SWITCH_PORT_SPEED_100: ++ phydev->speed = SPEED_100; ++ break; ++ case SWITCH_PORT_SPEED_1000: ++ phydev->speed = SPEED_1000; ++ break; ++ default: ++ phydev->speed = 0; ++ } ++ phydev->duplex = link.duplex ? DUPLEX_FULL : DUPLEX_HALF; ++ ++ phydev->state = PHY_RUNNING; ++ netif_carrier_on(phydev->attached_dev); ++ if (phydev->adjust_link) ++ phydev->adjust_link(phydev->attached_dev); ++ ++ return 0; ++} ++ ++static int ++ar8xxx_phy_config_aneg(struct phy_device *phydev) ++{ ++ if (phydev->mdio.addr == 0) ++ return 0; ++ ++ return genphy_config_aneg(phydev); ++} ++ ++static int ++ar8xxx_get_features(struct phy_device *phydev) ++{ ++ struct ar8xxx_priv *priv = phydev->priv; ++ ++ linkmode_copy(phydev->supported, PHY_BASIC_FEATURES); ++ if (ar8xxx_has_gige(priv)) ++ linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, phydev->supported); ++ ++ return 0; ++} ++ ++static const u32 ar8xxx_phy_ids[] = { ++ 0x004dd033, ++ 0x004dd034, /* AR8327 */ ++ 0x004dd036, /* AR8337 */ ++ 0x004dd041, ++ 0x004dd042, ++ 0x004dd043, /* AR8236 */ ++}; ++ ++static bool ++ar8xxx_phy_match(u32 phy_id) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(ar8xxx_phy_ids); i++) ++ if (phy_id == ar8xxx_phy_ids[i]) ++ return true; ++ ++ return false; ++} ++ ++static bool ++ar8xxx_is_possible(struct mii_bus *bus) ++{ ++ unsigned int i, found_phys = 0; ++ ++ for (i = 0; i < 5; i++) { ++ u32 phy_id; ++ ++ phy_id = mdiobus_read(bus, i, MII_PHYSID1) << 16; ++ phy_id |= mdiobus_read(bus, i, MII_PHYSID2); ++ if (ar8xxx_phy_match(phy_id)) { ++ found_phys++; ++ } else if (phy_id) { ++ pr_debug("ar8xxx: unknown PHY at %s:%02x id:%08x\n", ++ dev_name(&bus->dev), i, phy_id); ++ } ++ } ++ return !!found_phys; ++} ++ ++static int ++ar8xxx_phy_probe(struct phy_device *phydev) ++{ ++ struct ar8xxx_priv *priv; ++ struct switch_dev *swdev; ++ int ret; ++ ++ /* skip PHYs at unused adresses */ ++ if (phydev->mdio.addr != 0 && phydev->mdio.addr != 3 && phydev->mdio.addr != 4) ++ return -ENODEV; ++ ++ if (!ar8xxx_is_possible(phydev->mdio.bus)) ++ return -ENODEV; ++ ++ mutex_lock(&ar8xxx_dev_list_lock); ++ list_for_each_entry(priv, &ar8xxx_dev_list, list) ++ if (priv->mii_bus == phydev->mdio.bus) ++ goto found; ++ ++ priv = ar8xxx_create(); ++ if (priv == NULL) { ++ ret = -ENOMEM; ++ goto unlock; ++ } ++ ++ priv->mii_bus = phydev->mdio.bus; ++ priv->pdev = &phydev->mdio.dev; ++ ++ ret = of_property_read_u32(priv->pdev->of_node, "qca,mib-poll-interval", ++ &priv->mib_poll_interval); ++ if (ret) ++ priv->mib_poll_interval = 0; ++ ++ ret = ar8xxx_id_chip(priv); ++ if (ret) ++ goto free_priv; ++ ++ ret = ar8xxx_probe_switch(priv); ++ if (ret) ++ goto free_priv; ++ ++ swdev = &priv->dev; ++ swdev->alias = dev_name(&priv->mii_bus->dev); ++ ret = register_switch(swdev, NULL); ++ if (ret) ++ goto free_priv; ++ ++ pr_info("%s: %s rev. %u switch registered on %s\n", ++ swdev->devname, swdev->name, priv->chip_rev, ++ dev_name(&priv->mii_bus->dev)); ++ ++ list_add(&priv->list, &ar8xxx_dev_list); ++ ++found: ++ priv->use_count++; ++ ++ if (phydev->mdio.addr == 0 && priv->chip->config_at_probe) { ++ priv->phy = phydev; ++ ++ ret = ar8xxx_start(priv); ++ if (ret) ++ goto err_unregister_switch; ++ } else if (priv->chip->phy_rgmii_set) { ++ priv->chip->phy_rgmii_set(priv, phydev); ++ } ++ ++ phydev->priv = priv; ++ ++ mutex_unlock(&ar8xxx_dev_list_lock); ++ ++ return 0; ++ ++err_unregister_switch: ++ if (--priv->use_count) ++ goto unlock; ++ ++ unregister_switch(&priv->dev); ++ ++free_priv: ++ ar8xxx_free(priv); ++unlock: ++ mutex_unlock(&ar8xxx_dev_list_lock); ++ return ret; ++} ++ ++static void ++ar8xxx_phy_detach(struct phy_device *phydev) ++{ ++ struct net_device *dev = phydev->attached_dev; ++ ++ if (!dev) ++ return; ++ ++#ifdef CONFIG_ETHERNET_PACKET_MANGLE ++ dev->phy_ptr = NULL; ++ dev->priv_flags &= ~IFF_NO_IP_ALIGN; ++ dev->eth_mangle_rx = NULL; ++ dev->eth_mangle_tx = NULL; ++#endif ++} ++ ++static void ++ar8xxx_phy_remove(struct phy_device *phydev) ++{ ++ struct ar8xxx_priv *priv = phydev->priv; ++ ++ if (WARN_ON(!priv)) ++ return; ++ ++ phydev->priv = NULL; ++ ++ mutex_lock(&ar8xxx_dev_list_lock); ++ ++ if (--priv->use_count > 0) { ++ mutex_unlock(&ar8xxx_dev_list_lock); ++ return; ++ } ++ ++ list_del(&priv->list); ++ mutex_unlock(&ar8xxx_dev_list_lock); ++ ++ unregister_switch(&priv->dev); ++ ar8xxx_mib_stop(priv); ++ ar8xxx_free(priv); ++} ++ ++static struct phy_driver ar8xxx_phy_driver[] = { ++ { ++ .phy_id = 0x004d0000, ++ .name = "Atheros AR8216/AR8236/AR8316", ++ .phy_id_mask = 0xffff0000, ++ .probe = ar8xxx_phy_probe, ++ .remove = ar8xxx_phy_remove, ++ .detach = ar8xxx_phy_detach, ++ .config_init = ar8xxx_phy_config_init, ++ .config_aneg = ar8xxx_phy_config_aneg, ++ .read_status = ar8xxx_phy_read_status, ++ .get_features = ar8xxx_get_features, ++ } ++}; ++ ++static const struct of_device_id ar8xxx_mdiodev_of_match[] = { ++ { ++ .compatible = "qca,ar7240sw", ++ .data = &ar7240sw_chip, ++ }, { ++ .compatible = "qca,ar8229", ++ .data = &ar8229_chip, ++ }, { ++ .compatible = "qca,ar8236", ++ .data = &ar8236_chip, ++ }, { ++ .compatible = "qca,ar8327", ++ .data = &ar8327_chip, ++ }, ++ { /* sentinel */ }, ++}; ++ ++static int ++ar8xxx_mdiodev_probe(struct mdio_device *mdiodev) ++{ ++ const struct of_device_id *match; ++ struct ar8xxx_priv *priv; ++ struct switch_dev *swdev; ++ struct device_node *mdio_node; ++ int ret; ++ ++ match = of_match_device(ar8xxx_mdiodev_of_match, &mdiodev->dev); ++ if (!match) ++ return -EINVAL; ++ ++ priv = ar8xxx_create(); ++ if (priv == NULL) ++ return -ENOMEM; ++ ++ priv->mii_bus = mdiodev->bus; ++ priv->pdev = &mdiodev->dev; ++ priv->chip = (const struct ar8xxx_chip *) match->data; ++ ++ ret = of_property_read_u32(priv->pdev->of_node, "qca,mib-poll-interval", ++ &priv->mib_poll_interval); ++ if (ret) ++ priv->mib_poll_interval = 0; ++ ++ ret = ar8xxx_read_id(priv); ++ if (ret) ++ goto free_priv; ++ ++ ret = ar8xxx_probe_switch(priv); ++ if (ret) ++ goto free_priv; ++ ++ if (priv->chip->phy_read && priv->chip->phy_write) { ++ priv->sw_mii_bus = devm_mdiobus_alloc(&mdiodev->dev); ++ priv->sw_mii_bus->name = "ar8xxx-mdio"; ++ priv->sw_mii_bus->read = ar8xxx_phy_read; ++ priv->sw_mii_bus->write = ar8xxx_phy_write; ++ priv->sw_mii_bus->priv = priv; ++ priv->sw_mii_bus->parent = &mdiodev->dev; ++ snprintf(priv->sw_mii_bus->id, MII_BUS_ID_SIZE, "%s", ++ dev_name(&mdiodev->dev)); ++ mdio_node = of_get_child_by_name(priv->pdev->of_node, "mdio-bus"); ++ ret = of_mdiobus_register(priv->sw_mii_bus, mdio_node); ++ if (ret) ++ goto free_priv; ++ } ++ ++ swdev = &priv->dev; ++ swdev->alias = dev_name(&mdiodev->dev); ++ ++ if (of_property_read_bool(priv->pdev->of_node, "qca,phy4-mii-enable")) { ++ priv->port4_phy = true; ++ swdev->ports--; ++ } ++ ++ ret = register_switch(swdev, NULL); ++ if (ret) ++ goto free_priv; ++ ++ pr_info("%s: %s rev. %u switch registered on %s\n", ++ swdev->devname, swdev->name, priv->chip_rev, ++ dev_name(&priv->mii_bus->dev)); ++ ++ mutex_lock(&ar8xxx_dev_list_lock); ++ list_add(&priv->list, &ar8xxx_dev_list); ++ mutex_unlock(&ar8xxx_dev_list_lock); ++ ++ priv->use_count++; ++ ++ ret = ar8xxx_start(priv); ++ if (ret) ++ goto err_unregister_switch; ++ ++ dev_set_drvdata(&mdiodev->dev, priv); ++ ++ return 0; ++ ++err_unregister_switch: ++ if (--priv->use_count) ++ return ret; ++ ++ unregister_switch(&priv->dev); ++ ++free_priv: ++ ar8xxx_free(priv); ++ return ret; ++} ++ ++static void ++ar8xxx_mdiodev_remove(struct mdio_device *mdiodev) ++{ ++ struct ar8xxx_priv *priv = dev_get_drvdata(&mdiodev->dev); ++ ++ if (WARN_ON(!priv)) ++ return; ++ ++ mutex_lock(&ar8xxx_dev_list_lock); ++ ++ if (--priv->use_count > 0) { ++ mutex_unlock(&ar8xxx_dev_list_lock); ++ return; ++ } ++ ++ list_del(&priv->list); ++ mutex_unlock(&ar8xxx_dev_list_lock); ++ ++ unregister_switch(&priv->dev); ++ ar8xxx_mib_stop(priv); ++ if(priv->sw_mii_bus) ++ mdiobus_unregister(priv->sw_mii_bus); ++ ar8xxx_free(priv); ++} ++ ++static struct mdio_driver ar8xxx_mdio_driver = { ++ .probe = ar8xxx_mdiodev_probe, ++ .remove = ar8xxx_mdiodev_remove, ++ .mdiodrv.driver = { ++ .name = "ar8xxx-switch", ++ .of_match_table = ar8xxx_mdiodev_of_match, ++ }, ++}; ++ ++static int __init ar8216_init(void) ++{ ++ int ret; ++ ++ ret = phy_drivers_register(ar8xxx_phy_driver, ++ ARRAY_SIZE(ar8xxx_phy_driver), ++ THIS_MODULE); ++ if (ret) ++ return ret; ++ ++ ret = mdio_driver_register(&ar8xxx_mdio_driver); ++ if (ret) ++ phy_drivers_unregister(ar8xxx_phy_driver, ++ ARRAY_SIZE(ar8xxx_phy_driver)); ++ ++ return ret; ++} ++module_init(ar8216_init); ++ ++static void __exit ar8216_exit(void) ++{ ++ mdio_driver_unregister(&ar8xxx_mdio_driver); ++ phy_drivers_unregister(ar8xxx_phy_driver, ++ ARRAY_SIZE(ar8xxx_phy_driver)); ++} ++module_exit(ar8216_exit); ++ ++MODULE_LICENSE("GPL"); +diff --git a/drivers/net/phy/ar8216.h b/drivers/net/phy/ar8216.h +new file mode 100644 +index 000000000000..f046b35f43fb +--- /dev/null ++++ b/drivers/net/phy/ar8216.h +@@ -0,0 +1,725 @@ ++/* ++ * ar8216.h: AR8216 switch driver ++ * ++ * Copyright (C) 2009 Felix Fietkau ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version 2 ++ * of the License, or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#ifndef __AR8216_H ++#define __AR8216_H ++ ++#define BITS(_s, _n) (((1UL << (_n)) - 1) << _s) ++ ++#define AR8XXX_CAP_GIGE BIT(0) ++#define AR8XXX_CAP_MIB_COUNTERS BIT(1) ++ ++#define AR8XXX_NUM_PHYS 5 ++#define AR8216_PORT_CPU 0 ++#define AR8216_NUM_PORTS 6 ++#define AR8216_NUM_VLANS 16 ++#define AR7240SW_NUM_PORTS 5 ++#define AR8316_NUM_VLANS 4096 ++ ++/* size of the vlan table */ ++#define AR8X16_MAX_VLANS 128 ++#define AR83X7_MAX_VLANS 4096 ++#define AR8XXX_MAX_VLANS AR83X7_MAX_VLANS ++ ++#define AR8X16_PROBE_RETRIES 10 ++#define AR8X16_MAX_PORTS 8 ++ ++#define AR8XXX_REG_ARL_CTRL_AGE_TIME_SECS 7 ++#define AR8XXX_DEFAULT_ARL_AGE_TIME 300 ++ ++/* Atheros specific MII registers */ ++#define MII_ATH_MMD_ADDR 0x0d ++#define MII_ATH_MMD_DATA 0x0e ++#define MII_ATH_DBG_ADDR 0x1d ++#define MII_ATH_DBG_DATA 0x1e ++ ++#define AR8216_REG_CTRL 0x0000 ++#define AR8216_CTRL_REVISION BITS(0, 8) ++#define AR8216_CTRL_REVISION_S 0 ++#define AR8216_CTRL_VERSION BITS(8, 8) ++#define AR8216_CTRL_VERSION_S 8 ++#define AR8216_CTRL_RESET BIT(31) ++ ++#define AR8216_REG_FLOOD_MASK 0x002C ++#define AR8216_FM_UNI_DEST_PORTS BITS(0, 6) ++#define AR8216_FM_MULTI_DEST_PORTS BITS(16, 6) ++#define AR8216_FM_CPU_BROADCAST_EN BIT(26) ++#define AR8229_FLOOD_MASK_UC_DP(_p) BIT(_p) ++#define AR8229_FLOOD_MASK_MC_DP(_p) BIT(16 + (_p)) ++#define AR8229_FLOOD_MASK_BC_DP(_p) BIT(25 + (_p)) ++ ++#define AR8216_REG_GLOBAL_CTRL 0x0030 ++#define AR8216_GCTRL_MTU BITS(0, 11) ++#define AR8236_GCTRL_MTU BITS(0, 14) ++#define AR8316_GCTRL_MTU BITS(0, 14) ++ ++#define AR8216_REG_VTU 0x0040 ++#define AR8216_VTU_OP BITS(0, 3) ++#define AR8216_VTU_OP_NOOP 0x0 ++#define AR8216_VTU_OP_FLUSH 0x1 ++#define AR8216_VTU_OP_LOAD 0x2 ++#define AR8216_VTU_OP_PURGE 0x3 ++#define AR8216_VTU_OP_REMOVE_PORT 0x4 ++#define AR8216_VTU_ACTIVE BIT(3) ++#define AR8216_VTU_FULL BIT(4) ++#define AR8216_VTU_PORT BITS(8, 4) ++#define AR8216_VTU_PORT_S 8 ++#define AR8216_VTU_VID BITS(16, 12) ++#define AR8216_VTU_VID_S 16 ++#define AR8216_VTU_PRIO BITS(28, 3) ++#define AR8216_VTU_PRIO_S 28 ++#define AR8216_VTU_PRIO_EN BIT(31) ++ ++#define AR8216_REG_VTU_DATA 0x0044 ++#define AR8216_VTUDATA_MEMBER BITS(0, 10) ++#define AR8236_VTUDATA_MEMBER BITS(0, 7) ++#define AR8216_VTUDATA_VALID BIT(11) ++ ++#define AR8216_REG_ATU_FUNC0 0x0050 ++#define AR8216_ATU_OP BITS(0, 3) ++#define AR8216_ATU_OP_NOOP 0x0 ++#define AR8216_ATU_OP_FLUSH 0x1 ++#define AR8216_ATU_OP_LOAD 0x2 ++#define AR8216_ATU_OP_PURGE 0x3 ++#define AR8216_ATU_OP_FLUSH_UNLOCKED 0x4 ++#define AR8216_ATU_OP_FLUSH_PORT 0x5 ++#define AR8216_ATU_OP_GET_NEXT 0x6 ++#define AR8216_ATU_ACTIVE BIT(3) ++#define AR8216_ATU_PORT_NUM BITS(8, 4) ++#define AR8216_ATU_PORT_NUM_S 8 ++#define AR8216_ATU_FULL_VIO BIT(12) ++#define AR8216_ATU_ADDR5 BITS(16, 8) ++#define AR8216_ATU_ADDR5_S 16 ++#define AR8216_ATU_ADDR4 BITS(24, 8) ++#define AR8216_ATU_ADDR4_S 24 ++ ++#define AR8216_REG_ATU_FUNC1 0x0054 ++#define AR8216_ATU_ADDR3 BITS(0, 8) ++#define AR8216_ATU_ADDR3_S 0 ++#define AR8216_ATU_ADDR2 BITS(8, 8) ++#define AR8216_ATU_ADDR2_S 8 ++#define AR8216_ATU_ADDR1 BITS(16, 8) ++#define AR8216_ATU_ADDR1_S 16 ++#define AR8216_ATU_ADDR0 BITS(24, 8) ++#define AR8216_ATU_ADDR0_S 24 ++ ++#define AR8216_REG_ATU_FUNC2 0x0058 ++#define AR8216_ATU_PORTS BITS(0, 6) ++#define AR8216_ATU_PORTS_S 0 ++#define AR8216_ATU_PORT0 BIT(0) ++#define AR8216_ATU_PORT1 BIT(1) ++#define AR8216_ATU_PORT2 BIT(2) ++#define AR8216_ATU_PORT3 BIT(3) ++#define AR8216_ATU_PORT4 BIT(4) ++#define AR8216_ATU_PORT5 BIT(5) ++#define AR8216_ATU_STATUS BITS(16, 4) ++#define AR8216_ATU_STATUS_S 16 ++ ++#define AR8216_REG_ATU_CTRL 0x005C ++#define AR8216_ATU_CTRL_AGE_EN BIT(17) ++#define AR8216_ATU_CTRL_AGE_TIME BITS(0, 16) ++#define AR8216_ATU_CTRL_AGE_TIME_S 0 ++#define AR8236_ATU_CTRL_RES BIT(20) ++#define AR8216_ATU_CTRL_LEARN_CHANGE BIT(18) ++#define AR8216_ATU_CTRL_RESERVED BIT(19) ++#define AR8216_ATU_CTRL_ARP_EN BIT(20) ++ ++#define AR8216_REG_TAG_PRIORITY 0x0070 ++ ++#define AR8216_REG_SERVICE_TAG 0x0074 ++#define AR8216_SERVICE_TAG_M BITS(0, 16) ++ ++#define AR8216_REG_MIB_FUNC 0x0080 ++#define AR8216_MIB_TIMER BITS(0, 16) ++#define AR8216_MIB_AT_HALF_EN BIT(16) ++#define AR8216_MIB_BUSY BIT(17) ++#define AR8216_MIB_FUNC BITS(24, 3) ++#define AR8216_MIB_FUNC_S 24 ++#define AR8216_MIB_FUNC_NO_OP 0x0 ++#define AR8216_MIB_FUNC_FLUSH 0x1 ++#define AR8216_MIB_FUNC_CAPTURE 0x3 ++#define AR8236_MIB_EN BIT(30) ++ ++#define AR8216_REG_GLOBAL_CPUPORT 0x0078 ++#define AR8216_GLOBAL_CPUPORT_MIRROR_PORT BITS(4, 4) ++#define AR8216_GLOBAL_CPUPORT_MIRROR_PORT_S 4 ++#define AR8216_GLOBAL_CPUPORT_EN BIT(8) ++ ++#define AR8216_REG_MDIO_CTRL 0x98 ++#define AR8216_MDIO_CTRL_DATA_M BITS(0, 16) ++#define AR8216_MDIO_CTRL_REG_ADDR_S 16 ++#define AR8216_MDIO_CTRL_PHY_ADDR_S 21 ++#define AR8216_MDIO_CTRL_CMD_WRITE 0 ++#define AR8216_MDIO_CTRL_CMD_READ BIT(27) ++#define AR8216_MDIO_CTRL_MASTER_EN BIT(30) ++#define AR8216_MDIO_CTRL_BUSY BIT(31) ++ ++#define AR8216_PORT_OFFSET(_i) (0x0100 * (_i + 1)) ++#define AR8216_REG_PORT_STATUS(_i) (AR8216_PORT_OFFSET(_i) + 0x0000) ++#define AR8216_PORT_STATUS_SPEED BITS(0,2) ++#define AR8216_PORT_STATUS_SPEED_S 0 ++#define AR8216_PORT_STATUS_TXMAC BIT(2) ++#define AR8216_PORT_STATUS_RXMAC BIT(3) ++#define AR8216_PORT_STATUS_TXFLOW BIT(4) ++#define AR8216_PORT_STATUS_RXFLOW BIT(5) ++#define AR8216_PORT_STATUS_DUPLEX BIT(6) ++#define AR8216_PORT_STATUS_LINK_UP BIT(8) ++#define AR8216_PORT_STATUS_LINK_AUTO BIT(9) ++#define AR8216_PORT_STATUS_LINK_PAUSE BIT(10) ++#define AR8216_PORT_STATUS_FLOW_CONTROL BIT(12) ++ ++#define AR8216_REG_PORT_CTRL(_i) (AR8216_PORT_OFFSET(_i) + 0x0004) ++ ++/* port forwarding state */ ++#define AR8216_PORT_CTRL_STATE BITS(0, 3) ++#define AR8216_PORT_CTRL_STATE_S 0 ++ ++#define AR8216_PORT_CTRL_LEARN_LOCK BIT(7) ++ ++/* egress 802.1q mode */ ++#define AR8216_PORT_CTRL_VLAN_MODE BITS(8, 2) ++#define AR8216_PORT_CTRL_VLAN_MODE_S 8 ++ ++#define AR8216_PORT_CTRL_IGMP_SNOOP BIT(10) ++#define AR8216_PORT_CTRL_HEADER BIT(11) ++#define AR8216_PORT_CTRL_MAC_LOOP BIT(12) ++#define AR8216_PORT_CTRL_SINGLE_VLAN BIT(13) ++#define AR8216_PORT_CTRL_LEARN BIT(14) ++#define AR8216_PORT_CTRL_MIRROR_TX BIT(16) ++#define AR8216_PORT_CTRL_MIRROR_RX BIT(17) ++ ++#define AR8216_REG_PORT_VLAN(_i) (AR8216_PORT_OFFSET(_i) + 0x0008) ++ ++#define AR8216_PORT_VLAN_DEFAULT_ID BITS(0, 12) ++#define AR8216_PORT_VLAN_DEFAULT_ID_S 0 ++ ++#define AR8216_PORT_VLAN_DEST_PORTS BITS(16, 9) ++#define AR8216_PORT_VLAN_DEST_PORTS_S 16 ++ ++/* bit0 added to the priority field of egress frames */ ++#define AR8216_PORT_VLAN_TX_PRIO BIT(27) ++ ++/* port default priority */ ++#define AR8216_PORT_VLAN_PRIORITY BITS(28, 2) ++#define AR8216_PORT_VLAN_PRIORITY_S 28 ++ ++/* ingress 802.1q mode */ ++#define AR8216_PORT_VLAN_MODE BITS(30, 2) ++#define AR8216_PORT_VLAN_MODE_S 30 ++ ++#define AR8216_REG_PORT_RATE(_i) (AR8216_PORT_OFFSET(_i) + 0x000c) ++#define AR8216_REG_PORT_PRIO(_i) (AR8216_PORT_OFFSET(_i) + 0x0010) ++ ++#define AR8216_STATS_RXBROAD 0x00 ++#define AR8216_STATS_RXPAUSE 0x04 ++#define AR8216_STATS_RXMULTI 0x08 ++#define AR8216_STATS_RXFCSERR 0x0c ++#define AR8216_STATS_RXALIGNERR 0x10 ++#define AR8216_STATS_RXRUNT 0x14 ++#define AR8216_STATS_RXFRAGMENT 0x18 ++#define AR8216_STATS_RX64BYTE 0x1c ++#define AR8216_STATS_RX128BYTE 0x20 ++#define AR8216_STATS_RX256BYTE 0x24 ++#define AR8216_STATS_RX512BYTE 0x28 ++#define AR8216_STATS_RX1024BYTE 0x2c ++#define AR8216_STATS_RXMAXBYTE 0x30 ++#define AR8216_STATS_RXTOOLONG 0x34 ++#define AR8216_STATS_RXGOODBYTE 0x38 ++#define AR8216_STATS_RXBADBYTE 0x40 ++#define AR8216_STATS_RXOVERFLOW 0x48 ++#define AR8216_STATS_FILTERED 0x4c ++#define AR8216_STATS_TXBROAD 0x50 ++#define AR8216_STATS_TXPAUSE 0x54 ++#define AR8216_STATS_TXMULTI 0x58 ++#define AR8216_STATS_TXUNDERRUN 0x5c ++#define AR8216_STATS_TX64BYTE 0x60 ++#define AR8216_STATS_TX128BYTE 0x64 ++#define AR8216_STATS_TX256BYTE 0x68 ++#define AR8216_STATS_TX512BYTE 0x6c ++#define AR8216_STATS_TX1024BYTE 0x70 ++#define AR8216_STATS_TXMAXBYTE 0x74 ++#define AR8216_STATS_TXOVERSIZE 0x78 ++#define AR8216_STATS_TXBYTE 0x7c ++#define AR8216_STATS_TXCOLLISION 0x84 ++#define AR8216_STATS_TXABORTCOL 0x88 ++#define AR8216_STATS_TXMULTICOL 0x8c ++#define AR8216_STATS_TXSINGLECOL 0x90 ++#define AR8216_STATS_TXEXCDEFER 0x94 ++#define AR8216_STATS_TXDEFER 0x98 ++#define AR8216_STATS_TXLATECOL 0x9c ++ ++#define AR8216_MIB_RXB_ID 14 /* RxGoodByte */ ++#define AR8216_MIB_TXB_ID 29 /* TxByte */ ++ ++#define AR8229_REG_OPER_MODE0 0x04 ++#define AR8229_OPER_MODE0_MAC_GMII_EN BIT(6) ++#define AR8229_OPER_MODE0_PHY_MII_EN BIT(10) ++ ++#define AR8229_REG_OPER_MODE1 0x08 ++#define AR8229_REG_OPER_MODE1_PHY4_MII_EN BIT(28) ++ ++#define AR8229_REG_QM_CTRL 0x3c ++#define AR8229_QM_CTRL_ARP_EN BIT(15) ++ ++#define AR8236_REG_PORT_VLAN(_i) (AR8216_PORT_OFFSET((_i)) + 0x0008) ++#define AR8236_PORT_VLAN_DEFAULT_ID BITS(16, 12) ++#define AR8236_PORT_VLAN_DEFAULT_ID_S 16 ++#define AR8236_PORT_VLAN_PRIORITY BITS(29, 3) ++#define AR8236_PORT_VLAN_PRIORITY_S 28 ++ ++#define AR8236_REG_PORT_VLAN2(_i) (AR8216_PORT_OFFSET((_i)) + 0x000c) ++#define AR8236_PORT_VLAN2_MEMBER BITS(16, 7) ++#define AR8236_PORT_VLAN2_MEMBER_S 16 ++#define AR8236_PORT_VLAN2_TX_PRIO BIT(23) ++#define AR8236_PORT_VLAN2_VLAN_MODE BITS(30, 2) ++#define AR8236_PORT_VLAN2_VLAN_MODE_S 30 ++ ++#define AR8236_STATS_RXBROAD 0x00 ++#define AR8236_STATS_RXPAUSE 0x04 ++#define AR8236_STATS_RXMULTI 0x08 ++#define AR8236_STATS_RXFCSERR 0x0c ++#define AR8236_STATS_RXALIGNERR 0x10 ++#define AR8236_STATS_RXRUNT 0x14 ++#define AR8236_STATS_RXFRAGMENT 0x18 ++#define AR8236_STATS_RX64BYTE 0x1c ++#define AR8236_STATS_RX128BYTE 0x20 ++#define AR8236_STATS_RX256BYTE 0x24 ++#define AR8236_STATS_RX512BYTE 0x28 ++#define AR8236_STATS_RX1024BYTE 0x2c ++#define AR8236_STATS_RX1518BYTE 0x30 ++#define AR8236_STATS_RXMAXBYTE 0x34 ++#define AR8236_STATS_RXTOOLONG 0x38 ++#define AR8236_STATS_RXGOODBYTE 0x3c ++#define AR8236_STATS_RXBADBYTE 0x44 ++#define AR8236_STATS_RXOVERFLOW 0x4c ++#define AR8236_STATS_FILTERED 0x50 ++#define AR8236_STATS_TXBROAD 0x54 ++#define AR8236_STATS_TXPAUSE 0x58 ++#define AR8236_STATS_TXMULTI 0x5c ++#define AR8236_STATS_TXUNDERRUN 0x60 ++#define AR8236_STATS_TX64BYTE 0x64 ++#define AR8236_STATS_TX128BYTE 0x68 ++#define AR8236_STATS_TX256BYTE 0x6c ++#define AR8236_STATS_TX512BYTE 0x70 ++#define AR8236_STATS_TX1024BYTE 0x74 ++#define AR8236_STATS_TX1518BYTE 0x78 ++#define AR8236_STATS_TXMAXBYTE 0x7c ++#define AR8236_STATS_TXOVERSIZE 0x80 ++#define AR8236_STATS_TXBYTE 0x84 ++#define AR8236_STATS_TXCOLLISION 0x8c ++#define AR8236_STATS_TXABORTCOL 0x90 ++#define AR8236_STATS_TXMULTICOL 0x94 ++#define AR8236_STATS_TXSINGLECOL 0x98 ++#define AR8236_STATS_TXEXCDEFER 0x9c ++#define AR8236_STATS_TXDEFER 0xa0 ++#define AR8236_STATS_TXLATECOL 0xa4 ++ ++#define AR8236_MIB_RXB_ID 15 /* RxGoodByte */ ++#define AR8236_MIB_TXB_ID 31 /* TxByte */ ++ ++#define AR8316_REG_POSTRIP 0x0008 ++#define AR8316_POSTRIP_MAC0_GMII_EN BIT(0) ++#define AR8316_POSTRIP_MAC0_RGMII_EN BIT(1) ++#define AR8316_POSTRIP_PHY4_GMII_EN BIT(2) ++#define AR8316_POSTRIP_PHY4_RGMII_EN BIT(3) ++#define AR8316_POSTRIP_MAC0_MAC_MODE BIT(4) ++#define AR8316_POSTRIP_RTL_MODE BIT(5) ++#define AR8316_POSTRIP_RGMII_RXCLK_DELAY_EN BIT(6) ++#define AR8316_POSTRIP_RGMII_TXCLK_DELAY_EN BIT(7) ++#define AR8316_POSTRIP_SERDES_EN BIT(8) ++#define AR8316_POSTRIP_SEL_ANA_RST BIT(9) ++#define AR8316_POSTRIP_GATE_25M_EN BIT(10) ++#define AR8316_POSTRIP_SEL_CLK25M BIT(11) ++#define AR8316_POSTRIP_HIB_PULSE_HW BIT(12) ++#define AR8316_POSTRIP_DBG_MODE_I BIT(13) ++#define AR8316_POSTRIP_MAC5_MAC_MODE BIT(14) ++#define AR8316_POSTRIP_MAC5_PHY_MODE BIT(15) ++#define AR8316_POSTRIP_POWER_DOWN_HW BIT(16) ++#define AR8316_POSTRIP_LPW_STATE_EN BIT(17) ++#define AR8316_POSTRIP_MAN_EN BIT(18) ++#define AR8316_POSTRIP_PHY_PLL_ON BIT(19) ++#define AR8316_POSTRIP_LPW_EXIT BIT(20) ++#define AR8316_POSTRIP_TXDELAY_S0 BIT(21) ++#define AR8316_POSTRIP_TXDELAY_S1 BIT(22) ++#define AR8316_POSTRIP_RXDELAY_S0 BIT(23) ++#define AR8316_POSTRIP_LED_OPEN_EN BIT(24) ++#define AR8316_POSTRIP_SPI_EN BIT(25) ++#define AR8316_POSTRIP_RXDELAY_S1 BIT(26) ++#define AR8316_POSTRIP_POWER_ON_SEL BIT(31) ++ ++/* port speed */ ++enum { ++ AR8216_PORT_SPEED_10M = 0, ++ AR8216_PORT_SPEED_100M = 1, ++ AR8216_PORT_SPEED_1000M = 2, ++ AR8216_PORT_SPEED_ERR = 3, ++}; ++ ++/* ingress 802.1q mode */ ++enum { ++ AR8216_IN_PORT_ONLY = 0, ++ AR8216_IN_PORT_FALLBACK = 1, ++ AR8216_IN_VLAN_ONLY = 2, ++ AR8216_IN_SECURE = 3 ++}; ++ ++/* egress 802.1q mode */ ++enum { ++ AR8216_OUT_KEEP = 0, ++ AR8216_OUT_STRIP_VLAN = 1, ++ AR8216_OUT_ADD_VLAN = 2 ++}; ++ ++/* port forwarding state */ ++enum { ++ AR8216_PORT_STATE_DISABLED = 0, ++ AR8216_PORT_STATE_BLOCK = 1, ++ AR8216_PORT_STATE_LISTEN = 2, ++ AR8216_PORT_STATE_LEARN = 3, ++ AR8216_PORT_STATE_FORWARD = 4 ++}; ++ ++/* mib counter type */ ++enum { ++ AR8XXX_MIB_BASIC = 0, ++ AR8XXX_MIB_EXTENDED = 1 ++}; ++ ++enum { ++ AR8XXX_VER_AR8216 = 0x01, ++ AR8XXX_VER_AR8236 = 0x03, ++ AR8XXX_VER_AR8316 = 0x10, ++ AR8XXX_VER_AR8327 = 0x12, ++ AR8XXX_VER_AR8337 = 0x13, ++}; ++ ++#define AR8XXX_NUM_ARL_RECORDS 100 ++ ++enum arl_op { ++ AR8XXX_ARL_INITIALIZE, ++ AR8XXX_ARL_GET_NEXT ++}; ++ ++struct arl_entry { ++ u16 portmap; ++ u8 mac[6]; ++}; ++ ++struct ar8xxx_priv; ++ ++struct ar8xxx_mib_desc { ++ unsigned int size; ++ unsigned int offset; ++ const char *name; ++ u8 type; ++}; ++ ++struct ar8xxx_chip { ++ unsigned long caps; ++ bool config_at_probe; ++ bool mii_lo_first; ++ ++ /* parameters to calculate REG_PORT_STATS_BASE */ ++ unsigned reg_port_stats_start; ++ unsigned reg_port_stats_length; ++ ++ unsigned reg_arl_ctrl; ++ ++ int (*hw_init)(struct ar8xxx_priv *priv); ++ void (*cleanup)(struct ar8xxx_priv *priv); ++ ++ const char *name; ++ int vlans; ++ int ports; ++ const struct switch_dev_ops *swops; ++ ++ void (*init_globals)(struct ar8xxx_priv *priv); ++ void (*init_port)(struct ar8xxx_priv *priv, int port); ++ void (*setup_port)(struct ar8xxx_priv *priv, int port, u32 members); ++ u32 (*read_port_status)(struct ar8xxx_priv *priv, int port); ++ u32 (*read_port_eee_status)(struct ar8xxx_priv *priv, int port); ++ int (*atu_flush)(struct ar8xxx_priv *priv); ++ int (*atu_flush_port)(struct ar8xxx_priv *priv, int port); ++ void (*vtu_flush)(struct ar8xxx_priv *priv); ++ void (*vtu_load_vlan)(struct ar8xxx_priv *priv, u32 vid, u32 port_mask); ++ void (*phy_fixup)(struct ar8xxx_priv *priv, int phy); ++ void (*set_mirror_regs)(struct ar8xxx_priv *priv); ++ void (*get_arl_entry)(struct ar8xxx_priv *priv, struct arl_entry *a, ++ u32 *status, enum arl_op op); ++ int (*sw_hw_apply)(struct switch_dev *dev); ++ void (*phy_rgmii_set)(struct ar8xxx_priv *priv, struct phy_device *phydev); ++ int (*phy_read)(struct ar8xxx_priv *priv, int addr, int regnum); ++ int (*phy_write)(struct ar8xxx_priv *priv, int addr, int regnum, u16 val); ++ ++ const struct ar8xxx_mib_desc *mib_decs; ++ unsigned num_mibs; ++ unsigned mib_func; ++ int mib_rxb_id; ++ int mib_txb_id; ++}; ++ ++struct ar8xxx_priv { ++ struct switch_dev dev; ++ struct mii_bus *mii_bus; ++ struct mii_bus *sw_mii_bus; ++ struct phy_device *phy; ++ struct device *pdev; ++ ++ int (*get_port_link)(unsigned port); ++ ++ const struct net_device_ops *ndo_old; ++ struct net_device_ops ndo; ++ struct mutex reg_mutex; ++ u8 chip_ver; ++ u8 chip_rev; ++ const struct ar8xxx_chip *chip; ++ void *chip_data; ++ bool initialized; ++ bool port4_phy; ++ char buf[2048]; ++ struct arl_entry arl_table[AR8XXX_NUM_ARL_RECORDS]; ++ char arl_buf[AR8XXX_NUM_ARL_RECORDS * 32 + 256]; ++ bool link_up[AR8X16_MAX_PORTS]; ++ ++ bool init; ++ ++ struct mutex mib_lock; ++ struct delayed_work mib_work; ++ u64 *mib_stats; ++ u32 mib_poll_interval; ++ u8 mib_type; ++ ++ struct list_head list; ++ unsigned int use_count; ++ ++ /* all fields below are cleared on reset */ ++ struct_group(ar8xxx_priv_volatile, ++ bool vlan; ++ ++ u16 vlan_id[AR8XXX_MAX_VLANS]; ++ u8 vlan_table[AR8XXX_MAX_VLANS]; ++ u8 vlan_tagged; ++ u16 pvid[AR8X16_MAX_PORTS]; ++ int arl_age_time; ++ ++ /* mirroring */ ++ bool mirror_rx; ++ bool mirror_tx; ++ int source_port; ++ int monitor_port; ++ u8 port_vlan_prio[AR8X16_MAX_PORTS]; ++ ); ++}; ++ ++u32 ++ar8xxx_mii_read32(struct ar8xxx_priv *priv, int phy_id, int regnum); ++void ++ar8xxx_mii_write32(struct ar8xxx_priv *priv, int phy_id, int regnum, u32 val); ++u32 ++ar8xxx_read(struct ar8xxx_priv *priv, int reg); ++void ++ar8xxx_write(struct ar8xxx_priv *priv, int reg, u32 val); ++u32 ++ar8xxx_rmw(struct ar8xxx_priv *priv, int reg, u32 mask, u32 val); ++ ++void ++ar8xxx_phy_dbg_read(struct ar8xxx_priv *priv, int phy_addr, ++ u16 dbg_addr, u16 *dbg_data); ++void ++ar8xxx_phy_dbg_write(struct ar8xxx_priv *priv, int phy_addr, ++ u16 dbg_addr, u16 dbg_data); ++void ++ar8xxx_phy_mmd_write(struct ar8xxx_priv *priv, int phy_addr, u16 addr, u16 reg, u16 data); ++u16 ++ar8xxx_phy_mmd_read(struct ar8xxx_priv *priv, int phy_addr, u16 addr, u16 reg); ++void ++ar8xxx_phy_init(struct ar8xxx_priv *priv); ++int ++ar8xxx_sw_set_vlan(struct switch_dev *dev, const struct switch_attr *attr, ++ struct switch_val *val); ++int ++ar8xxx_sw_get_vlan(struct switch_dev *dev, const struct switch_attr *attr, ++ struct switch_val *val); ++int ++ar8xxx_sw_set_reset_mibs(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val); ++int ++ar8xxx_sw_set_mib_poll_interval(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val); ++int ++ar8xxx_sw_get_mib_poll_interval(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val); ++int ++ar8xxx_sw_set_mib_type(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val); ++int ++ar8xxx_sw_get_mib_type(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val); ++int ++ar8xxx_sw_set_mirror_rx_enable(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val); ++int ++ar8xxx_sw_get_mirror_rx_enable(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val); ++int ++ar8xxx_sw_set_mirror_tx_enable(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val); ++int ++ar8xxx_sw_get_mirror_tx_enable(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val); ++int ++ar8xxx_sw_set_mirror_monitor_port(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val); ++int ++ar8xxx_sw_get_mirror_monitor_port(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val); ++int ++ar8xxx_sw_set_mirror_source_port(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val); ++int ++ar8xxx_sw_get_mirror_source_port(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val); ++int ++ar8xxx_sw_set_pvid(struct switch_dev *dev, int port, int vlan); ++int ++ar8xxx_sw_get_pvid(struct switch_dev *dev, int port, int *vlan); ++int ++ar8xxx_sw_hw_apply(struct switch_dev *dev); ++int ++ar8xxx_sw_reset_switch(struct switch_dev *dev); ++int ++ar8xxx_sw_get_port_link(struct switch_dev *dev, int port, ++ struct switch_port_link *link); ++int ++ar8xxx_sw_set_port_reset_mib(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val); ++int ++ar8xxx_sw_get_port_mib(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val); ++int ++ar8xxx_sw_get_arl_age_time(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val); ++int ++ar8xxx_sw_set_arl_age_time(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val); ++int ++ar8xxx_sw_get_arl_table(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val); ++int ++ar8xxx_sw_set_flush_arl_table(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val); ++int ++ar8xxx_sw_set_flush_port_arl_table(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val); ++int ++ar8xxx_sw_get_port_stats(struct switch_dev *dev, int port, ++ struct switch_port_stats *stats); ++int ++ar8216_wait_bit(struct ar8xxx_priv *priv, int reg, u32 mask, u32 val); ++ ++static inline struct ar8xxx_priv * ++swdev_to_ar8xxx(struct switch_dev *swdev) ++{ ++ return container_of(swdev, struct ar8xxx_priv, dev); ++} ++ ++static inline bool ar8xxx_has_gige(struct ar8xxx_priv *priv) ++{ ++ return priv->chip->caps & AR8XXX_CAP_GIGE; ++} ++ ++static inline bool ar8xxx_has_mib_counters(struct ar8xxx_priv *priv) ++{ ++ return priv->chip->caps & AR8XXX_CAP_MIB_COUNTERS; ++} ++ ++static inline bool chip_is_ar8216(struct ar8xxx_priv *priv) ++{ ++ return priv->chip_ver == AR8XXX_VER_AR8216; ++} ++ ++static inline bool chip_is_ar8236(struct ar8xxx_priv *priv) ++{ ++ return priv->chip_ver == AR8XXX_VER_AR8236; ++} ++ ++static inline bool chip_is_ar8316(struct ar8xxx_priv *priv) ++{ ++ return priv->chip_ver == AR8XXX_VER_AR8316; ++} ++ ++static inline bool chip_is_ar8327(struct ar8xxx_priv *priv) ++{ ++ return priv->chip_ver == AR8XXX_VER_AR8327; ++} ++ ++static inline bool chip_is_ar8337(struct ar8xxx_priv *priv) ++{ ++ return priv->chip_ver == AR8XXX_VER_AR8337; ++} ++ ++static inline void ++ar8xxx_reg_set(struct ar8xxx_priv *priv, int reg, u32 val) ++{ ++ ar8xxx_rmw(priv, reg, 0, val); ++} ++ ++static inline void ++ar8xxx_reg_clear(struct ar8xxx_priv *priv, int reg, u32 val) ++{ ++ ar8xxx_rmw(priv, reg, val, 0); ++} ++ ++static inline void ++split_addr(u32 regaddr, u16 *r1, u16 *r2, u16 *page) ++{ ++ regaddr >>= 1; ++ *r1 = regaddr & 0x1e; ++ ++ regaddr >>= 5; ++ *r2 = regaddr & 0x7; ++ ++ regaddr >>= 3; ++ *page = regaddr & 0x1ff; ++} ++ ++static inline void ++wait_for_page_switch(void) ++{ ++ udelay(5); ++} ++ ++#endif +diff --git a/drivers/net/phy/ar8327.c b/drivers/net/phy/ar8327.c +new file mode 100644 +index 000000000000..d6749ad70ed2 +--- /dev/null ++++ b/drivers/net/phy/ar8327.c +@@ -0,0 +1,1589 @@ ++/* ++ * ar8327.c: AR8216 switch driver ++ * ++ * Copyright (C) 2009 Felix Fietkau ++ * Copyright (C) 2011-2012 Gabor Juhos ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version 2 ++ * of the License, or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "ar8216.h" ++#include "ar8327.h" ++ ++extern const struct ar8xxx_mib_desc ar8236_mibs[39]; ++extern const struct switch_attr ar8xxx_sw_attr_vlan[1]; ++ ++static u32 ++ar8327_get_pad_cfg(struct ar8327_pad_cfg *cfg) ++{ ++ u32 t; ++ ++ if (!cfg) ++ return 0; ++ ++ t = 0; ++ switch (cfg->mode) { ++ case AR8327_PAD_NC: ++ break; ++ ++ case AR8327_PAD_MAC2MAC_MII: ++ t = AR8327_PAD_MAC_MII_EN; ++ if (cfg->rxclk_sel) ++ t |= AR8327_PAD_MAC_MII_RXCLK_SEL; ++ if (cfg->txclk_sel) ++ t |= AR8327_PAD_MAC_MII_TXCLK_SEL; ++ break; ++ ++ case AR8327_PAD_MAC2MAC_GMII: ++ t = AR8327_PAD_MAC_GMII_EN; ++ if (cfg->rxclk_sel) ++ t |= AR8327_PAD_MAC_GMII_RXCLK_SEL; ++ if (cfg->txclk_sel) ++ t |= AR8327_PAD_MAC_GMII_TXCLK_SEL; ++ break; ++ ++ case AR8327_PAD_MAC_SGMII: ++ t = AR8327_PAD_SGMII_EN; ++ ++ /* ++ * WAR for the QUalcomm Atheros AP136 board. ++ * It seems that RGMII TX/RX delay settings needs to be ++ * applied for SGMII mode as well, The ethernet is not ++ * reliable without this. ++ */ ++ t |= cfg->txclk_delay_sel << AR8327_PAD_RGMII_TXCLK_DELAY_SEL_S; ++ t |= cfg->rxclk_delay_sel << AR8327_PAD_RGMII_RXCLK_DELAY_SEL_S; ++ if (cfg->rxclk_delay_en) ++ t |= AR8327_PAD_RGMII_RXCLK_DELAY_EN; ++ if (cfg->txclk_delay_en) ++ t |= AR8327_PAD_RGMII_TXCLK_DELAY_EN; ++ ++ if (cfg->sgmii_delay_en) ++ t |= AR8327_PAD_SGMII_DELAY_EN; ++ ++ break; ++ ++ case AR8327_PAD_MAC2PHY_MII: ++ t = AR8327_PAD_PHY_MII_EN; ++ if (cfg->rxclk_sel) ++ t |= AR8327_PAD_PHY_MII_RXCLK_SEL; ++ if (cfg->txclk_sel) ++ t |= AR8327_PAD_PHY_MII_TXCLK_SEL; ++ break; ++ ++ case AR8327_PAD_MAC2PHY_GMII: ++ t = AR8327_PAD_PHY_GMII_EN; ++ if (cfg->pipe_rxclk_sel) ++ t |= AR8327_PAD_PHY_GMII_PIPE_RXCLK_SEL; ++ if (cfg->rxclk_sel) ++ t |= AR8327_PAD_PHY_GMII_RXCLK_SEL; ++ if (cfg->txclk_sel) ++ t |= AR8327_PAD_PHY_GMII_TXCLK_SEL; ++ break; ++ ++ case AR8327_PAD_MAC_RGMII: ++ t = AR8327_PAD_RGMII_EN; ++ t |= cfg->txclk_delay_sel << AR8327_PAD_RGMII_TXCLK_DELAY_SEL_S; ++ t |= cfg->rxclk_delay_sel << AR8327_PAD_RGMII_RXCLK_DELAY_SEL_S; ++ if (cfg->rxclk_delay_en) ++ t |= AR8327_PAD_RGMII_RXCLK_DELAY_EN; ++ if (cfg->txclk_delay_en) ++ t |= AR8327_PAD_RGMII_TXCLK_DELAY_EN; ++ break; ++ ++ case AR8327_PAD_PHY_GMII: ++ t = AR8327_PAD_PHYX_GMII_EN; ++ break; ++ ++ case AR8327_PAD_PHY_RGMII: ++ t = AR8327_PAD_PHYX_RGMII_EN; ++ break; ++ ++ case AR8327_PAD_PHY_MII: ++ t = AR8327_PAD_PHYX_MII_EN; ++ break; ++ } ++ ++ return t; ++} ++ ++static void ++ar8327_phy_rgmii_set(struct ar8xxx_priv *priv, struct phy_device *phydev) ++{ ++ u16 phy_val = 0; ++ int phyaddr = phydev->mdio.addr; ++ struct device_node *np = phydev->mdio.dev.of_node; ++ ++ if (!np) ++ return; ++ ++ if (!of_property_read_bool(np, "qca,phy-rgmii-en")) { ++ pr_err("ar8327: qca,phy-rgmii-en is not specified\n"); ++ return; ++ } ++ ar8xxx_phy_dbg_read(priv, phyaddr, ++ AR8327_PHY_MODE_SEL, &phy_val); ++ phy_val |= AR8327_PHY_MODE_SEL_RGMII; ++ ar8xxx_phy_dbg_write(priv, phyaddr, ++ AR8327_PHY_MODE_SEL, phy_val); ++ ++ /* set rgmii tx clock delay if needed */ ++ if (!of_property_read_bool(np, "qca,txclk-delay-en")) { ++ pr_err("ar8327: qca,txclk-delay-en is not specified\n"); ++ return; ++ } ++ ar8xxx_phy_dbg_read(priv, phyaddr, ++ AR8327_PHY_SYS_CTRL, &phy_val); ++ phy_val |= AR8327_PHY_SYS_CTRL_RGMII_TX_DELAY; ++ ar8xxx_phy_dbg_write(priv, phyaddr, ++ AR8327_PHY_SYS_CTRL, phy_val); ++ ++ /* set rgmii rx clock delay if needed */ ++ if (!of_property_read_bool(np, "qca,rxclk-delay-en")) { ++ pr_err("ar8327: qca,rxclk-delay-en is not specified\n"); ++ return; ++ } ++ ar8xxx_phy_dbg_read(priv, phyaddr, ++ AR8327_PHY_TEST_CTRL, &phy_val); ++ phy_val |= AR8327_PHY_TEST_CTRL_RGMII_RX_DELAY; ++ ar8xxx_phy_dbg_write(priv, phyaddr, ++ AR8327_PHY_TEST_CTRL, phy_val); ++} ++ ++static void ++ar8327_phy_fixup(struct ar8xxx_priv *priv, int phy) ++{ ++ switch (priv->chip_rev) { ++ case 1: ++ /* For 100M waveform */ ++ ar8xxx_phy_dbg_write(priv, phy, 0, 0x02ea); ++ /* Turn on Gigabit clock */ ++ ar8xxx_phy_dbg_write(priv, phy, 0x3d, 0x68a0); ++ break; ++ ++ case 2: ++ ar8xxx_phy_mmd_write(priv, phy, 0x7, 0x3c, 0x0); ++ fallthrough; ++ case 4: ++ ar8xxx_phy_mmd_write(priv, phy, 0x3, 0x800d, 0x803f); ++ ar8xxx_phy_dbg_write(priv, phy, 0x3d, 0x6860); ++ ar8xxx_phy_dbg_write(priv, phy, 0x5, 0x2c46); ++ ar8xxx_phy_dbg_write(priv, phy, 0x3c, 0x6000); ++ break; ++ } ++} ++ ++static u32 ++ar8327_get_port_init_status(struct ar8327_port_cfg *cfg) ++{ ++ u32 t; ++ ++ if (!cfg->force_link) ++ return AR8216_PORT_STATUS_LINK_AUTO; ++ ++ t = AR8216_PORT_STATUS_TXMAC | AR8216_PORT_STATUS_RXMAC; ++ t |= cfg->duplex ? AR8216_PORT_STATUS_DUPLEX : 0; ++ t |= cfg->rxpause ? AR8216_PORT_STATUS_RXFLOW : 0; ++ t |= cfg->txpause ? AR8216_PORT_STATUS_TXFLOW : 0; ++ ++ switch (cfg->speed) { ++ case AR8327_PORT_SPEED_10: ++ t |= AR8216_PORT_SPEED_10M; ++ break; ++ case AR8327_PORT_SPEED_100: ++ t |= AR8216_PORT_SPEED_100M; ++ break; ++ case AR8327_PORT_SPEED_1000: ++ t |= AR8216_PORT_SPEED_1000M; ++ break; ++ } ++ ++ return t; ++} ++ ++#define AR8327_LED_ENTRY(_num, _reg, _shift) \ ++ [_num] = { .reg = (_reg), .shift = (_shift) } ++ ++static const struct ar8327_led_entry ++ar8327_led_map[AR8327_NUM_LEDS] = { ++ AR8327_LED_ENTRY(AR8327_LED_PHY0_0, 0, 14), ++ AR8327_LED_ENTRY(AR8327_LED_PHY0_1, 1, 14), ++ AR8327_LED_ENTRY(AR8327_LED_PHY0_2, 2, 14), ++ ++ AR8327_LED_ENTRY(AR8327_LED_PHY1_0, 3, 8), ++ AR8327_LED_ENTRY(AR8327_LED_PHY1_1, 3, 10), ++ AR8327_LED_ENTRY(AR8327_LED_PHY1_2, 3, 12), ++ ++ AR8327_LED_ENTRY(AR8327_LED_PHY2_0, 3, 14), ++ AR8327_LED_ENTRY(AR8327_LED_PHY2_1, 3, 16), ++ AR8327_LED_ENTRY(AR8327_LED_PHY2_2, 3, 18), ++ ++ AR8327_LED_ENTRY(AR8327_LED_PHY3_0, 3, 20), ++ AR8327_LED_ENTRY(AR8327_LED_PHY3_1, 3, 22), ++ AR8327_LED_ENTRY(AR8327_LED_PHY3_2, 3, 24), ++ ++ AR8327_LED_ENTRY(AR8327_LED_PHY4_0, 0, 30), ++ AR8327_LED_ENTRY(AR8327_LED_PHY4_1, 1, 30), ++ AR8327_LED_ENTRY(AR8327_LED_PHY4_2, 2, 30), ++}; ++ ++static void ++ar8327_set_led_pattern(struct ar8xxx_priv *priv, unsigned int led_num, ++ enum ar8327_led_pattern pattern) ++{ ++ const struct ar8327_led_entry *entry; ++ ++ entry = &ar8327_led_map[led_num]; ++ ar8xxx_rmw(priv, AR8327_REG_LED_CTRL(entry->reg), ++ (3 << entry->shift), pattern << entry->shift); ++} ++ ++static void ++ar8327_led_work_func(struct work_struct *work) ++{ ++ struct ar8327_led *aled; ++ u8 pattern; ++ ++ aled = container_of(work, struct ar8327_led, led_work); ++ ++ pattern = aled->pattern; ++ ++ ar8327_set_led_pattern(aled->sw_priv, aled->led_num, ++ pattern); ++} ++ ++static void ++ar8327_led_schedule_change(struct ar8327_led *aled, u8 pattern) ++{ ++ if (aled->pattern == pattern) ++ return; ++ ++ aled->pattern = pattern; ++ schedule_work(&aled->led_work); ++} ++ ++static inline struct ar8327_led * ++led_cdev_to_ar8327_led(struct led_classdev *led_cdev) ++{ ++ return container_of(led_cdev, struct ar8327_led, cdev); ++} ++ ++static int ++ar8327_led_blink_set(struct led_classdev *led_cdev, ++ unsigned long *delay_on, ++ unsigned long *delay_off) ++{ ++ struct ar8327_led *aled = led_cdev_to_ar8327_led(led_cdev); ++ ++ if (*delay_on == 0 && *delay_off == 0) { ++ *delay_on = 125; ++ *delay_off = 125; ++ } ++ ++ if (*delay_on != 125 || *delay_off != 125) { ++ /* ++ * The hardware only supports blinking at 4Hz. Fall back ++ * to software implementation in other cases. ++ */ ++ return -EINVAL; ++ } ++ ++ spin_lock(&aled->lock); ++ ++ aled->enable_hw_mode = false; ++ ar8327_led_schedule_change(aled, AR8327_LED_PATTERN_BLINK); ++ ++ spin_unlock(&aled->lock); ++ ++ return 0; ++} ++ ++static void ++ar8327_led_set_brightness(struct led_classdev *led_cdev, ++ enum led_brightness brightness) ++{ ++ struct ar8327_led *aled = led_cdev_to_ar8327_led(led_cdev); ++ u8 pattern; ++ bool active; ++ ++ active = (brightness != LED_OFF) != aled->active_low; ++ ++ pattern = (active) ? AR8327_LED_PATTERN_ON : ++ AR8327_LED_PATTERN_OFF; ++ ++ spin_lock(&aled->lock); ++ ++ aled->enable_hw_mode = false; ++ ar8327_led_schedule_change(aled, pattern); ++ ++ spin_unlock(&aled->lock); ++} ++ ++static ssize_t ++ar8327_led_enable_hw_mode_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct led_classdev *led_cdev = dev_get_drvdata(dev); ++ struct ar8327_led *aled = led_cdev_to_ar8327_led(led_cdev); ++ ssize_t ret = 0; ++ ++ ret += scnprintf(buf, PAGE_SIZE, "%d\n", aled->enable_hw_mode); ++ ++ return ret; ++} ++ ++static ssize_t ++ar8327_led_enable_hw_mode_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, ++ size_t size) ++{ ++ struct led_classdev *led_cdev = dev_get_drvdata(dev); ++ struct ar8327_led *aled = led_cdev_to_ar8327_led(led_cdev); ++ u8 pattern; ++ u8 value; ++ int ret; ++ ++ ret = kstrtou8(buf, 10, &value); ++ if (ret < 0) ++ return -EINVAL; ++ ++ spin_lock(&aled->lock); ++ ++ aled->enable_hw_mode = !!value; ++ if (aled->enable_hw_mode) ++ pattern = AR8327_LED_PATTERN_RULE; ++ else ++ pattern = AR8327_LED_PATTERN_OFF; ++ ++ ar8327_led_schedule_change(aled, pattern); ++ ++ spin_unlock(&aled->lock); ++ ++ return size; ++} ++ ++static DEVICE_ATTR(enable_hw_mode, S_IRUGO | S_IWUSR, ++ ar8327_led_enable_hw_mode_show, ++ ar8327_led_enable_hw_mode_store); ++ ++static int ++ar8327_led_register(struct ar8327_led *aled) ++{ ++ int ret; ++ struct led_init_data init_data = { ++ .fwnode = aled->fwnode ++ }; ++ ++ ret = led_classdev_register_ext(NULL, &aled->cdev, &init_data); ++ if (ret < 0) ++ return ret; ++ ++ if (aled->mode == AR8327_LED_MODE_HW) { ++ ret = device_create_file(aled->cdev.dev, ++ &dev_attr_enable_hw_mode); ++ if (ret) ++ goto err_unregister; ++ } ++ ++ return 0; ++ ++err_unregister: ++ led_classdev_unregister(&aled->cdev); ++ return ret; ++} ++ ++static void ++ar8327_led_unregister(struct ar8327_led *aled) ++{ ++ if (aled->mode == AR8327_LED_MODE_HW) ++ device_remove_file(aled->cdev.dev, &dev_attr_enable_hw_mode); ++ ++ led_classdev_unregister(&aled->cdev); ++ cancel_work_sync(&aled->led_work); ++} ++ ++static int ++ar8327_led_create(struct ar8xxx_priv *priv, ++ const struct ar8327_led_info *led_info) ++{ ++ struct ar8327_data *data = priv->chip_data; ++ struct ar8327_led *aled; ++ int ret; ++ ++ if (!IS_ENABLED(CONFIG_AR8216_PHY_LEDS)) ++ return 0; ++ ++ if (!led_info->name) ++ return -EINVAL; ++ ++ if (led_info->led_num >= AR8327_NUM_LEDS) ++ return -EINVAL; ++ ++ aled = kzalloc(sizeof(*aled) + strlen(led_info->name) + 1, ++ GFP_KERNEL); ++ if (!aled) ++ return -ENOMEM; ++ ++ aled->sw_priv = priv; ++ aled->led_num = led_info->led_num; ++ aled->active_low = led_info->active_low; ++ aled->mode = led_info->mode; ++ aled->fwnode = led_info->fwnode; ++ ++ if (aled->mode == AR8327_LED_MODE_HW) ++ aled->enable_hw_mode = true; ++ ++ aled->name = (char *)(aled + 1); ++ strcpy(aled->name, led_info->name); ++ ++ aled->cdev.name = aled->name; ++ aled->cdev.brightness_set = ar8327_led_set_brightness; ++ aled->cdev.blink_set = ar8327_led_blink_set; ++ aled->cdev.default_trigger = led_info->default_trigger; ++ ++ spin_lock_init(&aled->lock); ++ mutex_init(&aled->mutex); ++ INIT_WORK(&aled->led_work, ar8327_led_work_func); ++ ++ ret = ar8327_led_register(aled); ++ if (ret) ++ goto err_free; ++ ++ data->leds[data->num_leds++] = aled; ++ ++ return 0; ++ ++err_free: ++ kfree(aled); ++ return ret; ++} ++ ++static void ++ar8327_led_destroy(struct ar8327_led *aled) ++{ ++ ar8327_led_unregister(aled); ++ kfree(aled); ++} ++ ++static void ++ar8327_leds_init(struct ar8xxx_priv *priv) ++{ ++ struct ar8327_data *data = priv->chip_data; ++ unsigned i; ++ ++ if (!IS_ENABLED(CONFIG_AR8216_PHY_LEDS)) ++ return; ++ ++ for (i = 0; i < data->num_leds; i++) { ++ struct ar8327_led *aled; ++ ++ aled = data->leds[i]; ++ ++ if (aled->enable_hw_mode) ++ aled->pattern = AR8327_LED_PATTERN_RULE; ++ else ++ aled->pattern = aled->active_low ? ++ AR8327_LED_PATTERN_ON : AR8327_LED_PATTERN_OFF; ++ ++ ar8327_set_led_pattern(priv, aled->led_num, aled->pattern); ++ } ++} ++ ++static void ++ar8327_leds_cleanup(struct ar8xxx_priv *priv) ++{ ++ struct ar8327_data *data = priv->chip_data; ++ unsigned i; ++ ++ if (!IS_ENABLED(CONFIG_AR8216_PHY_LEDS)) ++ return; ++ ++ for (i = 0; i < data->num_leds; i++) { ++ struct ar8327_led *aled; ++ ++ aled = data->leds[i]; ++ ar8327_led_destroy(aled); ++ } ++ ++ kfree(data->leds); ++} ++ ++static int ++ar8327_hw_config_pdata(struct ar8xxx_priv *priv, ++ struct ar8327_platform_data *pdata) ++{ ++ struct ar8327_led_cfg *led_cfg; ++ struct ar8327_data *data = priv->chip_data; ++ u32 pos, new_pos; ++ u32 t; ++ ++ if (!pdata) ++ return -EINVAL; ++ ++ priv->get_port_link = pdata->get_port_link; ++ ++ data->port0_status = ar8327_get_port_init_status(&pdata->port0_cfg); ++ data->port6_status = ar8327_get_port_init_status(&pdata->port6_cfg); ++ ++ t = ar8327_get_pad_cfg(pdata->pad0_cfg); ++ if (chip_is_ar8337(priv) && !pdata->pad0_cfg->mac06_exchange_dis) ++ t |= AR8337_PAD_MAC06_EXCHANGE_EN; ++ ar8xxx_write(priv, AR8327_REG_PAD0_MODE, t); ++ ++ t = ar8327_get_pad_cfg(pdata->pad5_cfg); ++ ar8xxx_write(priv, AR8327_REG_PAD5_MODE, t); ++ t = ar8327_get_pad_cfg(pdata->pad6_cfg); ++ ar8xxx_write(priv, AR8327_REG_PAD6_MODE, t); ++ ++ pos = ar8xxx_read(priv, AR8327_REG_POWER_ON_STRAP); ++ new_pos = pos; ++ ++ led_cfg = pdata->led_cfg; ++ if (led_cfg) { ++ if (led_cfg->open_drain) ++ new_pos |= AR8327_POWER_ON_STRAP_LED_OPEN_EN; ++ else ++ new_pos &= ~AR8327_POWER_ON_STRAP_LED_OPEN_EN; ++ ++ ar8xxx_write(priv, AR8327_REG_LED_CTRL0, led_cfg->led_ctrl0); ++ ar8xxx_write(priv, AR8327_REG_LED_CTRL1, led_cfg->led_ctrl1); ++ ar8xxx_write(priv, AR8327_REG_LED_CTRL2, led_cfg->led_ctrl2); ++ ar8xxx_write(priv, AR8327_REG_LED_CTRL3, led_cfg->led_ctrl3); ++ ++ if (new_pos != pos) ++ new_pos |= AR8327_POWER_ON_STRAP_POWER_ON_SEL; ++ } ++ ++ if (pdata->sgmii_cfg) { ++ t = pdata->sgmii_cfg->sgmii_ctrl; ++ if (priv->chip_rev == 1) ++ t |= AR8327_SGMII_CTRL_EN_PLL | ++ AR8327_SGMII_CTRL_EN_RX | ++ AR8327_SGMII_CTRL_EN_TX; ++ else ++ t &= ~(AR8327_SGMII_CTRL_EN_PLL | ++ AR8327_SGMII_CTRL_EN_RX | ++ AR8327_SGMII_CTRL_EN_TX); ++ ++ ar8xxx_write(priv, AR8327_REG_SGMII_CTRL, t); ++ ++ if (pdata->sgmii_cfg->serdes_aen) ++ new_pos &= ~AR8327_POWER_ON_STRAP_SERDES_AEN; ++ else ++ new_pos |= AR8327_POWER_ON_STRAP_SERDES_AEN; ++ } ++ ++ ar8xxx_write(priv, AR8327_REG_POWER_ON_STRAP, new_pos); ++ ++ if (pdata->leds && pdata->num_leds) { ++ int i; ++ ++ data->leds = kzalloc(pdata->num_leds * sizeof(void *), ++ GFP_KERNEL); ++ if (!data->leds) ++ return -ENOMEM; ++ ++ for (i = 0; i < pdata->num_leds; i++) ++ ar8327_led_create(priv, &pdata->leds[i]); ++ } ++ ++ return 0; ++} ++ ++#ifdef CONFIG_OF ++static int ++ar8327_hw_config_of(struct ar8xxx_priv *priv, struct device_node *np) ++{ ++ struct ar8327_data *data = priv->chip_data; ++ const __be32 *paddr; ++ int len; ++ int i; ++ struct device_node *leds, *child; ++ ++ paddr = of_get_property(np, "qca,ar8327-initvals", &len); ++ if (!paddr || len < (2 * sizeof(*paddr))) ++ return -EINVAL; ++ ++ len /= sizeof(*paddr); ++ ++ for (i = 0; i < len - 1; i += 2) { ++ u32 reg; ++ u32 val; ++ ++ reg = be32_to_cpup(paddr + i); ++ val = be32_to_cpup(paddr + i + 1); ++ ++ switch (reg) { ++ case AR8327_REG_PORT_STATUS(0): ++ data->port0_status = val; ++ break; ++ case AR8327_REG_PORT_STATUS(6): ++ data->port6_status = val; ++ break; ++ default: ++ ar8xxx_write(priv, reg, val); ++ break; ++ } ++ } ++ ++ leds = of_get_child_by_name(np, "leds"); ++ if (!leds) ++ return 0; ++ ++ data->leds = kvcalloc(of_get_child_count(leds), sizeof(void *), ++ GFP_KERNEL); ++ if (!data->leds) ++ return -ENOMEM; ++ ++ for_each_available_child_of_node(leds, child) { ++ u32 reg = 0, mode = 0; ++ struct ar8327_led_info info; ++ int ret; ++ ++ ret = of_property_read_u32(child, "reg", ®); ++ if (ret) { ++ pr_err("ar8327: LED %s is missing reg node\n", child->name); ++ continue; ++ } ++ ++ of_property_read_u32(child, "qca,led-mode", &mode); ++ ++ info = (struct ar8327_led_info) { ++ .name = of_get_property(child, "label", NULL) ? : child->name, ++ .fwnode = of_fwnode_handle(child), ++ .active_low = of_property_read_bool(child, "active-low"), ++ .led_num = (enum ar8327_led_num) reg, ++ .mode = (enum ar8327_led_mode) mode ++ }; ++ ar8327_led_create(priv, &info); ++ } ++ ++ of_node_put(leds); ++ return 0; ++} ++#else ++static inline int ++ar8327_hw_config_of(struct ar8xxx_priv *priv, struct device_node *np) ++{ ++ return -EINVAL; ++} ++#endif ++ ++static int ++ar8327_hw_init(struct ar8xxx_priv *priv) ++{ ++ int ret; ++ ++ priv->chip_data = kzalloc(sizeof(struct ar8327_data), GFP_KERNEL); ++ if (!priv->chip_data) ++ return -ENOMEM; ++ ++ if (priv->pdev->of_node) ++ ret = ar8327_hw_config_of(priv, priv->pdev->of_node); ++ else ++ ret = ar8327_hw_config_pdata(priv, ++ priv->phy->mdio.dev.platform_data); ++ ++ if (ret) ++ return ret; ++ ++ ar8327_leds_init(priv); ++ ++ ar8xxx_phy_init(priv); ++ ++ return 0; ++} ++ ++static void ++ar8327_cleanup(struct ar8xxx_priv *priv) ++{ ++ ar8327_leds_cleanup(priv); ++} ++ ++static void ++ar8327_init_globals(struct ar8xxx_priv *priv) ++{ ++ struct ar8327_data *data = priv->chip_data; ++ u32 t; ++ int i; ++ ++ /* enable CPU port and disable mirror port */ ++ t = AR8327_FWD_CTRL0_CPU_PORT_EN | ++ AR8327_FWD_CTRL0_MIRROR_PORT; ++ ar8xxx_write(priv, AR8327_REG_FWD_CTRL0, t); ++ ++ /* forward multicast and broadcast frames to CPU */ ++ t = (AR8327_PORTS_ALL << AR8327_FWD_CTRL1_UC_FLOOD_S) | ++ (AR8327_PORTS_ALL << AR8327_FWD_CTRL1_MC_FLOOD_S) | ++ (AR8327_PORTS_ALL << AR8327_FWD_CTRL1_BC_FLOOD_S); ++ ar8xxx_write(priv, AR8327_REG_FWD_CTRL1, t); ++ ++ /* enable jumbo frames */ ++ ar8xxx_rmw(priv, AR8327_REG_MAX_FRAME_SIZE, ++ AR8327_MAX_FRAME_SIZE_MTU, 9018 + 8 + 2); ++ ++ /* Enable MIB counters */ ++ ar8xxx_reg_set(priv, AR8327_REG_MODULE_EN, ++ AR8327_MODULE_EN_MIB); ++ ++ /* Disable EEE on all phy's due to stability issues */ ++ for (i = 0; i < AR8XXX_NUM_PHYS; i++) ++ data->eee[i] = false; ++} ++ ++static void ++ar8327_init_port(struct ar8xxx_priv *priv, int port) ++{ ++ struct ar8327_data *data = priv->chip_data; ++ u32 t; ++ ++ if (port == AR8216_PORT_CPU) ++ t = data->port0_status; ++ else if (port == 6) ++ t = data->port6_status; ++ else ++ t = AR8216_PORT_STATUS_LINK_AUTO; ++ ++ if (port != AR8216_PORT_CPU && port != 6) { ++ /*hw limitation:if configure mac when there is traffic, ++ port MAC may work abnormal. Need disable lan&wan mac at fisrt*/ ++ ar8xxx_write(priv, AR8327_REG_PORT_STATUS(port), 0); ++ msleep(100); ++ t |= AR8216_PORT_STATUS_FLOW_CONTROL; ++ ar8xxx_write(priv, AR8327_REG_PORT_STATUS(port), t); ++ } else { ++ ar8xxx_write(priv, AR8327_REG_PORT_STATUS(port), t); ++ } ++ ++ ar8xxx_write(priv, AR8327_REG_PORT_HEADER(port), 0); ++ ++ ar8xxx_write(priv, AR8327_REG_PORT_VLAN0(port), 0); ++ ++ t = AR8327_PORT_VLAN1_OUT_MODE_UNTOUCH << AR8327_PORT_VLAN1_OUT_MODE_S; ++ ar8xxx_write(priv, AR8327_REG_PORT_VLAN1(port), t); ++ ++ t = AR8327_PORT_LOOKUP_LEARN; ++ t |= AR8216_PORT_STATE_FORWARD << AR8327_PORT_LOOKUP_STATE_S; ++ ar8xxx_write(priv, AR8327_REG_PORT_LOOKUP(port), t); ++} ++ ++static u32 ++ar8327_read_port_status(struct ar8xxx_priv *priv, int port) ++{ ++ u32 t; ++ ++ t = ar8xxx_read(priv, AR8327_REG_PORT_STATUS(port)); ++ /* map the flow control autoneg result bits to the flow control bits ++ * used in forced mode to allow ar8216_read_port_link detect ++ * flow control properly if autoneg is used ++ */ ++ if (t & AR8216_PORT_STATUS_LINK_UP && ++ t & AR8216_PORT_STATUS_LINK_AUTO) { ++ t &= ~(AR8216_PORT_STATUS_TXFLOW | AR8216_PORT_STATUS_RXFLOW); ++ if (t & AR8327_PORT_STATUS_TXFLOW_AUTO) ++ t |= AR8216_PORT_STATUS_TXFLOW; ++ if (t & AR8327_PORT_STATUS_RXFLOW_AUTO) ++ t |= AR8216_PORT_STATUS_RXFLOW; ++ } ++ ++ return t; ++} ++ ++static u32 ++ar8327_read_port_eee_status(struct ar8xxx_priv *priv, int port) ++{ ++ int phy; ++ u16 t; ++ ++ if (port >= priv->dev.ports) ++ return 0; ++ ++ if (port == 0 || port == 6) ++ return 0; ++ ++ phy = port - 1; ++ ++ /* EEE Ability Auto-negotiation Result */ ++ t = ar8xxx_phy_mmd_read(priv, phy, 0x7, 0x8000); ++ ++ return mmd_eee_adv_to_ethtool_adv_t(t); ++} ++ ++static int ++ar8327_atu_flush(struct ar8xxx_priv *priv) ++{ ++ int ret; ++ ++ ret = ar8216_wait_bit(priv, AR8327_REG_ATU_FUNC, ++ AR8327_ATU_FUNC_BUSY, 0); ++ if (!ret) ++ ar8xxx_write(priv, AR8327_REG_ATU_FUNC, ++ AR8327_ATU_FUNC_OP_FLUSH | ++ AR8327_ATU_FUNC_BUSY); ++ ++ return ret; ++} ++ ++static int ++ar8327_atu_flush_port(struct ar8xxx_priv *priv, int port) ++{ ++ u32 t; ++ int ret; ++ ++ ret = ar8216_wait_bit(priv, AR8327_REG_ATU_FUNC, ++ AR8327_ATU_FUNC_BUSY, 0); ++ if (!ret) { ++ t = (port << AR8327_ATU_PORT_NUM_S); ++ t |= AR8327_ATU_FUNC_OP_FLUSH_PORT; ++ t |= AR8327_ATU_FUNC_BUSY; ++ ar8xxx_write(priv, AR8327_REG_ATU_FUNC, t); ++ } ++ ++ return ret; ++} ++ ++static int ++ar8327_get_port_igmp(struct ar8xxx_priv *priv, int port) ++{ ++ u32 fwd_ctrl, frame_ack; ++ ++ fwd_ctrl = (BIT(port) << AR8327_FWD_CTRL1_IGMP_S); ++ frame_ack = ((AR8327_FRAME_ACK_CTRL_IGMP_MLD | ++ AR8327_FRAME_ACK_CTRL_IGMP_JOIN | ++ AR8327_FRAME_ACK_CTRL_IGMP_LEAVE) << ++ AR8327_FRAME_ACK_CTRL_S(port)); ++ ++ return (ar8xxx_read(priv, AR8327_REG_FWD_CTRL1) & ++ fwd_ctrl) == fwd_ctrl && ++ (ar8xxx_read(priv, AR8327_REG_FRAME_ACK_CTRL(port)) & ++ frame_ack) == frame_ack; ++} ++ ++static void ++ar8327_set_port_igmp(struct ar8xxx_priv *priv, int port, int enable) ++{ ++ int reg_frame_ack = AR8327_REG_FRAME_ACK_CTRL(port); ++ u32 val_frame_ack = (AR8327_FRAME_ACK_CTRL_IGMP_MLD | ++ AR8327_FRAME_ACK_CTRL_IGMP_JOIN | ++ AR8327_FRAME_ACK_CTRL_IGMP_LEAVE) << ++ AR8327_FRAME_ACK_CTRL_S(port); ++ ++ if (enable) { ++ ar8xxx_rmw(priv, AR8327_REG_FWD_CTRL1, ++ BIT(port) << AR8327_FWD_CTRL1_MC_FLOOD_S, ++ BIT(port) << AR8327_FWD_CTRL1_IGMP_S); ++ ar8xxx_reg_set(priv, reg_frame_ack, val_frame_ack); ++ } else { ++ ar8xxx_rmw(priv, AR8327_REG_FWD_CTRL1, ++ BIT(port) << AR8327_FWD_CTRL1_IGMP_S, ++ BIT(port) << AR8327_FWD_CTRL1_MC_FLOOD_S); ++ ar8xxx_reg_clear(priv, reg_frame_ack, val_frame_ack); ++ } ++} ++ ++static void ++ar8327_vtu_op(struct ar8xxx_priv *priv, u32 op, u32 val) ++{ ++ if (ar8216_wait_bit(priv, AR8327_REG_VTU_FUNC1, ++ AR8327_VTU_FUNC1_BUSY, 0)) ++ return; ++ ++ if ((op & AR8327_VTU_FUNC1_OP) == AR8327_VTU_FUNC1_OP_LOAD) ++ ar8xxx_write(priv, AR8327_REG_VTU_FUNC0, val); ++ ++ op |= AR8327_VTU_FUNC1_BUSY; ++ ar8xxx_write(priv, AR8327_REG_VTU_FUNC1, op); ++} ++ ++static void ++ar8327_vtu_flush(struct ar8xxx_priv *priv) ++{ ++ ar8327_vtu_op(priv, AR8327_VTU_FUNC1_OP_FLUSH, 0); ++} ++ ++static void ++ar8327_vtu_load_vlan(struct ar8xxx_priv *priv, u32 vid, u32 port_mask) ++{ ++ u32 op; ++ u32 val; ++ int i; ++ ++ op = AR8327_VTU_FUNC1_OP_LOAD | (vid << AR8327_VTU_FUNC1_VID_S); ++ val = AR8327_VTU_FUNC0_VALID | AR8327_VTU_FUNC0_IVL; ++ for (i = 0; i < AR8327_NUM_PORTS; i++) { ++ u32 mode; ++ ++ if ((port_mask & BIT(i)) == 0) ++ mode = AR8327_VTU_FUNC0_EG_MODE_NOT; ++ else if (priv->vlan == 0) ++ mode = AR8327_VTU_FUNC0_EG_MODE_KEEP; ++ else if ((priv->vlan_tagged & BIT(i)) || (priv->vlan_id[priv->pvid[i]] != vid)) ++ mode = AR8327_VTU_FUNC0_EG_MODE_TAG; ++ else ++ mode = AR8327_VTU_FUNC0_EG_MODE_UNTAG; ++ ++ val |= mode << AR8327_VTU_FUNC0_EG_MODE_S(i); ++ } ++ ar8327_vtu_op(priv, op, val); ++} ++ ++static void ++ar8327_setup_port(struct ar8xxx_priv *priv, int port, u32 members) ++{ ++ u32 t; ++ u32 egress, ingress; ++ u32 pvid = priv->vlan_id[priv->pvid[port]]; ++ ++ if (priv->vlan) { ++ egress = AR8327_PORT_VLAN1_OUT_MODE_UNMOD; ++ ingress = AR8216_IN_SECURE; ++ } else { ++ egress = AR8327_PORT_VLAN1_OUT_MODE_UNTOUCH; ++ ingress = AR8216_IN_PORT_ONLY; ++ } ++ ++ t = pvid << AR8327_PORT_VLAN0_DEF_SVID_S; ++ t |= pvid << AR8327_PORT_VLAN0_DEF_CVID_S; ++ if (priv->vlan && priv->port_vlan_prio[port]) { ++ u32 prio = priv->port_vlan_prio[port]; ++ ++ t |= prio << AR8327_PORT_VLAN0_DEF_SPRI_S; ++ t |= prio << AR8327_PORT_VLAN0_DEF_CPRI_S; ++ } ++ ar8xxx_write(priv, AR8327_REG_PORT_VLAN0(port), t); ++ ++ t = AR8327_PORT_VLAN1_PORT_VLAN_PROP; ++ t |= egress << AR8327_PORT_VLAN1_OUT_MODE_S; ++ if (priv->vlan && priv->port_vlan_prio[port]) ++ t |= AR8327_PORT_VLAN1_VLAN_PRI_PROP; ++ ++ ar8xxx_write(priv, AR8327_REG_PORT_VLAN1(port), t); ++ ++ t = members; ++ t |= AR8327_PORT_LOOKUP_LEARN; ++ t |= ingress << AR8327_PORT_LOOKUP_IN_MODE_S; ++ t |= AR8216_PORT_STATE_FORWARD << AR8327_PORT_LOOKUP_STATE_S; ++ ar8xxx_write(priv, AR8327_REG_PORT_LOOKUP(port), t); ++} ++ ++static int ++ar8327_sw_get_ports(struct switch_dev *dev, struct switch_val *val) ++{ ++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); ++ u8 ports = priv->vlan_table[val->port_vlan]; ++ int i; ++ ++ val->len = 0; ++ for (i = 0; i < dev->ports; i++) { ++ struct switch_port *p; ++ ++ if (!(ports & (1 << i))) ++ continue; ++ ++ p = &val->value.ports[val->len++]; ++ p->id = i; ++ if ((priv->vlan_tagged & (1 << i)) || (priv->pvid[i] != val->port_vlan)) ++ p->flags = (1 << SWITCH_PORT_FLAG_TAGGED); ++ else ++ p->flags = 0; ++ } ++ return 0; ++} ++ ++static int ++ar8327_sw_set_ports(struct switch_dev *dev, struct switch_val *val) ++{ ++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); ++ u8 *vt = &priv->vlan_table[val->port_vlan]; ++ int i; ++ ++ *vt = 0; ++ for (i = 0; i < val->len; i++) { ++ struct switch_port *p = &val->value.ports[i]; ++ ++ if (p->flags & (1 << SWITCH_PORT_FLAG_TAGGED)) { ++ if (val->port_vlan == priv->pvid[p->id]) { ++ priv->vlan_tagged |= (1 << p->id); ++ } ++ } else { ++ priv->vlan_tagged &= ~(1 << p->id); ++ priv->pvid[p->id] = val->port_vlan; ++ } ++ ++ *vt |= 1 << p->id; ++ } ++ return 0; ++} ++ ++static void ++ar8327_set_mirror_regs(struct ar8xxx_priv *priv) ++{ ++ int port; ++ ++ /* reset all mirror registers */ ++ ar8xxx_rmw(priv, AR8327_REG_FWD_CTRL0, ++ AR8327_FWD_CTRL0_MIRROR_PORT, ++ (0xF << AR8327_FWD_CTRL0_MIRROR_PORT_S)); ++ for (port = 0; port < AR8327_NUM_PORTS; port++) { ++ ar8xxx_reg_clear(priv, AR8327_REG_PORT_LOOKUP(port), ++ AR8327_PORT_LOOKUP_ING_MIRROR_EN); ++ ++ ar8xxx_reg_clear(priv, AR8327_REG_PORT_HOL_CTRL1(port), ++ AR8327_PORT_HOL_CTRL1_EG_MIRROR_EN); ++ } ++ ++ /* now enable mirroring if necessary */ ++ if (priv->source_port >= AR8327_NUM_PORTS || ++ priv->monitor_port >= AR8327_NUM_PORTS || ++ priv->source_port == priv->monitor_port) { ++ return; ++ } ++ ++ ar8xxx_rmw(priv, AR8327_REG_FWD_CTRL0, ++ AR8327_FWD_CTRL0_MIRROR_PORT, ++ (priv->monitor_port << AR8327_FWD_CTRL0_MIRROR_PORT_S)); ++ ++ if (priv->mirror_rx) ++ ar8xxx_reg_set(priv, AR8327_REG_PORT_LOOKUP(priv->source_port), ++ AR8327_PORT_LOOKUP_ING_MIRROR_EN); ++ ++ if (priv->mirror_tx) ++ ar8xxx_reg_set(priv, AR8327_REG_PORT_HOL_CTRL1(priv->source_port), ++ AR8327_PORT_HOL_CTRL1_EG_MIRROR_EN); ++} ++ ++static int ++ar8327_sw_set_eee(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); ++ struct ar8327_data *data = priv->chip_data; ++ int port = val->port_vlan; ++ int phy; ++ ++ if (port >= dev->ports) ++ return -EINVAL; ++ if (port == 0 || port == 6) ++ return -EOPNOTSUPP; ++ ++ phy = port - 1; ++ ++ data->eee[phy] = !!(val->value.i); ++ ++ return 0; ++} ++ ++static int ++ar8327_sw_get_eee(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); ++ const struct ar8327_data *data = priv->chip_data; ++ int port = val->port_vlan; ++ int phy; ++ ++ if (port >= dev->ports) ++ return -EINVAL; ++ if (port == 0 || port == 6) ++ return -EOPNOTSUPP; ++ ++ phy = port - 1; ++ ++ val->value.i = data->eee[phy]; ++ ++ return 0; ++} ++ ++static void ++ar8327_wait_atu_ready(struct ar8xxx_priv *priv, u16 r2, u16 r1) ++{ ++ int timeout = 20; ++ ++ while (ar8xxx_mii_read32(priv, r2, r1) & AR8327_ATU_FUNC_BUSY && --timeout) { ++ udelay(10); ++ cond_resched(); ++ } ++ ++ if (!timeout) ++ pr_err("ar8327: timeout waiting for atu to become ready\n"); ++} ++ ++static void ar8327_get_arl_entry(struct ar8xxx_priv *priv, ++ struct arl_entry *a, u32 *status, enum arl_op op) ++{ ++ struct mii_bus *bus = priv->mii_bus; ++ u16 r2, page; ++ u16 r1_data0, r1_data1, r1_data2, r1_func; ++ u32 val0, val1, val2; ++ ++ split_addr(AR8327_REG_ATU_DATA0, &r1_data0, &r2, &page); ++ r2 |= 0x10; ++ ++ r1_data1 = (AR8327_REG_ATU_DATA1 >> 1) & 0x1e; ++ r1_data2 = (AR8327_REG_ATU_DATA2 >> 1) & 0x1e; ++ r1_func = (AR8327_REG_ATU_FUNC >> 1) & 0x1e; ++ ++ switch (op) { ++ case AR8XXX_ARL_INITIALIZE: ++ /* all ATU registers are on the same page ++ * therefore set page only once ++ */ ++ bus->write(bus, 0x18, 0, page); ++ wait_for_page_switch(); ++ ++ ar8327_wait_atu_ready(priv, r2, r1_func); ++ ++ ar8xxx_mii_write32(priv, r2, r1_data0, 0); ++ ar8xxx_mii_write32(priv, r2, r1_data1, 0); ++ ar8xxx_mii_write32(priv, r2, r1_data2, 0); ++ break; ++ case AR8XXX_ARL_GET_NEXT: ++ ar8xxx_mii_write32(priv, r2, r1_func, ++ AR8327_ATU_FUNC_OP_GET_NEXT | ++ AR8327_ATU_FUNC_BUSY); ++ ar8327_wait_atu_ready(priv, r2, r1_func); ++ ++ val0 = ar8xxx_mii_read32(priv, r2, r1_data0); ++ val1 = ar8xxx_mii_read32(priv, r2, r1_data1); ++ val2 = ar8xxx_mii_read32(priv, r2, r1_data2); ++ ++ *status = val2 & AR8327_ATU_STATUS; ++ if (!*status) ++ break; ++ ++ a->portmap = (val1 & AR8327_ATU_PORTS) >> AR8327_ATU_PORTS_S; ++ a->mac[0] = (val0 & AR8327_ATU_ADDR0) >> AR8327_ATU_ADDR0_S; ++ a->mac[1] = (val0 & AR8327_ATU_ADDR1) >> AR8327_ATU_ADDR1_S; ++ a->mac[2] = (val0 & AR8327_ATU_ADDR2) >> AR8327_ATU_ADDR2_S; ++ a->mac[3] = (val0 & AR8327_ATU_ADDR3) >> AR8327_ATU_ADDR3_S; ++ a->mac[4] = (val1 & AR8327_ATU_ADDR4) >> AR8327_ATU_ADDR4_S; ++ a->mac[5] = (val1 & AR8327_ATU_ADDR5) >> AR8327_ATU_ADDR5_S; ++ break; ++ } ++} ++ ++static int ++ar8327_sw_hw_apply(struct switch_dev *dev) ++{ ++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); ++ const struct ar8327_data *data = priv->chip_data; ++ int ret, i; ++ ++ ret = ar8xxx_sw_hw_apply(dev); ++ if (ret) ++ return ret; ++ ++ for (i=0; i < AR8XXX_NUM_PHYS; i++) { ++ if (data->eee[i]) ++ ar8xxx_reg_clear(priv, AR8327_REG_EEE_CTRL, ++ AR8327_EEE_CTRL_DISABLE_PHY(i)); ++ else ++ ar8xxx_reg_set(priv, AR8327_REG_EEE_CTRL, ++ AR8327_EEE_CTRL_DISABLE_PHY(i)); ++ } ++ ++ return 0; ++} ++ ++static int ++ar8327_sw_get_port_igmp_snooping(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); ++ int port = val->port_vlan; ++ ++ if (port >= dev->ports) ++ return -EINVAL; ++ ++ mutex_lock(&priv->reg_mutex); ++ val->value.i = ar8327_get_port_igmp(priv, port); ++ mutex_unlock(&priv->reg_mutex); ++ ++ return 0; ++} ++ ++static int ++ar8327_sw_set_port_igmp_snooping(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); ++ int port = val->port_vlan; ++ ++ if (port >= dev->ports) ++ return -EINVAL; ++ ++ mutex_lock(&priv->reg_mutex); ++ ar8327_set_port_igmp(priv, port, val->value.i); ++ mutex_unlock(&priv->reg_mutex); ++ ++ return 0; ++} ++ ++static int ++ar8327_sw_get_igmp_snooping(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ int port; ++ ++ for (port = 0; port < dev->ports; port++) { ++ val->port_vlan = port; ++ if (ar8327_sw_get_port_igmp_snooping(dev, attr, val) || ++ !val->value.i) ++ break; ++ } ++ ++ return 0; ++} ++ ++static int ++ar8327_sw_set_igmp_snooping(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ int port; ++ ++ for (port = 0; port < dev->ports; port++) { ++ val->port_vlan = port; ++ if (ar8327_sw_set_port_igmp_snooping(dev, attr, val)) ++ break; ++ } ++ ++ return 0; ++} ++ ++static int ++ar8327_sw_get_igmp_v3(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); ++ u32 val_reg; ++ ++ mutex_lock(&priv->reg_mutex); ++ val_reg = ar8xxx_read(priv, AR8327_REG_FRAME_ACK_CTRL1); ++ val->value.i = ((val_reg & AR8327_FRAME_ACK_CTRL_IGMP_V3_EN) != 0); ++ mutex_unlock(&priv->reg_mutex); ++ ++ return 0; ++} ++ ++static int ++ar8327_sw_set_igmp_v3(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); ++ ++ mutex_lock(&priv->reg_mutex); ++ if (val->value.i) ++ ar8xxx_reg_set(priv, AR8327_REG_FRAME_ACK_CTRL1, ++ AR8327_FRAME_ACK_CTRL_IGMP_V3_EN); ++ else ++ ar8xxx_reg_clear(priv, AR8327_REG_FRAME_ACK_CTRL1, ++ AR8327_FRAME_ACK_CTRL_IGMP_V3_EN); ++ mutex_unlock(&priv->reg_mutex); ++ ++ return 0; ++} ++ ++static int ++ar8327_sw_set_port_vlan_prio(struct switch_dev *dev, const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); ++ int port = val->port_vlan; ++ ++ if (port >= dev->ports) ++ return -EINVAL; ++ if (port == 0 || port == 6) ++ return -EOPNOTSUPP; ++ if (val->value.i < 0 || val->value.i > 7) ++ return -EINVAL; ++ ++ priv->port_vlan_prio[port] = val->value.i; ++ ++ return 0; ++} ++ ++static int ++ar8327_sw_get_port_vlan_prio(struct switch_dev *dev, const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); ++ int port = val->port_vlan; ++ ++ val->value.i = priv->port_vlan_prio[port]; ++ ++ return 0; ++} ++ ++static const struct switch_attr ar8327_sw_attr_globals[] = { ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "enable_vlan", ++ .description = "Enable VLAN mode", ++ .set = ar8xxx_sw_set_vlan, ++ .get = ar8xxx_sw_get_vlan, ++ .max = 1 ++ }, ++ { ++ .type = SWITCH_TYPE_NOVAL, ++ .name = "reset_mibs", ++ .description = "Reset all MIB counters", ++ .set = ar8xxx_sw_set_reset_mibs, ++ }, ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "ar8xxx_mib_poll_interval", ++ .description = "MIB polling interval in msecs (0 to disable)", ++ .set = ar8xxx_sw_set_mib_poll_interval, ++ .get = ar8xxx_sw_get_mib_poll_interval ++ }, ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "ar8xxx_mib_type", ++ .description = "MIB type (0=basic 1=extended)", ++ .set = ar8xxx_sw_set_mib_type, ++ .get = ar8xxx_sw_get_mib_type ++ }, ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "enable_mirror_rx", ++ .description = "Enable mirroring of RX packets", ++ .set = ar8xxx_sw_set_mirror_rx_enable, ++ .get = ar8xxx_sw_get_mirror_rx_enable, ++ .max = 1 ++ }, ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "enable_mirror_tx", ++ .description = "Enable mirroring of TX packets", ++ .set = ar8xxx_sw_set_mirror_tx_enable, ++ .get = ar8xxx_sw_get_mirror_tx_enable, ++ .max = 1 ++ }, ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "mirror_monitor_port", ++ .description = "Mirror monitor port", ++ .set = ar8xxx_sw_set_mirror_monitor_port, ++ .get = ar8xxx_sw_get_mirror_monitor_port, ++ .max = AR8327_NUM_PORTS - 1 ++ }, ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "mirror_source_port", ++ .description = "Mirror source port", ++ .set = ar8xxx_sw_set_mirror_source_port, ++ .get = ar8xxx_sw_get_mirror_source_port, ++ .max = AR8327_NUM_PORTS - 1 ++ }, ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "arl_age_time", ++ .description = "ARL age time (secs)", ++ .set = ar8xxx_sw_set_arl_age_time, ++ .get = ar8xxx_sw_get_arl_age_time, ++ }, ++ { ++ .type = SWITCH_TYPE_STRING, ++ .name = "arl_table", ++ .description = "Get ARL table", ++ .set = NULL, ++ .get = ar8xxx_sw_get_arl_table, ++ }, ++ { ++ .type = SWITCH_TYPE_NOVAL, ++ .name = "flush_arl_table", ++ .description = "Flush ARL table", ++ .set = ar8xxx_sw_set_flush_arl_table, ++ }, ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "igmp_snooping", ++ .description = "Enable IGMP Snooping", ++ .set = ar8327_sw_set_igmp_snooping, ++ .get = ar8327_sw_get_igmp_snooping, ++ .max = 1 ++ }, ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "igmp_v3", ++ .description = "Enable IGMPv3 support", ++ .set = ar8327_sw_set_igmp_v3, ++ .get = ar8327_sw_get_igmp_v3, ++ .max = 1 ++ }, ++}; ++ ++static const struct switch_attr ar8327_sw_attr_port[] = { ++ { ++ .type = SWITCH_TYPE_NOVAL, ++ .name = "reset_mib", ++ .description = "Reset single port MIB counters", ++ .set = ar8xxx_sw_set_port_reset_mib, ++ }, ++ { ++ .type = SWITCH_TYPE_STRING, ++ .name = "mib", ++ .description = "Get port's MIB counters", ++ .set = NULL, ++ .get = ar8xxx_sw_get_port_mib, ++ }, ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "enable_eee", ++ .description = "Enable EEE PHY sleep mode", ++ .set = ar8327_sw_set_eee, ++ .get = ar8327_sw_get_eee, ++ .max = 1, ++ }, ++ { ++ .type = SWITCH_TYPE_NOVAL, ++ .name = "flush_arl_table", ++ .description = "Flush port's ARL table entries", ++ .set = ar8xxx_sw_set_flush_port_arl_table, ++ }, ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "igmp_snooping", ++ .description = "Enable port's IGMP Snooping", ++ .set = ar8327_sw_set_port_igmp_snooping, ++ .get = ar8327_sw_get_port_igmp_snooping, ++ .max = 1 ++ }, ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "vlan_prio", ++ .description = "Port VLAN default priority (VLAN PCP) (0-7)", ++ .set = ar8327_sw_set_port_vlan_prio, ++ .get = ar8327_sw_get_port_vlan_prio, ++ .max = 7, ++ }, ++}; ++ ++static const struct switch_dev_ops ar8327_sw_ops = { ++ .attr_global = { ++ .attr = ar8327_sw_attr_globals, ++ .n_attr = ARRAY_SIZE(ar8327_sw_attr_globals), ++ }, ++ .attr_port = { ++ .attr = ar8327_sw_attr_port, ++ .n_attr = ARRAY_SIZE(ar8327_sw_attr_port), ++ }, ++ .attr_vlan = { ++ .attr = ar8xxx_sw_attr_vlan, ++ .n_attr = ARRAY_SIZE(ar8xxx_sw_attr_vlan), ++ }, ++ .get_port_pvid = ar8xxx_sw_get_pvid, ++ .set_port_pvid = ar8xxx_sw_set_pvid, ++ .get_vlan_ports = ar8327_sw_get_ports, ++ .set_vlan_ports = ar8327_sw_set_ports, ++ .apply_config = ar8327_sw_hw_apply, ++ .reset_switch = ar8xxx_sw_reset_switch, ++ .get_port_link = ar8xxx_sw_get_port_link, ++ .get_port_stats = ar8xxx_sw_get_port_stats, ++}; ++ ++const struct ar8xxx_chip ar8327_chip = { ++ .caps = AR8XXX_CAP_GIGE | AR8XXX_CAP_MIB_COUNTERS, ++ .config_at_probe = true, ++ .mii_lo_first = true, ++ ++ .name = "Atheros AR8327", ++ .ports = AR8327_NUM_PORTS, ++ .vlans = AR83X7_MAX_VLANS, ++ .swops = &ar8327_sw_ops, ++ ++ .reg_port_stats_start = 0x1000, ++ .reg_port_stats_length = 0x100, ++ .reg_arl_ctrl = AR8327_REG_ARL_CTRL, ++ ++ .hw_init = ar8327_hw_init, ++ .cleanup = ar8327_cleanup, ++ .init_globals = ar8327_init_globals, ++ .init_port = ar8327_init_port, ++ .setup_port = ar8327_setup_port, ++ .read_port_status = ar8327_read_port_status, ++ .read_port_eee_status = ar8327_read_port_eee_status, ++ .atu_flush = ar8327_atu_flush, ++ .atu_flush_port = ar8327_atu_flush_port, ++ .vtu_flush = ar8327_vtu_flush, ++ .vtu_load_vlan = ar8327_vtu_load_vlan, ++ .phy_fixup = ar8327_phy_fixup, ++ .set_mirror_regs = ar8327_set_mirror_regs, ++ .get_arl_entry = ar8327_get_arl_entry, ++ .sw_hw_apply = ar8327_sw_hw_apply, ++ ++ .num_mibs = ARRAY_SIZE(ar8236_mibs), ++ .mib_decs = ar8236_mibs, ++ .mib_func = AR8327_REG_MIB_FUNC, ++ .mib_rxb_id = AR8236_MIB_RXB_ID, ++ .mib_txb_id = AR8236_MIB_TXB_ID, ++}; ++ ++const struct ar8xxx_chip ar8337_chip = { ++ .caps = AR8XXX_CAP_GIGE | AR8XXX_CAP_MIB_COUNTERS, ++ .config_at_probe = true, ++ .mii_lo_first = true, ++ ++ .name = "Atheros AR8337", ++ .ports = AR8327_NUM_PORTS, ++ .vlans = AR83X7_MAX_VLANS, ++ .swops = &ar8327_sw_ops, ++ ++ .reg_port_stats_start = 0x1000, ++ .reg_port_stats_length = 0x100, ++ .reg_arl_ctrl = AR8327_REG_ARL_CTRL, ++ ++ .hw_init = ar8327_hw_init, ++ .cleanup = ar8327_cleanup, ++ .init_globals = ar8327_init_globals, ++ .init_port = ar8327_init_port, ++ .setup_port = ar8327_setup_port, ++ .read_port_status = ar8327_read_port_status, ++ .read_port_eee_status = ar8327_read_port_eee_status, ++ .atu_flush = ar8327_atu_flush, ++ .atu_flush_port = ar8327_atu_flush_port, ++ .vtu_flush = ar8327_vtu_flush, ++ .vtu_load_vlan = ar8327_vtu_load_vlan, ++ .phy_fixup = ar8327_phy_fixup, ++ .set_mirror_regs = ar8327_set_mirror_regs, ++ .get_arl_entry = ar8327_get_arl_entry, ++ .sw_hw_apply = ar8327_sw_hw_apply, ++ .phy_rgmii_set = ar8327_phy_rgmii_set, ++ ++ .num_mibs = ARRAY_SIZE(ar8236_mibs), ++ .mib_decs = ar8236_mibs, ++ .mib_func = AR8327_REG_MIB_FUNC, ++ .mib_rxb_id = AR8236_MIB_RXB_ID, ++ .mib_txb_id = AR8236_MIB_TXB_ID, ++}; +diff --git a/drivers/net/phy/ar8327.h b/drivers/net/phy/ar8327.h +new file mode 100644 +index 000000000000..53a82d1f76a3 +--- /dev/null ++++ b/drivers/net/phy/ar8327.h +@@ -0,0 +1,334 @@ ++/* ++ * ar8327.h: AR8216 switch driver ++ * ++ * Copyright (C) 2009 Felix Fietkau ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version 2 ++ * of the License, or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#ifndef __AR8327_H ++#define __AR8327_H ++ ++#define AR8327_NUM_PORTS 7 ++#define AR8327_NUM_LEDS 15 ++#define AR8327_PORTS_ALL 0x7f ++#define AR8327_NUM_LED_CTRL_REGS 4 ++ ++#define AR8327_REG_MASK 0x000 ++ ++#define AR8327_REG_PAD0_MODE 0x004 ++#define AR8327_REG_PAD5_MODE 0x008 ++#define AR8327_REG_PAD6_MODE 0x00c ++#define AR8327_PAD_MAC_MII_RXCLK_SEL BIT(0) ++#define AR8327_PAD_MAC_MII_TXCLK_SEL BIT(1) ++#define AR8327_PAD_MAC_MII_EN BIT(2) ++#define AR8327_PAD_MAC_GMII_RXCLK_SEL BIT(4) ++#define AR8327_PAD_MAC_GMII_TXCLK_SEL BIT(5) ++#define AR8327_PAD_MAC_GMII_EN BIT(6) ++#define AR8327_PAD_SGMII_EN BIT(7) ++#define AR8327_PAD_PHY_MII_RXCLK_SEL BIT(8) ++#define AR8327_PAD_PHY_MII_TXCLK_SEL BIT(9) ++#define AR8327_PAD_PHY_MII_EN BIT(10) ++#define AR8327_PAD_PHY_GMII_PIPE_RXCLK_SEL BIT(11) ++#define AR8327_PAD_PHY_GMII_RXCLK_SEL BIT(12) ++#define AR8327_PAD_PHY_GMII_TXCLK_SEL BIT(13) ++#define AR8327_PAD_PHY_GMII_EN BIT(14) ++#define AR8327_PAD_PHYX_GMII_EN BIT(16) ++#define AR8327_PAD_PHYX_RGMII_EN BIT(17) ++#define AR8327_PAD_PHYX_MII_EN BIT(18) ++#define AR8327_PAD_SGMII_DELAY_EN BIT(19) ++#define AR8327_PAD_RGMII_RXCLK_DELAY_SEL BITS(20, 2) ++#define AR8327_PAD_RGMII_RXCLK_DELAY_SEL_S 20 ++#define AR8327_PAD_RGMII_TXCLK_DELAY_SEL BITS(22, 2) ++#define AR8327_PAD_RGMII_TXCLK_DELAY_SEL_S 22 ++#define AR8327_PAD_RGMII_RXCLK_DELAY_EN BIT(24) ++#define AR8327_PAD_RGMII_TXCLK_DELAY_EN BIT(25) ++#define AR8327_PAD_RGMII_EN BIT(26) ++ ++#define AR8327_REG_POWER_ON_STRAP 0x010 ++#define AR8327_POWER_ON_STRAP_POWER_ON_SEL BIT(31) ++#define AR8327_POWER_ON_STRAP_LED_OPEN_EN BIT(24) ++#define AR8327_POWER_ON_STRAP_SERDES_AEN BIT(7) ++ ++#define AR8327_REG_INT_STATUS0 0x020 ++#define AR8327_INT0_VT_DONE BIT(20) ++ ++#define AR8327_REG_INT_STATUS1 0x024 ++#define AR8327_REG_INT_MASK0 0x028 ++#define AR8327_REG_INT_MASK1 0x02c ++ ++#define AR8327_REG_MODULE_EN 0x030 ++#define AR8327_MODULE_EN_MIB BIT(0) ++ ++#define AR8327_REG_MIB_FUNC 0x034 ++#define AR8327_MIB_CPU_KEEP BIT(20) ++ ++#define AR8327_REG_SERVICE_TAG 0x048 ++#define AR8327_REG_LED_CTRL(_i) (0x050 + (_i) * 4) ++#define AR8327_REG_LED_CTRL0 0x050 ++#define AR8327_REG_LED_CTRL1 0x054 ++#define AR8327_REG_LED_CTRL2 0x058 ++#define AR8327_REG_LED_CTRL3 0x05c ++#define AR8327_REG_MAC_ADDR0 0x060 ++#define AR8327_REG_MAC_ADDR1 0x064 ++ ++#define AR8327_REG_MAX_FRAME_SIZE 0x078 ++#define AR8327_MAX_FRAME_SIZE_MTU BITS(0, 14) ++ ++#define AR8327_REG_PORT_STATUS(_i) (0x07c + (_i) * 4) ++#define AR8327_PORT_STATUS_TXFLOW_AUTO BIT(10) ++#define AR8327_PORT_STATUS_RXFLOW_AUTO BIT(11) ++ ++#define AR8327_REG_HEADER_CTRL 0x098 ++#define AR8327_REG_PORT_HEADER(_i) (0x09c + (_i) * 4) ++ ++#define AR8327_REG_SGMII_CTRL 0x0e0 ++#define AR8327_SGMII_CTRL_EN_PLL BIT(1) ++#define AR8327_SGMII_CTRL_EN_RX BIT(2) ++#define AR8327_SGMII_CTRL_EN_TX BIT(3) ++ ++#define AR8327_REG_EEE_CTRL 0x100 ++#define AR8327_EEE_CTRL_DISABLE_PHY(_i) BIT(4 + (_i) * 2) ++ ++#define AR8327_REG_FRAME_ACK_CTRL0 0x210 ++#define AR8327_FRAME_ACK_CTRL_IGMP_MLD_EN0 BIT(0) ++#define AR8327_FRAME_ACK_CTRL_IGMP_JOIN_EN0 BIT(1) ++#define AR8327_FRAME_ACK_CTRL_IGMP_LEAVE_EN0 BIT(2) ++#define AR8327_FRAME_ACK_CTRL_EAPOL_EN0 BIT(3) ++#define AR8327_FRAME_ACK_CTRL_DHCP_EN0 BIT(4) ++#define AR8327_FRAME_ACK_CTRL_ARP_ACK_EN0 BIT(5) ++#define AR8327_FRAME_ACK_CTRL_ARP_REQ_EN0 BIT(6) ++#define AR8327_FRAME_ACK_CTRL_IGMP_MLD_EN1 BIT(8) ++#define AR8327_FRAME_ACK_CTRL_IGMP_JOIN_EN1 BIT(9) ++#define AR8327_FRAME_ACK_CTRL_IGMP_LEAVE_EN1 BIT(10) ++#define AR8327_FRAME_ACK_CTRL_EAPOL_EN1 BIT(11) ++#define AR8327_FRAME_ACK_CTRL_DHCP_EN1 BIT(12) ++#define AR8327_FRAME_ACK_CTRL_ARP_ACK_EN1 BIT(13) ++#define AR8327_FRAME_ACK_CTRL_ARP_REQ_EN1 BIT(14) ++#define AR8327_FRAME_ACK_CTRL_IGMP_MLD_EN2 BIT(16) ++#define AR8327_FRAME_ACK_CTRL_IGMP_JOIN_EN2 BIT(17) ++#define AR8327_FRAME_ACK_CTRL_IGMP_LEAVE_EN2 BIT(18) ++#define AR8327_FRAME_ACK_CTRL_EAPOL_EN2 BIT(19) ++#define AR8327_FRAME_ACK_CTRL_DHCP_EN2 BIT(20) ++#define AR8327_FRAME_ACK_CTRL_ARP_ACK_EN2 BIT(21) ++#define AR8327_FRAME_ACK_CTRL_ARP_REQ_EN2 BIT(22) ++#define AR8327_FRAME_ACK_CTRL_IGMP_MLD_EN3 BIT(24) ++#define AR8327_FRAME_ACK_CTRL_IGMP_JOIN_EN3 BIT(25) ++#define AR8327_FRAME_ACK_CTRL_IGMP_LEAVE_EN3 BIT(26) ++#define AR8327_FRAME_ACK_CTRL_EAPOL_EN3 BIT(27) ++#define AR8327_FRAME_ACK_CTRL_DHCP_EN3 BIT(28) ++#define AR8327_FRAME_ACK_CTRL_ARP_ACK_EN3 BIT(29) ++#define AR8327_FRAME_ACK_CTRL_ARP_REQ_EN3 BIT(30) ++ ++#define AR8327_REG_FRAME_ACK_CTRL1 0x214 ++#define AR8327_FRAME_ACK_CTRL_IGMP_MLD_EN4 BIT(0) ++#define AR8327_FRAME_ACK_CTRL_IGMP_JOIN_EN4 BIT(1) ++#define AR8327_FRAME_ACK_CTRL_IGMP_LEAVE_EN4 BIT(2) ++#define AR8327_FRAME_ACK_CTRL_EAPOL_EN4 BIT(3) ++#define AR8327_FRAME_ACK_CTRL_DHCP_EN4 BIT(4) ++#define AR8327_FRAME_ACK_CTRL_ARP_ACK_EN4 BIT(5) ++#define AR8327_FRAME_ACK_CTRL_ARP_REQ_EN4 BIT(6) ++#define AR8327_FRAME_ACK_CTRL_IGMP_MLD_EN5 BIT(8) ++#define AR8327_FRAME_ACK_CTRL_IGMP_JOIN_EN5 BIT(9) ++#define AR8327_FRAME_ACK_CTRL_IGMP_LEAVE_EN5 BIT(10) ++#define AR8327_FRAME_ACK_CTRL_EAPOL_EN5 BIT(11) ++#define AR8327_FRAME_ACK_CTRL_DHCP_EN5 BIT(12) ++#define AR8327_FRAME_ACK_CTRL_ARP_ACK_EN5 BIT(13) ++#define AR8327_FRAME_ACK_CTRL_ARP_REQ_EN5 BIT(14) ++#define AR8327_FRAME_ACK_CTRL_IGMP_MLD_EN6 BIT(16) ++#define AR8327_FRAME_ACK_CTRL_IGMP_JOIN_EN6 BIT(17) ++#define AR8327_FRAME_ACK_CTRL_IGMP_LEAVE_EN6 BIT(18) ++#define AR8327_FRAME_ACK_CTRL_EAPOL_EN6 BIT(19) ++#define AR8327_FRAME_ACK_CTRL_DHCP_EN6 BIT(20) ++#define AR8327_FRAME_ACK_CTRL_ARP_ACK_EN6 BIT(21) ++#define AR8327_FRAME_ACK_CTRL_ARP_REQ_EN6 BIT(22) ++#define AR8327_FRAME_ACK_CTRL_IGMP_V3_EN BIT(24) ++#define AR8327_FRAME_ACK_CTRL_PPPOE_EN BIT(25) ++ ++#define AR8327_REG_FRAME_ACK_CTRL(_i) (0x210 + ((_i) / 4) * 0x4) ++#define AR8327_FRAME_ACK_CTRL_IGMP_MLD BIT(0) ++#define AR8327_FRAME_ACK_CTRL_IGMP_JOIN BIT(1) ++#define AR8327_FRAME_ACK_CTRL_IGMP_LEAVE BIT(2) ++#define AR8327_FRAME_ACK_CTRL_EAPOL BIT(3) ++#define AR8327_FRAME_ACK_CTRL_DHCP BIT(4) ++#define AR8327_FRAME_ACK_CTRL_ARP_ACK BIT(5) ++#define AR8327_FRAME_ACK_CTRL_ARP_REQ BIT(6) ++#define AR8327_FRAME_ACK_CTRL_S(_i) (((_i) % 4) * 8) ++ ++#define AR8327_REG_PORT_VLAN0(_i) (0x420 + (_i) * 0x8) ++#define AR8327_PORT_VLAN0_DEF_PRI_MASK BITS(0, 3) ++#define AR8327_PORT_VLAN0_DEF_SVID BITS(0, 12) ++#define AR8327_PORT_VLAN0_DEF_SVID_S 0 ++#define AR8327_PORT_VLAN0_DEF_SPRI BITS(13, 3) ++#define AR8327_PORT_VLAN0_DEF_SPRI_S 13 ++#define AR8327_PORT_VLAN0_DEF_CVID BITS(16, 12) ++#define AR8327_PORT_VLAN0_DEF_CVID_S 16 ++#define AR8327_PORT_VLAN0_DEF_CPRI BITS(29, 3) ++#define AR8327_PORT_VLAN0_DEF_CPRI_S 29 ++ ++#define AR8327_REG_PORT_VLAN1(_i) (0x424 + (_i) * 0x8) ++#define AR8327_PORT_VLAN1_VLAN_PRI_PROP BIT(4) ++#define AR8327_PORT_VLAN1_PORT_VLAN_PROP BIT(6) ++#define AR8327_PORT_VLAN1_OUT_MODE BITS(12, 2) ++#define AR8327_PORT_VLAN1_OUT_MODE_S 12 ++#define AR8327_PORT_VLAN1_OUT_MODE_UNMOD 0 ++#define AR8327_PORT_VLAN1_OUT_MODE_UNTAG 1 ++#define AR8327_PORT_VLAN1_OUT_MODE_TAG 2 ++#define AR8327_PORT_VLAN1_OUT_MODE_UNTOUCH 3 ++ ++#define AR8327_REG_ATU_DATA0 0x600 ++#define AR8327_ATU_ADDR0 BITS(0, 8) ++#define AR8327_ATU_ADDR0_S 0 ++#define AR8327_ATU_ADDR1 BITS(8, 8) ++#define AR8327_ATU_ADDR1_S 8 ++#define AR8327_ATU_ADDR2 BITS(16, 8) ++#define AR8327_ATU_ADDR2_S 16 ++#define AR8327_ATU_ADDR3 BITS(24, 8) ++#define AR8327_ATU_ADDR3_S 24 ++#define AR8327_REG_ATU_DATA1 0x604 ++#define AR8327_ATU_ADDR4 BITS(0, 8) ++#define AR8327_ATU_ADDR4_S 0 ++#define AR8327_ATU_ADDR5 BITS(8, 8) ++#define AR8327_ATU_ADDR5_S 8 ++#define AR8327_ATU_PORTS BITS(16, 7) ++#define AR8327_ATU_PORTS_S 16 ++#define AR8327_ATU_PORT0 BIT(16) ++#define AR8327_ATU_PORT1 BIT(17) ++#define AR8327_ATU_PORT2 BIT(18) ++#define AR8327_ATU_PORT3 BIT(19) ++#define AR8327_ATU_PORT4 BIT(20) ++#define AR8327_ATU_PORT5 BIT(21) ++#define AR8327_ATU_PORT6 BIT(22) ++#define AR8327_REG_ATU_DATA2 0x608 ++#define AR8327_ATU_STATUS BITS(0, 4) ++ ++#define AR8327_REG_ATU_FUNC 0x60c ++#define AR8327_ATU_FUNC_OP BITS(0, 4) ++#define AR8327_ATU_FUNC_OP_NOOP 0x0 ++#define AR8327_ATU_FUNC_OP_FLUSH 0x1 ++#define AR8327_ATU_FUNC_OP_LOAD 0x2 ++#define AR8327_ATU_FUNC_OP_PURGE 0x3 ++#define AR8327_ATU_FUNC_OP_FLUSH_UNLOCKED 0x4 ++#define AR8327_ATU_FUNC_OP_FLUSH_PORT 0x5 ++#define AR8327_ATU_FUNC_OP_GET_NEXT 0x6 ++#define AR8327_ATU_FUNC_OP_SEARCH_MAC 0x7 ++#define AR8327_ATU_FUNC_OP_CHANGE_TRUNK 0x8 ++#define AR8327_ATU_PORT_NUM BITS(8, 4) ++#define AR8327_ATU_PORT_NUM_S 8 ++#define AR8327_ATU_FUNC_BUSY BIT(31) ++ ++#define AR8327_REG_VTU_FUNC0 0x0610 ++#define AR8327_VTU_FUNC0_EG_MODE BITS(4, 14) ++#define AR8327_VTU_FUNC0_EG_MODE_S(_i) (4 + (_i) * 2) ++#define AR8327_VTU_FUNC0_EG_MODE_KEEP 0 ++#define AR8327_VTU_FUNC0_EG_MODE_UNTAG 1 ++#define AR8327_VTU_FUNC0_EG_MODE_TAG 2 ++#define AR8327_VTU_FUNC0_EG_MODE_NOT 3 ++#define AR8327_VTU_FUNC0_IVL BIT(19) ++#define AR8327_VTU_FUNC0_VALID BIT(20) ++ ++#define AR8327_REG_VTU_FUNC1 0x0614 ++#define AR8327_VTU_FUNC1_OP BITS(0, 3) ++#define AR8327_VTU_FUNC1_OP_NOOP 0 ++#define AR8327_VTU_FUNC1_OP_FLUSH 1 ++#define AR8327_VTU_FUNC1_OP_LOAD 2 ++#define AR8327_VTU_FUNC1_OP_PURGE 3 ++#define AR8327_VTU_FUNC1_OP_REMOVE_PORT 4 ++#define AR8327_VTU_FUNC1_OP_GET_NEXT 5 ++#define AR8327_VTU_FUNC1_OP_GET_ONE 6 ++#define AR8327_VTU_FUNC1_FULL BIT(4) ++#define AR8327_VTU_FUNC1_PORT BIT(8, 4) ++#define AR8327_VTU_FUNC1_PORT_S 8 ++#define AR8327_VTU_FUNC1_VID BIT(16, 12) ++#define AR8327_VTU_FUNC1_VID_S 16 ++#define AR8327_VTU_FUNC1_BUSY BIT(31) ++ ++#define AR8327_REG_ARL_CTRL 0x0618 ++ ++#define AR8327_REG_FWD_CTRL0 0x620 ++#define AR8327_FWD_CTRL0_CPU_PORT_EN BIT(10) ++#define AR8327_FWD_CTRL0_MIRROR_PORT BITS(4, 4) ++#define AR8327_FWD_CTRL0_MIRROR_PORT_S 4 ++ ++#define AR8327_REG_FWD_CTRL1 0x624 ++#define AR8327_FWD_CTRL1_UC_FLOOD BITS(0, 7) ++#define AR8327_FWD_CTRL1_UC_FLOOD_S 0 ++#define AR8327_FWD_CTRL1_MC_FLOOD BITS(8, 7) ++#define AR8327_FWD_CTRL1_MC_FLOOD_S 8 ++#define AR8327_FWD_CTRL1_BC_FLOOD BITS(16, 7) ++#define AR8327_FWD_CTRL1_BC_FLOOD_S 16 ++#define AR8327_FWD_CTRL1_IGMP BITS(24, 7) ++#define AR8327_FWD_CTRL1_IGMP_S 24 ++ ++#define AR8327_REG_PORT_LOOKUP(_i) (0x660 + (_i) * 0xc) ++#define AR8327_PORT_LOOKUP_MEMBER BITS(0, 7) ++#define AR8327_PORT_LOOKUP_IN_MODE BITS(8, 2) ++#define AR8327_PORT_LOOKUP_IN_MODE_S 8 ++#define AR8327_PORT_LOOKUP_STATE BITS(16, 3) ++#define AR8327_PORT_LOOKUP_STATE_S 16 ++#define AR8327_PORT_LOOKUP_LEARN BIT(20) ++#define AR8327_PORT_LOOKUP_ING_MIRROR_EN BIT(25) ++ ++#define AR8327_REG_PORT_PRIO(_i) (0x664 + (_i) * 0xc) ++ ++#define AR8327_REG_PORT_HOL_CTRL1(_i) (0x974 + (_i) * 0x8) ++#define AR8327_PORT_HOL_CTRL1_EG_MIRROR_EN BIT(16) ++ ++#define AR8337_PAD_MAC06_EXCHANGE_EN BIT(31) ++ ++#define AR8327_PHY_MODE_SEL 0x12 ++#define AR8327_PHY_MODE_SEL_RGMII BIT(3) ++#define AR8327_PHY_TEST_CTRL 0x0 ++#define AR8327_PHY_TEST_CTRL_RGMII_RX_DELAY BIT(15) ++#define AR8327_PHY_SYS_CTRL 0x5 ++#define AR8327_PHY_SYS_CTRL_RGMII_TX_DELAY BIT(8) ++ ++enum ar8327_led_pattern { ++ AR8327_LED_PATTERN_OFF = 0, ++ AR8327_LED_PATTERN_BLINK, ++ AR8327_LED_PATTERN_ON, ++ AR8327_LED_PATTERN_RULE, ++}; ++ ++struct ar8327_led_entry { ++ unsigned reg; ++ unsigned shift; ++}; ++ ++struct ar8327_led { ++ struct led_classdev cdev; ++ struct ar8xxx_priv *sw_priv; ++ ++ char *name; ++ bool active_low; ++ u8 led_num; ++ enum ar8327_led_mode mode; ++ ++ struct mutex mutex; ++ spinlock_t lock; ++ struct work_struct led_work; ++ bool enable_hw_mode; ++ enum ar8327_led_pattern pattern; ++ struct fwnode_handle *fwnode; ++}; ++ ++struct ar8327_data { ++ u32 port0_status; ++ u32 port6_status; ++ ++ struct ar8327_led **leds; ++ unsigned int num_leds; ++ ++ /* all fields below are cleared on reset */ ++ bool eee[AR8XXX_NUM_PHYS]; ++}; ++ ++#endif +diff --git a/drivers/net/phy/b53/Kconfig b/drivers/net/phy/b53/Kconfig +new file mode 100644 +index 000000000000..08287e7adf79 +--- /dev/null ++++ b/drivers/net/phy/b53/Kconfig +@@ -0,0 +1,37 @@ ++menuconfig SWCONFIG_B53 ++ tristate "Broadcom bcm53xx managed switch support" ++ depends on SWCONFIG ++ help ++ This driver adds support for Broadcom managed switch chips. It supports ++ BCM5325E, BCM5365, BCM539x, BCM53115 and BCM53125 as well as BCM63XX ++ integrated switches. ++ ++config SWCONFIG_B53_SPI_DRIVER ++ tristate "B53 SPI connected switch driver" ++ depends on SWCONFIG_B53 && SPI ++ help ++ Select to enable support for registering switches configured through SPI. ++ ++config SWCONFIG_B53_PHY_DRIVER ++ tristate "B53 MDIO connected switch driver" ++ depends on SWCONFIG_B53 ++ select SWCONFIG_B53_PHY_FIXUP ++ help ++ Select to enable support for registering switches configured through MDIO. ++ ++config SWCONFIG_B53_MMAP_DRIVER ++ tristate "B53 MMAP connected switch driver" ++ depends on SWCONFIG_B53 ++ help ++ Select to enable support for memory-mapped switches like the BCM63XX ++ integrated switches. ++ ++config SWCONFIG_B53_SRAB_DRIVER ++ tristate "B53 SRAB connected switch driver" ++ depends on SWCONFIG_B53 ++ help ++ Select to enable support for memory-mapped Switch Register Access ++ Bridge Registers (SRAB) like it is found on the BCM53010 ++ ++config SWCONFIG_B53_PHY_FIXUP ++ bool +diff --git a/drivers/net/phy/b53/Makefile b/drivers/net/phy/b53/Makefile +new file mode 100644 +index 000000000000..13ff366448df +--- /dev/null ++++ b/drivers/net/phy/b53/Makefile +@@ -0,0 +1,10 @@ ++obj-$(CONFIG_SWCONFIG_B53) += b53_common.o ++ ++obj-$(CONFIG_SWCONFIG_B53_PHY_FIXUP) += b53_phy_fixup.o ++ ++obj-$(CONFIG_SWCONFIG_B53_MMAP_DRIVER) += b53_mmap.o ++obj-$(CONFIG_SWCONFIG_B53_SRAB_DRIVER) += b53_srab.o ++obj-$(CONFIG_SWCONFIG_B53_PHY_DRIVER) += b53_mdio.o ++obj-$(CONFIG_SWCONFIG_B53_SPI_DRIVER) += b53_spi.o ++ ++ccflags-y += -Werror +diff --git a/drivers/net/phy/b53/b53_common.c b/drivers/net/phy/b53/b53_common.c +new file mode 100644 +index 000000000000..d5f9bfc2f043 +--- /dev/null ++++ b/drivers/net/phy/b53/b53_common.c +@@ -0,0 +1,1724 @@ ++/* ++ * B53 switch driver main logic ++ * ++ * Copyright (C) 2011-2013 Jonas Gorski ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "b53_regs.h" ++#include "b53_priv.h" ++ ++/* buffer size needed for displaying all MIBs with max'd values */ ++#define B53_BUF_SIZE 1188 ++ ++struct b53_mib_desc { ++ u8 size; ++ u8 offset; ++ const char *name; ++}; ++ ++/* BCM5365 MIB counters */ ++static const struct b53_mib_desc b53_mibs_65[] = { ++ { 8, 0x00, "TxOctets" }, ++ { 4, 0x08, "TxDropPkts" }, ++ { 4, 0x10, "TxBroadcastPkts" }, ++ { 4, 0x14, "TxMulticastPkts" }, ++ { 4, 0x18, "TxUnicastPkts" }, ++ { 4, 0x1c, "TxCollisions" }, ++ { 4, 0x20, "TxSingleCollision" }, ++ { 4, 0x24, "TxMultipleCollision" }, ++ { 4, 0x28, "TxDeferredTransmit" }, ++ { 4, 0x2c, "TxLateCollision" }, ++ { 4, 0x30, "TxExcessiveCollision" }, ++ { 4, 0x38, "TxPausePkts" }, ++ { 8, 0x44, "RxOctets" }, ++ { 4, 0x4c, "RxUndersizePkts" }, ++ { 4, 0x50, "RxPausePkts" }, ++ { 4, 0x54, "Pkts64Octets" }, ++ { 4, 0x58, "Pkts65to127Octets" }, ++ { 4, 0x5c, "Pkts128to255Octets" }, ++ { 4, 0x60, "Pkts256to511Octets" }, ++ { 4, 0x64, "Pkts512to1023Octets" }, ++ { 4, 0x68, "Pkts1024to1522Octets" }, ++ { 4, 0x6c, "RxOversizePkts" }, ++ { 4, 0x70, "RxJabbers" }, ++ { 4, 0x74, "RxAlignmentErrors" }, ++ { 4, 0x78, "RxFCSErrors" }, ++ { 8, 0x7c, "RxGoodOctets" }, ++ { 4, 0x84, "RxDropPkts" }, ++ { 4, 0x88, "RxUnicastPkts" }, ++ { 4, 0x8c, "RxMulticastPkts" }, ++ { 4, 0x90, "RxBroadcastPkts" }, ++ { 4, 0x94, "RxSAChanges" }, ++ { 4, 0x98, "RxFragments" }, ++ { }, ++}; ++ ++#define B63XX_MIB_TXB_ID 0 /* TxOctets */ ++#define B63XX_MIB_RXB_ID 14 /* RxOctets */ ++ ++/* BCM63xx MIB counters */ ++static const struct b53_mib_desc b53_mibs_63xx[] = { ++ { 8, 0x00, "TxOctets" }, ++ { 4, 0x08, "TxDropPkts" }, ++ { 4, 0x0c, "TxQoSPkts" }, ++ { 4, 0x10, "TxBroadcastPkts" }, ++ { 4, 0x14, "TxMulticastPkts" }, ++ { 4, 0x18, "TxUnicastPkts" }, ++ { 4, 0x1c, "TxCollisions" }, ++ { 4, 0x20, "TxSingleCollision" }, ++ { 4, 0x24, "TxMultipleCollision" }, ++ { 4, 0x28, "TxDeferredTransmit" }, ++ { 4, 0x2c, "TxLateCollision" }, ++ { 4, 0x30, "TxExcessiveCollision" }, ++ { 4, 0x38, "TxPausePkts" }, ++ { 8, 0x3c, "TxQoSOctets" }, ++ { 8, 0x44, "RxOctets" }, ++ { 4, 0x4c, "RxUndersizePkts" }, ++ { 4, 0x50, "RxPausePkts" }, ++ { 4, 0x54, "Pkts64Octets" }, ++ { 4, 0x58, "Pkts65to127Octets" }, ++ { 4, 0x5c, "Pkts128to255Octets" }, ++ { 4, 0x60, "Pkts256to511Octets" }, ++ { 4, 0x64, "Pkts512to1023Octets" }, ++ { 4, 0x68, "Pkts1024to1522Octets" }, ++ { 4, 0x6c, "RxOversizePkts" }, ++ { 4, 0x70, "RxJabbers" }, ++ { 4, 0x74, "RxAlignmentErrors" }, ++ { 4, 0x78, "RxFCSErrors" }, ++ { 8, 0x7c, "RxGoodOctets" }, ++ { 4, 0x84, "RxDropPkts" }, ++ { 4, 0x88, "RxUnicastPkts" }, ++ { 4, 0x8c, "RxMulticastPkts" }, ++ { 4, 0x90, "RxBroadcastPkts" }, ++ { 4, 0x94, "RxSAChanges" }, ++ { 4, 0x98, "RxFragments" }, ++ { 4, 0xa0, "RxSymbolErrors" }, ++ { 4, 0xa4, "RxQoSPkts" }, ++ { 8, 0xa8, "RxQoSOctets" }, ++ { 4, 0xb0, "Pkts1523to2047Octets" }, ++ { 4, 0xb4, "Pkts2048to4095Octets" }, ++ { 4, 0xb8, "Pkts4096to8191Octets" }, ++ { 4, 0xbc, "Pkts8192to9728Octets" }, ++ { 4, 0xc0, "RxDiscarded" }, ++ { } ++}; ++ ++#define B53XX_MIB_TXB_ID 0 /* TxOctets */ ++#define B53XX_MIB_RXB_ID 12 /* RxOctets */ ++ ++/* MIB counters */ ++static const struct b53_mib_desc b53_mibs[] = { ++ { 8, 0x00, "TxOctets" }, ++ { 4, 0x08, "TxDropPkts" }, ++ { 4, 0x10, "TxBroadcastPkts" }, ++ { 4, 0x14, "TxMulticastPkts" }, ++ { 4, 0x18, "TxUnicastPkts" }, ++ { 4, 0x1c, "TxCollisions" }, ++ { 4, 0x20, "TxSingleCollision" }, ++ { 4, 0x24, "TxMultipleCollision" }, ++ { 4, 0x28, "TxDeferredTransmit" }, ++ { 4, 0x2c, "TxLateCollision" }, ++ { 4, 0x30, "TxExcessiveCollision" }, ++ { 4, 0x38, "TxPausePkts" }, ++ { 8, 0x50, "RxOctets" }, ++ { 4, 0x58, "RxUndersizePkts" }, ++ { 4, 0x5c, "RxPausePkts" }, ++ { 4, 0x60, "Pkts64Octets" }, ++ { 4, 0x64, "Pkts65to127Octets" }, ++ { 4, 0x68, "Pkts128to255Octets" }, ++ { 4, 0x6c, "Pkts256to511Octets" }, ++ { 4, 0x70, "Pkts512to1023Octets" }, ++ { 4, 0x74, "Pkts1024to1522Octets" }, ++ { 4, 0x78, "RxOversizePkts" }, ++ { 4, 0x7c, "RxJabbers" }, ++ { 4, 0x80, "RxAlignmentErrors" }, ++ { 4, 0x84, "RxFCSErrors" }, ++ { 8, 0x88, "RxGoodOctets" }, ++ { 4, 0x90, "RxDropPkts" }, ++ { 4, 0x94, "RxUnicastPkts" }, ++ { 4, 0x98, "RxMulticastPkts" }, ++ { 4, 0x9c, "RxBroadcastPkts" }, ++ { 4, 0xa0, "RxSAChanges" }, ++ { 4, 0xa4, "RxFragments" }, ++ { 4, 0xa8, "RxJumboPkts" }, ++ { 4, 0xac, "RxSymbolErrors" }, ++ { 4, 0xc0, "RxDiscarded" }, ++ { } ++}; ++ ++static int b53_do_vlan_op(struct b53_device *dev, u8 op) ++{ ++ unsigned int i; ++ ++ b53_write8(dev, B53_ARLIO_PAGE, dev->vta_regs[0], VTA_START_CMD | op); ++ ++ for (i = 0; i < 10; i++) { ++ u8 vta; ++ ++ b53_read8(dev, B53_ARLIO_PAGE, dev->vta_regs[0], &vta); ++ if (!(vta & VTA_START_CMD)) ++ return 0; ++ ++ usleep_range(100, 200); ++ } ++ ++ return -EIO; ++} ++ ++static void b53_set_vlan_entry(struct b53_device *dev, u16 vid, u16 members, ++ u16 untag) ++{ ++ if (is5325(dev)) { ++ u32 entry = 0; ++ ++ if (members) { ++ entry = ((untag & VA_UNTAG_MASK_25) << VA_UNTAG_S_25) | ++ members; ++ if (dev->core_rev >= 3) ++ entry |= VA_VALID_25_R4 | vid << VA_VID_HIGH_S; ++ else ++ entry |= VA_VALID_25; ++ } ++ ++ b53_write32(dev, B53_VLAN_PAGE, B53_VLAN_WRITE_25, entry); ++ b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_TABLE_ACCESS_25, vid | ++ VTA_RW_STATE_WR | VTA_RW_OP_EN); ++ } else if (is5365(dev)) { ++ u16 entry = 0; ++ ++ if (members) ++ entry = ((untag & VA_UNTAG_MASK_65) << VA_UNTAG_S_65) | ++ members | VA_VALID_65; ++ ++ b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_WRITE_65, entry); ++ b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_TABLE_ACCESS_65, vid | ++ VTA_RW_STATE_WR | VTA_RW_OP_EN); ++ } else { ++ b53_write16(dev, B53_ARLIO_PAGE, dev->vta_regs[1], vid); ++ b53_write32(dev, B53_ARLIO_PAGE, dev->vta_regs[2], ++ (untag << VTE_UNTAG_S) | members); ++ ++ b53_do_vlan_op(dev, VTA_CMD_WRITE); ++ } ++} ++ ++void b53_set_forwarding(struct b53_device *dev, int enable) ++{ ++ u8 mgmt; ++ ++ b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt); ++ ++ if (enable) ++ mgmt |= SM_SW_FWD_EN; ++ else ++ mgmt &= ~SM_SW_FWD_EN; ++ ++ b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, mgmt); ++} ++ ++static void b53_enable_vlan(struct b53_device *dev, int enable) ++{ ++ u8 mgmt, vc0, vc1, vc4 = 0, vc5; ++ ++ b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt); ++ b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL0, &vc0); ++ b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL1, &vc1); ++ ++ if (is5325(dev) || is5365(dev)) { ++ b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_25, &vc4); ++ b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5_25, &vc5); ++ } else if (is63xx(dev)) { ++ b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_63XX, &vc4); ++ b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5_63XX, &vc5); ++ } else { ++ b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4, &vc4); ++ b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5, &vc5); ++ } ++ ++ mgmt &= ~SM_SW_FWD_MODE; ++ ++ if (enable) { ++ vc0 |= VC0_VLAN_EN | VC0_VID_CHK_EN | VC0_VID_HASH_VID; ++ vc1 |= VC1_RX_MCST_UNTAG_EN | VC1_RX_MCST_FWD_EN; ++ vc4 &= ~VC4_ING_VID_CHECK_MASK; ++ vc4 |= VC4_ING_VID_VIO_DROP << VC4_ING_VID_CHECK_S; ++ vc5 |= VC5_DROP_VTABLE_MISS; ++ ++ if (is5325(dev)) ++ vc0 &= ~VC0_RESERVED_1; ++ ++ if (is5325(dev) || is5365(dev)) ++ vc1 |= VC1_RX_MCST_TAG_EN; ++ ++ if (!is5325(dev) && !is5365(dev)) { ++ if (dev->allow_vid_4095) ++ vc5 |= VC5_VID_FFF_EN; ++ else ++ vc5 &= ~VC5_VID_FFF_EN; ++ } ++ } else { ++ vc0 &= ~(VC0_VLAN_EN | VC0_VID_CHK_EN | VC0_VID_HASH_VID); ++ vc1 &= ~(VC1_RX_MCST_UNTAG_EN | VC1_RX_MCST_FWD_EN); ++ vc4 &= ~VC4_ING_VID_CHECK_MASK; ++ vc5 &= ~VC5_DROP_VTABLE_MISS; ++ ++ if (is5325(dev) || is5365(dev)) ++ vc4 |= VC4_ING_VID_VIO_FWD << VC4_ING_VID_CHECK_S; ++ else ++ vc4 |= VC4_ING_VID_VIO_TO_IMP << VC4_ING_VID_CHECK_S; ++ ++ if (is5325(dev) || is5365(dev)) ++ vc1 &= ~VC1_RX_MCST_TAG_EN; ++ ++ if (!is5325(dev) && !is5365(dev)) ++ vc5 &= ~VC5_VID_FFF_EN; ++ } ++ ++ b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL0, vc0); ++ b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL1, vc1); ++ ++ if (is5325(dev) || is5365(dev)) { ++ /* enable the high 8 bit vid check on 5325 */ ++ if (is5325(dev) && enable) ++ b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL3, ++ VC3_HIGH_8BIT_EN); ++ else ++ b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL3, 0); ++ ++ b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_25, vc4); ++ b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5_25, vc5); ++ } else if (is63xx(dev)) { ++ b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_CTRL3_63XX, 0); ++ b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_63XX, vc4); ++ b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5_63XX, vc5); ++ } else { ++ b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_CTRL3, 0); ++ b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4, vc4); ++ b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5, vc5); ++ } ++ ++ b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, mgmt); ++} ++ ++static int b53_set_jumbo(struct b53_device *dev, int enable, int allow_10_100) ++{ ++ u32 port_mask = 0; ++ u16 max_size = JMS_MIN_SIZE; ++ ++ if (is5325(dev) || is5365(dev)) ++ return -EINVAL; ++ ++ if (enable) { ++ port_mask = dev->enabled_ports; ++ max_size = JMS_MAX_SIZE; ++ if (allow_10_100) ++ port_mask |= JPM_10_100_JUMBO_EN; ++ } ++ ++ b53_write32(dev, B53_JUMBO_PAGE, dev->jumbo_pm_reg, port_mask); ++ return b53_write16(dev, B53_JUMBO_PAGE, dev->jumbo_size_reg, max_size); ++} ++ ++static int b53_flush_arl(struct b53_device *dev) ++{ ++ unsigned int i; ++ ++ b53_write8(dev, B53_CTRL_PAGE, B53_FAST_AGE_CTRL, ++ FAST_AGE_DONE | FAST_AGE_DYNAMIC | FAST_AGE_STATIC); ++ ++ for (i = 0; i < 10; i++) { ++ u8 fast_age_ctrl; ++ ++ b53_read8(dev, B53_CTRL_PAGE, B53_FAST_AGE_CTRL, ++ &fast_age_ctrl); ++ ++ if (!(fast_age_ctrl & FAST_AGE_DONE)) ++ return 0; ++ ++ mdelay(1); ++ } ++ ++ pr_warn("time out while flushing ARL\n"); ++ ++ return -EINVAL; ++} ++ ++static void b53_enable_ports(struct b53_device *dev) ++{ ++ unsigned i; ++ ++ b53_for_each_port(dev, i) { ++ u8 port_ctrl; ++ u16 pvlan_mask; ++ ++ /* ++ * prevent leaking packets between wan and lan in unmanaged ++ * mode through port vlans. ++ */ ++ if (dev->enable_vlan || is_cpu_port(dev, i)) ++ pvlan_mask = 0x1ff; ++ else if (is531x5(dev) || is5301x(dev)) ++ /* BCM53115 may use a different port as cpu port */ ++ pvlan_mask = BIT(dev->sw_dev.cpu_port); ++ else ++ pvlan_mask = BIT(B53_CPU_PORT); ++ ++ /* BCM5325 CPU port is at 8 */ ++ if ((is5325(dev) || is5365(dev)) && i == B53_CPU_PORT_25) ++ i = B53_CPU_PORT; ++ ++ if (dev->chip_id == BCM5398_DEVICE_ID && (i == 6 || i == 7)) ++ /* disable unused ports 6 & 7 */ ++ port_ctrl = PORT_CTRL_RX_DISABLE | PORT_CTRL_TX_DISABLE; ++ else if (i == B53_CPU_PORT) ++ port_ctrl = PORT_CTRL_RX_BCST_EN | ++ PORT_CTRL_RX_MCST_EN | ++ PORT_CTRL_RX_UCST_EN; ++ else ++ port_ctrl = 0; ++ ++ b53_write16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(i), ++ pvlan_mask); ++ ++ /* port state is handled by bcm63xx_enet driver */ ++ if (!is63xx(dev) && !(is5301x(dev) && i == 6)) ++ b53_write8(dev, B53_CTRL_PAGE, B53_PORT_CTRL(i), ++ port_ctrl); ++ } ++} ++ ++static void b53_enable_mib(struct b53_device *dev) ++{ ++ u8 gc; ++ ++ b53_read8(dev, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, &gc); ++ ++ gc &= ~(GC_RESET_MIB | GC_MIB_AC_EN); ++ ++ b53_write8(dev, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, gc); ++} ++ ++static int b53_apply(struct b53_device *dev) ++{ ++ int i; ++ ++ /* clear all vlan entries */ ++ if (is5325(dev) || is5365(dev)) { ++ for (i = 1; i < dev->sw_dev.vlans; i++) ++ b53_set_vlan_entry(dev, i, 0, 0); ++ } else { ++ b53_do_vlan_op(dev, VTA_CMD_CLEAR); ++ } ++ ++ b53_enable_vlan(dev, dev->enable_vlan); ++ ++ /* fill VLAN table */ ++ if (dev->enable_vlan) { ++ for (i = 0; i < dev->sw_dev.vlans; i++) { ++ struct b53_vlan *vlan = &dev->vlans[i]; ++ ++ if (!vlan->members) ++ continue; ++ ++ b53_set_vlan_entry(dev, i, vlan->members, vlan->untag); ++ } ++ ++ b53_for_each_port(dev, i) ++ b53_write16(dev, B53_VLAN_PAGE, ++ B53_VLAN_PORT_DEF_TAG(i), ++ dev->ports[i].pvid); ++ } else { ++ b53_for_each_port(dev, i) ++ b53_write16(dev, B53_VLAN_PAGE, ++ B53_VLAN_PORT_DEF_TAG(i), 1); ++ ++ } ++ ++ b53_enable_ports(dev); ++ ++ if (!is5325(dev) && !is5365(dev)) ++ b53_set_jumbo(dev, dev->enable_jumbo, 1); ++ ++ return 0; ++} ++ ++static void b53_switch_reset_gpio(struct b53_device *dev) ++{ ++ int gpio = dev->reset_gpio; ++ ++ if (gpio < 0) ++ return; ++ ++ /* ++ * Reset sequence: RESET low(50ms)->high(20ms) ++ */ ++ gpio_set_value(gpio, 0); ++ mdelay(50); ++ ++ gpio_set_value(gpio, 1); ++ mdelay(20); ++ ++ dev->current_page = 0xff; ++} ++ ++static int b53_configure_ports_of(struct b53_device *dev) ++{ ++ struct device_node *dn, *pn; ++ u32 port_num; ++ ++ dn = of_get_child_by_name(dev_of_node(dev->dev), "ports"); ++ ++ for_each_available_child_of_node(dn, pn) { ++ struct device_node *fixed_link; ++ ++ if (of_property_read_u32(pn, "reg", &port_num)) ++ continue; ++ ++ if (port_num > B53_CPU_PORT) ++ continue; ++ ++ fixed_link = of_get_child_by_name(pn, "fixed-link"); ++ if (fixed_link) { ++ u32 spd; ++ u8 po = GMII_PO_LINK; ++ phy_interface_t mode; ++ ++ of_get_phy_mode(pn, &mode); ++ ++ if (!of_property_read_u32(fixed_link, "speed", &spd)) { ++ switch (spd) { ++ case 10: ++ po |= GMII_PO_SPEED_10M; ++ break; ++ case 100: ++ po |= GMII_PO_SPEED_100M; ++ break; ++ case 2000: ++ if (is_imp_port(dev, port_num)) ++ po |= PORT_OVERRIDE_SPEED_2000M; ++ else ++ po |= GMII_PO_SPEED_2000M; ++ fallthrough; ++ case 1000: ++ po |= GMII_PO_SPEED_1000M; ++ break; ++ } ++ } ++ ++ if (of_property_read_bool(fixed_link, "full-duplex")) ++ po |= PORT_OVERRIDE_FULL_DUPLEX; ++ if (of_property_read_bool(fixed_link, "pause")) ++ po |= GMII_PO_RX_FLOW; ++ if (of_property_read_bool(fixed_link, "asym-pause")) ++ po |= GMII_PO_TX_FLOW; ++ ++ if (is_imp_port(dev, port_num)) { ++ po |= PORT_OVERRIDE_EN; ++ ++ if (is5325(dev) && ++ mode == PHY_INTERFACE_MODE_REVMII) ++ po |= PORT_OVERRIDE_RV_MII_25; ++ ++ b53_write8(dev, B53_CTRL_PAGE, ++ B53_PORT_OVERRIDE_CTRL, po); ++ ++ if (is5325(dev) && ++ mode == PHY_INTERFACE_MODE_REVMII) { ++ b53_read8(dev, B53_CTRL_PAGE, ++ B53_PORT_OVERRIDE_CTRL, &po); ++ if (!(po & PORT_OVERRIDE_RV_MII_25)) ++ pr_err("Failed to enable reverse MII mode\n"); ++ return -EINVAL; ++ } ++ } else { ++ po |= GMII_PO_EN; ++ b53_write8(dev, B53_CTRL_PAGE, ++ B53_GMII_PORT_OVERRIDE_CTRL(port_num), ++ po); ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++static int b53_configure_ports(struct b53_device *dev) ++{ ++ u8 cpu_port = dev->sw_dev.cpu_port; ++ ++ /* configure MII port if necessary */ ++ if (is5325(dev)) { ++ u8 mii_port_override; ++ ++ b53_read8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL, ++ &mii_port_override); ++ /* reverse mii needs to be enabled */ ++ if (!(mii_port_override & PORT_OVERRIDE_RV_MII_25)) { ++ b53_write8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL, ++ mii_port_override | PORT_OVERRIDE_RV_MII_25); ++ b53_read8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL, ++ &mii_port_override); ++ ++ if (!(mii_port_override & PORT_OVERRIDE_RV_MII_25)) { ++ pr_err("Failed to enable reverse MII mode\n"); ++ return -EINVAL; ++ } ++ } ++ } else if (is531x5(dev) && cpu_port == B53_CPU_PORT) { ++ u8 mii_port_override; ++ ++ b53_read8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL, ++ &mii_port_override); ++ b53_write8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL, ++ mii_port_override | PORT_OVERRIDE_EN | ++ PORT_OVERRIDE_LINK); ++ ++ /* BCM47189 has another interface connected to the port 5 */ ++ if (dev->enabled_ports & BIT(5)) { ++ u8 po_reg = B53_GMII_PORT_OVERRIDE_CTRL(5); ++ u8 gmii_po; ++ ++ b53_read8(dev, B53_CTRL_PAGE, po_reg, &gmii_po); ++ gmii_po |= GMII_PO_LINK | ++ GMII_PO_RX_FLOW | ++ GMII_PO_TX_FLOW | ++ GMII_PO_EN; ++ b53_write8(dev, B53_CTRL_PAGE, po_reg, gmii_po); ++ } ++ } else if (is5301x(dev)) { ++ if (cpu_port == 8) { ++ u8 mii_port_override; ++ ++ b53_read8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL, ++ &mii_port_override); ++ mii_port_override |= PORT_OVERRIDE_LINK | ++ PORT_OVERRIDE_RX_FLOW | ++ PORT_OVERRIDE_TX_FLOW | ++ PORT_OVERRIDE_SPEED_2000M | ++ PORT_OVERRIDE_EN; ++ b53_write8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL, ++ mii_port_override); ++ ++ /* TODO: Ports 5 & 7 require some extra handling */ ++ } else { ++ u8 po_reg = B53_GMII_PORT_OVERRIDE_CTRL(cpu_port); ++ u8 gmii_po; ++ ++ b53_read8(dev, B53_CTRL_PAGE, po_reg, &gmii_po); ++ gmii_po |= GMII_PO_LINK | ++ GMII_PO_RX_FLOW | ++ GMII_PO_TX_FLOW | ++ GMII_PO_EN | ++ GMII_PO_SPEED_2000M; ++ b53_write8(dev, B53_CTRL_PAGE, po_reg, gmii_po); ++ } ++ } ++ ++ return 0; ++} ++ ++static int b53_switch_reset(struct b53_device *dev) ++{ ++ int ret = 0; ++ u8 mgmt; ++ ++ b53_switch_reset_gpio(dev); ++ ++ if (is539x(dev)) { ++ b53_write8(dev, B53_CTRL_PAGE, B53_SOFTRESET, 0x83); ++ b53_write8(dev, B53_CTRL_PAGE, B53_SOFTRESET, 0x00); ++ } ++ ++ b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt); ++ ++ if (!(mgmt & SM_SW_FWD_EN)) { ++ mgmt &= ~SM_SW_FWD_MODE; ++ mgmt |= SM_SW_FWD_EN; ++ ++ b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, mgmt); ++ b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt); ++ ++ if (!(mgmt & SM_SW_FWD_EN)) { ++ pr_err("Failed to enable switch!\n"); ++ return -EINVAL; ++ } ++ } ++ ++ /* enable all ports */ ++ b53_enable_ports(dev); ++ ++ if (dev->dev->of_node) ++ ret = b53_configure_ports_of(dev); ++ else ++ ret = b53_configure_ports(dev); ++ ++ if (ret) ++ return ret; ++ ++ b53_enable_mib(dev); ++ ++ return b53_flush_arl(dev); ++} ++ ++/* ++ * Swconfig glue functions ++ */ ++ ++static int b53_global_get_vlan_enable(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct b53_device *priv = sw_to_b53(dev); ++ ++ val->value.i = priv->enable_vlan; ++ ++ return 0; ++} ++ ++static int b53_global_set_vlan_enable(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct b53_device *priv = sw_to_b53(dev); ++ ++ priv->enable_vlan = val->value.i; ++ ++ return 0; ++} ++ ++static int b53_global_get_jumbo_enable(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct b53_device *priv = sw_to_b53(dev); ++ ++ val->value.i = priv->enable_jumbo; ++ ++ return 0; ++} ++ ++static int b53_global_set_jumbo_enable(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct b53_device *priv = sw_to_b53(dev); ++ ++ priv->enable_jumbo = val->value.i; ++ ++ return 0; ++} ++ ++static int b53_global_get_4095_enable(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct b53_device *priv = sw_to_b53(dev); ++ ++ val->value.i = priv->allow_vid_4095; ++ ++ return 0; ++} ++ ++static int b53_global_set_4095_enable(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct b53_device *priv = sw_to_b53(dev); ++ ++ priv->allow_vid_4095 = val->value.i; ++ ++ return 0; ++} ++ ++static int b53_global_get_ports(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct b53_device *priv = sw_to_b53(dev); ++ ++ val->len = snprintf(priv->buf, B53_BUF_SIZE, "0x%04x", ++ priv->enabled_ports); ++ val->value.s = priv->buf; ++ ++ return 0; ++} ++ ++static int b53_port_get_pvid(struct switch_dev *dev, int port, int *val) ++{ ++ struct b53_device *priv = sw_to_b53(dev); ++ ++ *val = priv->ports[port].pvid; ++ ++ return 0; ++} ++ ++static int b53_port_set_pvid(struct switch_dev *dev, int port, int val) ++{ ++ struct b53_device *priv = sw_to_b53(dev); ++ ++ if (val > 15 && is5325(priv)) ++ return -EINVAL; ++ if (val == 4095 && !priv->allow_vid_4095) ++ return -EINVAL; ++ ++ priv->ports[port].pvid = val; ++ ++ return 0; ++} ++ ++static int b53_vlan_get_ports(struct switch_dev *dev, struct switch_val *val) ++{ ++ struct b53_device *priv = sw_to_b53(dev); ++ struct switch_port *port = &val->value.ports[0]; ++ struct b53_vlan *vlan = &priv->vlans[val->port_vlan]; ++ int i; ++ ++ val->len = 0; ++ ++ if (!vlan->members) ++ return 0; ++ ++ for (i = 0; i < dev->ports; i++) { ++ if (!(vlan->members & BIT(i))) ++ continue; ++ ++ ++ if (!(vlan->untag & BIT(i))) ++ port->flags = BIT(SWITCH_PORT_FLAG_TAGGED); ++ else ++ port->flags = 0; ++ ++ port->id = i; ++ val->len++; ++ port++; ++ } ++ ++ return 0; ++} ++ ++static int b53_vlan_set_ports(struct switch_dev *dev, struct switch_val *val) ++{ ++ struct b53_device *priv = sw_to_b53(dev); ++ struct switch_port *port; ++ struct b53_vlan *vlan = &priv->vlans[val->port_vlan]; ++ int i; ++ ++ /* only BCM5325 and BCM5365 supports VID 0 */ ++ if (val->port_vlan == 0 && !is5325(priv) && !is5365(priv)) ++ return -EINVAL; ++ ++ /* VLAN 4095 needs special handling */ ++ if (val->port_vlan == 4095 && !priv->allow_vid_4095) ++ return -EINVAL; ++ ++ port = &val->value.ports[0]; ++ vlan->members = 0; ++ vlan->untag = 0; ++ for (i = 0; i < val->len; i++, port++) { ++ vlan->members |= BIT(port->id); ++ ++ if (!(port->flags & BIT(SWITCH_PORT_FLAG_TAGGED))) { ++ vlan->untag |= BIT(port->id); ++ priv->ports[port->id].pvid = val->port_vlan; ++ }; ++ } ++ ++ /* ignore disabled ports */ ++ vlan->members &= priv->enabled_ports; ++ vlan->untag &= priv->enabled_ports; ++ ++ return 0; ++} ++ ++static int b53_port_get_link(struct switch_dev *dev, int port, ++ struct switch_port_link *link) ++{ ++ struct b53_device *priv = sw_to_b53(dev); ++ ++ if (is_cpu_port(priv, port)) { ++ link->link = 1; ++ link->duplex = 1; ++ link->speed = is5325(priv) || is5365(priv) ? ++ SWITCH_PORT_SPEED_100 : SWITCH_PORT_SPEED_1000; ++ link->aneg = 0; ++ } else if (priv->enabled_ports & BIT(port)) { ++ u32 speed; ++ u16 lnk, duplex; ++ ++ b53_read16(priv, B53_STAT_PAGE, B53_LINK_STAT, &lnk); ++ b53_read16(priv, B53_STAT_PAGE, priv->duplex_reg, &duplex); ++ ++ lnk = (lnk >> port) & 1; ++ duplex = (duplex >> port) & 1; ++ ++ if (is5325(priv) || is5365(priv)) { ++ u16 tmp; ++ ++ b53_read16(priv, B53_STAT_PAGE, B53_SPEED_STAT, &tmp); ++ speed = SPEED_PORT_FE(tmp, port); ++ } else { ++ b53_read32(priv, B53_STAT_PAGE, B53_SPEED_STAT, &speed); ++ speed = SPEED_PORT_GE(speed, port); ++ } ++ ++ link->link = lnk; ++ if (lnk) { ++ link->duplex = duplex; ++ switch (speed) { ++ case SPEED_STAT_10M: ++ link->speed = SWITCH_PORT_SPEED_10; ++ break; ++ case SPEED_STAT_100M: ++ link->speed = SWITCH_PORT_SPEED_100; ++ break; ++ case SPEED_STAT_1000M: ++ link->speed = SWITCH_PORT_SPEED_1000; ++ break; ++ } ++ } ++ ++ link->aneg = 1; ++ } else { ++ link->link = 0; ++ } ++ ++ return 0; ++ ++} ++ ++static int b53_port_set_link(struct switch_dev *sw_dev, int port, ++ struct switch_port_link *link) ++{ ++ struct b53_device *dev = sw_to_b53(sw_dev); ++ ++ /* ++ * TODO: BCM63XX requires special handling as it can have external phys ++ * and ports might be GE or only FE ++ */ ++ if (is63xx(dev)) ++ return -ENOTSUPP; ++ ++ if (port == sw_dev->cpu_port) ++ return -EINVAL; ++ ++ if (!(BIT(port) & dev->enabled_ports)) ++ return -EINVAL; ++ ++ if (link->speed == SWITCH_PORT_SPEED_1000 && ++ (is5325(dev) || is5365(dev))) ++ return -EINVAL; ++ ++ if (link->speed == SWITCH_PORT_SPEED_1000 && !link->duplex) ++ return -EINVAL; ++ ++ return switch_generic_set_link(sw_dev, port, link); ++} ++ ++static int b53_phy_read16(struct switch_dev *dev, int addr, u8 reg, u16 *value) ++{ ++ struct b53_device *priv = sw_to_b53(dev); ++ ++ if (priv->ops->phy_read16) ++ return priv->ops->phy_read16(priv, addr, reg, value); ++ ++ return b53_read16(priv, B53_PORT_MII_PAGE(addr), reg, value); ++} ++ ++static int b53_phy_write16(struct switch_dev *dev, int addr, u8 reg, u16 value) ++{ ++ struct b53_device *priv = sw_to_b53(dev); ++ ++ if (priv->ops->phy_write16) ++ return priv->ops->phy_write16(priv, addr, reg, value); ++ ++ return b53_write16(priv, B53_PORT_MII_PAGE(addr), reg, value); ++} ++ ++static int b53_global_reset_switch(struct switch_dev *dev) ++{ ++ struct b53_device *priv = sw_to_b53(dev); ++ ++ /* reset vlans */ ++ priv->enable_vlan = 0; ++ priv->enable_jumbo = 0; ++ priv->allow_vid_4095 = 0; ++ ++ memset(priv->vlans, 0, sizeof(*priv->vlans) * dev->vlans); ++ memset(priv->ports, 0, sizeof(*priv->ports) * dev->ports); ++ ++ return b53_switch_reset(priv); ++} ++ ++static int b53_global_apply_config(struct switch_dev *dev) ++{ ++ struct b53_device *priv = sw_to_b53(dev); ++ ++ /* disable switching */ ++ b53_set_forwarding(priv, 0); ++ ++ b53_apply(priv); ++ ++ /* enable switching */ ++ b53_set_forwarding(priv, 1); ++ ++ return 0; ++} ++ ++ ++static int b53_global_reset_mib(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct b53_device *priv = sw_to_b53(dev); ++ u8 gc; ++ ++ b53_read8(priv, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, &gc); ++ ++ b53_write8(priv, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, gc | GC_RESET_MIB); ++ mdelay(1); ++ b53_write8(priv, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, gc & ~GC_RESET_MIB); ++ mdelay(1); ++ ++ return 0; ++} ++ ++static int b53_port_get_mib(struct switch_dev *sw_dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct b53_device *dev = sw_to_b53(sw_dev); ++ const struct b53_mib_desc *mibs; ++ int port = val->port_vlan; ++ int len = 0; ++ ++ if (!(BIT(port) & dev->enabled_ports)) ++ return -1; ++ ++ if (is5365(dev)) { ++ if (port == 5) ++ port = 8; ++ ++ mibs = b53_mibs_65; ++ } else if (is63xx(dev)) { ++ mibs = b53_mibs_63xx; ++ } else { ++ mibs = b53_mibs; ++ } ++ ++ dev->buf[0] = 0; ++ ++ for (; mibs->size > 0; mibs++) { ++ u64 val; ++ ++ if (mibs->size == 8) { ++ b53_read64(dev, B53_MIB_PAGE(port), mibs->offset, &val); ++ } else { ++ u32 val32; ++ ++ b53_read32(dev, B53_MIB_PAGE(port), mibs->offset, ++ &val32); ++ val = val32; ++ } ++ ++ len += snprintf(dev->buf + len, B53_BUF_SIZE - len, ++ "%-20s: %llu\n", mibs->name, val); ++ } ++ ++ val->len = len; ++ val->value.s = dev->buf; ++ ++ return 0; ++} ++ ++static int b53_port_get_stats(struct switch_dev *sw_dev, int port, ++ struct switch_port_stats *stats) ++{ ++ struct b53_device *dev = sw_to_b53(sw_dev); ++ const struct b53_mib_desc *mibs; ++ int txb_id, rxb_id; ++ u64 rxb, txb; ++ ++ if (!(BIT(port) & dev->enabled_ports)) ++ return -EINVAL; ++ ++ txb_id = B53XX_MIB_TXB_ID; ++ rxb_id = B53XX_MIB_RXB_ID; ++ ++ if (is5365(dev)) { ++ if (port == 5) ++ port = 8; ++ ++ mibs = b53_mibs_65; ++ } else if (is63xx(dev)) { ++ mibs = b53_mibs_63xx; ++ txb_id = B63XX_MIB_TXB_ID; ++ rxb_id = B63XX_MIB_RXB_ID; ++ } else { ++ mibs = b53_mibs; ++ } ++ ++ dev->buf[0] = 0; ++ ++ if (mibs->size == 8) { ++ b53_read64(dev, B53_MIB_PAGE(port), mibs[txb_id].offset, &txb); ++ b53_read64(dev, B53_MIB_PAGE(port), mibs[rxb_id].offset, &rxb); ++ } else { ++ u32 val32; ++ ++ b53_read32(dev, B53_MIB_PAGE(port), mibs[txb_id].offset, &val32); ++ txb = val32; ++ ++ b53_read32(dev, B53_MIB_PAGE(port), mibs[rxb_id].offset, &val32); ++ rxb = val32; ++ } ++ ++ stats->tx_bytes = txb; ++ stats->rx_bytes = rxb; ++ ++ return 0; ++} ++ ++static struct switch_attr b53_global_ops_25[] = { ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "enable_vlan", ++ .description = "Enable VLAN mode", ++ .set = b53_global_set_vlan_enable, ++ .get = b53_global_get_vlan_enable, ++ .max = 1, ++ }, ++ { ++ .type = SWITCH_TYPE_STRING, ++ .name = "ports", ++ .description = "Available ports (as bitmask)", ++ .get = b53_global_get_ports, ++ }, ++}; ++ ++static struct switch_attr b53_global_ops_65[] = { ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "enable_vlan", ++ .description = "Enable VLAN mode", ++ .set = b53_global_set_vlan_enable, ++ .get = b53_global_get_vlan_enable, ++ .max = 1, ++ }, ++ { ++ .type = SWITCH_TYPE_STRING, ++ .name = "ports", ++ .description = "Available ports (as bitmask)", ++ .get = b53_global_get_ports, ++ }, ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "reset_mib", ++ .description = "Reset MIB counters", ++ .set = b53_global_reset_mib, ++ }, ++}; ++ ++static struct switch_attr b53_global_ops[] = { ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "enable_vlan", ++ .description = "Enable VLAN mode", ++ .set = b53_global_set_vlan_enable, ++ .get = b53_global_get_vlan_enable, ++ .max = 1, ++ }, ++ { ++ .type = SWITCH_TYPE_STRING, ++ .name = "ports", ++ .description = "Available Ports (as bitmask)", ++ .get = b53_global_get_ports, ++ }, ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "reset_mib", ++ .description = "Reset MIB counters", ++ .set = b53_global_reset_mib, ++ }, ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "enable_jumbo", ++ .description = "Enable Jumbo Frames", ++ .set = b53_global_set_jumbo_enable, ++ .get = b53_global_get_jumbo_enable, ++ .max = 1, ++ }, ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "allow_vid_4095", ++ .description = "Allow VID 4095", ++ .set = b53_global_set_4095_enable, ++ .get = b53_global_get_4095_enable, ++ .max = 1, ++ }, ++}; ++ ++static struct switch_attr b53_port_ops[] = { ++ { ++ .type = SWITCH_TYPE_STRING, ++ .name = "mib", ++ .description = "Get port's MIB counters", ++ .get = b53_port_get_mib, ++ }, ++}; ++ ++static struct switch_attr b53_no_ops[] = { ++}; ++ ++static const struct switch_dev_ops b53_switch_ops_25 = { ++ .attr_global = { ++ .attr = b53_global_ops_25, ++ .n_attr = ARRAY_SIZE(b53_global_ops_25), ++ }, ++ .attr_port = { ++ .attr = b53_no_ops, ++ .n_attr = ARRAY_SIZE(b53_no_ops), ++ }, ++ .attr_vlan = { ++ .attr = b53_no_ops, ++ .n_attr = ARRAY_SIZE(b53_no_ops), ++ }, ++ ++ .get_vlan_ports = b53_vlan_get_ports, ++ .set_vlan_ports = b53_vlan_set_ports, ++ .get_port_pvid = b53_port_get_pvid, ++ .set_port_pvid = b53_port_set_pvid, ++ .apply_config = b53_global_apply_config, ++ .reset_switch = b53_global_reset_switch, ++ .get_port_link = b53_port_get_link, ++ .set_port_link = b53_port_set_link, ++ .get_port_stats = b53_port_get_stats, ++ .phy_read16 = b53_phy_read16, ++ .phy_write16 = b53_phy_write16, ++}; ++ ++static const struct switch_dev_ops b53_switch_ops_65 = { ++ .attr_global = { ++ .attr = b53_global_ops_65, ++ .n_attr = ARRAY_SIZE(b53_global_ops_65), ++ }, ++ .attr_port = { ++ .attr = b53_port_ops, ++ .n_attr = ARRAY_SIZE(b53_port_ops), ++ }, ++ .attr_vlan = { ++ .attr = b53_no_ops, ++ .n_attr = ARRAY_SIZE(b53_no_ops), ++ }, ++ ++ .get_vlan_ports = b53_vlan_get_ports, ++ .set_vlan_ports = b53_vlan_set_ports, ++ .get_port_pvid = b53_port_get_pvid, ++ .set_port_pvid = b53_port_set_pvid, ++ .apply_config = b53_global_apply_config, ++ .reset_switch = b53_global_reset_switch, ++ .get_port_link = b53_port_get_link, ++ .set_port_link = b53_port_set_link, ++ .get_port_stats = b53_port_get_stats, ++ .phy_read16 = b53_phy_read16, ++ .phy_write16 = b53_phy_write16, ++}; ++ ++static const struct switch_dev_ops b53_switch_ops = { ++ .attr_global = { ++ .attr = b53_global_ops, ++ .n_attr = ARRAY_SIZE(b53_global_ops), ++ }, ++ .attr_port = { ++ .attr = b53_port_ops, ++ .n_attr = ARRAY_SIZE(b53_port_ops), ++ }, ++ .attr_vlan = { ++ .attr = b53_no_ops, ++ .n_attr = ARRAY_SIZE(b53_no_ops), ++ }, ++ ++ .get_vlan_ports = b53_vlan_get_ports, ++ .set_vlan_ports = b53_vlan_set_ports, ++ .get_port_pvid = b53_port_get_pvid, ++ .set_port_pvid = b53_port_set_pvid, ++ .apply_config = b53_global_apply_config, ++ .reset_switch = b53_global_reset_switch, ++ .get_port_link = b53_port_get_link, ++ .set_port_link = b53_port_set_link, ++ .get_port_stats = b53_port_get_stats, ++ .phy_read16 = b53_phy_read16, ++ .phy_write16 = b53_phy_write16, ++}; ++ ++struct b53_chip_data { ++ u32 chip_id; ++ const char *dev_name; ++ const char *alias; ++ u16 vlans; ++ u16 enabled_ports; ++ u8 cpu_port; ++ u8 vta_regs[3]; ++ u8 duplex_reg; ++ u8 jumbo_pm_reg; ++ u8 jumbo_size_reg; ++ const struct switch_dev_ops *sw_ops; ++}; ++ ++#define B53_VTA_REGS \ ++ { B53_VT_ACCESS, B53_VT_INDEX, B53_VT_ENTRY } ++#define B53_VTA_REGS_9798 \ ++ { B53_VT_ACCESS_9798, B53_VT_INDEX_9798, B53_VT_ENTRY_9798 } ++#define B53_VTA_REGS_63XX \ ++ { B53_VT_ACCESS_63XX, B53_VT_INDEX_63XX, B53_VT_ENTRY_63XX } ++ ++static const struct b53_chip_data b53_switch_chips[] = { ++ { ++ .chip_id = BCM5325_DEVICE_ID, ++ .dev_name = "BCM5325", ++ .alias = "bcm5325", ++ .vlans = 16, ++ .enabled_ports = 0x1f, ++ .cpu_port = B53_CPU_PORT_25, ++ .duplex_reg = B53_DUPLEX_STAT_FE, ++ .sw_ops = &b53_switch_ops_25, ++ }, ++ { ++ .chip_id = BCM5365_DEVICE_ID, ++ .dev_name = "BCM5365", ++ .alias = "bcm5365", ++ .vlans = 256, ++ .enabled_ports = 0x1f, ++ .cpu_port = B53_CPU_PORT_25, ++ .duplex_reg = B53_DUPLEX_STAT_FE, ++ .sw_ops = &b53_switch_ops_65, ++ }, ++ { ++ .chip_id = BCM5395_DEVICE_ID, ++ .dev_name = "BCM5395", ++ .alias = "bcm5395", ++ .vlans = 4096, ++ .enabled_ports = 0x1f, ++ .cpu_port = B53_CPU_PORT, ++ .vta_regs = B53_VTA_REGS, ++ .duplex_reg = B53_DUPLEX_STAT_GE, ++ .jumbo_pm_reg = B53_JUMBO_PORT_MASK, ++ .jumbo_size_reg = B53_JUMBO_MAX_SIZE, ++ .sw_ops = &b53_switch_ops, ++ }, ++ { ++ .chip_id = BCM5397_DEVICE_ID, ++ .dev_name = "BCM5397", ++ .alias = "bcm5397", ++ .vlans = 4096, ++ .enabled_ports = 0x1f, ++ .cpu_port = B53_CPU_PORT, ++ .vta_regs = B53_VTA_REGS_9798, ++ .duplex_reg = B53_DUPLEX_STAT_GE, ++ .jumbo_pm_reg = B53_JUMBO_PORT_MASK, ++ .jumbo_size_reg = B53_JUMBO_MAX_SIZE, ++ .sw_ops = &b53_switch_ops, ++ }, ++ { ++ .chip_id = BCM5398_DEVICE_ID, ++ .dev_name = "BCM5398", ++ .alias = "bcm5398", ++ .vlans = 4096, ++ .enabled_ports = 0x7f, ++ .cpu_port = B53_CPU_PORT, ++ .vta_regs = B53_VTA_REGS_9798, ++ .duplex_reg = B53_DUPLEX_STAT_GE, ++ .jumbo_pm_reg = B53_JUMBO_PORT_MASK, ++ .jumbo_size_reg = B53_JUMBO_MAX_SIZE, ++ .sw_ops = &b53_switch_ops, ++ }, ++ { ++ .chip_id = BCM53115_DEVICE_ID, ++ .dev_name = "BCM53115", ++ .alias = "bcm53115", ++ .vlans = 4096, ++ .enabled_ports = 0x1f, ++ .vta_regs = B53_VTA_REGS, ++ .cpu_port = B53_CPU_PORT, ++ .duplex_reg = B53_DUPLEX_STAT_GE, ++ .jumbo_pm_reg = B53_JUMBO_PORT_MASK, ++ .jumbo_size_reg = B53_JUMBO_MAX_SIZE, ++ .sw_ops = &b53_switch_ops, ++ }, ++ { ++ .chip_id = BCM53125_DEVICE_ID, ++ .dev_name = "BCM53125", ++ .alias = "bcm53125", ++ .vlans = 4096, ++ .enabled_ports = 0x1f, ++ .cpu_port = B53_CPU_PORT, ++ .vta_regs = B53_VTA_REGS, ++ .duplex_reg = B53_DUPLEX_STAT_GE, ++ .jumbo_pm_reg = B53_JUMBO_PORT_MASK, ++ .jumbo_size_reg = B53_JUMBO_MAX_SIZE, ++ .sw_ops = &b53_switch_ops, ++ }, ++ { ++ .chip_id = BCM53128_DEVICE_ID, ++ .dev_name = "BCM53128", ++ .alias = "bcm53128", ++ .vlans = 4096, ++ .enabled_ports = 0x1ff, ++ .cpu_port = B53_CPU_PORT, ++ .vta_regs = B53_VTA_REGS, ++ .duplex_reg = B53_DUPLEX_STAT_GE, ++ .jumbo_pm_reg = B53_JUMBO_PORT_MASK, ++ .jumbo_size_reg = B53_JUMBO_MAX_SIZE, ++ .sw_ops = &b53_switch_ops, ++ }, ++ { ++ .chip_id = BCM63XX_DEVICE_ID, ++ .dev_name = "BCM63xx", ++ .alias = "bcm63xx", ++ .vlans = 4096, ++ .enabled_ports = 0, /* pdata must provide them */ ++ .cpu_port = B53_CPU_PORT, ++ .vta_regs = B53_VTA_REGS_63XX, ++ .duplex_reg = B53_DUPLEX_STAT_63XX, ++ .jumbo_pm_reg = B53_JUMBO_PORT_MASK_63XX, ++ .jumbo_size_reg = B53_JUMBO_MAX_SIZE_63XX, ++ .sw_ops = &b53_switch_ops, ++ }, ++ { ++ .chip_id = BCM53010_DEVICE_ID, ++ .dev_name = "BCM53010", ++ .alias = "bcm53011", ++ .vlans = 4096, ++ .enabled_ports = 0x1f, ++ .cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */ ++ .vta_regs = B53_VTA_REGS, ++ .duplex_reg = B53_DUPLEX_STAT_GE, ++ .jumbo_pm_reg = B53_JUMBO_PORT_MASK, ++ .jumbo_size_reg = B53_JUMBO_MAX_SIZE, ++ .sw_ops = &b53_switch_ops, ++ }, ++ { ++ .chip_id = BCM53011_DEVICE_ID, ++ .dev_name = "BCM53011", ++ .alias = "bcm53011", ++ .vlans = 4096, ++ .enabled_ports = 0x1bf, ++ .cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */ ++ .vta_regs = B53_VTA_REGS, ++ .duplex_reg = B53_DUPLEX_STAT_GE, ++ .jumbo_pm_reg = B53_JUMBO_PORT_MASK, ++ .jumbo_size_reg = B53_JUMBO_MAX_SIZE, ++ .sw_ops = &b53_switch_ops, ++ }, ++ { ++ .chip_id = BCM53012_DEVICE_ID, ++ .dev_name = "BCM53012", ++ .alias = "bcm53011", ++ .vlans = 4096, ++ .enabled_ports = 0x1bf, ++ .cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */ ++ .vta_regs = B53_VTA_REGS, ++ .duplex_reg = B53_DUPLEX_STAT_GE, ++ .jumbo_pm_reg = B53_JUMBO_PORT_MASK, ++ .jumbo_size_reg = B53_JUMBO_MAX_SIZE, ++ .sw_ops = &b53_switch_ops, ++ }, ++ { ++ .chip_id = BCM53018_DEVICE_ID, ++ .dev_name = "BCM53018", ++ .alias = "bcm53018", ++ .vlans = 4096, ++ .enabled_ports = 0x1f, ++ .cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */ ++ .vta_regs = B53_VTA_REGS, ++ .duplex_reg = B53_DUPLEX_STAT_GE, ++ .jumbo_pm_reg = B53_JUMBO_PORT_MASK, ++ .jumbo_size_reg = B53_JUMBO_MAX_SIZE, ++ .sw_ops = &b53_switch_ops, ++ }, ++ { ++ .chip_id = BCM53019_DEVICE_ID, ++ .dev_name = "BCM53019", ++ .alias = "bcm53019", ++ .vlans = 4096, ++ .enabled_ports = 0x1f, ++ .cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */ ++ .vta_regs = B53_VTA_REGS, ++ .duplex_reg = B53_DUPLEX_STAT_GE, ++ .jumbo_pm_reg = B53_JUMBO_PORT_MASK, ++ .jumbo_size_reg = B53_JUMBO_MAX_SIZE, ++ .sw_ops = &b53_switch_ops, ++ }, ++}; ++ ++static int b53_switch_init_of(struct b53_device *dev) ++{ ++ struct device_node *dn, *pn; ++ const char *alias; ++ u32 port_num; ++ u16 ports = 0; ++ ++ dn = of_get_child_by_name(dev_of_node(dev->dev), "ports"); ++ if (!dn) ++ return -EINVAL; ++ ++ for_each_available_child_of_node(dn, pn) { ++ const char *label; ++ int len; ++ ++ if (of_property_read_u32(pn, "reg", &port_num)) ++ continue; ++ ++ if (port_num > B53_CPU_PORT) ++ continue; ++ ++ ports |= BIT(port_num); ++ ++ label = of_get_property(pn, "label", &len); ++ if (label && !strcmp(label, "cpu")) ++ dev->sw_dev.cpu_port = port_num; ++ } ++ ++ dev->enabled_ports = ports; ++ ++ if (!of_property_read_string(dev_of_node(dev->dev), "lede,alias", ++ &alias)) ++ dev->sw_dev.alias = devm_kstrdup(dev->dev, alias, GFP_KERNEL); ++ ++ return 0; ++} ++ ++static int b53_switch_init(struct b53_device *dev) ++{ ++ struct switch_dev *sw_dev = &dev->sw_dev; ++ unsigned i; ++ int ret; ++ ++ for (i = 0; i < ARRAY_SIZE(b53_switch_chips); i++) { ++ const struct b53_chip_data *chip = &b53_switch_chips[i]; ++ ++ if (chip->chip_id == dev->chip_id) { ++ sw_dev->name = chip->dev_name; ++ if (!sw_dev->alias) ++ sw_dev->alias = chip->alias; ++ if (!dev->enabled_ports) ++ dev->enabled_ports = chip->enabled_ports; ++ dev->duplex_reg = chip->duplex_reg; ++ dev->vta_regs[0] = chip->vta_regs[0]; ++ dev->vta_regs[1] = chip->vta_regs[1]; ++ dev->vta_regs[2] = chip->vta_regs[2]; ++ dev->jumbo_pm_reg = chip->jumbo_pm_reg; ++ sw_dev->ops = chip->sw_ops; ++ sw_dev->cpu_port = chip->cpu_port; ++ sw_dev->vlans = chip->vlans; ++ break; ++ } ++ } ++ ++ if (!sw_dev->name) ++ return -EINVAL; ++ ++ /* check which BCM5325x version we have */ ++ if (is5325(dev)) { ++ u8 vc4; ++ ++ b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_25, &vc4); ++ ++ /* check reserved bits */ ++ switch (vc4 & 3) { ++ case 1: ++ /* BCM5325E */ ++ break; ++ case 3: ++ /* BCM5325F - do not use port 4 */ ++ dev->enabled_ports &= ~BIT(4); ++ break; ++ default: ++/* On the BCM47XX SoCs this is the supported internal switch.*/ ++#ifndef CONFIG_BCM47XX ++ /* BCM5325M */ ++ return -EINVAL; ++#else ++ break; ++#endif ++ } ++ } else if (dev->chip_id == BCM53115_DEVICE_ID) { ++ u64 strap_value; ++ ++ b53_read48(dev, B53_STAT_PAGE, B53_STRAP_VALUE, &strap_value); ++ /* use second IMP port if GMII is enabled */ ++ if (strap_value & SV_GMII_CTRL_115) ++ sw_dev->cpu_port = 5; ++ } ++ ++ if (dev_of_node(dev->dev)) { ++ ret = b53_switch_init_of(dev); ++ if (ret) ++ return ret; ++ } ++ ++ dev->enabled_ports |= BIT(sw_dev->cpu_port); ++ sw_dev->ports = fls(dev->enabled_ports); ++ ++ dev->ports = devm_kzalloc(dev->dev, ++ sizeof(struct b53_port) * sw_dev->ports, ++ GFP_KERNEL); ++ if (!dev->ports) ++ return -ENOMEM; ++ ++ dev->vlans = devm_kzalloc(dev->dev, ++ sizeof(struct b53_vlan) * sw_dev->vlans, ++ GFP_KERNEL); ++ if (!dev->vlans) ++ return -ENOMEM; ++ ++ dev->buf = devm_kzalloc(dev->dev, B53_BUF_SIZE, GFP_KERNEL); ++ if (!dev->buf) ++ return -ENOMEM; ++ ++ dev->reset_gpio = b53_switch_get_reset_gpio(dev); ++ if (dev->reset_gpio >= 0) { ++ ret = devm_gpio_request_one(dev->dev, dev->reset_gpio, ++ GPIOF_OUT_INIT_HIGH, "robo_reset"); ++ if (ret) ++ return ret; ++ } ++ ++ return b53_switch_reset(dev); ++} ++ ++struct b53_device *b53_swconfig_switch_alloc(struct device *base, struct b53_io_ops *ops, ++ void *priv) ++{ ++ struct b53_device *dev; ++ ++ dev = devm_kzalloc(base, sizeof(*dev), GFP_KERNEL); ++ if (!dev) ++ return NULL; ++ ++ dev->dev = base; ++ dev->ops = ops; ++ dev->priv = priv; ++ mutex_init(&dev->reg_mutex); ++ ++ return dev; ++} ++EXPORT_SYMBOL(b53_swconfig_switch_alloc); ++ ++int b53_swconfig_switch_detect(struct b53_device *dev) ++{ ++ u32 id32; ++ u16 tmp; ++ u8 id8; ++ int ret; ++ ++ ret = b53_read8(dev, B53_MGMT_PAGE, B53_DEVICE_ID, &id8); ++ if (ret) ++ return ret; ++ ++ switch (id8) { ++ case 0: ++ /* ++ * BCM5325 and BCM5365 do not have this register so reads ++ * return 0. But the read operation did succeed, so assume ++ * this is one of them. ++ * ++ * Next check if we can write to the 5325's VTA register; for ++ * 5365 it is read only. ++ */ ++ ++ b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_TABLE_ACCESS_25, 0xf); ++ b53_read16(dev, B53_VLAN_PAGE, B53_VLAN_TABLE_ACCESS_25, &tmp); ++ ++ if (tmp == 0xf) ++ dev->chip_id = BCM5325_DEVICE_ID; ++ else ++ dev->chip_id = BCM5365_DEVICE_ID; ++ break; ++ case BCM5395_DEVICE_ID: ++ case BCM5397_DEVICE_ID: ++ case BCM5398_DEVICE_ID: ++ dev->chip_id = id8; ++ break; ++ default: ++ ret = b53_read32(dev, B53_MGMT_PAGE, B53_DEVICE_ID, &id32); ++ if (ret) ++ return ret; ++ ++ switch (id32) { ++ case BCM53115_DEVICE_ID: ++ case BCM53125_DEVICE_ID: ++ case BCM53128_DEVICE_ID: ++ case BCM53010_DEVICE_ID: ++ case BCM53011_DEVICE_ID: ++ case BCM53012_DEVICE_ID: ++ case BCM53018_DEVICE_ID: ++ case BCM53019_DEVICE_ID: ++ dev->chip_id = id32; ++ break; ++ default: ++ pr_err("unsupported switch detected (BCM53%02x/BCM%x)\n", ++ id8, id32); ++ return -ENODEV; ++ } ++ } ++ ++ if (dev->chip_id == BCM5325_DEVICE_ID) ++ return b53_read8(dev, B53_STAT_PAGE, B53_REV_ID_25, ++ &dev->core_rev); ++ else ++ return b53_read8(dev, B53_MGMT_PAGE, B53_REV_ID, ++ &dev->core_rev); ++} ++EXPORT_SYMBOL(b53_swconfig_switch_detect); ++ ++int b53_swconfig_switch_register(struct b53_device *dev) ++{ ++ int ret; ++ ++ if (dev->pdata) { ++ dev->chip_id = dev->pdata->chip_id; ++ dev->enabled_ports = dev->pdata->enabled_ports; ++ dev->sw_dev.alias = dev->pdata->alias; ++ } ++ ++ if (!dev->chip_id && b53_swconfig_switch_detect(dev)) ++ return -EINVAL; ++ ++ ret = b53_switch_init(dev); ++ if (ret) ++ return ret; ++ ++ pr_info("found switch: %s, rev %i\n", dev->sw_dev.name, dev->core_rev); ++ ++ return register_switch(&dev->sw_dev, NULL); ++} ++EXPORT_SYMBOL(b53_swconfig_switch_register); ++ ++MODULE_AUTHOR("Jonas Gorski "); ++MODULE_DESCRIPTION("B53 switch library"); ++MODULE_LICENSE("Dual BSD/GPL"); +diff --git a/drivers/net/phy/b53/b53_mdio.c b/drivers/net/phy/b53/b53_mdio.c +new file mode 100644 +index 000000000000..c85df1f30558 +--- /dev/null ++++ b/drivers/net/phy/b53/b53_mdio.c +@@ -0,0 +1,436 @@ ++/* ++ * B53 register access through MII registers ++ * ++ * Copyright (C) 2011-2013 Jonas Gorski ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#include ++#include ++#include ++ ++#include "b53_priv.h" ++ ++#define B53_PSEUDO_PHY 0x1e /* Register Access Pseudo PHY */ ++ ++/* MII registers */ ++#define REG_MII_PAGE 0x10 /* MII Page register */ ++#define REG_MII_ADDR 0x11 /* MII Address register */ ++#define REG_MII_DATA0 0x18 /* MII Data register 0 */ ++#define REG_MII_DATA1 0x19 /* MII Data register 1 */ ++#define REG_MII_DATA2 0x1a /* MII Data register 2 */ ++#define REG_MII_DATA3 0x1b /* MII Data register 3 */ ++ ++#define REG_MII_PAGE_ENABLE BIT(0) ++#define REG_MII_ADDR_WRITE BIT(0) ++#define REG_MII_ADDR_READ BIT(1) ++ ++static int b53_mdio_op(struct b53_device *dev, u8 page, u8 reg, u16 op) ++{ ++ int i; ++ u16 v; ++ int ret; ++ struct mii_bus *bus = dev->priv; ++ ++ if (dev->current_page != page) { ++ /* set page number */ ++ v = (page << 8) | REG_MII_PAGE_ENABLE; ++ ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_PAGE, v); ++ if (ret) ++ return ret; ++ dev->current_page = page; ++ } ++ ++ /* set register address */ ++ v = (reg << 8) | op; ++ ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_ADDR, v); ++ if (ret) ++ return ret; ++ ++ /* check if operation completed */ ++ for (i = 0; i < 5; ++i) { ++ v = mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_ADDR); ++ if (!(v & (REG_MII_ADDR_WRITE | REG_MII_ADDR_READ))) ++ break; ++ usleep_range(10, 100); ++ } ++ ++ if (WARN_ON(i == 5)) ++ return -EIO; ++ ++ return 0; ++} ++ ++static int b53_mdio_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val) ++{ ++ struct mii_bus *bus = dev->priv; ++ int ret; ++ ++ ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ); ++ if (ret) ++ return ret; ++ ++ *val = mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA0) & 0xff; ++ ++ return 0; ++} ++ ++static int b53_mdio_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val) ++{ ++ struct mii_bus *bus = dev->priv; ++ int ret; ++ ++ ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ); ++ if (ret) ++ return ret; ++ ++ *val = mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA0); ++ ++ return 0; ++} ++ ++static int b53_mdio_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val) ++{ ++ struct mii_bus *bus = dev->priv; ++ int ret; ++ ++ ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ); ++ if (ret) ++ return ret; ++ ++ *val = mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA0); ++ *val |= mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA1) << 16; ++ ++ return 0; ++} ++ ++static int b53_mdio_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val) ++{ ++ struct mii_bus *bus = dev->priv; ++ u64 temp = 0; ++ int i; ++ int ret; ++ ++ ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ); ++ if (ret) ++ return ret; ++ ++ for (i = 2; i >= 0; i--) { ++ temp <<= 16; ++ temp |= mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA0 + i); ++ } ++ ++ *val = temp; ++ ++ return 0; ++} ++ ++static int b53_mdio_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val) ++{ ++ struct mii_bus *bus = dev->priv; ++ u64 temp = 0; ++ int i; ++ int ret; ++ ++ ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ); ++ if (ret) ++ return ret; ++ ++ for (i = 3; i >= 0; i--) { ++ temp <<= 16; ++ temp |= mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA0 + i); ++ } ++ ++ *val = temp; ++ ++ return 0; ++} ++ ++static int b53_mdio_write8(struct b53_device *dev, u8 page, u8 reg, u8 value) ++{ ++ struct mii_bus *bus = dev->priv; ++ int ret; ++ ++ ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_DATA0, value); ++ if (ret) ++ return ret; ++ ++ return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE); ++} ++ ++static int b53_mdio_write16(struct b53_device *dev, u8 page, u8 reg, ++ u16 value) ++{ ++ struct mii_bus *bus = dev->priv; ++ int ret; ++ ++ ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_DATA0, value); ++ if (ret) ++ return ret; ++ ++ return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE); ++} ++ ++static int b53_mdio_write32(struct b53_device *dev, u8 page, u8 reg, ++ u32 value) ++{ ++ struct mii_bus *bus = dev->priv; ++ unsigned int i; ++ u32 temp = value; ++ ++ for (i = 0; i < 2; i++) { ++ int ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_DATA0 + i, ++ temp & 0xffff); ++ if (ret) ++ return ret; ++ temp >>= 16; ++ } ++ ++ return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE); ++ ++} ++ ++static int b53_mdio_write48(struct b53_device *dev, u8 page, u8 reg, ++ u64 value) ++{ ++ struct mii_bus *bus = dev->priv; ++ unsigned i; ++ u64 temp = value; ++ ++ for (i = 0; i < 3; i++) { ++ int ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_DATA0 + i, ++ temp & 0xffff); ++ if (ret) ++ return ret; ++ temp >>= 16; ++ } ++ ++ return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE); ++ ++} ++ ++static int b53_mdio_write64(struct b53_device *dev, u8 page, u8 reg, ++ u64 value) ++{ ++ struct mii_bus *bus = dev->priv; ++ unsigned i; ++ u64 temp = value; ++ ++ for (i = 0; i < 4; i++) { ++ int ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_DATA0 + i, ++ temp & 0xffff); ++ if (ret) ++ return ret; ++ temp >>= 16; ++ } ++ ++ return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE); ++} ++ ++static int b53_mdio_phy_read16(struct b53_device *dev, int addr, u8 reg, ++ u16 *value) ++{ ++ struct mii_bus *bus = dev->priv; ++ ++ *value = mdiobus_read(bus, addr, reg); ++ ++ return 0; ++} ++ ++static int b53_mdio_phy_write16(struct b53_device *dev, int addr, u8 reg, ++ u16 value) ++{ ++ struct mii_bus *bus = dev->priv; ++ ++ return mdiobus_write(bus, addr, reg, value); ++} ++ ++static struct b53_io_ops b53_mdio_ops = { ++ .read8 = b53_mdio_read8, ++ .read16 = b53_mdio_read16, ++ .read32 = b53_mdio_read32, ++ .read48 = b53_mdio_read48, ++ .read64 = b53_mdio_read64, ++ .write8 = b53_mdio_write8, ++ .write16 = b53_mdio_write16, ++ .write32 = b53_mdio_write32, ++ .write48 = b53_mdio_write48, ++ .write64 = b53_mdio_write64, ++ .phy_read16 = b53_mdio_phy_read16, ++ .phy_write16 = b53_mdio_phy_write16, ++}; ++ ++static int b53_phy_probe(struct phy_device *phydev) ++{ ++ struct b53_device *dev; ++ int ret; ++ ++ /* allow the generic phy driver to take over */ ++ if (phydev->mdio.addr != B53_PSEUDO_PHY && phydev->mdio.addr != 0) ++ return -ENODEV; ++ ++ dev = b53_swconfig_switch_alloc(&phydev->mdio.dev, &b53_mdio_ops, phydev->mdio.bus); ++ if (!dev) ++ return -ENOMEM; ++ ++ dev->current_page = 0xff; ++ dev->priv = phydev->mdio.bus; ++ dev->ops = &b53_mdio_ops; ++ dev->pdata = NULL; ++ mutex_init(&dev->reg_mutex); ++ ++ ret = b53_swconfig_switch_detect(dev); ++ if (ret) ++ return ret; ++ ++ linkmode_zero(phydev->supported); ++ if (is5325(dev) || is5365(dev)) ++ linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, phydev->supported); ++ else ++ linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, phydev->supported); ++ ++ linkmode_copy(phydev->advertising, phydev->supported); ++ ++ ret = b53_swconfig_switch_register(dev); ++ if (ret) { ++ dev_err(dev->dev, "failed to register switch: %i\n", ret); ++ return ret; ++ } ++ ++ phydev->priv = dev; ++ ++ return 0; ++} ++ ++static int b53_phy_config_init(struct phy_device *phydev) ++{ ++ struct b53_device *dev = phydev->priv; ++ ++ /* we don't use page 0xff, so force a page set */ ++ dev->current_page = 0xff; ++ /* force the ethX as alias */ ++ dev->sw_dev.alias = phydev->attached_dev->name; ++ ++ return 0; ++} ++ ++static void b53_phy_remove(struct phy_device *phydev) ++{ ++ struct b53_device *priv = phydev->priv; ++ ++ if (!priv) ++ return; ++ ++ b53_switch_remove(priv); ++ ++ phydev->priv = NULL; ++} ++ ++static int b53_phy_config_aneg(struct phy_device *phydev) ++{ ++ return 0; ++} ++ ++static int b53_phy_read_status(struct phy_device *phydev) ++{ ++ struct b53_device *priv = phydev->priv; ++ ++ if (is5325(priv) || is5365(priv)) ++ phydev->speed = 100; ++ else ++ phydev->speed = 1000; ++ ++ phydev->duplex = DUPLEX_FULL; ++ phydev->link = 1; ++ phydev->state = PHY_RUNNING; ++ ++ netif_carrier_on(phydev->attached_dev); ++ phydev->adjust_link(phydev->attached_dev); ++ ++ return 0; ++} ++ ++/* BCM5325, BCM539x */ ++static struct phy_driver b53_phy_driver_id1 = { ++ .phy_id = 0x0143bc00, ++ .name = "Broadcom B53 (1)", ++ .phy_id_mask = 0x1ffffc00, ++ .features = 0, ++ .probe = b53_phy_probe, ++ .remove = b53_phy_remove, ++ .config_aneg = b53_phy_config_aneg, ++ .config_init = b53_phy_config_init, ++ .read_status = b53_phy_read_status, ++}; ++ ++/* BCM53125, BCM53128 */ ++static struct phy_driver b53_phy_driver_id2 = { ++ .phy_id = 0x03625c00, ++ .name = "Broadcom B53 (2)", ++ .phy_id_mask = 0x1ffffc00, ++ .features = 0, ++ .probe = b53_phy_probe, ++ .remove = b53_phy_remove, ++ .config_aneg = b53_phy_config_aneg, ++ .config_init = b53_phy_config_init, ++ .read_status = b53_phy_read_status, ++}; ++ ++/* BCM5365 */ ++static struct phy_driver b53_phy_driver_id3 = { ++ .phy_id = 0x00406300, ++ .name = "Broadcom B53 (3)", ++ .phy_id_mask = 0x1fffff00, ++ .features = 0, ++ .probe = b53_phy_probe, ++ .remove = b53_phy_remove, ++ .config_aneg = b53_phy_config_aneg, ++ .config_init = b53_phy_config_init, ++ .read_status = b53_phy_read_status, ++}; ++ ++int __init b53_phy_driver_register(void) ++{ ++ int ret; ++ ++ ret = phy_driver_register(&b53_phy_driver_id1, THIS_MODULE); ++ if (ret) ++ return ret; ++ ++ ret = phy_driver_register(&b53_phy_driver_id2, THIS_MODULE); ++ if (ret) ++ goto err1; ++ ++ ret = phy_driver_register(&b53_phy_driver_id3, THIS_MODULE); ++ if (!ret) ++ return 0; ++ ++ phy_driver_unregister(&b53_phy_driver_id2); ++err1: ++ phy_driver_unregister(&b53_phy_driver_id1); ++ return ret; ++} ++ ++void __exit b53_phy_driver_unregister(void) ++{ ++ phy_driver_unregister(&b53_phy_driver_id3); ++ phy_driver_unregister(&b53_phy_driver_id2); ++ phy_driver_unregister(&b53_phy_driver_id1); ++} ++ ++module_init(b53_phy_driver_register); ++module_exit(b53_phy_driver_unregister); ++ ++MODULE_DESCRIPTION("B53 MDIO access driver"); ++MODULE_LICENSE("Dual BSD/GPL"); +diff --git a/drivers/net/phy/b53/b53_mmap.c b/drivers/net/phy/b53/b53_mmap.c +new file mode 100644 +index 000000000000..62dfe1c24282 +--- /dev/null ++++ b/drivers/net/phy/b53/b53_mmap.c +@@ -0,0 +1,239 @@ ++/* ++ * B53 register access through memory mapped registers ++ * ++ * Copyright (C) 2012-2013 Jonas Gorski ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "b53_priv.h" ++ ++static int b53_mmap_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val) ++{ ++ u8 __iomem *regs = dev->priv; ++ ++ *val = readb(regs + (page << 8) + reg); ++ ++ return 0; ++} ++ ++static int b53_mmap_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val) ++{ ++ u8 __iomem *regs = dev->priv; ++ ++ if (WARN_ON(reg % 2)) ++ return -EINVAL; ++ ++ if (dev->pdata && dev->pdata->big_endian) ++ *val = readw_be(regs + (page << 8) + reg); ++ else ++ *val = readw(regs + (page << 8) + reg); ++ ++ return 0; ++} ++ ++static int b53_mmap_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val) ++{ ++ u8 __iomem *regs = dev->priv; ++ ++ if (WARN_ON(reg % 4)) ++ return -EINVAL; ++ ++ if (dev->pdata && dev->pdata->big_endian) ++ *val = readl_be(regs + (page << 8) + reg); ++ else ++ *val = readl(regs + (page << 8) + reg); ++ ++ return 0; ++} ++ ++static int b53_mmap_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val) ++{ ++ if (WARN_ON(reg % 2)) ++ return -EINVAL; ++ ++ if (reg % 4) { ++ u16 lo; ++ u32 hi; ++ ++ b53_mmap_read16(dev, page, reg, &lo); ++ b53_mmap_read32(dev, page, reg + 2, &hi); ++ ++ *val = ((u64)hi << 16) | lo; ++ } else { ++ u32 lo; ++ u16 hi; ++ ++ b53_mmap_read32(dev, page, reg, &lo); ++ b53_mmap_read16(dev, page, reg + 4, &hi); ++ ++ *val = ((u64)hi << 32) | lo; ++ } ++ ++ return 0; ++} ++ ++static int b53_mmap_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val) ++{ ++ u32 hi, lo; ++ ++ if (WARN_ON(reg % 4)) ++ return -EINVAL; ++ ++ b53_mmap_read32(dev, page, reg, &lo); ++ b53_mmap_read32(dev, page, reg + 4, &hi); ++ ++ *val = ((u64)hi << 32) | lo; ++ ++ return 0; ++} ++ ++static int b53_mmap_write8(struct b53_device *dev, u8 page, u8 reg, u8 value) ++{ ++ u8 __iomem *regs = dev->priv; ++ ++ writeb(value, regs + (page << 8) + reg); ++ ++ return 0; ++} ++ ++static int b53_mmap_write16(struct b53_device *dev, u8 page, u8 reg, ++ u16 value) ++{ ++ u8 __iomem *regs = dev->priv; ++ ++ if (WARN_ON(reg % 2)) ++ return -EINVAL; ++ ++ if (dev->pdata && dev->pdata->big_endian) ++ writew_be(value, regs + (page << 8) + reg); ++ else ++ writew(value, regs + (page << 8) + reg); ++ ++ return 0; ++} ++ ++static int b53_mmap_write32(struct b53_device *dev, u8 page, u8 reg, ++ u32 value) ++{ ++ u8 __iomem *regs = dev->priv; ++ ++ if (WARN_ON(reg % 4)) ++ return -EINVAL; ++ ++ if (dev->pdata && dev->pdata->big_endian) ++ writel_be(value, regs + (page << 8) + reg); ++ else ++ writel(value, regs + (page << 8) + reg); ++ ++ return 0; ++} ++ ++static int b53_mmap_write48(struct b53_device *dev, u8 page, u8 reg, ++ u64 value) ++{ ++ if (WARN_ON(reg % 2)) ++ return -EINVAL; ++ ++ if (reg % 4) { ++ u32 hi = (u32)(value >> 16); ++ u16 lo = (u16)value; ++ ++ b53_mmap_write16(dev, page, reg, lo); ++ b53_mmap_write32(dev, page, reg + 2, hi); ++ } else { ++ u16 hi = (u16)(value >> 32); ++ u32 lo = (u32)value; ++ ++ b53_mmap_write32(dev, page, reg, lo); ++ b53_mmap_write16(dev, page, reg + 4, hi); ++ } ++ ++ return 0; ++} ++ ++static int b53_mmap_write64(struct b53_device *dev, u8 page, u8 reg, ++ u64 value) ++{ ++ u32 hi, lo; ++ ++ hi = (u32)(value >> 32); ++ lo = (u32)value; ++ ++ if (WARN_ON(reg % 4)) ++ return -EINVAL; ++ ++ b53_mmap_write32(dev, page, reg, lo); ++ b53_mmap_write32(dev, page, reg + 4, hi); ++ ++ return 0; ++} ++ ++static struct b53_io_ops b53_mmap_ops = { ++ .read8 = b53_mmap_read8, ++ .read16 = b53_mmap_read16, ++ .read32 = b53_mmap_read32, ++ .read48 = b53_mmap_read48, ++ .read64 = b53_mmap_read64, ++ .write8 = b53_mmap_write8, ++ .write16 = b53_mmap_write16, ++ .write32 = b53_mmap_write32, ++ .write48 = b53_mmap_write48, ++ .write64 = b53_mmap_write64, ++}; ++ ++static int b53_mmap_probe(struct platform_device *pdev) ++{ ++ struct b53_platform_data *pdata = pdev->dev.platform_data; ++ struct b53_device *dev; ++ ++ if (!pdata) ++ return -EINVAL; ++ ++ dev = b53_swconfig_switch_alloc(&pdev->dev, &b53_mmap_ops, pdata->regs); ++ if (!dev) ++ return -ENOMEM; ++ ++ if (pdata) ++ dev->pdata = pdata; ++ ++ platform_set_drvdata(pdev, dev); ++ ++ return b53_swconfig_switch_register(dev); ++} ++ ++static void b53_mmap_remove(struct platform_device *pdev) ++{ ++ struct b53_device *dev = platform_get_drvdata(pdev); ++ ++ if (dev) ++ b53_switch_remove(dev); ++} ++ ++static struct platform_driver b53_mmap_driver = { ++ .probe = b53_mmap_probe, ++ .remove_new = b53_mmap_remove, ++ .driver = { ++ .name = "b53-switch", ++ }, ++}; ++ ++module_platform_driver(b53_mmap_driver); ++MODULE_AUTHOR("Jonas Gorski "); ++MODULE_DESCRIPTION("B53 MMAP access driver"); ++MODULE_LICENSE("Dual BSD/GPL"); +diff --git a/drivers/net/phy/b53/b53_phy_fixup.c b/drivers/net/phy/b53/b53_phy_fixup.c +new file mode 100644 +index 000000000000..a19eccefd14c +--- /dev/null ++++ b/drivers/net/phy/b53/b53_phy_fixup.c +@@ -0,0 +1,55 @@ ++/* ++ * B53 PHY Fixup call ++ * ++ * Copyright (C) 2013 Jonas Gorski ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#include ++#include ++#include ++ ++#define B53_PSEUDO_PHY 0x1e /* Register Access Pseudo PHY */ ++ ++#define B53_BRCM_OUI_1 0x0143bc00 ++#define B53_BRCM_OUI_2 0x03625c00 ++#define B53_BRCM_OUI_3 0x00406300 ++ ++static int b53_phy_fixup(struct phy_device *dev) ++{ ++ struct mii_bus *bus = dev->mdio.bus; ++ u32 phy_id; ++ ++ if (dev->mdio.addr != B53_PSEUDO_PHY) ++ return 0; ++ ++ /* read the first port's id */ ++ phy_id = mdiobus_read(bus, 0, 2) << 16; ++ phy_id |= mdiobus_read(bus, 0, 3); ++ ++ if ((phy_id & 0xfffffc00) == B53_BRCM_OUI_1 || ++ (phy_id & 0xfffffc00) == B53_BRCM_OUI_2 || ++ (phy_id & 0xffffff00) == B53_BRCM_OUI_3) { ++ dev->phy_id = phy_id; ++ } ++ ++ return 0; ++} ++ ++int __init b53_phy_fixup_register(void) ++{ ++ return phy_register_fixup_for_id(PHY_ANY_ID, b53_phy_fixup); ++} ++ ++subsys_initcall(b53_phy_fixup_register); +diff --git a/drivers/net/phy/b53/b53_priv.h b/drivers/net/phy/b53/b53_priv.h +new file mode 100644 +index 000000000000..e455c755bf22 +--- /dev/null ++++ b/drivers/net/phy/b53/b53_priv.h +@@ -0,0 +1,336 @@ ++/* ++ * B53 common definitions ++ * ++ * Copyright (C) 2011-2013 Jonas Gorski ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#ifndef __B53_PRIV_H ++#define __B53_PRIV_H ++ ++#include ++#include ++#include ++ ++struct b53_device; ++ ++struct b53_io_ops { ++ int (*read8)(struct b53_device *dev, u8 page, u8 reg, u8 *value); ++ int (*read16)(struct b53_device *dev, u8 page, u8 reg, u16 *value); ++ int (*read32)(struct b53_device *dev, u8 page, u8 reg, u32 *value); ++ int (*read48)(struct b53_device *dev, u8 page, u8 reg, u64 *value); ++ int (*read64)(struct b53_device *dev, u8 page, u8 reg, u64 *value); ++ int (*write8)(struct b53_device *dev, u8 page, u8 reg, u8 value); ++ int (*write16)(struct b53_device *dev, u8 page, u8 reg, u16 value); ++ int (*write32)(struct b53_device *dev, u8 page, u8 reg, u32 value); ++ int (*write48)(struct b53_device *dev, u8 page, u8 reg, u64 value); ++ int (*write64)(struct b53_device *dev, u8 page, u8 reg, u64 value); ++ int (*phy_read16)(struct b53_device *dev, int addr, u8 reg, u16 *value); ++ int (*phy_write16)(struct b53_device *dev, int addr, u8 reg, u16 value); ++}; ++ ++enum { ++ BCM5325_DEVICE_ID = 0x25, ++ BCM5365_DEVICE_ID = 0x65, ++ BCM5395_DEVICE_ID = 0x95, ++ BCM5397_DEVICE_ID = 0x97, ++ BCM5398_DEVICE_ID = 0x98, ++ BCM53115_DEVICE_ID = 0x53115, ++ BCM53125_DEVICE_ID = 0x53125, ++ BCM53128_DEVICE_ID = 0x53128, ++ BCM63XX_DEVICE_ID = 0x6300, ++ BCM53010_DEVICE_ID = 0x53010, ++ BCM53011_DEVICE_ID = 0x53011, ++ BCM53012_DEVICE_ID = 0x53012, ++ BCM53018_DEVICE_ID = 0x53018, ++ BCM53019_DEVICE_ID = 0x53019, ++}; ++ ++#define B53_N_PORTS 9 ++#define B53_N_PORTS_25 6 ++ ++struct b53_vlan { ++ unsigned int members:B53_N_PORTS; ++ unsigned int untag:B53_N_PORTS; ++}; ++ ++struct b53_port { ++ unsigned int pvid:12; ++}; ++ ++struct b53_device { ++ struct switch_dev sw_dev; ++ struct b53_platform_data *pdata; ++ ++ struct mutex reg_mutex; ++ const struct b53_io_ops *ops; ++ ++ /* chip specific data */ ++ u32 chip_id; ++ u8 core_rev; ++ u8 vta_regs[3]; ++ u8 duplex_reg; ++ u8 jumbo_pm_reg; ++ u8 jumbo_size_reg; ++ int reset_gpio; ++ ++ /* used ports mask */ ++ u16 enabled_ports; ++ ++ /* connect specific data */ ++ u8 current_page; ++ struct device *dev; ++ void *priv; ++ ++ /* run time configuration */ ++ unsigned enable_vlan:1; ++ unsigned enable_jumbo:1; ++ unsigned allow_vid_4095:1; ++ ++ struct b53_port *ports; ++ struct b53_vlan *vlans; ++ ++ char *buf; ++}; ++ ++#define b53_for_each_port(dev, i) \ ++ for (i = 0; i < B53_N_PORTS; i++) \ ++ if (dev->enabled_ports & BIT(i)) ++ ++ ++ ++static inline int is5325(struct b53_device *dev) ++{ ++ return dev->chip_id == BCM5325_DEVICE_ID; ++} ++ ++static inline int is5365(struct b53_device *dev) ++{ ++#ifdef CONFIG_BCM47XX ++ return dev->chip_id == BCM5365_DEVICE_ID; ++#else ++ return 0; ++#endif ++} ++ ++static inline int is5397_98(struct b53_device *dev) ++{ ++ return dev->chip_id == BCM5397_DEVICE_ID || ++ dev->chip_id == BCM5398_DEVICE_ID; ++} ++ ++static inline int is539x(struct b53_device *dev) ++{ ++ return dev->chip_id == BCM5395_DEVICE_ID || ++ dev->chip_id == BCM5397_DEVICE_ID || ++ dev->chip_id == BCM5398_DEVICE_ID; ++} ++ ++static inline int is531x5(struct b53_device *dev) ++{ ++ return dev->chip_id == BCM53115_DEVICE_ID || ++ dev->chip_id == BCM53125_DEVICE_ID || ++ dev->chip_id == BCM53128_DEVICE_ID; ++} ++ ++static inline int is63xx(struct b53_device *dev) ++{ ++#ifdef CONFIG_BCM63XX ++ return dev->chip_id == BCM63XX_DEVICE_ID; ++#else ++ return 0; ++#endif ++} ++ ++static inline int is5301x(struct b53_device *dev) ++{ ++ return dev->chip_id == BCM53010_DEVICE_ID || ++ dev->chip_id == BCM53011_DEVICE_ID || ++ dev->chip_id == BCM53012_DEVICE_ID || ++ dev->chip_id == BCM53018_DEVICE_ID || ++ dev->chip_id == BCM53019_DEVICE_ID; ++} ++ ++#define B53_CPU_PORT_25 5 ++#define B53_CPU_PORT 8 ++ ++static inline int is_cpu_port(struct b53_device *dev, int port) ++{ ++ return dev->sw_dev.cpu_port == port; ++} ++ ++static inline int is_imp_port(struct b53_device *dev, int port) ++{ ++ if (is5325(dev) || is5365(dev)) ++ return port == B53_CPU_PORT_25; ++ else ++ return port == B53_CPU_PORT; ++} ++ ++static inline struct b53_device *sw_to_b53(struct switch_dev *sw) ++{ ++ return container_of(sw, struct b53_device, sw_dev); ++} ++ ++struct b53_device *b53_swconfig_switch_alloc(struct device *base, struct b53_io_ops *ops, ++ void *priv); ++ ++int b53_swconfig_switch_detect(struct b53_device *dev); ++ ++int b53_swconfig_switch_register(struct b53_device *dev); ++ ++static inline void b53_switch_remove(struct b53_device *dev) ++{ ++ unregister_switch(&dev->sw_dev); ++} ++ ++static inline int b53_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val) ++{ ++ int ret; ++ ++ mutex_lock(&dev->reg_mutex); ++ ret = dev->ops->read8(dev, page, reg, val); ++ mutex_unlock(&dev->reg_mutex); ++ ++ return ret; ++} ++ ++static inline int b53_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val) ++{ ++ int ret; ++ ++ mutex_lock(&dev->reg_mutex); ++ ret = dev->ops->read16(dev, page, reg, val); ++ mutex_unlock(&dev->reg_mutex); ++ ++ return ret; ++} ++ ++static inline int b53_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val) ++{ ++ int ret; ++ ++ mutex_lock(&dev->reg_mutex); ++ ret = dev->ops->read32(dev, page, reg, val); ++ mutex_unlock(&dev->reg_mutex); ++ ++ return ret; ++} ++ ++static inline int b53_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val) ++{ ++ int ret; ++ ++ mutex_lock(&dev->reg_mutex); ++ ret = dev->ops->read48(dev, page, reg, val); ++ mutex_unlock(&dev->reg_mutex); ++ ++ return ret; ++} ++ ++static inline int b53_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val) ++{ ++ int ret; ++ ++ mutex_lock(&dev->reg_mutex); ++ ret = dev->ops->read64(dev, page, reg, val); ++ mutex_unlock(&dev->reg_mutex); ++ ++ return ret; ++} ++ ++static inline int b53_write8(struct b53_device *dev, u8 page, u8 reg, u8 value) ++{ ++ int ret; ++ ++ mutex_lock(&dev->reg_mutex); ++ ret = dev->ops->write8(dev, page, reg, value); ++ mutex_unlock(&dev->reg_mutex); ++ ++ return ret; ++} ++ ++static inline int b53_write16(struct b53_device *dev, u8 page, u8 reg, ++ u16 value) ++{ ++ int ret; ++ ++ mutex_lock(&dev->reg_mutex); ++ ret = dev->ops->write16(dev, page, reg, value); ++ mutex_unlock(&dev->reg_mutex); ++ ++ return ret; ++} ++ ++static inline int b53_write32(struct b53_device *dev, u8 page, u8 reg, ++ u32 value) ++{ ++ int ret; ++ ++ mutex_lock(&dev->reg_mutex); ++ ret = dev->ops->write32(dev, page, reg, value); ++ mutex_unlock(&dev->reg_mutex); ++ ++ return ret; ++} ++ ++static inline int b53_write48(struct b53_device *dev, u8 page, u8 reg, ++ u64 value) ++{ ++ int ret; ++ ++ mutex_lock(&dev->reg_mutex); ++ ret = dev->ops->write48(dev, page, reg, value); ++ mutex_unlock(&dev->reg_mutex); ++ ++ return ret; ++} ++ ++static inline int b53_write64(struct b53_device *dev, u8 page, u8 reg, ++ u64 value) ++{ ++ int ret; ++ ++ mutex_lock(&dev->reg_mutex); ++ ret = dev->ops->write64(dev, page, reg, value); ++ mutex_unlock(&dev->reg_mutex); ++ ++ return ret; ++} ++ ++#ifdef CONFIG_BCM47XX ++#include ++#endif ++ ++#include ++#include ++ ++static inline int b53_switch_get_reset_gpio(struct b53_device *dev) ++{ ++#ifdef CONFIG_BCM47XX ++ enum bcm47xx_board board = bcm47xx_board_get(); ++ ++ switch (board) { ++ case BCM47XX_BOARD_LINKSYS_WRT300NV11: ++ case BCM47XX_BOARD_LINKSYS_WRT310NV1: ++ return 8; ++ default: ++ break; ++ } ++#endif ++ ++ return bcm47xx_nvram_gpio_pin("robo_reset"); ++} ++ ++#endif +diff --git a/drivers/net/phy/b53/b53_regs.h b/drivers/net/phy/b53/b53_regs.h +new file mode 100644 +index 000000000000..f0bf6744a75c +--- /dev/null ++++ b/drivers/net/phy/b53/b53_regs.h +@@ -0,0 +1,348 @@ ++/* ++ * B53 register definitions ++ * ++ * Copyright (C) 2004 Broadcom Corporation ++ * Copyright (C) 2011-2013 Jonas Gorski ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#ifndef __B53_REGS_H ++#define __B53_REGS_H ++ ++/* Management Port (SMP) Page offsets */ ++#define B53_CTRL_PAGE 0x00 /* Control */ ++#define B53_STAT_PAGE 0x01 /* Status */ ++#define B53_MGMT_PAGE 0x02 /* Management Mode */ ++#define B53_MIB_AC_PAGE 0x03 /* MIB Autocast */ ++#define B53_ARLCTRL_PAGE 0x04 /* ARL Control */ ++#define B53_ARLIO_PAGE 0x05 /* ARL Access */ ++#define B53_FRAMEBUF_PAGE 0x06 /* Management frame access */ ++#define B53_MEM_ACCESS_PAGE 0x08 /* Memory access */ ++ ++/* PHY Registers */ ++#define B53_PORT_MII_PAGE(i) (0x10 + (i)) /* Port i MII Registers */ ++#define B53_IM_PORT_PAGE 0x18 /* Inverse MII Port (to EMAC) */ ++#define B53_ALL_PORT_PAGE 0x19 /* All ports MII (broadcast) */ ++ ++/* MIB registers */ ++#define B53_MIB_PAGE(i) (0x20 + (i)) ++ ++/* Quality of Service (QoS) Registers */ ++#define B53_QOS_PAGE 0x30 ++ ++/* Port VLAN Page */ ++#define B53_PVLAN_PAGE 0x31 ++ ++/* VLAN Registers */ ++#define B53_VLAN_PAGE 0x34 ++ ++/* Jumbo Frame Registers */ ++#define B53_JUMBO_PAGE 0x40 ++ ++/* CFP Configuration Registers Page */ ++#define B53_CFP_PAGE 0xa1 ++ ++/************************************************************************* ++ * Control Page registers ++ *************************************************************************/ ++ ++/* Port Control Register (8 bit) */ ++#define B53_PORT_CTRL(i) (0x00 + (i)) ++#define PORT_CTRL_RX_DISABLE BIT(0) ++#define PORT_CTRL_TX_DISABLE BIT(1) ++#define PORT_CTRL_RX_BCST_EN BIT(2) /* Broadcast RX (P8 only) */ ++#define PORT_CTRL_RX_MCST_EN BIT(3) /* Multicast RX (P8 only) */ ++#define PORT_CTRL_RX_UCST_EN BIT(4) /* Unicast RX (P8 only) */ ++#define PORT_CTRL_STP_STATE_S 5 ++#define PORT_CTRL_STP_STATE_MASK (0x7 << PORT_CTRL_STP_STATE_S) ++ ++/* SMP Control Register (8 bit) */ ++#define B53_SMP_CTRL 0x0a ++ ++/* Switch Mode Control Register (8 bit) */ ++#define B53_SWITCH_MODE 0x0b ++#define SM_SW_FWD_MODE BIT(0) /* 1 = Managed Mode */ ++#define SM_SW_FWD_EN BIT(1) /* Forwarding Enable */ ++ ++/* IMP Port state override register (8 bit) */ ++#define B53_PORT_OVERRIDE_CTRL 0x0e ++#define PORT_OVERRIDE_LINK BIT(0) ++#define PORT_OVERRIDE_FULL_DUPLEX BIT(1) /* 0 = Half Duplex */ ++#define PORT_OVERRIDE_SPEED_S 2 ++#define PORT_OVERRIDE_SPEED_10M (0 << PORT_OVERRIDE_SPEED_S) ++#define PORT_OVERRIDE_SPEED_100M (1 << PORT_OVERRIDE_SPEED_S) ++#define PORT_OVERRIDE_SPEED_1000M (2 << PORT_OVERRIDE_SPEED_S) ++#define PORT_OVERRIDE_RV_MII_25 BIT(4) /* BCM5325 only */ ++#define PORT_OVERRIDE_RX_FLOW BIT(4) ++#define PORT_OVERRIDE_TX_FLOW BIT(5) ++#define PORT_OVERRIDE_SPEED_2000M BIT(6) /* BCM5301X only, requires setting 1000M */ ++#define PORT_OVERRIDE_EN BIT(7) /* Use the register contents */ ++ ++/* Power-down mode control */ ++#define B53_PD_MODE_CTRL_25 0x0f ++ ++/* IP Multicast control (8 bit) */ ++#define B53_IP_MULTICAST_CTRL 0x21 ++#define B53_IPMC_FWD_EN BIT(1) ++#define B53_UC_FWD_EN BIT(6) ++#define B53_MC_FWD_EN BIT(7) ++ ++/* (16 bit) */ ++#define B53_UC_FLOOD_MASK 0x32 ++#define B53_MC_FLOOD_MASK 0x34 ++#define B53_IPMC_FLOOD_MASK 0x36 ++ ++/* ++ * Override Ports 0-7 State on devices with xMII interfaces (8 bit) ++ * ++ * For port 8 still use B53_PORT_OVERRIDE_CTRL ++ * Please note that not all ports are available on every hardware, e.g. BCM5301X ++ * don't include overriding port 6, BCM63xx also have some limitations. ++ */ ++#define B53_GMII_PORT_OVERRIDE_CTRL(i) (0x58 + (i)) ++#define GMII_PO_LINK BIT(0) ++#define GMII_PO_FULL_DUPLEX BIT(1) /* 0 = Half Duplex */ ++#define GMII_PO_SPEED_S 2 ++#define GMII_PO_SPEED_10M (0 << GMII_PO_SPEED_S) ++#define GMII_PO_SPEED_100M (1 << GMII_PO_SPEED_S) ++#define GMII_PO_SPEED_1000M (2 << GMII_PO_SPEED_S) ++#define GMII_PO_RX_FLOW BIT(4) ++#define GMII_PO_TX_FLOW BIT(5) ++#define GMII_PO_EN BIT(6) /* Use the register contents */ ++#define GMII_PO_SPEED_2000M BIT(7) /* BCM5301X only, requires setting 1000M */ ++ ++/* Software reset register (8 bit) */ ++#define B53_SOFTRESET 0x79 ++ ++/* Fast Aging Control register (8 bit) */ ++#define B53_FAST_AGE_CTRL 0x88 ++#define FAST_AGE_STATIC BIT(0) ++#define FAST_AGE_DYNAMIC BIT(1) ++#define FAST_AGE_PORT BIT(2) ++#define FAST_AGE_VLAN BIT(3) ++#define FAST_AGE_STP BIT(4) ++#define FAST_AGE_MC BIT(5) ++#define FAST_AGE_DONE BIT(7) ++ ++/************************************************************************* ++ * Status Page registers ++ *************************************************************************/ ++ ++/* Link Status Summary Register (16bit) */ ++#define B53_LINK_STAT 0x00 ++ ++/* Link Status Change Register (16 bit) */ ++#define B53_LINK_STAT_CHANGE 0x02 ++ ++/* Port Speed Summary Register (16 bit for FE, 32 bit for GE) */ ++#define B53_SPEED_STAT 0x04 ++#define SPEED_PORT_FE(reg, port) (((reg) >> (port)) & 1) ++#define SPEED_PORT_GE(reg, port) (((reg) >> 2 * (port)) & 3) ++#define SPEED_STAT_10M 0 ++#define SPEED_STAT_100M 1 ++#define SPEED_STAT_1000M 2 ++ ++/* Duplex Status Summary (16 bit) */ ++#define B53_DUPLEX_STAT_FE 0x06 ++#define B53_DUPLEX_STAT_GE 0x08 ++#define B53_DUPLEX_STAT_63XX 0x0c ++ ++/* Revision ID register for BCM5325 */ ++#define B53_REV_ID_25 0x50 ++ ++/* Strap Value (48 bit) */ ++#define B53_STRAP_VALUE 0x70 ++#define SV_GMII_CTRL_115 BIT(27) ++ ++/************************************************************************* ++ * Management Mode Page Registers ++ *************************************************************************/ ++ ++/* Global Management Config Register (8 bit) */ ++#define B53_GLOBAL_CONFIG 0x00 ++#define GC_RESET_MIB 0x01 ++#define GC_RX_BPDU_EN 0x02 ++#define GC_MIB_AC_HDR_EN 0x10 ++#define GC_MIB_AC_EN 0x20 ++#define GC_FRM_MGMT_PORT_M 0xC0 ++#define GC_FRM_MGMT_PORT_04 0x00 ++#define GC_FRM_MGMT_PORT_MII 0x80 ++ ++/* Broadcom Header control register (8 bit) */ ++#define B53_BRCM_HDR 0x03 ++#define BRCM_HDR_P8_EN BIT(0) /* Enable tagging on port 8 */ ++#define BRCM_HDR_P5_EN BIT(1) /* Enable tagging on port 5 */ ++ ++/* Device ID register (8 or 32 bit) */ ++#define B53_DEVICE_ID 0x30 ++ ++/* Revision ID register (8 bit) */ ++#define B53_REV_ID 0x40 ++ ++/************************************************************************* ++ * ARL Access Page Registers ++ *************************************************************************/ ++ ++/* VLAN Table Access Register (8 bit) */ ++#define B53_VT_ACCESS 0x80 ++#define B53_VT_ACCESS_9798 0x60 /* for BCM5397/BCM5398 */ ++#define B53_VT_ACCESS_63XX 0x60 /* for BCM6328/62/68 */ ++#define VTA_CMD_WRITE 0 ++#define VTA_CMD_READ 1 ++#define VTA_CMD_CLEAR 2 ++#define VTA_START_CMD BIT(7) ++ ++/* VLAN Table Index Register (16 bit) */ ++#define B53_VT_INDEX 0x81 ++#define B53_VT_INDEX_9798 0x61 ++#define B53_VT_INDEX_63XX 0x62 ++ ++/* VLAN Table Entry Register (32 bit) */ ++#define B53_VT_ENTRY 0x83 ++#define B53_VT_ENTRY_9798 0x63 ++#define B53_VT_ENTRY_63XX 0x64 ++#define VTE_MEMBERS 0x1ff ++#define VTE_UNTAG_S 9 ++#define VTE_UNTAG (0x1ff << 9) ++ ++/************************************************************************* ++ * Port VLAN Registers ++ *************************************************************************/ ++ ++/* Port VLAN mask (16 bit) IMP port is always 8, also on 5325 & co */ ++#define B53_PVLAN_PORT_MASK(i) ((i) * 2) ++ ++/************************************************************************* ++ * 802.1Q Page Registers ++ *************************************************************************/ ++ ++/* Global QoS Control (8 bit) */ ++#define B53_QOS_GLOBAL_CTL 0x00 ++ ++/* Enable 802.1Q for individual Ports (16 bit) */ ++#define B53_802_1P_EN 0x04 ++ ++/************************************************************************* ++ * VLAN Page Registers ++ *************************************************************************/ ++ ++/* VLAN Control 0 (8 bit) */ ++#define B53_VLAN_CTRL0 0x00 ++#define VC0_8021PF_CTRL_MASK 0x3 ++#define VC0_8021PF_CTRL_NONE 0x0 ++#define VC0_8021PF_CTRL_CHANGE_PRI 0x1 ++#define VC0_8021PF_CTRL_CHANGE_VID 0x2 ++#define VC0_8021PF_CTRL_CHANGE_BOTH 0x3 ++#define VC0_8021QF_CTRL_MASK 0xc ++#define VC0_8021QF_CTRL_CHANGE_PRI 0x1 ++#define VC0_8021QF_CTRL_CHANGE_VID 0x2 ++#define VC0_8021QF_CTRL_CHANGE_BOTH 0x3 ++#define VC0_RESERVED_1 BIT(1) ++#define VC0_DROP_VID_MISS BIT(4) ++#define VC0_VID_HASH_VID BIT(5) ++#define VC0_VID_CHK_EN BIT(6) /* Use VID,DA or VID,SA */ ++#define VC0_VLAN_EN BIT(7) /* 802.1Q VLAN Enabled */ ++ ++/* VLAN Control 1 (8 bit) */ ++#define B53_VLAN_CTRL1 0x01 ++#define VC1_RX_MCST_TAG_EN BIT(1) ++#define VC1_RX_MCST_FWD_EN BIT(2) ++#define VC1_RX_MCST_UNTAG_EN BIT(3) ++ ++/* VLAN Control 2 (8 bit) */ ++#define B53_VLAN_CTRL2 0x02 ++ ++/* VLAN Control 3 (8 bit when BCM5325, 16 bit else) */ ++#define B53_VLAN_CTRL3 0x03 ++#define B53_VLAN_CTRL3_63XX 0x04 ++#define VC3_MAXSIZE_1532 BIT(6) /* 5325 only */ ++#define VC3_HIGH_8BIT_EN BIT(7) /* 5325 only */ ++ ++/* VLAN Control 4 (8 bit) */ ++#define B53_VLAN_CTRL4 0x05 ++#define B53_VLAN_CTRL4_25 0x04 ++#define B53_VLAN_CTRL4_63XX 0x06 ++#define VC4_ING_VID_CHECK_S 6 ++#define VC4_ING_VID_CHECK_MASK (0x3 << VC4_ING_VID_CHECK_S) ++#define VC4_ING_VID_VIO_FWD 0 /* forward, but do not learn */ ++#define VC4_ING_VID_VIO_DROP 1 /* drop VID violations */ ++#define VC4_NO_ING_VID_CHK 2 /* do not check */ ++#define VC4_ING_VID_VIO_TO_IMP 3 /* redirect to MII port */ ++ ++/* VLAN Control 5 (8 bit) */ ++#define B53_VLAN_CTRL5 0x06 ++#define B53_VLAN_CTRL5_25 0x05 ++#define B53_VLAN_CTRL5_63XX 0x07 ++#define VC5_VID_FFF_EN BIT(2) ++#define VC5_DROP_VTABLE_MISS BIT(3) ++ ++/* VLAN Control 6 (8 bit) */ ++#define B53_VLAN_CTRL6 0x07 ++#define B53_VLAN_CTRL6_63XX 0x08 ++ ++/* VLAN Table Access Register (16 bit) */ ++#define B53_VLAN_TABLE_ACCESS_25 0x06 /* BCM5325E/5350 */ ++#define B53_VLAN_TABLE_ACCESS_65 0x08 /* BCM5365 */ ++#define VTA_VID_LOW_MASK_25 0xf ++#define VTA_VID_LOW_MASK_65 0xff ++#define VTA_VID_HIGH_S_25 4 ++#define VTA_VID_HIGH_S_65 8 ++#define VTA_VID_HIGH_MASK_25 (0xff << VTA_VID_HIGH_S_25E) ++#define VTA_VID_HIGH_MASK_65 (0xf << VTA_VID_HIGH_S_65) ++#define VTA_RW_STATE BIT(12) ++#define VTA_RW_STATE_RD 0 ++#define VTA_RW_STATE_WR BIT(12) ++#define VTA_RW_OP_EN BIT(13) ++ ++/* VLAN Read/Write Registers for (16/32 bit) */ ++#define B53_VLAN_WRITE_25 0x08 ++#define B53_VLAN_WRITE_65 0x0a ++#define B53_VLAN_READ 0x0c ++#define VA_MEMBER_MASK 0x3f ++#define VA_UNTAG_S_25 6 ++#define VA_UNTAG_MASK_25 0x3f ++#define VA_UNTAG_S_65 7 ++#define VA_UNTAG_MASK_65 0x1f ++#define VA_VID_HIGH_S 12 ++#define VA_VID_HIGH_MASK (0xffff << VA_VID_HIGH_S) ++#define VA_VALID_25 BIT(20) ++#define VA_VALID_25_R4 BIT(24) ++#define VA_VALID_65 BIT(14) ++ ++/* VLAN Port Default Tag (16 bit) */ ++#define B53_VLAN_PORT_DEF_TAG(i) (0x10 + 2 * (i)) ++ ++/************************************************************************* ++ * Jumbo Frame Page Registers ++ *************************************************************************/ ++ ++/* Jumbo Enable Port Mask (bit i == port i enabled) (32 bit) */ ++#define B53_JUMBO_PORT_MASK 0x01 ++#define B53_JUMBO_PORT_MASK_63XX 0x04 ++#define JPM_10_100_JUMBO_EN BIT(24) /* GigE always enabled */ ++ ++/* Good Frame Max Size without 802.1Q TAG (16 bit) */ ++#define B53_JUMBO_MAX_SIZE 0x05 ++#define B53_JUMBO_MAX_SIZE_63XX 0x08 ++#define JMS_MIN_SIZE 1518 ++#define JMS_MAX_SIZE 9724 ++ ++/************************************************************************* ++ * CFP Configuration Page Registers ++ *************************************************************************/ ++ ++/* CFP Control Register with ports map (8 bit) */ ++#define B53_CFP_CTRL 0x00 ++ ++#endif /* !__B53_REGS_H */ +diff --git a/drivers/net/phy/b53/b53_spi.c b/drivers/net/phy/b53/b53_spi.c +new file mode 100644 +index 000000000000..400454df18c1 +--- /dev/null ++++ b/drivers/net/phy/b53/b53_spi.c +@@ -0,0 +1,344 @@ ++/* ++ * B53 register access through SPI ++ * ++ * Copyright (C) 2011-2013 Jonas Gorski ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "b53_priv.h" ++ ++#define B53_SPI_DATA 0xf0 ++ ++#define B53_SPI_STATUS 0xfe ++#define B53_SPI_CMD_SPIF BIT(7) ++#define B53_SPI_CMD_RACK BIT(5) ++ ++#define B53_SPI_CMD_READ 0x00 ++#define B53_SPI_CMD_WRITE 0x01 ++#define B53_SPI_CMD_NORMAL 0x60 ++#define B53_SPI_CMD_FAST 0x10 ++ ++#define B53_SPI_PAGE_SELECT 0xff ++ ++static inline int b53_spi_read_reg(struct spi_device *spi, u8 reg, u8 *val, ++ unsigned len) ++{ ++ u8 txbuf[2]; ++ ++ txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_READ; ++ txbuf[1] = reg; ++ ++ return spi_write_then_read(spi, txbuf, 2, val, len); ++} ++ ++static inline int b53_spi_clear_status(struct spi_device *spi) ++{ ++ unsigned int i; ++ u8 rxbuf; ++ int ret; ++ ++ for (i = 0; i < 10; i++) { ++ ret = b53_spi_read_reg(spi, B53_SPI_STATUS, &rxbuf, 1); ++ if (ret) ++ return ret; ++ ++ if (!(rxbuf & B53_SPI_CMD_SPIF)) ++ break; ++ ++ mdelay(1); ++ } ++ ++ if (i == 10) ++ return -EIO; ++ ++ return 0; ++} ++ ++static inline int b53_spi_set_page(struct spi_device *spi, u8 page) ++{ ++ u8 txbuf[3]; ++ ++ txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE; ++ txbuf[1] = B53_SPI_PAGE_SELECT; ++ txbuf[2] = page; ++ ++ return spi_write(spi, txbuf, sizeof(txbuf)); ++} ++ ++static inline int b53_prepare_reg_access(struct spi_device *spi, u8 page) ++{ ++ int ret = b53_spi_clear_status(spi); ++ ++ if (ret) ++ return ret; ++ ++ return b53_spi_set_page(spi, page); ++} ++ ++static int b53_spi_prepare_reg_read(struct spi_device *spi, u8 reg) ++{ ++ u8 rxbuf; ++ int retry_count; ++ int ret; ++ ++ ret = b53_spi_read_reg(spi, reg, &rxbuf, 1); ++ if (ret) ++ return ret; ++ ++ for (retry_count = 0; retry_count < 10; retry_count++) { ++ ret = b53_spi_read_reg(spi, B53_SPI_STATUS, &rxbuf, 1); ++ if (ret) ++ return ret; ++ ++ if (rxbuf & B53_SPI_CMD_RACK) ++ break; ++ ++ mdelay(1); ++ } ++ ++ if (retry_count == 10) ++ return -EIO; ++ ++ return 0; ++} ++ ++static int b53_spi_read(struct b53_device *dev, u8 page, u8 reg, u8 *data, ++ unsigned len) ++{ ++ struct spi_device *spi = dev->priv; ++ int ret; ++ ++ ret = b53_prepare_reg_access(spi, page); ++ if (ret) ++ return ret; ++ ++ ret = b53_spi_prepare_reg_read(spi, reg); ++ if (ret) ++ return ret; ++ ++ return b53_spi_read_reg(spi, B53_SPI_DATA, data, len); ++} ++ ++static int b53_spi_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val) ++{ ++ return b53_spi_read(dev, page, reg, val, 1); ++} ++ ++static int b53_spi_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val) ++{ ++ int ret = b53_spi_read(dev, page, reg, (u8 *)val, 2); ++ ++ if (!ret) ++ *val = le16_to_cpu(*val); ++ ++ return ret; ++} ++ ++static int b53_spi_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val) ++{ ++ int ret = b53_spi_read(dev, page, reg, (u8 *)val, 4); ++ ++ if (!ret) ++ *val = le32_to_cpu(*val); ++ ++ return ret; ++} ++ ++static int b53_spi_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val) ++{ ++ int ret; ++ ++ *val = 0; ++ ret = b53_spi_read(dev, page, reg, (u8 *)val, 6); ++ if (!ret) ++ *val = le64_to_cpu(*val); ++ ++ return ret; ++} ++ ++static int b53_spi_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val) ++{ ++ int ret = b53_spi_read(dev, page, reg, (u8 *)val, 8); ++ ++ if (!ret) ++ *val = le64_to_cpu(*val); ++ ++ return ret; ++} ++ ++static int b53_spi_write8(struct b53_device *dev, u8 page, u8 reg, u8 value) ++{ ++ struct spi_device *spi = dev->priv; ++ int ret; ++ u8 txbuf[3]; ++ ++ ret = b53_prepare_reg_access(spi, page); ++ if (ret) ++ return ret; ++ ++ txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE; ++ txbuf[1] = reg; ++ txbuf[2] = value; ++ ++ return spi_write(spi, txbuf, sizeof(txbuf)); ++} ++ ++static int b53_spi_write16(struct b53_device *dev, u8 page, u8 reg, u16 value) ++{ ++ struct spi_device *spi = dev->priv; ++ int ret; ++ u8 txbuf[4]; ++ ++ ret = b53_prepare_reg_access(spi, page); ++ if (ret) ++ return ret; ++ ++ txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE; ++ txbuf[1] = reg; ++ put_unaligned_le16(value, &txbuf[2]); ++ ++ return spi_write(spi, txbuf, sizeof(txbuf)); ++} ++ ++static int b53_spi_write32(struct b53_device *dev, u8 page, u8 reg, u32 value) ++{ ++ struct spi_device *spi = dev->priv; ++ int ret; ++ u8 txbuf[6]; ++ ++ ret = b53_prepare_reg_access(spi, page); ++ if (ret) ++ return ret; ++ ++ txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE; ++ txbuf[1] = reg; ++ put_unaligned_le32(value, &txbuf[2]); ++ ++ return spi_write(spi, txbuf, sizeof(txbuf)); ++} ++ ++static int b53_spi_write48(struct b53_device *dev, u8 page, u8 reg, u64 value) ++{ ++ struct spi_device *spi = dev->priv; ++ int ret; ++ u8 txbuf[10]; ++ ++ ret = b53_prepare_reg_access(spi, page); ++ if (ret) ++ return ret; ++ ++ txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE; ++ txbuf[1] = reg; ++ put_unaligned_le64(value, &txbuf[2]); ++ ++ return spi_write(spi, txbuf, sizeof(txbuf) - 2); ++} ++ ++static int b53_spi_write64(struct b53_device *dev, u8 page, u8 reg, u64 value) ++{ ++ struct spi_device *spi = dev->priv; ++ int ret; ++ u8 txbuf[10]; ++ ++ ret = b53_prepare_reg_access(spi, page); ++ if (ret) ++ return ret; ++ ++ txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE; ++ txbuf[1] = reg; ++ put_unaligned_le64(value, &txbuf[2]); ++ ++ return spi_write(spi, txbuf, sizeof(txbuf)); ++} ++ ++static struct b53_io_ops b53_spi_ops = { ++ .read8 = b53_spi_read8, ++ .read16 = b53_spi_read16, ++ .read32 = b53_spi_read32, ++ .read48 = b53_spi_read48, ++ .read64 = b53_spi_read64, ++ .write8 = b53_spi_write8, ++ .write16 = b53_spi_write16, ++ .write32 = b53_spi_write32, ++ .write48 = b53_spi_write48, ++ .write64 = b53_spi_write64, ++}; ++ ++static int b53_spi_probe(struct spi_device *spi) ++{ ++ struct b53_device *dev; ++ int ret; ++ ++ dev = b53_swconfig_switch_alloc(&spi->dev, &b53_spi_ops, spi); ++ if (!dev) ++ return -ENOMEM; ++ ++ if (spi->dev.platform_data) ++ dev->pdata = spi->dev.platform_data; ++ ++ ret = b53_swconfig_switch_register(dev); ++ if (ret) ++ return ret; ++ ++ spi_set_drvdata(spi, dev); ++ ++ return 0; ++} ++ ++static int b53_spi_remove(struct spi_device *spi) ++{ ++ struct b53_device *dev = spi_get_drvdata(spi); ++ ++ if (dev) ++ b53_switch_remove(dev); ++ ++ return 0; ++} ++ ++static const struct of_device_id b53_of_match[] = { ++ { .compatible = "brcm,bcm5325" }, ++ { .compatible = "brcm,bcm53115" }, ++ { .compatible = "brcm,bcm53125" }, ++ { .compatible = "brcm,bcm53128" }, ++ { .compatible = "brcm,bcm5365" }, ++ { .compatible = "brcm,bcm5395" }, ++ { .compatible = "brcm,bcm5397" }, ++ { .compatible = "brcm,bcm5398" }, ++ { /* sentinel */ }, ++}; ++ ++static struct spi_driver b53_spi_driver = { ++ .driver = { ++ .name = "b53-switch", ++ .bus = &spi_bus_type, ++ .owner = THIS_MODULE, ++ .of_match_table = b53_of_match, ++ }, ++ .probe = b53_spi_probe, ++ .remove = b53_spi_remove, ++}; ++ ++module_spi_driver(b53_spi_driver); ++ ++MODULE_AUTHOR("Jonas Gorski "); ++MODULE_DESCRIPTION("B53 SPI access driver"); ++MODULE_LICENSE("Dual BSD/GPL"); +diff --git a/drivers/net/phy/b53/b53_srab.c b/drivers/net/phy/b53/b53_srab.c +new file mode 100644 +index 000000000000..f8cb99383ff1 +--- /dev/null ++++ b/drivers/net/phy/b53/b53_srab.c +@@ -0,0 +1,376 @@ ++/* ++ * B53 register access through Switch Register Access Bridge Registers ++ * ++ * Copyright (C) 2013 Hauke Mehrtens ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "b53_priv.h" ++ ++/* command and status register of the SRAB */ ++#define B53_SRAB_CMDSTAT 0x2c ++#define B53_SRAB_CMDSTAT_RST BIT(2) ++#define B53_SRAB_CMDSTAT_WRITE BIT(1) ++#define B53_SRAB_CMDSTAT_GORDYN BIT(0) ++#define B53_SRAB_CMDSTAT_PAGE 24 ++#define B53_SRAB_CMDSTAT_REG 16 ++ ++/* high order word of write data to switch registe */ ++#define B53_SRAB_WD_H 0x30 ++ ++/* low order word of write data to switch registe */ ++#define B53_SRAB_WD_L 0x34 ++ ++/* high order word of read data from switch register */ ++#define B53_SRAB_RD_H 0x38 ++ ++/* low order word of read data from switch register */ ++#define B53_SRAB_RD_L 0x3c ++ ++/* command and status register of the SRAB */ ++#define B53_SRAB_CTRLS 0x40 ++#define B53_SRAB_CTRLS_RCAREQ BIT(3) ++#define B53_SRAB_CTRLS_RCAGNT BIT(4) ++#define B53_SRAB_CTRLS_SW_INIT_DONE BIT(6) ++ ++/* the register captures interrupt pulses from the switch */ ++#define B53_SRAB_INTR 0x44 ++ ++static int b53_srab_request_grant(struct b53_device *dev) ++{ ++ u8 __iomem *regs = dev->priv; ++ u32 ctrls; ++ int i; ++ ++ ctrls = readl(regs + B53_SRAB_CTRLS); ++ ctrls |= B53_SRAB_CTRLS_RCAREQ; ++ writel(ctrls, regs + B53_SRAB_CTRLS); ++ ++ for (i = 0; i < 20; i++) { ++ ctrls = readl(regs + B53_SRAB_CTRLS); ++ if (ctrls & B53_SRAB_CTRLS_RCAGNT) ++ break; ++ usleep_range(10, 100); ++ } ++ if (WARN_ON(i == 5)) ++ return -EIO; ++ ++ return 0; ++} ++ ++static void b53_srab_release_grant(struct b53_device *dev) ++{ ++ u8 __iomem *regs = dev->priv; ++ u32 ctrls; ++ ++ ctrls = readl(regs + B53_SRAB_CTRLS); ++ ctrls &= ~B53_SRAB_CTRLS_RCAREQ; ++ writel(ctrls, regs + B53_SRAB_CTRLS); ++} ++ ++static int b53_srab_op(struct b53_device *dev, u8 page, u8 reg, u32 op) ++{ ++ int i; ++ u32 cmdstat; ++ u8 __iomem *regs = dev->priv; ++ ++ /* set register address */ ++ cmdstat = (page << B53_SRAB_CMDSTAT_PAGE) | ++ (reg << B53_SRAB_CMDSTAT_REG) | ++ B53_SRAB_CMDSTAT_GORDYN | ++ op; ++ writel(cmdstat, regs + B53_SRAB_CMDSTAT); ++ ++ /* check if operation completed */ ++ for (i = 0; i < 5; ++i) { ++ cmdstat = readl(regs + B53_SRAB_CMDSTAT); ++ if (!(cmdstat & B53_SRAB_CMDSTAT_GORDYN)) ++ break; ++ usleep_range(10, 100); ++ } ++ ++ if (WARN_ON(i == 5)) ++ return -EIO; ++ ++ return 0; ++} ++ ++static int b53_srab_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val) ++{ ++ u8 __iomem *regs = dev->priv; ++ int ret = 0; ++ ++ ret = b53_srab_request_grant(dev); ++ if (ret) ++ goto err; ++ ++ ret = b53_srab_op(dev, page, reg, 0); ++ if (ret) ++ goto err; ++ ++ *val = readl(regs + B53_SRAB_RD_L) & 0xff; ++ ++err: ++ b53_srab_release_grant(dev); ++ ++ return ret; ++} ++ ++static int b53_srab_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val) ++{ ++ u8 __iomem *regs = dev->priv; ++ int ret = 0; ++ ++ ret = b53_srab_request_grant(dev); ++ if (ret) ++ goto err; ++ ++ ret = b53_srab_op(dev, page, reg, 0); ++ if (ret) ++ goto err; ++ ++ *val = readl(regs + B53_SRAB_RD_L) & 0xffff; ++ ++err: ++ b53_srab_release_grant(dev); ++ ++ return ret; ++} ++ ++static int b53_srab_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val) ++{ ++ u8 __iomem *regs = dev->priv; ++ int ret = 0; ++ ++ ret = b53_srab_request_grant(dev); ++ if (ret) ++ goto err; ++ ++ ret = b53_srab_op(dev, page, reg, 0); ++ if (ret) ++ goto err; ++ ++ *val = readl(regs + B53_SRAB_RD_L); ++ ++err: ++ b53_srab_release_grant(dev); ++ ++ return ret; ++} ++ ++static int b53_srab_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val) ++{ ++ u8 __iomem *regs = dev->priv; ++ int ret = 0; ++ ++ ret = b53_srab_request_grant(dev); ++ if (ret) ++ goto err; ++ ++ ret = b53_srab_op(dev, page, reg, 0); ++ if (ret) ++ goto err; ++ ++ *val = readl(regs + B53_SRAB_RD_L); ++ *val += ((u64)readl(regs + B53_SRAB_RD_H) & 0xffff) << 32; ++ ++err: ++ b53_srab_release_grant(dev); ++ ++ return ret; ++} ++ ++static int b53_srab_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val) ++{ ++ u8 __iomem *regs = dev->priv; ++ int ret = 0; ++ ++ ret = b53_srab_request_grant(dev); ++ if (ret) ++ goto err; ++ ++ ret = b53_srab_op(dev, page, reg, 0); ++ if (ret) ++ goto err; ++ ++ *val = readl(regs + B53_SRAB_RD_L); ++ *val += (u64)readl(regs + B53_SRAB_RD_H) << 32; ++ ++err: ++ b53_srab_release_grant(dev); ++ ++ return ret; ++} ++ ++static int b53_srab_write8(struct b53_device *dev, u8 page, u8 reg, u8 value) ++{ ++ u8 __iomem *regs = dev->priv; ++ int ret = 0; ++ ++ ret = b53_srab_request_grant(dev); ++ if (ret) ++ goto err; ++ ++ writel(value, regs + B53_SRAB_WD_L); ++ ++ ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE); ++ ++err: ++ b53_srab_release_grant(dev); ++ ++ return ret; ++} ++ ++static int b53_srab_write16(struct b53_device *dev, u8 page, u8 reg, ++ u16 value) ++{ ++ u8 __iomem *regs = dev->priv; ++ int ret = 0; ++ ++ ret = b53_srab_request_grant(dev); ++ if (ret) ++ goto err; ++ ++ writel(value, regs + B53_SRAB_WD_L); ++ ++ ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE); ++ ++err: ++ b53_srab_release_grant(dev); ++ ++ return ret; ++} ++ ++static int b53_srab_write32(struct b53_device *dev, u8 page, u8 reg, ++ u32 value) ++{ ++ u8 __iomem *regs = dev->priv; ++ int ret = 0; ++ ++ ret = b53_srab_request_grant(dev); ++ if (ret) ++ goto err; ++ ++ writel(value, regs + B53_SRAB_WD_L); ++ ++ ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE); ++ ++err: ++ b53_srab_release_grant(dev); ++ ++ return ret; ++ ++} ++ ++static int b53_srab_write48(struct b53_device *dev, u8 page, u8 reg, ++ u64 value) ++{ ++ u8 __iomem *regs = dev->priv; ++ int ret = 0; ++ ++ ret = b53_srab_request_grant(dev); ++ if (ret) ++ goto err; ++ ++ writel((u32)value, regs + B53_SRAB_WD_L); ++ writel((u16)(value >> 32), regs + B53_SRAB_WD_H); ++ ++ ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE); ++ ++err: ++ b53_srab_release_grant(dev); ++ ++ return ret; ++ ++} ++ ++static int b53_srab_write64(struct b53_device *dev, u8 page, u8 reg, ++ u64 value) ++{ ++ u8 __iomem *regs = dev->priv; ++ int ret = 0; ++ ++ ret = b53_srab_request_grant(dev); ++ if (ret) ++ goto err; ++ ++ writel((u32)value, regs + B53_SRAB_WD_L); ++ writel((u32)(value >> 32), regs + B53_SRAB_WD_H); ++ ++ ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE); ++ ++err: ++ b53_srab_release_grant(dev); ++ ++ return ret; ++} ++ ++static struct b53_io_ops b53_srab_ops = { ++ .read8 = b53_srab_read8, ++ .read16 = b53_srab_read16, ++ .read32 = b53_srab_read32, ++ .read48 = b53_srab_read48, ++ .read64 = b53_srab_read64, ++ .write8 = b53_srab_write8, ++ .write16 = b53_srab_write16, ++ .write32 = b53_srab_write32, ++ .write48 = b53_srab_write48, ++ .write64 = b53_srab_write64, ++}; ++ ++static int b53_srab_probe(struct platform_device *pdev) ++{ ++ struct b53_platform_data *pdata = pdev->dev.platform_data; ++ struct b53_device *dev; ++ ++ if (!pdata) ++ return -EINVAL; ++ ++ dev = b53_swconfig_switch_alloc(&pdev->dev, &b53_srab_ops, pdata->regs); ++ if (!dev) ++ return -ENOMEM; ++ ++ if (pdata) ++ dev->pdata = pdata; ++ ++ platform_set_drvdata(pdev, dev); ++ ++ return b53_swconfig_switch_register(dev); ++} ++ ++static void b53_srab_remove(struct platform_device *pdev) ++{ ++ struct b53_device *dev = platform_get_drvdata(pdev); ++ ++ if (dev) ++ b53_switch_remove(dev); ++} ++ ++static struct platform_driver b53_srab_driver = { ++ .probe = b53_srab_probe, ++ .remove_new = b53_srab_remove, ++ .driver = { ++ .name = "b53-srab-switch", ++ }, ++}; ++ ++module_platform_driver(b53_srab_driver); ++MODULE_AUTHOR("Hauke Mehrtens "); ++MODULE_DESCRIPTION("B53 Switch Register Access Bridge Registers (SRAB) access driver"); ++MODULE_LICENSE("Dual BSD/GPL"); +diff --git a/drivers/net/phy/en8801sc.c b/drivers/net/phy/en8801sc.c +new file mode 100644 +index 000000000000..08774e3b8889 +--- /dev/null ++++ b/drivers/net/phy/en8801sc.c +@@ -0,0 +1,1117 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* FILE NAME: en8801sc.c ++ * PURPOSE: ++ * EN8801SC phy driver for Linux ++ * NOTES: ++ * ++ */ ++ ++/* INCLUDE FILE DECLARATIONS ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include "en8801sc.h" ++ ++MODULE_DESCRIPTION("Airoha EN8801S PHY drivers for MediaTek SoC"); ++MODULE_AUTHOR("Airoha"); ++MODULE_LICENSE("GPL"); ++ ++#define airoha_mdio_lock(bus) mutex_lock(&((bus)->mdio_lock)) ++#define airoha_mdio_unlock(bus) mutex_unlock(&((bus)->mdio_lock)) ++ ++#define phydev_mdio_bus(_dev) (_dev->mdio.bus) ++#define phydev_phy_addr(_dev) (_dev->mdio.addr) ++#define phydev_dev(_dev) (&_dev->mdio.dev) ++#define phydev_pbus_addr(dev) ((dev)->mdio.addr + 1) ++ ++enum { ++ PHY_STATE_DONE = 0, ++ PHY_STATE_INIT = 1, ++ PHY_STATE_PROCESS = 2, ++ PHY_STATE_FAIL = 3, ++}; ++ ++struct en8801s_priv { ++ bool first_init; ++ u16 count; ++ u16 pro_version; ++}; ++ ++/* ++The following led_cfg example is for reference only. ++LED5 1000M/LINK/ACT (GPIO5) <-> BASE_T_LED0, ++LED6 10/100M/LINK/ACT (GPIO9) <-> BASE_T_LED1, ++LED4 100M/LINK/ACT (GPIO8) <-> BASE_T_LED2, ++*/ ++/* User-defined.B */ ++#define AIR_LED_SUPPORT ++#ifdef AIR_LED_SUPPORT ++static const struct AIR_BASE_T_LED_CFG_S led_cfg[4] = { ++/* ++* {LED Enable, GPIO, LED Polarity, LED ON, LED Blink} ++*/ ++ /* BASE-T LED0 */ ++ {LED_ENABLE, 5, AIR_ACTIVE_LOW, ++ BASE_T_LED0_ON_CFG, BASE_T_LED0_BLK_CFG}, ++ /* BASE-T LED1 */ ++ {LED_ENABLE, 9, AIR_ACTIVE_LOW, ++ BASE_T_LED1_ON_CFG, BASE_T_LED1_BLK_CFG}, ++ /* BASE-T LED2 */ ++ {LED_ENABLE, 8, AIR_ACTIVE_LOW, ++ BASE_T_LED2_ON_CFG, BASE_T_LED2_BLK_CFG}, ++ /* BASE-T LED3 */ ++ {LED_DISABLE, 1, AIR_ACTIVE_LOW, ++ BASE_T_LED3_ON_CFG, BASE_T_LED3_BLK_CFG}, ++}; ++static const u16 led_dur = UNIT_LED_BLINK_DURATION << AIR_LED_BLK_DUR_64M; ++#endif ++ ++/* User-defined.E */ ++ ++/************************************************************************ ++* F U N C T I O N S ++************************************************************************/ ++static int en8801s_phase2_init(struct phy_device *phydev); ++ ++static int __airoha_cl45_write(struct mii_bus *bus, int port, ++ u32 devad, u32 reg, u16 val) ++{ ++ int ret = 0; ++ struct device *dev = &bus->dev; ++ ++ ret = __mdiobus_write(bus, port, MII_MMD_ACC_CTL_REG, devad); ++ if (ret < 0) { ++ dev_err(dev, "%s fail. (ret=%d)\n", __func__, ret); ++ return ret; ++ } ++ ret = __mdiobus_write(bus, port, MII_MMD_ADDR_DATA_REG, reg); ++ if (ret < 0) { ++ dev_err(dev, "%s fail. (ret=%d)\n", __func__, ret); ++ return ret; ++ } ++ ret = __mdiobus_write(bus, port, MII_MMD_ACC_CTL_REG, ++ MMD_OP_MODE_DATA | devad); ++ if (ret < 0) { ++ dev_err(dev, "%s fail. (ret=%d)\n", __func__, ret); ++ return ret; ++ } ++ ret = __mdiobus_write(bus, port, MII_MMD_ADDR_DATA_REG, val); ++ if (ret < 0) { ++ dev_err(dev, "%s fail. (ret=%d)\n", __func__, ret); ++ return ret; ++ } ++ ++ return ret; ++} ++ ++static int __airoha_cl45_read(struct mii_bus *bus, int port, ++ u32 devad, u32 reg, u16 *read_data) ++{ ++ int ret = 0; ++ struct device *dev = &bus->dev; ++ ++ ret = __mdiobus_write(bus, port, MII_MMD_ACC_CTL_REG, devad); ++ if (ret < 0) { ++ dev_err(dev, "%s fail. (ret=%d)\n", __func__, ret); ++ return ret; ++ } ++ ret = __mdiobus_write(bus, port, MII_MMD_ADDR_DATA_REG, reg); ++ if (ret < 0) { ++ dev_err(dev, "%s fail. (ret=%d)\n", __func__, ret); ++ return ret; ++ } ++ ret = __mdiobus_write(bus, port, MII_MMD_ACC_CTL_REG, ++ MMD_OP_MODE_DATA | devad); ++ if (ret < 0) { ++ dev_err(dev, "%s fail. (ret=%d)\n", __func__, ret); ++ return ret; ++ } ++ *read_data = __mdiobus_read(bus, port, MII_MMD_ADDR_DATA_REG); ++ ++ return ret; ++} ++ ++static int airoha_cl45_write(struct mii_bus *bus, int port, ++ u32 devad, u32 reg, u16 val) ++{ ++ int ret = 0; ++ ++ airoha_mdio_lock(bus); ++ ret = __airoha_cl45_write(bus, port, devad, reg, val); ++ airoha_mdio_unlock(bus); ++ ++ return ret; ++} ++ ++static int airoha_cl45_read(struct mii_bus *bus, int port, ++ u32 devad, u32 reg, u16 *read_data) ++{ ++ int ret = 0; ++ ++ airoha_mdio_lock(bus); ++ ret = __airoha_cl45_read(bus, port, devad, reg, read_data); ++ airoha_mdio_unlock(bus); ++ ++ return ret; ++} ++ ++static int __airoha_pbus_write(struct mii_bus *ebus, int pbus_id, ++ unsigned long pbus_address, unsigned long pbus_data) ++{ ++ int ret = 0; ++ ++ ret = __mdiobus_write(ebus, pbus_id, 0x1F, ++ (unsigned int)(pbus_address >> 6)); ++ if (ret < 0) ++ return ret; ++ ret = __mdiobus_write(ebus, pbus_id, ++ (unsigned int)((pbus_address >> 2) & 0xf), ++ (unsigned int)(pbus_data & 0xFFFF)); ++ if (ret < 0) ++ return ret; ++ ret = __mdiobus_write(ebus, pbus_id, 0x10, ++ (unsigned int)(pbus_data >> 16)); ++ if (ret < 0) ++ return ret; ++ return ret; ++} ++ ++static unsigned long __airoha_pbus_read(struct mii_bus *ebus, int pbus_id, ++ unsigned long pbus_address) ++{ ++ unsigned long pbus_data; ++ unsigned int pbus_data_low, pbus_data_high; ++ int ret = 0; ++ struct device *dev = &ebus->dev; ++ ++ ret = __mdiobus_write(ebus, pbus_id, 0x1F, ++ (unsigned int)(pbus_address >> 6)); ++ if (ret < 0) { ++ dev_err(dev, "%s fail. (ret=%d)\n", __func__, ret); ++ return INVALID_DATA; ++ } ++ pbus_data_low = __mdiobus_read(ebus, pbus_id, ++ (unsigned int)((pbus_address >> 2) & 0xf)); ++ pbus_data_high = __mdiobus_read(ebus, pbus_id, 0x10); ++ pbus_data = (pbus_data_high << 16) + pbus_data_low; ++ return pbus_data; ++} ++ ++static int airoha_pbus_write(struct mii_bus *ebus, int pbus_id, ++ unsigned long pbus_address, unsigned long pbus_data) ++{ ++ int ret = 0; ++ ++ airoha_mdio_lock(ebus); ++ ret = __airoha_pbus_write(ebus, pbus_id, pbus_address, pbus_data); ++ airoha_mdio_unlock(ebus); ++ ++ return ret; ++} ++ ++static unsigned long airoha_pbus_read(struct mii_bus *ebus, int pbus_id, ++ unsigned long pbus_address) ++{ ++ unsigned long pbus_data; ++ ++ airoha_mdio_lock(ebus); ++ pbus_data = __airoha_pbus_read(ebus, pbus_id, pbus_address); ++ airoha_mdio_unlock(ebus); ++ ++ return pbus_data; ++} ++ ++/* Airoha Token Ring Write function */ ++static int airoha_tr_reg_write(struct phy_device *phydev, ++ unsigned long tr_address, unsigned long tr_data) ++{ ++ int ret = 0; ++ int phy_addr = phydev_phy_addr(phydev); ++ struct mii_bus *ebus = phydev_mdio_bus(phydev); ++ ++ airoha_mdio_lock(ebus); ++ ret = __mdiobus_write(ebus, phy_addr, 0x1F, 0x52b5); /* page select */ ++ ret = __mdiobus_write(ebus, phy_addr, 0x11, ++ (unsigned int)(tr_data & 0xffff)); ++ ret = __mdiobus_write(ebus, phy_addr, 0x12, ++ (unsigned int)(tr_data >> 16)); ++ ret = __mdiobus_write(ebus, phy_addr, 0x10, ++ (unsigned int)(tr_address | TrReg_WR)); ++ ret = __mdiobus_write(ebus, phy_addr, 0x1F, 0x0); /* page resetore */ ++ airoha_mdio_unlock(ebus); ++ ++ return ret; ++} ++ ++#ifdef AIR_LED_SUPPORT ++static int airoha_led_set_usr_def(struct phy_device *phydev, u8 entity, ++ int polar, u16 on_evt, u16 blk_evt) ++{ ++ int ret = 0; ++ int phy_addr = phydev_phy_addr(phydev); ++ struct mii_bus *mbus = phydev_mdio_bus(phydev); ++ ++ if (polar == AIR_ACTIVE_HIGH) ++ on_evt |= LED_ON_POL; ++ else ++ on_evt &= ~LED_ON_POL; ++ ++ ret = airoha_cl45_write(mbus, phy_addr, 0x1f, ++ LED_ON_CTRL(entity), on_evt | LED_ON_EN); ++ if (ret < 0) ++ return ret; ++ ++ ret = airoha_cl45_write(mbus, phy_addr, 0x1f, ++ LED_BLK_CTRL(entity), blk_evt); ++ if (ret < 0) ++ return ret; ++ ++ return 0; ++} ++ ++static int airoha_led_set_mode(struct phy_device *phydev, u8 mode) ++{ ++ u16 cl45_data; ++ int err = 0; ++ int phy_addr = phydev_phy_addr(phydev); ++ struct mii_bus *mbus = phydev_mdio_bus(phydev); ++ ++ err = airoha_cl45_read(mbus, phy_addr, 0x1f, LED_BCR, &cl45_data); ++ if (err < 0) ++ return err; ++ ++ switch (mode) { ++ case AIR_LED_MODE_DISABLE: ++ cl45_data &= ~LED_BCR_EXT_CTRL; ++ cl45_data &= ~LED_BCR_MODE_MASK; ++ cl45_data |= LED_BCR_MODE_DISABLE; ++ break; ++ case AIR_LED_MODE_USER_DEFINE: ++ cl45_data |= LED_BCR_EXT_CTRL; ++ cl45_data |= LED_BCR_CLK_EN; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ err = airoha_cl45_write(mbus, phy_addr, 0x1f, LED_BCR, cl45_data); ++ if (err < 0) ++ return err; ++ return 0; ++} ++ ++static int airoha_led_set_state(struct phy_device *phydev, u8 entity, u8 state) ++{ ++ u16 cl45_data; ++ int err; ++ int phy_addr = phydev_phy_addr(phydev); ++ struct mii_bus *mbus = phydev_mdio_bus(phydev); ++ ++ err = airoha_cl45_read(mbus, phy_addr, 0x1f, ++ LED_ON_CTRL(entity), &cl45_data); ++ if (err < 0) ++ return err; ++ if (state == LED_ENABLE) ++ cl45_data |= LED_ON_EN; ++ else ++ cl45_data &= ~LED_ON_EN; ++ ++ err = airoha_cl45_write(mbus, phy_addr, 0x1f, ++ LED_ON_CTRL(entity), cl45_data); ++ if (err < 0) ++ return err; ++ return 0; ++} ++ ++static int en8801s_led_init(struct phy_device *phydev) ++{ ++ ++ unsigned long led_gpio = 0, reg_value = 0; ++ int ret = 0, led_id; ++ struct mii_bus *mbus = phydev_mdio_bus(phydev); ++ int gpio_led_rg[3] = {0x1870, 0x1874, 0x1878}; ++ u16 cl45_data = led_dur; ++ struct device *dev = phydev_dev(phydev); ++ int phy_addr = phydev_phy_addr(phydev); ++ int pbus_addr = phydev_pbus_addr(phydev); ++ ++ ret = airoha_cl45_write(mbus, phy_addr, 0x1f, LED_BLK_DUR, cl45_data); ++ if (ret < 0) ++ return ret; ++ cl45_data >>= 1; ++ ret = airoha_cl45_write(mbus, phy_addr, 0x1f, LED_ON_DUR, cl45_data); ++ if (ret < 0) ++ return ret; ++ ret = airoha_led_set_mode(phydev, AIR_LED_MODE_USER_DEFINE); ++ if (ret != 0) { ++ dev_err(dev, "LED fail to set mode, ret %d !\n", ret); ++ return ret; ++ } ++ for (led_id = 0; led_id < EN8801S_LED_COUNT; led_id++) { ++ reg_value = 0; ++ ret = airoha_led_set_state(phydev, led_id, led_cfg[led_id].en); ++ if (ret != 0) { ++ dev_err(dev, "LED fail to set state, ret %d !\n", ret); ++ return ret; ++ } ++ if (led_cfg[led_id].en == LED_ENABLE) { ++ if ((led_cfg[led_id].gpio < 0) ++ || led_cfg[led_id].gpio > 9) { ++ dev_err(dev, "GPIO%d is out of range!! GPIO number is 0~9.\n", ++ led_cfg[led_id].gpio); ++ return -EIO; ++ } ++ led_gpio |= BIT(led_cfg[led_id].gpio); ++ reg_value = airoha_pbus_read(mbus, pbus_addr, ++ gpio_led_rg[led_cfg[led_id].gpio / 4]); ++ LED_SET_GPIO_SEL(led_cfg[led_id].gpio, ++ led_id, reg_value); ++ dev_dbg(dev, "[Airoha] gpio%d, reg_value 0x%lx\n", ++ led_cfg[led_id].gpio, reg_value); ++ ret = airoha_pbus_write(mbus, pbus_addr, ++ gpio_led_rg[led_cfg[led_id].gpio / 4], ++ reg_value); ++ if (ret < 0) ++ return ret; ++ ret = airoha_led_set_usr_def(phydev, led_id, ++ led_cfg[led_id].pol, ++ led_cfg[led_id].on_cfg, ++ led_cfg[led_id].blk_cfg); ++ if (ret != 0) { ++ dev_err(dev, "LED fail to set usr def, ret %d !\n", ++ ret); ++ return ret; ++ } ++ } ++ } ++ reg_value = (airoha_pbus_read(mbus, pbus_addr, 0x1880) & ~led_gpio); ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x1880, reg_value); ++ if (ret < 0) ++ return ret; ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x186c, led_gpio); ++ if (ret < 0) ++ return ret; ++ dev_info(dev, "LED initialize OK !\n"); ++ return 0; ++} ++#endif ++static int en8801s_phy_process(struct phy_device *phydev) ++{ ++ struct mii_bus *mbus = phydev_mdio_bus(phydev); ++ unsigned long reg_value = 0; ++ int ret = 0; ++ int pbus_addr = phydev_pbus_addr(phydev); ++ ++ reg_value = airoha_pbus_read(mbus, pbus_addr, 0x19e0); ++ reg_value |= BIT(0); ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x19e0, reg_value); ++ if (ret < 0) ++ return ret; ++ reg_value = airoha_pbus_read(mbus, pbus_addr, 0x19e0); ++ reg_value &= ~BIT(0); ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x19e0, reg_value); ++ if (ret < 0) ++ return ret; ++ return ret; ++} ++ ++static int en8801s_phase1_init(struct phy_device *phydev) ++{ ++ unsigned long pbus_data; ++ int pbus_addr = EN8801S_PBUS_DEFAULT_ADDR; ++ u16 reg_value; ++ int retry, ret = 0; ++ struct mii_bus *mbus = phydev_mdio_bus(phydev); ++ struct device *dev = phydev_dev(phydev); ++ struct en8801s_priv *priv = phydev->priv; ++ ++ priv->count = 1; ++ msleep(1000); ++ ++ retry = MAX_OUI_CHECK; ++ while (1) { ++ pbus_data = airoha_pbus_read(mbus, pbus_addr, ++ EN8801S_RG_ETHER_PHY_OUI); /* PHY OUI */ ++ if (pbus_data == EN8801S_PBUS_OUI) { ++ dev_info(dev, "PBUS addr 0x%x: Start initialized.\n", ++ pbus_addr); ++ break; ++ } ++ pbus_addr = phydev_pbus_addr(phydev); ++ if (0 == --retry) { ++ dev_err(dev, "Probe fail !\n"); ++ return 0; ++ } ++ } ++ ++ ret = airoha_pbus_write(mbus, pbus_addr, EN8801S_RG_BUCK_CTL, 0x03); ++ if (ret < 0) ++ return ret; ++ pbus_data = airoha_pbus_read(mbus, pbus_addr, EN8801S_RG_PROD_VER); ++ priv->pro_version = pbus_data & 0xf; ++ dev_info(dev, "EN8801S Procduct Version :E%d\n", priv->pro_version); ++ mdelay(10); ++ pbus_data = (airoha_pbus_read(mbus, pbus_addr, EN8801S_RG_LTR_CTL) ++ & 0xfffffffc) | BIT(2); ++ ret = airoha_pbus_write(mbus, pbus_addr, ++ EN8801S_RG_LTR_CTL, pbus_data); ++ if (ret < 0) ++ return ret; ++ mdelay(500); ++ pbus_data = (pbus_data & ~BIT(2)) | ++ EN8801S_RX_POLARITY_NORMAL | ++ EN8801S_TX_POLARITY_NORMAL; ++ ret = airoha_pbus_write(mbus, pbus_addr, ++ EN8801S_RG_LTR_CTL, pbus_data); ++ if (ret < 0) ++ return ret; ++ mdelay(500); ++ if (priv->pro_version == 4) { ++ pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1900); ++ dev_dbg(dev, "Before 0x1900 0x%lx\n", pbus_data); ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x1900, 0x101009f); ++ if (ret < 0) ++ return ret; ++ pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1900); ++ dev_dbg(dev, "After 0x1900 0x%lx\n", pbus_data); ++ pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x19a8); ++ dev_dbg(dev, "Before 19a8 0x%lx\n", pbus_data); ++ ret = airoha_pbus_write(mbus, pbus_addr, ++ 0x19a8, pbus_data & ~BIT(16)); ++ if (ret < 0) ++ return ret; ++ pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x19a8); ++ dev_dbg(dev, "After 19a8 0x%lx\n", pbus_data); ++ } ++ pbus_data = airoha_pbus_read(mbus, pbus_addr, ++ EN8801S_RG_SMI_ADDR); /* SMI ADDR */ ++ pbus_data = (pbus_data & 0xffff0000) | ++ (unsigned long)(phydev_pbus_addr(phydev) << 8) | ++ (unsigned long)(phydev_phy_addr(phydev)); ++ dev_info(phydev_dev(phydev), "SMI_ADDR=%lx (renew)\n", pbus_data); ++ ret = airoha_pbus_write(mbus, pbus_addr, ++ EN8801S_RG_SMI_ADDR, pbus_data); ++ mdelay(10); ++ ++ retry = MAX_RETRY; ++ while (1) { ++ mdelay(10); ++ reg_value = phy_read(phydev, MII_PHYSID2); ++ if (reg_value == EN8801S_PHY_ID2) ++ break; /* wait GPHY ready */ ++ ++ retry--; ++ if (retry == 0) { ++ dev_err(dev, "Initialize fail !\n"); ++ return 0; ++ } ++ } ++ /* Software Reset PHY */ ++ reg_value = phy_read(phydev, MII_BMCR); ++ reg_value |= BMCR_RESET; ++ ret = phy_write(phydev, MII_BMCR, reg_value); ++ if (ret < 0) ++ return ret; ++ retry = MAX_RETRY; ++ do { ++ mdelay(10); ++ reg_value = phy_read(phydev, MII_BMCR); ++ retry--; ++ if (retry == 0) { ++ dev_err(dev, "Reset fail !\n"); ++ return 0; ++ } ++ } while (reg_value & BMCR_RESET); ++ ++ phydev->dev_flags = PHY_STATE_INIT; ++ ++ dev_info(dev, "Phase1 initialize OK ! (%s)\n", EN8801S_DRIVER_VERSION); ++ if (priv->pro_version == 4) { ++ ret = en8801s_phase2_init(phydev); ++ if (ret != 0) { ++ dev_info(dev, "en8801_phase2_init failed\n"); ++ phydev->dev_flags = PHY_STATE_FAIL; ++ return 0; ++ } ++ phydev->dev_flags = PHY_STATE_PROCESS; ++ } ++ ++ return 0; ++} ++ ++static int en8801s_phase2_init(struct phy_device *phydev) ++{ ++ union gephy_all_REG_LpiReg1Ch GPHY_RG_LPI_1C; ++ union gephy_all_REG_dev1Eh_reg324h GPHY_RG_1E_324; ++ union gephy_all_REG_dev1Eh_reg012h GPHY_RG_1E_012; ++ union gephy_all_REG_dev1Eh_reg017h GPHY_RG_1E_017; ++ unsigned long pbus_data; ++ int phy_addr = phydev_phy_addr(phydev); ++ int pbus_addr = phydev_pbus_addr(phydev); ++ u16 cl45_value; ++ int retry, ret = 0; ++ struct mii_bus *mbus = phydev_mdio_bus(phydev); ++ struct device *dev = phydev_dev(phydev); ++ struct en8801s_priv *priv = phydev->priv; ++ ++ pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1690); ++ pbus_data |= BIT(31); ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x1690, pbus_data); ++ if (ret < 0) ++ return ret; ++ ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x0600, 0x0c000c00); ++ if (ret < 0) ++ return ret; ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x10, 0xD801); ++ if (ret < 0) ++ return ret; ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x0, 0x9140); ++ if (ret < 0) ++ return ret; ++ ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x0A14, 0x0003); ++ if (ret < 0) ++ return ret; ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x0600, 0x0c000c00); ++ if (ret < 0) ++ return ret; ++ /* Set FCM control */ ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x1404, 0x004b); ++ if (ret < 0) ++ return ret; ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x140c, 0x0007); ++ if (ret < 0) ++ return ret; ++ ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x142c, 0x05050505); ++ if (ret < 0) ++ return ret; ++ pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1440); ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x1440, pbus_data & ~BIT(11)); ++ if (ret < 0) ++ return ret; ++ ++ pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1408); ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x1408, pbus_data | BIT(5)); ++ if (ret < 0) ++ return ret; ++ ++ /* Set GPHY Perfomance*/ ++ /* Token Ring */ ++ ret = airoha_tr_reg_write(phydev, RgAddr_R1000DEC_15h, 0x0055A0); ++ if (ret < 0) ++ return ret; ++ ret = airoha_tr_reg_write(phydev, RgAddr_R1000DEC_17h, 0x07FF3F); ++ if (ret < 0) ++ return ret; ++ ret = airoha_tr_reg_write(phydev, RgAddr_PMA_00h, 0x00001E); ++ if (ret < 0) ++ return ret; ++ ret = airoha_tr_reg_write(phydev, RgAddr_PMA_01h, 0x6FB90A); ++ if (ret < 0) ++ return ret; ++ ret = airoha_tr_reg_write(phydev, RgAddr_PMA_17h, 0x060671); ++ if (ret < 0) ++ return ret; ++ ret = airoha_tr_reg_write(phydev, RgAddr_PMA_18h, 0x0E2F00); ++ if (ret < 0) ++ return ret; ++ ret = airoha_tr_reg_write(phydev, RgAddr_TR_26h, 0x444444); ++ if (ret < 0) ++ return ret; ++ ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_03h, 0x000000); ++ if (ret < 0) ++ return ret; ++ ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_06h, 0x2EBAEF); ++ if (ret < 0) ++ return ret; ++ ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_08h, 0x00000B); ++ if (ret < 0) ++ return ret; ++ ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_0Ch, 0x00504D); ++ if (ret < 0) ++ return ret; ++ ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_0Dh, 0x02314F); ++ if (ret < 0) ++ return ret; ++ ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_0Fh, 0x003028); ++ if (ret < 0) ++ return ret; ++ ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_10h, 0x005010); ++ if (ret < 0) ++ return ret; ++ ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_11h, 0x040001); ++ if (ret < 0) ++ return ret; ++ ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_13h, 0x018670); ++ if (ret < 0) ++ return ret; ++ ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_14h, 0x00024A); ++ if (ret < 0) ++ return ret; ++ ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_1Bh, 0x000072); ++ if (ret < 0) ++ return ret; ++ ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_1Ch, 0x003210); ++ if (ret < 0) ++ return ret; ++ ++ /* CL22 & CL45 */ ++ ret = phy_write(phydev, 0x1f, 0x03); ++ if (ret < 0) ++ return ret; ++ GPHY_RG_LPI_1C.DATA = phy_read(phydev, RgAddr_LPI_1Ch); ++ GPHY_RG_LPI_1C.DataBitField.smi_deton_th = 0x0C; ++ ret = phy_write(phydev, RgAddr_LPI_1Ch, GPHY_RG_LPI_1C.DATA); ++ if (ret < 0) ++ return ret; ++ ret = phy_write(phydev, RgAddr_LPI_1Ch, 0xC92); ++ if (ret < 0) ++ return ret; ++ ret = phy_write(phydev, RgAddr_AUXILIARY_1Dh, 0x1); ++ if (ret < 0) ++ return ret; ++ ret = phy_write(phydev, 0x1f, 0x0); ++ if (ret < 0) ++ return ret; ++ ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x120, 0x8014); ++ if (ret < 0) ++ return ret; ++ ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x122, 0xffff); ++ if (ret < 0) ++ return ret; ++ ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x123, 0xffff); ++ if (ret < 0) ++ return ret; ++ ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x144, 0x0200); ++ if (ret < 0) ++ return ret; ++ ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x14A, 0xEE20); ++ if (ret < 0) ++ return ret; ++ ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x189, 0x0110); ++ if (ret < 0) ++ return ret; ++ ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x19B, 0x0111); ++ if (ret < 0) ++ return ret; ++ ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x234, 0x0181); ++ if (ret < 0) ++ return ret; ++ ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x238, 0x0120); ++ if (ret < 0) ++ return ret; ++ ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x239, 0x0117); ++ if (ret < 0) ++ return ret; ++ ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x268, 0x07F4); ++ if (ret < 0) ++ return ret; ++ ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x2D1, 0x0733); ++ if (ret < 0) ++ return ret; ++ ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x323, 0x0011); ++ if (ret < 0) ++ return ret; ++ ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x324, 0x013F); ++ if (ret < 0) ++ return ret; ++ ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x326, 0x0037); ++ if (ret < 0) ++ return ret; ++ ++ ret = airoha_cl45_read(mbus, phy_addr, 0x1E, 0x324, &cl45_value); ++ if (ret < 0) ++ return ret; ++ GPHY_RG_1E_324.DATA = cl45_value; ++ GPHY_RG_1E_324.DataBitField.smi_det_deglitch_off = 0; ++ ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x324, ++ GPHY_RG_1E_324.DATA); ++ if (ret < 0) ++ return ret; ++ ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x19E, 0xC2); ++ if (ret < 0) ++ return ret; ++ ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x013, 0x0); ++ if (ret < 0) ++ return ret; ++ ++ /* EFUSE */ ++ airoha_pbus_write(mbus, pbus_addr, 0x1C08, 0x40000040); ++ retry = MAX_RETRY; ++ while (retry != 0) { ++ mdelay(1); ++ pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1C08); ++ if ((pbus_data & BIT(30)) == 0) ++ break; ++ ++ retry--; ++ } ++ pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1C38); /* RAW#2 */ ++ ret = airoha_cl45_read(mbus, phy_addr, 0x1E, 0x12, &cl45_value); ++ if (ret < 0) ++ return ret; ++ GPHY_RG_1E_012.DATA = cl45_value; ++ GPHY_RG_1E_012.DataBitField.da_tx_i2mpb_a_tbt = ++ (u16)(pbus_data & 0x03f); ++ ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x12, ++ GPHY_RG_1E_012.DATA); ++ if (ret < 0) ++ return ret; ++ ret = airoha_cl45_read(mbus, phy_addr, 0x1E, 0x17, &cl45_value); ++ if (ret < 0) ++ return ret; ++ GPHY_RG_1E_017.DATA = cl45_value; ++ GPHY_RG_1E_017.DataBitField.da_tx_i2mpb_b_tbt = ++ (u16)((pbus_data >> 8) & 0x03f); ++ ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x17, ++ GPHY_RG_1E_017.DATA); ++ if (ret < 0) ++ return ret; ++ ++ airoha_pbus_write(mbus, pbus_addr, 0x1C08, 0x40400040); ++ retry = MAX_RETRY; ++ while (retry != 0) { ++ mdelay(1); ++ pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1C08); ++ if ((pbus_data & BIT(30)) == 0) ++ break; ++ ++ retry--; ++ } ++ pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1C30); /* RAW#16 */ ++ GPHY_RG_1E_324.DataBitField.smi_det_deglitch_off = ++ (u16)((pbus_data >> 12) & 0x01); ++ ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x324, ++ GPHY_RG_1E_324.DATA); ++ if (ret < 0) ++ return ret; ++#ifdef AIR_LED_SUPPORT ++ ret = en8801s_led_init(phydev); ++ if (ret != 0) ++ dev_err(dev, "en8801s_led_init fail (ret:%d) !\n", ret); ++#endif ++ ++ ret = airoha_cl45_read(mbus, phy_addr, MDIO_MMD_AN, ++ MDIO_AN_EEE_ADV, &cl45_value); ++ if (ret < 0) ++ return ret; ++ if (cl45_value == 0) { ++ pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1960); ++ if (0xA == ((pbus_data & 0x07c00000) >> 22)) { ++ pbus_data = (pbus_data & 0xf83fffff) | (0xC << 22); ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x1960, ++ pbus_data); ++ if (ret < 0) ++ return ret; ++ mdelay(10); ++ pbus_data = (pbus_data & 0xf83fffff) | (0xE << 22); ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x1960, ++ pbus_data); ++ if (ret < 0) ++ return ret; ++ mdelay(10); ++ } ++ } else { ++ pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1960); ++ if (0xE == ((pbus_data & 0x07c00000) >> 22)) { ++ pbus_data = (pbus_data & 0xf83fffff) | (0xC << 22); ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x1960, ++ pbus_data); ++ if (ret < 0) ++ return ret; ++ mdelay(10); ++ pbus_data = (pbus_data & 0xf83fffff) | (0xA << 22); ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x1960, ++ pbus_data); ++ if (ret < 0) ++ return ret; ++ mdelay(10); ++ } ++ } ++ ++ priv->first_init = false; ++ dev_info(phydev_dev(phydev), "Phase2 initialize OK !\n"); ++ return 0; ++} ++ ++static int en8801s_read_status(struct phy_device *phydev) ++{ ++ int ret = 0, preSpeed = phydev->speed; ++ struct mii_bus *mbus = phydev_mdio_bus(phydev); ++ u32 reg_value; ++ struct device *dev = phydev_dev(phydev); ++ int pbus_addr = phydev_pbus_addr(phydev); ++ struct en8801s_priv *priv = phydev->priv; ++ ++ ret = genphy_read_status(phydev); ++ if (phydev->link == LINK_DOWN) ++ preSpeed = phydev->speed = 0; ++ ++ if (phydev->dev_flags == PHY_STATE_PROCESS) { ++ en8801s_phy_process(phydev); ++ phydev->dev_flags = PHY_STATE_DONE; ++ } ++ ++ if (phydev->dev_flags == PHY_STATE_INIT) { ++ dev_dbg(dev, "phydev->link %d, count %d\n", ++ phydev->link, priv->count); ++ if ((phydev->link) || (priv->count == 5)) { ++ if (priv->pro_version != 4) { ++ ret = en8801s_phase2_init(phydev); ++ if (ret != 0) { ++ dev_info(dev, "en8801_phase2_init failed\n"); ++ phydev->dev_flags = PHY_STATE_FAIL; ++ return 0; ++ } ++ phydev->dev_flags = PHY_STATE_PROCESS; ++ } ++ } ++ priv->count++; ++ } ++ ++ if ((preSpeed != phydev->speed) && (phydev->link == LINK_UP)) { ++ preSpeed = phydev->speed; ++ ++ if (preSpeed == SPEED_10) { ++ reg_value = airoha_pbus_read(mbus, pbus_addr, 0x1694); ++ reg_value |= BIT(31); ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x1694, ++ reg_value); ++ if (ret < 0) ++ return ret; ++ phydev->dev_flags = PHY_STATE_PROCESS; ++ } else { ++ reg_value = airoha_pbus_read(mbus, pbus_addr, 0x1694); ++ reg_value &= ~BIT(31); ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x1694, ++ reg_value); ++ if (ret < 0) ++ return ret; ++ phydev->dev_flags = PHY_STATE_PROCESS; ++ } ++ ++ airoha_pbus_write(mbus, pbus_addr, 0x0600, ++ 0x0c000c00); ++ if (preSpeed == SPEED_1000) { ++ dev_dbg(dev, "SPEED_1000\n"); ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x10, ++ 0xD801); ++ if (ret < 0) ++ return ret; ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x0, ++ 0x9140); ++ if (ret < 0) ++ return ret; ++ ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x0A14, ++ 0x0003); ++ if (ret < 0) ++ return ret; ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x0600, ++ 0x0c000c00); ++ if (ret < 0) ++ return ret; ++ mdelay(2); /* delay 2 ms */ ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x1404, ++ 0x004b); ++ if (ret < 0) ++ return ret; ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x140c, ++ 0x0007); ++ if (ret < 0) ++ return ret; ++ } else if (preSpeed == SPEED_100) { ++ dev_dbg(dev, "SPEED_100\n"); ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x10, ++ 0xD401); ++ if (ret < 0) ++ return ret; ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x0, ++ 0x9140); ++ if (ret < 0) ++ return ret; ++ ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x0A14, ++ 0x0007); ++ if (ret < 0) ++ return ret; ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x0600, ++ 0x0c11); ++ if (ret < 0) ++ return ret; ++ mdelay(2); /* delay 2 ms */ ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x1404, ++ 0x0027); ++ if (ret < 0) ++ return ret; ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x140c, ++ 0x0007); ++ if (ret < 0) ++ return ret; ++ } else if (preSpeed == SPEED_10) { ++ dev_dbg(dev, "SPEED_10\n"); ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x10, ++ 0xD001); ++ if (ret < 0) ++ return ret; ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x0, ++ 0x9140); ++ if (ret < 0) ++ return ret; ++ ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x0A14, ++ 0x000b); ++ if (ret < 0) ++ return ret; ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x0600, ++ 0x0c11); ++ if (ret < 0) ++ return ret; ++ mdelay(2); /* delay 2 ms */ ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x1404, ++ 0x0027); ++ if (ret < 0) ++ return ret; ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x140c, ++ 0x0007); ++ if (ret < 0) ++ return ret; ++ } ++ } ++ return ret; ++} ++ ++static int en8801s_probe(struct phy_device *phydev) ++{ ++ struct en8801s_priv *priv; ++ unsigned long phy_addr = phydev_phy_addr(phydev); ++ struct mdio_device *mdiodev = &phydev->mdio; ++ ++ priv = kzalloc(sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ priv->count = 0; ++ priv->first_init = true; ++ ++ if (mdiodev->reset_gpio) { ++ dev_dbg(phydev_dev(phydev), ++ "Assert PHY %lx HWRST until phy_init_hw\n", ++ phy_addr); ++ phy_device_reset(phydev, 1); ++ } ++ ++ phydev->priv = priv; ++ ++ return 0; ++} ++ ++static int airoha_mmd_read(struct phy_device *phydev, ++ int devad, u16 reg) ++{ ++ struct mii_bus *mbus = phydev_mdio_bus(phydev); ++ int phy_addr = phydev_phy_addr(phydev); ++ int ret = 0; ++ u16 cl45_value; ++ ++ ret = __airoha_cl45_read(mbus, phy_addr, devad, reg, &cl45_value); ++ if (ret < 0) ++ return ret; ++ ++ return cl45_value; ++} ++ ++static int airoha_mmd_write(struct phy_device *phydev, ++ int devad, u16 reg, u16 val) ++{ ++ struct mii_bus *mbus = phydev_mdio_bus(phydev); ++ int phy_addr = phydev_phy_addr(phydev); ++ int pbus_addr = phydev_pbus_addr(phydev); ++ unsigned long pbus_data; ++ int ret = 0; ++ ++ if (MDIO_MMD_AN == devad && MDIO_AN_EEE_ADV == reg) { ++ if (val == 0) { ++ pbus_data = __airoha_pbus_read(mbus, pbus_addr, 0x1960); ++ if (0xA == ((pbus_data & 0x07c00000) >> 22)) { ++ pbus_data = (pbus_data & 0xf83fffff) | ++ (0xC << 22); ++ __airoha_pbus_write(mbus, pbus_addr, 0x1960, ++ pbus_data); ++ mdelay(10); ++ pbus_data = (pbus_data & 0xf83fffff) | ++ (0xE << 22); ++ __airoha_pbus_write(mbus, pbus_addr, 0x1960, ++ pbus_data); ++ mdelay(10); ++ } ++ } else { ++ pbus_data = __airoha_pbus_read(mbus, pbus_addr, 0x1960); ++ if (0xE == ((pbus_data & 0x07c00000) >> 22)) { ++ pbus_data = (pbus_data & 0xf83fffff) | ++ (0xC << 22); ++ __airoha_pbus_write(mbus, pbus_addr, 0x1960, ++ pbus_data); ++ mdelay(10); ++ pbus_data = (pbus_data & 0xf83fffff) | ++ (0xA << 22); ++ __airoha_pbus_write(mbus, pbus_addr, 0x1960, ++ pbus_data); ++ mdelay(10); ++ } ++ } ++ } ++ ret = __airoha_cl45_write(mbus, phy_addr, devad, reg, val); ++ if (ret < 0) ++ return ret; ++ ++ return 0; ++} ++ ++static struct phy_driver Airoha_driver[] = { ++ { ++ .phy_id = EN8801SC_PHY_ID, ++ .name = "Airoha EN8801SC", ++ .phy_id_mask = 0x0ffffff0, ++ .features = PHY_GBIT_FEATURES, ++ .probe = en8801s_probe, ++ .config_init = en8801s_phase1_init, ++ .config_aneg = genphy_config_aneg, ++ .read_status = en8801s_read_status, ++ .suspend = genphy_suspend, ++ .resume = genphy_resume, ++ .read_mmd = airoha_mmd_read, ++ .write_mmd = airoha_mmd_write, ++ } ++}; ++ ++module_phy_driver(Airoha_driver); ++ ++static struct mdio_device_id __maybe_unused Airoha_tbl[] = { ++ { EN8801SC_PHY_ID, 0x0ffffff0 }, ++ { } ++}; ++ ++MODULE_DEVICE_TABLE(mdio, Airoha_tbl); +diff --git a/drivers/net/phy/en8801sc.h b/drivers/net/phy/en8801sc.h +new file mode 100644 +index 000000000000..d1e268c9aa3a +--- /dev/null ++++ b/drivers/net/phy/en8801sc.h +@@ -0,0 +1,250 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* FILE NAME: en8801sc.h ++ * PURPOSE: ++ * Define EN8801SC driver function ++ * ++ * NOTES: ++ * ++ */ ++ ++#ifndef __EN8801SC_H ++#define __EN8801SC_H ++ ++/* NAMING DECLARATIONS ++ */ ++#define EN8801S_DRIVER_VERSION "1.1.8_Generic" ++#define EN8801S_PBUS_DEFAULT_ADDR 0x1e ++#define EN8801S_PHY_DEFAULT_ADDR 0x1d ++#define EN8801S_RG_ETHER_PHY_OUI 0x19a4 ++#define EN8801S_RG_SMI_ADDR 0x19a8 ++#define EN8801S_RG_BUCK_CTL 0x1a20 ++#define EN8801S_RG_LTR_CTL 0x0cf8 ++#define EN8801S_RG_PROD_VER 0x18e0 ++ ++#define EN8801S_PBUS_OUI 0x17a5 ++#define EN8801S_PHY_ID1 0x03a2 ++#define EN8801S_PHY_ID2 0x9461 ++#define EN8801SC_PHY_ID 0x03a29471 ++ ++#define LED_ON_CTRL(i) (0x024 + ((i)*2)) ++#define LED_ON_EN (1 << 15) ++#define LED_ON_POL (1 << 14) ++#define LED_ON_EVT_MASK (0x7f) ++/* LED ON Event Option.B */ ++#define LED_ON_EVT_FORCE (1 << 6) ++#define LED_ON_EVT_LINK_DOWN (1 << 3) ++#define LED_ON_EVT_LINK_10M (1 << 2) ++#define LED_ON_EVT_LINK_100M (1 << 1) ++#define LED_ON_EVT_LINK_1000M (1 << 0) ++/* LED ON Event Option.E */ ++ ++#define LED_BLK_CTRL(i) (0x025 + ((i)*2)) ++#define LED_BLK_EVT_MASK (0x3ff) ++/* LED Blinking Event Option.B*/ ++#define LED_BLK_EVT_FORCE (1 << 9) ++#define LED_BLK_EVT_10M_RX_ACT (1 << 5) ++#define LED_BLK_EVT_10M_TX_ACT (1 << 4) ++#define LED_BLK_EVT_100M_RX_ACT (1 << 3) ++#define LED_BLK_EVT_100M_TX_ACT (1 << 2) ++#define LED_BLK_EVT_1000M_RX_ACT (1 << 1) ++#define LED_BLK_EVT_1000M_TX_ACT (1 << 0) ++/* LED Blinking Event Option.E*/ ++#define LED_ENABLE 1 ++#define LED_DISABLE 0 ++ ++#define LINK_UP 1 ++#define LINK_DOWN 0 ++ ++/* ++SFP Sample for verification ++Tx Reverse, Rx Reverse ++*/ ++#define EN8801S_TX_POLARITY_NORMAL 0x0 ++#define EN8801S_TX_POLARITY_REVERSE 0x1 ++ ++#define EN8801S_RX_POLARITY_NORMAL (0x1 << 1) ++#define EN8801S_RX_POLARITY_REVERSE (0x0 << 1) ++ ++/* ++The following led_cfg example is for reference only. ++LED5 1000M/LINK/ACT (GPIO5) <-> BASE_T_LED0, ++LED6 10/100M/LINK/ACT(GPIO9) <-> BASE_T_LED1, ++LED4 100M/LINK/ACT (GPIO8) <-> BASE_T_LED2, ++*/ ++/* User-defined.B */ ++#define BASE_T_LED0_ON_CFG (LED_ON_EVT_LINK_1000M) ++#define BASE_T_LED0_BLK_CFG \ ++ (LED_BLK_EVT_1000M_TX_ACT | \ ++ LED_BLK_EVT_1000M_RX_ACT) ++#define BASE_T_LED1_ON_CFG \ ++ (LED_ON_EVT_LINK_100M | \ ++ LED_ON_EVT_LINK_10M) ++#define BASE_T_LED1_BLK_CFG \ ++ (LED_BLK_EVT_100M_TX_ACT | \ ++ LED_BLK_EVT_100M_RX_ACT | \ ++ LED_BLK_EVT_10M_TX_ACT | \ ++ LED_BLK_EVT_10M_RX_ACT) ++#define BASE_T_LED2_ON_CFG \ ++ (LED_ON_EVT_LINK_100M) ++#define BASE_T_LED2_BLK_CFG \ ++ (LED_BLK_EVT_100M_TX_ACT | \ ++ LED_BLK_EVT_100M_RX_ACT) ++#define BASE_T_LED3_ON_CFG (0x0) ++#define BASE_T_LED3_BLK_CFG (0x0) ++/* User-defined.E */ ++ ++#define EN8801S_LED_COUNT 4 ++ ++#define MAX_RETRY 5 ++#define MAX_OUI_CHECK 2 ++/* CL45 MDIO control */ ++#define MII_MMD_ACC_CTL_REG 0x0d ++#define MII_MMD_ADDR_DATA_REG 0x0e ++#define MMD_OP_MODE_DATA BIT(14) ++ ++#define MAX_TRG_COUNTER 5 ++ ++/* CL22 Reg Support Page Select */ ++#define RgAddr_Reg1Fh 0x1f ++#define CL22_Page_Reg 0x0000 ++#define CL22_Page_ExtReg 0x0001 ++#define CL22_Page_MiscReg 0x0002 ++#define CL22_Page_LpiReg 0x0003 ++#define CL22_Page_tReg 0x02A3 ++#define CL22_Page_TrReg 0x52B5 ++ ++/* CL45 Reg Support DEVID */ ++#define DEVID_03 0x03 ++#define DEVID_07 0x07 ++#define DEVID_1E 0x1E ++#define DEVID_1F 0x1F ++ ++/* TokenRing Reg Access */ ++#define TrReg_PKT_XMT_STA 0x8000 ++#define TrReg_WR 0x8000 ++#define TrReg_RD 0xA000 ++ ++#define RgAddr_LPI_1Ch 0x1c ++#define RgAddr_AUXILIARY_1Dh 0x1d ++#define RgAddr_PMA_00h 0x0f80 ++#define RgAddr_PMA_01h 0x0f82 ++#define RgAddr_PMA_17h 0x0fae ++#define RgAddr_PMA_18h 0x0fb0 ++#define RgAddr_DSPF_03h 0x1686 ++#define RgAddr_DSPF_06h 0x168c ++#define RgAddr_DSPF_08h 0x1690 ++#define RgAddr_DSPF_0Ch 0x1698 ++#define RgAddr_DSPF_0Dh 0x169a ++#define RgAddr_DSPF_0Fh 0x169e ++#define RgAddr_DSPF_10h 0x16a0 ++#define RgAddr_DSPF_11h 0x16a2 ++#define RgAddr_DSPF_13h 0x16a6 ++#define RgAddr_DSPF_14h 0x16a8 ++#define RgAddr_DSPF_1Bh 0x16b6 ++#define RgAddr_DSPF_1Ch 0x16b8 ++#define RgAddr_TR_26h 0x0ecc ++#define RgAddr_R1000DEC_15h 0x03aa ++#define RgAddr_R1000DEC_17h 0x03ae ++ ++#define LED_BCR (0x021) ++#define LED_BCR_EXT_CTRL (1 << 15) ++#define LED_BCR_CLK_EN (1 << 3) ++#define LED_BCR_TIME_TEST (1 << 2) ++#define LED_BCR_MODE_MASK (3) ++#define LED_BCR_MODE_DISABLE (0) ++ ++#define LED_ON_DUR (0x022) ++#define LED_ON_DUR_MASK (0xffff) ++ ++#define LED_BLK_DUR (0x023) ++#define LED_BLK_DUR_MASK (0xffff) ++ ++#define LED_GPIO_SEL_MASK 0x7FFFFFF ++ ++#define UNIT_LED_BLINK_DURATION 1024 ++ ++/* Invalid data */ ++#define INVALID_DATA 0xffffffff ++ ++#define LED_SET_GPIO_SEL(gpio, led, val) \ ++ (val |= (led << (8 * (gpio % 4)))) \ ++ ++#define GET_BIT(val, bit) ((val & BIT(bit)) >> bit) ++/* DATA TYPE DECLARATIONS ++ */ ++struct AIR_BASE_T_LED_CFG_S { ++ u16 en; ++ u16 gpio; ++ u16 pol; ++ u16 on_cfg; ++ u16 blk_cfg; ++}; ++ ++union gephy_all_REG_LpiReg1Ch { ++ struct { ++ /* b[15:00] */ ++ u16 smi_deton_wt : 3; ++ u16 smi_det_mdi_inv : 1; ++ u16 smi_detoff_wt : 3; ++ u16 smi_sigdet_debouncing_en : 1; ++ u16 smi_deton_th : 6; ++ u16 rsv_14 : 2; ++ } DataBitField; ++ u16 DATA; ++}; ++ ++union gephy_all_REG_dev1Eh_reg324h { ++ struct { ++ /* b[15:00] */ ++ u16 rg_smi_detcnt_max : 6; ++ u16 rsv_6 : 2; ++ u16 rg_smi_det_max_en : 1; ++ u16 smi_det_deglitch_off : 1; ++ u16 rsv_10 : 6; ++ } DataBitField; ++ u16 DATA; ++}; ++ ++union gephy_all_REG_dev1Eh_reg012h { ++ struct { ++ /* b[15:00] */ ++ u16 da_tx_i2mpb_a_tbt : 6; ++ u16 rsv_6 : 4; ++ u16 da_tx_i2mpb_a_gbe : 6; ++ } DataBitField; ++ u16 DATA; ++}; ++ ++union gephy_all_REG_dev1Eh_reg017h { ++ struct { ++ /* b[15:00] */ ++ u16 da_tx_i2mpb_b_tbt : 6; ++ u16 rsv_6 : 2; ++ u16 da_tx_i2mpb_b_gbe : 6; ++ u16 rsv_14 : 2; ++ } DataBitField; ++ u16 DATA; ++}; ++ ++enum { ++ AIR_LED_BLK_DUR_32M, ++ AIR_LED_BLK_DUR_64M, ++ AIR_LED_BLK_DUR_128M, ++ AIR_LED_BLK_DUR_256M, ++ AIR_LED_BLK_DUR_512M, ++ AIR_LED_BLK_DUR_1024M, ++ AIR_LED_BLK_DUR_LAST ++}; ++ ++enum { ++ AIR_ACTIVE_LOW, ++ AIR_ACTIVE_HIGH, ++}; ++ ++enum { ++ AIR_LED_MODE_DISABLE, ++ AIR_LED_MODE_USER_DEFINE, ++ AIR_LED_MODE_LAST ++}; ++ ++#endif /* End of __EN8801SC_H */ +diff --git a/drivers/net/phy/ip17xx.c b/drivers/net/phy/ip17xx.c +new file mode 100644 +index 000000000000..c36980339578 +--- /dev/null ++++ b/drivers/net/phy/ip17xx.c +@@ -0,0 +1,1370 @@ ++/* ++ * ip17xx.c: Swconfig configuration for IC+ IP17xx switch family ++ * ++ * Copyright (C) 2008 Patrick Horn ++ * Copyright (C) 2008, 2010 Martin Mares ++ * Copyright (C) 2009 Felix Fietkau ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version 2 ++ * of the License, or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define MAX_VLANS 16 ++#define MAX_PORTS 9 ++#undef DUMP_MII_IO ++ ++typedef struct ip17xx_reg { ++ u16 p; // phy ++ u16 m; // mii ++} reg; ++typedef char bitnum; ++ ++#define NOTSUPPORTED {-1,-1} ++ ++#define REG_SUPP(x) (((x).m != ((u16)-1)) && ((x).p != (u16)-1)) ++ ++struct ip17xx_state; ++ ++/*********** CONSTANTS ***********/ ++struct register_mappings { ++ char *NAME; ++ u16 MODEL_NO; // Compare to bits 4-9 of MII register 0,3. ++ bitnum NUM_PORTS; ++ bitnum CPU_PORT; ++ ++/* The default VLAN for each port. ++ Default: 0x0001 for Ports 0,1,2,3 ++ 0x0002 for Ports 4,5 */ ++ reg VLAN_DEFAULT_TAG_REG[MAX_PORTS]; ++ ++/* These ports are tagged. ++ Default: 0x00 */ ++ reg ADD_TAG_REG; ++ reg REMOVE_TAG_REG; ++ bitnum ADD_TAG_BIT[MAX_PORTS]; ++/* These ports are untagged. ++ Default: 0x00 (i.e. do not alter any VLAN tags...) ++ Maybe set to 0 if user disables VLANs. */ ++ bitnum REMOVE_TAG_BIT[MAX_PORTS]; ++ ++/* Port M and Port N are on the same VLAN. ++ Default: All ports on all VLANs. */ ++// Use register {29, 19+N/2} ++ reg VLAN_LOOKUP_REG; ++// Port 5 uses register {30, 18} but same as odd bits. ++ reg VLAN_LOOKUP_REG_5; // in a different register on IP175C. ++ bitnum VLAN_LOOKUP_EVEN_BIT[MAX_PORTS]; ++ bitnum VLAN_LOOKUP_ODD_BIT[MAX_PORTS]; ++ ++/* This VLAN corresponds to which ports. ++ Default: 0x2f,0x30,0x3f,0x3f... */ ++ reg TAG_VLAN_MASK_REG; ++ bitnum TAG_VLAN_MASK_EVEN_BIT[MAX_PORTS]; ++ bitnum TAG_VLAN_MASK_ODD_BIT[MAX_PORTS]; ++ ++ int RESET_VAL; ++ reg RESET_REG; ++ ++ reg MODE_REG; ++ int MODE_VAL; ++ ++/* General flags */ ++ reg ROUTER_CONTROL_REG; ++ reg VLAN_CONTROL_REG; ++ bitnum TAG_VLAN_BIT; ++ bitnum ROUTER_EN_BIT; ++ bitnum NUMLAN_GROUPS_MAX; ++ bitnum NUMLAN_GROUPS_BIT; ++ ++ reg MII_REGISTER_EN; ++ bitnum MII_REGISTER_EN_BIT; ++ ++ // set to 1 for 178C, 0 for 175C. ++ bitnum SIMPLE_VLAN_REGISTERS; // 175C has two vlans per register but 178C has only one. ++ ++ // Pointers to functions which manipulate hardware state ++ int (*update_state)(struct ip17xx_state *state); ++ int (*set_vlan_mode)(struct ip17xx_state *state); ++ int (*reset)(struct ip17xx_state *state); ++}; ++ ++static int ip175c_update_state(struct ip17xx_state *state); ++static int ip175c_set_vlan_mode(struct ip17xx_state *state); ++static int ip175c_reset(struct ip17xx_state *state); ++ ++static const struct register_mappings IP178C = { ++ .NAME = "IP178C", ++ .MODEL_NO = 0x18, ++ .VLAN_DEFAULT_TAG_REG = { ++ {30,3},{30,4},{30,5},{30,6},{30,7},{30,8}, ++ {30,9},{30,10},{30,11}, ++ }, ++ ++ .ADD_TAG_REG = {30,12}, ++ .ADD_TAG_BIT = {0,1,2,3,4,5,6,7,8}, ++ .REMOVE_TAG_REG = {30,13}, ++ .REMOVE_TAG_BIT = {4,5,6,7,8,9,10,11,12}, ++ ++ .SIMPLE_VLAN_REGISTERS = 1, ++ ++ .VLAN_LOOKUP_REG = {31,0},// +N ++ .VLAN_LOOKUP_REG_5 = NOTSUPPORTED, // not used with SIMPLE_VLAN_REGISTERS ++ .VLAN_LOOKUP_EVEN_BIT = {0,1,2,3,4,5,6,7,8}, ++ .VLAN_LOOKUP_ODD_BIT = {0,1,2,3,4,5,6,7,8}, ++ ++ .TAG_VLAN_MASK_REG = {30,14}, // +N ++ .TAG_VLAN_MASK_EVEN_BIT = {0,1,2,3,4,5,6,7,8}, ++ .TAG_VLAN_MASK_ODD_BIT = {0,1,2,3,4,5,6,7,8}, ++ ++ .RESET_VAL = 0x55AA, ++ .RESET_REG = {30,0}, ++ .MODE_VAL = 0, ++ .MODE_REG = NOTSUPPORTED, ++ ++ .ROUTER_CONTROL_REG = {30,30}, ++ .ROUTER_EN_BIT = 11, ++ .NUMLAN_GROUPS_MAX = 8, ++ .NUMLAN_GROUPS_BIT = 8, // {0-2} ++ ++ .VLAN_CONTROL_REG = {30,13}, ++ .TAG_VLAN_BIT = 3, ++ ++ .CPU_PORT = 8, ++ .NUM_PORTS = 9, ++ ++ .MII_REGISTER_EN = NOTSUPPORTED, ++ ++ .update_state = ip175c_update_state, ++ .set_vlan_mode = ip175c_set_vlan_mode, ++ .reset = ip175c_reset, ++}; ++ ++static const struct register_mappings IP175C = { ++ .NAME = "IP175C", ++ .MODEL_NO = 0x18, ++ .VLAN_DEFAULT_TAG_REG = { ++ {29,24},{29,25},{29,26},{29,27},{29,28},{29,30}, ++ NOTSUPPORTED,NOTSUPPORTED,NOTSUPPORTED ++ }, ++ ++ .ADD_TAG_REG = {29,23}, ++ .REMOVE_TAG_REG = {29,23}, ++ .ADD_TAG_BIT = {11,12,13,14,15,1,-1,-1,-1}, ++ .REMOVE_TAG_BIT = {6,7,8,9,10,0,-1,-1,-1}, ++ ++ .SIMPLE_VLAN_REGISTERS = 0, ++ ++ .VLAN_LOOKUP_REG = {29,19},// +N/2 ++ .VLAN_LOOKUP_REG_5 = {30,18}, ++ .VLAN_LOOKUP_EVEN_BIT = {8,9,10,11,12,15,-1,-1,-1}, ++ .VLAN_LOOKUP_ODD_BIT = {0,1,2,3,4,7,-1,-1,-1}, ++ ++ .TAG_VLAN_MASK_REG = {30,1}, // +N/2 ++ .TAG_VLAN_MASK_EVEN_BIT = {0,1,2,3,4,5,-1,-1,-1}, ++ .TAG_VLAN_MASK_ODD_BIT = {8,9,10,11,12,13,-1,-1,-1}, ++ ++ .RESET_VAL = 0x175C, ++ .RESET_REG = {30,0}, ++ .MODE_VAL = 0x175C, ++ .MODE_REG = {29,31}, ++ ++ .ROUTER_CONTROL_REG = {30,9}, ++ .ROUTER_EN_BIT = 3, ++ .NUMLAN_GROUPS_MAX = 8, ++ .NUMLAN_GROUPS_BIT = 0, // {0-2} ++ ++ .VLAN_CONTROL_REG = {30,9}, ++ .TAG_VLAN_BIT = 7, ++ ++ .NUM_PORTS = 6, ++ .CPU_PORT = 5, ++ ++ .MII_REGISTER_EN = NOTSUPPORTED, ++ ++ .update_state = ip175c_update_state, ++ .set_vlan_mode = ip175c_set_vlan_mode, ++ .reset = ip175c_reset, ++}; ++ ++static const struct register_mappings IP175A = { ++ .NAME = "IP175A", ++ .MODEL_NO = 0x05, ++ .VLAN_DEFAULT_TAG_REG = { ++ {0,24},{0,25},{0,26},{0,27},{0,28},NOTSUPPORTED, ++ NOTSUPPORTED,NOTSUPPORTED,NOTSUPPORTED ++ }, ++ ++ .ADD_TAG_REG = {0,23}, ++ .REMOVE_TAG_REG = {0,23}, ++ .ADD_TAG_BIT = {11,12,13,14,15,-1,-1,-1,-1}, ++ .REMOVE_TAG_BIT = {6,7,8,9,10,-1,-1,-1,-1}, ++ ++ .SIMPLE_VLAN_REGISTERS = 0, ++ ++ // Only programmable via EEPROM ++ .VLAN_LOOKUP_REG = NOTSUPPORTED,// +N/2 ++ .VLAN_LOOKUP_REG_5 = NOTSUPPORTED, ++ .VLAN_LOOKUP_EVEN_BIT = {8,9,10,11,12,-1,-1,-1,-1}, ++ .VLAN_LOOKUP_ODD_BIT = {0,1,2,3,4,-1,-1,-1,-1}, ++ ++ .TAG_VLAN_MASK_REG = NOTSUPPORTED, // +N/2, ++ .TAG_VLAN_MASK_EVEN_BIT = {-1,-1,-1,-1,-1,-1,-1,-1,-1}, ++ .TAG_VLAN_MASK_ODD_BIT = {-1,-1,-1,-1,-1,-1,-1,-1,-1}, ++ ++ .RESET_VAL = -1, ++ .RESET_REG = NOTSUPPORTED, ++ .MODE_VAL = 0, ++ .MODE_REG = NOTSUPPORTED, ++ ++ .ROUTER_CONTROL_REG = NOTSUPPORTED, ++ .VLAN_CONTROL_REG = NOTSUPPORTED, ++ .TAG_VLAN_BIT = -1, ++ .ROUTER_EN_BIT = -1, ++ .NUMLAN_GROUPS_MAX = -1, ++ .NUMLAN_GROUPS_BIT = -1, // {0-2} ++ ++ .NUM_PORTS = 5, ++ .CPU_PORT = 4, ++ ++ .MII_REGISTER_EN = {0, 18}, ++ .MII_REGISTER_EN_BIT = 7, ++ ++ .update_state = ip175c_update_state, ++ .set_vlan_mode = ip175c_set_vlan_mode, ++ .reset = ip175c_reset, ++}; ++ ++ ++static int ip175d_update_state(struct ip17xx_state *state); ++static int ip175d_set_vlan_mode(struct ip17xx_state *state); ++static int ip175d_reset(struct ip17xx_state *state); ++ ++static const struct register_mappings IP175D = { ++ .NAME = "IP175D", ++ .MODEL_NO = 0x18, ++ ++ // The IP175D has a completely different interface, so we leave most ++ // of the registers undefined and switch to different code paths. ++ ++ .VLAN_DEFAULT_TAG_REG = { ++ NOTSUPPORTED,NOTSUPPORTED,NOTSUPPORTED,NOTSUPPORTED, ++ NOTSUPPORTED,NOTSUPPORTED,NOTSUPPORTED,NOTSUPPORTED, ++ }, ++ ++ .ADD_TAG_REG = NOTSUPPORTED, ++ .REMOVE_TAG_REG = NOTSUPPORTED, ++ ++ .SIMPLE_VLAN_REGISTERS = 0, ++ ++ .VLAN_LOOKUP_REG = NOTSUPPORTED, ++ .VLAN_LOOKUP_REG_5 = NOTSUPPORTED, ++ .TAG_VLAN_MASK_REG = NOTSUPPORTED, ++ ++ .RESET_VAL = 0x175D, ++ .RESET_REG = {20,2}, ++ .MODE_REG = NOTSUPPORTED, ++ ++ .ROUTER_CONTROL_REG = NOTSUPPORTED, ++ .ROUTER_EN_BIT = -1, ++ .NUMLAN_GROUPS_BIT = -1, ++ ++ .VLAN_CONTROL_REG = NOTSUPPORTED, ++ .TAG_VLAN_BIT = -1, ++ ++ .NUM_PORTS = 6, ++ .CPU_PORT = 5, ++ ++ .MII_REGISTER_EN = NOTSUPPORTED, ++ ++ .update_state = ip175d_update_state, ++ .set_vlan_mode = ip175d_set_vlan_mode, ++ .reset = ip175d_reset, ++}; ++ ++struct ip17xx_state { ++ struct switch_dev dev; ++ struct mii_bus *mii_bus; ++ bool registered; ++ ++ int router_mode; // ROUTER_EN ++ int vlan_enabled; // TAG_VLAN_EN ++ struct port_state { ++ u16 pvid; ++ unsigned int shareports; ++ } ports[MAX_PORTS]; ++ unsigned int add_tag; ++ unsigned int remove_tag; ++ int num_vlans; ++ struct vlan_state { ++ unsigned int ports; ++ unsigned int tag; // VLAN tag (IP175D only) ++ } vlans[MAX_VLANS]; ++ const struct register_mappings *regs; ++ reg proc_mii; // phy/reg for the low level register access via swconfig ++ ++ char buf[80]; ++}; ++ ++#define get_state(_dev) container_of((_dev), struct ip17xx_state, dev) ++ ++static int ip_phy_read(struct ip17xx_state *state, int port, int reg) ++{ ++ int val = mdiobus_read(state->mii_bus, port, reg); ++ if (val < 0) ++ pr_warn("IP17xx: Unable to get MII register %d,%d: error %d\n", port, reg, -val); ++#ifdef DUMP_MII_IO ++ else ++ pr_debug("IP17xx: Read MII(%d,%d) -> %04x\n", port, reg, val); ++#endif ++ return val; ++} ++ ++static int ip_phy_write(struct ip17xx_state *state, int port, int reg, u16 val) ++{ ++ int err; ++ ++#ifdef DUMP_MII_IO ++ pr_debug("IP17xx: Write MII(%d,%d) <- %04x\n", port, reg, val); ++#endif ++ err = mdiobus_write(state->mii_bus, port, reg, val); ++ if (err < 0) ++ pr_warn("IP17xx: Unable to write MII register %d,%d: error %d\n", port, reg, -err); ++ return err; ++} ++ ++static int ip_phy_write_masked(struct ip17xx_state *state, int port, int reg, unsigned int mask, unsigned int data) ++{ ++ int val = ip_phy_read(state, port, reg); ++ if (val < 0) ++ return 0; ++ return ip_phy_write(state, port, reg, (val & ~mask) | data); ++} ++ ++static int getPhy(struct ip17xx_state *state, reg mii) ++{ ++ if (!REG_SUPP(mii)) ++ return -EFAULT; ++ return ip_phy_read(state, mii.p, mii.m); ++} ++ ++static int setPhy(struct ip17xx_state *state, reg mii, u16 value) ++{ ++ int err; ++ ++ if (!REG_SUPP(mii)) ++ return -EFAULT; ++ err = ip_phy_write(state, mii.p, mii.m, value); ++ if (err < 0) ++ return err; ++ mdelay(2); ++ getPhy(state, mii); ++ return 0; ++} ++ ++ ++/** ++ * These two macros are to simplify the mapping of logical bits to the bits in hardware. ++ * NOTE: these macros will return if there is an error! ++ */ ++ ++#define GET_PORT_BITS(state, bits, addr, bit_lookup) \ ++ do { \ ++ int i, val = getPhy((state), (addr)); \ ++ if (val < 0) \ ++ return val; \ ++ (bits) = 0; \ ++ for (i = 0; i < MAX_PORTS; i++) { \ ++ if ((bit_lookup)[i] == -1) continue; \ ++ if (val & (1<<(bit_lookup)[i])) \ ++ (bits) |= (1<>i)<<(bit_lookup)[i]); \ ++ } \ ++ val = setPhy((state), (addr), val); \ ++ if (val < 0) \ ++ return val; \ ++ } while (0) ++ ++ ++static int get_model(struct ip17xx_state *state) ++{ ++ int id1, id2; ++ int oui_id, model_no, rev_no, chip_no; ++ ++ id1 = ip_phy_read(state, 0, 2); ++ id2 = ip_phy_read(state, 0, 3); ++ oui_id = (id1 << 6) | ((id2 >> 10) & 0x3f); ++ model_no = (id2 >> 4) & 0x3f; ++ rev_no = id2 & 0xf; ++ pr_debug("IP17xx: Identified oui=%06x model=%02x rev=%X\n", oui_id, model_no, rev_no); ++ ++ if (oui_id != 0x0090c3) // No other oui_id should have reached us anyway ++ return -ENODEV; ++ ++ if (model_no == IP175A.MODEL_NO) { ++ state->regs = &IP175A; ++ } else if (model_no == IP175C.MODEL_NO) { ++ /* ++ * Several models share the same model_no: ++ * 178C has more PHYs, so we try whether the device responds to a read from PHY5 ++ * 175D has a new chip ID register ++ * 175C has neither ++ */ ++ if (ip_phy_read(state, 5, 2) == 0x0243) { ++ state->regs = &IP178C; ++ } else { ++ chip_no = ip_phy_read(state, 20, 0); ++ pr_debug("IP17xx: Chip ID register reads %04x\n", chip_no); ++ if (chip_no == 0x175d) { ++ state->regs = &IP175D; ++ } else { ++ state->regs = &IP175C; ++ } ++ } ++ } else { ++ pr_warn("IP17xx: Found an unknown IC+ switch with model number %02x, revision %X.\n", model_no, rev_no); ++ return -EPERM; ++ } ++ return 0; ++} ++ ++/*** Low-level functions for the older models ***/ ++ ++/** Only set vlan and router flags in the switch **/ ++static int ip175c_set_flags(struct ip17xx_state *state) ++{ ++ int val; ++ ++ if (!REG_SUPP(state->regs->ROUTER_CONTROL_REG)) { ++ return 0; ++ } ++ ++ val = getPhy(state, state->regs->ROUTER_CONTROL_REG); ++ if (val < 0) { ++ return val; ++ } ++ if (state->regs->ROUTER_EN_BIT >= 0) { ++ if (state->router_mode) { ++ val |= (1<regs->ROUTER_EN_BIT); ++ } else { ++ val &= (~(1<regs->ROUTER_EN_BIT)); ++ } ++ } ++ if (state->regs->TAG_VLAN_BIT >= 0) { ++ if (state->vlan_enabled) { ++ val |= (1<regs->TAG_VLAN_BIT); ++ } else { ++ val &= (~(1<regs->TAG_VLAN_BIT)); ++ } ++ } ++ if (state->regs->NUMLAN_GROUPS_BIT >= 0) { ++ val &= (~((state->regs->NUMLAN_GROUPS_MAX-1)<regs->NUMLAN_GROUPS_BIT)); ++ if (state->num_vlans > state->regs->NUMLAN_GROUPS_MAX) { ++ val |= state->regs->NUMLAN_GROUPS_MAX << state->regs->NUMLAN_GROUPS_BIT; ++ } else if (state->num_vlans >= 1) { ++ val |= (state->num_vlans-1) << state->regs->NUMLAN_GROUPS_BIT; ++ } ++ } ++ return setPhy(state, state->regs->ROUTER_CONTROL_REG, val); ++} ++ ++/** Set all VLAN and port state. Usually you should call "correct_vlan_state" first. **/ ++static int ip175c_set_state(struct ip17xx_state *state) ++{ ++ int j; ++ int i; ++ SET_PORT_BITS(state, state->add_tag, ++ state->regs->ADD_TAG_REG, state->regs->ADD_TAG_BIT); ++ SET_PORT_BITS(state, state->remove_tag, ++ state->regs->REMOVE_TAG_REG, state->regs->REMOVE_TAG_BIT); ++ ++ if (REG_SUPP(state->regs->VLAN_LOOKUP_REG)) { ++ for (j=0; jregs->NUM_PORTS; j++) { ++ reg addr; ++ const bitnum *bit_lookup = (j%2==0)? ++ state->regs->VLAN_LOOKUP_EVEN_BIT: ++ state->regs->VLAN_LOOKUP_ODD_BIT; ++ ++ addr = state->regs->VLAN_LOOKUP_REG; ++ if (state->regs->SIMPLE_VLAN_REGISTERS) { ++ addr.m += j; ++ } else { ++ switch (j) { ++ case 0: ++ case 1: ++ break; ++ case 2: ++ case 3: ++ addr.m+=1; ++ break; ++ case 4: ++ addr.m+=2; ++ break; ++ case 5: ++ addr = state->regs->VLAN_LOOKUP_REG_5; ++ break; ++ default: ++ addr.m = -1; // shouldn't get here, but... ++ break; ++ } ++ } ++ //printf("shareports for %d is %02X\n",j,state->ports[j].shareports); ++ if (REG_SUPP(addr)) { ++ SET_PORT_BITS(state, state->ports[j].shareports, addr, bit_lookup); ++ } ++ } ++ } ++ if (REG_SUPP(state->regs->TAG_VLAN_MASK_REG)) { ++ for (j=0; jregs->TAG_VLAN_MASK_REG; ++ const bitnum *bit_lookup = (j%2==0)? ++ state->regs->TAG_VLAN_MASK_EVEN_BIT: ++ state->regs->TAG_VLAN_MASK_ODD_BIT; ++ unsigned int vlan_mask; ++ if (state->regs->SIMPLE_VLAN_REGISTERS) { ++ addr.m += j; ++ } else { ++ addr.m += j/2; ++ } ++ vlan_mask = state->vlans[j].ports; ++ SET_PORT_BITS(state, vlan_mask, addr, bit_lookup); ++ } ++ } ++ ++ for (i=0; iregs->VLAN_DEFAULT_TAG_REG[i])) { ++ int err = setPhy(state, state->regs->VLAN_DEFAULT_TAG_REG[i], ++ state->ports[i].pvid); ++ if (err < 0) { ++ return err; ++ } ++ } ++ } ++ ++ return ip175c_set_flags(state); ++} ++ ++/** ++ * Uses only the VLAN port mask and the add tag mask to generate the other fields: ++ * which ports are part of the same VLAN, removing vlan tags, and VLAN tag ids. ++ */ ++static void ip175c_correct_vlan_state(struct ip17xx_state *state) ++{ ++ int i, j; ++ state->num_vlans = 0; ++ for (i=0; ivlans[i].ports != 0) { ++ state->num_vlans = i+1; // Hack -- we need to store the "set" vlans somewhere... ++ } ++ } ++ ++ for (i=0; iregs->NUM_PORTS; i++) { ++ unsigned int portmask = (1<vlan_enabled) { ++ // Share with everybody! ++ state->ports[i].shareports = (1<regs->NUM_PORTS)-1; ++ continue; ++ } ++ state->ports[i].shareports = portmask; ++ for (j=0; jvlans[j].ports & portmask) ++ state->ports[i].shareports |= state->vlans[j].ports; ++ } ++ } ++} ++ ++static int ip175c_update_state(struct ip17xx_state *state) ++{ ++ ip175c_correct_vlan_state(state); ++ return ip175c_set_state(state); ++} ++ ++static int ip175c_set_vlan_mode(struct ip17xx_state *state) ++{ ++ return ip175c_update_state(state); ++} ++ ++static int ip175c_reset(struct ip17xx_state *state) ++{ ++ int err; ++ ++ if (REG_SUPP(state->regs->MODE_REG)) { ++ err = setPhy(state, state->regs->MODE_REG, state->regs->MODE_VAL); ++ if (err < 0) ++ return err; ++ err = getPhy(state, state->regs->MODE_REG); ++ if (err < 0) ++ return err; ++ } ++ ++ return ip175c_update_state(state); ++} ++ ++/*** Low-level functions for IP175D ***/ ++ ++static int ip175d_update_state(struct ip17xx_state *state) ++{ ++ unsigned int filter_mask = 0; ++ unsigned int ports[16], add[16], rem[16]; ++ int i, j; ++ int err = 0; ++ ++ for (i = 0; i < 16; i++) { ++ ports[i] = 0; ++ add[i] = 0; ++ rem[i] = 0; ++ if (!state->vlan_enabled) { ++ err |= ip_phy_write(state, 22, 14+i, i+1); // default tags ++ ports[i] = 0x3f; ++ continue; ++ } ++ if (!state->vlans[i].tag) { ++ // Reset the filter ++ err |= ip_phy_write(state, 22, 14+i, 0); // tag ++ continue; ++ } ++ filter_mask |= 1 << i; ++ err |= ip_phy_write(state, 22, 14+i, state->vlans[i].tag); ++ ports[i] = state->vlans[i].ports; ++ for (j = 0; j < 6; j++) { ++ if (ports[i] & (1 << j)) { ++ if (state->add_tag & (1 << j)) ++ add[i] |= 1 << j; ++ if (state->remove_tag & (1 << j)) ++ rem[i] |= 1 << j; ++ } ++ } ++ } ++ ++ // Port masks, tag adds and removals ++ for (i = 0; i < 8; i++) { ++ err |= ip_phy_write(state, 23, i, ports[2*i] | (ports[2*i+1] << 8)); ++ err |= ip_phy_write(state, 23, 8+i, add[2*i] | (add[2*i+1] << 8)); ++ err |= ip_phy_write(state, 23, 16+i, rem[2*i] | (rem[2*i+1] << 8)); ++ } ++ err |= ip_phy_write(state, 22, 10, filter_mask); ++ ++ // Default VLAN tag for each port ++ for (i = 0; i < 6; i++) ++ err |= ip_phy_write(state, 22, 4+i, state->vlans[state->ports[i].pvid].tag); ++ ++ return (err ? -EIO : 0); ++} ++ ++static int ip175d_set_vlan_mode(struct ip17xx_state *state) ++{ ++ int i; ++ int err = 0; ++ ++ if (state->vlan_enabled) { ++ // VLAN classification rules: tag-based VLANs, use VID to classify, ++ // drop packets that cannot be classified. ++ err |= ip_phy_write_masked(state, 22, 0, 0x3fff, 0x003f); ++ ++ // Ingress rules: CFI=1 dropped, null VID is untagged, VID=1 passed, ++ // VID=0xfff discarded, admin both tagged and untagged, ingress ++ // filters enabled. ++ err |= ip_phy_write_masked(state, 22, 1, 0x0fff, 0x0c3f); ++ ++ // Egress rules: IGMP processing off, keep VLAN header off ++ err |= ip_phy_write_masked(state, 22, 2, 0x0fff, 0x0000); ++ } else { ++ // VLAN classification rules: everything off & clear table ++ err |= ip_phy_write_masked(state, 22, 0, 0xbfff, 0x8000); ++ ++ // Ingress and egress rules: set to defaults ++ err |= ip_phy_write_masked(state, 22, 1, 0x0fff, 0x0c3f); ++ err |= ip_phy_write_masked(state, 22, 2, 0x0fff, 0x0000); ++ } ++ ++ // Reset default VLAN for each port to 0 ++ for (i = 0; i < 6; i++) ++ state->ports[i].pvid = 0; ++ ++ err |= ip175d_update_state(state); ++ ++ return (err ? -EIO : 0); ++} ++ ++static int ip175d_reset(struct ip17xx_state *state) ++{ ++ int err = 0; ++ ++ // Disable the special tagging mode ++ err |= ip_phy_write_masked(state, 21, 22, 0x0003, 0x0000); ++ ++ // Set 802.1q protocol type ++ err |= ip_phy_write(state, 22, 3, 0x8100); ++ ++ state->vlan_enabled = 0; ++ err |= ip175d_set_vlan_mode(state); ++ ++ return (err ? -EIO : 0); ++} ++ ++/*** High-level functions ***/ ++ ++static int ip17xx_get_enable_vlan(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) ++{ ++ struct ip17xx_state *state = get_state(dev); ++ ++ val->value.i = state->vlan_enabled; ++ return 0; ++} ++ ++static void ip17xx_reset_vlan_config(struct ip17xx_state *state) ++{ ++ int i; ++ ++ state->remove_tag = (state->vlan_enabled ? ((1<regs->NUM_PORTS)-1) : 0x0000); ++ state->add_tag = 0x0000; ++ for (i = 0; i < MAX_VLANS; i++) { ++ state->vlans[i].ports = 0x0000; ++ state->vlans[i].tag = (i ? i : 16); ++ } ++ for (i = 0; i < MAX_PORTS; i++) ++ state->ports[i].pvid = 0; ++} ++ ++static int ip17xx_set_enable_vlan(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) ++{ ++ struct ip17xx_state *state = get_state(dev); ++ int enable; ++ ++ enable = val->value.i; ++ if (state->vlan_enabled == enable) { ++ // Do not change any state. ++ return 0; ++ } ++ state->vlan_enabled = enable; ++ ++ // Otherwise, if we are switching state, set fields to a known default. ++ ip17xx_reset_vlan_config(state); ++ ++ return state->regs->set_vlan_mode(state); ++} ++ ++static int ip17xx_get_ports(struct switch_dev *dev, struct switch_val *val) ++{ ++ struct ip17xx_state *state = get_state(dev); ++ int b; ++ int ind; ++ unsigned int ports; ++ ++ if (val->port_vlan >= dev->vlans || val->port_vlan < 0) ++ return -EINVAL; ++ ++ ports = state->vlans[val->port_vlan].ports; ++ b = 0; ++ ind = 0; ++ while (b < MAX_PORTS) { ++ if (ports&1) { ++ int istagged = ((state->add_tag >> b) & 1); ++ val->value.ports[ind].id = b; ++ val->value.ports[ind].flags = (istagged << SWITCH_PORT_FLAG_TAGGED); ++ ind++; ++ } ++ b++; ++ ports >>= 1; ++ } ++ val->len = ind; ++ ++ return 0; ++} ++ ++static int ip17xx_set_ports(struct switch_dev *dev, struct switch_val *val) ++{ ++ struct ip17xx_state *state = get_state(dev); ++ int i; ++ ++ if (val->port_vlan >= dev->vlans || val->port_vlan < 0) ++ return -EINVAL; ++ ++ state->vlans[val->port_vlan].ports = 0; ++ for (i = 0; i < val->len; i++) { ++ unsigned int bitmask = (1<value.ports[i].id); ++ state->vlans[val->port_vlan].ports |= bitmask; ++ if (val->value.ports[i].flags & (1<add_tag |= bitmask; ++ state->remove_tag &= (~bitmask); ++ } else { ++ state->add_tag &= (~bitmask); ++ state->remove_tag |= bitmask; ++ } ++ } ++ ++ return state->regs->update_state(state); ++} ++ ++static int ip17xx_apply(struct switch_dev *dev) ++{ ++ struct ip17xx_state *state = get_state(dev); ++ ++ if (REG_SUPP(state->regs->MII_REGISTER_EN)) { ++ int val = getPhy(state, state->regs->MII_REGISTER_EN); ++ if (val < 0) { ++ return val; ++ } ++ val |= (1<regs->MII_REGISTER_EN_BIT); ++ return setPhy(state, state->regs->MII_REGISTER_EN, val); ++ } ++ return 0; ++} ++ ++static int ip17xx_reset(struct switch_dev *dev) ++{ ++ struct ip17xx_state *state = get_state(dev); ++ int i, err; ++ ++ if (REG_SUPP(state->regs->RESET_REG)) { ++ err = setPhy(state, state->regs->RESET_REG, state->regs->RESET_VAL); ++ if (err < 0) ++ return err; ++ err = getPhy(state, state->regs->RESET_REG); ++ ++ /* ++ * Data sheet specifies reset period to be 2 msec. ++ * (I don't see any mention of the 2ms delay in the IP178C spec, only ++ * in IP175C, but it can't hurt.) ++ */ ++ mdelay(2); ++ } ++ ++ /* reset switch ports */ ++ for (i = 0; i < state->regs->NUM_PORTS-1; i++) { ++ err = ip_phy_write(state, i, MII_BMCR, BMCR_RESET); ++ if (err < 0) ++ return err; ++ } ++ ++ state->router_mode = 0; ++ state->vlan_enabled = 0; ++ ip17xx_reset_vlan_config(state); ++ ++ return state->regs->reset(state); ++} ++ ++static int ip17xx_get_tagged(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) ++{ ++ struct ip17xx_state *state = get_state(dev); ++ ++ if (state->add_tag & (1<port_vlan)) { ++ if (state->remove_tag & (1<port_vlan)) ++ val->value.i = 3; // shouldn't ever happen. ++ else ++ val->value.i = 1; ++ } else { ++ if (state->remove_tag & (1<port_vlan)) ++ val->value.i = 0; ++ else ++ val->value.i = 2; ++ } ++ return 0; ++} ++ ++static int ip17xx_set_tagged(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) ++{ ++ struct ip17xx_state *state = get_state(dev); ++ ++ state->add_tag &= ~(1<port_vlan); ++ state->remove_tag &= ~(1<port_vlan); ++ ++ if (val->value.i == 0) ++ state->remove_tag |= (1<port_vlan); ++ if (val->value.i == 1) ++ state->add_tag |= (1<port_vlan); ++ ++ return state->regs->update_state(state); ++} ++ ++/** Get the current phy address */ ++static int ip17xx_get_phy(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) ++{ ++ struct ip17xx_state *state = get_state(dev); ++ ++ val->value.i = state->proc_mii.p; ++ return 0; ++} ++ ++/** Set a new phy address for low level access to registers */ ++static int ip17xx_set_phy(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) ++{ ++ struct ip17xx_state *state = get_state(dev); ++ int new_reg = val->value.i; ++ ++ if (new_reg < 0 || new_reg > 31) ++ state->proc_mii.p = (u16)-1; ++ else ++ state->proc_mii.p = (u16)new_reg; ++ return 0; ++} ++ ++/** Get the current register number */ ++static int ip17xx_get_reg(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) ++{ ++ struct ip17xx_state *state = get_state(dev); ++ ++ val->value.i = state->proc_mii.m; ++ return 0; ++} ++ ++/** Set a new register address for low level access to registers */ ++static int ip17xx_set_reg(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) ++{ ++ struct ip17xx_state *state = get_state(dev); ++ int new_reg = val->value.i; ++ ++ if (new_reg < 0 || new_reg > 31) ++ state->proc_mii.m = (u16)-1; ++ else ++ state->proc_mii.m = (u16)new_reg; ++ return 0; ++} ++ ++/** Get the register content of state->proc_mii */ ++static int ip17xx_get_val(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) ++{ ++ struct ip17xx_state *state = get_state(dev); ++ int retval = -EINVAL; ++ if (REG_SUPP(state->proc_mii)) ++ retval = getPhy(state, state->proc_mii); ++ ++ if (retval < 0) { ++ return retval; ++ } else { ++ val->value.i = retval; ++ return 0; ++ } ++} ++ ++/** Write a value to the register defined by phy/reg above */ ++static int ip17xx_set_val(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) ++{ ++ struct ip17xx_state *state = get_state(dev); ++ int myval, err = -EINVAL; ++ ++ myval = val->value.i; ++ if (myval <= 0xffff && myval >= 0 && REG_SUPP(state->proc_mii)) { ++ err = setPhy(state, state->proc_mii, (u16)myval); ++ } ++ return err; ++} ++ ++static int ip17xx_read_name(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) ++{ ++ struct ip17xx_state *state = get_state(dev); ++ val->value.s = state->regs->NAME; // Just a const pointer, won't be freed by swconfig. ++ return 0; ++} ++ ++static int ip17xx_get_tag(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) ++{ ++ struct ip17xx_state *state = get_state(dev); ++ int vlan = val->port_vlan; ++ ++ if (vlan < 0 || vlan >= MAX_VLANS) ++ return -EINVAL; ++ ++ val->value.i = state->vlans[vlan].tag; ++ return 0; ++} ++ ++static int ip17xx_set_tag(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) ++{ ++ struct ip17xx_state *state = get_state(dev); ++ int vlan = val->port_vlan; ++ int tag = val->value.i; ++ ++ if (vlan < 0 || vlan >= MAX_VLANS) ++ return -EINVAL; ++ ++ if (tag < 0 || tag > 4095) ++ return -EINVAL; ++ ++ state->vlans[vlan].tag = tag; ++ return state->regs->update_state(state); ++} ++ ++static int ip17xx_set_port_speed(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) ++{ ++ struct ip17xx_state *state = get_state(dev); ++ int nr = val->port_vlan; ++ int ctrl; ++ int autoneg; ++ int speed; ++ if (val->value.i == 100) { ++ speed = 1; ++ autoneg = 0; ++ } else if (val->value.i == 10) { ++ speed = 0; ++ autoneg = 0; ++ } else { ++ autoneg = 1; ++ speed = 1; ++ } ++ ++ /* Can't set speed for cpu port */ ++ if (nr == state->regs->CPU_PORT) ++ return -EINVAL; ++ ++ if (nr >= dev->ports || nr < 0) ++ return -EINVAL; ++ ++ ctrl = ip_phy_read(state, nr, 0); ++ if (ctrl < 0) ++ return -EIO; ++ ++ ctrl &= (~(1<<12)); ++ ctrl &= (~(1<<13)); ++ ctrl |= (autoneg<<12); ++ ctrl |= (speed<<13); ++ ++ return ip_phy_write(state, nr, 0, ctrl); ++} ++ ++static int ip17xx_get_port_speed(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) ++{ ++ struct ip17xx_state *state = get_state(dev); ++ int nr = val->port_vlan; ++ int speed, status; ++ ++ if (nr == state->regs->CPU_PORT) { ++ val->value.i = 100; ++ return 0; ++ } ++ ++ if (nr >= dev->ports || nr < 0) ++ return -EINVAL; ++ ++ status = ip_phy_read(state, nr, 1); ++ speed = ip_phy_read(state, nr, 18); ++ if (status < 0 || speed < 0) ++ return -EIO; ++ ++ if (status & 4) ++ val->value.i = ((speed & (1<<11)) ? 100 : 10); ++ else ++ val->value.i = 0; ++ ++ return 0; ++} ++ ++static int ip17xx_get_port_status(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) ++{ ++ struct ip17xx_state *state = get_state(dev); ++ int ctrl, speed, status; ++ int nr = val->port_vlan; ++ int len; ++ char *buf = state->buf; // fixed-length at 80. ++ ++ if (nr == state->regs->CPU_PORT) { ++ sprintf(buf, "up, 100 Mbps, cpu port"); ++ val->value.s = buf; ++ return 0; ++ } ++ ++ if (nr >= dev->ports || nr < 0) ++ return -EINVAL; ++ ++ ctrl = ip_phy_read(state, nr, 0); ++ status = ip_phy_read(state, nr, 1); ++ speed = ip_phy_read(state, nr, 18); ++ if (ctrl < 0 || status < 0 || speed < 0) ++ return -EIO; ++ ++ if (status & 4) ++ len = sprintf(buf, "up, %d Mbps, %s duplex", ++ ((speed & (1<<11)) ? 100 : 10), ++ ((speed & (1<<10)) ? "full" : "half")); ++ else ++ len = sprintf(buf, "down"); ++ ++ if (ctrl & (1<<12)) { ++ len += sprintf(buf+len, ", auto-negotiate"); ++ if (!(status & (1<<5))) ++ len += sprintf(buf+len, " (in progress)"); ++ } else { ++ len += sprintf(buf+len, ", fixed speed (%d)", ++ ((ctrl & (1<<13)) ? 100 : 10)); ++ } ++ ++ buf[len] = '\0'; ++ val->value.s = buf; ++ return 0; ++} ++ ++static int ip17xx_get_pvid(struct switch_dev *dev, int port, int *val) ++{ ++ struct ip17xx_state *state = get_state(dev); ++ ++ *val = state->ports[port].pvid; ++ return 0; ++} ++ ++static int ip17xx_set_pvid(struct switch_dev *dev, int port, int val) ++{ ++ struct ip17xx_state *state = get_state(dev); ++ ++ if (val < 0 || val >= MAX_VLANS) ++ return -EINVAL; ++ ++ state->ports[port].pvid = val; ++ return state->regs->update_state(state); ++} ++ ++ ++enum Ports { ++ IP17XX_PORT_STATUS, ++ IP17XX_PORT_LINK, ++ IP17XX_PORT_TAGGED, ++ IP17XX_PORT_PVID, ++}; ++ ++enum Globals { ++ IP17XX_ENABLE_VLAN, ++ IP17XX_GET_NAME, ++ IP17XX_REGISTER_PHY, ++ IP17XX_REGISTER_MII, ++ IP17XX_REGISTER_VALUE, ++ IP17XX_REGISTER_ERRNO, ++}; ++ ++enum Vlans { ++ IP17XX_VLAN_TAG, ++}; ++ ++static const struct switch_attr ip17xx_global[] = { ++ [IP17XX_ENABLE_VLAN] = { ++ .id = IP17XX_ENABLE_VLAN, ++ .type = SWITCH_TYPE_INT, ++ .name = "enable_vlan", ++ .description = "Flag to enable or disable VLANs and tagging", ++ .get = ip17xx_get_enable_vlan, ++ .set = ip17xx_set_enable_vlan, ++ }, ++ [IP17XX_GET_NAME] = { ++ .id = IP17XX_GET_NAME, ++ .type = SWITCH_TYPE_STRING, ++ .description = "Returns the type of IC+ chip.", ++ .name = "name", ++ .get = ip17xx_read_name, ++ .set = NULL, ++ }, ++ /* jal: added for low level debugging etc. */ ++ [IP17XX_REGISTER_PHY] = { ++ .id = IP17XX_REGISTER_PHY, ++ .type = SWITCH_TYPE_INT, ++ .description = "Direct register access: set PHY (0-4, or 29,30,31)", ++ .name = "phy", ++ .get = ip17xx_get_phy, ++ .set = ip17xx_set_phy, ++ }, ++ [IP17XX_REGISTER_MII] = { ++ .id = IP17XX_REGISTER_MII, ++ .type = SWITCH_TYPE_INT, ++ .description = "Direct register access: set MII register number (0-31)", ++ .name = "reg", ++ .get = ip17xx_get_reg, ++ .set = ip17xx_set_reg, ++ }, ++ [IP17XX_REGISTER_VALUE] = { ++ .id = IP17XX_REGISTER_VALUE, ++ .type = SWITCH_TYPE_INT, ++ .description = "Direct register access: read/write to register (0-65535)", ++ .name = "val", ++ .get = ip17xx_get_val, ++ .set = ip17xx_set_val, ++ }, ++}; ++ ++static const struct switch_attr ip17xx_vlan[] = { ++ [IP17XX_VLAN_TAG] = { ++ .id = IP17XX_VLAN_TAG, ++ .type = SWITCH_TYPE_INT, ++ .description = "VLAN ID (0-4095) [IP175D only]", ++ .name = "vid", ++ .get = ip17xx_get_tag, ++ .set = ip17xx_set_tag, ++ } ++}; ++ ++static const struct switch_attr ip17xx_port[] = { ++ [IP17XX_PORT_STATUS] = { ++ .id = IP17XX_PORT_STATUS, ++ .type = SWITCH_TYPE_STRING, ++ .description = "Returns Detailed port status", ++ .name = "status", ++ .get = ip17xx_get_port_status, ++ .set = NULL, ++ }, ++ [IP17XX_PORT_LINK] = { ++ .id = IP17XX_PORT_LINK, ++ .type = SWITCH_TYPE_INT, ++ .description = "Link speed. Can write 0 for auto-negotiate, or 10 or 100", ++ .name = "link", ++ .get = ip17xx_get_port_speed, ++ .set = ip17xx_set_port_speed, ++ }, ++ [IP17XX_PORT_TAGGED] = { ++ .id = IP17XX_PORT_LINK, ++ .type = SWITCH_TYPE_INT, ++ .description = "0 = untag, 1 = add tags, 2 = do not alter (This value is reset if vlans are altered)", ++ .name = "tagged", ++ .get = ip17xx_get_tagged, ++ .set = ip17xx_set_tagged, ++ }, ++}; ++ ++static const struct switch_dev_ops ip17xx_ops = { ++ .attr_global = { ++ .attr = ip17xx_global, ++ .n_attr = ARRAY_SIZE(ip17xx_global), ++ }, ++ .attr_port = { ++ .attr = ip17xx_port, ++ .n_attr = ARRAY_SIZE(ip17xx_port), ++ }, ++ .attr_vlan = { ++ .attr = ip17xx_vlan, ++ .n_attr = ARRAY_SIZE(ip17xx_vlan), ++ }, ++ ++ .get_port_pvid = ip17xx_get_pvid, ++ .set_port_pvid = ip17xx_set_pvid, ++ .get_vlan_ports = ip17xx_get_ports, ++ .set_vlan_ports = ip17xx_set_ports, ++ .apply_config = ip17xx_apply, ++ .reset_switch = ip17xx_reset, ++}; ++ ++static int ip17xx_probe(struct phy_device *pdev) ++{ ++ struct ip17xx_state *state; ++ struct switch_dev *dev; ++ int err; ++ ++ /* We only attach to PHY 0, but use all available PHYs */ ++ if (pdev->mdio.addr != 0) ++ return -ENODEV; ++ ++ state = kzalloc(sizeof(*state), GFP_KERNEL); ++ if (!state) ++ return -ENOMEM; ++ ++ dev = &state->dev; ++ ++ pdev->priv = state; ++ state->mii_bus = pdev->mdio.bus; ++ ++ err = get_model(state); ++ if (err < 0) ++ goto error; ++ ++ dev->vlans = MAX_VLANS; ++ dev->cpu_port = state->regs->CPU_PORT; ++ dev->ports = state->regs->NUM_PORTS; ++ dev->name = state->regs->NAME; ++ dev->ops = &ip17xx_ops; ++ ++ pr_info("IP17xx: Found %s at %s\n", dev->name, dev_name(&pdev->mdio.dev)); ++ return 0; ++ ++error: ++ kfree(state); ++ return err; ++} ++ ++static int ip17xx_config_init(struct phy_device *pdev) ++{ ++ struct ip17xx_state *state = pdev->priv; ++ struct net_device *dev = pdev->attached_dev; ++ int err; ++ ++ err = register_switch(&state->dev, dev); ++ if (err < 0) ++ return err; ++ ++ state->registered = true; ++ ip17xx_reset(&state->dev); ++ return 0; ++} ++ ++static void ip17xx_remove(struct phy_device *pdev) ++{ ++ struct ip17xx_state *state = pdev->priv; ++ ++ if (state->registered) ++ unregister_switch(&state->dev); ++ kfree(state); ++} ++ ++static int ip17xx_config_aneg(struct phy_device *pdev) ++{ ++ return 0; ++} ++ ++static int ip17xx_aneg_done(struct phy_device *pdev) ++{ ++ return 1; /* Return any positive value */ ++} ++ ++static int ip17xx_read_status(struct phy_device *pdev) ++{ ++ pdev->speed = SPEED_100; ++ pdev->duplex = DUPLEX_FULL; ++ pdev->pause = pdev->asym_pause = 0; ++ pdev->link = 1; ++ ++ return 0; ++} ++ ++static struct phy_driver ip17xx_driver[] = { ++ { ++ .name = "IC+ IP17xx", ++ .phy_id = 0x02430c00, ++ .phy_id_mask = 0x0ffffc00, ++ .features = PHY_BASIC_FEATURES, ++ .probe = ip17xx_probe, ++ .remove = ip17xx_remove, ++ .config_init = ip17xx_config_init, ++ .config_aneg = ip17xx_config_aneg, ++ .aneg_done = ip17xx_aneg_done, ++ .read_status = ip17xx_read_status, ++ } ++}; ++ ++module_phy_driver(ip17xx_driver); ++ ++MODULE_AUTHOR("Patrick Horn "); ++MODULE_AUTHOR("Felix Fietkau "); ++MODULE_AUTHOR("Martin Mares "); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/net/phy/psb6970.c b/drivers/net/phy/psb6970.c +new file mode 100644 +index 000000000000..e8b1b06f6365 +--- /dev/null ++++ b/drivers/net/phy/psb6970.c +@@ -0,0 +1,443 @@ ++/* ++ * Lantiq PSB6970 (Tantos) Switch driver ++ * ++ * Copyright (c) 2009,2010 Team Embedded. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License v2 as published by the ++ * Free Software Foundation. ++ * ++ * The switch programming done in this driver follows the ++ * "Ethernet Traffic Separation using VLAN" Application Note as ++ * published by Lantiq. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#define PSB6970_MAX_VLANS 16 ++#define PSB6970_NUM_PORTS 7 ++#define PSB6970_DEFAULT_PORT_CPU 6 ++#define PSB6970_IS_CPU_PORT(x) ((x) > 4) ++ ++#define PHYADDR(_reg) ((_reg >> 5) & 0xff), (_reg & 0x1f) ++ ++/* --- Identification --- */ ++#define PSB6970_CI0 0x0100 ++#define PSB6970_CI0_MASK 0x000f ++#define PSB6970_CI1 0x0101 ++#define PSB6970_CI1_VAL 0x2599 ++#define PSB6970_CI1_MASK 0xffff ++ ++/* --- VLAN filter table --- */ ++#define PSB6970_VFxL(i) ((i)*2+0x10) /* VLAN Filter Low */ ++#define PSB6970_VFxL_VV (1 << 15) /* VLAN_Valid */ ++ ++#define PSB6970_VFxH(i) ((i)*2+0x11) /* VLAN Filter High */ ++#define PSB6970_VFxH_TM_SHIFT 7 /* Tagged Member */ ++ ++/* --- Port registers --- */ ++#define PSB6970_EC(p) ((p)*0x20+2) /* Extended Control */ ++#define PSB6970_EC_IFNTE (1 << 1) /* Input Force No Tag Enable */ ++ ++#define PSB6970_PBVM(p) ((p)*0x20+3) /* Port Base VLAN Map */ ++#define PSB6970_PBVM_VMCE (1 << 8) ++#define PSB6970_PBVM_AOVTP (1 << 9) ++#define PSB6970_PBVM_VSD (1 << 10) ++#define PSB6970_PBVM_VC (1 << 11) /* VID Check with VID table */ ++#define PSB6970_PBVM_TBVE (1 << 13) /* Tag-Based VLAN enable */ ++ ++#define PSB6970_DVID(p) ((p)*0x20+4) /* Default VLAN ID & Priority */ ++ ++struct psb6970_priv { ++ struct switch_dev dev; ++ struct phy_device *phy; ++ u16 (*read) (struct phy_device* phydev, int reg); ++ void (*write) (struct phy_device* phydev, int reg, u16 val); ++ struct mutex reg_mutex; ++ ++ /* all fields below are cleared on reset */ ++ struct_group(psb6970_priv_volatile, ++ bool vlan; ++ u16 vlan_id[PSB6970_MAX_VLANS]; ++ u8 vlan_table[PSB6970_MAX_VLANS]; ++ u8 vlan_tagged; ++ u16 pvid[PSB6970_NUM_PORTS]; ++ ); ++}; ++ ++#define to_psb6970(_dev) container_of(_dev, struct psb6970_priv, dev) ++ ++static u16 psb6970_mii_read(struct phy_device *phydev, int reg) ++{ ++ struct mii_bus *bus = phydev->mdio.bus; ++ ++ return bus->read(bus, PHYADDR(reg)); ++} ++ ++static void psb6970_mii_write(struct phy_device *phydev, int reg, u16 val) ++{ ++ struct mii_bus *bus = phydev->mdio.bus; ++ ++ bus->write(bus, PHYADDR(reg), val); ++} ++ ++static int ++psb6970_set_vlan(struct switch_dev *dev, const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct psb6970_priv *priv = to_psb6970(dev); ++ priv->vlan = !!val->value.i; ++ return 0; ++} ++ ++static int ++psb6970_get_vlan(struct switch_dev *dev, const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct psb6970_priv *priv = to_psb6970(dev); ++ val->value.i = priv->vlan; ++ return 0; ++} ++ ++static int psb6970_set_pvid(struct switch_dev *dev, int port, int vlan) ++{ ++ struct psb6970_priv *priv = to_psb6970(dev); ++ ++ /* make sure no invalid PVIDs get set */ ++ if (vlan >= dev->vlans) ++ return -EINVAL; ++ ++ priv->pvid[port] = vlan; ++ return 0; ++} ++ ++static int psb6970_get_pvid(struct switch_dev *dev, int port, int *vlan) ++{ ++ struct psb6970_priv *priv = to_psb6970(dev); ++ *vlan = priv->pvid[port]; ++ return 0; ++} ++ ++static int ++psb6970_set_vid(struct switch_dev *dev, const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct psb6970_priv *priv = to_psb6970(dev); ++ priv->vlan_id[val->port_vlan] = val->value.i; ++ return 0; ++} ++ ++static int ++psb6970_get_vid(struct switch_dev *dev, const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct psb6970_priv *priv = to_psb6970(dev); ++ val->value.i = priv->vlan_id[val->port_vlan]; ++ return 0; ++} ++ ++static struct switch_attr psb6970_globals[] = { ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "enable_vlan", ++ .description = "Enable VLAN mode", ++ .set = psb6970_set_vlan, ++ .get = psb6970_get_vlan, ++ .max = 1}, ++}; ++ ++static struct switch_attr psb6970_port[] = { ++}; ++ ++static struct switch_attr psb6970_vlan[] = { ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "vid", ++ .description = "VLAN ID (0-4094)", ++ .set = psb6970_set_vid, ++ .get = psb6970_get_vid, ++ .max = 4094, ++ }, ++}; ++ ++static int psb6970_get_ports(struct switch_dev *dev, struct switch_val *val) ++{ ++ struct psb6970_priv *priv = to_psb6970(dev); ++ u8 ports = priv->vlan_table[val->port_vlan]; ++ int i; ++ ++ val->len = 0; ++ for (i = 0; i < PSB6970_NUM_PORTS; i++) { ++ struct switch_port *p; ++ ++ if (!(ports & (1 << i))) ++ continue; ++ ++ p = &val->value.ports[val->len++]; ++ p->id = i; ++ if (priv->vlan_tagged & (1 << i)) ++ p->flags = (1 << SWITCH_PORT_FLAG_TAGGED); ++ else ++ p->flags = 0; ++ } ++ return 0; ++} ++ ++static int psb6970_set_ports(struct switch_dev *dev, struct switch_val *val) ++{ ++ struct psb6970_priv *priv = to_psb6970(dev); ++ u8 *vt = &priv->vlan_table[val->port_vlan]; ++ int i, j; ++ ++ *vt = 0; ++ for (i = 0; i < val->len; i++) { ++ struct switch_port *p = &val->value.ports[i]; ++ ++ if (p->flags & (1 << SWITCH_PORT_FLAG_TAGGED)) ++ priv->vlan_tagged |= (1 << p->id); ++ else { ++ priv->vlan_tagged &= ~(1 << p->id); ++ priv->pvid[p->id] = val->port_vlan; ++ ++ /* make sure that an untagged port does not ++ * appear in other vlans */ ++ for (j = 0; j < PSB6970_MAX_VLANS; j++) { ++ if (j == val->port_vlan) ++ continue; ++ priv->vlan_table[j] &= ~(1 << p->id); ++ } ++ } ++ ++ *vt |= 1 << p->id; ++ } ++ return 0; ++} ++ ++static int psb6970_hw_apply(struct switch_dev *dev) ++{ ++ struct psb6970_priv *priv = to_psb6970(dev); ++ int i, j; ++ ++ mutex_lock(&priv->reg_mutex); ++ ++ if (priv->vlan) { ++ /* into the vlan translation unit */ ++ for (j = 0; j < PSB6970_MAX_VLANS; j++) { ++ u8 vp = priv->vlan_table[j]; ++ ++ if (vp) { ++ priv->write(priv->phy, PSB6970_VFxL(j), ++ PSB6970_VFxL_VV | priv->vlan_id[j]); ++ priv->write(priv->phy, PSB6970_VFxH(j), ++ ((vp & priv-> ++ vlan_tagged) << ++ PSB6970_VFxH_TM_SHIFT) | vp); ++ } else /* clear VLAN Valid flag for unused vlans */ ++ priv->write(priv->phy, PSB6970_VFxL(j), 0); ++ ++ } ++ } ++ ++ /* update the port destination mask registers and tag settings */ ++ for (i = 0; i < PSB6970_NUM_PORTS; i++) { ++ int dvid = 1, pbvm = 0x7f | PSB6970_PBVM_VSD, ec = 0; ++ ++ if (priv->vlan) { ++ ec = PSB6970_EC_IFNTE; ++ dvid = priv->vlan_id[priv->pvid[i]]; ++ pbvm |= PSB6970_PBVM_TBVE | PSB6970_PBVM_VMCE; ++ ++ if ((i << 1) & priv->vlan_tagged) ++ pbvm |= PSB6970_PBVM_AOVTP | PSB6970_PBVM_VC; ++ } ++ ++ priv->write(priv->phy, PSB6970_PBVM(i), pbvm); ++ ++ if (!PSB6970_IS_CPU_PORT(i)) { ++ priv->write(priv->phy, PSB6970_EC(i), ec); ++ priv->write(priv->phy, PSB6970_DVID(i), dvid); ++ } ++ } ++ ++ mutex_unlock(&priv->reg_mutex); ++ return 0; ++} ++ ++static int psb6970_reset_switch(struct switch_dev *dev) ++{ ++ struct psb6970_priv *priv = to_psb6970(dev); ++ int i; ++ ++ mutex_lock(&priv->reg_mutex); ++ ++ memset(&priv->psb6970_priv_volatile, 0, ++ sizeof(priv->psb6970_priv_volatile)); ++ ++ for (i = 0; i < PSB6970_MAX_VLANS; i++) ++ priv->vlan_id[i] = i; ++ ++ mutex_unlock(&priv->reg_mutex); ++ ++ return psb6970_hw_apply(dev); ++} ++ ++static const struct switch_dev_ops psb6970_ops = { ++ .attr_global = { ++ .attr = psb6970_globals, ++ .n_attr = ARRAY_SIZE(psb6970_globals), ++ }, ++ .attr_port = { ++ .attr = psb6970_port, ++ .n_attr = ARRAY_SIZE(psb6970_port), ++ }, ++ .attr_vlan = { ++ .attr = psb6970_vlan, ++ .n_attr = ARRAY_SIZE(psb6970_vlan), ++ }, ++ .get_port_pvid = psb6970_get_pvid, ++ .set_port_pvid = psb6970_set_pvid, ++ .get_vlan_ports = psb6970_get_ports, ++ .set_vlan_ports = psb6970_set_ports, ++ .apply_config = psb6970_hw_apply, ++ .reset_switch = psb6970_reset_switch, ++}; ++ ++static int psb6970_config_init(struct phy_device *pdev) ++{ ++ struct psb6970_priv *priv; ++ struct switch_dev *swdev; ++ int ret; ++ ++ priv = kzalloc(sizeof(struct psb6970_priv), GFP_KERNEL); ++ if (priv == NULL) ++ return -ENOMEM; ++ ++ priv->phy = pdev; ++ ++ if (pdev->mdio.addr == 0) ++ printk(KERN_INFO "%s: psb6970 switch driver attached.\n", ++ pdev->attached_dev->name); ++ ++ if (pdev->mdio.addr != 0) { ++ kfree(priv); ++ return 0; ++ } ++ ++ linkmode_zero(pdev->supported); ++ linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, pdev->supported); ++ linkmode_copy(pdev->advertising, pdev->supported); ++ ++ mutex_init(&priv->reg_mutex); ++ priv->read = psb6970_mii_read; ++ priv->write = psb6970_mii_write; ++ ++ pdev->priv = priv; ++ ++ swdev = &priv->dev; ++ swdev->cpu_port = PSB6970_DEFAULT_PORT_CPU; ++ swdev->ops = &psb6970_ops; ++ ++ swdev->name = "Lantiq PSB6970"; ++ swdev->vlans = PSB6970_MAX_VLANS; ++ swdev->ports = PSB6970_NUM_PORTS; ++ ++ if ((ret = register_switch(&priv->dev, pdev->attached_dev)) < 0) { ++ kfree(priv); ++ goto done; ++ } ++ ++ ret = psb6970_reset_switch(&priv->dev); ++ if (ret) { ++ kfree(priv); ++ goto done; ++ } ++ ++done: ++ return ret; ++} ++ ++static int psb6970_read_status(struct phy_device *phydev) ++{ ++ phydev->speed = SPEED_100; ++ phydev->duplex = DUPLEX_FULL; ++ phydev->link = 1; ++ ++ phydev->state = PHY_RUNNING; ++ netif_carrier_on(phydev->attached_dev); ++ phydev->adjust_link(phydev->attached_dev); ++ ++ return 0; ++} ++ ++static int psb6970_config_aneg(struct phy_device *phydev) ++{ ++ return 0; ++} ++ ++static int psb6970_probe(struct phy_device *pdev) ++{ ++ return 0; ++} ++ ++static void psb6970_remove(struct phy_device *pdev) ++{ ++ struct psb6970_priv *priv = pdev->priv; ++ ++ if (!priv) ++ return; ++ ++ if (pdev->mdio.addr == 0) ++ unregister_switch(&priv->dev); ++ kfree(priv); ++} ++ ++static int psb6970_fixup(struct phy_device *dev) ++{ ++ struct mii_bus *bus = dev->mdio.bus; ++ u16 reg; ++ ++ /* look for the switch on the bus */ ++ reg = bus->read(bus, PHYADDR(PSB6970_CI1)) & PSB6970_CI1_MASK; ++ if (reg != PSB6970_CI1_VAL) ++ return 0; ++ ++ dev->phy_id = (reg << 16); ++ dev->phy_id |= bus->read(bus, PHYADDR(PSB6970_CI0)) & PSB6970_CI0_MASK; ++ ++ return 0; ++} ++ ++static struct phy_driver psb6970_driver = { ++ .name = "Lantiq PSB6970", ++ .phy_id = PSB6970_CI1_VAL << 16, ++ .phy_id_mask = 0xffff0000, ++ .features = PHY_BASIC_FEATURES, ++ .probe = psb6970_probe, ++ .remove = psb6970_remove, ++ .config_init = &psb6970_config_init, ++ .config_aneg = &psb6970_config_aneg, ++ .read_status = &psb6970_read_status, ++}; ++ ++static int __init psb6970_init(void) ++{ ++ phy_register_fixup_for_id(PHY_ANY_ID, psb6970_fixup); ++ return phy_driver_register(&psb6970_driver, THIS_MODULE); ++} ++ ++module_init(psb6970_init); ++ ++static void __exit psb6970_exit(void) ++{ ++ phy_driver_unregister(&psb6970_driver); ++} ++ ++module_exit(psb6970_exit); ++ ++MODULE_DESCRIPTION("Lantiq PSB6970 Switch"); ++MODULE_AUTHOR("Ithamar R. Adema "); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/net/phy/rtk/Makefile b/drivers/net/phy/rtk/Makefile +new file mode 100644 +index 000000000000..0f2891ead419 +--- /dev/null ++++ b/drivers/net/phy/rtk/Makefile +@@ -0,0 +1,66 @@ ++obj-$(CONFIG_RTL8367S_GSW) += rtl8367s_gsw.o ++rtl8367s_gsw-objs := rtl8367s_mdio.o rtl8367s_dbg.o ++ifeq ($(CONFIG_SWCONFIG),y) ++rtl8367s_gsw-objs += rtl8367s.o ++endif ++rtl8367s_gsw-objs += rtl8367c/acl.o ++rtl8367s_gsw-objs += rtl8367c/cpu.o ++rtl8367s_gsw-objs += rtl8367c/dot1x.o ++rtl8367s_gsw-objs += rtl8367c/eee.o ++rtl8367s_gsw-objs += rtl8367c/igmp.o ++rtl8367s_gsw-objs += rtl8367c/interrupt.o ++rtl8367s_gsw-objs += rtl8367c/l2.o ++rtl8367s_gsw-objs += rtl8367c/leaky.o ++rtl8367s_gsw-objs += rtl8367c/led.o ++rtl8367s_gsw-objs += rtl8367c/mirror.o ++rtl8367s_gsw-objs += rtl8367c/oam.o ++rtl8367s_gsw-objs += rtl8367c/port.o ++rtl8367s_gsw-objs += rtl8367c/ptp.o ++rtl8367s_gsw-objs += rtl8367c/qos.o ++rtl8367s_gsw-objs += rtl8367c/rate.o ++rtl8367s_gsw-objs += rtl8367c/rldp.o ++rtl8367s_gsw-objs += rtl8367c/rtk_switch.o ++rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_acl.o ++rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv.o ++rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_cputag.o ++rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_dot1x.o ++rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_eav.o ++rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_eee.o ++rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_fc.o ++rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_green.o ++rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_hsb.o ++rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_igmp.o ++rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_inbwctrl.o ++rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_interrupt.o ++rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_led.o ++rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_lut.o ++rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_meter.o ++rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_mib.o ++rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_mirror.o ++rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_misc.o ++rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_oam.o ++rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_phy.o ++rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_port.o ++rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_portIsolation.o ++rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_qos.o ++rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_rldp.o ++rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_rma.o ++rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_scheduling.o ++rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_storm.o ++rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_svlan.o ++rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_trunking.o ++rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_unknownMulticast.o ++rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_vlan.o ++rtl8367s_gsw-objs += rtl8367c/smi.o ++rtl8367s_gsw-objs += rtl8367c/stat.o ++rtl8367s_gsw-objs += rtl8367c/storm.o ++rtl8367s_gsw-objs += rtl8367c/svlan.o ++rtl8367s_gsw-objs += rtl8367c/trap.o ++rtl8367s_gsw-objs += rtl8367c/trunk.o ++rtl8367s_gsw-objs += rtl8367c/vlan.o ++ ++ccflags-y += -Werror -D_LITTLE_ENDIAN -DMDC_MDIO_OPERATION ++ ++ccflags-y += -Idrivers/net/phy/rtk/rtl8367c/include ++ccflags-y += -Iinclude/linux/ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/acl.c b/drivers/net/phy/rtk/rtl8367c/acl.c +new file mode 100644 +index 000000000000..85c12b000ff8 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/acl.c +@@ -0,0 +1,2061 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ ++ * ++ * Purpose : RTK switch high-level API for RTL8367/RTL8367C ++ * Feature : Here is a list of all functions and variables in ACL module. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++CONST_T rtk_uint8 filter_templateField[RTL8367C_ACLTEMPLATENO][RTL8367C_ACLRULEFIELDNO] = { ++ {ACL_DMAC0, ACL_DMAC1, ACL_DMAC2, ACL_SMAC0, ACL_SMAC1, ACL_SMAC2, ACL_ETHERTYPE, ACL_FIELD_SELECT15}, ++ {ACL_IP4SIP0, ACL_IP4SIP1, ACL_IP4DIP0, ACL_IP4DIP1, ACL_FIELD_SELECT13, ACL_FIELD_SELECT14, ACL_FIELD_SELECT02, ACL_FIELD_SELECT15}, ++ {ACL_IP6SIP0WITHIPV4, ACL_IP6SIP1WITHIPV4,ACL_FIELD_SELECT03, ACL_FIELD_SELECT04, ACL_FIELD_SELECT05, ACL_FIELD_SELECT06, ACL_FIELD_SELECT07, ACL_FIELD_SELECT08}, ++ {ACL_IP6DIP0WITHIPV4, ACL_IP6DIP1WITHIPV4,ACL_FIELD_SELECT09, ACL_FIELD_SELECT10, ACL_FIELD_SELECT11, ACL_FIELD_SELECT12, ACL_FIELD_SELECT13, ACL_FIELD_SELECT14}, ++ {ACL_VIDRANGE, ACL_IPRANGE, ACL_PORTRANGE, ACL_CTAG, ACL_STAG, ACL_FIELD_SELECT13, ACL_FIELD_SELECT14, ACL_FIELD_SELECT15} ++}; ++ ++CONST_T rtk_uint8 filter_advanceCaretagField[RTL8367C_ACLTEMPLATENO][2] = { ++ {TRUE, 7}, ++ {TRUE, 7}, ++ {FALSE, 0}, ++ {FALSE, 0}, ++ {TRUE, 7}, ++}; ++ ++ ++CONST_T rtk_uint8 filter_fieldTemplateIndex[FILTER_FIELD_END][RTK_FILTER_FIELD_USED_MAX] = { ++ {0x00, 0x01,0x02}, ++ {0x03, 0x04,0x05}, ++ {0x06}, ++ {0x43}, ++ {0x44}, ++ {0x10, 0x11}, ++ {0x12, 0x13}, ++ {0x24}, ++ {0x25}, ++ {0x35}, ++ {0x35}, ++ {0x20, 0x21,0x22,0x23}, ++ {0x30, 0x31,0x32,0x33}, ++ {0x26}, ++ {0x27}, ++ {0x14}, ++ {0x15}, ++ {0x16}, ++ {0x14}, ++ {0x15}, ++ {0x14}, ++ {0x14}, ++ {0x14}, ++ ++ {0x40}, ++ {0x41}, ++ {0x42}, ++ ++ {0x14}, ++ {0x15}, ++ {0x16}, ++ {0x22}, ++ {0x23}, ++ {0x24}, ++ {0x25}, ++ {0x26}, ++ {0x27}, ++ {0x32}, ++ {0x33}, ++ {0x34}, ++ {0x35}, ++ {0x36}, ++ {0x37}, ++ {0x47}, ++ ++ {0xFF} /* Pattern Match */ ++}; ++ ++CONST_T rtk_uint8 filter_fieldSize[FILTER_FIELD_END] = { ++ 3, 3, 1, 1, 1, ++ 2, 2, 1, 1, 1, 1, 4, 4, 1, 1, ++ 1, 1, 1, 1, 1, 1, 1, 1, ++ 1, 1, 1, ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ++ 8 ++}; ++ ++CONST_T rtk_uint16 field_selector[RTL8367C_FIELDSEL_FORMAT_NUMBER][2] = ++{ ++ {FIELDSEL_FORMAT_DEFAULT, 0}, /* Field Selector 0 */ ++ {FIELDSEL_FORMAT_DEFAULT, 0}, /* Field Selector 1 */ ++ {FIELDSEL_FORMAT_IPPAYLOAD, 12}, /* Field Selector 2 */ ++ {FIELDSEL_FORMAT_IPV6, 10}, /* Field Selector 3 */ ++ {FIELDSEL_FORMAT_IPV6, 8}, /* Field Selector 4 */ ++ {FIELDSEL_FORMAT_IPV4, 0}, /* Field Selector 5 */ ++ {FIELDSEL_FORMAT_IPV4, 8}, /* Field Selector 6 */ ++ {FIELDSEL_FORMAT_IPV6, 0}, /* Field Selector 7 */ ++ {FIELDSEL_FORMAT_IPV6, 6}, /* Field Selector 8 */ ++ {FIELDSEL_FORMAT_IPV6, 26}, /* Field Selector 9 */ ++ {FIELDSEL_FORMAT_IPV6, 24}, /* Field Selector 10 */ ++ {FIELDSEL_FORMAT_DEFAULT, 0}, /* Field Selector 11 */ ++ {FIELDSEL_FORMAT_IPV4, 6}, /* Field Selector 12 */ ++ {FIELDSEL_FORMAT_IPPAYLOAD, 0}, /* Field Selector 13 */ ++ {FIELDSEL_FORMAT_IPPAYLOAD, 2}, /* Field Selector 14 */ ++ {FIELDSEL_FORMAT_DEFAULT, 0} /* Field Selector 15 */ ++}; ++ ++ ++static rtk_api_ret_t _rtk_filter_igrAcl_writeDataField(rtl8367c_aclrule *aclRule, rtk_filter_field_t *fieldPtr); ++ ++ ++/* Function Name: ++ * rtk_filter_igrAcl_init ++ * Description: ++ * ACL initialization function ++ * Input: ++ * None ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_NULL_POINTER - Pointer pFilter_field or pFilter_cfg point to NULL. ++ * Note: ++ * This function enable and initialize ACL function ++ */ ++rtk_api_ret_t rtk_filter_igrAcl_init(void) ++{ ++ rtl8367c_acltemplate_t aclTemp; ++ rtk_uint32 i, j; ++ rtk_api_ret_t ret; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if ((ret = rtk_filter_igrAcl_cfg_delAll()) != RT_ERR_OK) ++ return ret; ++ ++ for(i = 0; i < RTL8367C_ACLTEMPLATENO; i++) ++ { ++ for(j = 0; j < RTL8367C_ACLRULEFIELDNO;j++) ++ aclTemp.field[j] = filter_templateField[i][j]; ++ ++ if ((ret = rtl8367c_setAsicAclTemplate(i, &aclTemp)) != RT_ERR_OK) ++ return ret; ++ } ++ ++ for(i = 0; i < RTL8367C_FIELDSEL_FORMAT_NUMBER; i++) ++ { ++ if ((ret = rtl8367c_setAsicFieldSelector(i, field_selector[i][0], field_selector[i][1])) != RT_ERR_OK) ++ return ret; ++ } ++ ++ RTK_SCAN_ALL_PHY_PORTMASK(i) ++ { ++ if ((ret = rtl8367c_setAsicAcl(i, TRUE)) != RT_ERR_OK) ++ return ret; ++ ++ if ((ret = rtl8367c_setAsicAclUnmatchedPermit(i, TRUE)) != RT_ERR_OK) ++ return ret; ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_filter_igrAcl_field_add ++ * Description: ++ * Add comparison rule to an ACL configuration ++ * Input: ++ * pFilter_cfg - The ACL configuration that this function will add comparison rule ++ * pFilter_field - The comparison rule that will be added. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_NULL_POINTER - Pointer pFilter_field or pFilter_cfg point to NULL. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * This function add a comparison rule (*pFilter_field) to an ACL configuration (*pFilter_cfg). ++ * Pointer pFilter_cfg points to an ACL configuration structure, this structure keeps multiple ACL ++ * comparison rules by means of linked list. Pointer pFilter_field will be added to linked ++ * list kept by structure that pFilter_cfg points to. ++ */ ++rtk_api_ret_t rtk_filter_igrAcl_field_add(rtk_filter_cfg_t* pFilter_cfg, rtk_filter_field_t* pFilter_field) ++{ ++ rtk_uint32 i; ++ rtk_filter_field_t *tailPtr; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pFilter_cfg || NULL == pFilter_field) ++ return RT_ERR_NULL_POINTER; ++ ++ if(pFilter_field->fieldType >= FILTER_FIELD_END) ++ return RT_ERR_ENTRY_INDEX; ++ ++ ++ if(0 == pFilter_field->fieldTemplateNo) ++ { ++ pFilter_field->fieldTemplateNo = filter_fieldSize[pFilter_field->fieldType]; ++ ++ for(i = 0; i < pFilter_field->fieldTemplateNo; i++) ++ { ++ pFilter_field->fieldTemplateIdx[i] = filter_fieldTemplateIndex[pFilter_field->fieldType][i]; ++ } ++ } ++ ++ if(NULL == pFilter_cfg->fieldHead) ++ { ++ pFilter_cfg->fieldHead = pFilter_field; ++ } ++ else ++ { ++ if (pFilter_cfg->fieldHead->next == NULL) ++ { ++ pFilter_cfg->fieldHead->next = pFilter_field; ++ } ++ else ++ { ++ tailPtr = pFilter_cfg->fieldHead->next; ++ while( tailPtr->next != NULL) ++ { ++ tailPtr = tailPtr->next; ++ } ++ tailPtr->next = pFilter_field; ++ } ++ } ++ ++ return RT_ERR_OK; ++} ++ ++static rtk_api_ret_t _rtk_filter_igrAcl_writeDataField(rtl8367c_aclrule *aclRule, rtk_filter_field_t *fieldPtr) ++{ ++ rtk_uint32 i, tempIdx,fieldIdx, ipValue, ipMask; ++ rtk_uint32 ip6addr[RTK_IPV6_ADDR_WORD_LENGTH]; ++ rtk_uint32 ip6mask[RTK_IPV6_ADDR_WORD_LENGTH]; ++ ++ for(i = 0; i < fieldPtr->fieldTemplateNo; i++) ++ { ++ tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4; ++ ++ aclRule[tempIdx].valid = TRUE; ++ } ++ ++ switch (fieldPtr->fieldType) ++ { ++ /* use DMAC structure as representative for mac structure */ ++ case FILTER_FIELD_DMAC: ++ case FILTER_FIELD_SMAC: ++ ++ for(i = 0; i < fieldPtr->fieldTemplateNo; i++) ++ { ++ tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4; ++ fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F; ++ ++ aclRule[tempIdx].data_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.mac.value.octet[5 - i*2] | (fieldPtr->filter_pattern_union.mac.value.octet[5 - (i*2 + 1)] << 8); ++ aclRule[tempIdx].care_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.mac.mask.octet[5 - i*2] | (fieldPtr->filter_pattern_union.mac.mask.octet[5 - (i*2 + 1)] << 8); ++ } ++ break; ++ case FILTER_FIELD_ETHERTYPE: ++ for(i = 0; i < fieldPtr->fieldTemplateNo; i++) ++ { ++ tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4; ++ fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F; ++ ++ aclRule[tempIdx].data_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.etherType.value; ++ aclRule[tempIdx].care_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.etherType.mask; ++ } ++ break; ++ case FILTER_FIELD_IPV4_SIP: ++ case FILTER_FIELD_IPV4_DIP: ++ ++ ipValue = fieldPtr->filter_pattern_union.sip.value; ++ ipMask = fieldPtr->filter_pattern_union.sip.mask; ++ ++ for(i = 0; i < fieldPtr->fieldTemplateNo; i++) ++ { ++ tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4; ++ fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F; ++ ++ aclRule[tempIdx].data_bits.field[fieldIdx] = (0xFFFF & (ipValue >> (i*16))); ++ aclRule[tempIdx].care_bits.field[fieldIdx] = (0xFFFF & (ipMask >> (i*16))); ++ } ++ break; ++ case FILTER_FIELD_IPV4_TOS: ++ for(i = 0; i < fieldPtr->fieldTemplateNo; i++) ++ { ++ tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4; ++ fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F; ++ ++ aclRule[tempIdx].data_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.ipTos.value & 0xFF; ++ aclRule[tempIdx].care_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.ipTos.mask & 0xFF; ++ } ++ break; ++ case FILTER_FIELD_IPV4_PROTOCOL: ++ for(i = 0; i < fieldPtr->fieldTemplateNo; i++) ++ { ++ tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4; ++ fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F; ++ ++ aclRule[tempIdx].data_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.protocol.value & 0xFF; ++ aclRule[tempIdx].care_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.protocol.mask & 0xFF; ++ } ++ break; ++ case FILTER_FIELD_IPV6_SIPV6: ++ case FILTER_FIELD_IPV6_DIPV6: ++ for(i = 0; i < RTK_IPV6_ADDR_WORD_LENGTH; i++) ++ { ++ ip6addr[i] = fieldPtr->filter_pattern_union.sipv6.value.addr[i]; ++ ip6mask[i] = fieldPtr->filter_pattern_union.sipv6.mask.addr[i]; ++ } ++ ++ for(i = 0; i < fieldPtr->fieldTemplateNo; i++) ++ { ++ tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4; ++ fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F; ++ ++ if(i < 2) ++ { ++ aclRule[tempIdx].data_bits.field[fieldIdx] = ((ip6addr[0] & (0xFFFF << (i * 16))) >> (i * 16)); ++ aclRule[tempIdx].care_bits.field[fieldIdx] = ((ip6mask[0] & (0xFFFF << (i * 16))) >> (i * 16)); ++ } ++ else ++ { ++ /*default ACL template for ipv6 address supports MSB 32-bits and LSB 32-bits only*/ ++ aclRule[tempIdx].data_bits.field[fieldIdx] = ((ip6addr[3] & (0xFFFF << ((i&1) * 16))) >> ((i&1) * 16)); ++ aclRule[tempIdx].care_bits.field[fieldIdx] = ((ip6mask[3] & (0xFFFF << ((i&1) * 16))) >> ((i&1) * 16)); ++ } ++ } ++ ++ break; ++ case FILTER_FIELD_CTAG: ++ case FILTER_FIELD_STAG: ++ ++ for(i = 0; i < fieldPtr->fieldTemplateNo; i++) ++ { ++ tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4; ++ fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F; ++ ++ aclRule[tempIdx].data_bits.field[fieldIdx] = (fieldPtr->filter_pattern_union.l2tag.pri.value << 13) | (fieldPtr->filter_pattern_union.l2tag.cfi.value << 12) | fieldPtr->filter_pattern_union.l2tag.vid.value; ++ aclRule[tempIdx].care_bits.field[fieldIdx] = (fieldPtr->filter_pattern_union.l2tag.pri.mask << 13) | (fieldPtr->filter_pattern_union.l2tag.cfi.mask << 12) | fieldPtr->filter_pattern_union.l2tag.vid.mask; ++ } ++ break; ++ case FILTER_FIELD_IPV4_FLAG: ++ ++ for(i = 0; i < fieldPtr->fieldTemplateNo; i++) ++ { ++ tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4; ++ fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F; ++ ++ aclRule[tempIdx].data_bits.field[fieldIdx] &= 0x1FFF; ++ aclRule[tempIdx].data_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.ipFlag.xf.value << 15); ++ aclRule[tempIdx].data_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.ipFlag.df.value << 14); ++ aclRule[tempIdx].data_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.ipFlag.mf.value << 13); ++ ++ aclRule[tempIdx].care_bits.field[fieldIdx] &= 0x1FFF; ++ aclRule[tempIdx].care_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.ipFlag.xf.mask << 15); ++ aclRule[tempIdx].care_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.ipFlag.df.mask << 14); ++ aclRule[tempIdx].care_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.ipFlag.mf.mask << 13); ++ } ++ ++ break; ++ case FILTER_FIELD_IPV4_OFFSET: ++ ++ for(i = 0; i < fieldPtr->fieldTemplateNo; i++) ++ { ++ tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4; ++ fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F; ++ ++ aclRule[tempIdx].data_bits.field[fieldIdx] &= 0xE000; ++ aclRule[tempIdx].data_bits.field[fieldIdx] |= fieldPtr->filter_pattern_union.inData.value; ++ ++ aclRule[tempIdx].care_bits.field[fieldIdx] &= 0xE000; ++ aclRule[tempIdx].care_bits.field[fieldIdx] |= fieldPtr->filter_pattern_union.inData.mask; ++ } ++ ++ break; ++ ++ case FILTER_FIELD_IPV6_TRAFFIC_CLASS: ++ for(i = 0; i < fieldPtr->fieldTemplateNo; i++) ++ { ++ tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4; ++ fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F; ++ ++ ++ aclRule[tempIdx].data_bits.field[fieldIdx] = (fieldPtr->filter_pattern_union.inData.value << 4)&0x0FF0; ++ aclRule[tempIdx].care_bits.field[fieldIdx] = (fieldPtr->filter_pattern_union.inData.mask << 4)&0x0FF0; ++ } ++ break; ++ case FILTER_FIELD_IPV6_NEXT_HEADER: ++ for(i = 0; i < fieldPtr->fieldTemplateNo; i++) ++ { ++ tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4; ++ fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F; ++ ++ aclRule[tempIdx].data_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.inData.value << 8; ++ aclRule[tempIdx].care_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.inData.mask << 8; ++ } ++ break; ++ case FILTER_FIELD_TCP_SPORT: ++ for(i = 0; i < fieldPtr->fieldTemplateNo; i++) ++ { ++ tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4; ++ fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F; ++ ++ aclRule[tempIdx].data_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.tcpSrcPort.value; ++ aclRule[tempIdx].care_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.tcpSrcPort.mask; ++ } ++ break; ++ case FILTER_FIELD_TCP_DPORT: ++ for(i = 0; i < fieldPtr->fieldTemplateNo; i++) ++ { ++ tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4; ++ fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F; ++ ++ aclRule[tempIdx].data_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.tcpDstPort.value; ++ aclRule[tempIdx].care_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.tcpDstPort.mask; ++ } ++ break; ++ case FILTER_FIELD_TCP_FLAG: ++ ++ for(i = 0; i < fieldPtr->fieldTemplateNo; i++) ++ { ++ tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4; ++ fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F; ++ ++ aclRule[tempIdx].data_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.tcpFlag.cwr.value << 7); ++ aclRule[tempIdx].data_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.tcpFlag.ece.value << 6); ++ aclRule[tempIdx].data_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.tcpFlag.urg.value << 5); ++ aclRule[tempIdx].data_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.tcpFlag.ack.value << 4); ++ aclRule[tempIdx].data_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.tcpFlag.psh.value << 3); ++ aclRule[tempIdx].data_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.tcpFlag.rst.value << 2); ++ aclRule[tempIdx].data_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.tcpFlag.syn.value << 1); ++ aclRule[tempIdx].data_bits.field[fieldIdx] |= fieldPtr->filter_pattern_union.tcpFlag.fin.value; ++ ++ aclRule[tempIdx].care_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.tcpFlag.cwr.mask << 7); ++ aclRule[tempIdx].care_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.tcpFlag.ece.mask << 6); ++ aclRule[tempIdx].care_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.tcpFlag.urg.mask << 5); ++ aclRule[tempIdx].care_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.tcpFlag.ack.mask << 4); ++ aclRule[tempIdx].care_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.tcpFlag.psh.mask << 3); ++ aclRule[tempIdx].care_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.tcpFlag.rst.mask << 2); ++ aclRule[tempIdx].care_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.tcpFlag.syn.mask << 1); ++ aclRule[tempIdx].care_bits.field[fieldIdx] |= fieldPtr->filter_pattern_union.tcpFlag.fin.mask; ++ } ++ break; ++ case FILTER_FIELD_UDP_SPORT: ++ for(i = 0; i < fieldPtr->fieldTemplateNo; i++) ++ { ++ tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4; ++ fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F; ++ ++ aclRule[tempIdx].data_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.udpSrcPort.value; ++ aclRule[tempIdx].care_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.udpSrcPort.mask; ++ } ++ break; ++ case FILTER_FIELD_UDP_DPORT: ++ for(i = 0; i < fieldPtr->fieldTemplateNo; i++) ++ { ++ tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4; ++ fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F; ++ ++ aclRule[tempIdx].data_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.udpDstPort.value; ++ aclRule[tempIdx].care_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.udpDstPort.mask; ++ } ++ break; ++ case FILTER_FIELD_ICMP_CODE: ++ for(i = 0; i < fieldPtr->fieldTemplateNo; i++) ++ { ++ tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4; ++ fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F; ++ ++ aclRule[tempIdx].data_bits.field[fieldIdx] &= 0xFF00; ++ aclRule[tempIdx].data_bits.field[fieldIdx] |= fieldPtr->filter_pattern_union.icmpCode.value; ++ aclRule[tempIdx].care_bits.field[fieldIdx] &= 0xFF00; ++ aclRule[tempIdx].care_bits.field[fieldIdx] |= fieldPtr->filter_pattern_union.icmpCode.mask; ++ } ++ break; ++ case FILTER_FIELD_ICMP_TYPE: ++ for(i = 0; i < fieldPtr->fieldTemplateNo; i++) ++ { ++ tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4; ++ fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F; ++ ++ aclRule[tempIdx].data_bits.field[fieldIdx] &= 0x00FF; ++ aclRule[tempIdx].data_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.icmpType.value << 8); ++ aclRule[tempIdx].care_bits.field[fieldIdx] &= 0x00FF; ++ aclRule[tempIdx].care_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.icmpType.mask << 8); ++ } ++ break; ++ case FILTER_FIELD_IGMP_TYPE: ++ for(i = 0; i < fieldPtr->fieldTemplateNo; i++) ++ { ++ tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4; ++ fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F; ++ ++ aclRule[tempIdx].data_bits.field[fieldIdx] = (fieldPtr->filter_pattern_union.igmpType.value << 8); ++ aclRule[tempIdx].care_bits.field[fieldIdx] = (fieldPtr->filter_pattern_union.igmpType.mask << 8); ++ } ++ break; ++ case FILTER_FIELD_PATTERN_MATCH: ++ for(i = 0; i < fieldPtr->fieldTemplateNo; i++) ++ { ++ tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4; ++ fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F; ++ ++ aclRule[tempIdx].data_bits.field[fieldIdx] = ((fieldPtr->filter_pattern_union.pattern.value[i/2] >> (16 * (i%2))) & 0x0000FFFF ); ++ aclRule[tempIdx].care_bits.field[fieldIdx] = ((fieldPtr->filter_pattern_union.pattern.mask[i/2] >> (16 * (i%2))) & 0x0000FFFF ); ++ } ++ break; ++ case FILTER_FIELD_VID_RANGE: ++ case FILTER_FIELD_IP_RANGE: ++ case FILTER_FIELD_PORT_RANGE: ++ default: ++ tempIdx = (fieldPtr->fieldTemplateIdx[0] & 0xF0) >> 4; ++ fieldIdx = fieldPtr->fieldTemplateIdx[0] & 0x0F; ++ ++ aclRule[tempIdx].data_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.inData.value; ++ aclRule[tempIdx].care_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.inData.mask; ++ break; ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_filter_igrAcl_cfg_add ++ * Description: ++ * Add an ACL configuration to ASIC ++ * Input: ++ * filter_id - Start index of ACL configuration. ++ * pFilter_cfg - The ACL configuration that this function will add comparison rule ++ * pFilter_action - Action(s) of ACL configuration. ++ * Output: ++ * ruleNum - number of rules written in ACL table ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_NULL_POINTER - Pointer pFilter_field or pFilter_cfg point to NULL. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_ENTRY_INDEX - Invalid filter_id . ++ * RT_ERR_NULL_POINTER - Pointer pFilter_action or pFilter_cfg point to NULL. ++ * RT_ERR_FILTER_INACL_ACT_NOT_SUPPORT - Action is not supported in this chip. ++ * RT_ERR_FILTER_INACL_RULE_NOT_SUPPORT - Rule is not supported. ++ * Note: ++ * This function store pFilter_cfg, pFilter_action into ASIC. The starting ++ * index(es) is filter_id. ++ */ ++rtk_api_ret_t rtk_filter_igrAcl_cfg_add(rtk_filter_id_t filter_id, rtk_filter_cfg_t* pFilter_cfg, rtk_filter_action_t* pFilter_action, rtk_filter_number_t *ruleNum) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 careTagData, careTagMask; ++ rtk_uint32 i,vidx, svidx, actType, ruleId; ++ rtk_uint32 aclActCtrl; ++ rtk_uint32 cpuPort; ++ rtk_filter_field_t* fieldPtr; ++ rtl8367c_aclrule aclRule[RTL8367C_ACLTEMPLATENO]; ++ rtl8367c_aclrule tempRule; ++ rtl8367c_acl_act_t aclAct; ++ rtk_uint32 noRulesAdd; ++ rtk_uint32 portmask; ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(filter_id > RTL8367C_ACLRULEMAX ) ++ return RT_ERR_ENTRY_INDEX; ++ ++ if((NULL == pFilter_cfg) || (NULL == pFilter_action) || (NULL == ruleNum)) ++ return RT_ERR_NULL_POINTER; ++ ++ fieldPtr = pFilter_cfg->fieldHead; ++ ++ /* init RULE */ ++ for(i = 0; i < RTL8367C_ACLTEMPLATENO; i++) ++ { ++ memset(&aclRule[i], 0, sizeof(rtl8367c_aclrule)); ++ ++ aclRule[i].data_bits.type= i; ++ aclRule[i].care_bits.type= 0x7; ++ } ++ ++ while(NULL != fieldPtr) ++ { ++ _rtk_filter_igrAcl_writeDataField(aclRule, fieldPtr); ++ ++ fieldPtr = fieldPtr->next; ++ } ++ ++ /*set care tag mask in User Defined Field 15*/ ++ /*Follow care tag should not be used while ACL template and User defined fields are fully control by system designer*/ ++ /*those advanced packet type care tag is used in default template design structure only*/ ++ careTagData = 0; ++ careTagMask = 0; ++ ++ for(i = CARE_TAG_TCP; i < CARE_TAG_END; i++) ++ { ++ if(pFilter_cfg->careTag.tagType[i].mask) ++ careTagMask = careTagMask | (1 << (i-CARE_TAG_TCP)); ++ ++ if(pFilter_cfg->careTag.tagType[i].value) ++ careTagData = careTagData | (1 << (i-CARE_TAG_TCP)); ++ } ++ ++ if(careTagData || careTagMask) ++ { ++ i = 0; ++ while(i < RTL8367C_ACLTEMPLATENO) ++ { ++ if(aclRule[i].valid == 1 && filter_advanceCaretagField[i][0] == TRUE) ++ { ++ ++ aclRule[i].data_bits.field[filter_advanceCaretagField[i][1]] = careTagData & 0xFFFF; ++ aclRule[i].care_bits.field[filter_advanceCaretagField[i][1]] = careTagMask & 0xFFFF; ++ break; ++ } ++ i++; ++ } ++ /*none of previous used template containing field 15*/ ++ if(i == RTL8367C_ACLTEMPLATENO) ++ { ++ i = 0; ++ while(i < RTL8367C_ACLTEMPLATENO) ++ { ++ if(filter_advanceCaretagField[i][0] == TRUE) ++ { ++ aclRule[i].data_bits.field[filter_advanceCaretagField[i][1]] = careTagData & 0xFFFF; ++ aclRule[i].care_bits.field[filter_advanceCaretagField[i][1]] = careTagMask & 0xFFFF; ++ aclRule[i].valid = 1; ++ break; ++ } ++ i++; ++ } ++ } ++ } ++ ++ /*Check rule number*/ ++ noRulesAdd = 0; ++ for(i = 0; i < RTL8367C_ACLTEMPLATENO; i++) ++ { ++ if(1 == aclRule[i].valid) ++ { ++ noRulesAdd ++; ++ } ++ } ++ ++ *ruleNum = noRulesAdd; ++ ++ if((filter_id + noRulesAdd - 1) > RTL8367C_ACLRULEMAX) ++ { ++ return RT_ERR_ENTRY_INDEX; ++ } ++ ++ /*set care tag mask in TAG Indicator*/ ++ careTagData = 0; ++ careTagMask = 0; ++ ++ for(i = 0; i <= CARE_TAG_IPV6;i++) ++ { ++ if(0 == pFilter_cfg->careTag.tagType[i].mask ) ++ { ++ careTagMask &= ~(1 << i); ++ } ++ else ++ { ++ careTagMask |= (1 << i); ++ if(0 == pFilter_cfg->careTag.tagType[i].value ) ++ careTagData &= ~(1 << i); ++ else ++ careTagData |= (1 << i); ++ } ++ } ++ ++ for(i = 0; i < RTL8367C_ACLTEMPLATENO; i++) ++ { ++ aclRule[i].data_bits.tag_exist = (careTagData) & ACL_RULE_CARETAG_MASK; ++ aclRule[i].care_bits.tag_exist = (careTagMask) & ACL_RULE_CARETAG_MASK; ++ } ++ ++ RTK_CHK_PORTMASK_VALID(&pFilter_cfg->activeport.value); ++ RTK_CHK_PORTMASK_VALID(&pFilter_cfg->activeport.mask); ++ ++ for(i = 0; i < RTL8367C_ACLTEMPLATENO; i++) ++ { ++ if(TRUE == aclRule[i].valid) ++ { ++ if(rtk_switch_portmask_L2P_get(&pFilter_cfg->activeport.value, &portmask) != RT_ERR_OK) ++ return RT_ERR_PORT_MASK; ++ ++ aclRule[i].data_bits.active_portmsk = portmask; ++ ++ if(rtk_switch_portmask_L2P_get(&pFilter_cfg->activeport.mask, &portmask) != RT_ERR_OK) ++ return RT_ERR_PORT_MASK; ++ ++ aclRule[i].care_bits.active_portmsk = portmask; ++ } ++ } ++ ++ if(pFilter_cfg->invert >= FILTER_INVERT_END ) ++ return RT_ERR_INPUT; ++ ++ ++ /*Last action gets high priority if actions are the same*/ ++ memset(&aclAct, 0, sizeof(rtl8367c_acl_act_t)); ++ aclActCtrl = 0; ++ for(actType = 0; actType < FILTER_ENACT_END; actType ++) ++ { ++ if(pFilter_action->actEnable[actType]) ++ { ++ switch (actType) ++ { ++ case FILTER_ENACT_CVLAN_INGRESS: ++ if(pFilter_action->filterCvlanVid > RTL8367C_EVIDMAX) ++ return RT_ERR_INPUT; ++ ++ if((retVal = rtk_vlan_checkAndCreateMbr(pFilter_action->filterCvlanVid, &vidx)) != RT_ERR_OK) ++ { ++ return retVal; ++ } ++ aclAct.cact = FILTER_ENACT_CVLAN_TYPE(actType); ++ aclAct.cvidx_cact = vidx; ++ ++ if(aclActCtrl &(FILTER_ENACT_CVLAN_MASK)) ++ { ++ if(aclAct.cact_ext == FILTER_ENACT_CACTEXT_TAGONLY) ++ aclAct.cact_ext = FILTER_ENACT_CACTEXT_BOTHVLANTAG; ++ } ++ else ++ { ++ aclAct.cact_ext = FILTER_ENACT_CACTEXT_VLANONLY; ++ } ++ ++ aclActCtrl |= FILTER_ENACT_CVLAN_MASK; ++ break; ++ case FILTER_ENACT_CVLAN_EGRESS: ++ if(pFilter_action->filterCvlanVid > RTL8367C_EVIDMAX) ++ return RT_ERR_INPUT; ++ ++ if((retVal = rtk_vlan_checkAndCreateMbr(pFilter_action->filterCvlanVid, &vidx)) != RT_ERR_OK) ++ return retVal; ++ ++ aclAct.cact = FILTER_ENACT_CVLAN_TYPE(actType); ++ aclAct.cvidx_cact = vidx; ++ ++ if(aclActCtrl &(FILTER_ENACT_CVLAN_MASK)) ++ { ++ if(aclAct.cact_ext == FILTER_ENACT_CACTEXT_TAGONLY) ++ aclAct.cact_ext = FILTER_ENACT_CACTEXT_BOTHVLANTAG; ++ } ++ else ++ { ++ aclAct.cact_ext = FILTER_ENACT_CACTEXT_VLANONLY; ++ } ++ ++ aclActCtrl |= FILTER_ENACT_CVLAN_MASK; ++ break; ++ case FILTER_ENACT_CVLAN_SVID: ++ ++ aclAct.cact = FILTER_ENACT_CVLAN_TYPE(actType); ++ ++ if(aclActCtrl &(FILTER_ENACT_CVLAN_MASK)) ++ { ++ if(aclAct.cact_ext == FILTER_ENACT_CACTEXT_TAGONLY) ++ aclAct.cact_ext = FILTER_ENACT_CACTEXT_BOTHVLANTAG; ++ } ++ else ++ { ++ aclAct.cact_ext = FILTER_ENACT_CACTEXT_VLANONLY; ++ } ++ ++ aclActCtrl |= FILTER_ENACT_CVLAN_MASK; ++ break; ++ case FILTER_ENACT_POLICING_1: ++ if(pFilter_action->filterPolicingIdx[1] >= (RTK_METER_NUM + RTL8367C_MAX_LOG_CNT_NUM)) ++ return RT_ERR_INPUT; ++ ++ aclAct.cact = FILTER_ENACT_CVLAN_TYPE(actType); ++ aclAct.cvidx_cact = pFilter_action->filterPolicingIdx[1]; ++ ++ if(aclActCtrl &(FILTER_ENACT_CVLAN_MASK)) ++ { ++ if(aclAct.cact_ext == FILTER_ENACT_CACTEXT_TAGONLY) ++ aclAct.cact_ext = FILTER_ENACT_CACTEXT_BOTHVLANTAG; ++ } ++ else ++ { ++ aclAct.cact_ext = FILTER_ENACT_CACTEXT_VLANONLY; ++ } ++ ++ aclActCtrl |= FILTER_ENACT_CVLAN_MASK; ++ break; ++ ++ case FILTER_ENACT_SVLAN_INGRESS: ++ case FILTER_ENACT_SVLAN_EGRESS: ++ ++ if((retVal = rtk_svlan_checkAndCreateMbr(pFilter_action->filterSvlanVid, &svidx)) != RT_ERR_OK) ++ return retVal; ++ ++ aclAct.sact = FILTER_ENACT_SVLAN_TYPE(actType); ++ aclAct.svidx_sact = svidx; ++ aclActCtrl |= FILTER_ENACT_SVLAN_MASK; ++ break; ++ case FILTER_ENACT_SVLAN_CVID: ++ ++ aclAct.sact = FILTER_ENACT_SVLAN_TYPE(actType); ++ aclActCtrl |= FILTER_ENACT_SVLAN_MASK; ++ break; ++ case FILTER_ENACT_POLICING_2: ++ if(pFilter_action->filterPolicingIdx[2] >= (RTK_METER_NUM + RTL8367C_MAX_LOG_CNT_NUM)) ++ return RT_ERR_INPUT; ++ ++ aclAct.sact = FILTER_ENACT_SVLAN_TYPE(actType); ++ aclAct.svidx_sact = pFilter_action->filterPolicingIdx[2]; ++ aclActCtrl |= FILTER_ENACT_SVLAN_MASK; ++ break; ++ case FILTER_ENACT_POLICING_0: ++ if(pFilter_action->filterPolicingIdx[0] >= (RTK_METER_NUM + RTL8367C_MAX_LOG_CNT_NUM)) ++ return RT_ERR_INPUT; ++ ++ aclAct.aclmeteridx = pFilter_action->filterPolicingIdx[0]; ++ aclActCtrl |= FILTER_ENACT_POLICING_MASK; ++ break; ++ case FILTER_ENACT_PRIORITY: ++ case FILTER_ENACT_1P_REMARK: ++ if(pFilter_action->filterPriority > RTL8367C_PRIMAX) ++ return RT_ERR_INPUT; ++ ++ aclAct.priact = FILTER_ENACT_PRI_TYPE(actType); ++ aclAct.pridx = pFilter_action->filterPriority; ++ aclActCtrl |= FILTER_ENACT_PRIORITY_MASK; ++ break; ++ case FILTER_ENACT_DSCP_REMARK: ++ if(pFilter_action->filterPriority > RTL8367C_DSCPMAX) ++ return RT_ERR_INPUT; ++ ++ aclAct.priact = FILTER_ENACT_PRI_TYPE(actType); ++ aclAct.pridx = pFilter_action->filterPriority; ++ aclActCtrl |= FILTER_ENACT_PRIORITY_MASK; ++ break; ++ case FILTER_ENACT_POLICING_3: ++ if(pFilter_action->filterPriority >= (RTK_METER_NUM + RTL8367C_MAX_LOG_CNT_NUM)) ++ return RT_ERR_INPUT; ++ ++ aclAct.priact = FILTER_ENACT_PRI_TYPE(actType); ++ aclAct.pridx = pFilter_action->filterPolicingIdx[3]; ++ aclActCtrl |= FILTER_ENACT_PRIORITY_MASK; ++ break; ++ case FILTER_ENACT_DROP: ++ ++ aclAct.fwdact = FILTER_ENACT_FWD_TYPE(FILTER_ENACT_REDIRECT); ++ aclAct.fwdact_ext = FALSE; ++ ++ aclAct.fwdpmask = 0; ++ aclActCtrl |= FILTER_ENACT_FWD_MASK; ++ break; ++ case FILTER_ENACT_REDIRECT: ++ RTK_CHK_PORTMASK_VALID(&pFilter_action->filterPortmask); ++ ++ aclAct.fwdact = FILTER_ENACT_FWD_TYPE(actType); ++ aclAct.fwdact_ext = FALSE; ++ ++ if(rtk_switch_portmask_L2P_get(&pFilter_action->filterPortmask, &portmask) != RT_ERR_OK) ++ return RT_ERR_PORT_MASK; ++ aclAct.fwdpmask = portmask; ++ ++ aclActCtrl |= FILTER_ENACT_FWD_MASK; ++ break; ++ ++ case FILTER_ENACT_ADD_DSTPORT: ++ RTK_CHK_PORTMASK_VALID(&pFilter_action->filterPortmask); ++ ++ aclAct.fwdact = FILTER_ENACT_FWD_TYPE(actType); ++ aclAct.fwdact_ext = FALSE; ++ ++ if(rtk_switch_portmask_L2P_get(&pFilter_action->filterPortmask, &portmask) != RT_ERR_OK) ++ return RT_ERR_PORT_MASK; ++ aclAct.fwdpmask = portmask; ++ ++ aclActCtrl |= FILTER_ENACT_FWD_MASK; ++ break; ++ case FILTER_ENACT_MIRROR: ++ RTK_CHK_PORTMASK_VALID(&pFilter_action->filterPortmask); ++ ++ aclAct.fwdact = FILTER_ENACT_FWD_TYPE(actType); ++ aclAct.cact_ext = FALSE; ++ ++ if(rtk_switch_portmask_L2P_get(&pFilter_action->filterPortmask, &portmask) != RT_ERR_OK) ++ return RT_ERR_PORT_MASK; ++ aclAct.fwdpmask = portmask; ++ ++ aclActCtrl |= FILTER_ENACT_FWD_MASK; ++ break; ++ case FILTER_ENACT_TRAP_CPU: ++ ++ aclAct.fwdact = FILTER_ENACT_FWD_TYPE(actType); ++ aclAct.fwdact_ext = FALSE; ++ ++ aclActCtrl |= FILTER_ENACT_FWD_MASK; ++ break; ++ case FILTER_ENACT_COPY_CPU: ++ if((retVal = rtl8367c_getAsicCputagTrapPort(&cpuPort)) != RT_ERR_OK) ++ return retVal; ++ ++ aclAct.fwdact = FILTER_ENACT_FWD_TYPE(FILTER_ENACT_MIRROR); ++ aclAct.fwdact_ext = FALSE; ++ ++ aclAct.fwdpmask = 1 << cpuPort; ++ aclActCtrl |= FILTER_ENACT_FWD_MASK; ++ break; ++ case FILTER_ENACT_ISOLATION: ++ RTK_CHK_PORTMASK_VALID(&pFilter_action->filterPortmask); ++ ++ aclAct.fwdact_ext = TRUE; ++ ++ if(rtk_switch_portmask_L2P_get(&pFilter_action->filterPortmask, &portmask) != RT_ERR_OK) ++ return RT_ERR_PORT_MASK; ++ aclAct.fwdpmask = portmask; ++ ++ aclActCtrl |= FILTER_ENACT_FWD_MASK; ++ break; ++ ++ case FILTER_ENACT_INTERRUPT: ++ ++ aclAct.aclint = TRUE; ++ aclActCtrl |= FILTER_ENACT_INTGPIO_MASK; ++ break; ++ case FILTER_ENACT_GPO: ++ ++ aclAct.gpio_en = TRUE; ++ aclAct.gpio_pin = pFilter_action->filterPin; ++ aclActCtrl |= FILTER_ENACT_INTGPIO_MASK; ++ break; ++ case FILTER_ENACT_EGRESSCTAG_TAG: ++ ++ if(aclActCtrl &(FILTER_ENACT_CVLAN_MASK)) ++ { ++ if(aclAct.cact_ext == FILTER_ENACT_CACTEXT_VLANONLY) ++ aclAct.cact_ext = FILTER_ENACT_CACTEXT_BOTHVLANTAG; ++ } ++ else ++ { ++ aclAct.cact_ext = FILTER_ENACT_CACTEXT_TAGONLY; ++ } ++ aclAct.tag_fmt = FILTER_CTAGFMT_TAG; ++ aclActCtrl |= FILTER_ENACT_CVLAN_MASK; ++ break; ++ case FILTER_ENACT_EGRESSCTAG_UNTAG: ++ ++ if(aclActCtrl &(FILTER_ENACT_CVLAN_MASK)) ++ { ++ if(aclAct.cact_ext == FILTER_ENACT_CACTEXT_VLANONLY) ++ aclAct.cact_ext = FILTER_ENACT_CACTEXT_BOTHVLANTAG; ++ } ++ else ++ { ++ aclAct.cact_ext = FILTER_ENACT_CACTEXT_TAGONLY; ++ } ++ aclAct.tag_fmt = FILTER_CTAGFMT_UNTAG; ++ aclActCtrl |= FILTER_ENACT_CVLAN_MASK; ++ break; ++ case FILTER_ENACT_EGRESSCTAG_KEEP: ++ ++ if(aclActCtrl &(FILTER_ENACT_CVLAN_MASK)) ++ { ++ if(aclAct.cact_ext == FILTER_ENACT_CACTEXT_VLANONLY) ++ aclAct.cact_ext = FILTER_ENACT_CACTEXT_BOTHVLANTAG; ++ } ++ else ++ { ++ aclAct.cact_ext = FILTER_ENACT_CACTEXT_TAGONLY; ++ } ++ aclAct.tag_fmt = FILTER_CTAGFMT_KEEP; ++ aclActCtrl |= FILTER_ENACT_CVLAN_MASK; ++ break; ++ case FILTER_ENACT_EGRESSCTAG_KEEPAND1PRMK: ++ ++ if(aclActCtrl &(FILTER_ENACT_CVLAN_MASK)) ++ { ++ if(aclAct.cact_ext == FILTER_ENACT_CACTEXT_VLANONLY) ++ aclAct.cact_ext = FILTER_ENACT_CACTEXT_BOTHVLANTAG; ++ } ++ else ++ { ++ aclAct.cact_ext = FILTER_ENACT_CACTEXT_TAGONLY; ++ } ++ aclAct.tag_fmt = FILTER_CTAGFMT_KEEP1PRMK; ++ aclActCtrl |= FILTER_ENACT_CVLAN_MASK; ++ break; ++ default: ++ return RT_ERR_FILTER_INACL_ACT_NOT_SUPPORT; ++ } ++ } ++ } ++ ++ ++ /*check if free ACL rules are enough*/ ++ for(i = filter_id; i < (filter_id + noRulesAdd); i++) ++ { ++ if((retVal = rtl8367c_getAsicAclRule(i, &tempRule)) != RT_ERR_OK ) ++ return retVal; ++ ++ if(tempRule.valid == TRUE) ++ { ++ return RT_ERR_TBL_FULL; ++ } ++ } ++ ++ ruleId = 0; ++ for(i = 0; i < RTL8367C_ACLTEMPLATENO; i++) ++ { ++ if(aclRule[i].valid == TRUE) ++ { ++ /* write ACL action control */ ++ if((retVal = rtl8367c_setAsicAclActCtrl(filter_id + ruleId, aclActCtrl)) != RT_ERR_OK ) ++ return retVal; ++ /* write ACL action */ ++ if((retVal = rtl8367c_setAsicAclAct(filter_id + ruleId, &aclAct)) != RT_ERR_OK ) ++ return retVal; ++ ++ /* write ACL not */ ++ if((retVal = rtl8367c_setAsicAclNot(filter_id + ruleId, pFilter_cfg->invert)) != RT_ERR_OK ) ++ return retVal; ++ /* write ACL rule */ ++ if((retVal = rtl8367c_setAsicAclRule(filter_id + ruleId, &aclRule[i])) != RT_ERR_OK ) ++ return retVal; ++ ++ /* only the first rule will be written with input action control, aclActCtrl of other rules will be zero */ ++ aclActCtrl = 0; ++ memset(&aclAct, 0, sizeof(rtl8367c_acl_act_t)); ++ ++ ruleId ++; ++ } ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_filter_igrAcl_cfg_del ++ * Description: ++ * Delete an ACL configuration from ASIC ++ * Input: ++ * filter_id - Start index of ACL configuration. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_FILTER_ENTRYIDX - Invalid filter_id. ++ * Note: ++ * This function delete a group of ACL rules starting from filter_id. ++ */ ++rtk_api_ret_t rtk_filter_igrAcl_cfg_del(rtk_filter_id_t filter_id) ++{ ++ rtl8367c_aclrule initRule; ++ rtl8367c_acl_act_t initAct; ++ rtk_api_ret_t ret; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(filter_id > RTL8367C_ACLRULEMAX ) ++ return RT_ERR_FILTER_ENTRYIDX; ++ ++ memset(&initRule, 0, sizeof(rtl8367c_aclrule)); ++ memset(&initAct, 0, sizeof(rtl8367c_acl_act_t)); ++ ++ if((ret = rtl8367c_setAsicAclRule(filter_id, &initRule)) != RT_ERR_OK) ++ return ret; ++ if((ret = rtl8367c_setAsicAclActCtrl(filter_id, FILTER_ENACT_INIT_MASK))!= RT_ERR_OK) ++ return ret; ++ if((ret = rtl8367c_setAsicAclAct(filter_id, &initAct)) != RT_ERR_OK) ++ return ret; ++ if((ret = rtl8367c_setAsicAclNot(filter_id, DISABLED)) != RT_ERR_OK ) ++ return ret; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_filter_igrAcl_cfg_delAll ++ * Description: ++ * Delete all ACL entries from ASIC ++ * Input: ++ * None ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * This function delete all ACL configuration from ASIC. ++ */ ++rtk_api_ret_t rtk_filter_igrAcl_cfg_delAll(void) ++{ ++ rtk_uint32 i; ++ rtk_api_ret_t ret; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ for(i = 0; i < RTL8367C_ACLRULENO; i++) ++ { ++ if((ret = rtl8367c_setAsicAclActCtrl(i, FILTER_ENACT_INIT_MASK))!= RT_ERR_OK) ++ return ret; ++ if((ret = rtl8367c_setAsicAclNot(i, DISABLED)) != RT_ERR_OK ) ++ return ret; ++ } ++ ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_ACL_RESET_CFG, RTL8367C_ACL_RESET_CFG_OFFSET, TRUE);; ++} ++ ++/* Function Name: ++ * rtk_filter_igrAcl_cfg_get ++ * Description: ++ * Get one ingress ACL configuration from ASIC. ++ * Input: ++ * filter_id - Start index of ACL configuration. ++ * Output: ++ * pFilter_cfg - buffer pointer of ingress ACL data ++ * pFilter_action - buffer pointer of ingress ACL action ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_NULL_POINTER - Pointer pFilter_action or pFilter_cfg point to NULL. ++ * RT_ERR_FILTER_ENTRYIDX - Invalid entry index. ++ * Note: ++ * This function get configuration from ASIC. ++ */ ++rtk_api_ret_t rtk_filter_igrAcl_cfg_get(rtk_filter_id_t filter_id, rtk_filter_cfg_raw_t *pFilter_cfg, rtk_filter_action_t *pAction) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 i, tmp; ++ rtl8367c_aclrule aclRule; ++ rtl8367c_acl_act_t aclAct; ++ rtk_uint32 cpuPort; ++ rtl8367c_acltemplate_t type; ++ rtl8367c_svlan_memconf_t svlan_cfg; ++ rtl8367c_vlanconfiguser vlanMC; ++ rtk_uint32 phyPmask; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pFilter_cfg || NULL == pAction) ++ return RT_ERR_NULL_POINTER; ++ ++ if(filter_id > RTL8367C_ACLRULEMAX) ++ return RT_ERR_ENTRY_INDEX; ++ ++ if ((retVal = rtl8367c_getAsicAclRule(filter_id, &aclRule)) != RT_ERR_OK) ++ return retVal; ++ ++ /* Check valid */ ++ if(aclRule.valid == 0) ++ { ++ pFilter_cfg->valid = DISABLED; ++ return RT_ERR_OK; ++ } ++ ++ phyPmask = aclRule.data_bits.active_portmsk; ++ if(rtk_switch_portmask_P2L_get(phyPmask,&(pFilter_cfg->activeport.value)) != RT_ERR_OK) ++ return RT_ERR_FAILED; ++ ++ phyPmask = aclRule.care_bits.active_portmsk; ++ if(rtk_switch_portmask_P2L_get(phyPmask,&(pFilter_cfg->activeport.mask)) != RT_ERR_OK) ++ return RT_ERR_FAILED; ++ ++ for(i = 0; i <= CARE_TAG_IPV6; i++) ++ { ++ if(aclRule.data_bits.tag_exist & (1 << i)) ++ pFilter_cfg->careTag.tagType[i].value = 1; ++ else ++ pFilter_cfg->careTag.tagType[i].value = 0; ++ ++ if (aclRule.care_bits.tag_exist & (1 << i)) ++ pFilter_cfg->careTag.tagType[i].mask = 1; ++ else ++ pFilter_cfg->careTag.tagType[i].mask = 0; ++ } ++ ++ if(filter_advanceCaretagField[aclRule.data_bits.type][0] == TRUE) ++ { ++ /* Advanced Care tag setting */ ++ for(i = CARE_TAG_TCP; i < CARE_TAG_END; i++) ++ { ++ if(aclRule.data_bits.field[filter_advanceCaretagField[aclRule.data_bits.type][1]] & (0x0001 << (i-CARE_TAG_TCP)) ) ++ pFilter_cfg->careTag.tagType[i].value = 1; ++ else ++ pFilter_cfg->careTag.tagType[i].value = 0; ++ ++ if(aclRule.care_bits.field[filter_advanceCaretagField[aclRule.care_bits.type][1]] & (0x0001 << (i-CARE_TAG_TCP)) ) ++ pFilter_cfg->careTag.tagType[i].mask = 1; ++ else ++ pFilter_cfg->careTag.tagType[i].mask = 0; ++ } ++ } ++ ++ for(i = 0; i < RTL8367C_ACLRULEFIELDNO; i++) ++ { ++ pFilter_cfg->careFieldRaw[i] = aclRule.care_bits.field[i]; ++ pFilter_cfg->dataFieldRaw[i] = aclRule.data_bits.field[i]; ++ } ++ ++ if ((retVal = rtl8367c_getAsicAclNot(filter_id, &tmp))!= RT_ERR_OK) ++ return retVal; ++ ++ pFilter_cfg->invert = tmp; ++ ++ pFilter_cfg->valid = aclRule.valid; ++ ++ memset(pAction, 0, sizeof(rtk_filter_action_t)); ++ ++ if ((retVal = rtl8367c_getAsicAclActCtrl(filter_id, &tmp))!= RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_getAsicAclAct(filter_id, &aclAct)) != RT_ERR_OK) ++ return retVal; ++ ++ if(tmp & FILTER_ENACT_FWD_MASK) ++ { ++ if(TRUE == aclAct.fwdact_ext) ++ { ++ pAction->actEnable[FILTER_ENACT_ISOLATION] = TRUE; ++ ++ phyPmask = aclAct.fwdpmask; ++ if(rtk_switch_portmask_P2L_get(phyPmask,&(pAction->filterPortmask)) != RT_ERR_OK) ++ return RT_ERR_FAILED; ++ } ++ else if(aclAct.fwdact == RTL8367C_ACL_FWD_TRAP) ++ { ++ pAction->actEnable[FILTER_ENACT_TRAP_CPU] = TRUE; ++ } ++ else if (aclAct.fwdact == RTL8367C_ACL_FWD_MIRRORFUNTION ) ++ { ++ pAction->actEnable[FILTER_ENACT_MIRROR] = TRUE; ++ ++ phyPmask = aclAct.fwdpmask; ++ if(rtk_switch_portmask_P2L_get(phyPmask,&(pAction->filterPortmask)) != RT_ERR_OK) ++ return RT_ERR_FAILED; ++ } ++ else if (aclAct.fwdact == RTL8367C_ACL_FWD_REDIRECT) ++ { ++ if(aclAct.fwdpmask == 0 ) ++ pAction->actEnable[FILTER_ENACT_DROP] = TRUE; ++ else ++ { ++ pAction->actEnable[FILTER_ENACT_REDIRECT] = TRUE; ++ ++ phyPmask = aclAct.fwdpmask; ++ if(rtk_switch_portmask_P2L_get(phyPmask,&(pAction->filterPortmask)) != RT_ERR_OK) ++ return RT_ERR_FAILED; ++ } ++ } ++ else if (aclAct.fwdact == RTL8367C_ACL_FWD_MIRROR) ++ { ++ if((retVal = rtl8367c_getAsicCputagTrapPort(&cpuPort)) != RT_ERR_OK) ++ return retVal; ++ if (aclAct.fwdpmask == (1 << cpuPort)) ++ { ++ pAction->actEnable[FILTER_ENACT_COPY_CPU] = TRUE; ++ } ++ else ++ { ++ pAction->actEnable[FILTER_ENACT_ADD_DSTPORT] = TRUE; ++ ++ phyPmask = aclAct.fwdpmask; ++ if(rtk_switch_portmask_P2L_get(phyPmask,&(pAction->filterPortmask)) != RT_ERR_OK) ++ return RT_ERR_FAILED; ++ } ++ } ++ else ++ { ++ return RT_ERR_FAILED; ++ } ++ } ++ ++ if(tmp & FILTER_ENACT_POLICING_MASK) ++ { ++ pAction->actEnable[FILTER_ENACT_POLICING_0] = TRUE; ++ pAction->filterPolicingIdx[0] = aclAct.aclmeteridx; ++ } ++ ++ if(tmp & FILTER_ENACT_PRIORITY_MASK) ++ { ++ if(aclAct.priact == FILTER_ENACT_PRI_TYPE(FILTER_ENACT_PRIORITY)) ++ { ++ pAction->actEnable[FILTER_ENACT_PRIORITY] = TRUE; ++ pAction->filterPriority = aclAct.pridx; ++ } ++ else if(aclAct.priact == FILTER_ENACT_PRI_TYPE(FILTER_ENACT_1P_REMARK)) ++ { ++ pAction->actEnable[FILTER_ENACT_1P_REMARK] = TRUE; ++ pAction->filterPriority = aclAct.pridx; ++ } ++ else if(aclAct.priact == FILTER_ENACT_PRI_TYPE(FILTER_ENACT_DSCP_REMARK)) ++ { ++ pAction->actEnable[FILTER_ENACT_DSCP_REMARK] = TRUE; ++ pAction->filterPriority = aclAct.pridx; ++ } ++ else if(aclAct.priact == FILTER_ENACT_PRI_TYPE(FILTER_ENACT_POLICING_3)) ++ { ++ pAction->actEnable[FILTER_ENACT_POLICING_3] = TRUE; ++ pAction->filterPolicingIdx[3] = aclAct.pridx; ++ } ++ } ++ ++ if(tmp & FILTER_ENACT_SVLAN_MASK) ++ { ++ if(aclAct.sact == FILTER_ENACT_SVLAN_TYPE(FILTER_ENACT_SVLAN_INGRESS)) ++ { ++ if((retVal = rtl8367c_getAsicSvlanMemberConfiguration(aclAct.svidx_sact, &svlan_cfg)) != RT_ERR_OK) ++ return retVal; ++ ++ pAction->actEnable[FILTER_ENACT_SVLAN_INGRESS] = TRUE; ++ pAction->filterSvlanIdx = aclAct.svidx_sact; ++ pAction->filterSvlanVid = svlan_cfg.vs_svid; ++ } ++ else if(aclAct.sact == FILTER_ENACT_SVLAN_TYPE(FILTER_ENACT_SVLAN_EGRESS)) ++ { ++ if((retVal = rtl8367c_getAsicSvlanMemberConfiguration(aclAct.svidx_sact, &svlan_cfg)) != RT_ERR_OK) ++ return retVal; ++ ++ pAction->actEnable[FILTER_ENACT_SVLAN_EGRESS] = TRUE; ++ pAction->filterSvlanIdx = aclAct.svidx_sact; ++ pAction->filterSvlanVid = svlan_cfg.vs_svid; ++ } ++ else if(aclAct.sact == FILTER_ENACT_SVLAN_TYPE(FILTER_ENACT_SVLAN_CVID)) ++ pAction->actEnable[FILTER_ENACT_SVLAN_CVID] = TRUE; ++ else if(aclAct.sact == FILTER_ENACT_SVLAN_TYPE(FILTER_ENACT_POLICING_2)) ++ { ++ pAction->actEnable[FILTER_ENACT_POLICING_2] = TRUE; ++ pAction->filterPolicingIdx[2] = aclAct.svidx_sact; ++ } ++ } ++ ++ ++ if(tmp & FILTER_ENACT_CVLAN_MASK) ++ { ++ if(FILTER_ENACT_CACTEXT_TAGONLY == aclAct.cact_ext || ++ FILTER_ENACT_CACTEXT_BOTHVLANTAG == aclAct.cact_ext ) ++ { ++ if(FILTER_CTAGFMT_UNTAG == aclAct.tag_fmt) ++ { ++ pAction->actEnable[FILTER_ENACT_EGRESSCTAG_UNTAG] = TRUE; ++ } ++ else if(FILTER_CTAGFMT_TAG == aclAct.tag_fmt) ++ { ++ pAction->actEnable[FILTER_ENACT_EGRESSCTAG_TAG] = TRUE; ++ } ++ else if(FILTER_CTAGFMT_KEEP == aclAct.tag_fmt) ++ { ++ pAction->actEnable[FILTER_ENACT_EGRESSCTAG_KEEP] = TRUE; ++ } ++ else if(FILTER_CTAGFMT_KEEP1PRMK== aclAct.tag_fmt) ++ { ++ pAction->actEnable[FILTER_ENACT_EGRESSCTAG_KEEPAND1PRMK] = TRUE; ++ } ++ ++ } ++ ++ if(FILTER_ENACT_CACTEXT_VLANONLY == aclAct.cact_ext || ++ FILTER_ENACT_CACTEXT_BOTHVLANTAG == aclAct.cact_ext ) ++ { ++ if(aclAct.cact == FILTER_ENACT_CVLAN_TYPE(FILTER_ENACT_CVLAN_INGRESS)) ++ { ++ if((retVal = rtl8367c_getAsicVlanMemberConfig(aclAct.cvidx_cact, &vlanMC)) != RT_ERR_OK) ++ return retVal; ++ ++ pAction->actEnable[FILTER_ENACT_CVLAN_INGRESS] = TRUE; ++ pAction->filterCvlanIdx = aclAct.cvidx_cact; ++ pAction->filterCvlanVid = vlanMC.evid; ++ } ++ else if(aclAct.cact == FILTER_ENACT_CVLAN_TYPE(FILTER_ENACT_CVLAN_EGRESS)) ++ { ++ if((retVal = rtl8367c_getAsicVlanMemberConfig(aclAct.cvidx_cact, &vlanMC)) != RT_ERR_OK) ++ return retVal; ++ ++ pAction->actEnable[FILTER_ENACT_CVLAN_EGRESS] = TRUE; ++ pAction->filterCvlanIdx = aclAct.cvidx_cact; ++ pAction->filterCvlanVid = vlanMC.evid; ++ } ++ else if(aclAct.cact == FILTER_ENACT_CVLAN_TYPE(FILTER_ENACT_CVLAN_SVID)) ++ { ++ pAction->actEnable[FILTER_ENACT_CVLAN_SVID] = TRUE; ++ } ++ else if(aclAct.cact == FILTER_ENACT_CVLAN_TYPE(FILTER_ENACT_POLICING_1)) ++ { ++ pAction->actEnable[FILTER_ENACT_POLICING_1] = TRUE; ++ pAction->filterPolicingIdx[1] = aclAct.cvidx_cact; ++ } ++ } ++ } ++ ++ if(tmp & FILTER_ENACT_INTGPIO_MASK) ++ { ++ if(TRUE == aclAct.aclint) ++ { ++ pAction->actEnable[FILTER_ENACT_INTERRUPT] = TRUE; ++ } ++ ++ if(TRUE == aclAct.gpio_en) ++ { ++ pAction->actEnable[FILTER_ENACT_GPO] = TRUE; ++ pAction->filterPin = aclAct.gpio_pin; ++ } ++ } ++ ++ /* Get field type of RAW data */ ++ if ((retVal = rtl8367c_getAsicAclTemplate(aclRule.data_bits.type, &type))!= RT_ERR_OK) ++ return retVal; ++ ++ for(i = 0; i < RTL8367C_ACLRULEFIELDNO; i++) ++ { ++ pFilter_cfg->fieldRawType[i] = type.field[i]; ++ }/* end of for(i...) */ ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_filter_igrAcl_unmatchAction_set ++ * Description: ++ * Set action to packets when no ACL configuration match ++ * Input: ++ * port - Port id. ++ * action - Action. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port id. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * This function sets action of packets when no ACL configuration matches. ++ */ ++rtk_api_ret_t rtk_filter_igrAcl_unmatchAction_set(rtk_port_t port, rtk_filter_unmatch_action_t action) ++{ ++ rtk_api_ret_t ret; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check port valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if(action >= FILTER_UNMATCH_END) ++ return RT_ERR_INPUT; ++ ++ if((ret = rtl8367c_setAsicAclUnmatchedPermit(rtk_switch_port_L2P_get(port), action)) != RT_ERR_OK) ++ return ret; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_filter_igrAcl_unmatchAction_get ++ * Description: ++ * Get action to packets when no ACL configuration match ++ * Input: ++ * port - Port id. ++ * Output: ++ * pAction - Action. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port id. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * This function gets action of packets when no ACL configruation matches. ++ */ ++rtk_api_ret_t rtk_filter_igrAcl_unmatchAction_get(rtk_port_t port, rtk_filter_unmatch_action_t* pAction) ++{ ++ rtk_api_ret_t ret; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pAction) ++ return RT_ERR_NULL_POINTER; ++ ++ /* Check port valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if((ret = rtl8367c_getAsicAclUnmatchedPermit(rtk_switch_port_L2P_get(port), pAction)) != RT_ERR_OK) ++ return ret; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_filter_igrAcl_state_set ++ * Description: ++ * Set state of ingress ACL. ++ * Input: ++ * port - Port id. ++ * state - Ingress ACL state. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port id. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * This function gets action of packets when no ACL configuration matches. ++ */ ++rtk_api_ret_t rtk_filter_igrAcl_state_set(rtk_port_t port, rtk_filter_state_t state) ++{ ++ rtk_api_ret_t ret; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check port valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if(state >= RTK_ENABLE_END) ++ return RT_ERR_INPUT; ++ ++ if((ret = rtl8367c_setAsicAcl(rtk_switch_port_L2P_get(port), state)) != RT_ERR_OK) ++ return ret; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_filter_igrAcl_state_get ++ * Description: ++ * Get state of ingress ACL. ++ * Input: ++ * port - Port id. ++ * Output: ++ * pState - Ingress ACL state. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port id. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * This function gets action of packets when no ACL configuration matches. ++ */ ++rtk_api_ret_t rtk_filter_igrAcl_state_get(rtk_port_t port, rtk_filter_state_t* pState) ++{ ++ rtk_api_ret_t ret; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pState) ++ return RT_ERR_NULL_POINTER; ++ ++ /* Check port valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if((ret = rtl8367c_getAsicAcl(rtk_switch_port_L2P_get(port), pState)) != RT_ERR_OK) ++ return ret; ++ ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtk_filter_igrAcl_template_set ++ * Description: ++ * Set template of ingress ACL. ++ * Input: ++ * template - Ingress ACL template ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * This function set ACL template. ++ */ ++rtk_api_ret_t rtk_filter_igrAcl_template_set(rtk_filter_template_t *aclTemplate) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 idxField; ++ rtl8367c_acltemplate_t aclType; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(aclTemplate->index >= RTK_MAX_NUM_OF_FILTER_TYPE) ++ return RT_ERR_INPUT; ++ ++ for(idxField = 0; idxField < RTK_MAX_NUM_OF_FILTER_FIELD; idxField++) ++ { ++ if(aclTemplate->fieldType[idxField] < FILTER_FIELD_RAW_DMAC_15_0 || ++ (aclTemplate->fieldType[idxField] > FILTER_FIELD_RAW_CTAG && aclTemplate->fieldType[idxField] < FILTER_FIELD_RAW_IPV4_SIP_15_0 ) || ++ (aclTemplate->fieldType[idxField] > FILTER_FIELD_RAW_IPV4_DIP_31_16 && aclTemplate->fieldType[idxField] < FILTER_FIELD_RAW_IPV6_SIP_15_0 ) || ++ (aclTemplate->fieldType[idxField] > FILTER_FIELD_RAW_IPV6_DIP_31_16 && aclTemplate->fieldType[idxField] < FILTER_FIELD_RAW_VIDRANGE ) || ++ (aclTemplate->fieldType[idxField] > FILTER_FIELD_RAW_FIELD_VALID && aclTemplate->fieldType[idxField] < FILTER_FIELD_RAW_FIELD_SELECT00 ) || ++ aclTemplate->fieldType[idxField] >= FILTER_FIELD_RAW_END) ++ { ++ return RT_ERR_INPUT; ++ } ++ } ++ ++ for(idxField = 0; idxField < RTK_MAX_NUM_OF_FILTER_FIELD; idxField++) ++ { ++ aclType.field[idxField] = aclTemplate->fieldType[idxField]; ++ } ++ ++ if((retVal = rtl8367c_setAsicAclTemplate(aclTemplate->index, &aclType)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_filter_igrAcl_template_get ++ * Description: ++ * Get template of ingress ACL. ++ * Input: ++ * template - Ingress ACL template ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * This function gets template of ACL. ++ */ ++rtk_api_ret_t rtk_filter_igrAcl_template_get(rtk_filter_template_t *aclTemplate) ++{ ++ rtk_api_ret_t ret; ++ rtk_uint32 idxField; ++ rtl8367c_acltemplate_t aclType; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == aclTemplate) ++ return RT_ERR_NULL_POINTER; ++ ++ if(aclTemplate->index >= RTK_MAX_NUM_OF_FILTER_TYPE) ++ return RT_ERR_INPUT; ++ ++ if((ret = rtl8367c_getAsicAclTemplate(aclTemplate->index, &aclType)) != RT_ERR_OK) ++ return ret; ++ ++ for(idxField = 0; idxField < RTK_MAX_NUM_OF_FILTER_FIELD; idxField ++) ++ { ++ aclTemplate->fieldType[idxField] = aclType.field[idxField]; ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_filter_igrAcl_field_sel_set ++ * Description: ++ * Set user defined field selectors in HSB ++ * Input: ++ * index - index of field selector 0-15 ++ * format - Format of field selector ++ * offset - Retrieving data offset ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * System support 16 user defined field selectors. ++ * Each selector can be enabled or disable. ++ * User can defined retrieving 16-bits in many predefiend ++ * standard l2/l3/l4 payload. ++ */ ++rtk_api_ret_t rtk_filter_igrAcl_field_sel_set(rtk_uint32 index, rtk_field_sel_t format, rtk_uint32 offset) ++{ ++ rtk_api_ret_t ret; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(index >= RTL8367C_FIELDSEL_FORMAT_NUMBER) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ if(format >= FORMAT_END) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ if(offset > RTL8367C_FIELDSEL_MAX_OFFSET) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ if((ret = rtl8367c_setAsicFieldSelector(index, (rtk_uint32)format, offset)) != RT_ERR_OK) ++ return ret; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_filter_igrAcl_field_sel_get ++ * Description: ++ * Get user defined field selectors in HSB ++ * Input: ++ * index - index of field selector 0-15 ++ * Output: ++ * pFormat - Format of field selector ++ * pOffset - Retrieving data offset ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None. ++ */ ++rtk_api_ret_t rtk_filter_igrAcl_field_sel_get(rtk_uint32 index, rtk_field_sel_t *pFormat, rtk_uint32 *pOffset) ++{ ++ rtk_api_ret_t ret; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pFormat || NULL == pOffset) ++ return RT_ERR_NULL_POINTER; ++ ++ if(index >= RTL8367C_FIELDSEL_FORMAT_NUMBER) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ if((ret = rtl8367c_getAsicFieldSelector(index, pFormat, pOffset)) != RT_ERR_OK) ++ return ret; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_filter_iprange_set ++ * Description: ++ * Set IP Range check ++ * Input: ++ * index - index of IP Range 0-15 ++ * type - IP Range check type, 0:Delete a entry, 1: IPv4_SIP, 2: IPv4_DIP, 3:IPv6_SIP, 4:IPv6_DIP ++ * upperIp - The upper bound of IP range ++ * lowerIp - The lower Bound of IP range ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - The parameter is out of range ++ * RT_ERR_INPUT - Input error ++ * Note: ++ * upperIp must be larger or equal than lowerIp. ++ */ ++rtk_api_ret_t rtk_filter_iprange_set(rtk_uint32 index, rtk_filter_iprange_t type, ipaddr_t upperIp, ipaddr_t lowerIp) ++{ ++ rtk_api_ret_t ret; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(index > RTL8367C_ACLRANGEMAX) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ if(type >= IPRANGE_END) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ if(lowerIp > upperIp) ++ return RT_ERR_INPUT; ++ ++ if((ret = rtl8367c_setAsicAclIpRange(index, type, upperIp, lowerIp)) != RT_ERR_OK) ++ return ret; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_filter_iprange_get ++ * Description: ++ * Set IP Range check ++ * Input: ++ * index - index of IP Range 0-15 ++ * Output: ++ * pType - IP Range check type, 0:Delete a entry, 1: IPv4_SIP, 2: IPv4_DIP, 3:IPv6_SIP, 4:IPv6_DIP ++ * pUpperIp - The upper bound of IP range ++ * pLowerIp - The lower Bound of IP range ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - The parameter is out of range ++ * Note: ++ * None. ++ */ ++rtk_api_ret_t rtk_filter_iprange_get(rtk_uint32 index, rtk_filter_iprange_t *pType, ipaddr_t *pUpperIp, ipaddr_t *pLowerIp) ++{ ++ rtk_api_ret_t ret; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if((NULL == pType) || (NULL == pUpperIp) || (NULL == pLowerIp)) ++ return RT_ERR_NULL_POINTER; ++ ++ if(index > RTL8367C_ACLRANGEMAX) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ if((ret = rtl8367c_getAsicAclIpRange(index, pType, pUpperIp, pLowerIp)) != RT_ERR_OK) ++ return ret; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_filter_vidrange_set ++ * Description: ++ * Set VID Range check ++ * Input: ++ * index - index of VID Range 0-15 ++ * type - IP Range check type, 0:Delete a entry, 1: CVID, 2: SVID ++ * upperVid - The upper bound of VID range ++ * lowerVid - The lower Bound of VID range ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - The parameter is out of range ++ * RT_ERR_INPUT - Input error ++ * Note: ++ * upperVid must be larger or equal than lowerVid. ++ */ ++rtk_api_ret_t rtk_filter_vidrange_set(rtk_uint32 index, rtk_filter_vidrange_t type, rtk_uint32 upperVid, rtk_uint32 lowerVid) ++{ ++ rtk_api_ret_t ret; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(index > RTL8367C_ACLRANGEMAX) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ if(type >= VIDRANGE_END) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ if(lowerVid > upperVid) ++ return RT_ERR_INPUT; ++ ++ if( (upperVid > RTL8367C_VIDMAX) || (lowerVid > RTL8367C_VIDMAX)) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ if((ret = rtl8367c_setAsicAclVidRange(index, type, upperVid, lowerVid)) != RT_ERR_OK) ++ return ret; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_filter_vidrange_get ++ * Description: ++ * Get VID Range check ++ * Input: ++ * index - index of VID Range 0-15 ++ * Output: ++ * pType - IP Range check type, 0:Unused, 1: CVID, 2: SVID ++ * pUpperVid - The upper bound of VID range ++ * pLowerVid - The lower Bound of VID range ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - The parameter is out of range ++ * Note: ++ * None. ++ */ ++rtk_api_ret_t rtk_filter_vidrange_get(rtk_uint32 index, rtk_filter_vidrange_t *pType, rtk_uint32 *pUpperVid, rtk_uint32 *pLowerVid) ++{ ++ rtk_api_ret_t ret; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if((NULL == pType) || (NULL == pUpperVid) || (NULL == pLowerVid)) ++ return RT_ERR_NULL_POINTER; ++ ++ if(index > RTL8367C_ACLRANGEMAX) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ if((ret = rtl8367c_getAsicAclVidRange(index, pType, pUpperVid, pLowerVid)) != RT_ERR_OK) ++ return ret; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_filter_portrange_set ++ * Description: ++ * Set Port Range check ++ * Input: ++ * index - index of Port Range 0-15 ++ * type - IP Range check type, 0:Delete a entry, 1: Source Port, 2: Destination Port ++ * upperPort - The upper bound of Port range ++ * lowerPort - The lower Bound of Port range ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - The parameter is out of range ++ * RT_ERR_INPUT - Input error ++ * Note: ++ * upperPort must be larger or equal than lowerPort. ++ */ ++rtk_api_ret_t rtk_filter_portrange_set(rtk_uint32 index, rtk_filter_portrange_t type, rtk_uint32 upperPort, rtk_uint32 lowerPort) ++{ ++ rtk_api_ret_t ret; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(index > RTL8367C_ACLRANGEMAX) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ if(type >= PORTRANGE_END) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ if(lowerPort > upperPort) ++ return RT_ERR_INPUT; ++ ++ if(upperPort > RTL8367C_ACL_PORTRANGEMAX) ++ return RT_ERR_INPUT; ++ ++ if(lowerPort > RTL8367C_ACL_PORTRANGEMAX) ++ return RT_ERR_INPUT; ++ ++ if((ret = rtl8367c_setAsicAclPortRange(index, type, upperPort, lowerPort)) != RT_ERR_OK) ++ return ret; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_filter_portrange_get ++ * Description: ++ * Set Port Range check ++ * Input: ++ * index - index of Port Range 0-15 ++ * Output: ++ * pType - IP Range check type, 0:Delete a entry, 1: Source Port, 2: Destination Port ++ * pUpperPort - The upper bound of Port range ++ * pLowerPort - The lower Bound of Port range ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - The parameter is out of range ++ * RT_ERR_INPUT - Input error ++ * Note: ++ * None. ++ */ ++rtk_api_ret_t rtk_filter_portrange_get(rtk_uint32 index, rtk_filter_portrange_t *pType, rtk_uint32 *pUpperPort, rtk_uint32 *pLowerPort) ++{ ++ rtk_api_ret_t ret; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if((NULL == pType) || (NULL == pUpperPort) || (NULL == pLowerPort)) ++ return RT_ERR_NULL_POINTER; ++ ++ if(index > RTL8367C_ACLRANGEMAX) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ if((ret = rtl8367c_getAsicAclPortRange(index, pType, pUpperPort, pLowerPort)) != RT_ERR_OK) ++ return ret; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_filter_igrAclPolarity_set ++ * Description: ++ * Set ACL Goip control polarity ++ * Input: ++ * polarity - 1: High, 0: Low ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * none ++ */ ++rtk_api_ret_t rtk_filter_igrAclPolarity_set(rtk_uint32 polarity) ++{ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(polarity > 1) ++ return RT_ERR_OUT_OF_RANGE; ++ return rtl8367c_setAsicAclGpioPolarity(polarity); ++} ++/* Function Name: ++ * rtk_filter_igrAclPolarity_get ++ * Description: ++ * Get ACL Goip control polarity ++ * Input: ++ * pPolarity - 1: High, 0: Low ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * none ++ */ ++rtk_api_ret_t rtk_filter_igrAclPolarity_get(rtk_uint32* pPolarity) ++{ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pPolarity) ++ return RT_ERR_NULL_POINTER; ++ ++ return rtl8367c_getAsicAclGpioPolarity(pPolarity); ++} ++ ++ ++ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/cpu.c b/drivers/net/phy/rtk/rtl8367c/cpu.c +new file mode 100644 +index 000000000000..b031cbe920eb +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/cpu.c +@@ -0,0 +1,537 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ ++ * ++ * Purpose : RTK switch high-level API for RTL8367/RTL8367C ++ * Feature : Here is a list of all functions and variables in CPU module. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++/* Function Name: ++ * rtk_cpu_enable_set ++ * Description: ++ * Set CPU port function enable/disable. ++ * Input: ++ * enable - CPU port function enable ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameter. ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * The API can set CPU port function enable/disable. ++ */ ++rtk_api_ret_t rtk_cpu_enable_set(rtk_enable_t enable) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (enable >= RTK_ENABLE_END) ++ return RT_ERR_ENABLE; ++ ++ if ((retVal = rtl8367c_setAsicCputagEnable(enable)) != RT_ERR_OK) ++ return retVal; ++ ++ if (DISABLED == enable) ++ { ++ if ((retVal = rtl8367c_setAsicCputagPortmask(0)) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_cpu_enable_get ++ * Description: ++ * Get CPU port and its setting. ++ * Input: ++ * None ++ * Output: ++ * pEnable - CPU port function enable ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_L2_NO_CPU_PORT - CPU port is not exist ++ * Note: ++ * The API can get CPU port function enable/disable. ++ */ ++rtk_api_ret_t rtk_cpu_enable_get(rtk_enable_t *pEnable) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pEnable) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicCputagEnable(pEnable)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_cpu_tagPort_set ++ * Description: ++ * Set CPU port and CPU tag insert mode. ++ * Input: ++ * port - Port id. ++ * mode - CPU tag insert for packets egress from CPU port. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameter. ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * The API can set CPU port and inserting proprietary CPU tag mode (Length/Type 0x8899) ++ * to the frame that transmitting to CPU port. ++ * The insert CPU tag mode is as following: ++ * - CPU_INSERT_TO_ALL ++ * - CPU_INSERT_TO_TRAPPING ++ * - CPU_INSERT_TO_NONE ++ */ ++rtk_api_ret_t rtk_cpu_tagPort_set(rtk_port_t port, rtk_cpu_insert_t mode) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if (mode >= CPU_INSERT_END) ++ return RT_ERR_INPUT; ++ ++ if ((retVal = rtl8367c_setAsicCputagPortmask(1<= CPU_POS_END) ++ return RT_ERR_INPUT; ++ ++ if ((retVal = rtl8367c_setAsicCputagPosition(position)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_cpu_tagPosition_get ++ * Description: ++ * Get CPU tag position. ++ * Input: ++ * None ++ * Output: ++ * pPosition - CPU tag position. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input. ++ * Note: ++ * The API can get CPU tag position. ++ */ ++rtk_api_ret_t rtk_cpu_tagPosition_get(rtk_cpu_position_t *pPosition) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pPosition) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicCputagPosition(pPosition)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_cpu_tagLength_set ++ * Description: ++ * Set CPU tag length. ++ * Input: ++ * length - CPU tag length. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input. ++ * Note: ++ * The API can set CPU tag length. ++ */ ++rtk_api_ret_t rtk_cpu_tagLength_set(rtk_cpu_tag_length_t length) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (length >= CPU_LEN_END) ++ return RT_ERR_INPUT; ++ ++ if ((retVal = rtl8367c_setAsicCputagMode(length)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_cpu_tagLength_get ++ * Description: ++ * Get CPU tag length. ++ * Input: ++ * None ++ * Output: ++ * pLength - CPU tag length. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input. ++ * Note: ++ * The API can get CPU tag length. ++ */ ++rtk_api_ret_t rtk_cpu_tagLength_get(rtk_cpu_tag_length_t *pLength) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pLength) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicCputagMode(pLength)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_cpu_priRemap_set ++ * Description: ++ * Configure CPU priorities mapping to internal absolute priority. ++ * Input: ++ * int_pri - internal priority value. ++ * new_pri - new internal priority value. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_VLAN_PRIORITY - Invalid 1p priority. ++ * RT_ERR_QOS_INT_PRIORITY - Invalid priority. ++ * Note: ++ * Priority of CPU tag assignment for internal asic priority, and it is used for queue usage and packet scheduling. ++ */ ++rtk_api_ret_t rtk_cpu_priRemap_set(rtk_pri_t int_pri, rtk_pri_t new_pri) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (new_pri > RTL8367C_PRIMAX || int_pri > RTL8367C_PRIMAX) ++ return RT_ERR_VLAN_PRIORITY; ++ ++ if ((retVal = rtl8367c_setAsicCputagPriorityRemapping(int_pri, new_pri)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_cpu_priRemap_get ++ * Description: ++ * Configure CPU priorities mapping to internal absolute priority. ++ * Input: ++ * int_pri - internal priority value. ++ * Output: ++ * pNew_pri - new internal priority value. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_VLAN_PRIORITY - Invalid 1p priority. ++ * RT_ERR_QOS_INT_PRIORITY - Invalid priority. ++ * Note: ++ * Priority of CPU tag assignment for internal asic priority, and it is used for queue usage and packet scheduling. ++ */ ++rtk_api_ret_t rtk_cpu_priRemap_get(rtk_pri_t int_pri, rtk_pri_t *pNew_pri) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pNew_pri) ++ return RT_ERR_NULL_POINTER; ++ ++ if (int_pri > RTL8367C_PRIMAX) ++ return RT_ERR_QOS_INT_PRIORITY; ++ ++ if ((retVal = rtl8367c_getAsicCputagPriorityRemapping(int_pri, pNew_pri)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_cpu_acceptLength_set ++ * Description: ++ * Set CPU accept length. ++ * Input: ++ * length - CPU tag length. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input. ++ * Note: ++ * The API can set CPU accept length. ++ */ ++rtk_api_ret_t rtk_cpu_acceptLength_set(rtk_cpu_rx_length_t length) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (length >= CPU_RX_END) ++ return RT_ERR_INPUT; ++ ++ if ((retVal = rtl8367c_setAsicCputagRxMinLength(length)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_cpu_acceptLength_get ++ * Description: ++ * Get CPU accept length. ++ * Input: ++ * None ++ * Output: ++ * pLength - CPU tag length. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input. ++ * Note: ++ * The API can get CPU accept length. ++ */ ++rtk_api_ret_t rtk_cpu_acceptLength_get(rtk_cpu_rx_length_t *pLength) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pLength) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicCputagRxMinLength(pLength)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/dot1x.c b/drivers/net/phy/rtk/rtl8367c/dot1x.c +new file mode 100644 +index 000000000000..c9b146a6d887 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/dot1x.c +@@ -0,0 +1,843 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 75783 $ ++ * $Date: 2017-02-13 14:54:53 +0800 (週一, 13 二月 2017) $ ++ * ++ * Purpose : RTK switch high-level API for RTL8367/RTL8367C ++ * Feature : Here is a list of all functions and variables in 1X module. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Function Name: ++ * rtk_dot1x_unauthPacketOper_set ++ * Description: ++ * Set 802.1x unauth action configuration. ++ * Input: ++ * port - Port id. ++ * unauth_action - 802.1X unauth action. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_INPUT - Invalid input parameter. ++ * Note: ++ * This API can set 802.1x unauth action configuration. ++ * The unauth action is as following: ++ * - DOT1X_ACTION_DROP ++ * - DOT1X_ACTION_TRAP2CPU ++ * - DOT1X_ACTION_GUESTVLAN ++ */ ++rtk_api_ret_t rtk_dot1x_unauthPacketOper_set(rtk_port_t port, rtk_dot1x_unauth_action_t unauth_action) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if (unauth_action >= DOT1X_ACTION_END) ++ return RT_ERR_DOT1X_PROC; ++ ++ if ((retVal = rtl8367c_setAsic1xProcConfig(rtk_switch_port_L2P_get(port), unauth_action)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_dot1x_unauthPacketOper_get ++ * Description: ++ * Get 802.1x unauth action configuration. ++ * Input: ++ * port - Port id. ++ * Output: ++ * pUnauth_action - 802.1X unauth action. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * This API can get 802.1x unauth action configuration. ++ * The unauth action is as following: ++ * - DOT1X_ACTION_DROP ++ * - DOT1X_ACTION_TRAP2CPU ++ * - DOT1X_ACTION_GUESTVLAN ++ */ ++rtk_api_ret_t rtk_dot1x_unauthPacketOper_get(rtk_port_t port, rtk_dot1x_unauth_action_t *pUnauth_action) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if(NULL == pUnauth_action) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsic1xProcConfig(rtk_switch_port_L2P_get(port), pUnauth_action)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_dot1x_eapolFrame2CpuEnable_set ++ * Description: ++ * Set 802.1x EAPOL packet trap to CPU configuration ++ * Input: ++ * enable - The status of 802.1x EAPOL packet. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_ENABLE - Invalid enable input. ++ * Note: ++ * To support 802.1x authentication functionality, EAPOL frame (ether type = 0x888E) has to ++ * be trapped to CPU. ++ * The status of EAPOL frame trap to CPU is as following: ++ * - DISABLED ++ * - ENABLED ++ */ ++rtk_api_ret_t rtk_dot1x_eapolFrame2CpuEnable_set(rtk_enable_t enable) ++{ ++ rtk_api_ret_t retVal; ++ rtl8367c_rma_t rmacfg; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (enable >= RTK_ENABLE_END) ++ return RT_ERR_ENABLE; ++ ++ if ((retVal = rtl8367c_getAsicRma(3, &rmacfg)) != RT_ERR_OK) ++ return retVal; ++ ++ if (ENABLED == enable) ++ rmacfg.operation = RMAOP_TRAP_TO_CPU; ++ else if (DISABLED == enable) ++ rmacfg.operation = RMAOP_FORWARD; ++ ++ if ((retVal = rtl8367c_setAsicRma(3, &rmacfg)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_dot1x_eapolFrame2CpuEnable_get ++ * Description: ++ * Get 802.1x EAPOL packet trap to CPU configuration ++ * Input: ++ * None ++ * Output: ++ * pEnable - The status of 802.1x EAPOL packet. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * To support 802.1x authentication functionality, EAPOL frame (ether type = 0x888E) has to ++ * be trapped to CPU. ++ * The status of EAPOL frame trap to CPU is as following: ++ * - DISABLED ++ * - ENABLED ++ */ ++rtk_api_ret_t rtk_dot1x_eapolFrame2CpuEnable_get(rtk_enable_t *pEnable) ++{ ++ rtk_api_ret_t retVal; ++ rtl8367c_rma_t rmacfg; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pEnable) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicRma(3, &rmacfg)) != RT_ERR_OK) ++ return retVal; ++ ++ if (RMAOP_TRAP_TO_CPU == rmacfg.operation) ++ *pEnable = ENABLED; ++ else ++ *pEnable = DISABLED; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_dot1x_portBasedEnable_set ++ * Description: ++ * Set 802.1x port-based enable configuration ++ * Input: ++ * port - Port id. ++ * enable - The status of 802.1x port. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_ENABLE - Invalid enable input. ++ * RT_ERR_DOT1X_PORTBASEDPNEN - 802.1X port-based enable error ++ * Note: ++ * The API can update the port-based port enable register content. If a port is 802.1x ++ * port based network access control "enabled", it should be authenticated so packets ++ * from that port won't be dropped or trapped to CPU. ++ * The status of 802.1x port-based network access control is as following: ++ * - DISABLED ++ * - ENABLED ++ */ ++rtk_api_ret_t rtk_dot1x_portBasedEnable_set(rtk_port_t port, rtk_enable_t enable) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if (enable >= RTK_ENABLE_END) ++ return RT_ERR_ENABLE; ++ ++ if ((retVal = rtl8367c_setAsic1xPBEnConfig(rtk_switch_port_L2P_get(port),enable)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_dot1x_portBasedEnable_get ++ * Description: ++ * Get 802.1x port-based enable configuration ++ * Input: ++ * port - Port id. ++ * Output: ++ * pEnable - The status of 802.1x port. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * The API can get the 802.1x port-based port status. ++ */ ++rtk_api_ret_t rtk_dot1x_portBasedEnable_get(rtk_port_t port, rtk_enable_t *pEnable) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if(NULL == pEnable) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsic1xPBEnConfig(rtk_switch_port_L2P_get(port), pEnable)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_dot1x_portBasedAuthStatus_set ++ * Description: ++ * Set 802.1x port-based auth. port configuration ++ * Input: ++ * port - Port id. ++ * port_auth - The status of 802.1x port. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_DOT1X_PORTBASEDAUTH - 802.1X port-based auth error ++ * Note: ++ * The authenticated status of 802.1x port-based network access control is as following: ++ * - UNAUTH ++ * - AUTH ++ */ ++rtk_api_ret_t rtk_dot1x_portBasedAuthStatus_set(rtk_port_t port, rtk_dot1x_auth_status_t port_auth) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if (port_auth >= AUTH_STATUS_END) ++ return RT_ERR_DOT1X_PORTBASEDAUTH; ++ ++ if ((retVal = rtl8367c_setAsic1xPBAuthConfig(rtk_switch_port_L2P_get(port), port_auth)) != RT_ERR_OK) ++ return retVal; ++ ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_dot1x_portBasedAuthStatus_get ++ * Description: ++ * Get 802.1x port-based auth. port configuration ++ * Input: ++ * port - Port id. ++ * Output: ++ * pPort_auth - The status of 802.1x port. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * The API can get 802.1x port-based port auth.information. ++ */ ++rtk_api_ret_t rtk_dot1x_portBasedAuthStatus_get(rtk_port_t port, rtk_dot1x_auth_status_t *pPort_auth) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pPort_auth) ++ return RT_ERR_NULL_POINTER; ++ ++ /* Check port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if ((retVal = rtl8367c_getAsic1xPBAuthConfig(rtk_switch_port_L2P_get(port), pPort_auth)) != RT_ERR_OK) ++ return retVal; ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_dot1x_portBasedDirection_set ++ * Description: ++ * Set 802.1x port-based operational direction configuration ++ * Input: ++ * port - Port id. ++ * port_direction - Operation direction ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_DOT1X_PORTBASEDOPDIR - 802.1X port-based operation direction error ++ * Note: ++ * The operate controlled direction of 802.1x port-based network access control is as following: ++ * - BOTH ++ * - IN ++ */ ++rtk_api_ret_t rtk_dot1x_portBasedDirection_set(rtk_port_t port, rtk_dot1x_direction_t port_direction) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if (port_direction >= DIRECTION_END) ++ return RT_ERR_DOT1X_PORTBASEDOPDIR; ++ ++ if ((retVal = rtl8367c_setAsic1xPBOpdirConfig(rtk_switch_port_L2P_get(port), port_direction)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_dot1x_portBasedDirection_get ++ * Description: ++ * Get 802.1X port-based operational direction configuration ++ * Input: ++ * port - Port id. ++ * Output: ++ * pPort_direction - Operation direction ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * The API can get 802.1x port-based operational direction information. ++ */ ++rtk_api_ret_t rtk_dot1x_portBasedDirection_get(rtk_port_t port, rtk_dot1x_direction_t *pPort_direction) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pPort_direction) ++ return RT_ERR_NULL_POINTER; ++ ++ /* Check port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if ((retVal = rtl8367c_getAsic1xPBOpdirConfig(rtk_switch_port_L2P_get(port), pPort_direction)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_dot1x_macBasedEnable_set ++ * Description: ++ * Set 802.1x mac-based port enable configuration ++ * Input: ++ * port - Port id. ++ * enable - The status of 802.1x port. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_ENABLE - Invalid enable input. ++ * RT_ERR_DOT1X_MACBASEDPNEN - 802.1X mac-based enable error ++ * Note: ++ * If a port is 802.1x MAC based network access control "enabled", the incoming packets should ++ * be authenticated so packets from that port won't be dropped or trapped to CPU. ++ * The status of 802.1x MAC-based network access control is as following: ++ * - DISABLED ++ * - ENABLED ++ */ ++rtk_api_ret_t rtk_dot1x_macBasedEnable_set(rtk_port_t port, rtk_enable_t enable) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if (enable >= RTK_ENABLE_END) ++ return RT_ERR_ENABLE; ++ ++ if ((retVal = rtl8367c_setAsic1xMBEnConfig(rtk_switch_port_L2P_get(port),enable)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_dot1x_macBasedEnable_get ++ * Description: ++ * Get 802.1x mac-based port enable configuration ++ * Input: ++ * port - Port id. ++ * Output: ++ * pEnable - The status of 802.1x port. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * If a port is 802.1x MAC based network access control "enabled", the incoming packets should ++ * be authenticated so packets from that port wont be dropped or trapped to CPU. ++ * The status of 802.1x MAC-based network access control is as following: ++ * - DISABLED ++ * - ENABLED ++ */ ++rtk_api_ret_t rtk_dot1x_macBasedEnable_get(rtk_port_t port, rtk_enable_t *pEnable) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pEnable) ++ return RT_ERR_NULL_POINTER; ++ ++ /* Check port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if ((retVal = rtl8367c_getAsic1xMBEnConfig(rtk_switch_port_L2P_get(port), pEnable)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_dot1x_macBasedAuthMac_add ++ * Description: ++ * Add an authenticated MAC to ASIC ++ * Input: ++ * port - Port id. ++ * pAuth_mac - The authenticated MAC. ++ * fid - filtering database. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_ENABLE - Invalid enable input. ++ * RT_ERR_DOT1X_MACBASEDPNEN - 802.1X mac-based enable error ++ * Note: ++ * The API can add a 802.1x authenticated MAC address to port. If the MAC does not exist in LUT, ++ * user can't add this MAC to auth status. ++ */ ++rtk_api_ret_t rtk_dot1x_macBasedAuthMac_add(rtk_port_t port, rtk_mac_t *pAuth_mac, rtk_fid_t fid) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 method; ++ rtl8367c_luttb l2Table; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* must be unicast address */ ++ if ((pAuth_mac == NULL) || (pAuth_mac->octet[0] & 0x1)) ++ return RT_ERR_MAC; ++ ++ /* Check port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if (fid > RTL8367C_FIDMAX) ++ return RT_ERR_L2_FID; ++ ++ memset(&l2Table, 0, sizeof(rtl8367c_luttb)); ++ ++ /* fill key (MAC,FID) to get L2 entry */ ++ memcpy(l2Table.mac.octet, pAuth_mac->octet, ETHER_ADDR_LEN); ++ l2Table.fid = fid; ++ method = LUTREADMETHOD_MAC; ++ retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table); ++ if ( RT_ERR_OK == retVal) ++ { ++ if (l2Table.spa != rtk_switch_port_L2P_get(port)) ++ return RT_ERR_DOT1X_MAC_PORT_MISMATCH; ++ ++ memcpy(l2Table.mac.octet, pAuth_mac->octet, ETHER_ADDR_LEN); ++ l2Table.fid = fid; ++ l2Table.efid = 0; ++ l2Table.auth = 1; ++ retVal = rtl8367c_setAsicL2LookupTb(&l2Table); ++ return retVal; ++ } ++ else ++ return retVal; ++ ++} ++ ++/* Function Name: ++ * rtk_dot1x_macBasedAuthMac_del ++ * Description: ++ * Delete an authenticated MAC to ASIC ++ * Input: ++ * port - Port id. ++ * pAuth_mac - The authenticated MAC. ++ * fid - filtering database. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_MAC - Invalid MAC address. ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * The API can delete a 802.1x authenticated MAC address to port. It only change the auth status of ++ * the MAC and won't delete it from LUT. ++ */ ++rtk_api_ret_t rtk_dot1x_macBasedAuthMac_del(rtk_port_t port, rtk_mac_t *pAuth_mac, rtk_fid_t fid) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 method; ++ rtl8367c_luttb l2Table; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* must be unicast address */ ++ if ((pAuth_mac == NULL) || (pAuth_mac->octet[0] & 0x1)) ++ return RT_ERR_MAC; ++ ++ /* Check port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if (fid > RTL8367C_FIDMAX) ++ return RT_ERR_L2_FID; ++ ++ memset(&l2Table, 0, sizeof(rtl8367c_luttb)); ++ ++ /* fill key (MAC,FID) to get L2 entry */ ++ memcpy(l2Table.mac.octet, pAuth_mac->octet, ETHER_ADDR_LEN); ++ l2Table.fid = fid; ++ method = LUTREADMETHOD_MAC; ++ retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table); ++ if (RT_ERR_OK == retVal) ++ { ++ if (l2Table.spa != rtk_switch_port_L2P_get(port)) ++ return RT_ERR_DOT1X_MAC_PORT_MISMATCH; ++ ++ memcpy(l2Table.mac.octet, pAuth_mac->octet, ETHER_ADDR_LEN); ++ l2Table.fid = fid; ++ l2Table.auth = 0; ++ retVal = rtl8367c_setAsicL2LookupTb(&l2Table); ++ return retVal; ++ } ++ else ++ return retVal; ++ ++} ++ ++/* Function Name: ++ * rtk_dot1x_macBasedDirection_set ++ * Description: ++ * Set 802.1x mac-based operational direction configuration ++ * Input: ++ * mac_direction - Operation direction ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameter. ++ * RT_ERR_DOT1X_MACBASEDOPDIR - 802.1X mac-based operation direction error ++ * Note: ++ * The operate controlled direction of 802.1x mac-based network access control is as following: ++ * - BOTH ++ * - IN ++ */ ++rtk_api_ret_t rtk_dot1x_macBasedDirection_set(rtk_dot1x_direction_t mac_direction) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (mac_direction >= DIRECTION_END) ++ return RT_ERR_DOT1X_MACBASEDOPDIR; ++ ++ if ((retVal = rtl8367c_setAsic1xMBOpdirConfig(mac_direction)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_dot1x_macBasedDirection_get ++ * Description: ++ * Get 802.1x mac-based operational direction configuration ++ * Input: ++ * port - Port id. ++ * Output: ++ * pMac_direction - Operation direction ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can get 802.1x mac-based operational direction information. ++ */ ++rtk_api_ret_t rtk_dot1x_macBasedDirection_get(rtk_dot1x_direction_t *pMac_direction) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pMac_direction) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsic1xMBOpdirConfig(pMac_direction)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * Set 802.1x guest VLAN configuration ++ * Description: ++ * Set 802.1x mac-based operational direction configuration ++ * Input: ++ * vid - 802.1x guest VLAN ID ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameter. ++ * Note: ++ * The operate controlled 802.1x guest VLAN ++ */ ++rtk_api_ret_t rtk_dot1x_guestVlan_set(rtk_vlan_t vid) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 index; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* vid must be 0~4095 */ ++ if (vid > RTL8367C_VIDMAX) ++ return RT_ERR_VLAN_VID; ++ ++ if((retVal = rtk_vlan_checkAndCreateMbr(vid, &index)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsic1xGuestVidx(index)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_dot1x_guestVlan_get ++ * Description: ++ * Get 802.1x guest VLAN configuration ++ * Input: ++ * None ++ * Output: ++ * pVid - 802.1x guest VLAN ID ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can get 802.1x guest VLAN information. ++ */ ++rtk_api_ret_t rtk_dot1x_guestVlan_get(rtk_vlan_t *pVid) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 gvidx; ++ rtl8367c_vlanconfiguser vlanMC; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pVid) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsic1xGuestVidx(&gvidx)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_getAsicVlanMemberConfig(gvidx, &vlanMC)) != RT_ERR_OK) ++ return retVal; ++ ++ *pVid = vlanMC.evid; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_dot1x_guestVlan2Auth_set ++ * Description: ++ * Set 802.1x guest VLAN to auth host configuration ++ * Input: ++ * enable - The status of guest VLAN to auth host. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameter. ++ * Note: ++ * The operational direction of 802.1x guest VLAN to auth host control is as following: ++ * - ENABLED ++ * - DISABLED ++ */ ++rtk_api_ret_t rtk_dot1x_guestVlan2Auth_set(rtk_enable_t enable) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (enable >= RTK_ENABLE_END) ++ return RT_ERR_ENABLE; ++ ++ if ((retVal = rtl8367c_setAsic1xGVOpdir(enable)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_dot1x_guestVlan2Auth_get ++ * Description: ++ * Get 802.1x guest VLAN to auth host configuration ++ * Input: ++ * None ++ * Output: ++ * pEnable - The status of guest VLAN to auth host. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can get 802.1x guest VLAN to auth host information. ++ */ ++rtk_api_ret_t rtk_dot1x_guestVlan2Auth_get(rtk_enable_t *pEnable) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pEnable) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsic1xGVOpdir(pEnable)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/eee.c b/drivers/net/phy/rtk/rtl8367c/eee.c +new file mode 100644 +index 000000000000..cd14c2ce1325 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/eee.c +@@ -0,0 +1,162 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 48156 $ ++ * $Date: 2014-05-29 16:39:06 +0800 (週四, 29 五月 2014) $ ++ * ++ * Purpose : RTK switch high-level API for RTL8367/RTL8367C ++ * Feature : Here is a list of all functions and variables in EEE module. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++/* Function Name: ++ * rtk_eee_init ++ * Description: ++ * EEE function initialization. ++ * Input: ++ * None ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * This API is used to initialize EEE status. ++ */ ++rtk_api_ret_t rtk_eee_init(void) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if((retVal = rtl8367c_setAsicRegBit(0x0018, 10, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBit(0x0018, 11, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_eee_portEnable_set ++ * Description: ++ * Set enable status of EEE function. ++ * Input: ++ * port - port id. ++ * enable - enable EEE status. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_ENABLE - Invalid enable input. ++ * Note: ++ * This API can set EEE function to the specific port. ++ * The configuration of the port is as following: ++ * - DISABLE ++ * - ENABLE ++ */ ++rtk_api_ret_t rtk_eee_portEnable_set(rtk_port_t port, rtk_enable_t enable) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 regData; ++ rtk_uint32 phy_port; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check port is UTP port */ ++ RTK_CHK_PORT_IS_UTP(port); ++ ++ if (enable>=RTK_ENABLE_END) ++ return RT_ERR_INPUT; ++ ++ phy_port = rtk_switch_port_L2P_get(port); ++ ++ if ((retVal = rtl8367c_setAsicEee100M(phy_port,enable))!=RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicEeeGiga(phy_port,enable))!=RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicPHYReg(phy_port, RTL8367C_PHY_PAGE_ADDRESS, 0))!=RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_getAsicPHYReg(phy_port, 0, ®Data))!=RT_ERR_OK) ++ return retVal; ++ regData |= 0x0200; ++ if ((retVal = rtl8367c_setAsicPHYReg(phy_port, 0, regData))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_eee_portEnable_get ++ * Description: ++ * Get enable status of EEE function ++ * Input: ++ * port - Port id. ++ * Output: ++ * pEnable - Back pressure status. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * This API can get EEE function to the specific port. ++ * The configuration of the port is as following: ++ * - DISABLE ++ * - ENABLE ++ */ ++ ++rtk_api_ret_t rtk_eee_portEnable_get(rtk_port_t port, rtk_enable_t *pEnable) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 regData1, regData2; ++ rtk_uint32 phy_port; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check port is UTP port */ ++ RTK_CHK_PORT_IS_UTP(port); ++ ++ if(NULL == pEnable) ++ return RT_ERR_NULL_POINTER; ++ ++ phy_port = rtk_switch_port_L2P_get(port); ++ ++ if ((retVal = rtl8367c_getAsicEee100M(phy_port,®Data1))!=RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_getAsicEeeGiga(phy_port,®Data2))!=RT_ERR_OK) ++ return retVal; ++ ++ if (regData1==1&®Data2==1) ++ *pEnable = ENABLED; ++ else ++ *pEnable = DISABLED; ++ ++ return RT_ERR_OK; ++} ++ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/i2c.c b/drivers/net/phy/rtk/rtl8367c/i2c.c +new file mode 100644 +index 000000000000..17a5f3785bd4 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/i2c.c +@@ -0,0 +1,436 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 63932 $ ++ * $Date: 2015-12-08 14:06:29 +0800 (周二, 08 å二月 2015) $ ++ * ++ * Purpose : RTK switch high-level API for RTL8367/RTL8367C ++ * Feature : Here is a list of all functions and variables in i2c module. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++ ++static rtk_I2C_16bit_mode_t rtk_i2c_mode = I2C_LSB_16BIT_MODE; ++ ++ ++/* Function Name: ++ * rtk_i2c_init ++ * Description: ++ * I2C smart function initialization. ++ * Input: ++ * None ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * Note: ++ * This API is used to initialize EEE status. ++ * need used GPIO pins ++ * OpenDrain and clock ++ */ ++rtk_api_ret_t rtk_i2c_init(void) ++{ ++ rtk_uint32 retVal; ++ switch_chip_t ChipID; ++ /* probe switch */ ++ if((retVal = rtk_switch_probe(&ChipID)) != RT_ERR_OK) ++ return retVal; ++ ++ if( ChipID == CHIP_RTL8370B ) ++ { ++ /*set GPIO8, GPIO9, OpenDrain as I2C, clock = 252KHZ */ ++ if((retVal = rtl8367c_setAsicReg(RTL8367C_REG_M_I2C_SYS_CTL, 0x5c3f)) != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ return RT_ERR_FAILED; ++ return RT_ERR_OK; ++} ++ ++ ++/* Function Name: ++ * rtk_i2c_mode_set ++ * Description: ++ * Set I2C data byte-order. ++ * Input: ++ * i2cmode - byte-order mode ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_INPUT - Invalid input parameter. ++ * Note: ++ * This API can set I2c traffic's byte-order . ++ */ ++rtk_api_ret_t rtk_i2c_mode_set( rtk_I2C_16bit_mode_t i2cmode ) ++{ ++ if(i2cmode >= I2C_Mode_END) ++ { ++ return RT_ERR_INPUT; ++ } ++ else if(i2cmode == I2C_70B_LSB_16BIT_MODE) ++ { ++ rtk_i2c_mode = I2C_70B_LSB_16BIT_MODE; ++ ++ return RT_ERR_OK; ++ } ++ else if( i2cmode == I2C_LSB_16BIT_MODE) ++ { ++ rtk_i2c_mode = I2C_LSB_16BIT_MODE; ++ return RT_ERR_OK; ++ } ++ else ++ return RT_ERR_FAILED; ++ ++ return RT_ERR_OK; ++} ++ ++ ++/* Function Name: ++ * rtk_i2c_mode_get ++ * Description: ++ * Get i2c traffic byte-order setting. ++ * Input: ++ * None ++ * Output: ++ * pI2cMode - i2c byte-order ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_NULL_POINTER - input parameter is null pointer ++ * Note: ++ * The API can get i2c traffic byte-order setting. ++ */ ++rtk_api_ret_t rtk_i2c_mode_get( rtk_I2C_16bit_mode_t * pI2cMode) ++{ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ if(NULL == pI2cMode) ++ return RT_ERR_NULL_POINTER; ++ if(rtk_i2c_mode == I2C_70B_LSB_16BIT_MODE) ++ *pI2cMode = 1; ++ else if ((rtk_i2c_mode == I2C_LSB_16BIT_MODE)) ++ *pI2cMode = 0; ++ else ++ return RT_ERR_FAILED; ++ return RT_ERR_OK; ++} ++ ++ ++/* Function Name: ++ * rtk_i2c_gpioPinGroup_set ++ * Description: ++ * Set i2c SDA & SCL used GPIO pins group. ++ * Input: ++ * pins_group - GPIO pins group ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_INPUT - Invalid input parameter. ++ * Note: ++ * The API can set i2c used gpio pins group. ++ * There are three group pins could be used ++ */ ++rtk_api_ret_t rtk_i2c_gpioPinGroup_set( rtk_I2C_gpio_pin_t pins_group ) ++{ ++ rtk_uint32 retVal; ++ ++ ++ if( ( pins_group > I2C_GPIO_PIN_END )|| ( pins_group < I2C_GPIO_PIN_8_9) ) ++ return RT_ERR_INPUT; ++ ++ if( (retVal = rtl8367c_setAsicI2CGpioPinGroup(pins_group) ) != RT_ERR_OK ) ++ return retVal ; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_i2c_gpioPinGroup_get ++ * Description: ++ * Get i2c SDA & SCL used GPIO pins group. ++ * Input: ++ * None ++ * Output: ++ * pPins_group - GPIO pins group ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_NULL_POINTER - input parameter is null pointer ++ * Note: ++ * The API can get i2c used gpio pins group. ++ * There are three group pins could be used ++ */ ++rtk_api_ret_t rtk_i2c_gpioPinGroup_get( rtk_I2C_gpio_pin_t * pPins_group ) ++{ ++ rtk_uint32 retVal; ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pPins_group) ++ return RT_ERR_NULL_POINTER; ++ if( (retVal = rtl8367c_getAsicI2CGpioPinGroup(pPins_group) ) != RT_ERR_OK ) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_i2c_data_read ++ * Description: ++ * read i2c slave device register. ++ * Input: ++ * deviceAddr - access Slave device address ++ * slaveRegAddr - access Slave register address ++ * Output: ++ * pRegData - read data ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_NULL_POINTER - input parameter is null pointer ++ * Note: ++ * The API can access i2c slave and read i2c slave device register. ++ */ ++rtk_api_ret_t rtk_i2c_data_read(rtk_uint8 deviceAddr, rtk_uint32 slaveRegAddr, rtk_uint32 *pRegData) ++{ ++ rtk_uint32 retVal, counter=0; ++ rtk_uint8 controlByte_W, controlByte_R; ++ rtk_uint8 slaveRegAddr_L, slaveRegAddr_H = 0x0, temp; ++ rtk_uint8 regData_L, regData_H; ++ ++ /* control byte :deviceAddress + W, deviceAddress + R */ ++ controlByte_W = (rtk_uint8)(deviceAddr << 1) ; ++ controlByte_R = (rtk_uint8)(controlByte_W | 0x1); ++ ++ slaveRegAddr_L = (rtk_uint8) (slaveRegAddr & 0x00FF) ; ++ slaveRegAddr_H = (rtk_uint8) (slaveRegAddr >>8) ; ++ ++ if( rtk_i2c_mode == I2C_70B_LSB_16BIT_MODE) ++ { ++ temp = slaveRegAddr_L ; ++ slaveRegAddr_L = slaveRegAddr_H; ++ slaveRegAddr_H = temp; ++ } ++ ++ ++ /*check bus state: idle*/ ++ for(counter = 3000; counter>0; counter--) ++ { ++ if ( (retVal = rtl8367c_setAsicI2C_checkBusIdle() ) == RT_ERR_OK) ++ break; ++ } ++ if( counter ==0 ) ++ return retVal; /*i2c is busy*/ ++ ++ /*tx Start cmd*/ ++ if( (retVal = rtl8367c_setAsicI2CStartCmd() ) != RT_ERR_OK ) ++ return retVal ; ++ ++ ++ /*tx control _W*/ ++ if( (retVal = rtl8367c_setAsicI2CTxOneCharCmd(controlByte_W))!= RT_ERR_OK ) ++ return retVal ; ++ ++ ++ /*check if RX ack from slave*/ ++ if( (retVal = rtl8367c_setAsicI2CcheckRxAck()) != RT_ERR_OK ) ++ return retVal; ++ ++ /* tx slave buffer address low 8 bits */ ++ if( (retVal = rtl8367c_setAsicI2CTxOneCharCmd(slaveRegAddr_L))!= RT_ERR_OK ) ++ return retVal ; ++ ++ /*check if RX ack from slave*/ ++ if( (retVal = rtl8367c_setAsicI2CcheckRxAck()) != RT_ERR_OK ) ++ return retVal; ++ ++ ++ ++ /* tx slave buffer address high 8 bits */ ++ if( (retVal = rtl8367c_setAsicI2CTxOneCharCmd(slaveRegAddr_H))!= RT_ERR_OK ) ++ return retVal ; ++ ++ ++ /*check if RX ack from slave*/ ++ if( (retVal = rtl8367c_setAsicI2CcheckRxAck()) != RT_ERR_OK ) ++ return retVal; ++ ++ ++ /*tx Start cmd*/ ++ if( (retVal = rtl8367c_setAsicI2CStartCmd() ) != RT_ERR_OK ) ++ return retVal ; ++ ++ /*tx control _R*/ ++ if( (retVal = rtl8367c_setAsicI2CTxOneCharCmd(controlByte_R))!= RT_ERR_OK ) ++ return retVal ; ++ ++ ++ /*check if RX ack from slave*/ ++ if( (retVal = rtl8367c_setAsicI2CcheckRxAck()) != RT_ERR_OK ) ++ return retVal; ++ ++ ++ /* rx low 8bit data*/ ++ if( ( retVal = rtl8367c_setAsicI2CRxOneCharCmd( ®Data_L) ) != RT_ERR_OK ) ++ return retVal; ++ ++ ++ ++ /* tx ack to slave, keep receive */ ++ if( (retVal = rtl8367c_setAsicI2CTxAckCmd()) != RT_ERR_OK ) ++ return retVal; ++ ++ /* rx high 8bit data*/ ++ if( ( retVal = rtl8367c_setAsicI2CRxOneCharCmd( ®Data_H) ) != RT_ERR_OK ) ++ return retVal; ++ ++ ++ ++ /* tx Noack to slave, Stop receive */ ++ if( (retVal = rtl8367c_setAsicI2CTxNoAckCmd()) != RT_ERR_OK ) ++ return retVal; ++ ++ ++ /*tx Stop cmd */ ++ if( (retVal = rtl8367c_setAsicI2CStopCmd()) != RT_ERR_OK ) ++ return retVal; ++ ++ *pRegData = (regData_H << 8) | regData_L; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_i2c_data_write ++ * Description: ++ * write data to i2c slave device register ++ * Input: ++ * deviceAddr - access Slave device address ++ * slaveRegAddr - access Slave register address ++ * regData - data to set ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * Note: ++ * The API can access i2c slave and setting i2c slave device register. ++ */ ++rtk_api_ret_t rtk_i2c_data_write(rtk_uint8 deviceAddr, rtk_uint32 slaveRegAddr, rtk_uint32 regData) ++{ ++ rtk_uint32 retVal,counter; ++ rtk_uint8 controlByte_W; ++ rtk_uint8 slaveRegAddr_L, slaveRegAddr_H = 0x0, temp; ++ rtk_uint8 regData_L, regData_H; ++ ++ /* control byte :deviceAddress + W */ ++ controlByte_W = (rtk_uint8)(deviceAddr<< 1) ; ++ ++ slaveRegAddr_L = (rtk_uint8) (slaveRegAddr & 0x00FF) ; ++ slaveRegAddr_H = (rtk_uint8) (slaveRegAddr >>8) ; ++ ++ regData_H = (rtk_uint8) (regData>> 8); ++ regData_L = (rtk_uint8) (regData & 0x00FF); ++ ++ if( rtk_i2c_mode == I2C_70B_LSB_16BIT_MODE) ++ { ++ temp = slaveRegAddr_L ; ++ slaveRegAddr_L = slaveRegAddr_H; ++ slaveRegAddr_H = temp; ++ } ++ ++ ++ /*check bus state: idle*/ ++ for(counter = 3000; counter>0; counter--) ++ { ++ if ( (retVal = rtl8367c_setAsicI2C_checkBusIdle() ) == RT_ERR_OK) ++ break; ++ } ++ ++ if( counter ==0 ) ++ return retVal; /*i2c is busy*/ ++ ++ ++ /*tx Start cmd*/ ++ if( (retVal = rtl8367c_setAsicI2CStartCmd() ) != RT_ERR_OK ) ++ return retVal ; ++ ++ ++ /*tx control _W*/ ++ if( (retVal = rtl8367c_setAsicI2CTxOneCharCmd(controlByte_W))!= RT_ERR_OK ) ++ return retVal ; ++ ++ ++ /*check if RX ack from slave*/ ++ if( (retVal = rtl8367c_setAsicI2CcheckRxAck()) != RT_ERR_OK ) ++ return retVal; ++ ++ ++ /* tx slave buffer address low 8 bits */ ++ if( (retVal = rtl8367c_setAsicI2CTxOneCharCmd(slaveRegAddr_L))!= RT_ERR_OK ) ++ return retVal; ++ ++ ++ /*check if RX ack from slave*/ ++ if( (retVal = rtl8367c_setAsicI2CcheckRxAck()) != RT_ERR_OK ) ++ return retVal; ++ ++ ++ /* tx slave buffer address high 8 bits */ ++ if( (retVal = rtl8367c_setAsicI2CTxOneCharCmd(slaveRegAddr_H))!= RT_ERR_OK ) ++ return retVal; ++ ++ ++ /*check if RX ack from slave*/ ++ if( (retVal = rtl8367c_setAsicI2CcheckRxAck()) != RT_ERR_OK ) ++ return retVal; ++ ++ ++ /*tx Datavlue LSB*/ ++ if( (retVal = rtl8367c_setAsicI2CTxOneCharCmd(regData_L))!= RT_ERR_OK ) ++ return retVal; ++ ++ ++ /*check if RX ack from slave*/ ++ if( (retVal = rtl8367c_setAsicI2CcheckRxAck()) != RT_ERR_OK ) ++ return retVal; ++ ++ ++ /*tx Datavlue MSB*/ ++ if( (retVal = rtl8367c_setAsicI2CTxOneCharCmd(regData_H))!= RT_ERR_OK ) ++ return retVal; ++ ++ ++ /*check if RX ack from slave*/ ++ if( (retVal = rtl8367c_setAsicI2CcheckRxAck()) != RT_ERR_OK ) ++ return retVal; ++ ++ ++ /*tx Stop cmd */ ++ if( (retVal = rtl8367c_setAsicI2CStopCmd()) != RT_ERR_OK ) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/igmp.c b/drivers/net/phy/rtk/rtl8367c/igmp.c +new file mode 100644 +index 000000000000..18e145a21c8c +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/igmp.c +@@ -0,0 +1,1555 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ ++ * ++ * Purpose : RTK switch high-level API for RTL8367/RTL8367C ++ * Feature : Here is a list of all functions and variables in IGMP module. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++ ++/* Function Name: ++ * rtk_igmp_init ++ * Description: ++ * This API enables H/W IGMP and set a default initial configuration. ++ * Input: ++ * None. ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * This API enables H/W IGMP and set a default initial configuration. ++ */ ++rtk_api_ret_t rtk_igmp_init(void) ++{ ++ rtk_api_ret_t retVal; ++ rtk_port_t port; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if ((retVal = rtl8367c_setAsicLutIpMulticastLookup(ENABLED))!=RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicLutIpLookupMethod(1))!=RT_ERR_OK) ++ return retVal; ++ ++ RTK_SCAN_ALL_PHY_PORTMASK(port) ++ { ++ if ((retVal = rtl8367c_setAsicIGMPv1Opeartion(port, PROTOCOL_OP_ASIC))!=RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicIGMPv2Opeartion(port, PROTOCOL_OP_ASIC))!=RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicIGMPv3Opeartion(port, PROTOCOL_OP_FLOOD))!=RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicMLDv1Opeartion(port, PROTOCOL_OP_ASIC))!=RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicMLDv2Opeartion(port, PROTOCOL_OP_FLOOD))!=RT_ERR_OK) ++ return retVal; ++ } ++ ++ if ((retVal = rtl8367c_setAsicIGMPAllowDynamicRouterPort(rtk_switch_phyPortMask_get()))!=RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicIGMPFastLeaveEn(ENABLED))!=RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicIGMPReportLeaveFlood(1))!=RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicIgmp(ENABLED))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_igmp_state_set ++ * Description: ++ * This API set H/W IGMP state. ++ * Input: ++ * enabled - H/W IGMP state ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Error parameter ++ * Note: ++ * This API set H/W IGMP state. ++ */ ++rtk_api_ret_t rtk_igmp_state_set(rtk_enable_t enabled) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (enabled >= RTK_ENABLE_END) ++ return RT_ERR_INPUT; ++ ++ if ((retVal = rtl8367c_setAsicIgmp(enabled))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_igmp_state_get ++ * Description: ++ * This API get H/W IGMP state. ++ * Input: ++ * None. ++ * Output: ++ * pEnabled - H/W IGMP state ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Error parameter ++ * Note: ++ * This API set current H/W IGMP state. ++ */ ++rtk_api_ret_t rtk_igmp_state_get(rtk_enable_t *pEnabled) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(pEnabled == NULL) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicIgmp(pEnabled))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_igmp_static_router_port_set ++ * Description: ++ * Configure static router port ++ * Input: ++ * pPortmask - Static Port mask ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_MASK - Error parameter ++ * Note: ++ * This API set static router port ++ */ ++rtk_api_ret_t rtk_igmp_static_router_port_set(rtk_portmask_t *pPortmask) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 pmask; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Valid port mask */ ++ if(pPortmask == NULL) ++ return RT_ERR_NULL_POINTER; ++ ++ RTK_CHK_PORTMASK_VALID(pPortmask); ++ ++ if ((retVal = rtk_switch_portmask_L2P_get(pPortmask, &pmask))!=RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicIGMPStaticRouterPort(pmask))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_igmp_static_router_port_get ++ * Description: ++ * Get static router port ++ * Input: ++ * None. ++ * Output: ++ * pPortmask - Static port mask ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_MASK - Error parameter ++ * Note: ++ * This API get static router port ++ */ ++rtk_api_ret_t rtk_igmp_static_router_port_get(rtk_portmask_t *pPortmask) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 pmask; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(pPortmask == NULL) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicIGMPStaticRouterPort(&pmask))!=RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtk_switch_portmask_P2L_get(pmask, pPortmask))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_igmp_protocol_set ++ * Description: ++ * set IGMP/MLD protocol action ++ * Input: ++ * port - Port ID ++ * protocol - IGMP/MLD protocol ++ * action - Per-port and per-protocol IGMP action setting ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_MASK - Error parameter ++ * Note: ++ * This API set IGMP/MLD protocol action ++ */ ++rtk_api_ret_t rtk_igmp_protocol_set(rtk_port_t port, rtk_igmp_protocol_t protocol, rtk_igmp_action_t action) ++{ ++ rtk_uint32 operation; ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check port valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if(protocol >= PROTOCOL_END) ++ return RT_ERR_INPUT; ++ ++ if(action >= IGMP_ACTION_END) ++ return RT_ERR_INPUT; ++ ++ switch(action) ++ { ++ case IGMP_ACTION_FORWARD: ++ operation = PROTOCOL_OP_FLOOD; ++ break; ++ case IGMP_ACTION_TRAP2CPU: ++ operation = PROTOCOL_OP_TRAP; ++ break; ++ case IGMP_ACTION_DROP: ++ operation = PROTOCOL_OP_DROP; ++ break; ++ case IGMP_ACTION_ASIC: ++ operation = PROTOCOL_OP_ASIC; ++ break; ++ default: ++ return RT_ERR_INPUT; ++ } ++ ++ switch(protocol) ++ { ++ case PROTOCOL_IGMPv1: ++ if ((retVal = rtl8367c_setAsicIGMPv1Opeartion(rtk_switch_port_L2P_get(port), operation))!=RT_ERR_OK) ++ return retVal; ++ ++ break; ++ case PROTOCOL_IGMPv2: ++ if ((retVal = rtl8367c_setAsicIGMPv2Opeartion(rtk_switch_port_L2P_get(port), operation))!=RT_ERR_OK) ++ return retVal; ++ ++ break; ++ case PROTOCOL_IGMPv3: ++ if ((retVal = rtl8367c_setAsicIGMPv3Opeartion(rtk_switch_port_L2P_get(port), operation))!=RT_ERR_OK) ++ return retVal; ++ ++ break; ++ case PROTOCOL_MLDv1: ++ if ((retVal = rtl8367c_setAsicMLDv1Opeartion(rtk_switch_port_L2P_get(port), operation))!=RT_ERR_OK) ++ return retVal; ++ ++ break; ++ case PROTOCOL_MLDv2: ++ if ((retVal = rtl8367c_setAsicMLDv2Opeartion(rtk_switch_port_L2P_get(port), operation))!=RT_ERR_OK) ++ return retVal; ++ ++ break; ++ default: ++ return RT_ERR_INPUT; ++ ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_igmp_protocol_get ++ * Description: ++ * set IGMP/MLD protocol action ++ * Input: ++ * port - Port ID ++ * protocol - IGMP/MLD protocol ++ * action - Per-port and per-protocol IGMP action setting ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_MASK - Error parameter ++ * Note: ++ * This API set IGMP/MLD protocol action ++ */ ++rtk_api_ret_t rtk_igmp_protocol_get(rtk_port_t port, rtk_igmp_protocol_t protocol, rtk_igmp_action_t *pAction) ++{ ++ rtk_uint32 operation; ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check port valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if(protocol >= PROTOCOL_END) ++ return RT_ERR_INPUT; ++ ++ if(pAction == NULL) ++ return RT_ERR_NULL_POINTER; ++ ++ switch(protocol) ++ { ++ case PROTOCOL_IGMPv1: ++ if ((retVal = rtl8367c_getAsicIGMPv1Opeartion(rtk_switch_port_L2P_get(port), &operation))!=RT_ERR_OK) ++ return retVal; ++ ++ break; ++ case PROTOCOL_IGMPv2: ++ if ((retVal = rtl8367c_getAsicIGMPv2Opeartion(rtk_switch_port_L2P_get(port), &operation))!=RT_ERR_OK) ++ return retVal; ++ ++ break; ++ case PROTOCOL_IGMPv3: ++ if ((retVal = rtl8367c_getAsicIGMPv3Opeartion(rtk_switch_port_L2P_get(port), &operation))!=RT_ERR_OK) ++ return retVal; ++ ++ break; ++ case PROTOCOL_MLDv1: ++ if ((retVal = rtl8367c_getAsicMLDv1Opeartion(rtk_switch_port_L2P_get(port), &operation))!=RT_ERR_OK) ++ return retVal; ++ ++ break; ++ case PROTOCOL_MLDv2: ++ if ((retVal = rtl8367c_getAsicMLDv2Opeartion(rtk_switch_port_L2P_get(port), &operation))!=RT_ERR_OK) ++ return retVal; ++ ++ break; ++ default: ++ return RT_ERR_INPUT; ++ ++ } ++ ++ switch(operation) ++ { ++ case PROTOCOL_OP_FLOOD: ++ *pAction = IGMP_ACTION_FORWARD; ++ break; ++ case PROTOCOL_OP_TRAP: ++ *pAction = IGMP_ACTION_TRAP2CPU; ++ break; ++ case PROTOCOL_OP_DROP: ++ *pAction = IGMP_ACTION_DROP; ++ break; ++ case PROTOCOL_OP_ASIC: ++ *pAction = IGMP_ACTION_ASIC; ++ break; ++ default: ++ return RT_ERR_FAILED; ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_igmp_fastLeave_set ++ * Description: ++ * set IGMP/MLD FastLeave state ++ * Input: ++ * state - ENABLED: Enable FastLeave, DISABLED: disable FastLeave ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_INPUT - Error Input ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * This API set IGMP/MLD FastLeave state ++ */ ++rtk_api_ret_t rtk_igmp_fastLeave_set(rtk_enable_t state) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(state >= RTK_ENABLE_END) ++ return RT_ERR_INPUT; ++ ++ if ((retVal = rtl8367c_setAsicIGMPFastLeaveEn((rtk_uint32)state))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_igmp_fastLeave_get ++ * Description: ++ * get IGMP/MLD FastLeave state ++ * Input: ++ * None ++ * Output: ++ * pState - ENABLED: Enable FastLeave, DISABLED: disable FastLeave ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_NULL_POINTER - NULL pointer ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * This API get IGMP/MLD FastLeave state ++ */ ++rtk_api_ret_t rtk_igmp_fastLeave_get(rtk_enable_t *pState) ++{ ++ rtk_uint32 fast_leave; ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(pState == NULL) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicIGMPFastLeaveEn(&fast_leave))!=RT_ERR_OK) ++ return retVal; ++ ++ *pState = ((fast_leave == 1) ? ENABLED : DISABLED); ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_igmp_maxGroup_set ++ * Description: ++ * Set per port multicast group learning limit. ++ * Input: ++ * port - Port ID ++ * group - The number of multicast group learning limit. ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_PORT_ID - Error Port ID ++ * RT_ERR_OUT_OF_RANGE - parameter out of range ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * This API set per port multicast group learning limit. ++ */ ++rtk_api_ret_t rtk_igmp_maxGroup_set(rtk_port_t port, rtk_uint32 group) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check port valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if(group > RTL8367C_IGMP_MAX_GOUP) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ if ((retVal = rtl8367c_setAsicIGMPPortMAXGroup(rtk_switch_port_L2P_get(port), group))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_igmp_maxGroup_get ++ * Description: ++ * Get per port multicast group learning limit. ++ * Input: ++ * port - Port ID ++ * Output: ++ * pGroup - The number of multicast group learning limit. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_PORT_ID - Error Port ID ++ * RT_ERR_NULL_POINTER - Null pointer ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * This API get per port multicast group learning limit. ++ */ ++rtk_api_ret_t rtk_igmp_maxGroup_get(rtk_port_t port, rtk_uint32 *pGroup) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check port valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if(pGroup == NULL) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicIGMPPortMAXGroup(rtk_switch_port_L2P_get(port), pGroup))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_igmp_currentGroup_get ++ * Description: ++ * Get per port multicast group learning count. ++ * Input: ++ * port - Port ID ++ * Output: ++ * pGroup - The number of multicast group learning count. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_PORT_ID - Error Port ID ++ * RT_ERR_NULL_POINTER - Null pointer ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * This API get per port multicast group learning count. ++ */ ++rtk_api_ret_t rtk_igmp_currentGroup_get(rtk_port_t port, rtk_uint32 *pGroup) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check port valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if(pGroup == NULL) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicIGMPPortCurrentGroup(rtk_switch_port_L2P_get(port), pGroup))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_igmp_tableFullAction_set ++ * Description: ++ * set IGMP/MLD Table Full Action ++ * Input: ++ * action - Table Full Action ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_INPUT - Error Input ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ */ ++rtk_api_ret_t rtk_igmp_tableFullAction_set(rtk_igmp_tableFullAction_t action) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(action >= IGMP_TABLE_FULL_OP_END) ++ return RT_ERR_INPUT; ++ ++ if ((retVal = rtl8367c_setAsicIGMPTableFullOP((rtk_uint32)action))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_igmp_tableFullAction_get ++ * Description: ++ * get IGMP/MLD Table Full Action ++ * Input: ++ * None ++ * Output: ++ * pAction - Table Full Action ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_NULL_POINTER - Null pointer ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ */ ++rtk_api_ret_t rtk_igmp_tableFullAction_get(rtk_igmp_tableFullAction_t *pAction) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pAction) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicIGMPTableFullOP((rtk_uint32 *)pAction))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_igmp_checksumErrorAction_set ++ * Description: ++ * set IGMP/MLD Checksum Error Action ++ * Input: ++ * action - Checksum error Action ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_INPUT - Error Input ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ */ ++rtk_api_ret_t rtk_igmp_checksumErrorAction_set(rtk_igmp_checksumErrorAction_t action) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(action >= IGMP_CRC_ERR_OP_END) ++ return RT_ERR_INPUT; ++ ++ if ((retVal = rtl8367c_setAsicIGMPCRCErrOP((rtk_uint32)action))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++ ++/* Function Name: ++ * rtk_igmp_checksumErrorAction_get ++ * Description: ++ * get IGMP/MLD Checksum Error Action ++ * Input: ++ * None ++ * Output: ++ * pAction - Checksum error Action ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_NULL_POINTER - Null pointer ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ */ ++rtk_api_ret_t rtk_igmp_checksumErrorAction_get(rtk_igmp_checksumErrorAction_t *pAction) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pAction) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicIGMPCRCErrOP((rtk_uint32 *)pAction))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_igmp_leaveTimer_set ++ * Description: ++ * set IGMP/MLD Leave timer ++ * Input: ++ * timer - Leave timer ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_INPUT - Error Input ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ */ ++rtk_api_ret_t rtk_igmp_leaveTimer_set(rtk_uint32 timer) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(timer > RTL8367C_MAX_LEAVE_TIMER) ++ return RT_ERR_INPUT; ++ ++ if ((retVal = rtl8367c_setAsicIGMPLeaveTimer(timer))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_igmp_leaveTimer_get ++ * Description: ++ * get IGMP/MLD Leave timer ++ * Input: ++ * None ++ * Output: ++ * pTimer - Leave Timer. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_NULL_POINTER - Null pointer ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ */ ++rtk_api_ret_t rtk_igmp_leaveTimer_get(rtk_uint32 *pTimer) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pTimer) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicIGMPLeaveTimer(pTimer))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_igmp_queryInterval_set ++ * Description: ++ * set IGMP/MLD Query Interval ++ * Input: ++ * interval - Query Interval ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_INPUT - Error Input ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ */ ++rtk_api_ret_t rtk_igmp_queryInterval_set(rtk_uint32 interval) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(interval > RTL8367C_MAX_QUERY_INT) ++ return RT_ERR_INPUT; ++ ++ if ((retVal = rtl8367c_setAsicIGMPQueryInterval(interval))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_igmp_queryInterval_get ++ * Description: ++ * get IGMP/MLD Query Interval ++ * Input: ++ * None. ++ * Output: ++ * pInterval - Query Interval ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_NULL_POINTER - Null pointer ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ */ ++rtk_api_ret_t rtk_igmp_queryInterval_get(rtk_uint32 *pInterval) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pInterval) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicIGMPQueryInterval(pInterval))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_igmp_robustness_set ++ * Description: ++ * set IGMP/MLD Robustness value ++ * Input: ++ * robustness - Robustness value ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_INPUT - Error Input ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ */ ++rtk_api_ret_t rtk_igmp_robustness_set(rtk_uint32 robustness) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(robustness > RTL8367C_MAX_ROB_VAR) ++ return RT_ERR_INPUT; ++ ++ if ((retVal = rtl8367c_setAsicIGMPRobVar(robustness))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_igmp_robustness_get ++ * Description: ++ * get IGMP/MLD Robustness value ++ * Input: ++ * None ++ * Output: ++ * pRobustness - Robustness value. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_NULL_POINTER - Null pointer ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ */ ++rtk_api_ret_t rtk_igmp_robustness_get(rtk_uint32 *pRobustness) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pRobustness) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicIGMPRobVar(pRobustness))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_igmp_dynamicRouterRortAllow_set ++ * Description: ++ * Configure dynamic router port allow option ++ * Input: ++ * pPortmask - Dynamic Port allow mask ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_MASK - Error parameter ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_igmp_dynamicRouterPortAllow_set(rtk_portmask_t *pPortmask) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 pmask; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pPortmask) ++ return RT_ERR_NULL_POINTER; ++ ++ RTK_CHK_PORTMASK_VALID(pPortmask); ++ ++ if ((retVal = rtk_switch_portmask_L2P_get(pPortmask, &pmask))!=RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicIGMPAllowDynamicRouterPort(pmask))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_igmp_dynamicRouterRortAllow_get ++ * Description: ++ * Get dynamic router port allow option ++ * Input: ++ * None. ++ * Output: ++ * pPortmask - Dynamic Port allow mask ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_NULL_POINTER - Null pointer ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_MASK - Error parameter ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_igmp_dynamicRouterPortAllow_get(rtk_portmask_t *pPortmask) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 pmask; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pPortmask) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicIGMPAllowDynamicRouterPort(&pmask))!=RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtk_switch_portmask_P2L_get(pmask, pPortmask))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_igmp_dynamicRouterPort_get ++ * Description: ++ * Get dynamic router port ++ * Input: ++ * None. ++ * Output: ++ * pDynamicRouterPort - Dynamic Router Port ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_NULL_POINTER - Null pointer ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_MASK - Error parameter ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_igmp_dynamicRouterPort_get(rtk_igmp_dynamicRouterPort_t *pDynamicRouterPort) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 port; ++ rtk_uint32 timer; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pDynamicRouterPort) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicIGMPdynamicRouterPort1(&port, &timer))!= RT_ERR_OK) ++ return retVal; ++ ++ if (port == RTL8367C_ROUTER_PORT_INVALID) ++ { ++ pDynamicRouterPort->dynamicRouterPort0Valid = DISABLED; ++ pDynamicRouterPort->dynamicRouterPort0 = 0; ++ pDynamicRouterPort->dynamicRouterPort0Timer = 0; ++ } ++ else ++ { ++ pDynamicRouterPort->dynamicRouterPort0Valid = ENABLED; ++ pDynamicRouterPort->dynamicRouterPort0 = rtk_switch_port_P2L_get(port); ++ pDynamicRouterPort->dynamicRouterPort0Timer = timer; ++ } ++ ++ if ((retVal = rtl8367c_getAsicIGMPdynamicRouterPort2(&port, &timer))!= RT_ERR_OK) ++ return retVal; ++ ++ if (port == RTL8367C_ROUTER_PORT_INVALID) ++ { ++ pDynamicRouterPort->dynamicRouterPort1Valid = DISABLED; ++ pDynamicRouterPort->dynamicRouterPort1 = 0; ++ pDynamicRouterPort->dynamicRouterPort1Timer = 0; ++ } ++ else ++ { ++ pDynamicRouterPort->dynamicRouterPort1Valid = ENABLED; ++ pDynamicRouterPort->dynamicRouterPort1 = rtk_switch_port_P2L_get(port); ++ pDynamicRouterPort->dynamicRouterPort1Timer = timer; ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_igmp_suppressionEnable_set ++ * Description: ++ * Configure IGMPv1/v2 & MLDv1 Report/Leave/Done suppression ++ * Input: ++ * reportSuppression - Report suppression ++ * leaveSuppression - Leave suppression ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Error Input ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_igmp_suppressionEnable_set(rtk_enable_t reportSuppression, rtk_enable_t leaveSuppression) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(reportSuppression >= RTK_ENABLE_END) ++ return RT_ERR_INPUT; ++ ++ if(leaveSuppression >= RTK_ENABLE_END) ++ return RT_ERR_INPUT; ++ ++ if ((retVal = rtl8367c_setAsicIGMPSuppression((rtk_uint32)reportSuppression, (rtk_uint32)leaveSuppression))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_igmp_suppressionEnable_get ++ * Description: ++ * Get IGMPv1/v2 & MLDv1 Report/Leave/Done suppression ++ * Input: ++ * None ++ * Output: ++ * pReportSuppression - Report suppression ++ * pLeaveSuppression - Leave suppression ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_NULL_POINTER - Null pointer ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_igmp_suppressionEnable_get(rtk_enable_t *pReportSuppression, rtk_enable_t *pLeaveSuppression) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pReportSuppression) ++ return RT_ERR_NULL_POINTER; ++ ++ if(NULL == pLeaveSuppression) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicIGMPSuppression((rtk_uint32 *)pReportSuppression, (rtk_uint32 *)pLeaveSuppression))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_igmp_portRxPktEnable_set ++ * Description: ++ * Configure IGMP/MLD RX Packet configuration ++ * Input: ++ * port - Port ID ++ * pRxCfg - RX Packet Configuration ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Error Input ++ * RT_ERR_NULL_POINTER - Null pointer ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_igmp_portRxPktEnable_set(rtk_port_t port, rtk_igmp_rxPktEnable_t *pRxCfg) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check port valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if(NULL == pRxCfg) ++ return RT_ERR_NULL_POINTER; ++ ++ if(pRxCfg->rxQuery >= RTK_ENABLE_END) ++ return RT_ERR_INPUT; ++ ++ if(pRxCfg->rxReport >= RTK_ENABLE_END) ++ return RT_ERR_INPUT; ++ ++ if(pRxCfg->rxLeave >= RTK_ENABLE_END) ++ return RT_ERR_INPUT; ++ ++ if(pRxCfg->rxMRP >= RTK_ENABLE_END) ++ return RT_ERR_INPUT; ++ ++ if(pRxCfg->rxMcast >= RTK_ENABLE_END) ++ return RT_ERR_INPUT; ++ ++ if ((retVal = rtl8367c_setAsicIGMPQueryRX(rtk_switch_port_L2P_get(port), (rtk_uint32)pRxCfg->rxQuery))!=RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicIGMPReportRX(rtk_switch_port_L2P_get(port), (rtk_uint32)pRxCfg->rxReport))!=RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicIGMPLeaveRX(rtk_switch_port_L2P_get(port), (rtk_uint32)pRxCfg->rxLeave))!=RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicIGMPMRPRX(rtk_switch_port_L2P_get(port), (rtk_uint32)pRxCfg->rxMRP))!=RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicIGMPMcDataRX(rtk_switch_port_L2P_get(port), (rtk_uint32)pRxCfg->rxMcast))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_igmp_portRxPktEnable_get ++ * Description: ++ * Get IGMP/MLD RX Packet configuration ++ * Input: ++ * port - Port ID ++ * pRxCfg - RX Packet Configuration ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Error Input ++ * RT_ERR_NULL_POINTER - Null pointer ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_igmp_portRxPktEnable_get(rtk_port_t port, rtk_igmp_rxPktEnable_t *pRxCfg) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check port valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if(NULL == pRxCfg) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicIGMPQueryRX(rtk_switch_port_L2P_get(port), (rtk_uint32 *)&(pRxCfg->rxQuery)))!=RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_getAsicIGMPReportRX(rtk_switch_port_L2P_get(port), (rtk_uint32 *)&(pRxCfg->rxReport)))!=RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_getAsicIGMPLeaveRX(rtk_switch_port_L2P_get(port), (rtk_uint32 *)&(pRxCfg->rxLeave)))!=RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_getAsicIGMPMRPRX(rtk_switch_port_L2P_get(port), (rtk_uint32 *)&(pRxCfg->rxMRP)))!=RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_getAsicIGMPMcDataRX(rtk_switch_port_L2P_get(port), (rtk_uint32 *)&(pRxCfg->rxMcast)))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_igmp_groupInfo_get ++ * Description: ++ * Get IGMP/MLD Group database ++ * Input: ++ * index - Index (0~255) ++ * Output: ++ * pGroup - Group database information. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Error Input ++ * RT_ERR_NULL_POINTER - Null pointer ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_igmp_groupInfo_get(rtk_uint32 index, rtk_igmp_groupInfo_t *pGroup) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 valid; ++ rtl8367c_igmpgroup grp; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check index */ ++ if(index > RTL8367C_IGMP_MAX_GOUP) ++ return RT_ERR_INPUT; ++ ++ if(NULL == pGroup) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicIGMPGroup(index, &valid, &grp))!=RT_ERR_OK) ++ return retVal; ++ ++ memset(pGroup, 0x00, sizeof(rtk_igmp_groupInfo_t)); ++ pGroup->valid = valid; ++ pGroup->reportSuppFlag = grp.report_supp_flag; ++ ++ if(grp.p0_timer != 0) ++ { ++ RTK_PORTMASK_PORT_SET((pGroup->member), rtk_switch_port_P2L_get(0)); ++ pGroup->timer[rtk_switch_port_P2L_get(0)] = grp.p0_timer; ++ } ++ ++ if(grp.p1_timer != 0) ++ { ++ RTK_PORTMASK_PORT_SET((pGroup->member), rtk_switch_port_P2L_get(1)); ++ pGroup->timer[rtk_switch_port_P2L_get(1)] = grp.p1_timer; ++ } ++ ++ if(grp.p2_timer != 0) ++ { ++ RTK_PORTMASK_PORT_SET((pGroup->member), rtk_switch_port_P2L_get(2)); ++ pGroup->timer[rtk_switch_port_P2L_get(2)] = grp.p2_timer; ++ } ++ ++ if(grp.p3_timer != 0) ++ { ++ RTK_PORTMASK_PORT_SET((pGroup->member), rtk_switch_port_P2L_get(3)); ++ pGroup->timer[rtk_switch_port_P2L_get(3)] = grp.p3_timer; ++ } ++ ++ if(grp.p4_timer != 0) ++ { ++ RTK_PORTMASK_PORT_SET((pGroup->member), rtk_switch_port_P2L_get(4)); ++ pGroup->timer[rtk_switch_port_P2L_get(4)] = grp.p4_timer; ++ } ++ ++ if(grp.p5_timer != 0) ++ { ++ RTK_PORTMASK_PORT_SET((pGroup->member), rtk_switch_port_P2L_get(5)); ++ pGroup->timer[rtk_switch_port_P2L_get(5)] = grp.p5_timer; ++ } ++ ++ if(grp.p6_timer != 0) ++ { ++ RTK_PORTMASK_PORT_SET((pGroup->member), rtk_switch_port_P2L_get(6)); ++ pGroup->timer[rtk_switch_port_P2L_get(6)] = grp.p6_timer; ++ } ++ ++ if(grp.p7_timer != 0) ++ { ++ RTK_PORTMASK_PORT_SET((pGroup->member), rtk_switch_port_P2L_get(7)); ++ pGroup->timer[rtk_switch_port_P2L_get(7)] = grp.p7_timer; ++ } ++ ++ if(grp.p8_timer != 0) ++ { ++ RTK_PORTMASK_PORT_SET((pGroup->member), rtk_switch_port_P2L_get(8)); ++ pGroup->timer[rtk_switch_port_P2L_get(8)] = grp.p8_timer; ++ } ++ ++ if(grp.p9_timer != 0) ++ { ++ RTK_PORTMASK_PORT_SET((pGroup->member), rtk_switch_port_P2L_get(9)); ++ pGroup->timer[rtk_switch_port_P2L_get(9)] = grp.p9_timer; ++ } ++ ++ if(grp.p10_timer != 0) ++ { ++ RTK_PORTMASK_PORT_SET((pGroup->member), rtk_switch_port_P2L_get(10)); ++ pGroup->timer[rtk_switch_port_P2L_get(10)] = grp.p10_timer; ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_igmp_ReportLeaveFwdAction_set ++ * Description: ++ * Set Report Leave packet forwarding action ++ * Input: ++ * action - Action ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Error Input ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_igmp_ReportLeaveFwdAction_set(rtk_igmp_ReportLeaveFwdAct_t action) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 regData; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ switch(action) ++ { ++ case IGMP_REPORT_LEAVE_TO_ROUTER: ++ regData = 1; ++ break; ++ case IGMP_REPORT_LEAVE_TO_ALLPORT: ++ regData = 2; ++ break; ++ case IGMP_REPORT_LEAVE_TO_ROUTER_PORT_ADV: ++ regData = 3; ++ break; ++ default: ++ return RT_ERR_INPUT; ++ } ++ ++ if ((retVal = rtl8367c_setAsicIGMPReportLeaveFlood(regData))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_igmp_ReportLeaveFwdAction_get ++ * Description: ++ * Get Report Leave packet forwarding action ++ * Input: ++ * action - Action ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Error Input ++ * RT_ERR_NULL_POINTER - Null Pointer ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_igmp_ReportLeaveFwdAction_get(rtk_igmp_ReportLeaveFwdAct_t *pAction) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 regData; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pAction) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicIGMPReportLeaveFlood(®Data))!=RT_ERR_OK) ++ return retVal; ++ ++ switch(regData) ++ { ++ case 1: ++ *pAction = IGMP_REPORT_LEAVE_TO_ROUTER; ++ break; ++ case 2: ++ *pAction = IGMP_REPORT_LEAVE_TO_ALLPORT; ++ break; ++ case 3: ++ *pAction = IGMP_REPORT_LEAVE_TO_ROUTER_PORT_ADV; ++ break; ++ default: ++ return RT_ERR_FAILED; ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_igmp_dropLeaveZeroEnable_set ++ * Description: ++ * Set the function of dropping Leave packet with group IP = 0.0.0.0 ++ * Input: ++ * enabled - Action 1: drop, 0:pass ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Error Input ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_igmp_dropLeaveZeroEnable_set(rtk_enable_t enabled) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(enabled >= RTK_ENABLE_END) ++ return RT_ERR_INPUT; ++ ++ if ((retVal = rtl8367c_setAsicIGMPDropLeaveZero(enabled))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++ ++} ++ ++/* Function Name: ++ * rtk_igmp_dropLeaveZeroEnable_get ++ * Description: ++ * Get the function of dropping Leave packet with group IP = 0.0.0.0 ++ * Input: ++ * None ++ * Output: ++ * pEnabled. - Action 1: drop, 0:pass ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Error Input ++ * RT_ERR_NULL_POINTER - Null Pointer ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_igmp_dropLeaveZeroEnable_get(rtk_enable_t *pEnabled) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pEnabled) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicIGMPDropLeaveZero((rtk_uint32 *)pEnabled))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++ ++} ++ ++/* Function Name: ++ * rtk_igmp_bypassGroupRange_set ++ * Description: ++ * Set Bypass group ++ * Input: ++ * group - bypassed group ++ * enabled - enabled 1: Bypassed, 0: not bypass ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Error Input ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_igmp_bypassGroupRange_set(rtk_igmp_bypassGroup_t group, rtk_enable_t enabled) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(group >= IGMP_BYPASS_GROUP_END) ++ return RT_ERR_INPUT; ++ ++ if(enabled >= RTK_ENABLE_END) ++ return RT_ERR_INPUT; ++ ++ if ((retVal = rtl8367c_setAsicIGMPBypassGroup(group, enabled))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_igmp_bypassGroupRange_get ++ * Description: ++ * get Bypass group ++ * Input: ++ * group - bypassed group ++ * Output: ++ * pEnable - enabled 1: Bypassed, 0: not bypass ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Error Input ++ * RT_ERR_NULL_POINTER - Null Pointer ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_igmp_bypassGroupRange_get(rtk_igmp_bypassGroup_t group, rtk_enable_t *pEnable) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(group >= IGMP_BYPASS_GROUP_END) ++ return RT_ERR_INPUT; ++ ++ if(NULL == pEnable) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicIGMPBypassGroup(group, pEnable))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} +diff --git a/drivers/net/phy/rtk/rtl8367c/include/acl.h b/drivers/net/phy/rtk/rtl8367c/include/acl.h +new file mode 100644 +index 000000000000..634e7325d696 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/acl.h +@@ -0,0 +1,990 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * Purpose : RTL8367/RTL8367C switch high-level API ++ * ++ * Feature : The file includes ACL module high-layer API definition ++ * ++ */ ++ ++#ifndef __RTK_API_ACL_H__ ++#define __RTK_API_ACL_H__ ++ ++/* ++ * Data Type Declaration ++ */ ++#define RTK_FILTER_RAW_FIELD_NUMBER 8 ++ ++#define ACL_DEFAULT_ABILITY 0 ++#define ACL_DEFAULT_UNMATCH_PERMIT 1 ++ ++#define ACL_RULE_FREE 0 ++#define ACL_RULE_INAVAILABLE 1 ++#define ACL_RULE_CARETAG_MASK 0x1F ++#define FILTER_POLICING_MAX 4 ++#define FILTER_LOGGING_MAX 8 ++#define FILTER_PATTERN_MAX 4 ++ ++#define FILTER_ENACT_CVLAN_MASK 0x01 ++#define FILTER_ENACT_SVLAN_MASK 0x02 ++#define FILTER_ENACT_PRIORITY_MASK 0x04 ++#define FILTER_ENACT_POLICING_MASK 0x08 ++#define FILTER_ENACT_FWD_MASK 0x10 ++#define FILTER_ENACT_INTGPIO_MASK 0x20 ++#define FILTER_ENACT_INIT_MASK 0x3F ++ ++typedef enum rtk_filter_act_cactext_e ++{ ++ FILTER_ENACT_CACTEXT_VLANONLY=0, ++ FILTER_ENACT_CACTEXT_BOTHVLANTAG, ++ FILTER_ENACT_CACTEXT_TAGONLY, ++ FILTER_ENACT_CACTEXT_END, ++ ++ ++}rtk_filter_act_cactext_t; ++ ++typedef enum rtk_filter_act_ctagfmt_e ++{ ++ FILTER_CTAGFMT_UNTAG=0, ++ FILTER_CTAGFMT_TAG, ++ FILTER_CTAGFMT_KEEP, ++ FILTER_CTAGFMT_KEEP1PRMK, ++ ++ ++}rtk_filter_act_ctag_t; ++ ++ ++ ++ ++ ++#define RTK_MAX_NUM_OF_FILTER_TYPE 5 ++#define RTK_MAX_NUM_OF_FILTER_FIELD 8 ++ ++#define RTK_DOT_1AS_TIMESTAMP_UNIT_IN_WORD_LENGTH 3UL ++#define RTK_IPV6_ADDR_WORD_LENGTH 4UL ++ ++#define FILTER_ENACT_CVLAN_TYPE(type) (type - FILTER_ENACT_CVLAN_INGRESS) ++#define FILTER_ENACT_SVLAN_TYPE(type) (type - FILTER_ENACT_SVLAN_INGRESS) ++#define FILTER_ENACT_FWD_TYPE(type) (type - FILTER_ENACT_ADD_DSTPORT) ++#define FILTER_ENACT_PRI_TYPE(type) (type - FILTER_ENACT_PRIORITY) ++ ++#define RTK_FILTER_FIELD_USED_MAX 8 ++#define RTK_FILTER_FIELD_INDEX(template, index) ((template << 4) + index) ++ ++ ++typedef enum rtk_filter_act_enable_e ++{ ++ /* CVLAN */ ++ FILTER_ENACT_CVLAN_INGRESS = 0, ++ FILTER_ENACT_CVLAN_EGRESS, ++ FILTER_ENACT_CVLAN_SVID, ++ FILTER_ENACT_POLICING_1, ++ ++ /* SVLAN */ ++ FILTER_ENACT_SVLAN_INGRESS, ++ FILTER_ENACT_SVLAN_EGRESS, ++ FILTER_ENACT_SVLAN_CVID, ++ FILTER_ENACT_POLICING_2, ++ ++ /* Policing and Logging */ ++ FILTER_ENACT_POLICING_0, ++ ++ /* Forward */ ++ FILTER_ENACT_COPY_CPU, ++ FILTER_ENACT_DROP, ++ FILTER_ENACT_ADD_DSTPORT, ++ FILTER_ENACT_REDIRECT, ++ FILTER_ENACT_MIRROR, ++ FILTER_ENACT_TRAP_CPU, ++ FILTER_ENACT_ISOLATION, ++ ++ /* QoS */ ++ FILTER_ENACT_PRIORITY, ++ FILTER_ENACT_DSCP_REMARK, ++ FILTER_ENACT_1P_REMARK, ++ FILTER_ENACT_POLICING_3, ++ ++ /* Interrutp and GPO */ ++ FILTER_ENACT_INTERRUPT, ++ FILTER_ENACT_GPO, ++ ++ /*VLAN tag*/ ++ FILTER_ENACT_EGRESSCTAG_UNTAG, ++ FILTER_ENACT_EGRESSCTAG_TAG, ++ FILTER_ENACT_EGRESSCTAG_KEEP, ++ FILTER_ENACT_EGRESSCTAG_KEEPAND1PRMK, ++ ++ FILTER_ENACT_END, ++} rtk_filter_act_enable_t; ++ ++ ++typedef struct ++{ ++ rtk_filter_act_enable_t actEnable[FILTER_ENACT_END]; ++ ++ /* CVLAN acton */ ++ rtk_uint32 filterCvlanVid; ++ rtk_uint32 filterCvlanIdx; ++ /* SVLAN action */ ++ rtk_uint32 filterSvlanVid; ++ rtk_uint32 filterSvlanIdx; ++ ++ /* Policing action */ ++ rtk_uint32 filterPolicingIdx[FILTER_POLICING_MAX]; ++ ++ /* Forwarding action */ ++ rtk_portmask_t filterPortmask; ++ ++ /* QOS action */ ++ rtk_uint32 filterPriority; ++ ++ /*GPO*/ ++ rtk_uint32 filterPin; ++ ++} rtk_filter_action_t; ++ ++typedef struct rtk_filter_flag_s ++{ ++ rtk_uint32 value; ++ rtk_uint32 mask; ++} rtk_filter_flag_t; ++ ++typedef enum rtk_filter_care_tag_index_e ++{ ++ CARE_TAG_CTAG = 0, ++ CARE_TAG_STAG, ++ CARE_TAG_PPPOE, ++ CARE_TAG_IPV4, ++ CARE_TAG_IPV6, ++ CARE_TAG_TCP, ++ CARE_TAG_UDP, ++ CARE_TAG_ARP, ++ CARE_TAG_RSV1, ++ CARE_TAG_RSV2, ++ CARE_TAG_ICMP, ++ CARE_TAG_IGMP, ++ CARE_TAG_LLC, ++ CARE_TAG_RSV3, ++ CARE_TAG_HTTP, ++ CARE_TAG_RSV4, ++ CARE_TAG_RSV5, ++ CARE_TAG_DHCP, ++ CARE_TAG_DHCPV6, ++ CARE_TAG_SNMP, ++ CARE_TAG_OAM, ++ CARE_TAG_END, ++} rtk_filter_care_tag_index_t; ++ ++typedef struct rtk_filter_care_tag_s ++{ ++ rtk_filter_flag_t tagType[CARE_TAG_END]; ++} rtk_filter_care_tag_t; ++ ++typedef struct rtk_filter_field rtk_filter_field_t; ++ ++typedef struct ++{ ++ rtk_uint32 value[RTK_DOT_1AS_TIMESTAMP_UNIT_IN_WORD_LENGTH]; ++} rtk_filter_dot1as_timestamp_t; ++ ++typedef enum rtk_filter_field_data_type_e ++{ ++ FILTER_FIELD_DATA_MASK = 0, ++ FILTER_FIELD_DATA_RANGE, ++ FILTER_FIELD_DATA_END , ++} rtk_filter_field_data_type_t; ++ ++typedef struct rtk_filter_ip_s ++{ ++ rtk_uint32 dataType; ++ rtk_uint32 rangeStart; ++ rtk_uint32 rangeEnd; ++ rtk_uint32 value; ++ rtk_uint32 mask; ++} rtk_filter_ip_t; ++ ++typedef struct rtk_filter_mac_s ++{ ++ rtk_uint32 dataType; ++ rtk_mac_t value; ++ rtk_mac_t mask; ++ rtk_mac_t rangeStart; ++ rtk_mac_t rangeEnd; ++} rtk_filter_mac_t; ++ ++typedef rtk_uint32 rtk_filter_op_t; ++ ++typedef struct rtk_filter_value_s ++{ ++ rtk_uint32 dataType; ++ rtk_uint32 value; ++ rtk_uint32 mask; ++ rtk_uint32 rangeStart; ++ rtk_uint32 rangeEnd; ++ ++} rtk_filter_value_t; ++ ++typedef struct rtk_filter_activeport_s ++{ ++ rtk_portmask_t value; ++ rtk_portmask_t mask; ++ ++} rtk_filter_activeport_t; ++ ++ ++ ++typedef struct rtk_filter_tag_s ++{ ++ rtk_filter_value_t pri; ++ rtk_filter_flag_t cfi; ++ rtk_filter_value_t vid; ++} rtk_filter_tag_t; ++ ++typedef struct rtk_filter_ipFlag_s ++{ ++ rtk_filter_flag_t xf; ++ rtk_filter_flag_t mf; ++ rtk_filter_flag_t df; ++} rtk_filter_ipFlag_t; ++ ++typedef struct ++{ ++ rtk_uint32 addr[RTK_IPV6_ADDR_WORD_LENGTH]; ++} rtk_filter_ip6_addr_t; ++ ++typedef struct ++{ ++ rtk_uint32 dataType; ++ rtk_filter_ip6_addr_t value; ++ rtk_filter_ip6_addr_t mask; ++ rtk_filter_ip6_addr_t rangeStart; ++ rtk_filter_ip6_addr_t rangeEnd; ++} rtk_filter_ip6_t; ++ ++typedef rtk_uint32 rtk_filter_number_t; ++ ++typedef struct rtk_filter_pattern_s ++{ ++ rtk_uint32 value[FILTER_PATTERN_MAX]; ++ rtk_uint32 mask[FILTER_PATTERN_MAX]; ++} rtk_filter_pattern_t; ++ ++typedef struct rtk_filter_tcpFlag_s ++{ ++ rtk_filter_flag_t urg; ++ rtk_filter_flag_t ack; ++ rtk_filter_flag_t psh; ++ rtk_filter_flag_t rst; ++ rtk_filter_flag_t syn; ++ rtk_filter_flag_t fin; ++ rtk_filter_flag_t ns; ++ rtk_filter_flag_t cwr; ++ rtk_filter_flag_t ece; ++} rtk_filter_tcpFlag_t; ++ ++typedef rtk_uint32 rtk_filter_field_raw_t; ++ ++typedef enum rtk_filter_field_temple_input_e ++{ ++ FILTER_FIELD_TEMPLE_INPUT_TYPE = 0, ++ FILTER_FIELD_TEMPLE_INPUT_INDEX, ++ FILTER_FIELD_TEMPLE_INPUT_MAX , ++} rtk_filter_field_temple_input_t; ++ ++struct rtk_filter_field ++{ ++ rtk_uint32 fieldType; ++ ++ union ++ { ++ /* L2 struct */ ++ rtk_filter_mac_t dmac; ++ rtk_filter_mac_t smac; ++ rtk_filter_value_t etherType; ++ rtk_filter_tag_t ctag; ++ rtk_filter_tag_t relayCtag; ++ rtk_filter_tag_t stag; ++ rtk_filter_tag_t l2tag; ++ rtk_filter_dot1as_timestamp_t dot1asTimeStamp; ++ rtk_filter_mac_t mac; ++ ++ /* L3 struct */ ++ rtk_filter_ip_t sip; ++ rtk_filter_ip_t dip; ++ rtk_filter_ip_t ip; ++ rtk_filter_value_t protocol; ++ rtk_filter_value_t ipTos; ++ rtk_filter_ipFlag_t ipFlag; ++ rtk_filter_value_t ipOffset; ++ rtk_filter_ip6_t sipv6; ++ rtk_filter_ip6_t dipv6; ++ rtk_filter_ip6_t ipv6; ++ rtk_filter_value_t ipv6TrafficClass; ++ rtk_filter_value_t ipv6NextHeader; ++ rtk_filter_value_t flowLabel; ++ ++ /* L4 struct */ ++ rtk_filter_value_t tcpSrcPort; ++ rtk_filter_value_t tcpDstPort; ++ rtk_filter_tcpFlag_t tcpFlag; ++ rtk_filter_value_t tcpSeqNumber; ++ rtk_filter_value_t tcpAckNumber; ++ rtk_filter_value_t udpSrcPort; ++ rtk_filter_value_t udpDstPort; ++ rtk_filter_value_t icmpCode; ++ rtk_filter_value_t icmpType; ++ rtk_filter_value_t igmpType; ++ ++ /* pattern match */ ++ rtk_filter_pattern_t pattern; ++ ++ rtk_filter_value_t inData; ++ ++ } filter_pattern_union; ++ ++ rtk_uint32 fieldTemplateNo; ++ rtk_uint32 fieldTemplateIdx[RTK_FILTER_FIELD_USED_MAX]; ++ ++ struct rtk_filter_field *next; ++}; ++ ++typedef enum rtk_filter_field_type_e ++{ ++ FILTER_FIELD_DMAC = 0, ++ FILTER_FIELD_SMAC, ++ FILTER_FIELD_ETHERTYPE, ++ FILTER_FIELD_CTAG, ++ FILTER_FIELD_STAG, ++ ++ FILTER_FIELD_IPV4_SIP, ++ FILTER_FIELD_IPV4_DIP, ++ FILTER_FIELD_IPV4_TOS, ++ FILTER_FIELD_IPV4_PROTOCOL, ++ FILTER_FIELD_IPV4_FLAG, ++ FILTER_FIELD_IPV4_OFFSET, ++ FILTER_FIELD_IPV6_SIPV6, ++ FILTER_FIELD_IPV6_DIPV6, ++ FILTER_FIELD_IPV6_TRAFFIC_CLASS, ++ FILTER_FIELD_IPV6_NEXT_HEADER, ++ ++ FILTER_FIELD_TCP_SPORT, ++ FILTER_FIELD_TCP_DPORT, ++ FILTER_FIELD_TCP_FLAG, ++ FILTER_FIELD_UDP_SPORT, ++ FILTER_FIELD_UDP_DPORT, ++ FILTER_FIELD_ICMP_CODE, ++ FILTER_FIELD_ICMP_TYPE, ++ FILTER_FIELD_IGMP_TYPE, ++ ++ FILTER_FIELD_VID_RANGE, ++ FILTER_FIELD_IP_RANGE, ++ FILTER_FIELD_PORT_RANGE, ++ ++ FILTER_FIELD_USER_DEFINED00, ++ FILTER_FIELD_USER_DEFINED01, ++ FILTER_FIELD_USER_DEFINED02, ++ FILTER_FIELD_USER_DEFINED03, ++ FILTER_FIELD_USER_DEFINED04, ++ FILTER_FIELD_USER_DEFINED05, ++ FILTER_FIELD_USER_DEFINED06, ++ FILTER_FIELD_USER_DEFINED07, ++ FILTER_FIELD_USER_DEFINED08, ++ FILTER_FIELD_USER_DEFINED09, ++ FILTER_FIELD_USER_DEFINED10, ++ FILTER_FIELD_USER_DEFINED11, ++ FILTER_FIELD_USER_DEFINED12, ++ FILTER_FIELD_USER_DEFINED13, ++ FILTER_FIELD_USER_DEFINED14, ++ FILTER_FIELD_USER_DEFINED15, ++ ++ FILTER_FIELD_PATTERN_MATCH, ++ ++ FILTER_FIELD_END, ++} rtk_filter_field_type_t; ++ ++ ++typedef enum rtk_filter_field_type_raw_e ++{ ++ FILTER_FIELD_RAW_UNUSED = 0, ++ FILTER_FIELD_RAW_DMAC_15_0, ++ FILTER_FIELD_RAW_DMAC_31_16, ++ FILTER_FIELD_RAW_DMAC_47_32, ++ FILTER_FIELD_RAW_SMAC_15_0, ++ FILTER_FIELD_RAW_SMAC_31_16, ++ FILTER_FIELD_RAW_SMAC_47_32, ++ FILTER_FIELD_RAW_ETHERTYPE, ++ FILTER_FIELD_RAW_STAG, ++ FILTER_FIELD_RAW_CTAG, ++ ++ FILTER_FIELD_RAW_IPV4_SIP_15_0 = 0x10, ++ FILTER_FIELD_RAW_IPV4_SIP_31_16, ++ FILTER_FIELD_RAW_IPV4_DIP_15_0, ++ FILTER_FIELD_RAW_IPV4_DIP_31_16, ++ ++ ++ FILTER_FIELD_RAW_IPV6_SIP_15_0 = 0x20, ++ FILTER_FIELD_RAW_IPV6_SIP_31_16, ++ FILTER_FIELD_RAW_IPV6_DIP_15_0 = 0x28, ++ FILTER_FIELD_RAW_IPV6_DIP_31_16, ++ ++ FILTER_FIELD_RAW_VIDRANGE = 0x30, ++ FILTER_FIELD_RAW_IPRANGE, ++ FILTER_FIELD_RAW_PORTRANGE, ++ FILTER_FIELD_RAW_FIELD_VALID, ++ ++ FILTER_FIELD_RAW_FIELD_SELECT00 = 0x40, ++ FILTER_FIELD_RAW_FIELD_SELECT01, ++ FILTER_FIELD_RAW_FIELD_SELECT02, ++ FILTER_FIELD_RAW_FIELD_SELECT03, ++ FILTER_FIELD_RAW_FIELD_SELECT04, ++ FILTER_FIELD_RAW_FIELD_SELECT05, ++ FILTER_FIELD_RAW_FIELD_SELECT06, ++ FILTER_FIELD_RAW_FIELD_SELECT07, ++ FILTER_FIELD_RAW_FIELD_SELECT08, ++ FILTER_FIELD_RAW_FIELD_SELECT09, ++ FILTER_FIELD_RAW_FIELD_SELECT10, ++ FILTER_FIELD_RAW_FIELD_SELECT11, ++ FILTER_FIELD_RAW_FIELD_SELECT12, ++ FILTER_FIELD_RAW_FIELD_SELECT13, ++ FILTER_FIELD_RAW_FIELD_SELECT14, ++ FILTER_FIELD_RAW_FIELD_SELECT15, ++ ++ FILTER_FIELD_RAW_END, ++} rtk_filter_field_type_raw_t; ++ ++typedef enum rtk_filter_flag_care_type_e ++{ ++ FILTER_FLAG_CARE_DONT_CARE = 0, ++ FILTER_FLAG_CARE_1, ++ FILTER_FLAG_CARE_0, ++ FILTER_FLAG_END ++} rtk_filter_flag_care_type_t; ++ ++typedef rtk_uint32 rtk_filter_id_t; /* filter id type */ ++ ++typedef enum rtk_filter_invert_e ++{ ++ FILTER_INVERT_DISABLE = 0, ++ FILTER_INVERT_ENABLE, ++ FILTER_INVERT_END, ++} rtk_filter_invert_t; ++ ++typedef rtk_uint32 rtk_filter_state_t; ++ ++typedef rtk_uint32 rtk_filter_unmatch_action_t; ++ ++typedef enum rtk_filter_unmatch_action_e ++{ ++ FILTER_UNMATCH_DROP = 0, ++ FILTER_UNMATCH_PERMIT, ++ FILTER_UNMATCH_END, ++} rtk_filter_unmatch_action_type_t; ++ ++typedef struct ++{ ++ rtk_filter_field_t *fieldHead; ++ rtk_filter_care_tag_t careTag; ++ rtk_filter_activeport_t activeport; ++ ++ rtk_filter_invert_t invert; ++} rtk_filter_cfg_t; ++ ++typedef struct ++{ ++ rtk_filter_field_raw_t dataFieldRaw[RTK_FILTER_RAW_FIELD_NUMBER]; ++ rtk_filter_field_raw_t careFieldRaw[RTK_FILTER_RAW_FIELD_NUMBER]; ++ rtk_filter_field_type_raw_t fieldRawType[RTK_FILTER_RAW_FIELD_NUMBER]; ++ rtk_filter_care_tag_t careTag; ++ rtk_filter_activeport_t activeport; ++ ++ rtk_filter_invert_t invert; ++ rtk_enable_t valid; ++} rtk_filter_cfg_raw_t; ++ ++typedef struct ++{ ++ rtk_uint32 index; ++ rtk_filter_field_type_raw_t fieldType[RTK_FILTER_RAW_FIELD_NUMBER]; ++} rtk_filter_template_t; ++ ++typedef enum rtk_field_sel_e ++{ ++ FORMAT_DEFAULT = 0, ++ FORMAT_RAW, ++ FORMAT_LLC, ++ FORMAT_IPV4, ++ FORMAT_ARP, ++ FORMAT_IPV6, ++ FORMAT_IPPAYLOAD, ++ FORMAT_L4PAYLOAD, ++ FORMAT_END ++}rtk_field_sel_t; ++ ++typedef enum rtk_filter_iprange_e ++{ ++ IPRANGE_UNUSED = 0, ++ IPRANGE_IPV4_SIP, ++ IPRANGE_IPV4_DIP, ++ IPRANGE_IPV6_SIP, ++ IPRANGE_IPV6_DIP, ++ IPRANGE_END ++}rtk_filter_iprange_t; ++ ++typedef enum rtk_filter_vidrange_e ++{ ++ VIDRANGE_UNUSED = 0, ++ VIDRANGE_CVID, ++ VIDRANGE_SVID, ++ VIDRANGE_END ++}rtk_filter_vidrange_t; ++ ++typedef enum rtk_filter_portrange_e ++{ ++ PORTRANGE_UNUSED = 0, ++ PORTRANGE_SPORT, ++ PORTRANGE_DPORT, ++ PORTRANGE_END ++}rtk_filter_portrange_t; ++ ++/* Function Name: ++ * rtk_filter_igrAcl_init ++ * Description: ++ * ACL initialization function ++ * Input: ++ * None ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_NULL_POINTER - Pointer pFilter_field or pFilter_cfg point to NULL. ++ * Note: ++ * This function enable and initialize ACL function ++ */ ++extern rtk_api_ret_t rtk_filter_igrAcl_init(void); ++ ++/* Function Name: ++ * rtk_filter_igrAcl_field_add ++ * Description: ++ * Add comparison rule to an ACL configuration ++ * Input: ++ * pFilter_cfg - The ACL configuration that this function will add comparison rule ++ * pFilter_field - The comparison rule that will be added. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_NULL_POINTER - Pointer pFilter_field or pFilter_cfg point to NULL. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * This function add a comparison rule (*pFilter_field) to an ACL configuration (*pFilter_cfg). ++ * Pointer pFilter_cfg points to an ACL configuration structure, this structure keeps multiple ACL ++ * comparison rules by means of linked list. Pointer pFilter_field will be added to linked ++ * list kept by structure that pFilter_cfg points to. ++ */ ++extern rtk_api_ret_t rtk_filter_igrAcl_field_add(rtk_filter_cfg_t *pFilter_cfg, rtk_filter_field_t *pFilter_field); ++ ++/* Function Name: ++ * rtk_filter_igrAcl_cfg_add ++ * Description: ++ * Add an ACL configuration to ASIC ++ * Input: ++ * filter_id - Start index of ACL configuration. ++ * pFilter_cfg - The ACL configuration that this function will add comparison rule ++ * pFilter_action - Action(s) of ACL configuration. ++ * Output: ++ * ruleNum - number of rules written in ACL table ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_NULL_POINTER - Pointer pFilter_field or pFilter_cfg point to NULL. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_ENTRY_INDEX - Invalid filter_id . ++ * RT_ERR_NULL_POINTER - Pointer pFilter_action or pFilter_cfg point to NULL. ++ * RT_ERR_FILTER_INACL_ACT_NOT_SUPPORT - Action is not supported in this chip. ++ * RT_ERR_FILTER_INACL_RULE_NOT_SUPPORT - Rule is not supported. ++ * Note: ++ * This function store pFilter_cfg, pFilter_action into ASIC. The starting ++ * index(es) is filter_id. ++ */ ++extern rtk_api_ret_t rtk_filter_igrAcl_cfg_add(rtk_filter_id_t filter_id, rtk_filter_cfg_t *pFilter_cfg, rtk_filter_action_t *pAction, rtk_filter_number_t *ruleNum); ++ ++/* Function Name: ++ * rtk_filter_igrAcl_cfg_del ++ * Description: ++ * Delete an ACL configuration from ASIC ++ * Input: ++ * filter_id - Start index of ACL configuration. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_FILTER_ENTRYIDX - Invalid filter_id. ++ * Note: ++ * This function delete a group of ACL rules starting from filter_id. ++ */ ++extern rtk_api_ret_t rtk_filter_igrAcl_cfg_del(rtk_filter_id_t filter_id); ++ ++/* Function Name: ++ * rtk_filter_igrAcl_cfg_delAll ++ * Description: ++ * Delete all ACL entries from ASIC ++ * Input: ++ * None ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * This function delete all ACL configuration from ASIC. ++ */ ++extern rtk_api_ret_t rtk_filter_igrAcl_cfg_delAll(void); ++ ++/* Function Name: ++ * rtk_filter_igrAcl_cfg_get ++ * Description: ++ * Get one ingress ACL configuration from ASIC. ++ * Input: ++ * filter_id - Start index of ACL configuration. ++ * Output: ++ * pFilter_cfg - buffer pointer of ingress ACL data ++ * pFilter_action - buffer pointer of ingress ACL action ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_NULL_POINTER - Pointer pFilter_action or pFilter_cfg point to NULL. ++ * RT_ERR_FILTER_ENTRYIDX - Invalid entry index. ++ * Note: ++ * This function delete all ACL configuration from ASIC. ++ */ ++extern rtk_api_ret_t rtk_filter_igrAcl_cfg_get(rtk_filter_id_t filter_id, rtk_filter_cfg_raw_t *pFilter_cfg, rtk_filter_action_t *pAction); ++ ++/* Function Name: ++ * rtk_filter_igrAcl_unmatchAction_set ++ * Description: ++ * Set action to packets when no ACL configuration match ++ * Input: ++ * port - Port id. ++ * action - Action. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port id. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * This function sets action of packets when no ACL configuration matches. ++ */ ++extern rtk_api_ret_t rtk_filter_igrAcl_unmatchAction_set(rtk_port_t port, rtk_filter_unmatch_action_t action); ++ ++/* Function Name: ++ * rtk_filter_igrAcl_unmatchAction_get ++ * Description: ++ * Get action to packets when no ACL configuration match ++ * Input: ++ * port - Port id. ++ * Output: ++ * pAction - Action. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port id. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * This function gets action of packets when no ACL configuration matches. ++ */ ++extern rtk_api_ret_t rtk_filter_igrAcl_unmatchAction_get(rtk_port_t port, rtk_filter_unmatch_action_t* action); ++ ++/* Function Name: ++ * rtk_filter_igrAcl_state_set ++ * Description: ++ * Set state of ingress ACL. ++ * Input: ++ * port - Port id. ++ * state - Ingress ACL state. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port id. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * This function gets action of packets when no ACL configuration matches. ++ */ ++extern rtk_api_ret_t rtk_filter_igrAcl_state_set(rtk_port_t port, rtk_filter_state_t state); ++ ++/* Function Name: ++ * rtk_filter_igrAcl_state_get ++ * Description: ++ * Get state of ingress ACL. ++ * Input: ++ * port - Port id. ++ * Output: ++ * pState - Ingress ACL state. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port id. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * This function gets action of packets when no ACL configuration matches. ++ */ ++extern rtk_api_ret_t rtk_filter_igrAcl_state_get(rtk_port_t port, rtk_filter_state_t* state); ++ ++/* Function Name: ++ * rtk_filter_igrAcl_template_set ++ * Description: ++ * Set template of ingress ACL. ++ * Input: ++ * template - Ingress ACL template ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * This function set ACL template. ++ */ ++extern rtk_api_ret_t rtk_filter_igrAcl_template_set(rtk_filter_template_t *aclTemplate); ++ ++/* Function Name: ++ * rtk_filter_igrAcl_template_get ++ * Description: ++ * Get template of ingress ACL. ++ * Input: ++ * template - Ingress ACL template ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * This function gets template of ACL. ++ */ ++extern rtk_api_ret_t rtk_filter_igrAcl_template_get(rtk_filter_template_t *aclTemplate); ++ ++/* Function Name: ++ * rtk_filter_igrAcl_field_sel_set ++ * Description: ++ * Set user defined field selectors in HSB ++ * Input: ++ * index - index of field selector 0-15 ++ * format - Format of field selector ++ * offset - Retrieving data offset ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * System support 16 user defined field selectors. ++ * Each selector can be enabled or disable. ++ * User can defined retrieving 16-bits in many predefiend ++ * standard l2/l3/l4 payload. ++ */ ++extern rtk_api_ret_t rtk_filter_igrAcl_field_sel_set(rtk_uint32 index, rtk_field_sel_t format, rtk_uint32 offset); ++ ++/* Function Name: ++ * rtk_filter_igrAcl_field_sel_get ++ * Description: ++ * Get user defined field selectors in HSB ++ * Input: ++ * index - index of field selector 0-15 ++ * Output: ++ * pFormat - Format of field selector ++ * pOffset - Retrieving data offset ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None. ++ */ ++extern rtk_api_ret_t rtk_filter_igrAcl_field_sel_get(rtk_uint32 index, rtk_field_sel_t *pFormat, rtk_uint32 *pOffset); ++ ++/* Function Name: ++ * rtk_filter_iprange_set ++ * Description: ++ * Set IP Range check ++ * Input: ++ * index - index of IP Range 0-15 ++ * type - IP Range check type, 0:Delete a entry, 1: IPv4_SIP, 2: IPv4_DIP, 3:IPv6_SIP, 4:IPv6_DIP ++ * upperIp - The upper bound of IP range ++ * lowerIp - The lower Bound of IP range ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - The parameter is out of range ++ * RT_ERR_INPUT - Input error ++ * Note: ++ * upperIp must be larger or equal than lowerIp. ++ */ ++extern rtk_api_ret_t rtk_filter_iprange_set(rtk_uint32 index, rtk_filter_iprange_t type, ipaddr_t upperIp, ipaddr_t lowerIp); ++ ++/* Function Name: ++ * rtk_filter_iprange_get ++ * Description: ++ * Set IP Range check ++ * Input: ++ * index - index of IP Range 0-15 ++ * Output: ++ * pType - IP Range check type, 0:Delete a entry, 1: IPv4_SIP, 2: IPv4_DIP, 3:IPv6_SIP, 4:IPv6_DIP ++ * pUpperIp - The upper bound of IP range ++ * pLowerIp - The lower Bound of IP range ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - The parameter is out of range ++ * Note: ++ * upperIp must be larger or equal than lowerIp. ++ */ ++extern rtk_api_ret_t rtk_filter_iprange_get(rtk_uint32 index, rtk_filter_iprange_t *pType, ipaddr_t *pUpperIp, ipaddr_t *pLowerIp); ++ ++/* Function Name: ++ * rtk_filter_vidrange_set ++ * Description: ++ * Set VID Range check ++ * Input: ++ * index - index of VID Range 0-15 ++ * type - IP Range check type, 0:Delete a entry, 1: CVID, 2: SVID ++ * upperVid - The upper bound of VID range ++ * lowerVid - The lower Bound of VID range ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - The parameter is out of range ++ * RT_ERR_INPUT - Input error ++ * Note: ++ * upperVid must be larger or equal than lowerVid. ++ */ ++extern rtk_api_ret_t rtk_filter_vidrange_set(rtk_uint32 index, rtk_filter_vidrange_t type, rtk_uint32 upperVid, rtk_uint32 lowerVid); ++ ++/* Function Name: ++ * rtk_filter_vidrange_get ++ * Description: ++ * Get VID Range check ++ * Input: ++ * index - index of VID Range 0-15 ++ * Output: ++ * pType - IP Range check type, 0:Unused, 1: CVID, 2: SVID ++ * pUpperVid - The upper bound of VID range ++ * pLowerVid - The lower Bound of VID range ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - The parameter is out of range ++ * Note: ++ * None. ++ */ ++extern rtk_api_ret_t rtk_filter_vidrange_get(rtk_uint32 index, rtk_filter_vidrange_t *pType, rtk_uint32 *pUpperVid, rtk_uint32 *pLowerVid); ++ ++/* Function Name: ++ * rtk_filter_portrange_set ++ * Description: ++ * Set Port Range check ++ * Input: ++ * index - index of Port Range 0-15 ++ * type - IP Range check type, 0:Delete a entry, 1: Source Port, 2: Destination Port ++ * upperPort - The upper bound of Port range ++ * lowerPort - The lower Bound of Port range ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - The parameter is out of range ++ * RT_ERR_INPUT - Input error ++ * Note: ++ * upperPort must be larger or equal than lowerPort. ++ */ ++extern rtk_api_ret_t rtk_filter_portrange_set(rtk_uint32 index, rtk_filter_portrange_t type, rtk_uint32 upperPort, rtk_uint32 lowerPort); ++ ++/* Function Name: ++ * rtk_filter_portrange_get ++ * Description: ++ * Set Port Range check ++ * Input: ++ * index - index of Port Range 0-15 ++ * Output: ++ * pType - IP Range check type, 0:Delete a entry, 1: Source Port, 2: Destination Port ++ * pUpperPort - The upper bound of Port range ++ * pLowerPort - The lower Bound of Port range ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - The parameter is out of range ++ * RT_ERR_INPUT - Input error ++ * Note: ++ * None. ++ */ ++extern rtk_api_ret_t rtk_filter_portrange_get(rtk_uint32 index, rtk_filter_portrange_t *pType, rtk_uint32 *pUpperPort, rtk_uint32 *pLowerPort); ++ ++/* Function Name: ++ * rtk_filter_igrAclPolarity_set ++ * Description: ++ * Set ACL Goip control polarity ++ * Input: ++ * polarity - 1: High, 0: Low ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * none ++ */ ++extern rtk_api_ret_t rtk_filter_igrAclPolarity_set(rtk_uint32 polarity); ++ ++/* Function Name: ++ * rtk_filter_igrAclPolarity_get ++ * Description: ++ * Get ACL Goip control polarity ++ * Input: ++ * pPolarity - 1: High, 0: Low ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * none ++ */ ++extern rtk_api_ret_t rtk_filter_igrAclPolarity_get(rtk_uint32* pPolarity); ++ ++ ++#endif /* __RTK_API_ACL_H__ */ +diff --git a/drivers/net/phy/rtk/rtl8367c/include/cpu.h b/drivers/net/phy/rtk/rtl8367c/include/cpu.h +new file mode 100644 +index 000000000000..67aa1e3d88ea +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/cpu.h +@@ -0,0 +1,327 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * Purpose : RTL8367/RTL8367C switch high-level API ++ * ++ * Feature : The file includes CPU module high-layer API definition ++ * ++ */ ++ ++#ifndef __RTK_API_CPU_H__ ++#define __RTK_API_CPU_H__ ++ ++ ++/* ++ * Data Type Declaration ++ */ ++typedef enum rtk_cpu_insert_e ++{ ++ CPU_INSERT_TO_ALL = 0, ++ CPU_INSERT_TO_TRAPPING, ++ CPU_INSERT_TO_NONE, ++ CPU_INSERT_END ++}rtk_cpu_insert_t; ++ ++typedef enum rtk_cpu_position_e ++{ ++ CPU_POS_AFTER_SA = 0, ++ CPU_POS_BEFORE_CRC, ++ CPU_POS_END ++}rtk_cpu_position_t; ++ ++typedef enum rtk_cpu_tag_length_e ++{ ++ CPU_LEN_8BYTES = 0, ++ CPU_LEN_4BYTES, ++ CPU_LEN_END ++}rtk_cpu_tag_length_t; ++ ++ ++typedef enum rtk_cpu_rx_length_e ++{ ++ CPU_RX_72BYTES = 0, ++ CPU_RX_64BYTES, ++ CPU_RX_END ++}rtk_cpu_rx_length_t; ++ ++ ++/* Function Name: ++ * rtk_cpu_enable_set ++ * Description: ++ * Set CPU port function enable/disable. ++ * Input: ++ * enable - CPU port function enable ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameter. ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * The API can set CPU port function enable/disable. ++ */ ++extern rtk_api_ret_t rtk_cpu_enable_set(rtk_enable_t enable); ++ ++/* Function Name: ++ * rtk_cpu_enable_get ++ * Description: ++ * Get CPU port and its setting. ++ * Input: ++ * None ++ * Output: ++ * pEnable - CPU port function enable ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_L2_NO_CPU_PORT - CPU port is not exist ++ * Note: ++ * The API can get CPU port function enable/disable. ++ */ ++extern rtk_api_ret_t rtk_cpu_enable_get(rtk_enable_t *pEnable); ++ ++/* Function Name: ++ * rtk_cpu_tagPort_set ++ * Description: ++ * Set CPU port and CPU tag insert mode. ++ * Input: ++ * port - Port id. ++ * mode - CPU tag insert for packets egress from CPU port. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameter. ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * The API can set CPU port and inserting proprietary CPU tag mode (Length/Type 0x8899) ++ * to the frame that transmitting to CPU port. ++ * The insert CPU tag mode is as following: ++ * - CPU_INSERT_TO_ALL ++ * - CPU_INSERT_TO_TRAPPING ++ * - CPU_INSERT_TO_NONE ++ */ ++extern rtk_api_ret_t rtk_cpu_tagPort_set(rtk_port_t port, rtk_cpu_insert_t mode); ++ ++/* Function Name: ++ * rtk_cpu_tagPort_get ++ * Description: ++ * Get CPU port and CPU tag insert mode. ++ * Input: ++ * None ++ * Output: ++ * pPort - Port id. ++ * pMode - CPU tag insert for packets egress from CPU port, 0:all insert 1:Only for trapped packets 2:no insert. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_L2_NO_CPU_PORT - CPU port is not exist ++ * Note: ++ * The API can get configured CPU port and its setting. ++ * The insert CPU tag mode is as following: ++ * - CPU_INSERT_TO_ALL ++ * - CPU_INSERT_TO_TRAPPING ++ * - CPU_INSERT_TO_NONE ++ */ ++extern rtk_api_ret_t rtk_cpu_tagPort_get(rtk_port_t *pPort, rtk_cpu_insert_t *pMode); ++ ++/* Function Name: ++ * rtk_cpu_awarePort_set ++ * Description: ++ * Set CPU aware port mask. ++ * Input: ++ * portmask - Port mask. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_MASK - Invalid port mask. ++ * Note: ++ * The API can set configured CPU aware port mask. ++ */ ++extern rtk_api_ret_t rtk_cpu_awarePort_set(rtk_portmask_t *pPortmask); ++ ++ ++/* Function Name: ++ * rtk_cpu_awarePort_get ++ * Description: ++ * Get CPU aware port mask. ++ * Input: ++ * None ++ * Output: ++ * pPortmask - Port mask. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * The API can get configured CPU aware port mask. ++ */ ++extern rtk_api_ret_t rtk_cpu_awarePort_get(rtk_portmask_t *pPortmask); ++ ++/* Function Name: ++ * rtk_cpu_tagPosition_set ++ * Description: ++ * Set CPU tag position. ++ * Input: ++ * position - CPU tag position. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input. ++ * Note: ++ * The API can set CPU tag position. ++ */ ++extern rtk_api_ret_t rtk_cpu_tagPosition_set(rtk_cpu_position_t position); ++ ++/* Function Name: ++ * rtk_cpu_tagPosition_get ++ * Description: ++ * Get CPU tag position. ++ * Input: ++ * None ++ * Output: ++ * pPosition - CPU tag position. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input. ++ * Note: ++ * The API can get CPU tag position. ++ */ ++extern rtk_api_ret_t rtk_cpu_tagPosition_get(rtk_cpu_position_t *pPosition); ++ ++/* Function Name: ++ * rtk_cpu_tagLength_set ++ * Description: ++ * Set CPU tag length. ++ * Input: ++ * length - CPU tag length. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input. ++ * Note: ++ * The API can set CPU tag length. ++ */ ++extern rtk_api_ret_t rtk_cpu_tagLength_set(rtk_cpu_tag_length_t length); ++ ++/* Function Name: ++ * rtk_cpu_tagLength_get ++ * Description: ++ * Get CPU tag length. ++ * Input: ++ * None ++ * Output: ++ * pLength - CPU tag length. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input. ++ * Note: ++ * The API can get CPU tag length. ++ */ ++extern rtk_api_ret_t rtk_cpu_tagLength_get(rtk_cpu_tag_length_t *pLength); ++ ++/* Function Name: ++ * rtk_cpu_acceptLength_set ++ * Description: ++ * Set CPU accept length. ++ * Input: ++ * length - CPU tag length. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input. ++ * Note: ++ * The API can set CPU accept length. ++ */ ++extern rtk_api_ret_t rtk_cpu_acceptLength_set(rtk_cpu_rx_length_t length); ++ ++/* Function Name: ++ * rtk_cpu_acceptLength_get ++ * Description: ++ * Get CPU accept length. ++ * Input: ++ * None ++ * Output: ++ * pLength - CPU tag length. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input. ++ * Note: ++ * The API can get CPU accept length. ++ */ ++extern rtk_api_ret_t rtk_cpu_acceptLength_get(rtk_cpu_rx_length_t *pLength); ++ ++/* Function Name: ++ * rtk_cpu_priRemap_set ++ * Description: ++ * Configure CPU priorities mapping to internal absolute priority. ++ * Input: ++ * int_pri - internal priority value. ++ * new_pri - new internal priority value. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_VLAN_PRIORITY - Invalid 1p priority. ++ * RT_ERR_QOS_INT_PRIORITY - Invalid priority. ++ * Note: ++ * Priority of CPU tag assignment for internal asic priority, and it is used for queue usage and packet scheduling. ++ */ ++extern rtk_api_ret_t rtk_cpu_priRemap_set(rtk_pri_t int_pri, rtk_pri_t new_pri); ++ ++/* Function Name: ++ * rtk_cpu_priRemap_get ++ * Description: ++ * Configure CPU priorities mapping to internal absolute priority. ++ * Input: ++ * int_pri - internal priority value. ++ * Output: ++ * pNew_pri - new internal priority value. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_VLAN_PRIORITY - Invalid 1p priority. ++ * RT_ERR_QOS_INT_PRIORITY - Invalid priority. ++ * Note: ++ * Priority of CPU tag assignment for internal asic priority, and it is used for queue usage and packet scheduling. ++ */ ++extern rtk_api_ret_t rtk_cpu_priRemap_get(rtk_pri_t int_pri, rtk_pri_t *pNew_pri); ++ ++ ++#endif /* __RTK_API_CPU_H__ */ +diff --git a/drivers/net/phy/rtk/rtl8367c/include/dot1x.h b/drivers/net/phy/rtk/rtl8367c/include/dot1x.h +new file mode 100644 +index 000000000000..082ee2569e2a +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/dot1x.h +@@ -0,0 +1,470 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * Purpose : RTL8367/RTL8367C switch high-level API ++ * ++ * Feature : The file includes 1X module high-layer API definition ++ * ++ */ ++ ++#ifndef __RTK_API_DOT1X_H__ ++#define __RTK_API_DOT1X_H__ ++ ++ ++/* Type of port-based dot1x auth/unauth*/ ++typedef enum rtk_dot1x_auth_status_e ++{ ++ UNAUTH = 0, ++ AUTH, ++ AUTH_STATUS_END ++} rtk_dot1x_auth_status_t; ++ ++typedef enum rtk_dot1x_direction_e ++{ ++ DIR_BOTH = 0, ++ DIR_IN, ++ DIRECTION_END ++} rtk_dot1x_direction_t; ++ ++/* unauth pkt action */ ++typedef enum rtk_dot1x_unauth_action_e ++{ ++ DOT1X_ACTION_DROP = 0, ++ DOT1X_ACTION_TRAP2CPU, ++ DOT1X_ACTION_GUESTVLAN, ++ DOT1X_ACTION_END ++} rtk_dot1x_unauth_action_t; ++ ++/* Function Name: ++ * rtk_dot1x_unauthPacketOper_set ++ * Description: ++ * Set 802.1x unauth action configuration. ++ * Input: ++ * port - Port id. ++ * unauth_action - 802.1X unauth action. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_INPUT - Invalid input parameter. ++ * Note: ++ * This API can set 802.1x unauth action configuration. ++ * The unauth action is as following: ++ * - DOT1X_ACTION_DROP ++ * - DOT1X_ACTION_TRAP2CPU ++ * - DOT1X_ACTION_GUESTVLAN ++ */ ++extern rtk_api_ret_t rtk_dot1x_unauthPacketOper_set(rtk_port_t port, rtk_dot1x_unauth_action_t unauth_action); ++ ++/* Function Name: ++ * rtk_dot1x_unauthPacketOper_get ++ * Description: ++ * Get 802.1x unauth action configuration. ++ * Input: ++ * port - Port id. ++ * Output: ++ * pUnauth_action - 802.1X unauth action. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * This API can get 802.1x unauth action configuration. ++ * The unauth action is as following: ++ * - DOT1X_ACTION_DROP ++ * - DOT1X_ACTION_TRAP2CPU ++ * - DOT1X_ACTION_GUESTVLAN ++ */ ++extern rtk_api_ret_t rtk_dot1x_unauthPacketOper_get(rtk_port_t port, rtk_dot1x_unauth_action_t *pUnauth_action); ++ ++/* Function Name: ++ * rtk_dot1x_eapolFrame2CpuEnable_set ++ * Description: ++ * Set 802.1x EAPOL packet trap to CPU configuration ++ * Input: ++ * enable - The status of 802.1x EAPOL packet. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_ENABLE - Invalid enable input. ++ * Note: ++ * To support 802.1x authentication functionality, EAPOL frame (ether type = 0x888E) has to ++ * be trapped to CPU. ++ * The status of EAPOL frame trap to CPU is as following: ++ * - DISABLED ++ * - ENABLED ++ */ ++extern rtk_api_ret_t rtk_dot1x_eapolFrame2CpuEnable_set(rtk_enable_t enable); ++ ++/* Function Name: ++ * rtk_dot1x_eapolFrame2CpuEnable_get ++ * Description: ++ * Get 802.1x EAPOL packet trap to CPU configuration ++ * Input: ++ * None ++ * Output: ++ * pEnable - The status of 802.1x EAPOL packet. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * To support 802.1x authentication functionality, EAPOL frame (ether type = 0x888E) has to ++ * be trapped to CPU. ++ * The status of EAPOL frame trap to CPU is as following: ++ * - DISABLED ++ * - ENABLED ++ */ ++extern rtk_api_ret_t rtk_dot1x_eapolFrame2CpuEnable_get(rtk_enable_t *pEnable); ++ ++/* Function Name: ++ * rtk_dot1x_portBasedEnable_set ++ * Description: ++ * Set 802.1x port-based enable configuration ++ * Input: ++ * port - Port id. ++ * enable - The status of 802.1x port. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_ENABLE - Invalid enable input. ++ * RT_ERR_DOT1X_PORTBASEDPNEN - 802.1X port-based enable error ++ * Note: ++ * The API can update the port-based port enable register content. If a port is 802.1x ++ * port based network access control "enabled", it should be authenticated so packets ++ * from that port won't be dropped or trapped to CPU. ++ * The status of 802.1x port-based network access control is as following: ++ * - DISABLED ++ * - ENABLED ++ */ ++extern rtk_api_ret_t rtk_dot1x_portBasedEnable_set(rtk_port_t port, rtk_enable_t enable); ++ ++/* Function Name: ++ * rtk_dot1x_portBasedEnable_get ++ * Description: ++ * Get 802.1x port-based enable configuration ++ * Input: ++ * port - Port id. ++ * Output: ++ * pEnable - The status of 802.1x port. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * The API can get the 802.1x port-based port status. ++ */ ++extern rtk_api_ret_t rtk_dot1x_portBasedEnable_get(rtk_port_t port, rtk_enable_t *pEnable); ++ ++/* Function Name: ++ * rtk_dot1x_portBasedAuthStatus_set ++ * Description: ++ * Set 802.1x port-based auth. port configuration ++ * Input: ++ * port - Port id. ++ * port_auth - The status of 802.1x port. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_DOT1X_PORTBASEDAUTH - 802.1X port-based auth error ++ * Note: ++ * The authenticated status of 802.1x port-based network access control is as following: ++ * - UNAUTH ++ * - AUTH ++ */ ++extern rtk_api_ret_t rtk_dot1x_portBasedAuthStatus_set(rtk_port_t port, rtk_dot1x_auth_status_t port_auth); ++ ++/* Function Name: ++ * rtk_dot1x_portBasedAuthStatus_get ++ * Description: ++ * Get 802.1x port-based auth. port configuration ++ * Input: ++ * port - Port id. ++ * Output: ++ * pPort_auth - The status of 802.1x port. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * The API can get 802.1x port-based port auth.information. ++ */ ++extern rtk_api_ret_t rtk_dot1x_portBasedAuthStatus_get(rtk_port_t port, rtk_dot1x_auth_status_t *pPort_auth); ++ ++/* Function Name: ++ * rtk_dot1x_portBasedDirection_set ++ * Description: ++ * Set 802.1x port-based operational direction configuration ++ * Input: ++ * port - Port id. ++ * port_direction - Operation direction ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_DOT1X_PORTBASEDOPDIR - 802.1X port-based operation direction error ++ * Note: ++ * The operate controlled direction of 802.1x port-based network access control is as following: ++ * - BOTH ++ * - IN ++ */ ++extern rtk_api_ret_t rtk_dot1x_portBasedDirection_set(rtk_port_t port, rtk_dot1x_direction_t port_direction); ++ ++/* Function Name: ++ * rtk_dot1x_portBasedDirection_get ++ * Description: ++ * Get 802.1X port-based operational direction configuration ++ * Input: ++ * port - Port id. ++ * Output: ++ * pPort_direction - Operation direction ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * The API can get 802.1x port-based operational direction information. ++ */ ++extern rtk_api_ret_t rtk_dot1x_portBasedDirection_get(rtk_port_t port, rtk_dot1x_direction_t *pPort_direction); ++ ++/* Function Name: ++ * rtk_dot1x_macBasedEnable_set ++ * Description: ++ * Set 802.1x mac-based port enable configuration ++ * Input: ++ * port - Port id. ++ * enable - The status of 802.1x port. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_ENABLE - Invalid enable input. ++ * RT_ERR_DOT1X_MACBASEDPNEN - 802.1X mac-based enable error ++ * Note: ++ * If a port is 802.1x MAC based network access control "enabled", the incoming packets should ++ * be authenticated so packets from that port won't be dropped or trapped to CPU. ++ * The status of 802.1x MAC-based network access control is as following: ++ * - DISABLED ++ * - ENABLED ++ */ ++extern rtk_api_ret_t rtk_dot1x_macBasedEnable_set(rtk_port_t port, rtk_enable_t enable); ++ ++/* Function Name: ++ * rtk_dot1x_macBasedEnable_get ++ * Description: ++ * Get 802.1x mac-based port enable configuration ++ * Input: ++ * port - Port id. ++ * Output: ++ * pEnable - The status of 802.1x port. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * If a port is 802.1x MAC based network access control "enabled", the incoming packets should ++ * be authenticated so packets from that port wont be dropped or trapped to CPU. ++ * The status of 802.1x MAC-based network access control is as following: ++ * - DISABLED ++ * - ENABLED ++ */ ++extern rtk_api_ret_t rtk_dot1x_macBasedEnable_get(rtk_port_t port, rtk_enable_t *pEnable); ++ ++/* Function Name: ++ * rtk_dot1x_macBasedAuthMac_add ++ * Description: ++ * Add an authenticated MAC to ASIC ++ * Input: ++ * port - Port id. ++ * pAuth_mac - The authenticated MAC. ++ * fid - filtering database. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_ENABLE - Invalid enable input. ++ * RT_ERR_DOT1X_MACBASEDPNEN - 802.1X mac-based enable error ++ * Note: ++ * The API can add a 802.1x authenticated MAC address to port. If the MAC does not exist in LUT, ++ * user can't add this MAC to auth status. ++ */ ++extern rtk_api_ret_t rtk_dot1x_macBasedAuthMac_add(rtk_port_t port, rtk_mac_t *pAuth_mac, rtk_fid_t fid); ++ ++/* Function Name: ++ * rtk_dot1x_macBasedAuthMac_del ++ * Description: ++ * Delete an authenticated MAC to ASIC ++ * Input: ++ * port - Port id. ++ * pAuth_mac - The authenticated MAC. ++ * fid - filtering database. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_MAC - Invalid MAC address. ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * The API can delete a 802.1x authenticated MAC address to port. It only change the auth status of ++ * the MAC and won't delete it from LUT. ++ */ ++extern rtk_api_ret_t rtk_dot1x_macBasedAuthMac_del(rtk_port_t port, rtk_mac_t *pAuth_mac, rtk_fid_t fid); ++ ++/* Function Name: ++ * rtk_dot1x_macBasedDirection_set ++ * Description: ++ * Set 802.1x mac-based operational direction configuration ++ * Input: ++ * mac_direction - Operation direction ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameter. ++ * RT_ERR_DOT1X_MACBASEDOPDIR - 802.1X mac-based operation direction error ++ * Note: ++ * The operate controlled direction of 802.1x mac-based network access control is as following: ++ * - BOTH ++ * - IN ++ */ ++extern rtk_api_ret_t rtk_dot1x_macBasedDirection_set(rtk_dot1x_direction_t mac_direction); ++ ++/* Function Name: ++ * rtk_dot1x_macBasedDirection_get ++ * Description: ++ * Get 802.1x mac-based operational direction configuration ++ * Input: ++ * port - Port id. ++ * Output: ++ * pMac_direction - Operation direction ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can get 802.1x mac-based operational direction information. ++ */ ++extern rtk_api_ret_t rtk_dot1x_macBasedDirection_get(rtk_dot1x_direction_t *pMac_direction); ++ ++/* Function Name: ++ * Set 802.1x guest VLAN configuration ++ * Description: ++ * Set 802.1x mac-based operational direction configuration ++ * Input: ++ * vid - 802.1x guest VLAN ID ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameter. ++ * Note: ++ * The operate controlled 802.1x guest VLAN ++ */ ++extern rtk_api_ret_t rtk_dot1x_guestVlan_set(rtk_vlan_t vid); ++ ++/* Function Name: ++ * rtk_dot1x_guestVlan_get ++ * Description: ++ * Get 802.1x guest VLAN configuration ++ * Input: ++ * None ++ * Output: ++ * pVid - 802.1x guest VLAN ID ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can get 802.1x guest VLAN information. ++ */ ++extern rtk_api_ret_t rtk_dot1x_guestVlan_get(rtk_vlan_t *pVid); ++ ++/* Function Name: ++ * rtk_dot1x_guestVlan2Auth_set ++ * Description: ++ * Set 802.1x guest VLAN to auth host configuration ++ * Input: ++ * enable - The status of guest VLAN to auth host. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameter. ++ * Note: ++ * The operational direction of 802.1x guest VLAN to auth host control is as following: ++ * - ENABLED ++ * - DISABLED ++ */ ++extern rtk_api_ret_t rtk_dot1x_guestVlan2Auth_set(rtk_enable_t enable); ++ ++/* Function Name: ++ * rtk_dot1x_guestVlan2Auth_get ++ * Description: ++ * Get 802.1x guest VLAN to auth host configuration ++ * Input: ++ * None ++ * Output: ++ * pEnable - The status of guest VLAN to auth host. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can get 802.1x guest VLAN to auth host information. ++ */ ++extern rtk_api_ret_t rtk_dot1x_guestVlan2Auth_get(rtk_enable_t *pEnable); ++ ++ ++#endif /* __RTK_API_DOT1X_H__ */ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/include/eee.h b/drivers/net/phy/rtk/rtl8367c/include/eee.h +new file mode 100644 +index 000000000000..e3920363d15c +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/eee.h +@@ -0,0 +1,82 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * Purpose : RTL8367/RTL8367C switch high-level API ++ * ++ * Feature : The file includes EEE module high-layer API definition ++ * ++ */ ++ ++#ifndef __RTK_API_EEE_H__ ++#define __RTK_API_EEE_H__ ++ ++/* Function Name: ++ * rtk_eee_init ++ * Description: ++ * EEE function initialization. ++ * Input: ++ * None ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * This API is used to initialize EEE status. ++ */ ++extern rtk_api_ret_t rtk_eee_init(void); ++ ++/* Function Name: ++ * rtk_eee_portEnable_set ++ * Description: ++ * Set enable status of EEE function. ++ * Input: ++ * port - port id. ++ * enable - enable EEE status. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_ENABLE - Invalid enable input. ++ * Note: ++ * This API can set EEE function to the specific port. ++ * The configuration of the port is as following: ++ * - DISABLE ++ * - ENABLE ++ */ ++extern rtk_api_ret_t rtk_eee_portEnable_set(rtk_port_t port, rtk_enable_t enable); ++ ++/* Function Name: ++ * rtk_eee_portEnable_get ++ * Description: ++ * Get port admin configuration of the specific port. ++ * Input: ++ * port - Port id. ++ * Output: ++ * pEnable - Back pressure status. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * This API can set EEE function to the specific port. ++ * The configuration of the port is as following: ++ * - DISABLE ++ * - ENABLE ++ */ ++extern rtk_api_ret_t rtk_eee_portEnable_get(rtk_port_t port, rtk_enable_t *pEnable); ++ ++ ++#endif /* __RTK_API_EEE_H__ */ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/include/i2c.h b/drivers/net/phy/rtk/rtl8367c/include/i2c.h +new file mode 100644 +index 000000000000..110f41e818ee +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/i2c.h +@@ -0,0 +1,168 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * Purpose : RTL8367/RTL8367C switch high-level API ++ * ++ * Feature : The file includes I2C module high-layer API definition ++ * ++ */ ++ ++ ++#ifndef __RTK_API_I2C_H__ ++#define __RTK_API_I2C_H__ ++#include ++ ++#define I2C_GPIO_MAX_GROUP (3) ++ ++typedef enum rtk_I2C_16bit_mode_e{ ++ I2C_LSB_16BIT_MODE = 0, ++ I2C_70B_LSB_16BIT_MODE, ++ I2C_Mode_END ++}rtk_I2C_16bit_mode_t; ++ ++ ++typedef enum rtk_I2C_gpio_pin_e{ ++ I2C_GPIO_PIN_8_9 = 0, ++ I2C_GPIO_PIN_15_16 , ++ I2C_GPIO_PIN_35_36 , ++ I2C_GPIO_PIN_END ++}rtk_I2C_gpio_pin_t; ++ ++ ++/* Function Name: ++ * rtk_i2c_data_read ++ * Description: ++ * read i2c slave device register. ++ * Input: ++ * deviceAddr - access Slave device address ++ * slaveRegAddr - access Slave register address ++ * Output: ++ * pRegData - read data ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_NULL_POINTER - input parameter is null pointer ++ * Note: ++ * The API can access i2c slave and read i2c slave device register. ++ */ ++extern rtk_api_ret_t rtk_i2c_data_read(rtk_uint8 deviceAddr, rtk_uint32 slaveRegAddr, rtk_uint32 *pRegData); ++ ++/* Function Name: ++ * rtk_i2c_data_write ++ * Description: ++ * write data to i2c slave device register ++ * Input: ++ * deviceAddr - access Slave device address ++ * slaveRegAddr - access Slave register address ++ * regData - data to set ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * Note: ++ * The API can access i2c slave and setting i2c slave device register. ++ */ ++extern rtk_api_ret_t rtk_i2c_data_write(rtk_uint8 deviceAddr, rtk_uint32 slaveRegAddr, rtk_uint32 regData); ++ ++ ++/* Function Name: ++ * rtk_i2c_init ++ * Description: ++ * I2C smart function initialization. ++ * Input: ++ * None ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * Note: ++ * This API is used to initialize EEE status. ++ * need used GPIO pins ++ * OpenDrain and clock ++ */ ++extern rtk_api_ret_t rtk_i2c_init(void); ++ ++/* Function Name: ++ * rtk_i2c_mode_set ++ * Description: ++ * Set I2C data byte-order. ++ * Input: ++ * i2cmode - byte-order mode ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_INPUT - Invalid input parameter. ++ * Note: ++ * This API can set I2c traffic's byte-order . ++ */ ++extern rtk_api_ret_t rtk_i2c_mode_set( rtk_I2C_16bit_mode_t i2cmode); ++ ++/* Function Name: ++ * rtk_i2c_mode_get ++ * Description: ++ * Get i2c traffic byte-order setting. ++ * Input: ++ * None ++ * Output: ++ * pI2cMode - i2c byte-order ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_NULL_POINTER - input parameter is null pointer ++ * Note: ++ * The API can get i2c traffic byte-order setting. ++ */ ++extern rtk_api_ret_t rtk_i2c_mode_get( rtk_I2C_16bit_mode_t * pI2cMode); ++ ++ ++/* Function Name: ++ * rtk_i2c_gpioPinGroup_set ++ * Description: ++ * Set i2c SDA & SCL used GPIO pins group. ++ * Input: ++ * pins_group - GPIO pins group ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_INPUT - Invalid input parameter. ++ * Note: ++ * The API can set i2c used gpio pins group. ++ * There are three group pins could be used ++ */ ++extern rtk_api_ret_t rtk_i2c_gpioPinGroup_set( rtk_I2C_gpio_pin_t pins_group); ++ ++/* Function Name: ++ * rtk_i2c_gpioPinGroup_get ++ * Description: ++ * Get i2c SDA & SCL used GPIO pins group. ++ * Input: ++ * None ++ * Output: ++ * pPins_group - GPIO pins group ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_NULL_POINTER - input parameter is null pointer ++ * Note: ++ * The API can get i2c used gpio pins group. ++ * There are three group pins could be used ++ */ ++extern rtk_api_ret_t rtk_i2c_gpioPinGroup_get(rtk_I2C_gpio_pin_t * pPins_group); ++ ++ ++ ++ ++ ++ ++ ++#endif ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/include/igmp.h b/drivers/net/phy/rtk/rtl8367c/include/igmp.h +new file mode 100644 +index 000000000000..b36db43d830c +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/igmp.h +@@ -0,0 +1,769 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * Purpose : RTL8367/RTL8367C switch high-level API ++ * ++ * Feature : The file includes IGMP module high-layer API definition ++ * ++ */ ++ ++#ifndef __RTK_API_IGMP_H__ ++#define __RTK_API_IGMP_H__ ++ ++/* ++ * Data Type Declaration ++ */ ++typedef enum rtk_igmp_type_e ++{ ++ IGMP_IPV4 = 0, ++ IGMP_PPPOE_IPV4, ++ IGMP_MLD, ++ IGMP_PPPOE_MLD, ++ IGMP_TYPE_END ++} rtk_igmp_type_t; ++ ++typedef enum rtk_trap_igmp_action_e ++{ ++ IGMP_ACTION_FORWARD = 0, ++ IGMP_ACTION_TRAP2CPU, ++ IGMP_ACTION_DROP, ++ IGMP_ACTION_ASIC, ++ IGMP_ACTION_END ++} rtk_igmp_action_t; ++ ++typedef enum rtk_igmp_protocol_e ++{ ++ PROTOCOL_IGMPv1 = 0, ++ PROTOCOL_IGMPv2, ++ PROTOCOL_IGMPv3, ++ PROTOCOL_MLDv1, ++ PROTOCOL_MLDv2, ++ PROTOCOL_END ++} rtk_igmp_protocol_t; ++ ++typedef enum rtk_igmp_tableFullAction_e ++{ ++ IGMP_TABLE_FULL_FORWARD = 0, ++ IGMP_TABLE_FULL_DROP, ++ IGMP_TABLE_FULL_TRAP, ++ IGMP_TABLE_FULL_OP_END ++}rtk_igmp_tableFullAction_t; ++ ++typedef enum rtk_igmp_checksumErrorAction_e ++{ ++ IGMP_CRC_ERR_DROP = 0, ++ IGMP_CRC_ERR_TRAP, ++ IGMP_CRC_ERR_FORWARD, ++ IGMP_CRC_ERR_OP_END ++}rtk_igmp_checksumErrorAction_t; ++ ++typedef enum rtk_igmp_bypassGroup_e ++{ ++ IGMP_BYPASS_224_0_0_X = 0, ++ IGMP_BYPASS_224_0_1_X, ++ IGMP_BYPASS_239_255_255_X, ++ IGMP_BYPASS_IPV6_00XX, ++ IGMP_BYPASS_GROUP_END ++}rtk_igmp_bypassGroup_t; ++ ++ ++typedef struct rtk_igmp_dynamicRouterPort_s ++{ ++ rtk_enable_t dynamicRouterPort0Valid; ++ rtk_port_t dynamicRouterPort0; ++ rtk_uint32 dynamicRouterPort0Timer; ++ rtk_enable_t dynamicRouterPort1Valid; ++ rtk_port_t dynamicRouterPort1; ++ rtk_uint32 dynamicRouterPort1Timer; ++ ++}rtk_igmp_dynamicRouterPort_t; ++ ++typedef struct rtk_igmp_rxPktEnable_s ++{ ++ rtk_enable_t rxQuery; ++ rtk_enable_t rxReport; ++ rtk_enable_t rxLeave; ++ rtk_enable_t rxMRP; ++ rtk_enable_t rxMcast; ++}rtk_igmp_rxPktEnable_t; ++ ++typedef struct rtk_igmp_groupInfo_s ++{ ++ rtk_enable_t valid; ++ rtk_portmask_t member; ++ rtk_uint32 timer[RTK_PORT_MAX]; ++ rtk_uint32 reportSuppFlag; ++}rtk_igmp_groupInfo_t; ++ ++typedef enum rtk_igmp_ReportLeaveFwdAct_e ++{ ++ IGMP_REPORT_LEAVE_TO_ROUTER = 0, ++ IGMP_REPORT_LEAVE_TO_ALLPORT, ++ IGMP_REPORT_LEAVE_TO_ROUTER_PORT_ADV, ++ IGMP_REPORT_LEAVE_ACT_END ++}rtk_igmp_ReportLeaveFwdAct_t; ++ ++/* Function Name: ++ * rtk_igmp_init ++ * Description: ++ * This API enables H/W IGMP and set a default initial configuration. ++ * Input: ++ * None. ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * This API enables H/W IGMP and set a default initial configuration. ++ */ ++extern rtk_api_ret_t rtk_igmp_init(void); ++ ++/* Function Name: ++ * rtk_igmp_state_set ++ * Description: ++ * This API set H/W IGMP state. ++ * Input: ++ * enabled - H/W IGMP state ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Error parameter ++ * Note: ++ * This API set H/W IGMP state. ++ */ ++extern rtk_api_ret_t rtk_igmp_state_set(rtk_enable_t enabled); ++ ++/* Function Name: ++ * rtk_igmp_state_get ++ * Description: ++ * This API get H/W IGMP state. ++ * Input: ++ * None. ++ * Output: ++ * pEnabled - H/W IGMP state ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Error parameter ++ * Note: ++ * This API set current H/W IGMP state. ++ */ ++extern rtk_api_ret_t rtk_igmp_state_get(rtk_enable_t *pEnabled); ++ ++/* Function Name: ++ * rtk_igmp_static_router_port_set ++ * Description: ++ * Configure static router port ++ * Input: ++ * pPortmask - Static Port mask ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_MASK - Error parameter ++ * Note: ++ * This API set static router port ++ */ ++extern rtk_api_ret_t rtk_igmp_static_router_port_set(rtk_portmask_t *pPortmask); ++ ++/* Function Name: ++ * rtk_igmp_static_router_port_get ++ * Description: ++ * Get static router port ++ * Input: ++ * None. ++ * Output: ++ * pPortmask - Static port mask ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_MASK - Error parameter ++ * Note: ++ * This API get static router port ++ */ ++extern rtk_api_ret_t rtk_igmp_static_router_port_get(rtk_portmask_t *pPortmask); ++ ++/* Function Name: ++ * rtk_igmp_protocol_set ++ * Description: ++ * set IGMP/MLD protocol action ++ * Input: ++ * port - Port ID ++ * protocol - IGMP/MLD protocol ++ * action - Per-port and per-protocol IGMP action setting ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_MASK - Error parameter ++ * Note: ++ * This API set IGMP/MLD protocol action ++ */ ++extern rtk_api_ret_t rtk_igmp_protocol_set(rtk_port_t port, rtk_igmp_protocol_t protocol, rtk_igmp_action_t action); ++ ++/* Function Name: ++ * rtk_igmp_protocol_get ++ * Description: ++ * set IGMP/MLD protocol action ++ * Input: ++ * port - Port ID ++ * protocol - IGMP/MLD protocol ++ * action - Per-port and per-protocol IGMP action setting ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_MASK - Error parameter ++ * Note: ++ * This API set IGMP/MLD protocol action ++ */ ++extern rtk_api_ret_t rtk_igmp_protocol_get(rtk_port_t port, rtk_igmp_protocol_t protocol, rtk_igmp_action_t *pAction); ++ ++/* Function Name: ++ * rtk_igmp_fastLeave_set ++ * Description: ++ * set IGMP/MLD FastLeave state ++ * Input: ++ * state - ENABLED: Enable FastLeave, DISABLED: disable FastLeave ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_INPUT - Error Input ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * This API set IGMP/MLD FastLeave state ++ */ ++extern rtk_api_ret_t rtk_igmp_fastLeave_set(rtk_enable_t state); ++ ++/* Function Name: ++ * rtk_igmp_fastLeave_get ++ * Description: ++ * get IGMP/MLD FastLeave state ++ * Input: ++ * None ++ * Output: ++ * pState - ENABLED: Enable FastLeave, DISABLED: disable FastLeave ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_NULL_POINTER - NULL pointer ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * This API get IGMP/MLD FastLeave state ++ */ ++extern rtk_api_ret_t rtk_igmp_fastLeave_get(rtk_enable_t *pState); ++ ++/* Function Name: ++ * rtk_igmp_maxGroup_set ++ * Description: ++ * Set per port multicast group learning limit. ++ * Input: ++ * port - Port ID ++ * group - The number of multicast group learning limit. ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_PORT_ID - Error Port ID ++ * RT_ERR_OUT_OF_RANGE - parameter out of range ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * This API set per port multicast group learning limit. ++ */ ++extern rtk_api_ret_t rtk_igmp_maxGroup_set(rtk_port_t port, rtk_uint32 group); ++ ++/* Function Name: ++ * rtk_igmp_maxGroup_get ++ * Description: ++ * Get per port multicast group learning limit. ++ * Input: ++ * port - Port ID ++ * Output: ++ * pGroup - The number of multicast group learning limit. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_PORT_ID - Error Port ID ++ * RT_ERR_NULL_POINTER - Null pointer ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * This API get per port multicast group learning limit. ++ */ ++extern rtk_api_ret_t rtk_igmp_maxGroup_get(rtk_port_t port, rtk_uint32 *pGroup); ++ ++/* Function Name: ++ * rtk_igmp_currentGroup_get ++ * Description: ++ * Get per port multicast group learning count. ++ * Input: ++ * port - Port ID ++ * Output: ++ * pGroup - The number of multicast group learning count. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_PORT_ID - Error Port ID ++ * RT_ERR_NULL_POINTER - Null pointer ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * This API get per port multicast group learning count. ++ */ ++extern rtk_api_ret_t rtk_igmp_currentGroup_get(rtk_port_t port, rtk_uint32 *pGroup); ++ ++/* Function Name: ++ * rtk_igmp_tableFullAction_set ++ * Description: ++ * set IGMP/MLD Table Full Action ++ * Input: ++ * action - Table Full Action ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_INPUT - Error Input ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ */ ++extern rtk_api_ret_t rtk_igmp_tableFullAction_set(rtk_igmp_tableFullAction_t action); ++ ++/* Function Name: ++ * rtk_igmp_tableFullAction_get ++ * Description: ++ * get IGMP/MLD Table Full Action ++ * Input: ++ * None ++ * Output: ++ * pAction - Table Full Action ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_NULL_POINTER - Null pointer ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ */ ++extern rtk_api_ret_t rtk_igmp_tableFullAction_get(rtk_igmp_tableFullAction_t *pAction); ++ ++/* Function Name: ++ * rtk_igmp_checksumErrorAction_set ++ * Description: ++ * set IGMP/MLD Checksum Error Action ++ * Input: ++ * action - Checksum error Action ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_INPUT - Error Input ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ */ ++extern rtk_api_ret_t rtk_igmp_checksumErrorAction_set(rtk_igmp_checksumErrorAction_t action); ++ ++/* Function Name: ++ * rtk_igmp_checksumErrorAction_get ++ * Description: ++ * get IGMP/MLD Checksum Error Action ++ * Input: ++ * None ++ * Output: ++ * pAction - Checksum error Action ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_NULL_POINTER - Null pointer ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ */ ++extern rtk_api_ret_t rtk_igmp_checksumErrorAction_get(rtk_igmp_checksumErrorAction_t *pAction); ++ ++/* Function Name: ++ * rtk_igmp_leaveTimer_set ++ * Description: ++ * set IGMP/MLD Leave timer ++ * Input: ++ * timer - Leave timer ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_INPUT - Error Input ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ */ ++extern rtk_api_ret_t rtk_igmp_leaveTimer_set(rtk_uint32 timer); ++ ++/* Function Name: ++ * rtk_igmp_leaveTimer_get ++ * Description: ++ * get IGMP/MLD Leave timer ++ * Input: ++ * None ++ * Output: ++ * pTimer - Leave Timer. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_NULL_POINTER - Null pointer ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ */ ++extern rtk_api_ret_t rtk_igmp_leaveTimer_get(rtk_uint32 *pTimer); ++ ++/* Function Name: ++ * rtk_igmp_queryInterval_set ++ * Description: ++ * set IGMP/MLD Query Interval ++ * Input: ++ * interval - Query Interval ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_INPUT - Error Input ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ */ ++extern rtk_api_ret_t rtk_igmp_queryInterval_set(rtk_uint32 interval); ++ ++/* Function Name: ++ * rtk_igmp_queryInterval_get ++ * Description: ++ * get IGMP/MLD Query Interval ++ * Input: ++ * None. ++ * Output: ++ * pInterval - Query Interval ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_NULL_POINTER - Null pointer ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ */ ++extern rtk_api_ret_t rtk_igmp_queryInterval_get(rtk_uint32 *pInterval); ++ ++/* Function Name: ++ * rtk_igmp_robustness_set ++ * Description: ++ * set IGMP/MLD Robustness value ++ * Input: ++ * robustness - Robustness value ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_INPUT - Error Input ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ */ ++extern rtk_api_ret_t rtk_igmp_robustness_set(rtk_uint32 robustness); ++ ++/* Function Name: ++ * rtk_igmp_robustness_get ++ * Description: ++ * get IGMP/MLD Robustness value ++ * Input: ++ * None ++ * Output: ++ * pRobustness - Robustness value. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_NULL_POINTER - Null pointer ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ */ ++extern rtk_api_ret_t rtk_igmp_robustness_get(rtk_uint32 *pRobustness); ++ ++/* Function Name: ++ * rtk_igmp_dynamicRouterRortAllow_set ++ * Description: ++ * Configure dynamic router port allow option ++ * Input: ++ * pPortmask - Dynamic Port allow mask ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_MASK - Error parameter ++ * Note: ++ * ++ */ ++extern rtk_api_ret_t rtk_igmp_dynamicRouterPortAllow_set(rtk_portmask_t *pPortmask); ++ ++/* Function Name: ++ * rtk_igmp_dynamicRouterRortAllow_get ++ * Description: ++ * Get dynamic router port allow option ++ * Input: ++ * None. ++ * Output: ++ * pPortmask - Dynamic Port allow mask ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_MASK - Error parameter ++ * Note: ++ * ++ */ ++extern rtk_api_ret_t rtk_igmp_dynamicRouterPortAllow_get(rtk_portmask_t *pPortmask); ++ ++/* Function Name: ++ * rtk_igmp_dynamicRouterPort_get ++ * Description: ++ * Get dynamic router port ++ * Input: ++ * None. ++ * Output: ++ * pDynamicRouterPort - Dynamic Router Port ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_NULL_POINTER - Null pointer ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_MASK - Error parameter ++ * Note: ++ * ++ */ ++extern rtk_api_ret_t rtk_igmp_dynamicRouterPort_get(rtk_igmp_dynamicRouterPort_t *pDynamicRouterPort); ++ ++/* Function Name: ++ * rtk_igmp_suppressionEnable_set ++ * Description: ++ * Configure IGMPv1/v2 & MLDv1 Report/Leave/Done suppression ++ * Input: ++ * reportSuppression - Report suppression ++ * leaveSuppression - Leave suppression ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Error Input ++ * Note: ++ * ++ */ ++extern rtk_api_ret_t rtk_igmp_suppressionEnable_set(rtk_enable_t reportSuppression, rtk_enable_t leaveSuppression); ++ ++/* Function Name: ++ * rtk_igmp_suppressionEnable_get ++ * Description: ++ * Get IGMPv1/v2 & MLDv1 Report/Leave/Done suppression ++ * Input: ++ * None ++ * Output: ++ * pReportSuppression - Report suppression ++ * pLeaveSuppression - Leave suppression ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_NULL_POINTER - Null pointer ++ * Note: ++ * ++ */ ++extern rtk_api_ret_t rtk_igmp_suppressionEnable_get(rtk_enable_t *pReportSuppression, rtk_enable_t *pLeaveSuppression); ++ ++/* Function Name: ++ * rtk_igmp_portRxPktEnable_set ++ * Description: ++ * Configure IGMP/MLD RX Packet configuration ++ * Input: ++ * port - Port ID ++ * pRxCfg - RX Packet Configuration ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Error Input ++ * RT_ERR_NULL_POINTER - Null pointer ++ * Note: ++ * ++ */ ++extern rtk_api_ret_t rtk_igmp_portRxPktEnable_set(rtk_port_t port, rtk_igmp_rxPktEnable_t *pRxCfg); ++ ++/* Function Name: ++ * rtk_igmp_portRxPktEnable_get ++ * Description: ++ * Get IGMP/MLD RX Packet configuration ++ * Input: ++ * port - Port ID ++ * pRxCfg - RX Packet Configuration ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Error Input ++ * RT_ERR_NULL_POINTER - Null pointer ++ * Note: ++ * ++ */ ++extern rtk_api_ret_t rtk_igmp_portRxPktEnable_get(rtk_port_t port, rtk_igmp_rxPktEnable_t *pRxCfg); ++ ++/* Function Name: ++ * rtk_igmp_groupInfo_get ++ * Description: ++ * Get IGMP/MLD Group database ++ * Input: ++ * index - Index (0~255) ++ * Output: ++ * pGroup - Group database information. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Error Input ++ * RT_ERR_NULL_POINTER - Null pointer ++ * Note: ++ * ++ */ ++extern rtk_api_ret_t rtk_igmp_groupInfo_get(rtk_uint32 index, rtk_igmp_groupInfo_t *pGroup); ++ ++/* Function Name: ++ * rtk_igmp_ReportLeaveFwdAction_set ++ * Description: ++ * Set Report Leave packet forwarding action ++ * Input: ++ * action - Action ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Error Input ++ * Note: ++ * ++ */ ++extern rtk_api_ret_t rtk_igmp_ReportLeaveFwdAction_set(rtk_igmp_ReportLeaveFwdAct_t action); ++ ++/* Function Name: ++ * rtk_igmp_ReportLeaveFwdAction_get ++ * Description: ++ * Get Report Leave packet forwarding action ++ * Input: ++ * action - Action ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Error Input ++ * RT_ERR_NULL_POINTER - Null Pointer ++ * Note: ++ * ++ */ ++extern rtk_api_ret_t rtk_igmp_ReportLeaveFwdAction_get(rtk_igmp_ReportLeaveFwdAct_t *pAction); ++ ++/* Function Name: ++ * rtk_igmp_dropLeaveZeroEnable_set ++ * Description: ++ * Set the function of dropping Leave packet with group IP = 0.0.0.0 ++ * Input: ++ * enabled - Action 1: drop, 0:pass ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Error Input ++ * Note: ++ * ++ */ ++extern rtk_api_ret_t rtk_igmp_dropLeaveZeroEnable_set(rtk_enable_t enabled); ++ ++/* Function Name: ++ * rtk_igmp_dropLeaveZeroEnable_get ++ * Description: ++ * Get the function of dropping Leave packet with group IP = 0.0.0.0 ++ * Input: ++ * None ++ * Output: ++ * pEnabled. - Action 1: drop, 0:pass ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Error Input ++ * RT_ERR_NULL_POINTER - Null Pointer ++ * Note: ++ * ++ */ ++extern rtk_api_ret_t rtk_igmp_dropLeaveZeroEnable_get(rtk_enable_t *pEnabled); ++ ++/* Function Name: ++ * rtk_igmp_bypassGroupRange_set ++ * Description: ++ * Set Bypass group ++ * Input: ++ * group - bypassed group ++ * enabled - enabled 1: Bypassed, 0: not bypass ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Error Input ++ * Note: ++ * ++ */ ++extern rtk_api_ret_t rtk_igmp_bypassGroupRange_set(rtk_igmp_bypassGroup_t group, rtk_enable_t enabled); ++ ++/* Function Name: ++ * rtk_igmp_bypassGroupRange_get ++ * Description: ++ * get Bypass group ++ * Input: ++ * group - bypassed group ++ * Output: ++ * pEnable - enabled 1: Bypassed, 0: not bypass ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Error Input ++ * RT_ERR_NULL_POINTER - Null Pointer ++ * Note: ++ * ++ */ ++extern rtk_api_ret_t rtk_igmp_bypassGroupRange_get(rtk_igmp_bypassGroup_t group, rtk_enable_t *pEnable); ++ ++#endif /* __RTK_API_IGMP_H__ */ +diff --git a/drivers/net/phy/rtk/rtl8367c/include/interrupt.h b/drivers/net/phy/rtk/rtl8367c/include/interrupt.h +new file mode 100644 +index 000000000000..20625fff52c2 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/interrupt.h +@@ -0,0 +1,254 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * Purpose : RTL8367/RTL8367C switch high-level API ++ * ++ * Feature : The file includes Interrupt module high-layer API definition ++ * ++ */ ++ ++#ifndef __RTK_API_INTERRUPT_H__ ++#define __RTK_API_INTERRUPT_H__ ++ ++ ++/* ++ * Data Type Declaration ++ */ ++#define RTK_MAX_NUM_OF_INTERRUPT_TYPE 1 ++ ++ ++typedef struct rtk_int_status_s ++{ ++ rtk_uint16 value[RTK_MAX_NUM_OF_INTERRUPT_TYPE]; ++} rtk_int_status_t; ++ ++typedef struct rtk_int_info_s ++{ ++ rtk_portmask_t portMask; ++ rtk_uint32 meterMask; ++ rtk_uint32 systemLearnOver; ++}rtk_int_info_t; ++ ++typedef enum rtk_int_type_e ++{ ++ INT_TYPE_LINK_STATUS = 0, ++ INT_TYPE_METER_EXCEED, ++ INT_TYPE_LEARN_LIMIT, ++ INT_TYPE_LINK_SPEED, ++ INT_TYPE_CONGEST, ++ INT_TYPE_GREEN_FEATURE, ++ INT_TYPE_LOOP_DETECT, ++ INT_TYPE_8051, ++ INT_TYPE_CABLE_DIAG, ++ INT_TYPE_ACL, ++ INT_TYPE_RESERVED, /* Unused */ ++ INT_TYPE_SLIENT, ++ INT_TYPE_END ++}rtk_int_type_t; ++ ++typedef enum rtk_int_advType_e ++{ ++ ADV_L2_LEARN_PORT_MASK = 0, ++ ADV_SPEED_CHANGE_PORT_MASK, ++ ADV_SPECIAL_CONGESTION_PORT_MASK, ++ ADV_PORT_LINKDOWN_PORT_MASK, ++ ADV_PORT_LINKUP_PORT_MASK, ++ ADV_METER_EXCEED_MASK, ++ ADV_RLDP_LOOPED, ++ ADV_RLDP_RELEASED, ++ ADV_END, ++} rtk_int_advType_t; ++ ++typedef enum rtk_int_polarity_e ++{ ++ INT_POLAR_HIGH = 0, ++ INT_POLAR_LOW, ++ INT_POLAR_END ++} rtk_int_polarity_t; ++ ++/* Function Name: ++ * rtk_int_polarity_set ++ * Description: ++ * Set interrupt polarity configuration. ++ * Input: ++ * type - Interruptpolarity type. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can set interrupt polarity configuration. ++ */ ++extern rtk_api_ret_t rtk_int_polarity_set(rtk_int_polarity_t type); ++ ++/* Function Name: ++ * rtk_int_polarity_get ++ * Description: ++ * Get interrupt polarity configuration. ++ * Input: ++ * None ++ * Output: ++ * pType - Interruptpolarity type. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * The API can get interrupt polarity configuration. ++ */ ++extern rtk_api_ret_t rtk_int_polarity_get(rtk_int_polarity_t *pType); ++ ++/* Function Name: ++ * rtk_int_control_set ++ * Description: ++ * Set interrupt trigger status configuration. ++ * Input: ++ * type - Interrupt type. ++ * enable - Interrupt status. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_ENABLE - Invalid enable input. ++ * Note: ++ * The API can set interrupt status configuration. ++ * The interrupt trigger status is shown in the following: ++ * - INT_TYPE_LINK_STATUS ++ * - INT_TYPE_METER_EXCEED ++ * - INT_TYPE_LEARN_LIMIT ++ * - INT_TYPE_LINK_SPEED ++ * - INT_TYPE_CONGEST ++ * - INT_TYPE_GREEN_FEATURE ++ * - INT_TYPE_LOOP_DETECT ++ * - INT_TYPE_8051, ++ * - INT_TYPE_CABLE_DIAG, ++ * - INT_TYPE_ACL, ++ * - INT_TYPE_SLIENT ++ */ ++extern rtk_api_ret_t rtk_int_control_set(rtk_int_type_t type, rtk_enable_t enable); ++ ++/* Function Name: ++ * rtk_int_control_get ++ * Description: ++ * Get interrupt trigger status configuration. ++ * Input: ++ * type - Interrupt type. ++ * Output: ++ * pEnable - Interrupt status. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can get interrupt status configuration. ++ * The interrupt trigger status is shown in the following: ++ * - INT_TYPE_LINK_STATUS ++ * - INT_TYPE_METER_EXCEED ++ * - INT_TYPE_LEARN_LIMIT ++ * - INT_TYPE_LINK_SPEED ++ * - INT_TYPE_CONGEST ++ * - INT_TYPE_GREEN_FEATURE ++ * - INT_TYPE_LOOP_DETECT ++ * - INT_TYPE_8051, ++ * - INT_TYPE_CABLE_DIAG, ++ * - INT_TYPE_ACL, ++ * - INT_TYPE_SLIENT ++ */ ++extern rtk_api_ret_t rtk_int_control_get(rtk_int_type_t type, rtk_enable_t* pEnable); ++ ++/* Function Name: ++ * rtk_int_status_set ++ * Description: ++ * Set interrupt trigger status to clean. ++ * Input: ++ * None ++ * Output: ++ * pStatusMask - Interrupt status bit mask. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can clean interrupt trigger status when interrupt happened. ++ * The interrupt trigger status is shown in the following: ++ * - INT_TYPE_LINK_STATUS (value[0] (Bit0)) ++ * - INT_TYPE_METER_EXCEED (value[0] (Bit1)) ++ * - INT_TYPE_LEARN_LIMIT (value[0] (Bit2)) ++ * - INT_TYPE_LINK_SPEED (value[0] (Bit3)) ++ * - INT_TYPE_CONGEST (value[0] (Bit4)) ++ * - INT_TYPE_GREEN_FEATURE (value[0] (Bit5)) ++ * - INT_TYPE_LOOP_DETECT (value[0] (Bit6)) ++ * - INT_TYPE_8051 (value[0] (Bit7)) ++ * - INT_TYPE_CABLE_DIAG (value[0] (Bit8)) ++ * - INT_TYPE_ACL (value[0] (Bit9)) ++ * - INT_TYPE_SLIENT (value[0] (Bit11)) ++ * The status will be cleared after execute this API. ++ */ ++extern rtk_api_ret_t rtk_int_status_set(rtk_int_status_t *pStatusMask); ++ ++/* Function Name: ++ * rtk_int_status_get ++ * Description: ++ * Get interrupt trigger status. ++ * Input: ++ * None ++ * Output: ++ * pStatusMask - Interrupt status bit mask. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can get interrupt trigger status when interrupt happened. ++ * The interrupt trigger status is shown in the following: ++ * - INT_TYPE_LINK_STATUS (value[0] (Bit0)) ++ * - INT_TYPE_METER_EXCEED (value[0] (Bit1)) ++ * - INT_TYPE_LEARN_LIMIT (value[0] (Bit2)) ++ * - INT_TYPE_LINK_SPEED (value[0] (Bit3)) ++ * - INT_TYPE_CONGEST (value[0] (Bit4)) ++ * - INT_TYPE_GREEN_FEATURE (value[0] (Bit5)) ++ * - INT_TYPE_LOOP_DETECT (value[0] (Bit6)) ++ * - INT_TYPE_8051 (value[0] (Bit7)) ++ * - INT_TYPE_CABLE_DIAG (value[0] (Bit8)) ++ * - INT_TYPE_ACL (value[0] (Bit9)) ++ * - INT_TYPE_SLIENT (value[0] (Bit11)) ++ * ++ */ ++extern rtk_api_ret_t rtk_int_status_get(rtk_int_status_t* pStatusMask); ++ ++/* Function Name: ++ * rtk_int_advanceInfo_get ++ * Description: ++ * Get interrupt advanced information. ++ * Input: ++ * adv_type - Advanced interrupt type. ++ * Output: ++ * info - Information per type. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * This API can get advanced information when interrupt happened. ++ * The status will be cleared after execute this API. ++ */ ++extern rtk_api_ret_t rtk_int_advanceInfo_get(rtk_int_advType_t adv_type, rtk_int_info_t* info); ++ ++ ++#endif /* __RTK_API_INTERRUPT_H__ */ +diff --git a/drivers/net/phy/rtk/rtl8367c/include/l2.h b/drivers/net/phy/rtk/rtl8367c/include/l2.h +new file mode 100644 +index 000000000000..ec5aad2e30b9 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/l2.h +@@ -0,0 +1,1181 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * Purpose : RTL8367/RTL8367C switch high-level API ++ * ++ * Feature : The file includes L2 module high-layer API definition ++ * ++ */ ++ ++#ifndef __RTK_API_L2_H__ ++#define __RTK_API_L2_H__ ++ ++ ++/* ++ * Data Type Declaration ++ */ ++#define RTK_MAX_NUM_OF_LEARN_LIMIT (rtk_switch_maxLutAddrNumber_get()) ++ ++#define RTK_MAC_ADDR_LEN 6 ++#define RTK_MAX_LUT_ADDRESS (RTK_MAX_NUM_OF_LEARN_LIMIT) ++#define RTK_MAX_LUT_ADDR_ID (RTK_MAX_LUT_ADDRESS - 1) ++ ++typedef rtk_uint32 rtk_l2_age_time_t; ++ ++typedef enum rtk_l2_flood_type_e ++{ ++ FLOOD_UNKNOWNDA = 0, ++ FLOOD_UNKNOWNMC, ++ FLOOD_BC, ++ FLOOD_END ++} rtk_l2_flood_type_t; ++ ++typedef rtk_uint32 rtk_l2_flushItem_t; ++ ++typedef enum rtk_l2_flushType_e ++{ ++ FLUSH_TYPE_BY_PORT = 0, /* physical port */ ++ FLUSH_TYPE_BY_PORT_VID, /* physical port + VID */ ++ FLUSH_TYPE_BY_PORT_FID, /* physical port + FID */ ++ FLUSH_TYPE_END ++} rtk_l2_flushType_t; ++ ++typedef struct rtk_l2_flushCfg_s ++{ ++ rtk_enable_t flushByVid; ++ rtk_vlan_t vid; ++ rtk_enable_t flushByFid; ++ rtk_uint32 fid; ++ rtk_enable_t flushByPort; ++ rtk_port_t port; ++ rtk_enable_t flushByMac; ++ rtk_mac_t ucastAddr; ++ rtk_enable_t flushStaticAddr; ++ rtk_enable_t flushAddrOnAllPorts; /* this is used when flushByVid */ ++} rtk_l2_flushCfg_t; ++ ++typedef enum rtk_l2_read_method_e{ ++ ++ READMETHOD_MAC = 0, ++ READMETHOD_ADDRESS, ++ READMETHOD_NEXT_ADDRESS, ++ READMETHOD_NEXT_L2UC, ++ READMETHOD_NEXT_L2MC, ++ READMETHOD_NEXT_L3MC, ++ READMETHOD_NEXT_L2L3MC, ++ READMETHOD_NEXT_L2UCSPA, ++ READMETHOD_END ++}rtk_l2_read_method_t; ++ ++/* l2 limit learning count action */ ++typedef enum rtk_l2_limitLearnCntAction_e ++{ ++ LIMIT_LEARN_CNT_ACTION_DROP = 0, ++ LIMIT_LEARN_CNT_ACTION_FORWARD, ++ LIMIT_LEARN_CNT_ACTION_TO_CPU, ++ LIMIT_LEARN_CNT_ACTION_END ++} rtk_l2_limitLearnCntAction_t; ++ ++typedef enum rtk_l2_ipmc_lookup_type_e ++{ ++ LOOKUP_MAC = 0, ++ LOOKUP_IP, ++ LOOKUP_IP_VID, ++ LOOKUP_END ++} rtk_l2_ipmc_lookup_type_t; ++ ++/* l2 address table - unicast data structure */ ++typedef struct rtk_l2_ucastAddr_s ++{ ++ rtk_mac_t mac; ++ rtk_uint32 ivl; ++ rtk_uint32 cvid; ++ rtk_uint32 fid; ++ rtk_uint32 efid; ++ rtk_uint32 port; ++ rtk_uint32 sa_block; ++ rtk_uint32 da_block; ++ rtk_uint32 auth; ++ rtk_uint32 is_static; ++ rtk_uint32 priority; ++ rtk_uint32 sa_pri_en; ++ rtk_uint32 fwd_pri_en; ++ rtk_uint32 address; ++}rtk_l2_ucastAddr_t; ++ ++/* l2 address table - multicast data structure */ ++typedef struct rtk_l2_mcastAddr_s ++{ ++ rtk_uint32 vid; ++ rtk_mac_t mac; ++ rtk_uint32 fid; ++ rtk_portmask_t portmask; ++ rtk_uint32 ivl; ++ rtk_uint32 priority; ++ rtk_uint32 fwd_pri_en; ++ rtk_uint32 igmp_asic; ++ rtk_uint32 igmp_index; ++ rtk_uint32 address; ++}rtk_l2_mcastAddr_t; ++ ++/* l2 address table - ip multicast data structure */ ++typedef struct rtk_l2_ipMcastAddr_s ++{ ++ ipaddr_t dip; ++ ipaddr_t sip; ++ rtk_portmask_t portmask; ++ rtk_uint32 priority; ++ rtk_uint32 fwd_pri_en; ++ rtk_uint32 igmp_asic; ++ rtk_uint32 igmp_index; ++ rtk_uint32 address; ++}rtk_l2_ipMcastAddr_t; ++ ++/* l2 address table - ip VID multicast data structure */ ++typedef struct rtk_l2_ipVidMcastAddr_s ++{ ++ ipaddr_t dip; ++ ipaddr_t sip; ++ rtk_uint32 vid; ++ rtk_portmask_t portmask; ++ rtk_uint32 address; ++}rtk_l2_ipVidMcastAddr_t; ++ ++typedef struct rtk_l2_addr_table_s ++{ ++ rtk_uint32 index; ++ ipaddr_t sip; ++ ipaddr_t dip; ++ rtk_mac_t mac; ++ rtk_uint32 sa_block; ++ rtk_uint32 auth; ++ rtk_portmask_t portmask; ++ rtk_uint32 age; ++ rtk_uint32 ivl; ++ rtk_uint32 cvid; ++ rtk_uint32 fid; ++ rtk_uint32 is_ipmul; ++ rtk_uint32 is_static; ++ rtk_uint32 is_ipvidmul; ++ rtk_uint32 l3_vid; ++}rtk_l2_addr_table_t; ++ ++typedef enum rtk_l2_clearStatus_e ++{ ++ L2_CLEAR_STATE_FINISH = 0, ++ L2_CLEAR_STATE_BUSY, ++ L2_CLEAR_STATE_END ++}rtk_l2_clearStatus_t; ++ ++/* Function Name: ++ * rtk_l2_init ++ * Description: ++ * Initialize l2 module of the specified device. ++ * Input: ++ * None ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * Initialize l2 module before calling any l2 APIs. ++ */ ++extern rtk_api_ret_t rtk_l2_init(void); ++ ++/* Function Name: ++ * rtk_l2_addr_add ++ * Description: ++ * Add LUT unicast entry. ++ * Input: ++ * pMac - 6 bytes unicast(I/G bit is 0) mac address to be written into LUT. ++ * pL2_data - Unicast entry parameter ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_MAC - Invalid MAC address. ++ * RT_ERR_L2_FID - Invalid FID . ++ * RT_ERR_L2_INDEXTBL_FULL - hashed index is full of entries. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * If the unicast mac address already existed in LUT, it will update the status of the entry. ++ * Otherwise, it will find an empty or asic auto learned entry to write. If all the entries ++ * with the same hash value can't be replaced, ASIC will return a RT_ERR_L2_INDEXTBL_FULL error. ++ */ ++extern rtk_api_ret_t rtk_l2_addr_add(rtk_mac_t *pMac, rtk_l2_ucastAddr_t *pL2_data); ++ ++/* Function Name: ++ * rtk_l2_addr_get ++ * Description: ++ * Get LUT unicast entry. ++ * Input: ++ * pMac - 6 bytes unicast(I/G bit is 0) mac address to be written into LUT. ++ * Output: ++ * pL2_data - Unicast entry parameter ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_MAC - Invalid MAC address. ++ * RT_ERR_L2_FID - Invalid FID . ++ * RT_ERR_L2_ENTRY_NOTFOUND - No such LUT entry. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * If the unicast mac address existed in LUT, it will return the port and fid where ++ * the mac is learned. Otherwise, it will return a RT_ERR_L2_ENTRY_NOTFOUND error. ++ */ ++extern rtk_api_ret_t rtk_l2_addr_get(rtk_mac_t *pMac, rtk_l2_ucastAddr_t *pL2_data); ++ ++/* Function Name: ++ * rtk_l2_addr_next_get ++ * Description: ++ * Get Next LUT unicast entry. ++ * Input: ++ * read_method - The reading method. ++ * port - The port number if the read_metohd is READMETHOD_NEXT_L2UCSPA ++ * pAddress - The Address ID ++ * Output: ++ * pL2_data - Unicast entry parameter ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_MAC - Invalid MAC address. ++ * RT_ERR_L2_FID - Invalid FID . ++ * RT_ERR_L2_ENTRY_NOTFOUND - No such LUT entry. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * Get the next unicast entry after the current entry pointed by pAddress. ++ * The address of next entry is returned by pAddress. User can use (address + 1) ++ * as pAddress to call this API again for dumping all entries is LUT. ++ */ ++extern rtk_api_ret_t rtk_l2_addr_next_get(rtk_l2_read_method_t read_method, rtk_port_t port, rtk_uint32 *pAddress, rtk_l2_ucastAddr_t *pL2_data); ++ ++/* Function Name: ++ * rtk_l2_addr_del ++ * Description: ++ * Delete LUT unicast entry. ++ * Input: ++ * pMac - 6 bytes unicast(I/G bit is 0) mac address to be written into LUT. ++ * fid - Filtering database ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_MAC - Invalid MAC address. ++ * RT_ERR_L2_FID - Invalid FID . ++ * RT_ERR_L2_ENTRY_NOTFOUND - No such LUT entry. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * If the mac has existed in the LUT, it will be deleted. Otherwise, it will return RT_ERR_L2_ENTRY_NOTFOUND. ++ */ ++extern rtk_api_ret_t rtk_l2_addr_del(rtk_mac_t *pMac, rtk_l2_ucastAddr_t *pL2_data); ++ ++/* Function Name: ++ * rtk_l2_mcastAddr_add ++ * Description: ++ * Add LUT multicast entry. ++ * Input: ++ * pMcastAddr - L2 multicast entry structure ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_MAC - Invalid MAC address. ++ * RT_ERR_L2_FID - Invalid FID . ++ * RT_ERR_L2_VID - Invalid VID . ++ * RT_ERR_L2_INDEXTBL_FULL - hashed index is full of entries. ++ * RT_ERR_PORT_MASK - Invalid portmask. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * If the multicast mac address already existed in the LUT, it will update the ++ * port mask of the entry. Otherwise, it will find an empty or asic auto learned ++ * entry to write. If all the entries with the same hash value can't be replaced, ++ * ASIC will return a RT_ERR_L2_INDEXTBL_FULL error. ++ */ ++extern rtk_api_ret_t rtk_l2_mcastAddr_add(rtk_l2_mcastAddr_t *pMcastAddr); ++ ++/* Function Name: ++ * rtk_l2_mcastAddr_get ++ * Description: ++ * Get LUT multicast entry. ++ * Input: ++ * pMcastAddr - L2 multicast entry structure ++ * Output: ++ * pMcastAddr - L2 multicast entry structure ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_MAC - Invalid MAC address. ++ * RT_ERR_L2_FID - Invalid FID . ++ * RT_ERR_L2_VID - Invalid VID . ++ * RT_ERR_L2_ENTRY_NOTFOUND - No such LUT entry. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * If the multicast mac address existed in the LUT, it will return the port where ++ * the mac is learned. Otherwise, it will return a RT_ERR_L2_ENTRY_NOTFOUND error. ++ */ ++extern rtk_api_ret_t rtk_l2_mcastAddr_get(rtk_l2_mcastAddr_t *pMcastAddr); ++ ++/* Function Name: ++ * rtk_l2_mcastAddr_next_get ++ * Description: ++ * Get Next L2 Multicast entry. ++ * Input: ++ * pAddress - The Address ID ++ * Output: ++ * pMcastAddr - L2 multicast entry structure ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_L2_ENTRY_NOTFOUND - No such LUT entry. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * Get the next L2 multicast entry after the current entry pointed by pAddress. ++ * The address of next entry is returned by pAddress. User can use (address + 1) ++ * as pAddress to call this API again for dumping all multicast entries is LUT. ++ */ ++extern rtk_api_ret_t rtk_l2_mcastAddr_next_get(rtk_uint32 *pAddress, rtk_l2_mcastAddr_t *pMcastAddr); ++ ++/* Function Name: ++ * rtk_l2_mcastAddr_del ++ * Description: ++ * Delete LUT multicast entry. ++ * Input: ++ * pMcastAddr - L2 multicast entry structure ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_MAC - Invalid MAC address. ++ * RT_ERR_L2_FID - Invalid FID . ++ * RT_ERR_L2_VID - Invalid VID . ++ * RT_ERR_L2_ENTRY_NOTFOUND - No such LUT entry. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * If the mac has existed in the LUT, it will be deleted. Otherwise, it will return RT_ERR_L2_ENTRY_NOTFOUND. ++ */ ++extern rtk_api_ret_t rtk_l2_mcastAddr_del(rtk_l2_mcastAddr_t *pMcastAddr); ++ ++/* Function Name: ++ * rtk_l2_ipMcastAddr_add ++ * Description: ++ * Add LUT IP multicast entry ++ * Input: ++ * pIpMcastAddr - IP Multicast entry ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_L2_INDEXTBL_FULL - hashed index is full of entries. ++ * RT_ERR_PORT_MASK - Invalid portmask. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * System supports L2 entry with IP multicast DIP/SIP to forward IP multicasting frame as user ++ * desired. If this function is enabled, then system will be looked up L2 IP multicast entry to ++ * forward IP multicast frame directly without flooding. ++ */ ++extern rtk_api_ret_t rtk_l2_ipMcastAddr_add(rtk_l2_ipMcastAddr_t *pIpMcastAddr); ++ ++/* Function Name: ++ * rtk_l2_ipMcastAddr_get ++ * Description: ++ * Get LUT IP multicast entry. ++ * Input: ++ * pIpMcastAddr - IP Multicast entry ++ * Output: ++ * pIpMcastAddr - IP Multicast entry ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_L2_ENTRY_NOTFOUND - No such LUT entry. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can get LUT table of IP multicast entry. ++ */ ++extern rtk_api_ret_t rtk_l2_ipMcastAddr_get(rtk_l2_ipMcastAddr_t *pIpMcastAddr); ++ ++/* Function Name: ++ * rtk_l2_ipMcastAddr_next_get ++ * Description: ++ * Get Next IP Multicast entry. ++ * Input: ++ * pAddress - The Address ID ++ * Output: ++ * pIpMcastAddr - IP Multicast entry ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_L2_ENTRY_NOTFOUND - No such LUT entry. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * Get the next IP multicast entry after the current entry pointed by pAddress. ++ * The address of next entry is returned by pAddress. User can use (address + 1) ++ * as pAddress to call this API again for dumping all IP multicast entries is LUT. ++ */ ++extern rtk_api_ret_t rtk_l2_ipMcastAddr_next_get(rtk_uint32 *pAddress, rtk_l2_ipMcastAddr_t *pIpMcastAddr); ++ ++/* Function Name: ++ * rtk_l2_ipMcastAddr_del ++ * Description: ++ * Delete a ip multicast address entry from the specified device. ++ * Input: ++ * pIpMcastAddr - IP Multicast entry ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_L2_ENTRY_NOTFOUND - No such LUT entry. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can delete a IP multicast address entry from the specified device. ++ */ ++extern rtk_api_ret_t rtk_l2_ipMcastAddr_del(rtk_l2_ipMcastAddr_t *pIpMcastAddr); ++ ++/* Function Name: ++ * rtk_l2_ipVidMcastAddr_add ++ * Description: ++ * Add LUT IP multicast+VID entry ++ * Input: ++ * pIpVidMcastAddr - IP & VID multicast Entry ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_L2_INDEXTBL_FULL - hashed index is full of entries. ++ * RT_ERR_PORT_MASK - Invalid portmask. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * ++ */ ++extern rtk_api_ret_t rtk_l2_ipVidMcastAddr_add(rtk_l2_ipVidMcastAddr_t *pIpVidMcastAddr); ++ ++/* Function Name: ++ * rtk_l2_ipVidMcastAddr_get ++ * Description: ++ * Get LUT IP multicast+VID entry. ++ * Input: ++ * pIpVidMcastAddr - IP & VID multicast Entry ++ * Output: ++ * pIpVidMcastAddr - IP & VID multicast Entry ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_L2_ENTRY_NOTFOUND - No such LUT entry. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * ++ */ ++extern rtk_api_ret_t rtk_l2_ipVidMcastAddr_get(rtk_l2_ipVidMcastAddr_t *pIpVidMcastAddr); ++ ++/* Function Name: ++ * rtk_l2_ipVidMcastAddr_next_get ++ * Description: ++ * Get Next IP Multicast+VID entry. ++ * Input: ++ * pAddress - The Address ID ++ * Output: ++ * pIpVidMcastAddr - IP & VID multicast Entry ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_L2_ENTRY_NOTFOUND - No such LUT entry. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * Get the next IP multicast entry after the current entry pointed by pAddress. ++ * The address of next entry is returned by pAddress. User can use (address + 1) ++ * as pAddress to call this API again for dumping all IP multicast entries is LUT. ++ */ ++extern rtk_api_ret_t rtk_l2_ipVidMcastAddr_next_get(rtk_uint32 *pAddress, rtk_l2_ipVidMcastAddr_t *pIpVidMcastAddr); ++ ++/* Function Name: ++ * rtk_l2_ipVidMcastAddr_del ++ * Description: ++ * Delete a ip multicast+VID address entry from the specified device. ++ * Input: ++ * pIpVidMcastAddr - IP & VID multicast Entry ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_L2_ENTRY_NOTFOUND - No such LUT entry. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * ++ */ ++extern rtk_api_ret_t rtk_l2_ipVidMcastAddr_del(rtk_l2_ipVidMcastAddr_t *pIpVidMcastAddr); ++ ++/* Function Name: ++ * rtk_l2_ucastAddr_flush ++ * Description: ++ * Flush L2 mac address by type in the specified device (both dynamic and static). ++ * Input: ++ * pConfig - flush configuration ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_VLAN_VID - Invalid VID parameter. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * flushByVid - 1: Flush by VID, 0: Don't flush by VID ++ * vid - VID (0 ~ 4095) ++ * flushByFid - 1: Flush by FID, 0: Don't flush by FID ++ * fid - FID (0 ~ 15) ++ * flushByPort - 1: Flush by Port, 0: Don't flush by Port ++ * port - Port ID ++ * flushByMac - Not Supported ++ * ucastAddr - Not Supported ++ * flushStaticAddr - 1: Flush both Static and Dynamic entries, 0: Flush only Dynamic entries ++ * flushAddrOnAllPorts - 1: Flush VID-matched entries at all ports, 0: Flush VID-matched entries per port. ++ */ ++extern rtk_api_ret_t rtk_l2_ucastAddr_flush(rtk_l2_flushCfg_t *pConfig); ++ ++/* Function Name: ++ * rtk_l2_table_clear ++ * Description: ++ * Flush all static & dynamic entries in LUT. ++ * Input: ++ * None ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * ++ */ ++extern rtk_api_ret_t rtk_l2_table_clear(void); ++ ++/* Function Name: ++ * rtk_l2_table_clearStatus_get ++ * Description: ++ * Get table clear status ++ * Input: ++ * None ++ * Output: ++ * pStatus - Clear status, 1:Busy, 0:finish ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * ++ */ ++extern rtk_api_ret_t rtk_l2_table_clearStatus_get(rtk_l2_clearStatus_t *pStatus); ++ ++/* Function Name: ++ * rtk_l2_flushLinkDownPortAddrEnable_set ++ * Description: ++ * Set HW flush linkdown port mac configuration of the specified device. ++ * Input: ++ * port - Port id. ++ * enable - link down flush status ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_ENABLE - Invalid enable input. ++ * Note: ++ * The status of flush linkdown port address is as following: ++ * - DISABLED ++ * - ENABLED ++ */ ++extern rtk_api_ret_t rtk_l2_flushLinkDownPortAddrEnable_set(rtk_port_t port, rtk_enable_t enable); ++ ++/* Function Name: ++ * rtk_l2_flushLinkDownPortAddrEnable_get ++ * Description: ++ * Get HW flush linkdown port mac configuration of the specified device. ++ * Input: ++ * port - Port id. ++ * Output: ++ * pEnable - link down flush status ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * The status of flush linkdown port address is as following: ++ * - DISABLED ++ * - ENABLED ++ */ ++extern rtk_api_ret_t rtk_l2_flushLinkDownPortAddrEnable_get(rtk_port_t port, rtk_enable_t *pEnable); ++ ++/* Function Name: ++ * rtk_l2_agingEnable_set ++ * Description: ++ * Set L2 LUT aging status per port setting. ++ * Input: ++ * port - Port id. ++ * enable - Aging status ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_ENABLE - Invalid enable input. ++ * Note: ++ * This API can be used to set L2 LUT aging status per port. ++ */ ++extern rtk_api_ret_t rtk_l2_agingEnable_set(rtk_port_t port, rtk_enable_t enable); ++ ++/* Function Name: ++ * rtk_l2_agingEnable_get ++ * Description: ++ * Get L2 LUT aging status per port setting. ++ * Input: ++ * port - Port id. ++ * Output: ++ * pEnable - Aging status ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * This API can be used to get L2 LUT aging function per port. ++ */ ++extern rtk_api_ret_t rtk_l2_agingEnable_get(rtk_port_t port, rtk_enable_t *pEnable); ++ ++/* Function Name: ++ * rtk_l2_limitLearningCnt_set ++ * Description: ++ * Set per-Port auto learning limit number ++ * Input: ++ * port - Port id. ++ * mac_cnt - Auto learning entries limit number ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_LIMITED_L2ENTRY_NUM - Invalid auto learning limit number ++ * Note: ++ * The API can set per-port ASIC auto learning limit number from 0(disable learning) ++ * to 8k. ++ */ ++extern rtk_api_ret_t rtk_l2_limitLearningCnt_set(rtk_port_t port, rtk_mac_cnt_t mac_cnt); ++ ++/* Function Name: ++ * rtk_l2_limitLearningCnt_get ++ * Description: ++ * Get per-Port auto learning limit number ++ * Input: ++ * port - Port id. ++ * Output: ++ * pMac_cnt - Auto learning entries limit number ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * The API can get per-port ASIC auto learning limit number. ++ */ ++extern rtk_api_ret_t rtk_l2_limitLearningCnt_get(rtk_port_t port, rtk_mac_cnt_t *pMac_cnt); ++ ++/* Function Name: ++ * rtk_l2_limitSystemLearningCnt_set ++ * Description: ++ * Set System auto learning limit number ++ * Input: ++ * mac_cnt - Auto learning entries limit number ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_LIMITED_L2ENTRY_NUM - Invalid auto learning limit number ++ * Note: ++ * The API can set system ASIC auto learning limit number from 0(disable learning) ++ * to 2112. ++ */ ++extern rtk_api_ret_t rtk_l2_limitSystemLearningCnt_set(rtk_mac_cnt_t mac_cnt); ++ ++/* Function Name: ++ * rtk_l2_limitSystemLearningCnt_get ++ * Description: ++ * Get System auto learning limit number ++ * Input: ++ * None ++ * Output: ++ * pMac_cnt - Auto learning entries limit number ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * The API can get system ASIC auto learning limit number. ++ */ ++extern rtk_api_ret_t rtk_l2_limitSystemLearningCnt_get(rtk_mac_cnt_t *pMac_cnt); ++ ++/* Function Name: ++ * rtk_l2_limitLearningCntAction_set ++ * Description: ++ * Configure auto learn over limit number action. ++ * Input: ++ * port - Port id. ++ * action - Auto learning entries limit number ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_NOT_ALLOWED - Invalid learn over action ++ * Note: ++ * The API can set SA unknown packet action while auto learn limit number is over ++ * The action symbol as following: ++ * - LIMIT_LEARN_CNT_ACTION_DROP, ++ * - LIMIT_LEARN_CNT_ACTION_FORWARD, ++ * - LIMIT_LEARN_CNT_ACTION_TO_CPU, ++ */ ++extern rtk_api_ret_t rtk_l2_limitLearningCntAction_set(rtk_port_t port, rtk_l2_limitLearnCntAction_t action); ++ ++/* Function Name: ++ * rtk_l2_limitLearningCntAction_get ++ * Description: ++ * Get auto learn over limit number action. ++ * Input: ++ * port - Port id. ++ * Output: ++ * pAction - Learn over action ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * The API can get SA unknown packet action while auto learn limit number is over ++ * The action symbol as following: ++ * - LIMIT_LEARN_CNT_ACTION_DROP, ++ * - LIMIT_LEARN_CNT_ACTION_FORWARD, ++ * - LIMIT_LEARN_CNT_ACTION_TO_CPU, ++ */ ++extern rtk_api_ret_t rtk_l2_limitLearningCntAction_get(rtk_port_t port, rtk_l2_limitLearnCntAction_t *pAction); ++ ++/* Function Name: ++ * rtk_l2_limitSystemLearningCntAction_set ++ * Description: ++ * Configure system auto learn over limit number action. ++ * Input: ++ * port - Port id. ++ * action - Auto learning entries limit number ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_NOT_ALLOWED - Invalid learn over action ++ * Note: ++ * The API can set SA unknown packet action while auto learn limit number is over ++ * The action symbol as following: ++ * - LIMIT_LEARN_CNT_ACTION_DROP, ++ * - LIMIT_LEARN_CNT_ACTION_FORWARD, ++ * - LIMIT_LEARN_CNT_ACTION_TO_CPU, ++ */ ++extern rtk_api_ret_t rtk_l2_limitSystemLearningCntAction_set(rtk_l2_limitLearnCntAction_t action); ++ ++/* Function Name: ++ * rtk_l2_limitSystemLearningCntAction_get ++ * Description: ++ * Get system auto learn over limit number action. ++ * Input: ++ * None. ++ * Output: ++ * pAction - Learn over action ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * The API can get SA unknown packet action while auto learn limit number is over ++ * The action symbol as following: ++ * - LIMIT_LEARN_CNT_ACTION_DROP, ++ * - LIMIT_LEARN_CNT_ACTION_FORWARD, ++ * - LIMIT_LEARN_CNT_ACTION_TO_CPU, ++ */ ++extern rtk_api_ret_t rtk_l2_limitSystemLearningCntAction_get(rtk_l2_limitLearnCntAction_t *pAction); ++ ++/* Function Name: ++ * rtk_l2_limitSystemLearningCntPortMask_set ++ * Description: ++ * Configure system auto learn portmask ++ * Input: ++ * pPortmask - Port Mask ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_MASK - Invalid port mask. ++ * Note: ++ * ++ */ ++extern rtk_api_ret_t rtk_l2_limitSystemLearningCntPortMask_set(rtk_portmask_t *pPortmask); ++ ++/* Function Name: ++ * rtk_l2_limitSystemLearningCntPortMask_get ++ * Description: ++ * get system auto learn portmask ++ * Input: ++ * None ++ * Output: ++ * pPortmask - Port Mask ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_NULL_POINTER - Null pointer. ++ * Note: ++ * ++ */ ++extern rtk_api_ret_t rtk_l2_limitSystemLearningCntPortMask_get(rtk_portmask_t *pPortmask); ++ ++/* Function Name: ++ * rtk_l2_learningCnt_get ++ * Description: ++ * Get per-Port current auto learning number ++ * Input: ++ * port - Port id. ++ * Output: ++ * pMac_cnt - ASIC auto learning entries number ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * The API can get per-port ASIC auto learning number ++ */ ++extern rtk_api_ret_t rtk_l2_learningCnt_get(rtk_port_t port, rtk_mac_cnt_t *pMac_cnt); ++ ++/* Function Name: ++ * rtk_l2_floodPortMask_set ++ * Description: ++ * Set flooding portmask ++ * Input: ++ * type - flooding type. ++ * pFlood_portmask - flooding portmask ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_MASK - Invalid portmask. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * This API can set the flooding mask. ++ * The flooding type is as following: ++ * - FLOOD_UNKNOWNDA ++ * - FLOOD_UNKNOWNMC ++ * - FLOOD_BC ++ */ ++extern rtk_api_ret_t rtk_l2_floodPortMask_set(rtk_l2_flood_type_t floood_type, rtk_portmask_t *pFlood_portmask); ++ ++/* Function Name: ++ * rtk_l2_floodPortMask_get ++ * Description: ++ * Get flooding portmask ++ * Input: ++ * type - flooding type. ++ * Output: ++ * pFlood_portmask - flooding portmask ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * This API can get the flooding mask. ++ * The flooding type is as following: ++ * - FLOOD_UNKNOWNDA ++ * - FLOOD_UNKNOWNMC ++ * - FLOOD_BC ++ */ ++extern rtk_api_ret_t rtk_l2_floodPortMask_get(rtk_l2_flood_type_t floood_type, rtk_portmask_t *pFlood_portmask); ++ ++/* Function Name: ++ * rtk_l2_localPktPermit_set ++ * Description: ++ * Set permission of frames if source port and destination port are the same. ++ * Input: ++ * port - Port id. ++ * permit - permission status ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_ENABLE - Invalid permit value. ++ * Note: ++ * This API is set to permit frame if its source port is equal to destination port. ++ */ ++extern rtk_api_ret_t rtk_l2_localPktPermit_set(rtk_port_t port, rtk_enable_t permit); ++ ++/* Function Name: ++ * rtk_l2_localPktPermit_get ++ * Description: ++ * Get permission of frames if source port and destination port are the same. ++ * Input: ++ * port - Port id. ++ * Output: ++ * pPermit - permission status ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * This API is to get permission status for frames if its source port is equal to destination port. ++ */ ++extern rtk_api_ret_t rtk_l2_localPktPermit_get(rtk_port_t port, rtk_enable_t *pPermit); ++ ++/* Function Name: ++ * rtk_l2_aging_set ++ * Description: ++ * Set LUT ageing out speed ++ * Input: ++ * aging_time - Ageing out time. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - input out of range. ++ * Note: ++ * The API can set LUT ageing out period for each entry and the range is from 14s to 800s. ++ */ ++extern rtk_api_ret_t rtk_l2_aging_set(rtk_l2_age_time_t aging_time); ++ ++/* Function Name: ++ * rtk_l2_aging_get ++ * Description: ++ * Get LUT ageing out time ++ * Input: ++ * None ++ * Output: ++ * pEnable - Aging status ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * The API can get LUT ageing out period for each entry. ++ */ ++extern rtk_api_ret_t rtk_l2_aging_get(rtk_l2_age_time_t *pAging_time); ++ ++/* Function Name: ++ * rtk_l2_ipMcastAddrLookup_set ++ * Description: ++ * Set LUT IP multicast lookup function ++ * Input: ++ * type - Lookup type for IPMC packet. ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * This API can work with rtk_l2_ipMcastAddrLookupException_add. ++ * If users set the lookup type to DIP, the group in exception table ++ * will be lookup by DIP+SIP ++ * If users set the lookup type to DIP+SIP, the group in exception table ++ * will be lookup by only DIP ++ */ ++extern rtk_api_ret_t rtk_l2_ipMcastAddrLookup_set(rtk_l2_ipmc_lookup_type_t type); ++ ++/* Function Name: ++ * rtk_l2_ipMcastAddrLookup_get ++ * Description: ++ * Get LUT IP multicast lookup function ++ * Input: ++ * None. ++ * Output: ++ * pType - Lookup type for IPMC packet. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None. ++ */ ++extern rtk_api_ret_t rtk_l2_ipMcastAddrLookup_get(rtk_l2_ipmc_lookup_type_t *pType); ++ ++/* Function Name: ++ * rtk_l2_ipMcastForwardRouterPort_set ++ * Description: ++ * Set IPMC packet forward to router port also or not ++ * Input: ++ * enabled - 1: Include router port, 0, exclude router port ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * ++ */ ++extern rtk_api_ret_t rtk_l2_ipMcastForwardRouterPort_set(rtk_enable_t enabled); ++ ++/* Function Name: ++ * rtk_l2_ipMcastForwardRouterPort_get ++ * Description: ++ * Get IPMC packet forward to router port also or not ++ * Input: ++ * None. ++ * Output: ++ * pEnabled - 1: Include router port, 0, exclude router port ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_NULL_POINTER - Null pointer ++ * Note: ++ * ++ */ ++extern rtk_api_ret_t rtk_l2_ipMcastForwardRouterPort_get(rtk_enable_t *pEnabled); ++ ++/* Function Name: ++ * rtk_l2_ipMcastGroupEntry_add ++ * Description: ++ * Add an IP Multicast entry to group table ++ * Input: ++ * ip_addr - IP address ++ * vid - VLAN ID ++ * pPortmask - portmask ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_TBL_FULL - Table Full ++ * Note: ++ * Add an entry to IP Multicast Group table. ++ */ ++extern rtk_api_ret_t rtk_l2_ipMcastGroupEntry_add(ipaddr_t ip_addr, rtk_uint32 vid, rtk_portmask_t *pPortmask); ++ ++/* Function Name: ++ * rtk_l2_ipMcastGroupEntry_del ++ * Description: ++ * Delete an entry from IP Multicast group table ++ * Input: ++ * ip_addr - IP address ++ * vid - VLAN ID ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_TBL_FULL - Table Full ++ * Note: ++ * Delete an entry from IP Multicast group table. ++ */ ++extern rtk_api_ret_t rtk_l2_ipMcastGroupEntry_del(ipaddr_t ip_addr, rtk_uint32 vid); ++ ++/* Function Name: ++ * rtk_l2_ipMcastGroupEntry_get ++ * Description: ++ * get an entry from IP Multicast group table ++ * Input: ++ * ip_addr - IP address ++ * vid - VLAN ID ++ * Output: ++ * pPortmask - member port mask ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_TBL_FULL - Table Full ++ * Note: ++ * Delete an entry from IP Multicast group table. ++ */ ++extern rtk_api_ret_t rtk_l2_ipMcastGroupEntry_get(ipaddr_t ip_addr, rtk_uint32 vid, rtk_portmask_t *pPortmask); ++ ++/* Function Name: ++ * rtk_l2_entry_get ++ * Description: ++ * Get LUT unicast entry. ++ * Input: ++ * pL2_entry - Index field in the structure. ++ * Output: ++ * pL2_entry - other fields such as MAC, port, age... ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_L2_EMPTY_ENTRY - Empty LUT entry. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * This API is used to get address by index from 0~2111. ++ */ ++extern rtk_api_ret_t rtk_l2_entry_get(rtk_l2_addr_table_t *pL2_entry); ++ ++ ++#endif /* __RTK_API_L2_H__ */ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/include/leaky.h b/drivers/net/phy/rtk/rtl8367c/include/leaky.h +new file mode 100644 +index 000000000000..e5b22e2878b4 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/leaky.h +@@ -0,0 +1,371 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * Purpose : RTL8367/RTL8367C switch high-level API ++ * ++ * Feature : The file includes Leaky module high-layer API definition ++ * ++ */ ++ ++#ifndef __RTK_API_LEAKY_H__ ++#define __RTK_API_LEAKY_H__ ++ ++ ++typedef enum rtk_leaky_type_e ++{ ++ LEAKY_BRG_GROUP = 0, ++ LEAKY_FD_PAUSE, ++ LEAKY_SP_MCAST, ++ LEAKY_1X_PAE, ++ LEAKY_UNDEF_BRG_04, ++ LEAKY_UNDEF_BRG_05, ++ LEAKY_UNDEF_BRG_06, ++ LEAKY_UNDEF_BRG_07, ++ LEAKY_PROVIDER_BRIDGE_GROUP_ADDRESS, ++ LEAKY_UNDEF_BRG_09, ++ LEAKY_UNDEF_BRG_0A, ++ LEAKY_UNDEF_BRG_0B, ++ LEAKY_UNDEF_BRG_0C, ++ LEAKY_PROVIDER_BRIDGE_GVRP_ADDRESS, ++ LEAKY_8021AB, ++ LEAKY_UNDEF_BRG_0F, ++ LEAKY_BRG_MNGEMENT, ++ LEAKY_UNDEFINED_11, ++ LEAKY_UNDEFINED_12, ++ LEAKY_UNDEFINED_13, ++ LEAKY_UNDEFINED_14, ++ LEAKY_UNDEFINED_15, ++ LEAKY_UNDEFINED_16, ++ LEAKY_UNDEFINED_17, ++ LEAKY_UNDEFINED_18, ++ LEAKY_UNDEFINED_19, ++ LEAKY_UNDEFINED_1A, ++ LEAKY_UNDEFINED_1B, ++ LEAKY_UNDEFINED_1C, ++ LEAKY_UNDEFINED_1D, ++ LEAKY_UNDEFINED_1E, ++ LEAKY_UNDEFINED_1F, ++ LEAKY_GMRP, ++ LEAKY_GVRP, ++ LEAKY_UNDEF_GARP_22, ++ LEAKY_UNDEF_GARP_23, ++ LEAKY_UNDEF_GARP_24, ++ LEAKY_UNDEF_GARP_25, ++ LEAKY_UNDEF_GARP_26, ++ LEAKY_UNDEF_GARP_27, ++ LEAKY_UNDEF_GARP_28, ++ LEAKY_UNDEF_GARP_29, ++ LEAKY_UNDEF_GARP_2A, ++ LEAKY_UNDEF_GARP_2B, ++ LEAKY_UNDEF_GARP_2C, ++ LEAKY_UNDEF_GARP_2D, ++ LEAKY_UNDEF_GARP_2E, ++ LEAKY_UNDEF_GARP_2F, ++ LEAKY_IGMP, ++ LEAKY_IPMULTICAST, ++ LEAKY_CDP, ++ LEAKY_CSSTP, ++ LEAKY_LLDP, ++ LEAKY_END, ++}rtk_leaky_type_t; ++ ++/* Function Name: ++ * rtk_leaky_vlan_set ++ * Description: ++ * Set VLAN leaky. ++ * Input: ++ * type - Packet type for VLAN leaky. ++ * enable - Leaky status. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_ENABLE - Invalid enable input ++ * Note: ++ * This API can set VLAN leaky for RMA ,IGMP/MLD, CDP, CSSTP, and LLDP packets. ++ * The leaky frame types are as following: ++ * - LEAKY_BRG_GROUP, ++ * - LEAKY_FD_PAUSE, ++ * - LEAKY_SP_MCAST, ++ * - LEAKY_1X_PAE, ++ * - LEAKY_UNDEF_BRG_04, ++ * - LEAKY_UNDEF_BRG_05, ++ * - LEAKY_UNDEF_BRG_06, ++ * - LEAKY_UNDEF_BRG_07, ++ * - LEAKY_PROVIDER_BRIDGE_GROUP_ADDRESS, ++ * - LEAKY_UNDEF_BRG_09, ++ * - LEAKY_UNDEF_BRG_0A, ++ * - LEAKY_UNDEF_BRG_0B, ++ * - LEAKY_UNDEF_BRG_0C, ++ * - LEAKY_PROVIDER_BRIDGE_GVRP_ADDRESS, ++ * - LEAKY_8021AB, ++ * - LEAKY_UNDEF_BRG_0F, ++ * - LEAKY_BRG_MNGEMENT, ++ * - LEAKY_UNDEFINED_11, ++ * - LEAKY_UNDEFINED_12, ++ * - LEAKY_UNDEFINED_13, ++ * - LEAKY_UNDEFINED_14, ++ * - LEAKY_UNDEFINED_15, ++ * - LEAKY_UNDEFINED_16, ++ * - LEAKY_UNDEFINED_17, ++ * - LEAKY_UNDEFINED_18, ++ * - LEAKY_UNDEFINED_19, ++ * - LEAKY_UNDEFINED_1A, ++ * - LEAKY_UNDEFINED_1B, ++ * - LEAKY_UNDEFINED_1C, ++ * - LEAKY_UNDEFINED_1D, ++ * - LEAKY_UNDEFINED_1E, ++ * - LEAKY_UNDEFINED_1F, ++ * - LEAKY_GMRP, ++ * - LEAKY_GVRP, ++ * - LEAKY_UNDEF_GARP_22, ++ * - LEAKY_UNDEF_GARP_23, ++ * - LEAKY_UNDEF_GARP_24, ++ * - LEAKY_UNDEF_GARP_25, ++ * - LEAKY_UNDEF_GARP_26, ++ * - LEAKY_UNDEF_GARP_27, ++ * - LEAKY_UNDEF_GARP_28, ++ * - LEAKY_UNDEF_GARP_29, ++ * - LEAKY_UNDEF_GARP_2A, ++ * - LEAKY_UNDEF_GARP_2B, ++ * - LEAKY_UNDEF_GARP_2C, ++ * - LEAKY_UNDEF_GARP_2D, ++ * - LEAKY_UNDEF_GARP_2E, ++ * - LEAKY_UNDEF_GARP_2F, ++ * - LEAKY_IGMP, ++ * - LEAKY_IPMULTICAST. ++ * - LEAKY_CDP, ++ * - LEAKY_CSSTP, ++ * - LEAKY_LLDP. ++ */ ++extern rtk_api_ret_t rtk_leaky_vlan_set(rtk_leaky_type_t type, rtk_enable_t enable); ++ ++/* Function Name: ++ * rtk_leaky_vlan_get ++ * Description: ++ * Get VLAN leaky. ++ * Input: ++ * type - Packet type for VLAN leaky. ++ * Output: ++ * pEnable - Leaky status. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * This API can get VLAN leaky status for RMA ,IGMP/MLD, CDP, CSSTP, and LLDP packets. ++ * The leaky frame types are as following: ++ * - LEAKY_BRG_GROUP, ++ * - LEAKY_FD_PAUSE, ++ * - LEAKY_SP_MCAST, ++ * - LEAKY_1X_PAE, ++ * - LEAKY_UNDEF_BRG_04, ++ * - LEAKY_UNDEF_BRG_05, ++ * - LEAKY_UNDEF_BRG_06, ++ * - LEAKY_UNDEF_BRG_07, ++ * - LEAKY_PROVIDER_BRIDGE_GROUP_ADDRESS, ++ * - LEAKY_UNDEF_BRG_09, ++ * - LEAKY_UNDEF_BRG_0A, ++ * - LEAKY_UNDEF_BRG_0B, ++ * - LEAKY_UNDEF_BRG_0C, ++ * - LEAKY_PROVIDER_BRIDGE_GVRP_ADDRESS, ++ * - LEAKY_8021AB, ++ * - LEAKY_UNDEF_BRG_0F, ++ * - LEAKY_BRG_MNGEMENT, ++ * - LEAKY_UNDEFINED_11, ++ * - LEAKY_UNDEFINED_12, ++ * - LEAKY_UNDEFINED_13, ++ * - LEAKY_UNDEFINED_14, ++ * - LEAKY_UNDEFINED_15, ++ * - LEAKY_UNDEFINED_16, ++ * - LEAKY_UNDEFINED_17, ++ * - LEAKY_UNDEFINED_18, ++ * - LEAKY_UNDEFINED_19, ++ * - LEAKY_UNDEFINED_1A, ++ * - LEAKY_UNDEFINED_1B, ++ * - LEAKY_UNDEFINED_1C, ++ * - LEAKY_UNDEFINED_1D, ++ * - LEAKY_UNDEFINED_1E, ++ * - LEAKY_UNDEFINED_1F, ++ * - LEAKY_GMRP, ++ * - LEAKY_GVRP, ++ * - LEAKY_UNDEF_GARP_22, ++ * - LEAKY_UNDEF_GARP_23, ++ * - LEAKY_UNDEF_GARP_24, ++ * - LEAKY_UNDEF_GARP_25, ++ * - LEAKY_UNDEF_GARP_26, ++ * - LEAKY_UNDEF_GARP_27, ++ * - LEAKY_UNDEF_GARP_28, ++ * - LEAKY_UNDEF_GARP_29, ++ * - LEAKY_UNDEF_GARP_2A, ++ * - LEAKY_UNDEF_GARP_2B, ++ * - LEAKY_UNDEF_GARP_2C, ++ * - LEAKY_UNDEF_GARP_2D, ++ * - LEAKY_UNDEF_GARP_2E, ++ * - LEAKY_UNDEF_GARP_2F, ++ * - LEAKY_IGMP, ++ * - LEAKY_IPMULTICAST. ++ * - LEAKY_CDP, ++ * - LEAKY_CSSTP, ++ * - LEAKY_LLDP. ++ */ ++extern rtk_api_ret_t rtk_leaky_vlan_get(rtk_leaky_type_t type, rtk_enable_t *pEnable); ++ ++/* Function Name: ++ * rtk_leaky_portIsolation_set ++ * Description: ++ * Set port isolation leaky. ++ * Input: ++ * type - Packet type for port isolation leaky. ++ * enable - Leaky status. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_ENABLE - Invalid enable input ++ * Note: ++ * This API can set port isolation leaky for RMA ,IGMP/MLD, CDP, CSSTP, and LLDP packets. ++ * The leaky frame types are as following: ++ * - LEAKY_BRG_GROUP, ++ * - LEAKY_FD_PAUSE, ++ * - LEAKY_SP_MCAST, ++ * - LEAKY_1X_PAE, ++ * - LEAKY_UNDEF_BRG_04, ++ * - LEAKY_UNDEF_BRG_05, ++ * - LEAKY_UNDEF_BRG_06, ++ * - LEAKY_UNDEF_BRG_07, ++ * - LEAKY_PROVIDER_BRIDGE_GROUP_ADDRESS, ++ * - LEAKY_UNDEF_BRG_09, ++ * - LEAKY_UNDEF_BRG_0A, ++ * - LEAKY_UNDEF_BRG_0B, ++ * - LEAKY_UNDEF_BRG_0C, ++ * - LEAKY_PROVIDER_BRIDGE_GVRP_ADDRESS, ++ * - LEAKY_8021AB, ++ * - LEAKY_UNDEF_BRG_0F, ++ * - LEAKY_BRG_MNGEMENT, ++ * - LEAKY_UNDEFINED_11, ++ * - LEAKY_UNDEFINED_12, ++ * - LEAKY_UNDEFINED_13, ++ * - LEAKY_UNDEFINED_14, ++ * - LEAKY_UNDEFINED_15, ++ * - LEAKY_UNDEFINED_16, ++ * - LEAKY_UNDEFINED_17, ++ * - LEAKY_UNDEFINED_18, ++ * - LEAKY_UNDEFINED_19, ++ * - LEAKY_UNDEFINED_1A, ++ * - LEAKY_UNDEFINED_1B, ++ * - LEAKY_UNDEFINED_1C, ++ * - LEAKY_UNDEFINED_1D, ++ * - LEAKY_UNDEFINED_1E, ++ * - LEAKY_UNDEFINED_1F, ++ * - LEAKY_GMRP, ++ * - LEAKY_GVRP, ++ * - LEAKY_UNDEF_GARP_22, ++ * - LEAKY_UNDEF_GARP_23, ++ * - LEAKY_UNDEF_GARP_24, ++ * - LEAKY_UNDEF_GARP_25, ++ * - LEAKY_UNDEF_GARP_26, ++ * - LEAKY_UNDEF_GARP_27, ++ * - LEAKY_UNDEF_GARP_28, ++ * - LEAKY_UNDEF_GARP_29, ++ * - LEAKY_UNDEF_GARP_2A, ++ * - LEAKY_UNDEF_GARP_2B, ++ * - LEAKY_UNDEF_GARP_2C, ++ * - LEAKY_UNDEF_GARP_2D, ++ * - LEAKY_UNDEF_GARP_2E, ++ * - LEAKY_UNDEF_GARP_2F, ++ * - LEAKY_IGMP, ++ * - LEAKY_IPMULTICAST. ++ * - LEAKY_CDP, ++ * - LEAKY_CSSTP, ++ * - LEAKY_LLDP. ++ */ ++extern rtk_api_ret_t rtk_leaky_portIsolation_set(rtk_leaky_type_t type, rtk_enable_t enable); ++ ++/* Function Name: ++ * rtk_leaky_portIsolation_get ++ * Description: ++ * Get port isolation leaky. ++ * Input: ++ * type - Packet type for port isolation leaky. ++ * Output: ++ * pEnable - Leaky status. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * This API can get port isolation leaky status for RMA ,IGMP/MLD, CDP, CSSTP, and LLDP packets. ++ * The leaky frame types are as following: ++ * - LEAKY_BRG_GROUP, ++ * - LEAKY_FD_PAUSE, ++ * - LEAKY_SP_MCAST, ++ * - LEAKY_1X_PAE, ++ * - LEAKY_UNDEF_BRG_04, ++ * - LEAKY_UNDEF_BRG_05, ++ * - LEAKY_UNDEF_BRG_06, ++ * - LEAKY_UNDEF_BRG_07, ++ * - LEAKY_PROVIDER_BRIDGE_GROUP_ADDRESS, ++ * - LEAKY_UNDEF_BRG_09, ++ * - LEAKY_UNDEF_BRG_0A, ++ * - LEAKY_UNDEF_BRG_0B, ++ * - LEAKY_UNDEF_BRG_0C, ++ * - LEAKY_PROVIDER_BRIDGE_GVRP_ADDRESS, ++ * - LEAKY_8021AB, ++ * - LEAKY_UNDEF_BRG_0F, ++ * - LEAKY_BRG_MNGEMENT, ++ * - LEAKY_UNDEFINED_11, ++ * - LEAKY_UNDEFINED_12, ++ * - LEAKY_UNDEFINED_13, ++ * - LEAKY_UNDEFINED_14, ++ * - LEAKY_UNDEFINED_15, ++ * - LEAKY_UNDEFINED_16, ++ * - LEAKY_UNDEFINED_17, ++ * - LEAKY_UNDEFINED_18, ++ * - LEAKY_UNDEFINED_19, ++ * - LEAKY_UNDEFINED_1A, ++ * - LEAKY_UNDEFINED_1B, ++ * - LEAKY_UNDEFINED_1C, ++ * - LEAKY_UNDEFINED_1D, ++ * - LEAKY_UNDEFINED_1E, ++ * - LEAKY_UNDEFINED_1F, ++ * - LEAKY_GMRP, ++ * - LEAKY_GVRP, ++ * - LEAKY_UNDEF_GARP_22, ++ * - LEAKY_UNDEF_GARP_23, ++ * - LEAKY_UNDEF_GARP_24, ++ * - LEAKY_UNDEF_GARP_25, ++ * - LEAKY_UNDEF_GARP_26, ++ * - LEAKY_UNDEF_GARP_27, ++ * - LEAKY_UNDEF_GARP_28, ++ * - LEAKY_UNDEF_GARP_29, ++ * - LEAKY_UNDEF_GARP_2A, ++ * - LEAKY_UNDEF_GARP_2B, ++ * - LEAKY_UNDEF_GARP_2C, ++ * - LEAKY_UNDEF_GARP_2D, ++ * - LEAKY_UNDEF_GARP_2E, ++ * - LEAKY_UNDEF_GARP_2F, ++ * - LEAKY_IGMP, ++ * - LEAKY_IPMULTICAST. ++ * - LEAKY_CDP, ++ * - LEAKY_CSSTP, ++ * - LEAKY_LLDP. ++ */ ++extern rtk_api_ret_t rtk_leaky_portIsolation_get(rtk_leaky_type_t type, rtk_enable_t *pEnable); ++ ++#endif /* __RTK_API_LEAKY_H__ */ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/include/led.h b/drivers/net/phy/rtk/rtl8367c/include/led.h +new file mode 100644 +index 000000000000..7706107ef40e +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/led.h +@@ -0,0 +1,481 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * Purpose : RTL8367/RTL8367C switch high-level API ++ * ++ * Feature : The file includes LED module high-layer API definition ++ * ++ */ ++ ++#ifndef __RTK_API_LED_H__ ++#define __RTK_API_LED_H__ ++ ++typedef enum rtk_led_operation_e ++{ ++ LED_OP_SCAN=0, ++ LED_OP_PARALLEL, ++ LED_OP_SERIAL, ++ LED_OP_END, ++}rtk_led_operation_t; ++ ++ ++typedef enum rtk_led_active_e ++{ ++ LED_ACTIVE_HIGH=0, ++ LED_ACTIVE_LOW, ++ LED_ACTIVE_END, ++}rtk_led_active_t; ++ ++typedef enum rtk_led_config_e ++{ ++ LED_CONFIG_LEDOFF=0, ++ LED_CONFIG_DUPCOL, ++ LED_CONFIG_LINK_ACT, ++ LED_CONFIG_SPD1000, ++ LED_CONFIG_SPD100, ++ LED_CONFIG_SPD10, ++ LED_CONFIG_SPD1000ACT, ++ LED_CONFIG_SPD100ACT, ++ LED_CONFIG_SPD10ACT, ++ LED_CONFIG_SPD10010ACT, ++ LED_CONFIG_LOOPDETECT, ++ LED_CONFIG_EEE, ++ LED_CONFIG_LINKRX, ++ LED_CONFIG_LINKTX, ++ LED_CONFIG_MASTER, ++ LED_CONFIG_ACT, ++ LED_CONFIG_END, ++}rtk_led_congig_t; ++ ++typedef struct rtk_led_ability_s ++{ ++ rtk_enable_t link_10m; ++ rtk_enable_t link_100m; ++ rtk_enable_t link_500m; ++ rtk_enable_t link_1000m; ++ rtk_enable_t act_rx; ++ rtk_enable_t act_tx; ++}rtk_led_ability_t; ++ ++typedef enum rtk_led_blink_rate_e ++{ ++ LED_BLINKRATE_32MS=0, ++ LED_BLINKRATE_64MS, ++ LED_BLINKRATE_128MS, ++ LED_BLINKRATE_256MS, ++ LED_BLINKRATE_512MS, ++ LED_BLINKRATE_1024MS, ++ LED_BLINKRATE_48MS, ++ LED_BLINKRATE_96MS, ++ LED_BLINKRATE_END, ++}rtk_led_blink_rate_t; ++ ++typedef enum rtk_led_group_e ++{ ++ LED_GROUP_0 = 0, ++ LED_GROUP_1, ++ LED_GROUP_2, ++ LED_GROUP_END ++}rtk_led_group_t; ++ ++ ++typedef enum rtk_led_force_mode_e ++{ ++ LED_FORCE_NORMAL=0, ++ LED_FORCE_BLINK, ++ LED_FORCE_OFF, ++ LED_FORCE_ON, ++ LED_FORCE_END ++}rtk_led_force_mode_t; ++ ++typedef enum rtk_led_serialOutput_e ++{ ++ SERIAL_LED_NONE = 0, ++ SERIAL_LED_0, ++ SERIAL_LED_0_1, ++ SERIAL_LED_0_2, ++ SERIAL_LED_END, ++}rtk_led_serialOutput_t; ++ ++ ++/* Function Name: ++ * rtk_led_enable_set ++ * Description: ++ * Set Led enable configuration ++ * Input: ++ * group - LED group id. ++ * pPortmask - LED enable port mask. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can be used to enable LED per port per group. ++ */ ++extern rtk_api_ret_t rtk_led_enable_set(rtk_led_group_t group, rtk_portmask_t *pPortmask); ++ ++/* Function Name: ++ * rtk_led_enable_get ++ * Description: ++ * Get Led enable configuration ++ * Input: ++ * group - LED group id. ++ * Output: ++ * pPortmask - LED enable port mask. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can be used to get LED enable status. ++ */ ++extern rtk_api_ret_t rtk_led_enable_get(rtk_led_group_t group, rtk_portmask_t *pPortmask); ++ ++/* Function Name: ++ * rtk_led_operation_set ++ * Description: ++ * Set Led operation mode ++ * Input: ++ * mode - LED operation mode. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can set Led operation mode. ++ * The modes that can be set are as following: ++ * - LED_OP_SCAN, ++ * - LED_OP_PARALLEL, ++ * - LED_OP_SERIAL, ++ */ ++extern rtk_api_ret_t rtk_led_operation_set(rtk_led_operation_t mode); ++ ++/* Function Name: ++ * rtk_led_operation_get ++ * Description: ++ * Get Led operation mode ++ * Input: ++ * None ++ * Output: ++ * pMode - Support LED operation mode. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can get Led operation mode. ++ * The modes that can be set are as following: ++ * - LED_OP_SCAN, ++ * - LED_OP_PARALLEL, ++ * - LED_OP_SERIAL, ++ */ ++extern rtk_api_ret_t rtk_led_operation_get(rtk_led_operation_t *pMode); ++ ++/* Function Name: ++ * rtk_led_modeForce_set ++ * Description: ++ * Set Led group to configuration force mode ++ * Input: ++ * port - port ID ++ * group - Support LED group id. ++ * mode - Support LED force mode. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_PORT_ID - Error Port ID ++ * Note: ++ * The API can force to one force mode. ++ * The force modes that can be set are as following: ++ * - LED_FORCE_NORMAL, ++ * - LED_FORCE_BLINK, ++ * - LED_FORCE_OFF, ++ * - LED_FORCE_ON. ++ */ ++extern rtk_api_ret_t rtk_led_modeForce_set(rtk_port_t port, rtk_led_group_t group, rtk_led_force_mode_t mode); ++ ++/* Function Name: ++ * rtk_led_modeForce_get ++ * Description: ++ * Get Led group to configuration force mode ++ * Input: ++ * port - port ID ++ * group - Support LED group id. ++ * pMode - Support LED force mode. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_PORT_ID - Error Port ID ++ * Note: ++ * The API can get forced Led group mode. ++ * The force modes that can be set are as following: ++ * - LED_FORCE_NORMAL, ++ * - LED_FORCE_BLINK, ++ * - LED_FORCE_OFF, ++ * - LED_FORCE_ON. ++ */ ++extern rtk_api_ret_t rtk_led_modeForce_get(rtk_port_t port, rtk_led_group_t group, rtk_led_force_mode_t *pMode); ++ ++/* Function Name: ++ * rtk_led_blinkRate_set ++ * Description: ++ * Set LED blinking rate ++ * Input: ++ * blinkRate - blinking rate. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * ASIC support 6 types of LED blinking rates at 43ms, 84ms, 120ms, 170ms, 340ms and 670ms. ++ */ ++extern rtk_api_ret_t rtk_led_blinkRate_set(rtk_led_blink_rate_t blinkRate); ++ ++/* Function Name: ++ * rtk_led_blinkRate_get ++ * Description: ++ * Get LED blinking rate at mode 0 to mode 3 ++ * Input: ++ * None ++ * Output: ++ * pBlinkRate - blinking rate. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * There are 6 types of LED blinking rates at 43ms, 84ms, 120ms, 170ms, 340ms and 670ms. ++ */ ++extern rtk_api_ret_t rtk_led_blinkRate_get(rtk_led_blink_rate_t *pBlinkRate); ++ ++/* Function Name: ++ * rtk_led_groupConfig_set ++ * Description: ++ * Set per group Led to configuration mode ++ * Input: ++ * group - LED group. ++ * config - LED configuration ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can set LED indicated information configuration for each LED group with 1 to 1 led mapping to each port. ++ * - Definition LED Statuses Description ++ * - 0000 LED_Off LED pin Tri-State. ++ * - 0001 Dup/Col Collision, Full duplex Indicator. ++ * - 0010 Link/Act Link, Activity Indicator. ++ * - 0011 Spd1000 1000Mb/s Speed Indicator. ++ * - 0100 Spd100 100Mb/s Speed Indicator. ++ * - 0101 Spd10 10Mb/s Speed Indicator. ++ * - 0110 Spd1000/Act 1000Mb/s Speed/Activity Indicator. ++ * - 0111 Spd100/Act 100Mb/s Speed/Activity Indicator. ++ * - 1000 Spd10/Act 10Mb/s Speed/Activity Indicator. ++ * - 1001 Spd100 (10)/Act 10/100Mb/s Speed/Activity Indicator. ++ * - 1010 LoopDetect LoopDetect Indicator. ++ * - 1011 EEE EEE Indicator. ++ * - 1100 Link/Rx Link, Activity Indicator. ++ * - 1101 Link/Tx Link, Activity Indicator. ++ * - 1110 Master Link on Master Indicator. ++ * - 1111 Act Activity Indicator. Low for link established. ++ */ ++extern rtk_api_ret_t rtk_led_groupConfig_set(rtk_led_group_t group, rtk_led_congig_t config); ++ ++/* Function Name: ++ * rtk_led_groupConfig_get ++ * Description: ++ * Get Led group configuration mode ++ * Input: ++ * group - LED group. ++ * Output: ++ * pConfig - LED configuration. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can get LED indicated information configuration for each LED group. ++ */ ++extern rtk_api_ret_t rtk_led_groupConfig_get(rtk_led_group_t group, rtk_led_congig_t *pConfig); ++ ++/* Function Name: ++ * rtk_led_groupAbility_set ++ * Description: ++ * Configure per group Led ability ++ * Input: ++ * group - LED group. ++ * pAbility - LED ability ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * None. ++ */ ++ ++extern rtk_api_ret_t rtk_led_groupAbility_set(rtk_led_group_t group, rtk_led_ability_t *pAbility); ++ ++/* Function Name: ++ * rtk_led_groupAbility_get ++ * Description: ++ * Get per group Led ability ++ * Input: ++ * group - LED group. ++ * pAbility - LED ability ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * None. ++ */ ++ ++extern rtk_api_ret_t rtk_led_groupAbility_get(rtk_led_group_t group, rtk_led_ability_t *pAbility); ++ ++/* Function Name: ++ * rtk_led_serialMode_set ++ * Description: ++ * Set Led serial mode active configuration ++ * Input: ++ * active - LED group. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can set LED serial mode active configuration. ++ */ ++extern rtk_api_ret_t rtk_led_serialMode_set(rtk_led_active_t active); ++ ++/* Function Name: ++ * rtk_led_serialMode_get ++ * Description: ++ * Get Led group configuration mode ++ * Input: ++ * group - LED group. ++ * Output: ++ * pConfig - LED configuration. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can get LED serial mode active configuration. ++ */ ++extern rtk_api_ret_t rtk_led_serialMode_get(rtk_led_active_t *pActive); ++ ++/* Function Name: ++ * rtk_led_OutputEnable_set ++ * Description: ++ * This API set LED I/O state. ++ * Input: ++ * enabled - LED I/O state ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Error parameter ++ * Note: ++ * This API set LED I/O state. ++ */ ++extern rtk_api_ret_t rtk_led_OutputEnable_set(rtk_enable_t state); ++ ++ ++/* Function Name: ++ * rtk_led_OutputEnable_get ++ * Description: ++ * This API get LED I/O state. ++ * Input: ++ * None. ++ * Output: ++ * pEnabled - LED I/O state ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Error parameter ++ * Note: ++ * This API set current LED I/O state. ++ */ ++extern rtk_api_ret_t rtk_led_OutputEnable_get(rtk_enable_t *pState); ++ ++/* Function Name: ++ * rtk_led_serialModePortmask_set ++ * Description: ++ * This API configure Serial LED output Group and portmask ++ * Input: ++ * output - output group ++ * pPortmask - output portmask ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Error parameter ++ * Note: ++ * None. ++ */ ++extern rtk_api_ret_t rtk_led_serialModePortmask_set(rtk_led_serialOutput_t output, rtk_portmask_t *pPortmask); ++ ++/* Function Name: ++ * rtk_led_serialModePortmask_get ++ * Description: ++ * This API get Serial LED output Group and portmask ++ * Input: ++ * None. ++ * Output: ++ * pOutput - output group ++ * pPortmask - output portmask ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Error parameter ++ * Note: ++ * None. ++ */ ++extern rtk_api_ret_t rtk_led_serialModePortmask_get(rtk_led_serialOutput_t *pOutput, rtk_portmask_t *pPortmask); ++ ++#endif /* __RTK_API_LED_H__ */ +diff --git a/drivers/net/phy/rtk/rtl8367c/include/mirror.h b/drivers/net/phy/rtk/rtl8367c/include/mirror.h +new file mode 100644 +index 000000000000..8d179ce2df48 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/mirror.h +@@ -0,0 +1,272 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * Purpose : RTL8367/RTL8367C switch high-level API ++ * ++ * Feature : The file includes Mirror module high-layer API definition ++ * ++ */ ++ ++#ifndef __RTK_API_MIRROR_H__ ++#define __RTK_API_MIRROR_H__ ++ ++typedef enum rtk_mirror_keep_e ++{ ++ MIRROR_FOLLOW_VLAN = 0, ++ MIRROR_KEEP_ORIGINAL, ++ MIRROR_KEEP_END ++}rtk_mirror_keep_t; ++ ++ ++/* Function Name: ++ * rtk_mirror_portBased_set ++ * Description: ++ * Set port mirror function. ++ * Input: ++ * mirroring_port - Monitor port. ++ * pMirrored_rx_portmask - Rx mirror port mask. ++ * pMirrored_tx_portmask - Tx mirror port mask. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * RT_ERR_PORT_MASK - Invalid portmask. ++ * Note: ++ * The API is to set mirror function of source port and mirror port. ++ * The mirror port can only be set to one port and the TX and RX mirror ports ++ * should be identical. ++ */ ++extern rtk_api_ret_t rtk_mirror_portBased_set(rtk_port_t mirroring_port, rtk_portmask_t *pMirrored_rx_portmask, rtk_portmask_t *pMirrored_tx_portmask); ++ ++/* Function Name: ++ * rtk_mirror_portBased_get ++ * Description: ++ * Get port mirror function. ++ * Input: ++ * None ++ * Output: ++ * pMirroring_port - Monitor port. ++ * pMirrored_rx_portmask - Rx mirror port mask. ++ * pMirrored_tx_portmask - Tx mirror port mask. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API is to get mirror function of source port and mirror port. ++ */ ++extern rtk_api_ret_t rtk_mirror_portBased_get(rtk_port_t* pMirroring_port, rtk_portmask_t *pMirrored_rx_portmask, rtk_portmask_t *pMirrored_tx_portmask); ++ ++/* Function Name: ++ * rtk_mirror_portIso_set ++ * Description: ++ * Set mirror port isolation. ++ * Input: ++ * enable |Mirror isolation status. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_ENABLE - Invalid enable input ++ * Note: ++ * The API is to set mirror isolation function that prevent normal forwarding packets to mirror port. ++ */ ++extern rtk_api_ret_t rtk_mirror_portIso_set(rtk_enable_t enable); ++ ++/* Function Name: ++ * rtk_mirror_portIso_get ++ * Description: ++ * Get mirror port isolation. ++ * Input: ++ * None ++ * Output: ++ * pEnable |Mirror isolation status. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API is to get mirror isolation status. ++ */ ++extern rtk_api_ret_t rtk_mirror_portIso_get(rtk_enable_t *pEnable); ++ ++/* Function Name: ++ * rtk_mirror_vlanLeaky_set ++ * Description: ++ * Set mirror VLAN leaky. ++ * Input: ++ * txenable -TX leaky enable. ++ * rxenable - RX leaky enable. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_ENABLE - Invalid enable input ++ * Note: ++ * The API is to set mirror VLAN leaky function forwarding packets to mirror port. ++ */ ++extern rtk_api_ret_t rtk_mirror_vlanLeaky_set(rtk_enable_t txenable, rtk_enable_t rxenable); ++ ++ ++/* Function Name: ++ * rtk_mirror_vlanLeaky_get ++ * Description: ++ * Get mirror VLAN leaky. ++ * Input: ++ * None ++ * Output: ++ * pTxenable - TX leaky enable. ++ * pRxenable - RX leaky enable. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API is to get mirror VLAN leaky status. ++ */ ++extern rtk_api_ret_t rtk_mirror_vlanLeaky_get(rtk_enable_t *pTxenable, rtk_enable_t *pRxenable); ++ ++/* Function Name: ++ * rtk_mirror_isolationLeaky_set ++ * Description: ++ * Set mirror Isolation leaky. ++ * Input: ++ * txenable -TX leaky enable. ++ * rxenable - RX leaky enable. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_ENABLE - Invalid enable input ++ * Note: ++ * The API is to set mirror VLAN leaky function forwarding packets to mirror port. ++ */ ++extern rtk_api_ret_t rtk_mirror_isolationLeaky_set(rtk_enable_t txenable, rtk_enable_t rxenable); ++ ++/* Function Name: ++ * rtk_mirror_isolationLeaky_get ++ * Description: ++ * Get mirror isolation leaky. ++ * Input: ++ * None ++ * Output: ++ * pTxenable - TX leaky enable. ++ * pRxenable - RX leaky enable. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API is to get mirror isolation leaky status. ++ */ ++extern rtk_api_ret_t rtk_mirror_isolationLeaky_get(rtk_enable_t *pTxenable, rtk_enable_t *pRxenable); ++ ++/* Function Name: ++ * rtk_mirror_keep_set ++ * Description: ++ * Set mirror packet format keep. ++ * Input: ++ * mode - -mirror keep mode. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_ENABLE - Invalid enable input ++ * Note: ++ * The API is to set -mirror keep mode. ++ * The mirror keep mode is as following: ++ * - MIRROR_FOLLOW_VLAN ++ * - MIRROR_KEEP_ORIGINAL ++ * - MIRROR_KEEP_END ++ */ ++extern rtk_api_ret_t rtk_mirror_keep_set(rtk_mirror_keep_t mode); ++ ++ ++/* Function Name: ++ * rtk_mirror_keep_get ++ * Description: ++ * Get mirror packet format keep. ++ * Input: ++ * None ++ * Output: ++ * pMode -mirror keep mode. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API is to get mirror keep mode. ++ * The mirror keep mode is as following: ++ * - MIRROR_FOLLOW_VLAN ++ * - MIRROR_KEEP_ORIGINAL ++ * - MIRROR_KEEP_END ++ */ ++extern rtk_api_ret_t rtk_mirror_keep_get(rtk_mirror_keep_t *pMode); ++ ++/* Function Name: ++ * rtk_mirror_override_set ++ * Description: ++ * Set port mirror override function. ++ * Input: ++ * rxMirror - 1: output mirrored packet, 0: output normal forward packet ++ * txMirror - 1: output mirrored packet, 0: output normal forward packet ++ * aclMirror - 1: output mirrored packet, 0: output normal forward packet ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * The API is to set mirror override function. ++ * This function control the output format when a port output ++ * normal forward & mirrored packet at the same time. ++ */ ++extern rtk_api_ret_t rtk_mirror_override_set(rtk_enable_t rxMirror, rtk_enable_t txMirror, rtk_enable_t aclMirror); ++ ++/* Function Name: ++ * rtk_mirror_override_get ++ * Description: ++ * Get port mirror override function. ++ * Input: ++ * None ++ * Output: ++ * pRxMirror - 1: output mirrored packet, 0: output normal forward packet ++ * pTxMirror - 1: output mirrored packet, 0: output normal forward packet ++ * pAclMirror - 1: output mirrored packet, 0: output normal forward packet ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_NULL_POINTER - Null Pointer ++ * Note: ++ * The API is to Get mirror override function. ++ * This function control the output format when a port output ++ * normal forward & mirrored packet at the same time. ++ */ ++extern rtk_api_ret_t rtk_mirror_override_get(rtk_enable_t *pRxMirror, rtk_enable_t *pTxMirror, rtk_enable_t *pAclMirror); ++ ++#endif /* __RTK_API_MIRROR_H__ */ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/include/oam.h b/drivers/net/phy/rtk/rtl8367c/include/oam.h +new file mode 100644 +index 000000000000..1fc14bd62fec +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/oam.h +@@ -0,0 +1,188 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ ++ * ++ * Purpose : RTL8367/RTL8367C switch high-level API ++ * ++ * Feature : The file includes the following modules and sub-modules ++ * (1) OAM (802.3ah) configuration ++ * ++ */ ++ ++#ifndef __RTK_OAM_H__ ++#define __RTK_OAM_H__ ++ ++/* ++ * Symbol Definition ++ */ ++ ++ ++/* ++ * Data Declaration ++ */ ++ ++ ++/* ++ * Macro Declaration ++ */ ++ ++typedef enum rtk_oam_parser_act_e ++{ ++ OAM_PARSER_ACTION_FORWARD = 0, ++ OAM_PARSER_ACTION_LOOPBACK, ++ OAM_PARSER_ACTION_DISCARD, ++ OAM_PARSER_ACTION_END, ++ ++} rtk_oam_parser_act_t; ++ ++typedef enum rtk_oam_multiplexer_act_e ++{ ++ OAM_MULTIPLEXER_ACTION_FORWARD = 0, ++ OAM_MULTIPLEXER_ACTION_DISCARD, ++ OAM_MULTIPLEXER_ACTION_CPUONLY, ++ OAM_MULTIPLEXER_ACTION_END, ++ ++} rtk_oam_multiplexer_act_t; ++ ++ ++/* ++ * Function Declaration ++ */ ++ ++/* Function Name: ++ * rtk_oam_init ++ * Description: ++ * Initialize oam module. ++ * Input: ++ * None ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * Note: ++ * Must initialize oam module before calling any oam APIs. ++ */ ++extern rtk_api_ret_t rtk_oam_init(void); ++ ++/* Function Name: ++ * rtk_oam_state_set ++ * Description: ++ * This API set OAM state. ++ * Input: ++ * enabled -OAMstate ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Error parameter ++ * Note: ++ * This API set OAM state. ++ */ ++extern rtk_api_ret_t rtk_oam_state_set(rtk_enable_t enabled); ++ ++/* Function Name: ++ * rtk_oam_state_get ++ * Description: ++ * This API get OAM state. ++ * Input: ++ * None. ++ * Output: ++ * pEnabled - H/W IGMP state ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Error parameter ++ * Note: ++ * This API set current OAM state. ++ */ ++extern rtk_api_ret_t rtk_oam_state_get(rtk_enable_t *pEnabled); ++ ++ ++/* Module Name : OAM */ ++ ++/* Function Name: ++ * rtk_oam_parserAction_set ++ * Description: ++ * Set OAM parser action ++ * Input: ++ * port - port id ++ * action - parser action ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_PORT_ID - invalid port id ++ * Note: ++ * None ++ */ ++extern rtk_api_ret_t rtk_oam_parserAction_set(rtk_port_t port, rtk_oam_parser_act_t action); ++ ++/* Function Name: ++ * rtk_oam_parserAction_set ++ * Description: ++ * Get OAM parser action ++ * Input: ++ * port - port id ++ * Output: ++ * pAction - parser action ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_PORT_ID - invalid port id ++ * Note: ++ * None ++ */ ++extern rtk_api_ret_t rtk_oam_parserAction_get(rtk_port_t port, rtk_oam_parser_act_t *pAction); ++ ++ ++/* Function Name: ++ * rtk_oam_multiplexerAction_set ++ * Description: ++ * Set OAM multiplexer action ++ * Input: ++ * port - port id ++ * action - parser action ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_PORT_ID - invalid port id ++ * Note: ++ * None ++ */ ++extern rtk_api_ret_t rtk_oam_multiplexerAction_set(rtk_port_t port, rtk_oam_multiplexer_act_t action); ++ ++/* Function Name: ++ * rtk_oam_multiplexerAction_set ++ * Description: ++ * Get OAM multiplexer action ++ * Input: ++ * port - port id ++ * Output: ++ * pAction - parser action ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_PORT_ID - invalid port id ++ * Note: ++ * None ++ */ ++extern rtk_api_ret_t rtk_oam_multiplexerAction_get(rtk_port_t port, rtk_oam_multiplexer_act_t *pAction); ++ ++ ++#endif /* __RTK_OAM_H__ */ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/include/port.h b/drivers/net/phy/rtk/rtl8367c/include/port.h +new file mode 100644 +index 000000000000..458f16bf6d97 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/port.h +@@ -0,0 +1,959 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * Purpose : RTL8367/RTL8367C switch high-level API ++ * ++ * Feature : The file includes port module high-layer API definition ++ * ++ */ ++ ++#ifndef __RTK_API_PORT_H__ ++#define __RTK_API_PORT_H__ ++ ++/* ++ * Data Type Declaration ++ */ ++ ++#define PHY_CONTROL_REG 0 ++#define PHY_STATUS_REG 1 ++#define PHY_AN_ADVERTISEMENT_REG 4 ++#define PHY_AN_LINKPARTNER_REG 5 ++#define PHY_1000_BASET_CONTROL_REG 9 ++#define PHY_1000_BASET_STATUS_REG 10 ++#define PHY_RESOLVED_REG 26 ++ ++#define RTK_EFID_MAX 0x7 ++ ++#define RTK_FIBER_FORCE_1000M 3 ++#define RTK_FIBER_FORCE_100M 5 ++#define RTK_FIBER_FORCE_100M1000M 7 ++ ++#define RTK_INDRECT_ACCESS_CRTL 0x1f00 ++#define RTK_INDRECT_ACCESS_STATUS 0x1f01 ++#define RTK_INDRECT_ACCESS_ADDRESS 0x1f02 ++#define RTK_INDRECT_ACCESS_WRITE_DATA 0x1f03 ++#define RTK_INDRECT_ACCESS_READ_DATA 0x1f04 ++#define RTK_INDRECT_ACCESS_DELAY 0x1f80 ++#define RTK_INDRECT_ACCESS_BURST 0x1f81 ++#define RTK_RW_MASK 0x2 ++#define RTK_CMD_MASK 0x1 ++#define RTK_PHY_BUSY_OFFSET 2 ++ ++ ++typedef enum rtk_mode_ext_e ++{ ++ MODE_EXT_DISABLE = 0, ++ MODE_EXT_RGMII, ++ MODE_EXT_MII_MAC, ++ MODE_EXT_MII_PHY, ++ MODE_EXT_TMII_MAC, ++ MODE_EXT_TMII_PHY, ++ MODE_EXT_GMII, ++ MODE_EXT_RMII_MAC, ++ MODE_EXT_RMII_PHY, ++ MODE_EXT_SGMII, ++ MODE_EXT_HSGMII, ++ MODE_EXT_1000X_100FX, ++ MODE_EXT_1000X, ++ MODE_EXT_100FX, ++ MODE_EXT_RGMII_2, ++ MODE_EXT_MII_MAC_2, ++ MODE_EXT_MII_PHY_2, ++ MODE_EXT_TMII_MAC_2, ++ MODE_EXT_TMII_PHY_2, ++ MODE_EXT_RMII_MAC_2, ++ MODE_EXT_RMII_PHY_2, ++ MODE_EXT_END ++} rtk_mode_ext_t; ++ ++typedef enum rtk_port_duplex_e ++{ ++ PORT_HALF_DUPLEX = 0, ++ PORT_FULL_DUPLEX, ++ PORT_DUPLEX_END ++} rtk_port_duplex_t; ++ ++typedef enum rtk_port_linkStatus_e ++{ ++ PORT_LINKDOWN = 0, ++ PORT_LINKUP, ++ PORT_LINKSTATUS_END ++} rtk_port_linkStatus_t; ++ ++typedef struct rtk_port_mac_ability_s ++{ ++ rtk_uint32 forcemode; ++ rtk_uint32 speed; ++ rtk_uint32 duplex; ++ rtk_uint32 link; ++ rtk_uint32 nway; ++ rtk_uint32 txpause; ++ rtk_uint32 rxpause; ++}rtk_port_mac_ability_t; ++ ++typedef struct rtk_port_phy_ability_s ++{ ++ rtk_uint32 AutoNegotiation; /*PHY register 0.12 setting for auto-negotiation process*/ ++ rtk_uint32 Half_10; /*PHY register 4.5 setting for 10BASE-TX half duplex capable*/ ++ rtk_uint32 Full_10; /*PHY register 4.6 setting for 10BASE-TX full duplex capable*/ ++ rtk_uint32 Half_100; /*PHY register 4.7 setting for 100BASE-TX half duplex capable*/ ++ rtk_uint32 Full_100; /*PHY register 4.8 setting for 100BASE-TX full duplex capable*/ ++ rtk_uint32 Full_1000; /*PHY register 9.9 setting for 1000BASE-T full duplex capable*/ ++ rtk_uint32 FC; /*PHY register 4.10 setting for flow control capability*/ ++ rtk_uint32 AsyFC; /*PHY register 4.11 setting for asymmetric flow control capability*/ ++} rtk_port_phy_ability_t; ++ ++typedef rtk_uint32 rtk_port_phy_data_t; /* phy page */ ++ ++typedef enum rtk_port_phy_mdix_mode_e ++{ ++ PHY_AUTO_CROSSOVER_MODE= 0, ++ PHY_FORCE_MDI_MODE, ++ PHY_FORCE_MDIX_MODE, ++ PHY_FORCE_MODE_END ++} rtk_port_phy_mdix_mode_t; ++ ++typedef enum rtk_port_phy_mdix_status_e ++{ ++ PHY_STATUS_AUTO_MDI_MODE= 0, ++ PHY_STATUS_AUTO_MDIX_MODE, ++ PHY_STATUS_FORCE_MDI_MODE, ++ PHY_STATUS_FORCE_MDIX_MODE, ++ PHY_STATUS_FORCE_MODE_END ++} rtk_port_phy_mdix_status_t; ++ ++typedef rtk_uint32 rtk_port_phy_page_t; /* phy page */ ++ ++typedef enum rtk_port_phy_reg_e ++{ ++ PHY_REG_CONTROL = 0, ++ PHY_REG_STATUS, ++ PHY_REG_IDENTIFIER_1, ++ PHY_REG_IDENTIFIER_2, ++ PHY_REG_AN_ADVERTISEMENT, ++ PHY_REG_AN_LINKPARTNER, ++ PHY_REG_1000_BASET_CONTROL = 9, ++ PHY_REG_1000_BASET_STATUS, ++ PHY_REG_END = 32 ++} rtk_port_phy_reg_t; ++ ++typedef enum rtk_port_phy_test_mode_e ++{ ++ PHY_TEST_MODE_NORMAL= 0, ++ PHY_TEST_MODE_1, ++ PHY_TEST_MODE_2, ++ PHY_TEST_MODE_3, ++ PHY_TEST_MODE_4, ++ PHY_TEST_MODE_END ++} rtk_port_phy_test_mode_t; ++ ++typedef enum rtk_port_speed_e ++{ ++ PORT_SPEED_10M = 0, ++ PORT_SPEED_100M, ++ PORT_SPEED_1000M, ++ PORT_SPEED_500M, ++ PORT_SPEED_2500M, ++ PORT_SPEED_END ++} rtk_port_speed_t; ++ ++typedef enum rtk_port_media_e ++{ ++ PORT_MEDIA_COPPER = 0, ++ PORT_MEDIA_FIBER, ++ PORT_MEDIA_END ++}rtk_port_media_t; ++ ++typedef struct rtk_rtctResult_s ++{ ++ rtk_port_speed_t linkType; ++ union ++ { ++ struct fe_result_s ++ { ++ rtk_uint32 isRxShort; ++ rtk_uint32 isTxShort; ++ rtk_uint32 isRxOpen; ++ rtk_uint32 isTxOpen; ++ rtk_uint32 isRxMismatch; ++ rtk_uint32 isTxMismatch; ++ rtk_uint32 isRxLinedriver; ++ rtk_uint32 isTxLinedriver; ++ rtk_uint32 rxLen; ++ rtk_uint32 txLen; ++ } fe_result; ++ ++ struct ge_result_s ++ { ++ rtk_uint32 channelAShort; ++ rtk_uint32 channelBShort; ++ rtk_uint32 channelCShort; ++ rtk_uint32 channelDShort; ++ ++ rtk_uint32 channelAOpen; ++ rtk_uint32 channelBOpen; ++ rtk_uint32 channelCOpen; ++ rtk_uint32 channelDOpen; ++ ++ rtk_uint32 channelAMismatch; ++ rtk_uint32 channelBMismatch; ++ rtk_uint32 channelCMismatch; ++ rtk_uint32 channelDMismatch; ++ ++ rtk_uint32 channelALinedriver; ++ rtk_uint32 channelBLinedriver; ++ rtk_uint32 channelCLinedriver; ++ rtk_uint32 channelDLinedriver; ++ ++ rtk_uint32 channelALen; ++ rtk_uint32 channelBLen; ++ rtk_uint32 channelCLen; ++ rtk_uint32 channelDLen; ++ } ge_result; ++ }result; ++} rtk_rtctResult_t; ++ ++/* Function Name: ++ * rtk_port_phyAutoNegoAbility_set ++ * Description: ++ * Set Ethernet PHY auto-negotiation desired ability. ++ * Input: ++ * port - port id. ++ * pAbility - Ability structure ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_PHY_REG_ID - Invalid PHY address ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy ++ * Note: ++ * If Full_1000 bit is set to 1, the AutoNegotiation will be automatic set to 1. While both AutoNegotiation and Full_1000 are set to 0, the PHY speed and duplex selection will ++ * be set as following 100F > 100H > 10F > 10H priority sequence. ++ */ ++extern rtk_api_ret_t rtk_port_phyAutoNegoAbility_set(rtk_port_t port, rtk_port_phy_ability_t *pAbility); ++ ++/* Function Name: ++ * rtk_port_phyAutoNegoAbility_get ++ * Description: ++ * Get PHY ability through PHY registers. ++ * Input: ++ * port - Port id. ++ * Output: ++ * pAbility - Ability structure ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_PHY_REG_ID - Invalid PHY address ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy ++ * Note: ++ * Get the capability of specified PHY. ++ */ ++extern rtk_api_ret_t rtk_port_phyAutoNegoAbility_get(rtk_port_t port, rtk_port_phy_ability_t *pAbility); ++ ++/* Function Name: ++ * rtk_port_phyForceModeAbility_set ++ * Description: ++ * Set the port speed/duplex mode/pause/asy_pause in the PHY force mode. ++ * Input: ++ * port - port id. ++ * pAbility - Ability structure ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_PHY_REG_ID - Invalid PHY address ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy ++ * Note: ++ * While both AutoNegotiation and Full_1000 are set to 0, the PHY speed and duplex selection will ++ * be set as following 100F > 100H > 10F > 10H priority sequence. ++ */ ++extern rtk_api_ret_t rtk_port_phyForceModeAbility_set(rtk_port_t port, rtk_port_phy_ability_t *pAbility); ++ ++/* Function Name: ++ * rtk_port_phyForceModeAbility_get ++ * Description: ++ * Get PHY ability through PHY registers. ++ * Input: ++ * port - Port id. ++ * Output: ++ * pAbility - Ability structure ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_PHY_REG_ID - Invalid PHY address ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy ++ * Note: ++ * Get the capability of specified PHY. ++ */ ++extern rtk_api_ret_t rtk_port_phyForceModeAbility_get(rtk_port_t port, rtk_port_phy_ability_t *pAbility); ++ ++/* Function Name: ++ * rtk_port_phyStatus_get ++ * Description: ++ * Get Ethernet PHY linking status ++ * Input: ++ * port - Port id. ++ * Output: ++ * linkStatus - PHY link status ++ * speed - PHY link speed ++ * duplex - PHY duplex mode ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_PHY_REG_ID - Invalid PHY address ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy ++ * Note: ++ * API will return auto negotiation status of phy. ++ */ ++extern rtk_api_ret_t rtk_port_phyStatus_get(rtk_port_t port, rtk_port_linkStatus_t *pLinkStatus, rtk_port_speed_t *pSpeed, rtk_port_duplex_t *pDuplex); ++ ++/* Function Name: ++ * rtk_port_macForceLink_set ++ * Description: ++ * Set port force linking configuration. ++ * Input: ++ * port - port id. ++ * pPortability - port ability configuration ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * This API can set Port/MAC force mode properties. ++ */ ++extern rtk_api_ret_t rtk_port_macForceLink_set(rtk_port_t port, rtk_port_mac_ability_t *pPortability); ++ ++/* Function Name: ++ * rtk_port_macForceLink_get ++ * Description: ++ * Get port force linking configuration. ++ * Input: ++ * port - Port id. ++ * Output: ++ * pPortability - port ability configuration ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * This API can get Port/MAC force mode properties. ++ */ ++extern rtk_api_ret_t rtk_port_macForceLink_get(rtk_port_t port, rtk_port_mac_ability_t *pPortability); ++ ++/* Function Name: ++ * rtk_port_macForceLinkExt_set ++ * Description: ++ * Set external interface force linking configuration. ++ * Input: ++ * port - external port ID ++ * mode - external interface mode ++ * pPortability - port ability configuration ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * This API can set external interface force mode properties. ++ * The external interface can be set to: ++ * - MODE_EXT_DISABLE, ++ * - MODE_EXT_RGMII, ++ * - MODE_EXT_MII_MAC, ++ * - MODE_EXT_MII_PHY, ++ * - MODE_EXT_TMII_MAC, ++ * - MODE_EXT_TMII_PHY, ++ * - MODE_EXT_GMII, ++ * - MODE_EXT_RMII_MAC, ++ * - MODE_EXT_RMII_PHY, ++ * - MODE_EXT_SGMII, ++ * - MODE_EXT_HSGMII, ++ * - MODE_EXT_1000X_100FX, ++ * - MODE_EXT_1000X, ++ * - MODE_EXT_100FX, ++ */ ++extern rtk_api_ret_t rtk_port_macForceLinkExt_set(rtk_port_t port, rtk_mode_ext_t mode, rtk_port_mac_ability_t *pPortability); ++ ++/* Function Name: ++ * rtk_port_macForceLinkExt_get ++ * Description: ++ * Set external interface force linking configuration. ++ * Input: ++ * port - external port ID ++ * Output: ++ * pMode - external interface mode ++ * pPortability - port ability configuration ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * This API can get external interface force mode properties. ++ */ ++extern rtk_api_ret_t rtk_port_macForceLinkExt_get(rtk_port_t port, rtk_mode_ext_t *pMode, rtk_port_mac_ability_t *pPortability); ++ ++/* Function Name: ++ * rtk_port_macStatus_get ++ * Description: ++ * Get port link status. ++ * Input: ++ * port - Port id. ++ * Output: ++ * pPortstatus - port ability configuration ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * This API can get Port/PHY properties. ++ */ ++extern rtk_api_ret_t rtk_port_macStatus_get(rtk_port_t port, rtk_port_mac_ability_t *pPortstatus); ++ ++/* Function Name: ++ * rtk_port_macLocalLoopbackEnable_set ++ * Description: ++ * Set Port Local Loopback. (Redirect TX to RX.) ++ * Input: ++ * port - Port id. ++ * enable - Loopback state, 0:disable, 1:enable ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * This API can enable/disable Local loopback in MAC. ++ * For UTP port, This API will also enable the digital ++ * loopback bit in PHY register for sync of speed between ++ * PHY and MAC. For EXT port, users need to force the ++ * link state by themselves. ++ */ ++extern rtk_api_ret_t rtk_port_macLocalLoopbackEnable_set(rtk_port_t port, rtk_enable_t enable); ++ ++/* Function Name: ++ * rtk_port_macLocalLoopbackEnable_get ++ * Description: ++ * Get Port Local Loopback. (Redirect TX to RX.) ++ * Input: ++ * port - Port id. ++ * Output: ++ * pEnable - Loopback state, 0:disable, 1:enable ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * None. ++ */ ++extern rtk_api_ret_t rtk_port_macLocalLoopbackEnable_get(rtk_port_t port, rtk_enable_t *pEnable); ++ ++/* Function Name: ++ * rtk_port_phyReg_set ++ * Description: ++ * Set PHY register data of the specific port. ++ * Input: ++ * port - port id. ++ * reg - Register id ++ * regData - Register data ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_PHY_REG_ID - Invalid PHY address ++ * RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy ++ * Note: ++ * This API can set PHY register data of the specific port. ++ */ ++extern rtk_api_ret_t rtk_port_phyReg_set(rtk_port_t port, rtk_port_phy_reg_t reg, rtk_port_phy_data_t value); ++ ++/* Function Name: ++ * rtk_port_phyReg_get ++ * Description: ++ * Get PHY register data of the specific port. ++ * Input: ++ * port - Port id. ++ * reg - Register id ++ * Output: ++ * pData - Register data ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_PHY_REG_ID - Invalid PHY address ++ * RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy ++ * Note: ++ * This API can get PHY register data of the specific port. ++ */ ++extern rtk_api_ret_t rtk_port_phyReg_get(rtk_port_t port, rtk_port_phy_reg_t reg, rtk_port_phy_data_t *pData); ++ ++/* Function Name: ++ * rtk_port_backpressureEnable_set ++ * Description: ++ * Set the half duplex back-pressure enable status of the specific port. ++ * Input: ++ * port - port id. ++ * enable - Back pressure status. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_ENABLE - Invalid enable input. ++ * Note: ++ * This API can set the half duplex back-pressure enable status of the specific port. ++ * The half duplex back-pressure enable status of the port is as following: ++ * - DISABLE ++ * - ENABLE ++ */ ++extern rtk_api_ret_t rtk_port_backpressureEnable_set(rtk_port_t port, rtk_enable_t enable); ++ ++/* Function Name: ++ * rtk_port_backpressureEnable_get ++ * Description: ++ * Get the half duplex back-pressure enable status of the specific port. ++ * Input: ++ * port - Port id. ++ * Output: ++ * pEnable - Back pressure status. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * This API can get the half duplex back-pressure enable status of the specific port. ++ * The half duplex back-pressure enable status of the port is as following: ++ * - DISABLE ++ * - ENABLE ++ */ ++extern rtk_api_ret_t rtk_port_backpressureEnable_get(rtk_port_t port, rtk_enable_t *pEnable); ++ ++/* Function Name: ++ * rtk_port_adminEnable_set ++ * Description: ++ * Set port admin configuration of the specific port. ++ * Input: ++ * port - port id. ++ * enable - Back pressure status. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_ENABLE - Invalid enable input. ++ * Note: ++ * This API can set port admin configuration of the specific port. ++ * The port admin configuration of the port is as following: ++ * - DISABLE ++ * - ENABLE ++ */ ++extern rtk_api_ret_t rtk_port_adminEnable_set(rtk_port_t port, rtk_enable_t enable); ++ ++/* Function Name: ++ * rtk_port_adminEnable_get ++ * Description: ++ * Get port admin configuration of the specific port. ++ * Input: ++ * port - Port id. ++ * Output: ++ * pEnable - Back pressure status. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * This API can get port admin configuration of the specific port. ++ * The port admin configuration of the port is as following: ++ * - DISABLE ++ * - ENABLE ++ */ ++extern rtk_api_ret_t rtk_port_adminEnable_get(rtk_port_t port, rtk_enable_t *pEnable); ++ ++/* Function Name: ++ * rtk_port_isolation_set ++ * Description: ++ * Set permitted port isolation portmask ++ * Input: ++ * port - port id. ++ * pPortmask - Permit port mask ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_PORT_MASK - Invalid portmask. ++ * Note: ++ * This API set the port mask that a port can transmit packet to of each port ++ * A port can only transmit packet to ports included in permitted portmask ++ */ ++extern rtk_api_ret_t rtk_port_isolation_set(rtk_port_t port, rtk_portmask_t *pPortmask); ++ ++/* Function Name: ++ * rtk_port_isolation_get ++ * Description: ++ * Get permitted port isolation portmask ++ * Input: ++ * port - Port id. ++ * Output: ++ * pPortmask - Permit port mask ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * This API get the port mask that a port can transmit packet to of each port ++ * A port can only transmit packet to ports included in permitted portmask ++ */ ++extern rtk_api_ret_t rtk_port_isolation_get(rtk_port_t port, rtk_portmask_t *pPortmask); ++ ++/* Function Name: ++ * rtk_port_rgmiiDelayExt_set ++ * Description: ++ * Set RGMII interface delay value for TX and RX. ++ * Input: ++ * txDelay - TX delay value, 1 for delay 2ns and 0 for no-delay ++ * rxDelay - RX delay value, 0~7 for delay setup. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * This API can set external interface 2 RGMII delay. ++ * In TX delay, there are 2 selection: no-delay and 2ns delay. ++ * In RX delay, there are 8 steps for delay tuning. 0 for no-delay, and 7 for maximum delay. ++ */ ++extern rtk_api_ret_t rtk_port_rgmiiDelayExt_set(rtk_port_t port, rtk_data_t txDelay, rtk_data_t rxDelay); ++ ++/* Function Name: ++ * rtk_port_rgmiiDelayExt_get ++ * Description: ++ * Get RGMII interface delay value for TX and RX. ++ * Input: ++ * None ++ * Output: ++ * pTxDelay - TX delay value ++ * pRxDelay - RX delay value ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * This API can set external interface 2 RGMII delay. ++ * In TX delay, there are 2 selection: no-delay and 2ns delay. ++ * In RX delay, there are 8 steps for delay tuning. 0 for n0-delay, and 7 for maximum delay. ++ */ ++extern rtk_api_ret_t rtk_port_rgmiiDelayExt_get(rtk_port_t port, rtk_data_t *pTxDelay, rtk_data_t *pRxDelay); ++ ++/* Function Name: ++ * rtk_port_phyEnableAll_set ++ * Description: ++ * Set all PHY enable status. ++ * Input: ++ * enable - PHY Enable State. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_ENABLE - Invalid enable input. ++ * Note: ++ * This API can set all PHY status. ++ * The configuration of all PHY is as following: ++ * - DISABLE ++ * - ENABLE ++ */ ++extern rtk_api_ret_t rtk_port_phyEnableAll_set(rtk_enable_t enable); ++ ++/* Function Name: ++ * rtk_port_phyEnableAll_get ++ * Description: ++ * Get all PHY enable status. ++ * Input: ++ * None ++ * Output: ++ * pEnable - PHY Enable State. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * This API can set all PHY status. ++ * The configuration of all PHY is as following: ++ * - DISABLE ++ * - ENABLE ++ */ ++extern rtk_api_ret_t rtk_port_phyEnableAll_get(rtk_enable_t *pEnable); ++ ++/* Function Name: ++ * rtk_port_efid_set ++ * Description: ++ * Set port-based enhanced filtering database ++ * Input: ++ * port - Port id. ++ * efid - Specified enhanced filtering database. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_L2_FID - Invalid fid. ++ * RT_ERR_INPUT - Invalid input parameter. ++ * RT_ERR_PORT_ID - Invalid port ID. ++ * Note: ++ * The API can set port-based enhanced filtering database. ++ */ ++extern rtk_api_ret_t rtk_port_efid_set(rtk_port_t port, rtk_data_t efid); ++ ++/* Function Name: ++ * rtk_port_efid_get ++ * Description: ++ * Get port-based enhanced filtering database ++ * Input: ++ * port - Port id. ++ * Output: ++ * pEfid - Specified enhanced filtering database. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_PORT_ID - Invalid port ID. ++ * Note: ++ * The API can get port-based enhanced filtering database status. ++ */ ++extern rtk_api_ret_t rtk_port_efid_get(rtk_port_t port, rtk_data_t *pEfid); ++ ++/* Function Name: ++ * rtk_port_phyComboPortMedia_set ++ * Description: ++ * Set Combo port media type ++ * Input: ++ * port - Port id. (Should be Port 4) ++ * media - Media (COPPER or FIBER) ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_PORT_ID - Invalid port ID. ++ * Note: ++ * The API can Set Combo port media type. ++ */ ++extern rtk_api_ret_t rtk_port_phyComboPortMedia_set(rtk_port_t port, rtk_port_media_t media); ++ ++/* Function Name: ++ * rtk_port_phyComboPortMedia_get ++ * Description: ++ * Get Combo port media type ++ * Input: ++ * port - Port id. (Should be Port 4) ++ * Output: ++ * pMedia - Media (COPPER or FIBER) ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_PORT_ID - Invalid port ID. ++ * Note: ++ * The API can Set Combo port media type. ++ */ ++extern rtk_api_ret_t rtk_port_phyComboPortMedia_get(rtk_port_t port, rtk_port_media_t *pMedia); ++ ++/* Function Name: ++ * rtk_port_rtctEnable_set ++ * Description: ++ * Enable RTCT test ++ * Input: ++ * pPortmask - Port mask of RTCT enabled port ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_MASK - Invalid port mask. ++ * Note: ++ * The API can enable RTCT Test ++ */ ++extern rtk_api_ret_t rtk_port_rtctEnable_set(rtk_portmask_t *pPortmask); ++ ++/* Function Name: ++ * rtk_port_rtctDisable_set ++ * Description: ++ * Disable RTCT test ++ * Input: ++ * pPortmask - Port mask of RTCT disabled port ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_MASK - Invalid port mask. ++ * Note: ++ * The API can disable RTCT Test ++ */ ++rtk_api_ret_t rtk_port_rtctDisable_set(rtk_portmask_t *pPortmask); ++ ++ ++/* Function Name: ++ * rtk_port_rtctResult_get ++ * Description: ++ * Get the result of RTCT test ++ * Input: ++ * port - Port ID ++ * Output: ++ * pRtctResult - The result of RTCT result ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port ID. ++ * RT_ERR_PHY_RTCT_NOT_FINISH - Testing does not finish. ++ * Note: ++ * The API can get RTCT test result. ++ * RTCT test may takes 4.8 seconds to finish its test at most. ++ * Thus, if this API return RT_ERR_PHY_RTCT_NOT_FINISH or ++ * other error code, the result can not be referenced and ++ * user should call this API again until this API returns ++ * a RT_ERR_OK. ++ * The result is stored at pRtctResult->ge_result ++ * pRtctResult->linkType is unused. ++ * The unit of channel length is 2.5cm. Ex. 300 means 300 * 2.5 = 750cm = 7.5M ++ */ ++extern rtk_api_ret_t rtk_port_rtctResult_get(rtk_port_t port, rtk_rtctResult_t *pRtctResult); ++ ++/* Function Name: ++ * rtk_port_sds_reset ++ * Description: ++ * Reset Serdes ++ * Input: ++ * port - Port ID ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port ID. ++ * Note: ++ * The API can reset Serdes ++ */ ++extern rtk_api_ret_t rtk_port_sds_reset(rtk_port_t port); ++ ++/* Function Name: ++ * rtk_port_sgmiiLinkStatus_get ++ * Description: ++ * Get SGMII status ++ * Input: ++ * port - Port ID ++ * Output: ++ * pSignalDetect - Signal detect ++ * pSync - Sync ++ * pLink - Link ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port ID. ++ * Note: ++ * The API can reset Serdes ++ */ ++extern rtk_api_ret_t rtk_port_sgmiiLinkStatus_get(rtk_port_t port, rtk_data_t *pSignalDetect, rtk_data_t *pSync, rtk_port_linkStatus_t *pLink); ++ ++/* Function Name: ++ * rtk_port_sgmiiNway_set ++ * Description: ++ * Configure SGMII/HSGMII port Nway state ++ * Input: ++ * port - Port ID ++ * state - Nway state ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port ID. ++ * Note: ++ * The API configure SGMII/HSGMII port Nway state ++ */ ++extern rtk_api_ret_t rtk_port_sgmiiNway_set(rtk_port_t port, rtk_enable_t state); ++ ++/* Function Name: ++ * rtk_port_sgmiiNway_get ++ * Description: ++ * Get SGMII/HSGMII port Nway state ++ * Input: ++ * port - Port ID ++ * Output: ++ * pState - Nway state ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port ID. ++ * Note: ++ * The API can get SGMII/HSGMII port Nway state ++ */ ++extern rtk_api_ret_t rtk_port_sgmiiNway_get(rtk_port_t port, rtk_enable_t *pState); ++ ++#endif /* __RTK_API_PORT_H__ */ ++ ++ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/include/ptp.h b/drivers/net/phy/rtk/rtl8367c/include/ptp.h +new file mode 100644 +index 000000000000..d18c4a01ed43 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/ptp.h +@@ -0,0 +1,511 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * Purpose : RTL8367/RTL8367C switch high-level API ++ * ++ * Feature : The file includes time module high-layer API definition ++ * ++ */ ++ ++#ifndef __RTK_API_PTP_H__ ++#define __RTK_API_PTP_H__ ++ ++/* ++ * Symbol Definition ++ */ ++#define RTK_MAX_NUM_OF_NANO_SECOND 0x3B9AC9FF ++#define RTK_PTP_INTR_MASK 0xFF ++#define RTK_MAX_NUM_OF_TPID 0xFFFF ++ ++/* Message Type */ ++typedef enum rtk_ptp_msgType_e ++{ ++ PTP_MSG_TYPE_TX_SYNC = 0, ++ PTP_MSG_TYPE_TX_DELAY_REQ, ++ PTP_MSG_TYPE_TX_PDELAY_REQ, ++ PTP_MSG_TYPE_TX_PDELAY_RESP, ++ PTP_MSG_TYPE_RX_SYNC, ++ PTP_MSG_TYPE_RX_DELAY_REQ, ++ PTP_MSG_TYPE_RX_PDELAY_REQ, ++ PTP_MSG_TYPE_RX_PDELAY_RESP, ++ PTP_MSG_TYPE_END ++} rtk_ptp_msgType_t; ++ ++typedef enum rtk_ptp_intType_e ++{ ++ PTP_INT_TYPE_TX_SYNC = 0, ++ PTP_INT_TYPE_TX_DELAY_REQ, ++ PTP_INT_TYPE_TX_PDELAY_REQ, ++ PTP_INT_TYPE_TX_PDELAY_RESP, ++ PTP_INT_TYPE_RX_SYNC, ++ PTP_INT_TYPE_RX_DELAY_REQ, ++ PTP_INT_TYPE_RX_PDELAY_REQ, ++ PTP_INT_TYPE_RX_PDELAY_RESP, ++ PTP_INT_TYPE_ALL, ++ PTP_INT_TYPE_END ++}rtk_ptp_intType_t; ++ ++typedef enum rtk_ptp_sys_adjust_e ++{ ++ SYS_ADJUST_PLUS = 0, ++ SYS_ADJUST_MINUS, ++ SYS_ADJUST_END ++} rtk_ptp_sys_adjust_t; ++ ++ ++/* Reference Time */ ++typedef struct rtk_ptp_timeStamp_s ++{ ++ rtk_uint32 sec; ++ rtk_uint32 nsec; ++} rtk_ptp_timeStamp_t; ++ ++typedef struct rtk_ptp_info_s ++{ ++ rtk_uint32 sequenceId; ++ rtk_ptp_timeStamp_t timeStamp; ++} rtk_ptp_info_t; ++ ++typedef rtk_uint32 rtk_ptp_tpid_t; ++ ++typedef rtk_uint32 rtk_ptp_intStatus_t; /* interrupt status mask */ ++ ++/* ++ * Data Declaration ++ */ ++ ++/* ++ * Function Declaration ++ */ ++/* Function Name: ++ * rtk_time_init ++ * Description: ++ * PTP function initialization. ++ * Input: ++ * None ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * This API is used to initialize EEE status. ++ */ ++extern rtk_api_ret_t rtk_ptp_init(void); ++ ++/* Function Name: ++ * rtk_ptp_mac_set ++ * Description: ++ * Configure PTP mac address. ++ * Input: ++ * mac - mac address to parser PTP packets. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameter. ++ * Note: ++ * None ++ */ ++extern rtk_api_ret_t rtk_ptp_mac_set(rtk_mac_t mac); ++ ++/* Function Name: ++ * rtk_ptp_mac_get ++ * Description: ++ * Get PTP mac address. ++ * Input: ++ * None ++ * Output: ++ * pMac - mac address to parser PTP packets. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameter. ++ * Note: ++ * None ++ */ ++extern rtk_api_ret_t rtk_ptp_mac_get(rtk_mac_t *pMac); ++ ++/* Function Name: ++ * rtk_ptp_tpid_set ++ * Description: ++ * Configure PTP accepted outer & inner tag TPID. ++ * Input: ++ * outerId - Ether type of S-tag frame parsing in PTP ports. ++ * innerId - Ether type of C-tag frame parsing in PTP ports. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameter. ++ * Note: ++ * None ++ */ ++extern rtk_api_ret_t rtk_ptp_tpid_set(rtk_ptp_tpid_t outerId, rtk_ptp_tpid_t innerId); ++ ++/* Function Name: ++ * rtk_ptp_tpid_get ++ * Description: ++ * Get PTP accepted outer & inner tag TPID. ++ * Input: ++ * None ++ * Output: ++ * pOuterId - Ether type of S-tag frame parsing in PTP ports. ++ * pInnerId - Ether type of C-tag frame parsing in PTP ports. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++extern rtk_api_ret_t rtk_ptp_tpid_get(rtk_ptp_tpid_t *pOuterId, rtk_ptp_tpid_t *pInnerId); ++ ++/* Function Name: ++ * rtk_ptp_refTime_set ++ * Description: ++ * Set the reference time of the specified device. ++ * Input: ++ * timeStamp - reference timestamp value ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_INPUT - invalid input parameter ++ * Applicable: ++ * 8390, 8380 ++ * Note: ++ * None ++ */ ++extern rtk_api_ret_t rtk_ptp_refTime_set(rtk_ptp_timeStamp_t timeStamp); ++ ++/* Function Name: ++ * rtk_ptp_refTime_get ++ * Description: ++ * Get the reference time of the specified device. ++ * Input: ++ * Output: ++ * pTimeStamp - pointer buffer of the reference time ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_UNIT_ID - invalid unit id ++ * RT_ERR_NOT_INIT - The module is not initial ++ * RT_ERR_NULL_POINTER - input parameter may be null pointer ++ * Applicable: ++ * 8390, 8380 ++ * Note: ++ * None ++ */ ++extern rtk_api_ret_t rtk_ptp_refTime_get(rtk_ptp_timeStamp_t *pTimeStamp); ++ ++/* Function Name: ++ * rtk_ptp_refTimeAdjust_set ++ * Description: ++ * Adjust the reference time. ++ * Input: ++ * unit - unit id ++ * sign - significant ++ * timeStamp - reference timestamp value ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_UNIT_ID - invalid unit id ++ * RT_ERR_NOT_INIT - The module is not initial ++ * RT_ERR_INPUT - invalid input parameter ++ * Note: ++ * sign=0 for positive adjustment, sign=1 for negative adjustment. ++ */ ++extern rtk_api_ret_t rtk_ptp_refTimeAdjust_set(rtk_ptp_sys_adjust_t sign, rtk_ptp_timeStamp_t timeStamp); ++ ++/* Function Name: ++ * rtk_ptp_refTimeEnable_set ++ * Description: ++ * Set the enable state of reference time of the specified device. ++ * Input: ++ * enable - status ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_INPUT - invalid input parameter ++ * Note: ++ * None ++ */ ++extern rtk_api_ret_t rtk_ptp_refTimeEnable_set(rtk_enable_t enable); ++ ++/* Function Name: ++ * rtk_ptp_refTimeEnable_get ++ * Description: ++ * Get the enable state of reference time of the specified device. ++ * Input: ++ * Output: ++ * pEnable - status ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_UNIT_ID - invalid unit id ++ * RT_ERR_NOT_INIT - The module is not initial ++ * RT_ERR_NULL_POINTER - input parameter may be null pointer ++ * Applicable: ++ * 8390, 8380 ++ * Note: ++ * None ++ */ ++extern rtk_api_ret_t rtk_ptp_refTimeEnable_get(rtk_enable_t *pEnable); ++ ++/* Function Name: ++ * rtk_ptp_portEnable_set ++ * Description: ++ * Set PTP status of the specified port. ++ * Input: ++ * port - port id ++ * enable - status ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_PORT - invalid port id ++ * RT_ERR_INPUT - invalid input parameter ++ * Note: ++ * None ++ */ ++extern rtk_api_ret_t rtk_ptp_portEnable_set(rtk_port_t port, rtk_enable_t enable); ++ ++/* Function Name: ++ * rtk_ptp_portEnable_get ++ * Description: ++ * Get PTP status of the specified port. ++ * Input: ++ * port - port id ++ * Output: ++ * pEnable - status ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_PORT - invalid port id ++ * RT_ERR_NULL_POINTER - input parameter may be null pointer ++ * Note: ++ * None ++ */ ++extern rtk_api_ret_t rtk_ptp_portEnable_get(rtk_port_t port, rtk_enable_t *pEnable); ++ ++/* Function Name: ++ * rtk_ptp_portTimestamp_get ++ * Description: ++ * Get PTP timestamp according to the PTP identifier on the dedicated port from the specified device. ++ * Input: ++ * unit - unit id ++ * port - port id ++ * type - PTP message type ++ * Output: ++ * pInfo - pointer buffer of sequence ID and timestamp ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_PORT_ID - invalid port id ++ * RT_ERR_INPUT - invalid input parameter ++ * RT_ERR_NULL_POINTER - input parameter may be null pointer ++ * Applicable: ++ * 8390, 8380 ++ * Note: ++ * None ++ */ ++extern rtk_api_ret_t rtk_ptp_portTimestamp_get( rtk_port_t port, rtk_ptp_msgType_t type, rtk_ptp_info_t *pInfo); ++ ++/* Function Name: ++ * rtk_ptp_intControl_set ++ * Description: ++ * Set PTP interrupt trigger status configuration. ++ * Input: ++ * type - Interrupt type. ++ * enable - Interrupt status. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_ENABLE - Invalid enable input. ++ * Note: ++ * The API can set PTP interrupt status configuration. ++ * The interrupt trigger status is shown in the following: ++ * PTP_INT_TYPE_TX_SYNC = 0, ++ * PTP_INT_TYPE_TX_DELAY_REQ, ++ * PTP_INT_TYPE_TX_PDELAY_REQ, ++ * PTP_INT_TYPE_TX_PDELAY_RESP, ++ * PTP_INT_TYPE_RX_SYNC, ++ * PTP_INT_TYPE_RX_DELAY_REQ, ++ * PTP_INT_TYPE_RX_PDELAY_REQ, ++ * PTP_INT_TYPE_RX_PDELAY_RESP, ++ * PTP_INT_TYPE_ALL, ++ */ ++extern rtk_api_ret_t rtk_ptp_intControl_set(rtk_ptp_intType_t type, rtk_enable_t enable); ++ ++/* Function Name: ++ * rtk_ptp_intControl_get ++ * Description: ++ * Get PTP interrupt trigger status configuration. ++ * Input: ++ * type - Interrupt type. ++ * Output: ++ * pEnable - Interrupt status. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can get interrupt status configuration. ++ * The interrupt trigger status is shown in the following: ++ * PTP_INT_TYPE_TX_SYNC = 0, ++ * PTP_INT_TYPE_TX_DELAY_REQ, ++ * PTP_INT_TYPE_TX_PDELAY_REQ, ++ * PTP_INT_TYPE_TX_PDELAY_RESP, ++ * PTP_INT_TYPE_RX_SYNC, ++ * PTP_INT_TYPE_RX_DELAY_REQ, ++ * PTP_INT_TYPE_RX_PDELAY_REQ, ++ * PTP_INT_TYPE_RX_PDELAY_RESP, ++ */ ++extern rtk_api_ret_t rtk_ptp_intControl_get(rtk_ptp_intType_t type, rtk_enable_t *pEnable); ++ ++ ++/* Function Name: ++ * rtk_ptp_intStatus_get ++ * Description: ++ * Get PTP port interrupt trigger status. ++ * Input: ++ * port - physical port ++ * Output: ++ * pStatusMask - Interrupt status bit mask. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can get interrupt trigger status when interrupt happened. ++ * The interrupt trigger status is shown in the following: ++ * - PORT 0 INT (value[0] (Bit0)) ++ * - PORT 1 INT (value[0] (Bit1)) ++ * - PORT 2 INT (value[0] (Bit2)) ++ * - PORT 3 INT (value[0] (Bit3)) ++ * - PORT 4 INT (value[0] (Bit4)) ++ ++ * ++ */ ++extern rtk_api_ret_t rtk_ptp_intStatus_get(rtk_ptp_intStatus_t *pStatusMask); ++ ++/* Function Name: ++ * rtk_ptp_portIntStatus_set ++ * Description: ++ * Set PTP port interrupt trigger status to clean. ++ * Input: ++ * port - physical port ++ * statusMask - Interrupt status bit mask. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can clean interrupt trigger status when interrupt happened. ++ * The interrupt trigger status is shown in the following: ++ * - PTP_INT_TYPE_TX_SYNC (value[0] (Bit0)) ++ * - PTP_INT_TYPE_TX_DELAY_REQ (value[0] (Bit1)) ++ * - PTP_INT_TYPE_TX_PDELAY_REQ (value[0] (Bit2)) ++ * - PTP_INT_TYPE_TX_PDELAY_RESP (value[0] (Bit3)) ++ * - PTP_INT_TYPE_RX_SYNC (value[0] (Bit4)) ++ * - PTP_INT_TYPE_RX_DELAY_REQ (value[0] (Bit5)) ++ * - PTP_INT_TYPE_RX_PDELAY_REQ (value[0] (Bit6)) ++ * - PTP_INT_TYPE_RX_PDELAY_RESP (value[0] (Bit7)) ++ * The status will be cleared after execute this API. ++ */ ++extern rtk_api_ret_t rtk_ptp_portIntStatus_set(rtk_port_t port, rtk_ptp_intStatus_t statusMask); ++ ++/* Function Name: ++ * rtk_ptp_portIntStatus_get ++ * Description: ++ * Get PTP port interrupt trigger status. ++ * Input: ++ * port - physical port ++ * Output: ++ * pStatusMask - Interrupt status bit mask. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can get interrupt trigger status when interrupt happened. ++ * The interrupt trigger status is shown in the following: ++ * - PTP_INT_TYPE_TX_SYNC (value[0] (Bit0)) ++ * - PTP_INT_TYPE_TX_DELAY_REQ (value[0] (Bit1)) ++ * - PTP_INT_TYPE_TX_PDELAY_REQ (value[0] (Bit2)) ++ * - PTP_INT_TYPE_TX_PDELAY_RESP (value[0] (Bit3)) ++ * - PTP_INT_TYPE_RX_SYNC (value[0] (Bit4)) ++ * - PTP_INT_TYPE_RX_DELAY_REQ (value[0] (Bit5)) ++ * - PTP_INT_TYPE_RX_PDELAY_REQ (value[0] (Bit6)) ++ * - PTP_INT_TYPE_RX_PDELAY_RESP (value[0] (Bit7)) ++ * ++ */ ++extern rtk_api_ret_t rtk_ptp_portIntStatus_get(rtk_port_t port, rtk_ptp_intStatus_t *pStatusMask); ++ ++/* Function Name: ++ * rtk_ptp_portPtpTrap_set ++ * Description: ++ * Set PTP packet trap of the specified port. ++ * Input: ++ * port - port id ++ * enable - status ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_PORT - invalid port id ++ * RT_ERR_INPUT - invalid input parameter ++ * Note: ++ * None ++ */ ++extern rtk_api_ret_t rtk_ptp_portTrap_set(rtk_port_t port, rtk_enable_t enable); ++ ++/* Function Name: ++ * rtk_ptp_portPtpEnable_get ++ * Description: ++ * Get PTP packet trap of the specified port. ++ * Input: ++ * port - port id ++ * Output: ++ * pEnable - status ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_PORT - invalid port id ++ * RT_ERR_NULL_POINTER - input parameter may be null pointer ++ * Note: ++ * None ++ */ ++extern rtk_api_ret_t rtk_ptp_portTrap_get(rtk_port_t port, rtk_enable_t *pEnable); ++ ++#endif /* __RTK_API_PTP_H__ */ +diff --git a/drivers/net/phy/rtk/rtl8367c/include/qos.h b/drivers/net/phy/rtk/rtl8367c/include/qos.h +new file mode 100644 +index 000000000000..d2d8fac24a23 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/qos.h +@@ -0,0 +1,781 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * Purpose : RTL8367/RTL8367C switch high-level API ++ * ++ * Feature : The file includes QoS module high-layer API definition ++ * ++ */ ++ ++#ifndef __RTK_API_QOS_H__ ++#define __RTK_API_QOS_H__ ++ ++/* ++ * Data Type Declaration ++ */ ++#define QOS_DEFAULT_TICK_PERIOD (19-1) ++#define QOS_DEFAULT_BYTE_PER_TOKEN 34 ++#define QOS_DEFAULT_LK_THRESHOLD (34*3) /* Why use 0x400? */ ++ ++ ++#define QOS_DEFAULT_INGRESS_BANDWIDTH 0x3FFF /* 0x3FFF => unlimit */ ++#define QOS_DEFAULT_EGRESS_BANDWIDTH 0x3D08 /*( 0x3D08 + 1) * 64Kbps => 1Gbps*/ ++#define QOS_DEFAULT_PREIFP 1 ++#define QOS_DEFAULT_PACKET_USED_PAGES_FC 0x60 ++#define QOS_DEFAULT_PACKET_USED_FC_EN 0 ++#define QOS_DEFAULT_QUEUE_BASED_FC_EN 1 ++ ++#define QOS_DEFAULT_PRIORITY_SELECT_PORT 8 ++#define QOS_DEFAULT_PRIORITY_SELECT_1Q 0 ++#define QOS_DEFAULT_PRIORITY_SELECT_ACL 0 ++#define QOS_DEFAULT_PRIORITY_SELECT_DSCP 0 ++ ++#define QOS_DEFAULT_DSCP_MAPPING_PRIORITY 0 ++ ++#define QOS_DEFAULT_1Q_REMARKING_ABILITY 0 ++#define QOS_DEFAULT_DSCP_REMARKING_ABILITY 0 ++#define QOS_DEFAULT_QUEUE_GAP 20 ++#define QOS_DEFAULT_QUEUE_NO_MAX 6 ++#define QOS_DEFAULT_AVERAGE_PACKET_RATE 0x3FFF ++#define QOS_DEFAULT_BURST_SIZE_IN_APR 0x3F ++#define QOS_DEFAULT_PEAK_PACKET_RATE 2 ++#define QOS_DEFAULT_SCHEDULER_ABILITY_APR 1 /*disable*/ ++#define QOS_DEFAULT_SCHEDULER_ABILITY_PPR 1 /*disable*/ ++#define QOS_DEFAULT_SCHEDULER_ABILITY_WFQ 1 /*disable*/ ++ ++#define QOS_WEIGHT_MAX 127 ++ ++#define RTK_MAX_NUM_OF_PRIORITY 8 ++#define RTK_MAX_NUM_OF_QUEUE 8 ++ ++#define RTK_PRIMAX 7 ++#define RTK_QIDMAX 7 ++#define RTK_DSCPMAX 63 ++ ++ ++/* enum Priority Selection Index */ ++typedef enum rtk_qos_priDecTbl_e ++{ ++ PRIDECTBL_IDX0 = 0, ++ PRIDECTBL_IDX1, ++ PRIDECTBL_END, ++}rtk_qos_priDecTbl_t; ++ ++ ++/* Types of 802.1p remarking source */ ++typedef enum rtk_qos_1pRmkSrc_e ++{ ++ DOT1P_RMK_SRC_USER_PRI, ++ DOT1P_RMK_SRC_TAG_PRI, ++ DOT1P_RMK_SRC_END ++} rtk_qos_1pRmkSrc_t; ++ ++ ++/* Types of DSCP remarking source */ ++typedef enum rtk_qos_dscpRmkSrc_e ++{ ++ DSCP_RMK_SRC_INT_PRI, ++ DSCP_RMK_SRC_DSCP, ++ DSCP_RMK_SRC_USER_PRI, ++ DSCP_RMK_SRC_END ++} rtk_qos_dscpRmkSrc_t; ++ ++ ++ ++ ++typedef struct rtk_priority_select_s ++{ ++ rtk_uint32 port_pri; ++ rtk_uint32 dot1q_pri; ++ rtk_uint32 acl_pri; ++ rtk_uint32 dscp_pri; ++ rtk_uint32 cvlan_pri; ++ rtk_uint32 svlan_pri; ++ rtk_uint32 dmac_pri; ++ rtk_uint32 smac_pri; ++} rtk_priority_select_t; ++ ++typedef struct rtk_qos_pri2queue_s ++{ ++ rtk_uint32 pri2queue[RTK_MAX_NUM_OF_PRIORITY]; ++} rtk_qos_pri2queue_t; ++ ++typedef struct rtk_qos_queue_weights_s ++{ ++ rtk_uint32 weights[RTK_MAX_NUM_OF_QUEUE]; ++} rtk_qos_queue_weights_t; ++ ++typedef enum rtk_qos_scheduling_type_e ++{ ++ WFQ = 0, /* Weighted-Fair-Queue */ ++ WRR, /* Weighted-Round-Robin */ ++ SCHEDULING_TYPE_END ++} rtk_qos_scheduling_type_t; ++ ++typedef rtk_uint32 rtk_queue_num_t; /* queue number*/ ++ ++/* Function Name: ++ * rtk_qos_init ++ * Description: ++ * Configure QoS default settings with queue number assignment to each port. ++ * Input: ++ * queueNum - Queue number of each port. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_QUEUE_NUM - Invalid queue number. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * This API will initialize related QoS setting with queue number assignment. ++ * The queue number is from 1 to 8. ++ */ ++extern rtk_api_ret_t rtk_qos_init(rtk_queue_num_t queueNum); ++ ++/* Function Name: ++ * rtk_qos_priSel_set ++ * Description: ++ * Configure the priority order among different priority mechanism. ++ * Input: ++ * index - Priority decision table index (0~1) ++ * pPriDec - Priority assign for port, dscp, 802.1p, cvlan, svlan, acl based priority decision. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_QOS_SEL_PRI_SOURCE - Invalid priority decision source parameter. ++ * Note: ++ * ASIC will follow user priority setting of mechanisms to select mapped queue priority for receiving frame. ++ * If two priority mechanisms are the same, the ASIC will chose the highest priority from mechanisms to ++ * assign queue priority to receiving frame. ++ * The priority sources are: ++ * - PRIDEC_PORT ++ * - PRIDEC_ACL ++ * - PRIDEC_DSCP ++ * - PRIDEC_1Q ++ * - PRIDEC_1AD ++ * - PRIDEC_CVLAN ++ * - PRIDEC_DA ++ * - PRIDEC_SA ++ */ ++extern rtk_api_ret_t rtk_qos_priSel_set(rtk_qos_priDecTbl_t index, rtk_priority_select_t *pPriDec); ++ ++ ++/* Function Name: ++ * rtk_qos_priSel_get ++ * Description: ++ * Get the priority order configuration among different priority mechanism. ++ * Input: ++ * index - Priority decision table index (0~1) ++ * Output: ++ * pPriDec - Priority assign for port, dscp, 802.1p, cvlan, svlan, acl based priority decision . ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * ASIC will follow user priority setting of mechanisms to select mapped queue priority for receiving frame. ++ * If two priority mechanisms are the same, the ASIC will chose the highest priority from mechanisms to ++ * assign queue priority to receiving frame. ++ * The priority sources are: ++ * - PRIDEC_PORT, ++ * - PRIDEC_ACL, ++ * - PRIDEC_DSCP, ++ * - PRIDEC_1Q, ++ * - PRIDEC_1AD, ++ * - PRIDEC_CVLAN, ++ * - PRIDEC_DA, ++ * - PRIDEC_SA, ++ */ ++extern rtk_api_ret_t rtk_qos_priSel_get(rtk_qos_priDecTbl_t index, rtk_priority_select_t *pPriDec); ++ ++/* Function Name: ++ * rtk_qos_1pPriRemap_set ++ * Description: ++ * Configure 1Q priorities mapping to internal absolute priority. ++ * Input: ++ * dot1p_pri - 802.1p priority value. ++ * int_pri - internal priority value. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_VLAN_PRIORITY - Invalid 1p priority. ++ * RT_ERR_QOS_INT_PRIORITY - Invalid priority. ++ * Note: ++ * Priority of 802.1Q assignment for internal asic priority, and it is used for queue usage and packet scheduling. ++ */ ++extern rtk_api_ret_t rtk_qos_1pPriRemap_set(rtk_pri_t dot1p_pri, rtk_pri_t int_pri); ++ ++/* Function Name: ++ * rtk_qos_1pPriRemap_get ++ * Description: ++ * Get 1Q priorities mapping to internal absolute priority. ++ * Input: ++ * dot1p_pri - 802.1p priority value . ++ * Output: ++ * pInt_pri - internal priority value. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_VLAN_PRIORITY - Invalid priority. ++ * RT_ERR_QOS_INT_PRIORITY - Invalid priority. ++ * Note: ++ * Priority of 802.1Q assignment for internal asic priority, and it is used for queue usage and packet scheduling. ++ */ ++extern rtk_api_ret_t rtk_qos_1pPriRemap_get(rtk_pri_t dot1p_pri, rtk_pri_t *pInt_pri); ++ ++ ++/* Function Name: ++ * rtk_qos_1pRemarkSrcSel_set ++ * Description: ++ * Set remarking source of 802.1p remarking. ++ * Input: ++ * type - remarking source ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_NOT_INIT - The module is not initial ++ * RT_ERR_PORT_ID - invalid port id ++ * RT_ERR_INPUT - invalid input parameter ++ ++ * Note: ++ * The API can configure 802.1p remark functionality to map original 802.1p value or internal ++ * priority to TX DSCP value. ++ */ ++extern rtk_api_ret_t rtk_qos_1pRemarkSrcSel_set(rtk_qos_1pRmkSrc_t type); ++ ++/* Function Name: ++ * rtk_qos_1pRemarkSrcSel_get ++ * Description: ++ * Get remarking source of 802.1p remarking. ++ * Input: ++ * none ++ * Output: ++ * pType - remarking source ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_NOT_INIT - The module is not initial ++ * RT_ERR_PORT_ID - invalid port id ++ * RT_ERR_INPUT - invalid input parameter ++ * RT_ERR_NULL_POINTER - input parameter may be null pointer ++ ++ * Note: ++ * None ++ */ ++extern rtk_api_ret_t rtk_qos_1pRemarkSrcSel_get(rtk_qos_1pRmkSrc_t *pType); ++ ++/* Function Name: ++ * rtk_qos_dscpPriRemap_set ++ * Description: ++ * Map dscp value to internal priority. ++ * Input: ++ * dscp - Dscp value of receiving frame ++ * int_pri - internal priority value . ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_QOS_DSCP_VALUE - Invalid DSCP value. ++ * RT_ERR_QOS_INT_PRIORITY - Invalid priority. ++ * Note: ++ * The Differentiated Service Code Point is a selector for router's per-hop behaviors. As a selector, there is no implication that a numerically ++ * greater DSCP implies a better network service. As can be seen, the DSCP totally overlaps the old precedence field of TOS. So if values of ++ * DSCP are carefully chosen then backward compatibility can be achieved. ++ */ ++extern rtk_api_ret_t rtk_qos_dscpPriRemap_set(rtk_dscp_t dscp, rtk_pri_t int_pri); ++ ++/* Function Name: ++ * rtk_qos_dscpPriRemap_get ++ * Description: ++ * Get dscp value to internal priority. ++ * Input: ++ * dscp - Dscp value of receiving frame ++ * Output: ++ * pInt_pri - internal priority value. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_QOS_DSCP_VALUE - Invalid DSCP value. ++ * Note: ++ * The Differentiated Service Code Point is a selector for router's per-hop behaviors. As a selector, there is no implication that a numerically ++ * greater DSCP implies a better network service. As can be seen, the DSCP totally overlaps the old precedence field of TOS. So if values of ++ * DSCP are carefully chosen then backward compatibility can be achieved. ++ */ ++extern rtk_api_ret_t rtk_qos_dscpPriRemap_get(rtk_dscp_t dscp, rtk_pri_t *pInt_pri); ++ ++/* Function Name: ++ * rtk_qos_portPri_set ++ * Description: ++ * Configure priority usage to each port. ++ * Input: ++ * port - Port id. ++ * int_pri - internal priority value. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_QOS_SEL_PORT_PRI - Invalid port priority. ++ * RT_ERR_QOS_INT_PRIORITY - Invalid priority. ++ * Note: ++ * The API can set priority of port assignments for queue usage and packet scheduling. ++ */ ++extern rtk_api_ret_t rtk_qos_portPri_set(rtk_port_t port, rtk_pri_t int_pri) ; ++ ++/* Function Name: ++ * rtk_qos_portPri_get ++ * Description: ++ * Get priority usage to each port. ++ * Input: ++ * port - Port id. ++ * Output: ++ * pInt_pri - internal priority value. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can get priority of port assignments for queue usage and packet scheduling. ++ */ ++extern rtk_api_ret_t rtk_qos_portPri_get(rtk_port_t port, rtk_pri_t *pInt_pri) ; ++ ++/* Function Name: ++ * rtk_qos_queueNum_set ++ * Description: ++ * Set output queue number for each port. ++ * Input: ++ * port - Port id. ++ * index - Mapping queue number (1~8) ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_QUEUE_NUM - Invalid queue number. ++ * Note: ++ * The API can set the output queue number of the specified port. The queue number is from 1 to 8. ++ */ ++extern rtk_api_ret_t rtk_qos_queueNum_set(rtk_port_t port, rtk_queue_num_t queue_num); ++ ++/* Function Name: ++ * rtk_qos_queueNum_get ++ * Description: ++ * Get output queue number. ++ * Input: ++ * port - Port id. ++ * Output: ++ * pQueue_num - Mapping queue number ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * The API will return the output queue number of the specified port. The queue number is from 1 to 8. ++ */ ++extern rtk_api_ret_t rtk_qos_queueNum_get(rtk_port_t port, rtk_queue_num_t *pQueue_num); ++ ++/* Function Name: ++ * rtk_qos_priMap_set ++ * Description: ++ * Set output queue number for each port. ++ * Input: ++ * queue_num - Queue number usage. ++ * pPri2qid - Priority mapping to queue ID. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_QUEUE_NUM - Invalid queue number. ++ * RT_ERR_QUEUE_ID - Invalid queue id. ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_QOS_INT_PRIORITY - Invalid priority. ++ * Note: ++ * ASIC supports priority mapping to queue with different queue number from 1 to 8. ++ * For different queue numbers usage, ASIC supports different internal available queue IDs. ++ */ ++extern rtk_api_ret_t rtk_qos_priMap_set(rtk_queue_num_t queue_num, rtk_qos_pri2queue_t *pPri2qid); ++ ++ ++/* Function Name: ++ * rtk_qos_priMap_get ++ * Description: ++ * Get priority to queue ID mapping table parameters. ++ * Input: ++ * queue_num - Queue number usage. ++ * Output: ++ * pPri2qid - Priority mapping to queue ID. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_QUEUE_NUM - Invalid queue number. ++ * Note: ++ * The API can return the mapping queue id of the specified priority and queue number. ++ * The queue number is from 1 to 8. ++ */ ++extern rtk_api_ret_t rtk_qos_priMap_get(rtk_queue_num_t queue_num, rtk_qos_pri2queue_t *pPri2qid); ++ ++/* Function Name: ++ * rtk_qos_schedulingQueue_set ++ * Description: ++ * Set weight and type of queues in dedicated port. ++ * Input: ++ * port - Port id. ++ * pQweights - The array of weights for WRR/WFQ queue (0 for STRICT_PRIORITY queue). ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_QOS_QUEUE_WEIGHT - Invalid queue weight. ++ * Note: ++ * The API can set weight and type, strict priority or weight fair queue (WFQ) for ++ * dedicated port for using queues. If queue id is not included in queue usage, ++ * then its type and weight setting in dummy for setting. There are priorities ++ * as queue id in strict queues. It means strict queue id 5 carrying higher priority ++ * than strict queue id 4. The WFQ queue weight is from 1 to 128, and weight 0 is ++ * for strict priority queue type. ++ */ ++extern rtk_api_ret_t rtk_qos_schedulingQueue_set(rtk_port_t port, rtk_qos_queue_weights_t *pQweights); ++ ++/* Function Name: ++ * rtk_qos_schedulingQueue_get ++ * Description: ++ * Get weight and type of queues in dedicated port. ++ * Input: ++ * port - Port id. ++ * Output: ++ * pQweights - The array of weights for WRR/WFQ queue (0 for STRICT_PRIORITY queue). ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * The API can get weight and type, strict priority or weight fair queue (WFQ) for dedicated port for using queues. ++ * The WFQ queue weight is from 1 to 128, and weight 0 is for strict priority queue type. ++ */ ++extern rtk_api_ret_t rtk_qos_schedulingQueue_get(rtk_port_t port, rtk_qos_queue_weights_t *pQweights); ++ ++/* Function Name: ++ * rtk_qos_1pRemarkEnable_set ++ * Description: ++ * Set 1p Remarking state ++ * Input: ++ * port - Port id. ++ * enable - State of per-port 1p Remarking ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_ENABLE - Invalid enable parameter. ++ * Note: ++ * The API can enable or disable 802.1p remarking ability for whole system. ++ * The status of 802.1p remark: ++ * - DISABLED ++ * - ENABLED ++ */ ++extern rtk_api_ret_t rtk_qos_1pRemarkEnable_set(rtk_port_t port, rtk_enable_t enable); ++ ++/* Function Name: ++ * rtk_qos_1pRemarkEnable_get ++ * Description: ++ * Get 802.1p remarking ability. ++ * Input: ++ * port - Port id. ++ * Output: ++ * pEnable - Status of 802.1p remark. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * The API can get 802.1p remarking ability. ++ * The status of 802.1p remark: ++ * - DISABLED ++ * - ENABLED ++ */ ++extern rtk_api_ret_t rtk_qos_1pRemarkEnable_get(rtk_port_t port, rtk_enable_t *pEnable); ++ ++/* Function Name: ++ * rtk_qos_1pRemark_set ++ * Description: ++ * Set 802.1p remarking parameter. ++ * Input: ++ * int_pri - Internal priority value. ++ * dot1p_pri - 802.1p priority value. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_VLAN_PRIORITY - Invalid 1p priority. ++ * RT_ERR_QOS_INT_PRIORITY - Invalid priority. ++ * Note: ++ * The API can set 802.1p parameters source priority and new priority. ++ */ ++extern rtk_api_ret_t rtk_qos_1pRemark_set(rtk_pri_t int_pri, rtk_pri_t dot1p_pri); ++ ++/* Function Name: ++ * rtk_qos_1pRemark_get ++ * Description: ++ * Get 802.1p remarking parameter. ++ * Input: ++ * int_pri - Internal priority value. ++ * Output: ++ * pDot1p_pri - 802.1p priority value. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_QOS_INT_PRIORITY - Invalid priority. ++ * Note: ++ * The API can get 802.1p remarking parameters. It would return new priority of ingress priority. ++ */ ++extern rtk_api_ret_t rtk_qos_1pRemark_get(rtk_pri_t int_pri, rtk_pri_t *pDot1p_pri); ++ ++/* Function Name: ++ * rtk_qos_dscpRemarkEnable_set ++ * Description: ++ * Set DSCP remarking ability. ++ * Input: ++ * port - Port id. ++ * enable - status of DSCP remark. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_QOS_INT_PRIORITY - Invalid priority. ++ * RT_ERR_ENABLE - Invalid enable parameter. ++ * Note: ++ * The API can enable or disable DSCP remarking ability for whole system. ++ * The status of DSCP remark: ++ * - DISABLED ++ * - ENABLED ++ */ ++extern rtk_api_ret_t rtk_qos_dscpRemarkEnable_set(rtk_port_t port, rtk_enable_t enable); ++ ++/* Function Name: ++ * rtk_qos_dscpRemarkEnable_get ++ * Description: ++ * Get DSCP remarking ability. ++ * Input: ++ * port - Port id. ++ * Output: ++ * pEnable - status of DSCP remarking. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * The API can get DSCP remarking ability. ++ * The status of DSCP remark: ++ * - DISABLED ++ * - ENABLED ++ */ ++extern rtk_api_ret_t rtk_qos_dscpRemarkEnable_get(rtk_port_t port, rtk_enable_t *pEnable); ++ ++/* Function Name: ++ * rtk_qos_dscpRemark_set ++ * Description: ++ * Set DSCP remarking parameter. ++ * Input: ++ * int_pri - Internal priority value. ++ * dscp - DSCP value. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_QOS_INT_PRIORITY - Invalid priority. ++ * RT_ERR_QOS_DSCP_VALUE - Invalid DSCP value. ++ * Note: ++ * The API can set DSCP value and mapping priority. ++ */ ++extern rtk_api_ret_t rtk_qos_dscpRemark_set(rtk_pri_t int_pri, rtk_dscp_t dscp); ++ ++/* Function Name: ++ * rtk_qos_dscpRemark_get ++ * Description: ++ * Get DSCP remarking parameter. ++ * Input: ++ * int_pri - Internal priority value. ++ * Output: ++ * Dscp - DSCP value. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_QOS_INT_PRIORITY - Invalid priority. ++ * Note: ++ * The API can get DSCP parameters. It would return DSCP value for mapping priority. ++ */ ++extern rtk_api_ret_t rtk_qos_dscpRemark_get(rtk_pri_t int_pri, rtk_dscp_t *pDscp); ++ ++/* Function Name: ++ * rtk_qos_dscpRemarkSrcSel_set ++ * Description: ++ * Set remarking source of DSCP remarking. ++ * Input: ++ * type - remarking source ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_NOT_INIT - The module is not initial ++ * RT_ERR_PORT_ID - invalid port id ++ * RT_ERR_INPUT - invalid input parameter ++ ++ * Note: ++ * The API can configure DSCP remark functionality to map original DSCP value or internal ++ * priority to TX DSCP value. ++ */ ++extern rtk_api_ret_t rtk_qos_dscpRemarkSrcSel_set(rtk_qos_dscpRmkSrc_t type); ++ ++ ++/* Function Name: ++ * rtk_qos_dcpRemarkSrcSel_get ++ * Description: ++ * Get remarking source of DSCP remarking. ++ * Input: ++ * none ++ * Output: ++ * pType - remarking source ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_NOT_INIT - The module is not initial ++ * RT_ERR_PORT_ID - invalid port id ++ * RT_ERR_INPUT - invalid input parameter ++ * RT_ERR_NULL_POINTER - input parameter may be null pointer ++ ++ * Note: ++ * None ++ */ ++extern rtk_api_ret_t rtk_qos_dscpRemarkSrcSel_get(rtk_qos_dscpRmkSrc_t *pType); ++ ++ ++/* Function Name: ++ * rtk_qos_dscpRemark2Dscp_set ++ * Description: ++ * Set DSCP to remarked DSCP mapping. ++ * Input: ++ * dscp - DSCP value ++ * rmkDscp - remarked DSCP value ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_QOS_DSCP_VALUE - Invalid dscp value ++ * Note: ++ * dscp parameter can be DSCP value or internal priority according to configuration of API ++ * dal_apollomp_qos_dscpRemarkSrcSel_set(), because DSCP remark functionality can map original DSCP ++ * value or internal priority to TX DSCP value. ++ */ ++extern rtk_api_ret_t rtk_qos_dscpRemark2Dscp_set(rtk_dscp_t dscp, rtk_dscp_t rmkDscp); ++ ++/* Function Name: ++ * rtk_qos_dscpRemark2Dscp_get ++ * Description: ++ * Get DSCP to remarked DSCP mapping. ++ * Input: ++ * dscp - DSCP value ++ * Output: ++ * pDscp - remarked DSCP value ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_QOS_DSCP_VALUE - Invalid dscp value ++ * RT_ERR_NULL_POINTER - NULL pointer ++ * Note: ++ * None. ++ */ ++extern rtk_api_ret_t rtk_qos_dscpRemark2Dscp_get(rtk_dscp_t dscp, rtk_dscp_t *pDscp); ++ ++/* Function Name: ++ * rtk_qos_portPriSelIndex_set ++ * Description: ++ * Configure priority decision index to each port. ++ * Input: ++ * port - Port id. ++ * index - priority decision index. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_ENTRY_INDEX - Invalid entry index. ++ * Note: ++ * The API can set priority of port assignments for queue usage and packet scheduling. ++ */ ++extern rtk_api_ret_t rtk_qos_portPriSelIndex_set(rtk_port_t port, rtk_qos_priDecTbl_t index); ++ ++/* Function Name: ++ * rtk_qos_portPriSelIndex_get ++ * Description: ++ * Get priority decision index from each port. ++ * Input: ++ * port - Port id. ++ * Output: ++ * pIndex - priority decision index. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * The API can get priority of port assignments for queue usage and packet scheduling. ++ */ ++extern rtk_api_ret_t rtk_qos_portPriSelIndex_get(rtk_port_t port, rtk_qos_priDecTbl_t *pIndex); ++ ++#endif /* __RTK_API_QOS_H__ */ +diff --git a/drivers/net/phy/rtk/rtl8367c/include/rate.h b/drivers/net/phy/rtk/rtl8367c/include/rate.h +new file mode 100644 +index 000000000000..b3cdf432f747 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/rate.h +@@ -0,0 +1,305 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * Purpose : RTL8367/RTL8367C switch high-level API ++ * ++ * Feature : The file includes rate module high-layer API definition ++ * ++ */ ++ ++#ifndef __RTK_API_RATE_H__ ++#define __RTK_API_RATE_H__ ++ ++/* ++ * Include Files ++ */ ++//#include ++ ++/* ++ * Data Type Declaration ++ */ ++#define RTK_MAX_METER_ID (rtk_switch_maxMeterId_get()) ++#define RTK_METER_NUM (RTK_MAX_METER_ID + 1) ++ ++typedef enum rtk_meter_type_e{ ++ METER_TYPE_KBPS = 0, /* Kbps */ ++ METER_TYPE_PPS, /* Packet per second */ ++ METER_TYPE_END ++}rtk_meter_type_t; ++ ++ ++/* ++ * Function Declaration ++ */ ++ ++ /* Rate */ ++/* Function Name: ++ * rtk_rate_shareMeter_set ++ * Description: ++ * Set meter configuration ++ * Input: ++ * index - shared meter index ++ * type - shared meter type ++ * rate - rate of share meter ++ * ifg_include - include IFG or not, ENABLE:include DISABLE:exclude ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_FILTER_METER_ID - Invalid meter ++ * RT_ERR_RATE - Invalid rate ++ * RT_ERR_INPUT - Invalid input parameters ++ * Note: ++ * The API can set shared meter rate and ifg include for each meter. ++ * The rate unit is 1 kbps and the range is from 8k to 1048568k if type is METER_TYPE_KBPS and ++ * the granularity of rate is 8 kbps. ++ * The rate unit is packets per second and the range is 1 ~ 0x1FFF if type is METER_TYPE_PPS. ++ * The ifg_include parameter is used ++ * for rate calculation with/without inter-frame-gap and preamble. ++ */ ++rtk_api_ret_t rtk_rate_shareMeter_set(rtk_meter_id_t index, rtk_meter_type_t type, rtk_rate_t rate, rtk_enable_t ifg_include); ++ ++/* Function Name: ++ * rtk_rate_shareMeter_get ++ * Description: ++ * Get meter configuration ++ * Input: ++ * index - shared meter index ++ * Output: ++ * pType - Meter Type ++ * pRate - pointer of rate of share meter ++ * pIfg_include - include IFG or not, ENABLE:include DISABLE:exclude ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_FILTER_METER_ID - Invalid meter ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_rate_shareMeter_get(rtk_meter_id_t index, rtk_meter_type_t *pType, rtk_rate_t *pRate, rtk_enable_t *pIfg_include); ++ ++/* Function Name: ++ * rtk_rate_shareMeterBucket_set ++ * Description: ++ * Set meter Bucket Size ++ * Input: ++ * index - shared meter index ++ * bucket_size - Bucket Size ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_INPUT - Error Input ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_FILTER_METER_ID - Invalid meter ++ * Note: ++ * The API can set shared meter bucket size. ++ */ ++extern rtk_api_ret_t rtk_rate_shareMeterBucket_set(rtk_meter_id_t index, rtk_uint32 bucket_size); ++ ++/* Function Name: ++ * rtk_rate_shareMeterBucket_get ++ * Description: ++ * Get meter Bucket Size ++ * Input: ++ * index - shared meter index ++ * Output: ++ * pBucket_size - Bucket Size ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_FILTER_METER_ID - Invalid meter ++ * Note: ++ * The API can get shared meter bucket size. ++ */ ++extern rtk_api_ret_t rtk_rate_shareMeterBucket_get(rtk_meter_id_t index, rtk_uint32 *pBucket_size); ++ ++/* Function Name: ++ * rtk_rate_igrBandwidthCtrlRate_set ++ * Description: ++ * Set port ingress bandwidth control ++ * Input: ++ * port - Port id ++ * rate - Rate of share meter ++ * ifg_include - include IFG or not, ENABLE:include DISABLE:exclude ++ * fc_enable - enable flow control or not, ENABLE:use flow control DISABLE:drop ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_ENABLE - Invalid IFG parameter. ++ * RT_ERR_INBW_RATE - Invalid ingress rate parameter. ++ * Note: ++ * The rate unit is 1 kbps and the range is from 8k to 1048568k. The granularity of rate is 8 kbps. ++ * The ifg_include parameter is used for rate calculation with/without inter-frame-gap and preamble. ++ */ ++extern rtk_api_ret_t rtk_rate_igrBandwidthCtrlRate_set( rtk_port_t port, rtk_rate_t rate, rtk_enable_t ifg_include, rtk_enable_t fc_enable); ++ ++/* Function Name: ++ * rtk_rate_igrBandwidthCtrlRate_get ++ * Description: ++ * Get port ingress bandwidth control ++ * Input: ++ * port - Port id ++ * Output: ++ * pRate - Rate of share meter ++ * pIfg_include - Rate's calculation including IFG, ENABLE:include DISABLE:exclude ++ * pFc_enable - enable flow control or not, ENABLE:use flow control DISABLE:drop ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The rate unit is 1 kbps and the range is from 8k to 1048568k. The granularity of rate is 8 kbps. ++ * The ifg_include parameter is used for rate calculation with/without inter-frame-gap and preamble. ++ */ ++extern rtk_api_ret_t rtk_rate_igrBandwidthCtrlRate_get(rtk_port_t port, rtk_rate_t *pRate, rtk_enable_t *pIfg_include, rtk_enable_t *pFc_enable); ++ ++/* Function Name: ++ * rtk_rate_egrBandwidthCtrlRate_set ++ * Description: ++ * Set port egress bandwidth control ++ * Input: ++ * port - Port id ++ * rate - Rate of egress bandwidth ++ * ifg_include - include IFG or not, ENABLE:include DISABLE:exclude ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_QOS_EBW_RATE - Invalid egress bandwidth/rate ++ * Note: ++ * The rate unit is 1 kbps and the range is from 8k to 1048568k. The granularity of rate is 8 kbps. ++ * The ifg_include parameter is used for rate calculation with/without inter-frame-gap and preamble. ++ */ ++extern rtk_api_ret_t rtk_rate_egrBandwidthCtrlRate_set(rtk_port_t port, rtk_rate_t rate, rtk_enable_t ifg_includ); ++ ++/* Function Name: ++ * rtk_rate_egrBandwidthCtrlRate_get ++ * Description: ++ * Get port egress bandwidth control ++ * Input: ++ * port - Port id ++ * Output: ++ * pRate - Rate of egress bandwidth ++ * pIfg_include - Rate's calculation including IFG, ENABLE:include DISABLE:exclude ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The rate unit is 1 kbps and the range is from 8k to 1048568k. The granularity of rate is 8 kbps. ++ * The ifg_include parameter is used for rate calculation with/without inter-frame-gap and preamble. ++ */ ++extern rtk_api_ret_t rtk_rate_egrBandwidthCtrlRate_get(rtk_port_t port, rtk_rate_t *pRate, rtk_enable_t *pIfg_include); ++ ++/* Function Name: ++ * rtk_rate_egrQueueBwCtrlEnable_set ++ * Description: ++ * Set enable status of egress bandwidth control on specified queue. ++ * Input: ++ * port - port id ++ * queue - queue id ++ * enable - enable status of egress queue bandwidth control ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_PORT_ID - invalid port id ++ * RT_ERR_QUEUE_ID - invalid queue id ++ * RT_ERR_INPUT - invalid input parameter ++ * Note: ++ * None ++ */ ++extern rtk_api_ret_t rtk_rate_egrQueueBwCtrlEnable_set(rtk_port_t port, rtk_qid_t queue, rtk_enable_t enable); ++ ++/* Function Name: ++ * rtk_rate_egrQueueBwCtrlRate_get ++ * Description: ++ * Get rate of egress bandwidth control on specified queue. ++ * Input: ++ * port - port id ++ * queue - queue id ++ * pIndex - shared meter index ++ * Output: ++ * pRate - pointer to rate of egress queue bandwidth control ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_PORT_ID - invalid port id ++ * RT_ERR_QUEUE_ID - invalid queue id ++ * RT_ERR_FILTER_METER_ID - Invalid meter id ++ * Note: ++ * None. ++ */ ++extern rtk_api_ret_t rtk_rate_egrQueueBwCtrlEnable_get(rtk_port_t port, rtk_qid_t queue, rtk_enable_t *pEnable); ++ ++/* Function Name: ++ * rtk_rate_egrQueueBwCtrlRate_set ++ * Description: ++ * Set rate of egress bandwidth control on specified queue. ++ * Input: ++ * port - port id ++ * queue - queue id ++ * index - shared meter index ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_PORT_ID - invalid port id ++ * RT_ERR_QUEUE_ID - invalid queue id ++ * RT_ERR_FILTER_METER_ID - Invalid meter id ++ * Note: ++ * The actual rate control is set in shared meters. ++ * The unit of granularity is 8Kbps. ++ */ ++extern rtk_api_ret_t rtk_rate_egrQueueBwCtrlRate_set(rtk_port_t port, rtk_qid_t queue, rtk_meter_id_t index); ++ ++/* Function Name: ++ * rtk_rate_egrQueueBwCtrlRate_get ++ * Description: ++ * Get rate of egress bandwidth control on specified queue. ++ * Input: ++ * port - port id ++ * queue - queue id ++ * pIndex - shared meter index ++ * Output: ++ * pRate - pointer to rate of egress queue bandwidth control ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_PORT_ID - invalid port id ++ * RT_ERR_QUEUE_ID - invalid queue id ++ * RT_ERR_FILTER_METER_ID - Invalid meter id ++ * Note: ++ * The actual rate control is set in shared meters. ++ * The unit of granularity is 8Kbps. ++ */ ++extern rtk_api_ret_t rtk_rate_egrQueueBwCtrlRate_get(rtk_port_t port, rtk_qid_t queue, rtk_meter_id_t *pIndex); ++ ++#endif /* __RTK_API_RATE_H__ */ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/include/rldp.h b/drivers/net/phy/rtk/rtl8367c/include/rldp.h +new file mode 100644 +index 000000000000..111de0c09377 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/rldp.h +@@ -0,0 +1,264 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (¶g¤T, 08 ¤T¤ë 2017) $ ++ * ++ * Purpose : Declaration of RLDP and RLPP API ++ * ++ * Feature : The file have include the following module and sub-modules ++ * 1) RLDP and RLPP configuration and status ++ * ++ */ ++ ++ ++#ifndef __RTK_RLDP_H__ ++#define __RTK_RLDP_H__ ++ ++ ++/* ++ * Include Files ++ */ ++ ++ ++/* ++ * Symbol Definition ++ */ ++typedef enum rtk_rldp_trigger_e ++{ ++ RTK_RLDP_TRIGGER_SAMOVING = 0, ++ RTK_RLDP_TRIGGER_PERIOD, ++ RTK_RLDP_TRIGGER_END ++} rtk_rldp_trigger_t; ++ ++typedef enum rtk_rldp_cmpType_e ++{ ++ RTK_RLDP_CMPTYPE_MAGIC = 0, /* Compare the RLDP with magic only */ ++ RTK_RLDP_CMPTYPE_MAGIC_ID, /* Compare the RLDP with both magic + ID */ ++ RTK_RLDP_CMPTYPE_END ++} rtk_rldp_cmpType_t; ++ ++typedef enum rtk_rldp_loopStatus_e ++{ ++ RTK_RLDP_LOOPSTS_NONE = 0, ++ RTK_RLDP_LOOPSTS_LOOPING, ++ RTK_RLDP_LOOPSTS_END ++} rtk_rldp_loopStatus_t; ++ ++typedef enum rtk_rlpp_trapType_e ++{ ++ RTK_RLPP_TRAPTYPE_NONE = 0, ++ RTK_RLPP_TRAPTYPE_CPU, ++ RTK_RLPP_TRAPTYPE_END ++} rtk_rlpp_trapType_t; ++ ++typedef struct rtk_rldp_config_s ++{ ++ rtk_enable_t rldp_enable; ++ rtk_rldp_trigger_t trigger_mode; ++ rtk_mac_t magic; ++ rtk_rldp_cmpType_t compare_type; ++ rtk_uint32 interval_check; /* Checking interval for check state */ ++ rtk_uint32 num_check; /* Checking number for check state */ ++ rtk_uint32 interval_loop; /* Checking interval for loop state */ ++ rtk_uint32 num_loop; /* Checking number for loop state */ ++} rtk_rldp_config_t; ++ ++typedef struct rtk_rldp_portConfig_s ++{ ++ rtk_enable_t tx_enable; ++} rtk_rldp_portConfig_t; ++ ++typedef struct rtk_rldp_status_s ++{ ++ rtk_mac_t id; ++} rtk_rldp_status_t; ++ ++typedef struct rtk_rldp_portStatus_s ++{ ++ rtk_rldp_loopStatus_t loop_status; ++ rtk_rldp_loopStatus_t loop_enter; ++ rtk_rldp_loopStatus_t loop_leave; ++} rtk_rldp_portStatus_t; ++ ++/* ++ * Data Declaration ++ */ ++ ++ ++/* ++ * Macro Declaration ++ */ ++ ++#define RTK_RLDP_INTERVAL_MAX 0xffff ++#define RTK_RLDP_NUM_MAX 0xff ++ ++ ++/* ++ * Function Declaration ++ */ ++ ++/* Module Name : RLDP */ ++ ++ ++/* Function Name: ++ * rtk_rldp_config_set ++ * Description: ++ * Set RLDP module configuration ++ * Input: ++ * pConfig - configuration structure of RLDP ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_INPUT ++ * RT_ERR_NULL_POINTER ++ * Note: ++ * None ++ */ ++extern rtk_api_ret_t rtk_rldp_config_set(rtk_rldp_config_t *pConfig); ++ ++ ++/* Function Name: ++ * rtk_rldp_config_get ++ * Description: ++ * Get RLDP module configuration ++ * Input: ++ * None ++ * Output: ++ * pConfig - configuration structure of RLDP ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_INPUT ++ * RT_ERR_NULL_POINTER ++ * Note: ++ * None ++ */ ++extern rtk_api_ret_t rtk_rldp_config_get(rtk_rldp_config_t *pConfig); ++ ++ ++/* Function Name: ++ * rtk_rldp_portConfig_set ++ * Description: ++ * Set per port RLDP module configuration ++ * Input: ++ * port - port number to be configured ++ * pPortConfig - per port configuration structure of RLDP ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_INPUT ++ * RT_ERR_NULL_POINTER ++ * Note: ++ * None ++ */ ++extern rtk_api_ret_t rtk_rldp_portConfig_set(rtk_port_t port, rtk_rldp_portConfig_t *pPortConfig); ++ ++ ++/* Function Name: ++ * rtk_rldp_portConfig_get ++ * Description: ++ * Get per port RLDP module configuration ++ * Input: ++ * port - port number to be get ++ * Output: ++ * pPortConfig - per port configuration structure of RLDP ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_INPUT ++ * RT_ERR_NULL_POINTER ++ * Note: ++ * None ++ */ ++extern rtk_api_ret_t rtk_rldp_portConfig_get(rtk_port_t port, rtk_rldp_portConfig_t *pPortConfig); ++ ++ ++/* Function Name: ++ * rtk_rldp_status_get ++ * Description: ++ * Get RLDP module status ++ * Input: ++ * None ++ * Output: ++ * pStatus - status structure of RLDP ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_NULL_POINTER ++ * Note: ++ * None ++ */ ++extern rtk_api_ret_t rtk_rldp_status_get(rtk_rldp_status_t *pStatus); ++ ++ ++/* Function Name: ++ * rtk_rldp_portStatus_get ++ * Description: ++ * Get RLDP module status ++ * Input: ++ * port - port number to be get ++ * Output: ++ * pPortStatus - per port status structure of RLDP ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_INPUT ++ * RT_ERR_NULL_POINTER ++ * Note: ++ * None ++ */ ++extern rtk_api_ret_t rtk_rldp_portStatus_get(rtk_port_t port, rtk_rldp_portStatus_t *pPortStatus); ++ ++ ++/* Function Name: ++ * rtk_rldp_portStatus_clear ++ * Description: ++ * Clear RLDP module status ++ * Input: ++ * port - port number to be clear ++ * pPortStatus - per port status structure of RLDP ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_INPUT ++ * RT_ERR_NULL_POINTER ++ * Note: ++ * Clear operation effect loop_enter and loop_leave only, other field in ++ * the structure are don't care ++ */ ++extern rtk_api_ret_t rtk_rldp_portStatus_set(rtk_port_t port, rtk_rldp_portStatus_t *pPortStatus); ++ ++ ++/* Function Name: ++ * rtk_rldp_portLoopPair_get ++ * Description: ++ * Get RLDP port loop pairs ++ * Input: ++ * port - port number to be get ++ * Output: ++ * pPortmask - per port related loop ports ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_INPUT ++ * RT_ERR_NULL_POINTER ++ * Note: ++ * None ++ */ ++extern rtk_api_ret_t rtk_rldp_portLoopPair_get(rtk_port_t port, rtk_portmask_t *pPortmask); ++ ++#endif /* __RTK_RLDP_H__ */ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtk_error.h b/drivers/net/phy/rtk/rtl8367c/include/rtk_error.h +new file mode 100644 +index 000000000000..54d1a13f3bee +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/rtk_error.h +@@ -0,0 +1,229 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ ++ * ++ * Purpose : Definition the error number in the SDK. ++ * Feature : error definition ++ * ++ */ ++ ++#ifndef __COMMON_RT_ERROR_H__ ++#define __COMMON_RT_ERROR_H__ ++ ++/* ++ * Include Files ++ */ ++ ++/* ++ * Data Type Declaration ++ */ ++typedef enum rt_error_code_e ++{ ++ RT_ERR_FAILED = -1, /* General Error */ ++ ++ /* 0x0000xxxx for common error code */ ++ RT_ERR_OK = 0, /* 0x00000000, OK */ ++ RT_ERR_INPUT, /* 0x00000001, invalid input parameter */ ++ RT_ERR_UNIT_ID, /* 0x00000002, invalid unit id */ ++ RT_ERR_PORT_ID, /* 0x00000003, invalid port id */ ++ RT_ERR_PORT_MASK, /* 0x00000004, invalid port mask */ ++ RT_ERR_PORT_LINKDOWN, /* 0x00000005, link down port status */ ++ RT_ERR_ENTRY_INDEX, /* 0x00000006, invalid entry index */ ++ RT_ERR_NULL_POINTER, /* 0x00000007, input parameter is null pointer */ ++ RT_ERR_QUEUE_ID, /* 0x00000008, invalid queue id */ ++ RT_ERR_QUEUE_NUM, /* 0x00000009, invalid queue number */ ++ RT_ERR_BUSYWAIT_TIMEOUT, /* 0x0000000a, busy waiting time out */ ++ RT_ERR_MAC, /* 0x0000000b, invalid mac address */ ++ RT_ERR_OUT_OF_RANGE, /* 0x0000000c, input parameter out of range */ ++ RT_ERR_CHIP_NOT_SUPPORTED, /* 0x0000000d, functions not supported by this chip model */ ++ RT_ERR_SMI, /* 0x0000000e, SMI error */ ++ RT_ERR_NOT_INIT, /* 0x0000000f, The module is not initial */ ++ RT_ERR_CHIP_NOT_FOUND, /* 0x00000010, The chip can not found */ ++ RT_ERR_NOT_ALLOWED, /* 0x00000011, actions not allowed by the function */ ++ RT_ERR_DRIVER_NOT_FOUND, /* 0x00000012, The driver can not found */ ++ RT_ERR_SEM_LOCK_FAILED, /* 0x00000013, Failed to lock semaphore */ ++ RT_ERR_SEM_UNLOCK_FAILED, /* 0x00000014, Failed to unlock semaphore */ ++ RT_ERR_ENABLE, /* 0x00000015, invalid enable parameter */ ++ RT_ERR_TBL_FULL, /* 0x00000016, input table full */ ++ ++ /* 0x0001xxxx for vlan */ ++ RT_ERR_VLAN_VID = 0x00010000, /* 0x00010000, invalid vid */ ++ RT_ERR_VLAN_PRIORITY, /* 0x00010001, invalid 1p priority */ ++ RT_ERR_VLAN_EMPTY_ENTRY, /* 0x00010002, empty entry of vlan table */ ++ RT_ERR_VLAN_ACCEPT_FRAME_TYPE, /* 0x00010003, invalid accept frame type */ ++ RT_ERR_VLAN_EXIST, /* 0x00010004, vlan is exist */ ++ RT_ERR_VLAN_ENTRY_NOT_FOUND, /* 0x00010005, specified vlan entry not found */ ++ RT_ERR_VLAN_PORT_MBR_EXIST, /* 0x00010006, member port exist in the specified vlan */ ++ RT_ERR_VLAN_PROTO_AND_PORT, /* 0x00010008, invalid protocol and port based vlan */ ++ ++ /* 0x0002xxxx for svlan */ ++ RT_ERR_SVLAN_ENTRY_INDEX = 0x00020000, /* 0x00020000, invalid svid entry no */ ++ RT_ERR_SVLAN_ETHER_TYPE, /* 0x00020001, invalid SVLAN ether type */ ++ RT_ERR_SVLAN_TABLE_FULL, /* 0x00020002, no empty entry in SVLAN table */ ++ RT_ERR_SVLAN_ENTRY_NOT_FOUND, /* 0x00020003, specified svlan entry not found */ ++ RT_ERR_SVLAN_EXIST, /* 0x00020004, SVLAN entry is exist */ ++ RT_ERR_SVLAN_VID, /* 0x00020005, invalid svid */ ++ ++ /* 0x0003xxxx for MSTP */ ++ RT_ERR_MSTI = 0x00030000, /* 0x00030000, invalid msti */ ++ RT_ERR_MSTP_STATE, /* 0x00030001, invalid spanning tree status */ ++ RT_ERR_MSTI_EXIST, /* 0x00030002, MSTI exist */ ++ RT_ERR_MSTI_NOT_EXIST, /* 0x00030003, MSTI not exist */ ++ ++ /* 0x0004xxxx for BUCKET */ ++ RT_ERR_TIMESLOT = 0x00040000, /* 0x00040000, invalid time slot */ ++ RT_ERR_TOKEN, /* 0x00040001, invalid token amount */ ++ RT_ERR_RATE, /* 0x00040002, invalid rate */ ++ RT_ERR_TICK, /* 0x00040003, invalid tick */ ++ ++ /* 0x0005xxxx for RMA */ ++ RT_ERR_RMA_ADDR = 0x00050000, /* 0x00050000, invalid rma mac address */ ++ RT_ERR_RMA_ACTION, /* 0x00050001, invalid rma action */ ++ ++ /* 0x0006xxxx for L2 */ ++ RT_ERR_L2_HASH_KEY = 0x00060000, /* 0x00060000, invalid L2 Hash key */ ++ RT_ERR_L2_HASH_INDEX, /* 0x00060001, invalid L2 Hash index */ ++ RT_ERR_L2_CAM_INDEX, /* 0x00060002, invalid L2 CAM index */ ++ RT_ERR_L2_ENRTYSEL, /* 0x00060003, invalid EntrySel */ ++ RT_ERR_L2_INDEXTABLE_INDEX, /* 0x00060004, invalid L2 index table(=portMask table) index */ ++ RT_ERR_LIMITED_L2ENTRY_NUM, /* 0x00060005, invalid limited L2 entry number */ ++ RT_ERR_L2_AGGREG_PORT, /* 0x00060006, this aggregated port is not the lowest physical ++ port of its aggregation group */ ++ RT_ERR_L2_FID, /* 0x00060007, invalid fid */ ++ RT_ERR_L2_VID, /* 0x00060008, invalid cvid */ ++ RT_ERR_L2_NO_EMPTY_ENTRY, /* 0x00060009, no empty entry in L2 table */ ++ RT_ERR_L2_ENTRY_NOTFOUND, /* 0x0006000a, specified entry not found */ ++ RT_ERR_L2_INDEXTBL_FULL, /* 0x0006000b, the L2 index table is full */ ++ RT_ERR_L2_INVALID_FLOWTYPE, /* 0x0006000c, invalid L2 flow type */ ++ RT_ERR_L2_L2UNI_PARAM, /* 0x0006000d, invalid L2 unicast parameter */ ++ RT_ERR_L2_L2MULTI_PARAM, /* 0x0006000e, invalid L2 multicast parameter */ ++ RT_ERR_L2_IPMULTI_PARAM, /* 0x0006000f, invalid L2 ip multicast parameter */ ++ RT_ERR_L2_PARTIAL_HASH_KEY, /* 0x00060010, invalid L2 partial Hash key */ ++ RT_ERR_L2_EMPTY_ENTRY, /* 0x00060011, the entry is empty(invalid) */ ++ RT_ERR_L2_FLUSH_TYPE, /* 0x00060012, the flush type is invalid */ ++ RT_ERR_L2_NO_CPU_PORT, /* 0x00060013, CPU port not exist */ ++ ++ /* 0x0007xxxx for FILTER (PIE) */ ++ RT_ERR_FILTER_BLOCKNUM = 0x00070000, /* 0x00070000, invalid block number */ ++ RT_ERR_FILTER_ENTRYIDX, /* 0x00070001, invalid entry index */ ++ RT_ERR_FILTER_CUTLINE, /* 0x00070002, invalid cutline value */ ++ RT_ERR_FILTER_FLOWTBLBLOCK, /* 0x00070003, block belongs to flow table */ ++ RT_ERR_FILTER_INACLBLOCK, /* 0x00070004, block belongs to ingress ACL */ ++ RT_ERR_FILTER_ACTION, /* 0x00070005, action doesn't consist to entry type */ ++ RT_ERR_FILTER_INACL_RULENUM, /* 0x00070006, invalid ACL rulenum */ ++ RT_ERR_FILTER_INACL_TYPE, /* 0x00070007, entry type isn't an ingress ACL rule */ ++ RT_ERR_FILTER_INACL_EXIST, /* 0x00070008, ACL entry is already exit */ ++ RT_ERR_FILTER_INACL_EMPTY, /* 0x00070009, ACL entry is empty */ ++ RT_ERR_FILTER_FLOWTBL_TYPE, /* 0x0007000a, entry type isn't an flow table rule */ ++ RT_ERR_FILTER_FLOWTBL_RULENUM, /* 0x0007000b, invalid flow table rulenum */ ++ RT_ERR_FILTER_FLOWTBL_EMPTY, /* 0x0007000c, flow table entry is empty */ ++ RT_ERR_FILTER_FLOWTBL_EXIST, /* 0x0007000d, flow table entry is already exist */ ++ RT_ERR_FILTER_METER_ID, /* 0x0007000e, invalid metering id */ ++ RT_ERR_FILTER_LOG_ID, /* 0x0007000f, invalid log id */ ++ RT_ERR_FILTER_INACL_NONE_BEGIN_IDX, /* 0x00070010, entry index is not starting index of a group of rules */ ++ RT_ERR_FILTER_INACL_ACT_NOT_SUPPORT, /* 0x00070011, action not support */ ++ RT_ERR_FILTER_INACL_RULE_NOT_SUPPORT, /* 0x00070012, rule not support */ ++ ++ /* 0x0008xxxx for ACL Rate Limit */ ++ RT_ERR_ACLRL_HTHR = 0x00080000, /* 0x00080000, invalid high threshold */ ++ RT_ERR_ACLRL_TIMESLOT, /* 0x00080001, invalid time slot */ ++ RT_ERR_ACLRL_TOKEN, /* 0x00080002, invalid token amount */ ++ RT_ERR_ACLRL_RATE, /* 0x00080003, invalid rate */ ++ ++ /* 0x0009xxxx for Link aggregation */ ++ RT_ERR_LA_CPUPORT = 0x00090000, /* 0x00090000, CPU port can not be aggregated port */ ++ RT_ERR_LA_TRUNK_ID, /* 0x00090001, invalid trunk id */ ++ RT_ERR_LA_PORTMASK, /* 0x00090002, invalid port mask */ ++ RT_ERR_LA_HASHMASK, /* 0x00090003, invalid hash mask */ ++ RT_ERR_LA_DUMB, /* 0x00090004, this API should be used in 802.1ad dumb mode */ ++ RT_ERR_LA_PORTNUM_DUMB, /* 0x00090005, it can only aggregate at most four ports when 802.1ad dumb mode */ ++ RT_ERR_LA_PORTNUM_NORMAL, /* 0x00090006, it can only aggregate at most eight ports when 802.1ad normal mode */ ++ RT_ERR_LA_MEMBER_OVERLAP, /* 0x00090007, the specified port mask is overlapped with other group */ ++ RT_ERR_LA_NOT_MEMBER_PORT, /* 0x00090008, the port is not a member port of the trunk */ ++ RT_ERR_LA_TRUNK_NOT_EXIST, /* 0x00090009, the trunk doesn't exist */ ++ ++ ++ /* 0x000axxxx for storm filter */ ++ RT_ERR_SFC_TICK_PERIOD = 0x000a0000, /* 0x000a0000, invalid SFC tick period */ ++ RT_ERR_SFC_UNKNOWN_GROUP, /* 0x000a0001, Unknown Storm filter group */ ++ ++ /* 0x000bxxxx for pattern match */ ++ RT_ERR_PM_MASK = 0x000b0000, /* 0x000b0000, invalid pattern length. Pattern length should be 8 */ ++ RT_ERR_PM_LENGTH, /* 0x000b0001, invalid pattern match mask, first byte must care */ ++ RT_ERR_PM_MODE, /* 0x000b0002, invalid pattern match mode */ ++ ++ /* 0x000cxxxx for input bandwidth control */ ++ RT_ERR_INBW_TICK_PERIOD = 0x000c0000, /* 0x000c0000, invalid tick period for input bandwidth control */ ++ RT_ERR_INBW_TOKEN_AMOUNT, /* 0x000c0001, invalid amount of token for input bandwidth control */ ++ RT_ERR_INBW_FCON_VALUE, /* 0x000c0002, invalid flow control ON threshold value for input bandwidth control */ ++ RT_ERR_INBW_FCOFF_VALUE, /* 0x000c0003, invalid flow control OFF threshold value for input bandwidth control */ ++ RT_ERR_INBW_FC_ALLOWANCE, /* 0x000c0004, invalid allowance of incoming packet for input bandwidth control */ ++ RT_ERR_INBW_RATE, /* 0x000c0005, invalid input bandwidth */ ++ ++ /* 0x000dxxxx for QoS */ ++ RT_ERR_QOS_1P_PRIORITY = 0x000d0000, /* 0x000d0000, invalid 802.1P priority */ ++ RT_ERR_QOS_DSCP_VALUE, /* 0x000d0001, invalid DSCP value */ ++ RT_ERR_QOS_INT_PRIORITY, /* 0x000d0002, invalid internal priority */ ++ RT_ERR_QOS_SEL_DSCP_PRI, /* 0x000d0003, invalid DSCP selection priority */ ++ RT_ERR_QOS_SEL_PORT_PRI, /* 0x000d0004, invalid port selection priority */ ++ RT_ERR_QOS_SEL_IN_ACL_PRI, /* 0x000d0005, invalid ingress ACL selection priority */ ++ RT_ERR_QOS_SEL_CLASS_PRI, /* 0x000d0006, invalid classifier selection priority */ ++ RT_ERR_QOS_EBW_RATE, /* 0x000d0007, invalid egress bandwidth rate */ ++ RT_ERR_QOS_SCHE_TYPE, /* 0x000d0008, invalid QoS scheduling type */ ++ RT_ERR_QOS_QUEUE_WEIGHT, /* 0x000d0009, invalid Queue weight */ ++ RT_ERR_QOS_SEL_PRI_SOURCE, /* 0x000d000a, invalid selection of priority source */ ++ ++ /* 0x000exxxx for port ability */ ++ RT_ERR_PHY_PAGE_ID = 0x000e0000, /* 0x000e0000, invalid PHY page id */ ++ RT_ERR_PHY_REG_ID, /* 0x000e0001, invalid PHY reg id */ ++ RT_ERR_PHY_DATAMASK, /* 0x000e0002, invalid PHY data mask */ ++ RT_ERR_PHY_AUTO_NEGO_MODE, /* 0x000e0003, invalid PHY auto-negotiation mode*/ ++ RT_ERR_PHY_SPEED, /* 0x000e0004, invalid PHY speed setting */ ++ RT_ERR_PHY_DUPLEX, /* 0x000e0005, invalid PHY duplex setting */ ++ RT_ERR_PHY_FORCE_ABILITY, /* 0x000e0006, invalid PHY force mode ability parameter */ ++ RT_ERR_PHY_FORCE_1000, /* 0x000e0007, invalid PHY force mode 1G speed setting */ ++ RT_ERR_PHY_TXRX, /* 0x000e0008, invalid PHY tx/rx */ ++ RT_ERR_PHY_ID, /* 0x000e0009, invalid PHY id */ ++ RT_ERR_PHY_RTCT_NOT_FINISH, /* 0x000e000a, PHY RTCT in progress */ ++ ++ /* 0x000fxxxx for mirror */ ++ RT_ERR_MIRROR_DIRECTION = 0x000f0000, /* 0x000f0000, invalid error mirror direction */ ++ RT_ERR_MIRROR_SESSION_FULL, /* 0x000f0001, mirroring session is full */ ++ RT_ERR_MIRROR_SESSION_NOEXIST, /* 0x000f0002, mirroring session not exist */ ++ RT_ERR_MIRROR_PORT_EXIST, /* 0x000f0003, mirroring port already exists */ ++ RT_ERR_MIRROR_PORT_NOT_EXIST, /* 0x000f0004, mirroring port does not exists */ ++ RT_ERR_MIRROR_PORT_FULL, /* 0x000f0005, Exceeds maximum number of supported mirroring port */ ++ ++ /* 0x0010xxxx for stat */ ++ RT_ERR_STAT_INVALID_GLOBAL_CNTR = 0x00100000, /* 0x00100000, Invalid Global Counter */ ++ RT_ERR_STAT_INVALID_PORT_CNTR, /* 0x00100001, Invalid Port Counter */ ++ RT_ERR_STAT_GLOBAL_CNTR_FAIL, /* 0x00100002, Could not retrieve/reset Global Counter */ ++ RT_ERR_STAT_PORT_CNTR_FAIL, /* 0x00100003, Could not retrieve/reset Port Counter */ ++ RT_ERR_STAT_INVALID_CNTR, /* 0x00100004, Invalid Counter */ ++ RT_ERR_STAT_CNTR_FAIL, /* 0x00100005, Could not retrieve/reset Counter */ ++ ++ /* 0x0011xxxx for dot1x */ ++ RT_ERR_DOT1X_INVALID_DIRECTION = 0x00110000, /* 0x00110000, Invalid Authentication Direction */ ++ RT_ERR_DOT1X_PORTBASEDPNEN, /* 0x00110001, Port-based enable port error */ ++ RT_ERR_DOT1X_PORTBASEDAUTH, /* 0x00110002, Port-based auth port error */ ++ RT_ERR_DOT1X_PORTBASEDOPDIR, /* 0x00110003, Port-based opdir error */ ++ RT_ERR_DOT1X_MACBASEDPNEN, /* 0x00110004, MAC-based enable port error */ ++ RT_ERR_DOT1X_MACBASEDOPDIR, /* 0x00110005, MAC-based opdir error */ ++ RT_ERR_DOT1X_PROC, /* 0x00110006, unauthorized behavior error */ ++ RT_ERR_DOT1X_GVLANIDX, /* 0x00110007, guest vlan index error */ ++ RT_ERR_DOT1X_GVLANTALK, /* 0x00110008, guest vlan OPDIR error */ ++ RT_ERR_DOT1X_MAC_PORT_MISMATCH, /* 0x00110009, Auth MAC and port mismatch error */ ++ ++ RT_ERR_END /* The symbol is the latest symbol */ ++} rt_error_code_t; ++ ++ ++#endif /* __COMMON_RT_ERROR_H__ */ +diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtk_hal.h b/drivers/net/phy/rtk/rtl8367c/include/rtk_hal.h +new file mode 100644 +index 000000000000..6ddb23f2ede7 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/rtk_hal.h +@@ -0,0 +1,44 @@ ++#ifndef __RTK_HAL_H__ ++#define __RTK_HAL_H__ ++#include "ra_ioctl.h" ++ ++#define RTK_SW_VID_RANGE 16 ++void rtk_hal_switch_init(void); ++void rtk_hal_dump_mib(void); ++void rtk_hal_dump_full_mib(void); ++int rtk_hal_dump_vlan(void); ++void rtk_hal_clear_vlan(void); ++int rtk_hal_set_vlan(struct ra_switch_ioctl_data *data); ++int rtk_hal_set_ingress_rate(struct ra_switch_ioctl_data *data); ++int rtk_hal_set_egress_rate(struct ra_switch_ioctl_data *data); ++void rtk_hal_dump_table(void); ++void rtk_hal_clear_table(void); ++void rtk_hal_get_phy_status(struct ra_switch_ioctl_data *data); ++void rtk_hal_set_port_mirror(struct ra_switch_ioctl_data *data); ++void rtk_hal_read_reg(struct ra_switch_ioctl_data *data); ++void rtk_hal_write_reg(struct ra_switch_ioctl_data *data); ++void rtk_hal_qos_en(struct ra_switch_ioctl_data *data); ++void rtk_hal_qos_set_table2type(struct ra_switch_ioctl_data *data); ++void rtk_hal_qos_get_table2type(struct ra_switch_ioctl_data *data); ++void rtk_hal_qos_set_port2table(struct ra_switch_ioctl_data *data); ++void rtk_hal_qos_get_port2table(struct ra_switch_ioctl_data *data); ++void rtk_hal_qos_set_port2pri(struct ra_switch_ioctl_data *data); ++void rtk_hal_qos_get_port2pri(struct ra_switch_ioctl_data *data); ++void rtk_hal_qos_set_dscp2pri(struct ra_switch_ioctl_data *data); ++void rtk_hal_qos_get_dscp2pri(struct ra_switch_ioctl_data *data); ++void rtk_hal_qos_set_pri2queue(struct ra_switch_ioctl_data *data); ++void rtk_hal_qos_get_pri2queue(struct ra_switch_ioctl_data *data); ++void rtk_hal_qos_set_queue_weight(struct ra_switch_ioctl_data *data); ++void rtk_hal_qos_get_queue_weight(struct ra_switch_ioctl_data *data); ++void rtk_hal_enable_igmpsnoop(struct ra_switch_ioctl_data *data); ++void rtk_hal_disable_igmpsnoop(void); ++void rtk_hal_set_phy_test_mode(struct ra_switch_ioctl_data *data); ++void rtk_hal_get_phy_reg(struct ra_switch_ioctl_data *data); ++void rtk_hal_set_phy_reg(struct ra_switch_ioctl_data *data); ++void rtk_hal_vlan_tag(struct ra_switch_ioctl_data *data); ++void rtk_hal_vlan_portpvid_set(rtk_port_t port, rtk_vlan_t pvid, rtk_pri_t priority); ++void rtk_hal_add_table(struct ra_switch_ioctl_data *data); ++void rtk_hal_del_table(struct ra_switch_ioctl_data *data); ++void rtk_hal_vlan_mode(struct ra_switch_ioctl_data *data); ++void rtk_hal_set_port_trunk(struct ra_switch_ioctl_data *data); ++#endif +diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtk_switch.h b/drivers/net/phy/rtk/rtl8367c/include/rtk_switch.h +new file mode 100644 +index 000000000000..1c92188d6b19 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/rtk_switch.h +@@ -0,0 +1,741 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76336 $ ++ * $Date: 2017-03-09 10:41:21 +0800 (週四, 09 三月 2017) $ ++ * ++ * Purpose : RTK switch high-level API ++ * Feature : Here is a list of all functions and variables in this module. ++ * ++ */ ++ ++#ifndef __RTK_SWITCH_H__ ++#define __RTK_SWITCH_H__ ++ ++#include ++ ++#define UNDEFINE_PHY_PORT (0xFF) ++#define RTK_SWITCH_PORT_NUM (32) ++ ++#define MAXPKTLEN_CFG_ID_MAX (1) ++ ++#define RTK_SWITCH_MAX_PKTLEN (0x3FFF) ++ ++typedef enum init_state_e ++{ ++ INIT_NOT_COMPLETED = 0, ++ INIT_COMPLETED, ++ INIT_STATE_END ++} init_state_t; ++ ++typedef enum switch_chip_e ++{ ++ CHIP_RTL8367C = 0, ++ CHIP_RTL8370B, ++ CHIP_RTL8364B, ++ CHIP_RTL8363SC_VB, ++ CHIP_END ++}switch_chip_t; ++ ++typedef enum port_type_e ++{ ++ UTP_PORT = 0, ++ EXT_PORT, ++ UNKNOWN_PORT = 0xFF, ++ PORT_TYPE_END ++}port_type_t; ++ ++typedef struct rtk_switch_halCtrl_s ++{ ++ switch_chip_t switch_type; ++ rtk_uint32 l2p_port[RTK_SWITCH_PORT_NUM]; ++ rtk_uint32 p2l_port[RTK_SWITCH_PORT_NUM]; ++ port_type_t log_port_type[RTK_SWITCH_PORT_NUM]; ++ rtk_uint32 ptp_port[RTK_SWITCH_PORT_NUM]; ++ rtk_uint32 valid_portmask; ++ rtk_uint32 valid_utp_portmask; ++ rtk_uint32 valid_ext_portmask; ++ rtk_uint32 valid_cpu_portmask; ++ rtk_uint32 min_phy_port; ++ rtk_uint32 max_phy_port; ++ rtk_uint32 phy_portmask; ++ rtk_uint32 combo_logical_port; ++ rtk_uint32 hsg_logical_port; ++ rtk_uint32 sg_logical_portmask; ++ rtk_uint32 max_meter_id; ++ rtk_uint32 max_lut_addr_num; ++ rtk_uint32 trunk_group_mask; ++ ++}rtk_switch_halCtrl_t; ++ ++typedef enum rtk_switch_maxPktLen_linkSpeed_e { ++ MAXPKTLEN_LINK_SPEED_FE = 0, ++ MAXPKTLEN_LINK_SPEED_GE, ++ MAXPKTLEN_LINK_SPEED_END, ++} rtk_switch_maxPktLen_linkSpeed_t; ++ ++ ++/* UTIL MACRO */ ++#define RTK_CHK_INIT_STATE() \ ++ do \ ++ { \ ++ if(rtk_switch_initialState_get() != INIT_COMPLETED) \ ++ { \ ++ return RT_ERR_NOT_INIT; \ ++ } \ ++ }while(0) ++ ++#define RTK_CHK_PORT_VALID(__port__) \ ++ do \ ++ { \ ++ if(rtk_switch_logicalPortCheck(__port__) != RT_ERR_OK) \ ++ { \ ++ return RT_ERR_PORT_ID; \ ++ } \ ++ }while(0) ++ ++#define RTK_CHK_PORT_IS_UTP(__port__) \ ++ do \ ++ { \ ++ if(rtk_switch_isUtpPort(__port__) != RT_ERR_OK) \ ++ { \ ++ return RT_ERR_PORT_ID; \ ++ } \ ++ }while(0) ++ ++#define RTK_CHK_PORT_IS_EXT(__port__) \ ++ do \ ++ { \ ++ if(rtk_switch_isExtPort(__port__) != RT_ERR_OK) \ ++ { \ ++ return RT_ERR_PORT_ID; \ ++ } \ ++ }while(0) ++ ++#define RTK_CHK_PORT_IS_COMBO(__port__) \ ++ do \ ++ { \ ++ if(rtk_switch_isComboPort(__port__) != RT_ERR_OK) \ ++ { \ ++ return RT_ERR_PORT_ID; \ ++ } \ ++ }while(0) ++ ++#define RTK_CHK_PORT_IS_PTP(__port__) \ ++ do \ ++ { \ ++ if(rtk_switch_isPtpPort(__port__) != RT_ERR_OK) \ ++ { \ ++ return RT_ERR_PORT_ID; \ ++ } \ ++ }while(0) ++ ++#define RTK_CHK_PORTMASK_VALID(__portmask__) \ ++ do \ ++ { \ ++ if(rtk_switch_isPortMaskValid(__portmask__) != RT_ERR_OK) \ ++ { \ ++ return RT_ERR_PORT_MASK; \ ++ } \ ++ }while(0) ++ ++#define RTK_CHK_PORTMASK_VALID_ONLY_UTP(__portmask__) \ ++ do \ ++ { \ ++ if(rtk_switch_isPortMaskUtp(__portmask__) != RT_ERR_OK) \ ++ { \ ++ return RT_ERR_PORT_MASK; \ ++ } \ ++ }while(0) ++ ++#define RTK_CHK_PORTMASK_VALID_ONLY_EXT(__portmask__) \ ++ do \ ++ { \ ++ if(rtk_switch_isPortMaskExt(__portmask__) != RT_ERR_OK) \ ++ { \ ++ return RT_ERR_PORT_MASK; \ ++ } \ ++ }while(0) ++ ++#define RTK_CHK_TRUNK_GROUP_VALID(__grpId__) \ ++ do \ ++ { \ ++ if(rtk_switch_isValidTrunkGrpId(__grpId__) != RT_ERR_OK) \ ++ { \ ++ return RT_ERR_LA_TRUNK_ID; \ ++ } \ ++ }while(0) ++ ++#define RTK_PORTMASK_IS_PORT_SET(__portmask__, __port__) (((__portmask__).bits[0] & (0x00000001 << __port__)) ? 1 : 0) ++#define RTK_PORTMASK_IS_EMPTY(__portmask__) (((__portmask__).bits[0] == 0) ? 1 : 0) ++#define RTK_PORTMASK_CLEAR(__portmask__) ((__portmask__).bits[0] = 0) ++#define RTK_PORTMASK_PORT_SET(__portmask__, __port__) ((__portmask__).bits[0] |= (0x00000001 << __port__)) ++#define RTK_PORTMASK_PORT_CLEAR(__portmask__, __port__) ((__portmask__).bits[0] &= ~(0x00000001 << __port__)) ++#define RTK_PORTMASK_ALLPORT_SET(__portmask__) (rtk_switch_logPortMask_get(&__portmask__)) ++#define RTK_PORTMASK_SCAN(__portmask__, __port__) for(__port__ = 0; __port__ < RTK_SWITCH_PORT_NUM; __port__++) if(RTK_PORTMASK_IS_PORT_SET(__portmask__, __port__)) ++#define RTK_PORTMASK_COMPARE(__portmask_A__, __portmask_B__) ((__portmask_A__).bits[0] - (__portmask_B__).bits[0]) ++ ++#define RTK_SCAN_ALL_PHY_PORTMASK(__port__) for(__port__ = 0; __port__ < RTK_SWITCH_PORT_NUM; __port__++) if( (rtk_switch_phyPortMask_get() & (0x00000001 << __port__))) ++#define RTK_SCAN_ALL_LOG_PORT(__port__) for(__port__ = 0; __port__ < RTK_SWITCH_PORT_NUM; __port__++) if( rtk_switch_logicalPortCheck(__port__) == RT_ERR_OK) ++#define RTK_SCAN_ALL_LOG_PORTMASK(__portmask__) for((__portmask__).bits[0] = 0; (__portmask__).bits[0] < 0x7FFFF; (__portmask__).bits[0]++) if( rtk_switch_isPortMaskValid(&__portmask__) == RT_ERR_OK) ++ ++/* Port mask definition */ ++#define RTK_PHY_PORTMASK_ALL (rtk_switch_phyPortMask_get()) ++ ++/* Port definition*/ ++#define RTK_MAX_LOGICAL_PORT_ID (rtk_switch_maxLogicalPort_get()) ++ ++/* Function Name: ++ * rtk_switch_probe ++ * Description: ++ * Probe switch ++ * Input: ++ * None ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Switch probed ++ * RT_ERR_FAILED - Switch Unprobed. ++ * Note: ++ * ++ */ ++extern rtk_api_ret_t rtk_switch_probe(switch_chip_t *pSwitchChip); ++ ++/* Function Name: ++ * rtk_switch_initialState_set ++ * Description: ++ * Set initial status ++ * Input: ++ * state - Initial state; ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Initialized ++ * RT_ERR_FAILED - Uninitialized ++ * Note: ++ * ++ */ ++extern rtk_api_ret_t rtk_switch_initialState_set(init_state_t state); ++ ++/* Function Name: ++ * rtk_switch_initialState_get ++ * Description: ++ * Get initial status ++ * Input: ++ * None ++ * Output: ++ * None ++ * Return: ++ * INIT_COMPLETED - Initialized ++ * INIT_NOT_COMPLETED - Uninitialized ++ * Note: ++ * ++ */ ++extern init_state_t rtk_switch_initialState_get(void); ++ ++/* Function Name: ++ * rtk_switch_logicalPortCheck ++ * Description: ++ * Check logical port ID. ++ * Input: ++ * logicalPort - logical port ID ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Port ID is correct ++ * RT_ERR_FAILED - Port ID is not correct ++ * RT_ERR_NOT_INIT - Not Initialize ++ * Note: ++ * ++ */ ++extern rtk_api_ret_t rtk_switch_logicalPortCheck(rtk_port_t logicalPort); ++ ++/* Function Name: ++ * rtk_switch_isUtpPort ++ * Description: ++ * Check is logical port a UTP port ++ * Input: ++ * logicalPort - logical port ID ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Port ID is a UTP port ++ * RT_ERR_FAILED - Port ID is not a UTP port ++ * RT_ERR_NOT_INIT - Not Initialize ++ * Note: ++ * ++ */ ++extern rtk_api_ret_t rtk_switch_isUtpPort(rtk_port_t logicalPort); ++ ++/* Function Name: ++ * rtk_switch_isExtPort ++ * Description: ++ * Check is logical port a Extension port ++ * Input: ++ * logicalPort - logical port ID ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Port ID is a EXT port ++ * RT_ERR_FAILED - Port ID is not a EXT port ++ * RT_ERR_NOT_INIT - Not Initialize ++ * Note: ++ * ++ */ ++extern rtk_api_ret_t rtk_switch_isExtPort(rtk_port_t logicalPort); ++ ++/* Function Name: ++ * rtk_switch_isHsgPort ++ * Description: ++ * Check is logical port a HSG port ++ * Input: ++ * logicalPort - logical port ID ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Port ID is a HSG port ++ * RT_ERR_FAILED - Port ID is not a HSG port ++ * RT_ERR_NOT_INIT - Not Initialize ++ * Note: ++ * ++ */ ++extern rtk_api_ret_t rtk_switch_isHsgPort(rtk_port_t logicalPort); ++ ++/* Function Name: ++ * rtk_switch_isSgmiiPort ++ * Description: ++ * Check is logical port a SGMII port ++ * Input: ++ * logicalPort - logical port ID ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Port ID is a SGMII port ++ * RT_ERR_FAILED - Port ID is not a SGMII port ++ * RT_ERR_NOT_INIT - Not Initialize ++ * Note: ++ * ++ */ ++extern rtk_api_ret_t rtk_switch_isSgmiiPort(rtk_port_t logicalPort); ++ ++/* Function Name: ++ * rtk_switch_isCPUPort ++ * Description: ++ * Check is logical port a CPU port ++ * Input: ++ * logicalPort - logical port ID ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Port ID is a CPU port ++ * RT_ERR_FAILED - Port ID is not a CPU port ++ * RT_ERR_NOT_INIT - Not Initialize ++ * Note: ++ * ++ */ ++extern rtk_api_ret_t rtk_switch_isCPUPort(rtk_port_t logicalPort); ++ ++/* Function Name: ++ * rtk_switch_isComboPort ++ * Description: ++ * Check is logical port a Combo port ++ * Input: ++ * logicalPort - logical port ID ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Port ID is a combo port ++ * RT_ERR_FAILED - Port ID is not a combo port ++ * RT_ERR_NOT_INIT - Not Initialize ++ * Note: ++ * ++ */ ++extern rtk_api_ret_t rtk_switch_isComboPort(rtk_port_t logicalPort); ++ ++/* Function Name: ++ * rtk_switch_ComboPort_get ++ * Description: ++ * Get Combo port ID ++ * Input: ++ * None ++ * Output: ++ * None ++ * Return: ++ * Port ID of combo port ++ * Note: ++ * ++ */ ++extern rtk_uint32 rtk_switch_ComboPort_get(void); ++ ++/* Function Name: ++ * rtk_switch_isPtpPort ++ * Description: ++ * Check is logical port a PTP port ++ * Input: ++ * logicalPort - logical port ID ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Port ID is a PTP port ++ * RT_ERR_FAILED - Port ID is not a PTP port ++ * RT_ERR_NOT_INIT - Not Initialize ++ * Note: ++ * ++ */ ++extern rtk_api_ret_t rtk_switch_isPtpPort(rtk_port_t logicalPort); ++ ++/* Function Name: ++ * rtk_switch_port_L2P_get ++ * Description: ++ * Get physical port ID ++ * Input: ++ * logicalPort - logical port ID ++ * Output: ++ * None ++ * Return: ++ * Physical port ID ++ * Note: ++ * ++ */ ++extern rtk_uint32 rtk_switch_port_L2P_get(rtk_port_t logicalPort); ++ ++/* Function Name: ++ * rtk_switch_port_P2L_get ++ * Description: ++ * Get logical port ID ++ * Input: ++ * physicalPort - physical port ID ++ * Output: ++ * None ++ * Return: ++ * logical port ID ++ * Note: ++ * ++ */ ++extern rtk_port_t rtk_switch_port_P2L_get(rtk_uint32 physicalPort); ++ ++/* Function Name: ++ * rtk_switch_isPortMaskValid ++ * Description: ++ * Check portmask is valid or not ++ * Input: ++ * pPmask - logical port mask ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - port mask is valid ++ * RT_ERR_FAILED - port mask is not valid ++ * RT_ERR_NOT_INIT - Not Initialize ++ * RT_ERR_NULL_POINTER - Null pointer ++ * Note: ++ * ++ */ ++extern rtk_api_ret_t rtk_switch_isPortMaskValid(rtk_portmask_t *pPmask); ++ ++/* Function Name: ++ * rtk_switch_isPortMaskUtp ++ * Description: ++ * Check all ports in portmask are only UTP port ++ * Input: ++ * pPmask - logical port mask ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Only UTP port in port mask ++ * RT_ERR_FAILED - Not only UTP port in port mask ++ * RT_ERR_NOT_INIT - Not Initialize ++ * RT_ERR_NULL_POINTER - Null pointer ++ * Note: ++ * ++ */ ++extern rtk_api_ret_t rtk_switch_isPortMaskUtp(rtk_portmask_t *pPmask); ++ ++/* Function Name: ++ * rtk_switch_isPortMaskExt ++ * Description: ++ * Check all ports in portmask are only EXT port ++ * Input: ++ * pPmask - logical port mask ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Only EXT port in port mask ++ * RT_ERR_FAILED - Not only EXT port in port mask ++ * RT_ERR_NOT_INIT - Not Initialize ++ * RT_ERR_NULL_POINTER - Null pointer ++ * Note: ++ * ++ */ ++extern rtk_api_ret_t rtk_switch_isPortMaskExt(rtk_portmask_t *pPmask); ++ ++/* Function Name: ++ * rtk_switch_portmask_L2P_get ++ * Description: ++ * Get physical portmask from logical portmask ++ * Input: ++ * pLogicalPmask - logical port mask ++ * Output: ++ * pPhysicalPortmask - physical port mask ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_NOT_INIT - Not Initialize ++ * RT_ERR_NULL_POINTER - Null pointer ++ * RT_ERR_PORT_MASK - Error port mask ++ * Note: ++ * ++ */ ++extern rtk_api_ret_t rtk_switch_portmask_L2P_get(rtk_portmask_t *pLogicalPmask, rtk_uint32 *pPhysicalPortmask); ++ ++/* Function Name: ++ * rtk_switch_portmask_P2L_get ++ * Description: ++ * Get logical portmask from physical portmask ++ * Input: ++ * physicalPortmask - physical port mask ++ * Output: ++ * pLogicalPmask - logical port mask ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_NOT_INIT - Not Initialize ++ * RT_ERR_NULL_POINTER - Null pointer ++ * RT_ERR_PORT_MASK - Error port mask ++ * Note: ++ * ++ */ ++extern rtk_api_ret_t rtk_switch_portmask_P2L_get(rtk_uint32 physicalPortmask, rtk_portmask_t *pLogicalPmask); ++ ++/* Function Name: ++ * rtk_switch_phyPortMask_get ++ * Description: ++ * Get physical portmask ++ * Input: ++ * None ++ * Output: ++ * None ++ * Return: ++ * 0x00 - Not Initialize ++ * Other value - Physical port mask ++ * Note: ++ * ++ */ ++rtk_uint32 rtk_switch_phyPortMask_get(void); ++ ++/* Function Name: ++ * rtk_switch_logPortMask_get ++ * Description: ++ * Get Logical portmask ++ * Input: ++ * None ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_NOT_INIT - Not Initialize ++ * RT_ERR_NULL_POINTER - Null pointer ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_switch_logPortMask_get(rtk_portmask_t *pPortmask); ++ ++/* Function Name: ++ * rtk_switch_init ++ * Description: ++ * Set chip to default configuration environment ++ * Input: ++ * None ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * The API can set chip registers to default configuration for different release chip model. ++ */ ++extern rtk_api_ret_t rtk_switch_init(void); ++ ++/* Function Name: ++ * rtk_switch_portMaxPktLen_set ++ * Description: ++ * Set Max packet length ++ * Input: ++ * port - Port ID ++ * speed - Speed ++ * cfgId - Configuration ID ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Error Input ++ * Note: ++ */ ++extern rtk_api_ret_t rtk_switch_portMaxPktLen_set(rtk_port_t port, rtk_switch_maxPktLen_linkSpeed_t speed, rtk_uint32 cfgId); ++ ++/* Function Name: ++ * rtk_switch_portMaxPktLen_get ++ * Description: ++ * Get Max packet length ++ * Input: ++ * port - Port ID ++ * speed - Speed ++ * Output: ++ * pCfgId - Configuration ID ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Error Input ++ * Note: ++ */ ++extern rtk_api_ret_t rtk_switch_portMaxPktLen_get(rtk_port_t port, rtk_switch_maxPktLen_linkSpeed_t speed, rtk_uint32 *pCfgId); ++ ++/* Function Name: ++ * rtk_switch_maxPktLenCfg_set ++ * Description: ++ * Set Max packet length configuration ++ * Input: ++ * cfgId - Configuration ID ++ * pktLen - Max packet length ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Error Input ++ * Note: ++ */ ++extern rtk_api_ret_t rtk_switch_maxPktLenCfg_set(rtk_uint32 cfgId, rtk_uint32 pktLen); ++ ++/* Function Name: ++ * rtk_switch_maxPktLenCfg_get ++ * Description: ++ * Get Max packet length configuration ++ * Input: ++ * cfgId - Configuration ID ++ * pPktLen - Max packet length ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Error Input ++ * Note: ++ */ ++extern rtk_api_ret_t rtk_switch_maxPktLenCfg_get(rtk_uint32 cfgId, rtk_uint32 *pPktLen); ++ ++/* Function Name: ++ * rtk_switch_greenEthernet_set ++ * Description: ++ * Set all Ports Green Ethernet state. ++ * Input: ++ * enable - Green Ethernet state. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_ENABLE - Invalid enable input. ++ * Note: ++ * This API can set all Ports Green Ethernet state. ++ * The configuration is as following: ++ * - DISABLE ++ * - ENABLE ++ */ ++extern rtk_api_ret_t rtk_switch_greenEthernet_set(rtk_enable_t enable); ++ ++/* Function Name: ++ * rtk_switch_greenEthernet_get ++ * Description: ++ * Get all Ports Green Ethernet state. ++ * Input: ++ * None ++ * Output: ++ * pEnable - Green Ethernet state. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * This API can get Green Ethernet state. ++ */ ++extern rtk_api_ret_t rtk_switch_greenEthernet_get(rtk_enable_t *pEnable); ++ ++/* Function Name: ++ * rtk_switch_maxLogicalPort_get ++ * Description: ++ * Get Max logical port ID ++ * Input: ++ * None ++ * Output: ++ * None ++ * Return: ++ * Max logical port ++ * Note: ++ * This API can get max logical port ++ */ ++extern rtk_port_t rtk_switch_maxLogicalPort_get(void); ++ ++/* Function Name: ++ * rtk_switch_maxMeterId_get ++ * Description: ++ * Get Max Meter ID ++ * Input: ++ * None ++ * Output: ++ * None ++ * Return: ++ * 0x00 - Not Initialize ++ * Other value - Max Meter ID ++ * Note: ++ * ++ */ ++extern rtk_uint32 rtk_switch_maxMeterId_get(void); ++ ++/* Function Name: ++ * rtk_switch_maxLutAddrNumber_get ++ * Description: ++ * Get Max LUT Address number ++ * Input: ++ * None ++ * Output: ++ * None ++ * Return: ++ * 0x00 - Not Initialize ++ * Other value - Max LUT Address number ++ * Note: ++ * ++ */ ++extern rtk_uint32 rtk_switch_maxLutAddrNumber_get(void); ++ ++/* Function Name: ++ * rtk_switch_isValidTrunkGrpId ++ * Description: ++ * Check if trunk group is valid or not ++ * Input: ++ * grpId - Group ID ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Trunk Group ID is valid ++ * RT_ERR_LA_TRUNK_ID - Trunk Group ID is not valid ++ * Note: ++ * ++ */ ++rtk_uint32 rtk_switch_isValidTrunkGrpId(rtk_uint32 grpId); ++ ++int gsw_debug_proc_init(void); ++void gsw_debug_proc_exit(void); ++int rtl8367s_swconfig_init(void (*reset_func)(void)); ++ ++#endif +diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtk_types.h b/drivers/net/phy/rtk/rtl8367c/include/rtk_types.h +new file mode 100644 +index 000000000000..cafc7ff9da36 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/rtk_types.h +@@ -0,0 +1,155 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (¶g¤T, 08 ¤T¤ë 2017) $ ++ * ++ * Purpose : RTL8367C switch high-level type enum definition. ++ * Feature : ++ * ++ */ ++ ++#ifndef _RTL8367C_TYPES_H_ ++#define _RTL8367C_TYPES_H_ ++ ++//#include ++ ++typedef unsigned long long rtk_uint64; ++typedef long long rtk_int64; ++typedef unsigned int rtk_uint32; ++typedef int rtk_int32; ++typedef unsigned short rtk_uint16; ++typedef short rtk_int16; ++typedef unsigned char rtk_uint8; ++typedef char rtk_int8; ++ ++#define CONST_T const ++ ++#define RTK_TOTAL_NUM_OF_WORD_FOR_1BIT_PORT_LIST 1 ++ ++#define RTK_MAX_NUM_OF_PORT 8 ++#define RTK_PORT_ID_MAX (RTK_MAX_NUM_OF_PORT-1) ++#define RTK_PHY_ID_MAX (RTK_MAX_NUM_OF_PORT-4) ++#define RTK_MAX_PORT_MASK 0xFF ++ ++#define RTK_WHOLE_SYSTEM 0xFF ++ ++typedef struct rtk_portmask_s ++{ ++ rtk_uint32 bits[RTK_TOTAL_NUM_OF_WORD_FOR_1BIT_PORT_LIST]; ++} rtk_portmask_t; ++ ++typedef enum rtk_enable_e ++{ ++ DISABLED = 0, ++ ENABLED, ++ RTK_ENABLE_END ++} rtk_enable_t; ++ ++#ifndef ETHER_ADDR_LEN ++#define ETHER_ADDR_LEN 6 ++#endif ++ ++/* Ethernet address type */ ++typedef struct rtk_mac_s ++{ ++ rtk_uint8 octet[ETHER_ADDR_LEN]; ++} rtk_mac_t; ++ ++typedef rtk_uint32 rtk_pri_t; /* priority value */ ++typedef rtk_uint32 rtk_qid_t; /* queue id type */ ++typedef rtk_uint32 rtk_data_t; ++typedef rtk_uint32 rtk_dscp_t; /* dscp vlaue */ ++typedef rtk_uint32 rtk_fid_t; /* filter id type */ ++typedef rtk_uint32 rtk_vlan_t; /* vlan id type */ ++typedef rtk_uint32 rtk_mac_cnt_t; /* MAC count type */ ++typedef rtk_uint32 rtk_meter_id_t; /* meter id type */ ++typedef rtk_uint32 rtk_rate_t; /* rate type */ ++ ++typedef enum rtk_port_e ++{ ++ UTP_PORT0 = 0, ++ UTP_PORT1, ++ UTP_PORT2, ++ UTP_PORT3, ++ UTP_PORT4, ++ UTP_PORT5, ++ UTP_PORT6, ++ UTP_PORT7, ++ ++ EXT_PORT0 = 16, ++ EXT_PORT1, ++ EXT_PORT2, ++ ++ UNDEFINE_PORT = 30, ++ RTK_PORT_MAX = 31 ++} rtk_port_t; ++ ++ ++#ifndef _RTL_TYPES_H ++ ++#if 0 ++typedef unsigned long long uint64; ++typedef long long int64; ++typedef unsigned int uint32; ++typedef int int32; ++typedef unsigned short uint16; ++typedef short int16; ++typedef unsigned char uint8; ++typedef char int8; ++#endif ++ ++typedef rtk_uint32 ipaddr_t; ++typedef rtk_uint32 memaddr; ++ ++#ifndef ETHER_ADDR_LEN ++#define ETHER_ADDR_LEN 6 ++#endif ++ ++typedef struct ether_addr_s { ++ rtk_uint8 octet[ETHER_ADDR_LEN]; ++} ether_addr_t; ++ ++#ifdef __KERNEL__ ++#define rtlglue_printf printk ++#else ++#define rtlglue_printf printf ++#endif ++#define PRINT rtlglue_printf ++#endif /*_RTL_TYPES_H*/ ++ ++/* type abstraction */ ++#ifdef EMBEDDED_SUPPORT ++ ++typedef rtk_int16 rtk_api_ret_t; ++typedef rtk_int16 ret_t; ++typedef rtk_uint32 rtk_u_long; ++ ++#else ++ ++typedef rtk_int32 rtk_api_ret_t; ++typedef rtk_int32 ret_t; ++typedef rtk_uint64 rtk_u_long_t; ++ ++#endif ++ ++#ifndef NULL ++#define NULL 0 ++#endif ++ ++#ifndef TRUE ++#define TRUE 1 ++#endif ++ ++#ifndef FALSE ++#define FALSE 0 ++#endif ++ ++#define CONST const ++#endif /* _RTL8367C_TYPES_H_ */ +diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv.h +new file mode 100644 +index 000000000000..55cb41b06728 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv.h +@@ -0,0 +1,129 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (¶g¤T, 08 ¤T¤ë 2017) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : ++ * ++ */ ++ ++ ++#ifndef _RTL8367C_ASICDRV_H_ ++#define _RTL8367C_ASICDRV_H_ ++ ++#include ++#include ++#include ++#include ++ ++#define RTL8367C_REGBITLENGTH 16 ++#define RTL8367C_REGDATAMAX 0xFFFF ++ ++#define RTL8367C_VIDMAX 0xFFF ++#define RTL8367C_EVIDMAX 0x1FFF ++#define RTL8367C_CVIDXNO 32 ++#define RTL8367C_CVIDXMAX (RTL8367C_CVIDXNO-1) ++ ++#define RTL8367C_PRIMAX 7 ++#define RTL8367C_DSCPMAX 63 ++ ++#define RTL8367C_PORTNO 11 ++#define RTL8367C_PORTIDMAX (RTL8367C_PORTNO-1) ++#define RTL8367C_PMSKMAX ((1<<(RTL8367C_PORTNO))-1) ++#define RTL8367C_PORTMASK 0x7FF ++ ++#define RTL8367C_PHYNO 5 ++#define RTL8367C_PHYIDMAX (RTL8367C_PHYNO-1) ++ ++#define RTL8367C_SVIDXNO 64 ++#define RTL8367C_SVIDXMAX (RTL8367C_SVIDXNO-1) ++#define RTL8367C_MSTIMAX 15 ++ ++#define RTL8367C_METERNO 64 ++#define RTL8367C_METERMAX (RTL8367C_METERNO-1) ++#define RTL8367C_METERBUCKETSIZEMAX 0xFFFF ++ ++#define RTL8367C_QUEUENO 8 ++#define RTL8367C_QIDMAX (RTL8367C_QUEUENO-1) ++ ++#define RTL8367C_PHY_BUSY_CHECK_COUNTER 1000 ++ ++#define RTL8367C_QOS_GRANULARTY_MAX 0x7FFFF ++#define RTL8367C_QOS_GRANULARTY_LSB_MASK 0xFFFF ++#define RTL8367C_QOS_GRANULARTY_LSB_OFFSET 0 ++#define RTL8367C_QOS_GRANULARTY_MSB_MASK 0x70000 ++#define RTL8367C_QOS_GRANULARTY_MSB_OFFSET 16 ++ ++#define RTL8367C_QOS_GRANULARTY_UNIT_KBPS 8 ++ ++#define RTL8367C_QOS_RATE_INPUT_MAX (0x1FFFF * 8) ++#define RTL8367C_QOS_RATE_INPUT_MAX_HSG (0x7FFFF * 8) ++#define RTL8367C_QOS_RATE_INPUT_MIN 8 ++#define RTL8367C_QOS_PPS_INPUT_MAX (0x7FFFF) ++#define RTL8367C_QOS_PPS_INPUT_MIN 1 ++ ++#define RTL8367C_QUEUE_MASK 0xFF ++ ++#define RTL8367C_EFIDMAX 0x7 ++#define RTL8367C_FIDMAX 0xF ++ ++#define RTL8367C_EAV_SECONDMAX 0xFFFFFFFF ++#define RTL8367C_EAV_NANOSECONDMAX 0x3B9AC9FF ++ ++ ++/* the above macro is generated by genDotH */ ++#define RTL8367C_VALID_REG_NO 3869 ++ ++/*======================================================================= ++ * Enum ++ *========================================================================*/ ++enum RTL8367C_TABLE_ACCESS_OP ++{ ++ TB_OP_READ = 0, ++ TB_OP_WRITE ++}; ++ ++enum RTL8367C_TABLE_ACCESS_TARGET ++{ ++ TB_TARGET_ACLRULE = 1, ++ TB_TARGET_ACLACT, ++ TB_TARGET_CVLAN, ++ TB_TARGET_L2, ++ TB_TARGET_IGMP_GROUP ++}; ++ ++#define RTL8367C_TABLE_ACCESS_REG_DATA(op, target) ((op << 3) | target) ++ ++/*======================================================================= ++ * Structures ++ *========================================================================*/ ++ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++extern ret_t rtl8367c_setAsicRegBit(rtk_uint32 reg, rtk_uint32 bit, rtk_uint32 value); ++extern ret_t rtl8367c_getAsicRegBit(rtk_uint32 reg, rtk_uint32 bit, rtk_uint32 *pValue); ++ ++extern ret_t rtl8367c_setAsicRegBits(rtk_uint32 reg, rtk_uint32 bits, rtk_uint32 value); ++extern ret_t rtl8367c_getAsicRegBits(rtk_uint32 reg, rtk_uint32 bits, rtk_uint32 *pValue); ++ ++extern ret_t rtl8367c_setAsicReg(rtk_uint32 reg, rtk_uint32 value); ++extern ret_t rtl8367c_getAsicReg(rtk_uint32 reg, rtk_uint32 *pValue); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++ ++ ++#endif /*#ifndef _RTL8367C_ASICDRV_H_*/ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_acl.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_acl.h +new file mode 100644 +index 000000000000..8ae69ac332c2 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_acl.h +@@ -0,0 +1,231 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (¶g¤T, 08 ¤T¤ë 2017) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : ACL related function drivers ++ * ++ */ ++ ++#ifndef _RTL8367C_ASICDRV_ACL_H_ ++#define _RTL8367C_ASICDRV_ACL_H_ ++ ++#include ++ ++#define RTL8367C_ACLRULENO 96 ++ ++#define RTL8367C_ACLRULEMAX (RTL8367C_ACLRULENO-1) ++#define RTL8367C_ACLRULEFIELDNO 8 ++#define RTL8367C_ACLTEMPLATENO 5 ++#define RTL8367C_ACLTYPEMAX (RTL8367C_ACLTEMPLATENO-1) ++ ++#define RTL8367C_ACLRULETBLEN 9 ++#define RTL8367C_ACLACTTBLEN 4 ++#define RTL8367C_ACLRULETBADDR(type, rule) ((type << 6) | rule) ++#define RTL8367C_ACLRULETBADDR2(type, rule) ((type << 5) | (rule + 64)) ++ ++#define ACL_ACT_CVLAN_ENABLE_MASK 0x1 ++#define ACL_ACT_SVLAN_ENABLE_MASK 0x2 ++#define ACL_ACT_PRIORITY_ENABLE_MASK 0x4 ++#define ACL_ACT_POLICING_ENABLE_MASK 0x8 ++#define ACL_ACT_FWD_ENABLE_MASK 0x10 ++#define ACL_ACT_INTGPIO_ENABLE_MASK 0x20 ++ ++#define RTL8367C_ACLRULETAGBITS 5 ++ ++#define RTL8367C_ACLRANGENO 16 ++ ++#define RTL8367C_ACLRANGEMAX (RTL8367C_ACLRANGENO-1) ++ ++#define RTL8367C_ACL_PORTRANGEMAX (0xFFFF) ++#define RTL8367C_ACL_ACT_TABLE_LEN (4) ++ ++enum ACLTCAMTYPES ++{ ++ CAREBITS= 0, ++ DATABITS ++}; ++ ++typedef enum aclFwdAct ++{ ++ RTL8367C_ACL_FWD_MIRROR = 0, ++ RTL8367C_ACL_FWD_REDIRECT, ++ RTL8367C_ACL_FWD_MIRRORFUNTION, ++ RTL8367C_ACL_FWD_TRAP, ++} rtl8367c_aclFwd_t; ++ ++enum ACLFIELDTYPES ++{ ++ ACL_UNUSED, ++ ACL_DMAC0, ++ ACL_DMAC1, ++ ACL_DMAC2, ++ ACL_SMAC0, ++ ACL_SMAC1, ++ ACL_SMAC2, ++ ACL_ETHERTYPE, ++ ACL_STAG, ++ ACL_CTAG, ++ ACL_IP4SIP0 = 0x10, ++ ACL_IP4SIP1, ++ ACL_IP4DIP0, ++ ACL_IP4DIP1, ++ ACL_IP6SIP0WITHIPV4 = 0x20, ++ ACL_IP6SIP1WITHIPV4, ++ ACL_IP6DIP0WITHIPV4 = 0x28, ++ ACL_IP6DIP1WITHIPV4, ++ ACL_VIDRANGE = 0x30, ++ ACL_IPRANGE, ++ ACL_PORTRANGE, ++ ACL_FIELD_VALID, ++ ACL_FIELD_SELECT00 = 0x40, ++ ACL_FIELD_SELECT01, ++ ACL_FIELD_SELECT02, ++ ACL_FIELD_SELECT03, ++ ACL_FIELD_SELECT04, ++ ACL_FIELD_SELECT05, ++ ACL_FIELD_SELECT06, ++ ACL_FIELD_SELECT07, ++ ACL_FIELD_SELECT08, ++ ACL_FIELD_SELECT09, ++ ACL_FIELD_SELECT10, ++ ACL_FIELD_SELECT11, ++ ACL_FIELD_SELECT12, ++ ACL_FIELD_SELECT13, ++ ACL_FIELD_SELECT14, ++ ACL_FIELD_SELECT15, ++ ACL_TCPSPORT = 0x80, ++ ACL_TCPDPORT, ++ ACL_TCPFLAG, ++ ACL_UDPSPORT, ++ ACL_UDPDPORT, ++ ACL_ICMPCODETYPE, ++ ACL_IGMPTYPE, ++ ACL_SPORT, ++ ACL_DPORT, ++ ACL_IP4TOSPROTO, ++ ACL_IP4FLAGOFF, ++ ACL_TCNH, ++ ACL_CPUTAG, ++ ACL_L2PAYLOAD, ++ ACL_IP6SIP0, ++ ACL_IP6SIP1, ++ ACL_IP6SIP2, ++ ACL_IP6SIP3, ++ ACL_IP6SIP4, ++ ACL_IP6SIP5, ++ ACL_IP6SIP6, ++ ACL_IP6SIP7, ++ ACL_IP6DIP0, ++ ACL_IP6DIP1, ++ ACL_IP6DIP2, ++ ACL_IP6DIP3, ++ ACL_IP6DIP4, ++ ACL_IP6DIP5, ++ ACL_IP6DIP6, ++ ACL_IP6DIP7, ++ ACL_TYPE_END ++}; ++ ++struct acl_rule_smi_st{ ++ rtk_uint16 rule_info; ++ rtk_uint16 field[RTL8367C_ACLRULEFIELDNO]; ++}; ++ ++struct acl_rule_smi_ext_st{ ++ rtk_uint16 rule_info; ++}; ++ ++typedef struct ACLRULESMI{ ++ struct acl_rule_smi_st care_bits; ++ rtk_uint16 valid:1; ++ struct acl_rule_smi_st data_bits; ++ ++ struct acl_rule_smi_ext_st care_bits_ext; ++ struct acl_rule_smi_ext_st data_bits_ext; ++}rtl8367c_aclrulesmi; ++ ++struct acl_rule_st{ ++ rtk_uint16 active_portmsk:11; ++ rtk_uint16 type:3; ++ rtk_uint16 tag_exist:5; ++ rtk_uint16 field[RTL8367C_ACLRULEFIELDNO]; ++}; ++ ++typedef struct ACLRULE{ ++ struct acl_rule_st data_bits; ++ rtk_uint16 valid:1; ++ struct acl_rule_st care_bits; ++}rtl8367c_aclrule; ++ ++ ++typedef struct rtl8367c_acltemplate_s{ ++ rtk_uint8 field[8]; ++}rtl8367c_acltemplate_t; ++ ++ ++typedef struct acl_act_s{ ++ rtk_uint16 cvidx_cact:7; ++ rtk_uint16 cact:2; ++ rtk_uint16 svidx_sact:7; ++ rtk_uint16 sact:2; ++ ++ ++ rtk_uint16 aclmeteridx:7; ++ rtk_uint16 fwdpmask:11; ++ rtk_uint16 fwdact:2; ++ ++ rtk_uint16 pridx:7; ++ rtk_uint16 priact:2; ++ rtk_uint16 gpio_pin:4; ++ rtk_uint16 gpio_en:1; ++ rtk_uint16 aclint:1; ++ ++ rtk_uint16 cact_ext:2; ++ rtk_uint16 fwdact_ext:1; ++ rtk_uint16 tag_fmt:2; ++}rtl8367c_acl_act_t; ++ ++typedef struct acl_rule_union_s ++{ ++ rtl8367c_aclrule aclRule; ++ rtl8367c_acl_act_t aclAct; ++ rtk_uint32 aclActCtrl; ++ rtk_uint32 aclNot; ++}rtl8367c_acl_rule_union_t; ++ ++ ++extern ret_t rtl8367c_setAsicAcl(rtk_uint32 port, rtk_uint32 enabled); ++extern ret_t rtl8367c_getAsicAcl(rtk_uint32 port, rtk_uint32* pEnabled); ++extern ret_t rtl8367c_setAsicAclUnmatchedPermit(rtk_uint32 port, rtk_uint32 enabled); ++extern ret_t rtl8367c_getAsicAclUnmatchedPermit(rtk_uint32 port, rtk_uint32* pEnabled); ++extern ret_t rtl8367c_setAsicAclRule(rtk_uint32 index, rtl8367c_aclrule *pAclRule); ++extern ret_t rtl8367c_getAsicAclRule(rtk_uint32 index, rtl8367c_aclrule *pAclRule); ++extern ret_t rtl8367c_setAsicAclNot(rtk_uint32 index, rtk_uint32 not); ++extern ret_t rtl8367c_getAsicAclNot(rtk_uint32 index, rtk_uint32* pNot); ++extern ret_t rtl8367c_setAsicAclTemplate(rtk_uint32 index, rtl8367c_acltemplate_t* pAclType); ++extern ret_t rtl8367c_getAsicAclTemplate(rtk_uint32 index, rtl8367c_acltemplate_t *pAclType); ++extern ret_t rtl8367c_setAsicAclAct(rtk_uint32 index, rtl8367c_acl_act_t* pAclAct); ++extern ret_t rtl8367c_getAsicAclAct(rtk_uint32 index, rtl8367c_acl_act_t *pAclAct); ++extern ret_t rtl8367c_setAsicAclActCtrl(rtk_uint32 index, rtk_uint32 aclActCtrl); ++extern ret_t rtl8367c_getAsicAclActCtrl(rtk_uint32 index, rtk_uint32 *aclActCtrl); ++extern ret_t rtl8367c_setAsicAclPortRange(rtk_uint32 index, rtk_uint32 type, rtk_uint32 upperPort, rtk_uint32 lowerPort); ++extern ret_t rtl8367c_getAsicAclPortRange(rtk_uint32 index, rtk_uint32* pType, rtk_uint32* pUpperPort, rtk_uint32* pLowerPort); ++extern ret_t rtl8367c_setAsicAclVidRange(rtk_uint32 index, rtk_uint32 type, rtk_uint32 upperVid, rtk_uint32 lowerVid); ++extern ret_t rtl8367c_getAsicAclVidRange(rtk_uint32 index, rtk_uint32* pType, rtk_uint32* pUpperVid, rtk_uint32* pLowerVid); ++extern ret_t rtl8367c_setAsicAclIpRange(rtk_uint32 index, rtk_uint32 type, ipaddr_t upperIp, ipaddr_t lowerIp); ++extern ret_t rtl8367c_getAsicAclIpRange(rtk_uint32 index, rtk_uint32* pType, ipaddr_t* pUpperIp, ipaddr_t* pLowerIp); ++extern ret_t rtl8367c_setAsicAclGpioPolarity(rtk_uint32 polarity); ++extern ret_t rtl8367c_getAsicAclGpioPolarity(rtk_uint32* pPolarity); ++ ++#endif /*_RTL8367C_ASICDRV_ACL_H_*/ ++ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_cputag.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_cputag.h +new file mode 100644 +index 000000000000..982e2c4bfcdb +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_cputag.h +@@ -0,0 +1,49 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (¶g¤T, 08 ¤T¤ë 2017) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : Proprietary CPU-tag related function drivers ++ * ++ */ ++ ++#ifndef _RTL8367C_ASICDRV_CPUTAG_H_ ++#define _RTL8367C_ASICDRV_CPUTAG_H_ ++ ++#include ++ ++enum CPUTAG_INSERT_MODE ++{ ++ CPUTAG_INSERT_TO_ALL = 0, ++ CPUTAG_INSERT_TO_TRAPPING, ++ CPUTAG_INSERT_TO_NO, ++ CPUTAG_INSERT_END ++}; ++ ++extern ret_t rtl8367c_setAsicCputagEnable(rtk_uint32 enabled); ++extern ret_t rtl8367c_getAsicCputagEnable(rtk_uint32 *pEnabled); ++extern ret_t rtl8367c_setAsicCputagTrapPort(rtk_uint32 port); ++extern ret_t rtl8367c_getAsicCputagTrapPort(rtk_uint32 *pPort); ++extern ret_t rtl8367c_setAsicCputagPortmask(rtk_uint32 portmask); ++extern ret_t rtl8367c_getAsicCputagPortmask(rtk_uint32 *pPmsk); ++extern ret_t rtl8367c_setAsicCputagInsertMode(rtk_uint32 mode); ++extern ret_t rtl8367c_getAsicCputagInsertMode(rtk_uint32 *pMode); ++extern ret_t rtl8367c_setAsicCputagPriorityRemapping(rtk_uint32 srcPri, rtk_uint32 newPri); ++extern ret_t rtl8367c_getAsicCputagPriorityRemapping(rtk_uint32 srcPri, rtk_uint32 *pNewPri); ++extern ret_t rtl8367c_setAsicCputagPosition(rtk_uint32 position); ++extern ret_t rtl8367c_getAsicCputagPosition(rtk_uint32* pPostion); ++extern ret_t rtl8367c_setAsicCputagMode(rtk_uint32 mode); ++extern ret_t rtl8367c_getAsicCputagMode(rtk_uint32 *pMode); ++extern ret_t rtl8367c_setAsicCputagRxMinLength(rtk_uint32 mode); ++extern ret_t rtl8367c_getAsicCputagRxMinLength(rtk_uint32 *pMode); ++ ++#endif /*#ifndef _RTL8367C_ASICDRV_CPUTAG_H_*/ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_dot1x.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_dot1x.h +new file mode 100644 +index 000000000000..7639ae782b5c +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_dot1x.h +@@ -0,0 +1,52 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (¶g¤T, 08 ¤T¤ë 2017) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : 802.1X related functions ++ * ++ */ ++ ++#ifndef _RTL8367C_ASICDRV_DOT1X_H_ ++#define _RTL8367C_ASICDRV_DOT1X_H_ ++ ++#include ++ ++enum DOT1X_UNAUTH_BEHAV ++{ ++ DOT1X_UNAUTH_DROP = 0, ++ DOT1X_UNAUTH_TRAP, ++ DOT1X_UNAUTH_GVLAN, ++ DOT1X_UNAUTH_END ++}; ++ ++extern ret_t rtl8367c_setAsic1xPBEnConfig(rtk_uint32 port, rtk_uint32 enabled); ++extern ret_t rtl8367c_getAsic1xPBEnConfig(rtk_uint32 port, rtk_uint32 *pEnabled); ++extern ret_t rtl8367c_setAsic1xPBAuthConfig(rtk_uint32 port, rtk_uint32 auth); ++extern ret_t rtl8367c_getAsic1xPBAuthConfig(rtk_uint32 port, rtk_uint32 *pAuth); ++extern ret_t rtl8367c_setAsic1xPBOpdirConfig(rtk_uint32 port, rtk_uint32 opdir); ++extern ret_t rtl8367c_getAsic1xPBOpdirConfig(rtk_uint32 port, rtk_uint32 *pOpdir); ++extern ret_t rtl8367c_setAsic1xMBEnConfig(rtk_uint32 port, rtk_uint32 enabled); ++extern ret_t rtl8367c_getAsic1xMBEnConfig(rtk_uint32 port, rtk_uint32 *pEnabled); ++extern ret_t rtl8367c_setAsic1xMBOpdirConfig(rtk_uint32 opdir); ++extern ret_t rtl8367c_getAsic1xMBOpdirConfig(rtk_uint32 *pOpdir); ++extern ret_t rtl8367c_setAsic1xProcConfig(rtk_uint32 port, rtk_uint32 proc); ++extern ret_t rtl8367c_getAsic1xProcConfig(rtk_uint32 port, rtk_uint32 *pProc); ++extern ret_t rtl8367c_setAsic1xGuestVidx(rtk_uint32 index); ++extern ret_t rtl8367c_getAsic1xGuestVidx(rtk_uint32 *pIndex); ++extern ret_t rtl8367c_setAsic1xGVOpdir(rtk_uint32 enabled); ++extern ret_t rtl8367c_getAsic1xGVOpdir(rtk_uint32 *pEnabled); ++extern ret_t rtl8367c_setAsic1xTrapPriority(rtk_uint32 priority); ++extern ret_t rtl8367c_getAsic1xTrapPriority(rtk_uint32 *pPriority); ++ ++ ++#endif /*_RTL8367C_ASICDRV_DOT1X_H_*/ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_eav.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_eav.h +new file mode 100644 +index 000000000000..b633f66fb0c0 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_eav.h +@@ -0,0 +1,109 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (¶g¤T, 08 ¤T¤ë 2017) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : Ethernet AV related functions ++ * ++ */ ++ ++#ifndef _RTL8367C_ASICDRV_EAV_H_ ++#define _RTL8367C_ASICDRV_EAV_H_ ++ ++#include ++ ++typedef enum RTL8367C_PTP_TIME_CMD_E ++{ ++ PTP_TIME_READ = 0, ++ PTP_TIME_WRITE, ++ PTP_TIME_INC, ++ PTP_TIME_DEC, ++ PTP_TIME_CMD_END ++}RTL8367C_PTP_TIME_CMD; ++ ++typedef enum RTL8367C_PTP_TIME_ADJ_E ++{ ++ PTP_TIME_ADJ_INC = 0, ++ PTP_TIME_ADJ_DEC, ++ PTP_TIME_ADJ_END ++}RTL8367C_PTP_TIME_ADJ; ++ ++typedef enum RTL8367C_PTP_TIME_CTRL_E ++{ ++ PTP_TIME_CTRL_STOP = 0, ++ PTP_TIME_CTRL_START, ++ PTP_TIME_CTRL_END ++}RTL8367C_PTP_TIME_CTRL; ++ ++typedef enum RTL8367C_PTP_INTR_IMRS_E ++{ ++ PTP_IMRS_TX_SYNC, ++ PTP_IMRS_TX_DELAY_REQ, ++ PTP_IMRS_TX_PDELAY_REQ, ++ PTP_IMRS_TX_PDELAY_RESP, ++ PTP_IMRS_RX_SYNC, ++ PTP_IMRS_RX_DELAY_REQ, ++ PTP_IMRS_RX_PDELAY_REQ, ++ PTP_IMRS_RX_PDELAY_RESP, ++ PTP_IMRS_END, ++}RTL8367C_PTP_INTR_IMRS; ++ ++ ++typedef enum RTL8367C_PTP_PKT_TYPE_E ++{ ++ PTP_PKT_TYPE_TX_SYNC, ++ PTP_PKT_TYPE_TX_DELAY_REQ, ++ PTP_PKT_TYPE_TX_PDELAY_REQ, ++ PTP_PKT_TYPE_TX_PDELAY_RESP, ++ PTP_PKT_TYPE_RX_SYNC, ++ PTP_PKT_TYPE_RX_DELAY_REQ, ++ PTP_PKT_TYPE_RX_PDELAY_REQ, ++ PTP_PKT_TYPE_RX_PDELAY_RESP, ++ PTP_PKT_TYPE_END, ++}RTL8367C_PTP_PKT_TYPE; ++ ++typedef struct rtl8367c_ptp_time_stamp_s{ ++ rtk_uint32 sequence_id; ++ rtk_uint32 second; ++ rtk_uint32 nano_second; ++}rtl8367c_ptp_time_stamp_t; ++ ++#define RTL8367C_PTP_INTR_MASK 0xFF ++ ++#define RTL8367C_PTP_PORT_MASK 0x3FF ++ ++extern ret_t rtl8367c_setAsicEavMacAddress(ether_addr_t mac); ++extern ret_t rtl8367c_getAsicEavMacAddress(ether_addr_t *pMac); ++extern ret_t rtl8367c_setAsicEavTpid(rtk_uint32 outerTag, rtk_uint32 innerTag); ++extern ret_t rtl8367c_getAsicEavTpid(rtk_uint32* pOuterTag, rtk_uint32* pInnerTag); ++extern ret_t rtl8367c_setAsicEavSysTime(rtk_uint32 second, rtk_uint32 nanoSecond); ++extern ret_t rtl8367c_getAsicEavSysTime(rtk_uint32* pSecond, rtk_uint32* pNanoSecond); ++extern ret_t rtl8367c_setAsicEavSysTimeAdjust(rtk_uint32 type, rtk_uint32 second, rtk_uint32 nanoSecond); ++extern ret_t rtl8367c_setAsicEavSysTimeCtrl(rtk_uint32 control); ++extern ret_t rtl8367c_getAsicEavSysTimeCtrl(rtk_uint32* pControl); ++extern ret_t rtl8367c_setAsicEavInterruptMask(rtk_uint32 imr); ++extern ret_t rtl8367c_getAsicEavInterruptMask(rtk_uint32* pImr); ++extern ret_t rtl8367c_getAsicEavInterruptStatus(rtk_uint32* pIms); ++extern ret_t rtl8367c_setAsicEavPortInterruptStatus(rtk_uint32 port, rtk_uint32 ims); ++extern ret_t rtl8367c_getAsicEavPortInterruptStatus(rtk_uint32 port, rtk_uint32* pIms); ++extern ret_t rtl8367c_setAsicEavPortEnable(rtk_uint32 port, rtk_uint32 enabled); ++extern ret_t rtl8367c_getAsicEavPortEnable(rtk_uint32 port, rtk_uint32 *pEnabled); ++extern ret_t rtl8367c_getAsicEavPortTimeStamp(rtk_uint32 port, rtk_uint32 type, rtl8367c_ptp_time_stamp_t* timeStamp); ++ ++extern ret_t rtl8367c_setAsicEavTrap(rtk_uint32 port, rtk_uint32 enabled); ++extern ret_t rtl8367c_getAsicEavTrap(rtk_uint32 port, rtk_uint32 *pEnabled); ++extern ret_t rtl8367c_setAsicEavEnable(rtk_uint32 port, rtk_uint32 enabled); ++extern ret_t rtl8367c_getAsicEavEnable(rtk_uint32 port, rtk_uint32 *pEnabled); ++extern ret_t rtl8367c_setAsicEavPriRemapping(rtk_uint32 srcpriority, rtk_uint32 priority); ++extern ret_t rtl8367c_getAsicEavPriRemapping(rtk_uint32 srcpriority, rtk_uint32 *pPriority); ++ ++#endif /*#ifndef _RTL8367C_ASICDRV_EAV_H_*/ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_eee.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_eee.h +new file mode 100644 +index 000000000000..6bedce62b0ad +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_eee.h +@@ -0,0 +1,31 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 48989 $ ++ * $Date: 2014-07-01 15:45:24 +0800 (¶g¤G, 01 ¤C¤ë 2014) $ ++ * ++ * Purpose : RTL8370 switch high-level API for RTL8367C ++ * Feature : ++ * ++ */ ++ ++#ifndef _RTL8367C_ASICDRV_EEE_H_ ++#define _RTL8367C_ASICDRV_EEE_H_ ++ ++#include ++ ++#define EEE_OCP_PHY_ADDR (0xA5D0) ++ ++extern ret_t rtl8367c_setAsicEee100M(rtk_uint32 port, rtk_uint32 enable); ++extern ret_t rtl8367c_getAsicEee100M(rtk_uint32 port, rtk_uint32 *enable); ++extern ret_t rtl8367c_setAsicEeeGiga(rtk_uint32 port, rtk_uint32 enable); ++extern ret_t rtl8367c_getAsicEeeGiga(rtk_uint32 port, rtk_uint32 *enable); ++ ++ ++#endif /*_RTL8367C_ASICDRV_EEE_H_*/ +diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_fc.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_fc.h +new file mode 100644 +index 000000000000..ce67cdebacad +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_fc.h +@@ -0,0 +1,99 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (¶g¤T, 08 ¤T¤ë 2017) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : Flow control related functions ++ * ++ */ ++ ++#ifndef _RTL8367C_ASICDRV_FC_H_ ++#define _RTL8367C_ASICDRV_FC_H_ ++ ++#include ++ ++#define RTL8367C_PAGE_NUMBER 0x600 ++ ++ ++enum FLOW_CONTROL_TYPE ++{ ++ FC_EGRESS = 0, ++ FC_INGRESS, ++}; ++ ++enum FC_JUMBO_SIZE ++{ ++ FC_JUMBO_SIZE_3K = 0, ++ FC_JUMBO_SIZE_4K, ++ FC_JUMBO_SIZE_6K, ++ FC_JUMBO_SIZE_9K, ++ FC_JUMBO_SIZE_END, ++ ++}; ++ ++ ++extern ret_t rtl8367c_setAsicFlowControlSelect(rtk_uint32 select); ++extern ret_t rtl8367c_getAsicFlowControlSelect(rtk_uint32 *pSelect); ++extern ret_t rtl8367c_setAsicFlowControlJumboMode(rtk_uint32 enabled); ++extern ret_t rtl8367c_getAsicFlowControlJumboMode(rtk_uint32* pEnabled); ++extern ret_t rtl8367c_setAsicFlowControlJumboModeSize(rtk_uint32 size); ++extern ret_t rtl8367c_getAsicFlowControlJumboModeSize(rtk_uint32* pSize); ++extern ret_t rtl8367c_setAsicFlowControlQueueEgressEnable(rtk_uint32 port, rtk_uint32 qid, rtk_uint32 enabled); ++extern ret_t rtl8367c_getAsicFlowControlQueueEgressEnable(rtk_uint32 port, rtk_uint32 qid, rtk_uint32* pEnabled); ++extern ret_t rtl8367c_setAsicFlowControlDropAll(rtk_uint32 dropall); ++extern ret_t rtl8367c_getAsicFlowControlDropAll(rtk_uint32* pDropall); ++extern ret_t rtl8367c_setAsicFlowControlPauseAllThreshold(rtk_uint32 threshold); ++extern ret_t rtl8367c_getAsicFlowControlPauseAllThreshold(rtk_uint32 *pThreshold); ++extern ret_t rtl8367c_setAsicFlowControlSystemThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold); ++extern ret_t rtl8367c_getAsicFlowControlSystemThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold); ++extern ret_t rtl8367c_setAsicFlowControlSharedThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold); ++extern ret_t rtl8367c_getAsicFlowControlSharedThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold); ++extern ret_t rtl8367c_setAsicFlowControlPortThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold); ++extern ret_t rtl8367c_getAsicFlowControlPortThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold); ++extern ret_t rtl8367c_setAsicFlowControlPortPrivateThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold); ++extern ret_t rtl8367c_getAsicFlowControlPortPrivateThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold); ++extern ret_t rtl8367c_setAsicFlowControlSystemDropThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold); ++extern ret_t rtl8367c_getAsicFlowControlSystemDropThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold); ++extern ret_t rtl8367c_setAsicFlowControlSharedDropThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold); ++extern ret_t rtl8367c_getAsicFlowControlSharedDropThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold); ++extern ret_t rtl8367c_setAsicFlowControlPortDropThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold); ++extern ret_t rtl8367c_getAsicFlowControlPortDropThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold); ++extern ret_t rtl8367c_setAsicFlowControlPortPrivateDropThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold); ++extern ret_t rtl8367c_getAsicFlowControlPortPrivateDropThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold); ++extern ret_t rtl8367c_setAsicFlowControlSystemJumboThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold); ++extern ret_t rtl8367c_getAsicFlowControlSystemJumboThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold); ++extern ret_t rtl8367c_setAsicFlowControlSharedJumboThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold); ++extern ret_t rtl8367c_getAsicFlowControlSharedJumboThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold); ++extern ret_t rtl8367c_setAsicFlowControlPortJumboThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold); ++extern ret_t rtl8367c_getAsicFlowControlPortJumboThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold); ++extern ret_t rtl8367c_setAsicFlowControlPortPrivateJumboThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold); ++extern ret_t rtl8367c_getAsicFlowControlPortPrivateJumboThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold); ++ ++extern ret_t rtl8367c_setAsicEgressFlowControlPortDropGap(rtk_uint32 gap); ++extern ret_t rtl8367c_getAsicEgressFlowControlPortDropGap(rtk_uint32 *pGap); ++extern ret_t rtl8367c_setAsicEgressFlowControlQueueDropGap(rtk_uint32 gap); ++extern ret_t rtl8367c_getAsicEgressFlowControlQueueDropGap(rtk_uint32 *pGap); ++extern ret_t rtl8367c_setAsicEgressFlowControlPortDropThreshold(rtk_uint32 port, rtk_uint32 threshold); ++extern ret_t rtl8367c_getAsicEgressFlowControlPortDropThreshold(rtk_uint32 port, rtk_uint32 *pThreshold); ++extern ret_t rtl8367c_setAsicEgressFlowControlQueueDropThreshold(rtk_uint32 qid, rtk_uint32 threshold); ++extern ret_t rtl8367c_getAsicEgressFlowControlQueueDropThreshold(rtk_uint32 qid, rtk_uint32 *pThreshold); ++extern ret_t rtl8367c_getAsicEgressQueueEmptyPortMask(rtk_uint32 *pPortmask); ++extern ret_t rtl8367c_getAsicTotalPage(rtk_uint32 *pPageCount); ++extern ret_t rtl8367c_getAsicPulbicPage(rtk_uint32 *pPageCount); ++extern ret_t rtl8367c_getAsicMaxTotalPage(rtk_uint32 *pPageCount); ++extern ret_t rtl8367c_getAsicMaxPulbicPage(rtk_uint32 *pPageCount); ++extern ret_t rtl8367c_getAsicPortPage(rtk_uint32 port, rtk_uint32 *pPageCount); ++extern ret_t rtl8367c_getAsicPortPageMax(rtk_uint32 port, rtk_uint32 *pPageCount); ++extern ret_t rtl8367c_setAsicFlowControlEgressPortIndep(rtk_uint32 port, rtk_uint32 enable); ++extern ret_t rtl8367c_getAsicFlowControlEgressPortIndep(rtk_uint32 port, rtk_uint32 *pEnable); ++ ++#endif /*_RTL8367C_ASICDRV_FC_H_*/ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_green.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_green.h +new file mode 100644 +index 000000000000..95c1b20bd49f +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_green.h +@@ -0,0 +1,36 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (¶g¤T, 08 ¤T¤ë 2017) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : Green Ethernet related functions ++ * ++ */ ++ ++#ifndef _RTL8367C_ASICDRV_GREEN_H_ ++#define _RTL8367C_ASICDRV_GREEN_H_ ++ ++#include ++#include ++ ++#define PHY_POWERSAVING_REG 24 ++ ++extern ret_t rtl8367c_setAsicGreenTrafficType(rtk_uint32 priority, rtk_uint32 traffictype); ++extern ret_t rtl8367c_getAsicGreenTrafficType(rtk_uint32 priority, rtk_uint32* pTraffictype); ++extern ret_t rtl8367c_getAsicGreenPortPage(rtk_uint32 port, rtk_uint32* pPage); ++extern ret_t rtl8367c_getAsicGreenHighPriorityTraffic(rtk_uint32 port, rtk_uint32* pIndicator); ++extern ret_t rtl8367c_setAsicGreenHighPriorityTraffic(rtk_uint32 port); ++extern ret_t rtl8367c_setAsicGreenEthernet(rtk_uint32 port, rtk_uint32 green); ++extern ret_t rtl8367c_getAsicGreenEthernet(rtk_uint32 port, rtk_uint32* green); ++extern ret_t rtl8367c_setAsicPowerSaving(rtk_uint32 phy, rtk_uint32 enable); ++extern ret_t rtl8367c_getAsicPowerSaving(rtk_uint32 phy, rtk_uint32* enable); ++#endif /*#ifndef _RTL8367C_ASICDRV_GREEN_H_*/ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_hsb.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_hsb.h +new file mode 100644 +index 000000000000..f4f9bb377b9f +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_hsb.h +@@ -0,0 +1,43 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (¶g¤T, 08 ¤T¤ë 2017) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : Field selector related functions ++ * ++ */ ++ ++#ifndef _RTL8367C_ASICDRV__HSB_H_ ++#define _RTL8367C_ASICDRV__HSB_H_ ++ ++#include ++ ++#define RTL8367C_FIELDSEL_FORMAT_NUMBER (16) ++#define RTL8367C_FIELDSEL_MAX_OFFSET (255) ++ ++enum FIELDSEL_FORMAT_FORMAT ++{ ++ FIELDSEL_FORMAT_DEFAULT = 0, ++ FIELDSEL_FORMAT_RAW, ++ FIELDSEL_FORMAT_LLC, ++ FIELDSEL_FORMAT_IPV4, ++ FIELDSEL_FORMAT_ARP, ++ FIELDSEL_FORMAT_IPV6, ++ FIELDSEL_FORMAT_IPPAYLOAD, ++ FIELDSEL_FORMAT_L4PAYLOAD, ++ FIELDSEL_FORMAT_END ++}; ++ ++extern ret_t rtl8367c_setAsicFieldSelector(rtk_uint32 index, rtk_uint32 format, rtk_uint32 offset); ++extern ret_t rtl8367c_getAsicFieldSelector(rtk_uint32 index, rtk_uint32* pFormat, rtk_uint32* pOffset); ++ ++#endif /*_RTL8367C_ASICDRV__HSB_H_*/ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_i2c.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_i2c.h +new file mode 100644 +index 000000000000..d5b095a0e5c6 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_i2c.h +@@ -0,0 +1,47 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 38651 $ ++ * $Date: 2016-02-27 14:32:56 +0800 (©P¤T, 17 ¥|¤ë 2016) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : I2C related functions ++ * ++ */ ++ ++ ++#ifndef _RTL8367C_ASICDRV_I2C_H_ ++#define _RTL8367C_ASICDRV_I2C_H_ ++#include ++#include ++ ++ ++#define TIMEROUT_FOR_MICROSEMI (0x400) ++ ++#define GPIO_INPUT 1 ++#define GPIO_OUTPUT 2 ++ ++extern ret_t rtl8367c_setAsicI2C_checkBusIdle(void); ++extern ret_t rtl8367c_setAsicI2CStartCmd(void); ++extern ret_t rtl8367c_setAsicI2CStopCmd(void); ++extern ret_t rtl8367c_setAsicI2CTxOneCharCmd(rtk_uint8 oneChar); ++extern ret_t rtl8367c_setAsicI2CcheckRxAck(void); ++extern ret_t rtl8367c_setAsicI2CRxOneCharCmd(rtk_uint8 *pValue); ++extern ret_t rtl8367c_setAsicI2CTxAckCmd(void); ++extern ret_t rtl8367c_setAsicI2CTxNoAckCmd(void); ++extern ret_t rtl8367c_setAsicI2CSoftRSTseqCmd(void); ++extern ret_t rtl8367c_setAsicI2CGpioPinGroup(rtk_uint32 pinGroup_ID); ++extern ret_t rtl8367c_getAsicI2CGpioPinGroup(rtk_uint32 * pPinGroup_ID); ++ ++ ++ ++ ++ ++#endif /*#ifndef _RTL8367C_ASICDRV_I2C_H_*/ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_igmp.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_igmp.h +new file mode 100644 +index 000000000000..b879b6b520e4 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_igmp.h +@@ -0,0 +1,169 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : IGMP related functions ++ * ++ */ ++ ++#ifndef _RTL8367C_ASICDRV_IGMP_H_ ++#define _RTL8367C_ASICDRV_IGMP_H_ ++ ++/****************************************************************/ ++/* Header File inclusion */ ++/****************************************************************/ ++#include ++ ++#define RTL8367C_MAX_LEAVE_TIMER (7) ++#define RTL8367C_MAX_QUERY_INT (0xFFFF) ++#define RTL8367C_MAX_ROB_VAR (7) ++ ++#define RTL8367C_IGMP_GOUP_NO (256) ++#define RTL8367C_IGMP_MAX_GOUP (0xFF) ++#define RTL8367C_IGMP_GRP_BLEN (3) ++#define RTL8367C_ROUTER_PORT_INVALID (0xF) ++ ++enum RTL8367C_IGMPTABLE_FULL_OP ++{ ++ TABLE_FULL_FORWARD = 0, ++ TABLE_FULL_DROP, ++ TABLE_FULL_TRAP, ++ TABLE_FULL_OP_END ++}; ++ ++enum RTL8367C_CRC_ERR_OP ++{ ++ CRC_ERR_DROP = 0, ++ CRC_ERR_TRAP, ++ CRC_ERR_FORWARD, ++ CRC_ERR_OP_END ++}; ++ ++enum RTL8367C_IGMP_MLD_PROTOCOL_OP ++{ ++ PROTOCOL_OP_ASIC = 0, ++ PROTOCOL_OP_FLOOD, ++ PROTOCOL_OP_TRAP, ++ PROTOCOL_OP_DROP, ++ PROTOCOL_OP_END ++}; ++ ++enum RTL8367C_IGMP_MLD_BYPASS_GROUP ++{ ++ BYPASS_224_0_0_X = 0, ++ BYPASS_224_0_1_X, ++ BYPASS_239_255_255_X, ++ BYPASS_IPV6_00XX, ++ BYPASS_GROUP_END ++}; ++ ++typedef struct ++{ ++ rtk_uint32 p0_timer; ++ rtk_uint32 p1_timer; ++ rtk_uint32 p2_timer; ++ rtk_uint32 p3_timer; ++ rtk_uint32 p4_timer; ++ rtk_uint32 p5_timer; ++ rtk_uint32 p6_timer; ++ rtk_uint32 p7_timer; ++ rtk_uint32 p8_timer; ++ rtk_uint32 p9_timer; ++ rtk_uint32 p10_timer; ++ rtk_uint32 report_supp_flag; ++ ++}rtl8367c_igmpgroup; ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * This program is the proprietary software of Realtek Semiconductor ++ * Corporation and/or its licensors, and only be used, duplicated, ++ * modified or distributed under the authorized license from Realtek. ++ * ++ * ANY USE OF THE SOFTWARE OTHER THAN AS AUTHORIZED UNDER ++ * THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : IGMP related functions ++ * ++ */ ++#include ++ ++ret_t rtl8367c_setAsicIgmp(rtk_uint32 enabled); ++ret_t rtl8367c_getAsicIgmp(rtk_uint32 *pEnabled); ++ret_t rtl8367c_setAsicIpMulticastVlanLeaky(rtk_uint32 port, rtk_uint32 enabled ); ++ret_t rtl8367c_getAsicIpMulticastVlanLeaky(rtk_uint32 port, rtk_uint32 *pEnabled ); ++ret_t rtl8367c_setAsicIGMPTableFullOP(rtk_uint32 operation); ++ret_t rtl8367c_getAsicIGMPTableFullOP(rtk_uint32 *pOperation); ++ret_t rtl8367c_setAsicIGMPCRCErrOP(rtk_uint32 operation); ++ret_t rtl8367c_getAsicIGMPCRCErrOP(rtk_uint32 *pOperation); ++ret_t rtl8367c_setAsicIGMPFastLeaveEn(rtk_uint32 enabled); ++ret_t rtl8367c_getAsicIGMPFastLeaveEn(rtk_uint32 *pEnabled); ++ret_t rtl8367c_setAsicIGMPLeaveTimer(rtk_uint32 leave_timer); ++ret_t rtl8367c_getAsicIGMPLeaveTimer(rtk_uint32 *pLeave_timer); ++ret_t rtl8367c_setAsicIGMPQueryInterval(rtk_uint32 interval); ++ret_t rtl8367c_getAsicIGMPQueryInterval(rtk_uint32 *pInterval); ++ret_t rtl8367c_setAsicIGMPRobVar(rtk_uint32 rob_var); ++ret_t rtl8367c_getAsicIGMPRobVar(rtk_uint32 *pRob_var); ++ret_t rtl8367c_setAsicIGMPStaticRouterPort(rtk_uint32 pmsk); ++ret_t rtl8367c_getAsicIGMPStaticRouterPort(rtk_uint32 *pMsk); ++ret_t rtl8367c_setAsicIGMPAllowDynamicRouterPort(rtk_uint32 pmsk); ++ret_t rtl8367c_getAsicIGMPAllowDynamicRouterPort(rtk_uint32 *pPmsk); ++ret_t rtl8367c_getAsicIGMPdynamicRouterPort1(rtk_uint32 *pPort, rtk_uint32 *pTimer); ++ret_t rtl8367c_getAsicIGMPdynamicRouterPort2(rtk_uint32 *pPort, rtk_uint32 *pTimer); ++ret_t rtl8367c_setAsicIGMPSuppression(rtk_uint32 report_supp_enabled, rtk_uint32 leave_supp_enabled); ++ret_t rtl8367c_getAsicIGMPSuppression(rtk_uint32 *pReport_supp_enabled, rtk_uint32 *pLeave_supp_enabled); ++ret_t rtl8367c_setAsicIGMPQueryRX(rtk_uint32 port, rtk_uint32 allow_query); ++ret_t rtl8367c_getAsicIGMPQueryRX(rtk_uint32 port, rtk_uint32 *pAllow_query); ++ret_t rtl8367c_setAsicIGMPReportRX(rtk_uint32 port, rtk_uint32 allow_report); ++ret_t rtl8367c_getAsicIGMPReportRX(rtk_uint32 port, rtk_uint32 *pAllow_report); ++ret_t rtl8367c_setAsicIGMPLeaveRX(rtk_uint32 port, rtk_uint32 allow_leave); ++ret_t rtl8367c_getAsicIGMPLeaveRX(rtk_uint32 port, rtk_uint32 *pAllow_leave); ++ret_t rtl8367c_setAsicIGMPMRPRX(rtk_uint32 port, rtk_uint32 allow_mrp); ++ret_t rtl8367c_getAsicIGMPMRPRX(rtk_uint32 port, rtk_uint32 *pAllow_mrp); ++ret_t rtl8367c_setAsicIGMPMcDataRX(rtk_uint32 port, rtk_uint32 allow_mcdata); ++ret_t rtl8367c_getAsicIGMPMcDataRX(rtk_uint32 port, rtk_uint32 *pAllow_mcdata); ++ret_t rtl8367c_setAsicIGMPv1Opeartion(rtk_uint32 port, rtk_uint32 igmpv1_op); ++ret_t rtl8367c_getAsicIGMPv1Opeartion(rtk_uint32 port, rtk_uint32 *pIgmpv1_op); ++ret_t rtl8367c_setAsicIGMPv2Opeartion(rtk_uint32 port, rtk_uint32 igmpv2_op); ++ret_t rtl8367c_getAsicIGMPv2Opeartion(rtk_uint32 port, rtk_uint32 *pIgmpv2_op); ++ret_t rtl8367c_setAsicIGMPv3Opeartion(rtk_uint32 port, rtk_uint32 igmpv3_op); ++ret_t rtl8367c_getAsicIGMPv3Opeartion(rtk_uint32 port, rtk_uint32 *pIgmpv3_op); ++ret_t rtl8367c_setAsicMLDv1Opeartion(rtk_uint32 port, rtk_uint32 mldv1_op); ++ret_t rtl8367c_getAsicMLDv1Opeartion(rtk_uint32 port, rtk_uint32 *pMldv1_op); ++ret_t rtl8367c_setAsicMLDv2Opeartion(rtk_uint32 port, rtk_uint32 mldv2_op); ++ret_t rtl8367c_getAsicMLDv2Opeartion(rtk_uint32 port, rtk_uint32 *pMldv2_op); ++ret_t rtl8367c_setAsicIGMPPortMAXGroup(rtk_uint32 port, rtk_uint32 max_group); ++ret_t rtl8367c_getAsicIGMPPortMAXGroup(rtk_uint32 port, rtk_uint32 *pMax_group); ++ret_t rtl8367c_getAsicIGMPPortCurrentGroup(rtk_uint32 port, rtk_uint32 *pCurrent_group); ++ret_t rtl8367c_getAsicIGMPGroup(rtk_uint32 idx, rtk_uint32 *pValid, rtl8367c_igmpgroup *pGrp); ++ret_t rtl8367c_setAsicIpMulticastPortIsoLeaky(rtk_uint32 port, rtk_uint32 enabled); ++ret_t rtl8367c_getAsicIpMulticastPortIsoLeaky(rtk_uint32 port, rtk_uint32 *pEnabled); ++ret_t rtl8367c_setAsicIGMPReportLeaveFlood(rtk_uint32 flood); ++ret_t rtl8367c_getAsicIGMPReportLeaveFlood(rtk_uint32 *pFlood); ++ret_t rtl8367c_setAsicIGMPDropLeaveZero(rtk_uint32 drop); ++ret_t rtl8367c_getAsicIGMPDropLeaveZero(rtk_uint32 *pDrop); ++ret_t rtl8367c_setAsicIGMPBypassStormCTRL(rtk_uint32 bypass); ++ret_t rtl8367c_getAsicIGMPBypassStormCTRL(rtk_uint32 *pBypass); ++ret_t rtl8367c_setAsicIGMPIsoLeaky(rtk_uint32 leaky); ++ret_t rtl8367c_getAsicIGMPIsoLeaky(rtk_uint32 *pLeaky); ++ret_t rtl8367c_setAsicIGMPVLANLeaky(rtk_uint32 leaky); ++ret_t rtl8367c_getAsicIGMPVLANLeaky(rtk_uint32 *pLeaky); ++ret_t rtl8367c_setAsicIGMPBypassGroup(rtk_uint32 bypassType, rtk_uint32 enabled); ++ret_t rtl8367c_getAsicIGMPBypassGroup(rtk_uint32 bypassType, rtk_uint32 *pEnabled); ++ ++#endif /*#ifndef _RTL8367C_ASICDRV_IGMP_H_*/ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_inbwctrl.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_inbwctrl.h +new file mode 100644 +index 000000000000..10f3545322c9 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_inbwctrl.h +@@ -0,0 +1,30 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (¶g¤T, 08 ¤T¤ë 2017) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : Ingress bandwidth control related functions ++ * ++ */ ++ ++#ifndef _RTL8367C_ASICDRV_INBWCTRL_H_ ++#define _RTL8367C_ASICDRV_INBWCTRL_H_ ++ ++#include ++ ++extern ret_t rtl8367c_setAsicPortIngressBandwidth(rtk_uint32 port, rtk_uint32 bandwidth, rtk_uint32 preifg, rtk_uint32 enableFC); ++extern ret_t rtl8367c_getAsicPortIngressBandwidth(rtk_uint32 port, rtk_uint32* pBandwidth, rtk_uint32* pPreifg, rtk_uint32* pEnableFC ); ++extern ret_t rtl8367c_setAsicPortIngressBandwidthBypass(rtk_uint32 enabled); ++extern ret_t rtl8367c_getAsicPortIngressBandwidthBypass(rtk_uint32* pEnabled); ++ ++ ++#endif /*_RTL8367C_ASICDRV_INBWCTRL_H_*/ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_interrupt.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_interrupt.h +new file mode 100644 +index 000000000000..8b78014ab01b +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_interrupt.h +@@ -0,0 +1,66 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (¶g¤T, 08 ¤T¤ë 2017) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : Interrupt related functions ++ * ++ */ ++ ++#ifndef _RTL8367C_ASICDRV_INTERRUPT_H_ ++#define _RTL8367C_ASICDRV_INTERRUPT_H_ ++ ++#include ++ ++typedef enum RTL8367C_INTR_IMRS_E ++{ ++ IMRS_LINK_CHANGE, ++ IMRS_METER_EXCEED, ++ IMRS_L2_LEARN, ++ IMRS_SPEED_CHANGE, ++ IMRS_SPECIAL_CONGESTION, ++ IMRS_GREEN_FEATURE, ++ IMRS_LOOP_DETECTION, ++ IMRS_8051, ++ IMRS_CABLE_DIAG, ++ IMRS_ACL, ++ IMRS_RESERVED, /* Unused */ ++ IMRS_SLIENT, ++ IMRS_END, ++}RTL8367C_INTR_IMRS; ++ ++typedef enum RTL8367C_INTR_INDICATOR_E ++{ ++ INTRST_L2_LEARN = 0, ++ INTRST_SPEED_CHANGE, ++ INTRST_SPECIAL_CONGESTION, ++ INTRST_PORT_LINKDOWN, ++ INTRST_PORT_LINKUP, ++ INTRST_METER0_15, ++ INTRST_METER16_31, ++ INTRST_RLDP_LOOPED, ++ INTRST_RLDP_RELEASED, ++ INTRST_SYS_LEARN, ++ INTRST_END, ++}RTL8367C_INTR_INDICATOR; ++ ++extern ret_t rtl8367c_setAsicInterruptPolarity(rtk_uint32 polarity); ++extern ret_t rtl8367c_getAsicInterruptPolarity(rtk_uint32* pPolarity); ++extern ret_t rtl8367c_setAsicInterruptMask(rtk_uint32 imr); ++extern ret_t rtl8367c_getAsicInterruptMask(rtk_uint32* pImr); ++extern ret_t rtl8367c_setAsicInterruptStatus(rtk_uint32 ims); ++extern ret_t rtl8367c_getAsicInterruptStatus(rtk_uint32* pIms); ++extern ret_t rtl8367c_setAsicInterruptRelatedStatus(rtk_uint32 type, rtk_uint32 status); ++extern ret_t rtl8367c_getAsicInterruptRelatedStatus(rtk_uint32 type, rtk_uint32* pStatus); ++ ++ ++#endif /*#ifndef _RTL8367C_ASICDRV_INTERRUPT_H_*/ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_led.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_led.h +new file mode 100644 +index 000000000000..a7f8e2064320 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_led.h +@@ -0,0 +1,138 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (¶g¤T, 08 ¤T¤ë 2017) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : LED related functions ++ * ++ */ ++ ++#ifndef _RTL8367C_ASICDRV_LED_H_ ++#define _RTL8367C_ASICDRV_LED_H_ ++ ++#include ++ ++#define RTL8367C_LEDGROUPNO 3 ++#define RTL8367C_LEDGROUPMASK 0x7 ++#define RTL8367C_LED_FORCE_MODE_BASE RTL8367C_REG_CPU_FORCE_LED0_CFG0 ++#define RTL8367C_LED_FORCE_CTRL RTL8367C_REG_CPU_FORCE_LED_CFG ++ ++enum RTL8367C_LEDOP{ ++ ++ LEDOP_SCAN0=0, ++ LEDOP_SCAN1, ++ LEDOP_PARALLEL, ++ LEDOP_SERIAL, ++ LEDOP_END, ++}; ++ ++enum RTL8367C_LEDSERACT{ ++ ++ LEDSERACT_HIGH=0, ++ LEDSERACT_LOW, ++ LEDSERACT_MAX, ++}; ++ ++enum RTL8367C_LEDSER{ ++ ++ LEDSER_16G=0, ++ LEDSER_8G, ++ LEDSER_MAX, ++}; ++ ++enum RTL8367C_LEDCONF{ ++ ++ LEDCONF_LEDOFF=0, ++ LEDCONF_DUPCOL, ++ LEDCONF_LINK_ACT, ++ LEDCONF_SPD1000, ++ LEDCONF_SPD100, ++ LEDCONF_SPD10, ++ LEDCONF_SPD1000ACT, ++ LEDCONF_SPD100ACT, ++ LEDCONF_SPD10ACT, ++ LEDCONF_SPD10010ACT, ++ LEDCONF_LOOPDETECT, ++ LEDCONF_EEE, ++ LEDCONF_LINKRX, ++ LEDCONF_LINKTX, ++ LEDCONF_MASTER, ++ LEDCONF_ACT, ++ LEDCONF_END ++}; ++ ++enum RTL8367C_LEDBLINKRATE{ ++ ++ LEDBLINKRATE_32MS=0, ++ LEDBLINKRATE_64MS, ++ LEDBLINKRATE_128MS, ++ LEDBLINKRATE_256MS, ++ LEDBLINKRATE_512MS, ++ LEDBLINKRATE_1024MS, ++ LEDBLINKRATE_48MS, ++ LEDBLINKRATE_96MS, ++ LEDBLINKRATE_END, ++}; ++ ++enum RTL8367C_LEDFORCEMODE{ ++ ++ LEDFORCEMODE_NORMAL=0, ++ LEDFORCEMODE_BLINK, ++ LEDFORCEMODE_OFF, ++ LEDFORCEMODE_ON, ++ LEDFORCEMODE_END, ++}; ++ ++enum RTL8367C_LEDFORCERATE{ ++ ++ LEDFORCERATE_512MS=0, ++ LEDFORCERATE_1024MS, ++ LEDFORCERATE_2048MS, ++ LEDFORCERATE_NORMAL, ++ LEDFORCERATE_END, ++ ++}; ++ ++enum RTL8367C_LEDMODE ++{ ++ RTL8367C_LED_MODE_0 = 0, ++ RTL8367C_LED_MODE_1, ++ RTL8367C_LED_MODE_2, ++ RTL8367C_LED_MODE_3, ++ RTL8367C_LED_MODE_END ++}; ++ ++extern ret_t rtl8367c_setAsicLedIndicateInfoConfig(rtk_uint32 ledno, rtk_uint32 config); ++extern ret_t rtl8367c_getAsicLedIndicateInfoConfig(rtk_uint32 ledno, rtk_uint32* pConfig); ++extern ret_t rtl8367c_setAsicForceLed(rtk_uint32 port, rtk_uint32 group, rtk_uint32 mode); ++extern ret_t rtl8367c_getAsicForceLed(rtk_uint32 port, rtk_uint32 group, rtk_uint32* pMode); ++extern ret_t rtl8367c_setAsicForceGroupLed(rtk_uint32 groupmask, rtk_uint32 mode); ++extern ret_t rtl8367c_getAsicForceGroupLed(rtk_uint32* groupmask, rtk_uint32* pMode); ++extern ret_t rtl8367c_setAsicLedBlinkRate(rtk_uint32 blinkRate); ++extern ret_t rtl8367c_getAsicLedBlinkRate(rtk_uint32* pBlinkRate); ++extern ret_t rtl8367c_setAsicLedForceBlinkRate(rtk_uint32 blinkRate); ++extern ret_t rtl8367c_getAsicLedForceBlinkRate(rtk_uint32* pBlinkRate); ++extern ret_t rtl8367c_setAsicLedGroupMode(rtk_uint32 mode); ++extern ret_t rtl8367c_getAsicLedGroupMode(rtk_uint32* pMode); ++extern ret_t rtl8367c_setAsicLedGroupEnable(rtk_uint32 group, rtk_uint32 portmask); ++extern ret_t rtl8367c_getAsicLedGroupEnable(rtk_uint32 group, rtk_uint32 *portmask); ++extern ret_t rtl8367c_setAsicLedOperationMode(rtk_uint32 mode); ++extern ret_t rtl8367c_getAsicLedOperationMode(rtk_uint32 *mode); ++extern ret_t rtl8367c_setAsicLedSerialModeConfig(rtk_uint32 active, rtk_uint32 serimode); ++extern ret_t rtl8367c_getAsicLedSerialModeConfig(rtk_uint32 *active, rtk_uint32 *serimode); ++extern ret_t rtl8367c_setAsicLedOutputEnable(rtk_uint32 enabled); ++extern ret_t rtl8367c_getAsicLedOutputEnable(rtk_uint32 *ptr_enabled); ++extern ret_t rtl8367c_setAsicLedSerialOutput(rtk_uint32 output, rtk_uint32 pmask); ++extern ret_t rtl8367c_getAsicLedSerialOutput(rtk_uint32 *pOutput, rtk_uint32 *pPmask); ++ ++ ++#endif /*#ifndef _RTL8367C_ASICDRV_LED_H_*/ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_lut.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_lut.h +new file mode 100644 +index 000000000000..c94ea0760193 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_lut.h +@@ -0,0 +1,159 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (¶g¤T, 08 ¤T¤ë 2017) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : LUT related functions ++ * ++ */ ++ ++ ++#ifndef _RTL8367C_ASICDRV_LUT_H_ ++#define _RTL8367C_ASICDRV_LUT_H_ ++ ++#include ++ ++#define RTL8367C_LUT_AGETIMERMAX (7) ++#define RTL8367C_LUT_AGESPEEDMAX (3) ++#define RTL8367C_LUT_LEARNLIMITMAX (0x1040) ++#define RTL8367C_LUT_ADDRMAX (0x103F) ++#define RTL8367C_LUT_IPMCGRP_TABLE_MAX (0x3F) ++#define RTL8367C_LUT_ENTRY_SIZE (6) ++#define RTL8367C_LUT_BUSY_CHECK_NO (10) ++ ++#define RTL8367C_LUT_TABLE_SIZE (6) ++ ++enum RTL8367C_LUTHASHMETHOD{ ++ ++ LUTHASHMETHOD_SVL=0, ++ LUTHASHMETHOD_IVL, ++ LUTHASHMETHOD_END, ++}; ++ ++ ++enum RTL8367C_LRNOVERACT{ ++ ++ LRNOVERACT_FORWARD=0, ++ LRNOVERACT_DROP, ++ LRNOVERACT_TRAP, ++ LRNOVERACT_END, ++}; ++ ++enum RTL8367C_LUTREADMETHOD{ ++ ++ LUTREADMETHOD_MAC =0, ++ LUTREADMETHOD_ADDRESS, ++ LUTREADMETHOD_NEXT_ADDRESS, ++ LUTREADMETHOD_NEXT_L2UC, ++ LUTREADMETHOD_NEXT_L2MC, ++ LUTREADMETHOD_NEXT_L3MC, ++ LUTREADMETHOD_NEXT_L2L3MC, ++ LUTREADMETHOD_NEXT_L2UCSPA, ++}; ++ ++enum RTL8367C_FLUSHMODE ++{ ++ FLUSHMDOE_PORT = 0, ++ FLUSHMDOE_VID, ++ FLUSHMDOE_FID, ++ FLUSHMDOE_END, ++}; ++ ++enum RTL8367C_FLUSHTYPE ++{ ++ FLUSHTYPE_DYNAMIC = 0, ++ FLUSHTYPE_BOTH, ++ FLUSHTYPE_END, ++}; ++ ++ ++typedef struct LUTTABLE{ ++ ++ ipaddr_t sip; ++ ipaddr_t dip; ++ ether_addr_t mac; ++ rtk_uint16 ivl_svl:1; ++ rtk_uint16 cvid_fid:12; ++ rtk_uint16 fid:4; ++ rtk_uint16 efid:3; ++ ++ rtk_uint16 nosalearn:1; ++ rtk_uint16 da_block:1; ++ rtk_uint16 sa_block:1; ++ rtk_uint16 auth:1; ++ rtk_uint16 lut_pri:3; ++ rtk_uint16 sa_en:1; ++ rtk_uint16 fwd_en:1; ++ rtk_uint16 mbr:11; ++ rtk_uint16 spa:4; ++ rtk_uint16 age:3; ++ rtk_uint16 l3lookup:1; ++ rtk_uint16 igmp_asic:1; ++ rtk_uint16 igmpidx:8; ++ ++ rtk_uint16 lookup_hit:1; ++ rtk_uint16 lookup_busy:1; ++ rtk_uint16 address:13; ++ ++ rtk_uint16 l3vidlookup:1; ++ rtk_uint16 l3_vid:12; ++ ++ rtk_uint16 wait_time; ++ ++}rtl8367c_luttb; ++ ++extern ret_t rtl8367c_setAsicLutIpMulticastLookup(rtk_uint32 enabled); ++extern ret_t rtl8367c_getAsicLutIpMulticastLookup(rtk_uint32* pEnabled); ++extern ret_t rtl8367c_setAsicLutIpMulticastVidLookup(rtk_uint32 enabled); ++extern ret_t rtl8367c_getAsicLutIpMulticastVidLookup(rtk_uint32* pEnabled); ++extern ret_t rtl8367c_setAsicLutAgeTimerSpeed(rtk_uint32 timer, rtk_uint32 speed); ++extern ret_t rtl8367c_getAsicLutAgeTimerSpeed(rtk_uint32* pTimer, rtk_uint32* pSpeed); ++extern ret_t rtl8367c_setAsicLutCamTbUsage(rtk_uint32 enabled); ++extern ret_t rtl8367c_getAsicLutCamTbUsage(rtk_uint32* pEnabled); ++extern ret_t rtl8367c_getAsicLutCamType(rtk_uint32* pType); ++extern ret_t rtl8367c_setAsicLutLearnLimitNo(rtk_uint32 port, rtk_uint32 number); ++extern ret_t rtl8367c_getAsicLutLearnLimitNo(rtk_uint32 port, rtk_uint32* pNumber); ++extern ret_t rtl8367c_setAsicSystemLutLearnLimitNo(rtk_uint32 number); ++extern ret_t rtl8367c_getAsicSystemLutLearnLimitNo(rtk_uint32 *pNumber); ++extern ret_t rtl8367c_setAsicLutLearnOverAct(rtk_uint32 action); ++extern ret_t rtl8367c_getAsicLutLearnOverAct(rtk_uint32* pAction); ++extern ret_t rtl8367c_setAsicSystemLutLearnOverAct(rtk_uint32 action); ++extern ret_t rtl8367c_getAsicSystemLutLearnOverAct(rtk_uint32 *pAction); ++extern ret_t rtl8367c_setAsicSystemLutLearnPortMask(rtk_uint32 portmask); ++extern ret_t rtl8367c_getAsicSystemLutLearnPortMask(rtk_uint32 *pPortmask); ++extern ret_t rtl8367c_setAsicL2LookupTb(rtl8367c_luttb *pL2Table); ++extern ret_t rtl8367c_getAsicL2LookupTb(rtk_uint32 method, rtl8367c_luttb *pL2Table); ++extern ret_t rtl8367c_getAsicLutLearnNo(rtk_uint32 port, rtk_uint32* pNumber); ++extern ret_t rtl8367c_setAsicLutIpLookupMethod(rtk_uint32 type); ++extern ret_t rtl8367c_getAsicLutIpLookupMethod(rtk_uint32* pType); ++extern ret_t rtl8367c_setAsicLutForceFlush(rtk_uint32 portmask); ++extern ret_t rtl8367c_getAsicLutForceFlushStatus(rtk_uint32 *pPortmask); ++extern ret_t rtl8367c_setAsicLutFlushMode(rtk_uint32 mode); ++extern ret_t rtl8367c_getAsicLutFlushMode(rtk_uint32* pMode); ++extern ret_t rtl8367c_setAsicLutFlushType(rtk_uint32 type); ++extern ret_t rtl8367c_getAsicLutFlushType(rtk_uint32* pType); ++extern ret_t rtl8367c_setAsicLutFlushVid(rtk_uint32 vid); ++extern ret_t rtl8367c_getAsicLutFlushVid(rtk_uint32* pVid); ++extern ret_t rtl8367c_setAsicLutFlushFid(rtk_uint32 fid); ++extern ret_t rtl8367c_getAsicLutFlushFid(rtk_uint32* pFid); ++extern ret_t rtl8367c_setAsicLutDisableAging(rtk_uint32 port, rtk_uint32 disabled); ++extern ret_t rtl8367c_getAsicLutDisableAging(rtk_uint32 port, rtk_uint32 *pDisabled); ++extern ret_t rtl8367c_setAsicLutIPMCGroup(rtk_uint32 index, ipaddr_t group_addr, rtk_uint32 vid, rtk_uint32 pmask, rtk_uint32 valid); ++extern ret_t rtl8367c_getAsicLutIPMCGroup(rtk_uint32 index, ipaddr_t *pGroup_addr, rtk_uint32 *pVid, rtk_uint32 *pPmask, rtk_uint32 *pValid); ++extern ret_t rtl8367c_setAsicLutLinkDownForceAging(rtk_uint32 enable); ++extern ret_t rtl8367c_getAsicLutLinkDownForceAging(rtk_uint32 *pEnable); ++extern ret_t rtl8367c_setAsicLutFlushAll(void); ++extern ret_t rtl8367c_getAsicLutFlushAllStatus(rtk_uint32 *pBusyStatus); ++extern ret_t rtl8367c_setAsicLutIpmcFwdRouterPort(rtk_uint32 enable); ++extern ret_t rtl8367c_getAsicLutIpmcFwdRouterPort(rtk_uint32 *pEnable); ++ ++#endif /*_RTL8367C_ASICDRV_LUT_H_*/ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_meter.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_meter.h +new file mode 100644 +index 000000000000..ba761a94f8da +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_meter.h +@@ -0,0 +1,34 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (¶g¤T, 08 ¤T¤ë 2017) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : Shared meter related functions ++ * ++ */ ++ ++#ifndef _RTL8367C_ASICDRV_METER_H_ ++#define _RTL8367C_ASICDRV_METER_H_ ++ ++#include ++ ++ ++extern ret_t rtl8367c_setAsicShareMeter(rtk_uint32 index, rtk_uint32 rate, rtk_uint32 ifg); ++extern ret_t rtl8367c_getAsicShareMeter(rtk_uint32 index, rtk_uint32 *pRate, rtk_uint32 *pIfg); ++extern ret_t rtl8367c_setAsicShareMeterBucketSize(rtk_uint32 index, rtk_uint32 lbThreshold); ++extern ret_t rtl8367c_getAsicShareMeterBucketSize(rtk_uint32 index, rtk_uint32 *pLbThreshold); ++extern ret_t rtl8367c_setAsicShareMeterType(rtk_uint32 index, rtk_uint32 type); ++extern ret_t rtl8367c_getAsicShareMeterType(rtk_uint32 index, rtk_uint32 *pType); ++extern ret_t rtl8367c_setAsicMeterExceedStatus(rtk_uint32 index); ++extern ret_t rtl8367c_getAsicMeterExceedStatus(rtk_uint32 index, rtk_uint32* pStatus); ++ ++#endif /*_RTL8367C_ASICDRV_FC_H_*/ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_mib.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_mib.h +new file mode 100644 +index 000000000000..ca46e0f4706c +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_mib.h +@@ -0,0 +1,133 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (¶g¤T, 08 ¤T¤ë 2017) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : MIB related functions ++ * ++ */ ++ ++#ifndef _RTL8367C_ASICDRV_MIB_H_ ++#define _RTL8367C_ASICDRV_MIB_H_ ++ ++#include ++ ++#define RTL8367C_MIB_PORT_OFFSET (0x7C) ++#define RTL8367C_MIB_LEARNENTRYDISCARD_OFFSET (0x420) ++ ++#define RTL8367C_MAX_LOG_CNT_NUM (32) ++#define RTL8367C_MIB_MAX_LOG_CNT_IDX (RTL8367C_MAX_LOG_CNT_NUM - 1) ++#define RTL8367C_MIB_LOG_CNT_OFFSET (0x3E0) ++#define RTL8367C_MIB_MAX_LOG_MODE_IDX (16-1) ++ ++typedef enum RTL8367C_MIBCOUNTER_E{ ++ ++ /* RX */ ++ ifInOctets = 0, ++ ++ dot3StatsFCSErrors, ++ dot3StatsSymbolErrors, ++ dot3InPauseFrames, ++ dot3ControlInUnknownOpcodes, ++ ++ etherStatsFragments, ++ etherStatsJabbers, ++ ifInUcastPkts, ++ etherStatsDropEvents, ++ ++ ifInMulticastPkts, ++ ifInBroadcastPkts, ++ inMldChecksumError, ++ inIgmpChecksumError, ++ inMldSpecificQuery, ++ inMldGeneralQuery, ++ inIgmpSpecificQuery, ++ inIgmpGeneralQuery, ++ inMldLeaves, ++ inIgmpLeaves, ++ ++ /* TX/RX */ ++ etherStatsOctets, ++ ++ etherStatsUnderSizePkts, ++ etherOversizeStats, ++ etherStatsPkts64Octets, ++ etherStatsPkts65to127Octets, ++ etherStatsPkts128to255Octets, ++ etherStatsPkts256to511Octets, ++ etherStatsPkts512to1023Octets, ++ etherStatsPkts1024to1518Octets, ++ ++ /* TX */ ++ ifOutOctets, ++ ++ dot3StatsSingleCollisionFrames, ++ dot3StatMultipleCollisionFrames, ++ dot3sDeferredTransmissions, ++ dot3StatsLateCollisions, ++ etherStatsCollisions, ++ dot3StatsExcessiveCollisions, ++ dot3OutPauseFrames, ++ ifOutDiscards, ++ ++ /* ALE */ ++ dot1dTpPortInDiscards, ++ ifOutUcastPkts, ++ ifOutMulticastPkts, ++ ifOutBroadcastPkts, ++ outOampduPkts, ++ inOampduPkts, ++ ++ inIgmpJoinsSuccess, ++ inIgmpJoinsFail, ++ inMldJoinsSuccess, ++ inMldJoinsFail, ++ inReportSuppressionDrop, ++ inLeaveSuppressionDrop, ++ outIgmpReports, ++ outIgmpLeaves, ++ outIgmpGeneralQuery, ++ outIgmpSpecificQuery, ++ outMldReports, ++ outMldLeaves, ++ outMldGeneralQuery, ++ outMldSpecificQuery, ++ inKnownMulticastPkts, ++ ++ /*Device only */ ++ dot1dTpLearnedEntryDiscards, ++ RTL8367C_MIBS_NUMBER, ++ ++}RTL8367C_MIBCOUNTER; ++ ++ ++extern ret_t rtl8367c_setAsicMIBsCounterReset(rtk_uint32 greset, rtk_uint32 qmreset, rtk_uint32 pmask); ++extern ret_t rtl8367c_getAsicMIBsCounter(rtk_uint32 port,RTL8367C_MIBCOUNTER mibIdx, rtk_uint64* pCounter); ++extern ret_t rtl8367c_getAsicMIBsLogCounter(rtk_uint32 index, rtk_uint32 *pCounter); ++extern ret_t rtl8367c_getAsicMIBsControl(rtk_uint32* pMask); ++ ++extern ret_t rtl8367c_setAsicMIBsResetValue(rtk_uint32 value); ++extern ret_t rtl8367c_getAsicMIBsResetValue(rtk_uint32* value); ++ ++extern ret_t rtl8367c_setAsicMIBsUsageMode(rtk_uint32 mode); ++extern ret_t rtl8367c_getAsicMIBsUsageMode(rtk_uint32* pMode); ++extern ret_t rtl8367c_setAsicMIBsTimer(rtk_uint32 timer); ++extern ret_t rtl8367c_getAsicMIBsTimer(rtk_uint32* pTimer); ++extern ret_t rtl8367c_setAsicMIBsLoggingMode(rtk_uint32 index, rtk_uint32 mode); ++extern ret_t rtl8367c_getAsicMIBsLoggingMode(rtk_uint32 index, rtk_uint32* pMode); ++extern ret_t rtl8367c_setAsicMIBsLoggingType(rtk_uint32 index, rtk_uint32 type); ++extern ret_t rtl8367c_getAsicMIBsLoggingType(rtk_uint32 index, rtk_uint32* pType); ++extern ret_t rtl8367c_setAsicMIBsResetLoggingCounter(rtk_uint32 index); ++extern ret_t rtl8367c_setAsicMIBsLength(rtk_uint32 txLengthMode, rtk_uint32 rxLengthMode); ++extern ret_t rtl8367c_getAsicMIBsLength(rtk_uint32 *pTxLengthMode, rtk_uint32 *pRxLengthMode); ++ ++#endif /*#ifndef _RTL8367C_ASICDRV_MIB_H_*/ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_mii_mgr.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_mii_mgr.h +new file mode 100644 +index 000000000000..816763fae1e8 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_mii_mgr.h +@@ -0,0 +1,26 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76333 $ ++ * $Date: 2017-03-09 09:33:15 +0800 (¶g¥|, 09 ¤T¤ë 2017) $ ++ * ++ * Purpose : RTL8367C switch MII access ++ * Feature : MII access functions ++ * ++ */ ++ ++#ifndef _RTL8367C_ASICDRV_MII_MGR_H_ ++#define _RTL8367C_ASICDRV_MII_MGR_H_ ++ ++#define u32 unsigned int ++extern u32 mii_mgr_read(u32 phy_addr, u32 phy_register, u32 *read_data); ++extern u32 mii_mgr_write(u32 phy_addr, u32 phy_register, u32 write_data); ++ ++#endif /*_RTL8367C_ASICDRV_MII_MGR_H_*/ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_mirror.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_mirror.h +new file mode 100644 +index 000000000000..23b788d7a629 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_mirror.h +@@ -0,0 +1,49 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (¶g¤T, 08 ¤T¤ë 2017) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : Port mirror related functions ++ * ++ */ ++ ++#ifndef _RTL8367C_ASICDRV_MIRROR_H_ ++#define _RTL8367C_ASICDRV_MIRROR_H_ ++ ++#include ++ ++extern ret_t rtl8367c_setAsicPortMirror(rtk_uint32 source, rtk_uint32 monitor); ++extern ret_t rtl8367c_getAsicPortMirror(rtk_uint32 *pSource, rtk_uint32 *pMonitor); ++extern ret_t rtl8367c_setAsicPortMirrorRxFunction(rtk_uint32 enabled); ++extern ret_t rtl8367c_getAsicPortMirrorRxFunction(rtk_uint32* pEnabled); ++extern ret_t rtl8367c_setAsicPortMirrorTxFunction(rtk_uint32 enabled); ++extern ret_t rtl8367c_getAsicPortMirrorTxFunction(rtk_uint32* pEnabled); ++extern ret_t rtl8367c_setAsicPortMirrorIsolation(rtk_uint32 enabled); ++extern ret_t rtl8367c_getAsicPortMirrorIsolation(rtk_uint32* pEnabled); ++extern ret_t rtl8367c_setAsicPortMirrorPriority(rtk_uint32 priority); ++extern ret_t rtl8367c_getAsicPortMirrorPriority(rtk_uint32* pPriority); ++extern ret_t rtl8367c_setAsicPortMirrorMask(rtk_uint32 SourcePortmask); ++extern ret_t rtl8367c_getAsicPortMirrorMask(rtk_uint32 *pSourcePortmask); ++extern ret_t rtl8367c_setAsicPortMirrorVlanRxLeaky(rtk_uint32 enabled); ++extern ret_t rtl8367c_getAsicPortMirrorVlanRxLeaky(rtk_uint32* pEnabled); ++extern ret_t rtl8367c_setAsicPortMirrorVlanTxLeaky(rtk_uint32 enabled); ++extern ret_t rtl8367c_getAsicPortMirrorVlanTxLeaky(rtk_uint32* pEnabled); ++extern ret_t rtl8367c_setAsicPortMirrorIsolationRxLeaky(rtk_uint32 enabled); ++extern ret_t rtl8367c_getAsicPortMirrorIsolationRxLeaky(rtk_uint32* pEnabled); ++extern ret_t rtl8367c_setAsicPortMirrorIsolationTxLeaky(rtk_uint32 enabled); ++extern ret_t rtl8367c_getAsicPortMirrorIsolationTxLeaky(rtk_uint32* pEnabled); ++extern ret_t rtl8367c_setAsicPortMirrorRealKeep(rtk_uint32 mode); ++extern ret_t rtl8367c_getAsicPortMirrorRealKeep(rtk_uint32* pMode); ++extern ret_t rtl8367c_setAsicPortMirrorOverride(rtk_uint32 rxMirror, rtk_uint32 txMirror, rtk_uint32 aclMirror); ++extern ret_t rtl8367c_getAsicPortMirrorOverride(rtk_uint32 *pRxMirror, rtk_uint32 *pTxMirror, rtk_uint32 *pAclMirror); ++ ++#endif /*#ifndef _RTL8367C_ASICDRV_MIRROR_H_*/ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_misc.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_misc.h +new file mode 100644 +index 000000000000..c666a7b58bd5 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_misc.h +@@ -0,0 +1,34 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (¶g¤T, 08 ¤T¤ë 2017) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : Miscellaneous functions ++ * ++ */ ++ ++#ifndef _RTL8367C_ASICDRV_MISC_H_ ++#define _RTL8367C_ASICDRV_MISC_H_ ++ ++#include ++ ++extern ret_t rtl8367c_setAsicMacAddress(ether_addr_t mac); ++extern ret_t rtl8367c_getAsicMacAddress(ether_addr_t *pMac); ++extern ret_t rtl8367c_getAsicDebugInfo(rtk_uint32 port, rtk_uint32 *pDebugifo); ++extern ret_t rtl8367c_setAsicPortJamMode(rtk_uint32 mode); ++extern ret_t rtl8367c_getAsicPortJamMode(rtk_uint32* pMode); ++extern ret_t rtl8367c_setAsicMaxLengthCfg(rtk_uint32 cfgId, rtk_uint32 maxLength); ++extern ret_t rtl8367c_getAsicMaxLengthCfg(rtk_uint32 cfgId, rtk_uint32 *pMaxLength); ++extern ret_t rtl8367c_setAsicMaxLength(rtk_uint32 port, rtk_uint32 type, rtk_uint32 cfgId); ++extern ret_t rtl8367c_getAsicMaxLength(rtk_uint32 port, rtk_uint32 type, rtk_uint32 *pCfgId); ++ ++#endif /*_RTL8367C_ASICDRV_MISC_H_*/ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_oam.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_oam.h +new file mode 100644 +index 000000000000..c09dc7698868 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_oam.h +@@ -0,0 +1,47 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 42321 $ ++ * $Date: 2013-08-26 13:51:29 +0800 (¶g¤@, 26 ¤K¤ë 2013) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : OAM related functions ++ * ++ */ ++ ++#ifndef _RTL8367C_ASICDRV_OAM_H_ ++#define _RTL8367C_ASICDRV_OAM_H_ ++ ++#include ++ ++enum OAMPARACT ++{ ++ OAM_PARFWD = 0, ++ OAM_PARLB, ++ OAM_PARDISCARD, ++ OAM_PARFWDCPU ++}; ++ ++enum OAMMULACT ++{ ++ OAM_MULFWD = 0, ++ OAM_MULDISCARD, ++ OAM_MULCPU ++}; ++ ++extern ret_t rtl8367c_setAsicOamParser(rtk_uint32 port, rtk_uint32 parser); ++extern ret_t rtl8367c_getAsicOamParser(rtk_uint32 port, rtk_uint32* pParser); ++extern ret_t rtl8367c_setAsicOamMultiplexer(rtk_uint32 port, rtk_uint32 multiplexer); ++extern ret_t rtl8367c_getAsicOamMultiplexer(rtk_uint32 port, rtk_uint32* pMultiplexer); ++extern ret_t rtl8367c_setAsicOamCpuPri(rtk_uint32 priority); ++extern ret_t rtl8367c_getAsicOamCpuPri(rtk_uint32 *pPriority); ++extern ret_t rtl8367c_setAsicOamEnable(rtk_uint32 enabled); ++extern ret_t rtl8367c_getAsicOamEnable(rtk_uint32 *pEnabled); ++#endif /*_RTL8367C_ASICDRV_OAM_H_*/ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_phy.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_phy.h +new file mode 100644 +index 000000000000..e993d6edf73c +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_phy.h +@@ -0,0 +1,43 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (¶g¤T, 08 ¤T¤ë 2017) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : PHY related functions ++ * ++ */ ++ ++#ifndef _RTL8367C_ASICDRV_PHY_H_ ++#define _RTL8367C_ASICDRV_PHY_H_ ++ ++#include ++ ++#define RTL8367C_PHY_REGNOMAX 0x1F ++#define RTL8367C_PHY_EXTERNALMAX 0x7 ++ ++#define RTL8367C_PHY_BASE 0x2000 ++#define RTL8367C_PHY_EXT_BASE 0xA000 ++ ++#define RTL8367C_PHY_OFFSET 5 ++#define RTL8367C_PHY_EXT_OFFSET 9 ++ ++#define RTL8367C_PHY_PAGE_ADDRESS 31 ++ ++ ++extern ret_t rtl8367c_setAsicPHYReg(rtk_uint32 phyNo, rtk_uint32 phyAddr, rtk_uint32 regData ); ++extern ret_t rtl8367c_getAsicPHYReg(rtk_uint32 phyNo, rtk_uint32 phyAddr, rtk_uint32* pRegData ); ++extern ret_t rtl8367c_setAsicPHYOCPReg(rtk_uint32 phyNo, rtk_uint32 ocpAddr, rtk_uint32 ocpData ); ++extern ret_t rtl8367c_getAsicPHYOCPReg(rtk_uint32 phyNo, rtk_uint32 ocpAddr, rtk_uint32 *pRegData ); ++extern ret_t rtl8367c_setAsicSdsReg(rtk_uint32 sdsId, rtk_uint32 sdsReg, rtk_uint32 sdsPage, rtk_uint32 value); ++extern ret_t rtl8367c_getAsicSdsReg(rtk_uint32 sdsId, rtk_uint32 sdsReg, rtk_uint32 sdsPage, rtk_uint32 *value); ++ ++#endif /*#ifndef _RTL8367C_ASICDRV_PHY_H_*/ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_port.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_port.h +new file mode 100644 +index 000000000000..ad99d8560b7e +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_port.h +@@ -0,0 +1,237 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76333 $ ++ * $Date: 2017-03-09 09:33:15 +0800 (¶g¥|, 09 ¤T¤ë 2017) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : Port security related functions ++ * ++ */ ++ ++#ifndef _RTL8367C_ASICDRV_PORTSECURITY_H_ ++#define _RTL8367C_ASICDRV_PORTSECURITY_H_ ++ ++#include ++#include ++#include ++ ++/****************************************************************/ ++/* Type Definition */ ++/****************************************************************/ ++ ++#define RTL8367C_MAC7 7 ++#define RTL8367C_EXTNO 3 ++ ++#define RTL8367C_RTCT_PAGE (11) ++#define RTL8367C_RTCT_RESULT_A_REG (27) ++#define RTL8367C_RTCT_RESULT_B_REG (28) ++#define RTL8367C_RTCT_RESULT_C_REG (29) ++#define RTL8367C_RTCT_RESULT_D_REG (30) ++#define RTL8367C_RTCT_STATUS_REG (26) ++ ++enum L2_SECURITY_BEHAVE ++{ ++ L2_BEHAVE_FLOODING = 0, ++ L2_BEHAVE_DROP, ++ L2_BEHAVE_TRAP, ++ L2_BEHAVE_END ++}; ++ ++enum L2_UNDA_BEHAVE ++{ ++ L2_UNDA_BEHAVE_FLOODING_PMASK = 0, ++ L2_UNDA_BEHAVE_DROP, ++ L2_UNDA_BEHAVE_TRAP, ++ L2_UNDA_BEHAVE_FLOODING, ++ L2_UNDA_BEHAVE_END ++}; ++ ++enum L2_SECURITY_SA_BEHAVE ++{ ++ L2_BEHAVE_SA_FLOODING = 0, ++ L2_BEHAVE_SA_DROP, ++ L2_BEHAVE_SA_TRAP, ++ L2_BEHAVE_SA_COPY28051, ++ L2_BEHAVE_SA_END ++}; ++ ++/* enum for port current link speed */ ++enum SPEEDMODE ++{ ++ SPD_10M = 0, ++ SPD_100M, ++ SPD_1000M, ++ SPD_2500M ++}; ++ ++/* enum for mac link mode */ ++enum LINKMODE ++{ ++ MAC_NORMAL = 0, ++ MAC_FORCE, ++}; ++ ++/* enum for port current link duplex mode */ ++enum DUPLEXMODE ++{ ++ HALF_DUPLEX = 0, ++ FULL_DUPLEX ++}; ++ ++/* enum for port current MST mode */ ++enum MSTMODE ++{ ++ SLAVE_MODE= 0, ++ MASTER_MODE ++}; ++ ++ ++enum EXTMODE ++{ ++ EXT_DISABLE = 0, ++ EXT_RGMII, ++ EXT_MII_MAC, ++ EXT_MII_PHY, ++ EXT_TMII_MAC, ++ EXT_TMII_PHY, ++ EXT_GMII, ++ EXT_RMII_MAC, ++ EXT_RMII_PHY, ++ EXT_SGMII, ++ EXT_HSGMII, ++ EXT_1000X_100FX, ++ EXT_1000X, ++ EXT_100FX, ++ EXT_RGMII_2, ++ EXT_MII_MAC_2, ++ EXT_MII_PHY_2, ++ EXT_TMII_MAC_2, ++ EXT_TMII_PHY_2, ++ EXT_RMII_MAC_2, ++ EXT_RMII_PHY_2, ++ EXT_END ++}; ++ ++enum DOSTYPE ++{ ++ DOS_DAEQSA = 0, ++ DOS_LANDATTACKS, ++ DOS_BLATATTACKS, ++ DOS_SYNFINSCAN, ++ DOS_XMASCAN, ++ DOS_NULLSCAN, ++ DOS_SYN1024, ++ DOS_TCPSHORTHDR, ++ DOS_TCPFRAGERROR, ++ DOS_ICMPFRAGMENT, ++ DOS_END, ++ ++}; ++ ++typedef struct rtl8367c_port_ability_s{ ++ rtk_uint16 forcemode; ++ rtk_uint16 mstfault; ++ rtk_uint16 mstmode; ++ rtk_uint16 nway; ++ rtk_uint16 txpause; ++ rtk_uint16 rxpause; ++ rtk_uint16 link; ++ rtk_uint16 duplex; ++ rtk_uint16 speed; ++}rtl8367c_port_ability_t; ++ ++typedef struct rtl8367c_port_status_s{ ++ ++ rtk_uint16 lpi1000; ++ rtk_uint16 lpi100; ++ rtk_uint16 mstfault; ++ rtk_uint16 mstmode; ++ rtk_uint16 nway; ++ rtk_uint16 txpause; ++ rtk_uint16 rxpause; ++ rtk_uint16 link; ++ rtk_uint16 duplex; ++ rtk_uint16 speed; ++ ++}rtl8367c_port_status_t; ++ ++typedef struct rtct_result_s ++{ ++ rtk_uint32 channelAShort; ++ rtk_uint32 channelBShort; ++ rtk_uint32 channelCShort; ++ rtk_uint32 channelDShort; ++ ++ rtk_uint32 channelAOpen; ++ rtk_uint32 channelBOpen; ++ rtk_uint32 channelCOpen; ++ rtk_uint32 channelDOpen; ++ ++ rtk_uint32 channelAMismatch; ++ rtk_uint32 channelBMismatch; ++ rtk_uint32 channelCMismatch; ++ rtk_uint32 channelDMismatch; ++ ++ rtk_uint32 channelALinedriver; ++ rtk_uint32 channelBLinedriver; ++ rtk_uint32 channelCLinedriver; ++ rtk_uint32 channelDLinedriver; ++ ++ rtk_uint32 channelALen; ++ rtk_uint32 channelBLen; ++ rtk_uint32 channelCLen; ++ rtk_uint32 channelDLen; ++} rtl8367c_port_rtct_result_t; ++ ++ ++/****************************************************************/ ++/* Driver Proto Type Definition */ ++/****************************************************************/ ++extern ret_t rtl8367c_setAsicPortUnknownDaBehavior(rtk_uint32 port, rtk_uint32 behavior); ++extern ret_t rtl8367c_getAsicPortUnknownDaBehavior(rtk_uint32 port, rtk_uint32 *pBehavior); ++extern ret_t rtl8367c_setAsicPortUnknownSaBehavior(rtk_uint32 behavior); ++extern ret_t rtl8367c_getAsicPortUnknownSaBehavior(rtk_uint32 *pBehavior); ++extern ret_t rtl8367c_setAsicPortUnmatchedSaBehavior(rtk_uint32 behavior); ++extern ret_t rtl8367c_getAsicPortUnmatchedSaBehavior(rtk_uint32 *pBehavior); ++extern ret_t rtl8367c_setAsicPortUnmatchedSaMoving(rtk_uint32 port, rtk_uint32 enabled); ++extern ret_t rtl8367c_getAsicPortUnmatchedSaMoving(rtk_uint32 port, rtk_uint32 *pEnabled); ++extern ret_t rtl8367c_setAsicPortUnknownDaFloodingPortmask(rtk_uint32 portmask); ++extern ret_t rtl8367c_getAsicPortUnknownDaFloodingPortmask(rtk_uint32 *pPortmask); ++extern ret_t rtl8367c_setAsicPortUnknownMulticastFloodingPortmask(rtk_uint32 portmask); ++extern ret_t rtl8367c_getAsicPortUnknownMulticastFloodingPortmask(rtk_uint32 *pPortmask); ++extern ret_t rtl8367c_setAsicPortBcastFloodingPortmask(rtk_uint32 portmask); ++extern ret_t rtl8367c_getAsicPortBcastFloodingPortmask(rtk_uint32 *pPortmask); ++extern ret_t rtl8367c_setAsicPortBlockSpa(rtk_uint32 port, rtk_uint32 block); ++extern ret_t rtl8367c_getAsicPortBlockSpa(rtk_uint32 port, rtk_uint32 *pBlock); ++extern ret_t rtl8367c_setAsicPortForceLink(rtk_uint32 port, rtl8367c_port_ability_t *pPortAbility); ++extern ret_t rtl8367c_getAsicPortForceLink(rtk_uint32 port, rtl8367c_port_ability_t *pPortAbility); ++extern ret_t rtl8367c_getAsicPortStatus(rtk_uint32 port, rtl8367c_port_status_t *pPortStatus); ++extern ret_t rtl8367c_setAsicPortForceLinkExt(rtk_uint32 id, rtl8367c_port_ability_t *pPortAbility); ++extern ret_t rtl8367c_getAsicPortForceLinkExt(rtk_uint32 id, rtl8367c_port_ability_t *pPortAbility); ++extern ret_t rtl8367c_setAsicPortExtMode(rtk_uint32 id, rtk_uint32 mode); ++extern ret_t rtl8367c_getAsicPortExtMode(rtk_uint32 id, rtk_uint32 *pMode); ++extern ret_t rtl8367c_setAsicPortDos(rtk_uint32 type, rtk_uint32 drop); ++extern ret_t rtl8367c_getAsicPortDos(rtk_uint32 type, rtk_uint32* pDrop); ++extern ret_t rtl8367c_setAsicPortEnableAll(rtk_uint32 enable); ++extern ret_t rtl8367c_getAsicPortEnableAll(rtk_uint32 *pEnable); ++extern ret_t rtl8367c_setAsicPortSmallIpg(rtk_uint32 port, rtk_uint32 enable); ++extern ret_t rtl8367c_getAsicPortSmallIpg(rtk_uint32 port, rtk_uint32* pEnable); ++extern ret_t rtl8367c_setAsicPortLoopback(rtk_uint32 port, rtk_uint32 enable); ++extern ret_t rtl8367c_getAsicPortLoopback(rtk_uint32 port, rtk_uint32 *pEnable); ++extern ret_t rtl8367c_setAsicPortRTCTEnable(rtk_uint32 portmask); ++extern ret_t rtl8367c_setAsicPortRTCTDisable(rtk_uint32 portmask); ++extern ret_t rtl8367c_getAsicPortRTCTResult(rtk_uint32 port, rtl8367c_port_rtct_result_t *pResult); ++extern ret_t rtl8367c_sdsReset(rtk_uint32 id); ++extern ret_t rtl8367c_getSdsLinkStatus(rtk_uint32 ext_id, rtk_uint32 *pSignalDetect, rtk_uint32 *pSync, rtk_uint32 *pLink); ++extern ret_t rtl8367c_setSgmiiNway(rtk_uint32 ext_id, rtk_uint32 state); ++extern ret_t rtl8367c_getSgmiiNway(rtk_uint32 ext_id, rtk_uint32 *pState); ++ ++#endif /*_RTL8367C_ASICDRV_PORTSECURITY_H_*/ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_portIsolation.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_portIsolation.h +new file mode 100644 +index 000000000000..e23d88e81f60 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_portIsolation.h +@@ -0,0 +1,28 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (¶g¤T, 08 ¤T¤ë 2017) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : Port isolation related functions ++ * ++ */ ++ ++#ifndef _RTL8367C_ASICDRV_PORTISOLATION_H_ ++#define _RTL8367C_ASICDRV_PORTISOLATION_H_ ++ ++#include ++ ++extern ret_t rtl8367c_setAsicPortIsolationPermittedPortmask(rtk_uint32 port, rtk_uint32 permitPortmask); ++extern ret_t rtl8367c_getAsicPortIsolationPermittedPortmask(rtk_uint32 port, rtk_uint32 *pPermitPortmask); ++extern ret_t rtl8367c_setAsicPortIsolationEfid(rtk_uint32 port, rtk_uint32 efid); ++extern ret_t rtl8367c_getAsicPortIsolationEfid(rtk_uint32 port, rtk_uint32 *pEfid); ++ ++#endif /*_RTL8367C_ASICDRV_PORTISOLATION_H_*/ +diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_qos.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_qos.h +new file mode 100644 +index 000000000000..d0a8995879c3 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_qos.h +@@ -0,0 +1,96 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (¶g¤T, 08 ¤T¤ë 2017) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : QoS related functions ++ * ++ */ ++ ++#ifndef _RTL8367C_ASICDRV_QOS_H_ ++#define _RTL8367C_ASICDRV_QOS_H_ ++ ++#include ++ ++#define RTL8367C_DECISIONPRIMAX 0xFF ++ ++/* enum Priority Selection Types */ ++enum PRIDECISION ++{ ++ PRIDEC_PORT = 0, ++ PRIDEC_ACL, ++ PRIDEC_DSCP, ++ PRIDEC_1Q, ++ PRIDEC_1AD, ++ PRIDEC_CVLAN, ++ PRIDEC_DA, ++ PRIDEC_SA, ++ PRIDEC_END, ++}; ++ ++/* enum Priority Selection Index */ ++enum RTL8367C_PRIDEC_TABLE ++{ ++ PRIDEC_IDX0 = 0, ++ PRIDEC_IDX1, ++ PRIDEC_IDX_END, ++}; ++ ++enum RTL8367C_DOT1P_PRISEL ++{ ++ DOT1P_PRISEL_USER = 0, ++ DOT1P_PRISEL_TAG, ++ DOT1P_PRISEL_END ++}; ++ ++enum RTL8367C_DSCP_PRISEL ++{ ++ DSCP_PRISEL_INTERNAL = 0, ++ DSCP_PRISEL_DSCP, ++ DSCP_PRISEL_USER , ++ DSCP_PRISEL_END ++}; ++ ++ ++extern ret_t rtl8367c_setAsicRemarkingDot1pAbility(rtk_uint32 port, rtk_uint32 enabled); ++extern ret_t rtl8367c_getAsicRemarkingDot1pAbility(rtk_uint32 port, rtk_uint32* pEnabled); ++extern ret_t rtl8367c_setAsicRemarkingDot1pParameter(rtk_uint32 priority, rtk_uint32 newPriority ); ++extern ret_t rtl8367c_getAsicRemarkingDot1pParameter(rtk_uint32 priority, rtk_uint32 *pNewPriority ); ++extern ret_t rtl8367c_setAsicRemarkingDot1pSrc(rtk_uint32 type); ++extern ret_t rtl8367c_getAsicRemarkingDot1pSrc(rtk_uint32 *pType); ++extern ret_t rtl8367c_setAsicRemarkingDscpAbility(rtk_uint32 enabled); ++extern ret_t rtl8367c_getAsicRemarkingDscpAbility(rtk_uint32* pEnabled); ++extern ret_t rtl8367c_setAsicRemarkingDscpParameter(rtk_uint32 priority, rtk_uint32 newDscp ); ++extern ret_t rtl8367c_getAsicRemarkingDscpParameter(rtk_uint32 priority, rtk_uint32* pNewDscp ); ++ ++extern ret_t rtl8367c_setAsicPriorityDot1qRemapping(rtk_uint32 srcpriority, rtk_uint32 priority ); ++extern ret_t rtl8367c_getAsicPriorityDot1qRemapping(rtk_uint32 srcpriority, rtk_uint32 *pPriority ); ++extern ret_t rtl8367c_setAsicPriorityDscpBased(rtk_uint32 dscp, rtk_uint32 priority ); ++extern ret_t rtl8367c_getAsicPriorityDscpBased(rtk_uint32 dscp, rtk_uint32 *pPriority ); ++extern ret_t rtl8367c_setAsicPriorityPortBased(rtk_uint32 port, rtk_uint32 priority ); ++extern ret_t rtl8367c_getAsicPriorityPortBased(rtk_uint32 port, rtk_uint32 *pPriority ); ++extern ret_t rtl8367c_setAsicPriorityDecision(rtk_uint32 index, rtk_uint32 prisrc, rtk_uint32 decisionPri); ++extern ret_t rtl8367c_getAsicPriorityDecision(rtk_uint32 index, rtk_uint32 prisrc, rtk_uint32* pDecisionPri); ++extern ret_t rtl8367c_setAsicPriorityToQIDMappingTable(rtk_uint32 qnum, rtk_uint32 priority, rtk_uint32 qid ); ++extern ret_t rtl8367c_getAsicPriorityToQIDMappingTable(rtk_uint32 qnum, rtk_uint32 priority, rtk_uint32* pQid); ++extern ret_t rtl8367c_setAsicOutputQueueMappingIndex(rtk_uint32 port, rtk_uint32 qnum ); ++extern ret_t rtl8367c_getAsicOutputQueueMappingIndex(rtk_uint32 port, rtk_uint32 *pQnum ); ++ ++extern ret_t rtl8367c_setAsicRemarkingDscpSrc(rtk_uint32 type); ++extern ret_t rtl8367c_getAsicRemarkingDscpSrc(rtk_uint32 *pType); ++extern ret_t rtl8367c_setAsicRemarkingDscp2Dscp(rtk_uint32 dscp, rtk_uint32 rmkDscp); ++extern ret_t rtl8367c_getAsicRemarkingDscp2Dscp(rtk_uint32 dscp, rtk_uint32 *pRmkDscp); ++ ++extern ret_t rtl8367c_setAsicPortPriorityDecisionIndex(rtk_uint32 port, rtk_uint32 index ); ++extern ret_t rtl8367c_getAsicPortPriorityDecisionIndex(rtk_uint32 port, rtk_uint32 *pIndex ); ++ ++#endif /*#ifndef _RTL8367C_ASICDRV_QOS_H_*/ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_rldp.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_rldp.h +new file mode 100644 +index 000000000000..cde970b638b3 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_rldp.h +@@ -0,0 +1,60 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 42321 $ ++ * $Date: 2013-08-26 13:51:29 +0800 (¶g¤@, 26 ¤K¤ë 2013) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : RLDP related functions ++ * ++ */ ++ ++#ifndef _RTL8367C_ASICDRV_RLDP_H_ ++#define _RTL8367C_ASICDRV_RLDP_H_ ++ ++#include ++#include ++ ++extern ret_t rtl8367c_setAsicRldp(rtk_uint32 enabled); ++extern ret_t rtl8367c_getAsicRldp(rtk_uint32 *pEnabled); ++extern ret_t rtl8367c_setAsicRldpEnable8051(rtk_uint32 enabled); ++extern ret_t rtl8367c_getAsicRldpEnable8051(rtk_uint32 *pEnabled); ++extern ret_t rtl8367c_setAsicRldpCompareRandomNumber(rtk_uint32 enabled); ++extern ret_t rtl8367c_getAsicRldpCompareRandomNumber(rtk_uint32 *pEnabled); ++extern ret_t rtl8367c_setAsicRldpIndicatorSource(rtk_uint32 src); ++extern ret_t rtl8367c_getAsicRldpIndicatorSource(rtk_uint32 *pSrc); ++extern ret_t rtl8367c_setAsicRldpCheckingStatePara(rtk_uint32 retryCount, rtk_uint32 retryPeriod); ++extern ret_t rtl8367c_getAsicRldpCheckingStatePara(rtk_uint32 *pRetryCount, rtk_uint32 *pRetryPeriod); ++extern ret_t rtl8367c_setAsicRldpLoopStatePara(rtk_uint32 retryCount, rtk_uint32 retryPeriod); ++extern ret_t rtl8367c_getAsicRldpLoopStatePara(rtk_uint32 *pRetryCount, rtk_uint32 *pRetryPeriod); ++extern ret_t rtl8367c_setAsicRldpTxPortmask(rtk_uint32 portmask); ++extern ret_t rtl8367c_getAsicRldpTxPortmask(rtk_uint32 *pPortmask); ++extern ret_t rtl8367c_setAsicRldpMagicNum(ether_addr_t seed); ++extern ret_t rtl8367c_getAsicRldpMagicNum(ether_addr_t *pSeed); ++extern ret_t rtl8367c_getAsicRldpLoopedPortmask(rtk_uint32 *pPortmask); ++extern ret_t rtl8367c_setAsicRldp8051Portmask(rtk_uint32 portmask); ++extern ret_t rtl8367c_getAsicRldp8051Portmask(rtk_uint32 *pPortmask); ++ ++ ++extern ret_t rtl8367c_getAsicRldpRandomNumber(ether_addr_t *pRandNumber); ++extern ret_t rtl8367c_getAsicRldpLoopedPortPair(rtk_uint32 port, rtk_uint32 *pLoopedPair); ++extern ret_t rtl8367c_setAsicRlppTrap8051(rtk_uint32 enabled); ++extern ret_t rtl8367c_getAsicRlppTrap8051(rtk_uint32 *pEnabled); ++ ++extern ret_t rtl8367c_setAsicRldpLeaveLoopedPortmask(rtk_uint32 portmask); ++extern ret_t rtl8367c_getAsicRldpLeaveLoopedPortmask(rtk_uint32 *pPortmask); ++ ++extern ret_t rtl8367c_setAsicRldpEnterLoopedPortmask(rtk_uint32 portmask); ++extern ret_t rtl8367c_getAsicRldpEnterLoopedPortmask(rtk_uint32 *pPortmask); ++ ++extern ret_t rtl8367c_setAsicRldpTriggerMode(rtk_uint32 enabled); ++extern ret_t rtl8367c_getAsicRldpTriggerMode(rtk_uint32 *pEnabled); ++ ++#endif /*_RTL8367C_ASICDRV_RLDP_H_*/ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_rma.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_rma.h +new file mode 100644 +index 000000000000..10c707544f93 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_rma.h +@@ -0,0 +1,57 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 64716 $ ++ * $Date: 2015-12-31 16:31:55 +0800 (¶g¥|, 31 ¤Q¤G¤ë 2015) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : RMA related functions ++ * ++ */ ++ ++#ifndef _RTL8367C_ASICDRV_RMA_H_ ++#define _RTL8367C_ASICDRV_RMA_H_ ++ ++#include ++ ++#define RTL8367C_RMAMAX 0x2F ++ ++enum RTL8367C_RMAOP ++{ ++ RMAOP_FORWARD = 0, ++ RMAOP_TRAP_TO_CPU, ++ RMAOP_DROP, ++ RMAOP_FORWARD_EXCLUDE_CPU, ++ RMAOP_END ++}; ++ ++ ++typedef struct rtl8367c_rma_s{ ++ ++ rtk_uint16 operation; ++ rtk_uint16 discard_storm_filter; ++ rtk_uint16 trap_priority; ++ rtk_uint16 keep_format; ++ rtk_uint16 vlan_leaky; ++ rtk_uint16 portiso_leaky; ++ ++}rtl8367c_rma_t; ++ ++ ++extern ret_t rtl8367c_setAsicRma(rtk_uint32 index, rtl8367c_rma_t* pRmacfg); ++extern ret_t rtl8367c_getAsicRma(rtk_uint32 index, rtl8367c_rma_t* pRmacfg); ++extern ret_t rtl8367c_setAsicRmaCdp(rtl8367c_rma_t* pRmacfg); ++extern ret_t rtl8367c_getAsicRmaCdp(rtl8367c_rma_t* pRmacfg); ++extern ret_t rtl8367c_setAsicRmaCsstp(rtl8367c_rma_t* pRmacfg); ++extern ret_t rtl8367c_getAsicRmaCsstp(rtl8367c_rma_t* pRmacfg); ++extern ret_t rtl8367c_setAsicRmaLldp(rtk_uint32 enabled, rtl8367c_rma_t* pRmacfg); ++extern ret_t rtl8367c_getAsicRmaLldp(rtk_uint32 *pEnabled, rtl8367c_rma_t* pRmacfg); ++ ++#endif /*#ifndef _RTL8367C_ASICDRV_RMA_H_*/ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_scheduling.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_scheduling.h +new file mode 100644 +index 000000000000..919a4ca69262 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_scheduling.h +@@ -0,0 +1,58 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (¶g¤T, 08 ¤T¤ë 2017) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : Packet Scheduling related functions ++ * ++ */ ++ ++#ifndef _RTL8367C_ASICDRV_SCHEDULING_H_ ++#define _RTL8367C_ASICDRV_SCHEDULING_H_ ++ ++#include ++ ++#define RTL8367C_QWEIGHTMAX 0x7F ++#define RTL8367C_PORT_QUEUE_METER_INDEX_MAX 7 ++ ++/* enum for queue type */ ++enum QUEUETYPE ++{ ++ QTYPE_STRICT = 0, ++ QTYPE_WFQ, ++}; ++extern ret_t rtl8367c_setAsicLeakyBucketParameter(rtk_uint32 tick, rtk_uint32 token); ++extern ret_t rtl8367c_getAsicLeakyBucketParameter(rtk_uint32 *tick, rtk_uint32 *token); ++extern ret_t rtl8367c_setAsicAprMeter(rtk_uint32 port, rtk_uint32 qid, rtk_uint32 apridx); ++extern ret_t rtl8367c_getAsicAprMeter(rtk_uint32 port, rtk_uint32 qid, rtk_uint32 *apridx); ++extern ret_t rtl8367c_setAsicPprMeter(rtk_uint32 port, rtk_uint32 qid, rtk_uint32 ppridx); ++extern ret_t rtl8367c_getAsicPprMeter(rtk_uint32 port, rtk_uint32 qid, rtk_uint32 *ppridx); ++extern ret_t rtl8367c_setAsicAprEnable(rtk_uint32 port, rtk_uint32 aprEnable); ++extern ret_t rtl8367c_getAsicAprEnable(rtk_uint32 port, rtk_uint32 *aprEnable); ++extern ret_t rtl8367c_setAsicPprEnable(rtk_uint32 port, rtk_uint32 pprEnable); ++extern ret_t rtl8367c_getAsicPprEnable(rtk_uint32 port, rtk_uint32 *pprEnable); ++ ++extern ret_t rtl8367c_setAsicWFQWeight(rtk_uint32, rtk_uint32 queueid, rtk_uint32 weight ); ++extern ret_t rtl8367c_getAsicWFQWeight(rtk_uint32, rtk_uint32 queueid, rtk_uint32 *weight ); ++extern ret_t rtl8367c_setAsicWFQBurstSize(rtk_uint32 burstsize); ++extern ret_t rtl8367c_getAsicWFQBurstSize(rtk_uint32 *burstsize); ++ ++extern ret_t rtl8367c_setAsicQueueType(rtk_uint32 port, rtk_uint32 qid, rtk_uint32 queueType); ++extern ret_t rtl8367c_getAsicQueueType(rtk_uint32 port, rtk_uint32 qid, rtk_uint32 *queueType); ++extern ret_t rtl8367c_setAsicQueueRate(rtk_uint32 port, rtk_uint32 qid, rtk_uint32 ppridx, rtk_uint32 apridx ); ++extern ret_t rtl8367c_getAsicQueueRate(rtk_uint32 port, rtk_uint32 qid, rtk_uint32* ppridx, rtk_uint32* apridx ); ++extern ret_t rtl8367c_setAsicPortEgressRate(rtk_uint32 port, rtk_uint32 rate); ++extern ret_t rtl8367c_getAsicPortEgressRate(rtk_uint32 port, rtk_uint32 *rate); ++extern ret_t rtl8367c_setAsicPortEgressRateIfg(rtk_uint32 ifg); ++extern ret_t rtl8367c_getAsicPortEgressRateIfg(rtk_uint32 *ifg); ++ ++#endif /*_RTL8367C_ASICDRV_SCHEDULING_H_*/ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_storm.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_storm.h +new file mode 100644 +index 000000000000..3865b5225a81 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_storm.h +@@ -0,0 +1,61 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (¶g¤T, 08 ¤T¤ë 2017) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : Storm control filtering related functions ++ * ++ */ ++ ++#ifndef _RTL8367C_ASICDRV_STORM_H_ ++#define _RTL8367C_ASICDRV_STORM_H_ ++ ++#include ++ ++extern ret_t rtl8367c_setAsicStormFilterBroadcastEnable(rtk_uint32 port, rtk_uint32 enabled); ++extern ret_t rtl8367c_getAsicStormFilterBroadcastEnable(rtk_uint32 port, rtk_uint32 *pEnabled); ++extern ret_t rtl8367c_setAsicStormFilterBroadcastMeter(rtk_uint32 port, rtk_uint32 meter); ++extern ret_t rtl8367c_getAsicStormFilterBroadcastMeter(rtk_uint32 port, rtk_uint32 *pMeter); ++extern ret_t rtl8367c_setAsicStormFilterMulticastEnable(rtk_uint32 port, rtk_uint32 enabled); ++extern ret_t rtl8367c_getAsicStormFilterMulticastEnable(rtk_uint32 port, rtk_uint32 *pEnabled); ++extern ret_t rtl8367c_setAsicStormFilterMulticastMeter(rtk_uint32 port, rtk_uint32 meter); ++extern ret_t rtl8367c_getAsicStormFilterMulticastMeter(rtk_uint32 port, rtk_uint32 *pMeter); ++extern ret_t rtl8367c_setAsicStormFilterUnknownMulticastEnable(rtk_uint32 port, rtk_uint32 enabled); ++extern ret_t rtl8367c_getAsicStormFilterUnknownMulticastEnable(rtk_uint32 port, rtk_uint32 *pEnabled); ++extern ret_t rtl8367c_setAsicStormFilterUnknownMulticastMeter(rtk_uint32 port, rtk_uint32 meter); ++extern ret_t rtl8367c_getAsicStormFilterUnknownMulticastMeter(rtk_uint32 port, rtk_uint32 *pMeter); ++extern ret_t rtl8367c_setAsicStormFilterUnknownUnicastEnable(rtk_uint32 port, rtk_uint32 enabled); ++extern ret_t rtl8367c_getAsicStormFilterUnknownUnicastEnable(rtk_uint32 port, rtk_uint32 *pEnabled); ++extern ret_t rtl8367c_setAsicStormFilterUnknownUnicastMeter(rtk_uint32 port, rtk_uint32 meter); ++extern ret_t rtl8367c_getAsicStormFilterUnknownUnicastMeter(rtk_uint32 port, rtk_uint32 *pMeter); ++extern ret_t rtl8367c_setAsicStormFilterExtBroadcastMeter(rtk_uint32 meter); ++extern ret_t rtl8367c_getAsicStormFilterExtBroadcastMeter(rtk_uint32 *pMeter); ++extern ret_t rtl8367c_setAsicStormFilterExtMulticastMeter(rtk_uint32 meter); ++extern ret_t rtl8367c_getAsicStormFilterExtMulticastMeter(rtk_uint32 *pMeter); ++extern ret_t rtl8367c_setAsicStormFilterExtUnknownMulticastMeter(rtk_uint32 meter); ++extern ret_t rtl8367c_getAsicStormFilterExtUnknownMulticastMeter(rtk_uint32 *pMeter); ++extern ret_t rtl8367c_setAsicStormFilterExtUnknownUnicastMeter(rtk_uint32 meter); ++extern ret_t rtl8367c_getAsicStormFilterExtUnknownUnicastMeter(rtk_uint32 *pMeter); ++extern ret_t rtl8367c_setAsicStormFilterExtBroadcastEnable(rtk_uint32 enabled); ++extern ret_t rtl8367c_getAsicStormFilterExtBroadcastEnable(rtk_uint32 *pEnabled); ++extern ret_t rtl8367c_setAsicStormFilterExtMulticastEnable(rtk_uint32 enabled); ++extern ret_t rtl8367c_getAsicStormFilterExtMulticastEnable(rtk_uint32 *pEnabled); ++extern ret_t rtl8367c_setAsicStormFilterExtUnknownMulticastEnable(rtk_uint32 enabled); ++extern ret_t rtl8367c_getAsicStormFilterExtUnknownMulticastEnable(rtk_uint32 *pEnabled); ++extern ret_t rtl8367c_setAsicStormFilterExtUnknownUnicastEnable(rtk_uint32 enabled); ++extern ret_t rtl8367c_getAsicStormFilterExtUnknownUnicastEnable(rtk_uint32 *pEnabled); ++extern ret_t rtl8367c_setAsicStormFilterExtEnablePortMask(rtk_uint32 portmask); ++extern ret_t rtl8367c_getAsicStormFilterExtEnablePortMask(rtk_uint32 *pPortmask); ++ ++ ++#endif /*_RTL8367C_ASICDRV_STORM_H_*/ ++ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_svlan.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_svlan.h +new file mode 100644 +index 000000000000..5a6a4a83290a +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_svlan.h +@@ -0,0 +1,132 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (¶g¤T, 08 ¤T¤ë 2017) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : SVLAN related functions ++ * ++ */ ++ ++#ifndef _RTL8367C_ASICDRV_SVLAN_H_ ++#define _RTL8367C_ASICDRV_SVLAN_H_ ++ ++#include ++ ++#define RTL8367C_C2SIDXNO 128 ++#define RTL8367C_C2SIDXMAX (RTL8367C_C2SIDXNO-1) ++#define RTL8367C_MC2SIDXNO 32 ++#define RTL8367C_MC2SIDXMAX (RTL8367C_MC2SIDXNO-1) ++#define RTL8367C_SP2CIDXNO 128 ++#define RTL8367C_SP2CMAX (RTL8367C_SP2CIDXNO-1) ++ ++#define RTL8367C_SVLAN_MEMCONF_LEN 4 ++#define RTL8367C_SVLAN_MC2S_LEN 5 ++#define RTL8367C_SVLAN_SP2C_LEN 2 ++ ++enum RTL8367C_SPRISEL ++{ ++ SPRISEL_INTERNALPRI = 0, ++ SPRISEL_CTAGPRI, ++ SPRISEL_VSPRI, ++ SPRISEL_PBPRI, ++ SPRISEL_END ++}; ++ ++enum RTL8367C_SUNACCEPT ++{ ++ SUNACCEPT_DROP = 0, ++ SUNACCEPT_TRAP, ++ SUNACCEPT_SVLAN, ++ SUNACCEPT_END ++}; ++ ++enum RTL8367C_SVLAN_MC2S_MODE ++{ ++ SVLAN_MC2S_MODE_MAC = 0, ++ SVLAN_MC2S_MODE_IP, ++ SVLAN_MC2S_MODE_END ++}; ++ ++ ++typedef struct rtl8367c_svlan_memconf_s{ ++ ++ rtk_uint16 vs_member:11; ++ rtk_uint16 vs_untag:11; ++ ++ rtk_uint16 vs_fid_msti:4; ++ rtk_uint16 vs_priority:3; ++ rtk_uint16 vs_force_fid:1; ++ rtk_uint16 reserved:8; ++ ++ rtk_uint16 vs_svid:12; ++ rtk_uint16 vs_efiden:1; ++ rtk_uint16 vs_efid:3; ++ ++ ++}rtl8367c_svlan_memconf_t; ++ ++ ++typedef struct rtl8367c_svlan_mc2s_s{ ++ ++ rtk_uint16 valid:1; ++ rtk_uint16 format:1; ++ rtk_uint16 svidx:6; ++ rtk_uint32 sdata; ++ rtk_uint32 smask; ++}rtl8367c_svlan_mc2s_t; ++ ++ ++typedef struct rtl8367c_svlan_s2c_s{ ++ ++ rtk_uint16 valid:1; ++ rtk_uint16 svidx:6; ++ rtk_uint16 dstport:4; ++ rtk_uint32 vid:12; ++}rtl8367c_svlan_s2c_t; ++ ++extern ret_t rtl8367c_setAsicSvlanIngressUntag(rtk_uint32 mode); ++extern ret_t rtl8367c_getAsicSvlanIngressUntag(rtk_uint32* pMode); ++extern ret_t rtl8367c_setAsicSvlanIngressUnmatch(rtk_uint32 mode); ++extern ret_t rtl8367c_getAsicSvlanIngressUnmatch(rtk_uint32* pMode); ++extern ret_t rtl8367c_setAsicSvlanTrapPriority(rtk_uint32 priority); ++extern ret_t rtl8367c_getAsicSvlanTrapPriority(rtk_uint32* pPriority); ++extern ret_t rtl8367c_setAsicSvlanDefaultVlan(rtk_uint32 port, rtk_uint32 index); ++extern ret_t rtl8367c_getAsicSvlanDefaultVlan(rtk_uint32 port, rtk_uint32* pIndex); ++ ++extern ret_t rtl8367c_setAsicSvlanMemberConfiguration(rtk_uint32 index,rtl8367c_svlan_memconf_t* pSvlanMemCfg); ++extern ret_t rtl8367c_getAsicSvlanMemberConfiguration(rtk_uint32 index,rtl8367c_svlan_memconf_t* pSvlanMemCfg); ++ ++extern ret_t rtl8367c_setAsicSvlanPrioritySel(rtk_uint32 priSel); ++extern ret_t rtl8367c_getAsicSvlanPrioritySel(rtk_uint32* pPriSel); ++extern ret_t rtl8367c_setAsicSvlanTpid(rtk_uint32 protocolType); ++extern ret_t rtl8367c_getAsicSvlanTpid(rtk_uint32* pProtocolType); ++extern ret_t rtl8367c_setAsicSvlanUplinkPortMask(rtk_uint32 portMask); ++extern ret_t rtl8367c_getAsicSvlanUplinkPortMask(rtk_uint32* pPortmask); ++extern ret_t rtl8367c_setAsicSvlanEgressUnassign(rtk_uint32 enabled); ++extern ret_t rtl8367c_getAsicSvlanEgressUnassign(rtk_uint32* pEnabled); ++extern ret_t rtl8367c_setAsicSvlanC2SConf(rtk_uint32 index, rtk_uint32 evid, rtk_uint32 portmask, rtk_uint32 svidx); ++extern ret_t rtl8367c_getAsicSvlanC2SConf(rtk_uint32 index, rtk_uint32* pEvid, rtk_uint32* pPortmask, rtk_uint32* pSvidx); ++extern ret_t rtl8367c_setAsicSvlanMC2SConf(rtk_uint32 index,rtl8367c_svlan_mc2s_t* pSvlanMc2sCfg); ++extern ret_t rtl8367c_getAsicSvlanMC2SConf(rtk_uint32 index,rtl8367c_svlan_mc2s_t* pSvlanMc2sCfg); ++extern ret_t rtl8367c_setAsicSvlanSP2CConf(rtk_uint32 index,rtl8367c_svlan_s2c_t* pSvlanSp2cCfg); ++extern ret_t rtl8367c_getAsicSvlanSP2CConf(rtk_uint32 index,rtl8367c_svlan_s2c_t* pSvlanSp2cCfg); ++extern ret_t rtl8367c_setAsicSvlanDmacCvidSel(rtk_uint32 port, rtk_uint32 enabled); ++extern ret_t rtl8367c_getAsicSvlanDmacCvidSel(rtk_uint32 port, rtk_uint32* pEnabled); ++extern ret_t rtl8367c_setAsicSvlanUntagVlan(rtk_uint32 index); ++extern ret_t rtl8367c_getAsicSvlanUntagVlan(rtk_uint32* pIndex); ++extern ret_t rtl8367c_setAsicSvlanUnmatchVlan(rtk_uint32 index); ++extern ret_t rtl8367c_getAsicSvlanUnmatchVlan(rtk_uint32* pIndex); ++extern ret_t rtl8367c_setAsicSvlanLookupType(rtk_uint32 type); ++extern ret_t rtl8367c_getAsicSvlanLookupType(rtk_uint32* pType); ++ ++ ++#endif /*#ifndef _RTL8367C_ASICDRV_SVLAN_H_*/ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_trunking.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_trunking.h +new file mode 100644 +index 000000000000..2e3a682819db +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_trunking.h +@@ -0,0 +1,48 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (¶g¤T, 08 ¤T¤ë 2017) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : Port trunking related functions ++ * ++ */ ++ ++ ++#ifndef _RTL8367C_ASICDRV_TRUNKING_H_ ++#define _RTL8367C_ASICDRV_TRUNKING_H_ ++ ++#include ++ ++#define RTL8367C_MAX_TRUNK_GID (2) ++#define RTL8367C_TRUNKING_PORTNO (4) ++#define RTL8367C_TRUNKING1_PORTN0 (2) ++#define RTL8367C_TRUNKING_HASHVALUE_MAX (15) ++ ++extern ret_t rtl8367c_setAsicTrunkingGroup(rtk_uint32 group, rtk_uint32 portmask); ++extern ret_t rtl8367c_getAsicTrunkingGroup(rtk_uint32 group, rtk_uint32* pPortmask); ++extern ret_t rtl8367c_setAsicTrunkingFlood(rtk_uint32 enabled); ++extern ret_t rtl8367c_getAsicTrunkingFlood(rtk_uint32* pEnabled); ++extern ret_t rtl8367c_setAsicTrunkingHashSelect(rtk_uint32 hashsel); ++extern ret_t rtl8367c_getAsicTrunkingHashSelect(rtk_uint32* pHashsel); ++ ++extern ret_t rtl8367c_getAsicQeueuEmptyStatus(rtk_uint32* pPortmask); ++ ++extern ret_t rtl8367c_setAsicTrunkingMode(rtk_uint32 mode); ++extern ret_t rtl8367c_getAsicTrunkingMode(rtk_uint32* pMode); ++extern ret_t rtl8367c_setAsicTrunkingFc(rtk_uint32 group, rtk_uint32 enabled); ++extern ret_t rtl8367c_getAsicTrunkingFc(rtk_uint32 group, rtk_uint32* pEnabled); ++extern ret_t rtl8367c_setAsicTrunkingHashTable(rtk_uint32 hashval, rtk_uint32 portId); ++extern ret_t rtl8367c_getAsicTrunkingHashTable(rtk_uint32 hashval, rtk_uint32* pPortId); ++extern ret_t rtl8367c_setAsicTrunkingHashTable1(rtk_uint32 hashval, rtk_uint32 portId); ++extern ret_t rtl8367c_getAsicTrunkingHashTable1(rtk_uint32 hashval, rtk_uint32* pPortId); ++ ++#endif /*_RTL8367C_ASICDRV_TRUNKING_H_*/ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_unknownMulticast.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_unknownMulticast.h +new file mode 100644 +index 000000000000..e492e715b39b +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_unknownMulticast.h +@@ -0,0 +1,59 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (¶g¤T, 08 ¤T¤ë 2017) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : Unknown multicast related functions ++ * ++ */ ++ ++#ifndef _RTL8367C_ASICDRV_UNKNOWNMULTICAST_H_ ++#define _RTL8367C_ASICDRV_UNKNOWNMULTICAST_H_ ++ ++#include ++ ++enum L2_UNKOWN_MULTICAST_BEHAVE ++{ ++ L2_UNKOWN_MULTICAST_FLOODING = 0, ++ L2_UNKOWN_MULTICAST_DROP, ++ L2_UNKOWN_MULTICAST_TRAP, ++ L2_UNKOWN_MULTICAST_DROP_EXCLUDE_RMA, ++ L2_UNKOWN_MULTICAST_END ++}; ++ ++enum L3_UNKOWN_MULTICAST_BEHAVE ++{ ++ L3_UNKOWN_MULTICAST_FLOODING = 0, ++ L3_UNKOWN_MULTICAST_DROP, ++ L3_UNKOWN_MULTICAST_TRAP, ++ L3_UNKOWN_MULTICAST_ROUTER, ++ L3_UNKOWN_MULTICAST_END ++}; ++ ++enum MULTICASTTYPE{ ++ MULTICAST_TYPE_IPV4 = 0, ++ MULTICAST_TYPE_IPV6, ++ MULTICAST_TYPE_L2, ++ MULTICAST_TYPE_END ++}; ++ ++extern ret_t rtl8367c_setAsicUnknownL2MulticastBehavior(rtk_uint32 port, rtk_uint32 behave); ++extern ret_t rtl8367c_getAsicUnknownL2MulticastBehavior(rtk_uint32 port, rtk_uint32 *pBehave); ++extern ret_t rtl8367c_setAsicUnknownIPv4MulticastBehavior(rtk_uint32 port, rtk_uint32 behave); ++extern ret_t rtl8367c_getAsicUnknownIPv4MulticastBehavior(rtk_uint32 port, rtk_uint32 *pBehave); ++extern ret_t rtl8367c_setAsicUnknownIPv6MulticastBehavior(rtk_uint32 port, rtk_uint32 behave); ++extern ret_t rtl8367c_getAsicUnknownIPv6MulticastBehavior(rtk_uint32 port, rtk_uint32 *pBehave); ++extern ret_t rtl8367c_setAsicUnknownMulticastTrapPriority(rtk_uint32 priority); ++extern ret_t rtl8367c_getAsicUnknownMulticastTrapPriority(rtk_uint32 *pPriority); ++ ++#endif /*_RTL8367C_ASICDRV_UNKNOWNMULTICAST_H_*/ ++ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_vlan.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_vlan.h +new file mode 100644 +index 000000000000..61848650b579 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_vlan.h +@@ -0,0 +1,157 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (¶g¤T, 08 ¤T¤ë 2017) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : VLAN related functions ++ * ++ */ ++ ++ ++#ifndef _RTL8367C_ASICDRV_VLAN_H_ ++#define _RTL8367C_ASICDRV_VLAN_H_ ++ ++/****************************************************************/ ++/* Header File inclusion */ ++/****************************************************************/ ++#include ++ ++/****************************************************************/ ++/* Constant Definition */ ++/****************************************************************/ ++#define RTL8367C_PROTOVLAN_GIDX_MAX 3 ++#define RTL8367C_PROTOVLAN_GROUPNO 4 ++ ++#define RTL8367C_VLAN_BUSY_CHECK_NO (10) ++ ++#define RTL8367C_VLAN_MBRCFG_LEN (4) ++#define RTL8367C_VLAN_4KTABLE_LEN (3) ++ ++/****************************************************************/ ++/* Type Definition */ ++/****************************************************************/ ++typedef struct VLANCONFIGUSER ++{ ++ rtk_uint16 evid; ++ rtk_uint16 mbr; ++ rtk_uint16 fid_msti; ++ rtk_uint16 envlanpol; ++ rtk_uint16 meteridx; ++ rtk_uint16 vbpen; ++ rtk_uint16 vbpri; ++}rtl8367c_vlanconfiguser; ++ ++typedef struct USER_VLANTABLE{ ++ ++ rtk_uint16 vid; ++ rtk_uint16 mbr; ++ rtk_uint16 untag; ++ rtk_uint16 fid_msti; ++ rtk_uint16 envlanpol; ++ rtk_uint16 meteridx; ++ rtk_uint16 vbpen; ++ rtk_uint16 vbpri; ++ rtk_uint16 ivl_svl; ++ ++}rtl8367c_user_vlan4kentry; ++ ++typedef enum ++{ ++ FRAME_TYPE_BOTH = 0, ++ FRAME_TYPE_TAGGED_ONLY, ++ FRAME_TYPE_UNTAGGED_ONLY, ++ FRAME_TYPE_MAX_BOUND ++} rtl8367c_accframetype; ++ ++typedef enum ++{ ++ EG_TAG_MODE_ORI = 0, ++ EG_TAG_MODE_KEEP, ++ EG_TAG_MODE_PRI_TAG, ++ EG_TAG_MODE_REAL_KEEP, ++ EG_TAG_MODE_END ++} rtl8367c_egtagmode; ++ ++typedef enum ++{ ++ PPVLAN_FRAME_TYPE_ETHERNET = 0, ++ PPVLAN_FRAME_TYPE_LLC, ++ PPVLAN_FRAME_TYPE_RFC1042, ++ PPVLAN_FRAME_TYPE_END ++} rtl8367c_provlan_frametype; ++ ++enum RTL8367C_STPST ++{ ++ STPST_DISABLED = 0, ++ STPST_BLOCKING, ++ STPST_LEARNING, ++ STPST_FORWARDING ++}; ++ ++enum RTL8367C_RESVIDACT ++{ ++ RES_VID_ACT_UNTAG = 0, ++ RES_VID_ACT_TAG, ++ RES_VID_ACT_END ++}; ++ ++typedef struct ++{ ++ rtl8367c_provlan_frametype frameType; ++ rtk_uint32 etherType; ++} rtl8367c_protocolgdatacfg; ++ ++typedef struct ++{ ++ rtk_uint32 valid; ++ rtk_uint32 vlan_idx; ++ rtk_uint32 priority; ++} rtl8367c_protocolvlancfg; ++ ++extern ret_t rtl8367c_setAsicVlanMemberConfig(rtk_uint32 index, rtl8367c_vlanconfiguser *pVlanCg); ++extern ret_t rtl8367c_getAsicVlanMemberConfig(rtk_uint32 index, rtl8367c_vlanconfiguser *pVlanCg); ++extern ret_t rtl8367c_setAsicVlan4kEntry(rtl8367c_user_vlan4kentry *pVlan4kEntry ); ++extern ret_t rtl8367c_getAsicVlan4kEntry(rtl8367c_user_vlan4kentry *pVlan4kEntry ); ++extern ret_t rtl8367c_setAsicVlanAccpetFrameType(rtk_uint32 port, rtl8367c_accframetype frameType); ++extern ret_t rtl8367c_getAsicVlanAccpetFrameType(rtk_uint32 port, rtl8367c_accframetype *pFrameType); ++extern ret_t rtl8367c_setAsicVlanIngressFilter(rtk_uint32 port, rtk_uint32 enabled); ++extern ret_t rtl8367c_getAsicVlanIngressFilter(rtk_uint32 port, rtk_uint32 *pEnable); ++extern ret_t rtl8367c_setAsicVlanEgressTagMode(rtk_uint32 port, rtl8367c_egtagmode tagMode); ++extern ret_t rtl8367c_getAsicVlanEgressTagMode(rtk_uint32 port, rtl8367c_egtagmode *pTagMode); ++extern ret_t rtl8367c_setAsicVlanPortBasedVID(rtk_uint32 port, rtk_uint32 index, rtk_uint32 pri); ++extern ret_t rtl8367c_getAsicVlanPortBasedVID(rtk_uint32 port, rtk_uint32 *pIndex, rtk_uint32 *pPri); ++extern ret_t rtl8367c_setAsicVlanProtocolBasedGroupData(rtk_uint32 index, rtl8367c_protocolgdatacfg *pPbCfg); ++extern ret_t rtl8367c_getAsicVlanProtocolBasedGroupData(rtk_uint32 index, rtl8367c_protocolgdatacfg *pPbCfg); ++extern ret_t rtl8367c_setAsicVlanPortAndProtocolBased(rtk_uint32 port, rtk_uint32 index, rtl8367c_protocolvlancfg *pPpbCfg); ++extern ret_t rtl8367c_getAsicVlanPortAndProtocolBased(rtk_uint32 port, rtk_uint32 index, rtl8367c_protocolvlancfg *pPpbCfg); ++extern ret_t rtl8367c_setAsicVlanFilter(rtk_uint32 enabled); ++extern ret_t rtl8367c_getAsicVlanFilter(rtk_uint32* pEnabled); ++ ++extern ret_t rtl8367c_setAsicPortBasedFid(rtk_uint32 port, rtk_uint32 fid); ++extern ret_t rtl8367c_getAsicPortBasedFid(rtk_uint32 port, rtk_uint32* pFid); ++extern ret_t rtl8367c_setAsicPortBasedFidEn(rtk_uint32 port, rtk_uint32 enabled); ++extern ret_t rtl8367c_getAsicPortBasedFidEn(rtk_uint32 port, rtk_uint32* pEnabled); ++extern ret_t rtl8367c_setAsicSpanningTreeStatus(rtk_uint32 port, rtk_uint32 msti, rtk_uint32 state); ++extern ret_t rtl8367c_getAsicSpanningTreeStatus(rtk_uint32 port, rtk_uint32 msti, rtk_uint32* pState); ++extern ret_t rtl8367c_setAsicVlanUntagDscpPriorityEn(rtk_uint32 enabled); ++extern ret_t rtl8367c_getAsicVlanUntagDscpPriorityEn(rtk_uint32* enabled); ++extern ret_t rtl8367c_setAsicVlanTransparent(rtk_uint32 port, rtk_uint32 portmask); ++extern ret_t rtl8367c_getAsicVlanTransparent(rtk_uint32 port, rtk_uint32 *pPortmask); ++extern ret_t rtl8367c_setAsicVlanEgressKeep(rtk_uint32 port, rtk_uint32 portmask); ++extern ret_t rtl8367c_getAsicVlanEgressKeep(rtk_uint32 port, rtk_uint32* pPortmask); ++extern ret_t rtl8367c_setReservedVidAction(rtk_uint32 vid0Action, rtk_uint32 vid4095Action); ++extern ret_t rtl8367c_getReservedVidAction(rtk_uint32 *pVid0Action, rtk_uint32 *pVid4095Action); ++extern ret_t rtl8367c_setRealKeepRemarkEn(rtk_uint32 enabled); ++extern ret_t rtl8367c_getRealKeepRemarkEn(rtk_uint32 *pEnabled); ++extern ret_t rtl8367c_resetVlan(void); ++ ++#endif /*#ifndef _RTL8367C_ASICDRV_VLAN_H_*/ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_base.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_base.h +new file mode 100644 +index 000000000000..7a70e158fa6f +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_base.h +@@ -0,0 +1,596 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (¶g¤T, 08 ¤T¤ë 2017) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : Register MACRO related definition ++ * ++ */ ++ ++#ifndef _RTL8367C_BASE_H_ ++#define _RTL8367C_BASE_H_ ++ ++#include ++ ++/* (16'h0000) port_reg */ ++ ++#define RTL8367C_PORT_SPECIAL_CONGEST_MODE_TIMER_BASE RTL8367C_REG_PKTGEN_PORT0_TIMER ++#define RTL8367C_PORT_SPECIAL_CONGEST_MODE_TIMER_REG(port) (RTL8367C_PORT_SPECIAL_CONGEST_MODE_TIMER_BASE + (port << 5)) ++ ++#define RTL8367C_PORT_MISC_CFG_BASE RTL8367C_REG_PORT0_MISC_CFG ++#define RTL8367C_PORT_MISC_CFG_REG(port) (RTL8367C_PORT_MISC_CFG_BASE + (port << 5)) ++#define RTL8367C_1QREMARK_ENABLE_OFFSET RTL8367C_PORT0_MISC_CFG_DOT1Q_REMARK_ENABLE_OFFSET ++#define RTL8367C_1QREMARK_ENABLE_MASK RTL8367C_PORT0_MISC_CFG_DOT1Q_REMARK_ENABLE_MASK ++ ++#define RTL8367C_INGRESSBW_PORT_IFG_MASK RTL8367C_PORT0_MISC_CFG_INGRESSBW_IFG_MASK ++#define RTL8367C_VLAN_EGRESS_MDOE_MASK RTL8367C_PORT0_MISC_CFG_VLAN_EGRESS_MODE_MASK ++#define RTL8367C_SPECIALCONGEST_SUSTAIN_TIMER_MASK RTL8367C_PORT0_MISC_CFG_CONGESTION_SUSTAIN_TIME_MASK ++ ++#define RTL8367C_INGRESSBW_PORT_RATE_LSB_BASE RTL8367C_REG_INGRESSBW_PORT0_RATE_CTRL0 ++#define RTL8367C_INGRESSBW_PORT_RATE_LSB_REG(port) (RTL8367C_INGRESSBW_PORT_RATE_LSB_BASE + (port << 5)) ++ ++#define RTL8367C_PORT_SMALL_IPG_REG(port) (RTL8367C_REG_PORT0_MISC_CFG + (port*0x20)) ++ ++#define RTL8367C_PORT_EEE_CFG_BASE RTL8367C_REG_PORT0_EEECFG ++#define RTL8367C_PORT_EEE_CFG_REG(port) (RTL8367C_REG_PORT0_EEECFG + (port << 5)) ++#define RTL8367C_PORT_EEE_100M_OFFSET RTL8367C_PORT0_EEECFG_EEE_100M_OFFSET ++#define RTL8367C_PORT_EEE_100M_MASK RTL8367C_PORT0_EEECFG_EEE_100M_MASK ++#define RTL8367C_PORT_EEE_GIGA_OFFSET RTL8367C_PORT0_EEECFG_EEE_GIGA_500M_OFFSET ++#define RTL8367C_PORT_EEE_GIGA_MASK RTL8367C_PORT0_EEECFG_EEE_GIGA_500M_MASK ++ ++ ++/* (16'h0200) outq_reg */ ++ ++#define RTL8367C_FLOWCTRL_QUEUE_DROP_ON_BASE RTL8367C_REG_FLOWCTRL_QUEUE0_DROP_ON ++#define RTL8367C_FLOWCTRL_QUEUE_DROP_ON_REG(queue) (RTL8367C_FLOWCTRL_QUEUE_DROP_ON_BASE + queue) ++#define RTL8367C_FLOWCTRL_QUEUE_DROP_ON_MASK RTL8367C_FLOWCTRL_QUEUE0_DROP_ON_MASK ++ ++#define RTL8367C_FLOWCTRL_PORT_DROP_ON_BASE RTL8367C_REG_FLOWCTRL_PORT0_DROP_ON ++#define RTL8367C_FLOWCTRL_PORT_DROP_ON_REG(PORT) (RTL8367C_FLOWCTRL_PORT_DROP_ON_BASE + PORT) ++#define RTL8367C_FLOWCTRL_PORT_DROP_ON_MASK RTL8367C_FLOWCTRL_PORT0_DROP_ON_MASK ++ ++#define RTL8367C_FLOWCTRL_PORT_GAP_REG RTL8367C_REG_FLOWCTRL_PORT_GAP ++#define RTL8367C_FLOWCTRL_QUEUE_GAP_REG RTL8367C_REG_FLOWCTRL_QUEUE_GAP ++#define RTL8367C_FLOWCTRL_PORT_QEMPTY_REG RTL8367C_REG_PORT_QEMPTY ++ ++/* (16'h0300) sch_reg */ ++ ++#define RTL8367C_SCHEDULE_WFQ_BURST_SIZE_REG RTL8367C_REG_SCHEDULE_WFQ_BURST_SIZE ++ ++#define RTL8367C_SCHEDULE_QUEUE_TYPE_BASE RTL8367C_REG_SCHEDULE_QUEUE_TYPE_CTRL0 ++#define RTL8367C_SCHEDULE_QUEUE_TYPE_REG(port) (RTL8367C_SCHEDULE_QUEUE_TYPE_BASE + (port >> 1)) ++#define RTL8367C_SCHEDULE_QUEUE_TYPE_OFFSET(port, queue) (((port & 0x1) << 3) + queue) ++#define RTL8367C_SCHEDULE_QUEUE_TYPE_MASK(port, queue) RTL8367C_SCHEDULE_QUEUE_TYPE_OFFSET(port, queue) ++ ++#define RTL8367C_SCHEDULE_PORT_QUEUE_WFQ_WEIGHT_BASE RTL8367C_REG_SCHEDULE_PORT0_QUEUE0_WFQ_WEIGHT ++#define RTL8367C_SCHEDULE_PORT_QUEUE_WFQ_WEIGHT_REG(port, queue) (RTL8367C_SCHEDULE_PORT_QUEUE_WFQ_WEIGHT_BASE + (port << 3) + queue) ++ ++#define RTL8367C_SCHEDULE_APR_CTRL_REG RTL8367C_REG_SCHEDULE_APR_CTRL0 ++#define RTL8367C_SCHEDULE_APR_CTRL_OFFSET(port) (port) ++#define RTL8367C_SCHEDULE_APR_CTRL_MASK(port) (1 << RTL8367C_SCHEDULE_APR_CTRL_OFFSET(port)) ++ ++#define RTL8367C_SCHEDULE_PORT_APR_METER_BASE RTL8367C_REG_SCHEDULE_PORT0_APR_METER_CTRL0 ++#define RTL8367C_SCHEDULE_PORT_APR_METER_REG(port, queue) (RTL8367C_SCHEDULE_PORT_APR_METER_BASE + (port << 2) + (queue / 5)) ++#define RTL8367C_SCHEDULE_PORT_APR_METER_OFFSET(queue) (3 * (queue % 5)) ++#define RTL8367C_SCHEDULE_PORT_APR_METER_MASK(queue) (RTL8367C_SCHEDULE_PORT0_APR_METER_CTRL0_QUEUE0_APR_METER_MASK << RTL8367C_SCHEDULE_PORT_APR_METER_OFFSET(queue)) ++ ++#define RTL8367C_PORT_EGRESSBW_LSB_BASE RTL8367C_REG_PORT0_EGRESSBW_CTRL0 ++#define RTL8367C_PORT_EGRESSBW_LSB_REG(port) (RTL8367C_PORT_EGRESSBW_LSB_BASE + (port << 1)) ++ ++#define RTL8367C_PORT_EGRESSBW_MSB_BASE RTL8367C_REG_PORT0_EGRESSBW_CTRL1 ++#define RTL8367C_PORT_EGRESSBW_MSB_REG(port) (RTL8367C_PORT_EGRESSBW_MSB_BASE + (port << 1)) ++ ++/* (16'h0500) table_reg */ ++ ++#define RTL8367C_TABLE_ACCESS_CTRL_REG RTL8367C_REG_TABLE_ACCESS_CTRL ++ ++#define RTL8367C_TABLE_ACCESS_ADDR_REG RTL8367C_REG_TABLE_ACCESS_ADDR ++ ++#define RTL8367C_TABLE_ACCESS_STATUS_REG RTL8367C_REG_TABLE_LUT_ADDR ++ ++#define RTL8367C_TABLE_ACCESS_WRDATA_BASE RTL8367C_REG_TABLE_WRITE_DATA0 ++#define RTL8367C_TABLE_ACCESS_WRDATA_REG(index) (RTL8367C_TABLE_ACCESS_WRDATA_BASE + index) ++ ++#define RTL8367C_TABLE_ACCESS_RDDATA_BASE RTL8367C_REG_TABLE_READ_DATA0 ++#define RTL8367C_TABLE_ACCESS_RDDATA_REG(index) (RTL8367C_TABLE_ACCESS_RDDATA_BASE + index) ++ ++ ++ ++/* (16'h0600) acl_reg */ ++ ++#define RTL8367C_ACL_RULE_TEMPLATE_CTRL_BASE RTL8367C_REG_ACL_RULE_TEMPLATE0_CTRL0 ++#define RTL8367C_ACL_RULE_TEMPLATE_CTRL_REG(template) (RTL8367C_ACL_RULE_TEMPLATE_CTRL_BASE + template * 0x4) ++#define RTL8367C_ACL_TEMPLATE_FIELD_OFFSET(field) ((field & 0x01) <<3) ++#define RTL8367C_ACL_TEMPLATE_FIELD_MASK(field) (0x3F << RTL8367C_ACL_TEMPLATE_FIELD_OFFSET(field)) ++ ++#define RTL8367C_ACL_ACTION_CTRL_BASE RTL8367C_REG_ACL_ACTION_CTRL0 ++#define RTL8367C_ACL_ACTION_CTRL_REG(rule) (RTL8367C_ACL_ACTION_CTRL_BASE + (rule >> 1)) ++#define RTL8367C_ACL_ACTION_CTRL2_BASE RTL8367C_REG_ACL_ACTION_CTRL32 ++#define RTL8367C_ACL_ACTION_CTRL2_REG(rule) (RTL8367C_ACL_ACTION_CTRL2_BASE + ((rule-64) >> 1)) ++ ++#define RTL8367C_ACL_OP_NOT_OFFSET(rule) (6 + ((rule & 0x1) << 3)) ++#define RTL8367C_ACL_OP_NOT_MASK(rule) (1 << RTL8367C_ACL_OP_NOT_OFFSET(rule)) ++#define RTL8367C_ACL_OP_ACTION_OFFSET(rule) ((rule & 0x1) << 3) ++#define RTL8367C_ACL_OP_ACTION_MASK(rule) (0x3F << RTL8367C_ACL_OP_ACTION_OFFSET(rule)) ++ ++#define RTL8367C_ACL_ENABLE_REG RTL8367C_REG_ACL_ENABLE ++#define RTL8367C_ACL_UNMATCH_PERMIT_REG RTL8367C_REG_ACL_UNMATCH_PERMIT ++ ++/* (16'h0700) cvlan_reg */ ++ ++#define RTL8367C_VLAN_PVID_CTRL_BASE RTL8367C_REG_VLAN_PVID_CTRL0 ++#define RTL8367C_VLAN_PVID_CTRL_REG(port) (RTL8367C_VLAN_PVID_CTRL_BASE + (port >> 1)) ++#define RTL8367C_PORT_VIDX_OFFSET(port) ((port &1)<<3) ++#define RTL8367C_PORT_VIDX_MASK(port) (RTL8367C_PORT0_VIDX_MASK << RTL8367C_PORT_VIDX_OFFSET(port)) ++ ++#define RTL8367C_VLAN_PPB_VALID_BASE RTL8367C_REG_VLAN_PPB0_VALID ++#define RTL8367C_VLAN_PPB_VALID_REG(item) (RTL8367C_VLAN_PPB_VALID_BASE + (item << 3)) ++ ++#define RTL8367C_VLAN_PPB_CTRL_BASE RTL8367C_REG_VLAN_PPB0_CTRL0 ++#define RTL8367C_VLAN_PPB_CTRL_REG(item, port) (RTL8367C_VLAN_PPB_CTRL_BASE + (item << 3) + (port / 3) ) ++#define RTL8367C_VLAN_PPB_CTRL_OFFSET(port) ((port % 3) * 5) ++#define RTL8367C_VLAN_PPB_CTRL_MASK(port) (RTL8367C_VLAN_PPB0_CTRL0_PORT0_INDEX_MASK << RTL8367C_VLAN_PPB_CTRL_OFFSET(port)) ++ ++#define RTL8367C_VLAN_PPB_FRAMETYPE_BASE RTL8367C_REG_VLAN_PPB0_CTRL2 ++#define RTL8367C_VLAN_PPB_FRAMETYPE_REG(item) (RTL8367C_VLAN_PPB_FRAMETYPE_BASE + (item << 3)) ++#define RTL8367C_VLAN_PPB_FRAMETYPE_MASK RTL8367C_VLAN_PPB0_CTRL2_FRAME_TYPE_MASK ++ ++#define RTL8367C_VLAN_PPB_ETHERTYPR_BASE RTL8367C_REG_VLAN_PPB0_CTRL3 ++#define RTL8367C_VLAN_PPB_ETHERTYPR_REG(item) (RTL8367C_VLAN_PPB_ETHERTYPR_BASE + (item << 3)) ++ ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION_BASE RTL8367C_REG_VLAN_MEMBER_CONFIGURATION0_CTRL0 ++ ++ ++#define RTL8367C_VLAN_CTRL_REG RTL8367C_REG_VLAN_CTRL ++ ++#define RTL8367C_VLAN_INGRESS_REG RTL8367C_REG_VLAN_INGRESS ++ ++#define RTL8367C_VLAN_ACCEPT_FRAME_TYPE_BASE RTL8367C_REG_VLAN_ACCEPT_FRAME_TYPE_CTRL0 ++#define RTL8367C_VLAN_ACCEPT_FRAME_TYPE_REG(port) (RTL8367C_VLAN_ACCEPT_FRAME_TYPE_BASE + (port >> 3)) ++#define RTL8367C_VLAN_ACCEPT_FRAME_TYPE_MASK(port) (RTL8367C_PORT0_FRAME_TYPE_MASK << ((port & 0x7) << 1)) ++ ++#define RTL8367C_PORT_EFID_BASE RTL8367C_REG_PORT_EFID_CTRL0 ++#define RTL8367C_PORT_EFID_REG(port) (RTL8367C_PORT_EFID_BASE + (port >> 2)) ++#define RTL8367C_PORT_EFID_OFFSET(port) ((port & 0x3) << 2) ++#define RTL8367C_PORT_EFID_MASK(port) (RTL8367C_PORT0_EFID_MASK << RTL8367C_PORT_EFID_OFFSET(port)) ++ ++#define RTL8367C_PORT_PBFIDEN_REG RTL8367C_REG_PORT_PBFIDEN ++ ++#define RTL8367C_PORT_PBFID_BASE RTL8367C_REG_PORT0_PBFID ++#define RTL8367C_PORT_PBFID_REG(port) (RTL8367C_PORT_PBFID_BASE + port) ++ ++/* (16'h0800) dpm_reg */ ++ ++#define RTL8367C_RMA_CTRL_BASE RTL8367C_REG_RMA_CTRL00 ++ ++ ++#define RTL8367C_VLAN_PORTBASED_PRIORITY_BASE RTL8367C_REG_VLAN_PORTBASED_PRIORITY_CTRL0 ++#define RTL8367C_VLAN_PORTBASED_PRIORITY_REG(port) (RTL8367C_VLAN_PORTBASED_PRIORITY_BASE + (port >> 2)) ++#define RTL8367C_VLAN_PORTBASED_PRIORITY_OFFSET(port) ((port & 0x3) << 2) ++#define RTL8367C_VLAN_PORTBASED_PRIORITY_MASK(port) (0x7 << RTL8367C_VLAN_PORTBASED_PRIORITY_OFFSET(port)) ++ ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM_BASE RTL8367C_REG_VLAN_PPB_PRIORITY_ITEM0_CTRL0 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM_REG(port, item) (RTL8367C_VLAN_PPB_PRIORITY_ITEM_BASE + (item << 2)+ (port>>2)) ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM_OFFSET(port) ((port & 0x3) <<2) ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM_MASK(port) (RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL0_PORT0_PRIORITY_MASK << RTL8367C_VLAN_PPB_PRIORITY_ITEM_OFFSET(port)) ++ ++#define RTL8367C_QOS_1Q_PRIORITY_REMAPPING_BASE RTL8367C_REG_QOS_1Q_PRIORITY_REMAPPING_CTRL0 ++#define RTL8367C_QOS_1Q_PRIORITY_REMAPPING_REG(pri) (RTL8367C_QOS_1Q_PRIORITY_REMAPPING_BASE + (pri >> 2)) ++#define RTL8367C_QOS_1Q_PRIORITY_REMAPPING_OFFSET(pri) ((pri & 0x3) << 2) ++#define RTL8367C_QOS_1Q_PRIORITY_REMAPPING_MASK(pri) (0x7 << RTL8367C_QOS_1Q_PRIORITY_REMAPPING_OFFSET(pri)) ++ ++#define RTL8367C_QOS_DSCP_TO_PRIORITY_BASE RTL8367C_REG_QOS_DSCP_TO_PRIORITY_CTRL0 ++#define RTL8367C_QOS_DSCP_TO_PRIORITY_REG(dscp) (RTL8367C_QOS_DSCP_TO_PRIORITY_BASE + (dscp >> 2)) ++#define RTL8367C_QOS_DSCP_TO_PRIORITY_OFFSET(dscp) ((dscp & 0x3) << 2) ++#define RTL8367C_QOS_DSCP_TO_PRIORITY_MASK(dscp) (0x7 << RTL8367C_QOS_DSCP_TO_PRIORITY_OFFSET(dscp)) ++ ++#define RTL8367C_QOS_PORTBASED_PRIORITY_BASE RTL8367C_REG_QOS_PORTBASED_PRIORITY_CTRL0 ++#define RTL8367C_QOS_PORTBASED_PRIORITY_REG(port) (RTL8367C_QOS_PORTBASED_PRIORITY_BASE + (port >> 2)) ++#define RTL8367C_QOS_PORTBASED_PRIORITY_OFFSET(port) ((port & 0x3) << 2) ++#define RTL8367C_QOS_PORTBASED_PRIORITY_MASK(port) (0x7 << RTL8367C_QOS_PORTBASED_PRIORITY_OFFSET(port)) ++ ++#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_BASE RTL8367C_REG_QOS_INTERNAL_PRIORITY_DECISION_CTRL0 ++#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_REG(src) (RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_BASE + (src >> 1)) ++#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_OFFSET(src) ((src & 1) << 3) ++#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_MASK(src) (RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_CTRL0_QOS_PORT_WEIGHT_MASK << RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_OFFSET(src)) ++ ++#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_BASE RTL8367C_REG_QOS_INTERNAL_PRIORITY_DECISION2_CTRL0 ++#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_REG(src) (RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_BASE + (src >> 1)) ++#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_OFFSET(src) ((src & 1) << 3) ++#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_MASK(src) (RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_CTRL0_QOS_PORT_WEIGHT_MASK << RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_OFFSET(src)) ++ ++#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_IDX_CTRL RTL8367C_REG_QOS_INTERNAL_PRIORITY_DECISION_IDX ++#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_IDX(port) (1 << port) ++ ++#define RTL8367C_QOS_PRIPORITY_REMAPPING_IN_CPU_BASE RTL8367C_REG_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL0 ++#define RTL8367C_QOS_PRIPORITY_REMAPPING_IN_CPU_REG(pri) (RTL8367C_QOS_PRIPORITY_REMAPPING_IN_CPU_BASE + (pri >> 2)) ++#define RTL8367C_QOS_PRIPORITY_REMAPPING_IN_CPU_OFFSET(pri) ((pri & 0x3) << 2) ++#define RTL8367C_QOS_PRIPORITY_REMAPPING_IN_CPU_MASK(pri) (RTL8367C_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL0_PRIORITY0_MASK << RTL8367C_QOS_PRIPORITY_REMAPPING_IN_CPU_OFFSET(pri)) ++ ++#define RTL8367C_QOS_TRAP_PRIORITY_CTRL0_REG RTL8367C_REG_QOS_TRAP_PRIORITY0 ++ ++#define RTL8367C_QOS_TRAP_PRIORITY_CTRL1_REG RTL8367C_REG_QOS_TRAP_PRIORITY1 ++ ++#define RTL8367C_QOS_DSCP_TO_DSCP_BASE RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL0 ++#define RTL8367C_QOS_DSCP_TO_DSCP_REG(dscp) (RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL0 + (dscp >> 1)) ++#define RTL8367C_QOS_DSCP_TO_DSCP_OFFSET(dscp) ((dscp & 0x1) << 8) ++#define RTL8367C_QOS_DSCP_TO_DSCP_MASK(dscp) (0x3F << RTL8367C_QOS_DSCP_TO_DSCP_OFFSET(dscp)) ++ ++#define RTL8367C_UNUCAST_FLOADING_PMSK_REG RTL8367C_REG_UNDA_FLOODING_PMSK ++ ++#define RTL8367C_UNMCAST_FLOADING_PMSK_REG RTL8367C_REG_UNMCAST_FLOADING_PMSK ++ ++#define RTL8367C_BCAST_FLOADING_PMSK_REG RTL8367C_REG_BCAST_FLOADING_PMSK ++ ++#define RTL8367C_PORT_ISOLATION_PORT_MASK_BASE RTL8367C_REG_PORT_ISOLATION_PORT0_MASK ++#define RTL8367C_PORT_ISOLATION_PORT_MASK_REG(port) (RTL8367C_PORT_ISOLATION_PORT_MASK_BASE + port) ++ ++#define RTL8367C_FORCE_CTRL_REG RTL8367C_REG_FORCE_CTRL ++ ++#define RTL8367C_SOURCE_PORT_BLOCK_REG RTL8367C_REG_SOURCE_PORT_PERMIT ++ ++#define RTL8367C_IPMCAST_VLAN_LEAKY_REG RTL8367C_REG_IPMCAST_VLAN_LEAKY ++ ++#define RTL8367C_IPMCAST_PORTISO_LEAKY_REG RTL8367C_REG_IPMCAST_PORTISO_LEAKY ++ ++#define RTL8367C_PORT_SECURIT_CTRL_REG RTL8367C_REG_PORT_SECURITY_CTRL ++ ++#define RTL8367C_UNKNOWN_IPV4_MULTICAST_BASE RTL8367C_REG_UNKNOWN_IPV4_MULTICAST_CTRL0 ++#define RTL8367C_UNKNOWN_IPV4_MULTICAST_REG(port) (RTL8367C_UNKNOWN_IPV4_MULTICAST_BASE + (port >> 3)) ++#define RTL8367C_UNKNOWN_IPV4_MULTICAST_OFFSET(port) ((port & 0x7) << 1) ++#define RTL8367C_UNKNOWN_IPV4_MULTICAST_MASK(port) (RTL8367C_PORT0_UNKNOWN_IP4_MCAST_MASK << RTL8367C_UNKNOWN_IPV4_MULTICAST_OFFSET(port)) ++ ++#define RTL8367C_UNKNOWN_IPV6_MULTICAST_BASE RTL8367C_REG_UNKNOWN_IPV6_MULTICAST_CTRL0 ++#define RTL8367C_UNKNOWN_IPV6_MULTICAST_REG(port) (RTL8367C_UNKNOWN_IPV6_MULTICAST_BASE + (port >> 3)) ++#define RTL8367C_UNKNOWN_IPV6_MULTICAST_OFFSET(port) ((port & 0x7) << 1) ++#define RTL8367C_UNKNOWN_IPV6_MULTICAST_MASK(port) (RTL8367C_PORT0_UNKNOWN_IP4_MCAST_MASK << RTL8367C_UNKNOWN_IPV6_MULTICAST_OFFSET(port)) ++ ++#define RTL8367C_UNKNOWN_L2_MULTICAST_BASE RTL8367C_REG_UNKNOWN_L2_MULTICAST_CTRL0 ++#define RTL8367C_UNKNOWN_L2_MULTICAST_REG(port) (RTL8367C_UNKNOWN_L2_MULTICAST_BASE + (port >> 3)) ++#define RTL8367C_UNKNOWN_L2_MULTICAST_OFFSET(port) ((port & 0x7) << 1) ++#define RTL8367C_UNKNOWN_L2_MULTICAST_MASK(port) (RTL8367C_PORT0_UNKNOWN_L2_MCAST_MASK << RTL8367C_UNKNOWN_L2_MULTICAST_OFFSET(port)) ++ ++#define RTL8367C_PORT_TRUNK_CTRL_REG RTL8367C_REG_PORT_TRUNK_CTRL ++#define RTL8367C_PORT_TRUNK_HASH_MASK 0x007F ++ ++#define RTL8367C_PORT_TRUNK_GROUP_MASK_REG RTL8367C_REG_PORT_TRUNK_GROUP_MASK ++#define RTL8367C_PORT_TRUNK_GROUP_MASK_OFFSET(group) (group << 2) ++#define RTL8367C_PORT_TRUNK_GROUP_MASK_MASK(group) (RTL8367C_PORT_TRUNK_GROUP0_MASK_MASK << RTL8367C_PORT_TRUNK_GROUP_MASK_OFFSET(group)) ++ ++#define RTL8367C_PORT_TRUNK_FLOWCTRL_REG RTL8367C_REG_PORT_TRUNK_FLOWCTRL ++ ++#define RTL8367C_QOS_PORT_QUEUE_NUMBER_BASE RTL8367C_REG_QOS_PORT_QUEUE_NUMBER_CTRL0 ++#define RTL8367C_QOS_PORT_QUEUE_NUMBER_REG(port) (RTL8367C_QOS_PORT_QUEUE_NUMBER_BASE + (port >> 2)) ++#define RTL8367C_QOS_PORT_QUEUE_NUMBER_OFFSET(port) ((port & 0x3) << 2) ++#define RTL8367C_QOS_PORT_QUEUE_NUMBER_MASK(port) (0x7 << RTL8367C_QOS_PORT_QUEUE_NUMBER_OFFSET(port)) ++ ++#define RTL8367C_QOS_1Q_PRIORITY_TO_QID_BASE RTL8367C_REG_QOS_1Q_PRIORITY_TO_QID_CTRL0 ++#define RTL8367C_QOS_1Q_PRIORITY_TO_QID_REG(index, pri) (RTL8367C_QOS_1Q_PRIORITY_TO_QID_BASE + (index << 1) + (pri >> 2)) ++#define RTL8367C_QOS_1Q_PRIORITY_TO_QID_OFFSET(pri) ((pri & 0x3) << 2) ++#define RTL8367C_QOS_1Q_PRIORITY_TO_QID_MASK(pri) (RTL8367C_QOS_1Q_PRIORITY_TO_QID_CTRL0_PRIORITY0_TO_QID_MASK << RTL8367C_QOS_1Q_PRIORITY_TO_QID_OFFSET(pri)) ++ ++#define RTL8367C_DEBUG_INFO_BASE RTL8367C_REG_PORT_DEBUG_INFO_CTRL0 ++#define RTL8367C_DEBUG_INFO_REG(port) (RTL8367C_DEBUG_INFO_BASE + (port >>1)) ++#define RTL8367C_DEBUG_INFO_OFFSET(port) ((port&1)<<3) ++#define RTL8367C_DEBUG_INFO_MASK(port) (RTL8367C_PORT0_DEBUG_INFO_MASK << RTL8367C_DEBUG_INFO_OFFSET(port)) ++ ++/* (16'h0a00) l2_reg */ ++ ++#define RTL8367C_VLAN_MSTI_BASE RTL8367C_REG_VLAN_MSTI0_CTRL0 ++#define RTL8367C_VLAN_MSTI_REG(tree, port) (RTL8367C_VLAN_MSTI_BASE + (tree << 1) + (port >> 3)) ++#define RTL8367C_VLAN_MSTI_OFFSET(port) ((port & 0x7) << 1) ++#define RTL8367C_VLAN_MSTI_MASK(port) (RTL8367C_VLAN_MSTI0_CTRL0_PORT0_STATE_MASK << RTL8367C_VLAN_MSTI_OFFSET(port)) ++ ++#define RTL8367C_LUT_PORT_LEARN_LIMITNO_BASE RTL8367C_REG_LUT_PORT0_LEARN_LIMITNO ++#define RTL8367C_LUT_PORT_LEARN_LIMITNO_REG(port) (RTL8367C_LUT_PORT_LEARN_LIMITNO_BASE + port) ++ ++#define RTL8367C_LUT_CFG_REG RTL8367C_REG_LUT_CFG ++ ++#define RTL8367C_LUT_AGEOUT_CTRL_REG RTL8367C_REG_LUT_AGEOUT_CTRL ++ ++#define RTL8367C_FORCE_FLUSH_REG RTL8367C_REG_FORCE_FLUSH ++ ++#define RTL8367C_STORM_BCAST_REG RTL8367C_REG_STORM_BCAST ++ ++#define RTL8367C_STORM_MCAST_REG RTL8367C_REG_STORM_MCAST ++ ++#define RTL8367C_STORM_UNKNOWN_UCAST_REG RTL8367C_REG_STORM_UNKOWN_UCAST ++ ++#define RTL8367C_STORM_UNKNOWN_MCAST_REG RTL8367C_REG_STORM_UNKOWN_MCAST ++ ++#define RTL8367C_STORM_BCAST_METER_CTRL_BASE RTL8367C_REG_STORM_BCAST_METER_CTRL0 ++#define RTL8367C_STORM_BCAST_METER_CTRL_REG(port) (RTL8367C_STORM_BCAST_METER_CTRL_BASE + (port >> 1)) ++#define RTL8367C_STORM_BCAST_METER_CTRL_OFFSET(port) ((port & 0x1) << 3) ++#define RTL8367C_STORM_BCAST_METER_CTRL_MASK(port) (0xFF << RTL8367C_STORM_BCAST_METER_CTRL_OFFSET(port)) ++ ++#define RTL8367C_STORM_MCAST_METER_CTRL_BASE RTL8367C_REG_STORM_MCAST_METER_CTRL0 ++#define RTL8367C_STORM_MCAST_METER_CTRL_REG(port) (RTL8367C_STORM_MCAST_METER_CTRL_BASE + (port >> 1)) ++#define RTL8367C_STORM_MCAST_METER_CTRL_OFFSET(port) ((port & 0x1) << 3) ++#define RTL8367C_STORM_MCAST_METER_CTRL_MASK(port) (0xFF << RTL8367C_STORM_MCAST_METER_CTRL_OFFSET(port)) ++ ++#define RTL8367C_STORM_UNDA_METER_CTRL_BASE RTL8367C_REG_STORM_UNDA_METER_CTRL0 ++#define RTL8367C_STORM_UNDA_METER_CTRL_REG(port) (RTL8367C_STORM_UNDA_METER_CTRL_BASE + (port >> 1)) ++#define RTL8367C_STORM_UNDA_METER_CTRL_OFFSET(port) ((port & 0x1) << 3) ++#define RTL8367C_STORM_UNDA_METER_CTRL_MASK(port) (0xFF << RTL8367C_STORM_UNDA_METER_CTRL_OFFSET(port)) ++ ++#define RTL8367C_STORM_UNMC_METER_CTRL_BASE RTL8367C_REG_STORM_UNMC_METER_CTRL0 ++#define RTL8367C_STORM_UNMC_METER_CTRL_REG(port) (RTL8367C_STORM_UNMC_METER_CTRL_BASE + (port >> 1)) ++#define RTL8367C_STORM_UNMC_METER_CTRL_OFFSET(port) ((port & 0x1) << 3) ++#define RTL8367C_STORM_UNMC_METER_CTRL_MASK(port) (0xFF << RTL8367C_STORM_UNMC_METER_CTRL_OFFSET(port)) ++ ++#define RTL8367C_OAM_PARSER_OFFSET(port) (port*2) ++#define RTL8367C_OAM_PARSER_MASK(port) (RTL8367C_PORT0_PARACT_MASK << RTL8367C_OAM_PARSER_OFFSET(port)) ++ ++#define RTL8367C_OAM_MULTIPLEXER_OFFSET(port) (port*2) ++#define RTL8367C_OAM_MULTIPLEXER_MASK(port) (RTL8367C_PORT0_PARACT_MASK << RTL8367C_OAM_MULTIPLEXER_OFFSET(port)) ++ ++#define RTL8367C_OAM_CTRL_REG RTL8367C_REG_OAM_CTRL ++ ++#define RTL8367C_DOT1X_PORT_ENABLE_REG RTL8367C_REG_DOT1X_PORT_ENABLE ++ ++#define RTL8367C_DOT1X_MAC_ENABLE_REG RTL8367C_REG_DOT1X_MAC_ENABLE ++ ++#define RTL8367C_DOT1X_PORT_AUTH_REG RTL8367C_REG_DOT1X_PORT_AUTH ++ ++#define RTL8367C_DOT1X_PORT_OPDIR_REG RTL8367C_REG_DOT1X_PORT_OPDIR ++ ++#define RTL8367C_DOT1X_UNAUTH_ACT_BASE RTL8367C_REG_DOT1X_UNAUTH_ACT_W0 ++#define RTL8367C_DOT1X_UNAUTH_ACT_OFFSET(port) ((port & 0x7) << 1) ++#define RTL8367C_DOT1X_UNAUTH_ACT_MASK(port) (RTL8367C_DOT1X_PORT0_UNAUTHBH_MASK << RTL8367C_DOT1X_UNAUTH_ACT_OFFSET(port)) ++ ++#define RTL8367C_DOT1X_CFG_REG RTL8367C_REG_DOT1X_CFG ++ ++#define RTL8367C_REG_L2_LRN_CNT_BASE RTL8367C_REG_L2_LRN_CNT_CTRL0 ++#define RTL8367C_REG_L2_LRN_CNT_REG(port) (RTL8367C_REG_L2_LRN_CNT_BASE + port) ++ ++/* (16'h0b00) mltvlan_reg */ ++ ++#define RTL8367C_SVLAN_MCAST2S_ENTRY_BASE_REG(index) (RTL8367C_REG_SVLAN_MCAST2S_ENTRY0_CTRL0 + index*5) ++ ++/* (16'h0c00) svlan_reg */ ++ ++#define RTL8367C_SVLAN_MEMBERCFG_BASE_REG(index) (RTL8367C_REG_SVLAN_MEMBERCFG0_CTRL1 + index*3) ++#define RTL8367C_SVLAN_C2SCFG_BASE_REG(index) (RTL8367C_REG_SVLAN_C2SCFG0_CTRL0+ index*3) ++#define RTL8367C_SVLAN_CFG_REG RTL8367C_REG_SVLAN_CFG ++ ++/* (16'h0f00) hsactrl_reg */ ++ ++#define RTL8367C_SVLAN_S2C_ENTRY_BASE_REG(index) (RTL8367C_REG_SVLAN_SP2C_ENTRY0_CTRL0 + index*2) ++ ++/* (16'h1000) mib_reg */ ++ ++#define RTL8367C_MIB_COUNTER_BASE_REG RTL8367C_REG_MIB_COUNTER0 ++ ++#define RTL8367C_MIB_ADDRESS_REG RTL8367C_REG_MIB_ADDRESS ++ ++#define RTL8367C_MIB_CTRL_REG RTL8367C_REG_MIB_CTRL0 ++#define RTL8367C_MIB_PORT07_MASK (0xFF<> 4)) ++#define RTL8367C_REG_METER_EXCEED_INDICATOR_OFFSET(meter) (meter & 0xF) ++ ++/* (16'h1200) swcore_reg */ ++ ++#define RTL8367C_VS_TPID_REG RTL8367C_REG_VS_TPID ++ ++#define RTL8367C_SWITCH_MAC_BASE RTL8367C_REG_SWITCH_MAC0 ++ ++#define RTL8367C_REMARKING_CTRL_REG RTL8367C_REG_SWITCH_CTRL0 ++ ++#define RTL8367C_QOS_DSCP_REMARK_BASE RTL8367C_REG_QOS_DSCP_REMARK_CTRL0 ++#define RTL8367C_QOS_DSCP_REMARK_REG(pri) (RTL8367C_QOS_DSCP_REMARK_BASE + (pri >> 1)) ++#define RTL8367C_QOS_DSCP_REMARK_OFFSET(pri) (((pri) & 0x1) << 3) ++#define RTL8367C_QOS_DSCP_REMARK_MASK(pri) (0x3F << RTL8367C_QOS_DSCP_REMARK_OFFSET(pri)) ++ ++#define RTL8367C_QOS_1Q_REMARK_BASE RTL8367C_REG_QOS_1Q_REMARK_CTRL0 ++#define RTL8367C_QOS_1Q_REMARK_REG(pri) (RTL8367C_QOS_1Q_REMARK_BASE + (pri >> 2)) ++#define RTL8367C_QOS_1Q_REMARK_OFFSET(pri) ((pri & 0x3) << 2) ++#define RTL8367C_QOS_1Q_REMARK_MASK(pri) (0x7 << RTL8367C_QOS_1Q_REMARK_OFFSET(pri)) ++ ++#define RTL8367C_PTKGEN_PAYLOAD_CTRL0_REG RTL8367C_REG_PTKGEN_PAYLOAD_CTRL0 ++ ++#define RTL8367C_PTKGEN_PAYLOAD_CTRL1_REG RTL8367C_REG_PTKGEN_PAYLOAD_CTRL1 ++ ++#define RTL8367C_SVLAN_UPLINK_PORTMASK_REG RTL8367C_REG_SVLAN_UPLINK_PORTMASK ++ ++#define RTL8367C_CPU_PORT_MASK_REG RTL8367C_REG_CPU_PORT_MASK ++ ++#define RTL8367C_CPU_CTRL_REG RTL8367C_REG_CPU_CTRL ++ ++#define RTL8367C_MIRROR_CTRL_REG RTL8367C_REG_MIRROR_CTRL ++ ++ ++#define RTL8367C_FLOWCRTL_EGRESS_QUEUE_ENABLE_BASE RTL8367C_REG_FLOWCRTL_EGRESS_QUEUE_ENABLE_CTRL0 ++#define RTL8367C_FLOWCRTL_EGRESS_QUEUE_ENABLE_REG(port) (RTL8367C_FLOWCRTL_EGRESS_QUEUE_ENABLE_BASE + (port >> 1)) ++#define RTL8367C_FLOWCRTL_EGRESS_QUEUE_ENABLE_REG_OFFSET(port) ((port & 0x1) << 3) ++#define RTL8367C_FLOWCRTL_EGRESS_QUEUE_ENABLE_REG_MASK(port) (RTL8367C_PORT0_QUEUE_MASK_MASK << RTL8367C_FLOWCRTL_EGRESS_QUEUE_ENABLE_REG_OFFSET(port)) ++ ++ ++#define RTL8367C_FLOWCTRL_PORT_PAGE_COUNTER_BASE RTL8367C_REG_FLOWCTRL_PORT0_PAGE_COUNTER ++#define RTL8367C_FLOWCTRL_PORT_PAGE_COUNTER_REG(port) (RTL8367C_FLOWCTRL_PORT_PAGE_COUNTER_BASE + port) ++#define RTL8367C_FLOWCTRL_PORT_PAGE_COUNTER_MASK RTL8367C_FLOWCTRL_PORT0_PAGE_COUNTER_MASK ++ ++#define RTL8367C_FLOWCTRL_PORT_PAGE_MAX_BASE RTL8367C_REG_FLOWCTRL_PORT0_PAGE_MAX ++#define RTL8367C_FLOWCTRL_PORT_PAGE_MAX_REG(port) (RTL8367C_FLOWCTRL_PORT_PAGE_MAX_BASE + port) ++#define RTL8367C_FLOWCTRL_PORT_PAGE_MAX_MASK RTL8367C_FLOWCTRL_PORT0_PAGE_MAX_MASK ++ ++#define RTL8367C_FIELD_SELECTOR_REG(index) (RTL8367C_REG_FIELD_SELECTOR0 + index) ++#define RTL8367C_FIELD_SELECTOR_ENABLE_OFFSET RTL8367C_FIELD_SELECTOR0_ENABLE_OFFSET ++#define RTL8367C_FIELD_SELECTOR_ENABLE_MASK RTL8367C_FIELD_SELECTOR0_ENABLE_MASK ++#define RTL8367C_FIELD_SELECTOR_FORMAT_OFFSET RTL8367C_FIELD_SELECTOR0_FORMAT_OFFSET ++#define RTL8367C_FIELD_SELECTOR_FORMAT_MASK RTL8367C_FIELD_SELECTOR0_FORMAT_MASK ++#define RTL8367C_FIELD_SELECTOR_OFFSET_OFFSET RTL8367C_FIELD_SELECTOR0_OFFSET_OFFSET ++#define RTL8367C_FIELD_SELECTOR_OFFSET_MASK RTL8367C_FIELD_SELECTOR0_OFFSET_MASK ++ ++/* (16'h1300) chip_reg*/ ++ ++/* (16'h1400) mtrpool_reg */ ++#define RTL8367C_METER_RATE_BASE RTL8367C_REG_METER0_RATE_CTRL0 ++#define RTL8367C_METER_RATE_REG(meter) ((meter << 1) + RTL8367C_METER_RATE_BASE) ++ ++#define RTL8367C_METER_BUCKET_SIZE_BASE RTL8367C_REG_METER0_BUCKET_SIZE ++#define RTL8367C_METER_BUCKET_SIZE_REG(meter) (RTL8367C_METER_BUCKET_SIZE_BASE + meter) ++ ++#define RTL8367C_LEAKY_BUCKET_TICK_REG RTL8367C_REG_METER_CTRL0 ++#define RTL8367C_LEAKY_BUCKET_TICK_OFFSET RTL8367C_METER_TICK_OFFSET ++#define RTL8367C_LEAKY_BUCKET_TICK_MASK RTL8367C_METER_TICK_MASK ++ ++#define RTL8367C_LEAKY_BUCKET_TOKEN_REG RTL8367C_REG_METER_CTRL1 ++#define RTL8367C_LEAKY_BUCKET_TOKEN_OFFSET RTL8367C_METER_CTRL1_OFFSET ++#define RTL8367C_LEAKY_BUCKET_TOKEN_MASK RTL8367C_METER_CTRL1_MASK ++ ++#define RTL8367C_METER_OVERRATE_INDICATOR_BASE RTL8367C_REG_METER_OVERRATE_INDICATOR0 ++#define RTL8367C_METER_OVERRATE_INDICATOR_REG(meter) (RTL8367C_METER_OVERRATE_INDICATOR_BASE + (meter >> 4)) ++#define RTL8367C_METER_EXCEED_OFFSET(meter) (meter & 0xF) ++#define RTL8367C_METER_EXCEED_MASK(meter) (1 << RTL8367C_METER_EXCEED_OFFSET(meter)) ++ ++#define RTL8367C_METER_IFG_CTRL_BASE RTL8367C_REG_METER_IFG_CTRL0 ++#define RTL8367C_METER_IFG_CTRL_REG(meter) (RTL8367C_METER_IFG_CTRL_BASE + (meter >> 4)) ++#define RTL8367C_METER_IFG_OFFSET(meter) (meter & 0xF) ++#define RTL8367C_METER_IFG_MASK(meter) (1 << RTL8367C_METER_IFG_OFFSET(meter)) ++ ++#define RTL8367C_FLOWCTRL_CTRL_REG RTL8367C_REG_FLOWCTRL_CTRL0 ++ ++/* (16'h1800)8051_RLDP_EEE_reg */ ++#define RTL8367C_EEELLDP_CTRL0_REG RTL8367C_REG_EEELLDP_CTRL0 ++ ++#define RTL8367C_EEELLDP_CTRL1_REG RTL8367C_REG_EEELLDP_CTRL1 ++ ++#define RTL8367C_EEELLDP_PMSK_REG RTL8367C_REG_EEELLDP_PMSK ++ ++#define RTL8367C_EEELLDP_TX_FRAMEU_REG_BASE RTL8367C_REG_EEELLDP_FRAMEU00 ++ ++#define RTL8367C_EEELLDP_TX_CAP_FRAMEL_REG_BASE RTL8367C_REG_EEELLDP_CAP_FRAMEL00 ++ ++#define RTL8367C_EEELLDP_RX_VALUE_PORT_BASE RTL8367C_REG_EEELLDP_RX_VALUE_P00_00 ++#define RTL8367C_EEELLDP_RX_VALUE_PORT_REG(port) (RTL8367C_EEELLDP_RX_VALUE_PORT_BASE + (port * 9)) ++ ++#define RTL8367C_RLDP_CTRL0_REG RTL8367C_REG_RLDP_CTRL0 ++#define RTL8367C_RLDP_MODE_OFFSET 14 ++ ++#define RTL8367C_RLDP_RETRY_COUNT_REG RTL8367C_REG_RLDP_CTRL1 ++ ++#define RTL8367C_RLDP_RETRY_PERIOD_LOOPSTATE_REG RTL8367C_REG_RLDP_CTRL2 ++ ++#define RTL8367C_RLDP_RETRY_PERIOD_CHKSTATE_REG RTL8367C_REG_RLDP_CTRL3 ++ ++#define RTL8367C_RLDP_TX_PMSK_REG RTL8367C_REG_RLDP_CTRL4 ++ ++#define RTL8367C_RLDP_RAND_NUM_REG_BASE RTL8367C_REG_RLDP_RAND_NUM0 ++ ++#define RTL8367C_RLDP_MAGIC_NUM_REG_BASE RTL8367C_REG_RLDP_MAGIC_NUM0 ++ ++#define RTL8367C_RLDP_LOOP_PMSK_REG RTL8367C_REG_RLDP_LOOPSTATUS_INDICATOR ++ ++#define RTL8367C_RLDP_LOOP_PORT_BASE RTL8367C_REG_RLDP_LOOP_PORT_REG0 ++#define RTL8367C_RLDP_LOOP_PORT_REG(port) (RTL8367C_RLDP_LOOP_PORT_BASE + (port >> 1)) ++#define RTL8367C_RLDP_LOOP_PORT_OFFSET(port) ((port & 0x1) << 3) ++#define RTL8367C_RLDP_LOOP_PORT_MASK(port) (RTL8367C_RLDP_LOOP_PORT_00_MASK << RTL8367C_RLDP_LOOP_PORT_OFFSET(port)) ++ ++#define RTL8367C_PAGEMETER_PORT_BASE RTL8367C_REG_PAGEMETER_PORT0_CTRL0 ++#define RTL8367C_PAGEMETER_PORT_REG(port) (RTL8367C_PAGEMETER_PORT_BASE + 0x20*port) ++ ++#define RTL8367C_HIGHPRI_INDICATOR_REG RTL8367C_REG_HIGHPRI_INDICATOR ++#define RTL8367C_PORT_INDICATOR_OFFSET(port) (port) ++#define RTL8367C_PORT_INDICATOR_MASK(port) (RTL8367C_PORT0_INDICATOR_MASK << RTL8367C_PORT_INDICATOR_OFFSET(port)) ++ ++#define RTL8367C_HIGHPRI_CFG_REG RTL8367C_REG_HIGHPRI_CFG ++ ++#define RTL8367C_EAV_PRIORITY_REMAPPING_BASE RTL8367C_REG_EAV_CTRL1 ++#define RTL8367C_EAV_PRIORITY_REMAPPING_REG(pri) (RTL8367C_EAV_PRIORITY_REMAPPING_BASE + (pri >> 2)) ++#define RTL8367C_EAV_PRIORITY_REMAPPING_OFFSET(pri) ((pri & 0x3) * RTL8367C_REMAP_EAV_PRI1_REGEN_OFFSET) ++#define RTL8367C_EAV_PRIORITY_REMAPPING_MASK(pri) (RTL8367C_REMAP_EAV_PRI0_REGEN_MASK << RTL8367C_EAV_PRIORITY_REMAPPING_OFFSET(pri)) ++ ++#define RTL8367C_EEEP_CFG_BASE RTL8367C_REG_PORT0_EEECFG ++#define RTL8367C_EEEP_CFG_REG(port) (RTL8367C_EEEP_CFG_BASE + (port*0x20)) ++ ++#define RTL8367C_PKG_CFG_BASE RTL8367C_REG_PKTGEN_PORT0_CTRL ++#define RTL8367C_PKG_CFG_REG(port) (RTL8367C_PKG_CFG_BASE + (port*0x20)) ++ ++#define RTL8367C_PKG_DA_BASE RTL8367C_REG_PKTGEN_PORT0_DA0 ++#define RTL8367C_PKG_DA_REG(port) (RTL8367C_PKG_DA_BASE + (port*0x20)) ++ ++#define RTL8367C_PKG_SA_BASE RTL8367C_REG_PKTGEN_PORT0_SA0 ++#define RTL8367C_PKG_SA_REG(port) (RTL8367C_PKG_SA_BASE + (port*0x20)) ++ ++#define RTL8367C_PKG_NUM_BASE RTL8367C_REG_PKTGEN_PORT0_COUNTER0 ++#define RTL8367C_PKG_NUM_REG(port) (RTL8367C_PKG_NUM_BASE + (port*0x20)) ++ ++#define RTL8367C_PKG_LENGTH_BASE RTL8367C_REG_PKTGEN_PORT0_TX_LENGTH ++#define RTL8367C_PKG_LENGTH_REG(port) (RTL8367C_PKG_LENGTH_BASE + (port*0x20)) ++ ++/* (16'h1c00)IGMP_MLD_reg */ ++#define RTL8367C_IGMP_GROUP_USAGE_BASE RTL8367C_REG_IGMP_GROUP_USAGE_LIST0 ++#define RTL8367C_IGMP_GROUP_USAGE_REG(idx) (RTL8367C_IGMP_GROUP_USAGE_BASE + (idx / 16)) ++ ++#define RTL8367C_FALLBACK_BASE RTL8367C_REG_FALLBACK_PORT0_CFG0 ++#define RTL8367C_FALLBACK_PORT_CFG_REG(port) (RTL8367C_FALLBACK_BASE + (port * 4)) ++#define RTL8367C_FALLBACK_PORT_MON_CNT_REG(port) (RTL8367C_FALLBACK_BASE + 1 + (port * 4)) ++#define RTL8367C_FALLBACK_PORT_ERR_CNT_REG(port) (RTL8367C_FALLBACK_BASE + 3 + (port * 4)) ++ ++ ++/* (16'h6400)timer_1588 */ ++#define RTL8367C_EAV_CFG_BASE RTL8367C_REG_P0_EAV_CFG ++#define RTL8367C_EAV_PORT_CFG_REG(port) (RTL8367C_EAV_CFG_BASE + (port *0x10)) ++#define RTL8367C_EAV_CFG_PTP_PHY_EN_EN_OFFSET RTL8367C_P0_EAV_CFG_PTP_PHY_EN_EN_OFFSET ++#define RTL8367C_EAV_CFG_RX_PDELAY_RESP_OFFSET RTL8367C_P0_EAV_CFG_RX_PDELAY_RESP_OFFSET ++#define RTL8367C_EAV_CFG_RX_PDELAY_REQ_OFFSET RTL8367C_P0_EAV_CFG_RX_PDELAY_REQ_OFFSET ++#define RTL8367C_EAV_CFG_RX_DELAY_REQ_OFFSET RTL8367C_P0_EAV_CFG_RX_DELAY_REQ_OFFSET ++#define RTL8367C_EAV_CFG_RX_SYNC_OFFSET RTL8367C_P0_EAV_CFG_RX_SYNC_OFFSET ++#define RTL8367C_EAV_CFG_TX_PDELAY_RESP_OFFSET RTL8367C_P0_EAV_CFG_TX_PDELAY_RESP_OFFSET ++#define RTL8367C_EAV_CFG_TX_PDELAY_REQ_OFFSET RTL8367C_P0_EAV_CFG_TX_PDELAY_REQ_OFFSET ++#define RTL8367C_EAV_CFG_TX_DELAY_REQ_OFFSET RTL8367C_P0_EAV_CFG_TX_DELAY_REQ_OFFSET ++#define RTL8367C_EAV_CFG_TX_SYNC_OFFSET RTL8367C_P0_EAV_CFG_TX_SYNC_OFFSET ++ ++#define RTL8367C_REG_TX_SYNC_SEQ_ID_BASE RTL8367C_REG_P0_TX_SYNC_SEQ_ID ++#define RTL8367C_REG_TX_SYNC_SEQ_ID(port) (RTL8367C_REG_TX_SYNC_SEQ_ID_BASE + (port *0x10)) ++#define RTL8367C_REG_SEQ_ID(port, type) (RTL8367C_REG_TX_SYNC_SEQ_ID_BASE + type + (port *0x10)) ++ ++#define RTL8367C_REG_TX_DELAY_REQ_SEQ_ID_BASE RTL8367C_REG_P0_TX_DELAY_REQ_SEQ_ID ++#define RTL8367C_REG_TX_PDELAY_REQ_SEQ_ID_BASE RTL8367C_REG_P0_TX_PDELAY_REQ_SEQ_ID ++#define RTL8367C_REG_TX_PDELAY_RESP_SEQ_ID_BASE RTL8367C_REG_P0_TX_PDELAY_RESP_SEQ_ID ++#define RTL8367C_REG_RX_SYNC_SEQ_ID_BASE RTL8367C_REG_P0_RX_SYNC_SEQ_ID ++#define RTL8367C_REG_RX_DELAY_REQ_SEQ_ID_BASE RTL8367C_REG_P0_RX_DELAY_REQ_SEQ_ID ++#define RTL8367C_REG_RX_PDELAY_REQ_SEQ_ID_BASE RTL8367C_REG_P0_RX_PDELAY_REQ_SEQ_ID ++#define RTL8367C_REG_RX_PDELAY_RESP_SEQ_ID_BASE RTL8367C_REG_P0_RX_PDELAY_RESP_SEQ_ID ++ ++#define RTL8367C_REG_PORT_NSEC_L_BASE RTL8367C_REG_P0_PORT_NSEC_15_0 ++#define RTL8367C_REG_PORT_NSEC_L(port) (RTL8367C_REG_PORT_NSEC_L_BASE + (port *0x10)) ++#define RTL8367C_REG_PORT_NSEC_H_BASE RTL8367C_REG_P0_PORT_NSEC_26_16 ++#define RTL8367C_REG_PORT_NSEC_H(port) (RTL8367C_REG_PORT_NSEC_H_BASE + (port *0x10)) ++#define RTL8367C_PORT_NSEC_H_OFFSET RTL8367C_P0_PORT_NSEC_26_16_OFFSET ++#define RTL8367C_PORT_NSEC_H_MASK RTL8367C_P0_PORT_NSEC_26_16_MASK ++ ++#define RTL8367C_REG_PORT_SEC_L_BASE RTL8367C_REG_P0_PORT_SEC_15_0 ++#define RTL8367C_REG_PORT_SEC_L(port) (RTL8367C_REG_PORT_SEC_L_BASE + (port *0x10)) ++#define RTL8367C_REG_PORT_SEC_H_BASE RTL8367C_REG_P0_PORT_SEC_31_16 ++#define RTL8367C_REG_PORT_SEC_H(port) (RTL8367C_REG_PORT_SEC_H_BASE + (port *0x10)) ++ ++#endif /*#ifndef _RTL8367C_BASE_H_*/ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_reg.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_reg.h +new file mode 100644 +index 000000000000..f973c7bcb62d +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_reg.h +@@ -0,0 +1,22819 @@ ++#ifndef _RTL8367C_REG_H_ ++#define _RTL8367C_REG_H_ ++ ++/************************************************************ ++auto-generated register address and field data ++*************************************************************/ ++ ++/* (16'h0000)port_reg */ ++ ++#define RTL8367C_REG_PORT0_CGST_HALF_CFG 0x0000 ++#define RTL8367C_PORT0_CGST_HALF_CFG_CONGESTION_TIME_OFFSET 4 ++#define RTL8367C_PORT0_CGST_HALF_CFG_CONGESTION_TIME_MASK 0xF0 ++#define RTL8367C_PORT0_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_OFFSET 0 ++#define RTL8367C_PORT0_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_MASK 0xF ++ ++#define RTL8367C_REG_PKTGEN_PORT0_CTRL 0x0001 ++#define RTL8367C_PKTGEN_PORT0_CTRL_STATUS_OFFSET 15 ++#define RTL8367C_PKTGEN_PORT0_CTRL_STATUS_MASK 0x8000 ++#define RTL8367C_PKTGEN_PORT0_CTRL_PKTGEN_STS_OFFSET 13 ++#define RTL8367C_PKTGEN_PORT0_CTRL_PKTGEN_STS_MASK 0x2000 ++#define RTL8367C_PKTGEN_PORT0_CTRL_CRC_NO_ERROR_OFFSET 4 ++#define RTL8367C_PKTGEN_PORT0_CTRL_CRC_NO_ERROR_MASK 0x10 ++#define RTL8367C_PKTGEN_PORT0_CTRL_CMD_START_OFFSET 0 ++#define RTL8367C_PKTGEN_PORT0_CTRL_CMD_START_MASK 0x1 ++ ++#define RTL8367C_REG_TX_ERR_CNT_PORT0 0x0002 ++#define RTL8367C_TX_ERR_CNT_PORT0_OFFSET 0 ++#define RTL8367C_TX_ERR_CNT_PORT0_MASK 0x7 ++ ++#define RTL8367C_REG_PKTGEN_PORT0_DA0 0x0003 ++ ++#define RTL8367C_REG_PKTGEN_PORT0_DA1 0x0004 ++ ++#define RTL8367C_REG_PKTGEN_PORT0_DA2 0x0005 ++ ++#define RTL8367C_REG_PKTGEN_PORT0_SA0 0x0006 ++ ++#define RTL8367C_REG_PKTGEN_PORT0_SA1 0x0007 ++ ++#define RTL8367C_REG_PKTGEN_PORT0_SA2 0x0008 ++ ++#define RTL8367C_REG_PKTGEN_PORT0_COUNTER0 0x0009 ++ ++#define RTL8367C_REG_PKTGEN_PORT0_COUNTER1 0x000a ++#define RTL8367C_PKTGEN_PORT0_COUNTER1_OFFSET 0 ++#define RTL8367C_PKTGEN_PORT0_COUNTER1_MASK 0xFF ++ ++#define RTL8367C_REG_PKTGEN_PORT0_TX_LENGTH 0x000b ++#define RTL8367C_PKTGEN_PORT0_TX_LENGTH_OFFSET 0 ++#define RTL8367C_PKTGEN_PORT0_TX_LENGTH_MASK 0x3FFF ++ ++#define RTL8367C_REG_PKTGEN_PORT0_TIMER 0x000d ++#define RTL8367C_PKTGEN_PORT0_TIMER_TIMER_OFFSET 4 ++#define RTL8367C_PKTGEN_PORT0_TIMER_TIMER_MASK 0xF0 ++#define RTL8367C_PKTGEN_PORT0_TIMER_RX_DMA_ERR_FLAG_OFFSET 3 ++#define RTL8367C_PKTGEN_PORT0_TIMER_RX_DMA_ERR_FLAG_MASK 0x8 ++ ++#define RTL8367C_REG_PORT0_MISC_CFG 0x000e ++#define RTL8367C_PORT0_MISC_CFG_SMALL_TAG_IPG_OFFSET 15 ++#define RTL8367C_PORT0_MISC_CFG_SMALL_TAG_IPG_MASK 0x8000 ++#define RTL8367C_PORT0_MISC_CFG_TX_ITFSP_MODE_OFFSET 14 ++#define RTL8367C_PORT0_MISC_CFG_TX_ITFSP_MODE_MASK 0x4000 ++#define RTL8367C_PORT0_MISC_CFG_FLOWCTRL_INDEP_OFFSET 13 ++#define RTL8367C_PORT0_MISC_CFG_FLOWCTRL_INDEP_MASK 0x2000 ++#define RTL8367C_PORT0_MISC_CFG_DOT1Q_REMARK_ENABLE_OFFSET 12 ++#define RTL8367C_PORT0_MISC_CFG_DOT1Q_REMARK_ENABLE_MASK 0x1000 ++#define RTL8367C_PORT0_MISC_CFG_INGRESSBW_FLOWCTRL_OFFSET 11 ++#define RTL8367C_PORT0_MISC_CFG_INGRESSBW_FLOWCTRL_MASK 0x800 ++#define RTL8367C_PORT0_MISC_CFG_INGRESSBW_IFG_OFFSET 10 ++#define RTL8367C_PORT0_MISC_CFG_INGRESSBW_IFG_MASK 0x400 ++#define RTL8367C_PORT0_MISC_CFG_RX_SPC_OFFSET 9 ++#define RTL8367C_PORT0_MISC_CFG_RX_SPC_MASK 0x200 ++#define RTL8367C_PORT0_MISC_CFG_CRC_SKIP_OFFSET 8 ++#define RTL8367C_PORT0_MISC_CFG_CRC_SKIP_MASK 0x100 ++#define RTL8367C_PORT0_MISC_CFG_PKTGEN_TX_FIRST_OFFSET 7 ++#define RTL8367C_PORT0_MISC_CFG_PKTGEN_TX_FIRST_MASK 0x80 ++#define RTL8367C_PORT0_MISC_CFG_MAC_LOOPBACK_OFFSET 6 ++#define RTL8367C_PORT0_MISC_CFG_MAC_LOOPBACK_MASK 0x40 ++#define RTL8367C_PORT0_MISC_CFG_VLAN_EGRESS_MODE_OFFSET 4 ++#define RTL8367C_PORT0_MISC_CFG_VLAN_EGRESS_MODE_MASK 0x30 ++#define RTL8367C_PORT0_MISC_CFG_CONGESTION_SUSTAIN_TIME_OFFSET 0 ++#define RTL8367C_PORT0_MISC_CFG_CONGESTION_SUSTAIN_TIME_MASK 0xF ++ ++#define RTL8367C_REG_INGRESSBW_PORT0_RATE_CTRL0 0x000f ++ ++#define RTL8367C_REG_INGRESSBW_PORT0_RATE_CTRL1 0x0010 ++#define RTL8367C_INGRESSBW_PORT0_RATE_CTRL1_DUMMY_OFFSET 3 ++#define RTL8367C_INGRESSBW_PORT0_RATE_CTRL1_DUMMY_MASK 0xFFF8 ++#define RTL8367C_INGRESSBW_PORT0_RATE_CTRL1_INGRESSBW_RATE16_OFFSET 0 ++#define RTL8367C_INGRESSBW_PORT0_RATE_CTRL1_INGRESSBW_RATE16_MASK 0x7 ++ ++#define RTL8367C_REG_PORT0_FORCE_RATE0 0x0011 ++ ++#define RTL8367C_REG_PORT0_FORCE_RATE1 0x0012 ++ ++#define RTL8367C_REG_PORT0_CURENT_RATE0 0x0013 ++ ++#define RTL8367C_REG_PORT0_CURENT_RATE1 0x0014 ++ ++#define RTL8367C_REG_PORT0_PAGE_COUNTER 0x0015 ++#define RTL8367C_PORT0_PAGE_COUNTER_OFFSET 0 ++#define RTL8367C_PORT0_PAGE_COUNTER_MASK 0x7F ++ ++#define RTL8367C_REG_PAGEMETER_PORT0_CTRL0 0x0016 ++ ++#define RTL8367C_REG_PAGEMETER_PORT0_CTRL1 0x0017 ++ ++#define RTL8367C_REG_PORT0_EEECFG 0x0018 ++#define RTL8367C_PORT0_EEECFG_EEEP_ENABLE_TX_OFFSET 14 ++#define RTL8367C_PORT0_EEECFG_EEEP_ENABLE_TX_MASK 0x4000 ++#define RTL8367C_PORT0_EEECFG_EEEP_ENABLE_RX_OFFSET 13 ++#define RTL8367C_PORT0_EEECFG_EEEP_ENABLE_RX_MASK 0x2000 ++#define RTL8367C_PORT0_EEECFG_EEE_FORCE_OFFSET 12 ++#define RTL8367C_PORT0_EEECFG_EEE_FORCE_MASK 0x1000 ++#define RTL8367C_PORT0_EEECFG_EEE_100M_OFFSET 11 ++#define RTL8367C_PORT0_EEECFG_EEE_100M_MASK 0x800 ++#define RTL8367C_PORT0_EEECFG_EEE_GIGA_500M_OFFSET 10 ++#define RTL8367C_PORT0_EEECFG_EEE_GIGA_500M_MASK 0x400 ++#define RTL8367C_PORT0_EEECFG_EEE_TX_OFFSET 9 ++#define RTL8367C_PORT0_EEECFG_EEE_TX_MASK 0x200 ++#define RTL8367C_PORT0_EEECFG_EEE_RX_OFFSET 8 ++#define RTL8367C_PORT0_EEECFG_EEE_RX_MASK 0x100 ++#define RTL8367C_PORT0_EEECFG_EEE_DSP_RX_OFFSET 6 ++#define RTL8367C_PORT0_EEECFG_EEE_DSP_RX_MASK 0x40 ++#define RTL8367C_PORT0_EEECFG_EEE_LPI_OFFSET 5 ++#define RTL8367C_PORT0_EEECFG_EEE_LPI_MASK 0x20 ++#define RTL8367C_PORT0_EEECFG_EEE_TX_LPI_OFFSET 4 ++#define RTL8367C_PORT0_EEECFG_EEE_TX_LPI_MASK 0x10 ++#define RTL8367C_PORT0_EEECFG_EEE_RX_LPI_OFFSET 3 ++#define RTL8367C_PORT0_EEECFG_EEE_RX_LPI_MASK 0x8 ++#define RTL8367C_PORT0_EEECFG_EEE_PAUSE_INDICATOR_OFFSET 2 ++#define RTL8367C_PORT0_EEECFG_EEE_PAUSE_INDICATOR_MASK 0x4 ++#define RTL8367C_PORT0_EEECFG_EEE_WAKE_REQ_OFFSET 1 ++#define RTL8367C_PORT0_EEECFG_EEE_WAKE_REQ_MASK 0x2 ++#define RTL8367C_PORT0_EEECFG_EEE_SLEEP_REQ_OFFSET 0 ++#define RTL8367C_PORT0_EEECFG_EEE_SLEEP_REQ_MASK 0x1 ++ ++#define RTL8367C_REG_PORT0_EEETXMTR 0x0019 ++ ++#define RTL8367C_REG_PORT0_EEERXMTR 0x001a ++ ++#define RTL8367C_REG_PORT0_EEEPTXMTR 0x001b ++ ++#define RTL8367C_REG_PORT0_EEEPRXMTR 0x001c ++ ++#define RTL8367C_REG_PTP_PORT0_CFG1 0x001e ++#define RTL8367C_PTP_PORT0_CFG1_OFFSET 7 ++#define RTL8367C_PTP_PORT0_CFG1_MASK 0xFF ++ ++#define RTL8367C_REG_P0_MSIC1 0x001f ++#define RTL8367C_P0_MSIC1_OFFSET 0 ++#define RTL8367C_P0_MSIC1_MASK 0x1 ++ ++#define RTL8367C_REG_PORT1_CGST_HALF_CFG 0x0020 ++#define RTL8367C_PORT1_CGST_HALF_CFG_CONGESTION_TIME_OFFSET 4 ++#define RTL8367C_PORT1_CGST_HALF_CFG_CONGESTION_TIME_MASK 0xF0 ++#define RTL8367C_PORT1_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_OFFSET 0 ++#define RTL8367C_PORT1_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_MASK 0xF ++ ++#define RTL8367C_REG_PKTGEN_PORT1_CTRL 0x0021 ++#define RTL8367C_PKTGEN_PORT1_CTRL_STATUS_OFFSET 15 ++#define RTL8367C_PKTGEN_PORT1_CTRL_STATUS_MASK 0x8000 ++#define RTL8367C_PKTGEN_PORT1_CTRL_PKTGEN_STS_OFFSET 13 ++#define RTL8367C_PKTGEN_PORT1_CTRL_PKTGEN_STS_MASK 0x2000 ++#define RTL8367C_PKTGEN_PORT1_CTRL_CRC_NO_ERROR_OFFSET 4 ++#define RTL8367C_PKTGEN_PORT1_CTRL_CRC_NO_ERROR_MASK 0x10 ++#define RTL8367C_PKTGEN_PORT1_CTRL_CMD_START_OFFSET 0 ++#define RTL8367C_PKTGEN_PORT1_CTRL_CMD_START_MASK 0x1 ++ ++#define RTL8367C_REG_TX_ERR_CNT_PORT1 0x0022 ++#define RTL8367C_TX_ERR_CNT_PORT1_OFFSET 0 ++#define RTL8367C_TX_ERR_CNT_PORT1_MASK 0x7 ++ ++#define RTL8367C_REG_PKTGEN_PORT1_DA0 0x0023 ++ ++#define RTL8367C_REG_PKTGEN_PORT1_DA1 0x0024 ++ ++#define RTL8367C_REG_PKTGEN_PORT1_DA2 0x0025 ++ ++#define RTL8367C_REG_PKTGEN_PORT1_SA0 0x0026 ++ ++#define RTL8367C_REG_PKTGEN_PORT1_SA1 0x0027 ++ ++#define RTL8367C_REG_PKTGEN_PORT1_SA2 0x0028 ++ ++#define RTL8367C_REG_PKTGEN_PORT1_COUNTER0 0x0029 ++ ++#define RTL8367C_REG_PKTGEN_PORT1_COUNTER1 0x002a ++#define RTL8367C_PKTGEN_PORT1_COUNTER1_OFFSET 0 ++#define RTL8367C_PKTGEN_PORT1_COUNTER1_MASK 0xFF ++ ++#define RTL8367C_REG_PKTGEN_PORT1_TX_LENGTH 0x002b ++#define RTL8367C_PKTGEN_PORT1_TX_LENGTH_OFFSET 0 ++#define RTL8367C_PKTGEN_PORT1_TX_LENGTH_MASK 0x3FFF ++ ++#define RTL8367C_REG_PKTGEN_PORT1_TIMER 0x002d ++#define RTL8367C_PKTGEN_PORT1_TIMER_TIMER_OFFSET 4 ++#define RTL8367C_PKTGEN_PORT1_TIMER_TIMER_MASK 0xF0 ++#define RTL8367C_PKTGEN_PORT1_TIMER_RX_DMA_ERR_FLAG_OFFSET 3 ++#define RTL8367C_PKTGEN_PORT1_TIMER_RX_DMA_ERR_FLAG_MASK 0x8 ++ ++#define RTL8367C_REG_PORT1_MISC_CFG 0x002e ++#define RTL8367C_PORT1_MISC_CFG_SMALL_TAG_IPG_OFFSET 15 ++#define RTL8367C_PORT1_MISC_CFG_SMALL_TAG_IPG_MASK 0x8000 ++#define RTL8367C_PORT1_MISC_CFG_TX_ITFSP_MODE_OFFSET 14 ++#define RTL8367C_PORT1_MISC_CFG_TX_ITFSP_MODE_MASK 0x4000 ++#define RTL8367C_PORT1_MISC_CFG_FLOWCTRL_INDEP_OFFSET 13 ++#define RTL8367C_PORT1_MISC_CFG_FLOWCTRL_INDEP_MASK 0x2000 ++#define RTL8367C_PORT1_MISC_CFG_DOT1Q_REMARK_ENABLE_OFFSET 12 ++#define RTL8367C_PORT1_MISC_CFG_DOT1Q_REMARK_ENABLE_MASK 0x1000 ++#define RTL8367C_PORT1_MISC_CFG_INGRESSBW_FLOWCTRL_OFFSET 11 ++#define RTL8367C_PORT1_MISC_CFG_INGRESSBW_FLOWCTRL_MASK 0x800 ++#define RTL8367C_PORT1_MISC_CFG_INGRESSBW_IFG_OFFSET 10 ++#define RTL8367C_PORT1_MISC_CFG_INGRESSBW_IFG_MASK 0x400 ++#define RTL8367C_PORT1_MISC_CFG_RX_SPC_OFFSET 9 ++#define RTL8367C_PORT1_MISC_CFG_RX_SPC_MASK 0x200 ++#define RTL8367C_PORT1_MISC_CFG_CRC_SKIP_OFFSET 8 ++#define RTL8367C_PORT1_MISC_CFG_CRC_SKIP_MASK 0x100 ++#define RTL8367C_PORT1_MISC_CFG_PKTGEN_TX_FIRST_OFFSET 7 ++#define RTL8367C_PORT1_MISC_CFG_PKTGEN_TX_FIRST_MASK 0x80 ++#define RTL8367C_PORT1_MISC_CFG_MAC_LOOPBACK_OFFSET 6 ++#define RTL8367C_PORT1_MISC_CFG_MAC_LOOPBACK_MASK 0x40 ++#define RTL8367C_PORT1_MISC_CFG_VLAN_EGRESS_MODE_OFFSET 4 ++#define RTL8367C_PORT1_MISC_CFG_VLAN_EGRESS_MODE_MASK 0x30 ++#define RTL8367C_PORT1_MISC_CFG_CONGESTION_SUSTAIN_TIME_OFFSET 0 ++#define RTL8367C_PORT1_MISC_CFG_CONGESTION_SUSTAIN_TIME_MASK 0xF ++ ++#define RTL8367C_REG_INGRESSBW_PORT1_RATE_CTRL0 0x002f ++ ++#define RTL8367C_REG_INGRESSBW_PORT1_RATE_CTRL1 0x0030 ++#define RTL8367C_INGRESSBW_PORT1_RATE_CTRL1_DUMMY_OFFSET 3 ++#define RTL8367C_INGRESSBW_PORT1_RATE_CTRL1_DUMMY_MASK 0xFFF8 ++#define RTL8367C_INGRESSBW_PORT1_RATE_CTRL1_INGRESSBW_RATE16_OFFSET 0 ++#define RTL8367C_INGRESSBW_PORT1_RATE_CTRL1_INGRESSBW_RATE16_MASK 0x7 ++ ++#define RTL8367C_REG_PORT1_FORCE_RATE0 0x0031 ++ ++#define RTL8367C_REG_PORT1_FORCE_RATE1 0x0032 ++ ++#define RTL8367C_REG_PORT1_CURENT_RATE0 0x0033 ++ ++#define RTL8367C_REG_PORT1_CURENT_RATE1 0x0034 ++ ++#define RTL8367C_REG_PORT1_PAGE_COUNTER 0x0035 ++#define RTL8367C_PORT1_PAGE_COUNTER_OFFSET 0 ++#define RTL8367C_PORT1_PAGE_COUNTER_MASK 0x7F ++ ++#define RTL8367C_REG_PAGEMETER_PORT1_CTRL0 0x0036 ++ ++#define RTL8367C_REG_PAGEMETER_PORT1_CTRL1 0x0037 ++ ++#define RTL8367C_REG_PORT1_EEECFG 0x0038 ++#define RTL8367C_PORT1_EEECFG_EEEP_ENABLE_TX_OFFSET 14 ++#define RTL8367C_PORT1_EEECFG_EEEP_ENABLE_TX_MASK 0x4000 ++#define RTL8367C_PORT1_EEECFG_EEEP_ENABLE_RX_OFFSET 13 ++#define RTL8367C_PORT1_EEECFG_EEEP_ENABLE_RX_MASK 0x2000 ++#define RTL8367C_PORT1_EEECFG_EEE_FORCE_OFFSET 12 ++#define RTL8367C_PORT1_EEECFG_EEE_FORCE_MASK 0x1000 ++#define RTL8367C_PORT1_EEECFG_EEE_100M_OFFSET 11 ++#define RTL8367C_PORT1_EEECFG_EEE_100M_MASK 0x800 ++#define RTL8367C_PORT1_EEECFG_EEE_GIGA_500M_OFFSET 10 ++#define RTL8367C_PORT1_EEECFG_EEE_GIGA_500M_MASK 0x400 ++#define RTL8367C_PORT1_EEECFG_EEE_TX_OFFSET 9 ++#define RTL8367C_PORT1_EEECFG_EEE_TX_MASK 0x200 ++#define RTL8367C_PORT1_EEECFG_EEE_RX_OFFSET 8 ++#define RTL8367C_PORT1_EEECFG_EEE_RX_MASK 0x100 ++#define RTL8367C_PORT1_EEECFG_EEE_DSP_RX_OFFSET 6 ++#define RTL8367C_PORT1_EEECFG_EEE_DSP_RX_MASK 0x40 ++#define RTL8367C_PORT1_EEECFG_EEE_LPI_OFFSET 5 ++#define RTL8367C_PORT1_EEECFG_EEE_LPI_MASK 0x20 ++#define RTL8367C_PORT1_EEECFG_EEE_TX_LPI_OFFSET 4 ++#define RTL8367C_PORT1_EEECFG_EEE_TX_LPI_MASK 0x10 ++#define RTL8367C_PORT1_EEECFG_EEE_RX_LPI_OFFSET 3 ++#define RTL8367C_PORT1_EEECFG_EEE_RX_LPI_MASK 0x8 ++#define RTL8367C_PORT1_EEECFG_EEE_PAUSE_INDICATOR_OFFSET 2 ++#define RTL8367C_PORT1_EEECFG_EEE_PAUSE_INDICATOR_MASK 0x4 ++#define RTL8367C_PORT1_EEECFG_EEE_WAKE_REQ_OFFSET 1 ++#define RTL8367C_PORT1_EEECFG_EEE_WAKE_REQ_MASK 0x2 ++#define RTL8367C_PORT1_EEECFG_EEE_SLEEP_REQ_OFFSET 0 ++#define RTL8367C_PORT1_EEECFG_EEE_SLEEP_REQ_MASK 0x1 ++ ++#define RTL8367C_REG_PORT1_EEETXMTR 0x0039 ++ ++#define RTL8367C_REG_PORT1_EEERXMTR 0x003a ++ ++#define RTL8367C_REG_PORT1_EEEPTXMTR 0x003b ++ ++#define RTL8367C_REG_PORT1_EEEPRXMTR 0x003c ++ ++#define RTL8367C_REG_PTP_PORT1_CFG1 0x003e ++#define RTL8367C_PTP_PORT1_CFG1_OFFSET 7 ++#define RTL8367C_PTP_PORT1_CFG1_MASK 0xFF ++ ++#define RTL8367C_REG_P1_MSIC1 0x003f ++#define RTL8367C_P1_MSIC1_OFFSET 0 ++#define RTL8367C_P1_MSIC1_MASK 0x1 ++ ++#define RTL8367C_REG_PORT2_CGST_HALF_CFG 0x0040 ++#define RTL8367C_PORT2_CGST_HALF_CFG_CONGESTION_TIME_OFFSET 4 ++#define RTL8367C_PORT2_CGST_HALF_CFG_CONGESTION_TIME_MASK 0xF0 ++#define RTL8367C_PORT2_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_OFFSET 0 ++#define RTL8367C_PORT2_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_MASK 0xF ++ ++#define RTL8367C_REG_PKTGEN_PORT2_CTRL 0x0041 ++#define RTL8367C_PKTGEN_PORT2_CTRL_STATUS_OFFSET 15 ++#define RTL8367C_PKTGEN_PORT2_CTRL_STATUS_MASK 0x8000 ++#define RTL8367C_PKTGEN_PORT2_CTRL_PKTGEN_STS_OFFSET 13 ++#define RTL8367C_PKTGEN_PORT2_CTRL_PKTGEN_STS_MASK 0x2000 ++#define RTL8367C_PKTGEN_PORT2_CTRL_CRC_NO_ERROR_OFFSET 4 ++#define RTL8367C_PKTGEN_PORT2_CTRL_CRC_NO_ERROR_MASK 0x10 ++#define RTL8367C_PKTGEN_PORT2_CTRL_CMD_START_OFFSET 0 ++#define RTL8367C_PKTGEN_PORT2_CTRL_CMD_START_MASK 0x1 ++ ++#define RTL8367C_REG_TX_ERR_CNT_PORT2 0x0042 ++#define RTL8367C_TX_ERR_CNT_PORT2_OFFSET 0 ++#define RTL8367C_TX_ERR_CNT_PORT2_MASK 0x7 ++ ++#define RTL8367C_REG_PKTGEN_PORT2_DA0 0x0043 ++ ++#define RTL8367C_REG_PKTGEN_PORT2_DA1 0x0044 ++ ++#define RTL8367C_REG_PKTGEN_PORT2_DA2 0x0045 ++ ++#define RTL8367C_REG_PKTGEN_PORT2_SA0 0x0046 ++ ++#define RTL8367C_REG_PKTGEN_PORT2_SA1 0x0047 ++ ++#define RTL8367C_REG_PKTGEN_PORT2_SA2 0x0048 ++ ++#define RTL8367C_REG_PKTGEN_PORT2_COUNTER0 0x0049 ++ ++#define RTL8367C_REG_PKTGEN_PORT2_COUNTER1 0x004a ++#define RTL8367C_PKTGEN_PORT2_COUNTER1_OFFSET 0 ++#define RTL8367C_PKTGEN_PORT2_COUNTER1_MASK 0xFF ++ ++#define RTL8367C_REG_PKTGEN_PORT2_TX_LENGTH 0x004b ++#define RTL8367C_PKTGEN_PORT2_TX_LENGTH_OFFSET 0 ++#define RTL8367C_PKTGEN_PORT2_TX_LENGTH_MASK 0x3FFF ++ ++#define RTL8367C_REG_PKTGEN_PORT2_TIMER 0x004d ++#define RTL8367C_PKTGEN_PORT2_TIMER_TIMER_OFFSET 4 ++#define RTL8367C_PKTGEN_PORT2_TIMER_TIMER_MASK 0xF0 ++#define RTL8367C_PKTGEN_PORT2_TIMER_RX_DMA_ERR_FLAG_OFFSET 3 ++#define RTL8367C_PKTGEN_PORT2_TIMER_RX_DMA_ERR_FLAG_MASK 0x8 ++ ++#define RTL8367C_REG_PORT2_MISC_CFG 0x004e ++#define RTL8367C_PORT2_MISC_CFG_SMALL_TAG_IPG_OFFSET 15 ++#define RTL8367C_PORT2_MISC_CFG_SMALL_TAG_IPG_MASK 0x8000 ++#define RTL8367C_PORT2_MISC_CFG_TX_ITFSP_MODE_OFFSET 14 ++#define RTL8367C_PORT2_MISC_CFG_TX_ITFSP_MODE_MASK 0x4000 ++#define RTL8367C_PORT2_MISC_CFG_FLOWCTRL_INDEP_OFFSET 13 ++#define RTL8367C_PORT2_MISC_CFG_FLOWCTRL_INDEP_MASK 0x2000 ++#define RTL8367C_PORT2_MISC_CFG_DOT1Q_REMARK_ENABLE_OFFSET 12 ++#define RTL8367C_PORT2_MISC_CFG_DOT1Q_REMARK_ENABLE_MASK 0x1000 ++#define RTL8367C_PORT2_MISC_CFG_INGRESSBW_FLOWCTRL_OFFSET 11 ++#define RTL8367C_PORT2_MISC_CFG_INGRESSBW_FLOWCTRL_MASK 0x800 ++#define RTL8367C_PORT2_MISC_CFG_INGRESSBW_IFG_OFFSET 10 ++#define RTL8367C_PORT2_MISC_CFG_INGRESSBW_IFG_MASK 0x400 ++#define RTL8367C_PORT2_MISC_CFG_RX_SPC_OFFSET 9 ++#define RTL8367C_PORT2_MISC_CFG_RX_SPC_MASK 0x200 ++#define RTL8367C_PORT2_MISC_CFG_CRC_SKIP_OFFSET 8 ++#define RTL8367C_PORT2_MISC_CFG_CRC_SKIP_MASK 0x100 ++#define RTL8367C_PORT2_MISC_CFG_PKTGEN_TX_FIRST_OFFSET 7 ++#define RTL8367C_PORT2_MISC_CFG_PKTGEN_TX_FIRST_MASK 0x80 ++#define RTL8367C_PORT2_MISC_CFG_MAC_LOOPBACK_OFFSET 6 ++#define RTL8367C_PORT2_MISC_CFG_MAC_LOOPBACK_MASK 0x40 ++#define RTL8367C_PORT2_MISC_CFG_VLAN_EGRESS_MODE_OFFSET 4 ++#define RTL8367C_PORT2_MISC_CFG_VLAN_EGRESS_MODE_MASK 0x30 ++#define RTL8367C_PORT2_MISC_CFG_CONGESTION_SUSTAIN_TIME_OFFSET 0 ++#define RTL8367C_PORT2_MISC_CFG_CONGESTION_SUSTAIN_TIME_MASK 0xF ++ ++#define RTL8367C_REG_INGRESSBW_PORT2_RATE_CTRL0 0x004f ++ ++#define RTL8367C_REG_INGRESSBW_PORT2_RATE_CTRL1 0x0050 ++#define RTL8367C_INGRESSBW_PORT2_RATE_CTRL1_DUMMY_OFFSET 3 ++#define RTL8367C_INGRESSBW_PORT2_RATE_CTRL1_DUMMY_MASK 0xFFF8 ++#define RTL8367C_INGRESSBW_PORT2_RATE_CTRL1_INGRESSBW_RATE16_OFFSET 0 ++#define RTL8367C_INGRESSBW_PORT2_RATE_CTRL1_INGRESSBW_RATE16_MASK 0x7 ++ ++#define RTL8367C_REG_PORT2_FORCE_RATE0 0x0051 ++ ++#define RTL8367C_REG_PORT2_FORCE_RATE1 0x0052 ++ ++#define RTL8367C_REG_PORT2_CURENT_RATE0 0x0053 ++ ++#define RTL8367C_REG_PORT2_CURENT_RATE1 0x0054 ++ ++#define RTL8367C_REG_PORT2_PAGE_COUNTER 0x0055 ++#define RTL8367C_PORT2_PAGE_COUNTER_OFFSET 0 ++#define RTL8367C_PORT2_PAGE_COUNTER_MASK 0x7F ++ ++#define RTL8367C_REG_PAGEMETER_PORT2_CTRL0 0x0056 ++ ++#define RTL8367C_REG_PAGEMETER_PORT2_CTRL1 0x0057 ++ ++#define RTL8367C_REG_PORT2_EEECFG 0x0058 ++#define RTL8367C_PORT2_EEECFG_EEEP_ENABLE_TX_OFFSET 14 ++#define RTL8367C_PORT2_EEECFG_EEEP_ENABLE_TX_MASK 0x4000 ++#define RTL8367C_PORT2_EEECFG_EEEP_ENABLE_RX_OFFSET 13 ++#define RTL8367C_PORT2_EEECFG_EEEP_ENABLE_RX_MASK 0x2000 ++#define RTL8367C_PORT2_EEECFG_EEE_FORCE_OFFSET 12 ++#define RTL8367C_PORT2_EEECFG_EEE_FORCE_MASK 0x1000 ++#define RTL8367C_PORT2_EEECFG_EEE_100M_OFFSET 11 ++#define RTL8367C_PORT2_EEECFG_EEE_100M_MASK 0x800 ++#define RTL8367C_PORT2_EEECFG_EEE_GIGA_500M_OFFSET 10 ++#define RTL8367C_PORT2_EEECFG_EEE_GIGA_500M_MASK 0x400 ++#define RTL8367C_PORT2_EEECFG_EEE_TX_OFFSET 9 ++#define RTL8367C_PORT2_EEECFG_EEE_TX_MASK 0x200 ++#define RTL8367C_PORT2_EEECFG_EEE_RX_OFFSET 8 ++#define RTL8367C_PORT2_EEECFG_EEE_RX_MASK 0x100 ++#define RTL8367C_PORT2_EEECFG_EEE_DSP_RX_OFFSET 6 ++#define RTL8367C_PORT2_EEECFG_EEE_DSP_RX_MASK 0x40 ++#define RTL8367C_PORT2_EEECFG_EEE_LPI_OFFSET 5 ++#define RTL8367C_PORT2_EEECFG_EEE_LPI_MASK 0x20 ++#define RTL8367C_PORT2_EEECFG_EEE_TX_LPI_OFFSET 4 ++#define RTL8367C_PORT2_EEECFG_EEE_TX_LPI_MASK 0x10 ++#define RTL8367C_PORT2_EEECFG_EEE_RX_LPI_OFFSET 3 ++#define RTL8367C_PORT2_EEECFG_EEE_RX_LPI_MASK 0x8 ++#define RTL8367C_PORT2_EEECFG_EEE_PAUSE_INDICATOR_OFFSET 2 ++#define RTL8367C_PORT2_EEECFG_EEE_PAUSE_INDICATOR_MASK 0x4 ++#define RTL8367C_PORT2_EEECFG_EEE_WAKE_REQ_OFFSET 1 ++#define RTL8367C_PORT2_EEECFG_EEE_WAKE_REQ_MASK 0x2 ++#define RTL8367C_PORT2_EEECFG_EEE_SLEEP_REQ_OFFSET 0 ++#define RTL8367C_PORT2_EEECFG_EEE_SLEEP_REQ_MASK 0x1 ++ ++#define RTL8367C_REG_PORT2_EEETXMTR 0x0059 ++ ++#define RTL8367C_REG_PORT2_EEERXMTR 0x005a ++ ++#define RTL8367C_REG_PORT2_EEEPTXMTR 0x005b ++ ++#define RTL8367C_REG_PORT2_EEEPRXMTR 0x005c ++ ++#define RTL8367C_REG_PTP_PORT2_CFG1 0x005e ++#define RTL8367C_PTP_PORT2_CFG1_OFFSET 7 ++#define RTL8367C_PTP_PORT2_CFG1_MASK 0xFF ++ ++#define RTL8367C_REG_P2_MSIC1 0x005f ++#define RTL8367C_P2_MSIC1_OFFSET 0 ++#define RTL8367C_P2_MSIC1_MASK 0x1 ++ ++#define RTL8367C_REG_PORT3_CGST_HALF_CFG 0x0060 ++#define RTL8367C_PORT3_CGST_HALF_CFG_CONGESTION_TIME_OFFSET 4 ++#define RTL8367C_PORT3_CGST_HALF_CFG_CONGESTION_TIME_MASK 0xF0 ++#define RTL8367C_PORT3_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_OFFSET 0 ++#define RTL8367C_PORT3_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_MASK 0xF ++ ++#define RTL8367C_REG_PKTGEN_PORT3_CTRL 0x0061 ++#define RTL8367C_PKTGEN_PORT3_CTRL_STATUS_OFFSET 15 ++#define RTL8367C_PKTGEN_PORT3_CTRL_STATUS_MASK 0x8000 ++#define RTL8367C_PKTGEN_PORT3_CTRL_PKTGEN_STS_OFFSET 13 ++#define RTL8367C_PKTGEN_PORT3_CTRL_PKTGEN_STS_MASK 0x2000 ++#define RTL8367C_PKTGEN_PORT3_CTRL_CRC_NO_ERROR_OFFSET 4 ++#define RTL8367C_PKTGEN_PORT3_CTRL_CRC_NO_ERROR_MASK 0x10 ++#define RTL8367C_PKTGEN_PORT3_CTRL_CMD_START_OFFSET 0 ++#define RTL8367C_PKTGEN_PORT3_CTRL_CMD_START_MASK 0x1 ++ ++#define RTL8367C_REG_TX_ERR_CNT_PORT3 0x0062 ++#define RTL8367C_TX_ERR_CNT_PORT3_OFFSET 0 ++#define RTL8367C_TX_ERR_CNT_PORT3_MASK 0x7 ++ ++#define RTL8367C_REG_PKTGEN_PORT3_DA0 0x0063 ++ ++#define RTL8367C_REG_PKTGEN_PORT3_DA1 0x0064 ++ ++#define RTL8367C_REG_PKTGEN_PORT3_DA2 0x0065 ++ ++#define RTL8367C_REG_PKTGEN_PORT3_SA0 0x0066 ++ ++#define RTL8367C_REG_PKTGEN_PORT3_SA1 0x0067 ++ ++#define RTL8367C_REG_PKTGEN_PORT3_SA2 0x0068 ++ ++#define RTL8367C_REG_PKTGEN_PORT3_COUNTER0 0x0069 ++ ++#define RTL8367C_REG_PKTGEN_PORT3_COUNTER1 0x006a ++#define RTL8367C_PKTGEN_PORT3_COUNTER1_OFFSET 0 ++#define RTL8367C_PKTGEN_PORT3_COUNTER1_MASK 0xFF ++ ++#define RTL8367C_REG_PKTGEN_PORT3_TX_LENGTH 0x006b ++#define RTL8367C_PKTGEN_PORT3_TX_LENGTH_OFFSET 0 ++#define RTL8367C_PKTGEN_PORT3_TX_LENGTH_MASK 0x3FFF ++ ++#define RTL8367C_REG_PKTGEN_PORT3_TIMER 0x006d ++#define RTL8367C_PKTGEN_PORT3_TIMER_TIMER_OFFSET 4 ++#define RTL8367C_PKTGEN_PORT3_TIMER_TIMER_MASK 0xF0 ++#define RTL8367C_PKTGEN_PORT3_TIMER_RX_DMA_ERR_FLAG_OFFSET 3 ++#define RTL8367C_PKTGEN_PORT3_TIMER_RX_DMA_ERR_FLAG_MASK 0x8 ++ ++#define RTL8367C_REG_PORT3_MISC_CFG 0x006e ++#define RTL8367C_PORT3_MISC_CFG_SMALL_TAG_IPG_OFFSET 15 ++#define RTL8367C_PORT3_MISC_CFG_SMALL_TAG_IPG_MASK 0x8000 ++#define RTL8367C_PORT3_MISC_CFG_TX_ITFSP_MODE_OFFSET 14 ++#define RTL8367C_PORT3_MISC_CFG_TX_ITFSP_MODE_MASK 0x4000 ++#define RTL8367C_PORT3_MISC_CFG_FLOWCTRL_INDEP_OFFSET 13 ++#define RTL8367C_PORT3_MISC_CFG_FLOWCTRL_INDEP_MASK 0x2000 ++#define RTL8367C_PORT3_MISC_CFG_DOT1Q_REMARK_ENABLE_OFFSET 12 ++#define RTL8367C_PORT3_MISC_CFG_DOT1Q_REMARK_ENABLE_MASK 0x1000 ++#define RTL8367C_PORT3_MISC_CFG_INGRESSBW_FLOWCTRL_OFFSET 11 ++#define RTL8367C_PORT3_MISC_CFG_INGRESSBW_FLOWCTRL_MASK 0x800 ++#define RTL8367C_PORT3_MISC_CFG_INGRESSBW_IFG_OFFSET 10 ++#define RTL8367C_PORT3_MISC_CFG_INGRESSBW_IFG_MASK 0x400 ++#define RTL8367C_PORT3_MISC_CFG_RX_SPC_OFFSET 9 ++#define RTL8367C_PORT3_MISC_CFG_RX_SPC_MASK 0x200 ++#define RTL8367C_PORT3_MISC_CFG_CRC_SKIP_OFFSET 8 ++#define RTL8367C_PORT3_MISC_CFG_CRC_SKIP_MASK 0x100 ++#define RTL8367C_PORT3_MISC_CFG_PKTGEN_TX_FIRST_OFFSET 7 ++#define RTL8367C_PORT3_MISC_CFG_PKTGEN_TX_FIRST_MASK 0x80 ++#define RTL8367C_PORT3_MISC_CFG_MAC_LOOPBACK_OFFSET 6 ++#define RTL8367C_PORT3_MISC_CFG_MAC_LOOPBACK_MASK 0x40 ++#define RTL8367C_PORT3_MISC_CFG_VLAN_EGRESS_MODE_OFFSET 4 ++#define RTL8367C_PORT3_MISC_CFG_VLAN_EGRESS_MODE_MASK 0x30 ++#define RTL8367C_PORT3_MISC_CFG_CONGESTION_SUSTAIN_TIME_OFFSET 0 ++#define RTL8367C_PORT3_MISC_CFG_CONGESTION_SUSTAIN_TIME_MASK 0xF ++ ++#define RTL8367C_REG_INGRESSBW_PORT3_RATE_CTRL0 0x006f ++ ++#define RTL8367C_REG_INGRESSBW_PORT3_RATE_CTRL1 0x0070 ++#define RTL8367C_INGRESSBW_PORT3_RATE_CTRL1_DUMMY_OFFSET 3 ++#define RTL8367C_INGRESSBW_PORT3_RATE_CTRL1_DUMMY_MASK 0xFFF8 ++#define RTL8367C_INGRESSBW_PORT3_RATE_CTRL1_INGRESSBW_RATE16_OFFSET 0 ++#define RTL8367C_INGRESSBW_PORT3_RATE_CTRL1_INGRESSBW_RATE16_MASK 0x7 ++ ++#define RTL8367C_REG_PORT3_FORCE_RATE0 0x0071 ++ ++#define RTL8367C_REG_PORT3_FORCE_RATE1 0x0072 ++ ++#define RTL8367C_REG_PORT3_CURENT_RATE0 0x0073 ++ ++#define RTL8367C_REG_PORT3_CURENT_RATE1 0x0074 ++ ++#define RTL8367C_REG_PORT3_PAGE_COUNTER 0x0075 ++#define RTL8367C_PORT3_PAGE_COUNTER_OFFSET 0 ++#define RTL8367C_PORT3_PAGE_COUNTER_MASK 0x7F ++ ++#define RTL8367C_REG_PAGEMETER_PORT3_CTRL0 0x0076 ++ ++#define RTL8367C_REG_PAGEMETER_PORT3_CTRL1 0x0077 ++ ++#define RTL8367C_REG_PORT3_EEECFG 0x0078 ++#define RTL8367C_PORT3_EEECFG_EEEP_ENABLE_TX_OFFSET 14 ++#define RTL8367C_PORT3_EEECFG_EEEP_ENABLE_TX_MASK 0x4000 ++#define RTL8367C_PORT3_EEECFG_EEEP_ENABLE_RX_OFFSET 13 ++#define RTL8367C_PORT3_EEECFG_EEEP_ENABLE_RX_MASK 0x2000 ++#define RTL8367C_PORT3_EEECFG_EEE_FORCE_OFFSET 12 ++#define RTL8367C_PORT3_EEECFG_EEE_FORCE_MASK 0x1000 ++#define RTL8367C_PORT3_EEECFG_EEE_100M_OFFSET 11 ++#define RTL8367C_PORT3_EEECFG_EEE_100M_MASK 0x800 ++#define RTL8367C_PORT3_EEECFG_EEE_GIGA_500M_OFFSET 10 ++#define RTL8367C_PORT3_EEECFG_EEE_GIGA_500M_MASK 0x400 ++#define RTL8367C_PORT3_EEECFG_EEE_TX_OFFSET 9 ++#define RTL8367C_PORT3_EEECFG_EEE_TX_MASK 0x200 ++#define RTL8367C_PORT3_EEECFG_EEE_RX_OFFSET 8 ++#define RTL8367C_PORT3_EEECFG_EEE_RX_MASK 0x100 ++#define RTL8367C_PORT3_EEECFG_EEE_DSP_RX_OFFSET 6 ++#define RTL8367C_PORT3_EEECFG_EEE_DSP_RX_MASK 0x40 ++#define RTL8367C_PORT3_EEECFG_EEE_LPI_OFFSET 5 ++#define RTL8367C_PORT3_EEECFG_EEE_LPI_MASK 0x20 ++#define RTL8367C_PORT3_EEECFG_EEE_TX_LPI_OFFSET 4 ++#define RTL8367C_PORT3_EEECFG_EEE_TX_LPI_MASK 0x10 ++#define RTL8367C_PORT3_EEECFG_EEE_RX_LPI_OFFSET 3 ++#define RTL8367C_PORT3_EEECFG_EEE_RX_LPI_MASK 0x8 ++#define RTL8367C_PORT3_EEECFG_EEE_PAUSE_INDICATOR_OFFSET 2 ++#define RTL8367C_PORT3_EEECFG_EEE_PAUSE_INDICATOR_MASK 0x4 ++#define RTL8367C_PORT3_EEECFG_EEE_WAKE_REQ_OFFSET 1 ++#define RTL8367C_PORT3_EEECFG_EEE_WAKE_REQ_MASK 0x2 ++#define RTL8367C_PORT3_EEECFG_EEE_SLEEP_REQ_OFFSET 0 ++#define RTL8367C_PORT3_EEECFG_EEE_SLEEP_REQ_MASK 0x1 ++ ++#define RTL8367C_REG_PORT3_EEETXMTR 0x0079 ++ ++#define RTL8367C_REG_PORT3_EEERXMTR 0x007a ++ ++#define RTL8367C_REG_PORT3_EEEPTXMTR 0x007b ++ ++#define RTL8367C_REG_PORT3_EEEPRXMTR 0x007c ++ ++#define RTL8367C_REG_PTP_PORT3_CFG1 0x007e ++#define RTL8367C_PTP_PORT3_CFG1_OFFSET 7 ++#define RTL8367C_PTP_PORT3_CFG1_MASK 0xFF ++ ++#define RTL8367C_REG_P3_MSIC1 0x007f ++#define RTL8367C_P3_MSIC1_OFFSET 0 ++#define RTL8367C_P3_MSIC1_MASK 0x1 ++ ++#define RTL8367C_REG_PORT4_CGST_HALF_CFG 0x0080 ++#define RTL8367C_PORT4_CGST_HALF_CFG_CONGESTION_TIME_OFFSET 4 ++#define RTL8367C_PORT4_CGST_HALF_CFG_CONGESTION_TIME_MASK 0xF0 ++#define RTL8367C_PORT4_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_OFFSET 0 ++#define RTL8367C_PORT4_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_MASK 0xF ++ ++#define RTL8367C_REG_PKTGEN_PORT4_CTRL 0x0081 ++#define RTL8367C_PKTGEN_PORT4_CTRL_STATUS_OFFSET 15 ++#define RTL8367C_PKTGEN_PORT4_CTRL_STATUS_MASK 0x8000 ++#define RTL8367C_PKTGEN_PORT4_CTRL_PKTGEN_STS_OFFSET 13 ++#define RTL8367C_PKTGEN_PORT4_CTRL_PKTGEN_STS_MASK 0x2000 ++#define RTL8367C_PKTGEN_PORT4_CTRL_CRC_NO_ERROR_OFFSET 4 ++#define RTL8367C_PKTGEN_PORT4_CTRL_CRC_NO_ERROR_MASK 0x10 ++#define RTL8367C_PKTGEN_PORT4_CTRL_CMD_START_OFFSET 0 ++#define RTL8367C_PKTGEN_PORT4_CTRL_CMD_START_MASK 0x1 ++ ++#define RTL8367C_REG_TX_ERR_CNT_PORT4 0x0082 ++#define RTL8367C_TX_ERR_CNT_PORT4_OFFSET 0 ++#define RTL8367C_TX_ERR_CNT_PORT4_MASK 0x7 ++ ++#define RTL8367C_REG_PKTGEN_PORT4_DA0 0x0083 ++ ++#define RTL8367C_REG_PKTGEN_PORT4_DA1 0x0084 ++ ++#define RTL8367C_REG_PKTGEN_PORT4_DA2 0x0085 ++ ++#define RTL8367C_REG_PKTGEN_PORT4_SA0 0x0086 ++ ++#define RTL8367C_REG_PKTGEN_PORT4_SA1 0x0087 ++ ++#define RTL8367C_REG_PKTGEN_PORT4_SA2 0x0088 ++ ++#define RTL8367C_REG_PKTGEN_PORT4_COUNTER0 0x0089 ++ ++#define RTL8367C_REG_PKTGEN_PORT4_COUNTER1 0x008a ++#define RTL8367C_PKTGEN_PORT4_COUNTER1_OFFSET 0 ++#define RTL8367C_PKTGEN_PORT4_COUNTER1_MASK 0xFF ++ ++#define RTL8367C_REG_PKTGEN_PORT4_TX_LENGTH 0x008b ++#define RTL8367C_PKTGEN_PORT4_TX_LENGTH_OFFSET 0 ++#define RTL8367C_PKTGEN_PORT4_TX_LENGTH_MASK 0x3FFF ++ ++#define RTL8367C_REG_PKTGEN_PORT4_TIMER 0x008d ++#define RTL8367C_PKTGEN_PORT4_TIMER_TIMER_OFFSET 4 ++#define RTL8367C_PKTGEN_PORT4_TIMER_TIMER_MASK 0xF0 ++#define RTL8367C_PKTGEN_PORT4_TIMER_RX_DMA_ERR_FLAG_OFFSET 3 ++#define RTL8367C_PKTGEN_PORT4_TIMER_RX_DMA_ERR_FLAG_MASK 0x8 ++ ++#define RTL8367C_REG_PORT4_MISC_CFG 0x008e ++#define RTL8367C_PORT4_MISC_CFG_SMALL_TAG_IPG_OFFSET 15 ++#define RTL8367C_PORT4_MISC_CFG_SMALL_TAG_IPG_MASK 0x8000 ++#define RTL8367C_PORT4_MISC_CFG_TX_ITFSP_MODE_OFFSET 14 ++#define RTL8367C_PORT4_MISC_CFG_TX_ITFSP_MODE_MASK 0x4000 ++#define RTL8367C_PORT4_MISC_CFG_FLOWCTRL_INDEP_OFFSET 13 ++#define RTL8367C_PORT4_MISC_CFG_FLOWCTRL_INDEP_MASK 0x2000 ++#define RTL8367C_PORT4_MISC_CFG_DOT1Q_REMARK_ENABLE_OFFSET 12 ++#define RTL8367C_PORT4_MISC_CFG_DOT1Q_REMARK_ENABLE_MASK 0x1000 ++#define RTL8367C_PORT4_MISC_CFG_INGRESSBW_FLOWCTRL_OFFSET 11 ++#define RTL8367C_PORT4_MISC_CFG_INGRESSBW_FLOWCTRL_MASK 0x800 ++#define RTL8367C_PORT4_MISC_CFG_INGRESSBW_IFG_OFFSET 10 ++#define RTL8367C_PORT4_MISC_CFG_INGRESSBW_IFG_MASK 0x400 ++#define RTL8367C_PORT4_MISC_CFG_RX_SPC_OFFSET 9 ++#define RTL8367C_PORT4_MISC_CFG_RX_SPC_MASK 0x200 ++#define RTL8367C_PORT4_MISC_CFG_CRC_SKIP_OFFSET 8 ++#define RTL8367C_PORT4_MISC_CFG_CRC_SKIP_MASK 0x100 ++#define RTL8367C_PORT4_MISC_CFG_PKTGEN_TX_FIRST_OFFSET 7 ++#define RTL8367C_PORT4_MISC_CFG_PKTGEN_TX_FIRST_MASK 0x80 ++#define RTL8367C_PORT4_MISC_CFG_MAC_LOOPBACK_OFFSET 6 ++#define RTL8367C_PORT4_MISC_CFG_MAC_LOOPBACK_MASK 0x40 ++#define RTL8367C_PORT4_MISC_CFG_VLAN_EGRESS_MODE_OFFSET 4 ++#define RTL8367C_PORT4_MISC_CFG_VLAN_EGRESS_MODE_MASK 0x30 ++#define RTL8367C_PORT4_MISC_CFG_CONGESTION_SUSTAIN_TIME_OFFSET 0 ++#define RTL8367C_PORT4_MISC_CFG_CONGESTION_SUSTAIN_TIME_MASK 0xF ++ ++#define RTL8367C_REG_INGRESSBW_PORT4_RATE_CTRL0 0x008f ++ ++#define RTL8367C_REG_INGRESSBW_PORT4_RATE_CTRL1 0x0090 ++#define RTL8367C_INGRESSBW_PORT4_RATE_CTRL1_DUMMY_OFFSET 3 ++#define RTL8367C_INGRESSBW_PORT4_RATE_CTRL1_DUMMY_MASK 0xFFF8 ++#define RTL8367C_INGRESSBW_PORT4_RATE_CTRL1_INGRESSBW_RATE16_OFFSET 0 ++#define RTL8367C_INGRESSBW_PORT4_RATE_CTRL1_INGRESSBW_RATE16_MASK 0x7 ++ ++#define RTL8367C_REG_PORT4_FORCE_RATE0 0x0091 ++ ++#define RTL8367C_REG_PORT4_FORCE_RATE1 0x0092 ++ ++#define RTL8367C_REG_PORT4_CURENT_RATE0 0x0093 ++ ++#define RTL8367C_REG_PORT4_CURENT_RATE1 0x0094 ++ ++#define RTL8367C_REG_PORT4_PAGE_COUNTER 0x0095 ++#define RTL8367C_PORT4_PAGE_COUNTER_OFFSET 0 ++#define RTL8367C_PORT4_PAGE_COUNTER_MASK 0x7F ++ ++#define RTL8367C_REG_PAGEMETER_PORT4_CTRL0 0x0096 ++ ++#define RTL8367C_REG_PAGEMETER_PORT4_CTRL1 0x0097 ++ ++#define RTL8367C_REG_PORT4_EEECFG 0x0098 ++#define RTL8367C_PORT4_EEECFG_EEEP_ENABLE_TX_OFFSET 14 ++#define RTL8367C_PORT4_EEECFG_EEEP_ENABLE_TX_MASK 0x4000 ++#define RTL8367C_PORT4_EEECFG_EEEP_ENABLE_RX_OFFSET 13 ++#define RTL8367C_PORT4_EEECFG_EEEP_ENABLE_RX_MASK 0x2000 ++#define RTL8367C_PORT4_EEECFG_EEE_FORCE_OFFSET 12 ++#define RTL8367C_PORT4_EEECFG_EEE_FORCE_MASK 0x1000 ++#define RTL8367C_PORT4_EEECFG_EEE_100M_OFFSET 11 ++#define RTL8367C_PORT4_EEECFG_EEE_100M_MASK 0x800 ++#define RTL8367C_PORT4_EEECFG_EEE_GIGA_500M_OFFSET 10 ++#define RTL8367C_PORT4_EEECFG_EEE_GIGA_500M_MASK 0x400 ++#define RTL8367C_PORT4_EEECFG_EEE_TX_OFFSET 9 ++#define RTL8367C_PORT4_EEECFG_EEE_TX_MASK 0x200 ++#define RTL8367C_PORT4_EEECFG_EEE_RX_OFFSET 8 ++#define RTL8367C_PORT4_EEECFG_EEE_RX_MASK 0x100 ++#define RTL8367C_PORT4_EEECFG_EEE_DSP_RX_OFFSET 6 ++#define RTL8367C_PORT4_EEECFG_EEE_DSP_RX_MASK 0x40 ++#define RTL8367C_PORT4_EEECFG_EEE_LPI_OFFSET 5 ++#define RTL8367C_PORT4_EEECFG_EEE_LPI_MASK 0x20 ++#define RTL8367C_PORT4_EEECFG_EEE_TX_LPI_OFFSET 4 ++#define RTL8367C_PORT4_EEECFG_EEE_TX_LPI_MASK 0x10 ++#define RTL8367C_PORT4_EEECFG_EEE_RX_LPI_OFFSET 3 ++#define RTL8367C_PORT4_EEECFG_EEE_RX_LPI_MASK 0x8 ++#define RTL8367C_PORT4_EEECFG_EEE_PAUSE_INDICATOR_OFFSET 2 ++#define RTL8367C_PORT4_EEECFG_EEE_PAUSE_INDICATOR_MASK 0x4 ++#define RTL8367C_PORT4_EEECFG_EEE_WAKE_REQ_OFFSET 1 ++#define RTL8367C_PORT4_EEECFG_EEE_WAKE_REQ_MASK 0x2 ++#define RTL8367C_PORT4_EEECFG_EEE_SLEEP_REQ_OFFSET 0 ++#define RTL8367C_PORT4_EEECFG_EEE_SLEEP_REQ_MASK 0x1 ++ ++#define RTL8367C_REG_PORT4_EEETXMTR 0x0099 ++ ++#define RTL8367C_REG_PORT4_EEERXMTR 0x009a ++ ++#define RTL8367C_REG_PORT4_EEEPTXMTR 0x009b ++ ++#define RTL8367C_REG_PORT4_EEEPRXMTR 0x009c ++ ++#define RTL8367C_REG_PTP_PORT4_CFG1 0x009e ++#define RTL8367C_PTP_PORT4_CFG1_OFFSET 7 ++#define RTL8367C_PTP_PORT4_CFG1_MASK 0xFF ++ ++#define RTL8367C_REG_P4_MSIC1 0x009f ++#define RTL8367C_P4_MSIC1_OFFSET 0 ++#define RTL8367C_P4_MSIC1_MASK 0x1 ++ ++#define RTL8367C_REG_PORT5_CGST_HALF_CFG 0x00a0 ++#define RTL8367C_PORT5_CGST_HALF_CFG_CONGESTION_TIME_OFFSET 4 ++#define RTL8367C_PORT5_CGST_HALF_CFG_CONGESTION_TIME_MASK 0xF0 ++#define RTL8367C_PORT5_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_OFFSET 0 ++#define RTL8367C_PORT5_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_MASK 0xF ++ ++#define RTL8367C_REG_PKTGEN_PORT5_CTRL 0x00a1 ++#define RTL8367C_PKTGEN_PORT5_CTRL_STATUS_OFFSET 15 ++#define RTL8367C_PKTGEN_PORT5_CTRL_STATUS_MASK 0x8000 ++#define RTL8367C_PKTGEN_PORT5_CTRL_PKTGEN_STS_OFFSET 13 ++#define RTL8367C_PKTGEN_PORT5_CTRL_PKTGEN_STS_MASK 0x2000 ++#define RTL8367C_PKTGEN_PORT5_CTRL_CRC_NO_ERROR_OFFSET 4 ++#define RTL8367C_PKTGEN_PORT5_CTRL_CRC_NO_ERROR_MASK 0x10 ++#define RTL8367C_PKTGEN_PORT5_CTRL_CMD_START_OFFSET 0 ++#define RTL8367C_PKTGEN_PORT5_CTRL_CMD_START_MASK 0x1 ++ ++#define RTL8367C_REG_TX_ERR_CNT_PORT5 0x00a2 ++#define RTL8367C_TX_ERR_CNT_PORT5_OFFSET 0 ++#define RTL8367C_TX_ERR_CNT_PORT5_MASK 0x7 ++ ++#define RTL8367C_REG_PKTGEN_PORT5_DA0 0x00a3 ++ ++#define RTL8367C_REG_PKTGEN_PORT5_DA1 0x00a4 ++ ++#define RTL8367C_REG_PKTGEN_PORT5_DA2 0x00a5 ++ ++#define RTL8367C_REG_PKTGEN_PORT5_SA0 0x00a6 ++ ++#define RTL8367C_REG_PKTGEN_PORT5_SA1 0x00a7 ++ ++#define RTL8367C_REG_PKTGEN_PORT5_SA2 0x00a8 ++ ++#define RTL8367C_REG_PKTGEN_PORT5_COUNTER0 0x00a9 ++ ++#define RTL8367C_REG_PKTGEN_PORT5_COUNTER1 0x00aa ++#define RTL8367C_PKTGEN_PORT5_COUNTER1_OFFSET 0 ++#define RTL8367C_PKTGEN_PORT5_COUNTER1_MASK 0xFF ++ ++#define RTL8367C_REG_PKTGEN_PORT5_TX_LENGTH 0x00ab ++#define RTL8367C_PKTGEN_PORT5_TX_LENGTH_OFFSET 0 ++#define RTL8367C_PKTGEN_PORT5_TX_LENGTH_MASK 0x3FFF ++ ++#define RTL8367C_REG_PKTGEN_PORT5_TIMER 0x00ad ++#define RTL8367C_PKTGEN_PORT5_TIMER_TIMER_OFFSET 4 ++#define RTL8367C_PKTGEN_PORT5_TIMER_TIMER_MASK 0xF0 ++#define RTL8367C_PKTGEN_PORT5_TIMER_RX_DMA_ERR_FLAG_OFFSET 3 ++#define RTL8367C_PKTGEN_PORT5_TIMER_RX_DMA_ERR_FLAG_MASK 0x8 ++ ++#define RTL8367C_REG_PORT5_MISC_CFG 0x00ae ++#define RTL8367C_PORT5_MISC_CFG_SMALL_TAG_IPG_OFFSET 15 ++#define RTL8367C_PORT5_MISC_CFG_SMALL_TAG_IPG_MASK 0x8000 ++#define RTL8367C_PORT5_MISC_CFG_TX_ITFSP_MODE_OFFSET 14 ++#define RTL8367C_PORT5_MISC_CFG_TX_ITFSP_MODE_MASK 0x4000 ++#define RTL8367C_PORT5_MISC_CFG_FLOWCTRL_INDEP_OFFSET 13 ++#define RTL8367C_PORT5_MISC_CFG_FLOWCTRL_INDEP_MASK 0x2000 ++#define RTL8367C_PORT5_MISC_CFG_DOT1Q_REMARK_ENABLE_OFFSET 12 ++#define RTL8367C_PORT5_MISC_CFG_DOT1Q_REMARK_ENABLE_MASK 0x1000 ++#define RTL8367C_PORT5_MISC_CFG_INGRESSBW_FLOWCTRL_OFFSET 11 ++#define RTL8367C_PORT5_MISC_CFG_INGRESSBW_FLOWCTRL_MASK 0x800 ++#define RTL8367C_PORT5_MISC_CFG_INGRESSBW_IFG_OFFSET 10 ++#define RTL8367C_PORT5_MISC_CFG_INGRESSBW_IFG_MASK 0x400 ++#define RTL8367C_PORT5_MISC_CFG_RX_SPC_OFFSET 9 ++#define RTL8367C_PORT5_MISC_CFG_RX_SPC_MASK 0x200 ++#define RTL8367C_PORT5_MISC_CFG_CRC_SKIP_OFFSET 8 ++#define RTL8367C_PORT5_MISC_CFG_CRC_SKIP_MASK 0x100 ++#define RTL8367C_PORT5_MISC_CFG_PKTGEN_TX_FIRST_OFFSET 7 ++#define RTL8367C_PORT5_MISC_CFG_PKTGEN_TX_FIRST_MASK 0x80 ++#define RTL8367C_PORT5_MISC_CFG_MAC_LOOPBACK_OFFSET 6 ++#define RTL8367C_PORT5_MISC_CFG_MAC_LOOPBACK_MASK 0x40 ++#define RTL8367C_PORT5_MISC_CFG_VLAN_EGRESS_MODE_OFFSET 4 ++#define RTL8367C_PORT5_MISC_CFG_VLAN_EGRESS_MODE_MASK 0x30 ++#define RTL8367C_PORT5_MISC_CFG_CONGESTION_SUSTAIN_TIME_OFFSET 0 ++#define RTL8367C_PORT5_MISC_CFG_CONGESTION_SUSTAIN_TIME_MASK 0xF ++ ++#define RTL8367C_REG_INGRESSBW_PORT5_RATE_CTRL0 0x00af ++ ++#define RTL8367C_REG_INGRESSBW_PORT5_RATE_CTRL1 0x00b0 ++#define RTL8367C_INGRESSBW_PORT5_RATE_CTRL1_DUMMY_OFFSET 3 ++#define RTL8367C_INGRESSBW_PORT5_RATE_CTRL1_DUMMY_MASK 0xFFF8 ++#define RTL8367C_INGRESSBW_PORT5_RATE_CTRL1_INGRESSBW_RATE16_OFFSET 0 ++#define RTL8367C_INGRESSBW_PORT5_RATE_CTRL1_INGRESSBW_RATE16_MASK 0x7 ++ ++#define RTL8367C_REG_PORT5_FORCE_RATE0 0x00b1 ++ ++#define RTL8367C_REG_PORT5_FORCE_RATE1 0x00b2 ++ ++#define RTL8367C_REG_PORT5_CURENT_RATE0 0x00b3 ++ ++#define RTL8367C_REG_PORT5_CURENT_RATE1 0x00b4 ++ ++#define RTL8367C_REG_PORT5_PAGE_COUNTER 0x00b5 ++#define RTL8367C_PORT5_PAGE_COUNTER_OFFSET 0 ++#define RTL8367C_PORT5_PAGE_COUNTER_MASK 0x7F ++ ++#define RTL8367C_REG_PAGEMETER_PORT5_CTRL0 0x00b6 ++ ++#define RTL8367C_REG_PAGEMETER_PORT5_CTRL1 0x00b7 ++ ++#define RTL8367C_REG_PORT5_EEECFG 0x00b8 ++#define RTL8367C_PORT5_EEECFG_EEEP_ENABLE_TX_OFFSET 14 ++#define RTL8367C_PORT5_EEECFG_EEEP_ENABLE_TX_MASK 0x4000 ++#define RTL8367C_PORT5_EEECFG_EEEP_ENABLE_RX_OFFSET 13 ++#define RTL8367C_PORT5_EEECFG_EEEP_ENABLE_RX_MASK 0x2000 ++#define RTL8367C_PORT5_EEECFG_EEE_FORCE_OFFSET 12 ++#define RTL8367C_PORT5_EEECFG_EEE_FORCE_MASK 0x1000 ++#define RTL8367C_PORT5_EEECFG_EEE_100M_OFFSET 11 ++#define RTL8367C_PORT5_EEECFG_EEE_100M_MASK 0x800 ++#define RTL8367C_PORT5_EEECFG_EEE_GIGA_500M_OFFSET 10 ++#define RTL8367C_PORT5_EEECFG_EEE_GIGA_500M_MASK 0x400 ++#define RTL8367C_PORT5_EEECFG_EEE_TX_OFFSET 9 ++#define RTL8367C_PORT5_EEECFG_EEE_TX_MASK 0x200 ++#define RTL8367C_PORT5_EEECFG_EEE_RX_OFFSET 8 ++#define RTL8367C_PORT5_EEECFG_EEE_RX_MASK 0x100 ++#define RTL8367C_PORT5_EEECFG_EEE_DSP_RX_OFFSET 6 ++#define RTL8367C_PORT5_EEECFG_EEE_DSP_RX_MASK 0x40 ++#define RTL8367C_PORT5_EEECFG_EEE_LPI_OFFSET 5 ++#define RTL8367C_PORT5_EEECFG_EEE_LPI_MASK 0x20 ++#define RTL8367C_PORT5_EEECFG_EEE_TX_LPI_OFFSET 4 ++#define RTL8367C_PORT5_EEECFG_EEE_TX_LPI_MASK 0x10 ++#define RTL8367C_PORT5_EEECFG_EEE_RX_LPI_OFFSET 3 ++#define RTL8367C_PORT5_EEECFG_EEE_RX_LPI_MASK 0x8 ++#define RTL8367C_PORT5_EEECFG_EEE_PAUSE_INDICATOR_OFFSET 2 ++#define RTL8367C_PORT5_EEECFG_EEE_PAUSE_INDICATOR_MASK 0x4 ++#define RTL8367C_PORT5_EEECFG_EEE_WAKE_REQ_OFFSET 1 ++#define RTL8367C_PORT5_EEECFG_EEE_WAKE_REQ_MASK 0x2 ++#define RTL8367C_PORT5_EEECFG_EEE_SLEEP_REQ_OFFSET 0 ++#define RTL8367C_PORT5_EEECFG_EEE_SLEEP_REQ_MASK 0x1 ++ ++#define RTL8367C_REG_PORT5_EEETXMTR 0x00b9 ++ ++#define RTL8367C_REG_PORT5_EEERXMTR 0x00ba ++ ++#define RTL8367C_REG_PORT5_EEEPTXMTR 0x00bb ++ ++#define RTL8367C_REG_PORT5_EEEPRXMTR 0x00bc ++ ++#define RTL8367C_REG_PTP_PORT5_CFG1 0x00be ++#define RTL8367C_PTP_PORT5_CFG1_OFFSET 7 ++#define RTL8367C_PTP_PORT5_CFG1_MASK 0xFF ++ ++#define RTL8367C_REG_P5_MSIC1 0x00bf ++#define RTL8367C_P5_MSIC1_OFFSET 0 ++#define RTL8367C_P5_MSIC1_MASK 0x1 ++ ++#define RTL8367C_REG_PORT6_CGST_HALF_CFG 0x00c0 ++#define RTL8367C_PORT6_CGST_HALF_CFG_CONGESTION_TIME_OFFSET 4 ++#define RTL8367C_PORT6_CGST_HALF_CFG_CONGESTION_TIME_MASK 0xF0 ++#define RTL8367C_PORT6_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_OFFSET 0 ++#define RTL8367C_PORT6_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_MASK 0xF ++ ++#define RTL8367C_REG_PKTGEN_PORT6_CTRL 0x00c1 ++#define RTL8367C_PKTGEN_PORT6_CTRL_STATUS_OFFSET 15 ++#define RTL8367C_PKTGEN_PORT6_CTRL_STATUS_MASK 0x8000 ++#define RTL8367C_PKTGEN_PORT6_CTRL_PKTGEN_STS_OFFSET 13 ++#define RTL8367C_PKTGEN_PORT6_CTRL_PKTGEN_STS_MASK 0x2000 ++#define RTL8367C_PKTGEN_PORT6_CTRL_CRC_NO_ERROR_OFFSET 4 ++#define RTL8367C_PKTGEN_PORT6_CTRL_CRC_NO_ERROR_MASK 0x10 ++#define RTL8367C_PKTGEN_PORT6_CTRL_CMD_START_OFFSET 0 ++#define RTL8367C_PKTGEN_PORT6_CTRL_CMD_START_MASK 0x1 ++ ++#define RTL8367C_REG_TX_ERR_CNT_PORT6 0x00c2 ++#define RTL8367C_TX_ERR_CNT_PORT6_OFFSET 0 ++#define RTL8367C_TX_ERR_CNT_PORT6_MASK 0x7 ++ ++#define RTL8367C_REG_PKTGEN_PORT6_DA0 0x00c3 ++ ++#define RTL8367C_REG_PKTGEN_PORT6_DA1 0x00c4 ++ ++#define RTL8367C_REG_PKTGEN_PORT6_DA2 0x00c5 ++ ++#define RTL8367C_REG_PKTGEN_PORT6_SA0 0x00c6 ++ ++#define RTL8367C_REG_PKTGEN_PORT6_SA1 0x00c7 ++ ++#define RTL8367C_REG_PKTGEN_PORT6_SA2 0x00c8 ++ ++#define RTL8367C_REG_PKTGEN_PORT6_COUNTER0 0x00c9 ++ ++#define RTL8367C_REG_PKTGEN_PORT6_COUNTER1 0x00ca ++#define RTL8367C_PKTGEN_PORT6_COUNTER1_OFFSET 0 ++#define RTL8367C_PKTGEN_PORT6_COUNTER1_MASK 0xFF ++ ++#define RTL8367C_REG_PKTGEN_PORT6_TX_LENGTH 0x00cb ++#define RTL8367C_PKTGEN_PORT6_TX_LENGTH_OFFSET 0 ++#define RTL8367C_PKTGEN_PORT6_TX_LENGTH_MASK 0x3FFF ++ ++#define RTL8367C_REG_PKTGEN_PORT6_TIMER 0x00cd ++#define RTL8367C_PKTGEN_PORT6_TIMER_TIMER_OFFSET 4 ++#define RTL8367C_PKTGEN_PORT6_TIMER_TIMER_MASK 0xF0 ++#define RTL8367C_PKTGEN_PORT6_TIMER_RX_DMA_ERR_FLAG_OFFSET 3 ++#define RTL8367C_PKTGEN_PORT6_TIMER_RX_DMA_ERR_FLAG_MASK 0x8 ++ ++#define RTL8367C_REG_PORT6_MISC_CFG 0x00ce ++#define RTL8367C_PORT6_MISC_CFG_SMALL_TAG_IPG_OFFSET 15 ++#define RTL8367C_PORT6_MISC_CFG_SMALL_TAG_IPG_MASK 0x8000 ++#define RTL8367C_PORT6_MISC_CFG_TX_ITFSP_MODE_OFFSET 14 ++#define RTL8367C_PORT6_MISC_CFG_TX_ITFSP_MODE_MASK 0x4000 ++#define RTL8367C_PORT6_MISC_CFG_FLOWCTRL_INDEP_OFFSET 13 ++#define RTL8367C_PORT6_MISC_CFG_FLOWCTRL_INDEP_MASK 0x2000 ++#define RTL8367C_PORT6_MISC_CFG_DOT1Q_REMARK_ENABLE_OFFSET 12 ++#define RTL8367C_PORT6_MISC_CFG_DOT1Q_REMARK_ENABLE_MASK 0x1000 ++#define RTL8367C_PORT6_MISC_CFG_INGRESSBW_FLOWCTRL_OFFSET 11 ++#define RTL8367C_PORT6_MISC_CFG_INGRESSBW_FLOWCTRL_MASK 0x800 ++#define RTL8367C_PORT6_MISC_CFG_INGRESSBW_IFG_OFFSET 10 ++#define RTL8367C_PORT6_MISC_CFG_INGRESSBW_IFG_MASK 0x400 ++#define RTL8367C_PORT6_MISC_CFG_RX_SPC_OFFSET 9 ++#define RTL8367C_PORT6_MISC_CFG_RX_SPC_MASK 0x200 ++#define RTL8367C_PORT6_MISC_CFG_CRC_SKIP_OFFSET 8 ++#define RTL8367C_PORT6_MISC_CFG_CRC_SKIP_MASK 0x100 ++#define RTL8367C_PORT6_MISC_CFG_PKTGEN_TX_FIRST_OFFSET 7 ++#define RTL8367C_PORT6_MISC_CFG_PKTGEN_TX_FIRST_MASK 0x80 ++#define RTL8367C_PORT6_MISC_CFG_MAC_LOOPBACK_OFFSET 6 ++#define RTL8367C_PORT6_MISC_CFG_MAC_LOOPBACK_MASK 0x40 ++#define RTL8367C_PORT6_MISC_CFG_VLAN_EGRESS_MODE_OFFSET 4 ++#define RTL8367C_PORT6_MISC_CFG_VLAN_EGRESS_MODE_MASK 0x30 ++#define RTL8367C_PORT6_MISC_CFG_CONGESTION_SUSTAIN_TIME_OFFSET 0 ++#define RTL8367C_PORT6_MISC_CFG_CONGESTION_SUSTAIN_TIME_MASK 0xF ++ ++#define RTL8367C_REG_INGRESSBW_PORT6_RATE_CTRL0 0x00cf ++ ++#define RTL8367C_REG_INGRESSBW_PORT6_RATE_CTRL1 0x00d0 ++#define RTL8367C_INGRESSBW_PORT6_RATE_CTRL1_DUMMY_OFFSET 3 ++#define RTL8367C_INGRESSBW_PORT6_RATE_CTRL1_DUMMY_MASK 0xFFF8 ++#define RTL8367C_INGRESSBW_PORT6_RATE_CTRL1_INGRESSBW_RATE16_OFFSET 0 ++#define RTL8367C_INGRESSBW_PORT6_RATE_CTRL1_INGRESSBW_RATE16_MASK 0x7 ++ ++#define RTL8367C_REG_PORT6_FORCE_RATE0 0x00d1 ++ ++#define RTL8367C_REG_PORT6_FORCE_RATE1 0x00d2 ++ ++#define RTL8367C_REG_PORT6_CURENT_RATE0 0x00d3 ++ ++#define RTL8367C_REG_PORT6_CURENT_RATE1 0x00d4 ++ ++#define RTL8367C_REG_PORT6_PAGE_COUNTER 0x00d5 ++#define RTL8367C_PORT6_PAGE_COUNTER_OFFSET 0 ++#define RTL8367C_PORT6_PAGE_COUNTER_MASK 0x7F ++ ++#define RTL8367C_REG_PAGEMETER_PORT6_CTRL0 0x00d6 ++ ++#define RTL8367C_REG_PAGEMETER_PORT6_CTRL1 0x00d7 ++ ++#define RTL8367C_REG_PORT6_EEECFG 0x00d8 ++#define RTL8367C_PORT6_EEECFG_EEEP_ENABLE_TX_OFFSET 14 ++#define RTL8367C_PORT6_EEECFG_EEEP_ENABLE_TX_MASK 0x4000 ++#define RTL8367C_PORT6_EEECFG_EEEP_ENABLE_RX_OFFSET 13 ++#define RTL8367C_PORT6_EEECFG_EEEP_ENABLE_RX_MASK 0x2000 ++#define RTL8367C_PORT6_EEECFG_EEE_FORCE_OFFSET 12 ++#define RTL8367C_PORT6_EEECFG_EEE_FORCE_MASK 0x1000 ++#define RTL8367C_PORT6_EEECFG_EEE_100M_OFFSET 11 ++#define RTL8367C_PORT6_EEECFG_EEE_100M_MASK 0x800 ++#define RTL8367C_PORT6_EEECFG_EEE_GIGA_500M_OFFSET 10 ++#define RTL8367C_PORT6_EEECFG_EEE_GIGA_500M_MASK 0x400 ++#define RTL8367C_PORT6_EEECFG_EEE_TX_OFFSET 9 ++#define RTL8367C_PORT6_EEECFG_EEE_TX_MASK 0x200 ++#define RTL8367C_PORT6_EEECFG_EEE_RX_OFFSET 8 ++#define RTL8367C_PORT6_EEECFG_EEE_RX_MASK 0x100 ++#define RTL8367C_PORT6_EEECFG_EEE_DSP_RX_OFFSET 6 ++#define RTL8367C_PORT6_EEECFG_EEE_DSP_RX_MASK 0x40 ++#define RTL8367C_PORT6_EEECFG_EEE_LPI_OFFSET 5 ++#define RTL8367C_PORT6_EEECFG_EEE_LPI_MASK 0x20 ++#define RTL8367C_PORT6_EEECFG_EEE_TX_LPI_OFFSET 4 ++#define RTL8367C_PORT6_EEECFG_EEE_TX_LPI_MASK 0x10 ++#define RTL8367C_PORT6_EEECFG_EEE_RX_LPI_OFFSET 3 ++#define RTL8367C_PORT6_EEECFG_EEE_RX_LPI_MASK 0x8 ++#define RTL8367C_PORT6_EEECFG_EEE_PAUSE_INDICATOR_OFFSET 2 ++#define RTL8367C_PORT6_EEECFG_EEE_PAUSE_INDICATOR_MASK 0x4 ++#define RTL8367C_PORT6_EEECFG_EEE_WAKE_REQ_OFFSET 1 ++#define RTL8367C_PORT6_EEECFG_EEE_WAKE_REQ_MASK 0x2 ++#define RTL8367C_PORT6_EEECFG_EEE_SLEEP_REQ_OFFSET 0 ++#define RTL8367C_PORT6_EEECFG_EEE_SLEEP_REQ_MASK 0x1 ++ ++#define RTL8367C_REG_PORT6_EEETXMTR 0x00d9 ++ ++#define RTL8367C_REG_PORT6_EEERXMTR 0x00da ++ ++#define RTL8367C_REG_PORT6_EEEPTXMTR 0x00db ++ ++#define RTL8367C_REG_PORT6_EEEPRXMTR 0x00dc ++ ++#define RTL8367C_REG_PTP_PORT6_CFG1 0x00de ++#define RTL8367C_PTP_PORT6_CFG1_OFFSET 7 ++#define RTL8367C_PTP_PORT6_CFG1_MASK 0xFF ++ ++#define RTL8367C_REG_P6_MSIC1 0x00df ++#define RTL8367C_P6_MSIC1_OFFSET 0 ++#define RTL8367C_P6_MSIC1_MASK 0x1 ++ ++#define RTL8367C_REG_PORT7_CGST_HALF_CFG 0x00e0 ++#define RTL8367C_PORT7_CGST_HALF_CFG_CONGESTION_TIME_OFFSET 4 ++#define RTL8367C_PORT7_CGST_HALF_CFG_CONGESTION_TIME_MASK 0xF0 ++#define RTL8367C_PORT7_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_OFFSET 0 ++#define RTL8367C_PORT7_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_MASK 0xF ++ ++#define RTL8367C_REG_PKTGEN_PORT7_CTRL 0x00e1 ++#define RTL8367C_PKTGEN_PORT7_CTRL_STATUS_OFFSET 15 ++#define RTL8367C_PKTGEN_PORT7_CTRL_STATUS_MASK 0x8000 ++#define RTL8367C_PKTGEN_PORT7_CTRL_PKTGEN_STS_OFFSET 13 ++#define RTL8367C_PKTGEN_PORT7_CTRL_PKTGEN_STS_MASK 0x2000 ++#define RTL8367C_PKTGEN_PORT7_CTRL_CRC_NO_ERROR_OFFSET 4 ++#define RTL8367C_PKTGEN_PORT7_CTRL_CRC_NO_ERROR_MASK 0x10 ++#define RTL8367C_PKTGEN_PORT7_CTRL_CMD_START_OFFSET 0 ++#define RTL8367C_PKTGEN_PORT7_CTRL_CMD_START_MASK 0x1 ++ ++#define RTL8367C_REG_TX_ERR_CNT_PORT7 0x00e2 ++#define RTL8367C_TX_ERR_CNT_PORT7_OFFSET 0 ++#define RTL8367C_TX_ERR_CNT_PORT7_MASK 0x7 ++ ++#define RTL8367C_REG_PKTGEN_PORT7_DA0 0x00e3 ++ ++#define RTL8367C_REG_PKTGEN_PORT7_DA1 0x00e4 ++ ++#define RTL8367C_REG_PKTGEN_PORT7_DA2 0x00e5 ++ ++#define RTL8367C_REG_PKTGEN_PORT7_SA0 0x00e6 ++ ++#define RTL8367C_REG_PKTGEN_PORT7_SA1 0x00e7 ++ ++#define RTL8367C_REG_PKTGEN_PORT7_SA2 0x00e8 ++ ++#define RTL8367C_REG_PKTGEN_PORT7_COUNTER0 0x00e9 ++ ++#define RTL8367C_REG_PKTGEN_PORT7_COUNTER1 0x00ea ++#define RTL8367C_PKTGEN_PORT7_COUNTER1_OFFSET 0 ++#define RTL8367C_PKTGEN_PORT7_COUNTER1_MASK 0xFF ++ ++#define RTL8367C_REG_PKTGEN_PORT7_TX_LENGTH 0x00eb ++#define RTL8367C_PKTGEN_PORT7_TX_LENGTH_OFFSET 0 ++#define RTL8367C_PKTGEN_PORT7_TX_LENGTH_MASK 0x3FFF ++ ++#define RTL8367C_REG_PKTGEN_PORT7_TIMER 0x00ed ++#define RTL8367C_PKTGEN_PORT7_TIMER_TIMER_OFFSET 4 ++#define RTL8367C_PKTGEN_PORT7_TIMER_TIMER_MASK 0xF0 ++#define RTL8367C_PKTGEN_PORT7_TIMER_RX_DMA_ERR_FLAG_OFFSET 3 ++#define RTL8367C_PKTGEN_PORT7_TIMER_RX_DMA_ERR_FLAG_MASK 0x8 ++ ++#define RTL8367C_REG_PORT7_MISC_CFG 0x00ee ++#define RTL8367C_PORT7_MISC_CFG_SMALL_TAG_IPG_OFFSET 15 ++#define RTL8367C_PORT7_MISC_CFG_SMALL_TAG_IPG_MASK 0x8000 ++#define RTL8367C_PORT7_MISC_CFG_TX_ITFSP_MODE_OFFSET 14 ++#define RTL8367C_PORT7_MISC_CFG_TX_ITFSP_MODE_MASK 0x4000 ++#define RTL8367C_PORT7_MISC_CFG_FLOWCTRL_INDEP_OFFSET 13 ++#define RTL8367C_PORT7_MISC_CFG_FLOWCTRL_INDEP_MASK 0x2000 ++#define RTL8367C_PORT7_MISC_CFG_DOT1Q_REMARK_ENABLE_OFFSET 12 ++#define RTL8367C_PORT7_MISC_CFG_DOT1Q_REMARK_ENABLE_MASK 0x1000 ++#define RTL8367C_PORT7_MISC_CFG_INGRESSBW_FLOWCTRL_OFFSET 11 ++#define RTL8367C_PORT7_MISC_CFG_INGRESSBW_FLOWCTRL_MASK 0x800 ++#define RTL8367C_PORT7_MISC_CFG_INGRESSBW_IFG_OFFSET 10 ++#define RTL8367C_PORT7_MISC_CFG_INGRESSBW_IFG_MASK 0x400 ++#define RTL8367C_PORT7_MISC_CFG_RX_SPC_OFFSET 9 ++#define RTL8367C_PORT7_MISC_CFG_RX_SPC_MASK 0x200 ++#define RTL8367C_PORT7_MISC_CFG_CRC_SKIP_OFFSET 8 ++#define RTL8367C_PORT7_MISC_CFG_CRC_SKIP_MASK 0x100 ++#define RTL8367C_PORT7_MISC_CFG_PKTGEN_TX_FIRST_OFFSET 7 ++#define RTL8367C_PORT7_MISC_CFG_PKTGEN_TX_FIRST_MASK 0x80 ++#define RTL8367C_PORT7_MISC_CFG_MAC_LOOPBACK_OFFSET 6 ++#define RTL8367C_PORT7_MISC_CFG_MAC_LOOPBACK_MASK 0x40 ++#define RTL8367C_PORT7_MISC_CFG_VLAN_EGRESS_MODE_OFFSET 4 ++#define RTL8367C_PORT7_MISC_CFG_VLAN_EGRESS_MODE_MASK 0x30 ++#define RTL8367C_PORT7_MISC_CFG_CONGESTION_SUSTAIN_TIME_OFFSET 0 ++#define RTL8367C_PORT7_MISC_CFG_CONGESTION_SUSTAIN_TIME_MASK 0xF ++ ++#define RTL8367C_REG_INGRESSBW_PORT7_RATE_CTRL0 0x00ef ++ ++#define RTL8367C_REG_INGRESSBW_PORT7_RATE_CTRL1 0x00f0 ++#define RTL8367C_INGRESSBW_PORT7_RATE_CTRL1_DUMMY_OFFSET 3 ++#define RTL8367C_INGRESSBW_PORT7_RATE_CTRL1_DUMMY_MASK 0xFFF8 ++#define RTL8367C_INGRESSBW_PORT7_RATE_CTRL1_INGRESSBW_RATE16_OFFSET 0 ++#define RTL8367C_INGRESSBW_PORT7_RATE_CTRL1_INGRESSBW_RATE16_MASK 0x7 ++ ++#define RTL8367C_REG_PORT7_FORCE_RATE0 0x00f1 ++ ++#define RTL8367C_REG_PORT7_FORCE_RATE1 0x00f2 ++ ++#define RTL8367C_REG_PORT7_CURENT_RATE0 0x00f3 ++ ++#define RTL8367C_REG_PORT7_CURENT_RATE1 0x00f4 ++ ++#define RTL8367C_REG_PORT7_PAGE_COUNTER 0x00f5 ++#define RTL8367C_PORT7_PAGE_COUNTER_OFFSET 0 ++#define RTL8367C_PORT7_PAGE_COUNTER_MASK 0x7F ++ ++#define RTL8367C_REG_PAGEMETER_PORT7_CTRL0 0x00f6 ++ ++#define RTL8367C_REG_PAGEMETER_PORT7_CTRL1 0x00f7 ++ ++#define RTL8367C_REG_PORT7_EEECFG 0x00f8 ++#define RTL8367C_PORT7_EEECFG_EEEP_ENABLE_TX_OFFSET 14 ++#define RTL8367C_PORT7_EEECFG_EEEP_ENABLE_TX_MASK 0x4000 ++#define RTL8367C_PORT7_EEECFG_EEEP_ENABLE_RX_OFFSET 13 ++#define RTL8367C_PORT7_EEECFG_EEEP_ENABLE_RX_MASK 0x2000 ++#define RTL8367C_PORT7_EEECFG_EEE_FORCE_OFFSET 12 ++#define RTL8367C_PORT7_EEECFG_EEE_FORCE_MASK 0x1000 ++#define RTL8367C_PORT7_EEECFG_EEE_100M_OFFSET 11 ++#define RTL8367C_PORT7_EEECFG_EEE_100M_MASK 0x800 ++#define RTL8367C_PORT7_EEECFG_EEE_GIGA_500M_OFFSET 10 ++#define RTL8367C_PORT7_EEECFG_EEE_GIGA_500M_MASK 0x400 ++#define RTL8367C_PORT7_EEECFG_EEE_TX_OFFSET 9 ++#define RTL8367C_PORT7_EEECFG_EEE_TX_MASK 0x200 ++#define RTL8367C_PORT7_EEECFG_EEE_RX_OFFSET 8 ++#define RTL8367C_PORT7_EEECFG_EEE_RX_MASK 0x100 ++#define RTL8367C_PORT7_EEECFG_EEE_DSP_RX_OFFSET 6 ++#define RTL8367C_PORT7_EEECFG_EEE_DSP_RX_MASK 0x40 ++#define RTL8367C_PORT7_EEECFG_EEE_LPI_OFFSET 5 ++#define RTL8367C_PORT7_EEECFG_EEE_LPI_MASK 0x20 ++#define RTL8367C_PORT7_EEECFG_EEE_TX_LPI_OFFSET 4 ++#define RTL8367C_PORT7_EEECFG_EEE_TX_LPI_MASK 0x10 ++#define RTL8367C_PORT7_EEECFG_EEE_RX_LPI_OFFSET 3 ++#define RTL8367C_PORT7_EEECFG_EEE_RX_LPI_MASK 0x8 ++#define RTL8367C_PORT7_EEECFG_EEE_PAUSE_INDICATOR_OFFSET 2 ++#define RTL8367C_PORT7_EEECFG_EEE_PAUSE_INDICATOR_MASK 0x4 ++#define RTL8367C_PORT7_EEECFG_EEE_WAKE_REQ_OFFSET 1 ++#define RTL8367C_PORT7_EEECFG_EEE_WAKE_REQ_MASK 0x2 ++#define RTL8367C_PORT7_EEECFG_EEE_SLEEP_REQ_OFFSET 0 ++#define RTL8367C_PORT7_EEECFG_EEE_SLEEP_REQ_MASK 0x1 ++ ++#define RTL8367C_REG_PORT7_EEETXMTR 0x00f9 ++ ++#define RTL8367C_REG_PORT7_EEERXMTR 0x00fa ++ ++#define RTL8367C_REG_PORT7_EEEPTXMTR 0x00fb ++ ++#define RTL8367C_REG_PORT7_EEEPRXMTR 0x00fc ++ ++#define RTL8367C_REG_PTP_PORT7_CFG1 0x00fe ++#define RTL8367C_PTP_PORT7_CFG1_OFFSET 7 ++#define RTL8367C_PTP_PORT7_CFG1_MASK 0xFF ++ ++#define RTL8367C_REG_P7_MSIC1 0x00ff ++#define RTL8367C_P7_MSIC1_OFFSET 0 ++#define RTL8367C_P7_MSIC1_MASK 0x1 ++ ++#define RTL8367C_REG_PORT8_CGST_HALF_CFG 0x0100 ++#define RTL8367C_PORT8_CGST_HALF_CFG_CONGESTION_TIME_OFFSET 4 ++#define RTL8367C_PORT8_CGST_HALF_CFG_CONGESTION_TIME_MASK 0xF0 ++#define RTL8367C_PORT8_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_OFFSET 0 ++#define RTL8367C_PORT8_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_MASK 0xF ++ ++#define RTL8367C_REG_PKTGEN_PORT8_CTRL 0x0101 ++#define RTL8367C_PKTGEN_PORT8_CTRL_STATUS_OFFSET 15 ++#define RTL8367C_PKTGEN_PORT8_CTRL_STATUS_MASK 0x8000 ++#define RTL8367C_PKTGEN_PORT8_CTRL_PKTGEN_STS_OFFSET 13 ++#define RTL8367C_PKTGEN_PORT8_CTRL_PKTGEN_STS_MASK 0x2000 ++#define RTL8367C_PKTGEN_PORT8_CTRL_CRC_NO_ERROR_OFFSET 4 ++#define RTL8367C_PKTGEN_PORT8_CTRL_CRC_NO_ERROR_MASK 0x10 ++#define RTL8367C_PKTGEN_PORT8_CTRL_CMD_START_OFFSET 0 ++#define RTL8367C_PKTGEN_PORT8_CTRL_CMD_START_MASK 0x1 ++ ++#define RTL8367C_REG_TX_ERR_CNT_PORT8 0x0102 ++#define RTL8367C_TX_ERR_CNT_PORT8_OFFSET 0 ++#define RTL8367C_TX_ERR_CNT_PORT8_MASK 0x7 ++ ++#define RTL8367C_REG_PKTGEN_PORT8_DA0 0x0103 ++ ++#define RTL8367C_REG_PKTGEN_PORT8_DA1 0x0104 ++ ++#define RTL8367C_REG_PKTGEN_PORT8_DA2 0x0105 ++ ++#define RTL8367C_REG_PKTGEN_PORT8_SA0 0x0106 ++ ++#define RTL8367C_REG_PKTGEN_PORT8_SA1 0x0107 ++ ++#define RTL8367C_REG_PKTGEN_PORT8_SA2 0x0108 ++ ++#define RTL8367C_REG_PKTGEN_PORT8_COUNTER0 0x0109 ++ ++#define RTL8367C_REG_PKTGEN_PORT8_COUNTER1 0x010a ++#define RTL8367C_PKTGEN_PORT8_COUNTER1_OFFSET 0 ++#define RTL8367C_PKTGEN_PORT8_COUNTER1_MASK 0xFF ++ ++#define RTL8367C_REG_PKTGEN_PORT8_TX_LENGTH 0x010b ++#define RTL8367C_PKTGEN_PORT8_TX_LENGTH_OFFSET 0 ++#define RTL8367C_PKTGEN_PORT8_TX_LENGTH_MASK 0x3FFF ++ ++#define RTL8367C_REG_PKTGEN_PORT8_TIMER 0x010d ++#define RTL8367C_PKTGEN_PORT8_TIMER_TIMER_OFFSET 4 ++#define RTL8367C_PKTGEN_PORT8_TIMER_TIMER_MASK 0xF0 ++#define RTL8367C_PKTGEN_PORT8_TIMER_RX_DMA_ERR_FLAG_OFFSET 3 ++#define RTL8367C_PKTGEN_PORT8_TIMER_RX_DMA_ERR_FLAG_MASK 0x8 ++ ++#define RTL8367C_REG_PORT8_MISC_CFG 0x010e ++#define RTL8367C_PORT8_MISC_CFG_SMALL_TAG_IPG_OFFSET 15 ++#define RTL8367C_PORT8_MISC_CFG_SMALL_TAG_IPG_MASK 0x8000 ++#define RTL8367C_PORT8_MISC_CFG_TX_ITFSP_MODE_OFFSET 14 ++#define RTL8367C_PORT8_MISC_CFG_TX_ITFSP_MODE_MASK 0x4000 ++#define RTL8367C_PORT8_MISC_CFG_FLOWCTRL_INDEP_OFFSET 13 ++#define RTL8367C_PORT8_MISC_CFG_FLOWCTRL_INDEP_MASK 0x2000 ++#define RTL8367C_PORT8_MISC_CFG_DOT1Q_REMARK_ENABLE_OFFSET 12 ++#define RTL8367C_PORT8_MISC_CFG_DOT1Q_REMARK_ENABLE_MASK 0x1000 ++#define RTL8367C_PORT8_MISC_CFG_INGRESSBW_FLOWCTRL_OFFSET 11 ++#define RTL8367C_PORT8_MISC_CFG_INGRESSBW_FLOWCTRL_MASK 0x800 ++#define RTL8367C_PORT8_MISC_CFG_INGRESSBW_IFG_OFFSET 10 ++#define RTL8367C_PORT8_MISC_CFG_INGRESSBW_IFG_MASK 0x400 ++#define RTL8367C_PORT8_MISC_CFG_RX_SPC_OFFSET 9 ++#define RTL8367C_PORT8_MISC_CFG_RX_SPC_MASK 0x200 ++#define RTL8367C_PORT8_MISC_CFG_CRC_SKIP_OFFSET 8 ++#define RTL8367C_PORT8_MISC_CFG_CRC_SKIP_MASK 0x100 ++#define RTL8367C_PORT8_MISC_CFG_PKTGEN_TX_FIRST_OFFSET 7 ++#define RTL8367C_PORT8_MISC_CFG_PKTGEN_TX_FIRST_MASK 0x80 ++#define RTL8367C_PORT8_MISC_CFG_MAC_LOOPBACK_OFFSET 6 ++#define RTL8367C_PORT8_MISC_CFG_MAC_LOOPBACK_MASK 0x40 ++#define RTL8367C_PORT8_MISC_CFG_VLAN_EGRESS_MODE_OFFSET 4 ++#define RTL8367C_PORT8_MISC_CFG_VLAN_EGRESS_MODE_MASK 0x30 ++#define RTL8367C_PORT8_MISC_CFG_CONGESTION_SUSTAIN_TIME_OFFSET 0 ++#define RTL8367C_PORT8_MISC_CFG_CONGESTION_SUSTAIN_TIME_MASK 0xF ++ ++#define RTL8367C_REG_INGRESSBW_PORT8_RATE_CTRL0 0x010f ++ ++#define RTL8367C_REG_INGRESSBW_PORT8_RATE_CTRL1 0x0110 ++#define RTL8367C_INGRESSBW_PORT8_RATE_CTRL1_DUMMY_OFFSET 3 ++#define RTL8367C_INGRESSBW_PORT8_RATE_CTRL1_DUMMY_MASK 0xFFF8 ++#define RTL8367C_INGRESSBW_PORT8_RATE_CTRL1_INGRESSBW_RATE16_OFFSET 0 ++#define RTL8367C_INGRESSBW_PORT8_RATE_CTRL1_INGRESSBW_RATE16_MASK 0x7 ++ ++#define RTL8367C_REG_PORT8_FORCE_RATE0 0x0111 ++ ++#define RTL8367C_REG_PORT8_FORCE_RATE1 0x0112 ++ ++#define RTL8367C_REG_PORT8_CURENT_RATE0 0x0113 ++ ++#define RTL8367C_REG_PORT8_CURENT_RATE1 0x0114 ++ ++#define RTL8367C_REG_PORT8_PAGE_COUNTER 0x0115 ++#define RTL8367C_PORT8_PAGE_COUNTER_OFFSET 0 ++#define RTL8367C_PORT8_PAGE_COUNTER_MASK 0x7F ++ ++#define RTL8367C_REG_PAGEMETER_PORT8_CTRL0 0x0116 ++ ++#define RTL8367C_REG_PAGEMETER_PORT8_CTRL1 0x0117 ++ ++#define RTL8367C_REG_PORT8_EEECFG 0x0118 ++#define RTL8367C_PORT8_EEECFG_EEEP_ENABLE_TX_OFFSET 14 ++#define RTL8367C_PORT8_EEECFG_EEEP_ENABLE_TX_MASK 0x4000 ++#define RTL8367C_PORT8_EEECFG_EEEP_ENABLE_RX_OFFSET 13 ++#define RTL8367C_PORT8_EEECFG_EEEP_ENABLE_RX_MASK 0x2000 ++#define RTL8367C_PORT8_EEECFG_EEE_FORCE_OFFSET 12 ++#define RTL8367C_PORT8_EEECFG_EEE_FORCE_MASK 0x1000 ++#define RTL8367C_PORT8_EEECFG_EEE_100M_OFFSET 11 ++#define RTL8367C_PORT8_EEECFG_EEE_100M_MASK 0x800 ++#define RTL8367C_PORT8_EEECFG_EEE_GIGA_500M_OFFSET 10 ++#define RTL8367C_PORT8_EEECFG_EEE_GIGA_500M_MASK 0x400 ++#define RTL8367C_PORT8_EEECFG_EEE_TX_OFFSET 9 ++#define RTL8367C_PORT8_EEECFG_EEE_TX_MASK 0x200 ++#define RTL8367C_PORT8_EEECFG_EEE_RX_OFFSET 8 ++#define RTL8367C_PORT8_EEECFG_EEE_RX_MASK 0x100 ++#define RTL8367C_PORT8_EEECFG_EEE_DSP_RX_OFFSET 6 ++#define RTL8367C_PORT8_EEECFG_EEE_DSP_RX_MASK 0x40 ++#define RTL8367C_PORT8_EEECFG_EEE_LPI_OFFSET 5 ++#define RTL8367C_PORT8_EEECFG_EEE_LPI_MASK 0x20 ++#define RTL8367C_PORT8_EEECFG_EEE_TX_LPI_OFFSET 4 ++#define RTL8367C_PORT8_EEECFG_EEE_TX_LPI_MASK 0x10 ++#define RTL8367C_PORT8_EEECFG_EEE_RX_LPI_OFFSET 3 ++#define RTL8367C_PORT8_EEECFG_EEE_RX_LPI_MASK 0x8 ++#define RTL8367C_PORT8_EEECFG_EEE_PAUSE_INDICATOR_OFFSET 2 ++#define RTL8367C_PORT8_EEECFG_EEE_PAUSE_INDICATOR_MASK 0x4 ++#define RTL8367C_PORT8_EEECFG_EEE_WAKE_REQ_OFFSET 1 ++#define RTL8367C_PORT8_EEECFG_EEE_WAKE_REQ_MASK 0x2 ++#define RTL8367C_PORT8_EEECFG_EEE_SLEEP_REQ_OFFSET 0 ++#define RTL8367C_PORT8_EEECFG_EEE_SLEEP_REQ_MASK 0x1 ++ ++#define RTL8367C_REG_PORT8_EEETXMTR 0x0119 ++ ++#define RTL8367C_REG_PORT8_EEERXMTR 0x011a ++ ++#define RTL8367C_REG_PORT8_EEEPTXMTR 0x011b ++ ++#define RTL8367C_REG_PORT8_EEEPRXMTR 0x011c ++ ++#define RTL8367C_REG_PTP_PORT8_CFG1 0x011e ++#define RTL8367C_PTP_PORT8_CFG1_OFFSET 7 ++#define RTL8367C_PTP_PORT8_CFG1_MASK 0xFF ++ ++#define RTL8367C_REG_P8_MSIC1 0x011f ++#define RTL8367C_P8_MSIC1_OFFSET 0 ++#define RTL8367C_P8_MSIC1_MASK 0x1 ++ ++#define RTL8367C_REG_PORT9_CGST_HALF_CFG 0x0120 ++#define RTL8367C_PORT9_CGST_HALF_CFG_CONGESTION_TIME_OFFSET 4 ++#define RTL8367C_PORT9_CGST_HALF_CFG_CONGESTION_TIME_MASK 0xF0 ++#define RTL8367C_PORT9_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_OFFSET 0 ++#define RTL8367C_PORT9_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_MASK 0xF ++ ++#define RTL8367C_REG_PKTGEN_PORT9_CTRL 0x0121 ++#define RTL8367C_PKTGEN_PORT9_CTRL_STATUS_OFFSET 15 ++#define RTL8367C_PKTGEN_PORT9_CTRL_STATUS_MASK 0x8000 ++#define RTL8367C_PKTGEN_PORT9_CTRL_PKTGEN_STS_OFFSET 13 ++#define RTL8367C_PKTGEN_PORT9_CTRL_PKTGEN_STS_MASK 0x2000 ++#define RTL8367C_PKTGEN_PORT9_CTRL_CRC_NO_ERROR_OFFSET 4 ++#define RTL8367C_PKTGEN_PORT9_CTRL_CRC_NO_ERROR_MASK 0x10 ++#define RTL8367C_PKTGEN_PORT9_CTRL_CMD_START_OFFSET 0 ++#define RTL8367C_PKTGEN_PORT9_CTRL_CMD_START_MASK 0x1 ++ ++#define RTL8367C_REG_TX_ERR_CNT_PORT9 0x0122 ++#define RTL8367C_TX_ERR_CNT_PORT9_OFFSET 0 ++#define RTL8367C_TX_ERR_CNT_PORT9_MASK 0x7 ++ ++#define RTL8367C_REG_PKTGEN_PORT9_DA0 0x0123 ++ ++#define RTL8367C_REG_PKTGEN_PORT9_DA1 0x0124 ++ ++#define RTL8367C_REG_PKTGEN_PORT9_DA2 0x0125 ++ ++#define RTL8367C_REG_PKTGEN_PORT9_SA0 0x0126 ++ ++#define RTL8367C_REG_PKTGEN_PORT9_SA1 0x0127 ++ ++#define RTL8367C_REG_PKTGEN_PORT9_SA2 0x0128 ++ ++#define RTL8367C_REG_PKTGEN_PORT9_COUNTER0 0x0129 ++ ++#define RTL8367C_REG_PKTGEN_PORT9_COUNTER1 0x012a ++#define RTL8367C_PKTGEN_PORT9_COUNTER1_OFFSET 0 ++#define RTL8367C_PKTGEN_PORT9_COUNTER1_MASK 0xFF ++ ++#define RTL8367C_REG_PKTGEN_PORT9_TX_LENGTH 0x012b ++#define RTL8367C_PKTGEN_PORT9_TX_LENGTH_OFFSET 0 ++#define RTL8367C_PKTGEN_PORT9_TX_LENGTH_MASK 0x3FFF ++ ++#define RTL8367C_REG_PKTGEN_PORT9_TIMER 0x012d ++#define RTL8367C_PKTGEN_PORT9_TIMER_TIMER_OFFSET 4 ++#define RTL8367C_PKTGEN_PORT9_TIMER_TIMER_MASK 0xF0 ++#define RTL8367C_PKTGEN_PORT9_TIMER_RX_DMA_ERR_FLAG_OFFSET 3 ++#define RTL8367C_PKTGEN_PORT9_TIMER_RX_DMA_ERR_FLAG_MASK 0x8 ++ ++#define RTL8367C_REG_PORT9_MISC_CFG 0x012e ++#define RTL8367C_PORT9_MISC_CFG_SMALL_TAG_IPG_OFFSET 15 ++#define RTL8367C_PORT9_MISC_CFG_SMALL_TAG_IPG_MASK 0x8000 ++#define RTL8367C_PORT9_MISC_CFG_TX_ITFSP_MODE_OFFSET 14 ++#define RTL8367C_PORT9_MISC_CFG_TX_ITFSP_MODE_MASK 0x4000 ++#define RTL8367C_PORT9_MISC_CFG_FLOWCTRL_INDEP_OFFSET 13 ++#define RTL8367C_PORT9_MISC_CFG_FLOWCTRL_INDEP_MASK 0x2000 ++#define RTL8367C_PORT9_MISC_CFG_DOT1Q_REMARK_ENABLE_OFFSET 12 ++#define RTL8367C_PORT9_MISC_CFG_DOT1Q_REMARK_ENABLE_MASK 0x1000 ++#define RTL8367C_PORT9_MISC_CFG_INGRESSBW_FLOWCTRL_OFFSET 11 ++#define RTL8367C_PORT9_MISC_CFG_INGRESSBW_FLOWCTRL_MASK 0x800 ++#define RTL8367C_PORT9_MISC_CFG_INGRESSBW_IFG_OFFSET 10 ++#define RTL8367C_PORT9_MISC_CFG_INGRESSBW_IFG_MASK 0x400 ++#define RTL8367C_PORT9_MISC_CFG_RX_SPC_OFFSET 9 ++#define RTL8367C_PORT9_MISC_CFG_RX_SPC_MASK 0x200 ++#define RTL8367C_PORT9_MISC_CFG_CRC_SKIP_OFFSET 8 ++#define RTL8367C_PORT9_MISC_CFG_CRC_SKIP_MASK 0x100 ++#define RTL8367C_PORT9_MISC_CFG_PKTGEN_TX_FIRST_OFFSET 7 ++#define RTL8367C_PORT9_MISC_CFG_PKTGEN_TX_FIRST_MASK 0x80 ++#define RTL8367C_PORT9_MISC_CFG_MAC_LOOPBACK_OFFSET 6 ++#define RTL8367C_PORT9_MISC_CFG_MAC_LOOPBACK_MASK 0x40 ++#define RTL8367C_PORT9_MISC_CFG_VLAN_EGRESS_MODE_OFFSET 4 ++#define RTL8367C_PORT9_MISC_CFG_VLAN_EGRESS_MODE_MASK 0x30 ++#define RTL8367C_PORT9_MISC_CFG_CONGESTION_SUSTAIN_TIME_OFFSET 0 ++#define RTL8367C_PORT9_MISC_CFG_CONGESTION_SUSTAIN_TIME_MASK 0xF ++ ++#define RTL8367C_REG_INGRESSBW_PORT9_RATE_CTRL0 0x012f ++ ++#define RTL8367C_REG_INGRESSBW_PORT9_RATE_CTRL1 0x0130 ++#define RTL8367C_INGRESSBW_PORT9_RATE_CTRL1_DUMMY_OFFSET 3 ++#define RTL8367C_INGRESSBW_PORT9_RATE_CTRL1_DUMMY_MASK 0xFFF8 ++#define RTL8367C_INGRESSBW_PORT9_RATE_CTRL1_INGRESSBW_RATE16_OFFSET 0 ++#define RTL8367C_INGRESSBW_PORT9_RATE_CTRL1_INGRESSBW_RATE16_MASK 0x7 ++ ++#define RTL8367C_REG_PORT9_FORCE_RATE0 0x0131 ++ ++#define RTL8367C_REG_PORT9_FORCE_RATE1 0x0132 ++ ++#define RTL8367C_REG_PORT9_CURENT_RATE0 0x0133 ++ ++#define RTL8367C_REG_PORT9_CURENT_RATE1 0x0134 ++ ++#define RTL8367C_REG_PORT9_PAGE_COUNTER 0x0135 ++#define RTL8367C_PORT9_PAGE_COUNTER_OFFSET 0 ++#define RTL8367C_PORT9_PAGE_COUNTER_MASK 0x7F ++ ++#define RTL8367C_REG_PAGEMETER_PORT9_CTRL0 0x0136 ++ ++#define RTL8367C_REG_PAGEMETER_PORT9_CTRL1 0x0137 ++ ++#define RTL8367C_REG_PORT9_EEECFG 0x0138 ++#define RTL8367C_PORT9_EEECFG_EEEP_ENABLE_TX_OFFSET 14 ++#define RTL8367C_PORT9_EEECFG_EEEP_ENABLE_TX_MASK 0x4000 ++#define RTL8367C_PORT9_EEECFG_EEEP_ENABLE_RX_OFFSET 13 ++#define RTL8367C_PORT9_EEECFG_EEEP_ENABLE_RX_MASK 0x2000 ++#define RTL8367C_PORT9_EEECFG_EEE_FORCE_OFFSET 12 ++#define RTL8367C_PORT9_EEECFG_EEE_FORCE_MASK 0x1000 ++#define RTL8367C_PORT9_EEECFG_EEE_100M_OFFSET 11 ++#define RTL8367C_PORT9_EEECFG_EEE_100M_MASK 0x800 ++#define RTL8367C_PORT9_EEECFG_EEE_GIGA_500M_OFFSET 10 ++#define RTL8367C_PORT9_EEECFG_EEE_GIGA_500M_MASK 0x400 ++#define RTL8367C_PORT9_EEECFG_EEE_TX_OFFSET 9 ++#define RTL8367C_PORT9_EEECFG_EEE_TX_MASK 0x200 ++#define RTL8367C_PORT9_EEECFG_EEE_RX_OFFSET 8 ++#define RTL8367C_PORT9_EEECFG_EEE_RX_MASK 0x100 ++#define RTL8367C_PORT9_EEECFG_EEE_DSP_RX_OFFSET 6 ++#define RTL8367C_PORT9_EEECFG_EEE_DSP_RX_MASK 0x40 ++#define RTL8367C_PORT9_EEECFG_EEE_LPI_OFFSET 5 ++#define RTL8367C_PORT9_EEECFG_EEE_LPI_MASK 0x20 ++#define RTL8367C_PORT9_EEECFG_EEE_TX_LPI_OFFSET 4 ++#define RTL8367C_PORT9_EEECFG_EEE_TX_LPI_MASK 0x10 ++#define RTL8367C_PORT9_EEECFG_EEE_RX_LPI_OFFSET 3 ++#define RTL8367C_PORT9_EEECFG_EEE_RX_LPI_MASK 0x8 ++#define RTL8367C_PORT9_EEECFG_EEE_PAUSE_INDICATOR_OFFSET 2 ++#define RTL8367C_PORT9_EEECFG_EEE_PAUSE_INDICATOR_MASK 0x4 ++#define RTL8367C_PORT9_EEECFG_EEE_WAKE_REQ_OFFSET 1 ++#define RTL8367C_PORT9_EEECFG_EEE_WAKE_REQ_MASK 0x2 ++#define RTL8367C_PORT9_EEECFG_EEE_SLEEP_REQ_OFFSET 0 ++#define RTL8367C_PORT9_EEECFG_EEE_SLEEP_REQ_MASK 0x1 ++ ++#define RTL8367C_REG_PORT9_EEETXMTR 0x0139 ++ ++#define RTL8367C_REG_PORT9_EEERXMTR 0x013a ++ ++#define RTL8367C_REG_PORT9_EEEPTXMTR 0x013b ++ ++#define RTL8367C_REG_PORT9_EEEPRXMTR 0x013c ++ ++#define RTL8367C_REG_PTP_PORT9_CFG1 0x013e ++#define RTL8367C_PTP_PORT9_CFG1_OFFSET 7 ++#define RTL8367C_PTP_PORT9_CFG1_MASK 0xFF ++ ++#define RTL8367C_REG_P9_MSIC1 0x013f ++#define RTL8367C_P9_MSIC1_OFFSET 0 ++#define RTL8367C_P9_MSIC1_MASK 0x1 ++ ++#define RTL8367C_REG_PORT10_CGST_HALF_CFG 0x0140 ++#define RTL8367C_PORT10_CGST_HALF_CFG_CONGESTION_TIME_OFFSET 4 ++#define RTL8367C_PORT10_CGST_HALF_CFG_CONGESTION_TIME_MASK 0xF0 ++#define RTL8367C_PORT10_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_OFFSET 0 ++#define RTL8367C_PORT10_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_MASK 0xF ++ ++#define RTL8367C_REG_PKTGEN_PORT10_CTRL 0x0141 ++#define RTL8367C_PKTGEN_PORT10_CTRL_STATUS_OFFSET 15 ++#define RTL8367C_PKTGEN_PORT10_CTRL_STATUS_MASK 0x8000 ++#define RTL8367C_PKTGEN_PORT10_CTRL_PKTGEN_STS_OFFSET 13 ++#define RTL8367C_PKTGEN_PORT10_CTRL_PKTGEN_STS_MASK 0x2000 ++#define RTL8367C_PKTGEN_PORT10_CTRL_CRC_NO_ERROR_OFFSET 4 ++#define RTL8367C_PKTGEN_PORT10_CTRL_CRC_NO_ERROR_MASK 0x10 ++#define RTL8367C_PKTGEN_PORT10_CTRL_CMD_START_OFFSET 0 ++#define RTL8367C_PKTGEN_PORT10_CTRL_CMD_START_MASK 0x1 ++ ++#define RTL8367C_REG_TX_ERR_CNT_PORT10 0x0142 ++#define RTL8367C_TX_ERR_CNT_PORT10_OFFSET 0 ++#define RTL8367C_TX_ERR_CNT_PORT10_MASK 0x7 ++ ++#define RTL8367C_REG_PKTGEN_PORT10_DA0 0x0143 ++ ++#define RTL8367C_REG_PKTGEN_PORT10_DA1 0x0144 ++ ++#define RTL8367C_REG_PKTGEN_PORT10_DA2 0x0145 ++ ++#define RTL8367C_REG_PKTGEN_PORT10_SA0 0x0146 ++ ++#define RTL8367C_REG_PKTGEN_PORT10_SA1 0x0147 ++ ++#define RTL8367C_REG_PKTGEN_PORT10_SA2 0x0148 ++ ++#define RTL8367C_REG_PKTGEN_PORT10_COUNTER0 0x0149 ++ ++#define RTL8367C_REG_PKTGEN_PORT10_COUNTER1 0x014a ++#define RTL8367C_PKTGEN_PORT10_COUNTER1_OFFSET 0 ++#define RTL8367C_PKTGEN_PORT10_COUNTER1_MASK 0xFF ++ ++#define RTL8367C_REG_PKTGEN_PORT10_TX_LENGTH 0x014b ++#define RTL8367C_PKTGEN_PORT10_TX_LENGTH_OFFSET 0 ++#define RTL8367C_PKTGEN_PORT10_TX_LENGTH_MASK 0x3FFF ++ ++#define RTL8367C_REG_PKTGEN_PORT10_TIMER 0x014d ++#define RTL8367C_PKTGEN_PORT10_TIMER_TIMER_OFFSET 4 ++#define RTL8367C_PKTGEN_PORT10_TIMER_TIMER_MASK 0xF0 ++#define RTL8367C_PKTGEN_PORT10_TIMER_RX_DMA_ERR_FLAG_OFFSET 3 ++#define RTL8367C_PKTGEN_PORT10_TIMER_RX_DMA_ERR_FLAG_MASK 0x8 ++ ++#define RTL8367C_REG_PORT10_MISC_CFG 0x014e ++#define RTL8367C_PORT10_MISC_CFG_SMALL_TAG_IPG_OFFSET 15 ++#define RTL8367C_PORT10_MISC_CFG_SMALL_TAG_IPG_MASK 0x8000 ++#define RTL8367C_PORT10_MISC_CFG_TX_ITFSP_MODE_OFFSET 14 ++#define RTL8367C_PORT10_MISC_CFG_TX_ITFSP_MODE_MASK 0x4000 ++#define RTL8367C_PORT10_MISC_CFG_FLOWCTRL_INDEP_OFFSET 13 ++#define RTL8367C_PORT10_MISC_CFG_FLOWCTRL_INDEP_MASK 0x2000 ++#define RTL8367C_PORT10_MISC_CFG_DOT1Q_REMARK_ENABLE_OFFSET 12 ++#define RTL8367C_PORT10_MISC_CFG_DOT1Q_REMARK_ENABLE_MASK 0x1000 ++#define RTL8367C_PORT10_MISC_CFG_INGRESSBW_FLOWCTRL_OFFSET 11 ++#define RTL8367C_PORT10_MISC_CFG_INGRESSBW_FLOWCTRL_MASK 0x800 ++#define RTL8367C_PORT10_MISC_CFG_INGRESSBW_IFG_OFFSET 10 ++#define RTL8367C_PORT10_MISC_CFG_INGRESSBW_IFG_MASK 0x400 ++#define RTL8367C_PORT10_MISC_CFG_RX_SPC_OFFSET 9 ++#define RTL8367C_PORT10_MISC_CFG_RX_SPC_MASK 0x200 ++#define RTL8367C_PORT10_MISC_CFG_CRC_SKIP_OFFSET 8 ++#define RTL8367C_PORT10_MISC_CFG_CRC_SKIP_MASK 0x100 ++#define RTL8367C_PORT10_MISC_CFG_PKTGEN_TX_FIRST_OFFSET 7 ++#define RTL8367C_PORT10_MISC_CFG_PKTGEN_TX_FIRST_MASK 0x80 ++#define RTL8367C_PORT10_MISC_CFG_MAC_LOOPBACK_OFFSET 6 ++#define RTL8367C_PORT10_MISC_CFG_MAC_LOOPBACK_MASK 0x40 ++#define RTL8367C_PORT10_MISC_CFG_VLAN_EGRESS_MODE_OFFSET 4 ++#define RTL8367C_PORT10_MISC_CFG_VLAN_EGRESS_MODE_MASK 0x30 ++#define RTL8367C_PORT10_MISC_CFG_CONGESTION_SUSTAIN_TIME_OFFSET 0 ++#define RTL8367C_PORT10_MISC_CFG_CONGESTION_SUSTAIN_TIME_MASK 0xF ++ ++#define RTL8367C_REG_INGRESSBW_PORT10_RATE_CTRL0 0x014f ++ ++#define RTL8367C_REG_INGRESSBW_PORT10_RATE_CTRL1 0x0150 ++#define RTL8367C_INGRESSBW_PORT10_RATE_CTRL1_DUMMY_OFFSET 3 ++#define RTL8367C_INGRESSBW_PORT10_RATE_CTRL1_DUMMY_MASK 0xFFF8 ++#define RTL8367C_INGRESSBW_PORT10_RATE_CTRL1_INGRESSBW_RATE16_OFFSET 0 ++#define RTL8367C_INGRESSBW_PORT10_RATE_CTRL1_INGRESSBW_RATE16_MASK 0x7 ++ ++#define RTL8367C_REG_PORT10_FORCE_RATE0 0x0151 ++ ++#define RTL8367C_REG_PORT10_FORCE_RATE1 0x0152 ++ ++#define RTL8367C_REG_PORT10_CURENT_RATE0 0x0153 ++ ++#define RTL8367C_REG_PORT10_CURENT_RATE1 0x0154 ++ ++#define RTL8367C_REG_PORT10_PAGE_COUNTER 0x0155 ++#define RTL8367C_PORT10_PAGE_COUNTER_OFFSET 0 ++#define RTL8367C_PORT10_PAGE_COUNTER_MASK 0x7F ++ ++#define RTL8367C_REG_PAGEMETER_PORT10_CTRL0 0x0156 ++ ++#define RTL8367C_REG_PAGEMETER_PORT10_CTRL1 0x0157 ++ ++#define RTL8367C_REG_PORT10_EEECFG 0x0158 ++#define RTL8367C_PORT10_EEECFG_EEEP_ENABLE_TX_OFFSET 14 ++#define RTL8367C_PORT10_EEECFG_EEEP_ENABLE_TX_MASK 0x4000 ++#define RTL8367C_PORT10_EEECFG_EEEP_ENABLE_RX_OFFSET 13 ++#define RTL8367C_PORT10_EEECFG_EEEP_ENABLE_RX_MASK 0x2000 ++#define RTL8367C_PORT10_EEECFG_EEE_FORCE_OFFSET 12 ++#define RTL8367C_PORT10_EEECFG_EEE_FORCE_MASK 0x1000 ++#define RTL8367C_PORT10_EEECFG_EEE_100M_OFFSET 11 ++#define RTL8367C_PORT10_EEECFG_EEE_100M_MASK 0x800 ++#define RTL8367C_PORT10_EEECFG_EEE_GIGA_500M_OFFSET 10 ++#define RTL8367C_PORT10_EEECFG_EEE_GIGA_500M_MASK 0x400 ++#define RTL8367C_PORT10_EEECFG_EEE_TX_OFFSET 9 ++#define RTL8367C_PORT10_EEECFG_EEE_TX_MASK 0x200 ++#define RTL8367C_PORT10_EEECFG_EEE_RX_OFFSET 8 ++#define RTL8367C_PORT10_EEECFG_EEE_RX_MASK 0x100 ++#define RTL8367C_PORT10_EEECFG_EEE_DSP_RX_OFFSET 6 ++#define RTL8367C_PORT10_EEECFG_EEE_DSP_RX_MASK 0x40 ++#define RTL8367C_PORT10_EEECFG_EEE_LPI_OFFSET 5 ++#define RTL8367C_PORT10_EEECFG_EEE_LPI_MASK 0x20 ++#define RTL8367C_PORT10_EEECFG_EEE_TX_LPI_OFFSET 4 ++#define RTL8367C_PORT10_EEECFG_EEE_TX_LPI_MASK 0x10 ++#define RTL8367C_PORT10_EEECFG_EEE_RX_LPI_OFFSET 3 ++#define RTL8367C_PORT10_EEECFG_EEE_RX_LPI_MASK 0x8 ++#define RTL8367C_PORT10_EEECFG_EEE_PAUSE_INDICATOR_OFFSET 2 ++#define RTL8367C_PORT10_EEECFG_EEE_PAUSE_INDICATOR_MASK 0x4 ++#define RTL8367C_PORT10_EEECFG_EEE_WAKE_REQ_OFFSET 1 ++#define RTL8367C_PORT10_EEECFG_EEE_WAKE_REQ_MASK 0x2 ++#define RTL8367C_PORT10_EEECFG_EEE_SLEEP_REQ_OFFSET 0 ++#define RTL8367C_PORT10_EEECFG_EEE_SLEEP_REQ_MASK 0x1 ++ ++#define RTL8367C_REG_PORT10_EEETXMTR 0x0159 ++ ++#define RTL8367C_REG_PORT10_EEERXMTR 0x015a ++ ++#define RTL8367C_REG_PORT10_EEEPTXMTR 0x015b ++ ++#define RTL8367C_REG_PORT10_EEEPRXMTR 0x015c ++ ++#define RTL8367C_REG_PTP_PORT10_CFG1 0x015e ++#define RTL8367C_PTP_PORT10_CFG1_OFFSET 7 ++#define RTL8367C_PTP_PORT10_CFG1_MASK 0xFF ++ ++#define RTL8367C_REG_P10_MSIC1 0x015f ++#define RTL8367C_P10_MSIC1_OFFSET 0 ++#define RTL8367C_P10_MSIC1_MASK 0x1 ++ ++/* (16'h0200)outq_reg */ ++ ++#define RTL8367C_REG_FLOWCTRL_QUEUE0_DROP_ON 0x0200 ++#define RTL8367C_FLOWCTRL_QUEUE0_DROP_ON_OFFSET 0 ++#define RTL8367C_FLOWCTRL_QUEUE0_DROP_ON_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_QUEUE1_DROP_ON 0x0201 ++#define RTL8367C_FLOWCTRL_QUEUE1_DROP_ON_OFFSET 0 ++#define RTL8367C_FLOWCTRL_QUEUE1_DROP_ON_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_QUEUE2_DROP_ON 0x0202 ++#define RTL8367C_FLOWCTRL_QUEUE2_DROP_ON_OFFSET 0 ++#define RTL8367C_FLOWCTRL_QUEUE2_DROP_ON_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_QUEUE3_DROP_ON 0x0203 ++#define RTL8367C_FLOWCTRL_QUEUE3_DROP_ON_OFFSET 0 ++#define RTL8367C_FLOWCTRL_QUEUE3_DROP_ON_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_QUEUE4_DROP_ON 0x0204 ++#define RTL8367C_FLOWCTRL_QUEUE4_DROP_ON_OFFSET 0 ++#define RTL8367C_FLOWCTRL_QUEUE4_DROP_ON_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_QUEUE5_DROP_ON 0x0205 ++#define RTL8367C_FLOWCTRL_QUEUE5_DROP_ON_OFFSET 0 ++#define RTL8367C_FLOWCTRL_QUEUE5_DROP_ON_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_QUEUE6_DROP_ON 0x0206 ++#define RTL8367C_FLOWCTRL_QUEUE6_DROP_ON_OFFSET 0 ++#define RTL8367C_FLOWCTRL_QUEUE6_DROP_ON_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_QUEUE7_DROP_ON 0x0207 ++#define RTL8367C_FLOWCTRL_QUEUE7_DROP_ON_OFFSET 0 ++#define RTL8367C_FLOWCTRL_QUEUE7_DROP_ON_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_PORT0_DROP_ON 0x0208 ++#define RTL8367C_FLOWCTRL_PORT0_DROP_ON_OFFSET 0 ++#define RTL8367C_FLOWCTRL_PORT0_DROP_ON_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_PORT1_DROP_ON 0x0209 ++#define RTL8367C_FLOWCTRL_PORT1_DROP_ON_OFFSET 0 ++#define RTL8367C_FLOWCTRL_PORT1_DROP_ON_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_PORT2_DROP_ON 0x020a ++#define RTL8367C_FLOWCTRL_PORT2_DROP_ON_OFFSET 0 ++#define RTL8367C_FLOWCTRL_PORT2_DROP_ON_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_PORT3_DROP_ON 0x020b ++#define RTL8367C_FLOWCTRL_PORT3_DROP_ON_OFFSET 0 ++#define RTL8367C_FLOWCTRL_PORT3_DROP_ON_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_PORT4_DROP_ON 0x020c ++#define RTL8367C_FLOWCTRL_PORT4_DROP_ON_OFFSET 0 ++#define RTL8367C_FLOWCTRL_PORT4_DROP_ON_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_PORT5_DROP_ON 0x020d ++#define RTL8367C_FLOWCTRL_PORT5_DROP_ON_OFFSET 0 ++#define RTL8367C_FLOWCTRL_PORT5_DROP_ON_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_PORT6_DROP_ON 0x020e ++#define RTL8367C_FLOWCTRL_PORT6_DROP_ON_OFFSET 0 ++#define RTL8367C_FLOWCTRL_PORT6_DROP_ON_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_PORT7_DROP_ON 0x020f ++#define RTL8367C_FLOWCTRL_PORT7_DROP_ON_OFFSET 0 ++#define RTL8367C_FLOWCTRL_PORT7_DROP_ON_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_PORT8_DROP_ON 0x0210 ++#define RTL8367C_FLOWCTRL_PORT8_DROP_ON_OFFSET 0 ++#define RTL8367C_FLOWCTRL_PORT8_DROP_ON_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_PORT9_DROP_ON 0x0211 ++#define RTL8367C_FLOWCTRL_PORT9_DROP_ON_OFFSET 0 ++#define RTL8367C_FLOWCTRL_PORT9_DROP_ON_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_PORT10_DROP_ON 0x0212 ++#define RTL8367C_FLOWCTRL_PORT10_DROP_ON_OFFSET 0 ++#define RTL8367C_FLOWCTRL_PORT10_DROP_ON_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_PORT_GAP 0x0218 ++#define RTL8367C_FLOWCTRL_PORT_GAP_OFFSET 0 ++#define RTL8367C_FLOWCTRL_PORT_GAP_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_QUEUE_GAP 0x0219 ++#define RTL8367C_FLOWCTRL_QUEUE_GAP_OFFSET 0 ++#define RTL8367C_FLOWCTRL_QUEUE_GAP_MASK 0x7FF ++ ++#define RTL8367C_REG_PORT_QEMPTY 0x022d ++#define RTL8367C_PORT_QEMPTY_OFFSET 0 ++#define RTL8367C_PORT_QEMPTY_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_DEBUG_CTRL0 0x022e ++#define RTL8367C_FLOWCTRL_DEBUG_CTRL0_OFFSET 0 ++#define RTL8367C_FLOWCTRL_DEBUG_CTRL0_MASK 0xF ++ ++#define RTL8367C_REG_FLOWCTRL_DEBUG_CTRL1 0x022f ++#define RTL8367C_TOTAL_OFFSET 9 ++#define RTL8367C_TOTAL_MASK 0x200 ++#define RTL8367C_PORT_MAX_OFFSET 8 ++#define RTL8367C_PORT_MAX_MASK 0x100 ++#define RTL8367C_QMAX_MASK_OFFSET 0 ++#define RTL8367C_QMAX_MASK_MASK 0xFF ++ ++#define RTL8367C_REG_FLOWCTRL_QUEUE0_PAGE_COUNT 0x0230 ++#define RTL8367C_FLOWCTRL_QUEUE0_PAGE_COUNT_OFFSET 0 ++#define RTL8367C_FLOWCTRL_QUEUE0_PAGE_COUNT_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_QUEUE1_PAGE_COUNT 0x0231 ++#define RTL8367C_FLOWCTRL_QUEUE1_PAGE_COUNT_OFFSET 0 ++#define RTL8367C_FLOWCTRL_QUEUE1_PAGE_COUNT_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_QUEUE2_PAGE_COUNT 0x0232 ++#define RTL8367C_FLOWCTRL_QUEUE2_PAGE_COUNT_OFFSET 0 ++#define RTL8367C_FLOWCTRL_QUEUE2_PAGE_COUNT_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_QUEUE3_PAGE_COUNT 0x0233 ++#define RTL8367C_FLOWCTRL_QUEUE3_PAGE_COUNT_OFFSET 0 ++#define RTL8367C_FLOWCTRL_QUEUE3_PAGE_COUNT_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_QUEUE4_PAGE_COUNT 0x0234 ++#define RTL8367C_FLOWCTRL_QUEUE4_PAGE_COUNT_OFFSET 0 ++#define RTL8367C_FLOWCTRL_QUEUE4_PAGE_COUNT_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_QUEUE5_PAGE_COUNT 0x0235 ++#define RTL8367C_FLOWCTRL_QUEUE5_PAGE_COUNT_OFFSET 0 ++#define RTL8367C_FLOWCTRL_QUEUE5_PAGE_COUNT_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_QUEUE6_PAGE_COUNT 0x0236 ++#define RTL8367C_FLOWCTRL_QUEUE6_PAGE_COUNT_OFFSET 0 ++#define RTL8367C_FLOWCTRL_QUEUE6_PAGE_COUNT_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_QUEUE7_PAGE_COUNT 0x0237 ++#define RTL8367C_FLOWCTRL_QUEUE7_PAGE_COUNT_OFFSET 0 ++#define RTL8367C_FLOWCTRL_QUEUE7_PAGE_COUNT_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_PORT_PAGE_COUNT 0x0238 ++#define RTL8367C_FLOWCTRL_PORT_PAGE_COUNT_OFFSET 0 ++#define RTL8367C_FLOWCTRL_PORT_PAGE_COUNT_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_QUEUE0_MAX_PAGE_COUNT 0x0239 ++#define RTL8367C_FLOWCTRL_QUEUE0_MAX_PAGE_COUNT_OFFSET 0 ++#define RTL8367C_FLOWCTRL_QUEUE0_MAX_PAGE_COUNT_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_QUEUE1_MAX_PAGE_COUNT 0x023a ++#define RTL8367C_FLOWCTRL_QUEUE1_MAX_PAGE_COUNT_OFFSET 0 ++#define RTL8367C_FLOWCTRL_QUEUE1_MAX_PAGE_COUNT_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_QUEUE2_MAX_PAGE_COUNT 0x023b ++#define RTL8367C_FLOWCTRL_QUEUE2_MAX_PAGE_COUNT_OFFSET 0 ++#define RTL8367C_FLOWCTRL_QUEUE2_MAX_PAGE_COUNT_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_QUEUE3_MAX_PAGE_COUNT 0x023c ++#define RTL8367C_FLOWCTRL_QUEUE3_MAX_PAGE_COUNT_OFFSET 0 ++#define RTL8367C_FLOWCTRL_QUEUE3_MAX_PAGE_COUNT_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_QUEUE4_MAX_PAGE_COUNT 0x023d ++#define RTL8367C_FLOWCTRL_QUEUE4_MAX_PAGE_COUNT_OFFSET 0 ++#define RTL8367C_FLOWCTRL_QUEUE4_MAX_PAGE_COUNT_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_QUEUE5_MAX_PAGE_COUNT 0x023e ++#define RTL8367C_FLOWCTRL_QUEUE5_MAX_PAGE_COUNT_OFFSET 0 ++#define RTL8367C_FLOWCTRL_QUEUE5_MAX_PAGE_COUNT_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_QUEUE6_MAX_PAGE_COUNT 0x023f ++#define RTL8367C_FLOWCTRL_QUEUE6_MAX_PAGE_COUNT_OFFSET 0 ++#define RTL8367C_FLOWCTRL_QUEUE6_MAX_PAGE_COUNT_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_QUEUE7_MAX_PAGE_COUNT 0x0240 ++#define RTL8367C_FLOWCTRL_QUEUE7_MAX_PAGE_COUNT_OFFSET 0 ++#define RTL8367C_FLOWCTRL_QUEUE7_MAX_PAGE_COUNT_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_PORT_MAX_PAGE_COUNT 0x0241 ++#define RTL8367C_FLOWCTRL_PORT_MAX_PAGE_COUNT_OFFSET 0 ++#define RTL8367C_FLOWCTRL_PORT_MAX_PAGE_COUNT_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_TOTAL_PACKET_COUNT 0x0243 ++ ++#define RTL8367C_REG_HIGH_QUEUE_MASK0 0x0244 ++#define RTL8367C_PORT1_HIGH_QUEUE_MASK_OFFSET 8 ++#define RTL8367C_PORT1_HIGH_QUEUE_MASK_MASK 0xFF00 ++#define RTL8367C_PORT0_HIGH_QUEUE_MASK_OFFSET 0 ++#define RTL8367C_PORT0_HIGH_QUEUE_MASK_MASK 0xFF ++ ++#define RTL8367C_REG_HIGH_QUEUE_MASK1 0x0245 ++#define RTL8367C_PORT3_HIGH_QUEUE_MASK_OFFSET 8 ++#define RTL8367C_PORT3_HIGH_QUEUE_MASK_MASK 0xFF00 ++#define RTL8367C_PORT2_HIGH_QUEUE_MASK_OFFSET 0 ++#define RTL8367C_PORT2_HIGH_QUEUE_MASK_MASK 0xFF ++ ++#define RTL8367C_REG_HIGH_QUEUE_MASK2 0x0246 ++#define RTL8367C_PORT5_HIGH_QUEUE_MASK_OFFSET 8 ++#define RTL8367C_PORT5_HIGH_QUEUE_MASK_MASK 0xFF00 ++#define RTL8367C_PORT4_HIGH_QUEUE_MASK_OFFSET 0 ++#define RTL8367C_PORT4_HIGH_QUEUE_MASK_MASK 0xFF ++ ++#define RTL8367C_REG_HIGH_QUEUE_MASK3 0x0247 ++#define RTL8367C_PORT7_HIGH_QUEUE_MASK_OFFSET 8 ++#define RTL8367C_PORT7_HIGH_QUEUE_MASK_MASK 0xFF00 ++#define RTL8367C_PORT6_HIGH_QUEUE_MASK_OFFSET 0 ++#define RTL8367C_PORT6_HIGH_QUEUE_MASK_MASK 0xFF ++ ++#define RTL8367C_REG_HIGH_QUEUE_MASK4 0x0248 ++#define RTL8367C_PORT9_HIGH_QUEUE_MASK_OFFSET 8 ++#define RTL8367C_PORT9_HIGH_QUEUE_MASK_MASK 0xFF00 ++#define RTL8367C_PORT8_HIGH_QUEUE_MASK_OFFSET 0 ++#define RTL8367C_PORT8_HIGH_QUEUE_MASK_MASK 0xFF ++ ++#define RTL8367C_REG_HIGH_QUEUE_MASK5 0x0249 ++#define RTL8367C_HIGH_QUEUE_MASK5_OFFSET 0 ++#define RTL8367C_HIGH_QUEUE_MASK5_MASK 0xFF ++ ++#define RTL8367C_REG_LOW_QUEUE_TH 0x024c ++#define RTL8367C_LOW_QUEUE_TH_OFFSET 0 ++#define RTL8367C_LOW_QUEUE_TH_MASK 0x7FF ++ ++#define RTL8367C_REG_TH_TX_PREFET 0x0250 ++#define RTL8367C_TH_TX_PREFET_OFFSET 0 ++#define RTL8367C_TH_TX_PREFET_MASK 0xFF ++ ++#define RTL8367C_REG_DUMMY_0251 0x0251 ++ ++#define RTL8367C_REG_DUMMY_0252 0x0252 ++ ++#define RTL8367C_REG_DUMMY_0253 0x0253 ++ ++#define RTL8367C_REG_DUMMY_0254 0x0254 ++ ++#define RTL8367C_REG_DUMMY_0255 0x0255 ++ ++#define RTL8367C_REG_DUMMY_0256 0x0256 ++ ++#define RTL8367C_REG_DUMMY_0257 0x0257 ++ ++#define RTL8367C_REG_DUMMY_0258 0x0258 ++ ++#define RTL8367C_REG_DUMMY_0259 0x0259 ++ ++#define RTL8367C_REG_DUMMY_025A 0x025A ++ ++#define RTL8367C_REG_DUMMY_025B 0x025B ++ ++#define RTL8367C_REG_DUMMY_025C 0x025C ++ ++#define RTL8367C_REG_Q_TXPKT_CNT_CTL 0x025d ++#define RTL8367C_QUEUE_PKT_CNT_CLR_OFFSET 4 ++#define RTL8367C_QUEUE_PKT_CNT_CLR_MASK 0x10 ++#define RTL8367C_PORT_ID_QUEUE_PKT_CNT_OFFSET 0 ++#define RTL8367C_PORT_ID_QUEUE_PKT_CNT_MASK 0xF ++ ++#define RTL8367C_REG_Q0_TXPKT_CNT_L 0x025e ++ ++#define RTL8367C_REG_Q0_TXPKT_CNT_H 0x025f ++ ++#define RTL8367C_REG_Q1_TXPKT_CNT_L 0x0260 ++ ++#define RTL8367C_REG_Q1_TXPKT_CNT_H 0x0261 ++ ++#define RTL8367C_REG_Q2_TXPKT_CNT_L 0x0262 ++ ++#define RTL8367C_REG_Q2_TXPKT_CNT_H 0x0263 ++ ++#define RTL8367C_REG_Q3_TXPKT_CNT_L 0x0264 ++ ++#define RTL8367C_REG_Q3_TXPKT_CNT_H 0x0265 ++ ++#define RTL8367C_REG_Q4_TXPKT_CNT_L 0x0266 ++ ++#define RTL8367C_REG_Q4_TXPKT_CNT_H 0x0267 ++ ++#define RTL8367C_REG_Q5_TXPKT_CNT_L 0x0268 ++ ++#define RTL8367C_REG_Q5_TXPKT_CNT_H 0x0269 ++ ++#define RTL8367C_REG_Q6_TXPKT_CNT_L 0x026a ++ ++#define RTL8367C_REG_Q6_TXPKT_CNT_H 0x026b ++ ++#define RTL8367C_REG_Q7_TXPKT_CNT_L 0x026c ++ ++#define RTL8367C_REG_Q7_TXPKT_CNT_H 0x026d ++ ++/* (16'h0300)sch_reg */ ++ ++#define RTL8367C_REG_SCHEDULE_WFQ_CTRL 0x0300 ++#define RTL8367C_SCHEDULE_WFQ_CTRL_OFFSET 0 ++#define RTL8367C_SCHEDULE_WFQ_CTRL_MASK 0x1 ++ ++#define RTL8367C_REG_SCHEDULE_WFQ_BURST_SIZE 0x0301 ++ ++#define RTL8367C_REG_SCHEDULE_QUEUE_TYPE_CTRL0 0x0302 ++#define RTL8367C_PORT1_QUEUE7_TYPE_OFFSET 15 ++#define RTL8367C_PORT1_QUEUE7_TYPE_MASK 0x8000 ++#define RTL8367C_PORT1_QUEUE6_TYPE_OFFSET 14 ++#define RTL8367C_PORT1_QUEUE6_TYPE_MASK 0x4000 ++#define RTL8367C_PORT1_QUEUE5_TYPE_OFFSET 13 ++#define RTL8367C_PORT1_QUEUE5_TYPE_MASK 0x2000 ++#define RTL8367C_PORT1_QUEUE4_TYPE_OFFSET 12 ++#define RTL8367C_PORT1_QUEUE4_TYPE_MASK 0x1000 ++#define RTL8367C_PORT1_QUEUE3_TYPE_OFFSET 11 ++#define RTL8367C_PORT1_QUEUE3_TYPE_MASK 0x800 ++#define RTL8367C_PORT1_QUEUE2_TYPE_OFFSET 10 ++#define RTL8367C_PORT1_QUEUE2_TYPE_MASK 0x400 ++#define RTL8367C_PORT1_QUEUE1_TYPE_OFFSET 9 ++#define RTL8367C_PORT1_QUEUE1_TYPE_MASK 0x200 ++#define RTL8367C_PORT1_QUEUE0_TYPE_OFFSET 8 ++#define RTL8367C_PORT1_QUEUE0_TYPE_MASK 0x100 ++#define RTL8367C_PORT0_QUEUE7_TYPE_OFFSET 7 ++#define RTL8367C_PORT0_QUEUE7_TYPE_MASK 0x80 ++#define RTL8367C_PORT0_QUEUE6_TYPE_OFFSET 6 ++#define RTL8367C_PORT0_QUEUE6_TYPE_MASK 0x40 ++#define RTL8367C_PORT0_QUEUE5_TYPE_OFFSET 5 ++#define RTL8367C_PORT0_QUEUE5_TYPE_MASK 0x20 ++#define RTL8367C_PORT0_QUEUE4_TYPE_OFFSET 4 ++#define RTL8367C_PORT0_QUEUE4_TYPE_MASK 0x10 ++#define RTL8367C_PORT0_QUEUE3_TYPE_OFFSET 3 ++#define RTL8367C_PORT0_QUEUE3_TYPE_MASK 0x8 ++#define RTL8367C_PORT0_QUEUE2_TYPE_OFFSET 2 ++#define RTL8367C_PORT0_QUEUE2_TYPE_MASK 0x4 ++#define RTL8367C_PORT0_QUEUE1_TYPE_OFFSET 1 ++#define RTL8367C_PORT0_QUEUE1_TYPE_MASK 0x2 ++#define RTL8367C_PORT0_QUEUE0_TYPE_OFFSET 0 ++#define RTL8367C_PORT0_QUEUE0_TYPE_MASK 0x1 ++ ++#define RTL8367C_REG_SCHEDULE_QUEUE_TYPE_CTRL1 0x0303 ++#define RTL8367C_PORT3_QUEUE7_TYPE_OFFSET 15 ++#define RTL8367C_PORT3_QUEUE7_TYPE_MASK 0x8000 ++#define RTL8367C_PORT3_QUEUE6_TYPE_OFFSET 14 ++#define RTL8367C_PORT3_QUEUE6_TYPE_MASK 0x4000 ++#define RTL8367C_PORT3_QUEUE5_TYPE_OFFSET 13 ++#define RTL8367C_PORT3_QUEUE5_TYPE_MASK 0x2000 ++#define RTL8367C_PORT3_QUEUE4_TYPE_OFFSET 12 ++#define RTL8367C_PORT3_QUEUE4_TYPE_MASK 0x1000 ++#define RTL8367C_PORT3_QUEUE3_TYPE_OFFSET 11 ++#define RTL8367C_PORT3_QUEUE3_TYPE_MASK 0x800 ++#define RTL8367C_PORT3_QUEUE2_TYPE_OFFSET 10 ++#define RTL8367C_PORT3_QUEUE2_TYPE_MASK 0x400 ++#define RTL8367C_PORT3_QUEUE1_TYPE_OFFSET 9 ++#define RTL8367C_PORT3_QUEUE1_TYPE_MASK 0x200 ++#define RTL8367C_PORT3_QUEUE0_TYPE_OFFSET 8 ++#define RTL8367C_PORT3_QUEUE0_TYPE_MASK 0x100 ++#define RTL8367C_PORT2_QUEUE7_TYPE_OFFSET 7 ++#define RTL8367C_PORT2_QUEUE7_TYPE_MASK 0x80 ++#define RTL8367C_PORT2_QUEUE6_TYPE_OFFSET 6 ++#define RTL8367C_PORT2_QUEUE6_TYPE_MASK 0x40 ++#define RTL8367C_PORT2_QUEUE5_TYPE_OFFSET 5 ++#define RTL8367C_PORT2_QUEUE5_TYPE_MASK 0x20 ++#define RTL8367C_PORT2_QUEUE4_TYPE_OFFSET 4 ++#define RTL8367C_PORT2_QUEUE4_TYPE_MASK 0x10 ++#define RTL8367C_PORT2_QUEUE3_TYPE_OFFSET 3 ++#define RTL8367C_PORT2_QUEUE3_TYPE_MASK 0x8 ++#define RTL8367C_PORT2_QUEUE2_TYPE_OFFSET 2 ++#define RTL8367C_PORT2_QUEUE2_TYPE_MASK 0x4 ++#define RTL8367C_PORT2_QUEUE1_TYPE_OFFSET 1 ++#define RTL8367C_PORT2_QUEUE1_TYPE_MASK 0x2 ++#define RTL8367C_PORT2_QUEUE0_TYPE_OFFSET 0 ++#define RTL8367C_PORT2_QUEUE0_TYPE_MASK 0x1 ++ ++#define RTL8367C_REG_SCHEDULE_QUEUE_TYPE_CTRL2 0x0304 ++#define RTL8367C_PORT5_QUEUE7_TYPE_OFFSET 15 ++#define RTL8367C_PORT5_QUEUE7_TYPE_MASK 0x8000 ++#define RTL8367C_PORT5_QUEUE6_TYPE_OFFSET 14 ++#define RTL8367C_PORT5_QUEUE6_TYPE_MASK 0x4000 ++#define RTL8367C_PORT5_QUEUE5_TYPE_OFFSET 13 ++#define RTL8367C_PORT5_QUEUE5_TYPE_MASK 0x2000 ++#define RTL8367C_PORT5_QUEUE4_TYPE_OFFSET 12 ++#define RTL8367C_PORT5_QUEUE4_TYPE_MASK 0x1000 ++#define RTL8367C_PORT5_QUEUE3_TYPE_OFFSET 11 ++#define RTL8367C_PORT5_QUEUE3_TYPE_MASK 0x800 ++#define RTL8367C_PORT5_QUEUE2_TYPE_OFFSET 10 ++#define RTL8367C_PORT5_QUEUE2_TYPE_MASK 0x400 ++#define RTL8367C_PORT5_QUEUE1_TYPE_OFFSET 9 ++#define RTL8367C_PORT5_QUEUE1_TYPE_MASK 0x200 ++#define RTL8367C_PORT5_QUEUE0_TYPE_OFFSET 8 ++#define RTL8367C_PORT5_QUEUE0_TYPE_MASK 0x100 ++#define RTL8367C_PORT4_QUEUE7_TYPE_OFFSET 7 ++#define RTL8367C_PORT4_QUEUE7_TYPE_MASK 0x80 ++#define RTL8367C_PORT4_QUEUE6_TYPE_OFFSET 6 ++#define RTL8367C_PORT4_QUEUE6_TYPE_MASK 0x40 ++#define RTL8367C_PORT4_QUEUE5_TYPE_OFFSET 5 ++#define RTL8367C_PORT4_QUEUE5_TYPE_MASK 0x20 ++#define RTL8367C_PORT4_QUEUE4_TYPE_OFFSET 4 ++#define RTL8367C_PORT4_QUEUE4_TYPE_MASK 0x10 ++#define RTL8367C_PORT4_QUEUE3_TYPE_OFFSET 3 ++#define RTL8367C_PORT4_QUEUE3_TYPE_MASK 0x8 ++#define RTL8367C_PORT4_QUEUE2_TYPE_OFFSET 2 ++#define RTL8367C_PORT4_QUEUE2_TYPE_MASK 0x4 ++#define RTL8367C_PORT4_QUEUE1_TYPE_OFFSET 1 ++#define RTL8367C_PORT4_QUEUE1_TYPE_MASK 0x2 ++#define RTL8367C_PORT4_QUEUE0_TYPE_OFFSET 0 ++#define RTL8367C_PORT4_QUEUE0_TYPE_MASK 0x1 ++ ++#define RTL8367C_REG_SCHEDULE_QUEUE_TYPE_CTRL3 0x0305 ++#define RTL8367C_PORT7_QUEUE7_TYPE_OFFSET 15 ++#define RTL8367C_PORT7_QUEUE7_TYPE_MASK 0x8000 ++#define RTL8367C_PORT7_QUEUE6_TYPE_OFFSET 14 ++#define RTL8367C_PORT7_QUEUE6_TYPE_MASK 0x4000 ++#define RTL8367C_PORT7_QUEUE5_TYPE_OFFSET 13 ++#define RTL8367C_PORT7_QUEUE5_TYPE_MASK 0x2000 ++#define RTL8367C_PORT7_QUEUE4_TYPE_OFFSET 12 ++#define RTL8367C_PORT7_QUEUE4_TYPE_MASK 0x1000 ++#define RTL8367C_PORT7_QUEUE3_TYPE_OFFSET 11 ++#define RTL8367C_PORT7_QUEUE3_TYPE_MASK 0x800 ++#define RTL8367C_PORT7_QUEUE2_TYPE_OFFSET 10 ++#define RTL8367C_PORT7_QUEUE2_TYPE_MASK 0x400 ++#define RTL8367C_PORT7_QUEUE1_TYPE_OFFSET 9 ++#define RTL8367C_PORT7_QUEUE1_TYPE_MASK 0x200 ++#define RTL8367C_PORT7_QUEUE0_TYPE_OFFSET 8 ++#define RTL8367C_PORT7_QUEUE0_TYPE_MASK 0x100 ++#define RTL8367C_PORT6_QUEUE7_TYPE_OFFSET 7 ++#define RTL8367C_PORT6_QUEUE7_TYPE_MASK 0x80 ++#define RTL8367C_PORT6_QUEUE6_TYPE_OFFSET 6 ++#define RTL8367C_PORT6_QUEUE6_TYPE_MASK 0x40 ++#define RTL8367C_PORT6_QUEUE5_TYPE_OFFSET 5 ++#define RTL8367C_PORT6_QUEUE5_TYPE_MASK 0x20 ++#define RTL8367C_PORT6_QUEUE4_TYPE_OFFSET 4 ++#define RTL8367C_PORT6_QUEUE4_TYPE_MASK 0x10 ++#define RTL8367C_PORT6_QUEUE3_TYPE_OFFSET 3 ++#define RTL8367C_PORT6_QUEUE3_TYPE_MASK 0x8 ++#define RTL8367C_PORT6_QUEUE2_TYPE_OFFSET 2 ++#define RTL8367C_PORT6_QUEUE2_TYPE_MASK 0x4 ++#define RTL8367C_PORT6_QUEUE1_TYPE_OFFSET 1 ++#define RTL8367C_PORT6_QUEUE1_TYPE_MASK 0x2 ++#define RTL8367C_SCHEDULE_QUEUE_TYPE_CTRL3_PORT6_QUEUE0_TYPE_OFFSET 0 ++#define RTL8367C_SCHEDULE_QUEUE_TYPE_CTRL3_PORT6_QUEUE0_TYPE_MASK 0x1 ++ ++#define RTL8367C_REG_SCHEDULE_QUEUE_TYPE_CTRL4 0x0306 ++#define RTL8367C_PORT9_QUEUE7_TYPE_OFFSET 15 ++#define RTL8367C_PORT9_QUEUE7_TYPE_MASK 0x8000 ++#define RTL8367C_PORT9_QUEUE6_TYPE_OFFSET 14 ++#define RTL8367C_PORT9_QUEUE6_TYPE_MASK 0x4000 ++#define RTL8367C_PORT9_QUEUE5_TYPE_OFFSET 13 ++#define RTL8367C_PORT9_QUEUE5_TYPE_MASK 0x2000 ++#define RTL8367C_PORT9_QUEUE4_TYPE_OFFSET 12 ++#define RTL8367C_PORT9_QUEUE4_TYPE_MASK 0x1000 ++#define RTL8367C_PORT9_QUEUE3_TYPE_OFFSET 11 ++#define RTL8367C_PORT9_QUEUE3_TYPE_MASK 0x800 ++#define RTL8367C_PORT9_QUEUE2_TYPE_OFFSET 10 ++#define RTL8367C_PORT9_QUEUE2_TYPE_MASK 0x400 ++#define RTL8367C_PORT9_QUEUE1_TYPE_OFFSET 9 ++#define RTL8367C_PORT9_QUEUE1_TYPE_MASK 0x200 ++#define RTL8367C_PORT9_QUEUE0_TYPE_OFFSET 8 ++#define RTL8367C_PORT9_QUEUE0_TYPE_MASK 0x100 ++#define RTL8367C_PORT8_QUEUE7_TYPE_OFFSET 7 ++#define RTL8367C_PORT8_QUEUE7_TYPE_MASK 0x80 ++#define RTL8367C_PORT8_QUEUE6_TYPE_OFFSET 6 ++#define RTL8367C_PORT8_QUEUE6_TYPE_MASK 0x40 ++#define RTL8367C_PORT8_QUEUE5_TYPE_OFFSET 5 ++#define RTL8367C_PORT8_QUEUE5_TYPE_MASK 0x20 ++#define RTL8367C_PORT8_QUEUE4_TYPE_OFFSET 4 ++#define RTL8367C_PORT8_QUEUE4_TYPE_MASK 0x10 ++#define RTL8367C_PORT8_QUEUE3_TYPE_OFFSET 3 ++#define RTL8367C_PORT8_QUEUE3_TYPE_MASK 0x8 ++#define RTL8367C_PORT8_QUEUE2_TYPE_OFFSET 2 ++#define RTL8367C_PORT8_QUEUE2_TYPE_MASK 0x4 ++#define RTL8367C_PORT8_QUEUE1_TYPE_OFFSET 1 ++#define RTL8367C_PORT8_QUEUE1_TYPE_MASK 0x2 ++#define RTL8367C_SCHEDULE_QUEUE_TYPE_CTRL4_PORT6_QUEUE0_TYPE_OFFSET 0 ++#define RTL8367C_SCHEDULE_QUEUE_TYPE_CTRL4_PORT6_QUEUE0_TYPE_MASK 0x1 ++ ++#define RTL8367C_REG_SCHEDULE_QUEUE_TYPE_CTRL5 0x0307 ++#define RTL8367C_PORT10_QUEUE7_TYPE_OFFSET 7 ++#define RTL8367C_PORT10_QUEUE7_TYPE_MASK 0x80 ++#define RTL8367C_PORT10_QUEUE6_TYPE_OFFSET 6 ++#define RTL8367C_PORT10_QUEUE6_TYPE_MASK 0x40 ++#define RTL8367C_PORT10_QUEUE5_TYPE_OFFSET 5 ++#define RTL8367C_PORT10_QUEUE5_TYPE_MASK 0x20 ++#define RTL8367C_PORT10_QUEUE4_TYPE_OFFSET 4 ++#define RTL8367C_PORT10_QUEUE4_TYPE_MASK 0x10 ++#define RTL8367C_PORT10_QUEUE3_TYPE_OFFSET 3 ++#define RTL8367C_PORT10_QUEUE3_TYPE_MASK 0x8 ++#define RTL8367C_PORT10_QUEUE2_TYPE_OFFSET 2 ++#define RTL8367C_PORT10_QUEUE2_TYPE_MASK 0x4 ++#define RTL8367C_PORT10_QUEUE1_TYPE_OFFSET 1 ++#define RTL8367C_PORT10_QUEUE1_TYPE_MASK 0x2 ++#define RTL8367C_PORT10_QUEUE0_TYPE_OFFSET 0 ++#define RTL8367C_PORT10_QUEUE0_TYPE_MASK 0x1 ++ ++#define RTL8367C_REG_SCHEDULE_APR_CTRL0 0x030a ++#define RTL8367C_PORT10_APR_ENABLE_OFFSET 10 ++#define RTL8367C_PORT10_APR_ENABLE_MASK 0x400 ++#define RTL8367C_PORT9_APR_ENABLE_OFFSET 9 ++#define RTL8367C_PORT9_APR_ENABLE_MASK 0x200 ++#define RTL8367C_PORT8_APR_ENABLE_OFFSET 8 ++#define RTL8367C_PORT8_APR_ENABLE_MASK 0x100 ++#define RTL8367C_PORT7_APR_ENABLE_OFFSET 7 ++#define RTL8367C_PORT7_APR_ENABLE_MASK 0x80 ++#define RTL8367C_PORT6_APR_ENABLE_OFFSET 6 ++#define RTL8367C_PORT6_APR_ENABLE_MASK 0x40 ++#define RTL8367C_PORT5_APR_ENABLE_OFFSET 5 ++#define RTL8367C_PORT5_APR_ENABLE_MASK 0x20 ++#define RTL8367C_PORT4_APR_ENABLE_OFFSET 4 ++#define RTL8367C_PORT4_APR_ENABLE_MASK 0x10 ++#define RTL8367C_PORT3_APR_ENABLE_OFFSET 3 ++#define RTL8367C_PORT3_APR_ENABLE_MASK 0x8 ++#define RTL8367C_PORT2_APR_ENABLE_OFFSET 2 ++#define RTL8367C_PORT2_APR_ENABLE_MASK 0x4 ++#define RTL8367C_PORT1_APR_ENABLE_OFFSET 1 ++#define RTL8367C_PORT1_APR_ENABLE_MASK 0x2 ++#define RTL8367C_PORT0_APR_ENABLE_OFFSET 0 ++#define RTL8367C_PORT0_APR_ENABLE_MASK 0x1 ++ ++#define RTL8367C_REG_SCHEDULE_PORT0_QUEUE0_WFQ_WEIGHT 0x030c ++ ++#define RTL8367C_REG_SCHEDULE_PORT0_QUEUE1_WFQ_WEIGHT 0x030d ++#define RTL8367C_SCHEDULE_PORT0_QUEUE1_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT0_QUEUE1_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT0_QUEUE2_WFQ_WEIGHT 0x030e ++#define RTL8367C_SCHEDULE_PORT0_QUEUE2_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT0_QUEUE2_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT0_QUEUE3_WFQ_WEIGHT 0x030f ++#define RTL8367C_SCHEDULE_PORT0_QUEUE3_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT0_QUEUE3_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT0_QUEUE4_WFQ_WEIGHT 0x0310 ++#define RTL8367C_SCHEDULE_PORT0_QUEUE4_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT0_QUEUE4_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT0_QUEUE5_WFQ_WEIGHT 0x0311 ++#define RTL8367C_SCHEDULE_PORT0_QUEUE5_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT0_QUEUE5_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT0_QUEUE6_WFQ_WEIGHT 0x0312 ++#define RTL8367C_SCHEDULE_PORT0_QUEUE6_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT0_QUEUE6_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT0_QUEUE7_WFQ_WEIGHT 0x0313 ++#define RTL8367C_SCHEDULE_PORT0_QUEUE7_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT0_QUEUE7_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT1_QUEUE0_WFQ_WEIGHT 0x0314 ++ ++#define RTL8367C_REG_SCHEDULE_PORT1_QUEUE1_WFQ_WEIGHT 0x0315 ++#define RTL8367C_SCHEDULE_PORT1_QUEUE1_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT1_QUEUE1_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT1_QUEUE2_WFQ_WEIGHT 0x0316 ++#define RTL8367C_SCHEDULE_PORT1_QUEUE2_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT1_QUEUE2_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT1_QUEUE3_WFQ_WEIGHT 0x0317 ++#define RTL8367C_SCHEDULE_PORT1_QUEUE3_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT1_QUEUE3_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT1_QUEUE4_WFQ_WEIGHT 0x0318 ++#define RTL8367C_SCHEDULE_PORT1_QUEUE4_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT1_QUEUE4_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT1_QUEUE5_WFQ_WEIGHT 0x0319 ++#define RTL8367C_SCHEDULE_PORT1_QUEUE5_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT1_QUEUE5_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT1_QUEUE6_WFQ_WEIGHT 0x031a ++#define RTL8367C_SCHEDULE_PORT1_QUEUE6_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT1_QUEUE6_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT1_QUEUE7_WFQ_WEIGHT 0x031b ++#define RTL8367C_SCHEDULE_PORT1_QUEUE7_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT1_QUEUE7_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT2_QUEUE0_WFQ_WEIGHT 0x031c ++ ++#define RTL8367C_REG_SCHEDULE_PORT2_QUEUE1_WFQ_WEIGHT 0x031d ++#define RTL8367C_SCHEDULE_PORT2_QUEUE1_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT2_QUEUE1_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT2_QUEUE2_WFQ_WEIGHT 0x031e ++#define RTL8367C_SCHEDULE_PORT2_QUEUE2_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT2_QUEUE2_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT2_QUEUE3_WFQ_WEIGHT 0x031f ++#define RTL8367C_SCHEDULE_PORT2_QUEUE3_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT2_QUEUE3_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT2_QUEUE4_WFQ_WEIGHT 0x0320 ++#define RTL8367C_SCHEDULE_PORT2_QUEUE4_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT2_QUEUE4_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT2_QUEUE5_WFQ_WEIGHT 0x0321 ++#define RTL8367C_SCHEDULE_PORT2_QUEUE5_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT2_QUEUE5_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT2_QUEUE6_WFQ_WEIGHT 0x0322 ++#define RTL8367C_SCHEDULE_PORT2_QUEUE6_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT2_QUEUE6_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT2_QUEUE7_WFQ_WEIGHT 0x0323 ++#define RTL8367C_SCHEDULE_PORT2_QUEUE7_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT2_QUEUE7_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT3_QUEUE0_WFQ_WEIGHT 0x0324 ++ ++#define RTL8367C_REG_SCHEDULE_PORT3_QUEUE1_WFQ_WEIGHT 0x0325 ++#define RTL8367C_SCHEDULE_PORT3_QUEUE1_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT3_QUEUE1_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT3_QUEUE2_WFQ_WEIGHT 0x0326 ++#define RTL8367C_SCHEDULE_PORT3_QUEUE2_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT3_QUEUE2_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT3_QUEUE3_WFQ_WEIGHT 0x0327 ++#define RTL8367C_SCHEDULE_PORT3_QUEUE3_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT3_QUEUE3_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT3_QUEUE4_WFQ_WEIGHT 0x0328 ++#define RTL8367C_SCHEDULE_PORT3_QUEUE4_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT3_QUEUE4_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT3_QUEUE5_WFQ_WEIGHT 0x0329 ++#define RTL8367C_SCHEDULE_PORT3_QUEUE5_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT3_QUEUE5_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT3_QUEUE6_WFQ_WEIGHT 0x032a ++#define RTL8367C_SCHEDULE_PORT3_QUEUE6_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT3_QUEUE6_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT3_QUEUE7_WFQ_WEIGHT 0x032b ++#define RTL8367C_SCHEDULE_PORT3_QUEUE7_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT3_QUEUE7_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT4_QUEUE0_WFQ_WEIGHT 0x032c ++ ++#define RTL8367C_REG_SCHEDULE_PORT4_QUEUE1_WFQ_WEIGHT 0x032d ++#define RTL8367C_SCHEDULE_PORT4_QUEUE1_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT4_QUEUE1_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT4_QUEUE2_WFQ_WEIGHT 0x032e ++#define RTL8367C_SCHEDULE_PORT4_QUEUE2_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT4_QUEUE2_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT4_QUEUE3_WFQ_WEIGHT 0x032f ++#define RTL8367C_SCHEDULE_PORT4_QUEUE3_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT4_QUEUE3_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT4_QUEUE4_WFQ_WEIGHT 0x0330 ++#define RTL8367C_SCHEDULE_PORT4_QUEUE4_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT4_QUEUE4_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT4_QUEUE5_WFQ_WEIGHT 0x0331 ++#define RTL8367C_SCHEDULE_PORT4_QUEUE5_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT4_QUEUE5_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT4_QUEUE6_WFQ_WEIGHT 0x0332 ++#define RTL8367C_SCHEDULE_PORT4_QUEUE6_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT4_QUEUE6_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT4_QUEUE7_WFQ_WEIGHT 0x0333 ++#define RTL8367C_SCHEDULE_PORT4_QUEUE7_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT4_QUEUE7_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT5_QUEUE0_WFQ_WEIGHT 0x0334 ++ ++#define RTL8367C_REG_SCHEDULE_PORT5_QUEUE1_WFQ_WEIGHT 0x0335 ++#define RTL8367C_SCHEDULE_PORT5_QUEUE1_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT5_QUEUE1_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT5_QUEUE2_WFQ_WEIGHT 0x0336 ++#define RTL8367C_SCHEDULE_PORT5_QUEUE2_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT5_QUEUE2_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT5_QUEUE3_WFQ_WEIGHT 0x0337 ++#define RTL8367C_SCHEDULE_PORT5_QUEUE3_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT5_QUEUE3_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT5_QUEUE4_WFQ_WEIGHT 0x0338 ++#define RTL8367C_SCHEDULE_PORT5_QUEUE4_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT5_QUEUE4_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT5_QUEUE5_WFQ_WEIGHT 0x0339 ++#define RTL8367C_SCHEDULE_PORT5_QUEUE5_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT5_QUEUE5_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT5_QUEUE6_WFQ_WEIGHT 0x033a ++#define RTL8367C_SCHEDULE_PORT5_QUEUE6_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT5_QUEUE6_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT5_QUEUE7_WFQ_WEIGHT 0x033b ++#define RTL8367C_SCHEDULE_PORT5_QUEUE7_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT5_QUEUE7_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT6_QUEUE0_WFQ_WEIGHT 0x033c ++ ++#define RTL8367C_REG_SCHEDULE_PORT6_QUEUE1_WFQ_WEIGHT 0x033d ++#define RTL8367C_SCHEDULE_PORT6_QUEUE1_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT6_QUEUE1_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT6_QUEUE2_WFQ_WEIGHT 0x033e ++#define RTL8367C_SCHEDULE_PORT6_QUEUE2_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT6_QUEUE2_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT6_QUEUE3_WFQ_WEIGHT 0x033f ++#define RTL8367C_SCHEDULE_PORT6_QUEUE3_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT6_QUEUE3_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT6_QUEUE4_WFQ_WEIGHT 0x0340 ++#define RTL8367C_SCHEDULE_PORT6_QUEUE4_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT6_QUEUE4_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT6_QUEUE5_WFQ_WEIGHT 0x0341 ++#define RTL8367C_SCHEDULE_PORT6_QUEUE5_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT6_QUEUE5_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT6_QUEUE6_WFQ_WEIGHT 0x0342 ++#define RTL8367C_SCHEDULE_PORT6_QUEUE6_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT6_QUEUE6_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT6_QUEUE7_WFQ_WEIGHT 0x0343 ++#define RTL8367C_SCHEDULE_PORT6_QUEUE7_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT6_QUEUE7_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT7_QUEUE0_WFQ_WEIGHT 0x0344 ++ ++#define RTL8367C_REG_SCHEDULE_PORT7_QUEUE1_WFQ_WEIGHT 0x0345 ++#define RTL8367C_SCHEDULE_PORT7_QUEUE1_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT7_QUEUE1_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT7_QUEUE2_WFQ_WEIGHT 0x0346 ++#define RTL8367C_SCHEDULE_PORT7_QUEUE2_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT7_QUEUE2_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT7_QUEUE3_WFQ_WEIGHT 0x0347 ++#define RTL8367C_SCHEDULE_PORT7_QUEUE3_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT7_QUEUE3_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT7_QUEUE4_WFQ_WEIGHT 0x0348 ++#define RTL8367C_SCHEDULE_PORT7_QUEUE4_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT7_QUEUE4_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT7_QUEUE5_WFQ_WEIGHT 0x0349 ++#define RTL8367C_SCHEDULE_PORT7_QUEUE5_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT7_QUEUE5_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT7_QUEUE6_WFQ_WEIGHT 0x034a ++#define RTL8367C_SCHEDULE_PORT7_QUEUE6_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT7_QUEUE6_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT7_QUEUE7_WFQ_WEIGHT 0x034b ++#define RTL8367C_SCHEDULE_PORT7_QUEUE7_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT7_QUEUE7_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT8_QUEUE0_WFQ_WEIGHT 0x034c ++ ++#define RTL8367C_REG_SCHEDULE_PORT8_QUEUE1_WFQ_WEIGHT 0x034d ++#define RTL8367C_SCHEDULE_PORT8_QUEUE1_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT8_QUEUE1_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT8_QUEUE2_WFQ_WEIGHT 0x034e ++#define RTL8367C_SCHEDULE_PORT8_QUEUE2_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT8_QUEUE2_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT8_QUEUE3_WFQ_WEIGHT 0x034f ++#define RTL8367C_SCHEDULE_PORT8_QUEUE3_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT8_QUEUE3_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT8_QUEUE4_WFQ_WEIGHT 0x0350 ++#define RTL8367C_SCHEDULE_PORT8_QUEUE4_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT8_QUEUE4_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT8_QUEUE5_WFQ_WEIGHT 0x0351 ++#define RTL8367C_SCHEDULE_PORT8_QUEUE5_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT8_QUEUE5_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT8_QUEUE6_WFQ_WEIGHT 0x0352 ++#define RTL8367C_SCHEDULE_PORT8_QUEUE6_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT8_QUEUE6_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT8_QUEUE7_WFQ_WEIGHT 0x0353 ++#define RTL8367C_SCHEDULE_PORT8_QUEUE7_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT8_QUEUE7_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT9_QUEUE0_WFQ_WEIGHT 0x0354 ++ ++#define RTL8367C_REG_SCHEDULE_PORT9_QUEUE1_WFQ_WEIGHT 0x0355 ++#define RTL8367C_SCHEDULE_PORT9_QUEUE1_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT9_QUEUE1_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT9_QUEUE2_WFQ_WEIGHT 0x0356 ++#define RTL8367C_SCHEDULE_PORT9_QUEUE2_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT9_QUEUE2_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT9_QUEUE3_WFQ_WEIGHT 0x0357 ++#define RTL8367C_SCHEDULE_PORT9_QUEUE3_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT9_QUEUE3_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT9_QUEUE4_WFQ_WEIGHT 0x0358 ++#define RTL8367C_SCHEDULE_PORT9_QUEUE4_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT9_QUEUE4_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT9_QUEUE5_WFQ_WEIGHT 0x0359 ++#define RTL8367C_SCHEDULE_PORT9_QUEUE5_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT9_QUEUE5_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT9_QUEUE6_WFQ_WEIGHT 0x035a ++#define RTL8367C_SCHEDULE_PORT9_QUEUE6_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT9_QUEUE6_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT9_QUEUE7_WFQ_WEIGHT 0x035b ++#define RTL8367C_SCHEDULE_PORT9_QUEUE7_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT9_QUEUE7_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT10_QUEUE0_WFQ_WEIGHT 0x035c ++ ++#define RTL8367C_REG_SCHEDULE_PORT10_QUEUE1_WFQ_WEIGHT 0x035d ++#define RTL8367C_SCHEDULE_PORT10_QUEUE1_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT10_QUEUE1_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT10_QUEUE2_WFQ_WEIGHT 0x035e ++#define RTL8367C_SCHEDULE_PORT10_QUEUE2_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT10_QUEUE2_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT10_QUEUE3_WFQ_WEIGHT 0x035f ++#define RTL8367C_SCHEDULE_PORT10_QUEUE3_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT10_QUEUE3_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT10_QUEUE4_WFQ_WEIGHT 0x0360 ++#define RTL8367C_SCHEDULE_PORT10_QUEUE4_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT10_QUEUE4_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT10_QUEUE5_WFQ_WEIGHT 0x0361 ++#define RTL8367C_SCHEDULE_PORT10_QUEUE5_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT10_QUEUE5_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT10_QUEUE6_WFQ_WEIGHT 0x0362 ++#define RTL8367C_SCHEDULE_PORT10_QUEUE6_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT10_QUEUE6_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_SCHEDULE_PORT10_QUEUE7_WFQ_WEIGHT 0x0363 ++#define RTL8367C_SCHEDULE_PORT10_QUEUE7_WFQ_WEIGHT_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT10_QUEUE7_WFQ_WEIGHT_MASK 0x7F ++ ++#define RTL8367C_REG_PORT0_EGRESSBW_CTRL0 0x038c ++ ++#define RTL8367C_REG_PORT0_EGRESSBW_CTRL1 0x038d ++#define RTL8367C_PORT0_EGRESSBW_CTRL1_OFFSET 0 ++#define RTL8367C_PORT0_EGRESSBW_CTRL1_MASK 0x1 ++ ++#define RTL8367C_REG_PORT1_EGRESSBW_CTRL0 0x038e ++ ++#define RTL8367C_REG_PORT1_EGRESSBW_CTRL1 0x038f ++#define RTL8367C_PORT1_EGRESSBW_CTRL1_OFFSET 0 ++#define RTL8367C_PORT1_EGRESSBW_CTRL1_MASK 0x1 ++ ++#define RTL8367C_REG_PORT2_EGRESSBW_CTRL0 0x0390 ++ ++#define RTL8367C_REG_PORT2_EGRESSBW_CTRL1 0x0391 ++#define RTL8367C_PORT2_EGRESSBW_CTRL1_OFFSET 0 ++#define RTL8367C_PORT2_EGRESSBW_CTRL1_MASK 0x1 ++ ++#define RTL8367C_REG_PORT3_EGRESSBW_CTRL0 0x0392 ++ ++#define RTL8367C_REG_PORT3_EGRESSBW_CTRL1 0x0393 ++#define RTL8367C_PORT3_EGRESSBW_CTRL1_OFFSET 0 ++#define RTL8367C_PORT3_EGRESSBW_CTRL1_MASK 0x1 ++ ++#define RTL8367C_REG_PORT4_EGRESSBW_CTRL0 0x0394 ++ ++#define RTL8367C_REG_PORT4_EGRESSBW_CTRL1 0x0395 ++#define RTL8367C_PORT4_EGRESSBW_CTRL1_OFFSET 0 ++#define RTL8367C_PORT4_EGRESSBW_CTRL1_MASK 0x1 ++ ++#define RTL8367C_REG_PORT5_EGRESSBW_CTRL0 0x0396 ++ ++#define RTL8367C_REG_PORT5_EGRESSBW_CTRL1 0x0397 ++#define RTL8367C_PORT5_EGRESSBW_CTRL1_OFFSET 0 ++#define RTL8367C_PORT5_EGRESSBW_CTRL1_MASK 0x1 ++ ++#define RTL8367C_REG_PORT6_EGRESSBW_CTRL0 0x0398 ++ ++#define RTL8367C_REG_PORT6_EGRESSBW_CTRL1 0x0399 ++#define RTL8367C_PORT6_EGRESSBW_CTRL1_OFFSET 0 ++#define RTL8367C_PORT6_EGRESSBW_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_PORT7_EGRESSBW_CTRL0 0x039a ++ ++#define RTL8367C_REG_PORT7_EGRESSBW_CTRL1 0x039b ++#define RTL8367C_PORT7_EGRESSBW_CTRL1_OFFSET 0 ++#define RTL8367C_PORT7_EGRESSBW_CTRL1_MASK 0x1 ++ ++#define RTL8367C_REG_PORT8_EGRESSBW_CTRL0 0x039c ++ ++#define RTL8367C_REG_PORT8_EGRESSBW_CTRL1 0x039d ++#define RTL8367C_PORT8_EGRESSBW_CTRL1_OFFSET 0 ++#define RTL8367C_PORT8_EGRESSBW_CTRL1_MASK 0x1 ++ ++#define RTL8367C_REG_PORT9_EGRESSBW_CTRL0 0x039e ++ ++#define RTL8367C_REG_PORT9_EGRESSBW_CTRL1 0x039f ++#define RTL8367C_PORT9_EGRESSBW_CTRL1_OFFSET 0 ++#define RTL8367C_PORT9_EGRESSBW_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_PORT10_EGRESSBW_CTRL0 0x03a0 ++ ++#define RTL8367C_REG_PORT10_EGRESSBW_CTRL1 0x03a1 ++#define RTL8367C_PORT10_EGRESSBW_CTRL1_OFFSET 0 ++#define RTL8367C_PORT10_EGRESSBW_CTRL1_MASK 0x1 ++ ++#define RTL8367C_REG_SCHEDULE_PORT0_APR_METER_CTRL0 0x03ac ++#define RTL8367C_SCHEDULE_PORT0_APR_METER_CTRL0_QUEUE4_APR_METER_OFFSET 12 ++#define RTL8367C_SCHEDULE_PORT0_APR_METER_CTRL0_QUEUE4_APR_METER_MASK 0x7000 ++#define RTL8367C_SCHEDULE_PORT0_APR_METER_CTRL0_QUEUE3_APR_METER_OFFSET 9 ++#define RTL8367C_SCHEDULE_PORT0_APR_METER_CTRL0_QUEUE3_APR_METER_MASK 0xE00 ++#define RTL8367C_SCHEDULE_PORT0_APR_METER_CTRL0_QUEUE2_APR_METER_OFFSET 6 ++#define RTL8367C_SCHEDULE_PORT0_APR_METER_CTRL0_QUEUE2_APR_METER_MASK 0x1C0 ++#define RTL8367C_SCHEDULE_PORT0_APR_METER_CTRL0_QUEUE1_APR_METER_OFFSET 3 ++#define RTL8367C_SCHEDULE_PORT0_APR_METER_CTRL0_QUEUE1_APR_METER_MASK 0x38 ++#define RTL8367C_SCHEDULE_PORT0_APR_METER_CTRL0_QUEUE0_APR_METER_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT0_APR_METER_CTRL0_QUEUE0_APR_METER_MASK 0x7 ++ ++#define RTL8367C_REG_SCHEDULE_PORT0_APR_METER_CTRL1 0x03ad ++#define RTL8367C_SCHEDULE_PORT0_APR_METER_CTRL1_QUEUE7_APR_METER_OFFSET 6 ++#define RTL8367C_SCHEDULE_PORT0_APR_METER_CTRL1_QUEUE7_APR_METER_MASK 0x1C0 ++#define RTL8367C_SCHEDULE_PORT0_APR_METER_CTRL1_QUEUE6_APR_METER_OFFSET 3 ++#define RTL8367C_SCHEDULE_PORT0_APR_METER_CTRL1_QUEUE6_APR_METER_MASK 0x38 ++#define RTL8367C_SCHEDULE_PORT0_APR_METER_CTRL1_QUEUE5_APR_METER_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT0_APR_METER_CTRL1_QUEUE5_APR_METER_MASK 0x7 ++ ++#define RTL8367C_REG_SCHEDULE_PORT1_APR_METER_CTRL0 0x03b0 ++#define RTL8367C_SCHEDULE_PORT1_APR_METER_CTRL0_QUEUE4_APR_METER_OFFSET 12 ++#define RTL8367C_SCHEDULE_PORT1_APR_METER_CTRL0_QUEUE4_APR_METER_MASK 0x7000 ++#define RTL8367C_SCHEDULE_PORT1_APR_METER_CTRL0_QUEUE3_APR_METER_OFFSET 9 ++#define RTL8367C_SCHEDULE_PORT1_APR_METER_CTRL0_QUEUE3_APR_METER_MASK 0xE00 ++#define RTL8367C_SCHEDULE_PORT1_APR_METER_CTRL0_QUEUE2_APR_METER_OFFSET 6 ++#define RTL8367C_SCHEDULE_PORT1_APR_METER_CTRL0_QUEUE2_APR_METER_MASK 0x1C0 ++#define RTL8367C_SCHEDULE_PORT1_APR_METER_CTRL0_QUEUE1_APR_METER_OFFSET 3 ++#define RTL8367C_SCHEDULE_PORT1_APR_METER_CTRL0_QUEUE1_APR_METER_MASK 0x38 ++#define RTL8367C_SCHEDULE_PORT1_APR_METER_CTRL0_QUEUE0_APR_METER_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT1_APR_METER_CTRL0_QUEUE0_APR_METER_MASK 0x7 ++ ++#define RTL8367C_REG_SCHEDULE_PORT1_APR_METER_CTRL1 0x03b1 ++#define RTL8367C_SCHEDULE_PORT1_APR_METER_CTRL1_QUEUE7_APR_METER_OFFSET 6 ++#define RTL8367C_SCHEDULE_PORT1_APR_METER_CTRL1_QUEUE7_APR_METER_MASK 0x1C0 ++#define RTL8367C_SCHEDULE_PORT1_APR_METER_CTRL1_QUEUE6_APR_METER_OFFSET 3 ++#define RTL8367C_SCHEDULE_PORT1_APR_METER_CTRL1_QUEUE6_APR_METER_MASK 0x38 ++#define RTL8367C_SCHEDULE_PORT1_APR_METER_CTRL1_QUEUE5_APR_METER_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT1_APR_METER_CTRL1_QUEUE5_APR_METER_MASK 0x7 ++ ++#define RTL8367C_REG_SCHEDULE_PORT2_APR_METER_CTRL0 0x03b4 ++#define RTL8367C_SCHEDULE_PORT2_APR_METER_CTRL0_QUEUE4_APR_METER_OFFSET 12 ++#define RTL8367C_SCHEDULE_PORT2_APR_METER_CTRL0_QUEUE4_APR_METER_MASK 0x7000 ++#define RTL8367C_SCHEDULE_PORT2_APR_METER_CTRL0_QUEUE3_APR_METER_OFFSET 9 ++#define RTL8367C_SCHEDULE_PORT2_APR_METER_CTRL0_QUEUE3_APR_METER_MASK 0xE00 ++#define RTL8367C_SCHEDULE_PORT2_APR_METER_CTRL0_QUEUE2_APR_METER_OFFSET 6 ++#define RTL8367C_SCHEDULE_PORT2_APR_METER_CTRL0_QUEUE2_APR_METER_MASK 0x1C0 ++#define RTL8367C_SCHEDULE_PORT2_APR_METER_CTRL0_QUEUE1_APR_METER_OFFSET 3 ++#define RTL8367C_SCHEDULE_PORT2_APR_METER_CTRL0_QUEUE1_APR_METER_MASK 0x38 ++#define RTL8367C_SCHEDULE_PORT2_APR_METER_CTRL0_QUEUE0_APR_METER_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT2_APR_METER_CTRL0_QUEUE0_APR_METER_MASK 0x7 ++ ++#define RTL8367C_REG_SCHEDULE_PORT2_APR_METER_CTRL1 0x03b5 ++#define RTL8367C_SCHEDULE_PORT2_APR_METER_CTRL1_QUEUE7_APR_METER_OFFSET 6 ++#define RTL8367C_SCHEDULE_PORT2_APR_METER_CTRL1_QUEUE7_APR_METER_MASK 0x1C0 ++#define RTL8367C_SCHEDULE_PORT2_APR_METER_CTRL1_QUEUE6_APR_METER_OFFSET 3 ++#define RTL8367C_SCHEDULE_PORT2_APR_METER_CTRL1_QUEUE6_APR_METER_MASK 0x38 ++#define RTL8367C_SCHEDULE_PORT2_APR_METER_CTRL1_QUEUE5_APR_METER_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT2_APR_METER_CTRL1_QUEUE5_APR_METER_MASK 0x7 ++ ++#define RTL8367C_REG_SCHEDULE_PORT3_APR_METER_CTRL0 0x03b8 ++#define RTL8367C_SCHEDULE_PORT3_APR_METER_CTRL0_QUEUE4_APR_METER_OFFSET 12 ++#define RTL8367C_SCHEDULE_PORT3_APR_METER_CTRL0_QUEUE4_APR_METER_MASK 0x7000 ++#define RTL8367C_SCHEDULE_PORT3_APR_METER_CTRL0_QUEUE3_APR_METER_OFFSET 9 ++#define RTL8367C_SCHEDULE_PORT3_APR_METER_CTRL0_QUEUE3_APR_METER_MASK 0xE00 ++#define RTL8367C_SCHEDULE_PORT3_APR_METER_CTRL0_QUEUE2_APR_METER_OFFSET 6 ++#define RTL8367C_SCHEDULE_PORT3_APR_METER_CTRL0_QUEUE2_APR_METER_MASK 0x1C0 ++#define RTL8367C_SCHEDULE_PORT3_APR_METER_CTRL0_QUEUE1_APR_METER_OFFSET 3 ++#define RTL8367C_SCHEDULE_PORT3_APR_METER_CTRL0_QUEUE1_APR_METER_MASK 0x38 ++#define RTL8367C_SCHEDULE_PORT3_APR_METER_CTRL0_QUEUE0_APR_METER_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT3_APR_METER_CTRL0_QUEUE0_APR_METER_MASK 0x7 ++ ++#define RTL8367C_REG_SCHEDULE_PORT3_APR_METER_CTRL1 0x03b9 ++#define RTL8367C_SCHEDULE_PORT3_APR_METER_CTRL1_QUEUE7_APR_METER_OFFSET 6 ++#define RTL8367C_SCHEDULE_PORT3_APR_METER_CTRL1_QUEUE7_APR_METER_MASK 0x1C0 ++#define RTL8367C_SCHEDULE_PORT3_APR_METER_CTRL1_QUEUE6_APR_METER_OFFSET 3 ++#define RTL8367C_SCHEDULE_PORT3_APR_METER_CTRL1_QUEUE6_APR_METER_MASK 0x38 ++#define RTL8367C_SCHEDULE_PORT3_APR_METER_CTRL1_QUEUE5_APR_METER_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT3_APR_METER_CTRL1_QUEUE5_APR_METER_MASK 0x7 ++ ++#define RTL8367C_REG_SCHEDULE_PORT4_APR_METER_CTRL0 0x03bc ++#define RTL8367C_SCHEDULE_PORT4_APR_METER_CTRL0_QUEUE4_APR_METER_OFFSET 12 ++#define RTL8367C_SCHEDULE_PORT4_APR_METER_CTRL0_QUEUE4_APR_METER_MASK 0x7000 ++#define RTL8367C_SCHEDULE_PORT4_APR_METER_CTRL0_QUEUE3_APR_METER_OFFSET 9 ++#define RTL8367C_SCHEDULE_PORT4_APR_METER_CTRL0_QUEUE3_APR_METER_MASK 0xE00 ++#define RTL8367C_SCHEDULE_PORT4_APR_METER_CTRL0_QUEUE2_APR_METER_OFFSET 6 ++#define RTL8367C_SCHEDULE_PORT4_APR_METER_CTRL0_QUEUE2_APR_METER_MASK 0x1C0 ++#define RTL8367C_SCHEDULE_PORT4_APR_METER_CTRL0_QUEUE1_APR_METER_OFFSET 3 ++#define RTL8367C_SCHEDULE_PORT4_APR_METER_CTRL0_QUEUE1_APR_METER_MASK 0x38 ++#define RTL8367C_SCHEDULE_PORT4_APR_METER_CTRL0_QUEUE0_APR_METER_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT4_APR_METER_CTRL0_QUEUE0_APR_METER_MASK 0x7 ++ ++#define RTL8367C_REG_SCHEDULE_PORT4_APR_METER_CTRL1 0x03bd ++#define RTL8367C_SCHEDULE_PORT4_APR_METER_CTRL1_QUEUE7_APR_METER_OFFSET 6 ++#define RTL8367C_SCHEDULE_PORT4_APR_METER_CTRL1_QUEUE7_APR_METER_MASK 0x1C0 ++#define RTL8367C_SCHEDULE_PORT4_APR_METER_CTRL1_QUEUE6_APR_METER_OFFSET 3 ++#define RTL8367C_SCHEDULE_PORT4_APR_METER_CTRL1_QUEUE6_APR_METER_MASK 0x38 ++#define RTL8367C_SCHEDULE_PORT4_APR_METER_CTRL1_QUEUE5_APR_METER_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT4_APR_METER_CTRL1_QUEUE5_APR_METER_MASK 0x7 ++ ++#define RTL8367C_REG_SCHEDULE_PORT5_APR_METER_CTRL0 0x03c0 ++#define RTL8367C_SCHEDULE_PORT5_APR_METER_CTRL0_QUEUE4_APR_METER_OFFSET 12 ++#define RTL8367C_SCHEDULE_PORT5_APR_METER_CTRL0_QUEUE4_APR_METER_MASK 0x7000 ++#define RTL8367C_SCHEDULE_PORT5_APR_METER_CTRL0_QUEUE3_APR_METER_OFFSET 9 ++#define RTL8367C_SCHEDULE_PORT5_APR_METER_CTRL0_QUEUE3_APR_METER_MASK 0xE00 ++#define RTL8367C_SCHEDULE_PORT5_APR_METER_CTRL0_QUEUE2_APR_METER_OFFSET 6 ++#define RTL8367C_SCHEDULE_PORT5_APR_METER_CTRL0_QUEUE2_APR_METER_MASK 0x1C0 ++#define RTL8367C_SCHEDULE_PORT5_APR_METER_CTRL0_QUEUE1_APR_METER_OFFSET 3 ++#define RTL8367C_SCHEDULE_PORT5_APR_METER_CTRL0_QUEUE1_APR_METER_MASK 0x38 ++#define RTL8367C_SCHEDULE_PORT5_APR_METER_CTRL0_QUEUE0_APR_METER_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT5_APR_METER_CTRL0_QUEUE0_APR_METER_MASK 0x7 ++ ++#define RTL8367C_REG_SCHEDULE_PORT5_APR_METER_CTRL1 0x03c1 ++#define RTL8367C_SCHEDULE_PORT5_APR_METER_CTRL1_QUEUE7_APR_METER_OFFSET 6 ++#define RTL8367C_SCHEDULE_PORT5_APR_METER_CTRL1_QUEUE7_APR_METER_MASK 0x1C0 ++#define RTL8367C_SCHEDULE_PORT5_APR_METER_CTRL1_QUEUE6_APR_METER_OFFSET 3 ++#define RTL8367C_SCHEDULE_PORT5_APR_METER_CTRL1_QUEUE6_APR_METER_MASK 0x38 ++#define RTL8367C_SCHEDULE_PORT5_APR_METER_CTRL1_QUEUE5_APR_METER_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT5_APR_METER_CTRL1_QUEUE5_APR_METER_MASK 0x7 ++ ++#define RTL8367C_REG_SCHEDULE_PORT6_APR_METER_CTRL0 0x03c4 ++#define RTL8367C_SCHEDULE_PORT6_APR_METER_CTRL0_QUEUE4_APR_METER_OFFSET 12 ++#define RTL8367C_SCHEDULE_PORT6_APR_METER_CTRL0_QUEUE4_APR_METER_MASK 0x7000 ++#define RTL8367C_SCHEDULE_PORT6_APR_METER_CTRL0_QUEUE3_APR_METER_OFFSET 9 ++#define RTL8367C_SCHEDULE_PORT6_APR_METER_CTRL0_QUEUE3_APR_METER_MASK 0xE00 ++#define RTL8367C_SCHEDULE_PORT6_APR_METER_CTRL0_QUEUE2_APR_METER_OFFSET 6 ++#define RTL8367C_SCHEDULE_PORT6_APR_METER_CTRL0_QUEUE2_APR_METER_MASK 0x1C0 ++#define RTL8367C_SCHEDULE_PORT6_APR_METER_CTRL0_QUEUE1_APR_METER_OFFSET 3 ++#define RTL8367C_SCHEDULE_PORT6_APR_METER_CTRL0_QUEUE1_APR_METER_MASK 0x38 ++#define RTL8367C_SCHEDULE_PORT6_APR_METER_CTRL0_QUEUE0_APR_METER_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT6_APR_METER_CTRL0_QUEUE0_APR_METER_MASK 0x7 ++ ++#define RTL8367C_REG_SCHEDULE_PORT6_APR_METER_CTRL1 0x03c5 ++#define RTL8367C_SCHEDULE_PORT6_APR_METER_CTRL1_QUEUE7_APR_METER_OFFSET 6 ++#define RTL8367C_SCHEDULE_PORT6_APR_METER_CTRL1_QUEUE7_APR_METER_MASK 0x1C0 ++#define RTL8367C_SCHEDULE_PORT6_APR_METER_CTRL1_QUEUE6_APR_METER_OFFSET 3 ++#define RTL8367C_SCHEDULE_PORT6_APR_METER_CTRL1_QUEUE6_APR_METER_MASK 0x38 ++#define RTL8367C_SCHEDULE_PORT6_APR_METER_CTRL1_QUEUE5_APR_METER_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT6_APR_METER_CTRL1_QUEUE5_APR_METER_MASK 0x7 ++ ++#define RTL8367C_REG_SCHEDULE_PORT7_APR_METER_CTRL0 0x03c8 ++#define RTL8367C_SCHEDULE_PORT7_APR_METER_CTRL0_QUEUE4_APR_METER_OFFSET 12 ++#define RTL8367C_SCHEDULE_PORT7_APR_METER_CTRL0_QUEUE4_APR_METER_MASK 0x7000 ++#define RTL8367C_SCHEDULE_PORT7_APR_METER_CTRL0_QUEUE3_APR_METER_OFFSET 9 ++#define RTL8367C_SCHEDULE_PORT7_APR_METER_CTRL0_QUEUE3_APR_METER_MASK 0xE00 ++#define RTL8367C_SCHEDULE_PORT7_APR_METER_CTRL0_QUEUE2_APR_METER_OFFSET 6 ++#define RTL8367C_SCHEDULE_PORT7_APR_METER_CTRL0_QUEUE2_APR_METER_MASK 0x1C0 ++#define RTL8367C_SCHEDULE_PORT7_APR_METER_CTRL0_QUEUE1_APR_METER_OFFSET 3 ++#define RTL8367C_SCHEDULE_PORT7_APR_METER_CTRL0_QUEUE1_APR_METER_MASK 0x38 ++#define RTL8367C_SCHEDULE_PORT7_APR_METER_CTRL0_QUEUE0_APR_METER_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT7_APR_METER_CTRL0_QUEUE0_APR_METER_MASK 0x7 ++ ++#define RTL8367C_REG_SCHEDULE_PORT7_APR_METER_CTRL1 0x03c9 ++#define RTL8367C_SCHEDULE_PORT7_APR_METER_CTRL1_QUEUE7_APR_METER_OFFSET 6 ++#define RTL8367C_SCHEDULE_PORT7_APR_METER_CTRL1_QUEUE7_APR_METER_MASK 0x1C0 ++#define RTL8367C_SCHEDULE_PORT7_APR_METER_CTRL1_QUEUE6_APR_METER_OFFSET 3 ++#define RTL8367C_SCHEDULE_PORT7_APR_METER_CTRL1_QUEUE6_APR_METER_MASK 0x38 ++#define RTL8367C_SCHEDULE_PORT7_APR_METER_CTRL1_QUEUE5_APR_METER_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT7_APR_METER_CTRL1_QUEUE5_APR_METER_MASK 0x7 ++ ++#define RTL8367C_REG_SCHEDULE_PORT8_APR_METER_CTRL0 0x03ca ++#define RTL8367C_SCHEDULE_PORT8_APR_METER_CTRL0_QUEUE4_APR_METER_OFFSET 12 ++#define RTL8367C_SCHEDULE_PORT8_APR_METER_CTRL0_QUEUE4_APR_METER_MASK 0x7000 ++#define RTL8367C_SCHEDULE_PORT8_APR_METER_CTRL0_QUEUE3_APR_METER_OFFSET 9 ++#define RTL8367C_SCHEDULE_PORT8_APR_METER_CTRL0_QUEUE3_APR_METER_MASK 0xE00 ++#define RTL8367C_SCHEDULE_PORT8_APR_METER_CTRL0_QUEUE2_APR_METER_OFFSET 6 ++#define RTL8367C_SCHEDULE_PORT8_APR_METER_CTRL0_QUEUE2_APR_METER_MASK 0x1C0 ++#define RTL8367C_SCHEDULE_PORT8_APR_METER_CTRL0_QUEUE1_APR_METER_OFFSET 3 ++#define RTL8367C_SCHEDULE_PORT8_APR_METER_CTRL0_QUEUE1_APR_METER_MASK 0x38 ++#define RTL8367C_SCHEDULE_PORT8_APR_METER_CTRL0_QUEUE0_APR_METER_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT8_APR_METER_CTRL0_QUEUE0_APR_METER_MASK 0x7 ++ ++#define RTL8367C_REG_SCHEDULE_PORT8_APR_METER_CTRL1 0x03cb ++#define RTL8367C_SCHEDULE_PORT8_APR_METER_CTRL1_QUEUE7_APR_METER_OFFSET 6 ++#define RTL8367C_SCHEDULE_PORT8_APR_METER_CTRL1_QUEUE7_APR_METER_MASK 0x1C0 ++#define RTL8367C_SCHEDULE_PORT8_APR_METER_CTRL1_QUEUE6_APR_METER_OFFSET 3 ++#define RTL8367C_SCHEDULE_PORT8_APR_METER_CTRL1_QUEUE6_APR_METER_MASK 0x38 ++#define RTL8367C_SCHEDULE_PORT8_APR_METER_CTRL1_QUEUE5_APR_METER_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT8_APR_METER_CTRL1_QUEUE5_APR_METER_MASK 0x7 ++ ++#define RTL8367C_REG_SCHEDULE_PORT9_APR_METER_CTRL0 0x03cc ++#define RTL8367C_SCHEDULE_PORT9_APR_METER_CTRL0_QUEUE4_APR_METER_OFFSET 12 ++#define RTL8367C_SCHEDULE_PORT9_APR_METER_CTRL0_QUEUE4_APR_METER_MASK 0x7000 ++#define RTL8367C_SCHEDULE_PORT9_APR_METER_CTRL0_QUEUE3_APR_METER_OFFSET 9 ++#define RTL8367C_SCHEDULE_PORT9_APR_METER_CTRL0_QUEUE3_APR_METER_MASK 0xE00 ++#define RTL8367C_SCHEDULE_PORT9_APR_METER_CTRL0_QUEUE2_APR_METER_OFFSET 6 ++#define RTL8367C_SCHEDULE_PORT9_APR_METER_CTRL0_QUEUE2_APR_METER_MASK 0x1C0 ++#define RTL8367C_SCHEDULE_PORT9_APR_METER_CTRL0_QUEUE1_APR_METER_OFFSET 3 ++#define RTL8367C_SCHEDULE_PORT9_APR_METER_CTRL0_QUEUE1_APR_METER_MASK 0x38 ++#define RTL8367C_SCHEDULE_PORT9_APR_METER_CTRL0_QUEUE0_APR_METER_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT9_APR_METER_CTRL0_QUEUE0_APR_METER_MASK 0x7 ++ ++#define RTL8367C_REG_SCHEDULE_PORT9_APR_METER_CTRL1 0x03cd ++#define RTL8367C_SCHEDULE_PORT9_APR_METER_CTRL1_QUEUE7_APR_METER_OFFSET 6 ++#define RTL8367C_SCHEDULE_PORT9_APR_METER_CTRL1_QUEUE7_APR_METER_MASK 0x1C0 ++#define RTL8367C_SCHEDULE_PORT9_APR_METER_CTRL1_QUEUE6_APR_METER_OFFSET 3 ++#define RTL8367C_SCHEDULE_PORT9_APR_METER_CTRL1_QUEUE6_APR_METER_MASK 0x38 ++#define RTL8367C_SCHEDULE_PORT9_APR_METER_CTRL1_QUEUE5_APR_METER_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT9_APR_METER_CTRL1_QUEUE5_APR_METER_MASK 0x7 ++ ++#define RTL8367C_REG_SCHEDULE_PORT10_APR_METER_CTRL0 0x03ce ++#define RTL8367C_SCHEDULE_PORT10_APR_METER_CTRL0_QUEUE4_APR_METER_OFFSET 12 ++#define RTL8367C_SCHEDULE_PORT10_APR_METER_CTRL0_QUEUE4_APR_METER_MASK 0x7000 ++#define RTL8367C_SCHEDULE_PORT10_APR_METER_CTRL0_QUEUE3_APR_METER_OFFSET 9 ++#define RTL8367C_SCHEDULE_PORT10_APR_METER_CTRL0_QUEUE3_APR_METER_MASK 0xE00 ++#define RTL8367C_SCHEDULE_PORT10_APR_METER_CTRL0_QUEUE2_APR_METER_OFFSET 6 ++#define RTL8367C_SCHEDULE_PORT10_APR_METER_CTRL0_QUEUE2_APR_METER_MASK 0x1C0 ++#define RTL8367C_SCHEDULE_PORT10_APR_METER_CTRL0_QUEUE1_APR_METER_OFFSET 3 ++#define RTL8367C_SCHEDULE_PORT10_APR_METER_CTRL0_QUEUE1_APR_METER_MASK 0x38 ++#define RTL8367C_SCHEDULE_PORT10_APR_METER_CTRL0_QUEUE0_APR_METER_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT10_APR_METER_CTRL0_QUEUE0_APR_METER_MASK 0x7 ++ ++#define RTL8367C_REG_SCHEDULE_PORT10_APR_METER_CTRL1 0x03cf ++#define RTL8367C_SCHEDULE_PORT10_APR_METER_CTRL1_QUEUE7_APR_METER_OFFSET 6 ++#define RTL8367C_SCHEDULE_PORT10_APR_METER_CTRL1_QUEUE7_APR_METER_MASK 0x1C0 ++#define RTL8367C_SCHEDULE_PORT10_APR_METER_CTRL1_QUEUE6_APR_METER_OFFSET 3 ++#define RTL8367C_SCHEDULE_PORT10_APR_METER_CTRL1_QUEUE6_APR_METER_MASK 0x38 ++#define RTL8367C_SCHEDULE_PORT10_APR_METER_CTRL1_QUEUE5_APR_METER_OFFSET 0 ++#define RTL8367C_SCHEDULE_PORT10_APR_METER_CTRL1_QUEUE5_APR_METER_MASK 0x7 ++ ++#define RTL8367C_REG_LINE_RATE_1G_L 0x03ec ++ ++#define RTL8367C_REG_LINE_RATE_1G_H 0x03ed ++#define RTL8367C_LINE_RATE_1G_H_OFFSET 0 ++#define RTL8367C_LINE_RATE_1G_H_MASK 0x1 ++ ++#define RTL8367C_REG_LINE_RATE_100_L 0x03ee ++ ++#define RTL8367C_REG_LINE_RATE_100_H 0x03ef ++#define RTL8367C_LINE_RATE_100_H_OFFSET 0 ++#define RTL8367C_LINE_RATE_100_H_MASK 0x1 ++ ++#define RTL8367C_REG_LINE_RATE_10_L 0x03f0 ++ ++#define RTL8367C_REG_LINE_RATE_10_H 0x03f1 ++#define RTL8367C_LINE_RATE_10_H_OFFSET 0 ++#define RTL8367C_LINE_RATE_10_H_MASK 0x1 ++ ++#define RTL8367C_REG_DUMMY_03f2 0x03f2 ++ ++#define RTL8367C_REG_DUMMY_03f3 0x03f3 ++ ++#define RTL8367C_REG_DUMMY_03f4 0x03f4 ++ ++#define RTL8367C_REG_DUMMY_03f5 0x03f5 ++ ++#define RTL8367C_REG_DUMMY_03f6 0x03f6 ++ ++#define RTL8367C_REG_BYPASS_LINE_RATE 0x03f7 ++#define RTL8367C_BYPASS_PORT10_CONSTRAINT_OFFSET 5 ++#define RTL8367C_BYPASS_PORT10_CONSTRAINT_MASK 0x20 ++#define RTL8367C_BYPASS_PORT9_CONSTRAINT_OFFSET 4 ++#define RTL8367C_BYPASS_PORT9_CONSTRAINT_MASK 0x10 ++#define RTL8367C_BYPASS_PORT8_CONSTRAINT_OFFSET 3 ++#define RTL8367C_BYPASS_PORT8_CONSTRAINT_MASK 0x8 ++#define RTL8367C_BYPASS_PORT7_CONSTRAINT_OFFSET 2 ++#define RTL8367C_BYPASS_PORT7_CONSTRAINT_MASK 0x4 ++#define RTL8367C_BYPASS_PORT6_CONSTRAINT_OFFSET 1 ++#define RTL8367C_BYPASS_PORT6_CONSTRAINT_MASK 0x2 ++#define RTL8367C_BYPASS_PORT5_CONSTRAINT_OFFSET 0 ++#define RTL8367C_BYPASS_PORT5_CONSTRAINT_MASK 0x1 ++ ++#define RTL8367C_REG_LINE_RATE_500_H 0x03f8 ++#define RTL8367C_LINE_RATE_500_H_OFFSET 0 ++#define RTL8367C_LINE_RATE_500_H_MASK 0x7 ++ ++#define RTL8367C_REG_LINE_RATE_500_L 0x03f9 ++ ++#define RTL8367C_REG_LINE_RATE_HSG_H 0x03fa ++#define RTL8367C_LINE_RATE_HSG_H_OFFSET 0 ++#define RTL8367C_LINE_RATE_HSG_H_MASK 0x7 ++ ++#define RTL8367C_REG_LINE_RATE_HSG_L 0x03fb ++ ++/* (16'h0500)table_reg */ ++ ++#define RTL8367C_REG_TABLE_ACCESS_CTRL 0x0500 ++#define RTL8367C_TABLE_ACCESS_CTRL_SPA_OFFSET 8 ++#define RTL8367C_TABLE_ACCESS_CTRL_SPA_MASK 0xF00 ++#define RTL8367C_ACCESS_METHOD_OFFSET 4 ++#define RTL8367C_ACCESS_METHOD_MASK 0x70 ++#define RTL8367C_COMMAND_TYPE_OFFSET 3 ++#define RTL8367C_COMMAND_TYPE_MASK 0x8 ++#define RTL8367C_TABLE_TYPE_OFFSET 0 ++#define RTL8367C_TABLE_TYPE_MASK 0x7 ++ ++#define RTL8367C_REG_TABLE_ACCESS_ADDR 0x0501 ++#define RTL8367C_TABLE_ACCESS_ADDR_OFFSET 0 ++#define RTL8367C_TABLE_ACCESS_ADDR_MASK 0x1FFF ++ ++#define RTL8367C_REG_TABLE_LUT_ADDR 0x0502 ++#define RTL8367C_ADDRESS2_OFFSET 14 ++#define RTL8367C_ADDRESS2_MASK 0x4000 ++#define RTL8367C_TABLE_LUT_ADDR_BUSY_FLAG_OFFSET 13 ++#define RTL8367C_TABLE_LUT_ADDR_BUSY_FLAG_MASK 0x2000 ++#define RTL8367C_HIT_STATUS_OFFSET 12 ++#define RTL8367C_HIT_STATUS_MASK 0x1000 ++#define RTL8367C_TABLE_LUT_ADDR_TYPE_OFFSET 11 ++#define RTL8367C_TABLE_LUT_ADDR_TYPE_MASK 0x800 ++#define RTL8367C_TABLE_LUT_ADDR_ADDRESS_OFFSET 0 ++#define RTL8367C_TABLE_LUT_ADDR_ADDRESS_MASK 0x7FF ++ ++#define RTL8367C_REG_HSA_HSB_LATCH 0x0503 ++#define RTL8367C_LATCH_ALWAYS_OFFSET 15 ++#define RTL8367C_LATCH_ALWAYS_MASK 0x8000 ++#define RTL8367C_LATCH_FIRST_OFFSET 14 ++#define RTL8367C_LATCH_FIRST_MASK 0x4000 ++#define RTL8367C_SPA_EN_OFFSET 13 ++#define RTL8367C_SPA_EN_MASK 0x2000 ++#define RTL8367C_FORWARD_EN_OFFSET 12 ++#define RTL8367C_FORWARD_EN_MASK 0x1000 ++#define RTL8367C_REASON_EN_OFFSET 11 ++#define RTL8367C_REASON_EN_MASK 0x800 ++#define RTL8367C_HSA_HSB_LATCH_SPA_OFFSET 8 ++#define RTL8367C_HSA_HSB_LATCH_SPA_MASK 0x700 ++#define RTL8367C_FORWARD_OFFSET 6 ++#define RTL8367C_FORWARD_MASK 0xC0 ++#define RTL8367C_REASON_OFFSET 0 ++#define RTL8367C_REASON_MASK 0x3F ++ ++#define RTL8367C_REG_HSA_HSB_LATCH2 0x0504 ++#define RTL8367C_HSA_HSB_LATCH2_Reserved_OFFSET 1 ++#define RTL8367C_HSA_HSB_LATCH2_Reserved_MASK 0xFFFE ++#define RTL8367C_SPA2_OFFSET 0 ++#define RTL8367C_SPA2_MASK 0x1 ++ ++#define RTL8367C_REG_TABLE_WRITE_DATA0 0x0510 ++ ++#define RTL8367C_REG_TABLE_WRITE_DATA1 0x0511 ++ ++#define RTL8367C_REG_TABLE_WRITE_DATA2 0x0512 ++ ++#define RTL8367C_REG_TABLE_WRITE_DATA3 0x0513 ++ ++#define RTL8367C_REG_TABLE_WRITE_DATA4 0x0514 ++ ++#define RTL8367C_REG_TABLE_WRITE_DATA5 0x0515 ++ ++#define RTL8367C_REG_TABLE_WRITE_DATA6 0x0516 ++ ++#define RTL8367C_REG_TABLE_WRITE_DATA7 0x0517 ++ ++#define RTL8367C_REG_TABLE_WRITE_DATA8 0x0518 ++ ++#define RTL8367C_REG_TABLE_WRITE_DATA9 0x0519 ++#define RTL8367C_TABLE_WRITE_DATA9_OFFSET 0 ++#define RTL8367C_TABLE_WRITE_DATA9_MASK 0xF ++ ++#define RTL8367C_REG_TABLE_READ_DATA0 0x0520 ++ ++#define RTL8367C_REG_TABLE_READ_DATA1 0x0521 ++ ++#define RTL8367C_REG_TABLE_READ_DATA2 0x0522 ++ ++#define RTL8367C_REG_TABLE_READ_DATA3 0x0523 ++ ++#define RTL8367C_REG_TABLE_READ_DATA4 0x0524 ++ ++#define RTL8367C_REG_TABLE_READ_DATA5 0x0525 ++ ++#define RTL8367C_REG_TABLE_READ_DATA6 0x0526 ++ ++#define RTL8367C_REG_TABLE_READ_DATA7 0x0527 ++ ++#define RTL8367C_REG_TABLE_READ_DATA8 0x0528 ++ ++#define RTL8367C_REG_TABLE_READ_DATA9 0x0529 ++#define RTL8367C_TABLE_READ_DATA9_OFFSET 0 ++#define RTL8367C_TABLE_READ_DATA9_MASK 0xF ++ ++#define RTL8367C_REG_TBL_DUMMY00 0x0550 ++ ++#define RTL8367C_REG_TBL_DUMMY01 0x0551 ++ ++/* (16'h0600)acl_reg */ ++ ++#define RTL8367C_REG_ACL_RULE_TEMPLATE0_CTRL0 0x0600 ++#define RTL8367C_ACL_RULE_TEMPLATE0_CTRL0_FIELD1_OFFSET 8 ++#define RTL8367C_ACL_RULE_TEMPLATE0_CTRL0_FIELD1_MASK 0x7F00 ++#define RTL8367C_ACL_RULE_TEMPLATE0_CTRL0_FIELD0_OFFSET 0 ++#define RTL8367C_ACL_RULE_TEMPLATE0_CTRL0_FIELD0_MASK 0x7F ++ ++#define RTL8367C_REG_ACL_RULE_TEMPLATE0_CTRL1 0x0601 ++#define RTL8367C_ACL_RULE_TEMPLATE0_CTRL1_FIELD3_OFFSET 8 ++#define RTL8367C_ACL_RULE_TEMPLATE0_CTRL1_FIELD3_MASK 0x7F00 ++#define RTL8367C_ACL_RULE_TEMPLATE0_CTRL1_FIELD2_OFFSET 0 ++#define RTL8367C_ACL_RULE_TEMPLATE0_CTRL1_FIELD2_MASK 0x7F ++ ++#define RTL8367C_REG_ACL_RULE_TEMPLATE0_CTRL2 0x0602 ++#define RTL8367C_ACL_RULE_TEMPLATE0_CTRL2_FIELD5_OFFSET 8 ++#define RTL8367C_ACL_RULE_TEMPLATE0_CTRL2_FIELD5_MASK 0x7F00 ++#define RTL8367C_ACL_RULE_TEMPLATE0_CTRL2_FIELD4_OFFSET 0 ++#define RTL8367C_ACL_RULE_TEMPLATE0_CTRL2_FIELD4_MASK 0x7F ++ ++#define RTL8367C_REG_ACL_RULE_TEMPLATE0_CTRL3 0x0603 ++#define RTL8367C_ACL_RULE_TEMPLATE0_CTRL3_FIELD7_OFFSET 8 ++#define RTL8367C_ACL_RULE_TEMPLATE0_CTRL3_FIELD7_MASK 0x7F00 ++#define RTL8367C_ACL_RULE_TEMPLATE0_CTRL3_FIELD6_OFFSET 0 ++#define RTL8367C_ACL_RULE_TEMPLATE0_CTRL3_FIELD6_MASK 0x7F ++ ++#define RTL8367C_REG_ACL_RULE_TEMPLATE1_CTRL0 0x0604 ++#define RTL8367C_ACL_RULE_TEMPLATE1_CTRL0_FIELD1_OFFSET 8 ++#define RTL8367C_ACL_RULE_TEMPLATE1_CTRL0_FIELD1_MASK 0x7F00 ++#define RTL8367C_ACL_RULE_TEMPLATE1_CTRL0_FIELD0_OFFSET 0 ++#define RTL8367C_ACL_RULE_TEMPLATE1_CTRL0_FIELD0_MASK 0x7F ++ ++#define RTL8367C_REG_ACL_RULE_TEMPLATE1_CTRL1 0x0605 ++#define RTL8367C_ACL_RULE_TEMPLATE1_CTRL1_FIELD3_OFFSET 8 ++#define RTL8367C_ACL_RULE_TEMPLATE1_CTRL1_FIELD3_MASK 0x7F00 ++#define RTL8367C_ACL_RULE_TEMPLATE1_CTRL1_FIELD2_OFFSET 0 ++#define RTL8367C_ACL_RULE_TEMPLATE1_CTRL1_FIELD2_MASK 0x7F ++ ++#define RTL8367C_REG_ACL_RULE_TEMPLATE1_CTRL2 0x0606 ++#define RTL8367C_ACL_RULE_TEMPLATE1_CTRL2_FIELD5_OFFSET 8 ++#define RTL8367C_ACL_RULE_TEMPLATE1_CTRL2_FIELD5_MASK 0x7F00 ++#define RTL8367C_ACL_RULE_TEMPLATE1_CTRL2_FIELD4_OFFSET 0 ++#define RTL8367C_ACL_RULE_TEMPLATE1_CTRL2_FIELD4_MASK 0x7F ++ ++#define RTL8367C_REG_ACL_RULE_TEMPLATE1_CTRL3 0x0607 ++#define RTL8367C_ACL_RULE_TEMPLATE1_CTRL3_FIELD7_OFFSET 8 ++#define RTL8367C_ACL_RULE_TEMPLATE1_CTRL3_FIELD7_MASK 0x7F00 ++#define RTL8367C_ACL_RULE_TEMPLATE1_CTRL3_FIELD6_OFFSET 0 ++#define RTL8367C_ACL_RULE_TEMPLATE1_CTRL3_FIELD6_MASK 0x7F ++ ++#define RTL8367C_REG_ACL_RULE_TEMPLATE2_CTRL0 0x0608 ++#define RTL8367C_ACL_RULE_TEMPLATE2_CTRL0_FIELD1_OFFSET 8 ++#define RTL8367C_ACL_RULE_TEMPLATE2_CTRL0_FIELD1_MASK 0x7F00 ++#define RTL8367C_ACL_RULE_TEMPLATE2_CTRL0_FIELD0_OFFSET 0 ++#define RTL8367C_ACL_RULE_TEMPLATE2_CTRL0_FIELD0_MASK 0x7F ++ ++#define RTL8367C_REG_ACL_RULE_TEMPLATE2_CTRL1 0x0609 ++#define RTL8367C_ACL_RULE_TEMPLATE2_CTRL1_FIELD3_OFFSET 8 ++#define RTL8367C_ACL_RULE_TEMPLATE2_CTRL1_FIELD3_MASK 0x7F00 ++#define RTL8367C_ACL_RULE_TEMPLATE2_CTRL1_FIELD2_OFFSET 0 ++#define RTL8367C_ACL_RULE_TEMPLATE2_CTRL1_FIELD2_MASK 0x7F ++ ++#define RTL8367C_REG_ACL_RULE_TEMPLATE2_CTRL2 0x060a ++#define RTL8367C_ACL_RULE_TEMPLATE2_CTRL2_FIELD5_OFFSET 8 ++#define RTL8367C_ACL_RULE_TEMPLATE2_CTRL2_FIELD5_MASK 0x7F00 ++#define RTL8367C_ACL_RULE_TEMPLATE2_CTRL2_FIELD4_OFFSET 0 ++#define RTL8367C_ACL_RULE_TEMPLATE2_CTRL2_FIELD4_MASK 0x7F ++ ++#define RTL8367C_REG_ACL_RULE_TEMPLATE2_CTRL3 0x060b ++#define RTL8367C_ACL_RULE_TEMPLATE2_CTRL3_FIELD7_OFFSET 8 ++#define RTL8367C_ACL_RULE_TEMPLATE2_CTRL3_FIELD7_MASK 0x7F00 ++#define RTL8367C_ACL_RULE_TEMPLATE2_CTRL3_FIELD6_OFFSET 0 ++#define RTL8367C_ACL_RULE_TEMPLATE2_CTRL3_FIELD6_MASK 0x7F ++ ++#define RTL8367C_REG_ACL_RULE_TEMPLATE3_CTRL0 0x060c ++#define RTL8367C_ACL_RULE_TEMPLATE3_CTRL0_FIELD1_OFFSET 8 ++#define RTL8367C_ACL_RULE_TEMPLATE3_CTRL0_FIELD1_MASK 0x7F00 ++#define RTL8367C_ACL_RULE_TEMPLATE3_CTRL0_FIELD0_OFFSET 0 ++#define RTL8367C_ACL_RULE_TEMPLATE3_CTRL0_FIELD0_MASK 0x7F ++ ++#define RTL8367C_REG_ACL_RULE_TEMPLATE3_CTRL1 0x060d ++#define RTL8367C_ACL_RULE_TEMPLATE3_CTRL1_FIELD3_OFFSET 8 ++#define RTL8367C_ACL_RULE_TEMPLATE3_CTRL1_FIELD3_MASK 0x7F00 ++#define RTL8367C_ACL_RULE_TEMPLATE3_CTRL1_FIELD2_OFFSET 0 ++#define RTL8367C_ACL_RULE_TEMPLATE3_CTRL1_FIELD2_MASK 0x7F ++ ++#define RTL8367C_REG_ACL_RULE_TEMPLATE3_CTRL2 0x060e ++#define RTL8367C_ACL_RULE_TEMPLATE3_CTRL2_FIELD5_OFFSET 8 ++#define RTL8367C_ACL_RULE_TEMPLATE3_CTRL2_FIELD5_MASK 0x7F00 ++#define RTL8367C_ACL_RULE_TEMPLATE3_CTRL2_FIELD4_OFFSET 0 ++#define RTL8367C_ACL_RULE_TEMPLATE3_CTRL2_FIELD4_MASK 0x7F ++ ++#define RTL8367C_REG_ACL_RULE_TEMPLATE3_CTRL3 0x060f ++#define RTL8367C_ACL_RULE_TEMPLATE3_CTRL3_FIELD7_OFFSET 8 ++#define RTL8367C_ACL_RULE_TEMPLATE3_CTRL3_FIELD7_MASK 0x7F00 ++#define RTL8367C_ACL_RULE_TEMPLATE3_CTRL3_FIELD6_OFFSET 0 ++#define RTL8367C_ACL_RULE_TEMPLATE3_CTRL3_FIELD6_MASK 0x7F ++ ++#define RTL8367C_REG_ACL_RULE_TEMPLATE4_CTRL0 0x0610 ++#define RTL8367C_ACL_RULE_TEMPLATE4_CTRL0_FIELD1_OFFSET 8 ++#define RTL8367C_ACL_RULE_TEMPLATE4_CTRL0_FIELD1_MASK 0x7F00 ++#define RTL8367C_ACL_RULE_TEMPLATE4_CTRL0_FIELD0_OFFSET 0 ++#define RTL8367C_ACL_RULE_TEMPLATE4_CTRL0_FIELD0_MASK 0x7F ++ ++#define RTL8367C_REG_ACL_RULE_TEMPLATE4_CTRL1 0x0611 ++#define RTL8367C_ACL_RULE_TEMPLATE4_CTRL1_FIELD3_OFFSET 8 ++#define RTL8367C_ACL_RULE_TEMPLATE4_CTRL1_FIELD3_MASK 0x7F00 ++#define RTL8367C_ACL_RULE_TEMPLATE4_CTRL1_FIELD2_OFFSET 0 ++#define RTL8367C_ACL_RULE_TEMPLATE4_CTRL1_FIELD2_MASK 0x7F ++ ++#define RTL8367C_REG_ACL_RULE_TEMPLATE4_CTRL2 0x0612 ++#define RTL8367C_ACL_RULE_TEMPLATE4_CTRL2_FIELD5_OFFSET 8 ++#define RTL8367C_ACL_RULE_TEMPLATE4_CTRL2_FIELD5_MASK 0x7F00 ++#define RTL8367C_ACL_RULE_TEMPLATE4_CTRL2_FIELD4_OFFSET 0 ++#define RTL8367C_ACL_RULE_TEMPLATE4_CTRL2_FIELD4_MASK 0x7F ++ ++#define RTL8367C_REG_ACL_RULE_TEMPLATE4_CTRL3 0x0613 ++#define RTL8367C_ACL_RULE_TEMPLATE4_CTRL3_FIELD7_OFFSET 8 ++#define RTL8367C_ACL_RULE_TEMPLATE4_CTRL3_FIELD7_MASK 0x7F00 ++#define RTL8367C_ACL_RULE_TEMPLATE4_CTRL3_FIELD6_OFFSET 0 ++#define RTL8367C_ACL_RULE_TEMPLATE4_CTRL3_FIELD6_MASK 0x7F ++ ++#define RTL8367C_REG_ACL_ACTION_CTRL0 0x0614 ++#define RTL8367C_OP1_NOT_OFFSET 14 ++#define RTL8367C_OP1_NOT_MASK 0x4000 ++#define RTL8367C_ACT1_GPIO_OFFSET 13 ++#define RTL8367C_ACT1_GPIO_MASK 0x2000 ++#define RTL8367C_ACT1_FORWARD_OFFSET 12 ++#define RTL8367C_ACT1_FORWARD_MASK 0x1000 ++#define RTL8367C_ACT1_POLICING_OFFSET 11 ++#define RTL8367C_ACT1_POLICING_MASK 0x800 ++#define RTL8367C_ACT1_PRIORITY_OFFSET 10 ++#define RTL8367C_ACT1_PRIORITY_MASK 0x400 ++#define RTL8367C_ACT1_SVID_OFFSET 9 ++#define RTL8367C_ACT1_SVID_MASK 0x200 ++#define RTL8367C_ACT1_CVID_OFFSET 8 ++#define RTL8367C_ACT1_CVID_MASK 0x100 ++#define RTL8367C_OP0_NOT_OFFSET 6 ++#define RTL8367C_OP0_NOT_MASK 0x40 ++#define RTL8367C_ACT0_GPIO_OFFSET 5 ++#define RTL8367C_ACT0_GPIO_MASK 0x20 ++#define RTL8367C_ACT0_FORWARD_OFFSET 4 ++#define RTL8367C_ACT0_FORWARD_MASK 0x10 ++#define RTL8367C_ACT0_POLICING_OFFSET 3 ++#define RTL8367C_ACT0_POLICING_MASK 0x8 ++#define RTL8367C_ACT0_PRIORITY_OFFSET 2 ++#define RTL8367C_ACT0_PRIORITY_MASK 0x4 ++#define RTL8367C_ACT0_SVID_OFFSET 1 ++#define RTL8367C_ACT0_SVID_MASK 0x2 ++#define RTL8367C_ACT0_CVID_OFFSET 0 ++#define RTL8367C_ACT0_CVID_MASK 0x1 ++ ++#define RTL8367C_REG_ACL_ACTION_CTRL1 0x0615 ++#define RTL8367C_OP3_NOT_OFFSET 14 ++#define RTL8367C_OP3_NOT_MASK 0x4000 ++#define RTL8367C_ACT3_GPIO_OFFSET 13 ++#define RTL8367C_ACT3_GPIO_MASK 0x2000 ++#define RTL8367C_ACT3_FORWARD_OFFSET 12 ++#define RTL8367C_ACT3_FORWARD_MASK 0x1000 ++#define RTL8367C_ACT3_POLICING_OFFSET 11 ++#define RTL8367C_ACT3_POLICING_MASK 0x800 ++#define RTL8367C_ACT3_PRIORITY_OFFSET 10 ++#define RTL8367C_ACT3_PRIORITY_MASK 0x400 ++#define RTL8367C_ACT3_SVID_OFFSET 9 ++#define RTL8367C_ACT3_SVID_MASK 0x200 ++#define RTL8367C_ACT3_CVID_OFFSET 8 ++#define RTL8367C_ACT3_CVID_MASK 0x100 ++#define RTL8367C_OP2_NOT_OFFSET 6 ++#define RTL8367C_OP2_NOT_MASK 0x40 ++#define RTL8367C_ACT2_GPIO_OFFSET 5 ++#define RTL8367C_ACT2_GPIO_MASK 0x20 ++#define RTL8367C_ACT2_FORWARD_OFFSET 4 ++#define RTL8367C_ACT2_FORWARD_MASK 0x10 ++#define RTL8367C_ACT2_POLICING_OFFSET 3 ++#define RTL8367C_ACT2_POLICING_MASK 0x8 ++#define RTL8367C_ACT2_PRIORITY_OFFSET 2 ++#define RTL8367C_ACT2_PRIORITY_MASK 0x4 ++#define RTL8367C_ACT2_SVID_OFFSET 1 ++#define RTL8367C_ACT2_SVID_MASK 0x2 ++#define RTL8367C_ACT2_CVID_OFFSET 0 ++#define RTL8367C_ACT2_CVID_MASK 0x1 ++ ++#define RTL8367C_REG_ACL_ACTION_CTRL2 0x0616 ++#define RTL8367C_OP5_NOT_OFFSET 14 ++#define RTL8367C_OP5_NOT_MASK 0x4000 ++#define RTL8367C_ACT5_GPIO_OFFSET 13 ++#define RTL8367C_ACT5_GPIO_MASK 0x2000 ++#define RTL8367C_ACT5_FORWARD_OFFSET 12 ++#define RTL8367C_ACT5_FORWARD_MASK 0x1000 ++#define RTL8367C_ACT5_POLICING_OFFSET 11 ++#define RTL8367C_ACT5_POLICING_MASK 0x800 ++#define RTL8367C_ACT5_PRIORITY_OFFSET 10 ++#define RTL8367C_ACT5_PRIORITY_MASK 0x400 ++#define RTL8367C_ACT5_SVID_OFFSET 9 ++#define RTL8367C_ACT5_SVID_MASK 0x200 ++#define RTL8367C_ACT5_CVID_OFFSET 8 ++#define RTL8367C_ACT5_CVID_MASK 0x100 ++#define RTL8367C_OP4_NOT_OFFSET 6 ++#define RTL8367C_OP4_NOT_MASK 0x40 ++#define RTL8367C_ACT4_GPIO_OFFSET 5 ++#define RTL8367C_ACT4_GPIO_MASK 0x20 ++#define RTL8367C_ACT4_FORWARD_OFFSET 4 ++#define RTL8367C_ACT4_FORWARD_MASK 0x10 ++#define RTL8367C_ACT4_POLICING_OFFSET 3 ++#define RTL8367C_ACT4_POLICING_MASK 0x8 ++#define RTL8367C_ACT4_PRIORITY_OFFSET 2 ++#define RTL8367C_ACT4_PRIORITY_MASK 0x4 ++#define RTL8367C_ACT4_SVID_OFFSET 1 ++#define RTL8367C_ACT4_SVID_MASK 0x2 ++#define RTL8367C_ACT4_CVID_OFFSET 0 ++#define RTL8367C_ACT4_CVID_MASK 0x1 ++ ++#define RTL8367C_REG_ACL_ACTION_CTRL3 0x0617 ++#define RTL8367C_OP7_NOT_OFFSET 14 ++#define RTL8367C_OP7_NOT_MASK 0x4000 ++#define RTL8367C_ACT7_GPIO_OFFSET 13 ++#define RTL8367C_ACT7_GPIO_MASK 0x2000 ++#define RTL8367C_ACT7_FORWARD_OFFSET 12 ++#define RTL8367C_ACT7_FORWARD_MASK 0x1000 ++#define RTL8367C_ACT7_POLICING_OFFSET 11 ++#define RTL8367C_ACT7_POLICING_MASK 0x800 ++#define RTL8367C_ACT7_PRIORITY_OFFSET 10 ++#define RTL8367C_ACT7_PRIORITY_MASK 0x400 ++#define RTL8367C_ACT7_SVID_OFFSET 9 ++#define RTL8367C_ACT7_SVID_MASK 0x200 ++#define RTL8367C_ACT7_CVID_OFFSET 8 ++#define RTL8367C_ACT7_CVID_MASK 0x100 ++#define RTL8367C_OP6_NOT_OFFSET 6 ++#define RTL8367C_OP6_NOT_MASK 0x40 ++#define RTL8367C_ACT6_GPIO_OFFSET 5 ++#define RTL8367C_ACT6_GPIO_MASK 0x20 ++#define RTL8367C_ACT6_FORWARD_OFFSET 4 ++#define RTL8367C_ACT6_FORWARD_MASK 0x10 ++#define RTL8367C_ACT6_POLICING_OFFSET 3 ++#define RTL8367C_ACT6_POLICING_MASK 0x8 ++#define RTL8367C_ACT6_PRIORITY_OFFSET 2 ++#define RTL8367C_ACT6_PRIORITY_MASK 0x4 ++#define RTL8367C_ACT6_SVID_OFFSET 1 ++#define RTL8367C_ACT6_SVID_MASK 0x2 ++#define RTL8367C_ACT6_CVID_OFFSET 0 ++#define RTL8367C_ACT6_CVID_MASK 0x1 ++ ++#define RTL8367C_REG_ACL_ACTION_CTRL4 0x0618 ++#define RTL8367C_OP9_NOT_OFFSET 14 ++#define RTL8367C_OP9_NOT_MASK 0x4000 ++#define RTL8367C_ACT9_GPIO_OFFSET 13 ++#define RTL8367C_ACT9_GPIO_MASK 0x2000 ++#define RTL8367C_ACT9_FORWARD_OFFSET 12 ++#define RTL8367C_ACT9_FORWARD_MASK 0x1000 ++#define RTL8367C_ACT9_POLICING_OFFSET 11 ++#define RTL8367C_ACT9_POLICING_MASK 0x800 ++#define RTL8367C_ACT9_PRIORITY_OFFSET 10 ++#define RTL8367C_ACT9_PRIORITY_MASK 0x400 ++#define RTL8367C_ACT9_SVID_OFFSET 9 ++#define RTL8367C_ACT9_SVID_MASK 0x200 ++#define RTL8367C_ACT9_CVID_OFFSET 8 ++#define RTL8367C_ACT9_CVID_MASK 0x100 ++#define RTL8367C_OP8_NOT_OFFSET 6 ++#define RTL8367C_OP8_NOT_MASK 0x40 ++#define RTL8367C_ACT8_GPIO_OFFSET 5 ++#define RTL8367C_ACT8_GPIO_MASK 0x20 ++#define RTL8367C_ACT8_FORWARD_OFFSET 4 ++#define RTL8367C_ACT8_FORWARD_MASK 0x10 ++#define RTL8367C_ACT8_POLICING_OFFSET 3 ++#define RTL8367C_ACT8_POLICING_MASK 0x8 ++#define RTL8367C_ACT8_PRIORITY_OFFSET 2 ++#define RTL8367C_ACT8_PRIORITY_MASK 0x4 ++#define RTL8367C_ACT8_SVID_OFFSET 1 ++#define RTL8367C_ACT8_SVID_MASK 0x2 ++#define RTL8367C_ACT8_CVID_OFFSET 0 ++#define RTL8367C_ACT8_CVID_MASK 0x1 ++ ++#define RTL8367C_REG_ACL_ACTION_CTRL5 0x0619 ++#define RTL8367C_OP11_NOT_OFFSET 14 ++#define RTL8367C_OP11_NOT_MASK 0x4000 ++#define RTL8367C_ACT11_GPIO_OFFSET 13 ++#define RTL8367C_ACT11_GPIO_MASK 0x2000 ++#define RTL8367C_ACT11_FORWARD_OFFSET 12 ++#define RTL8367C_ACT11_FORWARD_MASK 0x1000 ++#define RTL8367C_ACT11_POLICING_OFFSET 11 ++#define RTL8367C_ACT11_POLICING_MASK 0x800 ++#define RTL8367C_ACT11_PRIORITY_OFFSET 10 ++#define RTL8367C_ACT11_PRIORITY_MASK 0x400 ++#define RTL8367C_ACT11_SVID_OFFSET 9 ++#define RTL8367C_ACT11_SVID_MASK 0x200 ++#define RTL8367C_ACT11_CVID_OFFSET 8 ++#define RTL8367C_ACT11_CVID_MASK 0x100 ++#define RTL8367C_OP10_NOT_OFFSET 6 ++#define RTL8367C_OP10_NOT_MASK 0x40 ++#define RTL8367C_ACT10_GPIO_OFFSET 5 ++#define RTL8367C_ACT10_GPIO_MASK 0x20 ++#define RTL8367C_ACT10_FORWARD_OFFSET 4 ++#define RTL8367C_ACT10_FORWARD_MASK 0x10 ++#define RTL8367C_ACT10_POLICING_OFFSET 3 ++#define RTL8367C_ACT10_POLICING_MASK 0x8 ++#define RTL8367C_ACT10_PRIORITY_OFFSET 2 ++#define RTL8367C_ACT10_PRIORITY_MASK 0x4 ++#define RTL8367C_ACT10_SVID_OFFSET 1 ++#define RTL8367C_ACT10_SVID_MASK 0x2 ++#define RTL8367C_ACT10_CVID_OFFSET 0 ++#define RTL8367C_ACT10_CVID_MASK 0x1 ++ ++#define RTL8367C_REG_ACL_ACTION_CTRL6 0x061a ++#define RTL8367C_OP13_NOT_OFFSET 14 ++#define RTL8367C_OP13_NOT_MASK 0x4000 ++#define RTL8367C_ACT13_GPIO_OFFSET 13 ++#define RTL8367C_ACT13_GPIO_MASK 0x2000 ++#define RTL8367C_ACT13_FORWARD_OFFSET 12 ++#define RTL8367C_ACT13_FORWARD_MASK 0x1000 ++#define RTL8367C_ACT13_POLICING_OFFSET 11 ++#define RTL8367C_ACT13_POLICING_MASK 0x800 ++#define RTL8367C_ACT13_PRIORITY_OFFSET 10 ++#define RTL8367C_ACT13_PRIORITY_MASK 0x400 ++#define RTL8367C_ACT13_SVID_OFFSET 9 ++#define RTL8367C_ACT13_SVID_MASK 0x200 ++#define RTL8367C_ACT13_CVID_OFFSET 8 ++#define RTL8367C_ACT13_CVID_MASK 0x100 ++#define RTL8367C_OP12_NOT_OFFSET 6 ++#define RTL8367C_OP12_NOT_MASK 0x40 ++#define RTL8367C_ACT12_GPIO_OFFSET 5 ++#define RTL8367C_ACT12_GPIO_MASK 0x20 ++#define RTL8367C_ACT12_FORWARD_OFFSET 4 ++#define RTL8367C_ACT12_FORWARD_MASK 0x10 ++#define RTL8367C_ACT12_POLICING_OFFSET 3 ++#define RTL8367C_ACT12_POLICING_MASK 0x8 ++#define RTL8367C_ACT12_PRIORITY_OFFSET 2 ++#define RTL8367C_ACT12_PRIORITY_MASK 0x4 ++#define RTL8367C_ACT12_SVID_OFFSET 1 ++#define RTL8367C_ACT12_SVID_MASK 0x2 ++#define RTL8367C_ACT12_CVID_OFFSET 0 ++#define RTL8367C_ACT12_CVID_MASK 0x1 ++ ++#define RTL8367C_REG_ACL_ACTION_CTRL7 0x061b ++#define RTL8367C_OP15_NOT_OFFSET 14 ++#define RTL8367C_OP15_NOT_MASK 0x4000 ++#define RTL8367C_ACT15_GPIO_OFFSET 13 ++#define RTL8367C_ACT15_GPIO_MASK 0x2000 ++#define RTL8367C_ACT15_FORWARD_OFFSET 12 ++#define RTL8367C_ACT15_FORWARD_MASK 0x1000 ++#define RTL8367C_ACT15_POLICING_OFFSET 11 ++#define RTL8367C_ACT15_POLICING_MASK 0x800 ++#define RTL8367C_ACT15_PRIORITY_OFFSET 10 ++#define RTL8367C_ACT15_PRIORITY_MASK 0x400 ++#define RTL8367C_ACT15_SVID_OFFSET 9 ++#define RTL8367C_ACT15_SVID_MASK 0x200 ++#define RTL8367C_ACT15_CVID_OFFSET 8 ++#define RTL8367C_ACT15_CVID_MASK 0x100 ++#define RTL8367C_OP14_NOT_OFFSET 6 ++#define RTL8367C_OP14_NOT_MASK 0x40 ++#define RTL8367C_ACT14_GPIO_OFFSET 5 ++#define RTL8367C_ACT14_GPIO_MASK 0x20 ++#define RTL8367C_ACT14_FORWARD_OFFSET 4 ++#define RTL8367C_ACT14_FORWARD_MASK 0x10 ++#define RTL8367C_ACT14_POLICING_OFFSET 3 ++#define RTL8367C_ACT14_POLICING_MASK 0x8 ++#define RTL8367C_ACT14_PRIORITY_OFFSET 2 ++#define RTL8367C_ACT14_PRIORITY_MASK 0x4 ++#define RTL8367C_ACT14_SVID_OFFSET 1 ++#define RTL8367C_ACT14_SVID_MASK 0x2 ++#define RTL8367C_ACT14_CVID_OFFSET 0 ++#define RTL8367C_ACT14_CVID_MASK 0x1 ++ ++#define RTL8367C_REG_ACL_ACTION_CTRL8 0x061c ++#define RTL8367C_OP17_NOT_OFFSET 14 ++#define RTL8367C_OP17_NOT_MASK 0x4000 ++#define RTL8367C_ACT17_GPIO_OFFSET 13 ++#define RTL8367C_ACT17_GPIO_MASK 0x2000 ++#define RTL8367C_ACT17_FORWARD_OFFSET 12 ++#define RTL8367C_ACT17_FORWARD_MASK 0x1000 ++#define RTL8367C_ACT17_POLICING_OFFSET 11 ++#define RTL8367C_ACT17_POLICING_MASK 0x800 ++#define RTL8367C_ACT17_PRIORITY_OFFSET 10 ++#define RTL8367C_ACT17_PRIORITY_MASK 0x400 ++#define RTL8367C_ACT17_SVID_OFFSET 9 ++#define RTL8367C_ACT17_SVID_MASK 0x200 ++#define RTL8367C_ACT17_CVID_OFFSET 8 ++#define RTL8367C_ACT17_CVID_MASK 0x100 ++#define RTL8367C_OP16_NOT_OFFSET 6 ++#define RTL8367C_OP16_NOT_MASK 0x40 ++#define RTL8367C_ACT16_GPIO_OFFSET 5 ++#define RTL8367C_ACT16_GPIO_MASK 0x20 ++#define RTL8367C_ACT16_FORWARD_OFFSET 4 ++#define RTL8367C_ACT16_FORWARD_MASK 0x10 ++#define RTL8367C_ACT16_POLICING_OFFSET 3 ++#define RTL8367C_ACT16_POLICING_MASK 0x8 ++#define RTL8367C_ACT16_PRIORITY_OFFSET 2 ++#define RTL8367C_ACT16_PRIORITY_MASK 0x4 ++#define RTL8367C_ACT16_SVID_OFFSET 1 ++#define RTL8367C_ACT16_SVID_MASK 0x2 ++#define RTL8367C_ACT16_CVID_OFFSET 0 ++#define RTL8367C_ACT16_CVID_MASK 0x1 ++ ++#define RTL8367C_REG_ACL_ACTION_CTRL9 0x061d ++#define RTL8367C_OP19_NOT_OFFSET 14 ++#define RTL8367C_OP19_NOT_MASK 0x4000 ++#define RTL8367C_ACT19_GPIO_OFFSET 13 ++#define RTL8367C_ACT19_GPIO_MASK 0x2000 ++#define RTL8367C_ACT19_FORWARD_OFFSET 12 ++#define RTL8367C_ACT19_FORWARD_MASK 0x1000 ++#define RTL8367C_ACT19_POLICING_OFFSET 11 ++#define RTL8367C_ACT19_POLICING_MASK 0x800 ++#define RTL8367C_ACT19_PRIORITY_OFFSET 10 ++#define RTL8367C_ACT19_PRIORITY_MASK 0x400 ++#define RTL8367C_ACT19_SVID_OFFSET 9 ++#define RTL8367C_ACT19_SVID_MASK 0x200 ++#define RTL8367C_ACT19_CVID_OFFSET 8 ++#define RTL8367C_ACT19_CVID_MASK 0x100 ++#define RTL8367C_OP18_NOT_OFFSET 6 ++#define RTL8367C_OP18_NOT_MASK 0x40 ++#define RTL8367C_ACT18_GPIO_OFFSET 5 ++#define RTL8367C_ACT18_GPIO_MASK 0x20 ++#define RTL8367C_ACT18_FORWARD_OFFSET 4 ++#define RTL8367C_ACT18_FORWARD_MASK 0x10 ++#define RTL8367C_ACT18_POLICING_OFFSET 3 ++#define RTL8367C_ACT18_POLICING_MASK 0x8 ++#define RTL8367C_ACT18_PRIORITY_OFFSET 2 ++#define RTL8367C_ACT18_PRIORITY_MASK 0x4 ++#define RTL8367C_ACT18_SVID_OFFSET 1 ++#define RTL8367C_ACT18_SVID_MASK 0x2 ++#define RTL8367C_ACT18_CVID_OFFSET 0 ++#define RTL8367C_ACT18_CVID_MASK 0x1 ++ ++#define RTL8367C_REG_ACL_ACTION_CTRL10 0x061e ++#define RTL8367C_OP21_NOT_OFFSET 14 ++#define RTL8367C_OP21_NOT_MASK 0x4000 ++#define RTL8367C_ACT21_GPIO_OFFSET 13 ++#define RTL8367C_ACT21_GPIO_MASK 0x2000 ++#define RTL8367C_ACT21_FORWARD_OFFSET 12 ++#define RTL8367C_ACT21_FORWARD_MASK 0x1000 ++#define RTL8367C_ACT21_POLICING_OFFSET 11 ++#define RTL8367C_ACT21_POLICING_MASK 0x800 ++#define RTL8367C_ACT21_PRIORITY_OFFSET 10 ++#define RTL8367C_ACT21_PRIORITY_MASK 0x400 ++#define RTL8367C_ACT21_SVID_OFFSET 9 ++#define RTL8367C_ACT21_SVID_MASK 0x200 ++#define RTL8367C_ACT21_CVID_OFFSET 8 ++#define RTL8367C_ACT21_CVID_MASK 0x100 ++#define RTL8367C_OP20_NOT_OFFSET 6 ++#define RTL8367C_OP20_NOT_MASK 0x40 ++#define RTL8367C_ACT20_GPIO_OFFSET 5 ++#define RTL8367C_ACT20_GPIO_MASK 0x20 ++#define RTL8367C_ACT20_FORWARD_OFFSET 4 ++#define RTL8367C_ACT20_FORWARD_MASK 0x10 ++#define RTL8367C_ACT20_POLICING_OFFSET 3 ++#define RTL8367C_ACT20_POLICING_MASK 0x8 ++#define RTL8367C_ACT20_PRIORITY_OFFSET 2 ++#define RTL8367C_ACT20_PRIORITY_MASK 0x4 ++#define RTL8367C_ACT20_SVID_OFFSET 1 ++#define RTL8367C_ACT20_SVID_MASK 0x2 ++#define RTL8367C_ACT20_CVID_OFFSET 0 ++#define RTL8367C_ACT20_CVID_MASK 0x1 ++ ++#define RTL8367C_REG_ACL_ACTION_CTRL11 0x061f ++#define RTL8367C_OP23_NOT_OFFSET 14 ++#define RTL8367C_OP23_NOT_MASK 0x4000 ++#define RTL8367C_ACT23_GPIO_OFFSET 13 ++#define RTL8367C_ACT23_GPIO_MASK 0x2000 ++#define RTL8367C_ACT23_FORWARD_OFFSET 12 ++#define RTL8367C_ACT23_FORWARD_MASK 0x1000 ++#define RTL8367C_ACT23_POLICING_OFFSET 11 ++#define RTL8367C_ACT23_POLICING_MASK 0x800 ++#define RTL8367C_ACT23_PRIORITY_OFFSET 10 ++#define RTL8367C_ACT23_PRIORITY_MASK 0x400 ++#define RTL8367C_ACT23_SVID_OFFSET 9 ++#define RTL8367C_ACT23_SVID_MASK 0x200 ++#define RTL8367C_ACT23_CVID_OFFSET 8 ++#define RTL8367C_ACT23_CVID_MASK 0x100 ++#define RTL8367C_OP22_NOT_OFFSET 6 ++#define RTL8367C_OP22_NOT_MASK 0x40 ++#define RTL8367C_ACT22_GPIO_OFFSET 5 ++#define RTL8367C_ACT22_GPIO_MASK 0x20 ++#define RTL8367C_ACT22_FORWARD_OFFSET 4 ++#define RTL8367C_ACT22_FORWARD_MASK 0x10 ++#define RTL8367C_ACT22_POLICING_OFFSET 3 ++#define RTL8367C_ACT22_POLICING_MASK 0x8 ++#define RTL8367C_ACT22_PRIORITY_OFFSET 2 ++#define RTL8367C_ACT22_PRIORITY_MASK 0x4 ++#define RTL8367C_ACT22_SVID_OFFSET 1 ++#define RTL8367C_ACT22_SVID_MASK 0x2 ++#define RTL8367C_ACT22_CVID_OFFSET 0 ++#define RTL8367C_ACT22_CVID_MASK 0x1 ++ ++#define RTL8367C_REG_ACL_ACTION_CTRL12 0x0620 ++#define RTL8367C_OP25_NOT_OFFSET 14 ++#define RTL8367C_OP25_NOT_MASK 0x4000 ++#define RTL8367C_ACT25_GPIO_OFFSET 13 ++#define RTL8367C_ACT25_GPIO_MASK 0x2000 ++#define RTL8367C_ACT25_FORWARD_OFFSET 12 ++#define RTL8367C_ACT25_FORWARD_MASK 0x1000 ++#define RTL8367C_ACT25_POLICING_OFFSET 11 ++#define RTL8367C_ACT25_POLICING_MASK 0x800 ++#define RTL8367C_ACT25_PRIORITY_OFFSET 10 ++#define RTL8367C_ACT25_PRIORITY_MASK 0x400 ++#define RTL8367C_ACT25_SVID_OFFSET 9 ++#define RTL8367C_ACT25_SVID_MASK 0x200 ++#define RTL8367C_ACT25_CVID_OFFSET 8 ++#define RTL8367C_ACT25_CVID_MASK 0x100 ++#define RTL8367C_OP24_NOT_OFFSET 6 ++#define RTL8367C_OP24_NOT_MASK 0x40 ++#define RTL8367C_ACT24_GPIO_OFFSET 5 ++#define RTL8367C_ACT24_GPIO_MASK 0x20 ++#define RTL8367C_ACT24_FORWARD_OFFSET 4 ++#define RTL8367C_ACT24_FORWARD_MASK 0x10 ++#define RTL8367C_ACT24_POLICING_OFFSET 3 ++#define RTL8367C_ACT24_POLICING_MASK 0x8 ++#define RTL8367C_ACT24_PRIORITY_OFFSET 2 ++#define RTL8367C_ACT24_PRIORITY_MASK 0x4 ++#define RTL8367C_ACT24_SVID_OFFSET 1 ++#define RTL8367C_ACT24_SVID_MASK 0x2 ++#define RTL8367C_ACT24_CVID_OFFSET 0 ++#define RTL8367C_ACT24_CVID_MASK 0x1 ++ ++#define RTL8367C_REG_ACL_ACTION_CTRL13 0x0621 ++#define RTL8367C_OP27_NOT_OFFSET 14 ++#define RTL8367C_OP27_NOT_MASK 0x4000 ++#define RTL8367C_ACT27_GPIO_OFFSET 13 ++#define RTL8367C_ACT27_GPIO_MASK 0x2000 ++#define RTL8367C_ACT27_FORWARD_OFFSET 12 ++#define RTL8367C_ACT27_FORWARD_MASK 0x1000 ++#define RTL8367C_ACT27_POLICING_OFFSET 11 ++#define RTL8367C_ACT27_POLICING_MASK 0x800 ++#define RTL8367C_ACT27_PRIORITY_OFFSET 10 ++#define RTL8367C_ACT27_PRIORITY_MASK 0x400 ++#define RTL8367C_ACT27_SVID_OFFSET 9 ++#define RTL8367C_ACT27_SVID_MASK 0x200 ++#define RTL8367C_ACT27_CVID_OFFSET 8 ++#define RTL8367C_ACT27_CVID_MASK 0x100 ++#define RTL8367C_OP26_NOT_OFFSET 6 ++#define RTL8367C_OP26_NOT_MASK 0x40 ++#define RTL8367C_ACT26_GPIO_OFFSET 5 ++#define RTL8367C_ACT26_GPIO_MASK 0x20 ++#define RTL8367C_ACT26_FORWARD_OFFSET 4 ++#define RTL8367C_ACT26_FORWARD_MASK 0x10 ++#define RTL8367C_ACT26_POLICING_OFFSET 3 ++#define RTL8367C_ACT26_POLICING_MASK 0x8 ++#define RTL8367C_ACT26_PRIORITY_OFFSET 2 ++#define RTL8367C_ACT26_PRIORITY_MASK 0x4 ++#define RTL8367C_ACT26_SVID_OFFSET 1 ++#define RTL8367C_ACT26_SVID_MASK 0x2 ++#define RTL8367C_ACT26_CVID_OFFSET 0 ++#define RTL8367C_ACT26_CVID_MASK 0x1 ++ ++#define RTL8367C_REG_ACL_ACTION_CTRL14 0x0622 ++#define RTL8367C_OP29_NOT_OFFSET 14 ++#define RTL8367C_OP29_NOT_MASK 0x4000 ++#define RTL8367C_ACT29_GPIO_OFFSET 13 ++#define RTL8367C_ACT29_GPIO_MASK 0x2000 ++#define RTL8367C_ACT29_FORWARD_OFFSET 12 ++#define RTL8367C_ACT29_FORWARD_MASK 0x1000 ++#define RTL8367C_ACT29_POLICING_OFFSET 11 ++#define RTL8367C_ACT29_POLICING_MASK 0x800 ++#define RTL8367C_ACT29_PRIORITY_OFFSET 10 ++#define RTL8367C_ACT29_PRIORITY_MASK 0x400 ++#define RTL8367C_ACT29_SVID_OFFSET 9 ++#define RTL8367C_ACT29_SVID_MASK 0x200 ++#define RTL8367C_ACT29_CVID_OFFSET 8 ++#define RTL8367C_ACT29_CVID_MASK 0x100 ++#define RTL8367C_OP28_NOT_OFFSET 6 ++#define RTL8367C_OP28_NOT_MASK 0x40 ++#define RTL8367C_ACT28_GPIO_OFFSET 5 ++#define RTL8367C_ACT28_GPIO_MASK 0x20 ++#define RTL8367C_ACT28_FORWARD_OFFSET 4 ++#define RTL8367C_ACT28_FORWARD_MASK 0x10 ++#define RTL8367C_ACT28_POLICING_OFFSET 3 ++#define RTL8367C_ACT28_POLICING_MASK 0x8 ++#define RTL8367C_ACT28_PRIORITY_OFFSET 2 ++#define RTL8367C_ACT28_PRIORITY_MASK 0x4 ++#define RTL8367C_ACT28_SVID_OFFSET 1 ++#define RTL8367C_ACT28_SVID_MASK 0x2 ++#define RTL8367C_ACT28_CVID_OFFSET 0 ++#define RTL8367C_ACT28_CVID_MASK 0x1 ++ ++#define RTL8367C_REG_ACL_ACTION_CTRL15 0x0623 ++#define RTL8367C_OP31_NOT_OFFSET 14 ++#define RTL8367C_OP31_NOT_MASK 0x4000 ++#define RTL8367C_ACT31_GPIO_OFFSET 13 ++#define RTL8367C_ACT31_GPIO_MASK 0x2000 ++#define RTL8367C_ACT31_FORWARD_OFFSET 12 ++#define RTL8367C_ACT31_FORWARD_MASK 0x1000 ++#define RTL8367C_ACT31_POLICING_OFFSET 11 ++#define RTL8367C_ACT31_POLICING_MASK 0x800 ++#define RTL8367C_ACT31_PRIORITY_OFFSET 10 ++#define RTL8367C_ACT31_PRIORITY_MASK 0x400 ++#define RTL8367C_ACT31_SVID_OFFSET 9 ++#define RTL8367C_ACT31_SVID_MASK 0x200 ++#define RTL8367C_ACT31_CVID_OFFSET 8 ++#define RTL8367C_ACT31_CVID_MASK 0x100 ++#define RTL8367C_OP30_NOT_OFFSET 6 ++#define RTL8367C_OP30_NOT_MASK 0x40 ++#define RTL8367C_ACT30_GPIO_OFFSET 5 ++#define RTL8367C_ACT30_GPIO_MASK 0x20 ++#define RTL8367C_ACT30_FORWARD_OFFSET 4 ++#define RTL8367C_ACT30_FORWARD_MASK 0x10 ++#define RTL8367C_ACT30_POLICING_OFFSET 3 ++#define RTL8367C_ACT30_POLICING_MASK 0x8 ++#define RTL8367C_ACT30_PRIORITY_OFFSET 2 ++#define RTL8367C_ACT30_PRIORITY_MASK 0x4 ++#define RTL8367C_ACT30_SVID_OFFSET 1 ++#define RTL8367C_ACT30_SVID_MASK 0x2 ++#define RTL8367C_ACT30_CVID_OFFSET 0 ++#define RTL8367C_ACT30_CVID_MASK 0x1 ++ ++#define RTL8367C_REG_ACL_ACTION_CTRL16 0x0624 ++#define RTL8367C_OP33_NOT_OFFSET 14 ++#define RTL8367C_OP33_NOT_MASK 0x4000 ++#define RTL8367C_ACT33_GPIO_OFFSET 13 ++#define RTL8367C_ACT33_GPIO_MASK 0x2000 ++#define RTL8367C_ACT33_FORWARD_OFFSET 12 ++#define RTL8367C_ACT33_FORWARD_MASK 0x1000 ++#define RTL8367C_ACT33_POLICING_OFFSET 11 ++#define RTL8367C_ACT33_POLICING_MASK 0x800 ++#define RTL8367C_ACT33_PRIORITY_OFFSET 10 ++#define RTL8367C_ACT33_PRIORITY_MASK 0x400 ++#define RTL8367C_ACT33_SVID_OFFSET 9 ++#define RTL8367C_ACT33_SVID_MASK 0x200 ++#define RTL8367C_ACT33_CVID_OFFSET 8 ++#define RTL8367C_ACT33_CVID_MASK 0x100 ++#define RTL8367C_OP32_NOT_OFFSET 6 ++#define RTL8367C_OP32_NOT_MASK 0x40 ++#define RTL8367C_ACT32_GPIO_OFFSET 5 ++#define RTL8367C_ACT32_GPIO_MASK 0x20 ++#define RTL8367C_ACT32_FORWARD_OFFSET 4 ++#define RTL8367C_ACT32_FORWARD_MASK 0x10 ++#define RTL8367C_ACT32_POLICING_OFFSET 3 ++#define RTL8367C_ACT32_POLICING_MASK 0x8 ++#define RTL8367C_ACT32_PRIORITY_OFFSET 2 ++#define RTL8367C_ACT32_PRIORITY_MASK 0x4 ++#define RTL8367C_ACT32_SVID_OFFSET 1 ++#define RTL8367C_ACT32_SVID_MASK 0x2 ++#define RTL8367C_ACT32_CVID_OFFSET 0 ++#define RTL8367C_ACT32_CVID_MASK 0x1 ++ ++#define RTL8367C_REG_ACL_ACTION_CTRL17 0x0625 ++#define RTL8367C_OP35_NOT_OFFSET 14 ++#define RTL8367C_OP35_NOT_MASK 0x4000 ++#define RTL8367C_ACT35_GPIO_OFFSET 13 ++#define RTL8367C_ACT35_GPIO_MASK 0x2000 ++#define RTL8367C_ACT35_FORWARD_OFFSET 12 ++#define RTL8367C_ACT35_FORWARD_MASK 0x1000 ++#define RTL8367C_ACT35_POLICING_OFFSET 11 ++#define RTL8367C_ACT35_POLICING_MASK 0x800 ++#define RTL8367C_ACT35_PRIORITY_OFFSET 10 ++#define RTL8367C_ACT35_PRIORITY_MASK 0x400 ++#define RTL8367C_ACT35_SVID_OFFSET 9 ++#define RTL8367C_ACT35_SVID_MASK 0x200 ++#define RTL8367C_ACT35_CVID_OFFSET 8 ++#define RTL8367C_ACT35_CVID_MASK 0x100 ++#define RTL8367C_OP34_NOT_OFFSET 6 ++#define RTL8367C_OP34_NOT_MASK 0x40 ++#define RTL8367C_ACT34_GPIO_OFFSET 5 ++#define RTL8367C_ACT34_GPIO_MASK 0x20 ++#define RTL8367C_ACT34_FORWARD_OFFSET 4 ++#define RTL8367C_ACT34_FORWARD_MASK 0x10 ++#define RTL8367C_ACT34_POLICING_OFFSET 3 ++#define RTL8367C_ACT34_POLICING_MASK 0x8 ++#define RTL8367C_ACT34_PRIORITY_OFFSET 2 ++#define RTL8367C_ACT34_PRIORITY_MASK 0x4 ++#define RTL8367C_ACT34_SVID_OFFSET 1 ++#define RTL8367C_ACT34_SVID_MASK 0x2 ++#define RTL8367C_ACT34_CVID_OFFSET 0 ++#define RTL8367C_ACT34_CVID_MASK 0x1 ++ ++#define RTL8367C_REG_ACL_ACTION_CTRL18 0x0626 ++#define RTL8367C_OP37_NOT_OFFSET 14 ++#define RTL8367C_OP37_NOT_MASK 0x4000 ++#define RTL8367C_ACT37_GPIO_OFFSET 13 ++#define RTL8367C_ACT37_GPIO_MASK 0x2000 ++#define RTL8367C_ACT37_FORWARD_OFFSET 12 ++#define RTL8367C_ACT37_FORWARD_MASK 0x1000 ++#define RTL8367C_ACT37_POLICING_OFFSET 11 ++#define RTL8367C_ACT37_POLICING_MASK 0x800 ++#define RTL8367C_ACT37_PRIORITY_OFFSET 10 ++#define RTL8367C_ACT37_PRIORITY_MASK 0x400 ++#define RTL8367C_ACT37_SVID_OFFSET 9 ++#define RTL8367C_ACT37_SVID_MASK 0x200 ++#define RTL8367C_ACT37_CVID_OFFSET 8 ++#define RTL8367C_ACT37_CVID_MASK 0x100 ++#define RTL8367C_OP36_NOT_OFFSET 6 ++#define RTL8367C_OP36_NOT_MASK 0x40 ++#define RTL8367C_ACT36_GPIO_OFFSET 5 ++#define RTL8367C_ACT36_GPIO_MASK 0x20 ++#define RTL8367C_ACT36_FORWARD_OFFSET 4 ++#define RTL8367C_ACT36_FORWARD_MASK 0x10 ++#define RTL8367C_ACT36_POLICING_OFFSET 3 ++#define RTL8367C_ACT36_POLICING_MASK 0x8 ++#define RTL8367C_ACT36_PRIORITY_OFFSET 2 ++#define RTL8367C_ACT36_PRIORITY_MASK 0x4 ++#define RTL8367C_ACT36_SVID_OFFSET 1 ++#define RTL8367C_ACT36_SVID_MASK 0x2 ++#define RTL8367C_ACT36_CVID_OFFSET 0 ++#define RTL8367C_ACT36_CVID_MASK 0x1 ++ ++#define RTL8367C_REG_ACL_ACTION_CTRL19 0x0627 ++#define RTL8367C_OP39_NOT_OFFSET 14 ++#define RTL8367C_OP39_NOT_MASK 0x4000 ++#define RTL8367C_ACT39_GPIO_OFFSET 13 ++#define RTL8367C_ACT39_GPIO_MASK 0x2000 ++#define RTL8367C_ACT39_FORWARD_OFFSET 12 ++#define RTL8367C_ACT39_FORWARD_MASK 0x1000 ++#define RTL8367C_ACT39_POLICING_OFFSET 11 ++#define RTL8367C_ACT39_POLICING_MASK 0x800 ++#define RTL8367C_ACT39_PRIORITY_OFFSET 10 ++#define RTL8367C_ACT39_PRIORITY_MASK 0x400 ++#define RTL8367C_ACT39_SVID_OFFSET 9 ++#define RTL8367C_ACT39_SVID_MASK 0x200 ++#define RTL8367C_ACT39_CVID_OFFSET 8 ++#define RTL8367C_ACT39_CVID_MASK 0x100 ++#define RTL8367C_OP38_NOT_OFFSET 6 ++#define RTL8367C_OP38_NOT_MASK 0x40 ++#define RTL8367C_ACT38_GPIO_OFFSET 5 ++#define RTL8367C_ACT38_GPIO_MASK 0x20 ++#define RTL8367C_ACT38_FORWARD_OFFSET 4 ++#define RTL8367C_ACT38_FORWARD_MASK 0x10 ++#define RTL8367C_ACT38_POLICING_OFFSET 3 ++#define RTL8367C_ACT38_POLICING_MASK 0x8 ++#define RTL8367C_ACT38_PRIORITY_OFFSET 2 ++#define RTL8367C_ACT38_PRIORITY_MASK 0x4 ++#define RTL8367C_ACT38_SVID_OFFSET 1 ++#define RTL8367C_ACT38_SVID_MASK 0x2 ++#define RTL8367C_ACT38_CVID_OFFSET 0 ++#define RTL8367C_ACT38_CVID_MASK 0x1 ++ ++#define RTL8367C_REG_ACL_ACTION_CTRL20 0x0628 ++#define RTL8367C_OP41_NOT_OFFSET 14 ++#define RTL8367C_OP41_NOT_MASK 0x4000 ++#define RTL8367C_ACT41_GPIO_OFFSET 13 ++#define RTL8367C_ACT41_GPIO_MASK 0x2000 ++#define RTL8367C_ACT41_FORWARD_OFFSET 12 ++#define RTL8367C_ACT41_FORWARD_MASK 0x1000 ++#define RTL8367C_ACT41_POLICING_OFFSET 11 ++#define RTL8367C_ACT41_POLICING_MASK 0x800 ++#define RTL8367C_ACT41_PRIORITY_OFFSET 10 ++#define RTL8367C_ACT41_PRIORITY_MASK 0x400 ++#define RTL8367C_ACT41_SVID_OFFSET 9 ++#define RTL8367C_ACT41_SVID_MASK 0x200 ++#define RTL8367C_ACT41_CVID_OFFSET 8 ++#define RTL8367C_ACT41_CVID_MASK 0x100 ++#define RTL8367C_OP40_NOT_OFFSET 6 ++#define RTL8367C_OP40_NOT_MASK 0x40 ++#define RTL8367C_ACT40_GPIO_OFFSET 5 ++#define RTL8367C_ACT40_GPIO_MASK 0x20 ++#define RTL8367C_ACT40_FORWARD_OFFSET 4 ++#define RTL8367C_ACT40_FORWARD_MASK 0x10 ++#define RTL8367C_ACT40_POLICING_OFFSET 3 ++#define RTL8367C_ACT40_POLICING_MASK 0x8 ++#define RTL8367C_ACT40_PRIORITY_OFFSET 2 ++#define RTL8367C_ACT40_PRIORITY_MASK 0x4 ++#define RTL8367C_ACT40_SVID_OFFSET 1 ++#define RTL8367C_ACT40_SVID_MASK 0x2 ++#define RTL8367C_ACT40_CVID_OFFSET 0 ++#define RTL8367C_ACT40_CVID_MASK 0x1 ++ ++#define RTL8367C_REG_ACL_ACTION_CTRL21 0x0629 ++#define RTL8367C_OP43_NOT_OFFSET 14 ++#define RTL8367C_OP43_NOT_MASK 0x4000 ++#define RTL8367C_ACT43_GPIO_OFFSET 13 ++#define RTL8367C_ACT43_GPIO_MASK 0x2000 ++#define RTL8367C_ACT43_FORWARD_OFFSET 12 ++#define RTL8367C_ACT43_FORWARD_MASK 0x1000 ++#define RTL8367C_ACT43_POLICING_OFFSET 11 ++#define RTL8367C_ACT43_POLICING_MASK 0x800 ++#define RTL8367C_ACT43_PRIORITY_OFFSET 10 ++#define RTL8367C_ACT43_PRIORITY_MASK 0x400 ++#define RTL8367C_ACT43_SVID_OFFSET 9 ++#define RTL8367C_ACT43_SVID_MASK 0x200 ++#define RTL8367C_ACT43_CVID_OFFSET 8 ++#define RTL8367C_ACT43_CVID_MASK 0x100 ++#define RTL8367C_OP42_NOT_OFFSET 6 ++#define RTL8367C_OP42_NOT_MASK 0x40 ++#define RTL8367C_ACT42_GPIO_OFFSET 5 ++#define RTL8367C_ACT42_GPIO_MASK 0x20 ++#define RTL8367C_ACT42_FORWARD_OFFSET 4 ++#define RTL8367C_ACT42_FORWARD_MASK 0x10 ++#define RTL8367C_ACT42_POLICING_OFFSET 3 ++#define RTL8367C_ACT42_POLICING_MASK 0x8 ++#define RTL8367C_ACT42_PRIORITY_OFFSET 2 ++#define RTL8367C_ACT42_PRIORITY_MASK 0x4 ++#define RTL8367C_ACT42_SVID_OFFSET 1 ++#define RTL8367C_ACT42_SVID_MASK 0x2 ++#define RTL8367C_ACT42_CVID_OFFSET 0 ++#define RTL8367C_ACT42_CVID_MASK 0x1 ++ ++#define RTL8367C_REG_ACL_ACTION_CTRL22 0x062a ++#define RTL8367C_OP45_NOT_OFFSET 14 ++#define RTL8367C_OP45_NOT_MASK 0x4000 ++#define RTL8367C_ACT45_GPIO_OFFSET 13 ++#define RTL8367C_ACT45_GPIO_MASK 0x2000 ++#define RTL8367C_ACT45_FORWARD_OFFSET 12 ++#define RTL8367C_ACT45_FORWARD_MASK 0x1000 ++#define RTL8367C_ACT45_POLICING_OFFSET 11 ++#define RTL8367C_ACT45_POLICING_MASK 0x800 ++#define RTL8367C_ACT45_PRIORITY_OFFSET 10 ++#define RTL8367C_ACT45_PRIORITY_MASK 0x400 ++#define RTL8367C_ACT45_SVID_OFFSET 9 ++#define RTL8367C_ACT45_SVID_MASK 0x200 ++#define RTL8367C_ACT45_CVID_OFFSET 8 ++#define RTL8367C_ACT45_CVID_MASK 0x100 ++#define RTL8367C_OP44_NOT_OFFSET 6 ++#define RTL8367C_OP44_NOT_MASK 0x40 ++#define RTL8367C_ACT44_GPIO_OFFSET 5 ++#define RTL8367C_ACT44_GPIO_MASK 0x20 ++#define RTL8367C_ACT44_FORWARD_OFFSET 4 ++#define RTL8367C_ACT44_FORWARD_MASK 0x10 ++#define RTL8367C_ACT44_POLICING_OFFSET 3 ++#define RTL8367C_ACT44_POLICING_MASK 0x8 ++#define RTL8367C_ACT44_PRIORITY_OFFSET 2 ++#define RTL8367C_ACT44_PRIORITY_MASK 0x4 ++#define RTL8367C_ACT44_SVID_OFFSET 1 ++#define RTL8367C_ACT44_SVID_MASK 0x2 ++#define RTL8367C_ACT44_CVID_OFFSET 0 ++#define RTL8367C_ACT44_CVID_MASK 0x1 ++ ++#define RTL8367C_REG_ACL_ACTION_CTRL23 0x062b ++#define RTL8367C_OP47_NOT_OFFSET 14 ++#define RTL8367C_OP47_NOT_MASK 0x4000 ++#define RTL8367C_ACT47_GPIO_OFFSET 13 ++#define RTL8367C_ACT47_GPIO_MASK 0x2000 ++#define RTL8367C_ACT47_FORWARD_OFFSET 12 ++#define RTL8367C_ACT47_FORWARD_MASK 0x1000 ++#define RTL8367C_ACT47_POLICING_OFFSET 11 ++#define RTL8367C_ACT47_POLICING_MASK 0x800 ++#define RTL8367C_ACT47_PRIORITY_OFFSET 10 ++#define RTL8367C_ACT47_PRIORITY_MASK 0x400 ++#define RTL8367C_ACT47_SVID_OFFSET 9 ++#define RTL8367C_ACT47_SVID_MASK 0x200 ++#define RTL8367C_ACT47_CVID_OFFSET 8 ++#define RTL8367C_ACT47_CVID_MASK 0x100 ++#define RTL8367C_OP46_NOT_OFFSET 6 ++#define RTL8367C_OP46_NOT_MASK 0x40 ++#define RTL8367C_ACT46_GPIO_OFFSET 5 ++#define RTL8367C_ACT46_GPIO_MASK 0x20 ++#define RTL8367C_ACT46_FORWARD_OFFSET 4 ++#define RTL8367C_ACT46_FORWARD_MASK 0x10 ++#define RTL8367C_ACT46_POLICING_OFFSET 3 ++#define RTL8367C_ACT46_POLICING_MASK 0x8 ++#define RTL8367C_ACT46_PRIORITY_OFFSET 2 ++#define RTL8367C_ACT46_PRIORITY_MASK 0x4 ++#define RTL8367C_ACT46_SVID_OFFSET 1 ++#define RTL8367C_ACT46_SVID_MASK 0x2 ++#define RTL8367C_ACT46_CVID_OFFSET 0 ++#define RTL8367C_ACT46_CVID_MASK 0x1 ++ ++#define RTL8367C_REG_ACL_ACTION_CTRL24 0x062c ++#define RTL8367C_OP49_NOT_OFFSET 14 ++#define RTL8367C_OP49_NOT_MASK 0x4000 ++#define RTL8367C_ACT49_GPIO_OFFSET 13 ++#define RTL8367C_ACT49_GPIO_MASK 0x2000 ++#define RTL8367C_ACT49_FORWARD_OFFSET 12 ++#define RTL8367C_ACT49_FORWARD_MASK 0x1000 ++#define RTL8367C_ACT49_POLICING_OFFSET 11 ++#define RTL8367C_ACT49_POLICING_MASK 0x800 ++#define RTL8367C_ACT49_PRIORITY_OFFSET 10 ++#define RTL8367C_ACT49_PRIORITY_MASK 0x400 ++#define RTL8367C_ACT49_SVID_OFFSET 9 ++#define RTL8367C_ACT49_SVID_MASK 0x200 ++#define RTL8367C_ACT49_CVID_OFFSET 8 ++#define RTL8367C_ACT49_CVID_MASK 0x100 ++#define RTL8367C_OP48_NOT_OFFSET 6 ++#define RTL8367C_OP48_NOT_MASK 0x40 ++#define RTL8367C_ACT48_GPIO_OFFSET 5 ++#define RTL8367C_ACT48_GPIO_MASK 0x20 ++#define RTL8367C_ACT48_FORWARD_OFFSET 4 ++#define RTL8367C_ACT48_FORWARD_MASK 0x10 ++#define RTL8367C_ACT48_POLICING_OFFSET 3 ++#define RTL8367C_ACT48_POLICING_MASK 0x8 ++#define RTL8367C_ACT48_PRIORITY_OFFSET 2 ++#define RTL8367C_ACT48_PRIORITY_MASK 0x4 ++#define RTL8367C_ACT48_SVID_OFFSET 1 ++#define RTL8367C_ACT48_SVID_MASK 0x2 ++#define RTL8367C_ACT48_CVID_OFFSET 0 ++#define RTL8367C_ACT48_CVID_MASK 0x1 ++ ++#define RTL8367C_REG_ACL_ACTION_CTRL25 0x062d ++#define RTL8367C_OP51_NOT_OFFSET 14 ++#define RTL8367C_OP51_NOT_MASK 0x4000 ++#define RTL8367C_ACT51_GPIO_OFFSET 13 ++#define RTL8367C_ACT51_GPIO_MASK 0x2000 ++#define RTL8367C_ACT51_FORWARD_OFFSET 12 ++#define RTL8367C_ACT51_FORWARD_MASK 0x1000 ++#define RTL8367C_ACT51_POLICING_OFFSET 11 ++#define RTL8367C_ACT51_POLICING_MASK 0x800 ++#define RTL8367C_ACT51_PRIORITY_OFFSET 10 ++#define RTL8367C_ACT51_PRIORITY_MASK 0x400 ++#define RTL8367C_ACT51_SVID_OFFSET 9 ++#define RTL8367C_ACT51_SVID_MASK 0x200 ++#define RTL8367C_ACT51_CVID_OFFSET 8 ++#define RTL8367C_ACT51_CVID_MASK 0x100 ++#define RTL8367C_OP50_NOT_OFFSET 6 ++#define RTL8367C_OP50_NOT_MASK 0x40 ++#define RTL8367C_ACT50_GPIO_OFFSET 5 ++#define RTL8367C_ACT50_GPIO_MASK 0x20 ++#define RTL8367C_ACT50_FORWARD_OFFSET 4 ++#define RTL8367C_ACT50_FORWARD_MASK 0x10 ++#define RTL8367C_ACT50_POLICING_OFFSET 3 ++#define RTL8367C_ACT50_POLICING_MASK 0x8 ++#define RTL8367C_ACT50_PRIORITY_OFFSET 2 ++#define RTL8367C_ACT50_PRIORITY_MASK 0x4 ++#define RTL8367C_ACT50_SVID_OFFSET 1 ++#define RTL8367C_ACT50_SVID_MASK 0x2 ++#define RTL8367C_ACT50_CVID_OFFSET 0 ++#define RTL8367C_ACT50_CVID_MASK 0x1 ++ ++#define RTL8367C_REG_ACL_ACTION_CTRL26 0x062e ++#define RTL8367C_OP53_NOT_OFFSET 14 ++#define RTL8367C_OP53_NOT_MASK 0x4000 ++#define RTL8367C_ACT53_GPIO_OFFSET 13 ++#define RTL8367C_ACT53_GPIO_MASK 0x2000 ++#define RTL8367C_ACT53_FORWARD_OFFSET 12 ++#define RTL8367C_ACT53_FORWARD_MASK 0x1000 ++#define RTL8367C_ACT53_POLICING_OFFSET 11 ++#define RTL8367C_ACT53_POLICING_MASK 0x800 ++#define RTL8367C_ACT53_PRIORITY_OFFSET 10 ++#define RTL8367C_ACT53_PRIORITY_MASK 0x400 ++#define RTL8367C_ACT53_SVID_OFFSET 9 ++#define RTL8367C_ACT53_SVID_MASK 0x200 ++#define RTL8367C_ACT53_CVID_OFFSET 8 ++#define RTL8367C_ACT53_CVID_MASK 0x100 ++#define RTL8367C_OP52_NOT_OFFSET 6 ++#define RTL8367C_OP52_NOT_MASK 0x40 ++#define RTL8367C_ACT52_GPIO_OFFSET 5 ++#define RTL8367C_ACT52_GPIO_MASK 0x20 ++#define RTL8367C_ACT52_FORWARD_OFFSET 4 ++#define RTL8367C_ACT52_FORWARD_MASK 0x10 ++#define RTL8367C_ACT52_POLICING_OFFSET 3 ++#define RTL8367C_ACT52_POLICING_MASK 0x8 ++#define RTL8367C_ACT52_PRIORITY_OFFSET 2 ++#define RTL8367C_ACT52_PRIORITY_MASK 0x4 ++#define RTL8367C_ACT52_SVID_OFFSET 1 ++#define RTL8367C_ACT52_SVID_MASK 0x2 ++#define RTL8367C_ACT52_CVID_OFFSET 0 ++#define RTL8367C_ACT52_CVID_MASK 0x1 ++ ++#define RTL8367C_REG_ACL_ACTION_CTRL27 0x062f ++#define RTL8367C_OP55_NOT_OFFSET 14 ++#define RTL8367C_OP55_NOT_MASK 0x4000 ++#define RTL8367C_ACT55_GPIO_OFFSET 13 ++#define RTL8367C_ACT55_GPIO_MASK 0x2000 ++#define RTL8367C_ACT55_FORWARD_OFFSET 12 ++#define RTL8367C_ACT55_FORWARD_MASK 0x1000 ++#define RTL8367C_ACT55_POLICING_OFFSET 11 ++#define RTL8367C_ACT55_POLICING_MASK 0x800 ++#define RTL8367C_ACT55_PRIORITY_OFFSET 10 ++#define RTL8367C_ACT55_PRIORITY_MASK 0x400 ++#define RTL8367C_ACT55_SVID_OFFSET 9 ++#define RTL8367C_ACT55_SVID_MASK 0x200 ++#define RTL8367C_ACT55_CVID_OFFSET 8 ++#define RTL8367C_ACT55_CVID_MASK 0x100 ++#define RTL8367C_OP54_NOT_OFFSET 6 ++#define RTL8367C_OP54_NOT_MASK 0x40 ++#define RTL8367C_ACT54_GPIO_OFFSET 5 ++#define RTL8367C_ACT54_GPIO_MASK 0x20 ++#define RTL8367C_ACT54_FORWARD_OFFSET 4 ++#define RTL8367C_ACT54_FORWARD_MASK 0x10 ++#define RTL8367C_ACT54_POLICING_OFFSET 3 ++#define RTL8367C_ACT54_POLICING_MASK 0x8 ++#define RTL8367C_ACT54_PRIORITY_OFFSET 2 ++#define RTL8367C_ACT54_PRIORITY_MASK 0x4 ++#define RTL8367C_ACT54_SVID_OFFSET 1 ++#define RTL8367C_ACT54_SVID_MASK 0x2 ++#define RTL8367C_ACT54_CVID_OFFSET 0 ++#define RTL8367C_ACT54_CVID_MASK 0x1 ++ ++#define RTL8367C_REG_ACL_ACTION_CTRL28 0x0630 ++#define RTL8367C_OP57_NOT_OFFSET 14 ++#define RTL8367C_OP57_NOT_MASK 0x4000 ++#define RTL8367C_ACT57_GPIO_OFFSET 13 ++#define RTL8367C_ACT57_GPIO_MASK 0x2000 ++#define RTL8367C_ACT57_FORWARD_OFFSET 12 ++#define RTL8367C_ACT57_FORWARD_MASK 0x1000 ++#define RTL8367C_ACT57_POLICING_OFFSET 11 ++#define RTL8367C_ACT57_POLICING_MASK 0x800 ++#define RTL8367C_ACT57_PRIORITY_OFFSET 10 ++#define RTL8367C_ACT57_PRIORITY_MASK 0x400 ++#define RTL8367C_ACT57_SVID_OFFSET 9 ++#define RTL8367C_ACT57_SVID_MASK 0x200 ++#define RTL8367C_ACT57_CVID_OFFSET 8 ++#define RTL8367C_ACT57_CVID_MASK 0x100 ++#define RTL8367C_OP56_NOT_OFFSET 6 ++#define RTL8367C_OP56_NOT_MASK 0x40 ++#define RTL8367C_ACT56_GPIO_OFFSET 5 ++#define RTL8367C_ACT56_GPIO_MASK 0x20 ++#define RTL8367C_ACT56_FORWARD_OFFSET 4 ++#define RTL8367C_ACT56_FORWARD_MASK 0x10 ++#define RTL8367C_ACT56_POLICING_OFFSET 3 ++#define RTL8367C_ACT56_POLICING_MASK 0x8 ++#define RTL8367C_ACT56_PRIORITY_OFFSET 2 ++#define RTL8367C_ACT56_PRIORITY_MASK 0x4 ++#define RTL8367C_ACT56_SVID_OFFSET 1 ++#define RTL8367C_ACT56_SVID_MASK 0x2 ++#define RTL8367C_ACT56_CVID_OFFSET 0 ++#define RTL8367C_ACT56_CVID_MASK 0x1 ++ ++#define RTL8367C_REG_ACL_ACTION_CTRL29 0x0631 ++#define RTL8367C_OP59_NOT_OFFSET 14 ++#define RTL8367C_OP59_NOT_MASK 0x4000 ++#define RTL8367C_ACT59_GPIO_OFFSET 13 ++#define RTL8367C_ACT59_GPIO_MASK 0x2000 ++#define RTL8367C_ACT59_FORWARD_OFFSET 12 ++#define RTL8367C_ACT59_FORWARD_MASK 0x1000 ++#define RTL8367C_ACT59_POLICING_OFFSET 11 ++#define RTL8367C_ACT59_POLICING_MASK 0x800 ++#define RTL8367C_ACT59_PRIORITY_OFFSET 10 ++#define RTL8367C_ACT59_PRIORITY_MASK 0x400 ++#define RTL8367C_ACT59_SVID_OFFSET 9 ++#define RTL8367C_ACT59_SVID_MASK 0x200 ++#define RTL8367C_ACT59_CVID_OFFSET 8 ++#define RTL8367C_ACT59_CVID_MASK 0x100 ++#define RTL8367C_OP58_NOT_OFFSET 6 ++#define RTL8367C_OP58_NOT_MASK 0x40 ++#define RTL8367C_ACT58_GPIO_OFFSET 5 ++#define RTL8367C_ACT58_GPIO_MASK 0x20 ++#define RTL8367C_ACT58_FORWARD_OFFSET 4 ++#define RTL8367C_ACT58_FORWARD_MASK 0x10 ++#define RTL8367C_ACT58_POLICING_OFFSET 3 ++#define RTL8367C_ACT58_POLICING_MASK 0x8 ++#define RTL8367C_ACT58_PRIORITY_OFFSET 2 ++#define RTL8367C_ACT58_PRIORITY_MASK 0x4 ++#define RTL8367C_ACT58_SVID_OFFSET 1 ++#define RTL8367C_ACT58_SVID_MASK 0x2 ++#define RTL8367C_ACT58_CVID_OFFSET 0 ++#define RTL8367C_ACT58_CVID_MASK 0x1 ++ ++#define RTL8367C_REG_ACL_ACTION_CTRL30 0x0632 ++#define RTL8367C_OP61_NOT_OFFSET 14 ++#define RTL8367C_OP61_NOT_MASK 0x4000 ++#define RTL8367C_ACT61_GPIO_OFFSET 13 ++#define RTL8367C_ACT61_GPIO_MASK 0x2000 ++#define RTL8367C_ACT61_FORWARD_OFFSET 12 ++#define RTL8367C_ACT61_FORWARD_MASK 0x1000 ++#define RTL8367C_ACT61_POLICING_OFFSET 11 ++#define RTL8367C_ACT61_POLICING_MASK 0x800 ++#define RTL8367C_ACT61_PRIORITY_OFFSET 10 ++#define RTL8367C_ACT61_PRIORITY_MASK 0x400 ++#define RTL8367C_ACT61_SVID_OFFSET 9 ++#define RTL8367C_ACT61_SVID_MASK 0x200 ++#define RTL8367C_ACT61_CVID_OFFSET 8 ++#define RTL8367C_ACT61_CVID_MASK 0x100 ++#define RTL8367C_OP60_NOT_OFFSET 6 ++#define RTL8367C_OP60_NOT_MASK 0x40 ++#define RTL8367C_ACT60_GPIO_OFFSET 5 ++#define RTL8367C_ACT60_GPIO_MASK 0x20 ++#define RTL8367C_ACT60_FORWARD_OFFSET 4 ++#define RTL8367C_ACT60_FORWARD_MASK 0x10 ++#define RTL8367C_ACT60_POLICING_OFFSET 3 ++#define RTL8367C_ACT60_POLICING_MASK 0x8 ++#define RTL8367C_ACT60_PRIORITY_OFFSET 2 ++#define RTL8367C_ACT60_PRIORITY_MASK 0x4 ++#define RTL8367C_ACT60_SVID_OFFSET 1 ++#define RTL8367C_ACT60_SVID_MASK 0x2 ++#define RTL8367C_ACT60_CVID_OFFSET 0 ++#define RTL8367C_ACT60_CVID_MASK 0x1 ++ ++#define RTL8367C_REG_ACL_ACTION_CTRL31 0x0633 ++#define RTL8367C_OP63_NOT_OFFSET 14 ++#define RTL8367C_OP63_NOT_MASK 0x4000 ++#define RTL8367C_ACT63_GPIO_OFFSET 13 ++#define RTL8367C_ACT63_GPIO_MASK 0x2000 ++#define RTL8367C_ACT63_FORWARD_OFFSET 12 ++#define RTL8367C_ACT63_FORWARD_MASK 0x1000 ++#define RTL8367C_ACT63_POLICING_OFFSET 11 ++#define RTL8367C_ACT63_POLICING_MASK 0x800 ++#define RTL8367C_ACT63_PRIORITY_OFFSET 10 ++#define RTL8367C_ACT63_PRIORITY_MASK 0x400 ++#define RTL8367C_ACT63_SVID_OFFSET 9 ++#define RTL8367C_ACT63_SVID_MASK 0x200 ++#define RTL8367C_ACT63_CVID_OFFSET 8 ++#define RTL8367C_ACT63_CVID_MASK 0x100 ++#define RTL8367C_OP62_NOT_OFFSET 6 ++#define RTL8367C_OP62_NOT_MASK 0x40 ++#define RTL8367C_ACT62_GPIO_OFFSET 5 ++#define RTL8367C_ACT62_GPIO_MASK 0x20 ++#define RTL8367C_ACT62_FORWARD_OFFSET 4 ++#define RTL8367C_ACT62_FORWARD_MASK 0x10 ++#define RTL8367C_ACT62_POLICING_OFFSET 3 ++#define RTL8367C_ACT62_POLICING_MASK 0x8 ++#define RTL8367C_ACT62_PRIORITY_OFFSET 2 ++#define RTL8367C_ACT62_PRIORITY_MASK 0x4 ++#define RTL8367C_ACT62_SVID_OFFSET 1 ++#define RTL8367C_ACT62_SVID_MASK 0x2 ++#define RTL8367C_ACT62_CVID_OFFSET 0 ++#define RTL8367C_ACT62_CVID_MASK 0x1 ++ ++#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY0_CTRL0 0x0635 ++ ++#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY0_CTRL1 0x0636 ++ ++#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY0_CTRL2 0x0637 ++#define RTL8367C_ACL_SDPORT_RANGE_ENTRY0_CTRL2_OFFSET 0 ++#define RTL8367C_ACL_SDPORT_RANGE_ENTRY0_CTRL2_MASK 0x3 ++ ++#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY1_CTRL0 0x0638 ++ ++#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY1_CTRL1 0x0639 ++ ++#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY1_CTRL2 0x063a ++#define RTL8367C_ACL_SDPORT_RANGE_ENTRY1_CTRL2_OFFSET 0 ++#define RTL8367C_ACL_SDPORT_RANGE_ENTRY1_CTRL2_MASK 0x3 ++ ++#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY2_CTRL0 0x063b ++ ++#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY2_CTRL1 0x063c ++ ++#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY2_CTRL2 0x063d ++#define RTL8367C_ACL_SDPORT_RANGE_ENTRY2_CTRL2_OFFSET 0 ++#define RTL8367C_ACL_SDPORT_RANGE_ENTRY2_CTRL2_MASK 0x3 ++ ++#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY3_CTRL0 0x063e ++ ++#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY3_CTRL1 0x063f ++ ++#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY3_CTRL2 0x0640 ++#define RTL8367C_ACL_SDPORT_RANGE_ENTRY3_CTRL2_OFFSET 0 ++#define RTL8367C_ACL_SDPORT_RANGE_ENTRY3_CTRL2_MASK 0x3 ++ ++#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY4_CTRL0 0x0641 ++ ++#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY4_CTRL1 0x0642 ++ ++#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY4_CTRL2 0x0643 ++#define RTL8367C_ACL_SDPORT_RANGE_ENTRY4_CTRL2_OFFSET 0 ++#define RTL8367C_ACL_SDPORT_RANGE_ENTRY4_CTRL2_MASK 0x3 ++ ++#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY5_CTRL0 0x0644 ++ ++#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY5_CTRL1 0x0645 ++ ++#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY5_CTRL2 0x0646 ++#define RTL8367C_ACL_SDPORT_RANGE_ENTRY5_CTRL2_OFFSET 0 ++#define RTL8367C_ACL_SDPORT_RANGE_ENTRY5_CTRL2_MASK 0x3 ++ ++#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY6_CTRL0 0x0647 ++ ++#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY6_CTRL1 0x0648 ++ ++#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY6_CTRL2 0x0649 ++#define RTL8367C_ACL_SDPORT_RANGE_ENTRY6_CTRL2_OFFSET 0 ++#define RTL8367C_ACL_SDPORT_RANGE_ENTRY6_CTRL2_MASK 0x3 ++ ++#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY7_CTRL0 0x064a ++ ++#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY7_CTRL1 0x064b ++ ++#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY7_CTRL2 0x064c ++#define RTL8367C_ACL_SDPORT_RANGE_ENTRY7_CTRL2_OFFSET 0 ++#define RTL8367C_ACL_SDPORT_RANGE_ENTRY7_CTRL2_MASK 0x3 ++ ++#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY8_CTRL0 0x064d ++ ++#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY8_CTRL1 0x064e ++ ++#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY8_CTRL2 0x064f ++#define RTL8367C_ACL_SDPORT_RANGE_ENTRY8_CTRL2_OFFSET 0 ++#define RTL8367C_ACL_SDPORT_RANGE_ENTRY8_CTRL2_MASK 0x3 ++ ++#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY9_CTRL0 0x0650 ++ ++#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY9_CTRL1 0x0651 ++ ++#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY9_CTRL2 0x0652 ++#define RTL8367C_ACL_SDPORT_RANGE_ENTRY9_CTRL2_OFFSET 0 ++#define RTL8367C_ACL_SDPORT_RANGE_ENTRY9_CTRL2_MASK 0x3 ++ ++#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY10_CTRL0 0x0653 ++ ++#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY10_CTRL1 0x0654 ++ ++#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY10_CTRL2 0x0655 ++#define RTL8367C_ACL_SDPORT_RANGE_ENTRY10_CTRL2_OFFSET 0 ++#define RTL8367C_ACL_SDPORT_RANGE_ENTRY10_CTRL2_MASK 0x3 ++ ++#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY11_CTRL0 0x0656 ++ ++#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY11_CTRL1 0x0657 ++ ++#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY11_CTRL2 0x0658 ++#define RTL8367C_ACL_SDPORT_RANGE_ENTRY11_CTRL2_OFFSET 0 ++#define RTL8367C_ACL_SDPORT_RANGE_ENTRY11_CTRL2_MASK 0x3 ++ ++#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY12_CTRL0 0x0659 ++ ++#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY12_CTRL1 0x065a ++ ++#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY12_CTRL2 0x065b ++#define RTL8367C_ACL_SDPORT_RANGE_ENTRY12_CTRL2_OFFSET 0 ++#define RTL8367C_ACL_SDPORT_RANGE_ENTRY12_CTRL2_MASK 0x3 ++ ++#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY13_CTRL0 0x065c ++ ++#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY13_CTRL1 0x065d ++ ++#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY13_CTRL2 0x065e ++#define RTL8367C_ACL_SDPORT_RANGE_ENTRY13_CTRL2_OFFSET 0 ++#define RTL8367C_ACL_SDPORT_RANGE_ENTRY13_CTRL2_MASK 0x3 ++ ++#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY14_CTRL0 0x065f ++ ++#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY14_CTRL1 0x0660 ++ ++#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY14_CTRL2 0x0661 ++#define RTL8367C_ACL_SDPORT_RANGE_ENTRY14_CTRL2_OFFSET 0 ++#define RTL8367C_ACL_SDPORT_RANGE_ENTRY14_CTRL2_MASK 0x3 ++ ++#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY15_CTRL0 0x0662 ++ ++#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY15_CTRL1 0x0663 ++ ++#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY15_CTRL2 0x0664 ++#define RTL8367C_ACL_SDPORT_RANGE_ENTRY15_CTRL2_OFFSET 0 ++#define RTL8367C_ACL_SDPORT_RANGE_ENTRY15_CTRL2_MASK 0x3 ++ ++#define RTL8367C_REG_ACL_VID_RANGE_ENTRY0_CTRL0 0x0665 ++#define RTL8367C_ACL_VID_RANGE_ENTRY0_CTRL0_OFFSET 0 ++#define RTL8367C_ACL_VID_RANGE_ENTRY0_CTRL0_MASK 0xFFF ++ ++#define RTL8367C_REG_ACL_VID_RANGE_ENTRY0_CTRL1 0x0666 ++#define RTL8367C_ACL_VID_RANGE_ENTRY0_CTRL1_CHECK0_TYPE_OFFSET 12 ++#define RTL8367C_ACL_VID_RANGE_ENTRY0_CTRL1_CHECK0_TYPE_MASK 0x3000 ++#define RTL8367C_ACL_VID_RANGE_ENTRY0_CTRL1_CHECK0_HIGH_OFFSET 0 ++#define RTL8367C_ACL_VID_RANGE_ENTRY0_CTRL1_CHECK0_HIGH_MASK 0xFFF ++ ++#define RTL8367C_REG_ACL_VID_RANGE_ENTRY1_CTRL0 0x0667 ++#define RTL8367C_ACL_VID_RANGE_ENTRY1_CTRL0_OFFSET 0 ++#define RTL8367C_ACL_VID_RANGE_ENTRY1_CTRL0_MASK 0xFFF ++ ++#define RTL8367C_REG_ACL_VID_RANGE_ENTRY1_CTRL1 0x0668 ++#define RTL8367C_ACL_VID_RANGE_ENTRY1_CTRL1_CHECK1_TYPE_OFFSET 12 ++#define RTL8367C_ACL_VID_RANGE_ENTRY1_CTRL1_CHECK1_TYPE_MASK 0x3000 ++#define RTL8367C_ACL_VID_RANGE_ENTRY1_CTRL1_CHECK1_HIGH_OFFSET 0 ++#define RTL8367C_ACL_VID_RANGE_ENTRY1_CTRL1_CHECK1_HIGH_MASK 0xFFF ++ ++#define RTL8367C_REG_ACL_VID_RANGE_ENTRY2_CTRL0 0x0669 ++#define RTL8367C_ACL_VID_RANGE_ENTRY2_CTRL0_OFFSET 0 ++#define RTL8367C_ACL_VID_RANGE_ENTRY2_CTRL0_MASK 0xFFF ++ ++#define RTL8367C_REG_ACL_VID_RANGE_ENTRY2_CTRL1 0x066a ++#define RTL8367C_ACL_VID_RANGE_ENTRY2_CTRL1_CHECK2_TYPE_OFFSET 12 ++#define RTL8367C_ACL_VID_RANGE_ENTRY2_CTRL1_CHECK2_TYPE_MASK 0x3000 ++#define RTL8367C_ACL_VID_RANGE_ENTRY2_CTRL1_CHECK2_HIGH_OFFSET 0 ++#define RTL8367C_ACL_VID_RANGE_ENTRY2_CTRL1_CHECK2_HIGH_MASK 0xFFF ++ ++#define RTL8367C_REG_ACL_VID_RANGE_ENTRY3_CTRL0 0x066b ++#define RTL8367C_ACL_VID_RANGE_ENTRY3_CTRL0_OFFSET 0 ++#define RTL8367C_ACL_VID_RANGE_ENTRY3_CTRL0_MASK 0xFFF ++ ++#define RTL8367C_REG_ACL_VID_RANGE_ENTRY3_CTRL1 0x066c ++#define RTL8367C_ACL_VID_RANGE_ENTRY3_CTRL1_CHECK3_TYPE_OFFSET 12 ++#define RTL8367C_ACL_VID_RANGE_ENTRY3_CTRL1_CHECK3_TYPE_MASK 0x3000 ++#define RTL8367C_ACL_VID_RANGE_ENTRY3_CTRL1_CHECK3_HIGH_OFFSET 0 ++#define RTL8367C_ACL_VID_RANGE_ENTRY3_CTRL1_CHECK3_HIGH_MASK 0xFFF ++ ++#define RTL8367C_REG_ACL_VID_RANGE_ENTRY4_CTRL0 0x066d ++#define RTL8367C_ACL_VID_RANGE_ENTRY4_CTRL0_OFFSET 0 ++#define RTL8367C_ACL_VID_RANGE_ENTRY4_CTRL0_MASK 0xFFF ++ ++#define RTL8367C_REG_ACL_VID_RANGE_ENTRY4_CTRL1 0x066e ++#define RTL8367C_ACL_VID_RANGE_ENTRY4_CTRL1_CHECK4_TYPE_OFFSET 12 ++#define RTL8367C_ACL_VID_RANGE_ENTRY4_CTRL1_CHECK4_TYPE_MASK 0x3000 ++#define RTL8367C_ACL_VID_RANGE_ENTRY4_CTRL1_CHECK4_HIGH_OFFSET 0 ++#define RTL8367C_ACL_VID_RANGE_ENTRY4_CTRL1_CHECK4_HIGH_MASK 0xFFF ++ ++#define RTL8367C_REG_ACL_VID_RANGE_ENTRY5_CTRL0 0x066f ++#define RTL8367C_ACL_VID_RANGE_ENTRY5_CTRL0_OFFSET 0 ++#define RTL8367C_ACL_VID_RANGE_ENTRY5_CTRL0_MASK 0xFFF ++ ++#define RTL8367C_REG_ACL_VID_RANGE_ENTRY5_CTRL1 0x0670 ++#define RTL8367C_ACL_VID_RANGE_ENTRY5_CTRL1_CHECK5_TYPE_OFFSET 12 ++#define RTL8367C_ACL_VID_RANGE_ENTRY5_CTRL1_CHECK5_TYPE_MASK 0x3000 ++#define RTL8367C_ACL_VID_RANGE_ENTRY5_CTRL1_CHECK5_HIGH_OFFSET 0 ++#define RTL8367C_ACL_VID_RANGE_ENTRY5_CTRL1_CHECK5_HIGH_MASK 0xFFF ++ ++#define RTL8367C_REG_ACL_VID_RANGE_ENTRY6_CTRL0 0x0671 ++#define RTL8367C_ACL_VID_RANGE_ENTRY6_CTRL0_OFFSET 0 ++#define RTL8367C_ACL_VID_RANGE_ENTRY6_CTRL0_MASK 0xFFF ++ ++#define RTL8367C_REG_ACL_VID_RANGE_ENTRY6_CTRL1 0x0672 ++#define RTL8367C_ACL_VID_RANGE_ENTRY6_CTRL1_CHECK6_TYPE_OFFSET 12 ++#define RTL8367C_ACL_VID_RANGE_ENTRY6_CTRL1_CHECK6_TYPE_MASK 0x3000 ++#define RTL8367C_ACL_VID_RANGE_ENTRY6_CTRL1_CHECK6_HIGH_OFFSET 0 ++#define RTL8367C_ACL_VID_RANGE_ENTRY6_CTRL1_CHECK6_HIGH_MASK 0xFFF ++ ++#define RTL8367C_REG_ACL_VID_RANGE_ENTRY7_CTRL0 0x0673 ++#define RTL8367C_ACL_VID_RANGE_ENTRY7_CTRL0_OFFSET 0 ++#define RTL8367C_ACL_VID_RANGE_ENTRY7_CTRL0_MASK 0xFFF ++ ++#define RTL8367C_REG_ACL_VID_RANGE_ENTRY7_CTRL1 0x0674 ++#define RTL8367C_ACL_VID_RANGE_ENTRY7_CTRL1_CHECK7_TYPE_OFFSET 12 ++#define RTL8367C_ACL_VID_RANGE_ENTRY7_CTRL1_CHECK7_TYPE_MASK 0x3000 ++#define RTL8367C_ACL_VID_RANGE_ENTRY7_CTRL1_CHECK7_HIGH_OFFSET 0 ++#define RTL8367C_ACL_VID_RANGE_ENTRY7_CTRL1_CHECK7_HIGH_MASK 0xFFF ++ ++#define RTL8367C_REG_ACL_VID_RANGE_ENTRY8_CTRL0 0x0675 ++#define RTL8367C_ACL_VID_RANGE_ENTRY8_CTRL0_OFFSET 0 ++#define RTL8367C_ACL_VID_RANGE_ENTRY8_CTRL0_MASK 0xFFF ++ ++#define RTL8367C_REG_ACL_VID_RANGE_ENTRY8_CTRL1 0x0676 ++#define RTL8367C_ACL_VID_RANGE_ENTRY8_CTRL1_CHECK8_TYPE_OFFSET 12 ++#define RTL8367C_ACL_VID_RANGE_ENTRY8_CTRL1_CHECK8_TYPE_MASK 0x3000 ++#define RTL8367C_ACL_VID_RANGE_ENTRY8_CTRL1_CHECK8_HIGH_OFFSET 0 ++#define RTL8367C_ACL_VID_RANGE_ENTRY8_CTRL1_CHECK8_HIGH_MASK 0xFFF ++ ++#define RTL8367C_REG_ACL_VID_RANGE_ENTRY9_CTRL0 0x0677 ++#define RTL8367C_ACL_VID_RANGE_ENTRY9_CTRL0_OFFSET 0 ++#define RTL8367C_ACL_VID_RANGE_ENTRY9_CTRL0_MASK 0xFFF ++ ++#define RTL8367C_REG_ACL_VID_RANGE_ENTRY9_CTRL1 0x0678 ++#define RTL8367C_ACL_VID_RANGE_ENTRY9_CTRL1_CHECK9_TYPE_OFFSET 12 ++#define RTL8367C_ACL_VID_RANGE_ENTRY9_CTRL1_CHECK9_TYPE_MASK 0x3000 ++#define RTL8367C_ACL_VID_RANGE_ENTRY9_CTRL1_CHECK9_HIGH_OFFSET 0 ++#define RTL8367C_ACL_VID_RANGE_ENTRY9_CTRL1_CHECK9_HIGH_MASK 0xFFF ++ ++#define RTL8367C_REG_ACL_VID_RANGE_ENTRY10_CTRL0 0x0679 ++#define RTL8367C_ACL_VID_RANGE_ENTRY10_CTRL0_OFFSET 0 ++#define RTL8367C_ACL_VID_RANGE_ENTRY10_CTRL0_MASK 0xFFF ++ ++#define RTL8367C_REG_ACL_VID_RANGE_ENTRY10_CTRL1 0x067a ++#define RTL8367C_ACL_VID_RANGE_ENTRY10_CTRL1_CHECK10_TYPE_OFFSET 12 ++#define RTL8367C_ACL_VID_RANGE_ENTRY10_CTRL1_CHECK10_TYPE_MASK 0x3000 ++#define RTL8367C_ACL_VID_RANGE_ENTRY10_CTRL1_CHECK10_HIGH_OFFSET 0 ++#define RTL8367C_ACL_VID_RANGE_ENTRY10_CTRL1_CHECK10_HIGH_MASK 0xFFF ++ ++#define RTL8367C_REG_ACL_VID_RANGE_ENTRY11_CTRL0 0x067b ++#define RTL8367C_ACL_VID_RANGE_ENTRY11_CTRL0_OFFSET 0 ++#define RTL8367C_ACL_VID_RANGE_ENTRY11_CTRL0_MASK 0xFFF ++ ++#define RTL8367C_REG_ACL_VID_RANGE_ENTRY11_CTRL1 0x067c ++#define RTL8367C_ACL_VID_RANGE_ENTRY11_CTRL1_CHECK11_TYPE_OFFSET 12 ++#define RTL8367C_ACL_VID_RANGE_ENTRY11_CTRL1_CHECK11_TYPE_MASK 0x3000 ++#define RTL8367C_ACL_VID_RANGE_ENTRY11_CTRL1_CHECK11_HIGH_OFFSET 0 ++#define RTL8367C_ACL_VID_RANGE_ENTRY11_CTRL1_CHECK11_HIGH_MASK 0xFFF ++ ++#define RTL8367C_REG_ACL_VID_RANGE_ENTRY12_CTRL0 0x067d ++#define RTL8367C_ACL_VID_RANGE_ENTRY12_CTRL0_OFFSET 0 ++#define RTL8367C_ACL_VID_RANGE_ENTRY12_CTRL0_MASK 0xFFF ++ ++#define RTL8367C_REG_ACL_VID_RANGE_ENTRY12_CTRL1 0x067e ++#define RTL8367C_ACL_VID_RANGE_ENTRY12_CTRL1_CHECK12_TYPE_OFFSET 12 ++#define RTL8367C_ACL_VID_RANGE_ENTRY12_CTRL1_CHECK12_TYPE_MASK 0x3000 ++#define RTL8367C_ACL_VID_RANGE_ENTRY12_CTRL1_CHECK12_HIGH_OFFSET 0 ++#define RTL8367C_ACL_VID_RANGE_ENTRY12_CTRL1_CHECK12_HIGH_MASK 0xFFF ++ ++#define RTL8367C_REG_ACL_VID_RANGE_ENTRY13_CTRL0 0x067f ++#define RTL8367C_ACL_VID_RANGE_ENTRY13_CTRL0_OFFSET 0 ++#define RTL8367C_ACL_VID_RANGE_ENTRY13_CTRL0_MASK 0xFFF ++ ++#define RTL8367C_REG_ACL_VID_RANGE_ENTRY13_CTRL1 0x0680 ++#define RTL8367C_ACL_VID_RANGE_ENTRY13_CTRL1_CHECK13_TYPE_OFFSET 12 ++#define RTL8367C_ACL_VID_RANGE_ENTRY13_CTRL1_CHECK13_TYPE_MASK 0x3000 ++#define RTL8367C_ACL_VID_RANGE_ENTRY13_CTRL1_CHECK13_HIGH_OFFSET 0 ++#define RTL8367C_ACL_VID_RANGE_ENTRY13_CTRL1_CHECK13_HIGH_MASK 0xFFF ++ ++#define RTL8367C_REG_ACL_VID_RANGE_ENTRY14_CTRL0 0x0681 ++#define RTL8367C_ACL_VID_RANGE_ENTRY14_CTRL0_OFFSET 0 ++#define RTL8367C_ACL_VID_RANGE_ENTRY14_CTRL0_MASK 0xFFF ++ ++#define RTL8367C_REG_ACL_VID_RANGE_ENTRY14_CTRL1 0x0682 ++#define RTL8367C_ACL_VID_RANGE_ENTRY14_CTRL1_CHECK14_TYPE_OFFSET 12 ++#define RTL8367C_ACL_VID_RANGE_ENTRY14_CTRL1_CHECK14_TYPE_MASK 0x3000 ++#define RTL8367C_ACL_VID_RANGE_ENTRY14_CTRL1_CHECK14_HIGH_OFFSET 0 ++#define RTL8367C_ACL_VID_RANGE_ENTRY14_CTRL1_CHECK14_HIGH_MASK 0xFFF ++ ++#define RTL8367C_REG_ACL_VID_RANGE_ENTRY15_CTRL0 0x0683 ++#define RTL8367C_ACL_VID_RANGE_ENTRY15_CTRL0_OFFSET 0 ++#define RTL8367C_ACL_VID_RANGE_ENTRY15_CTRL0_MASK 0xFFF ++ ++#define RTL8367C_REG_ACL_VID_RANGE_ENTRY15_CTRL1 0x0684 ++#define RTL8367C_ACL_VID_RANGE_ENTRY15_CTRL1_CHECK15_TYPE_OFFSET 12 ++#define RTL8367C_ACL_VID_RANGE_ENTRY15_CTRL1_CHECK15_TYPE_MASK 0x3000 ++#define RTL8367C_ACL_VID_RANGE_ENTRY15_CTRL1_CHECK15_HIGH_OFFSET 0 ++#define RTL8367C_ACL_VID_RANGE_ENTRY15_CTRL1_CHECK15_HIGH_MASK 0xFFF ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY0_CTRL0 0x0685 ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY0_CTRL1 0x0686 ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY0_CTRL2 0x0687 ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY0_CTRL3 0x0688 ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY0_CTRL4 0x0689 ++#define RTL8367C_ACL_IP_RANGE_ENTRY0_CTRL4_OFFSET 0 ++#define RTL8367C_ACL_IP_RANGE_ENTRY0_CTRL4_MASK 0x7 ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY1_CTRL0 0x068a ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY1_CTRL1 0x068b ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY1_CTRL2 0x068c ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY1_CTRL3 0x068d ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY1_CTRL4 0x068e ++#define RTL8367C_ACL_IP_RANGE_ENTRY1_CTRL4_OFFSET 0 ++#define RTL8367C_ACL_IP_RANGE_ENTRY1_CTRL4_MASK 0x7 ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY2_CTRL0 0x068f ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY2_CTRL1 0x0690 ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY2_CTRL2 0x0691 ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY2_CTRL3 0x0692 ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY2_CTRL4 0x0693 ++#define RTL8367C_ACL_IP_RANGE_ENTRY2_CTRL4_OFFSET 0 ++#define RTL8367C_ACL_IP_RANGE_ENTRY2_CTRL4_MASK 0x7 ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY3_CTRL0 0x0694 ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY3_CTRL1 0x0695 ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY3_CTRL2 0x0696 ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY3_CTRL3 0x0697 ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY3_CTRL4 0x0698 ++#define RTL8367C_ACL_IP_RANGE_ENTRY3_CTRL4_OFFSET 0 ++#define RTL8367C_ACL_IP_RANGE_ENTRY3_CTRL4_MASK 0x7 ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY4_CTRL0 0x0699 ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY4_CTRL1 0x069a ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY4_CTRL2 0x069b ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY4_CTRL3 0x069c ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY4_CTRL4 0x069d ++#define RTL8367C_ACL_IP_RANGE_ENTRY4_CTRL4_OFFSET 0 ++#define RTL8367C_ACL_IP_RANGE_ENTRY4_CTRL4_MASK 0x7 ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY5_CTRL0 0x069e ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY5_CTRL1 0x069f ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY5_CTRL2 0x06a0 ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY5_CTRL3 0x06a1 ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY5_CTRL4 0x06a2 ++#define RTL8367C_ACL_IP_RANGE_ENTRY5_CTRL4_OFFSET 0 ++#define RTL8367C_ACL_IP_RANGE_ENTRY5_CTRL4_MASK 0x7 ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY6_CTRL0 0x06a3 ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY6_CTRL1 0x06a4 ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY6_CTRL2 0x06a5 ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY6_CTRL3 0x06a6 ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY6_CTRL4 0x06a7 ++#define RTL8367C_ACL_IP_RANGE_ENTRY6_CTRL4_OFFSET 0 ++#define RTL8367C_ACL_IP_RANGE_ENTRY6_CTRL4_MASK 0x7 ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY7_CTRL0 0x06a8 ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY7_CTRL1 0x06a9 ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY7_CTRL2 0x06aa ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY7_CTRL3 0x06ab ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY7_CTRL4 0x06ac ++#define RTL8367C_ACL_IP_RANGE_ENTRY7_CTRL4_OFFSET 0 ++#define RTL8367C_ACL_IP_RANGE_ENTRY7_CTRL4_MASK 0x7 ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY8_CTRL0 0x06ad ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY8_CTRL1 0x06ae ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY8_CTRL2 0x06af ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY8_CTRL3 0x06b0 ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY8_CTRL4 0x06b1 ++#define RTL8367C_ACL_IP_RANGE_ENTRY8_CTRL4_OFFSET 0 ++#define RTL8367C_ACL_IP_RANGE_ENTRY8_CTRL4_MASK 0x7 ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY9_CTRL0 0x06b2 ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY9_CTRL1 0x06b3 ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY9_CTRL2 0x06b4 ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY9_CTRL3 0x06b5 ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY9_CTRL4 0x06b6 ++#define RTL8367C_ACL_IP_RANGE_ENTRY9_CTRL4_OFFSET 0 ++#define RTL8367C_ACL_IP_RANGE_ENTRY9_CTRL4_MASK 0x7 ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY10_CTRL0 0x06b7 ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY10_CTRL1 0x06b8 ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY10_CTRL2 0x06b9 ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY10_CTRL3 0x06ba ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY10_CTRL4 0x06bb ++#define RTL8367C_ACL_IP_RANGE_ENTRY10_CTRL4_OFFSET 0 ++#define RTL8367C_ACL_IP_RANGE_ENTRY10_CTRL4_MASK 0x7 ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY11_CTRL0 0x06bc ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY11_CTRL1 0x06bd ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY11_CTRL2 0x06be ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY11_CTRL3 0x06bf ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY11_CTRL4 0x06c0 ++#define RTL8367C_ACL_IP_RANGE_ENTRY11_CTRL4_OFFSET 0 ++#define RTL8367C_ACL_IP_RANGE_ENTRY11_CTRL4_MASK 0x7 ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY12_CTRL0 0x06c1 ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY12_CTRL1 0x06c2 ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY12_CTRL2 0x06c3 ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY12_CTRL3 0x06c4 ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY12_CTRL4 0x06c5 ++#define RTL8367C_ACL_IP_RANGE_ENTRY12_CTRL4_OFFSET 0 ++#define RTL8367C_ACL_IP_RANGE_ENTRY12_CTRL4_MASK 0x7 ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY13_CTRL0 0x06c6 ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY13_CTRL1 0x06c7 ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY13_CTRL2 0x06c8 ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY13_CTRL3 0x06c9 ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY13_CTRL4 0x06ca ++#define RTL8367C_ACL_IP_RANGE_ENTRY13_CTRL4_OFFSET 0 ++#define RTL8367C_ACL_IP_RANGE_ENTRY13_CTRL4_MASK 0x7 ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY14_CTRL0 0x06cb ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY14_CTRL1 0x06cc ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY14_CTRL2 0x06cd ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY14_CTRL3 0x06ce ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY14_CTRL4 0x06cf ++#define RTL8367C_ACL_IP_RANGE_ENTRY14_CTRL4_OFFSET 0 ++#define RTL8367C_ACL_IP_RANGE_ENTRY14_CTRL4_MASK 0x7 ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY15_CTRL0 0x06d0 ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY15_CTRL1 0x06d1 ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY15_CTRL2 0x06d2 ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY15_CTRL3 0x06d3 ++ ++#define RTL8367C_REG_ACL_IP_RANGE_ENTRY15_CTRL4 0x06d4 ++#define RTL8367C_ACL_IP_RANGE_ENTRY15_CTRL4_OFFSET 0 ++#define RTL8367C_ACL_IP_RANGE_ENTRY15_CTRL4_MASK 0x7 ++ ++#define RTL8367C_REG_ACL_ENABLE 0x06d5 ++#define RTL8367C_PORT10_ENABLE_OFFSET 10 ++#define RTL8367C_PORT10_ENABLE_MASK 0x400 ++#define RTL8367C_PORT9_ENABLE_OFFSET 9 ++#define RTL8367C_PORT9_ENABLE_MASK 0x200 ++#define RTL8367C_PORT8_ENABLE_OFFSET 8 ++#define RTL8367C_PORT8_ENABLE_MASK 0x100 ++#define RTL8367C_PORT7_ENABLE_OFFSET 7 ++#define RTL8367C_PORT7_ENABLE_MASK 0x80 ++#define RTL8367C_PORT6_ENABLE_OFFSET 6 ++#define RTL8367C_PORT6_ENABLE_MASK 0x40 ++#define RTL8367C_PORT5_ENABLE_OFFSET 5 ++#define RTL8367C_PORT5_ENABLE_MASK 0x20 ++#define RTL8367C_PORT4_ENABLE_OFFSET 4 ++#define RTL8367C_PORT4_ENABLE_MASK 0x10 ++#define RTL8367C_PORT3_ENABLE_OFFSET 3 ++#define RTL8367C_PORT3_ENABLE_MASK 0x8 ++#define RTL8367C_PORT2_ENABLE_OFFSET 2 ++#define RTL8367C_PORT2_ENABLE_MASK 0x4 ++#define RTL8367C_PORT1_ENABLE_OFFSET 1 ++#define RTL8367C_PORT1_ENABLE_MASK 0x2 ++#define RTL8367C_PORT0_ENABLE_OFFSET 0 ++#define RTL8367C_PORT0_ENABLE_MASK 0x1 ++ ++#define RTL8367C_REG_ACL_UNMATCH_PERMIT 0x06d6 ++#define RTL8367C_PORT10_PERMIT_OFFSET 10 ++#define RTL8367C_PORT10_PERMIT_MASK 0x400 ++#define RTL8367C_PORT9_PERMIT_OFFSET 9 ++#define RTL8367C_PORT9_PERMIT_MASK 0x200 ++#define RTL8367C_PORT8_PERMIT_OFFSET 8 ++#define RTL8367C_PORT8_PERMIT_MASK 0x100 ++#define RTL8367C_PORT7_PERMIT_OFFSET 7 ++#define RTL8367C_PORT7_PERMIT_MASK 0x80 ++#define RTL8367C_PORT6_PERMIT_OFFSET 6 ++#define RTL8367C_PORT6_PERMIT_MASK 0x40 ++#define RTL8367C_PORT5_PERMIT_OFFSET 5 ++#define RTL8367C_PORT5_PERMIT_MASK 0x20 ++#define RTL8367C_PORT4_PERMIT_OFFSET 4 ++#define RTL8367C_PORT4_PERMIT_MASK 0x10 ++#define RTL8367C_PORT3_PERMIT_OFFSET 3 ++#define RTL8367C_PORT3_PERMIT_MASK 0x8 ++#define RTL8367C_PORT2_PERMIT_OFFSET 2 ++#define RTL8367C_PORT2_PERMIT_MASK 0x4 ++#define RTL8367C_PORT1_PERMIT_OFFSET 1 ++#define RTL8367C_PORT1_PERMIT_MASK 0x2 ++#define RTL8367C_PORT0_PERMIT_OFFSET 0 ++#define RTL8367C_PORT0_PERMIT_MASK 0x1 ++ ++#define RTL8367C_REG_ACL_GPIO_POLARITY 0x06d7 ++#define RTL8367C_ACL_GPIO_POLARITY_OFFSET 0 ++#define RTL8367C_ACL_GPIO_POLARITY_MASK 0x1 ++ ++#define RTL8367C_REG_ACL_LOG_CNT_TYPE 0x06d8 ++#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER15_TYPE_OFFSET 15 ++#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER15_TYPE_MASK 0x8000 ++#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER14_TYPE_OFFSET 14 ++#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER14_TYPE_MASK 0x4000 ++#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER13_TYPE_OFFSET 13 ++#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER13_TYPE_MASK 0x2000 ++#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER12_TYPE_OFFSET 12 ++#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER12_TYPE_MASK 0x1000 ++#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER11_TYPE_OFFSET 11 ++#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER11_TYPE_MASK 0x800 ++#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER10_TYPE_OFFSET 10 ++#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER10_TYPE_MASK 0x400 ++#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER9_TYPE_OFFSET 9 ++#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER9_TYPE_MASK 0x200 ++#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER8_TYPE_OFFSET 8 ++#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER8_TYPE_MASK 0x100 ++#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER7_TYPE_OFFSET 7 ++#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER7_TYPE_MASK 0x80 ++#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER6_TYPE_OFFSET 6 ++#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER6_TYPE_MASK 0x40 ++#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER5_TYPE_OFFSET 5 ++#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER5_TYPE_MASK 0x20 ++#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER4_TYPE_OFFSET 4 ++#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER4_TYPE_MASK 0x10 ++#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER3_TYPE_OFFSET 3 ++#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER3_TYPE_MASK 0x8 ++#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER2_TYPE_OFFSET 2 ++#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER2_TYPE_MASK 0x4 ++#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER1_TYPE_OFFSET 1 ++#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER1_TYPE_MASK 0x2 ++#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER0_TYPE_OFFSET 0 ++#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER0_TYPE_MASK 0x1 ++ ++#define RTL8367C_REG_ACL_RESET_CFG 0x06d9 ++#define RTL8367C_ACL_RESET_CFG_OFFSET 0 ++#define RTL8367C_ACL_RESET_CFG_MASK 0x1 ++ ++#define RTL8367C_REG_ACL_DUMMY00 0x06E0 ++ ++#define RTL8367C_REG_ACL_DUMMY01 0x06E1 ++ ++#define RTL8367C_REG_ACL_DUMMY02 0x06E2 ++ ++#define RTL8367C_REG_ACL_DUMMY03 0x06E3 ++ ++#define RTL8367C_REG_ACL_DUMMY04 0x06E4 ++ ++#define RTL8367C_REG_ACL_DUMMY05 0x06E5 ++ ++#define RTL8367C_REG_ACL_DUMMY06 0x06E6 ++ ++#define RTL8367C_REG_ACL_DUMMY07 0x06E7 ++ ++#define RTL8367C_REG_ACL_REASON_01 0x06E8 ++#define RTL8367C_ACL_ACT_1_OFFSET 8 ++#define RTL8367C_ACL_ACT_1_MASK 0xFF00 ++#define RTL8367C_ACL_ACT_0_OFFSET 0 ++#define RTL8367C_ACL_ACT_0_MASK 0xFF ++ ++#define RTL8367C_REG_ACL_REASON_23 0x06E9 ++#define RTL8367C_ACL_ACT_3_OFFSET 8 ++#define RTL8367C_ACL_ACT_3_MASK 0xFF00 ++#define RTL8367C_ACL_ACT_2_OFFSET 0 ++#define RTL8367C_ACL_ACT_2_MASK 0xFF ++ ++#define RTL8367C_REG_ACL_REASON_45 0x06EA ++#define RTL8367C_ACL_ACT_5_OFFSET 8 ++#define RTL8367C_ACL_ACT_5_MASK 0xFF00 ++#define RTL8367C_ACL_ACT_4_OFFSET 0 ++#define RTL8367C_ACL_ACT_4_MASK 0xFF ++ ++#define RTL8367C_REG_ACL_ACCESS_MODE 0x06EB ++#define RTL8367C_ACL_ACCESS_MODE_OFFSET 0 ++#define RTL8367C_ACL_ACCESS_MODE_MASK 0x1 ++ ++#define RTL8367C_REG_ACL_ACTION_CTRL32 0x06F0 ++#define RTL8367C_OP65_NOT_OFFSET 14 ++#define RTL8367C_OP65_NOT_MASK 0x4000 ++#define RTL8367C_ACT65_GPIO_OFFSET 13 ++#define RTL8367C_ACT65_GPIO_MASK 0x2000 ++#define RTL8367C_ACT65_FORWARD_OFFSET 12 ++#define RTL8367C_ACT65_FORWARD_MASK 0x1000 ++#define RTL8367C_ACT65_POLICING_OFFSET 11 ++#define RTL8367C_ACT65_POLICING_MASK 0x800 ++#define RTL8367C_ACT65_PRIORITY_OFFSET 10 ++#define RTL8367C_ACT65_PRIORITY_MASK 0x400 ++#define RTL8367C_ACT65_SVID_OFFSET 9 ++#define RTL8367C_ACT65_SVID_MASK 0x200 ++#define RTL8367C_ACT65_CVID_OFFSET 8 ++#define RTL8367C_ACT65_CVID_MASK 0x100 ++#define RTL8367C_OP64_NOT_OFFSET 6 ++#define RTL8367C_OP64_NOT_MASK 0x40 ++#define RTL8367C_ACT64_GPIO_OFFSET 5 ++#define RTL8367C_ACT64_GPIO_MASK 0x20 ++#define RTL8367C_ACT64_FORWARD_OFFSET 4 ++#define RTL8367C_ACT64_FORWARD_MASK 0x10 ++#define RTL8367C_ACT64_POLICING_OFFSET 3 ++#define RTL8367C_ACT64_POLICING_MASK 0x8 ++#define RTL8367C_ACT64_PRIORITY_OFFSET 2 ++#define RTL8367C_ACT64_PRIORITY_MASK 0x4 ++#define RTL8367C_ACT64_SVID_OFFSET 1 ++#define RTL8367C_ACT64_SVID_MASK 0x2 ++#define RTL8367C_ACT64_CVID_OFFSET 0 ++#define RTL8367C_ACT64_CVID_MASK 0x1 ++ ++#define RTL8367C_REG_ACL_ACTION_CTRL33 0x06F1 ++#define RTL8367C_OP67_NOT_OFFSET 14 ++#define RTL8367C_OP67_NOT_MASK 0x4000 ++#define RTL8367C_ACT67_GPIO_OFFSET 13 ++#define RTL8367C_ACT67_GPIO_MASK 0x2000 ++#define RTL8367C_ACT67_FORWARD_OFFSET 12 ++#define RTL8367C_ACT67_FORWARD_MASK 0x1000 ++#define RTL8367C_ACT67_POLICING_OFFSET 11 ++#define RTL8367C_ACT67_POLICING_MASK 0x800 ++#define RTL8367C_ACT67_PRIORITY_OFFSET 10 ++#define RTL8367C_ACT67_PRIORITY_MASK 0x400 ++#define RTL8367C_ACT67_SVID_OFFSET 9 ++#define RTL8367C_ACT67_SVID_MASK 0x200 ++#define RTL8367C_ACT67_CVID_OFFSET 8 ++#define RTL8367C_ACT67_CVID_MASK 0x100 ++#define RTL8367C_OP66_NOT_OFFSET 6 ++#define RTL8367C_OP66_NOT_MASK 0x40 ++#define RTL8367C_ACT66_GPIO_OFFSET 5 ++#define RTL8367C_ACT66_GPIO_MASK 0x20 ++#define RTL8367C_ACT66_FORWARD_OFFSET 4 ++#define RTL8367C_ACT66_FORWARD_MASK 0x10 ++#define RTL8367C_ACT66_POLICING_OFFSET 3 ++#define RTL8367C_ACT66_POLICING_MASK 0x8 ++#define RTL8367C_ACT66_PRIORITY_OFFSET 2 ++#define RTL8367C_ACT66_PRIORITY_MASK 0x4 ++#define RTL8367C_ACT66_SVID_OFFSET 1 ++#define RTL8367C_ACT66_SVID_MASK 0x2 ++#define RTL8367C_ACT66_CVID_OFFSET 0 ++#define RTL8367C_ACT66_CVID_MASK 0x1 ++ ++#define RTL8367C_REG_ACL_ACTION_CTRL34 0x06F2 ++#define RTL8367C_OP69_NOT_OFFSET 14 ++#define RTL8367C_OP69_NOT_MASK 0x4000 ++#define RTL8367C_ACT69_GPIO_OFFSET 13 ++#define RTL8367C_ACT69_GPIO_MASK 0x2000 ++#define RTL8367C_ACT69_FORWARD_OFFSET 12 ++#define RTL8367C_ACT69_FORWARD_MASK 0x1000 ++#define RTL8367C_ACT69_POLICING_OFFSET 11 ++#define RTL8367C_ACT69_POLICING_MASK 0x800 ++#define RTL8367C_ACT69_PRIORITY_OFFSET 10 ++#define RTL8367C_ACT69_PRIORITY_MASK 0x400 ++#define RTL8367C_ACT69_SVID_OFFSET 9 ++#define RTL8367C_ACT69_SVID_MASK 0x200 ++#define RTL8367C_ACT69_CVID_OFFSET 8 ++#define RTL8367C_ACT69_CVID_MASK 0x100 ++#define RTL8367C_OP68_NOT_OFFSET 6 ++#define RTL8367C_OP68_NOT_MASK 0x40 ++#define RTL8367C_ACT68_GPIO_OFFSET 5 ++#define RTL8367C_ACT68_GPIO_MASK 0x20 ++#define RTL8367C_ACT68_FORWARD_OFFSET 4 ++#define RTL8367C_ACT68_FORWARD_MASK 0x10 ++#define RTL8367C_ACT68_POLICING_OFFSET 3 ++#define RTL8367C_ACT68_POLICING_MASK 0x8 ++#define RTL8367C_ACT68_PRIORITY_OFFSET 2 ++#define RTL8367C_ACT68_PRIORITY_MASK 0x4 ++#define RTL8367C_ACT68_SVID_OFFSET 1 ++#define RTL8367C_ACT68_SVID_MASK 0x2 ++#define RTL8367C_ACT68_CVID_OFFSET 0 ++#define RTL8367C_ACT68_CVID_MASK 0x1 ++ ++#define RTL8367C_REG_ACL_ACTION_CTRL35 0x06F3 ++#define RTL8367C_OP71_NOT_OFFSET 14 ++#define RTL8367C_OP71_NOT_MASK 0x4000 ++#define RTL8367C_ACT71_GPIO_OFFSET 13 ++#define RTL8367C_ACT71_GPIO_MASK 0x2000 ++#define RTL8367C_ACT71_FORWARD_OFFSET 12 ++#define RTL8367C_ACT71_FORWARD_MASK 0x1000 ++#define RTL8367C_ACT71_POLICING_OFFSET 11 ++#define RTL8367C_ACT71_POLICING_MASK 0x800 ++#define RTL8367C_ACT71_PRIORITY_OFFSET 10 ++#define RTL8367C_ACT71_PRIORITY_MASK 0x400 ++#define RTL8367C_ACT71_SVID_OFFSET 9 ++#define RTL8367C_ACT71_SVID_MASK 0x200 ++#define RTL8367C_ACT71_CVID_OFFSET 8 ++#define RTL8367C_ACT71_CVID_MASK 0x100 ++#define RTL8367C_OP70_NOT_OFFSET 6 ++#define RTL8367C_OP70_NOT_MASK 0x40 ++#define RTL8367C_ACT70_GPIO_OFFSET 5 ++#define RTL8367C_ACT70_GPIO_MASK 0x20 ++#define RTL8367C_ACT70_FORWARD_OFFSET 4 ++#define RTL8367C_ACT70_FORWARD_MASK 0x10 ++#define RTL8367C_ACT70_POLICING_OFFSET 3 ++#define RTL8367C_ACT70_POLICING_MASK 0x8 ++#define RTL8367C_ACT70_PRIORITY_OFFSET 2 ++#define RTL8367C_ACT70_PRIORITY_MASK 0x4 ++#define RTL8367C_ACT70_SVID_OFFSET 1 ++#define RTL8367C_ACT70_SVID_MASK 0x2 ++#define RTL8367C_ACT70_CVID_OFFSET 0 ++#define RTL8367C_ACT70_CVID_MASK 0x1 ++ ++#define RTL8367C_REG_ACL_ACTION_CTRL36 0x06F4 ++#define RTL8367C_OP73_NOT_OFFSET 14 ++#define RTL8367C_OP73_NOT_MASK 0x4000 ++#define RTL8367C_ACT73_GPIO_OFFSET 13 ++#define RTL8367C_ACT73_GPIO_MASK 0x2000 ++#define RTL8367C_ACT73_FORWARD_OFFSET 12 ++#define RTL8367C_ACT73_FORWARD_MASK 0x1000 ++#define RTL8367C_ACT73_POLICING_OFFSET 11 ++#define RTL8367C_ACT73_POLICING_MASK 0x800 ++#define RTL8367C_ACT73_PRIORITY_OFFSET 10 ++#define RTL8367C_ACT73_PRIORITY_MASK 0x400 ++#define RTL8367C_ACT73_SVID_OFFSET 9 ++#define RTL8367C_ACT73_SVID_MASK 0x200 ++#define RTL8367C_ACT73_CVID_OFFSET 8 ++#define RTL8367C_ACT73_CVID_MASK 0x100 ++#define RTL8367C_OP72_NOT_OFFSET 6 ++#define RTL8367C_OP72_NOT_MASK 0x40 ++#define RTL8367C_ACT72_GPIO_OFFSET 5 ++#define RTL8367C_ACT72_GPIO_MASK 0x20 ++#define RTL8367C_ACT72_FORWARD_OFFSET 4 ++#define RTL8367C_ACT72_FORWARD_MASK 0x10 ++#define RTL8367C_ACT72_POLICING_OFFSET 3 ++#define RTL8367C_ACT72_POLICING_MASK 0x8 ++#define RTL8367C_ACT72_PRIORITY_OFFSET 2 ++#define RTL8367C_ACT72_PRIORITY_MASK 0x4 ++#define RTL8367C_ACT72_SVID_OFFSET 1 ++#define RTL8367C_ACT72_SVID_MASK 0x2 ++#define RTL8367C_ACT72_CVID_OFFSET 0 ++#define RTL8367C_ACT72_CVID_MASK 0x1 ++ ++#define RTL8367C_REG_ACL_ACTION_CTRL37 0x06F5 ++#define RTL8367C_OP75_NOT_OFFSET 14 ++#define RTL8367C_OP75_NOT_MASK 0x4000 ++#define RTL8367C_ACT75_GPIO_OFFSET 13 ++#define RTL8367C_ACT75_GPIO_MASK 0x2000 ++#define RTL8367C_ACT75_FORWARD_OFFSET 12 ++#define RTL8367C_ACT75_FORWARD_MASK 0x1000 ++#define RTL8367C_ACT75_POLICING_OFFSET 11 ++#define RTL8367C_ACT75_POLICING_MASK 0x800 ++#define RTL8367C_ACT75_PRIORITY_OFFSET 10 ++#define RTL8367C_ACT75_PRIORITY_MASK 0x400 ++#define RTL8367C_ACT75_SVID_OFFSET 9 ++#define RTL8367C_ACT75_SVID_MASK 0x200 ++#define RTL8367C_ACT75_CVID_OFFSET 8 ++#define RTL8367C_ACT75_CVID_MASK 0x100 ++#define RTL8367C_OP74_NOT_OFFSET 6 ++#define RTL8367C_OP74_NOT_MASK 0x40 ++#define RTL8367C_ACT74_GPIO_OFFSET 5 ++#define RTL8367C_ACT74_GPIO_MASK 0x20 ++#define RTL8367C_ACT74_FORWARD_OFFSET 4 ++#define RTL8367C_ACT74_FORWARD_MASK 0x10 ++#define RTL8367C_ACT74_POLICING_OFFSET 3 ++#define RTL8367C_ACT74_POLICING_MASK 0x8 ++#define RTL8367C_ACT74_PRIORITY_OFFSET 2 ++#define RTL8367C_ACT74_PRIORITY_MASK 0x4 ++#define RTL8367C_ACT74_SVID_OFFSET 1 ++#define RTL8367C_ACT74_SVID_MASK 0x2 ++#define RTL8367C_ACT74_CVID_OFFSET 0 ++#define RTL8367C_ACT74_CVID_MASK 0x1 ++ ++#define RTL8367C_REG_ACL_ACTION_CTRL38 0x06F6 ++#define RTL8367C_OP77_NOT_OFFSET 14 ++#define RTL8367C_OP77_NOT_MASK 0x4000 ++#define RTL8367C_ACT77_GPIO_OFFSET 13 ++#define RTL8367C_ACT77_GPIO_MASK 0x2000 ++#define RTL8367C_ACT77_FORWARD_OFFSET 12 ++#define RTL8367C_ACT77_FORWARD_MASK 0x1000 ++#define RTL8367C_ACT77_POLICING_OFFSET 11 ++#define RTL8367C_ACT77_POLICING_MASK 0x800 ++#define RTL8367C_ACT77_PRIORITY_OFFSET 10 ++#define RTL8367C_ACT77_PRIORITY_MASK 0x400 ++#define RTL8367C_ACT77_SVID_OFFSET 9 ++#define RTL8367C_ACT77_SVID_MASK 0x200 ++#define RTL8367C_ACT77_CVID_OFFSET 8 ++#define RTL8367C_ACT77_CVID_MASK 0x100 ++#define RTL8367C_OP76_NOT_OFFSET 6 ++#define RTL8367C_OP76_NOT_MASK 0x40 ++#define RTL8367C_ACT76_GPIO_OFFSET 5 ++#define RTL8367C_ACT76_GPIO_MASK 0x20 ++#define RTL8367C_ACT76_FORWARD_OFFSET 4 ++#define RTL8367C_ACT76_FORWARD_MASK 0x10 ++#define RTL8367C_ACT76_POLICING_OFFSET 3 ++#define RTL8367C_ACT76_POLICING_MASK 0x8 ++#define RTL8367C_ACT76_PRIORITY_OFFSET 2 ++#define RTL8367C_ACT76_PRIORITY_MASK 0x4 ++#define RTL8367C_ACT76_SVID_OFFSET 1 ++#define RTL8367C_ACT76_SVID_MASK 0x2 ++#define RTL8367C_ACT76_CVID_OFFSET 0 ++#define RTL8367C_ACT76_CVID_MASK 0x1 ++ ++#define RTL8367C_REG_ACL_ACTION_CTRL39 0x06F7 ++#define RTL8367C_OP79_NOT_OFFSET 14 ++#define RTL8367C_OP79_NOT_MASK 0x4000 ++#define RTL8367C_ACT79_GPIO_OFFSET 13 ++#define RTL8367C_ACT79_GPIO_MASK 0x2000 ++#define RTL8367C_ACT79_FORWARD_OFFSET 12 ++#define RTL8367C_ACT79_FORWARD_MASK 0x1000 ++#define RTL8367C_ACT79_POLICING_OFFSET 11 ++#define RTL8367C_ACT79_POLICING_MASK 0x800 ++#define RTL8367C_ACT79_PRIORITY_OFFSET 10 ++#define RTL8367C_ACT79_PRIORITY_MASK 0x400 ++#define RTL8367C_ACT79_SVID_OFFSET 9 ++#define RTL8367C_ACT79_SVID_MASK 0x200 ++#define RTL8367C_ACT79_CVID_OFFSET 8 ++#define RTL8367C_ACT79_CVID_MASK 0x100 ++#define RTL8367C_OP78_NOT_OFFSET 6 ++#define RTL8367C_OP78_NOT_MASK 0x40 ++#define RTL8367C_ACT78_GPIO_OFFSET 5 ++#define RTL8367C_ACT78_GPIO_MASK 0x20 ++#define RTL8367C_ACT78_FORWARD_OFFSET 4 ++#define RTL8367C_ACT78_FORWARD_MASK 0x10 ++#define RTL8367C_ACT78_POLICING_OFFSET 3 ++#define RTL8367C_ACT78_POLICING_MASK 0x8 ++#define RTL8367C_ACT78_PRIORITY_OFFSET 2 ++#define RTL8367C_ACT78_PRIORITY_MASK 0x4 ++#define RTL8367C_ACT78_SVID_OFFSET 1 ++#define RTL8367C_ACT78_SVID_MASK 0x2 ++#define RTL8367C_ACT78_CVID_OFFSET 0 ++#define RTL8367C_ACT78_CVID_MASK 0x1 ++ ++#define RTL8367C_REG_ACL_ACTION_CTRL40 0x06F8 ++#define RTL8367C_OP81_NOT_OFFSET 14 ++#define RTL8367C_OP81_NOT_MASK 0x4000 ++#define RTL8367C_ACT81_GPIO_OFFSET 13 ++#define RTL8367C_ACT81_GPIO_MASK 0x2000 ++#define RTL8367C_ACT81_FORWARD_OFFSET 12 ++#define RTL8367C_ACT81_FORWARD_MASK 0x1000 ++#define RTL8367C_ACT81_POLICING_OFFSET 11 ++#define RTL8367C_ACT81_POLICING_MASK 0x800 ++#define RTL8367C_ACT81_PRIORITY_OFFSET 10 ++#define RTL8367C_ACT81_PRIORITY_MASK 0x400 ++#define RTL8367C_ACT81_SVID_OFFSET 9 ++#define RTL8367C_ACT81_SVID_MASK 0x200 ++#define RTL8367C_ACT81_CVID_OFFSET 8 ++#define RTL8367C_ACT81_CVID_MASK 0x100 ++#define RTL8367C_OP80_NOT_OFFSET 6 ++#define RTL8367C_OP80_NOT_MASK 0x40 ++#define RTL8367C_ACT80_GPIO_OFFSET 5 ++#define RTL8367C_ACT80_GPIO_MASK 0x20 ++#define RTL8367C_ACT80_FORWARD_OFFSET 4 ++#define RTL8367C_ACT80_FORWARD_MASK 0x10 ++#define RTL8367C_ACT80_POLICING_OFFSET 3 ++#define RTL8367C_ACT80_POLICING_MASK 0x8 ++#define RTL8367C_ACT80_PRIORITY_OFFSET 2 ++#define RTL8367C_ACT80_PRIORITY_MASK 0x4 ++#define RTL8367C_ACT80_SVID_OFFSET 1 ++#define RTL8367C_ACT80_SVID_MASK 0x2 ++#define RTL8367C_ACT80_CVID_OFFSET 0 ++#define RTL8367C_ACT80_CVID_MASK 0x1 ++ ++#define RTL8367C_REG_ACL_ACTION_CTRL41 0x06F9 ++#define RTL8367C_OP83_NOT_OFFSET 14 ++#define RTL8367C_OP83_NOT_MASK 0x4000 ++#define RTL8367C_ACT83_GPIO_OFFSET 13 ++#define RTL8367C_ACT83_GPIO_MASK 0x2000 ++#define RTL8367C_ACT83_FORWARD_OFFSET 12 ++#define RTL8367C_ACT83_FORWARD_MASK 0x1000 ++#define RTL8367C_ACT83_POLICING_OFFSET 11 ++#define RTL8367C_ACT83_POLICING_MASK 0x800 ++#define RTL8367C_ACT83_PRIORITY_OFFSET 10 ++#define RTL8367C_ACT83_PRIORITY_MASK 0x400 ++#define RTL8367C_ACT83_SVID_OFFSET 9 ++#define RTL8367C_ACT83_SVID_MASK 0x200 ++#define RTL8367C_ACT83_CVID_OFFSET 8 ++#define RTL8367C_ACT83_CVID_MASK 0x100 ++#define RTL8367C_OP82_NOT_OFFSET 6 ++#define RTL8367C_OP82_NOT_MASK 0x40 ++#define RTL8367C_ACT82_GPIO_OFFSET 5 ++#define RTL8367C_ACT82_GPIO_MASK 0x20 ++#define RTL8367C_ACT82_FORWARD_OFFSET 4 ++#define RTL8367C_ACT82_FORWARD_MASK 0x10 ++#define RTL8367C_ACT82_POLICING_OFFSET 3 ++#define RTL8367C_ACT82_POLICING_MASK 0x8 ++#define RTL8367C_ACT82_PRIORITY_OFFSET 2 ++#define RTL8367C_ACT82_PRIORITY_MASK 0x4 ++#define RTL8367C_ACT82_SVID_OFFSET 1 ++#define RTL8367C_ACT82_SVID_MASK 0x2 ++#define RTL8367C_ACT82_CVID_OFFSET 0 ++#define RTL8367C_ACT82_CVID_MASK 0x1 ++ ++#define RTL8367C_REG_ACL_ACTION_CTRL42 0x06FA ++#define RTL8367C_OP85_NOT_OFFSET 14 ++#define RTL8367C_OP85_NOT_MASK 0x4000 ++#define RTL8367C_ACT85_GPIO_OFFSET 13 ++#define RTL8367C_ACT85_GPIO_MASK 0x2000 ++#define RTL8367C_ACT85_FORWARD_OFFSET 12 ++#define RTL8367C_ACT85_FORWARD_MASK 0x1000 ++#define RTL8367C_ACT85_POLICING_OFFSET 11 ++#define RTL8367C_ACT85_POLICING_MASK 0x800 ++#define RTL8367C_ACT85_PRIORITY_OFFSET 10 ++#define RTL8367C_ACT85_PRIORITY_MASK 0x400 ++#define RTL8367C_ACT85_SVID_OFFSET 9 ++#define RTL8367C_ACT85_SVID_MASK 0x200 ++#define RTL8367C_ACT85_CVID_OFFSET 8 ++#define RTL8367C_ACT85_CVID_MASK 0x100 ++#define RTL8367C_OP84_NOT_OFFSET 6 ++#define RTL8367C_OP84_NOT_MASK 0x40 ++#define RTL8367C_ACT84_GPIO_OFFSET 5 ++#define RTL8367C_ACT84_GPIO_MASK 0x20 ++#define RTL8367C_ACT84_FORWARD_OFFSET 4 ++#define RTL8367C_ACT84_FORWARD_MASK 0x10 ++#define RTL8367C_ACT84_POLICING_OFFSET 3 ++#define RTL8367C_ACT84_POLICING_MASK 0x8 ++#define RTL8367C_ACT84_PRIORITY_OFFSET 2 ++#define RTL8367C_ACT84_PRIORITY_MASK 0x4 ++#define RTL8367C_ACT84_SVID_OFFSET 1 ++#define RTL8367C_ACT84_SVID_MASK 0x2 ++#define RTL8367C_ACT84_CVID_OFFSET 0 ++#define RTL8367C_ACT84_CVID_MASK 0x1 ++ ++#define RTL8367C_REG_ACL_ACTION_CTRL43 0x06FB ++#define RTL8367C_OP87_NOT_OFFSET 14 ++#define RTL8367C_OP87_NOT_MASK 0x4000 ++#define RTL8367C_ACT87_GPIO_OFFSET 13 ++#define RTL8367C_ACT87_GPIO_MASK 0x2000 ++#define RTL8367C_ACT87_FORWARD_OFFSET 12 ++#define RTL8367C_ACT87_FORWARD_MASK 0x1000 ++#define RTL8367C_ACT87_POLICING_OFFSET 11 ++#define RTL8367C_ACT87_POLICING_MASK 0x800 ++#define RTL8367C_ACT87_PRIORITY_OFFSET 10 ++#define RTL8367C_ACT87_PRIORITY_MASK 0x400 ++#define RTL8367C_ACT87_SVID_OFFSET 9 ++#define RTL8367C_ACT87_SVID_MASK 0x200 ++#define RTL8367C_ACT87_CVID_OFFSET 8 ++#define RTL8367C_ACT87_CVID_MASK 0x100 ++#define RTL8367C_OP86_NOT_OFFSET 6 ++#define RTL8367C_OP86_NOT_MASK 0x40 ++#define RTL8367C_ACT86_GPIO_OFFSET 5 ++#define RTL8367C_ACT86_GPIO_MASK 0x20 ++#define RTL8367C_ACT86_FORWARD_OFFSET 4 ++#define RTL8367C_ACT86_FORWARD_MASK 0x10 ++#define RTL8367C_ACT86_POLICING_OFFSET 3 ++#define RTL8367C_ACT86_POLICING_MASK 0x8 ++#define RTL8367C_ACT86_PRIORITY_OFFSET 2 ++#define RTL8367C_ACT86_PRIORITY_MASK 0x4 ++#define RTL8367C_ACT86_SVID_OFFSET 1 ++#define RTL8367C_ACT86_SVID_MASK 0x2 ++#define RTL8367C_ACT86_CVID_OFFSET 0 ++#define RTL8367C_ACT86_CVID_MASK 0x1 ++ ++#define RTL8367C_REG_ACL_ACTION_CTRL44 0x06FC ++#define RTL8367C_OP89_NOT_OFFSET 14 ++#define RTL8367C_OP89_NOT_MASK 0x4000 ++#define RTL8367C_ACT89_GPIO_OFFSET 13 ++#define RTL8367C_ACT89_GPIO_MASK 0x2000 ++#define RTL8367C_ACT89_FORWARD_OFFSET 12 ++#define RTL8367C_ACT89_FORWARD_MASK 0x1000 ++#define RTL8367C_ACT89_POLICING_OFFSET 11 ++#define RTL8367C_ACT89_POLICING_MASK 0x800 ++#define RTL8367C_ACT89_PRIORITY_OFFSET 10 ++#define RTL8367C_ACT89_PRIORITY_MASK 0x400 ++#define RTL8367C_ACT89_SVID_OFFSET 9 ++#define RTL8367C_ACT89_SVID_MASK 0x200 ++#define RTL8367C_ACT89_CVID_OFFSET 8 ++#define RTL8367C_ACT89_CVID_MASK 0x100 ++#define RTL8367C_OP88_NOT_OFFSET 6 ++#define RTL8367C_OP88_NOT_MASK 0x40 ++#define RTL8367C_ACT88_GPIO_OFFSET 5 ++#define RTL8367C_ACT88_GPIO_MASK 0x20 ++#define RTL8367C_ACT88_FORWARD_OFFSET 4 ++#define RTL8367C_ACT88_FORWARD_MASK 0x10 ++#define RTL8367C_ACT88_POLICING_OFFSET 3 ++#define RTL8367C_ACT88_POLICING_MASK 0x8 ++#define RTL8367C_ACT88_PRIORITY_OFFSET 2 ++#define RTL8367C_ACT88_PRIORITY_MASK 0x4 ++#define RTL8367C_ACT88_SVID_OFFSET 1 ++#define RTL8367C_ACT88_SVID_MASK 0x2 ++#define RTL8367C_ACT88_CVID_OFFSET 0 ++#define RTL8367C_ACT88_CVID_MASK 0x1 ++ ++#define RTL8367C_REG_ACL_ACTION_CTRL45 0x06FD ++#define RTL8367C_OP91_NOT_OFFSET 14 ++#define RTL8367C_OP91_NOT_MASK 0x4000 ++#define RTL8367C_ACT91_GPIO_OFFSET 13 ++#define RTL8367C_ACT91_GPIO_MASK 0x2000 ++#define RTL8367C_ACT91_FORWARD_OFFSET 12 ++#define RTL8367C_ACT91_FORWARD_MASK 0x1000 ++#define RTL8367C_ACT91_POLICING_OFFSET 11 ++#define RTL8367C_ACT91_POLICING_MASK 0x800 ++#define RTL8367C_ACT91_PRIORITY_OFFSET 10 ++#define RTL8367C_ACT91_PRIORITY_MASK 0x400 ++#define RTL8367C_ACT91_SVID_OFFSET 9 ++#define RTL8367C_ACT91_SVID_MASK 0x200 ++#define RTL8367C_ACT91_CVID_OFFSET 8 ++#define RTL8367C_ACT91_CVID_MASK 0x100 ++#define RTL8367C_OP90_NOT_OFFSET 6 ++#define RTL8367C_OP90_NOT_MASK 0x40 ++#define RTL8367C_ACT90_GPIO_OFFSET 5 ++#define RTL8367C_ACT90_GPIO_MASK 0x20 ++#define RTL8367C_ACT90_FORWARD_OFFSET 4 ++#define RTL8367C_ACT90_FORWARD_MASK 0x10 ++#define RTL8367C_ACT90_POLICING_OFFSET 3 ++#define RTL8367C_ACT90_POLICING_MASK 0x8 ++#define RTL8367C_ACT90_PRIORITY_OFFSET 2 ++#define RTL8367C_ACT90_PRIORITY_MASK 0x4 ++#define RTL8367C_ACT90_SVID_OFFSET 1 ++#define RTL8367C_ACT90_SVID_MASK 0x2 ++#define RTL8367C_ACT90_CVID_OFFSET 0 ++#define RTL8367C_ACT90_CVID_MASK 0x1 ++ ++#define RTL8367C_REG_ACL_ACTION_CTRL46 0x06FE ++#define RTL8367C_OP93_NOT_OFFSET 14 ++#define RTL8367C_OP93_NOT_MASK 0x4000 ++#define RTL8367C_ACT93_GPIO_OFFSET 13 ++#define RTL8367C_ACT93_GPIO_MASK 0x2000 ++#define RTL8367C_ACT93_FORWARD_OFFSET 12 ++#define RTL8367C_ACT93_FORWARD_MASK 0x1000 ++#define RTL8367C_ACT93_POLICING_OFFSET 11 ++#define RTL8367C_ACT93_POLICING_MASK 0x800 ++#define RTL8367C_ACT93_PRIORITY_OFFSET 10 ++#define RTL8367C_ACT93_PRIORITY_MASK 0x400 ++#define RTL8367C_ACT93_SVID_OFFSET 9 ++#define RTL8367C_ACT93_SVID_MASK 0x200 ++#define RTL8367C_ACT93_CVID_OFFSET 8 ++#define RTL8367C_ACT93_CVID_MASK 0x100 ++#define RTL8367C_OP92_NOT_OFFSET 6 ++#define RTL8367C_OP92_NOT_MASK 0x40 ++#define RTL8367C_ACT92_GPIO_OFFSET 5 ++#define RTL8367C_ACT92_GPIO_MASK 0x20 ++#define RTL8367C_ACT92_FORWARD_OFFSET 4 ++#define RTL8367C_ACT92_FORWARD_MASK 0x10 ++#define RTL8367C_ACT92_POLICING_OFFSET 3 ++#define RTL8367C_ACT92_POLICING_MASK 0x8 ++#define RTL8367C_ACT92_PRIORITY_OFFSET 2 ++#define RTL8367C_ACT92_PRIORITY_MASK 0x4 ++#define RTL8367C_ACT92_SVID_OFFSET 1 ++#define RTL8367C_ACT92_SVID_MASK 0x2 ++#define RTL8367C_ACT92_CVID_OFFSET 0 ++#define RTL8367C_ACT92_CVID_MASK 0x1 ++ ++#define RTL8367C_REG_ACL_ACTION_CTRL47 0x06FF ++#define RTL8367C_OP95_NOT_OFFSET 14 ++#define RTL8367C_OP95_NOT_MASK 0x4000 ++#define RTL8367C_ACT95_GPIO_OFFSET 13 ++#define RTL8367C_ACT95_GPIO_MASK 0x2000 ++#define RTL8367C_ACT95_FORWARD_OFFSET 12 ++#define RTL8367C_ACT95_FORWARD_MASK 0x1000 ++#define RTL8367C_ACT95_POLICING_OFFSET 11 ++#define RTL8367C_ACT95_POLICING_MASK 0x800 ++#define RTL8367C_ACT95_PRIORITY_OFFSET 10 ++#define RTL8367C_ACT95_PRIORITY_MASK 0x400 ++#define RTL8367C_ACT95_SVID_OFFSET 9 ++#define RTL8367C_ACT95_SVID_MASK 0x200 ++#define RTL8367C_ACT95_CVID_OFFSET 8 ++#define RTL8367C_ACT95_CVID_MASK 0x100 ++#define RTL8367C_OP94_NOT_OFFSET 6 ++#define RTL8367C_OP94_NOT_MASK 0x40 ++#define RTL8367C_ACT94_GPIO_OFFSET 5 ++#define RTL8367C_ACT94_GPIO_MASK 0x20 ++#define RTL8367C_ACT94_FORWARD_OFFSET 4 ++#define RTL8367C_ACT94_FORWARD_MASK 0x10 ++#define RTL8367C_ACT94_POLICING_OFFSET 3 ++#define RTL8367C_ACT94_POLICING_MASK 0x8 ++#define RTL8367C_ACT94_PRIORITY_OFFSET 2 ++#define RTL8367C_ACT94_PRIORITY_MASK 0x4 ++#define RTL8367C_ACT94_SVID_OFFSET 1 ++#define RTL8367C_ACT94_SVID_MASK 0x2 ++#define RTL8367C_ACT94_CVID_OFFSET 0 ++#define RTL8367C_ACT94_CVID_MASK 0x1 ++ ++/* (16'h0700)cvlan_reg */ ++ ++#define RTL8367C_REG_VLAN_PVID_CTRL0 0x0700 ++#define RTL8367C_PORT1_VIDX_OFFSET 8 ++#define RTL8367C_PORT1_VIDX_MASK 0x1F00 ++#define RTL8367C_PORT0_VIDX_OFFSET 0 ++#define RTL8367C_PORT0_VIDX_MASK 0x1F ++ ++#define RTL8367C_REG_VLAN_PVID_CTRL1 0x0701 ++#define RTL8367C_PORT3_VIDX_OFFSET 8 ++#define RTL8367C_PORT3_VIDX_MASK 0x1F00 ++#define RTL8367C_PORT2_VIDX_OFFSET 0 ++#define RTL8367C_PORT2_VIDX_MASK 0x1F ++ ++#define RTL8367C_REG_VLAN_PVID_CTRL2 0x0702 ++#define RTL8367C_PORT5_VIDX_OFFSET 8 ++#define RTL8367C_PORT5_VIDX_MASK 0x1F00 ++#define RTL8367C_PORT4_VIDX_OFFSET 0 ++#define RTL8367C_PORT4_VIDX_MASK 0x1F ++ ++#define RTL8367C_REG_VLAN_PVID_CTRL3 0x0703 ++#define RTL8367C_PORT7_VIDX_OFFSET 8 ++#define RTL8367C_PORT7_VIDX_MASK 0x1F00 ++#define RTL8367C_PORT6_VIDX_OFFSET 0 ++#define RTL8367C_PORT6_VIDX_MASK 0x1F ++ ++#define RTL8367C_REG_VLAN_PVID_CTRL4 0x0704 ++#define RTL8367C_PORT9_VIDX_OFFSET 8 ++#define RTL8367C_PORT9_VIDX_MASK 0x1F00 ++#define RTL8367C_PORT8_VIDX_OFFSET 0 ++#define RTL8367C_PORT8_VIDX_MASK 0x1F ++ ++#define RTL8367C_REG_VLAN_PVID_CTRL5 0x0705 ++#define RTL8367C_VLAN_PVID_CTRL5_OFFSET 0 ++#define RTL8367C_VLAN_PVID_CTRL5_MASK 0x1F ++ ++#define RTL8367C_REG_VLAN_PPB0_VALID 0x0708 ++#define RTL8367C_VLAN_PPB0_VALID_VALID_EXT_OFFSET 8 ++#define RTL8367C_VLAN_PPB0_VALID_VALID_EXT_MASK 0x700 ++#define RTL8367C_VLAN_PPB0_VALID_VALID_OFFSET 0 ++#define RTL8367C_VLAN_PPB0_VALID_VALID_MASK 0xFF ++ ++#define RTL8367C_REG_VLAN_PPB0_CTRL0 0x0709 ++#define RTL8367C_VLAN_PPB0_CTRL0_PORT2_INDEX_OFFSET 10 ++#define RTL8367C_VLAN_PPB0_CTRL0_PORT2_INDEX_MASK 0x7C00 ++#define RTL8367C_VLAN_PPB0_CTRL0_PORT1_INDEX_OFFSET 5 ++#define RTL8367C_VLAN_PPB0_CTRL0_PORT1_INDEX_MASK 0x3E0 ++#define RTL8367C_VLAN_PPB0_CTRL0_PORT0_INDEX_OFFSET 0 ++#define RTL8367C_VLAN_PPB0_CTRL0_PORT0_INDEX_MASK 0x1F ++ ++#define RTL8367C_REG_VLAN_PPB0_CTRL1 0x070a ++#define RTL8367C_VLAN_PPB0_CTRL1_PORT5_INDEX_OFFSET 10 ++#define RTL8367C_VLAN_PPB0_CTRL1_PORT5_INDEX_MASK 0x7C00 ++#define RTL8367C_VLAN_PPB0_CTRL1_PORT4_INDEX_OFFSET 5 ++#define RTL8367C_VLAN_PPB0_CTRL1_PORT4_INDEX_MASK 0x3E0 ++#define RTL8367C_VLAN_PPB0_CTRL1_PORT3_INDEX_OFFSET 0 ++#define RTL8367C_VLAN_PPB0_CTRL1_PORT3_INDEX_MASK 0x1F ++ ++#define RTL8367C_REG_VLAN_PPB0_CTRL2 0x070b ++#define RTL8367C_VLAN_PPB0_CTRL2_FRAME_TYPE_OFFSET 10 ++#define RTL8367C_VLAN_PPB0_CTRL2_FRAME_TYPE_MASK 0xC00 ++#define RTL8367C_VLAN_PPB0_CTRL2_PORT7_INDEX_OFFSET 5 ++#define RTL8367C_VLAN_PPB0_CTRL2_PORT7_INDEX_MASK 0x3E0 ++#define RTL8367C_VLAN_PPB0_CTRL2_PORT6_INDEX_OFFSET 0 ++#define RTL8367C_VLAN_PPB0_CTRL2_PORT6_INDEX_MASK 0x1F ++ ++#define RTL8367C_REG_VLAN_PPB0_CTRL4 0x070c ++#define RTL8367C_VLAN_PPB0_CTRL4_PORT10_INDEX_OFFSET 10 ++#define RTL8367C_VLAN_PPB0_CTRL4_PORT10_INDEX_MASK 0x7C00 ++#define RTL8367C_VLAN_PPB0_CTRL4_PORT9_INDEX_OFFSET 5 ++#define RTL8367C_VLAN_PPB0_CTRL4_PORT9_INDEX_MASK 0x3E0 ++#define RTL8367C_VLAN_PPB0_CTRL4_PORT8_INDEX_OFFSET 0 ++#define RTL8367C_VLAN_PPB0_CTRL4_PORT8_INDEX_MASK 0x1F ++ ++#define RTL8367C_REG_VLAN_PPB0_CTRL3 0x070f ++ ++#define RTL8367C_REG_VLAN_PPB1_VALID 0x0710 ++#define RTL8367C_VLAN_PPB1_VALID_VALID_EXT_OFFSET 8 ++#define RTL8367C_VLAN_PPB1_VALID_VALID_EXT_MASK 0x700 ++#define RTL8367C_VLAN_PPB1_VALID_VALID_OFFSET 0 ++#define RTL8367C_VLAN_PPB1_VALID_VALID_MASK 0xFF ++ ++#define RTL8367C_REG_VLAN_PPB1_CTRL0 0x0711 ++#define RTL8367C_VLAN_PPB1_CTRL0_PORT2_INDEX_OFFSET 10 ++#define RTL8367C_VLAN_PPB1_CTRL0_PORT2_INDEX_MASK 0x7C00 ++#define RTL8367C_VLAN_PPB1_CTRL0_PORT1_INDEX_OFFSET 5 ++#define RTL8367C_VLAN_PPB1_CTRL0_PORT1_INDEX_MASK 0x3E0 ++#define RTL8367C_VLAN_PPB1_CTRL0_PORT0_INDEX_OFFSET 0 ++#define RTL8367C_VLAN_PPB1_CTRL0_PORT0_INDEX_MASK 0x1F ++ ++#define RTL8367C_REG_VLAN_PPB1_CTRL1 0x0712 ++#define RTL8367C_VLAN_PPB1_CTRL1_PORT5_INDEX_OFFSET 10 ++#define RTL8367C_VLAN_PPB1_CTRL1_PORT5_INDEX_MASK 0x7C00 ++#define RTL8367C_VLAN_PPB1_CTRL1_PORT4_INDEX_OFFSET 5 ++#define RTL8367C_VLAN_PPB1_CTRL1_PORT4_INDEX_MASK 0x3E0 ++#define RTL8367C_VLAN_PPB1_CTRL1_PORT3_INDEX_OFFSET 0 ++#define RTL8367C_VLAN_PPB1_CTRL1_PORT3_INDEX_MASK 0x1F ++ ++#define RTL8367C_REG_VLAN_PPB1_CTRL2 0x0713 ++#define RTL8367C_VLAN_PPB1_CTRL2_FRAME_TYPE_OFFSET 10 ++#define RTL8367C_VLAN_PPB1_CTRL2_FRAME_TYPE_MASK 0xC00 ++#define RTL8367C_VLAN_PPB1_CTRL2_PORT7_INDEX_OFFSET 5 ++#define RTL8367C_VLAN_PPB1_CTRL2_PORT7_INDEX_MASK 0x3E0 ++#define RTL8367C_VLAN_PPB1_CTRL2_PORT6_INDEX_OFFSET 0 ++#define RTL8367C_VLAN_PPB1_CTRL2_PORT6_INDEX_MASK 0x1F ++ ++#define RTL8367C_REG_VLAN_PPB1_CTRL4 0x0714 ++#define RTL8367C_VLAN_PPB1_CTRL4_PORT10_INDEX_OFFSET 10 ++#define RTL8367C_VLAN_PPB1_CTRL4_PORT10_INDEX_MASK 0x7C00 ++#define RTL8367C_VLAN_PPB1_CTRL4_PORT9_INDEX_OFFSET 5 ++#define RTL8367C_VLAN_PPB1_CTRL4_PORT9_INDEX_MASK 0x3E0 ++#define RTL8367C_VLAN_PPB1_CTRL4_PORT8_INDEX_OFFSET 0 ++#define RTL8367C_VLAN_PPB1_CTRL4_PORT8_INDEX_MASK 0x1F ++ ++#define RTL8367C_REG_VLAN_PPB1_CTRL3 0x0717 ++ ++#define RTL8367C_REG_VLAN_PPB2_VALID 0x0718 ++#define RTL8367C_VLAN_PPB2_VALID_VALID_EXT_OFFSET 8 ++#define RTL8367C_VLAN_PPB2_VALID_VALID_EXT_MASK 0x700 ++#define RTL8367C_VLAN_PPB2_VALID_VALID_OFFSET 0 ++#define RTL8367C_VLAN_PPB2_VALID_VALID_MASK 0xFF ++ ++#define RTL8367C_REG_VLAN_PPB2_CTRL0 0x0719 ++#define RTL8367C_VLAN_PPB2_CTRL0_PORT2_INDEX_OFFSET 10 ++#define RTL8367C_VLAN_PPB2_CTRL0_PORT2_INDEX_MASK 0x7C00 ++#define RTL8367C_VLAN_PPB2_CTRL0_PORT1_INDEX_OFFSET 5 ++#define RTL8367C_VLAN_PPB2_CTRL0_PORT1_INDEX_MASK 0x3E0 ++#define RTL8367C_VLAN_PPB2_CTRL0_PORT0_INDEX_OFFSET 0 ++#define RTL8367C_VLAN_PPB2_CTRL0_PORT0_INDEX_MASK 0x1F ++ ++#define RTL8367C_REG_VLAN_PPB2_CTRL1 0x071a ++#define RTL8367C_VLAN_PPB2_CTRL1_PORT5_INDEX_OFFSET 10 ++#define RTL8367C_VLAN_PPB2_CTRL1_PORT5_INDEX_MASK 0x7C00 ++#define RTL8367C_VLAN_PPB2_CTRL1_PORT4_INDEX_OFFSET 5 ++#define RTL8367C_VLAN_PPB2_CTRL1_PORT4_INDEX_MASK 0x3E0 ++#define RTL8367C_VLAN_PPB2_CTRL1_PORT3_INDEX_OFFSET 0 ++#define RTL8367C_VLAN_PPB2_CTRL1_PORT3_INDEX_MASK 0x1F ++ ++#define RTL8367C_REG_VLAN_PPB2_CTRL2 0x071b ++#define RTL8367C_VLAN_PPB2_CTRL2_FRAME_TYPE_OFFSET 10 ++#define RTL8367C_VLAN_PPB2_CTRL2_FRAME_TYPE_MASK 0xC00 ++#define RTL8367C_VLAN_PPB2_CTRL2_PORT7_INDEX_OFFSET 5 ++#define RTL8367C_VLAN_PPB2_CTRL2_PORT7_INDEX_MASK 0x3E0 ++#define RTL8367C_VLAN_PPB2_CTRL2_PORT6_INDEX_OFFSET 0 ++#define RTL8367C_VLAN_PPB2_CTRL2_PORT6_INDEX_MASK 0x1F ++ ++#define RTL8367C_REG_VLAN_PPB2_CTRL4 0x071c ++#define RTL8367C_VLAN_PPB2_CTRL4_PORT10_INDEX_OFFSET 10 ++#define RTL8367C_VLAN_PPB2_CTRL4_PORT10_INDEX_MASK 0x7C00 ++#define RTL8367C_VLAN_PPB2_CTRL4_PORT9_INDEX_OFFSET 5 ++#define RTL8367C_VLAN_PPB2_CTRL4_PORT9_INDEX_MASK 0x3E0 ++#define RTL8367C_VLAN_PPB2_CTRL4_PORT8_INDEX_OFFSET 0 ++#define RTL8367C_VLAN_PPB2_CTRL4_PORT8_INDEX_MASK 0x1F ++ ++#define RTL8367C_REG_VLAN_PPB2_CTRL3 0x071f ++ ++#define RTL8367C_REG_VLAN_PPB3_VALID 0x0720 ++#define RTL8367C_VLAN_PPB3_VALID_VALID_EXT_OFFSET 8 ++#define RTL8367C_VLAN_PPB3_VALID_VALID_EXT_MASK 0x700 ++#define RTL8367C_VLAN_PPB3_VALID_VALID_OFFSET 0 ++#define RTL8367C_VLAN_PPB3_VALID_VALID_MASK 0xFF ++ ++#define RTL8367C_REG_VLAN_PPB3_CTRL0 0x0721 ++#define RTL8367C_VLAN_PPB3_CTRL0_PORT2_INDEX_OFFSET 10 ++#define RTL8367C_VLAN_PPB3_CTRL0_PORT2_INDEX_MASK 0x7C00 ++#define RTL8367C_VLAN_PPB3_CTRL0_PORT1_INDEX_OFFSET 5 ++#define RTL8367C_VLAN_PPB3_CTRL0_PORT1_INDEX_MASK 0x3E0 ++#define RTL8367C_VLAN_PPB3_CTRL0_PORT0_INDEX_OFFSET 0 ++#define RTL8367C_VLAN_PPB3_CTRL0_PORT0_INDEX_MASK 0x1F ++ ++#define RTL8367C_REG_VLAN_PPB3_CTRL1 0x0722 ++#define RTL8367C_VLAN_PPB3_CTRL1_PORT5_INDEX_OFFSET 10 ++#define RTL8367C_VLAN_PPB3_CTRL1_PORT5_INDEX_MASK 0x7C00 ++#define RTL8367C_VLAN_PPB3_CTRL1_PORT4_INDEX_OFFSET 5 ++#define RTL8367C_VLAN_PPB3_CTRL1_PORT4_INDEX_MASK 0x3E0 ++#define RTL8367C_VLAN_PPB3_CTRL1_PORT3_INDEX_OFFSET 0 ++#define RTL8367C_VLAN_PPB3_CTRL1_PORT3_INDEX_MASK 0x1F ++ ++#define RTL8367C_REG_VLAN_PPB3_CTRL2 0x0723 ++#define RTL8367C_VLAN_PPB3_CTRL2_FRAME_TYPE_OFFSET 10 ++#define RTL8367C_VLAN_PPB3_CTRL2_FRAME_TYPE_MASK 0xC00 ++#define RTL8367C_VLAN_PPB3_CTRL2_PORT7_INDEX_OFFSET 5 ++#define RTL8367C_VLAN_PPB3_CTRL2_PORT7_INDEX_MASK 0x3E0 ++#define RTL8367C_VLAN_PPB3_CTRL2_PORT6_INDEX_OFFSET 0 ++#define RTL8367C_VLAN_PPB3_CTRL2_PORT6_INDEX_MASK 0x1F ++ ++#define RTL8367C_REG_VLAN_PPB3_CTRL4 0x0724 ++#define RTL8367C_VLAN_PPB3_CTRL4_PORT10_INDEX_OFFSET 10 ++#define RTL8367C_VLAN_PPB3_CTRL4_PORT10_INDEX_MASK 0x7C00 ++#define RTL8367C_VLAN_PPB3_CTRL4_PORT9_INDEX_OFFSET 5 ++#define RTL8367C_VLAN_PPB3_CTRL4_PORT9_INDEX_MASK 0x3E0 ++#define RTL8367C_VLAN_PPB3_CTRL4_PORT8_INDEX_OFFSET 0 ++#define RTL8367C_VLAN_PPB3_CTRL4_PORT8_INDEX_MASK 0x1F ++ ++#define RTL8367C_REG_VLAN_PPB3_CTRL3 0x0727 ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION0_CTRL0 0x0728 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION0_CTRL0_MBR_EXT_OFFSET 8 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION0_CTRL0_MBR_EXT_MASK 0x700 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION0_CTRL0_MBR_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION0_CTRL0_MBR_MASK 0xFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION0_CTRL1 0x0729 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION0_CTRL1_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION0_CTRL1_MASK 0xF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION0_CTRL2 0x072a ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION0_CTRL2_METERIDX_EXT_OFFSET 10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION0_CTRL2_METERIDX_EXT_MASK 0x400 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION0_CTRL2_METERIDX_OFFSET 5 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION0_CTRL2_METERIDX_MASK 0x3E0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION0_CTRL2_ENVLANPOL_OFFSET 4 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION0_CTRL2_ENVLANPOL_MASK 0x10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION0_CTRL2_VBPRI_OFFSET 1 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION0_CTRL2_VBPRI_MASK 0xE ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION0_CTRL2_VBPEN_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION0_CTRL2_VBPEN_MASK 0x1 ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION0_CTRL3 0x072b ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION0_CTRL3_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION0_CTRL3_MASK 0x1FFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION1_CTRL0 0x072c ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION1_CTRL0_MBR_EXT_OFFSET 8 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION1_CTRL0_MBR_EXT_MASK 0x700 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION1_CTRL0_MBR_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION1_CTRL0_MBR_MASK 0xFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION1_CTRL1 0x072d ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION1_CTRL1_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION1_CTRL1_MASK 0xF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION1_CTRL2 0x072e ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION1_CTRL2_METERIDX_EXT_OFFSET 10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION1_CTRL2_METERIDX_EXT_MASK 0x400 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION1_CTRL2_METERIDX_OFFSET 5 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION1_CTRL2_METERIDX_MASK 0x3E0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION1_CTRL2_ENVLANPOL_OFFSET 4 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION1_CTRL2_ENVLANPOL_MASK 0x10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION1_CTRL2_VBPRI_OFFSET 1 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION1_CTRL2_VBPRI_MASK 0xE ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION1_CTRL2_VBPEN_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION1_CTRL2_VBPEN_MASK 0x1 ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION1_CTRL3 0x072f ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION1_CTRL3_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION1_CTRL3_MASK 0x1FFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION2_CTRL0 0x0730 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION2_CTRL0_MBR_EXT_OFFSET 8 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION2_CTRL0_MBR_EXT_MASK 0x700 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION2_CTRL0_MBR_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION2_CTRL0_MBR_MASK 0xFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION2_CTRL1 0x0731 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION2_CTRL1_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION2_CTRL1_MASK 0xF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION2_CTRL2 0x0732 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION2_CTRL2_METERIDX_EXT_OFFSET 10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION2_CTRL2_METERIDX_EXT_MASK 0x400 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION2_CTRL2_METERIDX_OFFSET 5 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION2_CTRL2_METERIDX_MASK 0x3E0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION2_CTRL2_ENVLANPOL_OFFSET 4 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION2_CTRL2_ENVLANPOL_MASK 0x10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION2_CTRL2_VBPRI_OFFSET 1 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION2_CTRL2_VBPRI_MASK 0xE ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION2_CTRL2_VBPEN_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION2_CTRL2_VBPEN_MASK 0x1 ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION2_CTRL3 0x0733 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION2_CTRL3_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION2_CTRL3_MASK 0x1FFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION3_CTRL0 0x0734 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION3_CTRL0_MBR_EXT_OFFSET 8 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION3_CTRL0_MBR_EXT_MASK 0x700 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION3_CTRL0_MBR_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION3_CTRL0_MBR_MASK 0xFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION3_CTRL1 0x0735 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION3_CTRL1_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION3_CTRL1_MASK 0xF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION3_CTRL2 0x0736 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION3_CTRL2_METERIDX_EXT_OFFSET 10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION3_CTRL2_METERIDX_EXT_MASK 0x400 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION3_CTRL2_METERIDX_OFFSET 5 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION3_CTRL2_METERIDX_MASK 0x3E0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION3_CTRL2_ENVLANPOL_OFFSET 4 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION3_CTRL2_ENVLANPOL_MASK 0x10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION3_CTRL2_VBPRI_OFFSET 1 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION3_CTRL2_VBPRI_MASK 0xE ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION3_CTRL2_VBPEN_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION3_CTRL2_VBPEN_MASK 0x1 ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION3_CTRL3 0x0737 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION3_CTRL3_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION3_CTRL3_MASK 0x1FFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION4_CTRL0 0x0738 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION4_CTRL0_MBR_EXT_OFFSET 8 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION4_CTRL0_MBR_EXT_MASK 0x700 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION4_CTRL0_MBR_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION4_CTRL0_MBR_MASK 0xFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION4_CTRL1 0x0739 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION4_CTRL1_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION4_CTRL1_MASK 0xF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION4_CTRL2 0x073a ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION4_CTRL2_METERIDX_EXT_OFFSET 10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION4_CTRL2_METERIDX_EXT_MASK 0x400 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION4_CTRL2_METERIDX_OFFSET 5 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION4_CTRL2_METERIDX_MASK 0x3E0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION4_CTRL2_ENVLANPOL_OFFSET 4 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION4_CTRL2_ENVLANPOL_MASK 0x10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION4_CTRL2_VBPRI_OFFSET 1 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION4_CTRL2_VBPRI_MASK 0xE ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION4_CTRL2_VBPEN_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION4_CTRL2_VBPEN_MASK 0x1 ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION4_CTRL3 0x073b ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION4_CTRL3_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION4_CTRL3_MASK 0x1FFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION5_CTRL0 0x073c ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION5_CTRL0_MBR_EXT_OFFSET 8 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION5_CTRL0_MBR_EXT_MASK 0x700 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION5_CTRL0_MBR_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION5_CTRL0_MBR_MASK 0xFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION5_CTRL1 0x073d ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION5_CTRL1_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION5_CTRL1_MASK 0xF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION5_CTRL2 0x073e ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION5_CTRL2_METERIDX_EXT_OFFSET 10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION5_CTRL2_METERIDX_EXT_MASK 0x400 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION5_CTRL2_METERIDX_OFFSET 5 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION5_CTRL2_METERIDX_MASK 0x3E0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION5_CTRL2_ENVLANPOL_OFFSET 4 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION5_CTRL2_ENVLANPOL_MASK 0x10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION5_CTRL2_VBPRI_OFFSET 1 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION5_CTRL2_VBPRI_MASK 0xE ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION5_CTRL2_VBPEN_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION5_CTRL2_VBPEN_MASK 0x1 ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION5_CTRL3 0x073f ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION5_CTRL3_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION5_CTRL3_MASK 0x1FFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION6_CTRL0 0x0740 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION6_CTRL0_MBR_EXT_OFFSET 8 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION6_CTRL0_MBR_EXT_MASK 0x700 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION6_CTRL0_MBR_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION6_CTRL0_MBR_MASK 0xFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION6_CTRL1 0x0741 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION6_CTRL1_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION6_CTRL1_MASK 0xF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION6_CTRL2 0x0742 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION6_CTRL2_METERIDX_EXT_OFFSET 10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION6_CTRL2_METERIDX_EXT_MASK 0x400 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION6_CTRL2_METERIDX_OFFSET 5 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION6_CTRL2_METERIDX_MASK 0x3E0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION6_CTRL2_ENVLANPOL_OFFSET 4 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION6_CTRL2_ENVLANPOL_MASK 0x10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION6_CTRL2_VBPRI_OFFSET 1 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION6_CTRL2_VBPRI_MASK 0xE ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION6_CTRL2_VBPEN_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION6_CTRL2_VBPEN_MASK 0x1 ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION6_CTRL3 0x0743 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION6_CTRL3_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION6_CTRL3_MASK 0x1FFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION7_CTRL0 0x0744 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION7_CTRL0_MBR_EXT_OFFSET 8 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION7_CTRL0_MBR_EXT_MASK 0x700 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION7_CTRL0_MBR_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION7_CTRL0_MBR_MASK 0xFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION7_CTRL1 0x0745 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION7_CTRL1_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION7_CTRL1_MASK 0xF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION7_CTRL2 0x0746 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION7_CTRL2_METERIDX_EXT_OFFSET 10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION7_CTRL2_METERIDX_EXT_MASK 0x400 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION7_CTRL2_METERIDX_OFFSET 5 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION7_CTRL2_METERIDX_MASK 0x3E0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION7_CTRL2_ENVLANPOL_OFFSET 4 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION7_CTRL2_ENVLANPOL_MASK 0x10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION7_CTRL2_VBPRI_OFFSET 1 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION7_CTRL2_VBPRI_MASK 0xE ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION7_CTRL2_VBPEN_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION7_CTRL2_VBPEN_MASK 0x1 ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION7_CTRL3 0x0747 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION7_CTRL3_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION7_CTRL3_MASK 0x1FFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION8_CTRL0 0x0748 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION8_CTRL0_MBR_EXT_OFFSET 8 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION8_CTRL0_MBR_EXT_MASK 0x700 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION8_CTRL0_MBR_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION8_CTRL0_MBR_MASK 0xFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION8_CTRL1 0x0749 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION8_CTRL1_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION8_CTRL1_MASK 0xF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION8_CTRL2 0x074a ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION8_CTRL2_METERIDX_EXT_OFFSET 10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION8_CTRL2_METERIDX_EXT_MASK 0x400 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION8_CTRL2_METERIDX_OFFSET 5 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION8_CTRL2_METERIDX_MASK 0x3E0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION8_CTRL2_ENVLANPOL_OFFSET 4 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION8_CTRL2_ENVLANPOL_MASK 0x10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION8_CTRL2_VBPRI_OFFSET 1 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION8_CTRL2_VBPRI_MASK 0xE ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION8_CTRL2_VBPEN_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION8_CTRL2_VBPEN_MASK 0x1 ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION8_CTRL3 0x074b ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION8_CTRL3_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION8_CTRL3_MASK 0x1FFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION9_CTRL0 0x074c ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION9_CTRL0_MBR_EXT_OFFSET 8 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION9_CTRL0_MBR_EXT_MASK 0x700 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION9_CTRL0_MBR_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION9_CTRL0_MBR_MASK 0xFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION9_CTRL1 0x074d ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION9_CTRL1_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION9_CTRL1_MASK 0xF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION9_CTRL2 0x074e ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION9_CTRL2_METERIDX_EXT_OFFSET 10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION9_CTRL2_METERIDX_EXT_MASK 0x400 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION9_CTRL2_METERIDX_OFFSET 5 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION9_CTRL2_METERIDX_MASK 0x3E0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION9_CTRL2_ENVLANPOL_OFFSET 4 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION9_CTRL2_ENVLANPOL_MASK 0x10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION9_CTRL2_VBPRI_OFFSET 1 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION9_CTRL2_VBPRI_MASK 0xE ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION9_CTRL2_VBPEN_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION9_CTRL2_VBPEN_MASK 0x1 ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION9_CTRL3 0x074f ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION9_CTRL3_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION9_CTRL3_MASK 0x1FFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION10_CTRL0 0x0750 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION10_CTRL0_MBR_EXT_OFFSET 8 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION10_CTRL0_MBR_EXT_MASK 0x700 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION10_CTRL0_MBR_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION10_CTRL0_MBR_MASK 0xFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION10_CTRL1 0x0751 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION10_CTRL1_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION10_CTRL1_MASK 0xF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION10_CTRL2 0x0752 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION10_CTRL2_METERIDX_EXT_OFFSET 10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION10_CTRL2_METERIDX_EXT_MASK 0x400 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION10_CTRL2_METERIDX_OFFSET 5 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION10_CTRL2_METERIDX_MASK 0x3E0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION10_CTRL2_ENVLANPOL_OFFSET 4 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION10_CTRL2_ENVLANPOL_MASK 0x10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION10_CTRL2_VBPRI_OFFSET 1 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION10_CTRL2_VBPRI_MASK 0xE ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION10_CTRL2_VBPEN_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION10_CTRL2_VBPEN_MASK 0x1 ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION10_CTRL3 0x0753 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION10_CTRL3_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION10_CTRL3_MASK 0x1FFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION11_CTRL0 0x0754 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION11_CTRL0_MBR_EXT_OFFSET 8 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION11_CTRL0_MBR_EXT_MASK 0x700 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION11_CTRL0_MBR_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION11_CTRL0_MBR_MASK 0xFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION11_CTRL1 0x0755 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION11_CTRL1_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION11_CTRL1_MASK 0xF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION11_CTRL2 0x0756 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION11_CTRL2_METERIDX_EXT_OFFSET 10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION11_CTRL2_METERIDX_EXT_MASK 0x400 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION11_CTRL2_METERIDX_OFFSET 5 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION11_CTRL2_METERIDX_MASK 0x3E0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION11_CTRL2_ENVLANPOL_OFFSET 4 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION11_CTRL2_ENVLANPOL_MASK 0x10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION11_CTRL2_VBPRI_OFFSET 1 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION11_CTRL2_VBPRI_MASK 0xE ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION11_CTRL2_VBPEN_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION11_CTRL2_VBPEN_MASK 0x1 ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION11_CTRL3 0x0757 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION11_CTRL3_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION11_CTRL3_MASK 0x1FFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION12_CTRL0 0x0758 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION12_CTRL0_MBR_EXT_OFFSET 8 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION12_CTRL0_MBR_EXT_MASK 0x700 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION12_CTRL0_MBR_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION12_CTRL0_MBR_MASK 0xFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION12_CTRL1 0x0759 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION12_CTRL1_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION12_CTRL1_MASK 0xF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION12_CTRL2 0x075a ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION12_CTRL2_METERIDX_EXT_OFFSET 10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION12_CTRL2_METERIDX_EXT_MASK 0x400 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION12_CTRL2_METERIDX_OFFSET 5 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION12_CTRL2_METERIDX_MASK 0x3E0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION12_CTRL2_ENVLANPOL_OFFSET 4 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION12_CTRL2_ENVLANPOL_MASK 0x10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION12_CTRL2_VBPRI_OFFSET 1 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION12_CTRL2_VBPRI_MASK 0xE ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION12_CTRL2_VBPEN_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION12_CTRL2_VBPEN_MASK 0x1 ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION12_CTRL3 0x075b ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION12_CTRL3_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION12_CTRL3_MASK 0x1FFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION13_CTRL0 0x075c ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION13_CTRL0_MBR_EXT_OFFSET 8 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION13_CTRL0_MBR_EXT_MASK 0x700 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION13_CTRL0_MBR_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION13_CTRL0_MBR_MASK 0xFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION13_CTRL1 0x075d ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION13_CTRL1_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION13_CTRL1_MASK 0xF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION13_CTRL2 0x075e ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION13_CTRL2_METERIDX_EXT_OFFSET 10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION13_CTRL2_METERIDX_EXT_MASK 0x400 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION13_CTRL2_METERIDX_OFFSET 5 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION13_CTRL2_METERIDX_MASK 0x3E0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION13_CTRL2_ENVLANPOL_OFFSET 4 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION13_CTRL2_ENVLANPOL_MASK 0x10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION13_CTRL2_VBPRI_OFFSET 1 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION13_CTRL2_VBPRI_MASK 0xE ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION13_CTRL2_VBPEN_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION13_CTRL2_VBPEN_MASK 0x1 ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION13_CTRL3 0x075f ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION13_CTRL3_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION13_CTRL3_MASK 0x1FFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION14_CTRL0 0x0760 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION14_CTRL0_MBR_EXT_OFFSET 8 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION14_CTRL0_MBR_EXT_MASK 0x700 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION14_CTRL0_MBR_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION14_CTRL0_MBR_MASK 0xFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION14_CTRL1 0x0761 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION14_CTRL1_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION14_CTRL1_MASK 0xF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION14_CTRL2 0x0762 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION14_CTRL2_METERIDX_EXT_OFFSET 10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION14_CTRL2_METERIDX_EXT_MASK 0x400 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION14_CTRL2_METERIDX_OFFSET 5 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION14_CTRL2_METERIDX_MASK 0x3E0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION14_CTRL2_ENVLANPOL_OFFSET 4 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION14_CTRL2_ENVLANPOL_MASK 0x10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION14_CTRL2_VBPRI_OFFSET 1 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION14_CTRL2_VBPRI_MASK 0xE ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION14_CTRL2_VBPEN_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION14_CTRL2_VBPEN_MASK 0x1 ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION14_CTRL3 0x0763 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION14_CTRL3_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION14_CTRL3_MASK 0x1FFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION15_CTRL0 0x0764 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION15_CTRL0_MBR_EXT_OFFSET 8 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION15_CTRL0_MBR_EXT_MASK 0x700 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION15_CTRL0_MBR_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION15_CTRL0_MBR_MASK 0xFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION15_CTRL1 0x0765 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION15_CTRL1_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION15_CTRL1_MASK 0xF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION15_CTRL2 0x0766 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION15_CTRL2_METERIDX_EXT_OFFSET 10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION15_CTRL2_METERIDX_EXT_MASK 0x400 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION15_CTRL2_METERIDX_OFFSET 5 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION15_CTRL2_METERIDX_MASK 0x3E0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION15_CTRL2_ENVLANPOL_OFFSET 4 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION15_CTRL2_ENVLANPOL_MASK 0x10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION15_CTRL2_VBPRI_OFFSET 1 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION15_CTRL2_VBPRI_MASK 0xE ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION15_CTRL2_VBPEN_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION15_CTRL2_VBPEN_MASK 0x1 ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION15_CTRL3 0x0767 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION15_CTRL3_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION15_CTRL3_MASK 0x1FFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION16_CTRL0 0x0768 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION16_CTRL0_MBR_EXT_OFFSET 8 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION16_CTRL0_MBR_EXT_MASK 0x700 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION16_CTRL0_MBR_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION16_CTRL0_MBR_MASK 0xFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION16_CTRL1 0x0769 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION16_CTRL1_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION16_CTRL1_MASK 0xF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION16_CTRL2 0x076a ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION16_CTRL2_METERIDX_EXT_OFFSET 10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION16_CTRL2_METERIDX_EXT_MASK 0x400 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION16_CTRL2_METERIDX_OFFSET 5 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION16_CTRL2_METERIDX_MASK 0x3E0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION16_CTRL2_ENVLANPOL_OFFSET 4 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION16_CTRL2_ENVLANPOL_MASK 0x10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION16_CTRL2_VBPRI_OFFSET 1 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION16_CTRL2_VBPRI_MASK 0xE ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION16_CTRL2_VBPEN_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION16_CTRL2_VBPEN_MASK 0x1 ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION16_CTRL3 0x076b ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION16_CTRL3_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION16_CTRL3_MASK 0x1FFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION17_CTRL0 0x076c ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION17_CTRL0_MBR_EXT_OFFSET 8 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION17_CTRL0_MBR_EXT_MASK 0x700 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION17_CTRL0_MBR_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION17_CTRL0_MBR_MASK 0xFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION17_CTRL1 0x076d ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION17_CTRL1_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION17_CTRL1_MASK 0xF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION17_CTRL2 0x076e ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION17_CTRL2_METERIDX_EXT_OFFSET 10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION17_CTRL2_METERIDX_EXT_MASK 0x400 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION17_CTRL2_METERIDX_OFFSET 5 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION17_CTRL2_METERIDX_MASK 0x3E0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION17_CTRL2_ENVLANPOL_OFFSET 4 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION17_CTRL2_ENVLANPOL_MASK 0x10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION17_CTRL2_VBPRI_OFFSET 1 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION17_CTRL2_VBPRI_MASK 0xE ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION17_CTRL2_VBPEN_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION17_CTRL2_VBPEN_MASK 0x1 ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION17_CTRL3 0x076f ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION17_CTRL3_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION17_CTRL3_MASK 0x1FFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION18_CTRL0 0x0770 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION18_CTRL0_MBR_EXT_OFFSET 8 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION18_CTRL0_MBR_EXT_MASK 0x700 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION18_CTRL0_MBR_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION18_CTRL0_MBR_MASK 0xFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION18_CTRL1 0x0771 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION18_CTRL1_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION18_CTRL1_MASK 0xF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION18_CTRL2 0x0772 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION18_CTRL2_METERIDX_EXT_OFFSET 10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION18_CTRL2_METERIDX_EXT_MASK 0x400 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION18_CTRL2_METERIDX_OFFSET 5 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION18_CTRL2_METERIDX_MASK 0x3E0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION18_CTRL2_ENVLANPOL_OFFSET 4 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION18_CTRL2_ENVLANPOL_MASK 0x10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION18_CTRL2_VBPRI_OFFSET 1 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION18_CTRL2_VBPRI_MASK 0xE ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION18_CTRL2_VBPEN_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION18_CTRL2_VBPEN_MASK 0x1 ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION18_CTRL3 0x0773 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION18_CTRL3_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION18_CTRL3_MASK 0x1FFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION19_CTRL0 0x0774 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION19_CTRL0_MBR_EXT_OFFSET 8 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION19_CTRL0_MBR_EXT_MASK 0x700 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION19_CTRL0_MBR_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION19_CTRL0_MBR_MASK 0xFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION19_CTRL1 0x0775 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION19_CTRL1_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION19_CTRL1_MASK 0xF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION19_CTRL2 0x0776 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION19_CTRL2_METERIDX_EXT_OFFSET 10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION19_CTRL2_METERIDX_EXT_MASK 0x400 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION19_CTRL2_METERIDX_OFFSET 5 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION19_CTRL2_METERIDX_MASK 0x3E0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION19_CTRL2_ENVLANPOL_OFFSET 4 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION19_CTRL2_ENVLANPOL_MASK 0x10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION19_CTRL2_VBPRI_OFFSET 1 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION19_CTRL2_VBPRI_MASK 0xE ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION19_CTRL2_VBPEN_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION19_CTRL2_VBPEN_MASK 0x1 ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION19_CTRL3 0x0777 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION19_CTRL3_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION19_CTRL3_MASK 0x1FFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION20_CTRL0 0x0778 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION20_CTRL0_MBR_EXT_OFFSET 8 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION20_CTRL0_MBR_EXT_MASK 0x700 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION20_CTRL0_MBR_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION20_CTRL0_MBR_MASK 0xFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION20_CTRL1 0x0779 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION20_CTRL1_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION20_CTRL1_MASK 0xF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION20_CTRL2 0x077a ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION20_CTRL2_METERIDX_EXT_OFFSET 10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION20_CTRL2_METERIDX_EXT_MASK 0x400 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION20_CTRL2_METERIDX_OFFSET 5 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION20_CTRL2_METERIDX_MASK 0x3E0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION20_CTRL2_ENVLANPOL_OFFSET 4 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION20_CTRL2_ENVLANPOL_MASK 0x10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION20_CTRL2_VBPRI_OFFSET 1 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION20_CTRL2_VBPRI_MASK 0xE ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION20_CTRL2_VBPEN_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION20_CTRL2_VBPEN_MASK 0x1 ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION20_CTRL3 0x077b ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION20_CTRL3_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION20_CTRL3_MASK 0x1FFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION21_CTRL0 0x077c ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION21_CTRL0_MBR_EXT_OFFSET 8 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION21_CTRL0_MBR_EXT_MASK 0x700 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION21_CTRL0_MBR_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION21_CTRL0_MBR_MASK 0xFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION21_CTRL1 0x077d ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION21_CTRL1_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION21_CTRL1_MASK 0xF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION21_CTRL2 0x077e ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION21_CTRL2_METERIDX_EXT_OFFSET 10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION21_CTRL2_METERIDX_EXT_MASK 0x400 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION21_CTRL2_METERIDX_OFFSET 5 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION21_CTRL2_METERIDX_MASK 0x3E0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION21_CTRL2_ENVLANPOL_OFFSET 4 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION21_CTRL2_ENVLANPOL_MASK 0x10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION21_CTRL2_VBPRI_OFFSET 1 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION21_CTRL2_VBPRI_MASK 0xE ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION21_CTRL2_VBPEN_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION21_CTRL2_VBPEN_MASK 0x1 ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION21_CTRL3 0x077f ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION21_CTRL3_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION21_CTRL3_MASK 0x1FFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION22_CTRL0 0x0780 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION22_CTRL0_MBR_EXT_OFFSET 8 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION22_CTRL0_MBR_EXT_MASK 0x700 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION22_CTRL0_MBR_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION22_CTRL0_MBR_MASK 0xFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION22_CTRL1 0x0781 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION22_CTRL1_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION22_CTRL1_MASK 0xF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION22_CTRL2 0x0782 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION22_CTRL2_METERIDX_EXT_OFFSET 10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION22_CTRL2_METERIDX_EXT_MASK 0x400 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION22_CTRL2_METERIDX_OFFSET 5 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION22_CTRL2_METERIDX_MASK 0x3E0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION22_CTRL2_ENVLANPOL_OFFSET 4 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION22_CTRL2_ENVLANPOL_MASK 0x10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION22_CTRL2_VBPRI_OFFSET 1 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION22_CTRL2_VBPRI_MASK 0xE ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION22_CTRL2_VBPEN_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION22_CTRL2_VBPEN_MASK 0x1 ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION22_CTRL3 0x0783 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION22_CTRL3_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION22_CTRL3_MASK 0x1FFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION23_CTRL0 0x0784 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION23_CTRL0_MBR_EXT_OFFSET 8 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION23_CTRL0_MBR_EXT_MASK 0x700 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION23_CTRL0_MBR_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION23_CTRL0_MBR_MASK 0xFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION23_CTRL1 0x0785 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION23_CTRL1_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION23_CTRL1_MASK 0xF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION23_CTRL2 0x0786 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION23_CTRL2_METERIDX_EXT_OFFSET 10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION23_CTRL2_METERIDX_EXT_MASK 0x400 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION23_CTRL2_METERIDX_OFFSET 5 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION23_CTRL2_METERIDX_MASK 0x3E0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION23_CTRL2_ENVLANPOL_OFFSET 4 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION23_CTRL2_ENVLANPOL_MASK 0x10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION23_CTRL2_VBPRI_OFFSET 1 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION23_CTRL2_VBPRI_MASK 0xE ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION23_CTRL2_VBPEN_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION23_CTRL2_VBPEN_MASK 0x1 ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION23_CTRL3 0x0787 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION23_CTRL3_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION23_CTRL3_MASK 0x1FFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION24_CTRL0 0x0788 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION24_CTRL0_MBR_EXT_OFFSET 8 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION24_CTRL0_MBR_EXT_MASK 0x700 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION24_CTRL0_MBR_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION24_CTRL0_MBR_MASK 0xFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION24_CTRL1 0x0789 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION24_CTRL1_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION24_CTRL1_MASK 0xF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION24_CTRL2 0x078a ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION24_CTRL2_METERIDX_EXT_OFFSET 10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION24_CTRL2_METERIDX_EXT_MASK 0x400 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION24_CTRL2_METERIDX_OFFSET 5 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION24_CTRL2_METERIDX_MASK 0x3E0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION24_CTRL2_ENVLANPOL_OFFSET 4 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION24_CTRL2_ENVLANPOL_MASK 0x10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION24_CTRL2_VBPRI_OFFSET 1 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION24_CTRL2_VBPRI_MASK 0xE ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION24_CTRL2_VBPEN_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION24_CTRL2_VBPEN_MASK 0x1 ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION24_CTRL3 0x078b ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION24_CTRL3_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION24_CTRL3_MASK 0x1FFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION25_CTRL0 0x078c ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION25_CTRL0_MBR_EXT_OFFSET 8 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION25_CTRL0_MBR_EXT_MASK 0x700 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION25_CTRL0_MBR_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION25_CTRL0_MBR_MASK 0xFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION25_CTRL1 0x078d ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION25_CTRL1_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION25_CTRL1_MASK 0xF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION25_CTRL2 0x078e ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION25_CTRL2_METERIDX_EXT_OFFSET 10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION25_CTRL2_METERIDX_EXT_MASK 0x400 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION25_CTRL2_METERIDX_OFFSET 5 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION25_CTRL2_METERIDX_MASK 0x3E0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION25_CTRL2_ENVLANPOL_OFFSET 4 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION25_CTRL2_ENVLANPOL_MASK 0x10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION25_CTRL2_VBPRI_OFFSET 1 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION25_CTRL2_VBPRI_MASK 0xE ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION25_CTRL2_VBPEN_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION25_CTRL2_VBPEN_MASK 0x1 ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION25_CTRL3 0x078f ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION25_CTRL3_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION25_CTRL3_MASK 0x1FFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION26_CTRL0 0x0790 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION26_CTRL0_MBR_EXT_OFFSET 8 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION26_CTRL0_MBR_EXT_MASK 0x700 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION26_CTRL0_MBR_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION26_CTRL0_MBR_MASK 0xFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION26_CTRL1 0x0791 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION26_CTRL1_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION26_CTRL1_MASK 0xF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION26_CTRL2 0x0792 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION26_CTRL2_METERIDX_EXT_OFFSET 10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION26_CTRL2_METERIDX_EXT_MASK 0x400 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION26_CTRL2_METERIDX_OFFSET 5 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION26_CTRL2_METERIDX_MASK 0x3E0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION26_CTRL2_ENVLANPOL_OFFSET 4 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION26_CTRL2_ENVLANPOL_MASK 0x10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION26_CTRL2_VBPRI_OFFSET 1 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION26_CTRL2_VBPRI_MASK 0xE ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION26_CTRL2_VBPEN_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION26_CTRL2_VBPEN_MASK 0x1 ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION26_CTRL3 0x0793 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION26_CTRL3_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION26_CTRL3_MASK 0x1FFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION27_CTRL0 0x0794 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION27_CTRL0_MBR_EXT_OFFSET 8 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION27_CTRL0_MBR_EXT_MASK 0x700 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION27_CTRL0_MBR_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION27_CTRL0_MBR_MASK 0xFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION27_CTRL1 0x0795 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION27_CTRL1_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION27_CTRL1_MASK 0xF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION27_CTRL2 0x0796 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION27_CTRL2_METERIDX_EXT_OFFSET 10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION27_CTRL2_METERIDX_EXT_MASK 0x400 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION27_CTRL2_METERIDX_OFFSET 5 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION27_CTRL2_METERIDX_MASK 0x3E0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION27_CTRL2_ENVLANPOL_OFFSET 4 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION27_CTRL2_ENVLANPOL_MASK 0x10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION27_CTRL2_VBPRI_OFFSET 1 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION27_CTRL2_VBPRI_MASK 0xE ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION27_CTRL2_VBPEN_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION27_CTRL2_VBPEN_MASK 0x1 ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION27_CTRL3 0x0797 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION27_CTRL3_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION27_CTRL3_MASK 0x1FFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION28_CTRL0 0x0798 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION28_CTRL0_MBR_EXT_OFFSET 8 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION28_CTRL0_MBR_EXT_MASK 0x700 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION28_CTRL0_MBR_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION28_CTRL0_MBR_MASK 0xFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION28_CTRL1 0x0799 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION28_CTRL1_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION28_CTRL1_MASK 0xF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION28_CTRL2 0x079a ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION28_CTRL2_METERIDX_EXT_OFFSET 10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION28_CTRL2_METERIDX_EXT_MASK 0x400 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION28_CTRL2_METERIDX_OFFSET 5 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION28_CTRL2_METERIDX_MASK 0x3E0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION28_CTRL2_ENVLANPOL_OFFSET 4 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION28_CTRL2_ENVLANPOL_MASK 0x10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION28_CTRL2_VBPRI_OFFSET 1 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION28_CTRL2_VBPRI_MASK 0xE ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION28_CTRL2_VBPEN_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION28_CTRL2_VBPEN_MASK 0x1 ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION28_CTRL3 0x079b ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION28_CTRL3_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION28_CTRL3_MASK 0x1FFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION29_CTRL0 0x079c ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION29_CTRL0_MBR_EXT_OFFSET 8 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION29_CTRL0_MBR_EXT_MASK 0x700 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION29_CTRL0_MBR_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION29_CTRL0_MBR_MASK 0xFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION29_CTRL1 0x079d ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION29_CTRL1_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION29_CTRL1_MASK 0xF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION29_CTRL2 0x079e ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION29_CTRL2_METERIDX_EXT_OFFSET 10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION29_CTRL2_METERIDX_EXT_MASK 0x400 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION29_CTRL2_METERIDX_OFFSET 5 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION29_CTRL2_METERIDX_MASK 0x3E0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION29_CTRL2_ENVLANPOL_OFFSET 4 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION29_CTRL2_ENVLANPOL_MASK 0x10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION29_CTRL2_VBPRI_OFFSET 1 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION29_CTRL2_VBPRI_MASK 0xE ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION29_CTRL2_VBPEN_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION29_CTRL2_VBPEN_MASK 0x1 ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION29_CTRL3 0x079f ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION29_CTRL3_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION29_CTRL3_MASK 0x1FFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION30_CTRL0 0x07a0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION30_CTRL0_MBR_EXT_OFFSET 8 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION30_CTRL0_MBR_EXT_MASK 0x700 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION30_CTRL0_MBR_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION30_CTRL0_MBR_MASK 0xFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION30_CTRL1 0x07a1 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION30_CTRL1_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION30_CTRL1_MASK 0xF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION30_CTRL2 0x07a2 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION30_CTRL2_METERIDX_EXT_OFFSET 10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION30_CTRL2_METERIDX_EXT_MASK 0x400 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION30_CTRL2_METERIDX_OFFSET 5 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION30_CTRL2_METERIDX_MASK 0x3E0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION30_CTRL2_ENVLANPOL_OFFSET 4 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION30_CTRL2_ENVLANPOL_MASK 0x10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION30_CTRL2_VBPRI_OFFSET 1 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION30_CTRL2_VBPRI_MASK 0xE ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION30_CTRL2_VBPEN_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION30_CTRL2_VBPEN_MASK 0x1 ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION30_CTRL3 0x07a3 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION30_CTRL3_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION30_CTRL3_MASK 0x1FFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION31_CTRL0 0x07a4 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION31_CTRL0_MBR_EXT_OFFSET 8 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION31_CTRL0_MBR_EXT_MASK 0x700 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION31_CTRL0_MBR_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION31_CTRL0_MBR_MASK 0xFF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION31_CTRL1 0x07a5 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION31_CTRL1_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION31_CTRL1_MASK 0xF ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION31_CTRL2 0x07a6 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION31_CTRL2_METERIDX_EXT_OFFSET 10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION31_CTRL2_METERIDX_EXT_MASK 0x400 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION31_CTRL2_METERIDX_OFFSET 5 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION31_CTRL2_METERIDX_MASK 0x3E0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION31_CTRL2_ENVLANPOL_OFFSET 4 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION31_CTRL2_ENVLANPOL_MASK 0x10 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION31_CTRL2_VBPRI_OFFSET 1 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION31_CTRL2_VBPRI_MASK 0xE ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION31_CTRL2_VBPEN_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION31_CTRL2_VBPEN_MASK 0x1 ++ ++#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION31_CTRL3 0x07a7 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION31_CTRL3_OFFSET 0 ++#define RTL8367C_VLAN_MEMBER_CONFIGURATION31_CTRL3_MASK 0x1FFF ++ ++#define RTL8367C_REG_VLAN_CTRL 0x07a8 ++#define RTL8367C_VLAN_CTRL_OFFSET 0 ++#define RTL8367C_VLAN_CTRL_MASK 0x1 ++ ++#define RTL8367C_REG_VLAN_INGRESS 0x07a9 ++#define RTL8367C_VLAN_INGRESS_OFFSET 0 ++#define RTL8367C_VLAN_INGRESS_MASK 0x7FF ++ ++#define RTL8367C_REG_VLAN_ACCEPT_FRAME_TYPE_CTRL0 0x07aa ++#define RTL8367C_PORT7_FRAME_TYPE_OFFSET 14 ++#define RTL8367C_PORT7_FRAME_TYPE_MASK 0xC000 ++#define RTL8367C_PORT6_FRAME_TYPE_OFFSET 12 ++#define RTL8367C_PORT6_FRAME_TYPE_MASK 0x3000 ++#define RTL8367C_PORT5_FRAME_TYPE_OFFSET 10 ++#define RTL8367C_PORT5_FRAME_TYPE_MASK 0xC00 ++#define RTL8367C_PORT4_FRAME_TYPE_OFFSET 8 ++#define RTL8367C_PORT4_FRAME_TYPE_MASK 0x300 ++#define RTL8367C_PORT3_FRAME_TYPE_OFFSET 6 ++#define RTL8367C_PORT3_FRAME_TYPE_MASK 0xC0 ++#define RTL8367C_PORT2_FRAME_TYPE_OFFSET 4 ++#define RTL8367C_PORT2_FRAME_TYPE_MASK 0x30 ++#define RTL8367C_PORT1_FRAME_TYPE_OFFSET 2 ++#define RTL8367C_PORT1_FRAME_TYPE_MASK 0xC ++#define RTL8367C_PORT0_FRAME_TYPE_OFFSET 0 ++#define RTL8367C_PORT0_FRAME_TYPE_MASK 0x3 ++ ++#define RTL8367C_REG_VLAN_ACCEPT_FRAME_TYPE_CTRL1 0x07ab ++#define RTL8367C_PORT10_FRAME_TYPE_OFFSET 4 ++#define RTL8367C_PORT10_FRAME_TYPE_MASK 0x30 ++#define RTL8367C_PORT9_FRAME_TYPE_OFFSET 2 ++#define RTL8367C_PORT9_FRAME_TYPE_MASK 0xC ++#define RTL8367C_PORT8_FRAME_TYPE_OFFSET 0 ++#define RTL8367C_PORT8_FRAME_TYPE_MASK 0x3 ++ ++#define RTL8367C_REG_PORT_PBFIDEN 0x07ac ++#define RTL8367C_PORT_PBFIDEN_OFFSET 0 ++#define RTL8367C_PORT_PBFIDEN_MASK 0x7FF ++ ++#define RTL8367C_REG_PORT0_PBFID 0x07ad ++#define RTL8367C_PORT0_PBFID_OFFSET 0 ++#define RTL8367C_PORT0_PBFID_MASK 0xF ++ ++#define RTL8367C_REG_PORT1_PBFID 0x07ae ++#define RTL8367C_PORT1_PBFID_OFFSET 0 ++#define RTL8367C_PORT1_PBFID_MASK 0xF ++ ++#define RTL8367C_REG_PORT2_PBFID 0x07af ++#define RTL8367C_PORT2_PBFID_OFFSET 0 ++#define RTL8367C_PORT2_PBFID_MASK 0xF ++ ++#define RTL8367C_REG_PORT3_PBFID 0x07b0 ++#define RTL8367C_PORT3_PBFID_OFFSET 0 ++#define RTL8367C_PORT3_PBFID_MASK 0xF ++ ++#define RTL8367C_REG_PORT4_PBFID 0x07b1 ++#define RTL8367C_PORT4_PBFID_OFFSET 0 ++#define RTL8367C_PORT4_PBFID_MASK 0xF ++ ++#define RTL8367C_REG_PORT5_PBFID 0x07b2 ++#define RTL8367C_PORT5_PBFID_OFFSET 0 ++#define RTL8367C_PORT5_PBFID_MASK 0xF ++ ++#define RTL8367C_REG_PORT6_PBFID 0x07b3 ++#define RTL8367C_PORT6_PBFID_OFFSET 0 ++#define RTL8367C_PORT6_PBFID_MASK 0xF ++ ++#define RTL8367C_REG_PORT7_PBFID 0x07b4 ++#define RTL8367C_PORT7_PBFID_OFFSET 0 ++#define RTL8367C_PORT7_PBFID_MASK 0xF ++ ++#define RTL8367C_REG_VLAN_EXT_CTRL 0x07b5 ++#define RTL8367C_VLAN_1P_REMARK_BYPASS_REALKEEP_OFFSET 2 ++#define RTL8367C_VLAN_1P_REMARK_BYPASS_REALKEEP_MASK 0x4 ++#define RTL8367C_VLAN_VID4095_TYPE_OFFSET 1 ++#define RTL8367C_VLAN_VID4095_TYPE_MASK 0x2 ++#define RTL8367C_VLAN_VID0_TYPE_OFFSET 0 ++#define RTL8367C_VLAN_VID0_TYPE_MASK 0x1 ++ ++#define RTL8367C_REG_VLAN_EXT_CTRL2 0x07b6 ++#define RTL8367C_VLAN_EXT_CTRL2_OFFSET 0 ++#define RTL8367C_VLAN_EXT_CTRL2_MASK 0x1 ++ ++#define RTL8367C_REG_PORT8_PBFID 0x07b7 ++#define RTL8367C_PORT8_PBFID_OFFSET 0 ++#define RTL8367C_PORT8_PBFID_MASK 0xF ++ ++#define RTL8367C_REG_PORT9_PBFID 0x07b8 ++#define RTL8367C_PORT9_PBFID_OFFSET 0 ++#define RTL8367C_PORT9_PBFID_MASK 0xF ++ ++#define RTL8367C_REG_PORT10_PBFID 0x07b9 ++#define RTL8367C_PORT10_PBFID_OFFSET 0 ++#define RTL8367C_PORT10_PBFID_MASK 0xF ++ ++#define RTL8367C_REG_CVLAN_DUMMY00 0x07E0 ++ ++#define RTL8367C_REG_CVLAN_DUMMY01 0x07E1 ++ ++#define RTL8367C_REG_CVLAN_DUMMY02 0x07E2 ++ ++#define RTL8367C_REG_CVLAN_DUMMY03 0x07E3 ++ ++#define RTL8367C_REG_CVLAN_DUMMY04 0x07E4 ++ ++#define RTL8367C_REG_CVLAN_DUMMY05 0x07E5 ++ ++#define RTL8367C_REG_CVLAN_DUMMY06 0x07E6 ++ ++#define RTL8367C_REG_CVLAN_DUMMY07 0x07E7 ++ ++#define RTL8367C_REG_CVLAN_DUMMY08 0x07E8 ++ ++#define RTL8367C_REG_CVLAN_DUMMY09 0x07E9 ++ ++#define RTL8367C_REG_CVLAN_DUMMY10 0x07EA ++ ++#define RTL8367C_REG_CVLAN_DUMMY11 0x07EB ++ ++#define RTL8367C_REG_CVLAN_DUMMY12 0x07EC ++ ++#define RTL8367C_REG_CVLAN_DUMMY13 0x07ED ++ ++#define RTL8367C_REG_CVLAN_DUMMY14 0x07EE ++ ++#define RTL8367C_REG_CVLAN_DUMMY15 0x07EF ++ ++/* (16'h0800)dpm_reg */ ++ ++#define RTL8367C_REG_RMA_CTRL00 0x0800 ++#define RTL8367C_RMA_CTRL00_OPERATION_OFFSET 7 ++#define RTL8367C_RMA_CTRL00_OPERATION_MASK 0x180 ++#define RTL8367C_RMA_CTRL00_DISCARD_STORM_FILTER_OFFSET 6 ++#define RTL8367C_RMA_CTRL00_DISCARD_STORM_FILTER_MASK 0x40 ++#define RTL8367C_TRAP_PRIORITY_OFFSET 3 ++#define RTL8367C_TRAP_PRIORITY_MASK 0x38 ++#define RTL8367C_RMA_CTRL00_KEEP_FORMAT_OFFSET 2 ++#define RTL8367C_RMA_CTRL00_KEEP_FORMAT_MASK 0x4 ++#define RTL8367C_RMA_CTRL00_VLAN_LEAKY_OFFSET 1 ++#define RTL8367C_RMA_CTRL00_VLAN_LEAKY_MASK 0x2 ++#define RTL8367C_RMA_CTRL00_PORTISO_LEAKY_OFFSET 0 ++#define RTL8367C_RMA_CTRL00_PORTISO_LEAKY_MASK 0x1 ++ ++#define RTL8367C_REG_RMA_CTRL01 0x0801 ++#define RTL8367C_RMA_CTRL01_OPERATION_OFFSET 7 ++#define RTL8367C_RMA_CTRL01_OPERATION_MASK 0x180 ++#define RTL8367C_RMA_CTRL01_DISCARD_STORM_FILTER_OFFSET 6 ++#define RTL8367C_RMA_CTRL01_DISCARD_STORM_FILTER_MASK 0x40 ++#define RTL8367C_RMA_CTRL01_KEEP_FORMAT_OFFSET 2 ++#define RTL8367C_RMA_CTRL01_KEEP_FORMAT_MASK 0x4 ++#define RTL8367C_RMA_CTRL01_VLAN_LEAKY_OFFSET 1 ++#define RTL8367C_RMA_CTRL01_VLAN_LEAKY_MASK 0x2 ++#define RTL8367C_RMA_CTRL01_PORTISO_LEAKY_OFFSET 0 ++#define RTL8367C_RMA_CTRL01_PORTISO_LEAKY_MASK 0x1 ++ ++#define RTL8367C_REG_RMA_CTRL02 0x0802 ++#define RTL8367C_RMA_CTRL02_OPERATION_OFFSET 7 ++#define RTL8367C_RMA_CTRL02_OPERATION_MASK 0x180 ++#define RTL8367C_RMA_CTRL02_DISCARD_STORM_FILTER_OFFSET 6 ++#define RTL8367C_RMA_CTRL02_DISCARD_STORM_FILTER_MASK 0x40 ++#define RTL8367C_RMA_CTRL02_KEEP_FORMAT_OFFSET 2 ++#define RTL8367C_RMA_CTRL02_KEEP_FORMAT_MASK 0x4 ++#define RTL8367C_RMA_CTRL02_VLAN_LEAKY_OFFSET 1 ++#define RTL8367C_RMA_CTRL02_VLAN_LEAKY_MASK 0x2 ++#define RTL8367C_RMA_CTRL02_PORTISO_LEAKY_OFFSET 0 ++#define RTL8367C_RMA_CTRL02_PORTISO_LEAKY_MASK 0x1 ++ ++#define RTL8367C_REG_RMA_CTRL03 0x0803 ++#define RTL8367C_RMA_CTRL03_OPERATION_OFFSET 7 ++#define RTL8367C_RMA_CTRL03_OPERATION_MASK 0x180 ++#define RTL8367C_RMA_CTRL03_DISCARD_STORM_FILTER_OFFSET 6 ++#define RTL8367C_RMA_CTRL03_DISCARD_STORM_FILTER_MASK 0x40 ++#define RTL8367C_RMA_CTRL03_KEEP_FORMAT_OFFSET 2 ++#define RTL8367C_RMA_CTRL03_KEEP_FORMAT_MASK 0x4 ++#define RTL8367C_RMA_CTRL03_VLAN_LEAKY_OFFSET 1 ++#define RTL8367C_RMA_CTRL03_VLAN_LEAKY_MASK 0x2 ++#define RTL8367C_RMA_CTRL03_PORTISO_LEAKY_OFFSET 0 ++#define RTL8367C_RMA_CTRL03_PORTISO_LEAKY_MASK 0x1 ++ ++#define RTL8367C_REG_RMA_CTRL04 0x0804 ++#define RTL8367C_RMA_CTRL04_OPERATION_OFFSET 7 ++#define RTL8367C_RMA_CTRL04_OPERATION_MASK 0x180 ++#define RTL8367C_RMA_CTRL04_DISCARD_STORM_FILTER_OFFSET 6 ++#define RTL8367C_RMA_CTRL04_DISCARD_STORM_FILTER_MASK 0x40 ++#define RTL8367C_RMA_CTRL04_KEEP_FORMAT_OFFSET 2 ++#define RTL8367C_RMA_CTRL04_KEEP_FORMAT_MASK 0x4 ++#define RTL8367C_RMA_CTRL04_VLAN_LEAKY_OFFSET 1 ++#define RTL8367C_RMA_CTRL04_VLAN_LEAKY_MASK 0x2 ++#define RTL8367C_RMA_CTRL04_PORTISO_LEAKY_OFFSET 0 ++#define RTL8367C_RMA_CTRL04_PORTISO_LEAKY_MASK 0x1 ++ ++#define RTL8367C_REG_RMA_CTRL08 0x0808 ++#define RTL8367C_RMA_CTRL08_OPERATION_OFFSET 7 ++#define RTL8367C_RMA_CTRL08_OPERATION_MASK 0x180 ++#define RTL8367C_RMA_CTRL08_DISCARD_STORM_FILTER_OFFSET 6 ++#define RTL8367C_RMA_CTRL08_DISCARD_STORM_FILTER_MASK 0x40 ++#define RTL8367C_RMA_CTRL08_KEEP_FORMAT_OFFSET 2 ++#define RTL8367C_RMA_CTRL08_KEEP_FORMAT_MASK 0x4 ++#define RTL8367C_RMA_CTRL08_VLAN_LEAKY_OFFSET 1 ++#define RTL8367C_RMA_CTRL08_VLAN_LEAKY_MASK 0x2 ++#define RTL8367C_RMA_CTRL08_PORTISO_LEAKY_OFFSET 0 ++#define RTL8367C_RMA_CTRL08_PORTISO_LEAKY_MASK 0x1 ++ ++#define RTL8367C_REG_RMA_CTRL0D 0x080d ++#define RTL8367C_RMA_CTRL0D_OPERATION_OFFSET 7 ++#define RTL8367C_RMA_CTRL0D_OPERATION_MASK 0x180 ++#define RTL8367C_RMA_CTRL0D_DISCARD_STORM_FILTER_OFFSET 6 ++#define RTL8367C_RMA_CTRL0D_DISCARD_STORM_FILTER_MASK 0x40 ++#define RTL8367C_RMA_CTRL0D_KEEP_FORMAT_OFFSET 2 ++#define RTL8367C_RMA_CTRL0D_KEEP_FORMAT_MASK 0x4 ++#define RTL8367C_RMA_CTRL0D_VLAN_LEAKY_OFFSET 1 ++#define RTL8367C_RMA_CTRL0D_VLAN_LEAKY_MASK 0x2 ++#define RTL8367C_RMA_CTRL0D_PORTISO_LEAKY_OFFSET 0 ++#define RTL8367C_RMA_CTRL0D_PORTISO_LEAKY_MASK 0x1 ++ ++#define RTL8367C_REG_RMA_CTRL0E 0x080e ++#define RTL8367C_RMA_CTRL0E_OPERATION_OFFSET 7 ++#define RTL8367C_RMA_CTRL0E_OPERATION_MASK 0x180 ++#define RTL8367C_RMA_CTRL0E_DISCARD_STORM_FILTER_OFFSET 6 ++#define RTL8367C_RMA_CTRL0E_DISCARD_STORM_FILTER_MASK 0x40 ++#define RTL8367C_RMA_CTRL0E_KEEP_FORMAT_OFFSET 2 ++#define RTL8367C_RMA_CTRL0E_KEEP_FORMAT_MASK 0x4 ++#define RTL8367C_RMA_CTRL0E_VLAN_LEAKY_OFFSET 1 ++#define RTL8367C_RMA_CTRL0E_VLAN_LEAKY_MASK 0x2 ++#define RTL8367C_RMA_CTRL0E_PORTISO_LEAKY_OFFSET 0 ++#define RTL8367C_RMA_CTRL0E_PORTISO_LEAKY_MASK 0x1 ++ ++#define RTL8367C_REG_RMA_CTRL10 0x0810 ++#define RTL8367C_RMA_CTRL10_OPERATION_OFFSET 7 ++#define RTL8367C_RMA_CTRL10_OPERATION_MASK 0x180 ++#define RTL8367C_RMA_CTRL10_DISCARD_STORM_FILTER_OFFSET 6 ++#define RTL8367C_RMA_CTRL10_DISCARD_STORM_FILTER_MASK 0x40 ++#define RTL8367C_RMA_CTRL10_KEEP_FORMAT_OFFSET 2 ++#define RTL8367C_RMA_CTRL10_KEEP_FORMAT_MASK 0x4 ++#define RTL8367C_RMA_CTRL10_VLAN_LEAKY_OFFSET 1 ++#define RTL8367C_RMA_CTRL10_VLAN_LEAKY_MASK 0x2 ++#define RTL8367C_RMA_CTRL10_PORTISO_LEAKY_OFFSET 0 ++#define RTL8367C_RMA_CTRL10_PORTISO_LEAKY_MASK 0x1 ++ ++#define RTL8367C_REG_RMA_CTRL11 0x0811 ++#define RTL8367C_RMA_CTRL11_OPERATION_OFFSET 7 ++#define RTL8367C_RMA_CTRL11_OPERATION_MASK 0x180 ++#define RTL8367C_RMA_CTRL11_DISCARD_STORM_FILTER_OFFSET 6 ++#define RTL8367C_RMA_CTRL11_DISCARD_STORM_FILTER_MASK 0x40 ++#define RTL8367C_RMA_CTRL11_KEEP_FORMAT_OFFSET 2 ++#define RTL8367C_RMA_CTRL11_KEEP_FORMAT_MASK 0x4 ++#define RTL8367C_RMA_CTRL11_VLAN_LEAKY_OFFSET 1 ++#define RTL8367C_RMA_CTRL11_VLAN_LEAKY_MASK 0x2 ++#define RTL8367C_RMA_CTRL11_PORTISO_LEAKY_OFFSET 0 ++#define RTL8367C_RMA_CTRL11_PORTISO_LEAKY_MASK 0x1 ++ ++#define RTL8367C_REG_RMA_CTRL12 0x0812 ++#define RTL8367C_RMA_CTRL12_OPERATION_OFFSET 7 ++#define RTL8367C_RMA_CTRL12_OPERATION_MASK 0x180 ++#define RTL8367C_RMA_CTRL12_DISCARD_STORM_FILTER_OFFSET 6 ++#define RTL8367C_RMA_CTRL12_DISCARD_STORM_FILTER_MASK 0x40 ++#define RTL8367C_RMA_CTRL12_KEEP_FORMAT_OFFSET 2 ++#define RTL8367C_RMA_CTRL12_KEEP_FORMAT_MASK 0x4 ++#define RTL8367C_RMA_CTRL12_VLAN_LEAKY_OFFSET 1 ++#define RTL8367C_RMA_CTRL12_VLAN_LEAKY_MASK 0x2 ++#define RTL8367C_RMA_CTRL12_PORTISO_LEAKY_OFFSET 0 ++#define RTL8367C_RMA_CTRL12_PORTISO_LEAKY_MASK 0x1 ++ ++#define RTL8367C_REG_RMA_CTRL13 0x0813 ++#define RTL8367C_RMA_CTRL13_OPERATION_OFFSET 7 ++#define RTL8367C_RMA_CTRL13_OPERATION_MASK 0x180 ++#define RTL8367C_RMA_CTRL13_DISCARD_STORM_FILTER_OFFSET 6 ++#define RTL8367C_RMA_CTRL13_DISCARD_STORM_FILTER_MASK 0x40 ++#define RTL8367C_RMA_CTRL13_KEEP_FORMAT_OFFSET 2 ++#define RTL8367C_RMA_CTRL13_KEEP_FORMAT_MASK 0x4 ++#define RTL8367C_RMA_CTRL13_VLAN_LEAKY_OFFSET 1 ++#define RTL8367C_RMA_CTRL13_VLAN_LEAKY_MASK 0x2 ++#define RTL8367C_RMA_CTRL13_PORTISO_LEAKY_OFFSET 0 ++#define RTL8367C_RMA_CTRL13_PORTISO_LEAKY_MASK 0x1 ++ ++#define RTL8367C_REG_RMA_CTRL18 0x0818 ++#define RTL8367C_RMA_CTRL18_OPERATION_OFFSET 7 ++#define RTL8367C_RMA_CTRL18_OPERATION_MASK 0x180 ++#define RTL8367C_RMA_CTRL18_DISCARD_STORM_FILTER_OFFSET 6 ++#define RTL8367C_RMA_CTRL18_DISCARD_STORM_FILTER_MASK 0x40 ++#define RTL8367C_RMA_CTRL18_KEEP_FORMAT_OFFSET 2 ++#define RTL8367C_RMA_CTRL18_KEEP_FORMAT_MASK 0x4 ++#define RTL8367C_RMA_CTRL18_VLAN_LEAKY_OFFSET 1 ++#define RTL8367C_RMA_CTRL18_VLAN_LEAKY_MASK 0x2 ++#define RTL8367C_RMA_CTRL18_PORTISO_LEAKY_OFFSET 0 ++#define RTL8367C_RMA_CTRL18_PORTISO_LEAKY_MASK 0x1 ++ ++#define RTL8367C_REG_RMA_CTRL1A 0x081a ++#define RTL8367C_RMA_CTRL1A_OPERATION_OFFSET 7 ++#define RTL8367C_RMA_CTRL1A_OPERATION_MASK 0x180 ++#define RTL8367C_RMA_CTRL1A_DISCARD_STORM_FILTER_OFFSET 6 ++#define RTL8367C_RMA_CTRL1A_DISCARD_STORM_FILTER_MASK 0x40 ++#define RTL8367C_RMA_CTRL1A_KEEP_FORMAT_OFFSET 2 ++#define RTL8367C_RMA_CTRL1A_KEEP_FORMAT_MASK 0x4 ++#define RTL8367C_RMA_CTRL1A_VLAN_LEAKY_OFFSET 1 ++#define RTL8367C_RMA_CTRL1A_VLAN_LEAKY_MASK 0x2 ++#define RTL8367C_RMA_CTRL1A_PORTISO_LEAKY_OFFSET 0 ++#define RTL8367C_RMA_CTRL1A_PORTISO_LEAKY_MASK 0x1 ++ ++#define RTL8367C_REG_RMA_CTRL20 0x0820 ++#define RTL8367C_RMA_CTRL20_OPERATION_OFFSET 7 ++#define RTL8367C_RMA_CTRL20_OPERATION_MASK 0x180 ++#define RTL8367C_RMA_CTRL20_DISCARD_STORM_FILTER_OFFSET 6 ++#define RTL8367C_RMA_CTRL20_DISCARD_STORM_FILTER_MASK 0x40 ++#define RTL8367C_RMA_CTRL20_KEEP_FORMAT_OFFSET 2 ++#define RTL8367C_RMA_CTRL20_KEEP_FORMAT_MASK 0x4 ++#define RTL8367C_RMA_CTRL20_VLAN_LEAKY_OFFSET 1 ++#define RTL8367C_RMA_CTRL20_VLAN_LEAKY_MASK 0x2 ++#define RTL8367C_RMA_CTRL20_PORTISO_LEAKY_OFFSET 0 ++#define RTL8367C_RMA_CTRL20_PORTISO_LEAKY_MASK 0x1 ++ ++#define RTL8367C_REG_RMA_CTRL21 0x0821 ++#define RTL8367C_RMA_CTRL21_OPERATION_OFFSET 7 ++#define RTL8367C_RMA_CTRL21_OPERATION_MASK 0x180 ++#define RTL8367C_RMA_CTRL21_DISCARD_STORM_FILTER_OFFSET 6 ++#define RTL8367C_RMA_CTRL21_DISCARD_STORM_FILTER_MASK 0x40 ++#define RTL8367C_RMA_CTRL21_KEEP_FORMAT_OFFSET 2 ++#define RTL8367C_RMA_CTRL21_KEEP_FORMAT_MASK 0x4 ++#define RTL8367C_RMA_CTRL21_VLAN_LEAKY_OFFSET 1 ++#define RTL8367C_RMA_CTRL21_VLAN_LEAKY_MASK 0x2 ++#define RTL8367C_RMA_CTRL21_PORTISO_LEAKY_OFFSET 0 ++#define RTL8367C_RMA_CTRL21_PORTISO_LEAKY_MASK 0x1 ++ ++#define RTL8367C_REG_RMA_CTRL22 0x0822 ++#define RTL8367C_RMA_CTRL22_OPERATION_OFFSET 7 ++#define RTL8367C_RMA_CTRL22_OPERATION_MASK 0x180 ++#define RTL8367C_RMA_CTRL22_DISCARD_STORM_FILTER_OFFSET 6 ++#define RTL8367C_RMA_CTRL22_DISCARD_STORM_FILTER_MASK 0x40 ++#define RTL8367C_RMA_CTRL22_KEEP_FORMAT_OFFSET 2 ++#define RTL8367C_RMA_CTRL22_KEEP_FORMAT_MASK 0x4 ++#define RTL8367C_RMA_CTRL22_VLAN_LEAKY_OFFSET 1 ++#define RTL8367C_RMA_CTRL22_VLAN_LEAKY_MASK 0x2 ++#define RTL8367C_RMA_CTRL22_PORTISO_LEAKY_OFFSET 0 ++#define RTL8367C_RMA_CTRL22_PORTISO_LEAKY_MASK 0x1 ++ ++#define RTL8367C_REG_RMA_CTRL_CDP 0x0830 ++#define RTL8367C_RMA_CTRL_CDP_OPERATION_OFFSET 7 ++#define RTL8367C_RMA_CTRL_CDP_OPERATION_MASK 0x180 ++#define RTL8367C_RMA_CTRL_CDP_DISCARD_STORM_FILTER_OFFSET 6 ++#define RTL8367C_RMA_CTRL_CDP_DISCARD_STORM_FILTER_MASK 0x40 ++#define RTL8367C_RMA_CTRL_CDP_KEEP_FORMAT_OFFSET 2 ++#define RTL8367C_RMA_CTRL_CDP_KEEP_FORMAT_MASK 0x4 ++#define RTL8367C_RMA_CTRL_CDP_VLAN_LEAKY_OFFSET 1 ++#define RTL8367C_RMA_CTRL_CDP_VLAN_LEAKY_MASK 0x2 ++#define RTL8367C_RMA_CTRL_CDP_PORTISO_LEAKY_OFFSET 0 ++#define RTL8367C_RMA_CTRL_CDP_PORTISO_LEAKY_MASK 0x1 ++ ++#define RTL8367C_REG_RMA_CTRL_CSSTP 0x0831 ++#define RTL8367C_RMA_CTRL_CSSTP_OPERATION_OFFSET 7 ++#define RTL8367C_RMA_CTRL_CSSTP_OPERATION_MASK 0x180 ++#define RTL8367C_RMA_CTRL_CSSTP_DISCARD_STORM_FILTER_OFFSET 6 ++#define RTL8367C_RMA_CTRL_CSSTP_DISCARD_STORM_FILTER_MASK 0x40 ++#define RTL8367C_RMA_CTRL_CSSTP_KEEP_FORMAT_OFFSET 2 ++#define RTL8367C_RMA_CTRL_CSSTP_KEEP_FORMAT_MASK 0x4 ++#define RTL8367C_RMA_CTRL_CSSTP_VLAN_LEAKY_OFFSET 1 ++#define RTL8367C_RMA_CTRL_CSSTP_VLAN_LEAKY_MASK 0x2 ++#define RTL8367C_RMA_CTRL_CSSTP_PORTISO_LEAKY_OFFSET 0 ++#define RTL8367C_RMA_CTRL_CSSTP_PORTISO_LEAKY_MASK 0x1 ++ ++#define RTL8367C_REG_RMA_CTRL_LLDP 0x0832 ++#define RTL8367C_RMA_CTRL_LLDP_OPERATION_OFFSET 7 ++#define RTL8367C_RMA_CTRL_LLDP_OPERATION_MASK 0x180 ++#define RTL8367C_RMA_CTRL_LLDP_DISCARD_STORM_FILTER_OFFSET 6 ++#define RTL8367C_RMA_CTRL_LLDP_DISCARD_STORM_FILTER_MASK 0x40 ++#define RTL8367C_RMA_CTRL_LLDP_KEEP_FORMAT_OFFSET 2 ++#define RTL8367C_RMA_CTRL_LLDP_KEEP_FORMAT_MASK 0x4 ++#define RTL8367C_RMA_CTRL_LLDP_VLAN_LEAKY_OFFSET 1 ++#define RTL8367C_RMA_CTRL_LLDP_VLAN_LEAKY_MASK 0x2 ++#define RTL8367C_RMA_CTRL_LLDP_PORTISO_LEAKY_OFFSET 0 ++#define RTL8367C_RMA_CTRL_LLDP_PORTISO_LEAKY_MASK 0x1 ++ ++#define RTL8367C_REG_RMA_LLDP_EN 0x0833 ++#define RTL8367C_RMA_LLDP_EN_OFFSET 0 ++#define RTL8367C_RMA_LLDP_EN_MASK 0x1 ++ ++#define RTL8367C_REG_VLAN_PORTBASED_PRIORITY_CTRL0 0x0851 ++#define RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL0_PORT3_PRIORITY_OFFSET 12 ++#define RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL0_PORT3_PRIORITY_MASK 0x7000 ++#define RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL0_PORT2_PRIORITY_OFFSET 8 ++#define RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL0_PORT2_PRIORITY_MASK 0x700 ++#define RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL0_PORT1_PRIORITY_OFFSET 4 ++#define RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL0_PORT1_PRIORITY_MASK 0x70 ++#define RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL0_PORT0_PRIORITY_OFFSET 0 ++#define RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL0_PORT0_PRIORITY_MASK 0x7 ++ ++#define RTL8367C_REG_VLAN_PORTBASED_PRIORITY_CTRL1 0x0852 ++#define RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL1_PORT7_PRIORITY_OFFSET 12 ++#define RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL1_PORT7_PRIORITY_MASK 0x7000 ++#define RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL1_PORT6_PRIORITY_OFFSET 8 ++#define RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL1_PORT6_PRIORITY_MASK 0x700 ++#define RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL1_PORT5_PRIORITY_OFFSET 4 ++#define RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL1_PORT5_PRIORITY_MASK 0x70 ++#define RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL1_PORT4_PRIORITY_OFFSET 0 ++#define RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL1_PORT4_PRIORITY_MASK 0x7 ++ ++#define RTL8367C_REG_VLAN_PORTBASED_PRIORITY_CTRL2 0x0853 ++#define RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL2_PORT10_PRIORITY_OFFSET 8 ++#define RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL2_PORT10_PRIORITY_MASK 0x700 ++#define RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL2_PORT9_PRIORITY_OFFSET 4 ++#define RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL2_PORT9_PRIORITY_MASK 0x70 ++#define RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL2_PORT8_PRIORITY_OFFSET 0 ++#define RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL2_PORT8_PRIORITY_MASK 0x7 ++ ++#define RTL8367C_REG_VLAN_PPB_PRIORITY_ITEM0_CTRL0 0x0855 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL0_PORT3_PRIORITY_OFFSET 12 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL0_PORT3_PRIORITY_MASK 0x7000 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL0_PORT2_PRIORITY_OFFSET 8 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL0_PORT2_PRIORITY_MASK 0x700 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL0_PORT1_PRIORITY_OFFSET 4 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL0_PORT1_PRIORITY_MASK 0x70 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL0_PORT0_PRIORITY_OFFSET 0 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL0_PORT0_PRIORITY_MASK 0x7 ++ ++#define RTL8367C_REG_VLAN_PPB_PRIORITY_ITEM0_CTRL1 0x0856 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL1_PORT7_PRIORITY_OFFSET 12 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL1_PORT7_PRIORITY_MASK 0x7000 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL1_PORT6_PRIORITY_OFFSET 8 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL1_PORT6_PRIORITY_MASK 0x700 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL1_PORT5_PRIORITY_OFFSET 4 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL1_PORT5_PRIORITY_MASK 0x70 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL1_PORT4_PRIORITY_OFFSET 0 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL1_PORT4_PRIORITY_MASK 0x7 ++ ++#define RTL8367C_REG_VLAN_PPB_PRIORITY_ITEM0_CTRL2 0x0857 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL2_PORT10_PRIORITY_OFFSET 8 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL2_PORT10_PRIORITY_MASK 0x700 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL2_PORT9_PRIORITY_OFFSET 4 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL2_PORT9_PRIORITY_MASK 0x70 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL2_PORT8_PRIORITY_OFFSET 0 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL2_PORT8_PRIORITY_MASK 0x7 ++ ++#define RTL8367C_REG_VLAN_PPB_PRIORITY_ITEM1_CTRL0 0x0859 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL0_PORT3_PRIORITY_OFFSET 12 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL0_PORT3_PRIORITY_MASK 0x7000 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL0_PORT2_PRIORITY_OFFSET 8 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL0_PORT2_PRIORITY_MASK 0x700 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL0_PORT1_PRIORITY_OFFSET 4 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL0_PORT1_PRIORITY_MASK 0x70 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL0_PORT0_PRIORITY_OFFSET 0 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL0_PORT0_PRIORITY_MASK 0x7 ++ ++#define RTL8367C_REG_VLAN_PPB_PRIORITY_ITEM1_CTRL1 0x085a ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL1_PORT7_PRIORITY_OFFSET 12 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL1_PORT7_PRIORITY_MASK 0x7000 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL1_PORT6_PRIORITY_OFFSET 8 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL1_PORT6_PRIORITY_MASK 0x700 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL1_PORT5_PRIORITY_OFFSET 4 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL1_PORT5_PRIORITY_MASK 0x70 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL1_PORT4_PRIORITY_OFFSET 0 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL1_PORT4_PRIORITY_MASK 0x7 ++ ++#define RTL8367C_REG_VLAN_PPB_PRIORITY_ITEM1_CTRL2 0x085b ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL2_PORT10_PRIORITY_OFFSET 8 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL2_PORT10_PRIORITY_MASK 0x700 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL2_PORT9_PRIORITY_OFFSET 4 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL2_PORT9_PRIORITY_MASK 0x70 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL2_PORT8_PRIORITY_OFFSET 0 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL2_PORT8_PRIORITY_MASK 0x7 ++ ++#define RTL8367C_REG_VLAN_PPB_PRIORITY_ITEM2_CTRL0 0x085d ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL0_PORT3_PRIORITY_OFFSET 12 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL0_PORT3_PRIORITY_MASK 0x7000 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL0_PORT2_PRIORITY_OFFSET 8 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL0_PORT2_PRIORITY_MASK 0x700 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL0_PORT1_PRIORITY_OFFSET 4 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL0_PORT1_PRIORITY_MASK 0x70 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL0_PORT0_PRIORITY_OFFSET 0 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL0_PORT0_PRIORITY_MASK 0x7 ++ ++#define RTL8367C_REG_VLAN_PPB_PRIORITY_ITEM2_CTRL1 0x085e ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL1_PORT7_PRIORITY_OFFSET 12 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL1_PORT7_PRIORITY_MASK 0x7000 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL1_PORT6_PRIORITY_OFFSET 8 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL1_PORT6_PRIORITY_MASK 0x700 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL1_PORT5_PRIORITY_OFFSET 4 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL1_PORT5_PRIORITY_MASK 0x70 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL1_PORT4_PRIORITY_OFFSET 0 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL1_PORT4_PRIORITY_MASK 0x7 ++ ++#define RTL8367C_REG_VLAN_PPB_PRIORITY_ITEM2_CTRL2 0x085f ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL2_PORT10_PRIORITY_OFFSET 8 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL2_PORT10_PRIORITY_MASK 0x700 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL2_PORT9_PRIORITY_OFFSET 4 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL2_PORT9_PRIORITY_MASK 0x70 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL2_PORT8_PRIORITY_OFFSET 0 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL2_PORT8_PRIORITY_MASK 0x7 ++ ++#define RTL8367C_REG_VLAN_PPB_PRIORITY_ITEM3_CTRL0 0x0861 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL0_PORT3_PRIORITY_OFFSET 12 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL0_PORT3_PRIORITY_MASK 0x7000 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL0_PORT2_PRIORITY_OFFSET 8 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL0_PORT2_PRIORITY_MASK 0x700 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL0_PORT1_PRIORITY_OFFSET 4 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL0_PORT1_PRIORITY_MASK 0x70 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL0_PORT0_PRIORITY_OFFSET 0 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL0_PORT0_PRIORITY_MASK 0x7 ++ ++#define RTL8367C_REG_VLAN_PPB_PRIORITY_ITEM3_CTRL1 0x0862 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL1_PORT7_PRIORITY_OFFSET 12 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL1_PORT7_PRIORITY_MASK 0x7000 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL1_PORT6_PRIORITY_OFFSET 8 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL1_PORT6_PRIORITY_MASK 0x700 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL1_PORT5_PRIORITY_OFFSET 4 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL1_PORT5_PRIORITY_MASK 0x70 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL1_PORT4_PRIORITY_OFFSET 0 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL1_PORT4_PRIORITY_MASK 0x7 ++ ++#define RTL8367C_REG_VLAN_PPB_PRIORITY_ITEM3_CTRL2 0x0863 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL2_PORT10_PRIORITY_OFFSET 8 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL2_PORT10_PRIORITY_MASK 0x700 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL2_PORT9_PRIORITY_OFFSET 4 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL2_PORT9_PRIORITY_MASK 0x70 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL2_PORT8_PRIORITY_OFFSET 0 ++#define RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL2_PORT8_PRIORITY_MASK 0x7 ++ ++#define RTL8367C_REG_QOS_1Q_PRIORITY_REMAPPING_CTRL0 0x0865 ++#define RTL8367C_QOS_1Q_PRIORITY_REMAPPING_CTRL0_PRIORITY3_OFFSET 12 ++#define RTL8367C_QOS_1Q_PRIORITY_REMAPPING_CTRL0_PRIORITY3_MASK 0x7000 ++#define RTL8367C_QOS_1Q_PRIORITY_REMAPPING_CTRL0_PRIORITY2_OFFSET 8 ++#define RTL8367C_QOS_1Q_PRIORITY_REMAPPING_CTRL0_PRIORITY2_MASK 0x700 ++#define RTL8367C_QOS_1Q_PRIORITY_REMAPPING_CTRL0_PRIORITY1_OFFSET 4 ++#define RTL8367C_QOS_1Q_PRIORITY_REMAPPING_CTRL0_PRIORITY1_MASK 0x70 ++#define RTL8367C_QOS_1Q_PRIORITY_REMAPPING_CTRL0_PRIORITY0_OFFSET 0 ++#define RTL8367C_QOS_1Q_PRIORITY_REMAPPING_CTRL0_PRIORITY0_MASK 0x7 ++ ++#define RTL8367C_REG_QOS_1Q_PRIORITY_REMAPPING_CTRL1 0x0866 ++#define RTL8367C_QOS_1Q_PRIORITY_REMAPPING_CTRL1_PRIORITY7_OFFSET 12 ++#define RTL8367C_QOS_1Q_PRIORITY_REMAPPING_CTRL1_PRIORITY7_MASK 0x7000 ++#define RTL8367C_QOS_1Q_PRIORITY_REMAPPING_CTRL1_PRIORITY6_OFFSET 8 ++#define RTL8367C_QOS_1Q_PRIORITY_REMAPPING_CTRL1_PRIORITY6_MASK 0x700 ++#define RTL8367C_QOS_1Q_PRIORITY_REMAPPING_CTRL1_PRIORITY5_OFFSET 4 ++#define RTL8367C_QOS_1Q_PRIORITY_REMAPPING_CTRL1_PRIORITY5_MASK 0x70 ++#define RTL8367C_QOS_1Q_PRIORITY_REMAPPING_CTRL1_PRIORITY4_OFFSET 0 ++#define RTL8367C_QOS_1Q_PRIORITY_REMAPPING_CTRL1_PRIORITY4_MASK 0x7 ++ ++#define RTL8367C_REG_QOS_DSCP_TO_PRIORITY_CTRL0 0x0867 ++#define RTL8367C_DSCP3_PRIORITY_OFFSET 12 ++#define RTL8367C_DSCP3_PRIORITY_MASK 0x7000 ++#define RTL8367C_DSCP2_PRIORITY_OFFSET 8 ++#define RTL8367C_DSCP2_PRIORITY_MASK 0x700 ++#define RTL8367C_DSCP1_PRIORITY_OFFSET 4 ++#define RTL8367C_DSCP1_PRIORITY_MASK 0x70 ++#define RTL8367C_DSCP0_PRIORITY_OFFSET 0 ++#define RTL8367C_DSCP0_PRIORITY_MASK 0x7 ++ ++#define RTL8367C_REG_QOS_DSCP_TO_PRIORITY_CTRL1 0x0868 ++#define RTL8367C_DSCP7_PRIORITY_OFFSET 12 ++#define RTL8367C_DSCP7_PRIORITY_MASK 0x7000 ++#define RTL8367C_DSCP6_PRIORITY_OFFSET 8 ++#define RTL8367C_DSCP6_PRIORITY_MASK 0x700 ++#define RTL8367C_DSCP5_PRIORITY_OFFSET 4 ++#define RTL8367C_DSCP5_PRIORITY_MASK 0x70 ++#define RTL8367C_DSCP4_PRIORITY_OFFSET 0 ++#define RTL8367C_DSCP4_PRIORITY_MASK 0x7 ++ ++#define RTL8367C_REG_QOS_DSCP_TO_PRIORITY_CTRL2 0x0869 ++#define RTL8367C_DSCP11_PRIORITY_OFFSET 12 ++#define RTL8367C_DSCP11_PRIORITY_MASK 0x7000 ++#define RTL8367C_DSCP10_PRIORITY_OFFSET 8 ++#define RTL8367C_DSCP10_PRIORITY_MASK 0x700 ++#define RTL8367C_DSCP9_PRIORITY_OFFSET 4 ++#define RTL8367C_DSCP9_PRIORITY_MASK 0x70 ++#define RTL8367C_DSCP8_PRIORITY_OFFSET 0 ++#define RTL8367C_DSCP8_PRIORITY_MASK 0x7 ++ ++#define RTL8367C_REG_QOS_DSCP_TO_PRIORITY_CTRL3 0x086a ++#define RTL8367C_DSCP15_PRIORITY_OFFSET 12 ++#define RTL8367C_DSCP15_PRIORITY_MASK 0x7000 ++#define RTL8367C_DSCP14_PRIORITY_OFFSET 8 ++#define RTL8367C_DSCP14_PRIORITY_MASK 0x700 ++#define RTL8367C_DSCP13_PRIORITY_OFFSET 4 ++#define RTL8367C_DSCP13_PRIORITY_MASK 0x70 ++#define RTL8367C_DSCP12_PRIORITY_OFFSET 0 ++#define RTL8367C_DSCP12_PRIORITY_MASK 0x7 ++ ++#define RTL8367C_REG_QOS_DSCP_TO_PRIORITY_CTRL4 0x086b ++#define RTL8367C_DSCP19_PRIORITY_OFFSET 12 ++#define RTL8367C_DSCP19_PRIORITY_MASK 0x7000 ++#define RTL8367C_DSCP18_PRIORITY_OFFSET 8 ++#define RTL8367C_DSCP18_PRIORITY_MASK 0x700 ++#define RTL8367C_DSCP17_PRIORITY_OFFSET 4 ++#define RTL8367C_DSCP17_PRIORITY_MASK 0x70 ++#define RTL8367C_DSCP16_PRIORITY_OFFSET 0 ++#define RTL8367C_DSCP16_PRIORITY_MASK 0x7 ++ ++#define RTL8367C_REG_QOS_DSCP_TO_PRIORITY_CTRL5 0x086c ++#define RTL8367C_DSCP23_PRIORITY_OFFSET 12 ++#define RTL8367C_DSCP23_PRIORITY_MASK 0x7000 ++#define RTL8367C_DSCP22_PRIORITY_OFFSET 8 ++#define RTL8367C_DSCP22_PRIORITY_MASK 0x700 ++#define RTL8367C_DSCP21_PRIORITY_OFFSET 4 ++#define RTL8367C_DSCP21_PRIORITY_MASK 0x70 ++#define RTL8367C_DSCP20_PRIORITY_OFFSET 0 ++#define RTL8367C_DSCP20_PRIORITY_MASK 0x7 ++ ++#define RTL8367C_REG_QOS_DSCP_TO_PRIORITY_CTRL6 0x086d ++#define RTL8367C_DSCP27_PRIORITY_OFFSET 12 ++#define RTL8367C_DSCP27_PRIORITY_MASK 0x7000 ++#define RTL8367C_DSCP26_PRIORITY_OFFSET 8 ++#define RTL8367C_DSCP26_PRIORITY_MASK 0x700 ++#define RTL8367C_DSCP25_PRIORITY_OFFSET 4 ++#define RTL8367C_DSCP25_PRIORITY_MASK 0x70 ++#define RTL8367C_DSCP24_PRIORITY_OFFSET 0 ++#define RTL8367C_DSCP24_PRIORITY_MASK 0x7 ++ ++#define RTL8367C_REG_QOS_DSCP_TO_PRIORITY_CTRL7 0x086e ++#define RTL8367C_DSCP31_PRIORITY_OFFSET 12 ++#define RTL8367C_DSCP31_PRIORITY_MASK 0x7000 ++#define RTL8367C_DSCP30_PRIORITY_OFFSET 8 ++#define RTL8367C_DSCP30_PRIORITY_MASK 0x700 ++#define RTL8367C_DSCP29_PRIORITY_OFFSET 4 ++#define RTL8367C_DSCP29_PRIORITY_MASK 0x70 ++#define RTL8367C_DSCP28_PRIORITY_OFFSET 0 ++#define RTL8367C_DSCP28_PRIORITY_MASK 0x7 ++ ++#define RTL8367C_REG_QOS_DSCP_TO_PRIORITY_CTRL8 0x086f ++#define RTL8367C_DSCP35_PRIORITY_OFFSET 12 ++#define RTL8367C_DSCP35_PRIORITY_MASK 0x7000 ++#define RTL8367C_DSCP34_PRIORITY_OFFSET 8 ++#define RTL8367C_DSCP34_PRIORITY_MASK 0x700 ++#define RTL8367C_DSCP33_PRIORITY_OFFSET 4 ++#define RTL8367C_DSCP33_PRIORITY_MASK 0x70 ++#define RTL8367C_DSCP32_PRIORITY_OFFSET 0 ++#define RTL8367C_DSCP32_PRIORITY_MASK 0x7 ++ ++#define RTL8367C_REG_QOS_DSCP_TO_PRIORITY_CTRL9 0x0870 ++#define RTL8367C_DSCP39_PRIORITY_OFFSET 12 ++#define RTL8367C_DSCP39_PRIORITY_MASK 0x7000 ++#define RTL8367C_DSCP38_PRIORITY_OFFSET 8 ++#define RTL8367C_DSCP38_PRIORITY_MASK 0x700 ++#define RTL8367C_DSCP37_PRIORITY_OFFSET 4 ++#define RTL8367C_DSCP37_PRIORITY_MASK 0x70 ++#define RTL8367C_DSCP36_PRIORITY_OFFSET 0 ++#define RTL8367C_DSCP36_PRIORITY_MASK 0x7 ++ ++#define RTL8367C_REG_QOS_DSCP_TO_PRIORITY_CTRL10 0x0871 ++#define RTL8367C_DSCP43_PRIORITY_OFFSET 12 ++#define RTL8367C_DSCP43_PRIORITY_MASK 0x7000 ++#define RTL8367C_DSCP42_PRIORITY_OFFSET 8 ++#define RTL8367C_DSCP42_PRIORITY_MASK 0x700 ++#define RTL8367C_DSCP41_PRIORITY_OFFSET 4 ++#define RTL8367C_DSCP41_PRIORITY_MASK 0x70 ++#define RTL8367C_DSCP40_PRIORITY_OFFSET 0 ++#define RTL8367C_DSCP40_PRIORITY_MASK 0x7 ++ ++#define RTL8367C_REG_QOS_DSCP_TO_PRIORITY_CTRL11 0x0872 ++#define RTL8367C_DSCP47_PRIORITY_OFFSET 12 ++#define RTL8367C_DSCP47_PRIORITY_MASK 0x7000 ++#define RTL8367C_DSCP46_PRIORITY_OFFSET 8 ++#define RTL8367C_DSCP46_PRIORITY_MASK 0x700 ++#define RTL8367C_DSCP45_PRIORITY_OFFSET 4 ++#define RTL8367C_DSCP45_PRIORITY_MASK 0x70 ++#define RTL8367C_DSCP44_PRIORITY_OFFSET 0 ++#define RTL8367C_DSCP44_PRIORITY_MASK 0x7 ++ ++#define RTL8367C_REG_QOS_DSCP_TO_PRIORITY_CTRL12 0x0873 ++#define RTL8367C_DSCP51_PRIORITY_OFFSET 12 ++#define RTL8367C_DSCP51_PRIORITY_MASK 0x7000 ++#define RTL8367C_DSCP50_PRIORITY_OFFSET 8 ++#define RTL8367C_DSCP50_PRIORITY_MASK 0x700 ++#define RTL8367C_DSCP49_PRIORITY_OFFSET 4 ++#define RTL8367C_DSCP49_PRIORITY_MASK 0x70 ++#define RTL8367C_DSCP48_PRIORITY_OFFSET 0 ++#define RTL8367C_DSCP48_PRIORITY_MASK 0x7 ++ ++#define RTL8367C_REG_QOS_DSCP_TO_PRIORITY_CTRL13 0x0874 ++#define RTL8367C_DSCP55_PRIORITY_OFFSET 12 ++#define RTL8367C_DSCP55_PRIORITY_MASK 0x7000 ++#define RTL8367C_DSCP54_PRIORITY_OFFSET 8 ++#define RTL8367C_DSCP54_PRIORITY_MASK 0x700 ++#define RTL8367C_DSCP53_PRIORITY_OFFSET 4 ++#define RTL8367C_DSCP53_PRIORITY_MASK 0x70 ++#define RTL8367C_DSCP52_PRIORITY_OFFSET 0 ++#define RTL8367C_DSCP52_PRIORITY_MASK 0x7 ++ ++#define RTL8367C_REG_QOS_DSCP_TO_PRIORITY_CTRL14 0x0875 ++#define RTL8367C_DSCP59_PRIORITY_OFFSET 12 ++#define RTL8367C_DSCP59_PRIORITY_MASK 0x7000 ++#define RTL8367C_DSCP58_PRIORITY_OFFSET 8 ++#define RTL8367C_DSCP58_PRIORITY_MASK 0x700 ++#define RTL8367C_DSCP57_PRIORITY_OFFSET 4 ++#define RTL8367C_DSCP57_PRIORITY_MASK 0x70 ++#define RTL8367C_DSCP56_PRIORITY_OFFSET 0 ++#define RTL8367C_DSCP56_PRIORITY_MASK 0x7 ++ ++#define RTL8367C_REG_QOS_DSCP_TO_PRIORITY_CTRL15 0x0876 ++#define RTL8367C_DSCP63_PRIORITY_OFFSET 12 ++#define RTL8367C_DSCP63_PRIORITY_MASK 0x7000 ++#define RTL8367C_DSCP62_PRIORITY_OFFSET 8 ++#define RTL8367C_DSCP62_PRIORITY_MASK 0x700 ++#define RTL8367C_DSCP61_PRIORITY_OFFSET 4 ++#define RTL8367C_DSCP61_PRIORITY_MASK 0x70 ++#define RTL8367C_DSCP60_PRIORITY_OFFSET 0 ++#define RTL8367C_DSCP60_PRIORITY_MASK 0x7 ++ ++#define RTL8367C_REG_QOS_PORTBASED_PRIORITY_CTRL0 0x0877 ++#define RTL8367C_QOS_PORTBASED_PRIORITY_CTRL0_PORT3_PRIORITY_OFFSET 12 ++#define RTL8367C_QOS_PORTBASED_PRIORITY_CTRL0_PORT3_PRIORITY_MASK 0x7000 ++#define RTL8367C_QOS_PORTBASED_PRIORITY_CTRL0_PORT2_PRIORITY_OFFSET 8 ++#define RTL8367C_QOS_PORTBASED_PRIORITY_CTRL0_PORT2_PRIORITY_MASK 0x700 ++#define RTL8367C_QOS_PORTBASED_PRIORITY_CTRL0_PORT1_PRIORITY_OFFSET 4 ++#define RTL8367C_QOS_PORTBASED_PRIORITY_CTRL0_PORT1_PRIORITY_MASK 0x70 ++#define RTL8367C_QOS_PORTBASED_PRIORITY_CTRL0_PORT0_PRIORITY_OFFSET 0 ++#define RTL8367C_QOS_PORTBASED_PRIORITY_CTRL0_PORT0_PRIORITY_MASK 0x7 ++ ++#define RTL8367C_REG_QOS_PORTBASED_PRIORITY_CTRL1 0x0878 ++#define RTL8367C_QOS_PORTBASED_PRIORITY_CTRL1_PORT7_PRIORITY_OFFSET 12 ++#define RTL8367C_QOS_PORTBASED_PRIORITY_CTRL1_PORT7_PRIORITY_MASK 0x7000 ++#define RTL8367C_QOS_PORTBASED_PRIORITY_CTRL1_PORT6_PRIORITY_OFFSET 8 ++#define RTL8367C_QOS_PORTBASED_PRIORITY_CTRL1_PORT6_PRIORITY_MASK 0x700 ++#define RTL8367C_QOS_PORTBASED_PRIORITY_CTRL1_PORT5_PRIORITY_OFFSET 4 ++#define RTL8367C_QOS_PORTBASED_PRIORITY_CTRL1_PORT5_PRIORITY_MASK 0x70 ++#define RTL8367C_QOS_PORTBASED_PRIORITY_CTRL1_PORT4_PRIORITY_OFFSET 0 ++#define RTL8367C_QOS_PORTBASED_PRIORITY_CTRL1_PORT4_PRIORITY_MASK 0x7 ++ ++#define RTL8367C_REG_DUMMY0879 0x0879 ++#define RTL8367C_DUMMY0879_OFFSET 0 ++#define RTL8367C_DUMMY0879_MASK 0x1 ++ ++#define RTL8367C_REG_QOS_PORTBASED_PRIORITY_CTRL2 0x087a ++#define RTL8367C_QOS_PORTBASED_PRIORITY_CTRL2_PORT10_PRIORITY_OFFSET 8 ++#define RTL8367C_QOS_PORTBASED_PRIORITY_CTRL2_PORT10_PRIORITY_MASK 0x700 ++#define RTL8367C_QOS_PORTBASED_PRIORITY_CTRL2_PORT9_PRIORITY_OFFSET 4 ++#define RTL8367C_QOS_PORTBASED_PRIORITY_CTRL2_PORT9_PRIORITY_MASK 0x70 ++#define RTL8367C_QOS_PORTBASED_PRIORITY_CTRL2_PORT8_PRIORITY_OFFSET 0 ++#define RTL8367C_QOS_PORTBASED_PRIORITY_CTRL2_PORT8_PRIORITY_MASK 0x7 ++ ++#define RTL8367C_REG_QOS_INTERNAL_PRIORITY_DECISION_CTRL0 0x087b ++#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_CTRL0_QOS_ACL_WEIGHT_OFFSET 8 ++#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_CTRL0_QOS_ACL_WEIGHT_MASK 0xFF00 ++#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_CTRL0_QOS_PORT_WEIGHT_OFFSET 0 ++#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_CTRL0_QOS_PORT_WEIGHT_MASK 0xFF ++ ++#define RTL8367C_REG_QOS_INTERNAL_PRIORITY_DECISION_CTRL1 0x087c ++#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_CTRL1_QOS_DOT1Q_WEIGHT_OFFSET 8 ++#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_CTRL1_QOS_DOT1Q_WEIGHT_MASK 0xFF00 ++#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_CTRL1_QOS_DSCP_WEIGHT_OFFSET 0 ++#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_CTRL1_QOS_DSCP_WEIGHT_MASK 0xFF ++ ++#define RTL8367C_REG_QOS_INTERNAL_PRIORITY_DECISION_CTRL2 0x087d ++#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_CTRL2_QOS_CVLAN_WEIGHT_OFFSET 8 ++#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_CTRL2_QOS_CVLAN_WEIGHT_MASK 0xFF00 ++#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_CTRL2_QOS_SVLAN_WEIGHT_OFFSET 0 ++#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_CTRL2_QOS_SVLAN_WEIGHT_MASK 0xFF ++ ++#define RTL8367C_REG_QOS_INTERNAL_PRIORITY_DECISION_CTRL3 0x087e ++#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_CTRL3_QOS_SA_WEIGHT_OFFSET 8 ++#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_CTRL3_QOS_SA_WEIGHT_MASK 0xFF00 ++#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_CTRL3_QOS_LUTFWD_WEIGHT_OFFSET 0 ++#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_CTRL3_QOS_LUTFWD_WEIGHT_MASK 0xFF ++ ++#define RTL8367C_REG_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL0 0x087f ++#define RTL8367C_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL0_PRIORITY3_OFFSET 12 ++#define RTL8367C_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL0_PRIORITY3_MASK 0x7000 ++#define RTL8367C_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL0_PRIORITY2_OFFSET 8 ++#define RTL8367C_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL0_PRIORITY2_MASK 0x700 ++#define RTL8367C_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL0_PRIORITY1_OFFSET 4 ++#define RTL8367C_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL0_PRIORITY1_MASK 0x70 ++#define RTL8367C_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL0_PRIORITY0_OFFSET 0 ++#define RTL8367C_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL0_PRIORITY0_MASK 0x7 ++ ++#define RTL8367C_REG_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL1 0x0880 ++#define RTL8367C_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL1_PRIORITY7_OFFSET 12 ++#define RTL8367C_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL1_PRIORITY7_MASK 0x7000 ++#define RTL8367C_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL1_PRIORITY6_OFFSET 8 ++#define RTL8367C_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL1_PRIORITY6_MASK 0x700 ++#define RTL8367C_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL1_PRIORITY5_OFFSET 4 ++#define RTL8367C_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL1_PRIORITY5_MASK 0x70 ++#define RTL8367C_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL1_PRIORITY4_OFFSET 0 ++#define RTL8367C_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL1_PRIORITY4_MASK 0x7 ++ ++#define RTL8367C_REG_QOS_TRAP_PRIORITY0 0x0881 ++#define RTL8367C_UNKNOWN_MC_PRIORTY_OFFSET 12 ++#define RTL8367C_UNKNOWN_MC_PRIORTY_MASK 0x7000 ++#define RTL8367C_SVLAN_PRIOIRTY_OFFSET 8 ++#define RTL8367C_SVLAN_PRIOIRTY_MASK 0x700 ++#define RTL8367C_OAM_PRIOIRTY_OFFSET 4 ++#define RTL8367C_OAM_PRIOIRTY_MASK 0x70 ++#define RTL8367C_DOT1X_PRIORTY_OFFSET 0 ++#define RTL8367C_DOT1X_PRIORTY_MASK 0x7 ++ ++#define RTL8367C_REG_QOS_TRAP_PRIORITY1 0x0882 ++#define RTL8367C_DW8051_TRAP_PRI_OFFSET 4 ++#define RTL8367C_DW8051_TRAP_PRI_MASK 0x70 ++#define RTL8367C_EEELLDP_TRAP_PRI_OFFSET 0 ++#define RTL8367C_EEELLDP_TRAP_PRI_MASK 0x7 ++ ++#define RTL8367C_REG_MAX_LENGTH_CFG 0x0883 ++#define RTL8367C_MAX_LENGTH_GIGA_OFFSET 8 ++#define RTL8367C_MAX_LENGTH_GIGA_MASK 0xFF00 ++#define RTL8367C_MAX_LENGTH_10_100M_OFFSET 0 ++#define RTL8367C_MAX_LENGTH_10_100M_MASK 0xFF ++ ++#define RTL8367C_REG_MAX_LEN_RX_TX 0x0884 ++#define RTL8367C_MAX_LEN_RX_TX_OFFSET 0 ++#define RTL8367C_MAX_LEN_RX_TX_MASK 0x3 ++ ++#define RTL8367C_REG_QOS_INTERNAL_PRIORITY_DECISION2_CTRL0 0x0885 ++#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_CTRL0_QOS_ACL_WEIGHT_OFFSET 8 ++#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_CTRL0_QOS_ACL_WEIGHT_MASK 0xFF00 ++#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_CTRL0_QOS_PORT_WEIGHT_OFFSET 0 ++#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_CTRL0_QOS_PORT_WEIGHT_MASK 0xFF ++ ++#define RTL8367C_REG_QOS_INTERNAL_PRIORITY_DECISION2_CTRL1 0x0886 ++#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_CTRL1_QOS_DOT1Q_WEIGHT_OFFSET 8 ++#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_CTRL1_QOS_DOT1Q_WEIGHT_MASK 0xFF00 ++#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_CTRL1_QOS_DSCP_WEIGHT_OFFSET 0 ++#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_CTRL1_QOS_DSCP_WEIGHT_MASK 0xFF ++ ++#define RTL8367C_REG_QOS_INTERNAL_PRIORITY_DECISION2_CTRL2 0x0887 ++#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_CTRL2_QOS_CVLAN_WEIGHT_OFFSET 8 ++#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_CTRL2_QOS_CVLAN_WEIGHT_MASK 0xFF00 ++#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_CTRL2_QOS_SVLAN_WEIGHT_OFFSET 0 ++#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_CTRL2_QOS_SVLAN_WEIGHT_MASK 0xFF ++ ++#define RTL8367C_REG_QOS_INTERNAL_PRIORITY_DECISION2_CTRL3 0x0888 ++#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_CTRL3_QOS_SA_WEIGHT_OFFSET 8 ++#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_CTRL3_QOS_SA_WEIGHT_MASK 0xFF00 ++#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_CTRL3_QOS_LUTFWD_WEIGHT_OFFSET 0 ++#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_CTRL3_QOS_LUTFWD_WEIGHT_MASK 0xFF ++ ++#define RTL8367C_REG_QOS_INTERNAL_PRIORITY_DECISION_IDX 0x0889 ++#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_IDX_OFFSET 0 ++#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_IDX_MASK 0x7FF ++ ++#define RTL8367C_REG_MAX_LENGTH_CFG_EXT 0x088a ++#define RTL8367C_MAX_LENGTH_GIGA_EXT_OFFSET 3 ++#define RTL8367C_MAX_LENGTH_GIGA_EXT_MASK 0x38 ++#define RTL8367C_MAX_LENGTH_10_100M_EXT_OFFSET 0 ++#define RTL8367C_MAX_LENGTH_10_100M_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_MAX_LEN_RX_TX_CFG0 0x088c ++#define RTL8367C_MAX_LEN_RX_TX_CFG0_OFFSET 0 ++#define RTL8367C_MAX_LEN_RX_TX_CFG0_MASK 0x3FFF ++ ++#define RTL8367C_REG_MAX_LEN_RX_TX_CFG1 0x088d ++#define RTL8367C_MAX_LEN_RX_TX_CFG1_OFFSET 0 ++#define RTL8367C_MAX_LEN_RX_TX_CFG1_MASK 0x3FFF ++ ++#define RTL8367C_REG_UNDA_FLOODING_PMSK 0x0890 ++#define RTL8367C_UNDA_FLOODING_PMSK_OFFSET 0 ++#define RTL8367C_UNDA_FLOODING_PMSK_MASK 0x7FF ++ ++#define RTL8367C_REG_UNMCAST_FLOADING_PMSK 0x0891 ++#define RTL8367C_UNMCAST_FLOADING_PMSK_OFFSET 0 ++#define RTL8367C_UNMCAST_FLOADING_PMSK_MASK 0x7FF ++ ++#define RTL8367C_REG_BCAST_FLOADING_PMSK 0x0892 ++#define RTL8367C_BCAST_FLOADING_PMSK_OFFSET 0 ++#define RTL8367C_BCAST_FLOADING_PMSK_MASK 0x7FF ++ ++#define RTL8367C_REG_PORT_TRUNK_HASH_MAPPING_CTRL2 0x08a0 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL2_HASH7_OFFSET 14 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL2_HASH7_MASK 0xC000 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL2_HASH6_OFFSET 12 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL2_HASH6_MASK 0x3000 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL2_HASH5_OFFSET 10 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL2_HASH5_MASK 0xC00 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL2_HASH4_OFFSET 8 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL2_HASH4_MASK 0x300 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL2_HASH3_OFFSET 6 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL2_HASH3_MASK 0xC0 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL2_HASH2_OFFSET 4 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL2_HASH2_MASK 0x30 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL2_HASH1_OFFSET 2 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL2_HASH1_MASK 0xC ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL2_HASH0_OFFSET 0 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL2_HASH0_MASK 0x3 ++ ++#define RTL8367C_REG_PORT_TRUNK_HASH_MAPPING_CTRL3 0x08a1 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL3_HASH15_OFFSET 14 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL3_HASH15_MASK 0xC000 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL3_HASH14_OFFSET 12 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL3_HASH14_MASK 0x3000 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL3_HASH13_OFFSET 10 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL3_HASH13_MASK 0xC00 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL3_HASH12_OFFSET 8 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL3_HASH12_MASK 0x300 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL3_HASH11_OFFSET 6 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL3_HASH11_MASK 0xC0 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL3_HASH10_OFFSET 4 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL3_HASH10_MASK 0x30 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL3_HASH9_OFFSET 2 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL3_HASH9_MASK 0xC ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL3_HASH8_OFFSET 0 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL3_HASH8_MASK 0x3 ++ ++#define RTL8367C_REG_PORT_ISOLATION_PORT0_MASK 0x08a2 ++#define RTL8367C_PORT_ISOLATION_PORT0_MASK_OFFSET 0 ++#define RTL8367C_PORT_ISOLATION_PORT0_MASK_MASK 0x7FF ++ ++#define RTL8367C_REG_PORT_ISOLATION_PORT1_MASK 0x08a3 ++#define RTL8367C_PORT_ISOLATION_PORT1_MASK_OFFSET 0 ++#define RTL8367C_PORT_ISOLATION_PORT1_MASK_MASK 0x7FF ++ ++#define RTL8367C_REG_PORT_ISOLATION_PORT2_MASK 0x08a4 ++#define RTL8367C_PORT_ISOLATION_PORT2_MASK_OFFSET 0 ++#define RTL8367C_PORT_ISOLATION_PORT2_MASK_MASK 0x7FF ++ ++#define RTL8367C_REG_PORT_ISOLATION_PORT3_MASK 0x08a5 ++#define RTL8367C_PORT_ISOLATION_PORT3_MASK_OFFSET 0 ++#define RTL8367C_PORT_ISOLATION_PORT3_MASK_MASK 0x7FF ++ ++#define RTL8367C_REG_PORT_ISOLATION_PORT4_MASK 0x08a6 ++#define RTL8367C_PORT_ISOLATION_PORT4_MASK_OFFSET 0 ++#define RTL8367C_PORT_ISOLATION_PORT4_MASK_MASK 0x7FF ++ ++#define RTL8367C_REG_PORT_ISOLATION_PORT5_MASK 0x08a7 ++#define RTL8367C_PORT_ISOLATION_PORT5_MASK_OFFSET 0 ++#define RTL8367C_PORT_ISOLATION_PORT5_MASK_MASK 0x7FF ++ ++#define RTL8367C_REG_PORT_ISOLATION_PORT6_MASK 0x08a8 ++#define RTL8367C_PORT_ISOLATION_PORT6_MASK_OFFSET 0 ++#define RTL8367C_PORT_ISOLATION_PORT6_MASK_MASK 0x7FF ++ ++#define RTL8367C_REG_PORT_ISOLATION_PORT7_MASK 0x08a9 ++#define RTL8367C_PORT_ISOLATION_PORT7_MASK_OFFSET 0 ++#define RTL8367C_PORT_ISOLATION_PORT7_MASK_MASK 0x7FF ++ ++#define RTL8367C_REG_PORT_ISOLATION_PORT8_MASK 0x08aa ++#define RTL8367C_PORT_ISOLATION_PORT8_MASK_OFFSET 0 ++#define RTL8367C_PORT_ISOLATION_PORT8_MASK_MASK 0x7FF ++ ++#define RTL8367C_REG_PORT_ISOLATION_PORT9_MASK 0x08ab ++#define RTL8367C_PORT_ISOLATION_PORT9_MASK_OFFSET 0 ++#define RTL8367C_PORT_ISOLATION_PORT9_MASK_MASK 0x7FF ++ ++#define RTL8367C_REG_PORT_ISOLATION_PORT10_MASK 0x08ac ++#define RTL8367C_PORT_ISOLATION_PORT10_MASK_OFFSET 0 ++#define RTL8367C_PORT_ISOLATION_PORT10_MASK_MASK 0x7FF ++ ++#define RTL8367C_REG_FORCE_CTRL 0x08b4 ++#define RTL8367C_FORCE_CTRL_OFFSET 0 ++#define RTL8367C_FORCE_CTRL_MASK 0x7FF ++ ++#define RTL8367C_REG_FORCE_PORT0_MASK 0x08b5 ++#define RTL8367C_FORCE_PORT0_MASK_OFFSET 0 ++#define RTL8367C_FORCE_PORT0_MASK_MASK 0x7FF ++ ++#define RTL8367C_REG_FORCE_PORT1_MASK 0x08b6 ++#define RTL8367C_FORCE_PORT1_MASK_OFFSET 0 ++#define RTL8367C_FORCE_PORT1_MASK_MASK 0x7FF ++ ++#define RTL8367C_REG_FORCE_PORT2_MASK 0x08b7 ++#define RTL8367C_FORCE_PORT2_MASK_OFFSET 0 ++#define RTL8367C_FORCE_PORT2_MASK_MASK 0x7FF ++ ++#define RTL8367C_REG_FORCE_PORT3_MASK 0x08b8 ++#define RTL8367C_FORCE_PORT3_MASK_OFFSET 0 ++#define RTL8367C_FORCE_PORT3_MASK_MASK 0x7FF ++ ++#define RTL8367C_REG_FORCE_PORT4_MASK 0x08b9 ++#define RTL8367C_FORCE_PORT4_MASK_OFFSET 0 ++#define RTL8367C_FORCE_PORT4_MASK_MASK 0x7FF ++ ++#define RTL8367C_REG_FORCE_PORT5_MASK 0x08ba ++#define RTL8367C_FORCE_PORT5_MASK_OFFSET 0 ++#define RTL8367C_FORCE_PORT5_MASK_MASK 0x7FF ++ ++#define RTL8367C_REG_FORCE_PORT6_MASK 0x08bb ++#define RTL8367C_FORCE_PORT6_MASK_OFFSET 0 ++#define RTL8367C_FORCE_PORT6_MASK_MASK 0x7FF ++ ++#define RTL8367C_REG_FORCE_PORT7_MASK 0x08bc ++#define RTL8367C_FORCE_PORT7_MASK_OFFSET 0 ++#define RTL8367C_FORCE_PORT7_MASK_MASK 0x7FF ++ ++#define RTL8367C_REG_FORCE_PORT8_MASK 0x08bd ++#define RTL8367C_FORCE_PORT8_MASK_OFFSET 0 ++#define RTL8367C_FORCE_PORT8_MASK_MASK 0x7FF ++ ++#define RTL8367C_REG_FORCE_PORT9_MASK 0x08be ++#define RTL8367C_FORCE_PORT9_MASK_OFFSET 0 ++#define RTL8367C_FORCE_PORT9_MASK_MASK 0x7FF ++ ++#define RTL8367C_REG_FORCE_PORT10_MASK 0x08bf ++#define RTL8367C_FORCE_PORT10_MASK_OFFSET 0 ++#define RTL8367C_FORCE_PORT10_MASK_MASK 0x7FF ++ ++#define RTL8367C_REG_SOURCE_PORT_PERMIT 0x08c5 ++#define RTL8367C_SOURCE_PORT_PERMIT_OFFSET 0 ++#define RTL8367C_SOURCE_PORT_PERMIT_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMCAST_VLAN_LEAKY 0x08c6 ++#define RTL8367C_IPMCAST_VLAN_LEAKY_OFFSET 0 ++#define RTL8367C_IPMCAST_VLAN_LEAKY_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMCAST_PORTISO_LEAKY 0x08c7 ++#define RTL8367C_IPMCAST_PORTISO_LEAKY_OFFSET 0 ++#define RTL8367C_IPMCAST_PORTISO_LEAKY_MASK 0x7FF ++ ++#define RTL8367C_REG_PORT_SECURITY_CTRL 0x08c8 ++#define RTL8367C_UNKNOWN_UNICAST_DA_BEHAVE_OFFSET 6 ++#define RTL8367C_UNKNOWN_UNICAST_DA_BEHAVE_MASK 0xC0 ++#define RTL8367C_LUT_LEARN_OVER_ACT_OFFSET 4 ++#define RTL8367C_LUT_LEARN_OVER_ACT_MASK 0x30 ++#define RTL8367C_UNMATCHED_SA_BEHAVE_OFFSET 2 ++#define RTL8367C_UNMATCHED_SA_BEHAVE_MASK 0xC ++#define RTL8367C_UNKNOWN_SA_BEHAVE_OFFSET 0 ++#define RTL8367C_UNKNOWN_SA_BEHAVE_MASK 0x3 ++ ++#define RTL8367C_REG_UNKNOWN_IPV4_MULTICAST_CTRL0 0x08c9 ++#define RTL8367C_PORT7_UNKNOWN_IP4_MCAST_OFFSET 14 ++#define RTL8367C_PORT7_UNKNOWN_IP4_MCAST_MASK 0xC000 ++#define RTL8367C_PORT6_UNKNOWN_IP4_MCAST_OFFSET 12 ++#define RTL8367C_PORT6_UNKNOWN_IP4_MCAST_MASK 0x3000 ++#define RTL8367C_PORT5_UNKNOWN_IP4_MCAST_OFFSET 10 ++#define RTL8367C_PORT5_UNKNOWN_IP4_MCAST_MASK 0xC00 ++#define RTL8367C_PORT4_UNKNOWN_IP4_MCAST_OFFSET 8 ++#define RTL8367C_PORT4_UNKNOWN_IP4_MCAST_MASK 0x300 ++#define RTL8367C_PORT3_UNKNOWN_IP4_MCAST_OFFSET 6 ++#define RTL8367C_PORT3_UNKNOWN_IP4_MCAST_MASK 0xC0 ++#define RTL8367C_PORT2_UNKNOWN_IP4_MCAST_OFFSET 4 ++#define RTL8367C_PORT2_UNKNOWN_IP4_MCAST_MASK 0x30 ++#define RTL8367C_PORT1_UNKNOWN_IP4_MCAST_OFFSET 2 ++#define RTL8367C_PORT1_UNKNOWN_IP4_MCAST_MASK 0xC ++#define RTL8367C_PORT0_UNKNOWN_IP4_MCAST_OFFSET 0 ++#define RTL8367C_PORT0_UNKNOWN_IP4_MCAST_MASK 0x3 ++ ++#define RTL8367C_REG_UNKNOWN_IPV4_MULTICAST_CTRL1 0x08ca ++#define RTL8367C_PORT10_UNKNOWN_IP4_MCAST_OFFSET 4 ++#define RTL8367C_PORT10_UNKNOWN_IP4_MCAST_MASK 0x30 ++#define RTL8367C_PORT9_UNKNOWN_IP4_MCAST_OFFSET 2 ++#define RTL8367C_PORT9_UNKNOWN_IP4_MCAST_MASK 0xC ++#define RTL8367C_PORT8_UNKNOWN_IP4_MCAST_OFFSET 0 ++#define RTL8367C_PORT8_UNKNOWN_IP4_MCAST_MASK 0x3 ++ ++#define RTL8367C_REG_UNKNOWN_IPV6_MULTICAST_CTRL0 0x08cb ++#define RTL8367C_PORT7_UNKNOWN_IP6_MCAST_OFFSET 14 ++#define RTL8367C_PORT7_UNKNOWN_IP6_MCAST_MASK 0xC000 ++#define RTL8367C_PORT6_UNKNOWN_IP6_MCAST_OFFSET 12 ++#define RTL8367C_PORT6_UNKNOWN_IP6_MCAST_MASK 0x3000 ++#define RTL8367C_PORT5_UNKNOWN_IP6_MCAST_OFFSET 10 ++#define RTL8367C_PORT5_UNKNOWN_IP6_MCAST_MASK 0xC00 ++#define RTL8367C_PORT4_UNKNOWN_IP6_MCAST_OFFSET 8 ++#define RTL8367C_PORT4_UNKNOWN_IP6_MCAST_MASK 0x300 ++#define RTL8367C_PORT3_UNKNOWN_IP6_MCAST_OFFSET 6 ++#define RTL8367C_PORT3_UNKNOWN_IP6_MCAST_MASK 0xC0 ++#define RTL8367C_PORT2_UNKNOWN_IP6_MCAST_OFFSET 4 ++#define RTL8367C_PORT2_UNKNOWN_IP6_MCAST_MASK 0x30 ++#define RTL8367C_PORT1_UNKNOWN_IP6_MCAST_OFFSET 2 ++#define RTL8367C_PORT1_UNKNOWN_IP6_MCAST_MASK 0xC ++#define RTL8367C_PORT0_UNKNOWN_IP6_MCAST_OFFSET 0 ++#define RTL8367C_PORT0_UNKNOWN_IP6_MCAST_MASK 0x3 ++ ++#define RTL8367C_REG_UNKNOWN_IPV6_MULTICAST_CTRL1 0x08cc ++#define RTL8367C_PORT10_UNKNOWN_IP6_MCAST_OFFSET 4 ++#define RTL8367C_PORT10_UNKNOWN_IP6_MCAST_MASK 0x30 ++#define RTL8367C_PORT9_UNKNOWN_IP6_MCAST_OFFSET 2 ++#define RTL8367C_PORT9_UNKNOWN_IP6_MCAST_MASK 0xC ++#define RTL8367C_PORT8_UNKNOWN_IP6_MCAST_OFFSET 0 ++#define RTL8367C_PORT8_UNKNOWN_IP6_MCAST_MASK 0x3 ++ ++#define RTL8367C_REG_UNKNOWN_L2_MULTICAST_CTRL0 0x08cd ++#define RTL8367C_PORT7_UNKNOWN_L2_MCAST_OFFSET 14 ++#define RTL8367C_PORT7_UNKNOWN_L2_MCAST_MASK 0xC000 ++#define RTL8367C_PORT6_UNKNOWN_L2_MCAST_OFFSET 12 ++#define RTL8367C_PORT6_UNKNOWN_L2_MCAST_MASK 0x3000 ++#define RTL8367C_PORT5_UNKNOWN_L2_MCAST_OFFSET 10 ++#define RTL8367C_PORT5_UNKNOWN_L2_MCAST_MASK 0xC00 ++#define RTL8367C_PORT4_UNKNOWN_L2_MCAST_OFFSET 8 ++#define RTL8367C_PORT4_UNKNOWN_L2_MCAST_MASK 0x300 ++#define RTL8367C_PORT3_UNKNOWN_L2_MCAST_OFFSET 6 ++#define RTL8367C_PORT3_UNKNOWN_L2_MCAST_MASK 0xC0 ++#define RTL8367C_PORT2_UNKNOWN_L2_MCAST_OFFSET 4 ++#define RTL8367C_PORT2_UNKNOWN_L2_MCAST_MASK 0x30 ++#define RTL8367C_PORT1_UNKNOWN_L2_MCAST_OFFSET 2 ++#define RTL8367C_PORT1_UNKNOWN_L2_MCAST_MASK 0xC ++#define RTL8367C_PORT0_UNKNOWN_L2_MCAST_OFFSET 0 ++#define RTL8367C_PORT0_UNKNOWN_L2_MCAST_MASK 0x3 ++ ++#define RTL8367C_REG_PORT_TRUNK_DROP_CTRL 0x08ce ++#define RTL8367C_PORT_TRUNK_DROP_CTRL_OFFSET 0 ++#define RTL8367C_PORT_TRUNK_DROP_CTRL_MASK 0x1 ++ ++#define RTL8367C_REG_PORT_TRUNK_CTRL 0x08cf ++#define RTL8367C_PORT_TRUNK_DUMB_OFFSET 8 ++#define RTL8367C_PORT_TRUNK_DUMB_MASK 0x100 ++#define RTL8367C_PORT_TRUNK_FLOOD_OFFSET 7 ++#define RTL8367C_PORT_TRUNK_FLOOD_MASK 0x80 ++#define RTL8367C_DPORT_HASH_OFFSET 6 ++#define RTL8367C_DPORT_HASH_MASK 0x40 ++#define RTL8367C_SPORT_HASH_OFFSET 5 ++#define RTL8367C_SPORT_HASH_MASK 0x20 ++#define RTL8367C_DIP_HASH_OFFSET 4 ++#define RTL8367C_DIP_HASH_MASK 0x10 ++#define RTL8367C_SIP_HASH_OFFSET 3 ++#define RTL8367C_SIP_HASH_MASK 0x8 ++#define RTL8367C_DMAC_HASH_OFFSET 2 ++#define RTL8367C_DMAC_HASH_MASK 0x4 ++#define RTL8367C_SMAC_HASH_OFFSET 1 ++#define RTL8367C_SMAC_HASH_MASK 0x2 ++#define RTL8367C_SPA_HASH_OFFSET 0 ++#define RTL8367C_SPA_HASH_MASK 0x1 ++ ++#define RTL8367C_REG_PORT_TRUNK_GROUP_MASK 0x08d0 ++#define RTL8367C_PORT_TRUNK_GROUP2_MASK_OFFSET 8 ++#define RTL8367C_PORT_TRUNK_GROUP2_MASK_MASK 0x300 ++#define RTL8367C_PORT_TRUNK_GROUP1_MASK_OFFSET 4 ++#define RTL8367C_PORT_TRUNK_GROUP1_MASK_MASK 0xF0 ++#define RTL8367C_PORT_TRUNK_GROUP0_MASK_OFFSET 0 ++#define RTL8367C_PORT_TRUNK_GROUP0_MASK_MASK 0xF ++ ++#define RTL8367C_REG_PORT_TRUNK_FLOWCTRL 0x08d1 ++#define RTL8367C_EN_FLOWCTRL_TG2_OFFSET 2 ++#define RTL8367C_EN_FLOWCTRL_TG2_MASK 0x4 ++#define RTL8367C_EN_FLOWCTRL_TG1_OFFSET 1 ++#define RTL8367C_EN_FLOWCTRL_TG1_MASK 0x2 ++#define RTL8367C_EN_FLOWCTRL_TG0_OFFSET 0 ++#define RTL8367C_EN_FLOWCTRL_TG0_MASK 0x1 ++ ++#define RTL8367C_REG_PORT_TRUNK_HASH_MAPPING_CTRL0 0x08d2 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL0_HASH7_OFFSET 14 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL0_HASH7_MASK 0xC000 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL0_HASH6_OFFSET 12 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL0_HASH6_MASK 0x3000 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL0_HASH5_OFFSET 10 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL0_HASH5_MASK 0xC00 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL0_HASH4_OFFSET 8 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL0_HASH4_MASK 0x300 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL0_HASH3_OFFSET 6 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL0_HASH3_MASK 0xC0 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL0_HASH2_OFFSET 4 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL0_HASH2_MASK 0x30 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL0_HASH1_OFFSET 2 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL0_HASH1_MASK 0xC ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL0_HASH0_OFFSET 0 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL0_HASH0_MASK 0x3 ++ ++#define RTL8367C_REG_PORT_TRUNK_HASH_MAPPING_CTRL1 0x08d3 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL1_HASH15_OFFSET 14 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL1_HASH15_MASK 0xC000 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL1_HASH14_OFFSET 12 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL1_HASH14_MASK 0x3000 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL1_HASH13_OFFSET 10 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL1_HASH13_MASK 0xC00 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL1_HASH12_OFFSET 8 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL1_HASH12_MASK 0x300 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL1_HASH11_OFFSET 6 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL1_HASH11_MASK 0xC0 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL1_HASH10_OFFSET 4 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL1_HASH10_MASK 0x30 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL1_HASH9_OFFSET 2 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL1_HASH9_MASK 0xC ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL1_HASH8_OFFSET 0 ++#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL1_HASH8_MASK 0x3 ++ ++#define RTL8367C_REG_DOS_CFG 0x08d4 ++#define RTL8367C_DROP_ICMPFRAGMENT_OFFSET 9 ++#define RTL8367C_DROP_ICMPFRAGMENT_MASK 0x200 ++#define RTL8367C_DROP_TCPFRAGERROR_OFFSET 8 ++#define RTL8367C_DROP_TCPFRAGERROR_MASK 0x100 ++#define RTL8367C_DROP_TCPSHORTHDR_OFFSET 7 ++#define RTL8367C_DROP_TCPSHORTHDR_MASK 0x80 ++#define RTL8367C_DROP_SYN1024_OFFSET 6 ++#define RTL8367C_DROP_SYN1024_MASK 0x40 ++#define RTL8367C_DROP_NULLSCAN_OFFSET 5 ++#define RTL8367C_DROP_NULLSCAN_MASK 0x20 ++#define RTL8367C_DROP_XMASCAN_OFFSET 4 ++#define RTL8367C_DROP_XMASCAN_MASK 0x10 ++#define RTL8367C_DROP_SYNFINSCAN_OFFSET 3 ++#define RTL8367C_DROP_SYNFINSCAN_MASK 0x8 ++#define RTL8367C_DROP_BLATATTACKS_OFFSET 2 ++#define RTL8367C_DROP_BLATATTACKS_MASK 0x4 ++#define RTL8367C_DROP_LANDATTACKS_OFFSET 1 ++#define RTL8367C_DROP_LANDATTACKS_MASK 0x2 ++#define RTL8367C_DROP_DAEQSA_OFFSET 0 ++#define RTL8367C_DROP_DAEQSA_MASK 0x1 ++ ++#define RTL8367C_REG_UNKNOWN_L2_MULTICAST_CTRL1 0x08d5 ++#define RTL8367C_PORT10_UNKNOWN_L2_MCAST_OFFSET 4 ++#define RTL8367C_PORT10_UNKNOWN_L2_MCAST_MASK 0x30 ++#define RTL8367C_PORT9_UNKNOWN_L2_MCAST_OFFSET 2 ++#define RTL8367C_PORT9_UNKNOWN_L2_MCAST_MASK 0xC ++#define RTL8367C_PORT8_UNKNOWN_L2_MCAST_OFFSET 0 ++#define RTL8367C_PORT8_UNKNOWN_L2_MCAST_MASK 0x3 ++ ++#define RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL4 0x08d6 ++#define RTL8367C_PORT9_VLAN_KEEP_MASK_OFFSET 8 ++#define RTL8367C_PORT9_VLAN_KEEP_MASK_MASK 0xFF00 ++#define RTL8367C_PORT8_VLAN_KEEP_MASK_OFFSET 0 ++#define RTL8367C_PORT8_VLAN_KEEP_MASK_MASK 0xFF ++ ++#define RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL5 0x08d7 ++#define RTL8367C_VLAN_EGRESS_KEEP_CTRL5_OFFSET 0 ++#define RTL8367C_VLAN_EGRESS_KEEP_CTRL5_MASK 0xFF ++ ++#define RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL0_EXT 0x08d8 ++#define RTL8367C_PORT1_VLAN_KEEP_MASK_EXT_OFFSET 3 ++#define RTL8367C_PORT1_VLAN_KEEP_MASK_EXT_MASK 0x38 ++#define RTL8367C_PORT0_VLAN_KEEP_MASK_EXT_OFFSET 0 ++#define RTL8367C_PORT0_VLAN_KEEP_MASK_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL1_EXT 0x08d9 ++#define RTL8367C_PORT3_VLAN_KEEP_MASK_EXT_OFFSET 3 ++#define RTL8367C_PORT3_VLAN_KEEP_MASK_EXT_MASK 0x38 ++#define RTL8367C_PORT2_VLAN_KEEP_MASK_EXT_OFFSET 0 ++#define RTL8367C_PORT2_VLAN_KEEP_MASK_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL2_EXT 0x08da ++#define RTL8367C_PORT5_VLAN_KEEP_MASK_EXT_OFFSET 3 ++#define RTL8367C_PORT5_VLAN_KEEP_MASK_EXT_MASK 0x38 ++#define RTL8367C_PORT4_VLAN_KEEP_MASK_EXT_OFFSET 0 ++#define RTL8367C_PORT4_VLAN_KEEP_MASK_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL3_EXT 0x08db ++#define RTL8367C_PORT7_VLAN_KEEP_MASK_EXT_OFFSET 3 ++#define RTL8367C_PORT7_VLAN_KEEP_MASK_EXT_MASK 0x38 ++#define RTL8367C_PORT6_VLAN_KEEP_MASK_EXT_OFFSET 0 ++#define RTL8367C_PORT6_VLAN_KEEP_MASK_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL4_EXT 0x08dc ++#define RTL8367C_PORT9_VLAN_KEEP_MASK_EXT_OFFSET 3 ++#define RTL8367C_PORT9_VLAN_KEEP_MASK_EXT_MASK 0x38 ++#define RTL8367C_PORT8_VLAN_KEEP_MASK_EXT_OFFSET 0 ++#define RTL8367C_PORT8_VLAN_KEEP_MASK_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL5_EXT 0x08dd ++#define RTL8367C_VLAN_EGRESS_KEEP_CTRL5_EXT_OFFSET 0 ++#define RTL8367C_VLAN_EGRESS_KEEP_CTRL5_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_VLAN_EGRESS_TRANS_CTRL10 0x08de ++#define RTL8367C_VLAN_EGRESS_TRANS_CTRL10_OFFSET 0 ++#define RTL8367C_VLAN_EGRESS_TRANS_CTRL10_MASK 0x7FF ++ ++#define RTL8367C_REG_FPGA_VER_CEN 0x08e0 ++ ++#define RTL8367C_REG_FPGA_TIME_CEN 0x08e1 ++ ++#define RTL8367C_REG_FPGA_DATE_CEN 0x08e2 ++ ++#define RTL8367C_REG_QOS_PORT_QUEUE_NUMBER_CTRL0 0x0900 ++#define RTL8367C_PORT3_NUMBER_OFFSET 12 ++#define RTL8367C_PORT3_NUMBER_MASK 0x7000 ++#define RTL8367C_PORT2_NUMBER_OFFSET 8 ++#define RTL8367C_PORT2_NUMBER_MASK 0x700 ++#define RTL8367C_PORT1_NUMBER_OFFSET 4 ++#define RTL8367C_PORT1_NUMBER_MASK 0x70 ++#define RTL8367C_PORT0_NUMBER_OFFSET 0 ++#define RTL8367C_PORT0_NUMBER_MASK 0x7 ++ ++#define RTL8367C_REG_QOS_PORT_QUEUE_NUMBER_CTRL1 0x0901 ++#define RTL8367C_PORT7_NUMBER_OFFSET 12 ++#define RTL8367C_PORT7_NUMBER_MASK 0x7000 ++#define RTL8367C_PORT6_NUMBER_OFFSET 8 ++#define RTL8367C_PORT6_NUMBER_MASK 0x700 ++#define RTL8367C_PORT5_NUMBER_OFFSET 4 ++#define RTL8367C_PORT5_NUMBER_MASK 0x70 ++#define RTL8367C_PORT4_NUMBER_OFFSET 0 ++#define RTL8367C_PORT4_NUMBER_MASK 0x7 ++ ++#define RTL8367C_REG_QOS_PORT_QUEUE_NUMBER_CTRL2 0x0902 ++#define RTL8367C_PORT10_NUMBER_OFFSET 8 ++#define RTL8367C_PORT10_NUMBER_MASK 0x700 ++#define RTL8367C_PORT9_NUMBER_OFFSET 4 ++#define RTL8367C_PORT9_NUMBER_MASK 0x70 ++#define RTL8367C_PORT8_NUMBER_OFFSET 0 ++#define RTL8367C_PORT8_NUMBER_MASK 0x7 ++ ++#define RTL8367C_REG_QOS_1Q_PRIORITY_TO_QID_CTRL0 0x0904 ++#define RTL8367C_QOS_1Q_PRIORITY_TO_QID_CTRL0_PRIORITY3_TO_QID_OFFSET 12 ++#define RTL8367C_QOS_1Q_PRIORITY_TO_QID_CTRL0_PRIORITY3_TO_QID_MASK 0x7000 ++#define RTL8367C_QOS_1Q_PRIORITY_TO_QID_CTRL0_PRIORITY2_TO_QID_OFFSET 8 ++#define RTL8367C_QOS_1Q_PRIORITY_TO_QID_CTRL0_PRIORITY2_TO_QID_MASK 0x700 ++#define RTL8367C_QOS_1Q_PRIORITY_TO_QID_CTRL0_PRIORITY1_TO_QID_OFFSET 4 ++#define RTL8367C_QOS_1Q_PRIORITY_TO_QID_CTRL0_PRIORITY1_TO_QID_MASK 0x70 ++#define RTL8367C_QOS_1Q_PRIORITY_TO_QID_CTRL0_PRIORITY0_TO_QID_OFFSET 0 ++#define RTL8367C_QOS_1Q_PRIORITY_TO_QID_CTRL0_PRIORITY0_TO_QID_MASK 0x7 ++ ++#define RTL8367C_REG_QOS_1Q_PRIORITY_TO_QID_CTRL1 0x0905 ++#define RTL8367C_QOS_1Q_PRIORITY_TO_QID_CTRL1_PRIORITY7_TO_QID_OFFSET 12 ++#define RTL8367C_QOS_1Q_PRIORITY_TO_QID_CTRL1_PRIORITY7_TO_QID_MASK 0x7000 ++#define RTL8367C_QOS_1Q_PRIORITY_TO_QID_CTRL1_PRIORITY6_TO_QID_OFFSET 8 ++#define RTL8367C_QOS_1Q_PRIORITY_TO_QID_CTRL1_PRIORITY6_TO_QID_MASK 0x700 ++#define RTL8367C_QOS_1Q_PRIORITY_TO_QID_CTRL1_PRIORITY5_TO_QID_OFFSET 4 ++#define RTL8367C_QOS_1Q_PRIORITY_TO_QID_CTRL1_PRIORITY5_TO_QID_MASK 0x70 ++#define RTL8367C_QOS_1Q_PRIORITY_TO_QID_CTRL1_PRIORITY4_TO_QID_OFFSET 0 ++#define RTL8367C_QOS_1Q_PRIORITY_TO_QID_CTRL1_PRIORITY4_TO_QID_MASK 0x7 ++ ++#define RTL8367C_REG_QOS_2Q_PRIORITY_TO_QID_CTRL0 0x0906 ++#define RTL8367C_QOS_2Q_PRIORITY_TO_QID_CTRL0_PRIORITY3_TO_QID_OFFSET 12 ++#define RTL8367C_QOS_2Q_PRIORITY_TO_QID_CTRL0_PRIORITY3_TO_QID_MASK 0x7000 ++#define RTL8367C_QOS_2Q_PRIORITY_TO_QID_CTRL0_PRIORITY2_TO_QID_OFFSET 8 ++#define RTL8367C_QOS_2Q_PRIORITY_TO_QID_CTRL0_PRIORITY2_TO_QID_MASK 0x700 ++#define RTL8367C_QOS_2Q_PRIORITY_TO_QID_CTRL0_PRIORITY1_TO_QID_OFFSET 4 ++#define RTL8367C_QOS_2Q_PRIORITY_TO_QID_CTRL0_PRIORITY1_TO_QID_MASK 0x70 ++#define RTL8367C_QOS_2Q_PRIORITY_TO_QID_CTRL0_PRIORITY0_TO_QID_OFFSET 0 ++#define RTL8367C_QOS_2Q_PRIORITY_TO_QID_CTRL0_PRIORITY0_TO_QID_MASK 0x7 ++ ++#define RTL8367C_REG_QOS_2Q_PRIORITY_TO_QID_CTRL1 0x0907 ++#define RTL8367C_QOS_2Q_PRIORITY_TO_QID_CTRL1_PRIORITY7_TO_QID_OFFSET 12 ++#define RTL8367C_QOS_2Q_PRIORITY_TO_QID_CTRL1_PRIORITY7_TO_QID_MASK 0x7000 ++#define RTL8367C_QOS_2Q_PRIORITY_TO_QID_CTRL1_PRIORITY6_TO_QID_OFFSET 8 ++#define RTL8367C_QOS_2Q_PRIORITY_TO_QID_CTRL1_PRIORITY6_TO_QID_MASK 0x700 ++#define RTL8367C_QOS_2Q_PRIORITY_TO_QID_CTRL1_PRIORITY5_TO_QID_OFFSET 4 ++#define RTL8367C_QOS_2Q_PRIORITY_TO_QID_CTRL1_PRIORITY5_TO_QID_MASK 0x70 ++#define RTL8367C_QOS_2Q_PRIORITY_TO_QID_CTRL1_PRIORITY4_TO_QID_OFFSET 0 ++#define RTL8367C_QOS_2Q_PRIORITY_TO_QID_CTRL1_PRIORITY4_TO_QID_MASK 0x7 ++ ++#define RTL8367C_REG_QOS_3Q_PRIORITY_TO_QID_CTRL0 0x0908 ++#define RTL8367C_QOS_3Q_PRIORITY_TO_QID_CTRL0_PRIORITY3_TO_QID_OFFSET 12 ++#define RTL8367C_QOS_3Q_PRIORITY_TO_QID_CTRL0_PRIORITY3_TO_QID_MASK 0x7000 ++#define RTL8367C_QOS_3Q_PRIORITY_TO_QID_CTRL0_PRIORITY2_TO_QID_OFFSET 8 ++#define RTL8367C_QOS_3Q_PRIORITY_TO_QID_CTRL0_PRIORITY2_TO_QID_MASK 0x700 ++#define RTL8367C_QOS_3Q_PRIORITY_TO_QID_CTRL0_PRIORITY1_TO_QID_OFFSET 4 ++#define RTL8367C_QOS_3Q_PRIORITY_TO_QID_CTRL0_PRIORITY1_TO_QID_MASK 0x70 ++#define RTL8367C_QOS_3Q_PRIORITY_TO_QID_CTRL0_PRIORITY0_TO_QID_OFFSET 0 ++#define RTL8367C_QOS_3Q_PRIORITY_TO_QID_CTRL0_PRIORITY0_TO_QID_MASK 0x7 ++ ++#define RTL8367C_REG_QOS_3Q_PRIORITY_TO_QID_CTRL1 0x0909 ++#define RTL8367C_QOS_3Q_PRIORITY_TO_QID_CTRL1_PRIORITY7_TO_QID_OFFSET 12 ++#define RTL8367C_QOS_3Q_PRIORITY_TO_QID_CTRL1_PRIORITY7_TO_QID_MASK 0x7000 ++#define RTL8367C_QOS_3Q_PRIORITY_TO_QID_CTRL1_PRIORITY6_TO_QID_OFFSET 8 ++#define RTL8367C_QOS_3Q_PRIORITY_TO_QID_CTRL1_PRIORITY6_TO_QID_MASK 0x700 ++#define RTL8367C_QOS_3Q_PRIORITY_TO_QID_CTRL1_PRIORITY5_TO_QID_OFFSET 4 ++#define RTL8367C_QOS_3Q_PRIORITY_TO_QID_CTRL1_PRIORITY5_TO_QID_MASK 0x70 ++#define RTL8367C_QOS_3Q_PRIORITY_TO_QID_CTRL1_PRIORITY4_TO_QID_OFFSET 0 ++#define RTL8367C_QOS_3Q_PRIORITY_TO_QID_CTRL1_PRIORITY4_TO_QID_MASK 0x7 ++ ++#define RTL8367C_REG_QOS_4Q_PRIORITY_TO_QID_CTRL0 0x090a ++#define RTL8367C_QOS_4Q_PRIORITY_TO_QID_CTRL0_PRIORITY3_TO_QID_OFFSET 12 ++#define RTL8367C_QOS_4Q_PRIORITY_TO_QID_CTRL0_PRIORITY3_TO_QID_MASK 0x7000 ++#define RTL8367C_QOS_4Q_PRIORITY_TO_QID_CTRL0_PRIORITY2_TO_QID_OFFSET 8 ++#define RTL8367C_QOS_4Q_PRIORITY_TO_QID_CTRL0_PRIORITY2_TO_QID_MASK 0x700 ++#define RTL8367C_QOS_4Q_PRIORITY_TO_QID_CTRL0_PRIORITY1_TO_QID_OFFSET 4 ++#define RTL8367C_QOS_4Q_PRIORITY_TO_QID_CTRL0_PRIORITY1_TO_QID_MASK 0x70 ++#define RTL8367C_QOS_4Q_PRIORITY_TO_QID_CTRL0_PRIORITY0_TO_QID_OFFSET 0 ++#define RTL8367C_QOS_4Q_PRIORITY_TO_QID_CTRL0_PRIORITY0_TO_QID_MASK 0x7 ++ ++#define RTL8367C_REG_QOS_4Q_PRIORITY_TO_QID_CTRL1 0x090b ++#define RTL8367C_QOS_4Q_PRIORITY_TO_QID_CTRL1_PRIORITY7_TO_QID_OFFSET 12 ++#define RTL8367C_QOS_4Q_PRIORITY_TO_QID_CTRL1_PRIORITY7_TO_QID_MASK 0x7000 ++#define RTL8367C_QOS_4Q_PRIORITY_TO_QID_CTRL1_PRIORITY6_TO_QID_OFFSET 8 ++#define RTL8367C_QOS_4Q_PRIORITY_TO_QID_CTRL1_PRIORITY6_TO_QID_MASK 0x700 ++#define RTL8367C_QOS_4Q_PRIORITY_TO_QID_CTRL1_PRIORITY5_TO_QID_OFFSET 4 ++#define RTL8367C_QOS_4Q_PRIORITY_TO_QID_CTRL1_PRIORITY5_TO_QID_MASK 0x70 ++#define RTL8367C_QOS_4Q_PRIORITY_TO_QID_CTRL1_PRIORITY4_TO_QID_OFFSET 0 ++#define RTL8367C_QOS_4Q_PRIORITY_TO_QID_CTRL1_PRIORITY4_TO_QID_MASK 0x7 ++ ++#define RTL8367C_REG_QOS_5Q_PRIORITY_TO_QID_CTRL0 0x090c ++#define RTL8367C_QOS_5Q_PRIORITY_TO_QID_CTRL0_PRIORITY3_TO_QID_OFFSET 12 ++#define RTL8367C_QOS_5Q_PRIORITY_TO_QID_CTRL0_PRIORITY3_TO_QID_MASK 0x7000 ++#define RTL8367C_QOS_5Q_PRIORITY_TO_QID_CTRL0_PRIORITY2_TO_QID_OFFSET 8 ++#define RTL8367C_QOS_5Q_PRIORITY_TO_QID_CTRL0_PRIORITY2_TO_QID_MASK 0x700 ++#define RTL8367C_QOS_5Q_PRIORITY_TO_QID_CTRL0_PRIORITY1_TO_QID_OFFSET 4 ++#define RTL8367C_QOS_5Q_PRIORITY_TO_QID_CTRL0_PRIORITY1_TO_QID_MASK 0x70 ++#define RTL8367C_QOS_5Q_PRIORITY_TO_QID_CTRL0_PRIORITY0_TO_QID_OFFSET 0 ++#define RTL8367C_QOS_5Q_PRIORITY_TO_QID_CTRL0_PRIORITY0_TO_QID_MASK 0x7 ++ ++#define RTL8367C_REG_QOS_5Q_PRIORITY_TO_QID_CTRL1 0x090d ++#define RTL8367C_QOS_5Q_PRIORITY_TO_QID_CTRL1_PRIORITY7_TO_QID_OFFSET 12 ++#define RTL8367C_QOS_5Q_PRIORITY_TO_QID_CTRL1_PRIORITY7_TO_QID_MASK 0x7000 ++#define RTL8367C_QOS_5Q_PRIORITY_TO_QID_CTRL1_PRIORITY6_TO_QID_OFFSET 8 ++#define RTL8367C_QOS_5Q_PRIORITY_TO_QID_CTRL1_PRIORITY6_TO_QID_MASK 0x700 ++#define RTL8367C_QOS_5Q_PRIORITY_TO_QID_CTRL1_PRIORITY5_TO_QID_OFFSET 4 ++#define RTL8367C_QOS_5Q_PRIORITY_TO_QID_CTRL1_PRIORITY5_TO_QID_MASK 0x70 ++#define RTL8367C_QOS_5Q_PRIORITY_TO_QID_CTRL1_PRIORITY4_TO_QID_OFFSET 0 ++#define RTL8367C_QOS_5Q_PRIORITY_TO_QID_CTRL1_PRIORITY4_TO_QID_MASK 0x7 ++ ++#define RTL8367C_REG_QOS_6Q_PRIORITY_TO_QID_CTRL0 0x090e ++#define RTL8367C_QOS_6Q_PRIORITY_TO_QID_CTRL0_PRIORITY3_TO_QID_OFFSET 12 ++#define RTL8367C_QOS_6Q_PRIORITY_TO_QID_CTRL0_PRIORITY3_TO_QID_MASK 0x7000 ++#define RTL8367C_QOS_6Q_PRIORITY_TO_QID_CTRL0_PRIORITY2_TO_QID_OFFSET 8 ++#define RTL8367C_QOS_6Q_PRIORITY_TO_QID_CTRL0_PRIORITY2_TO_QID_MASK 0x700 ++#define RTL8367C_QOS_6Q_PRIORITY_TO_QID_CTRL0_PRIORITY1_TO_QID_OFFSET 4 ++#define RTL8367C_QOS_6Q_PRIORITY_TO_QID_CTRL0_PRIORITY1_TO_QID_MASK 0x70 ++#define RTL8367C_QOS_6Q_PRIORITY_TO_QID_CTRL0_PRIORITY0_TO_QID_OFFSET 0 ++#define RTL8367C_QOS_6Q_PRIORITY_TO_QID_CTRL0_PRIORITY0_TO_QID_MASK 0x7 ++ ++#define RTL8367C_REG_QOS_6Q_PRIORITY_TO_QID_CTRL1 0x090f ++#define RTL8367C_QOS_6Q_PRIORITY_TO_QID_CTRL1_PRIORITY7_TO_QID_OFFSET 12 ++#define RTL8367C_QOS_6Q_PRIORITY_TO_QID_CTRL1_PRIORITY7_TO_QID_MASK 0x7000 ++#define RTL8367C_QOS_6Q_PRIORITY_TO_QID_CTRL1_PRIORITY6_TO_QID_OFFSET 8 ++#define RTL8367C_QOS_6Q_PRIORITY_TO_QID_CTRL1_PRIORITY6_TO_QID_MASK 0x700 ++#define RTL8367C_QOS_6Q_PRIORITY_TO_QID_CTRL1_PRIORITY5_TO_QID_OFFSET 4 ++#define RTL8367C_QOS_6Q_PRIORITY_TO_QID_CTRL1_PRIORITY5_TO_QID_MASK 0x70 ++#define RTL8367C_QOS_6Q_PRIORITY_TO_QID_CTRL1_PRIORITY4_TO_QID_OFFSET 0 ++#define RTL8367C_QOS_6Q_PRIORITY_TO_QID_CTRL1_PRIORITY4_TO_QID_MASK 0x7 ++ ++#define RTL8367C_REG_QOS_7Q_PRIORITY_TO_QID_CTRL0 0x0910 ++#define RTL8367C_QOS_7Q_PRIORITY_TO_QID_CTRL0_PRIORITY3_TO_QID_OFFSET 12 ++#define RTL8367C_QOS_7Q_PRIORITY_TO_QID_CTRL0_PRIORITY3_TO_QID_MASK 0x7000 ++#define RTL8367C_QOS_7Q_PRIORITY_TO_QID_CTRL0_PRIORITY2_TO_QID_OFFSET 8 ++#define RTL8367C_QOS_7Q_PRIORITY_TO_QID_CTRL0_PRIORITY2_TO_QID_MASK 0x700 ++#define RTL8367C_QOS_7Q_PRIORITY_TO_QID_CTRL0_PRIORITY1_TO_QID_OFFSET 4 ++#define RTL8367C_QOS_7Q_PRIORITY_TO_QID_CTRL0_PRIORITY1_TO_QID_MASK 0x70 ++#define RTL8367C_QOS_7Q_PRIORITY_TO_QID_CTRL0_PRIORITY0_TO_QID_OFFSET 0 ++#define RTL8367C_QOS_7Q_PRIORITY_TO_QID_CTRL0_PRIORITY0_TO_QID_MASK 0x7 ++ ++#define RTL8367C_REG_QOS_7Q_PRIORITY_TO_QID_CTRL1 0x0911 ++#define RTL8367C_QOS_7Q_PRIORITY_TO_QID_CTRL1_PRIORITY7_TO_QID_OFFSET 12 ++#define RTL8367C_QOS_7Q_PRIORITY_TO_QID_CTRL1_PRIORITY7_TO_QID_MASK 0x7000 ++#define RTL8367C_QOS_7Q_PRIORITY_TO_QID_CTRL1_PRIORITY6_TO_QID_OFFSET 8 ++#define RTL8367C_QOS_7Q_PRIORITY_TO_QID_CTRL1_PRIORITY6_TO_QID_MASK 0x700 ++#define RTL8367C_QOS_7Q_PRIORITY_TO_QID_CTRL1_PRIORITY5_TO_QID_OFFSET 4 ++#define RTL8367C_QOS_7Q_PRIORITY_TO_QID_CTRL1_PRIORITY5_TO_QID_MASK 0x70 ++#define RTL8367C_QOS_7Q_PRIORITY_TO_QID_CTRL1_PRIORITY4_TO_QID_OFFSET 0 ++#define RTL8367C_QOS_7Q_PRIORITY_TO_QID_CTRL1_PRIORITY4_TO_QID_MASK 0x7 ++ ++#define RTL8367C_REG_QOS_8Q_PRIORITY_TO_QID_CTRL0 0x0912 ++#define RTL8367C_QOS_8Q_PRIORITY_TO_QID_CTRL0_PRIORITY3_TO_QID_OFFSET 12 ++#define RTL8367C_QOS_8Q_PRIORITY_TO_QID_CTRL0_PRIORITY3_TO_QID_MASK 0x7000 ++#define RTL8367C_QOS_8Q_PRIORITY_TO_QID_CTRL0_PRIORITY2_TO_QID_OFFSET 8 ++#define RTL8367C_QOS_8Q_PRIORITY_TO_QID_CTRL0_PRIORITY2_TO_QID_MASK 0x700 ++#define RTL8367C_QOS_8Q_PRIORITY_TO_QID_CTRL0_PRIORITY1_TO_QID_OFFSET 4 ++#define RTL8367C_QOS_8Q_PRIORITY_TO_QID_CTRL0_PRIORITY1_TO_QID_MASK 0x70 ++#define RTL8367C_QOS_8Q_PRIORITY_TO_QID_CTRL0_PRIORITY0_TO_QID_OFFSET 0 ++#define RTL8367C_QOS_8Q_PRIORITY_TO_QID_CTRL0_PRIORITY0_TO_QID_MASK 0x7 ++ ++#define RTL8367C_REG_QOS_8Q_PRIORITY_TO_QID_CTRL1 0x0913 ++#define RTL8367C_QOS_8Q_PRIORITY_TO_QID_CTRL1_PRIORITY7_TO_QID_OFFSET 12 ++#define RTL8367C_QOS_8Q_PRIORITY_TO_QID_CTRL1_PRIORITY7_TO_QID_MASK 0x7000 ++#define RTL8367C_QOS_8Q_PRIORITY_TO_QID_CTRL1_PRIORITY6_TO_QID_OFFSET 8 ++#define RTL8367C_QOS_8Q_PRIORITY_TO_QID_CTRL1_PRIORITY6_TO_QID_MASK 0x700 ++#define RTL8367C_QOS_8Q_PRIORITY_TO_QID_CTRL1_PRIORITY5_TO_QID_OFFSET 4 ++#define RTL8367C_QOS_8Q_PRIORITY_TO_QID_CTRL1_PRIORITY5_TO_QID_MASK 0x70 ++#define RTL8367C_QOS_8Q_PRIORITY_TO_QID_CTRL1_PRIORITY4_TO_QID_OFFSET 0 ++#define RTL8367C_QOS_8Q_PRIORITY_TO_QID_CTRL1_PRIORITY4_TO_QID_MASK 0x7 ++ ++#define RTL8367C_REG_HIGHPRI_INDICATOR 0x0915 ++#define RTL8367C_PORT10_INDICATOR_OFFSET 10 ++#define RTL8367C_PORT10_INDICATOR_MASK 0x400 ++#define RTL8367C_PORT9_INDICATOR_OFFSET 9 ++#define RTL8367C_PORT9_INDICATOR_MASK 0x200 ++#define RTL8367C_PORT8_INDICATOR_OFFSET 8 ++#define RTL8367C_PORT8_INDICATOR_MASK 0x100 ++#define RTL8367C_PORT7_INDICATOR_OFFSET 7 ++#define RTL8367C_PORT7_INDICATOR_MASK 0x80 ++#define RTL8367C_PORT6_INDICATOR_OFFSET 6 ++#define RTL8367C_PORT6_INDICATOR_MASK 0x40 ++#define RTL8367C_PORT5_INDICATOR_OFFSET 5 ++#define RTL8367C_PORT5_INDICATOR_MASK 0x20 ++#define RTL8367C_PORT4_INDICATOR_OFFSET 4 ++#define RTL8367C_PORT4_INDICATOR_MASK 0x10 ++#define RTL8367C_PORT3_INDICATOR_OFFSET 3 ++#define RTL8367C_PORT3_INDICATOR_MASK 0x8 ++#define RTL8367C_PORT2_INDICATOR_OFFSET 2 ++#define RTL8367C_PORT2_INDICATOR_MASK 0x4 ++#define RTL8367C_PORT1_INDICATOR_OFFSET 1 ++#define RTL8367C_PORT1_INDICATOR_MASK 0x2 ++#define RTL8367C_PORT0_INDICATOR_OFFSET 0 ++#define RTL8367C_PORT0_INDICATOR_MASK 0x1 ++ ++#define RTL8367C_REG_HIGHPRI_CFG 0x0916 ++#define RTL8367C_HIGHPRI_CFG_OFFSET 0 ++#define RTL8367C_HIGHPRI_CFG_MASK 0xFF ++ ++#define RTL8367C_REG_PORT_DEBUG_INFO_CTRL0 0x0917 ++#define RTL8367C_PORT1_DEBUG_INFO_OFFSET 8 ++#define RTL8367C_PORT1_DEBUG_INFO_MASK 0xFF00 ++#define RTL8367C_PORT0_DEBUG_INFO_OFFSET 0 ++#define RTL8367C_PORT0_DEBUG_INFO_MASK 0xFF ++ ++#define RTL8367C_REG_PORT_DEBUG_INFO_CTRL1 0x0918 ++#define RTL8367C_PORT3_DEBUG_INFO_OFFSET 8 ++#define RTL8367C_PORT3_DEBUG_INFO_MASK 0xFF00 ++#define RTL8367C_PORT2_DEBUG_INFO_OFFSET 0 ++#define RTL8367C_PORT2_DEBUG_INFO_MASK 0xFF ++ ++#define RTL8367C_REG_PORT_DEBUG_INFO_CTRL2 0x0919 ++#define RTL8367C_PORT5_DEBUG_INFO_OFFSET 8 ++#define RTL8367C_PORT5_DEBUG_INFO_MASK 0xFF00 ++#define RTL8367C_PORT4_DEBUG_INFO_OFFSET 0 ++#define RTL8367C_PORT4_DEBUG_INFO_MASK 0xFF ++ ++#define RTL8367C_REG_PORT_DEBUG_INFO_CTRL3 0x091a ++#define RTL8367C_PORT7_DEBUG_INFO_OFFSET 8 ++#define RTL8367C_PORT7_DEBUG_INFO_MASK 0xFF00 ++#define RTL8367C_PORT6_DEBUG_INFO_OFFSET 0 ++#define RTL8367C_PORT6_DEBUG_INFO_MASK 0xFF ++ ++#define RTL8367C_REG_PORT_DEBUG_INFO_CTRL4 0x091b ++#define RTL8367C_PORT9_DEBUG_INFO_OFFSET 8 ++#define RTL8367C_PORT9_DEBUG_INFO_MASK 0xFF00 ++#define RTL8367C_PORT8_DEBUG_INFO_OFFSET 0 ++#define RTL8367C_PORT8_DEBUG_INFO_MASK 0xFF ++ ++#define RTL8367C_REG_PORT_DEBUG_INFO_CTRL5 0x091c ++#define RTL8367C_PORT10_DEBUG_INFO_OFFSET 0 ++#define RTL8367C_PORT10_DEBUG_INFO_MASK 0xFF ++ ++#define RTL8367C_REG_PORT_DEBUG_INFO_CTRL6 0x091d ++#define RTL8367C_PORT7_DEBUG_INDICATOR_OFFSET 14 ++#define RTL8367C_PORT7_DEBUG_INDICATOR_MASK 0xC000 ++#define RTL8367C_PORT6_DEBUG_INDICATOR_OFFSET 12 ++#define RTL8367C_PORT6_DEBUG_INDICATOR_MASK 0x3000 ++#define RTL8367C_PORT5_DEBUG_INDICATOR_OFFSET 10 ++#define RTL8367C_PORT5_DEBUG_INDICATOR_MASK 0xC00 ++#define RTL8367C_PORT4_DEBUG_INDICATOR_OFFSET 8 ++#define RTL8367C_PORT4_DEBUG_INDICATOR_MASK 0x300 ++#define RTL8367C_PORT3_DEBUG_INDICATOR_OFFSET 6 ++#define RTL8367C_PORT3_DEBUG_INDICATOR_MASK 0xC0 ++#define RTL8367C_PORT2_DEBUG_INDICATOR_OFFSET 4 ++#define RTL8367C_PORT2_DEBUG_INDICATOR_MASK 0x30 ++#define RTL8367C_PORT1_DEBUG_INDICATOR_OFFSET 2 ++#define RTL8367C_PORT1_DEBUG_INDICATOR_MASK 0xC ++#define RTL8367C_PORT0_DEBUG_INDICATOR_OFFSET 0 ++#define RTL8367C_PORT0_DEBUG_INDICATOR_MASK 0x3 ++ ++#define RTL8367C_REG_PORT_DEBUG_INFO_CTRL7 0x091e ++#define RTL8367C_PORT10_DEBUG_INDICATOR_OFFSET 4 ++#define RTL8367C_PORT10_DEBUG_INDICATOR_MASK 0x30 ++#define RTL8367C_PORT9_DEBUG_INDICATOR_OFFSET 2 ++#define RTL8367C_PORT9_DEBUG_INDICATOR_MASK 0xC ++#define RTL8367C_PORT8_DEBUG_INDICATOR_OFFSET 0 ++#define RTL8367C_PORT8_DEBUG_INDICATOR_MASK 0x3 ++ ++#define RTL8367C_REG_FLOWCRTL_EGRESS_QUEUE_ENABLE_CTRL0 0x0930 ++#define RTL8367C_PORT1_QUEUE_MASK_OFFSET 8 ++#define RTL8367C_PORT1_QUEUE_MASK_MASK 0xFF00 ++#define RTL8367C_PORT0_QUEUE_MASK_OFFSET 0 ++#define RTL8367C_PORT0_QUEUE_MASK_MASK 0xFF ++ ++#define RTL8367C_REG_FLOWCRTL_EGRESS_QUEUE_ENABLE_CTRL1 0x0931 ++#define RTL8367C_PORT3_QUEUE_MASK_OFFSET 8 ++#define RTL8367C_PORT3_QUEUE_MASK_MASK 0xFF00 ++#define RTL8367C_PORT2_QUEUE_MASK_OFFSET 0 ++#define RTL8367C_PORT2_QUEUE_MASK_MASK 0xFF ++ ++#define RTL8367C_REG_FLOWCRTL_EGRESS_QUEUE_ENABLE_CTRL2 0x0932 ++#define RTL8367C_PORT5_QUEUE_MASK_OFFSET 8 ++#define RTL8367C_PORT5_QUEUE_MASK_MASK 0xFF00 ++#define RTL8367C_PORT4_QUEUE_MASK_OFFSET 0 ++#define RTL8367C_PORT4_QUEUE_MASK_MASK 0xFF ++ ++#define RTL8367C_REG_FLOWCRTL_EGRESS_QUEUE_ENABLE_CTRL3 0x0933 ++#define RTL8367C_PORT7_QUEUE_MASK_OFFSET 8 ++#define RTL8367C_PORT7_QUEUE_MASK_MASK 0xFF00 ++#define RTL8367C_PORT6_QUEUE_MASK_OFFSET 0 ++#define RTL8367C_PORT6_QUEUE_MASK_MASK 0xFF ++ ++#define RTL8367C_REG_FLOWCRTL_EGRESS_QUEUE_ENABLE_CTRL4 0x0934 ++#define RTL8367C_PORT9_QUEUE_MASK_OFFSET 8 ++#define RTL8367C_PORT9_QUEUE_MASK_MASK 0xFF00 ++#define RTL8367C_PORT8_QUEUE_MASK_OFFSET 0 ++#define RTL8367C_PORT8_QUEUE_MASK_MASK 0xFF ++ ++#define RTL8367C_REG_FLOWCRTL_EGRESS_QUEUE_ENABLE_CTRL5 0x0935 ++#define RTL8367C_FLOWCRTL_EGRESS_QUEUE_ENABLE_CTRL5_OFFSET 0 ++#define RTL8367C_FLOWCRTL_EGRESS_QUEUE_ENABLE_CTRL5_MASK 0xFF ++ ++#define RTL8367C_REG_FLOWCRTL_EGRESS_PORT_ENABLE 0x0938 ++#define RTL8367C_FLOWCRTL_EGRESS_PORT_ENABLE_OFFSET 0 ++#define RTL8367C_FLOWCRTL_EGRESS_PORT_ENABLE_MASK 0xFF ++ ++#define RTL8367C_REG_EAV_CTRL 0x0939 ++#define RTL8367C_EAV_TRAP_CPU_OFFSET 1 ++#define RTL8367C_EAV_TRAP_CPU_MASK 0x2 ++#define RTL8367C_EAV_TRAP_8051_OFFSET 0 ++#define RTL8367C_EAV_TRAP_8051_MASK 0x1 ++ ++#define RTL8367C_REG_UNTAG_DSCP_PRI_CFG 0x093a ++#define RTL8367C_UNTAG_DSCP_PRI_CFG_OFFSET 0 ++#define RTL8367C_UNTAG_DSCP_PRI_CFG_MASK 0x1 ++ ++#define RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL0 0x093b ++#define RTL8367C_PORT1_VLAN_KEEP_MASK_OFFSET 8 ++#define RTL8367C_PORT1_VLAN_KEEP_MASK_MASK 0xFF00 ++#define RTL8367C_PORT0_VLAN_KEEP_MASK_OFFSET 0 ++#define RTL8367C_PORT0_VLAN_KEEP_MASK_MASK 0xFF ++ ++#define RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL1 0x093c ++#define RTL8367C_PORT3_VLAN_KEEP_MASK_OFFSET 8 ++#define RTL8367C_PORT3_VLAN_KEEP_MASK_MASK 0xFF00 ++#define RTL8367C_PORT2_VLAN_KEEP_MASK_OFFSET 0 ++#define RTL8367C_PORT2_VLAN_KEEP_MASK_MASK 0xFF ++ ++#define RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL2 0x093d ++#define RTL8367C_PORT5_VLAN_KEEP_MASK_OFFSET 8 ++#define RTL8367C_PORT5_VLAN_KEEP_MASK_MASK 0xFF00 ++#define RTL8367C_PORT4_VLAN_KEEP_MASK_OFFSET 0 ++#define RTL8367C_PORT4_VLAN_KEEP_MASK_MASK 0xFF ++ ++#define RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL3 0x093e ++#define RTL8367C_PORT7_VLAN_KEEP_MASK_OFFSET 8 ++#define RTL8367C_PORT7_VLAN_KEEP_MASK_MASK 0xFF00 ++#define RTL8367C_PORT6_VLAN_KEEP_MASK_OFFSET 0 ++#define RTL8367C_PORT6_VLAN_KEEP_MASK_MASK 0xFF ++ ++#define RTL8367C_REG_VLAN_TRANSPARENT_EN_CFG 0x093f ++#define RTL8367C_VLAN_TRANSPARENT_EN_CFG_OFFSET 0 ++#define RTL8367C_VLAN_TRANSPARENT_EN_CFG_MASK 0x1 ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY0_H 0x0940 ++#define RTL8367C_IPMC_GROUP_ENTRY0_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY0_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY0_L 0x0941 ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY1_H 0x0942 ++#define RTL8367C_IPMC_GROUP_ENTRY1_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY1_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY1_L 0x0943 ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY2_H 0x0944 ++#define RTL8367C_IPMC_GROUP_ENTRY2_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY2_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY2_L 0x0945 ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY3_H 0x0946 ++#define RTL8367C_IPMC_GROUP_ENTRY3_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY3_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY3_L 0x0947 ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY4_H 0x0948 ++#define RTL8367C_IPMC_GROUP_ENTRY4_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY4_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY4_L 0x0949 ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY5_H 0x094a ++#define RTL8367C_IPMC_GROUP_ENTRY5_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY5_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY5_L 0x094b ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY6_H 0x094c ++#define RTL8367C_IPMC_GROUP_ENTRY6_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY6_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY6_L 0x094d ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY7_H 0x094e ++#define RTL8367C_IPMC_GROUP_ENTRY7_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY7_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY7_L 0x094f ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY8_H 0x0950 ++#define RTL8367C_IPMC_GROUP_ENTRY8_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY8_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY8_L 0x0951 ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY9_H 0x0952 ++#define RTL8367C_IPMC_GROUP_ENTRY9_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY9_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY9_L 0x0953 ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY10_H 0x0954 ++#define RTL8367C_IPMC_GROUP_ENTRY10_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY10_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY10_L 0x0955 ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY11_H 0x0956 ++#define RTL8367C_IPMC_GROUP_ENTRY11_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY11_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY11_L 0x0957 ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY12_H 0x0958 ++#define RTL8367C_IPMC_GROUP_ENTRY12_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY12_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY12_L 0x0959 ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY13_H 0x095a ++#define RTL8367C_IPMC_GROUP_ENTRY13_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY13_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY13_L 0x095b ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY14_H 0x095c ++#define RTL8367C_IPMC_GROUP_ENTRY14_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY14_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY14_L 0x095d ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY15_H 0x095e ++#define RTL8367C_IPMC_GROUP_ENTRY15_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY15_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY15_L 0x095f ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY16_H 0x0960 ++#define RTL8367C_IPMC_GROUP_ENTRY16_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY16_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY16_L 0x0961 ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY17_H 0x0962 ++#define RTL8367C_IPMC_GROUP_ENTRY17_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY17_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY17_L 0x0963 ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY18_H 0x0964 ++#define RTL8367C_IPMC_GROUP_ENTRY18_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY18_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY18_L 0x0965 ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY19_H 0x0966 ++#define RTL8367C_IPMC_GROUP_ENTRY19_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY19_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY19_L 0x0967 ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY20_H 0x0968 ++#define RTL8367C_IPMC_GROUP_ENTRY20_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY20_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY20_L 0x0969 ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY21_H 0x096a ++#define RTL8367C_IPMC_GROUP_ENTRY21_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY21_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY21_L 0x096b ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY22_H 0x096c ++#define RTL8367C_IPMC_GROUP_ENTRY22_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY22_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY22_L 0x096d ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY23_H 0x096e ++#define RTL8367C_IPMC_GROUP_ENTRY23_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY23_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY23_L 0x096f ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY24_H 0x0970 ++#define RTL8367C_IPMC_GROUP_ENTRY24_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY24_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY24_L 0x0971 ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY25_H 0x0972 ++#define RTL8367C_IPMC_GROUP_ENTRY25_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY25_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY25_L 0x0973 ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY26_H 0x0974 ++#define RTL8367C_IPMC_GROUP_ENTRY26_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY26_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY26_L 0x0975 ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY27_H 0x0976 ++#define RTL8367C_IPMC_GROUP_ENTRY27_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY27_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY27_L 0x0977 ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY28_H 0x0978 ++#define RTL8367C_IPMC_GROUP_ENTRY28_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY28_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY28_L 0x0979 ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY29_H 0x097a ++#define RTL8367C_IPMC_GROUP_ENTRY29_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY29_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY29_L 0x097b ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY30_H 0x097c ++#define RTL8367C_IPMC_GROUP_ENTRY30_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY30_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY30_L 0x097d ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY31_H 0x097e ++#define RTL8367C_IPMC_GROUP_ENTRY31_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY31_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY31_L 0x097f ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY32_H 0x0980 ++#define RTL8367C_IPMC_GROUP_ENTRY32_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY32_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY32_L 0x0981 ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY33_H 0x0982 ++#define RTL8367C_IPMC_GROUP_ENTRY33_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY33_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY33_L 0x0983 ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY34_H 0x0984 ++#define RTL8367C_IPMC_GROUP_ENTRY34_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY34_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY34_L 0x0985 ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY35_H 0x0986 ++#define RTL8367C_IPMC_GROUP_ENTRY35_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY35_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY35_L 0x0987 ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY36_H 0x0988 ++#define RTL8367C_IPMC_GROUP_ENTRY36_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY36_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY36_L 0x0989 ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY37_H 0x098a ++#define RTL8367C_IPMC_GROUP_ENTRY37_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY37_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY37_L 0x098b ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY38_H 0x098c ++#define RTL8367C_IPMC_GROUP_ENTRY38_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY38_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY38_L 0x098d ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY39_H 0x098e ++#define RTL8367C_IPMC_GROUP_ENTRY39_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY39_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY39_L 0x098f ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY40_H 0x0990 ++#define RTL8367C_IPMC_GROUP_ENTRY40_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY40_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY40_L 0x0991 ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY41_H 0x0992 ++#define RTL8367C_IPMC_GROUP_ENTRY41_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY41_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY41_L 0x0993 ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY42_H 0x0994 ++#define RTL8367C_IPMC_GROUP_ENTRY42_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY42_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY42_L 0x0995 ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY43_H 0x0996 ++#define RTL8367C_IPMC_GROUP_ENTRY43_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY43_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY43_L 0x0997 ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY44_H 0x0998 ++#define RTL8367C_IPMC_GROUP_ENTRY44_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY44_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY44_L 0x0999 ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY45_H 0x099a ++#define RTL8367C_IPMC_GROUP_ENTRY45_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY45_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY45_L 0x099b ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY46_H 0x099c ++#define RTL8367C_IPMC_GROUP_ENTRY46_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY46_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY46_L 0x099d ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY47_H 0x099e ++#define RTL8367C_IPMC_GROUP_ENTRY47_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY47_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY47_L 0x099f ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY48_H 0x09a0 ++#define RTL8367C_IPMC_GROUP_ENTRY48_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY48_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY48_L 0x09a1 ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY49_H 0x09a2 ++#define RTL8367C_IPMC_GROUP_ENTRY49_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY49_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY49_L 0x09a3 ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY50_H 0x09a4 ++#define RTL8367C_IPMC_GROUP_ENTRY50_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY50_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY50_L 0x09a5 ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY51_H 0x09a6 ++#define RTL8367C_IPMC_GROUP_ENTRY51_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY51_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY51_L 0x09a7 ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY52_H 0x09a8 ++#define RTL8367C_IPMC_GROUP_ENTRY52_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY52_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY52_L 0x09a9 ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY53_H 0x09aa ++#define RTL8367C_IPMC_GROUP_ENTRY53_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY53_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY53_L 0x09ab ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY54_H 0x09ac ++#define RTL8367C_IPMC_GROUP_ENTRY54_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY54_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY54_L 0x09ad ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY55_H 0x09ae ++#define RTL8367C_IPMC_GROUP_ENTRY55_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY55_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY55_L 0x09af ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY56_H 0x09b0 ++#define RTL8367C_IPMC_GROUP_ENTRY56_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY56_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY56_L 0x09b1 ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY57_H 0x09b2 ++#define RTL8367C_IPMC_GROUP_ENTRY57_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY57_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY57_L 0x09b3 ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY58_H 0x09b4 ++#define RTL8367C_IPMC_GROUP_ENTRY58_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY58_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY58_L 0x09b5 ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY59_H 0x09b6 ++#define RTL8367C_IPMC_GROUP_ENTRY59_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY59_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY59_L 0x09b7 ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY60_H 0x09b8 ++#define RTL8367C_IPMC_GROUP_ENTRY60_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY60_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY60_L 0x09b9 ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY61_H 0x09ba ++#define RTL8367C_IPMC_GROUP_ENTRY61_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY61_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY61_L 0x09bb ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY62_H 0x09bc ++#define RTL8367C_IPMC_GROUP_ENTRY62_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY62_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY62_L 0x09bd ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY63_H 0x09be ++#define RTL8367C_IPMC_GROUP_ENTRY63_H_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_ENTRY63_H_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_ENTRY63_L 0x09bf ++ ++#define RTL8367C_REG_UNKNOWN_UNICAST_DA_PORT_BEHAVE 0x09C0 ++#define RTL8367C_Port7_ACTION_OFFSET 14 ++#define RTL8367C_Port7_ACTION_MASK 0xC000 ++#define RTL8367C_Port6_ACTION_OFFSET 12 ++#define RTL8367C_Port6_ACTION_MASK 0x3000 ++#define RTL8367C_Port5_ACTION_OFFSET 10 ++#define RTL8367C_Port5_ACTION_MASK 0xC00 ++#define RTL8367C_Port4_ACTION_OFFSET 8 ++#define RTL8367C_Port4_ACTION_MASK 0x300 ++#define RTL8367C_Port3_ACTION_OFFSET 6 ++#define RTL8367C_Port3_ACTION_MASK 0xC0 ++#define RTL8367C_Port2_ACTION_OFFSET 4 ++#define RTL8367C_Port2_ACTION_MASK 0x30 ++#define RTL8367C_Port1_ACTION_OFFSET 2 ++#define RTL8367C_Port1_ACTION_MASK 0xC ++#define RTL8367C_Port0_ACTION_OFFSET 0 ++#define RTL8367C_Port0_ACTION_MASK 0x3 ++ ++#define RTL8367C_REG_MIRROR_CTRL3 0x09C1 ++#define RTL8367C_MIRROR_ACL_OVERRIDE_EN_OFFSET 2 ++#define RTL8367C_MIRROR_ACL_OVERRIDE_EN_MASK 0x4 ++#define RTL8367C_MIRROR_TX_OVERRIDE_EN_OFFSET 1 ++#define RTL8367C_MIRROR_TX_OVERRIDE_EN_MASK 0x2 ++#define RTL8367C_MIRROR_RX_OVERRIDE_EN_OFFSET 0 ++#define RTL8367C_MIRROR_RX_OVERRIDE_EN_MASK 0x1 ++ ++#define RTL8367C_REG_DPM_DUMMY02 0x09C2 ++ ++#define RTL8367C_REG_DPM_DUMMY03 0x09C3 ++ ++#define RTL8367C_REG_DPM_DUMMY04 0x09C4 ++ ++#define RTL8367C_REG_DPM_DUMMY05 0x09C5 ++ ++#define RTL8367C_REG_DPM_DUMMY06 0x09C6 ++ ++#define RTL8367C_REG_DPM_DUMMY07 0x09C7 ++ ++#define RTL8367C_REG_DPM_DUMMY08 0x09C8 ++ ++#define RTL8367C_REG_DPM_DUMMY09 0x09C9 ++ ++#define RTL8367C_REG_DPM_DUMMY10 0x09CA ++ ++#define RTL8367C_REG_DPM_DUMMY11 0x09CB ++ ++#define RTL8367C_REG_DPM_DUMMY12 0x09CC ++ ++#define RTL8367C_REG_DPM_DUMMY13 0x09CD ++ ++#define RTL8367C_REG_DPM_DUMMY14 0x09CE ++ ++#define RTL8367C_REG_DPM_DUMMY15 0x09CF ++ ++#define RTL8367C_REG_VLAN_EGRESS_TRANS_CTRL0 0x09D0 ++#define RTL8367C_VLAN_EGRESS_TRANS_CTRL0_OFFSET 0 ++#define RTL8367C_VLAN_EGRESS_TRANS_CTRL0_MASK 0x7FF ++ ++#define RTL8367C_REG_VLAN_EGRESS_TRANS_CTRL1 0x09D1 ++#define RTL8367C_VLAN_EGRESS_TRANS_CTRL1_OFFSET 0 ++#define RTL8367C_VLAN_EGRESS_TRANS_CTRL1_MASK 0x7FF ++ ++#define RTL8367C_REG_VLAN_EGRESS_TRANS_CTRL2 0x09D2 ++#define RTL8367C_VLAN_EGRESS_TRANS_CTRL2_OFFSET 0 ++#define RTL8367C_VLAN_EGRESS_TRANS_CTRL2_MASK 0x7FF ++ ++#define RTL8367C_REG_VLAN_EGRESS_TRANS_CTRL3 0x09D3 ++#define RTL8367C_VLAN_EGRESS_TRANS_CTRL3_OFFSET 0 ++#define RTL8367C_VLAN_EGRESS_TRANS_CTRL3_MASK 0x7FF ++ ++#define RTL8367C_REG_VLAN_EGRESS_TRANS_CTRL4 0x09D4 ++#define RTL8367C_VLAN_EGRESS_TRANS_CTRL4_OFFSET 0 ++#define RTL8367C_VLAN_EGRESS_TRANS_CTRL4_MASK 0x7FF ++ ++#define RTL8367C_REG_VLAN_EGRESS_TRANS_CTRL5 0x09D5 ++#define RTL8367C_VLAN_EGRESS_TRANS_CTRL5_OFFSET 0 ++#define RTL8367C_VLAN_EGRESS_TRANS_CTRL5_MASK 0x7FF ++ ++#define RTL8367C_REG_VLAN_EGRESS_TRANS_CTRL6 0x09D6 ++#define RTL8367C_VLAN_EGRESS_TRANS_CTRL6_OFFSET 0 ++#define RTL8367C_VLAN_EGRESS_TRANS_CTRL6_MASK 0x7FF ++ ++#define RTL8367C_REG_VLAN_EGRESS_TRANS_CTRL7 0x09D7 ++#define RTL8367C_VLAN_EGRESS_TRANS_CTRL7_OFFSET 0 ++#define RTL8367C_VLAN_EGRESS_TRANS_CTRL7_MASK 0x7FF ++ ++#define RTL8367C_REG_VLAN_EGRESS_TRANS_CTRL8 0x09D8 ++#define RTL8367C_VLAN_EGRESS_TRANS_CTRL8_OFFSET 0 ++#define RTL8367C_VLAN_EGRESS_TRANS_CTRL8_MASK 0x7FF ++ ++#define RTL8367C_REG_VLAN_EGRESS_TRANS_CTRL9 0x09D9 ++#define RTL8367C_VLAN_EGRESS_TRANS_CTRL9_OFFSET 0 ++#define RTL8367C_VLAN_EGRESS_TRANS_CTRL9_MASK 0x7FF ++ ++#define RTL8367C_REG_MIRROR_CTRL2 0x09DA ++#define RTL8367C_MIRROR_REALKEEP_EN_OFFSET 4 ++#define RTL8367C_MIRROR_REALKEEP_EN_MASK 0x10 ++#define RTL8367C_MIRROR_RX_ISOLATION_LEAKY_OFFSET 3 ++#define RTL8367C_MIRROR_RX_ISOLATION_LEAKY_MASK 0x8 ++#define RTL8367C_MIRROR_TX_ISOLATION_LEAKY_OFFSET 2 ++#define RTL8367C_MIRROR_TX_ISOLATION_LEAKY_MASK 0x4 ++#define RTL8367C_MIRROR_RX_VLAN_LEAKY_OFFSET 1 ++#define RTL8367C_MIRROR_RX_VLAN_LEAKY_MASK 0x2 ++#define RTL8367C_MIRROR_TX_VLAN_LEAKY_OFFSET 0 ++#define RTL8367C_MIRROR_TX_VLAN_LEAKY_MASK 0x1 ++ ++#define RTL8367C_REG_OUTPUT_DROP_CFG 0x09DB ++#define RTL8367C_ENABLE_PMASK_EXT_OFFSET 13 ++#define RTL8367C_ENABLE_PMASK_EXT_MASK 0xE000 ++#define RTL8367C_ENABLE_BC_OFFSET 12 ++#define RTL8367C_ENABLE_BC_MASK 0x1000 ++#define RTL8367C_ENABLE_MC_OFFSET 11 ++#define RTL8367C_ENABLE_MC_MASK 0x800 ++#define RTL8367C_ENABLE_UC_OFFSET 10 ++#define RTL8367C_ENABLE_UC_MASK 0x400 ++#define RTL8367C_ENABLE_PMASK_OFFSET 0 ++#define RTL8367C_ENABLE_PMASK_MASK 0xFF ++ ++#define RTL8367C_REG_UNKNOWN_UNICAST_DA_PORT_BEHAVE_EXT 0x09DC ++#define RTL8367C_PORT10_ACTION_OFFSET 4 ++#define RTL8367C_PORT10_ACTION_MASK 0x30 ++#define RTL8367C_PORT9_ACTION_OFFSET 2 ++#define RTL8367C_PORT9_ACTION_MASK 0xC ++#define RTL8367C_PORT8_ACTION_OFFSET 0 ++#define RTL8367C_PORT8_ACTION_MASK 0x3 ++ ++#define RTL8367C_REG_RMK_CFG_SEL_CTRL 0x09DF ++#define RTL8367C_RMK_1Q_CFG_SEL_OFFSET 2 ++#define RTL8367C_RMK_1Q_CFG_SEL_MASK 0x4 ++#define RTL8367C_RMK_DSCP_CFG_SEL_OFFSET 0 ++#define RTL8367C_RMK_DSCP_CFG_SEL_MASK 0x3 ++ ++#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL0 0x09E0 ++#define RTL8367C_DSCP1_DSCP_OFFSET 8 ++#define RTL8367C_DSCP1_DSCP_MASK 0x3F00 ++#define RTL8367C_DSCP0_DSCP_OFFSET 0 ++#define RTL8367C_DSCP0_DSCP_MASK 0x3F ++ ++#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL1 0x09E1 ++#define RTL8367C_DSCP3_DSCP_OFFSET 8 ++#define RTL8367C_DSCP3_DSCP_MASK 0x3F00 ++#define RTL8367C_DSCP2_DSCP_OFFSET 0 ++#define RTL8367C_DSCP2_DSCP_MASK 0x3F ++ ++#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL2 0x09E2 ++#define RTL8367C_DSCP5_DSCP_OFFSET 8 ++#define RTL8367C_DSCP5_DSCP_MASK 0x3F00 ++#define RTL8367C_DSCP4_DSCP_OFFSET 0 ++#define RTL8367C_DSCP4_DSCP_MASK 0x3F ++ ++#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL3 0x09E3 ++#define RTL8367C_DSCP7_DSCP_OFFSET 8 ++#define RTL8367C_DSCP7_DSCP_MASK 0x3F00 ++#define RTL8367C_DSCP6_DSCP_OFFSET 0 ++#define RTL8367C_DSCP6_DSCP_MASK 0x3F ++ ++#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL4 0x09E4 ++#define RTL8367C_DSCP9_DSCP_OFFSET 8 ++#define RTL8367C_DSCP9_DSCP_MASK 0x3F00 ++#define RTL8367C_DSCP8_DSCP_OFFSET 0 ++#define RTL8367C_DSCP8_DSCP_MASK 0x3F ++ ++#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL5 0x09E5 ++#define RTL8367C_DSCP11_DSCP_OFFSET 8 ++#define RTL8367C_DSCP11_DSCP_MASK 0x3F00 ++#define RTL8367C_DSCP10_DSCP_OFFSET 0 ++#define RTL8367C_DSCP10_DSCP_MASK 0x3F ++ ++#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL6 0x09E6 ++#define RTL8367C_DSCP13_DSCP_OFFSET 8 ++#define RTL8367C_DSCP13_DSCP_MASK 0x3F00 ++#define RTL8367C_DSCP12_DSCP_OFFSET 0 ++#define RTL8367C_DSCP12_DSCP_MASK 0x3F ++ ++#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL7 0x09E7 ++#define RTL8367C_DSCP15_DSCP_OFFSET 8 ++#define RTL8367C_DSCP15_DSCP_MASK 0x3F00 ++#define RTL8367C_DSCP14_DSCP_OFFSET 0 ++#define RTL8367C_DSCP14_DSCP_MASK 0x3F ++ ++#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL8 0x09E8 ++#define RTL8367C_DSCP17_DSCP_OFFSET 8 ++#define RTL8367C_DSCP17_DSCP_MASK 0x3F00 ++#define RTL8367C_DSCP16_DSCP_OFFSET 0 ++#define RTL8367C_DSCP16_DSCP_MASK 0x3F ++ ++#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL9 0x09E9 ++#define RTL8367C_DSCP19_DSCP_OFFSET 8 ++#define RTL8367C_DSCP19_DSCP_MASK 0x3F00 ++#define RTL8367C_DSCP18_DSCP_OFFSET 0 ++#define RTL8367C_DSCP18_DSCP_MASK 0x3F ++ ++#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL10 0x09EA ++#define RTL8367C_DSCP21_DSCP_OFFSET 8 ++#define RTL8367C_DSCP21_DSCP_MASK 0x3F00 ++#define RTL8367C_DSCP20_DSCP_OFFSET 0 ++#define RTL8367C_DSCP20_DSCP_MASK 0x3F ++ ++#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL11 0x09EB ++#define RTL8367C_DSCP23_DSCP_OFFSET 8 ++#define RTL8367C_DSCP23_DSCP_MASK 0x3F00 ++#define RTL8367C_DSCP22_DSCP_OFFSET 0 ++#define RTL8367C_DSCP22_DSCP_MASK 0x3F ++ ++#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL12 0x09EC ++#define RTL8367C_DSCP25_DSCP_OFFSET 8 ++#define RTL8367C_DSCP25_DSCP_MASK 0x3F00 ++#define RTL8367C_DSCP24_DSCP_OFFSET 0 ++#define RTL8367C_DSCP24_DSCP_MASK 0x3F ++ ++#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL13 0x09ED ++#define RTL8367C_DSCP27_DSCP_OFFSET 8 ++#define RTL8367C_DSCP27_DSCP_MASK 0x3F00 ++#define RTL8367C_DSCP26_DSCP_OFFSET 0 ++#define RTL8367C_DSCP26_DSCP_MASK 0x3F ++ ++#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL14 0x09EE ++#define RTL8367C_DSCP29_DSCP_OFFSET 8 ++#define RTL8367C_DSCP29_DSCP_MASK 0x3F00 ++#define RTL8367C_DSCP28_DSCP_OFFSET 0 ++#define RTL8367C_DSCP28_DSCP_MASK 0x3F ++ ++#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL15 0x09EF ++#define RTL8367C_DSCP31_DSCP_OFFSET 8 ++#define RTL8367C_DSCP31_DSCP_MASK 0x3F00 ++#define RTL8367C_DSCP30_DSCP_OFFSET 0 ++#define RTL8367C_DSCP30_DSCP_MASK 0x3F ++ ++#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL16 0x09F0 ++#define RTL8367C_DSCP33_DSCP_OFFSET 8 ++#define RTL8367C_DSCP33_DSCP_MASK 0x3F00 ++#define RTL8367C_DSCP32_DSCP_OFFSET 0 ++#define RTL8367C_DSCP32_DSCP_MASK 0x3F ++ ++#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL17 0x09F1 ++#define RTL8367C_DSCP35_DSCP_OFFSET 8 ++#define RTL8367C_DSCP35_DSCP_MASK 0x3F00 ++#define RTL8367C_DSCP34_DSCP_OFFSET 0 ++#define RTL8367C_DSCP34_DSCP_MASK 0x3F ++ ++#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL18 0x09F2 ++#define RTL8367C_DSCP37_DSCP_OFFSET 8 ++#define RTL8367C_DSCP37_DSCP_MASK 0x3F00 ++#define RTL8367C_DSCP36_DSCP_OFFSET 0 ++#define RTL8367C_DSCP36_DSCP_MASK 0x3F ++ ++#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL19 0x09F3 ++#define RTL8367C_DSCP39_DSCP_OFFSET 8 ++#define RTL8367C_DSCP39_DSCP_MASK 0x3F00 ++#define RTL8367C_DSCP38_DSCP_OFFSET 0 ++#define RTL8367C_DSCP38_DSCP_MASK 0x3F ++ ++#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL20 0x09F4 ++#define RTL8367C_DSCP41_DSCP_OFFSET 8 ++#define RTL8367C_DSCP41_DSCP_MASK 0x3F00 ++#define RTL8367C_DSCP40_DSCP_OFFSET 0 ++#define RTL8367C_DSCP40_DSCP_MASK 0x3F ++ ++#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL21 0x09F5 ++#define RTL8367C_DSCP43_DSCP_OFFSET 8 ++#define RTL8367C_DSCP43_DSCP_MASK 0x3F00 ++#define RTL8367C_DSCP42_DSCP_OFFSET 0 ++#define RTL8367C_DSCP42_DSCP_MASK 0x3F ++ ++#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL22 0x09F6 ++#define RTL8367C_DSCP45_DSCP_OFFSET 8 ++#define RTL8367C_DSCP45_DSCP_MASK 0x3F00 ++#define RTL8367C_DSCP44_DSCP_OFFSET 0 ++#define RTL8367C_DSCP44_DSCP_MASK 0x3F ++ ++#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL23 0x09F7 ++#define RTL8367C_DSCP47_DSCP_OFFSET 8 ++#define RTL8367C_DSCP47_DSCP_MASK 0x3F00 ++#define RTL8367C_DSCP46_DSCP_OFFSET 0 ++#define RTL8367C_DSCP46_DSCP_MASK 0x3F ++ ++#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL24 0x09F8 ++#define RTL8367C_DSCP49_DSCP_OFFSET 8 ++#define RTL8367C_DSCP49_DSCP_MASK 0x3F00 ++#define RTL8367C_DSCP48_DSCP_OFFSET 0 ++#define RTL8367C_DSCP48_DSCP_MASK 0x3F ++ ++#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL25 0x09F9 ++#define RTL8367C_DSCP51_DSCP_OFFSET 8 ++#define RTL8367C_DSCP51_DSCP_MASK 0x3F00 ++#define RTL8367C_DSCP50_DSCP_OFFSET 0 ++#define RTL8367C_DSCP50_DSCP_MASK 0x3F ++ ++#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL26 0x09FA ++#define RTL8367C_DSCP53_DSCP_OFFSET 8 ++#define RTL8367C_DSCP53_DSCP_MASK 0x3F00 ++#define RTL8367C_DSCP52_DSCP_OFFSET 0 ++#define RTL8367C_DSCP52_DSCP_MASK 0x3F ++ ++#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL27 0x09FB ++#define RTL8367C_DSCP55_DSCP_OFFSET 8 ++#define RTL8367C_DSCP55_DSCP_MASK 0x3F00 ++#define RTL8367C_DSCP54_DSCP_OFFSET 0 ++#define RTL8367C_DSCP54_DSCP_MASK 0x3F ++ ++#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL28 0x09FC ++#define RTL8367C_DSCP57_DSCP_OFFSET 8 ++#define RTL8367C_DSCP57_DSCP_MASK 0x3F00 ++#define RTL8367C_DSCP56_DSCP_OFFSET 0 ++#define RTL8367C_DSCP56_DSCP_MASK 0x3F ++ ++#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL29 0x09FD ++#define RTL8367C_DSCP59_DSCP_OFFSET 8 ++#define RTL8367C_DSCP59_DSCP_MASK 0x3F00 ++#define RTL8367C_DSCP58_DSCP_OFFSET 0 ++#define RTL8367C_DSCP58_DSCP_MASK 0x3F ++ ++#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL30 0x09FE ++#define RTL8367C_DSCP61_DSCP_OFFSET 8 ++#define RTL8367C_DSCP61_DSCP_MASK 0x3F00 ++#define RTL8367C_DSCP60_DSCP_OFFSET 0 ++#define RTL8367C_DSCP60_DSCP_MASK 0x3F ++ ++#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL31 0x09FF ++#define RTL8367C_DSCP63_DSCP_OFFSET 8 ++#define RTL8367C_DSCP63_DSCP_MASK 0x3F00 ++#define RTL8367C_DSCP62_DSCP_OFFSET 0 ++#define RTL8367C_DSCP62_DSCP_MASK 0x3F ++ ++/* (16'h0a00)l2_reg */ ++ ++#define RTL8367C_REG_VLAN_MSTI0_CTRL0 0x0a00 ++#define RTL8367C_VLAN_MSTI0_CTRL0_PORT7_STATE_OFFSET 14 ++#define RTL8367C_VLAN_MSTI0_CTRL0_PORT7_STATE_MASK 0xC000 ++#define RTL8367C_VLAN_MSTI0_CTRL0_PORT6_STATE_OFFSET 12 ++#define RTL8367C_VLAN_MSTI0_CTRL0_PORT6_STATE_MASK 0x3000 ++#define RTL8367C_VLAN_MSTI0_CTRL0_PORT5_STATE_OFFSET 10 ++#define RTL8367C_VLAN_MSTI0_CTRL0_PORT5_STATE_MASK 0xC00 ++#define RTL8367C_VLAN_MSTI0_CTRL0_PORT4_STATE_OFFSET 8 ++#define RTL8367C_VLAN_MSTI0_CTRL0_PORT4_STATE_MASK 0x300 ++#define RTL8367C_VLAN_MSTI0_CTRL0_PORT3_STATE_OFFSET 6 ++#define RTL8367C_VLAN_MSTI0_CTRL0_PORT3_STATE_MASK 0xC0 ++#define RTL8367C_VLAN_MSTI0_CTRL0_PORT2_STATE_OFFSET 4 ++#define RTL8367C_VLAN_MSTI0_CTRL0_PORT2_STATE_MASK 0x30 ++#define RTL8367C_VLAN_MSTI0_CTRL0_PORT1_STATE_OFFSET 2 ++#define RTL8367C_VLAN_MSTI0_CTRL0_PORT1_STATE_MASK 0xC ++#define RTL8367C_VLAN_MSTI0_CTRL0_PORT0_STATE_OFFSET 0 ++#define RTL8367C_VLAN_MSTI0_CTRL0_PORT0_STATE_MASK 0x3 ++ ++#define RTL8367C_REG_VLAN_MSTI0_CTRL1 0x0a01 ++#define RTL8367C_VLAN_MSTI0_CTRL1_PORT10_STATE_OFFSET 4 ++#define RTL8367C_VLAN_MSTI0_CTRL1_PORT10_STATE_MASK 0x30 ++#define RTL8367C_VLAN_MSTI0_CTRL1_PORT9_STATE_OFFSET 2 ++#define RTL8367C_VLAN_MSTI0_CTRL1_PORT9_STATE_MASK 0xC ++#define RTL8367C_VLAN_MSTI0_CTRL1_PORT8_STATE_OFFSET 0 ++#define RTL8367C_VLAN_MSTI0_CTRL1_PORT8_STATE_MASK 0x3 ++ ++#define RTL8367C_REG_VLAN_MSTI1_CTRL0 0x0a02 ++#define RTL8367C_VLAN_MSTI1_CTRL0_PORT7_STATE_OFFSET 14 ++#define RTL8367C_VLAN_MSTI1_CTRL0_PORT7_STATE_MASK 0xC000 ++#define RTL8367C_VLAN_MSTI1_CTRL0_PORT6_STATE_OFFSET 12 ++#define RTL8367C_VLAN_MSTI1_CTRL0_PORT6_STATE_MASK 0x3000 ++#define RTL8367C_VLAN_MSTI1_CTRL0_PORT5_STATE_OFFSET 10 ++#define RTL8367C_VLAN_MSTI1_CTRL0_PORT5_STATE_MASK 0xC00 ++#define RTL8367C_VLAN_MSTI1_CTRL0_PORT4_STATE_OFFSET 8 ++#define RTL8367C_VLAN_MSTI1_CTRL0_PORT4_STATE_MASK 0x300 ++#define RTL8367C_VLAN_MSTI1_CTRL0_PORT3_STATE_OFFSET 6 ++#define RTL8367C_VLAN_MSTI1_CTRL0_PORT3_STATE_MASK 0xC0 ++#define RTL8367C_VLAN_MSTI1_CTRL0_PORT2_STATE_OFFSET 4 ++#define RTL8367C_VLAN_MSTI1_CTRL0_PORT2_STATE_MASK 0x30 ++#define RTL8367C_VLAN_MSTI1_CTRL0_PORT1_STATE_OFFSET 2 ++#define RTL8367C_VLAN_MSTI1_CTRL0_PORT1_STATE_MASK 0xC ++#define RTL8367C_VLAN_MSTI1_CTRL0_PORT0_STATE_OFFSET 0 ++#define RTL8367C_VLAN_MSTI1_CTRL0_PORT0_STATE_MASK 0x3 ++ ++#define RTL8367C_REG_VLAN_MSTI1_CTRL1 0x0a03 ++#define RTL8367C_VLAN_MSTI1_CTRL1_PORT10_STATE_OFFSET 4 ++#define RTL8367C_VLAN_MSTI1_CTRL1_PORT10_STATE_MASK 0x30 ++#define RTL8367C_VLAN_MSTI1_CTRL1_PORT9_STATE_OFFSET 2 ++#define RTL8367C_VLAN_MSTI1_CTRL1_PORT9_STATE_MASK 0xC ++#define RTL8367C_VLAN_MSTI1_CTRL1_PORT8_STATE_OFFSET 0 ++#define RTL8367C_VLAN_MSTI1_CTRL1_PORT8_STATE_MASK 0x3 ++ ++#define RTL8367C_REG_VLAN_MSTI2_CTRL0 0x0a04 ++#define RTL8367C_VLAN_MSTI2_CTRL0_PORT7_STATE_OFFSET 14 ++#define RTL8367C_VLAN_MSTI2_CTRL0_PORT7_STATE_MASK 0xC000 ++#define RTL8367C_VLAN_MSTI2_CTRL0_PORT6_STATE_OFFSET 12 ++#define RTL8367C_VLAN_MSTI2_CTRL0_PORT6_STATE_MASK 0x3000 ++#define RTL8367C_VLAN_MSTI2_CTRL0_PORT5_STATE_OFFSET 10 ++#define RTL8367C_VLAN_MSTI2_CTRL0_PORT5_STATE_MASK 0xC00 ++#define RTL8367C_VLAN_MSTI2_CTRL0_PORT4_STATE_OFFSET 8 ++#define RTL8367C_VLAN_MSTI2_CTRL0_PORT4_STATE_MASK 0x300 ++#define RTL8367C_VLAN_MSTI2_CTRL0_PORT3_STATE_OFFSET 6 ++#define RTL8367C_VLAN_MSTI2_CTRL0_PORT3_STATE_MASK 0xC0 ++#define RTL8367C_VLAN_MSTI2_CTRL0_PORT2_STATE_OFFSET 4 ++#define RTL8367C_VLAN_MSTI2_CTRL0_PORT2_STATE_MASK 0x30 ++#define RTL8367C_VLAN_MSTI2_CTRL0_PORT1_STATE_OFFSET 2 ++#define RTL8367C_VLAN_MSTI2_CTRL0_PORT1_STATE_MASK 0xC ++#define RTL8367C_VLAN_MSTI2_CTRL0_PORT0_STATE_OFFSET 0 ++#define RTL8367C_VLAN_MSTI2_CTRL0_PORT0_STATE_MASK 0x3 ++ ++#define RTL8367C_REG_VLAN_MSTI2_CTRL1 0x0a05 ++#define RTL8367C_VLAN_MSTI2_CTRL1_PORT10_STATE_OFFSET 4 ++#define RTL8367C_VLAN_MSTI2_CTRL1_PORT10_STATE_MASK 0x30 ++#define RTL8367C_VLAN_MSTI2_CTRL1_PORT9_STATE_OFFSET 2 ++#define RTL8367C_VLAN_MSTI2_CTRL1_PORT9_STATE_MASK 0xC ++#define RTL8367C_VLAN_MSTI2_CTRL1_PORT8_STATE_OFFSET 0 ++#define RTL8367C_VLAN_MSTI2_CTRL1_PORT8_STATE_MASK 0x3 ++ ++#define RTL8367C_REG_VLAN_MSTI3_CTRL0 0x0a06 ++#define RTL8367C_VLAN_MSTI3_CTRL0_PORT7_STATE_OFFSET 14 ++#define RTL8367C_VLAN_MSTI3_CTRL0_PORT7_STATE_MASK 0xC000 ++#define RTL8367C_VLAN_MSTI3_CTRL0_PORT6_STATE_OFFSET 12 ++#define RTL8367C_VLAN_MSTI3_CTRL0_PORT6_STATE_MASK 0x3000 ++#define RTL8367C_VLAN_MSTI3_CTRL0_PORT5_STATE_OFFSET 10 ++#define RTL8367C_VLAN_MSTI3_CTRL0_PORT5_STATE_MASK 0xC00 ++#define RTL8367C_VLAN_MSTI3_CTRL0_PORT4_STATE_OFFSET 8 ++#define RTL8367C_VLAN_MSTI3_CTRL0_PORT4_STATE_MASK 0x300 ++#define RTL8367C_VLAN_MSTI3_CTRL0_PORT3_STATE_OFFSET 6 ++#define RTL8367C_VLAN_MSTI3_CTRL0_PORT3_STATE_MASK 0xC0 ++#define RTL8367C_VLAN_MSTI3_CTRL0_PORT2_STATE_OFFSET 4 ++#define RTL8367C_VLAN_MSTI3_CTRL0_PORT2_STATE_MASK 0x30 ++#define RTL8367C_VLAN_MSTI3_CTRL0_PORT1_STATE_OFFSET 2 ++#define RTL8367C_VLAN_MSTI3_CTRL0_PORT1_STATE_MASK 0xC ++#define RTL8367C_VLAN_MSTI3_CTRL0_PORT0_STATE_OFFSET 0 ++#define RTL8367C_VLAN_MSTI3_CTRL0_PORT0_STATE_MASK 0x3 ++ ++#define RTL8367C_REG_VLAN_MSTI3_CTRL1 0x0a07 ++#define RTL8367C_VLAN_MSTI3_CTRL1_PORT10_STATE_OFFSET 4 ++#define RTL8367C_VLAN_MSTI3_CTRL1_PORT10_STATE_MASK 0x30 ++#define RTL8367C_VLAN_MSTI3_CTRL1_PORT9_STATE_OFFSET 2 ++#define RTL8367C_VLAN_MSTI3_CTRL1_PORT9_STATE_MASK 0xC ++#define RTL8367C_VLAN_MSTI3_CTRL1_PORT8_STATE_OFFSET 0 ++#define RTL8367C_VLAN_MSTI3_CTRL1_PORT8_STATE_MASK 0x3 ++ ++#define RTL8367C_REG_VLAN_MSTI4_CTRL0 0x0a08 ++#define RTL8367C_VLAN_MSTI4_CTRL0_PORT7_STATE_OFFSET 14 ++#define RTL8367C_VLAN_MSTI4_CTRL0_PORT7_STATE_MASK 0xC000 ++#define RTL8367C_VLAN_MSTI4_CTRL0_PORT6_STATE_OFFSET 12 ++#define RTL8367C_VLAN_MSTI4_CTRL0_PORT6_STATE_MASK 0x3000 ++#define RTL8367C_VLAN_MSTI4_CTRL0_PORT5_STATE_OFFSET 10 ++#define RTL8367C_VLAN_MSTI4_CTRL0_PORT5_STATE_MASK 0xC00 ++#define RTL8367C_VLAN_MSTI4_CTRL0_PORT4_STATE_OFFSET 8 ++#define RTL8367C_VLAN_MSTI4_CTRL0_PORT4_STATE_MASK 0x300 ++#define RTL8367C_VLAN_MSTI4_CTRL0_PORT3_STATE_OFFSET 6 ++#define RTL8367C_VLAN_MSTI4_CTRL0_PORT3_STATE_MASK 0xC0 ++#define RTL8367C_VLAN_MSTI4_CTRL0_PORT2_STATE_OFFSET 4 ++#define RTL8367C_VLAN_MSTI4_CTRL0_PORT2_STATE_MASK 0x30 ++#define RTL8367C_VLAN_MSTI4_CTRL0_PORT1_STATE_OFFSET 2 ++#define RTL8367C_VLAN_MSTI4_CTRL0_PORT1_STATE_MASK 0xC ++#define RTL8367C_VLAN_MSTI4_CTRL0_PORT0_STATE_OFFSET 0 ++#define RTL8367C_VLAN_MSTI4_CTRL0_PORT0_STATE_MASK 0x3 ++ ++#define RTL8367C_REG_VLAN_MSTI4_CTRL1 0x0a09 ++#define RTL8367C_VLAN_MSTI4_CTRL1_PORT10_STATE_OFFSET 4 ++#define RTL8367C_VLAN_MSTI4_CTRL1_PORT10_STATE_MASK 0x30 ++#define RTL8367C_VLAN_MSTI4_CTRL1_PORT9_STATE_OFFSET 2 ++#define RTL8367C_VLAN_MSTI4_CTRL1_PORT9_STATE_MASK 0xC ++#define RTL8367C_VLAN_MSTI4_CTRL1_PORT8_STATE_OFFSET 0 ++#define RTL8367C_VLAN_MSTI4_CTRL1_PORT8_STATE_MASK 0x3 ++ ++#define RTL8367C_REG_VLAN_MSTI5_CTRL0 0x0a0a ++#define RTL8367C_VLAN_MSTI5_CTRL0_PORT7_STATE_OFFSET 14 ++#define RTL8367C_VLAN_MSTI5_CTRL0_PORT7_STATE_MASK 0xC000 ++#define RTL8367C_VLAN_MSTI5_CTRL0_PORT6_STATE_OFFSET 12 ++#define RTL8367C_VLAN_MSTI5_CTRL0_PORT6_STATE_MASK 0x3000 ++#define RTL8367C_VLAN_MSTI5_CTRL0_PORT5_STATE_OFFSET 10 ++#define RTL8367C_VLAN_MSTI5_CTRL0_PORT5_STATE_MASK 0xC00 ++#define RTL8367C_VLAN_MSTI5_CTRL0_PORT4_STATE_OFFSET 8 ++#define RTL8367C_VLAN_MSTI5_CTRL0_PORT4_STATE_MASK 0x300 ++#define RTL8367C_VLAN_MSTI5_CTRL0_PORT3_STATE_OFFSET 6 ++#define RTL8367C_VLAN_MSTI5_CTRL0_PORT3_STATE_MASK 0xC0 ++#define RTL8367C_VLAN_MSTI5_CTRL0_PORT2_STATE_OFFSET 4 ++#define RTL8367C_VLAN_MSTI5_CTRL0_PORT2_STATE_MASK 0x30 ++#define RTL8367C_VLAN_MSTI5_CTRL0_PORT1_STATE_OFFSET 2 ++#define RTL8367C_VLAN_MSTI5_CTRL0_PORT1_STATE_MASK 0xC ++#define RTL8367C_VLAN_MSTI5_CTRL0_PORT0_STATE_OFFSET 0 ++#define RTL8367C_VLAN_MSTI5_CTRL0_PORT0_STATE_MASK 0x3 ++ ++#define RTL8367C_REG_VLAN_MSTI5_CTRL1 0x0a0b ++#define RTL8367C_VLAN_MSTI5_CTRL1_PORT10_STATE_OFFSET 4 ++#define RTL8367C_VLAN_MSTI5_CTRL1_PORT10_STATE_MASK 0x30 ++#define RTL8367C_VLAN_MSTI5_CTRL1_PORT9_STATE_OFFSET 2 ++#define RTL8367C_VLAN_MSTI5_CTRL1_PORT9_STATE_MASK 0xC ++#define RTL8367C_VLAN_MSTI5_CTRL1_PORT8_STATE_OFFSET 0 ++#define RTL8367C_VLAN_MSTI5_CTRL1_PORT8_STATE_MASK 0x3 ++ ++#define RTL8367C_REG_VLAN_MSTI6_CTRL0 0x0a0c ++#define RTL8367C_VLAN_MSTI6_CTRL0_PORT7_STATE_OFFSET 14 ++#define RTL8367C_VLAN_MSTI6_CTRL0_PORT7_STATE_MASK 0xC000 ++#define RTL8367C_VLAN_MSTI6_CTRL0_PORT6_STATE_OFFSET 12 ++#define RTL8367C_VLAN_MSTI6_CTRL0_PORT6_STATE_MASK 0x3000 ++#define RTL8367C_VLAN_MSTI6_CTRL0_PORT5_STATE_OFFSET 10 ++#define RTL8367C_VLAN_MSTI6_CTRL0_PORT5_STATE_MASK 0xC00 ++#define RTL8367C_VLAN_MSTI6_CTRL0_PORT4_STATE_OFFSET 8 ++#define RTL8367C_VLAN_MSTI6_CTRL0_PORT4_STATE_MASK 0x300 ++#define RTL8367C_VLAN_MSTI6_CTRL0_PORT3_STATE_OFFSET 6 ++#define RTL8367C_VLAN_MSTI6_CTRL0_PORT3_STATE_MASK 0xC0 ++#define RTL8367C_VLAN_MSTI6_CTRL0_PORT2_STATE_OFFSET 4 ++#define RTL8367C_VLAN_MSTI6_CTRL0_PORT2_STATE_MASK 0x30 ++#define RTL8367C_VLAN_MSTI6_CTRL0_PORT1_STATE_OFFSET 2 ++#define RTL8367C_VLAN_MSTI6_CTRL0_PORT1_STATE_MASK 0xC ++#define RTL8367C_VLAN_MSTI6_CTRL0_PORT0_STATE_OFFSET 0 ++#define RTL8367C_VLAN_MSTI6_CTRL0_PORT0_STATE_MASK 0x3 ++ ++#define RTL8367C_REG_VLAN_MSTI6_CTRL1 0x0a0d ++#define RTL8367C_VLAN_MSTI6_CTRL1_PORT10_STATE_OFFSET 4 ++#define RTL8367C_VLAN_MSTI6_CTRL1_PORT10_STATE_MASK 0x30 ++#define RTL8367C_VLAN_MSTI6_CTRL1_PORT9_STATE_OFFSET 2 ++#define RTL8367C_VLAN_MSTI6_CTRL1_PORT9_STATE_MASK 0xC ++#define RTL8367C_VLAN_MSTI6_CTRL1_PORT8_STATE_OFFSET 0 ++#define RTL8367C_VLAN_MSTI6_CTRL1_PORT8_STATE_MASK 0x3 ++ ++#define RTL8367C_REG_VLAN_MSTI7_CTRL0 0x0a0e ++#define RTL8367C_VLAN_MSTI7_CTRL0_PORT7_STATE_OFFSET 14 ++#define RTL8367C_VLAN_MSTI7_CTRL0_PORT7_STATE_MASK 0xC000 ++#define RTL8367C_VLAN_MSTI7_CTRL0_PORT6_STATE_OFFSET 12 ++#define RTL8367C_VLAN_MSTI7_CTRL0_PORT6_STATE_MASK 0x3000 ++#define RTL8367C_VLAN_MSTI7_CTRL0_PORT5_STATE_OFFSET 10 ++#define RTL8367C_VLAN_MSTI7_CTRL0_PORT5_STATE_MASK 0xC00 ++#define RTL8367C_VLAN_MSTI7_CTRL0_PORT4_STATE_OFFSET 8 ++#define RTL8367C_VLAN_MSTI7_CTRL0_PORT4_STATE_MASK 0x300 ++#define RTL8367C_VLAN_MSTI7_CTRL0_PORT3_STATE_OFFSET 6 ++#define RTL8367C_VLAN_MSTI7_CTRL0_PORT3_STATE_MASK 0xC0 ++#define RTL8367C_VLAN_MSTI7_CTRL0_PORT2_STATE_OFFSET 4 ++#define RTL8367C_VLAN_MSTI7_CTRL0_PORT2_STATE_MASK 0x30 ++#define RTL8367C_VLAN_MSTI7_CTRL0_PORT1_STATE_OFFSET 2 ++#define RTL8367C_VLAN_MSTI7_CTRL0_PORT1_STATE_MASK 0xC ++#define RTL8367C_VLAN_MSTI7_CTRL0_PORT0_STATE_OFFSET 0 ++#define RTL8367C_VLAN_MSTI7_CTRL0_PORT0_STATE_MASK 0x3 ++ ++#define RTL8367C_REG_VLAN_MSTI7_CTRL1 0x0a0f ++#define RTL8367C_VLAN_MSTI7_CTRL1_PORT10_STATE_OFFSET 4 ++#define RTL8367C_VLAN_MSTI7_CTRL1_PORT10_STATE_MASK 0x30 ++#define RTL8367C_VLAN_MSTI7_CTRL1_PORT9_STATE_OFFSET 2 ++#define RTL8367C_VLAN_MSTI7_CTRL1_PORT9_STATE_MASK 0xC ++#define RTL8367C_VLAN_MSTI7_CTRL1_PORT8_STATE_OFFSET 0 ++#define RTL8367C_VLAN_MSTI7_CTRL1_PORT8_STATE_MASK 0x3 ++ ++#define RTL8367C_REG_VLAN_MSTI8_CTRL0 0x0a10 ++#define RTL8367C_VLAN_MSTI8_CTRL0_PORT7_STATE_OFFSET 14 ++#define RTL8367C_VLAN_MSTI8_CTRL0_PORT7_STATE_MASK 0xC000 ++#define RTL8367C_VLAN_MSTI8_CTRL0_PORT6_STATE_OFFSET 12 ++#define RTL8367C_VLAN_MSTI8_CTRL0_PORT6_STATE_MASK 0x3000 ++#define RTL8367C_VLAN_MSTI8_CTRL0_PORT5_STATE_OFFSET 10 ++#define RTL8367C_VLAN_MSTI8_CTRL0_PORT5_STATE_MASK 0xC00 ++#define RTL8367C_VLAN_MSTI8_CTRL0_PORT4_STATE_OFFSET 8 ++#define RTL8367C_VLAN_MSTI8_CTRL0_PORT4_STATE_MASK 0x300 ++#define RTL8367C_VLAN_MSTI8_CTRL0_PORT3_STATE_OFFSET 6 ++#define RTL8367C_VLAN_MSTI8_CTRL0_PORT3_STATE_MASK 0xC0 ++#define RTL8367C_VLAN_MSTI8_CTRL0_PORT2_STATE_OFFSET 4 ++#define RTL8367C_VLAN_MSTI8_CTRL0_PORT2_STATE_MASK 0x30 ++#define RTL8367C_VLAN_MSTI8_CTRL0_PORT1_STATE_OFFSET 2 ++#define RTL8367C_VLAN_MSTI8_CTRL0_PORT1_STATE_MASK 0xC ++#define RTL8367C_VLAN_MSTI8_CTRL0_PORT0_STATE_OFFSET 0 ++#define RTL8367C_VLAN_MSTI8_CTRL0_PORT0_STATE_MASK 0x3 ++ ++#define RTL8367C_REG_VLAN_MSTI8_CTRL1 0x0a11 ++#define RTL8367C_VLAN_MSTI8_CTRL1_PORT10_STATE_OFFSET 4 ++#define RTL8367C_VLAN_MSTI8_CTRL1_PORT10_STATE_MASK 0x30 ++#define RTL8367C_VLAN_MSTI8_CTRL1_PORT9_STATE_OFFSET 2 ++#define RTL8367C_VLAN_MSTI8_CTRL1_PORT9_STATE_MASK 0xC ++#define RTL8367C_VLAN_MSTI8_CTRL1_PORT8_STATE_OFFSET 0 ++#define RTL8367C_VLAN_MSTI8_CTRL1_PORT8_STATE_MASK 0x3 ++ ++#define RTL8367C_REG_VLAN_MSTI9_CTRL0 0x0a12 ++#define RTL8367C_VLAN_MSTI9_CTRL0_PORT7_STATE_OFFSET 14 ++#define RTL8367C_VLAN_MSTI9_CTRL0_PORT7_STATE_MASK 0xC000 ++#define RTL8367C_VLAN_MSTI9_CTRL0_PORT6_STATE_OFFSET 12 ++#define RTL8367C_VLAN_MSTI9_CTRL0_PORT6_STATE_MASK 0x3000 ++#define RTL8367C_VLAN_MSTI9_CTRL0_PORT5_STATE_OFFSET 10 ++#define RTL8367C_VLAN_MSTI9_CTRL0_PORT5_STATE_MASK 0xC00 ++#define RTL8367C_VLAN_MSTI9_CTRL0_PORT4_STATE_OFFSET 8 ++#define RTL8367C_VLAN_MSTI9_CTRL0_PORT4_STATE_MASK 0x300 ++#define RTL8367C_VLAN_MSTI9_CTRL0_PORT3_STATE_OFFSET 6 ++#define RTL8367C_VLAN_MSTI9_CTRL0_PORT3_STATE_MASK 0xC0 ++#define RTL8367C_VLAN_MSTI9_CTRL0_PORT2_STATE_OFFSET 4 ++#define RTL8367C_VLAN_MSTI9_CTRL0_PORT2_STATE_MASK 0x30 ++#define RTL8367C_VLAN_MSTI9_CTRL0_PORT1_STATE_OFFSET 2 ++#define RTL8367C_VLAN_MSTI9_CTRL0_PORT1_STATE_MASK 0xC ++#define RTL8367C_VLAN_MSTI9_CTRL0_PORT0_STATE_OFFSET 0 ++#define RTL8367C_VLAN_MSTI9_CTRL0_PORT0_STATE_MASK 0x3 ++ ++#define RTL8367C_REG_VLAN_MSTI9_CTRL1 0x0a13 ++#define RTL8367C_VLAN_MSTI9_CTRL1_PORT10_STATE_OFFSET 4 ++#define RTL8367C_VLAN_MSTI9_CTRL1_PORT10_STATE_MASK 0x30 ++#define RTL8367C_VLAN_MSTI9_CTRL1_PORT9_STATE_OFFSET 2 ++#define RTL8367C_VLAN_MSTI9_CTRL1_PORT9_STATE_MASK 0xC ++#define RTL8367C_VLAN_MSTI9_CTRL1_PORT8_STATE_OFFSET 0 ++#define RTL8367C_VLAN_MSTI9_CTRL1_PORT8_STATE_MASK 0x3 ++ ++#define RTL8367C_REG_VLAN_MSTI10_CTRL0 0x0a14 ++#define RTL8367C_VLAN_MSTI10_CTRL0_PORT7_STATE_OFFSET 14 ++#define RTL8367C_VLAN_MSTI10_CTRL0_PORT7_STATE_MASK 0xC000 ++#define RTL8367C_VLAN_MSTI10_CTRL0_PORT6_STATE_OFFSET 12 ++#define RTL8367C_VLAN_MSTI10_CTRL0_PORT6_STATE_MASK 0x3000 ++#define RTL8367C_VLAN_MSTI10_CTRL0_PORT5_STATE_OFFSET 10 ++#define RTL8367C_VLAN_MSTI10_CTRL0_PORT5_STATE_MASK 0xC00 ++#define RTL8367C_VLAN_MSTI10_CTRL0_PORT4_STATE_OFFSET 8 ++#define RTL8367C_VLAN_MSTI10_CTRL0_PORT4_STATE_MASK 0x300 ++#define RTL8367C_VLAN_MSTI10_CTRL0_PORT3_STATE_OFFSET 6 ++#define RTL8367C_VLAN_MSTI10_CTRL0_PORT3_STATE_MASK 0xC0 ++#define RTL8367C_VLAN_MSTI10_CTRL0_PORT2_STATE_OFFSET 4 ++#define RTL8367C_VLAN_MSTI10_CTRL0_PORT2_STATE_MASK 0x30 ++#define RTL8367C_VLAN_MSTI10_CTRL0_PORT1_STATE_OFFSET 2 ++#define RTL8367C_VLAN_MSTI10_CTRL0_PORT1_STATE_MASK 0xC ++#define RTL8367C_VLAN_MSTI10_CTRL0_PORT0_STATE_OFFSET 0 ++#define RTL8367C_VLAN_MSTI10_CTRL0_PORT0_STATE_MASK 0x3 ++ ++#define RTL8367C_REG_VLAN_MSTI10_CTRL1 0x0a15 ++#define RTL8367C_VLAN_MSTI10_CTRL1_PORT10_STATE_OFFSET 4 ++#define RTL8367C_VLAN_MSTI10_CTRL1_PORT10_STATE_MASK 0x30 ++#define RTL8367C_VLAN_MSTI10_CTRL1_PORT9_STATE_OFFSET 2 ++#define RTL8367C_VLAN_MSTI10_CTRL1_PORT9_STATE_MASK 0xC ++#define RTL8367C_VLAN_MSTI10_CTRL1_PORT8_STATE_OFFSET 0 ++#define RTL8367C_VLAN_MSTI10_CTRL1_PORT8_STATE_MASK 0x3 ++ ++#define RTL8367C_REG_VLAN_MSTI11_CTRL0 0x0a16 ++#define RTL8367C_VLAN_MSTI11_CTRL0_PORT7_STATE_OFFSET 14 ++#define RTL8367C_VLAN_MSTI11_CTRL0_PORT7_STATE_MASK 0xC000 ++#define RTL8367C_VLAN_MSTI11_CTRL0_PORT6_STATE_OFFSET 12 ++#define RTL8367C_VLAN_MSTI11_CTRL0_PORT6_STATE_MASK 0x3000 ++#define RTL8367C_VLAN_MSTI11_CTRL0_PORT5_STATE_OFFSET 10 ++#define RTL8367C_VLAN_MSTI11_CTRL0_PORT5_STATE_MASK 0xC00 ++#define RTL8367C_VLAN_MSTI11_CTRL0_PORT4_STATE_OFFSET 8 ++#define RTL8367C_VLAN_MSTI11_CTRL0_PORT4_STATE_MASK 0x300 ++#define RTL8367C_VLAN_MSTI11_CTRL0_PORT3_STATE_OFFSET 6 ++#define RTL8367C_VLAN_MSTI11_CTRL0_PORT3_STATE_MASK 0xC0 ++#define RTL8367C_VLAN_MSTI11_CTRL0_PORT2_STATE_OFFSET 4 ++#define RTL8367C_VLAN_MSTI11_CTRL0_PORT2_STATE_MASK 0x30 ++#define RTL8367C_VLAN_MSTI11_CTRL0_PORT1_STATE_OFFSET 2 ++#define RTL8367C_VLAN_MSTI11_CTRL0_PORT1_STATE_MASK 0xC ++#define RTL8367C_VLAN_MSTI11_CTRL0_PORT0_STATE_OFFSET 0 ++#define RTL8367C_VLAN_MSTI11_CTRL0_PORT0_STATE_MASK 0x3 ++ ++#define RTL8367C_REG_VLAN_MSTI11_CTRL1 0x0a17 ++#define RTL8367C_VLAN_MSTI11_CTRL1_PORT10_STATE_OFFSET 4 ++#define RTL8367C_VLAN_MSTI11_CTRL1_PORT10_STATE_MASK 0x30 ++#define RTL8367C_VLAN_MSTI11_CTRL1_PORT9_STATE_OFFSET 2 ++#define RTL8367C_VLAN_MSTI11_CTRL1_PORT9_STATE_MASK 0xC ++#define RTL8367C_VLAN_MSTI11_CTRL1_PORT8_STATE_OFFSET 0 ++#define RTL8367C_VLAN_MSTI11_CTRL1_PORT8_STATE_MASK 0x3 ++ ++#define RTL8367C_REG_VLAN_MSTI12_CTRL0 0x0a18 ++#define RTL8367C_VLAN_MSTI12_CTRL0_PORT7_STATE_OFFSET 14 ++#define RTL8367C_VLAN_MSTI12_CTRL0_PORT7_STATE_MASK 0xC000 ++#define RTL8367C_VLAN_MSTI12_CTRL0_PORT6_STATE_OFFSET 12 ++#define RTL8367C_VLAN_MSTI12_CTRL0_PORT6_STATE_MASK 0x3000 ++#define RTL8367C_VLAN_MSTI12_CTRL0_PORT5_STATE_OFFSET 10 ++#define RTL8367C_VLAN_MSTI12_CTRL0_PORT5_STATE_MASK 0xC00 ++#define RTL8367C_VLAN_MSTI12_CTRL0_PORT4_STATE_OFFSET 8 ++#define RTL8367C_VLAN_MSTI12_CTRL0_PORT4_STATE_MASK 0x300 ++#define RTL8367C_VLAN_MSTI12_CTRL0_PORT3_STATE_OFFSET 6 ++#define RTL8367C_VLAN_MSTI12_CTRL0_PORT3_STATE_MASK 0xC0 ++#define RTL8367C_VLAN_MSTI12_CTRL0_PORT2_STATE_OFFSET 4 ++#define RTL8367C_VLAN_MSTI12_CTRL0_PORT2_STATE_MASK 0x30 ++#define RTL8367C_VLAN_MSTI12_CTRL0_PORT1_STATE_OFFSET 2 ++#define RTL8367C_VLAN_MSTI12_CTRL0_PORT1_STATE_MASK 0xC ++#define RTL8367C_VLAN_MSTI12_CTRL0_PORT0_STATE_OFFSET 0 ++#define RTL8367C_VLAN_MSTI12_CTRL0_PORT0_STATE_MASK 0x3 ++ ++#define RTL8367C_REG_VLAN_MSTI12_CTRL1 0x0a19 ++#define RTL8367C_VLAN_MSTI12_CTRL1_PORT10_STATE_OFFSET 4 ++#define RTL8367C_VLAN_MSTI12_CTRL1_PORT10_STATE_MASK 0x30 ++#define RTL8367C_VLAN_MSTI12_CTRL1_PORT9_STATE_OFFSET 2 ++#define RTL8367C_VLAN_MSTI12_CTRL1_PORT9_STATE_MASK 0xC ++#define RTL8367C_VLAN_MSTI12_CTRL1_PORT8_STATE_OFFSET 0 ++#define RTL8367C_VLAN_MSTI12_CTRL1_PORT8_STATE_MASK 0x3 ++ ++#define RTL8367C_REG_VLAN_MSTI13_CTRL0 0x0a1a ++#define RTL8367C_VLAN_MSTI13_CTRL0_PORT7_STATE_OFFSET 14 ++#define RTL8367C_VLAN_MSTI13_CTRL0_PORT7_STATE_MASK 0xC000 ++#define RTL8367C_VLAN_MSTI13_CTRL0_PORT6_STATE_OFFSET 12 ++#define RTL8367C_VLAN_MSTI13_CTRL0_PORT6_STATE_MASK 0x3000 ++#define RTL8367C_VLAN_MSTI13_CTRL0_PORT5_STATE_OFFSET 10 ++#define RTL8367C_VLAN_MSTI13_CTRL0_PORT5_STATE_MASK 0xC00 ++#define RTL8367C_VLAN_MSTI13_CTRL0_PORT4_STATE_OFFSET 8 ++#define RTL8367C_VLAN_MSTI13_CTRL0_PORT4_STATE_MASK 0x300 ++#define RTL8367C_VLAN_MSTI13_CTRL0_PORT3_STATE_OFFSET 6 ++#define RTL8367C_VLAN_MSTI13_CTRL0_PORT3_STATE_MASK 0xC0 ++#define RTL8367C_VLAN_MSTI13_CTRL0_PORT2_STATE_OFFSET 4 ++#define RTL8367C_VLAN_MSTI13_CTRL0_PORT2_STATE_MASK 0x30 ++#define RTL8367C_VLAN_MSTI13_CTRL0_PORT1_STATE_OFFSET 2 ++#define RTL8367C_VLAN_MSTI13_CTRL0_PORT1_STATE_MASK 0xC ++#define RTL8367C_VLAN_MSTI13_CTRL0_PORT0_STATE_OFFSET 0 ++#define RTL8367C_VLAN_MSTI13_CTRL0_PORT0_STATE_MASK 0x3 ++ ++#define RTL8367C_REG_VLAN_MSTI13_CTRL1 0x0a1b ++#define RTL8367C_VLAN_MSTI13_CTRL1_PORT10_STATE_OFFSET 4 ++#define RTL8367C_VLAN_MSTI13_CTRL1_PORT10_STATE_MASK 0x30 ++#define RTL8367C_VLAN_MSTI13_CTRL1_PORT9_STATE_OFFSET 2 ++#define RTL8367C_VLAN_MSTI13_CTRL1_PORT9_STATE_MASK 0xC ++#define RTL8367C_VLAN_MSTI13_CTRL1_PORT8_STATE_OFFSET 0 ++#define RTL8367C_VLAN_MSTI13_CTRL1_PORT8_STATE_MASK 0x3 ++ ++#define RTL8367C_REG_VLAN_MSTI14_CTRL0 0x0a1c ++#define RTL8367C_VLAN_MSTI14_CTRL0_PORT7_STATE_OFFSET 14 ++#define RTL8367C_VLAN_MSTI14_CTRL0_PORT7_STATE_MASK 0xC000 ++#define RTL8367C_VLAN_MSTI14_CTRL0_PORT6_STATE_OFFSET 12 ++#define RTL8367C_VLAN_MSTI14_CTRL0_PORT6_STATE_MASK 0x3000 ++#define RTL8367C_VLAN_MSTI14_CTRL0_PORT5_STATE_OFFSET 10 ++#define RTL8367C_VLAN_MSTI14_CTRL0_PORT5_STATE_MASK 0xC00 ++#define RTL8367C_VLAN_MSTI14_CTRL0_PORT4_STATE_OFFSET 8 ++#define RTL8367C_VLAN_MSTI14_CTRL0_PORT4_STATE_MASK 0x300 ++#define RTL8367C_VLAN_MSTI14_CTRL0_PORT3_STATE_OFFSET 6 ++#define RTL8367C_VLAN_MSTI14_CTRL0_PORT3_STATE_MASK 0xC0 ++#define RTL8367C_VLAN_MSTI14_CTRL0_PORT2_STATE_OFFSET 4 ++#define RTL8367C_VLAN_MSTI14_CTRL0_PORT2_STATE_MASK 0x30 ++#define RTL8367C_VLAN_MSTI14_CTRL0_PORT1_STATE_OFFSET 2 ++#define RTL8367C_VLAN_MSTI14_CTRL0_PORT1_STATE_MASK 0xC ++#define RTL8367C_VLAN_MSTI14_CTRL0_PORT0_STATE_OFFSET 0 ++#define RTL8367C_VLAN_MSTI14_CTRL0_PORT0_STATE_MASK 0x3 ++ ++#define RTL8367C_REG_VLAN_MSTI14_CTRL1 0x0a1d ++#define RTL8367C_VLAN_MSTI14_CTRL1_PORT10_STATE_OFFSET 4 ++#define RTL8367C_VLAN_MSTI14_CTRL1_PORT10_STATE_MASK 0x30 ++#define RTL8367C_VLAN_MSTI14_CTRL1_PORT9_STATE_OFFSET 2 ++#define RTL8367C_VLAN_MSTI14_CTRL1_PORT9_STATE_MASK 0xC ++#define RTL8367C_VLAN_MSTI14_CTRL1_PORT8_STATE_OFFSET 0 ++#define RTL8367C_VLAN_MSTI14_CTRL1_PORT8_STATE_MASK 0x3 ++ ++#define RTL8367C_REG_VLAN_MSTI15_CTRL0 0x0a1e ++#define RTL8367C_VLAN_MSTI15_CTRL0_PORT7_STATE_OFFSET 14 ++#define RTL8367C_VLAN_MSTI15_CTRL0_PORT7_STATE_MASK 0xC000 ++#define RTL8367C_VLAN_MSTI15_CTRL0_PORT6_STATE_OFFSET 12 ++#define RTL8367C_VLAN_MSTI15_CTRL0_PORT6_STATE_MASK 0x3000 ++#define RTL8367C_VLAN_MSTI15_CTRL0_PORT5_STATE_OFFSET 10 ++#define RTL8367C_VLAN_MSTI15_CTRL0_PORT5_STATE_MASK 0xC00 ++#define RTL8367C_VLAN_MSTI15_CTRL0_PORT4_STATE_OFFSET 8 ++#define RTL8367C_VLAN_MSTI15_CTRL0_PORT4_STATE_MASK 0x300 ++#define RTL8367C_VLAN_MSTI15_CTRL0_PORT3_STATE_OFFSET 6 ++#define RTL8367C_VLAN_MSTI15_CTRL0_PORT3_STATE_MASK 0xC0 ++#define RTL8367C_VLAN_MSTI15_CTRL0_PORT2_STATE_OFFSET 4 ++#define RTL8367C_VLAN_MSTI15_CTRL0_PORT2_STATE_MASK 0x30 ++#define RTL8367C_VLAN_MSTI15_CTRL0_PORT1_STATE_OFFSET 2 ++#define RTL8367C_VLAN_MSTI15_CTRL0_PORT1_STATE_MASK 0xC ++#define RTL8367C_VLAN_MSTI15_CTRL0_PORT0_STATE_OFFSET 0 ++#define RTL8367C_VLAN_MSTI15_CTRL0_PORT0_STATE_MASK 0x3 ++ ++#define RTL8367C_REG_VLAN_MSTI15_CTRL1 0x0a1f ++#define RTL8367C_VLAN_MSTI15_CTRL1_PORT10_STATE_OFFSET 4 ++#define RTL8367C_VLAN_MSTI15_CTRL1_PORT10_STATE_MASK 0x30 ++#define RTL8367C_VLAN_MSTI15_CTRL1_PORT9_STATE_OFFSET 2 ++#define RTL8367C_VLAN_MSTI15_CTRL1_PORT9_STATE_MASK 0xC ++#define RTL8367C_VLAN_MSTI15_CTRL1_PORT8_STATE_OFFSET 0 ++#define RTL8367C_VLAN_MSTI15_CTRL1_PORT8_STATE_MASK 0x3 ++ ++#define RTL8367C_REG_LUT_PORT0_LEARN_LIMITNO 0x0a20 ++#define RTL8367C_LUT_PORT0_LEARN_LIMITNO_OFFSET 0 ++#define RTL8367C_LUT_PORT0_LEARN_LIMITNO_MASK 0x1FFF ++ ++#define RTL8367C_REG_LUT_PORT1_LEARN_LIMITNO 0x0a21 ++#define RTL8367C_LUT_PORT1_LEARN_LIMITNO_OFFSET 0 ++#define RTL8367C_LUT_PORT1_LEARN_LIMITNO_MASK 0x1FFF ++ ++#define RTL8367C_REG_LUT_PORT2_LEARN_LIMITNO 0x0a22 ++#define RTL8367C_LUT_PORT2_LEARN_LIMITNO_OFFSET 0 ++#define RTL8367C_LUT_PORT2_LEARN_LIMITNO_MASK 0x1FFF ++ ++#define RTL8367C_REG_LUT_PORT3_LEARN_LIMITNO 0x0a23 ++#define RTL8367C_LUT_PORT3_LEARN_LIMITNO_OFFSET 0 ++#define RTL8367C_LUT_PORT3_LEARN_LIMITNO_MASK 0x1FFF ++ ++#define RTL8367C_REG_LUT_PORT4_LEARN_LIMITNO 0x0a24 ++#define RTL8367C_LUT_PORT4_LEARN_LIMITNO_OFFSET 0 ++#define RTL8367C_LUT_PORT4_LEARN_LIMITNO_MASK 0x1FFF ++ ++#define RTL8367C_REG_LUT_PORT5_LEARN_LIMITNO 0x0a25 ++#define RTL8367C_LUT_PORT5_LEARN_LIMITNO_OFFSET 0 ++#define RTL8367C_LUT_PORT5_LEARN_LIMITNO_MASK 0x1FFF ++ ++#define RTL8367C_REG_LUT_PORT6_LEARN_LIMITNO 0x0a26 ++#define RTL8367C_LUT_PORT6_LEARN_LIMITNO_OFFSET 0 ++#define RTL8367C_LUT_PORT6_LEARN_LIMITNO_MASK 0x1FFF ++ ++#define RTL8367C_REG_LUT_PORT7_LEARN_LIMITNO 0x0a27 ++#define RTL8367C_LUT_PORT7_LEARN_LIMITNO_OFFSET 0 ++#define RTL8367C_LUT_PORT7_LEARN_LIMITNO_MASK 0x1FFF ++ ++#define RTL8367C_REG_LUT_SYS_LEARN_LIMITNO 0x0a28 ++#define RTL8367C_LUT_SYS_LEARN_LIMITNO_OFFSET 0 ++#define RTL8367C_LUT_SYS_LEARN_LIMITNO_MASK 0x1FFF ++ ++#define RTL8367C_REG_LUT_LRN_SYS_LMT_CTRL 0x0a29 ++#define RTL8367C_LUT_SYSTEM_LEARN_PMASK1_OFFSET 12 ++#define RTL8367C_LUT_SYSTEM_LEARN_PMASK1_MASK 0x7000 ++#define RTL8367C_LUT_SYSTEM_LEARN_OVER_ACT_OFFSET 10 ++#define RTL8367C_LUT_SYSTEM_LEARN_OVER_ACT_MASK 0xC00 ++#define RTL8367C_LUT_SYSTEM_LEARN_PMASK_OFFSET 0 ++#define RTL8367C_LUT_SYSTEM_LEARN_PMASK_MASK 0xFF ++ ++#define RTL8367C_REG_LUT_PORT8_LEARN_LIMITNO 0x0a2a ++#define RTL8367C_LUT_PORT8_LEARN_LIMITNO_OFFSET 0 ++#define RTL8367C_LUT_PORT8_LEARN_LIMITNO_MASK 0x1FFF ++ ++#define RTL8367C_REG_LUT_PORT9_LEARN_LIMITNO 0x0a2b ++#define RTL8367C_LUT_PORT9_LEARN_LIMITNO_OFFSET 0 ++#define RTL8367C_LUT_PORT9_LEARN_LIMITNO_MASK 0x1FFF ++ ++#define RTL8367C_REG_LUT_PORT10_LEARN_LIMITNO 0x0a2c ++#define RTL8367C_LUT_PORT10_LEARN_LIMITNO_OFFSET 0 ++#define RTL8367C_LUT_PORT10_LEARN_LIMITNO_MASK 0x1FFF ++ ++#define RTL8367C_REG_LUT_CFG 0x0a30 ++#define RTL8367C_AGE_SPEED_OFFSET 8 ++#define RTL8367C_AGE_SPEED_MASK 0x300 ++#define RTL8367C_BCAM_DISABLE_OFFSET 6 ++#define RTL8367C_BCAM_DISABLE_MASK 0x40 ++#define RTL8367C_LINKDOWN_AGEOUT_OFFSET 5 ++#define RTL8367C_LINKDOWN_AGEOUT_MASK 0x20 ++#define RTL8367C_LUT_IPMC_HASH_OFFSET 4 ++#define RTL8367C_LUT_IPMC_HASH_MASK 0x10 ++#define RTL8367C_LUT_IPMC_LOOKUP_OP_OFFSET 3 ++#define RTL8367C_LUT_IPMC_LOOKUP_OP_MASK 0x8 ++#define RTL8367C_AGE_TIMER_OFFSET 0 ++#define RTL8367C_AGE_TIMER_MASK 0x7 ++ ++#define RTL8367C_REG_LUT_AGEOUT_CTRL 0x0a31 ++#define RTL8367C_LUT_AGEOUT_CTRL_OFFSET 0 ++#define RTL8367C_LUT_AGEOUT_CTRL_MASK 0x7FF ++ ++#define RTL8367C_REG_PORT_EFID_CTRL0 0x0a32 ++#define RTL8367C_PORT3_EFID_OFFSET 12 ++#define RTL8367C_PORT3_EFID_MASK 0x7000 ++#define RTL8367C_PORT2_EFID_OFFSET 8 ++#define RTL8367C_PORT2_EFID_MASK 0x700 ++#define RTL8367C_PORT1_EFID_OFFSET 4 ++#define RTL8367C_PORT1_EFID_MASK 0x70 ++#define RTL8367C_PORT0_EFID_OFFSET 0 ++#define RTL8367C_PORT0_EFID_MASK 0x7 ++ ++#define RTL8367C_REG_PORT_EFID_CTRL1 0x0a33 ++#define RTL8367C_PORT7_EFID_OFFSET 12 ++#define RTL8367C_PORT7_EFID_MASK 0x7000 ++#define RTL8367C_PORT6_EFID_OFFSET 8 ++#define RTL8367C_PORT6_EFID_MASK 0x700 ++#define RTL8367C_PORT5_EFID_OFFSET 4 ++#define RTL8367C_PORT5_EFID_MASK 0x70 ++#define RTL8367C_PORT4_EFID_OFFSET 0 ++#define RTL8367C_PORT4_EFID_MASK 0x7 ++ ++#define RTL8367C_REG_PORT_EFID_CTRL2 0x0a34 ++#define RTL8367C_PORT10_EFID_OFFSET 8 ++#define RTL8367C_PORT10_EFID_MASK 0x700 ++#define RTL8367C_PORT9_EFID_OFFSET 4 ++#define RTL8367C_PORT9_EFID_MASK 0x70 ++#define RTL8367C_PORT8_EFID_OFFSET 0 ++#define RTL8367C_PORT8_EFID_MASK 0x7 ++ ++#define RTL8367C_REG_FORCE_FLUSH1 0x0a35 ++#define RTL8367C_BUSY_STATUS1_OFFSET 3 ++#define RTL8367C_BUSY_STATUS1_MASK 0x38 ++#define RTL8367C_PORTMASK1_OFFSET 0 ++#define RTL8367C_PORTMASK1_MASK 0x7 ++ ++#define RTL8367C_REG_FORCE_FLUSH 0x0a36 ++#define RTL8367C_BUSY_STATUS_OFFSET 8 ++#define RTL8367C_BUSY_STATUS_MASK 0xFF00 ++#define RTL8367C_FORCE_FLUSH_PORTMASK_OFFSET 0 ++#define RTL8367C_FORCE_FLUSH_PORTMASK_MASK 0xFF ++ ++#define RTL8367C_REG_L2_FLUSH_CTRL1 0x0a37 ++#define RTL8367C_LUT_FLUSH_FID_OFFSET 12 ++#define RTL8367C_LUT_FLUSH_FID_MASK 0xF000 ++#define RTL8367C_LUT_FLUSH_VID_OFFSET 0 ++#define RTL8367C_LUT_FLUSH_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_L2_FLUSH_CTRL2 0x0a38 ++#define RTL8367C_LUT_FLUSH_TYPE_OFFSET 2 ++#define RTL8367C_LUT_FLUSH_TYPE_MASK 0x4 ++#define RTL8367C_LUT_FLUSH_MODE_OFFSET 0 ++#define RTL8367C_LUT_FLUSH_MODE_MASK 0x3 ++ ++#define RTL8367C_REG_L2_FLUSH_CTRL3 0x0a39 ++#define RTL8367C_L2_FLUSH_CTRL3_OFFSET 0 ++#define RTL8367C_L2_FLUSH_CTRL3_MASK 0x1 ++ ++#define RTL8367C_REG_LUT_CFG2 0x0a3a ++#define RTL8367C_LUT_IPMC_FWD_RPORT_OFFSET 1 ++#define RTL8367C_LUT_IPMC_FWD_RPORT_MASK 0x2 ++#define RTL8367C_LUT_IPMC_VID_HASH_OFFSET 0 ++#define RTL8367C_LUT_IPMC_VID_HASH_MASK 0x1 ++ ++#define RTL8367C_REG_FLUSH_STATUS 0x0a3f ++#define RTL8367C_FLUSH_STATUS_OFFSET 0 ++#define RTL8367C_FLUSH_STATUS_MASK 0x1 ++ ++#define RTL8367C_REG_STORM_BCAST 0x0a40 ++#define RTL8367C_STORM_BCAST_OFFSET 0 ++#define RTL8367C_STORM_BCAST_MASK 0x7FF ++ ++#define RTL8367C_REG_STORM_MCAST 0x0a41 ++#define RTL8367C_STORM_MCAST_OFFSET 0 ++#define RTL8367C_STORM_MCAST_MASK 0x7FF ++ ++#define RTL8367C_REG_STORM_UNKOWN_UCAST 0x0a42 ++#define RTL8367C_STORM_UNKOWN_UCAST_OFFSET 0 ++#define RTL8367C_STORM_UNKOWN_UCAST_MASK 0x7FF ++ ++#define RTL8367C_REG_STORM_UNKOWN_MCAST 0x0a43 ++#define RTL8367C_STORM_UNKOWN_MCAST_OFFSET 0 ++#define RTL8367C_STORM_UNKOWN_MCAST_MASK 0x7FF ++ ++#define RTL8367C_REG_STORM_BCAST_METER_CTRL0 0x0a44 ++#define RTL8367C_STORM_BCAST_METER_CTRL0_PORT1_METERIDX_OFFSET 8 ++#define RTL8367C_STORM_BCAST_METER_CTRL0_PORT1_METERIDX_MASK 0x3F00 ++#define RTL8367C_STORM_BCAST_METER_CTRL0_PORT0_METERIDX_OFFSET 0 ++#define RTL8367C_STORM_BCAST_METER_CTRL0_PORT0_METERIDX_MASK 0x3F ++ ++#define RTL8367C_REG_STORM_BCAST_METER_CTRL1 0x0a45 ++#define RTL8367C_STORM_BCAST_METER_CTRL1_PORT3_METERIDX_OFFSET 8 ++#define RTL8367C_STORM_BCAST_METER_CTRL1_PORT3_METERIDX_MASK 0x3F00 ++#define RTL8367C_STORM_BCAST_METER_CTRL1_PORT2_METERIDX_OFFSET 0 ++#define RTL8367C_STORM_BCAST_METER_CTRL1_PORT2_METERIDX_MASK 0x3F ++ ++#define RTL8367C_REG_STORM_BCAST_METER_CTRL2 0x0a46 ++#define RTL8367C_STORM_BCAST_METER_CTRL2_PORT5_METERIDX_OFFSET 8 ++#define RTL8367C_STORM_BCAST_METER_CTRL2_PORT5_METERIDX_MASK 0x3F00 ++#define RTL8367C_STORM_BCAST_METER_CTRL2_PORT4_METERIDX_OFFSET 0 ++#define RTL8367C_STORM_BCAST_METER_CTRL2_PORT4_METERIDX_MASK 0x3F ++ ++#define RTL8367C_REG_STORM_BCAST_METER_CTRL3 0x0a47 ++#define RTL8367C_STORM_BCAST_METER_CTRL3_PORT7_METERIDX_OFFSET 8 ++#define RTL8367C_STORM_BCAST_METER_CTRL3_PORT7_METERIDX_MASK 0x3F00 ++#define RTL8367C_STORM_BCAST_METER_CTRL3_PORT6_METERIDX_OFFSET 0 ++#define RTL8367C_STORM_BCAST_METER_CTRL3_PORT6_METERIDX_MASK 0x3F ++ ++#define RTL8367C_REG_STORM_BCAST_METER_CTRL4 0x0a48 ++#define RTL8367C_STORM_BCAST_METER_CTRL4_PORT9_METERIDX_OFFSET 8 ++#define RTL8367C_STORM_BCAST_METER_CTRL4_PORT9_METERIDX_MASK 0x3F00 ++#define RTL8367C_STORM_BCAST_METER_CTRL4_PORT8_METERIDX_OFFSET 0 ++#define RTL8367C_STORM_BCAST_METER_CTRL4_PORT8_METERIDX_MASK 0x3F ++ ++#define RTL8367C_REG_STORM_BCAST_METER_CTRL5 0x0a49 ++#define RTL8367C_STORM_BCAST_METER_CTRL5_OFFSET 0 ++#define RTL8367C_STORM_BCAST_METER_CTRL5_MASK 0x3F ++ ++#define RTL8367C_REG_STORM_MCAST_METER_CTRL0 0x0a4c ++#define RTL8367C_STORM_MCAST_METER_CTRL0_PORT1_METERIDX_OFFSET 8 ++#define RTL8367C_STORM_MCAST_METER_CTRL0_PORT1_METERIDX_MASK 0x3F00 ++#define RTL8367C_STORM_MCAST_METER_CTRL0_PORT0_METERIDX_OFFSET 0 ++#define RTL8367C_STORM_MCAST_METER_CTRL0_PORT0_METERIDX_MASK 0x3F ++ ++#define RTL8367C_REG_STORM_MCAST_METER_CTRL1 0x0a4d ++#define RTL8367C_STORM_MCAST_METER_CTRL1_PORT3_METERIDX_OFFSET 8 ++#define RTL8367C_STORM_MCAST_METER_CTRL1_PORT3_METERIDX_MASK 0x3F00 ++#define RTL8367C_STORM_MCAST_METER_CTRL1_PORT2_METERIDX_OFFSET 0 ++#define RTL8367C_STORM_MCAST_METER_CTRL1_PORT2_METERIDX_MASK 0x3F ++ ++#define RTL8367C_REG_STORM_MCAST_METER_CTRL2 0x0a4e ++#define RTL8367C_STORM_MCAST_METER_CTRL2_PORT5_METERIDX_OFFSET 8 ++#define RTL8367C_STORM_MCAST_METER_CTRL2_PORT5_METERIDX_MASK 0x3F00 ++#define RTL8367C_STORM_MCAST_METER_CTRL2_PORT4_METERIDX_OFFSET 0 ++#define RTL8367C_STORM_MCAST_METER_CTRL2_PORT4_METERIDX_MASK 0x3F ++ ++#define RTL8367C_REG_STORM_MCAST_METER_CTRL3 0x0a4f ++#define RTL8367C_STORM_MCAST_METER_CTRL3_PORT7_METERIDX_OFFSET 8 ++#define RTL8367C_STORM_MCAST_METER_CTRL3_PORT7_METERIDX_MASK 0x3F00 ++#define RTL8367C_STORM_MCAST_METER_CTRL3_PORT6_METERIDX_OFFSET 0 ++#define RTL8367C_STORM_MCAST_METER_CTRL3_PORT6_METERIDX_MASK 0x3F ++ ++#define RTL8367C_REG_STORM_MCAST_METER_CTRL4 0x0a50 ++#define RTL8367C_STORM_MCAST_METER_CTRL4_PORT9_METERIDX_OFFSET 8 ++#define RTL8367C_STORM_MCAST_METER_CTRL4_PORT9_METERIDX_MASK 0x3F00 ++#define RTL8367C_STORM_MCAST_METER_CTRL4_PORT8_METERIDX_OFFSET 0 ++#define RTL8367C_STORM_MCAST_METER_CTRL4_PORT8_METERIDX_MASK 0x3F ++ ++#define RTL8367C_REG_STORM_MCAST_METER_CTRL5 0x0a51 ++#define RTL8367C_STORM_MCAST_METER_CTRL5_OFFSET 0 ++#define RTL8367C_STORM_MCAST_METER_CTRL5_MASK 0x3F ++ ++#define RTL8367C_REG_STORM_UNDA_METER_CTRL0 0x0a54 ++#define RTL8367C_STORM_UNDA_METER_CTRL0_PORT1_METERIDX_OFFSET 8 ++#define RTL8367C_STORM_UNDA_METER_CTRL0_PORT1_METERIDX_MASK 0x3F00 ++#define RTL8367C_STORM_UNDA_METER_CTRL0_PORT0_METERIDX_OFFSET 0 ++#define RTL8367C_STORM_UNDA_METER_CTRL0_PORT0_METERIDX_MASK 0x3F ++ ++#define RTL8367C_REG_STORM_UNDA_METER_CTRL1 0x0a55 ++#define RTL8367C_STORM_UNDA_METER_CTRL1_PORT3_METERIDX_OFFSET 8 ++#define RTL8367C_STORM_UNDA_METER_CTRL1_PORT3_METERIDX_MASK 0x3F00 ++#define RTL8367C_STORM_UNDA_METER_CTRL1_PORT2_METERIDX_OFFSET 0 ++#define RTL8367C_STORM_UNDA_METER_CTRL1_PORT2_METERIDX_MASK 0x3F ++ ++#define RTL8367C_REG_STORM_UNDA_METER_CTRL2 0x0a56 ++#define RTL8367C_STORM_UNDA_METER_CTRL2_PORT5_METERIDX_OFFSET 8 ++#define RTL8367C_STORM_UNDA_METER_CTRL2_PORT5_METERIDX_MASK 0x3F00 ++#define RTL8367C_STORM_UNDA_METER_CTRL2_PORT4_METERIDX_OFFSET 0 ++#define RTL8367C_STORM_UNDA_METER_CTRL2_PORT4_METERIDX_MASK 0x3F ++ ++#define RTL8367C_REG_STORM_UNDA_METER_CTRL3 0x0a57 ++#define RTL8367C_STORM_UNDA_METER_CTRL3_PORT7_METERIDX_OFFSET 8 ++#define RTL8367C_STORM_UNDA_METER_CTRL3_PORT7_METERIDX_MASK 0x3F00 ++#define RTL8367C_STORM_UNDA_METER_CTRL3_PORT6_METERIDX_OFFSET 0 ++#define RTL8367C_STORM_UNDA_METER_CTRL3_PORT6_METERIDX_MASK 0x3F ++ ++#define RTL8367C_REG_STORM_UNDA_METER_CTRL4 0x0a58 ++#define RTL8367C_STORM_UNDA_METER_CTRL4_PORT9_METERIDX_OFFSET 8 ++#define RTL8367C_STORM_UNDA_METER_CTRL4_PORT9_METERIDX_MASK 0x3F00 ++#define RTL8367C_STORM_UNDA_METER_CTRL4_PORT8_METERIDX_OFFSET 0 ++#define RTL8367C_STORM_UNDA_METER_CTRL4_PORT8_METERIDX_MASK 0x3F ++ ++#define RTL8367C_REG_STORM_UNDA_METER_CTRL5 0x0a59 ++#define RTL8367C_STORM_UNDA_METER_CTRL5_OFFSET 0 ++#define RTL8367C_STORM_UNDA_METER_CTRL5_MASK 0x3F ++ ++#define RTL8367C_REG_STORM_UNMC_METER_CTRL0 0x0a5c ++#define RTL8367C_STORM_UNMC_METER_CTRL0_PORT1_METERIDX_OFFSET 8 ++#define RTL8367C_STORM_UNMC_METER_CTRL0_PORT1_METERIDX_MASK 0x3F00 ++#define RTL8367C_STORM_UNMC_METER_CTRL0_PORT0_METERIDX_OFFSET 0 ++#define RTL8367C_STORM_UNMC_METER_CTRL0_PORT0_METERIDX_MASK 0x3F ++ ++#define RTL8367C_REG_STORM_UNMC_METER_CTRL1 0x0a5d ++#define RTL8367C_STORM_UNMC_METER_CTRL1_PORT3_METERIDX_OFFSET 8 ++#define RTL8367C_STORM_UNMC_METER_CTRL1_PORT3_METERIDX_MASK 0x3F00 ++#define RTL8367C_STORM_UNMC_METER_CTRL1_PORT2_METERIDX_OFFSET 0 ++#define RTL8367C_STORM_UNMC_METER_CTRL1_PORT2_METERIDX_MASK 0x3F ++ ++#define RTL8367C_REG_STORM_UNMC_METER_CTRL2 0x0a5e ++#define RTL8367C_STORM_UNMC_METER_CTRL2_PORT5_METERIDX_OFFSET 8 ++#define RTL8367C_STORM_UNMC_METER_CTRL2_PORT5_METERIDX_MASK 0x3F00 ++#define RTL8367C_STORM_UNMC_METER_CTRL2_PORT4_METERIDX_OFFSET 0 ++#define RTL8367C_STORM_UNMC_METER_CTRL2_PORT4_METERIDX_MASK 0x3F ++ ++#define RTL8367C_REG_STORM_UNMC_METER_CTRL3 0x0a5f ++#define RTL8367C_STORM_UNMC_METER_CTRL3_PORT7_METERIDX_OFFSET 8 ++#define RTL8367C_STORM_UNMC_METER_CTRL3_PORT7_METERIDX_MASK 0x3F00 ++#define RTL8367C_STORM_UNMC_METER_CTRL3_PORT6_METERIDX_OFFSET 0 ++#define RTL8367C_STORM_UNMC_METER_CTRL3_PORT6_METERIDX_MASK 0x3F ++ ++#define RTL8367C_REG_STORM_EXT_CFG 0x0a60 ++#define RTL8367C_STORM_EXT_EN_PORTMASK_EXT_OFFSET 14 ++#define RTL8367C_STORM_EXT_EN_PORTMASK_EXT_MASK 0x4000 ++#define RTL8367C_STORM_UNKNOWN_MCAST_EXT_EN_OFFSET 13 ++#define RTL8367C_STORM_UNKNOWN_MCAST_EXT_EN_MASK 0x2000 ++#define RTL8367C_STORM_UNKNOWN_UCAST_EXT_EN_OFFSET 12 ++#define RTL8367C_STORM_UNKNOWN_UCAST_EXT_EN_MASK 0x1000 ++#define RTL8367C_STORM_MCAST_EXT_EN_OFFSET 11 ++#define RTL8367C_STORM_MCAST_EXT_EN_MASK 0x800 ++#define RTL8367C_STORM_BCAST_EXT_EN_OFFSET 10 ++#define RTL8367C_STORM_BCAST_EXT_EN_MASK 0x400 ++#define RTL8367C_STORM_EXT_EN_PORTMASK_OFFSET 0 ++#define RTL8367C_STORM_EXT_EN_PORTMASK_MASK 0x3FF ++ ++#define RTL8367C_REG_STORM_EXT_MTRIDX_CFG0 0x0a61 ++#define RTL8367C_MC_STORM_EXT_METERIDX_OFFSET 8 ++#define RTL8367C_MC_STORM_EXT_METERIDX_MASK 0x3F00 ++#define RTL8367C_BC_STORM_EXT_METERIDX_OFFSET 0 ++#define RTL8367C_BC_STORM_EXT_METERIDX_MASK 0x3F ++ ++#define RTL8367C_REG_STORM_EXT_MTRIDX_CFG1 0x0a62 ++#define RTL8367C_UNMC_STORM_EXT_METERIDX_OFFSET 8 ++#define RTL8367C_UNMC_STORM_EXT_METERIDX_MASK 0x3F00 ++#define RTL8367C_UNUC_STORM_EXT_METERIDX_OFFSET 0 ++#define RTL8367C_UNUC_STORM_EXT_METERIDX_MASK 0x3F ++ ++#define RTL8367C_REG_STORM_UNMC_METER_CTRL4 0x0a63 ++#define RTL8367C_STORM_UNMC_METER_CTRL4_PORT9_METERIDX_OFFSET 8 ++#define RTL8367C_STORM_UNMC_METER_CTRL4_PORT9_METERIDX_MASK 0x3F00 ++#define RTL8367C_STORM_UNMC_METER_CTRL4_PORT8_METERIDX_OFFSET 0 ++#define RTL8367C_STORM_UNMC_METER_CTRL4_PORT8_METERIDX_MASK 0x3F ++ ++#define RTL8367C_REG_STORM_UNMC_METER_CTRL5 0x0a64 ++#define RTL8367C_STORM_UNMC_METER_CTRL5_OFFSET 0 ++#define RTL8367C_STORM_UNMC_METER_CTRL5_MASK 0x3F ++ ++#define RTL8367C_REG_OAM_PARSER_CTRL0 0x0a70 ++#define RTL8367C_PORT7_PARACT_OFFSET 14 ++#define RTL8367C_PORT7_PARACT_MASK 0xC000 ++#define RTL8367C_PORT6_PARACT_OFFSET 12 ++#define RTL8367C_PORT6_PARACT_MASK 0x3000 ++#define RTL8367C_PORT5_PARACT_OFFSET 10 ++#define RTL8367C_PORT5_PARACT_MASK 0xC00 ++#define RTL8367C_PORT4_PARACT_OFFSET 8 ++#define RTL8367C_PORT4_PARACT_MASK 0x300 ++#define RTL8367C_PORT3_PARACT_OFFSET 6 ++#define RTL8367C_PORT3_PARACT_MASK 0xC0 ++#define RTL8367C_PORT2_PARACT_OFFSET 4 ++#define RTL8367C_PORT2_PARACT_MASK 0x30 ++#define RTL8367C_PORT1_PARACT_OFFSET 2 ++#define RTL8367C_PORT1_PARACT_MASK 0xC ++#define RTL8367C_PORT0_PARACT_OFFSET 0 ++#define RTL8367C_PORT0_PARACT_MASK 0x3 ++ ++#define RTL8367C_REG_OAM_PARSER_CTRL1 0x0a71 ++#define RTL8367C_PORT10_PARACT_OFFSET 4 ++#define RTL8367C_PORT10_PARACT_MASK 0x30 ++#define RTL8367C_PORT9_PARACT_OFFSET 2 ++#define RTL8367C_PORT9_PARACT_MASK 0xC ++#define RTL8367C_PORT8_PARACT_OFFSET 0 ++#define RTL8367C_PORT8_PARACT_MASK 0x3 ++ ++#define RTL8367C_REG_OAM_MULTIPLEXER_CTRL0 0x0a72 ++#define RTL8367C_PORT7_MULACT_OFFSET 14 ++#define RTL8367C_PORT7_MULACT_MASK 0xC000 ++#define RTL8367C_PORT6_MULACT_OFFSET 12 ++#define RTL8367C_PORT6_MULACT_MASK 0x3000 ++#define RTL8367C_PORT5_MULACT_OFFSET 10 ++#define RTL8367C_PORT5_MULACT_MASK 0xC00 ++#define RTL8367C_PORT4_MULACT_OFFSET 8 ++#define RTL8367C_PORT4_MULACT_MASK 0x300 ++#define RTL8367C_PORT3_MULACT_OFFSET 6 ++#define RTL8367C_PORT3_MULACT_MASK 0xC0 ++#define RTL8367C_PORT2_MULACT_OFFSET 4 ++#define RTL8367C_PORT2_MULACT_MASK 0x30 ++#define RTL8367C_PORT1_MULACT_OFFSET 2 ++#define RTL8367C_PORT1_MULACT_MASK 0xC ++#define RTL8367C_PORT0_MULACT_OFFSET 0 ++#define RTL8367C_PORT0_MULACT_MASK 0x3 ++ ++#define RTL8367C_REG_OAM_MULTIPLEXER_CTRL1 0x0a73 ++#define RTL8367C_PORT10_MULACT_OFFSET 4 ++#define RTL8367C_PORT10_MULACT_MASK 0x30 ++#define RTL8367C_PORT9_MULACT_OFFSET 2 ++#define RTL8367C_PORT9_MULACT_MASK 0xC ++#define RTL8367C_PORT8_MULACT_OFFSET 0 ++#define RTL8367C_PORT8_MULACT_MASK 0x3 ++ ++#define RTL8367C_REG_OAM_CTRL 0x0a74 ++#define RTL8367C_OAM_CTRL_OFFSET 0 ++#define RTL8367C_OAM_CTRL_MASK 0x1 ++ ++#define RTL8367C_REG_DOT1X_PORT_ENABLE 0x0a80 ++#define RTL8367C_DOT1X_PORT_ENABLE_OFFSET 0 ++#define RTL8367C_DOT1X_PORT_ENABLE_MASK 0x7FF ++ ++#define RTL8367C_REG_DOT1X_MAC_ENABLE 0x0a81 ++#define RTL8367C_DOT1X_MAC_ENABLE_OFFSET 0 ++#define RTL8367C_DOT1X_MAC_ENABLE_MASK 0x7FF ++ ++#define RTL8367C_REG_DOT1X_PORT_AUTH 0x0a82 ++#define RTL8367C_DOT1X_PORT_AUTH_OFFSET 0 ++#define RTL8367C_DOT1X_PORT_AUTH_MASK 0x7FF ++ ++#define RTL8367C_REG_DOT1X_PORT_OPDIR 0x0a83 ++#define RTL8367C_DOT1X_PORT_OPDIR_OFFSET 0 ++#define RTL8367C_DOT1X_PORT_OPDIR_MASK 0x7FF ++ ++#define RTL8367C_REG_DOT1X_UNAUTH_ACT_W0 0x0a84 ++#define RTL8367C_DOT1X_PORT7_UNAUTHBH_OFFSET 14 ++#define RTL8367C_DOT1X_PORT7_UNAUTHBH_MASK 0xC000 ++#define RTL8367C_DOT1X_PORT6_UNAUTHBH_OFFSET 12 ++#define RTL8367C_DOT1X_PORT6_UNAUTHBH_MASK 0x3000 ++#define RTL8367C_DOT1X_PORT5_UNAUTHBH_OFFSET 10 ++#define RTL8367C_DOT1X_PORT5_UNAUTHBH_MASK 0xC00 ++#define RTL8367C_DOT1X_PORT4_UNAUTHBH_OFFSET 8 ++#define RTL8367C_DOT1X_PORT4_UNAUTHBH_MASK 0x300 ++#define RTL8367C_DOT1X_PORT3_UNAUTHBH_OFFSET 6 ++#define RTL8367C_DOT1X_PORT3_UNAUTHBH_MASK 0xC0 ++#define RTL8367C_DOT1X_PORT2_UNAUTHBH_OFFSET 4 ++#define RTL8367C_DOT1X_PORT2_UNAUTHBH_MASK 0x30 ++#define RTL8367C_DOT1X_PORT1_UNAUTHBH_OFFSET 2 ++#define RTL8367C_DOT1X_PORT1_UNAUTHBH_MASK 0xC ++#define RTL8367C_DOT1X_PORT0_UNAUTHBH_OFFSET 0 ++#define RTL8367C_DOT1X_PORT0_UNAUTHBH_MASK 0x3 ++ ++#define RTL8367C_REG_DOT1X_UNAUTH_ACT_W1 0x0a85 ++#define RTL8367C_DOT1X_PORT10_UNAUTHBH_OFFSET 4 ++#define RTL8367C_DOT1X_PORT10_UNAUTHBH_MASK 0x30 ++#define RTL8367C_DOT1X_PORT9_UNAUTHBH_OFFSET 2 ++#define RTL8367C_DOT1X_PORT9_UNAUTHBH_MASK 0xC ++#define RTL8367C_DOT1X_PORT8_UNAUTHBH_OFFSET 0 ++#define RTL8367C_DOT1X_PORT8_UNAUTHBH_MASK 0x3 ++ ++#define RTL8367C_REG_DOT1X_CFG 0x0a86 ++#define RTL8367C_DOT1X_GVOPDIR_OFFSET 6 ++#define RTL8367C_DOT1X_GVOPDIR_MASK 0x40 ++#define RTL8367C_DOT1X_MAC_OPDIR_OFFSET 5 ++#define RTL8367C_DOT1X_MAC_OPDIR_MASK 0x20 ++#define RTL8367C_DOT1X_GVIDX_OFFSET 0 ++#define RTL8367C_DOT1X_GVIDX_MASK 0x1F ++ ++#define RTL8367C_REG_L2_LRN_CNT_CTRL0 0x0a87 ++#define RTL8367C_L2_LRN_CNT_CTRL0_OFFSET 0 ++#define RTL8367C_L2_LRN_CNT_CTRL0_MASK 0x1FFF ++ ++#define RTL8367C_REG_L2_LRN_CNT_CTRL1 0x0a88 ++#define RTL8367C_L2_LRN_CNT_CTRL1_OFFSET 0 ++#define RTL8367C_L2_LRN_CNT_CTRL1_MASK 0x1FFF ++ ++#define RTL8367C_REG_L2_LRN_CNT_CTRL2 0x0a89 ++#define RTL8367C_L2_LRN_CNT_CTRL2_OFFSET 0 ++#define RTL8367C_L2_LRN_CNT_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_L2_LRN_CNT_CTRL3 0x0a8a ++#define RTL8367C_L2_LRN_CNT_CTRL3_OFFSET 0 ++#define RTL8367C_L2_LRN_CNT_CTRL3_MASK 0x1FFF ++ ++#define RTL8367C_REG_L2_LRN_CNT_CTRL4 0x0a8b ++#define RTL8367C_L2_LRN_CNT_CTRL4_OFFSET 0 ++#define RTL8367C_L2_LRN_CNT_CTRL4_MASK 0x1FFF ++ ++#define RTL8367C_REG_L2_LRN_CNT_CTRL5 0x0a8c ++#define RTL8367C_L2_LRN_CNT_CTRL5_OFFSET 0 ++#define RTL8367C_L2_LRN_CNT_CTRL5_MASK 0x1FFF ++ ++#define RTL8367C_REG_L2_LRN_CNT_CTRL6 0x0a8d ++#define RTL8367C_L2_LRN_CNT_CTRL6_OFFSET 0 ++#define RTL8367C_L2_LRN_CNT_CTRL6_MASK 0x1FFF ++ ++#define RTL8367C_REG_L2_LRN_CNT_CTRL7 0x0a8e ++#define RTL8367C_L2_LRN_CNT_CTRL7_OFFSET 0 ++#define RTL8367C_L2_LRN_CNT_CTRL7_MASK 0x1FFF ++ ++#define RTL8367C_REG_L2_LRN_CNT_CTRL8 0x0a8f ++#define RTL8367C_L2_LRN_CNT_CTRL8_OFFSET 0 ++#define RTL8367C_L2_LRN_CNT_CTRL8_MASK 0x1FFF ++ ++#define RTL8367C_REG_L2_LRN_CNT_CTRL9 0x0a90 ++#define RTL8367C_L2_LRN_CNT_CTRL9_OFFSET 0 ++#define RTL8367C_L2_LRN_CNT_CTRL9_MASK 0x1FFF ++ ++#define RTL8367C_REG_L2_LRN_CNT_CTRL10 0x0a92 ++#define RTL8367C_L2_LRN_CNT_CTRL10_OFFSET 0 ++#define RTL8367C_L2_LRN_CNT_CTRL10_MASK 0x1FFF ++ ++#define RTL8367C_REG_LUT_LRN_UNDER_STATUS 0x0a91 ++#define RTL8367C_LUT_LRN_UNDER_STATUS_OFFSET 0 ++#define RTL8367C_LUT_LRN_UNDER_STATUS_MASK 0x7FF ++ ++#define RTL8367C_REG_L2_SA_MOVING_FORBID 0x0aa0 ++#define RTL8367C_L2_SA_MOVING_FORBID_OFFSET 0 ++#define RTL8367C_L2_SA_MOVING_FORBID_MASK 0x7FF ++ ++#define RTL8367C_REG_DRPORT_LEARN_CTRL 0x0aa1 ++#define RTL8367C_FORBID1_OFFSET 1 ++#define RTL8367C_FORBID1_MASK 0x2 ++#define RTL8367C_FORBID0_OFFSET 0 ++#define RTL8367C_FORBID0_MASK 0x1 ++ ++#define RTL8367C_REG_L2_DUMMY02 0x0aa2 ++ ++#define RTL8367C_REG_L2_DUMMY03 0x0aa3 ++ ++#define RTL8367C_REG_L2_DUMMY04 0x0aa4 ++ ++#define RTL8367C_REG_L2_DUMMY05 0x0aa5 ++ ++#define RTL8367C_REG_L2_DUMMY06 0x0aa6 ++ ++#define RTL8367C_REG_L2_DUMMY07 0x0aa7 ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_00 0x0AC0 ++#define RTL8367C_IPMC_GROUP_PMSK_00_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_00_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_01 0x0AC1 ++#define RTL8367C_IPMC_GROUP_PMSK_01_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_01_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_02 0x0AC2 ++#define RTL8367C_IPMC_GROUP_PMSK_02_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_02_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_03 0x0AC3 ++#define RTL8367C_IPMC_GROUP_PMSK_03_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_03_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_04 0x0AC4 ++#define RTL8367C_IPMC_GROUP_PMSK_04_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_04_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_05 0x0AC5 ++#define RTL8367C_IPMC_GROUP_PMSK_05_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_05_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_06 0x0AC6 ++#define RTL8367C_IPMC_GROUP_PMSK_06_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_06_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_07 0x0AC7 ++#define RTL8367C_IPMC_GROUP_PMSK_07_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_07_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_08 0x0AC8 ++#define RTL8367C_IPMC_GROUP_PMSK_08_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_08_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_09 0x0AC9 ++#define RTL8367C_IPMC_GROUP_PMSK_09_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_09_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_10 0x0ACA ++#define RTL8367C_IPMC_GROUP_PMSK_10_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_10_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_11 0x0ACB ++#define RTL8367C_IPMC_GROUP_PMSK_11_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_11_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_12 0x0ACC ++#define RTL8367C_IPMC_GROUP_PMSK_12_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_12_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_13 0x0ACD ++#define RTL8367C_IPMC_GROUP_PMSK_13_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_13_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_14 0x0ACE ++#define RTL8367C_IPMC_GROUP_PMSK_14_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_14_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_15 0x0ACF ++#define RTL8367C_IPMC_GROUP_PMSK_15_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_15_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_16 0x0AD0 ++#define RTL8367C_IPMC_GROUP_PMSK_16_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_16_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_17 0x0AD1 ++#define RTL8367C_IPMC_GROUP_PMSK_17_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_17_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_18 0x0AD2 ++#define RTL8367C_IPMC_GROUP_PMSK_18_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_18_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_19 0x0AD3 ++#define RTL8367C_IPMC_GROUP_PMSK_19_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_19_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_20 0x0AD4 ++#define RTL8367C_IPMC_GROUP_PMSK_20_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_20_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_21 0x0AD5 ++#define RTL8367C_IPMC_GROUP_PMSK_21_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_21_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_22 0x0AD6 ++#define RTL8367C_IPMC_GROUP_PMSK_22_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_22_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_23 0x0AD7 ++#define RTL8367C_IPMC_GROUP_PMSK_23_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_23_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_24 0x0AD8 ++#define RTL8367C_IPMC_GROUP_PMSK_24_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_24_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_25 0x0AD9 ++#define RTL8367C_IPMC_GROUP_PMSK_25_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_25_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_26 0x0ADA ++#define RTL8367C_IPMC_GROUP_PMSK_26_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_26_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_27 0x0ADB ++#define RTL8367C_IPMC_GROUP_PMSK_27_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_27_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_28 0x0ADC ++#define RTL8367C_IPMC_GROUP_PMSK_28_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_28_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_29 0x0ADD ++#define RTL8367C_IPMC_GROUP_PMSK_29_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_29_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_30 0x0ADE ++#define RTL8367C_IPMC_GROUP_PMSK_30_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_30_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_31 0x0ADF ++#define RTL8367C_IPMC_GROUP_PMSK_31_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_31_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_32 0x0AE0 ++#define RTL8367C_IPMC_GROUP_PMSK_32_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_32_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_33 0x0AE1 ++#define RTL8367C_IPMC_GROUP_PMSK_33_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_33_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_34 0x0AE2 ++#define RTL8367C_IPMC_GROUP_PMSK_34_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_34_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_35 0x0AE3 ++#define RTL8367C_IPMC_GROUP_PMSK_35_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_35_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_36 0x0AE4 ++#define RTL8367C_IPMC_GROUP_PMSK_36_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_36_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_37 0x0AE5 ++#define RTL8367C_IPMC_GROUP_PMSK_37_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_37_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_38 0x0AE6 ++#define RTL8367C_IPMC_GROUP_PMSK_38_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_38_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_39 0x0AE7 ++#define RTL8367C_IPMC_GROUP_PMSK_39_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_39_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_40 0x0AE8 ++#define RTL8367C_IPMC_GROUP_PMSK_40_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_40_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_41 0x0AE9 ++#define RTL8367C_IPMC_GROUP_PMSK_41_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_41_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_42 0x0AEA ++#define RTL8367C_IPMC_GROUP_PMSK_42_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_42_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_43 0x0AEB ++#define RTL8367C_IPMC_GROUP_PMSK_43_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_43_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_44 0x0AEC ++#define RTL8367C_IPMC_GROUP_PMSK_44_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_44_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_45 0x0AED ++#define RTL8367C_IPMC_GROUP_PMSK_45_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_45_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_46 0x0AEE ++#define RTL8367C_IPMC_GROUP_PMSK_46_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_46_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_47 0x0AEF ++#define RTL8367C_IPMC_GROUP_PMSK_47_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_47_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_48 0x0AF0 ++#define RTL8367C_IPMC_GROUP_PMSK_48_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_48_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_49 0x0AF1 ++#define RTL8367C_IPMC_GROUP_PMSK_49_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_49_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_50 0x0AF2 ++#define RTL8367C_IPMC_GROUP_PMSK_50_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_50_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_51 0x0AF3 ++#define RTL8367C_IPMC_GROUP_PMSK_51_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_51_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_52 0x0AF4 ++#define RTL8367C_IPMC_GROUP_PMSK_52_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_52_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_53 0x0AF5 ++#define RTL8367C_IPMC_GROUP_PMSK_53_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_53_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_54 0x0AF6 ++#define RTL8367C_IPMC_GROUP_PMSK_54_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_54_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_55 0x0AF7 ++#define RTL8367C_IPMC_GROUP_PMSK_55_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_55_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_56 0x0AF8 ++#define RTL8367C_IPMC_GROUP_PMSK_56_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_56_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_57 0x0AF9 ++#define RTL8367C_IPMC_GROUP_PMSK_57_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_57_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_58 0x0AFA ++#define RTL8367C_IPMC_GROUP_PMSK_58_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_58_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_59 0x0AFB ++#define RTL8367C_IPMC_GROUP_PMSK_59_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_59_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_60 0x0AFC ++#define RTL8367C_IPMC_GROUP_PMSK_60_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_60_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_61 0x0AFD ++#define RTL8367C_IPMC_GROUP_PMSK_61_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_61_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_62 0x0AFE ++#define RTL8367C_IPMC_GROUP_PMSK_62_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_62_MASK 0x7FF ++ ++#define RTL8367C_REG_IPMC_GROUP_PMSK_63 0x0AFF ++#define RTL8367C_IPMC_GROUP_PMSK_63_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_PMSK_63_MASK 0x7FF ++ ++/* (16'h0b00)mltvlan_reg */ ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY0_CTRL0 0x0b00 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY0_CTRL0_VALID_OFFSET 7 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY0_CTRL0_VALID_MASK 0x80 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY0_CTRL0_FORMAT_OFFSET 6 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY0_CTRL0_FORMAT_MASK 0x40 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY0_CTRL0_SVIDX_OFFSET 0 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY0_CTRL0_SVIDX_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY0_CTRL1 0x0b01 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY0_CTRL2 0x0b02 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY0_CTRL3 0x0b03 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY0_CTRL4 0x0b04 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY1_CTRL0 0x0b05 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY1_CTRL0_VALID_OFFSET 7 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY1_CTRL0_VALID_MASK 0x80 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY1_CTRL0_FORMAT_OFFSET 6 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY1_CTRL0_FORMAT_MASK 0x40 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY1_CTRL0_SVIDX_OFFSET 0 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY1_CTRL0_SVIDX_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY1_CTRL1 0x0b06 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY1_CTRL2 0x0b07 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY1_CTRL3 0x0b08 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY1_CTRL4 0x0b09 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY2_CTRL0 0x0b0a ++#define RTL8367C_SVLAN_MCAST2S_ENTRY2_CTRL0_VALID_OFFSET 7 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY2_CTRL0_VALID_MASK 0x80 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY2_CTRL0_FORMAT_OFFSET 6 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY2_CTRL0_FORMAT_MASK 0x40 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY2_CTRL0_SVIDX_OFFSET 0 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY2_CTRL0_SVIDX_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY2_CTRL1 0x0b0b ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY2_CTRL2 0x0b0c ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY2_CTRL3 0x0b0d ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY2_CTRL4 0x0b0e ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY3_CTRL0 0x0b0f ++#define RTL8367C_SVLAN_MCAST2S_ENTRY3_CTRL0_VALID_OFFSET 7 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY3_CTRL0_VALID_MASK 0x80 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY3_CTRL0_FORMAT_OFFSET 6 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY3_CTRL0_FORMAT_MASK 0x40 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY3_CTRL0_SVIDX_OFFSET 0 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY3_CTRL0_SVIDX_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY3_CTRL1 0x0b10 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY3_CTRL2 0x0b11 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY3_CTRL3 0x0b12 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY3_CTRL4 0x0b13 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY4_CTRL0 0x0b14 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY4_CTRL0_VALID_OFFSET 7 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY4_CTRL0_VALID_MASK 0x80 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY4_CTRL0_FORMAT_OFFSET 6 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY4_CTRL0_FORMAT_MASK 0x40 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY4_CTRL0_SVIDX_OFFSET 0 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY4_CTRL0_SVIDX_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY4_CTRL1 0x0b15 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY4_CTRL2 0x0b16 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY4_CTRL3 0x0b17 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY4_CTRL4 0x0b18 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY5_CTRL0 0x0b19 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY5_CTRL0_VALID_OFFSET 7 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY5_CTRL0_VALID_MASK 0x80 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY5_CTRL0_FORMAT_OFFSET 6 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY5_CTRL0_FORMAT_MASK 0x40 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY5_CTRL0_SVIDX_OFFSET 0 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY5_CTRL0_SVIDX_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY5_CTRL1 0x0b1a ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY5_CTRL2 0x0b1b ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY5_CTRL3 0x0b1c ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY5_CTRL4 0x0b1d ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY6_CTRL0 0x0b1e ++#define RTL8367C_SVLAN_MCAST2S_ENTRY6_CTRL0_VALID_OFFSET 7 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY6_CTRL0_VALID_MASK 0x80 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY6_CTRL0_FORMAT_OFFSET 6 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY6_CTRL0_FORMAT_MASK 0x40 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY6_CTRL0_SVIDX_OFFSET 0 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY6_CTRL0_SVIDX_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY6_CTRL1 0x0b1f ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY6_CTRL2 0x0b20 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY6_CTRL3 0x0b21 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY6_CTRL4 0x0b22 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY7_CTRL0 0x0b23 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY7_CTRL0_VALID_OFFSET 7 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY7_CTRL0_VALID_MASK 0x80 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY7_CTRL0_FORMAT_OFFSET 6 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY7_CTRL0_FORMAT_MASK 0x40 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY7_CTRL0_SVIDX_OFFSET 0 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY7_CTRL0_SVIDX_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY7_CTRL1 0x0b24 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY7_CTRL2 0x0b25 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY7_CTRL3 0x0b26 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY7_CTRL4 0x0b27 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY8_CTRL0 0x0b28 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY8_CTRL0_VALID_OFFSET 7 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY8_CTRL0_VALID_MASK 0x80 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY8_CTRL0_FORMAT_OFFSET 6 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY8_CTRL0_FORMAT_MASK 0x40 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY8_CTRL0_SVIDX_OFFSET 0 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY8_CTRL0_SVIDX_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY8_CTRL1 0x0b29 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY8_CTRL2 0x0b2a ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY8_CTRL3 0x0b2b ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY8_CTRL4 0x0b2c ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY9_CTRL0 0x0b2d ++#define RTL8367C_SVLAN_MCAST2S_ENTRY9_CTRL0_VALID_OFFSET 7 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY9_CTRL0_VALID_MASK 0x80 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY9_CTRL0_FORMAT_OFFSET 6 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY9_CTRL0_FORMAT_MASK 0x40 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY9_CTRL0_SVIDX_OFFSET 0 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY9_CTRL0_SVIDX_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY9_CTRL1 0x0b2e ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY9_CTRL2 0x0b2f ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY9_CTRL3 0x0b30 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY9_CTRL4 0x0b31 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY10_CTRL0 0x0b32 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY10_CTRL0_VALID_OFFSET 7 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY10_CTRL0_VALID_MASK 0x80 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY10_CTRL0_FORMAT_OFFSET 6 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY10_CTRL0_FORMAT_MASK 0x40 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY10_CTRL0_SVIDX_OFFSET 0 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY10_CTRL0_SVIDX_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY10_CTRL1 0x0b33 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY10_CTRL2 0x0b34 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY10_CTRL3 0x0b35 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY10_CTRL4 0x0b36 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY11_CTRL0 0x0b37 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY11_CTRL0_VALID_OFFSET 7 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY11_CTRL0_VALID_MASK 0x80 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY11_CTRL0_FORMAT_OFFSET 6 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY11_CTRL0_FORMAT_MASK 0x40 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY11_CTRL0_SVIDX_OFFSET 0 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY11_CTRL0_SVIDX_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY11_CTRL1 0x0b38 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY11_CTRL2 0x0b39 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY11_CTRL3 0x0b3a ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY11_CTRL4 0x0b3b ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY12_CTRL0 0x0b3c ++#define RTL8367C_SVLAN_MCAST2S_ENTRY12_CTRL0_VALID_OFFSET 7 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY12_CTRL0_VALID_MASK 0x80 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY12_CTRL0_FORMAT_OFFSET 6 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY12_CTRL0_FORMAT_MASK 0x40 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY12_CTRL0_SVIDX_OFFSET 0 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY12_CTRL0_SVIDX_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY12_CTRL1 0x0b3d ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY12_CTRL2 0x0b3e ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY12_CTRL3 0x0b3f ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY12_CTRL4 0x0b40 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY13_CTRL0 0x0b41 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY13_CTRL0_VALID_OFFSET 7 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY13_CTRL0_VALID_MASK 0x80 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY13_CTRL0_FORMAT_OFFSET 6 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY13_CTRL0_FORMAT_MASK 0x40 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY13_CTRL0_SVIDX_OFFSET 0 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY13_CTRL0_SVIDX_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY13_CTRL1 0x0b42 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY13_CTRL2 0x0b43 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY13_CTRL3 0x0b44 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY13_CTRL4 0x0b45 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY14_CTRL0 0x0b46 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY14_CTRL0_VALID_OFFSET 7 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY14_CTRL0_VALID_MASK 0x80 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY14_CTRL0_FORMAT_OFFSET 6 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY14_CTRL0_FORMAT_MASK 0x40 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY14_CTRL0_SVIDX_OFFSET 0 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY14_CTRL0_SVIDX_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY14_CTRL1 0x0b47 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY14_CTRL2 0x0b48 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY14_CTRL3 0x0b49 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY14_CTRL4 0x0b4a ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY15_CTRL0 0x0b4b ++#define RTL8367C_SVLAN_MCAST2S_ENTRY15_CTRL0_VALID_OFFSET 7 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY15_CTRL0_VALID_MASK 0x80 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY15_CTRL0_FORMAT_OFFSET 6 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY15_CTRL0_FORMAT_MASK 0x40 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY15_CTRL0_SVIDX_OFFSET 0 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY15_CTRL0_SVIDX_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY15_CTRL1 0x0b4c ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY15_CTRL2 0x0b4d ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY15_CTRL3 0x0b4e ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY15_CTRL4 0x0b4f ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY16_CTRL0 0x0b50 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY16_CTRL0_VALID_OFFSET 7 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY16_CTRL0_VALID_MASK 0x80 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY16_CTRL0_FORMAT_OFFSET 6 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY16_CTRL0_FORMAT_MASK 0x40 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY16_CTRL0_SVIDX_OFFSET 0 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY16_CTRL0_SVIDX_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY16_CTRL1 0x0b51 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY16_CTRL2 0x0b52 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY16_CTRL3 0x0b53 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY16_CTRL4 0x0b54 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY17_CTRL0 0x0b55 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY17_CTRL0_VALID_OFFSET 7 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY17_CTRL0_VALID_MASK 0x80 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY17_CTRL0_FORMAT_OFFSET 6 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY17_CTRL0_FORMAT_MASK 0x40 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY17_CTRL0_SVIDX_OFFSET 0 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY17_CTRL0_SVIDX_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY17_CTRL1 0x0b56 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY17_CTRL2 0x0b57 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY17_CTRL3 0x0b58 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY17_CTRL4 0x0b59 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY18_CTRL0 0x0b5a ++#define RTL8367C_SVLAN_MCAST2S_ENTRY18_CTRL0_VALID_OFFSET 7 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY18_CTRL0_VALID_MASK 0x80 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY18_CTRL0_FORMAT_OFFSET 6 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY18_CTRL0_FORMAT_MASK 0x40 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY18_CTRL0_SVIDX_OFFSET 0 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY18_CTRL0_SVIDX_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY18_CTRL1 0x0b5b ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY18_CTRL2 0x0b5c ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY18_CTRL3 0x0b5d ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY18_CTRL4 0x0b5e ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY19_CTRL0 0x0b5f ++#define RTL8367C_SVLAN_MCAST2S_ENTRY19_CTRL0_VALID_OFFSET 7 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY19_CTRL0_VALID_MASK 0x80 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY19_CTRL0_FORMAT_OFFSET 6 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY19_CTRL0_FORMAT_MASK 0x40 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY19_CTRL0_SVIDX_OFFSET 0 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY19_CTRL0_SVIDX_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY19_CTRL1 0x0b60 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY19_CTRL2 0x0b61 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY19_CTRL3 0x0b62 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY19_CTRL4 0x0b63 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY20_CTRL0 0x0b64 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY20_CTRL0_VALID_OFFSET 7 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY20_CTRL0_VALID_MASK 0x80 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY20_CTRL0_FORMAT_OFFSET 6 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY20_CTRL0_FORMAT_MASK 0x40 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY20_CTRL0_SVIDX_OFFSET 0 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY20_CTRL0_SVIDX_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY20_CTRL1 0x0b65 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY20_CTRL2 0x0b66 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY20_CTRL3 0x0b67 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY20_CTRL4 0x0b68 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY21_CTRL0 0x0b69 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY21_CTRL0_VALID_OFFSET 7 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY21_CTRL0_VALID_MASK 0x80 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY21_CTRL0_FORMAT_OFFSET 6 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY21_CTRL0_FORMAT_MASK 0x40 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY21_CTRL0_SVIDX_OFFSET 0 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY21_CTRL0_SVIDX_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY21_CTRL1 0x0b6a ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY21_CTRL2 0x0b6b ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY21_CTRL3 0x0b6c ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY21_CTRL4 0x0b6d ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY22_CTRL0 0x0b6e ++#define RTL8367C_SVLAN_MCAST2S_ENTRY22_CTRL0_VALID_OFFSET 7 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY22_CTRL0_VALID_MASK 0x80 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY22_CTRL0_FORMAT_OFFSET 6 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY22_CTRL0_FORMAT_MASK 0x40 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY22_CTRL0_SVIDX_OFFSET 0 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY22_CTRL0_SVIDX_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY22_CTRL1 0x0b6f ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY22_CTRL2 0x0b70 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY22_CTRL3 0x0b71 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY22_CTRL4 0x0b72 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY23_CTRL0 0x0b73 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY23_CTRL0_VALID_OFFSET 7 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY23_CTRL0_VALID_MASK 0x80 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY23_CTRL0_FORMAT_OFFSET 6 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY23_CTRL0_FORMAT_MASK 0x40 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY23_CTRL0_SVIDX_OFFSET 0 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY23_CTRL0_SVIDX_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY23_CTRL1 0x0b74 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY23_CTRL2 0x0b75 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY23_CTRL3 0x0b76 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY23_CTRL4 0x0b77 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY24_CTRL0 0x0b78 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY24_CTRL0_VALID_OFFSET 7 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY24_CTRL0_VALID_MASK 0x80 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY24_CTRL0_FORMAT_OFFSET 6 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY24_CTRL0_FORMAT_MASK 0x40 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY24_CTRL0_SVIDX_OFFSET 0 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY24_CTRL0_SVIDX_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY24_CTRL1 0x0b79 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY24_CTRL2 0x0b7a ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY24_CTRL3 0x0b7b ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY24_CTRL4 0x0b7c ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY25_CTRL0 0x0b7d ++#define RTL8367C_SVLAN_MCAST2S_ENTRY25_CTRL0_VALID_OFFSET 7 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY25_CTRL0_VALID_MASK 0x80 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY25_CTRL0_FORMAT_OFFSET 6 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY25_CTRL0_FORMAT_MASK 0x40 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY25_CTRL0_SVIDX_OFFSET 0 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY25_CTRL0_SVIDX_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY25_CTRL1 0x0b7e ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY25_CTRL2 0x0b7f ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY25_CTRL3 0x0b80 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY25_CTRL4 0x0b81 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY26_CTRL0 0x0b82 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY26_CTRL0_VALID_OFFSET 7 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY26_CTRL0_VALID_MASK 0x80 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY26_CTRL0_FORMAT_OFFSET 6 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY26_CTRL0_FORMAT_MASK 0x40 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY26_CTRL0_SVIDX_OFFSET 0 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY26_CTRL0_SVIDX_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY26_CTRL1 0x0b83 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY26_CTRL2 0x0b84 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY26_CTRL3 0x0b85 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY26_CTRL4 0x0b86 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY27_CTRL0 0x0b87 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY27_CTRL0_VALID_OFFSET 7 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY27_CTRL0_VALID_MASK 0x80 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY27_CTRL0_FORMAT_OFFSET 6 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY27_CTRL0_FORMAT_MASK 0x40 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY27_CTRL0_SVIDX_OFFSET 0 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY27_CTRL0_SVIDX_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY27_CTRL1 0x0b88 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY27_CTRL2 0x0b89 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY27_CTRL3 0x0b8a ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY27_CTRL4 0x0b8b ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY28_CTRL0 0x0b8c ++#define RTL8367C_SVLAN_MCAST2S_ENTRY28_CTRL0_VALID_OFFSET 7 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY28_CTRL0_VALID_MASK 0x80 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY28_CTRL0_FORMAT_OFFSET 6 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY28_CTRL0_FORMAT_MASK 0x40 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY28_CTRL0_SVIDX_OFFSET 0 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY28_CTRL0_SVIDX_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY28_CTRL1 0x0b8d ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY28_CTRL2 0x0b8e ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY28_CTRL3 0x0b8f ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY28_CTRL4 0x0b90 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY29_CTRL0 0x0b91 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY29_CTRL0_VALID_OFFSET 7 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY29_CTRL0_VALID_MASK 0x80 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY29_CTRL0_FORMAT_OFFSET 6 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY29_CTRL0_FORMAT_MASK 0x40 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY29_CTRL0_SVIDX_OFFSET 0 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY29_CTRL0_SVIDX_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY29_CTRL1 0x0b92 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY29_CTRL2 0x0b93 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY29_CTRL3 0x0b94 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY29_CTRL4 0x0b95 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY30_CTRL0 0x0b96 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY30_CTRL0_VALID_OFFSET 7 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY30_CTRL0_VALID_MASK 0x80 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY30_CTRL0_FORMAT_OFFSET 6 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY30_CTRL0_FORMAT_MASK 0x40 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY30_CTRL0_SVIDX_OFFSET 0 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY30_CTRL0_SVIDX_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY30_CTRL1 0x0b97 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY30_CTRL2 0x0b98 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY30_CTRL3 0x0b99 ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY30_CTRL4 0x0b9a ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY31_CTRL0 0x0b9b ++#define RTL8367C_SVLAN_MCAST2S_ENTRY31_CTRL0_VALID_OFFSET 7 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY31_CTRL0_VALID_MASK 0x80 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY31_CTRL0_FORMAT_OFFSET 6 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY31_CTRL0_FORMAT_MASK 0x40 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY31_CTRL0_SVIDX_OFFSET 0 ++#define RTL8367C_SVLAN_MCAST2S_ENTRY31_CTRL0_SVIDX_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY31_CTRL1 0x0b9c ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY31_CTRL2 0x0b9d ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY31_CTRL3 0x0b9e ++ ++#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY31_CTRL4 0x0b9f ++ ++#define RTL8367C_REG_MLTVLAN_DUMMY_0 0x0ba0 ++ ++#define RTL8367C_REG_MLTVLAN_DUMMY_1 0x0ba1 ++ ++#define RTL8367C_REG_MLTVLAN_DUMMY_2 0x0ba2 ++ ++#define RTL8367C_REG_MLTVLAN_DUMMY_3 0x0ba3 ++ ++#define RTL8367C_REG_MLTVLAN_DUMMY_4 0x0ba4 ++ ++#define RTL8367C_REG_MLTVLAN_DUMMY_5 0x0ba5 ++ ++#define RTL8367C_REG_MLTVLAN_DUMMY_6 0x0ba6 ++ ++#define RTL8367C_REG_MLTVLAN_DUMMY_7 0x0ba7 ++ ++/* (16'h0c00)svlan_reg */ ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG0_CTRL1 0x0c01 ++#define RTL8367C_SVLAN_MEMBERCFG0_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG0_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG0_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG0_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG0_CTRL2 0x0c02 ++#define RTL8367C_SVLAN_MEMBERCFG0_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG0_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG0_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG0_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG0_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG0_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG0_CTRL3 0x0c03 ++#define RTL8367C_SVLAN_MEMBERCFG0_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG0_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG0_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG0_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG0_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG0_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG1_CTRL1 0x0c04 ++#define RTL8367C_SVLAN_MEMBERCFG1_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG1_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG1_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG1_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG1_CTRL2 0x0c05 ++#define RTL8367C_SVLAN_MEMBERCFG1_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG1_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG1_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG1_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG1_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG1_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG1_CTRL3 0x0c06 ++#define RTL8367C_SVLAN_MEMBERCFG1_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG1_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG1_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG1_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG1_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG1_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG2_CTRL1 0x0c07 ++#define RTL8367C_SVLAN_MEMBERCFG2_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG2_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG2_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG2_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG2_CTRL2 0x0c08 ++#define RTL8367C_SVLAN_MEMBERCFG2_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG2_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG2_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG2_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG2_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG2_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG2_CTRL3 0x0c09 ++#define RTL8367C_SVLAN_MEMBERCFG2_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG2_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG2_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG2_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG2_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG2_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG3_CTRL1 0x0c0a ++#define RTL8367C_SVLAN_MEMBERCFG3_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG3_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG3_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG3_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG3_CTRL2 0x0c0b ++#define RTL8367C_SVLAN_MEMBERCFG3_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG3_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG3_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG3_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG3_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG3_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG3_CTRL3 0x0c0c ++#define RTL8367C_SVLAN_MEMBERCFG3_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG3_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG3_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG3_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG3_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG3_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG4_CTRL1 0x0c0d ++#define RTL8367C_SVLAN_MEMBERCFG4_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG4_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG4_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG4_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG4_CTRL2 0x0c0e ++#define RTL8367C_SVLAN_MEMBERCFG4_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG4_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG4_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG4_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG4_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG4_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG4_CTRL3 0x0c0f ++#define RTL8367C_SVLAN_MEMBERCFG4_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG4_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG4_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG4_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG4_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG4_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG5_CTRL1 0x0c10 ++#define RTL8367C_SVLAN_MEMBERCFG5_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG5_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG5_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG5_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG5_CTRL2 0x0c11 ++#define RTL8367C_SVLAN_MEMBERCFG5_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG5_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG5_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG5_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG5_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG5_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG5_CTRL3 0x0c12 ++#define RTL8367C_SVLAN_MEMBERCFG5_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG5_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG5_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG5_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG5_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG5_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG6_CTRL1 0x0c13 ++#define RTL8367C_SVLAN_MEMBERCFG6_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG6_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG6_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG6_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG6_CTRL2 0x0c14 ++#define RTL8367C_SVLAN_MEMBERCFG6_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG6_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG6_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG6_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG6_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG6_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG6_CTRL3 0x0c15 ++#define RTL8367C_SVLAN_MEMBERCFG6_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG6_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG6_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG6_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG6_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG6_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG7_CTRL1 0x0c16 ++#define RTL8367C_SVLAN_MEMBERCFG7_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG7_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG7_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG7_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG7_CTRL2 0x0c17 ++#define RTL8367C_SVLAN_MEMBERCFG7_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG7_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG7_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG7_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG7_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG7_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG7_CTRL3 0x0c18 ++#define RTL8367C_SVLAN_MEMBERCFG7_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG7_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG7_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG7_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG7_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG7_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG8_CTRL1 0x0c19 ++#define RTL8367C_SVLAN_MEMBERCFG8_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG8_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG8_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG8_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG8_CTRL2 0x0c1a ++#define RTL8367C_SVLAN_MEMBERCFG8_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG8_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG8_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG8_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG8_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG8_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG8_CTRL3 0x0c1b ++#define RTL8367C_SVLAN_MEMBERCFG8_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG8_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG8_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG8_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG8_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG8_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG9_CTRL1 0x0c1c ++#define RTL8367C_SVLAN_MEMBERCFG9_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG9_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG9_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG9_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG9_CTRL2 0x0c1d ++#define RTL8367C_SVLAN_MEMBERCFG9_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG9_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG9_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG9_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG9_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG9_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG9_CTRL3 0x0c1e ++#define RTL8367C_SVLAN_MEMBERCFG9_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG9_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG9_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG9_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG9_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG9_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG10_CTRL1 0x0c1f ++#define RTL8367C_SVLAN_MEMBERCFG10_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG10_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG10_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG10_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG10_CTRL2 0x0c20 ++#define RTL8367C_SVLAN_MEMBERCFG10_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG10_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG10_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG10_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG10_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG10_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG10_CTRL3 0x0c21 ++#define RTL8367C_SVLAN_MEMBERCFG10_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG10_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG10_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG10_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG10_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG10_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG11_CTRL1 0x0c22 ++#define RTL8367C_SVLAN_MEMBERCFG11_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG11_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG11_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG11_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG11_CTRL2 0x0c23 ++#define RTL8367C_SVLAN_MEMBERCFG11_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG11_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG11_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG11_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG11_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG11_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG11_CTRL3 0x0c24 ++#define RTL8367C_SVLAN_MEMBERCFG11_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG11_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG11_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG11_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG11_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG11_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG12_CTRL1 0x0c25 ++#define RTL8367C_SVLAN_MEMBERCFG12_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG12_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG12_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG12_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG12_CTRL2 0x0c26 ++#define RTL8367C_SVLAN_MEMBERCFG12_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG12_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG12_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG12_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG12_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG12_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG12_CTRL3 0x0c27 ++#define RTL8367C_SVLAN_MEMBERCFG12_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG12_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG12_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG12_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG12_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG12_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG13_CTRL1 0x0c28 ++#define RTL8367C_SVLAN_MEMBERCFG13_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG13_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG13_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG13_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG13_CTRL2 0x0c29 ++#define RTL8367C_SVLAN_MEMBERCFG13_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG13_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG13_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG13_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG13_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG13_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG13_CTRL3 0x0c2a ++#define RTL8367C_SVLAN_MEMBERCFG13_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG13_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG13_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG13_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG13_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG13_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG14_CTRL1 0x0c2b ++#define RTL8367C_SVLAN_MEMBERCFG14_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG14_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG14_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG14_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG14_CTRL2 0x0c2c ++#define RTL8367C_SVLAN_MEMBERCFG14_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG14_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG14_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG14_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG14_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG14_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG14_CTRL3 0x0c2d ++#define RTL8367C_SVLAN_MEMBERCFG14_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG14_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG14_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG14_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG14_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG14_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG15_CTRL1 0x0c2e ++#define RTL8367C_SVLAN_MEMBERCFG15_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG15_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG15_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG15_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG15_CTRL2 0x0c2f ++#define RTL8367C_SVLAN_MEMBERCFG15_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG15_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG15_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG15_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG15_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG15_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG15_CTRL3 0x0c30 ++#define RTL8367C_SVLAN_MEMBERCFG15_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG15_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG15_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG15_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG15_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG15_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG16_CTRL1 0x0c31 ++#define RTL8367C_SVLAN_MEMBERCFG16_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG16_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG16_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG16_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG16_CTRL2 0x0c32 ++#define RTL8367C_SVLAN_MEMBERCFG16_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG16_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG16_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG16_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG16_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG16_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG16_CTRL3 0x0c33 ++#define RTL8367C_SVLAN_MEMBERCFG16_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG16_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG16_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG16_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG16_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG16_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG17_CTRL1 0x0c34 ++#define RTL8367C_SVLAN_MEMBERCFG17_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG17_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG17_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG17_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG17_CTRL2 0x0c35 ++#define RTL8367C_SVLAN_MEMBERCFG17_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG17_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG17_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG17_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG17_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG17_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG17_CTRL3 0x0c36 ++#define RTL8367C_SVLAN_MEMBERCFG17_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG17_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG17_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG17_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG17_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG17_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG18_CTRL1 0x0c37 ++#define RTL8367C_SVLAN_MEMBERCFG18_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG18_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG18_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG18_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG18_CTRL2 0x0c38 ++#define RTL8367C_SVLAN_MEMBERCFG18_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG18_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG18_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG18_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG18_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG18_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG18_CTRL3 0x0c39 ++#define RTL8367C_SVLAN_MEMBERCFG18_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG18_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG18_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG18_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG18_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG18_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG19_CTRL1 0x0c3a ++#define RTL8367C_SVLAN_MEMBERCFG19_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG19_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG19_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG19_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG19_CTRL2 0x0c3b ++#define RTL8367C_SVLAN_MEMBERCFG19_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG19_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG19_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG19_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG19_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG19_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG19_CTRL3 0x0c3c ++#define RTL8367C_SVLAN_MEMBERCFG19_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG19_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG19_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG19_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG19_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG19_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG20_CTRL1 0x0c3d ++#define RTL8367C_SVLAN_MEMBERCFG20_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG20_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG20_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG20_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG20_CTRL2 0x0c3e ++#define RTL8367C_SVLAN_MEMBERCFG20_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG20_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG20_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG20_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG20_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG20_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG20_CTRL3 0x0c3f ++#define RTL8367C_SVLAN_MEMBERCFG20_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG20_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG20_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG20_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG20_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG20_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG21_CTRL1 0x0c40 ++#define RTL8367C_SVLAN_MEMBERCFG21_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG21_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG21_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG21_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG21_CTRL2 0x0c41 ++#define RTL8367C_SVLAN_MEMBERCFG21_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG21_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG21_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG21_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG21_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG21_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG21_CTRL3 0x0c42 ++#define RTL8367C_SVLAN_MEMBERCFG21_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG21_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG21_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG21_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG21_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG21_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG22_CTRL1 0x0c43 ++#define RTL8367C_SVLAN_MEMBERCFG22_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG22_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG22_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG22_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG22_CTRL2 0x0c44 ++#define RTL8367C_SVLAN_MEMBERCFG22_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG22_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG22_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG22_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG22_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG22_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG22_CTRL3 0x0c45 ++#define RTL8367C_SVLAN_MEMBERCFG22_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG22_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG22_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG22_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG22_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG22_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG23_CTRL1 0x0c46 ++#define RTL8367C_SVLAN_MEMBERCFG23_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG23_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG23_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG23_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG23_CTRL2 0x0c47 ++#define RTL8367C_SVLAN_MEMBERCFG23_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG23_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG23_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG23_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG23_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG23_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG23_CTRL3 0x0c48 ++#define RTL8367C_SVLAN_MEMBERCFG23_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG23_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG23_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG23_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG23_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG23_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG24_CTRL1 0x0c49 ++#define RTL8367C_SVLAN_MEMBERCFG24_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG24_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG24_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG24_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG24_CTRL2 0x0c4a ++#define RTL8367C_SVLAN_MEMBERCFG24_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG24_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG24_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG24_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG24_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG24_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG24_CTRL3 0x0c4b ++#define RTL8367C_SVLAN_MEMBERCFG24_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG24_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG24_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG24_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG24_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG24_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG25_CTRL1 0x0c4c ++#define RTL8367C_SVLAN_MEMBERCFG25_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG25_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG25_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG25_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG25_CTRL2 0x0c4d ++#define RTL8367C_SVLAN_MEMBERCFG25_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG25_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG25_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG25_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG25_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG25_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG25_CTRL3 0x0c4e ++#define RTL8367C_SVLAN_MEMBERCFG25_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG25_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG25_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG25_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG25_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG25_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG26_CTRL1 0x0c4f ++#define RTL8367C_SVLAN_MEMBERCFG26_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG26_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG26_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG26_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG26_CTRL2 0x0c50 ++#define RTL8367C_SVLAN_MEMBERCFG26_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG26_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG26_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG26_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG26_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG26_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG26_CTRL3 0x0c51 ++#define RTL8367C_SVLAN_MEMBERCFG26_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG26_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG26_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG26_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG26_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG26_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG27_CTRL1 0x0c52 ++#define RTL8367C_SVLAN_MEMBERCFG27_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG27_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG27_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG27_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG27_CTRL2 0x0c53 ++#define RTL8367C_SVLAN_MEMBERCFG27_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG27_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG27_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG27_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG27_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG27_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG27_CTRL3 0x0c54 ++#define RTL8367C_SVLAN_MEMBERCFG27_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG27_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG27_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG27_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG27_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG27_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG28_CTRL1 0x0c55 ++#define RTL8367C_SVLAN_MEMBERCFG28_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG28_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG28_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG28_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG28_CTRL2 0x0c56 ++#define RTL8367C_SVLAN_MEMBERCFG28_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG28_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG28_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG28_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG28_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG28_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG28_CTRL3 0x0c57 ++#define RTL8367C_SVLAN_MEMBERCFG28_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG28_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG28_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG28_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG28_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG28_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG29_CTRL1 0x0c58 ++#define RTL8367C_SVLAN_MEMBERCFG29_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG29_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG29_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG29_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG29_CTRL2 0x0c59 ++#define RTL8367C_SVLAN_MEMBERCFG29_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG29_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG29_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG29_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG29_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG29_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG29_CTRL3 0x0c5a ++#define RTL8367C_SVLAN_MEMBERCFG29_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG29_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG29_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG29_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG29_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG29_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG30_CTRL1 0x0c5b ++#define RTL8367C_SVLAN_MEMBERCFG30_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG30_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG30_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG30_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG30_CTRL2 0x0c5c ++#define RTL8367C_SVLAN_MEMBERCFG30_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG30_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG30_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG30_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG30_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG30_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG30_CTRL3 0x0c5d ++#define RTL8367C_SVLAN_MEMBERCFG30_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG30_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG30_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG30_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG30_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG30_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG31_CTRL1 0x0c5e ++#define RTL8367C_SVLAN_MEMBERCFG31_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG31_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG31_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG31_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG31_CTRL2 0x0c5f ++#define RTL8367C_SVLAN_MEMBERCFG31_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG31_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG31_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG31_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG31_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG31_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG31_CTRL3 0x0c60 ++#define RTL8367C_SVLAN_MEMBERCFG31_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG31_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG31_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG31_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG31_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG31_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG32_CTRL1 0x0c61 ++#define RTL8367C_SVLAN_MEMBERCFG32_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG32_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG32_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG32_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG32_CTRL2 0x0c62 ++#define RTL8367C_SVLAN_MEMBERCFG32_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG32_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG32_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG32_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG32_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG32_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG32_CTRL3 0x0c63 ++#define RTL8367C_SVLAN_MEMBERCFG32_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG32_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG32_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG32_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG32_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG32_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG33_CTRL1 0x0c64 ++#define RTL8367C_SVLAN_MEMBERCFG33_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG33_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG33_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG33_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG33_CTRL2 0x0c65 ++#define RTL8367C_SVLAN_MEMBERCFG33_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG33_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG33_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG33_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG33_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG33_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG33_CTRL3 0x0c66 ++#define RTL8367C_SVLAN_MEMBERCFG33_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG33_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG33_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG33_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG33_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG33_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG34_CTRL1 0x0c67 ++#define RTL8367C_SVLAN_MEMBERCFG34_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG34_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG34_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG34_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG34_CTRL2 0x0c68 ++#define RTL8367C_SVLAN_MEMBERCFG34_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG34_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG34_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG34_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG34_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG34_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG34_CTRL3 0x0c69 ++#define RTL8367C_SVLAN_MEMBERCFG34_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG34_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG34_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG34_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG34_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG34_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG35_CTRL1 0x0c6a ++#define RTL8367C_SVLAN_MEMBERCFG35_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG35_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG35_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG35_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG35_CTRL2 0x0c6b ++#define RTL8367C_SVLAN_MEMBERCFG35_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG35_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG35_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG35_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG35_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG35_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG35_CTRL3 0x0c6c ++#define RTL8367C_SVLAN_MEMBERCFG35_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG35_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG35_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG35_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG35_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG35_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG36_CTRL1 0x0c6d ++#define RTL8367C_SVLAN_MEMBERCFG36_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG36_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG36_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG36_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG36_CTRL2 0x0c6e ++#define RTL8367C_SVLAN_MEMBERCFG36_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG36_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG36_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG36_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG36_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG36_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG36_CTRL3 0x0c6f ++#define RTL8367C_SVLAN_MEMBERCFG36_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG36_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG36_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG36_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG36_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG36_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG37_CTRL1 0x0c70 ++#define RTL8367C_SVLAN_MEMBERCFG37_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG37_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG37_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG37_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG37_CTRL2 0x0c71 ++#define RTL8367C_SVLAN_MEMBERCFG37_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG37_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG37_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG37_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG37_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG37_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG37_CTRL3 0x0c72 ++#define RTL8367C_SVLAN_MEMBERCFG37_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG37_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG37_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG37_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG37_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG37_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG38_CTRL1 0x0c73 ++#define RTL8367C_SVLAN_MEMBERCFG38_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG38_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG38_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG38_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG38_CTRL2 0x0c74 ++#define RTL8367C_SVLAN_MEMBERCFG38_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG38_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG38_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG38_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG38_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG38_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG38_CTRL3 0x0c75 ++#define RTL8367C_SVLAN_MEMBERCFG38_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG38_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG38_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG38_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG38_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG38_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG39_CTRL1 0x0c76 ++#define RTL8367C_SVLAN_MEMBERCFG39_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG39_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG39_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG39_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG39_CTRL2 0x0c77 ++#define RTL8367C_SVLAN_MEMBERCFG39_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG39_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG39_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG39_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG39_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG39_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG39_CTRL3 0x0c78 ++#define RTL8367C_SVLAN_MEMBERCFG39_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG39_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG39_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG39_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG39_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG39_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG40_CTRL1 0x0c79 ++#define RTL8367C_SVLAN_MEMBERCFG40_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG40_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG40_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG40_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG40_CTRL2 0x0c7a ++#define RTL8367C_SVLAN_MEMBERCFG40_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG40_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG40_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG40_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG40_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG40_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG40_CTRL3 0x0c7b ++#define RTL8367C_SVLAN_MEMBERCFG40_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG40_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG40_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG40_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG40_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG40_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG41_CTRL1 0x0c7c ++#define RTL8367C_SVLAN_MEMBERCFG41_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG41_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG41_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG41_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG41_CTRL2 0x0c7d ++#define RTL8367C_SVLAN_MEMBERCFG41_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG41_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG41_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG41_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG41_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG41_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG41_CTRL3 0x0c7e ++#define RTL8367C_SVLAN_MEMBERCFG41_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG41_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG41_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG41_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG41_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG41_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG42_CTRL1 0x0c7f ++#define RTL8367C_SVLAN_MEMBERCFG42_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG42_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG42_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG42_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG42_CTRL2 0x0c80 ++#define RTL8367C_SVLAN_MEMBERCFG42_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG42_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG42_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG42_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG42_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG42_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG42_CTRL3 0x0c81 ++#define RTL8367C_SVLAN_MEMBERCFG42_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG42_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG42_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG42_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG42_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG42_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG43_CTRL1 0x0c82 ++#define RTL8367C_SVLAN_MEMBERCFG43_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG43_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG43_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG43_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG43_CTRL2 0x0c83 ++#define RTL8367C_SVLAN_MEMBERCFG43_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG43_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG43_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG43_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG43_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG43_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG43_CTRL3 0x0c84 ++#define RTL8367C_SVLAN_MEMBERCFG43_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG43_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG43_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG43_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG43_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG43_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG44_CTRL1 0x0c85 ++#define RTL8367C_SVLAN_MEMBERCFG44_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG44_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG44_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG44_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG44_CTRL2 0x0c86 ++#define RTL8367C_SVLAN_MEMBERCFG44_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG44_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG44_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG44_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG44_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG44_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG44_CTRL3 0x0c87 ++#define RTL8367C_SVLAN_MEMBERCFG44_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG44_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG44_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG44_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG44_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG44_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG45_CTRL1 0x0c88 ++#define RTL8367C_SVLAN_MEMBERCFG45_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG45_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG45_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG45_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG45_CTRL2 0x0c89 ++#define RTL8367C_SVLAN_MEMBERCFG45_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG45_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG45_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG45_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG45_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG45_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG45_CTRL3 0x0c8a ++#define RTL8367C_SVLAN_MEMBERCFG45_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG45_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG45_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG45_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG45_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG45_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG46_CTRL1 0x0c8b ++#define RTL8367C_SVLAN_MEMBERCFG46_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG46_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG46_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG46_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG46_CTRL2 0x0c8c ++#define RTL8367C_SVLAN_MEMBERCFG46_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG46_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG46_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG46_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG46_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG46_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG46_CTRL3 0x0c8d ++#define RTL8367C_SVLAN_MEMBERCFG46_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG46_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG46_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG46_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG46_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG46_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG47_CTRL1 0x0c8e ++#define RTL8367C_SVLAN_MEMBERCFG47_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG47_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG47_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG47_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG47_CTRL2 0x0c8f ++#define RTL8367C_SVLAN_MEMBERCFG47_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG47_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG47_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG47_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG47_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG47_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG47_CTRL3 0x0c90 ++#define RTL8367C_SVLAN_MEMBERCFG47_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG47_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG47_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG47_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG47_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG47_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG48_CTRL1 0x0c91 ++#define RTL8367C_SVLAN_MEMBERCFG48_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG48_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG48_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG48_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG48_CTRL2 0x0c92 ++#define RTL8367C_SVLAN_MEMBERCFG48_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG48_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG48_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG48_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG48_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG48_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG48_CTRL3 0x0c93 ++#define RTL8367C_SVLAN_MEMBERCFG48_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG48_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG48_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG48_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG48_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG48_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG49_CTRL1 0x0c94 ++#define RTL8367C_SVLAN_MEMBERCFG49_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG49_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG49_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG49_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG49_CTRL2 0x0c95 ++#define RTL8367C_SVLAN_MEMBERCFG49_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG49_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG49_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG49_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG49_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG49_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG49_CTRL3 0x0c96 ++#define RTL8367C_SVLAN_MEMBERCFG49_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG49_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG49_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG49_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG49_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG49_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG50_CTRL1 0x0c97 ++#define RTL8367C_SVLAN_MEMBERCFG50_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG50_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG50_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG50_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG50_CTRL2 0x0c98 ++#define RTL8367C_SVLAN_MEMBERCFG50_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG50_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG50_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG50_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG50_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG50_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG50_CTRL3 0x0c99 ++#define RTL8367C_SVLAN_MEMBERCFG50_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG50_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG50_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG50_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG50_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG50_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG51_CTRL1 0x0c9a ++#define RTL8367C_SVLAN_MEMBERCFG51_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG51_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG51_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG51_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG51_CTRL2 0x0c9b ++#define RTL8367C_SVLAN_MEMBERCFG51_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG51_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG51_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG51_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG51_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG51_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG51_CTRL3 0x0c9c ++#define RTL8367C_SVLAN_MEMBERCFG51_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG51_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG51_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG51_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG51_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG51_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG52_CTRL1 0x0c9d ++#define RTL8367C_SVLAN_MEMBERCFG52_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG52_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG52_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG52_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG52_CTRL2 0x0c9e ++#define RTL8367C_SVLAN_MEMBERCFG52_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG52_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG52_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG52_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG52_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG52_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG52_CTRL3 0x0c9f ++#define RTL8367C_SVLAN_MEMBERCFG52_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG52_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG52_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG52_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG52_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG52_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG53_CTRL1 0x0ca0 ++#define RTL8367C_SVLAN_MEMBERCFG53_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG53_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG53_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG53_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG53_CTRL2 0x0ca1 ++#define RTL8367C_SVLAN_MEMBERCFG53_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG53_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG53_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG53_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG53_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG53_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG53_CTRL3 0x0ca2 ++#define RTL8367C_SVLAN_MEMBERCFG53_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG53_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG53_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG53_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG53_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG53_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG54_CTRL1 0x0ca3 ++#define RTL8367C_SVLAN_MEMBERCFG54_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG54_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG54_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG54_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG54_CTRL2 0x0ca4 ++#define RTL8367C_SVLAN_MEMBERCFG54_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG54_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG54_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG54_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG54_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG54_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG54_CTRL3 0x0ca5 ++#define RTL8367C_SVLAN_MEMBERCFG54_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG54_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG54_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG54_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG54_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG54_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG55_CTRL1 0x0ca6 ++#define RTL8367C_SVLAN_MEMBERCFG55_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG55_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG55_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG55_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG55_CTRL2 0x0ca7 ++#define RTL8367C_SVLAN_MEMBERCFG55_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG55_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG55_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG55_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG55_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG55_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG55_CTRL3 0x0ca8 ++#define RTL8367C_SVLAN_MEMBERCFG55_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG55_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG55_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG55_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG55_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG55_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG56_CTRL1 0x0ca9 ++#define RTL8367C_SVLAN_MEMBERCFG56_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG56_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG56_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG56_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG56_CTRL2 0x0caa ++#define RTL8367C_SVLAN_MEMBERCFG56_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG56_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG56_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG56_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG56_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG56_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG56_CTRL3 0x0cab ++#define RTL8367C_SVLAN_MEMBERCFG56_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG56_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG56_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG56_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG56_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG56_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG57_CTRL1 0x0cac ++#define RTL8367C_SVLAN_MEMBERCFG57_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG57_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG57_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG57_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG57_CTRL2 0x0cad ++#define RTL8367C_SVLAN_MEMBERCFG57_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG57_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG57_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG57_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG57_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG57_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG57_CTRL3 0x0cae ++#define RTL8367C_SVLAN_MEMBERCFG57_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG57_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG57_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG57_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG57_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG57_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG58_CTRL1 0x0caf ++#define RTL8367C_SVLAN_MEMBERCFG58_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG58_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG58_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG58_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG58_CTRL2 0x0cb0 ++#define RTL8367C_SVLAN_MEMBERCFG58_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG58_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG58_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG58_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG58_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG58_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG58_CTRL3 0x0cb1 ++#define RTL8367C_SVLAN_MEMBERCFG58_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG58_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG58_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG58_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG58_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG58_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG59_CTRL1 0x0cb2 ++#define RTL8367C_SVLAN_MEMBERCFG59_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG59_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG59_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG59_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG59_CTRL2 0x0cb3 ++#define RTL8367C_SVLAN_MEMBERCFG59_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG59_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG59_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG59_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG59_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG59_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG59_CTRL3 0x0cb4 ++#define RTL8367C_SVLAN_MEMBERCFG59_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG59_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG59_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG59_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG59_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG59_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG60_CTRL1 0x0cb5 ++#define RTL8367C_SVLAN_MEMBERCFG60_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG60_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG60_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG60_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG60_CTRL2 0x0cb6 ++#define RTL8367C_SVLAN_MEMBERCFG60_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG60_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG60_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG60_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG60_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG60_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG60_CTRL3 0x0cb7 ++#define RTL8367C_SVLAN_MEMBERCFG60_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG60_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG60_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG60_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG60_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG60_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG61_CTRL1 0x0cb8 ++#define RTL8367C_SVLAN_MEMBERCFG61_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG61_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG61_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG61_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG61_CTRL2 0x0cb9 ++#define RTL8367C_SVLAN_MEMBERCFG61_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG61_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG61_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG61_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG61_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG61_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG61_CTRL3 0x0cba ++#define RTL8367C_SVLAN_MEMBERCFG61_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG61_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG61_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG61_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG61_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG61_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG62_CTRL1 0x0cbb ++#define RTL8367C_SVLAN_MEMBERCFG62_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG62_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG62_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG62_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG62_CTRL2 0x0cbc ++#define RTL8367C_SVLAN_MEMBERCFG62_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG62_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG62_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG62_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG62_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG62_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG62_CTRL3 0x0cbd ++#define RTL8367C_SVLAN_MEMBERCFG62_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG62_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG62_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG62_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG62_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG62_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG63_CTRL1 0x0cbe ++#define RTL8367C_SVLAN_MEMBERCFG63_CTRL1_VS_UNTAGSET_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG63_CTRL1_VS_UNTAGSET_MASK 0xFF00 ++#define RTL8367C_SVLAN_MEMBERCFG63_CTRL1_VS_SMBR_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG63_CTRL1_VS_SMBR_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG63_CTRL2 0x0cbf ++#define RTL8367C_SVLAN_MEMBERCFG63_CTRL2_VS_FIDEN_OFFSET 7 ++#define RTL8367C_SVLAN_MEMBERCFG63_CTRL2_VS_FIDEN_MASK 0x80 ++#define RTL8367C_SVLAN_MEMBERCFG63_CTRL2_VS_SPRI_OFFSET 4 ++#define RTL8367C_SVLAN_MEMBERCFG63_CTRL2_VS_SPRI_MASK 0x70 ++#define RTL8367C_SVLAN_MEMBERCFG63_CTRL2_VS_FID_MSTI_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG63_CTRL2_VS_FID_MSTI_MASK 0xF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG63_CTRL3 0x0cc0 ++#define RTL8367C_SVLAN_MEMBERCFG63_CTRL3_VS_EFID_OFFSET 13 ++#define RTL8367C_SVLAN_MEMBERCFG63_CTRL3_VS_EFID_MASK 0xE000 ++#define RTL8367C_SVLAN_MEMBERCFG63_CTRL3_VS_EFIDEN_OFFSET 12 ++#define RTL8367C_SVLAN_MEMBERCFG63_CTRL3_VS_EFIDEN_MASK 0x1000 ++#define RTL8367C_SVLAN_MEMBERCFG63_CTRL3_VS_SVID_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG63_CTRL3_VS_SVID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG0_CTRL4 0x0cc1 ++#define RTL8367C_SVLAN_MEMBERCFG0_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG0_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG0_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG0_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG1_CTRL4 0x0cc2 ++#define RTL8367C_SVLAN_MEMBERCFG1_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG1_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG1_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG1_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG2_CTRL4 0x0cc3 ++#define RTL8367C_SVLAN_MEMBERCFG2_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG2_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG2_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG2_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG3_CTRL4 0x0cc4 ++#define RTL8367C_SVLAN_MEMBERCFG3_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG3_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG3_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG3_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG4_CTRL4 0x0cc5 ++#define RTL8367C_SVLAN_MEMBERCFG4_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG4_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG4_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG4_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG5_CTRL4 0x0cc6 ++#define RTL8367C_SVLAN_MEMBERCFG5_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG5_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG5_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG5_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG6_CTRL4 0x0cc7 ++#define RTL8367C_SVLAN_MEMBERCFG6_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG6_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG6_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG6_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG7_CTRL4 0x0cc8 ++#define RTL8367C_SVLAN_MEMBERCFG7_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG7_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG7_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG7_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG8_CTRL4 0x0cc9 ++#define RTL8367C_SVLAN_MEMBERCFG8_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG8_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG8_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG8_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG9_CTRL4 0x0cca ++#define RTL8367C_SVLAN_MEMBERCFG9_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG9_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG9_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG9_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG10_CTRL4 0x0ccb ++#define RTL8367C_SVLAN_MEMBERCFG10_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG10_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG10_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG10_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG11_CTRL4 0x0ccc ++#define RTL8367C_SVLAN_MEMBERCFG11_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG11_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG11_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG11_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG12_CTRL4 0x0ccd ++#define RTL8367C_SVLAN_MEMBERCFG12_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG12_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG12_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG12_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG13_CTRL4 0x0cce ++#define RTL8367C_SVLAN_MEMBERCFG13_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG13_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG13_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG13_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG14_CTRL4 0x0ccf ++#define RTL8367C_SVLAN_MEMBERCFG14_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG14_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG14_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG14_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG15_CTRL4 0x0cd0 ++#define RTL8367C_SVLAN_MEMBERCFG15_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG15_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG15_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG15_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG16_CTRL4 0x0cd1 ++#define RTL8367C_SVLAN_MEMBERCFG16_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG16_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG16_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG16_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG17_CTRL4 0x0cd2 ++#define RTL8367C_SVLAN_MEMBERCFG17_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG17_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG17_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG17_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG18_CTRL4 0x0cd3 ++#define RTL8367C_SVLAN_MEMBERCFG18_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG18_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG18_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG18_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG19_CTRL4 0x0cd4 ++#define RTL8367C_SVLAN_MEMBERCFG19_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG19_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG19_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG19_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG20_CTRL4 0x0cd5 ++#define RTL8367C_SVLAN_MEMBERCFG20_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG20_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG20_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG20_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG21_CTRL4 0x0cd6 ++#define RTL8367C_SVLAN_MEMBERCFG21_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG21_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG21_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG21_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG22_CTRL4 0x0cd7 ++#define RTL8367C_SVLAN_MEMBERCFG22_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG22_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG22_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG22_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG23_CTRL4 0x0cd8 ++#define RTL8367C_SVLAN_MEMBERCFG23_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG23_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG23_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG23_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG24_CTRL4 0x0cd9 ++#define RTL8367C_SVLAN_MEMBERCFG24_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG24_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG24_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG24_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG25_CTRL4 0x0cda ++#define RTL8367C_SVLAN_MEMBERCFG25_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG25_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG25_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG25_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG26_CTRL4 0x0cdb ++#define RTL8367C_SVLAN_MEMBERCFG26_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG26_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG26_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG26_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG27_CTRL4 0x0cdc ++#define RTL8367C_SVLAN_MEMBERCFG27_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG27_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG27_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG27_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG28_CTRL4 0x0cdd ++#define RTL8367C_SVLAN_MEMBERCFG28_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG28_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG28_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG28_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG29_CTRL4 0x0cde ++#define RTL8367C_SVLAN_MEMBERCFG29_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG29_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG29_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG29_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG30_CTRL4 0x0cdf ++#define RTL8367C_SVLAN_MEMBERCFG30_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG30_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG30_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG30_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG31_CTRL4 0x0ce0 ++#define RTL8367C_SVLAN_MEMBERCFG31_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG31_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG31_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG31_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG32_CTRL4 0x0ce1 ++#define RTL8367C_SVLAN_MEMBERCFG32_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG32_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG32_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG32_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG33_CTRL4 0x0ce2 ++#define RTL8367C_SVLAN_MEMBERCFG33_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG33_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG33_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG33_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG34_CTRL4 0x0ce3 ++#define RTL8367C_SVLAN_MEMBERCFG34_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG34_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG34_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG34_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG35_CTRL4 0x0ce4 ++#define RTL8367C_SVLAN_MEMBERCFG35_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG35_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG35_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG35_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG36_CTRL4 0x0ce5 ++#define RTL8367C_SVLAN_MEMBERCFG36_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG36_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG36_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG36_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG37_CTRL4 0x0ce6 ++#define RTL8367C_SVLAN_MEMBERCFG37_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG37_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG37_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG37_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG38_CTRL4 0x0ce7 ++#define RTL8367C_SVLAN_MEMBERCFG38_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG38_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG38_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG38_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG39_CTRL4 0x0ce8 ++#define RTL8367C_SVLAN_MEMBERCFG39_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG39_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG39_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG39_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG40_CTRL4 0x0ce9 ++#define RTL8367C_SVLAN_MEMBERCFG40_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG40_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG40_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG40_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG41_CTRL4 0x0cea ++#define RTL8367C_SVLAN_MEMBERCFG41_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG41_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG41_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG41_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG42_CTRL4 0x0ceb ++#define RTL8367C_SVLAN_MEMBERCFG42_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG42_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG42_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG42_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG43_CTRL4 0x0cec ++#define RTL8367C_SVLAN_MEMBERCFG43_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG43_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG43_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG43_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG44_CTRL4 0x0ced ++#define RTL8367C_SVLAN_MEMBERCFG44_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG44_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG44_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG44_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG45_CTRL4 0x0cee ++#define RTL8367C_SVLAN_MEMBERCFG45_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG45_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG45_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG45_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG46_CTRL4 0x0cef ++#define RTL8367C_SVLAN_MEMBERCFG46_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG46_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG46_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG46_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG47_CTRL4 0x0cf0 ++#define RTL8367C_SVLAN_MEMBERCFG47_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG47_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG47_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG47_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG48_CTRL4 0x0cf1 ++#define RTL8367C_SVLAN_MEMBERCFG48_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG48_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG48_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG48_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG49_CTRL4 0x0cf2 ++#define RTL8367C_SVLAN_MEMBERCFG49_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG49_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG49_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG49_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG50_CTRL4 0x0cf3 ++#define RTL8367C_SVLAN_MEMBERCFG50_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG50_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG50_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG50_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG51_CTRL4 0x0cf4 ++#define RTL8367C_SVLAN_MEMBERCFG51_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG51_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG51_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG51_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG52_CTRL4 0x0cf5 ++#define RTL8367C_SVLAN_MEMBERCFG52_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG52_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG52_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG52_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG53_CTRL4 0x0cf6 ++#define RTL8367C_SVLAN_MEMBERCFG53_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG53_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG53_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG53_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG54_CTRL4 0x0cf7 ++#define RTL8367C_SVLAN_MEMBERCFG54_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG54_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG54_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG54_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG55_CTRL4 0x0cf8 ++#define RTL8367C_SVLAN_MEMBERCFG55_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG55_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG55_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG55_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG56_CTRL4 0x0cf9 ++#define RTL8367C_SVLAN_MEMBERCFG56_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG56_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG56_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG56_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG57_CTRL4 0x0cfa ++#define RTL8367C_SVLAN_MEMBERCFG57_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG57_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG57_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG57_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG58_CTRL4 0x0cfb ++#define RTL8367C_SVLAN_MEMBERCFG58_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG58_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG58_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG58_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG59_CTRL4 0x0cfc ++#define RTL8367C_SVLAN_MEMBERCFG59_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG59_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG59_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG59_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG60_CTRL4 0x0cfd ++#define RTL8367C_SVLAN_MEMBERCFG60_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG60_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG60_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG60_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG61_CTRL4 0x0cfe ++#define RTL8367C_SVLAN_MEMBERCFG61_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG61_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG61_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG61_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG62_CTRL4 0x0cff ++#define RTL8367C_SVLAN_MEMBERCFG62_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG62_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG62_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG62_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_C2SCFG0_CTRL0 0x0d00 ++#define RTL8367C_SVLAN_C2SCFG0_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG0_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG0_CTRL1 0x0d01 ++#define RTL8367C_SVLAN_C2SCFG0_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG0_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG0_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG0_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG0_CTRL2 0x0d02 ++#define RTL8367C_SVLAN_C2SCFG0_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG0_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG1_CTRL0 0x0d03 ++#define RTL8367C_SVLAN_C2SCFG1_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG1_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG1_CTRL1 0x0d04 ++#define RTL8367C_SVLAN_C2SCFG1_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG1_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG1_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG1_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG1_CTRL2 0x0d05 ++#define RTL8367C_SVLAN_C2SCFG1_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG1_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG2_CTRL0 0x0d06 ++#define RTL8367C_SVLAN_C2SCFG2_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG2_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG2_CTRL1 0x0d07 ++#define RTL8367C_SVLAN_C2SCFG2_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG2_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG2_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG2_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG2_CTRL2 0x0d08 ++#define RTL8367C_SVLAN_C2SCFG2_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG2_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG3_CTRL0 0x0d09 ++#define RTL8367C_SVLAN_C2SCFG3_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG3_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG3_CTRL1 0x0d0a ++#define RTL8367C_SVLAN_C2SCFG3_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG3_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG3_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG3_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG3_CTRL2 0x0d0b ++#define RTL8367C_SVLAN_C2SCFG3_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG3_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG4_CTRL0 0x0d0c ++#define RTL8367C_SVLAN_C2SCFG4_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG4_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG4_CTRL1 0x0d0d ++#define RTL8367C_SVLAN_C2SCFG4_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG4_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG4_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG4_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG4_CTRL2 0x0d0e ++#define RTL8367C_SVLAN_C2SCFG4_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG4_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG5_CTRL0 0x0d0f ++#define RTL8367C_SVLAN_C2SCFG5_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG5_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG5_CTRL1 0x0d10 ++#define RTL8367C_SVLAN_C2SCFG5_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG5_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG5_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG5_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG5_CTRL2 0x0d11 ++#define RTL8367C_SVLAN_C2SCFG5_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG5_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG6_CTRL0 0x0d12 ++#define RTL8367C_SVLAN_C2SCFG6_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG6_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG6_CTRL1 0x0d13 ++#define RTL8367C_SVLAN_C2SCFG6_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG6_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG6_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG6_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG6_CTRL2 0x0d14 ++#define RTL8367C_SVLAN_C2SCFG6_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG6_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG7_CTRL0 0x0d15 ++#define RTL8367C_SVLAN_C2SCFG7_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG7_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG7_CTRL1 0x0d16 ++#define RTL8367C_SVLAN_C2SCFG7_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG7_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG7_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG7_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG7_CTRL2 0x0d17 ++#define RTL8367C_SVLAN_C2SCFG7_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG7_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG8_CTRL0 0x0d18 ++#define RTL8367C_SVLAN_C2SCFG8_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG8_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG8_CTRL1 0x0d19 ++#define RTL8367C_SVLAN_C2SCFG8_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG8_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG8_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG8_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG8_CTRL2 0x0d1a ++#define RTL8367C_SVLAN_C2SCFG8_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG8_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG9_CTRL0 0x0d1b ++#define RTL8367C_SVLAN_C2SCFG9_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG9_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG9_CTRL1 0x0d1c ++#define RTL8367C_SVLAN_C2SCFG9_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG9_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG9_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG9_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG9_CTRL2 0x0d1d ++#define RTL8367C_SVLAN_C2SCFG9_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG9_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG10_CTRL0 0x0d1e ++#define RTL8367C_SVLAN_C2SCFG10_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG10_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG10_CTRL1 0x0d1f ++#define RTL8367C_SVLAN_C2SCFG10_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG10_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG10_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG10_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG10_CTRL2 0x0d20 ++#define RTL8367C_SVLAN_C2SCFG10_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG10_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG11_CTRL0 0x0d21 ++#define RTL8367C_SVLAN_C2SCFG11_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG11_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG11_CTRL1 0x0d22 ++#define RTL8367C_SVLAN_C2SCFG11_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG11_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG11_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG11_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG11_CTRL2 0x0d23 ++#define RTL8367C_SVLAN_C2SCFG11_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG11_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG12_CTRL0 0x0d24 ++#define RTL8367C_SVLAN_C2SCFG12_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG12_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG12_CTRL1 0x0d25 ++#define RTL8367C_SVLAN_C2SCFG12_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG12_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG12_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG12_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG12_CTRL2 0x0d26 ++#define RTL8367C_SVLAN_C2SCFG12_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG12_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG13_CTRL0 0x0d27 ++#define RTL8367C_SVLAN_C2SCFG13_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG13_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG13_CTRL1 0x0d28 ++#define RTL8367C_SVLAN_C2SCFG13_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG13_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG13_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG13_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG13_CTRL2 0x0d29 ++#define RTL8367C_SVLAN_C2SCFG13_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG13_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG14_CTRL0 0x0d2a ++#define RTL8367C_SVLAN_C2SCFG14_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG14_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG14_CTRL1 0x0d2b ++#define RTL8367C_SVLAN_C2SCFG14_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG14_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG14_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG14_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG14_CTRL2 0x0d2c ++#define RTL8367C_SVLAN_C2SCFG14_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG14_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG15_CTRL0 0x0d2d ++#define RTL8367C_SVLAN_C2SCFG15_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG15_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG15_CTRL1 0x0d2e ++#define RTL8367C_SVLAN_C2SCFG15_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG15_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG15_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG15_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG15_CTRL2 0x0d2f ++#define RTL8367C_SVLAN_C2SCFG15_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG15_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG16_CTRL0 0x0d30 ++#define RTL8367C_SVLAN_C2SCFG16_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG16_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG16_CTRL1 0x0d31 ++#define RTL8367C_SVLAN_C2SCFG16_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG16_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG16_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG16_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG16_CTRL2 0x0d32 ++#define RTL8367C_SVLAN_C2SCFG16_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG16_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG17_CTRL0 0x0d33 ++#define RTL8367C_SVLAN_C2SCFG17_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG17_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG17_CTRL1 0x0d34 ++#define RTL8367C_SVLAN_C2SCFG17_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG17_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG17_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG17_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG17_CTRL2 0x0d35 ++#define RTL8367C_SVLAN_C2SCFG17_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG17_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG18_CTRL0 0x0d36 ++#define RTL8367C_SVLAN_C2SCFG18_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG18_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG18_CTRL1 0x0d37 ++#define RTL8367C_SVLAN_C2SCFG18_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG18_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG18_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG18_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG18_CTRL2 0x0d38 ++#define RTL8367C_SVLAN_C2SCFG18_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG18_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG19_CTRL0 0x0d39 ++#define RTL8367C_SVLAN_C2SCFG19_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG19_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG19_CTRL1 0x0d3a ++#define RTL8367C_SVLAN_C2SCFG19_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG19_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG19_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG19_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG19_CTRL2 0x0d3b ++#define RTL8367C_SVLAN_C2SCFG19_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG19_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG20_CTRL0 0x0d3c ++#define RTL8367C_SVLAN_C2SCFG20_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG20_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG20_CTRL1 0x0d3d ++#define RTL8367C_SVLAN_C2SCFG20_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG20_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG20_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG20_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG20_CTRL2 0x0d3e ++#define RTL8367C_SVLAN_C2SCFG20_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG20_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG21_CTRL0 0x0d3f ++#define RTL8367C_SVLAN_C2SCFG21_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG21_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG21_CTRL1 0x0d40 ++#define RTL8367C_SVLAN_C2SCFG21_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG21_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG21_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG21_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG21_CTRL2 0x0d41 ++#define RTL8367C_SVLAN_C2SCFG21_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG21_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG22_CTRL0 0x0d42 ++#define RTL8367C_SVLAN_C2SCFG22_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG22_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG22_CTRL1 0x0d43 ++#define RTL8367C_SVLAN_C2SCFG22_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG22_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG22_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG22_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG22_CTRL2 0x0d44 ++#define RTL8367C_SVLAN_C2SCFG22_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG22_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG23_CTRL0 0x0d45 ++#define RTL8367C_SVLAN_C2SCFG23_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG23_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG23_CTRL1 0x0d46 ++#define RTL8367C_SVLAN_C2SCFG23_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG23_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG23_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG23_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG23_CTRL2 0x0d47 ++#define RTL8367C_SVLAN_C2SCFG23_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG23_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG24_CTRL0 0x0d48 ++#define RTL8367C_SVLAN_C2SCFG24_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG24_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG24_CTRL1 0x0d49 ++#define RTL8367C_SVLAN_C2SCFG24_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG24_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG24_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG24_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG24_CTRL2 0x0d4a ++#define RTL8367C_SVLAN_C2SCFG24_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG24_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG25_CTRL0 0x0d4b ++#define RTL8367C_SVLAN_C2SCFG25_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG25_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG25_CTRL1 0x0d4c ++#define RTL8367C_SVLAN_C2SCFG25_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG25_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG25_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG25_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG25_CTRL2 0x0d4d ++#define RTL8367C_SVLAN_C2SCFG25_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG25_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG26_CTRL0 0x0d4e ++#define RTL8367C_SVLAN_C2SCFG26_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG26_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG26_CTRL1 0x0d4f ++#define RTL8367C_SVLAN_C2SCFG26_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG26_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG26_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG26_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG26_CTRL2 0x0d50 ++#define RTL8367C_SVLAN_C2SCFG26_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG26_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG27_CTRL0 0x0d51 ++#define RTL8367C_SVLAN_C2SCFG27_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG27_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG27_CTRL1 0x0d52 ++#define RTL8367C_SVLAN_C2SCFG27_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG27_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG27_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG27_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG27_CTRL2 0x0d53 ++#define RTL8367C_SVLAN_C2SCFG27_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG27_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG28_CTRL0 0x0d54 ++#define RTL8367C_SVLAN_C2SCFG28_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG28_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG28_CTRL1 0x0d55 ++#define RTL8367C_SVLAN_C2SCFG28_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG28_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG28_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG28_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG28_CTRL2 0x0d56 ++#define RTL8367C_SVLAN_C2SCFG28_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG28_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG29_CTRL0 0x0d57 ++#define RTL8367C_SVLAN_C2SCFG29_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG29_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG29_CTRL1 0x0d58 ++#define RTL8367C_SVLAN_C2SCFG29_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG29_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG29_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG29_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG29_CTRL2 0x0d59 ++#define RTL8367C_SVLAN_C2SCFG29_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG29_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG30_CTRL0 0x0d5a ++#define RTL8367C_SVLAN_C2SCFG30_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG30_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG30_CTRL1 0x0d5b ++#define RTL8367C_SVLAN_C2SCFG30_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG30_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG30_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG30_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG30_CTRL2 0x0d5c ++#define RTL8367C_SVLAN_C2SCFG30_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG30_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG31_CTRL0 0x0d5d ++#define RTL8367C_SVLAN_C2SCFG31_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG31_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG31_CTRL1 0x0d5e ++#define RTL8367C_SVLAN_C2SCFG31_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG31_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG31_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG31_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG31_CTRL2 0x0d5f ++#define RTL8367C_SVLAN_C2SCFG31_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG31_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG32_CTRL0 0x0d60 ++#define RTL8367C_SVLAN_C2SCFG32_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG32_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG32_CTRL1 0x0d61 ++#define RTL8367C_SVLAN_C2SCFG32_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG32_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG32_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG32_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG32_CTRL2 0x0d62 ++#define RTL8367C_SVLAN_C2SCFG32_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG32_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG33_CTRL0 0x0d63 ++#define RTL8367C_SVLAN_C2SCFG33_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG33_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG33_CTRL1 0x0d64 ++#define RTL8367C_SVLAN_C2SCFG33_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG33_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG33_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG33_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG33_CTRL2 0x0d65 ++#define RTL8367C_SVLAN_C2SCFG33_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG33_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG34_CTRL0 0x0d66 ++#define RTL8367C_SVLAN_C2SCFG34_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG34_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG34_CTRL1 0x0d67 ++#define RTL8367C_SVLAN_C2SCFG34_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG34_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG34_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG34_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG34_CTRL2 0x0d68 ++#define RTL8367C_SVLAN_C2SCFG34_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG34_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG35_CTRL0 0x0d69 ++#define RTL8367C_SVLAN_C2SCFG35_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG35_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG35_CTRL1 0x0d6a ++#define RTL8367C_SVLAN_C2SCFG35_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG35_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG35_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG35_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG35_CTRL2 0x0d6b ++#define RTL8367C_SVLAN_C2SCFG35_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG35_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG36_CTRL0 0x0d6c ++#define RTL8367C_SVLAN_C2SCFG36_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG36_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG36_CTRL1 0x0d6d ++#define RTL8367C_SVLAN_C2SCFG36_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG36_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG36_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG36_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG36_CTRL2 0x0d6e ++#define RTL8367C_SVLAN_C2SCFG36_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG36_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG37_CTRL0 0x0d6f ++#define RTL8367C_SVLAN_C2SCFG37_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG37_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG37_CTRL1 0x0d70 ++#define RTL8367C_SVLAN_C2SCFG37_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG37_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG37_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG37_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG37_CTRL2 0x0d71 ++#define RTL8367C_SVLAN_C2SCFG37_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG37_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG38_CTRL0 0x0d72 ++#define RTL8367C_SVLAN_C2SCFG38_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG38_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG38_CTRL1 0x0d73 ++#define RTL8367C_SVLAN_C2SCFG38_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG38_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG38_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG38_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG38_CTRL2 0x0d74 ++#define RTL8367C_SVLAN_C2SCFG38_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG38_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG39_CTRL0 0x0d75 ++#define RTL8367C_SVLAN_C2SCFG39_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG39_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG39_CTRL1 0x0d76 ++#define RTL8367C_SVLAN_C2SCFG39_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG39_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG39_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG39_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG39_CTRL2 0x0d77 ++#define RTL8367C_SVLAN_C2SCFG39_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG39_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG40_CTRL0 0x0d78 ++#define RTL8367C_SVLAN_C2SCFG40_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG40_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG40_CTRL1 0x0d79 ++#define RTL8367C_SVLAN_C2SCFG40_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG40_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG40_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG40_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG40_CTRL2 0x0d7a ++#define RTL8367C_SVLAN_C2SCFG40_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG40_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG41_CTRL0 0x0d7b ++#define RTL8367C_SVLAN_C2SCFG41_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG41_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG41_CTRL1 0x0d7c ++#define RTL8367C_SVLAN_C2SCFG41_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG41_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG41_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG41_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG41_CTRL2 0x0d7d ++#define RTL8367C_SVLAN_C2SCFG41_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG41_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG42_CTRL0 0x0d7e ++#define RTL8367C_SVLAN_C2SCFG42_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG42_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG42_CTRL1 0x0d7f ++#define RTL8367C_SVLAN_C2SCFG42_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG42_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG42_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG42_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG42_CTRL2 0x0d80 ++#define RTL8367C_SVLAN_C2SCFG42_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG42_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG43_CTRL0 0x0d81 ++#define RTL8367C_SVLAN_C2SCFG43_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG43_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG43_CTRL1 0x0d82 ++#define RTL8367C_SVLAN_C2SCFG43_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG43_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG43_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG43_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG43_CTRL2 0x0d83 ++#define RTL8367C_SVLAN_C2SCFG43_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG43_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG44_CTRL0 0x0d84 ++#define RTL8367C_SVLAN_C2SCFG44_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG44_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG44_CTRL1 0x0d85 ++#define RTL8367C_SVLAN_C2SCFG44_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG44_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG44_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG44_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG44_CTRL2 0x0d86 ++#define RTL8367C_SVLAN_C2SCFG44_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG44_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG45_CTRL0 0x0d87 ++#define RTL8367C_SVLAN_C2SCFG45_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG45_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG45_CTRL1 0x0d88 ++#define RTL8367C_SVLAN_C2SCFG45_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG45_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG45_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG45_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG45_CTRL2 0x0d89 ++#define RTL8367C_SVLAN_C2SCFG45_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG45_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG46_CTRL0 0x0d8a ++#define RTL8367C_SVLAN_C2SCFG46_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG46_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG46_CTRL1 0x0d8b ++#define RTL8367C_SVLAN_C2SCFG46_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG46_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG46_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG46_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG46_CTRL2 0x0d8c ++#define RTL8367C_SVLAN_C2SCFG46_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG46_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG47_CTRL0 0x0d8d ++#define RTL8367C_SVLAN_C2SCFG47_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG47_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG47_CTRL1 0x0d8e ++#define RTL8367C_SVLAN_C2SCFG47_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG47_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG47_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG47_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG47_CTRL2 0x0d8f ++#define RTL8367C_SVLAN_C2SCFG47_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG47_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG48_CTRL0 0x0d90 ++#define RTL8367C_SVLAN_C2SCFG48_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG48_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG48_CTRL1 0x0d91 ++#define RTL8367C_SVLAN_C2SCFG48_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG48_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG48_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG48_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG48_CTRL2 0x0d92 ++#define RTL8367C_SVLAN_C2SCFG48_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG48_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG49_CTRL0 0x0d93 ++#define RTL8367C_SVLAN_C2SCFG49_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG49_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG49_CTRL1 0x0d94 ++#define RTL8367C_SVLAN_C2SCFG49_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG49_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG49_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG49_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG49_CTRL2 0x0d95 ++#define RTL8367C_SVLAN_C2SCFG49_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG49_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG50_CTRL0 0x0d96 ++#define RTL8367C_SVLAN_C2SCFG50_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG50_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG50_CTRL1 0x0d97 ++#define RTL8367C_SVLAN_C2SCFG50_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG50_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG50_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG50_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG50_CTRL2 0x0d98 ++#define RTL8367C_SVLAN_C2SCFG50_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG50_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG51_CTRL0 0x0d99 ++#define RTL8367C_SVLAN_C2SCFG51_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG51_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG51_CTRL1 0x0d9a ++#define RTL8367C_SVLAN_C2SCFG51_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG51_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG51_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG51_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG51_CTRL2 0x0d9b ++#define RTL8367C_SVLAN_C2SCFG51_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG51_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG52_CTRL0 0x0d9c ++#define RTL8367C_SVLAN_C2SCFG52_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG52_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG52_CTRL1 0x0d9d ++#define RTL8367C_SVLAN_C2SCFG52_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG52_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG52_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG52_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG52_CTRL2 0x0d9e ++#define RTL8367C_SVLAN_C2SCFG52_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG52_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG53_CTRL0 0x0d9f ++#define RTL8367C_SVLAN_C2SCFG53_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG53_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG53_CTRL1 0x0da0 ++#define RTL8367C_SVLAN_C2SCFG53_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG53_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG53_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG53_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG53_CTRL2 0x0da1 ++#define RTL8367C_SVLAN_C2SCFG53_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG53_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG54_CTRL0 0x0da2 ++#define RTL8367C_SVLAN_C2SCFG54_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG54_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG54_CTRL1 0x0da3 ++#define RTL8367C_SVLAN_C2SCFG54_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG54_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG54_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG54_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG54_CTRL2 0x0da4 ++#define RTL8367C_SVLAN_C2SCFG54_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG54_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG55_CTRL0 0x0da5 ++#define RTL8367C_SVLAN_C2SCFG55_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG55_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG55_CTRL1 0x0da6 ++#define RTL8367C_SVLAN_C2SCFG55_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG55_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG55_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG55_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG55_CTRL2 0x0da7 ++#define RTL8367C_SVLAN_C2SCFG55_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG55_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG56_CTRL0 0x0da8 ++#define RTL8367C_SVLAN_C2SCFG56_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG56_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG56_CTRL1 0x0da9 ++#define RTL8367C_SVLAN_C2SCFG56_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG56_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG56_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG56_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG56_CTRL2 0x0daa ++#define RTL8367C_SVLAN_C2SCFG56_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG56_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG57_CTRL0 0x0dab ++#define RTL8367C_SVLAN_C2SCFG57_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG57_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG57_CTRL1 0x0dac ++#define RTL8367C_SVLAN_C2SCFG57_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG57_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG57_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG57_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG57_CTRL2 0x0dad ++#define RTL8367C_SVLAN_C2SCFG57_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG57_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG58_CTRL0 0x0dae ++#define RTL8367C_SVLAN_C2SCFG58_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG58_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG58_CTRL1 0x0daf ++#define RTL8367C_SVLAN_C2SCFG58_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG58_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG58_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG58_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG58_CTRL2 0x0db0 ++#define RTL8367C_SVLAN_C2SCFG58_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG58_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG59_CTRL0 0x0db1 ++#define RTL8367C_SVLAN_C2SCFG59_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG59_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG59_CTRL1 0x0db2 ++#define RTL8367C_SVLAN_C2SCFG59_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG59_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG59_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG59_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG59_CTRL2 0x0db3 ++#define RTL8367C_SVLAN_C2SCFG59_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG59_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG60_CTRL0 0x0db4 ++#define RTL8367C_SVLAN_C2SCFG60_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG60_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG60_CTRL1 0x0db5 ++#define RTL8367C_SVLAN_C2SCFG60_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG60_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG60_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG60_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG60_CTRL2 0x0db6 ++#define RTL8367C_SVLAN_C2SCFG60_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG60_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG61_CTRL0 0x0db7 ++#define RTL8367C_SVLAN_C2SCFG61_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG61_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG61_CTRL1 0x0db8 ++#define RTL8367C_SVLAN_C2SCFG61_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG61_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG61_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG61_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG61_CTRL2 0x0db9 ++#define RTL8367C_SVLAN_C2SCFG61_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG61_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG62_CTRL0 0x0dba ++#define RTL8367C_SVLAN_C2SCFG62_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG62_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG62_CTRL1 0x0dbb ++#define RTL8367C_SVLAN_C2SCFG62_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG62_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG62_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG62_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG62_CTRL2 0x0dbc ++#define RTL8367C_SVLAN_C2SCFG62_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG62_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG63_CTRL0 0x0dbd ++#define RTL8367C_SVLAN_C2SCFG63_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG63_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG63_CTRL1 0x0dbe ++#define RTL8367C_SVLAN_C2SCFG63_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG63_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG63_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG63_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG63_CTRL2 0x0dbf ++#define RTL8367C_SVLAN_C2SCFG63_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG63_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG64_CTRL0 0x0dc0 ++#define RTL8367C_SVLAN_C2SCFG64_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG64_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG64_CTRL1 0x0dc1 ++#define RTL8367C_SVLAN_C2SCFG64_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG64_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG64_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG64_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG64_CTRL2 0x0dc2 ++#define RTL8367C_SVLAN_C2SCFG64_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG64_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG65_CTRL0 0x0dc3 ++#define RTL8367C_SVLAN_C2SCFG65_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG65_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG65_CTRL1 0x0dc4 ++#define RTL8367C_SVLAN_C2SCFG65_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG65_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG65_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG65_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG65_CTRL2 0x0dc5 ++#define RTL8367C_SVLAN_C2SCFG65_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG65_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG66_CTRL0 0x0dc6 ++#define RTL8367C_SVLAN_C2SCFG66_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG66_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG66_CTRL1 0x0dc7 ++#define RTL8367C_SVLAN_C2SCFG66_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG66_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG66_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG66_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG66_CTRL2 0x0dc8 ++#define RTL8367C_SVLAN_C2SCFG66_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG66_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG67_CTRL0 0x0dc9 ++#define RTL8367C_SVLAN_C2SCFG67_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG67_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG67_CTRL1 0x0dca ++#define RTL8367C_SVLAN_C2SCFG67_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG67_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG67_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG67_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG67_CTRL2 0x0dcb ++#define RTL8367C_SVLAN_C2SCFG67_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG67_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG68_CTRL0 0x0dcc ++#define RTL8367C_SVLAN_C2SCFG68_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG68_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG68_CTRL1 0x0dcd ++#define RTL8367C_SVLAN_C2SCFG68_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG68_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG68_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG68_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG68_CTRL2 0x0dce ++#define RTL8367C_SVLAN_C2SCFG68_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG68_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG69_CTRL0 0x0dcf ++#define RTL8367C_SVLAN_C2SCFG69_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG69_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG69_CTRL1 0x0dd0 ++#define RTL8367C_SVLAN_C2SCFG69_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG69_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG69_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG69_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG69_CTRL2 0x0dd1 ++#define RTL8367C_SVLAN_C2SCFG69_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG69_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG70_CTRL0 0x0dd2 ++#define RTL8367C_SVLAN_C2SCFG70_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG70_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG70_CTRL1 0x0dd3 ++#define RTL8367C_SVLAN_C2SCFG70_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG70_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG70_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG70_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG70_CTRL2 0x0dd4 ++#define RTL8367C_SVLAN_C2SCFG70_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG70_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG71_CTRL0 0x0dd5 ++#define RTL8367C_SVLAN_C2SCFG71_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG71_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG71_CTRL1 0x0dd6 ++#define RTL8367C_SVLAN_C2SCFG71_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG71_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG71_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG71_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG71_CTRL2 0x0dd7 ++#define RTL8367C_SVLAN_C2SCFG71_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG71_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG72_CTRL0 0x0dd8 ++#define RTL8367C_SVLAN_C2SCFG72_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG72_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG72_CTRL1 0x0dd9 ++#define RTL8367C_SVLAN_C2SCFG72_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG72_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG72_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG72_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG72_CTRL2 0x0dda ++#define RTL8367C_SVLAN_C2SCFG72_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG72_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG73_CTRL0 0x0ddb ++#define RTL8367C_SVLAN_C2SCFG73_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG73_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG73_CTRL1 0x0ddc ++#define RTL8367C_SVLAN_C2SCFG73_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG73_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG73_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG73_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG73_CTRL2 0x0ddd ++#define RTL8367C_SVLAN_C2SCFG73_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG73_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG74_CTRL0 0x0dde ++#define RTL8367C_SVLAN_C2SCFG74_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG74_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG74_CTRL1 0x0ddf ++#define RTL8367C_SVLAN_C2SCFG74_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG74_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG74_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG74_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG74_CTRL2 0x0de0 ++#define RTL8367C_SVLAN_C2SCFG74_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG74_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG75_CTRL0 0x0de1 ++#define RTL8367C_SVLAN_C2SCFG75_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG75_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG75_CTRL1 0x0de2 ++#define RTL8367C_SVLAN_C2SCFG75_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG75_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG75_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG75_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG75_CTRL2 0x0de3 ++#define RTL8367C_SVLAN_C2SCFG75_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG75_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG76_CTRL0 0x0de4 ++#define RTL8367C_SVLAN_C2SCFG76_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG76_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG76_CTRL1 0x0de5 ++#define RTL8367C_SVLAN_C2SCFG76_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG76_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG76_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG76_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG76_CTRL2 0x0de6 ++#define RTL8367C_SVLAN_C2SCFG76_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG76_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG77_CTRL0 0x0de7 ++#define RTL8367C_SVLAN_C2SCFG77_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG77_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG77_CTRL1 0x0de8 ++#define RTL8367C_SVLAN_C2SCFG77_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG77_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG77_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG77_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG77_CTRL2 0x0de9 ++#define RTL8367C_SVLAN_C2SCFG77_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG77_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG78_CTRL0 0x0dea ++#define RTL8367C_SVLAN_C2SCFG78_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG78_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG78_CTRL1 0x0deb ++#define RTL8367C_SVLAN_C2SCFG78_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG78_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG78_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG78_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG78_CTRL2 0x0dec ++#define RTL8367C_SVLAN_C2SCFG78_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG78_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG79_CTRL0 0x0ded ++#define RTL8367C_SVLAN_C2SCFG79_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG79_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG79_CTRL1 0x0dee ++#define RTL8367C_SVLAN_C2SCFG79_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG79_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG79_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG79_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG79_CTRL2 0x0def ++#define RTL8367C_SVLAN_C2SCFG79_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG79_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG80_CTRL0 0x0df0 ++#define RTL8367C_SVLAN_C2SCFG80_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG80_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG80_CTRL1 0x0df1 ++#define RTL8367C_SVLAN_C2SCFG80_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG80_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG80_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG80_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG80_CTRL2 0x0df2 ++#define RTL8367C_SVLAN_C2SCFG80_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG80_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG81_CTRL0 0x0df3 ++#define RTL8367C_SVLAN_C2SCFG81_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG81_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG81_CTRL1 0x0df4 ++#define RTL8367C_SVLAN_C2SCFG81_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG81_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG81_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG81_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG81_CTRL2 0x0df5 ++#define RTL8367C_SVLAN_C2SCFG81_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG81_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG82_CTRL0 0x0df6 ++#define RTL8367C_SVLAN_C2SCFG82_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG82_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG82_CTRL1 0x0df7 ++#define RTL8367C_SVLAN_C2SCFG82_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG82_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG82_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG82_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG82_CTRL2 0x0df8 ++#define RTL8367C_SVLAN_C2SCFG82_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG82_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG83_CTRL0 0x0df9 ++#define RTL8367C_SVLAN_C2SCFG83_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG83_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG83_CTRL1 0x0dfa ++#define RTL8367C_SVLAN_C2SCFG83_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG83_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG83_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG83_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG83_CTRL2 0x0dfb ++#define RTL8367C_SVLAN_C2SCFG83_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG83_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG84_CTRL0 0x0dfc ++#define RTL8367C_SVLAN_C2SCFG84_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG84_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG84_CTRL1 0x0dfd ++#define RTL8367C_SVLAN_C2SCFG84_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG84_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG84_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG84_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG84_CTRL2 0x0dfe ++#define RTL8367C_SVLAN_C2SCFG84_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG84_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG85_CTRL0 0x0dff ++#define RTL8367C_SVLAN_C2SCFG85_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG85_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG85_CTRL1 0x0e00 ++#define RTL8367C_SVLAN_C2SCFG85_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG85_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG85_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG85_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG85_CTRL2 0x0e01 ++#define RTL8367C_SVLAN_C2SCFG85_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG85_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG86_CTRL0 0x0e02 ++#define RTL8367C_SVLAN_C2SCFG86_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG86_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG86_CTRL1 0x0e03 ++#define RTL8367C_SVLAN_C2SCFG86_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG86_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG86_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG86_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG86_CTRL2 0x0e04 ++#define RTL8367C_SVLAN_C2SCFG86_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG86_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG87_CTRL0 0x0e05 ++#define RTL8367C_SVLAN_C2SCFG87_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG87_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG87_CTRL1 0x0e06 ++#define RTL8367C_SVLAN_C2SCFG87_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG87_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG87_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG87_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG87_CTRL2 0x0e07 ++#define RTL8367C_SVLAN_C2SCFG87_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG87_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG88_CTRL0 0x0e08 ++#define RTL8367C_SVLAN_C2SCFG88_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG88_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG88_CTRL1 0x0e09 ++#define RTL8367C_SVLAN_C2SCFG88_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG88_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG88_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG88_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG88_CTRL2 0x0e0a ++#define RTL8367C_SVLAN_C2SCFG88_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG88_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG89_CTRL0 0x0e0b ++#define RTL8367C_SVLAN_C2SCFG89_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG89_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG89_CTRL1 0x0e0c ++#define RTL8367C_SVLAN_C2SCFG89_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG89_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG89_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG89_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG89_CTRL2 0x0e0d ++#define RTL8367C_SVLAN_C2SCFG89_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG89_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG90_CTRL0 0x0e0e ++#define RTL8367C_SVLAN_C2SCFG90_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG90_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG90_CTRL1 0x0e0f ++#define RTL8367C_SVLAN_C2SCFG90_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG90_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG90_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG90_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG90_CTRL2 0x0e10 ++#define RTL8367C_SVLAN_C2SCFG90_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG90_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG91_CTRL0 0x0e11 ++#define RTL8367C_SVLAN_C2SCFG91_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG91_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG91_CTRL1 0x0e12 ++#define RTL8367C_SVLAN_C2SCFG91_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG91_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG91_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG91_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG91_CTRL2 0x0e13 ++#define RTL8367C_SVLAN_C2SCFG91_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG91_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG92_CTRL0 0x0e14 ++#define RTL8367C_SVLAN_C2SCFG92_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG92_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG92_CTRL1 0x0e15 ++#define RTL8367C_SVLAN_C2SCFG92_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG92_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG92_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG92_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG92_CTRL2 0x0e16 ++#define RTL8367C_SVLAN_C2SCFG92_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG92_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG93_CTRL0 0x0e17 ++#define RTL8367C_SVLAN_C2SCFG93_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG93_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG93_CTRL1 0x0e18 ++#define RTL8367C_SVLAN_C2SCFG93_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG93_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG93_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG93_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG93_CTRL2 0x0e19 ++#define RTL8367C_SVLAN_C2SCFG93_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG93_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG94_CTRL0 0x0e1a ++#define RTL8367C_SVLAN_C2SCFG94_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG94_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG94_CTRL1 0x0e1b ++#define RTL8367C_SVLAN_C2SCFG94_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG94_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG94_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG94_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG94_CTRL2 0x0e1c ++#define RTL8367C_SVLAN_C2SCFG94_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG94_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG95_CTRL0 0x0e1d ++#define RTL8367C_SVLAN_C2SCFG95_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG95_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG95_CTRL1 0x0e1e ++#define RTL8367C_SVLAN_C2SCFG95_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG95_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG95_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG95_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG95_CTRL2 0x0e1f ++#define RTL8367C_SVLAN_C2SCFG95_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG95_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG96_CTRL0 0x0e20 ++#define RTL8367C_SVLAN_C2SCFG96_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG96_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG96_CTRL1 0x0e21 ++#define RTL8367C_SVLAN_C2SCFG96_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG96_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG96_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG96_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG96_CTRL2 0x0e22 ++#define RTL8367C_SVLAN_C2SCFG96_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG96_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG97_CTRL0 0x0e23 ++#define RTL8367C_SVLAN_C2SCFG97_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG97_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG97_CTRL1 0x0e24 ++#define RTL8367C_SVLAN_C2SCFG97_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG97_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG97_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG97_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG97_CTRL2 0x0e25 ++#define RTL8367C_SVLAN_C2SCFG97_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG97_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG98_CTRL0 0x0e26 ++#define RTL8367C_SVLAN_C2SCFG98_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG98_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG98_CTRL1 0x0e27 ++#define RTL8367C_SVLAN_C2SCFG98_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG98_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG98_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG98_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG98_CTRL2 0x0e28 ++#define RTL8367C_SVLAN_C2SCFG98_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG98_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG99_CTRL0 0x0e29 ++#define RTL8367C_SVLAN_C2SCFG99_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG99_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG99_CTRL1 0x0e2a ++#define RTL8367C_SVLAN_C2SCFG99_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG99_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG99_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG99_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG99_CTRL2 0x0e2b ++#define RTL8367C_SVLAN_C2SCFG99_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG99_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG100_CTRL0 0x0e2c ++#define RTL8367C_SVLAN_C2SCFG100_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG100_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG100_CTRL1 0x0e2d ++#define RTL8367C_SVLAN_C2SCFG100_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG100_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG100_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG100_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG100_CTRL2 0x0e2e ++#define RTL8367C_SVLAN_C2SCFG100_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG100_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG101_CTRL0 0x0e2f ++#define RTL8367C_SVLAN_C2SCFG101_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG101_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG101_CTRL1 0x0e30 ++#define RTL8367C_SVLAN_C2SCFG101_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG101_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG101_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG101_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG101_CTRL2 0x0e31 ++#define RTL8367C_SVLAN_C2SCFG101_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG101_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG102_CTRL0 0x0e32 ++#define RTL8367C_SVLAN_C2SCFG102_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG102_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG102_CTRL1 0x0e33 ++#define RTL8367C_SVLAN_C2SCFG102_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG102_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG102_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG102_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG102_CTRL2 0x0e34 ++#define RTL8367C_SVLAN_C2SCFG102_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG102_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG103_CTRL0 0x0e35 ++#define RTL8367C_SVLAN_C2SCFG103_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG103_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG103_CTRL1 0x0e36 ++#define RTL8367C_SVLAN_C2SCFG103_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG103_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG103_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG103_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG103_CTRL2 0x0e37 ++#define RTL8367C_SVLAN_C2SCFG103_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG103_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG104_CTRL0 0x0e38 ++#define RTL8367C_SVLAN_C2SCFG104_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG104_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG104_CTRL1 0x0e39 ++#define RTL8367C_SVLAN_C2SCFG104_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG104_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG104_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG104_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG104_CTRL2 0x0e3a ++#define RTL8367C_SVLAN_C2SCFG104_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG104_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG105_CTRL0 0x0e3b ++#define RTL8367C_SVLAN_C2SCFG105_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG105_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG105_CTRL1 0x0e3c ++#define RTL8367C_SVLAN_C2SCFG105_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG105_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG105_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG105_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG105_CTRL2 0x0e3d ++#define RTL8367C_SVLAN_C2SCFG105_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG105_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG106_CTRL0 0x0e3e ++#define RTL8367C_SVLAN_C2SCFG106_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG106_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG106_CTRL1 0x0e3f ++#define RTL8367C_SVLAN_C2SCFG106_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG106_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG106_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG106_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG106_CTRL2 0x0e40 ++#define RTL8367C_SVLAN_C2SCFG106_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG106_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG107_CTRL0 0x0e41 ++#define RTL8367C_SVLAN_C2SCFG107_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG107_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG107_CTRL1 0x0e42 ++#define RTL8367C_SVLAN_C2SCFG107_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG107_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG107_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG107_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG107_CTRL2 0x0e43 ++#define RTL8367C_SVLAN_C2SCFG107_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG107_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG108_CTRL0 0x0e44 ++#define RTL8367C_SVLAN_C2SCFG108_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG108_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG108_CTRL1 0x0e45 ++#define RTL8367C_SVLAN_C2SCFG108_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG108_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG108_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG108_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG108_CTRL2 0x0e46 ++#define RTL8367C_SVLAN_C2SCFG108_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG108_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG109_CTRL0 0x0e47 ++#define RTL8367C_SVLAN_C2SCFG109_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG109_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG109_CTRL1 0x0e48 ++#define RTL8367C_SVLAN_C2SCFG109_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG109_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG109_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG109_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG109_CTRL2 0x0e49 ++#define RTL8367C_SVLAN_C2SCFG109_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG109_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG110_CTRL0 0x0e4a ++#define RTL8367C_SVLAN_C2SCFG110_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG110_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG110_CTRL1 0x0e4b ++#define RTL8367C_SVLAN_C2SCFG110_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG110_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG110_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG110_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG110_CTRL2 0x0e4c ++#define RTL8367C_SVLAN_C2SCFG110_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG110_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG111_CTRL0 0x0e4d ++#define RTL8367C_SVLAN_C2SCFG111_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG111_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG111_CTRL1 0x0e4e ++#define RTL8367C_SVLAN_C2SCFG111_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG111_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG111_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG111_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG111_CTRL2 0x0e4f ++#define RTL8367C_SVLAN_C2SCFG111_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG111_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG112_CTRL0 0x0e50 ++#define RTL8367C_SVLAN_C2SCFG112_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG112_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG112_CTRL1 0x0e51 ++#define RTL8367C_SVLAN_C2SCFG112_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG112_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG112_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG112_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG112_CTRL2 0x0e52 ++#define RTL8367C_SVLAN_C2SCFG112_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG112_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG113_CTRL0 0x0e53 ++#define RTL8367C_SVLAN_C2SCFG113_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG113_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG113_CTRL1 0x0e54 ++#define RTL8367C_SVLAN_C2SCFG113_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG113_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG113_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG113_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG113_CTRL2 0x0e55 ++#define RTL8367C_SVLAN_C2SCFG113_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG113_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG114_CTRL0 0x0e56 ++#define RTL8367C_SVLAN_C2SCFG114_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG114_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG114_CTRL1 0x0e57 ++#define RTL8367C_SVLAN_C2SCFG114_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG114_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG114_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG114_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG114_CTRL2 0x0e58 ++#define RTL8367C_SVLAN_C2SCFG114_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG114_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG115_CTRL0 0x0e59 ++#define RTL8367C_SVLAN_C2SCFG115_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG115_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG115_CTRL1 0x0e5a ++#define RTL8367C_SVLAN_C2SCFG115_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG115_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG115_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG115_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG115_CTRL2 0x0e5b ++#define RTL8367C_SVLAN_C2SCFG115_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG115_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG116_CTRL0 0x0e5c ++#define RTL8367C_SVLAN_C2SCFG116_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG116_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG116_CTRL1 0x0e5d ++#define RTL8367C_SVLAN_C2SCFG116_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG116_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG116_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG116_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG116_CTRL2 0x0e5e ++#define RTL8367C_SVLAN_C2SCFG116_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG116_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG117_CTRL0 0x0e5f ++#define RTL8367C_SVLAN_C2SCFG117_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG117_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG117_CTRL1 0x0e60 ++#define RTL8367C_SVLAN_C2SCFG117_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG117_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG117_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG117_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG117_CTRL2 0x0e61 ++#define RTL8367C_SVLAN_C2SCFG117_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG117_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG118_CTRL0 0x0e62 ++#define RTL8367C_SVLAN_C2SCFG118_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG118_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG118_CTRL1 0x0e63 ++#define RTL8367C_SVLAN_C2SCFG118_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG118_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG118_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG118_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG118_CTRL2 0x0e64 ++#define RTL8367C_SVLAN_C2SCFG118_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG118_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG119_CTRL0 0x0e65 ++#define RTL8367C_SVLAN_C2SCFG119_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG119_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG119_CTRL1 0x0e66 ++#define RTL8367C_SVLAN_C2SCFG119_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG119_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG119_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG119_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG119_CTRL2 0x0e67 ++#define RTL8367C_SVLAN_C2SCFG119_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG119_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG120_CTRL0 0x0e68 ++#define RTL8367C_SVLAN_C2SCFG120_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG120_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG120_CTRL1 0x0e69 ++#define RTL8367C_SVLAN_C2SCFG120_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG120_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG120_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG120_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG120_CTRL2 0x0e6a ++#define RTL8367C_SVLAN_C2SCFG120_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG120_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG121_CTRL0 0x0e6b ++#define RTL8367C_SVLAN_C2SCFG121_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG121_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG121_CTRL1 0x0e6c ++#define RTL8367C_SVLAN_C2SCFG121_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG121_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG121_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG121_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG121_CTRL2 0x0e6d ++#define RTL8367C_SVLAN_C2SCFG121_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG121_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG122_CTRL0 0x0e6e ++#define RTL8367C_SVLAN_C2SCFG122_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG122_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG122_CTRL1 0x0e6f ++#define RTL8367C_SVLAN_C2SCFG122_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG122_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG122_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG122_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG122_CTRL2 0x0e70 ++#define RTL8367C_SVLAN_C2SCFG122_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG122_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG123_CTRL0 0x0e71 ++#define RTL8367C_SVLAN_C2SCFG123_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG123_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG123_CTRL1 0x0e72 ++#define RTL8367C_SVLAN_C2SCFG123_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG123_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG123_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG123_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG123_CTRL2 0x0e73 ++#define RTL8367C_SVLAN_C2SCFG123_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG123_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG124_CTRL0 0x0e74 ++#define RTL8367C_SVLAN_C2SCFG124_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG124_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG124_CTRL1 0x0e75 ++#define RTL8367C_SVLAN_C2SCFG124_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG124_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG124_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG124_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG124_CTRL2 0x0e76 ++#define RTL8367C_SVLAN_C2SCFG124_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG124_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG125_CTRL0 0x0e77 ++#define RTL8367C_SVLAN_C2SCFG125_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG125_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG125_CTRL1 0x0e78 ++#define RTL8367C_SVLAN_C2SCFG125_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG125_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG125_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG125_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG125_CTRL2 0x0e79 ++#define RTL8367C_SVLAN_C2SCFG125_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG125_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG126_CTRL0 0x0e7a ++#define RTL8367C_SVLAN_C2SCFG126_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG126_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG126_CTRL1 0x0e7b ++#define RTL8367C_SVLAN_C2SCFG126_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG126_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG126_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG126_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG126_CTRL2 0x0e7c ++#define RTL8367C_SVLAN_C2SCFG126_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG126_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG127_CTRL0 0x0e7d ++#define RTL8367C_SVLAN_C2SCFG127_CTRL0_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG127_CTRL0_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_C2SCFG127_CTRL1 0x0e7e ++#define RTL8367C_SVLAN_C2SCFG127_CTRL1_C2SENPMSK_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_C2SCFG127_CTRL1_C2SENPMSK_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_C2SCFG127_CTRL1_C2SENPMSK_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG127_CTRL1_C2SENPMSK_MASK 0xFF ++ ++#define RTL8367C_REG_SVLAN_C2SCFG127_CTRL2 0x0e7f ++#define RTL8367C_SVLAN_C2SCFG127_CTRL2_OFFSET 0 ++#define RTL8367C_SVLAN_C2SCFG127_CTRL2_MASK 0x1FFF ++ ++#define RTL8367C_REG_SVLAN_CFG 0x0e80 ++#define RTL8367C_VS_PORT7_DMACVIDSEL_OFFSET 14 ++#define RTL8367C_VS_PORT7_DMACVIDSEL_MASK 0x4000 ++#define RTL8367C_VS_PORT6_DMACVIDSEL_OFFSET 13 ++#define RTL8367C_VS_PORT6_DMACVIDSEL_MASK 0x2000 ++#define RTL8367C_VS_PORT5_DMACVIDSEL_OFFSET 12 ++#define RTL8367C_VS_PORT5_DMACVIDSEL_MASK 0x1000 ++#define RTL8367C_VS_PORT4_DMACVIDSEL_OFFSET 11 ++#define RTL8367C_VS_PORT4_DMACVIDSEL_MASK 0x800 ++#define RTL8367C_VS_PORT3_DMACVIDSEL_OFFSET 10 ++#define RTL8367C_VS_PORT3_DMACVIDSEL_MASK 0x400 ++#define RTL8367C_VS_PORT2_DMACVIDSEL_OFFSET 9 ++#define RTL8367C_VS_PORT2_DMACVIDSEL_MASK 0x200 ++#define RTL8367C_VS_PORT1_DMACVIDSEL_OFFSET 8 ++#define RTL8367C_VS_PORT1_DMACVIDSEL_MASK 0x100 ++#define RTL8367C_VS_PORT0_DMACVIDSEL_OFFSET 7 ++#define RTL8367C_VS_PORT0_DMACVIDSEL_MASK 0x80 ++#define RTL8367C_VS_UIFSEG_OFFSET 6 ++#define RTL8367C_VS_UIFSEG_MASK 0x40 ++#define RTL8367C_VS_UNMAT_OFFSET 4 ++#define RTL8367C_VS_UNMAT_MASK 0x30 ++#define RTL8367C_VS_UNTAG_OFFSET 2 ++#define RTL8367C_VS_UNTAG_MASK 0xC ++#define RTL8367C_VS_SPRISEL_OFFSET 0 ++#define RTL8367C_VS_SPRISEL_MASK 0x3 ++ ++#define RTL8367C_REG_SVLAN_PORTBASED_SVIDX_CTRL0 0x0e81 ++#define RTL8367C_VS_PORT1_SVIDX_OFFSET 8 ++#define RTL8367C_VS_PORT1_SVIDX_MASK 0x3F00 ++#define RTL8367C_VS_PORT0_SVIDX_OFFSET 0 ++#define RTL8367C_VS_PORT0_SVIDX_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_PORTBASED_SVIDX_CTRL1 0x0e82 ++#define RTL8367C_VS_PORT3_SVIDX_OFFSET 8 ++#define RTL8367C_VS_PORT3_SVIDX_MASK 0x3F00 ++#define RTL8367C_VS_PORT2_SVIDX_OFFSET 0 ++#define RTL8367C_VS_PORT2_SVIDX_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_PORTBASED_SVIDX_CTRL2 0x0e83 ++#define RTL8367C_VS_PORT5_SVIDX_OFFSET 8 ++#define RTL8367C_VS_PORT5_SVIDX_MASK 0x3F00 ++#define RTL8367C_VS_PORT4_SVIDX_OFFSET 0 ++#define RTL8367C_VS_PORT4_SVIDX_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_PORTBASED_SVIDX_CTRL3 0x0e84 ++#define RTL8367C_VS_PORT7_SVIDX_OFFSET 8 ++#define RTL8367C_VS_PORT7_SVIDX_MASK 0x3F00 ++#define RTL8367C_VS_PORT6_SVIDX_OFFSET 0 ++#define RTL8367C_VS_PORT6_SVIDX_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_UNTAG_UNMAT_CFG 0x0e85 ++#define RTL8367C_VS_UNTAG_SVIDX_OFFSET 8 ++#define RTL8367C_VS_UNTAG_SVIDX_MASK 0x3F00 ++#define RTL8367C_VS_UNMAT_SVIDX_OFFSET 0 ++#define RTL8367C_VS_UNMAT_SVIDX_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_LOOKUP_TYPE 0x0e86 ++#define RTL8367C_SVLAN_LOOKUP_TYPE_OFFSET 0 ++#define RTL8367C_SVLAN_LOOKUP_TYPE_MASK 0x1 ++ ++#define RTL8367C_REG_IPMC_GROUP_VALID_15_0 0x0e87 ++ ++#define RTL8367C_REG_IPMC_GROUP_VALID_31_16 0x0e88 ++ ++#define RTL8367C_REG_IPMC_GROUP_VALID_47_32 0x0e89 ++ ++#define RTL8367C_REG_IPMC_GROUP_VALID_63_48 0x0e8a ++ ++#define RTL8367C_REG_SVLAN_PORTBASED_SVIDX_CTRL4 0x0e8b ++#define RTL8367C_VS_PORT9_SVIDX_OFFSET 8 ++#define RTL8367C_VS_PORT9_SVIDX_MASK 0x3F00 ++#define RTL8367C_VS_PORT8_SVIDX_OFFSET 0 ++#define RTL8367C_VS_PORT8_SVIDX_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_PORTBASED_SVIDX_CTRL5 0x0e8c ++#define RTL8367C_SVLAN_PORTBASED_SVIDX_CTRL5_OFFSET 0 ++#define RTL8367C_SVLAN_PORTBASED_SVIDX_CTRL5_MASK 0x3F ++ ++#define RTL8367C_REG_SVLAN_CFG_EXT 0x0e8d ++#define RTL8367C_VS_PORT10_DMACVIDSEL_OFFSET 2 ++#define RTL8367C_VS_PORT10_DMACVIDSEL_MASK 0x4 ++#define RTL8367C_VS_PORT9_DMACVIDSEL_OFFSET 1 ++#define RTL8367C_VS_PORT9_DMACVIDSEL_MASK 0x2 ++#define RTL8367C_VS_PORT8_DMACVIDSEL_OFFSET 0 ++#define RTL8367C_VS_PORT8_DMACVIDSEL_MASK 0x1 ++ ++#define RTL8367C_REG_SVLAN_MEMBERCFG63_CTRL4 0x0e8e ++#define RTL8367C_SVLAN_MEMBERCFG63_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 ++#define RTL8367C_SVLAN_MEMBERCFG63_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 ++#define RTL8367C_SVLAN_MEMBERCFG63_CTRL4_VS_SMBR_EXT_OFFSET 0 ++#define RTL8367C_SVLAN_MEMBERCFG63_CTRL4_VS_SMBR_EXT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_DUMMY_0 0x0e90 ++ ++#define RTL8367C_REG_SVLAN_DUMMY_1 0x0e91 ++ ++#define RTL8367C_REG_SVLAN_DUMMY_2 0x0e92 ++ ++#define RTL8367C_REG_SVLAN_DUMMY_3 0x0e93 ++ ++#define RTL8367C_REG_SVLAN_DUMMY_4 0x0e94 ++ ++#define RTL8367C_REG_SVLAN_DUMMY_5 0x0e95 ++ ++#define RTL8367C_REG_SVLAN_DUMMY_6 0x0e96 ++ ++#define RTL8367C_REG_SVLAN_DUMMY_7 0x0e97 ++ ++#define RTL8367C_REG_SVLAN_DUMMY_8 0x0e98 ++ ++#define RTL8367C_REG_SVLAN_DUMMY_9 0x0e99 ++ ++#define RTL8367C_REG_SVLAN_DUMMY_10 0x0e9a ++ ++#define RTL8367C_REG_SVLAN_DUMMY_11 0x0e9b ++ ++#define RTL8367C_REG_SVLAN_DUMMY_12 0x0e9c ++ ++#define RTL8367C_REG_SVLAN_DUMMY_13 0x0e9d ++ ++#define RTL8367C_REG_SVLAN_DUMMY_14 0x0e9e ++ ++#define RTL8367C_REG_SVLAN_DUMMY_15 0x0e9f ++ ++#define RTL8367C_REG_SVLAN_DUMMY_16 0x0ea0 ++ ++#define RTL8367C_REG_SVLAN_DUMMY_17 0x0ea1 ++ ++#define RTL8367C_REG_SVLAN_DUMMY_18 0x0ea2 ++ ++#define RTL8367C_REG_SVLAN_DUMMY_19 0x0ea3 ++ ++#define RTL8367C_REG_SVLAN_DUMMY_20 0x0ea4 ++ ++#define RTL8367C_REG_SVLAN_DUMMY_21 0x0ea5 ++ ++#define RTL8367C_REG_SVLAN_DUMMY_22 0x0ea6 ++ ++#define RTL8367C_REG_SVLAN_DUMMY_23 0x0ea7 ++ ++#define RTL8367C_REG_SVLAN_DUMMY_24 0x0ea8 ++ ++#define RTL8367C_REG_SVLAN_DUMMY_25 0x0ea9 ++ ++#define RTL8367C_REG_SVLAN_DUMMY_26 0x0eaa ++ ++#define RTL8367C_REG_SVLAN_DUMMY_27 0x0eab ++ ++#define RTL8367C_REG_SVLAN_DUMMY_28 0x0eac ++ ++#define RTL8367C_REG_SVLAN_DUMMY_29 0x0ead ++ ++#define RTL8367C_REG_SVLAN_DUMMY_30 0x0eae ++ ++#define RTL8367C_REG_SVLAN_DUMMY_31 0x0eaf ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_00 0x0eb0 ++#define RTL8367C_IPMC_GROUP_VID_00_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_00_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_01 0x0eb1 ++#define RTL8367C_IPMC_GROUP_VID_01_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_01_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_02 0x0eb2 ++#define RTL8367C_IPMC_GROUP_VID_02_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_02_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_03 0x0eb3 ++#define RTL8367C_IPMC_GROUP_VID_03_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_03_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_04 0x0eb4 ++#define RTL8367C_IPMC_GROUP_VID_04_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_04_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_05 0x0eb5 ++#define RTL8367C_IPMC_GROUP_VID_05_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_05_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_06 0x0eb6 ++#define RTL8367C_IPMC_GROUP_VID_06_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_06_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_07 0x0eb7 ++#define RTL8367C_IPMC_GROUP_VID_07_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_07_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_08 0x0eb8 ++#define RTL8367C_IPMC_GROUP_VID_08_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_08_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_09 0x0eb9 ++#define RTL8367C_IPMC_GROUP_VID_09_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_09_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_10 0x0eba ++#define RTL8367C_IPMC_GROUP_VID_10_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_10_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_11 0x0ebb ++#define RTL8367C_IPMC_GROUP_VID_11_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_11_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_12 0x0ebc ++#define RTL8367C_IPMC_GROUP_VID_12_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_12_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_13 0x0ebd ++#define RTL8367C_IPMC_GROUP_VID_13_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_13_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_14 0x0ebe ++#define RTL8367C_IPMC_GROUP_VID_14_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_14_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_15 0x0ebf ++#define RTL8367C_IPMC_GROUP_VID_15_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_15_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_16 0x0ec0 ++#define RTL8367C_IPMC_GROUP_VID_16_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_16_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_17 0x0ec1 ++#define RTL8367C_IPMC_GROUP_VID_17_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_17_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_18 0x0ec2 ++#define RTL8367C_IPMC_GROUP_VID_18_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_18_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_19 0x0ec3 ++#define RTL8367C_IPMC_GROUP_VID_19_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_19_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_20 0x0ec4 ++#define RTL8367C_IPMC_GROUP_VID_20_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_20_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_21 0x0ec5 ++#define RTL8367C_IPMC_GROUP_VID_21_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_21_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_22 0x0ec6 ++#define RTL8367C_IPMC_GROUP_VID_22_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_22_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_23 0x0ec7 ++#define RTL8367C_IPMC_GROUP_VID_23_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_23_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_24 0x0ec8 ++#define RTL8367C_IPMC_GROUP_VID_24_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_24_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_25 0x0ec9 ++#define RTL8367C_IPMC_GROUP_VID_25_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_25_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_26 0x0eca ++#define RTL8367C_IPMC_GROUP_VID_26_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_26_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_27 0x0ecb ++#define RTL8367C_IPMC_GROUP_VID_27_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_27_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_28 0x0ecc ++#define RTL8367C_IPMC_GROUP_VID_28_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_28_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_29 0x0ecd ++#define RTL8367C_IPMC_GROUP_VID_29_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_29_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_30 0x0ece ++#define RTL8367C_IPMC_GROUP_VID_30_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_30_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_31 0x0ecf ++#define RTL8367C_IPMC_GROUP_VID_31_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_31_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_32 0x0ed0 ++#define RTL8367C_IPMC_GROUP_VID_32_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_32_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_33 0x0ed1 ++#define RTL8367C_IPMC_GROUP_VID_33_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_33_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_34 0x0ed2 ++#define RTL8367C_IPMC_GROUP_VID_34_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_34_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_35 0x0ed3 ++#define RTL8367C_IPMC_GROUP_VID_35_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_35_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_36 0x0ed4 ++#define RTL8367C_IPMC_GROUP_VID_36_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_36_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_37 0x0ed5 ++#define RTL8367C_IPMC_GROUP_VID_37_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_37_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_38 0x0ed6 ++#define RTL8367C_IPMC_GROUP_VID_38_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_38_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_39 0x0ed7 ++#define RTL8367C_IPMC_GROUP_VID_39_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_39_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_40 0x0ed8 ++#define RTL8367C_IPMC_GROUP_VID_40_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_40_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_41 0x0ed9 ++#define RTL8367C_IPMC_GROUP_VID_41_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_41_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_42 0x0eda ++#define RTL8367C_IPMC_GROUP_VID_42_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_42_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_43 0x0edb ++#define RTL8367C_IPMC_GROUP_VID_43_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_43_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_44 0x0edc ++#define RTL8367C_IPMC_GROUP_VID_44_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_44_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_45 0x0edd ++#define RTL8367C_IPMC_GROUP_VID_45_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_45_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_46 0x0ede ++#define RTL8367C_IPMC_GROUP_VID_46_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_46_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_47 0x0edf ++#define RTL8367C_IPMC_GROUP_VID_47_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_47_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_48 0x0ef0 ++#define RTL8367C_IPMC_GROUP_VID_48_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_48_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_49 0x0ef1 ++#define RTL8367C_IPMC_GROUP_VID_49_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_49_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_50 0x0ef2 ++#define RTL8367C_IPMC_GROUP_VID_50_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_50_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_51 0x0ef3 ++#define RTL8367C_IPMC_GROUP_VID_51_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_51_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_52 0x0ef4 ++#define RTL8367C_IPMC_GROUP_VID_52_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_52_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_53 0x0ef5 ++#define RTL8367C_IPMC_GROUP_VID_53_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_53_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_54 0x0ef6 ++#define RTL8367C_IPMC_GROUP_VID_54_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_54_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_55 0x0ef7 ++#define RTL8367C_IPMC_GROUP_VID_55_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_55_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_56 0x0ef8 ++#define RTL8367C_IPMC_GROUP_VID_56_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_56_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_57 0x0ef9 ++#define RTL8367C_IPMC_GROUP_VID_57_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_57_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_58 0x0efa ++#define RTL8367C_IPMC_GROUP_VID_58_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_58_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_59 0x0efb ++#define RTL8367C_IPMC_GROUP_VID_59_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_59_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_60 0x0efc ++#define RTL8367C_IPMC_GROUP_VID_60_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_60_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_61 0x0efd ++#define RTL8367C_IPMC_GROUP_VID_61_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_61_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_62 0x0efe ++#define RTL8367C_IPMC_GROUP_VID_62_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_62_MASK 0xFFF ++ ++#define RTL8367C_REG_IPMC_GROUP_VID_63 0x0eff ++#define RTL8367C_IPMC_GROUP_VID_63_OFFSET 0 ++#define RTL8367C_IPMC_GROUP_VID_63_MASK 0xFFF ++ ++/* (16'h0f00)hsactrl_reg */ ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY0_CTRL0 0x0f00 ++#define RTL8367C_SVLAN_SP2C_ENTRY0_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY0_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY0_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY0_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY0_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY0_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY0_CTRL1 0x0f01 ++#define RTL8367C_SVLAN_SP2C_ENTRY0_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY0_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY0_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY0_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY1_CTRL0 0x0f02 ++#define RTL8367C_SVLAN_SP2C_ENTRY1_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY1_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY1_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY1_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY1_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY1_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY1_CTRL1 0x0f03 ++#define RTL8367C_SVLAN_SP2C_ENTRY1_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY1_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY1_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY1_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY2_CTRL0 0x0f04 ++#define RTL8367C_SVLAN_SP2C_ENTRY2_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY2_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY2_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY2_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY2_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY2_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY2_CTRL1 0x0f05 ++#define RTL8367C_SVLAN_SP2C_ENTRY2_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY2_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY2_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY2_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY3_CTRL0 0x0f06 ++#define RTL8367C_SVLAN_SP2C_ENTRY3_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY3_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY3_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY3_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY3_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY3_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY3_CTRL1 0x0f07 ++#define RTL8367C_SVLAN_SP2C_ENTRY3_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY3_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY3_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY3_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY4_CTRL0 0x0f08 ++#define RTL8367C_SVLAN_SP2C_ENTRY4_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY4_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY4_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY4_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY4_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY4_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY4_CTRL1 0x0f09 ++#define RTL8367C_SVLAN_SP2C_ENTRY4_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY4_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY4_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY4_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY5_CTRL0 0x0f0a ++#define RTL8367C_SVLAN_SP2C_ENTRY5_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY5_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY5_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY5_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY5_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY5_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY5_CTRL1 0x0f0b ++#define RTL8367C_SVLAN_SP2C_ENTRY5_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY5_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY5_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY5_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY6_CTRL0 0x0f0c ++#define RTL8367C_SVLAN_SP2C_ENTRY6_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY6_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY6_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY6_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY6_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY6_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY6_CTRL1 0x0f0d ++#define RTL8367C_SVLAN_SP2C_ENTRY6_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY6_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY6_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY6_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY7_CTRL0 0x0f0e ++#define RTL8367C_SVLAN_SP2C_ENTRY7_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY7_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY7_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY7_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY7_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY7_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY7_CTRL1 0x0f0f ++#define RTL8367C_SVLAN_SP2C_ENTRY7_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY7_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY7_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY7_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY8_CTRL0 0x0f10 ++#define RTL8367C_SVLAN_SP2C_ENTRY8_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY8_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY8_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY8_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY8_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY8_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY8_CTRL1 0x0f11 ++#define RTL8367C_SVLAN_SP2C_ENTRY8_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY8_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY8_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY8_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY9_CTRL0 0x0f12 ++#define RTL8367C_SVLAN_SP2C_ENTRY9_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY9_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY9_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY9_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY9_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY9_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY9_CTRL1 0x0f13 ++#define RTL8367C_SVLAN_SP2C_ENTRY9_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY9_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY9_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY9_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY10_CTRL0 0x0f14 ++#define RTL8367C_SVLAN_SP2C_ENTRY10_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY10_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY10_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY10_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY10_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY10_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY10_CTRL1 0x0f15 ++#define RTL8367C_SVLAN_SP2C_ENTRY10_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY10_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY10_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY10_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY11_CTRL0 0x0f16 ++#define RTL8367C_SVLAN_SP2C_ENTRY11_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY11_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY11_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY11_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY11_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY11_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY11_CTRL1 0x0f17 ++#define RTL8367C_SVLAN_SP2C_ENTRY11_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY11_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY11_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY11_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY12_CTRL0 0x0f18 ++#define RTL8367C_SVLAN_SP2C_ENTRY12_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY12_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY12_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY12_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY12_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY12_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY12_CTRL1 0x0f19 ++#define RTL8367C_SVLAN_SP2C_ENTRY12_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY12_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY12_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY12_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY13_CTRL0 0x0f1a ++#define RTL8367C_SVLAN_SP2C_ENTRY13_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY13_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY13_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY13_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY13_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY13_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY13_CTRL1 0x0f1b ++#define RTL8367C_SVLAN_SP2C_ENTRY13_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY13_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY13_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY13_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY14_CTRL0 0x0f1c ++#define RTL8367C_SVLAN_SP2C_ENTRY14_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY14_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY14_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY14_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY14_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY14_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY14_CTRL1 0x0f1d ++#define RTL8367C_SVLAN_SP2C_ENTRY14_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY14_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY14_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY14_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY15_CTRL0 0x0f1e ++#define RTL8367C_SVLAN_SP2C_ENTRY15_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY15_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY15_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY15_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY15_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY15_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY15_CTRL1 0x0f1f ++#define RTL8367C_SVLAN_SP2C_ENTRY15_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY15_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY15_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY15_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY16_CTRL0 0x0f20 ++#define RTL8367C_SVLAN_SP2C_ENTRY16_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY16_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY16_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY16_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY16_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY16_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY16_CTRL1 0x0f21 ++#define RTL8367C_SVLAN_SP2C_ENTRY16_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY16_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY16_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY16_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY17_CTRL0 0x0f22 ++#define RTL8367C_SVLAN_SP2C_ENTRY17_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY17_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY17_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY17_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY17_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY17_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY17_CTRL1 0x0f23 ++#define RTL8367C_SVLAN_SP2C_ENTRY17_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY17_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY17_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY17_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY18_CTRL0 0x0f24 ++#define RTL8367C_SVLAN_SP2C_ENTRY18_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY18_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY18_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY18_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY18_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY18_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY18_CTRL1 0x0f25 ++#define RTL8367C_SVLAN_SP2C_ENTRY18_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY18_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY18_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY18_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY19_CTRL0 0x0f26 ++#define RTL8367C_SVLAN_SP2C_ENTRY19_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY19_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY19_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY19_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY19_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY19_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY19_CTRL1 0x0f27 ++#define RTL8367C_SVLAN_SP2C_ENTRY19_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY19_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY19_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY19_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY20_CTRL0 0x0f28 ++#define RTL8367C_SVLAN_SP2C_ENTRY20_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY20_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY20_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY20_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY20_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY20_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY20_CTRL1 0x0f29 ++#define RTL8367C_SVLAN_SP2C_ENTRY20_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY20_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY20_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY20_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY21_CTRL0 0x0f2a ++#define RTL8367C_SVLAN_SP2C_ENTRY21_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY21_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY21_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY21_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY21_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY21_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY21_CTRL1 0x0f2b ++#define RTL8367C_SVLAN_SP2C_ENTRY21_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY21_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY21_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY21_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY22_CTRL0 0x0f2c ++#define RTL8367C_SVLAN_SP2C_ENTRY22_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY22_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY22_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY22_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY22_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY22_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY22_CTRL1 0x0f2d ++#define RTL8367C_SVLAN_SP2C_ENTRY22_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY22_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY22_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY22_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY23_CTRL0 0x0f2e ++#define RTL8367C_SVLAN_SP2C_ENTRY23_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY23_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY23_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY23_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY23_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY23_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY23_CTRL1 0x0f2f ++#define RTL8367C_SVLAN_SP2C_ENTRY23_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY23_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY23_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY23_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY24_CTRL0 0x0f30 ++#define RTL8367C_SVLAN_SP2C_ENTRY24_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY24_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY24_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY24_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY24_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY24_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY24_CTRL1 0x0f31 ++#define RTL8367C_SVLAN_SP2C_ENTRY24_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY24_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY24_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY24_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY25_CTRL0 0x0f32 ++#define RTL8367C_SVLAN_SP2C_ENTRY25_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY25_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY25_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY25_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY25_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY25_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY25_CTRL1 0x0f33 ++#define RTL8367C_SVLAN_SP2C_ENTRY25_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY25_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY25_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY25_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY26_CTRL0 0x0f34 ++#define RTL8367C_SVLAN_SP2C_ENTRY26_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY26_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY26_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY26_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY26_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY26_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY26_CTRL1 0x0f35 ++#define RTL8367C_SVLAN_SP2C_ENTRY26_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY26_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY26_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY26_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY27_CTRL0 0x0f36 ++#define RTL8367C_SVLAN_SP2C_ENTRY27_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY27_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY27_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY27_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY27_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY27_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY27_CTRL1 0x0f37 ++#define RTL8367C_SVLAN_SP2C_ENTRY27_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY27_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY27_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY27_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY28_CTRL0 0x0f38 ++#define RTL8367C_SVLAN_SP2C_ENTRY28_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY28_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY28_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY28_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY28_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY28_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY28_CTRL1 0x0f39 ++#define RTL8367C_SVLAN_SP2C_ENTRY28_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY28_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY28_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY28_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY29_CTRL0 0x0f3a ++#define RTL8367C_SVLAN_SP2C_ENTRY29_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY29_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY29_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY29_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY29_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY29_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY29_CTRL1 0x0f3b ++#define RTL8367C_SVLAN_SP2C_ENTRY29_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY29_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY29_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY29_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY30_CTRL0 0x0f3c ++#define RTL8367C_SVLAN_SP2C_ENTRY30_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY30_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY30_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY30_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY30_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY30_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY30_CTRL1 0x0f3d ++#define RTL8367C_SVLAN_SP2C_ENTRY30_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY30_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY30_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY30_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY31_CTRL0 0x0f3e ++#define RTL8367C_SVLAN_SP2C_ENTRY31_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY31_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY31_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY31_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY31_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY31_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY31_CTRL1 0x0f3f ++#define RTL8367C_SVLAN_SP2C_ENTRY31_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY31_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY31_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY31_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY32_CTRL0 0x0f40 ++#define RTL8367C_SVLAN_SP2C_ENTRY32_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY32_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY32_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY32_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY32_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY32_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY32_CTRL1 0x0f41 ++#define RTL8367C_SVLAN_SP2C_ENTRY32_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY32_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY32_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY32_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY33_CTRL0 0x0f42 ++#define RTL8367C_SVLAN_SP2C_ENTRY33_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY33_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY33_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY33_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY33_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY33_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY33_CTRL1 0x0f43 ++#define RTL8367C_SVLAN_SP2C_ENTRY33_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY33_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY33_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY33_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY34_CTRL0 0x0f44 ++#define RTL8367C_SVLAN_SP2C_ENTRY34_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY34_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY34_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY34_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY34_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY34_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY34_CTRL1 0x0f45 ++#define RTL8367C_SVLAN_SP2C_ENTRY34_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY34_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY34_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY34_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY35_CTRL0 0x0f46 ++#define RTL8367C_SVLAN_SP2C_ENTRY35_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY35_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY35_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY35_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY35_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY35_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY35_CTRL1 0x0f47 ++#define RTL8367C_SVLAN_SP2C_ENTRY35_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY35_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY35_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY35_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY36_CTRL0 0x0f48 ++#define RTL8367C_SVLAN_SP2C_ENTRY36_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY36_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY36_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY36_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY36_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY36_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY36_CTRL1 0x0f49 ++#define RTL8367C_SVLAN_SP2C_ENTRY36_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY36_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY36_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY36_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY37_CTRL0 0x0f4a ++#define RTL8367C_SVLAN_SP2C_ENTRY37_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY37_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY37_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY37_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY37_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY37_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY37_CTRL1 0x0f4b ++#define RTL8367C_SVLAN_SP2C_ENTRY37_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY37_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY37_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY37_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY38_CTRL0 0x0f4c ++#define RTL8367C_SVLAN_SP2C_ENTRY38_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY38_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY38_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY38_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY38_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY38_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY38_CTRL1 0x0f4d ++#define RTL8367C_SVLAN_SP2C_ENTRY38_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY38_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY38_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY38_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY39_CTRL0 0x0f4e ++#define RTL8367C_SVLAN_SP2C_ENTRY39_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY39_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY39_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY39_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY39_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY39_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY39_CTRL1 0x0f4f ++#define RTL8367C_SVLAN_SP2C_ENTRY39_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY39_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY39_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY39_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY40_CTRL0 0x0f50 ++#define RTL8367C_SVLAN_SP2C_ENTRY40_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY40_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY40_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY40_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY40_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY40_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY40_CTRL1 0x0f51 ++#define RTL8367C_SVLAN_SP2C_ENTRY40_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY40_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY40_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY40_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY41_CTRL0 0x0f52 ++#define RTL8367C_SVLAN_SP2C_ENTRY41_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY41_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY41_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY41_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY41_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY41_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY41_CTRL1 0x0f53 ++#define RTL8367C_SVLAN_SP2C_ENTRY41_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY41_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY41_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY41_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY42_CTRL0 0x0f54 ++#define RTL8367C_SVLAN_SP2C_ENTRY42_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY42_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY42_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY42_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY42_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY42_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY42_CTRL1 0x0f55 ++#define RTL8367C_SVLAN_SP2C_ENTRY42_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY42_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY42_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY42_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY43_CTRL0 0x0f56 ++#define RTL8367C_SVLAN_SP2C_ENTRY43_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY43_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY43_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY43_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY43_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY43_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY43_CTRL1 0x0f57 ++#define RTL8367C_SVLAN_SP2C_ENTRY43_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY43_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY43_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY43_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY44_CTRL0 0x0f58 ++#define RTL8367C_SVLAN_SP2C_ENTRY44_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY44_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY44_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY44_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY44_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY44_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY44_CTRL1 0x0f59 ++#define RTL8367C_SVLAN_SP2C_ENTRY44_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY44_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY44_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY44_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY45_CTRL0 0x0f5a ++#define RTL8367C_SVLAN_SP2C_ENTRY45_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY45_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY45_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY45_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY45_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY45_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY45_CTRL1 0x0f5b ++#define RTL8367C_SVLAN_SP2C_ENTRY45_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY45_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY45_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY45_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY46_CTRL0 0x0f5c ++#define RTL8367C_SVLAN_SP2C_ENTRY46_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY46_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY46_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY46_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY46_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY46_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY46_CTRL1 0x0f5d ++#define RTL8367C_SVLAN_SP2C_ENTRY46_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY46_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY46_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY46_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY47_CTRL0 0x0f5e ++#define RTL8367C_SVLAN_SP2C_ENTRY47_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY47_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY47_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY47_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY47_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY47_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY47_CTRL1 0x0f5f ++#define RTL8367C_SVLAN_SP2C_ENTRY47_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY47_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY47_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY47_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY48_CTRL0 0x0f60 ++#define RTL8367C_SVLAN_SP2C_ENTRY48_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY48_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY48_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY48_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY48_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY48_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY48_CTRL1 0x0f61 ++#define RTL8367C_SVLAN_SP2C_ENTRY48_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY48_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY48_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY48_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY49_CTRL0 0x0f62 ++#define RTL8367C_SVLAN_SP2C_ENTRY49_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY49_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY49_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY49_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY49_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY49_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY49_CTRL1 0x0f63 ++#define RTL8367C_SVLAN_SP2C_ENTRY49_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY49_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY49_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY49_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY50_CTRL0 0x0f64 ++#define RTL8367C_SVLAN_SP2C_ENTRY50_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY50_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY50_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY50_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY50_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY50_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY50_CTRL1 0x0f65 ++#define RTL8367C_SVLAN_SP2C_ENTRY50_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY50_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY50_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY50_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY51_CTRL0 0x0f66 ++#define RTL8367C_SVLAN_SP2C_ENTRY51_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY51_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY51_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY51_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY51_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY51_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY51_CTRL1 0x0f67 ++#define RTL8367C_SVLAN_SP2C_ENTRY51_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY51_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY51_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY51_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY52_CTRL0 0x0f68 ++#define RTL8367C_SVLAN_SP2C_ENTRY52_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY52_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY52_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY52_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY52_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY52_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY52_CTRL1 0x0f69 ++#define RTL8367C_SVLAN_SP2C_ENTRY52_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY52_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY52_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY52_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY53_CTRL0 0x0f6a ++#define RTL8367C_SVLAN_SP2C_ENTRY53_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY53_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY53_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY53_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY53_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY53_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY53_CTRL1 0x0f6b ++#define RTL8367C_SVLAN_SP2C_ENTRY53_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY53_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY53_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY53_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY54_CTRL0 0x0f6c ++#define RTL8367C_SVLAN_SP2C_ENTRY54_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY54_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY54_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY54_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY54_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY54_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY54_CTRL1 0x0f6d ++#define RTL8367C_SVLAN_SP2C_ENTRY54_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY54_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY54_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY54_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY55_CTRL0 0x0f6e ++#define RTL8367C_SVLAN_SP2C_ENTRY55_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY55_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY55_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY55_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY55_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY55_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY55_CTRL1 0x0f6f ++#define RTL8367C_SVLAN_SP2C_ENTRY55_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY55_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY55_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY55_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY56_CTRL0 0x0f70 ++#define RTL8367C_SVLAN_SP2C_ENTRY56_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY56_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY56_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY56_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY56_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY56_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY56_CTRL1 0x0f71 ++#define RTL8367C_SVLAN_SP2C_ENTRY56_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY56_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY56_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY56_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY57_CTRL0 0x0f72 ++#define RTL8367C_SVLAN_SP2C_ENTRY57_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY57_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY57_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY57_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY57_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY57_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY57_CTRL1 0x0f73 ++#define RTL8367C_SVLAN_SP2C_ENTRY57_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY57_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY57_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY57_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY58_CTRL0 0x0f74 ++#define RTL8367C_SVLAN_SP2C_ENTRY58_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY58_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY58_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY58_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY58_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY58_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY58_CTRL1 0x0f75 ++#define RTL8367C_SVLAN_SP2C_ENTRY58_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY58_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY58_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY58_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY59_CTRL0 0x0f76 ++#define RTL8367C_SVLAN_SP2C_ENTRY59_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY59_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY59_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY59_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY59_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY59_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY59_CTRL1 0x0f77 ++#define RTL8367C_SVLAN_SP2C_ENTRY59_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY59_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY59_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY59_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY60_CTRL0 0x0f78 ++#define RTL8367C_SVLAN_SP2C_ENTRY60_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY60_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY60_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY60_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY60_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY60_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY60_CTRL1 0x0f79 ++#define RTL8367C_SVLAN_SP2C_ENTRY60_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY60_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY60_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY60_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY61_CTRL0 0x0f7a ++#define RTL8367C_SVLAN_SP2C_ENTRY61_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY61_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY61_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY61_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY61_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY61_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY61_CTRL1 0x0f7b ++#define RTL8367C_SVLAN_SP2C_ENTRY61_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY61_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY61_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY61_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY62_CTRL0 0x0f7c ++#define RTL8367C_SVLAN_SP2C_ENTRY62_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY62_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY62_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY62_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY62_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY62_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY62_CTRL1 0x0f7d ++#define RTL8367C_SVLAN_SP2C_ENTRY62_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY62_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY62_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY62_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY63_CTRL0 0x0f7e ++#define RTL8367C_SVLAN_SP2C_ENTRY63_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY63_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY63_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY63_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY63_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY63_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY63_CTRL1 0x0f7f ++#define RTL8367C_SVLAN_SP2C_ENTRY63_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY63_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY63_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY63_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY64_CTRL0 0x0f80 ++#define RTL8367C_SVLAN_SP2C_ENTRY64_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY64_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY64_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY64_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY64_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY64_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY64_CTRL1 0x0f81 ++#define RTL8367C_SVLAN_SP2C_ENTRY64_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY64_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY64_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY64_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY65_CTRL0 0x0f82 ++#define RTL8367C_SVLAN_SP2C_ENTRY65_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY65_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY65_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY65_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY65_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY65_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY65_CTRL1 0x0f83 ++#define RTL8367C_SVLAN_SP2C_ENTRY65_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY65_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY65_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY65_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY66_CTRL0 0x0f84 ++#define RTL8367C_SVLAN_SP2C_ENTRY66_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY66_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY66_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY66_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY66_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY66_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY66_CTRL1 0x0f85 ++#define RTL8367C_SVLAN_SP2C_ENTRY66_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY66_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY66_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY66_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY67_CTRL0 0x0f86 ++#define RTL8367C_SVLAN_SP2C_ENTRY67_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY67_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY67_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY67_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY67_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY67_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY67_CTRL1 0x0f87 ++#define RTL8367C_SVLAN_SP2C_ENTRY67_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY67_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY67_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY67_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY68_CTRL0 0x0f88 ++#define RTL8367C_SVLAN_SP2C_ENTRY68_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY68_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY68_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY68_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY68_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY68_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY68_CTRL1 0x0f89 ++#define RTL8367C_SVLAN_SP2C_ENTRY68_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY68_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY68_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY68_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY69_CTRL0 0x0f8a ++#define RTL8367C_SVLAN_SP2C_ENTRY69_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY69_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY69_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY69_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY69_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY69_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY69_CTRL1 0x0f8b ++#define RTL8367C_SVLAN_SP2C_ENTRY69_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY69_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY69_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY69_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY70_CTRL0 0x0f8c ++#define RTL8367C_SVLAN_SP2C_ENTRY70_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY70_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY70_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY70_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY70_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY70_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY70_CTRL1 0x0f8d ++#define RTL8367C_SVLAN_SP2C_ENTRY70_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY70_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY70_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY70_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY71_CTRL0 0x0f8e ++#define RTL8367C_SVLAN_SP2C_ENTRY71_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY71_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY71_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY71_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY71_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY71_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY71_CTRL1 0x0f8f ++#define RTL8367C_SVLAN_SP2C_ENTRY71_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY71_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY71_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY71_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY72_CTRL0 0x0f90 ++#define RTL8367C_SVLAN_SP2C_ENTRY72_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY72_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY72_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY72_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY72_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY72_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY72_CTRL1 0x0f91 ++#define RTL8367C_SVLAN_SP2C_ENTRY72_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY72_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY72_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY72_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY73_CTRL0 0x0f92 ++#define RTL8367C_SVLAN_SP2C_ENTRY73_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY73_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY73_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY73_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY73_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY73_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY73_CTRL1 0x0f93 ++#define RTL8367C_SVLAN_SP2C_ENTRY73_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY73_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY73_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY73_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY74_CTRL0 0x0f94 ++#define RTL8367C_SVLAN_SP2C_ENTRY74_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY74_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY74_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY74_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY74_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY74_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY74_CTRL1 0x0f95 ++#define RTL8367C_SVLAN_SP2C_ENTRY74_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY74_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY74_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY74_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY75_CTRL0 0x0f96 ++#define RTL8367C_SVLAN_SP2C_ENTRY75_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY75_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY75_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY75_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY75_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY75_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY75_CTRL1 0x0f97 ++#define RTL8367C_SVLAN_SP2C_ENTRY75_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY75_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY75_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY75_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY76_CTRL0 0x0f98 ++#define RTL8367C_SVLAN_SP2C_ENTRY76_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY76_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY76_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY76_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY76_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY76_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY76_CTRL1 0x0f99 ++#define RTL8367C_SVLAN_SP2C_ENTRY76_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY76_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY76_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY76_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY77_CTRL0 0x0f9a ++#define RTL8367C_SVLAN_SP2C_ENTRY77_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY77_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY77_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY77_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY77_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY77_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY77_CTRL1 0x0f9b ++#define RTL8367C_SVLAN_SP2C_ENTRY77_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY77_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY77_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY77_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY78_CTRL0 0x0f9c ++#define RTL8367C_SVLAN_SP2C_ENTRY78_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY78_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY78_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY78_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY78_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY78_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY78_CTRL1 0x0f9d ++#define RTL8367C_SVLAN_SP2C_ENTRY78_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY78_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY78_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY78_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY79_CTRL0 0x0f9e ++#define RTL8367C_SVLAN_SP2C_ENTRY79_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY79_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY79_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY79_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY79_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY79_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY79_CTRL1 0x0f9f ++#define RTL8367C_SVLAN_SP2C_ENTRY79_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY79_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY79_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY79_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY80_CTRL0 0x0fa0 ++#define RTL8367C_SVLAN_SP2C_ENTRY80_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY80_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY80_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY80_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY80_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY80_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY80_CTRL1 0x0fa1 ++#define RTL8367C_SVLAN_SP2C_ENTRY80_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY80_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY80_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY80_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY81_CTRL0 0x0fa2 ++#define RTL8367C_SVLAN_SP2C_ENTRY81_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY81_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY81_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY81_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY81_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY81_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY81_CTRL1 0x0fa3 ++#define RTL8367C_SVLAN_SP2C_ENTRY81_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY81_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY81_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY81_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY82_CTRL0 0x0fa4 ++#define RTL8367C_SVLAN_SP2C_ENTRY82_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY82_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY82_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY82_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY82_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY82_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY82_CTRL1 0x0fa5 ++#define RTL8367C_SVLAN_SP2C_ENTRY82_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY82_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY82_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY82_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY83_CTRL0 0x0fa6 ++#define RTL8367C_SVLAN_SP2C_ENTRY83_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY83_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY83_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY83_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY83_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY83_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY83_CTRL1 0x0fa7 ++#define RTL8367C_SVLAN_SP2C_ENTRY83_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY83_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY83_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY83_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY84_CTRL0 0x0fa8 ++#define RTL8367C_SVLAN_SP2C_ENTRY84_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY84_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY84_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY84_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY84_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY84_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY84_CTRL1 0x0fa9 ++#define RTL8367C_SVLAN_SP2C_ENTRY84_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY84_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY84_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY84_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY85_CTRL0 0x0faa ++#define RTL8367C_SVLAN_SP2C_ENTRY85_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY85_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY85_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY85_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY85_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY85_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY85_CTRL1 0x0fab ++#define RTL8367C_SVLAN_SP2C_ENTRY85_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY85_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY85_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY85_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY86_CTRL0 0x0fac ++#define RTL8367C_SVLAN_SP2C_ENTRY86_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY86_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY86_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY86_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY86_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY86_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY86_CTRL1 0x0fad ++#define RTL8367C_SVLAN_SP2C_ENTRY86_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY86_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY86_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY86_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY87_CTRL0 0x0fae ++#define RTL8367C_SVLAN_SP2C_ENTRY87_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY87_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY87_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY87_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY87_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY87_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY87_CTRL1 0x0faf ++#define RTL8367C_SVLAN_SP2C_ENTRY87_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY87_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY87_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY87_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY88_CTRL0 0x0fb0 ++#define RTL8367C_SVLAN_SP2C_ENTRY88_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY88_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY88_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY88_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY88_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY88_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY88_CTRL1 0x0fb1 ++#define RTL8367C_SVLAN_SP2C_ENTRY88_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY88_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY88_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY88_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY89_CTRL0 0x0fb2 ++#define RTL8367C_SVLAN_SP2C_ENTRY89_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY89_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY89_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY89_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY89_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY89_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY89_CTRL1 0x0fb3 ++#define RTL8367C_SVLAN_SP2C_ENTRY89_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY89_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY89_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY89_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY90_CTRL0 0x0fb4 ++#define RTL8367C_SVLAN_SP2C_ENTRY90_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY90_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY90_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY90_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY90_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY90_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY90_CTRL1 0x0fb5 ++#define RTL8367C_SVLAN_SP2C_ENTRY90_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY90_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY90_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY90_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY91_CTRL0 0x0fb6 ++#define RTL8367C_SVLAN_SP2C_ENTRY91_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY91_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY91_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY91_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY91_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY91_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY91_CTRL1 0x0fb7 ++#define RTL8367C_SVLAN_SP2C_ENTRY91_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY91_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY91_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY91_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY92_CTRL0 0x0fb8 ++#define RTL8367C_SVLAN_SP2C_ENTRY92_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY92_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY92_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY92_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY92_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY92_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY92_CTRL1 0x0fb9 ++#define RTL8367C_SVLAN_SP2C_ENTRY92_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY92_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY92_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY92_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY93_CTRL0 0x0fba ++#define RTL8367C_SVLAN_SP2C_ENTRY93_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY93_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY93_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY93_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY93_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY93_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY93_CTRL1 0x0fbb ++#define RTL8367C_SVLAN_SP2C_ENTRY93_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY93_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY93_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY93_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY94_CTRL0 0x0fbc ++#define RTL8367C_SVLAN_SP2C_ENTRY94_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY94_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY94_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY94_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY94_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY94_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY94_CTRL1 0x0fbd ++#define RTL8367C_SVLAN_SP2C_ENTRY94_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY94_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY94_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY94_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY95_CTRL0 0x0fbe ++#define RTL8367C_SVLAN_SP2C_ENTRY95_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY95_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY95_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY95_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY95_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY95_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY95_CTRL1 0x0fbf ++#define RTL8367C_SVLAN_SP2C_ENTRY95_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY95_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY95_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY95_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY96_CTRL0 0x0fc0 ++#define RTL8367C_SVLAN_SP2C_ENTRY96_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY96_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY96_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY96_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY96_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY96_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY96_CTRL1 0x0fc1 ++#define RTL8367C_SVLAN_SP2C_ENTRY96_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY96_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY96_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY96_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY97_CTRL0 0x0fc2 ++#define RTL8367C_SVLAN_SP2C_ENTRY97_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY97_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY97_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY97_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY97_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY97_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY97_CTRL1 0x0fc3 ++#define RTL8367C_SVLAN_SP2C_ENTRY97_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY97_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY97_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY97_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY98_CTRL0 0x0fc4 ++#define RTL8367C_SVLAN_SP2C_ENTRY98_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY98_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY98_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY98_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY98_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY98_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY98_CTRL1 0x0fc5 ++#define RTL8367C_SVLAN_SP2C_ENTRY98_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY98_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY98_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY98_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY99_CTRL0 0x0fc6 ++#define RTL8367C_SVLAN_SP2C_ENTRY99_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY99_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY99_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY99_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY99_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY99_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY99_CTRL1 0x0fc7 ++#define RTL8367C_SVLAN_SP2C_ENTRY99_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY99_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY99_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY99_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY100_CTRL0 0x0fc8 ++#define RTL8367C_SVLAN_SP2C_ENTRY100_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY100_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY100_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY100_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY100_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY100_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY100_CTRL1 0x0fc9 ++#define RTL8367C_SVLAN_SP2C_ENTRY100_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY100_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY100_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY100_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY101_CTRL0 0x0fca ++#define RTL8367C_SVLAN_SP2C_ENTRY101_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY101_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY101_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY101_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY101_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY101_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY101_CTRL1 0x0fcb ++#define RTL8367C_SVLAN_SP2C_ENTRY101_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY101_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY101_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY101_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY102_CTRL0 0x0fcc ++#define RTL8367C_SVLAN_SP2C_ENTRY102_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY102_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY102_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY102_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY102_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY102_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY102_CTRL1 0x0fcd ++#define RTL8367C_SVLAN_SP2C_ENTRY102_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY102_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY102_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY102_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY103_CTRL0 0x0fce ++#define RTL8367C_SVLAN_SP2C_ENTRY103_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY103_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY103_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY103_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY103_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY103_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY103_CTRL1 0x0fcf ++#define RTL8367C_SVLAN_SP2C_ENTRY103_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY103_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY103_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY103_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY104_CTRL0 0x0fd0 ++#define RTL8367C_SVLAN_SP2C_ENTRY104_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY104_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY104_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY104_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY104_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY104_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY104_CTRL1 0x0fd1 ++#define RTL8367C_SVLAN_SP2C_ENTRY104_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY104_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY104_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY104_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY105_CTRL0 0x0fd2 ++#define RTL8367C_SVLAN_SP2C_ENTRY105_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY105_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY105_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY105_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY105_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY105_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY105_CTRL1 0x0fd3 ++#define RTL8367C_SVLAN_SP2C_ENTRY105_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY105_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY105_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY105_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY106_CTRL0 0x0fd4 ++#define RTL8367C_SVLAN_SP2C_ENTRY106_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY106_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY106_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY106_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY106_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY106_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY106_CTRL1 0x0fd5 ++#define RTL8367C_SVLAN_SP2C_ENTRY106_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY106_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY106_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY106_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY107_CTRL0 0x0fd6 ++#define RTL8367C_SVLAN_SP2C_ENTRY107_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY107_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY107_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY107_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY107_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY107_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY107_CTRL1 0x0fd7 ++#define RTL8367C_SVLAN_SP2C_ENTRY107_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY107_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY107_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY107_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY108_CTRL0 0x0fd8 ++#define RTL8367C_SVLAN_SP2C_ENTRY108_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY108_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY108_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY108_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY108_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY108_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY108_CTRL1 0x0fd9 ++#define RTL8367C_SVLAN_SP2C_ENTRY108_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY108_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY108_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY108_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY109_CTRL0 0x0fda ++#define RTL8367C_SVLAN_SP2C_ENTRY109_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY109_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY109_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY109_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY109_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY109_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY109_CTRL1 0x0fdb ++#define RTL8367C_SVLAN_SP2C_ENTRY109_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY109_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY109_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY109_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY110_CTRL0 0x0fdc ++#define RTL8367C_SVLAN_SP2C_ENTRY110_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY110_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY110_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY110_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY110_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY110_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY110_CTRL1 0x0fdd ++#define RTL8367C_SVLAN_SP2C_ENTRY110_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY110_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY110_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY110_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY111_CTRL0 0x0fde ++#define RTL8367C_SVLAN_SP2C_ENTRY111_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY111_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY111_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY111_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY111_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY111_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY111_CTRL1 0x0fdf ++#define RTL8367C_SVLAN_SP2C_ENTRY111_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY111_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY111_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY111_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY112_CTRL0 0x0fe0 ++#define RTL8367C_SVLAN_SP2C_ENTRY112_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY112_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY112_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY112_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY112_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY112_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY112_CTRL1 0x0fe1 ++#define RTL8367C_SVLAN_SP2C_ENTRY112_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY112_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY112_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY112_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY113_CTRL0 0x0fe2 ++#define RTL8367C_SVLAN_SP2C_ENTRY113_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY113_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY113_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY113_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY113_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY113_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY113_CTRL1 0x0fe3 ++#define RTL8367C_SVLAN_SP2C_ENTRY113_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY113_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY113_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY113_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY114_CTRL0 0x0fe4 ++#define RTL8367C_SVLAN_SP2C_ENTRY114_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY114_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY114_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY114_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY114_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY114_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY114_CTRL1 0x0fe5 ++#define RTL8367C_SVLAN_SP2C_ENTRY114_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY114_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY114_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY114_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY115_CTRL0 0x0fe6 ++#define RTL8367C_SVLAN_SP2C_ENTRY115_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY115_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY115_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY115_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY115_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY115_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY115_CTRL1 0x0fe7 ++#define RTL8367C_SVLAN_SP2C_ENTRY115_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY115_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY115_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY115_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY116_CTRL0 0x0fe8 ++#define RTL8367C_SVLAN_SP2C_ENTRY116_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY116_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY116_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY116_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY116_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY116_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY116_CTRL1 0x0fe9 ++#define RTL8367C_SVLAN_SP2C_ENTRY116_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY116_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY116_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY116_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY117_CTRL0 0x0fea ++#define RTL8367C_SVLAN_SP2C_ENTRY117_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY117_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY117_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY117_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY117_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY117_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY117_CTRL1 0x0feb ++#define RTL8367C_SVLAN_SP2C_ENTRY117_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY117_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY117_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY117_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY118_CTRL0 0x0fec ++#define RTL8367C_SVLAN_SP2C_ENTRY118_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY118_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY118_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY118_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY118_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY118_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY118_CTRL1 0x0fed ++#define RTL8367C_SVLAN_SP2C_ENTRY118_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY118_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY118_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY118_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY119_CTRL0 0x0fee ++#define RTL8367C_SVLAN_SP2C_ENTRY119_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY119_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY119_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY119_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY119_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY119_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY119_CTRL1 0x0fef ++#define RTL8367C_SVLAN_SP2C_ENTRY119_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY119_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY119_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY119_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY120_CTRL0 0x0ff0 ++#define RTL8367C_SVLAN_SP2C_ENTRY120_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY120_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY120_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY120_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY120_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY120_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY120_CTRL1 0x0ff1 ++#define RTL8367C_SVLAN_SP2C_ENTRY120_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY120_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY120_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY120_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY121_CTRL0 0x0ff2 ++#define RTL8367C_SVLAN_SP2C_ENTRY121_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY121_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY121_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY121_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY121_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY121_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY121_CTRL1 0x0ff3 ++#define RTL8367C_SVLAN_SP2C_ENTRY121_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY121_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY121_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY121_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY122_CTRL0 0x0ff4 ++#define RTL8367C_SVLAN_SP2C_ENTRY122_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY122_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY122_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY122_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY122_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY122_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY122_CTRL1 0x0ff5 ++#define RTL8367C_SVLAN_SP2C_ENTRY122_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY122_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY122_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY122_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY123_CTRL0 0x0ff6 ++#define RTL8367C_SVLAN_SP2C_ENTRY123_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY123_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY123_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY123_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY123_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY123_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY123_CTRL1 0x0ff7 ++#define RTL8367C_SVLAN_SP2C_ENTRY123_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY123_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY123_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY123_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY124_CTRL0 0x0ff8 ++#define RTL8367C_SVLAN_SP2C_ENTRY124_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY124_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY124_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY124_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY124_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY124_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY124_CTRL1 0x0ff9 ++#define RTL8367C_SVLAN_SP2C_ENTRY124_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY124_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY124_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY124_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY125_CTRL0 0x0ffa ++#define RTL8367C_SVLAN_SP2C_ENTRY125_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY125_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY125_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY125_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY125_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY125_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY125_CTRL1 0x0ffb ++#define RTL8367C_SVLAN_SP2C_ENTRY125_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY125_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY125_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY125_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY126_CTRL0 0x0ffc ++#define RTL8367C_SVLAN_SP2C_ENTRY126_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY126_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY126_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY126_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY126_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY126_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY126_CTRL1 0x0ffd ++#define RTL8367C_SVLAN_SP2C_ENTRY126_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY126_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY126_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY126_CTRL1_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY127_CTRL0 0x0ffe ++#define RTL8367C_SVLAN_SP2C_ENTRY127_CTRL0_DST_PORT1_OFFSET 9 ++#define RTL8367C_SVLAN_SP2C_ENTRY127_CTRL0_DST_PORT1_MASK 0x200 ++#define RTL8367C_SVLAN_SP2C_ENTRY127_CTRL0_SVIDX_OFFSET 3 ++#define RTL8367C_SVLAN_SP2C_ENTRY127_CTRL0_SVIDX_MASK 0x1F8 ++#define RTL8367C_SVLAN_SP2C_ENTRY127_CTRL0_DST_PORT_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY127_CTRL0_DST_PORT_MASK 0x7 ++ ++#define RTL8367C_REG_SVLAN_SP2C_ENTRY127_CTRL1 0x0fff ++#define RTL8367C_SVLAN_SP2C_ENTRY127_CTRL1_VALID_OFFSET 12 ++#define RTL8367C_SVLAN_SP2C_ENTRY127_CTRL1_VALID_MASK 0x1000 ++#define RTL8367C_SVLAN_SP2C_ENTRY127_CTRL1_VID_OFFSET 0 ++#define RTL8367C_SVLAN_SP2C_ENTRY127_CTRL1_VID_MASK 0xFFF ++ ++/* (16'h1000)mib_reg */ ++ ++#define RTL8367C_REG_MIB_COUNTER0 0x1000 ++ ++#define RTL8367C_REG_MIB_COUNTER1 0x1001 ++ ++#define RTL8367C_REG_MIB_COUNTER2 0x1002 ++ ++#define RTL8367C_REG_MIB_COUNTER3 0x1003 ++ ++#define RTL8367C_REG_MIB_ADDRESS 0x1004 ++#define RTL8367C_MIB_ADDRESS_OFFSET 0 ++#define RTL8367C_MIB_ADDRESS_MASK 0x1FF ++ ++#define RTL8367C_REG_MIB_CTRL0 0x1005 ++#define RTL8367C_PORT10_RESET_OFFSET 15 ++#define RTL8367C_PORT10_RESET_MASK 0x8000 ++#define RTL8367C_PORT9_RESET_OFFSET 14 ++#define RTL8367C_PORT9_RESET_MASK 0x4000 ++#define RTL8367C_PORT8_RESET_OFFSET 13 ++#define RTL8367C_PORT8_RESET_MASK 0x2000 ++#define RTL8367C_RESET_VALUE_OFFSET 12 ++#define RTL8367C_RESET_VALUE_MASK 0x1000 ++#define RTL8367C_GLOBAL_RESET_OFFSET 11 ++#define RTL8367C_GLOBAL_RESET_MASK 0x800 ++#define RTL8367C_QM_RESET_OFFSET 10 ++#define RTL8367C_QM_RESET_MASK 0x400 ++#define RTL8367C_PORT7_RESET_OFFSET 9 ++#define RTL8367C_PORT7_RESET_MASK 0x200 ++#define RTL8367C_PORT6_RESET_OFFSET 8 ++#define RTL8367C_PORT6_RESET_MASK 0x100 ++#define RTL8367C_PORT5_RESET_OFFSET 7 ++#define RTL8367C_PORT5_RESET_MASK 0x80 ++#define RTL8367C_PORT4_RESET_OFFSET 6 ++#define RTL8367C_PORT4_RESET_MASK 0x40 ++#define RTL8367C_PORT3_RESET_OFFSET 5 ++#define RTL8367C_PORT3_RESET_MASK 0x20 ++#define RTL8367C_PORT2_RESET_OFFSET 4 ++#define RTL8367C_PORT2_RESET_MASK 0x10 ++#define RTL8367C_PORT1_RESET_OFFSET 3 ++#define RTL8367C_PORT1_RESET_MASK 0x8 ++#define RTL8367C_PORT0_RESET_OFFSET 2 ++#define RTL8367C_PORT0_RESET_MASK 0x4 ++#define RTL8367C_RESET_FLAG_OFFSET 1 ++#define RTL8367C_RESET_FLAG_MASK 0x2 ++#define RTL8367C_MIB_CTRL0_BUSY_FLAG_OFFSET 0 ++#define RTL8367C_MIB_CTRL0_BUSY_FLAG_MASK 0x1 ++ ++#define RTL8367C_REG_MIB_CTRL1 0x1007 ++#define RTL8367C_COUNTER15_RESET_OFFSET 15 ++#define RTL8367C_COUNTER15_RESET_MASK 0x8000 ++#define RTL8367C_COUNTER14_RESET_OFFSET 14 ++#define RTL8367C_COUNTER14_RESET_MASK 0x4000 ++#define RTL8367C_COUNTER13_RESET_OFFSET 13 ++#define RTL8367C_COUNTER13_RESET_MASK 0x2000 ++#define RTL8367C_COUNTER12_RESET_OFFSET 12 ++#define RTL8367C_COUNTER12_RESET_MASK 0x1000 ++#define RTL8367C_COUNTER11_RESET_OFFSET 11 ++#define RTL8367C_COUNTER11_RESET_MASK 0x800 ++#define RTL8367C_COUNTER10_RESET_OFFSET 10 ++#define RTL8367C_COUNTER10_RESET_MASK 0x400 ++#define RTL8367C_COUNTER9_RESET_OFFSET 9 ++#define RTL8367C_COUNTER9_RESET_MASK 0x200 ++#define RTL8367C_COUNTER8_RESET_OFFSET 8 ++#define RTL8367C_COUNTER8_RESET_MASK 0x100 ++#define RTL8367C_COUNTER7_RESET_OFFSET 7 ++#define RTL8367C_COUNTER7_RESET_MASK 0x80 ++#define RTL8367C_COUNTER6_RESET_OFFSET 6 ++#define RTL8367C_COUNTER6_RESET_MASK 0x40 ++#define RTL8367C_COUNTER5_RESET_OFFSET 5 ++#define RTL8367C_COUNTER5_RESET_MASK 0x20 ++#define RTL8367C_COUNTER4_RESET_OFFSET 4 ++#define RTL8367C_COUNTER4_RESET_MASK 0x10 ++#define RTL8367C_COUNTER3_RESET_OFFSET 3 ++#define RTL8367C_COUNTER3_RESET_MASK 0x8 ++#define RTL8367C_COUNTER2_RESET_OFFSET 2 ++#define RTL8367C_COUNTER2_RESET_MASK 0x4 ++#define RTL8367C_COUNTER1_RESET_OFFSET 1 ++#define RTL8367C_COUNTER1_RESET_MASK 0x2 ++#define RTL8367C_COUNTER0_RESET_OFFSET 0 ++#define RTL8367C_COUNTER0_RESET_MASK 0x1 ++ ++#define RTL8367C_REG_MIB_CTRL2 0x1008 ++#define RTL8367C_COUNTER31_RESET_OFFSET 15 ++#define RTL8367C_COUNTER31_RESET_MASK 0x8000 ++#define RTL8367C_COUNTER30_RESET_OFFSET 14 ++#define RTL8367C_COUNTER30_RESET_MASK 0x4000 ++#define RTL8367C_COUNTER29_RESET_OFFSET 13 ++#define RTL8367C_COUNTER29_RESET_MASK 0x2000 ++#define RTL8367C_COUNTER28_RESET_OFFSET 12 ++#define RTL8367C_COUNTER28_RESET_MASK 0x1000 ++#define RTL8367C_COUNTER27_RESET_OFFSET 11 ++#define RTL8367C_COUNTER27_RESET_MASK 0x800 ++#define RTL8367C_COUNTER26_RESET_OFFSET 10 ++#define RTL8367C_COUNTER26_RESET_MASK 0x400 ++#define RTL8367C_COUNTER25_RESET_OFFSET 9 ++#define RTL8367C_COUNTER25_RESET_MASK 0x200 ++#define RTL8367C_COUNTER24_RESET_OFFSET 8 ++#define RTL8367C_COUNTER24_RESET_MASK 0x100 ++#define RTL8367C_COUNTER23_RESET_OFFSET 7 ++#define RTL8367C_COUNTER23_RESET_MASK 0x80 ++#define RTL8367C_COUNTER22_RESET_OFFSET 6 ++#define RTL8367C_COUNTER22_RESET_MASK 0x40 ++#define RTL8367C_COUNTER21_RESET_OFFSET 5 ++#define RTL8367C_COUNTER21_RESET_MASK 0x20 ++#define RTL8367C_COUNTER20_RESET_OFFSET 4 ++#define RTL8367C_COUNTER20_RESET_MASK 0x10 ++#define RTL8367C_COUNTER19_RESET_OFFSET 3 ++#define RTL8367C_COUNTER19_RESET_MASK 0x8 ++#define RTL8367C_COUNTER18_RESET_OFFSET 2 ++#define RTL8367C_COUNTER18_RESET_MASK 0x4 ++#define RTL8367C_COUNTER17_RESET_OFFSET 1 ++#define RTL8367C_COUNTER17_RESET_MASK 0x2 ++#define RTL8367C_COUNTER16_RESET_OFFSET 0 ++#define RTL8367C_COUNTER16_RESET_MASK 0x1 ++ ++#define RTL8367C_REG_MIB_CTRL3 0x1009 ++#define RTL8367C_COUNTER15_MODE_OFFSET 15 ++#define RTL8367C_COUNTER15_MODE_MASK 0x8000 ++#define RTL8367C_COUNTER14_MODE_OFFSET 14 ++#define RTL8367C_COUNTER14_MODE_MASK 0x4000 ++#define RTL8367C_COUNTER13_MODE_OFFSET 13 ++#define RTL8367C_COUNTER13_MODE_MASK 0x2000 ++#define RTL8367C_COUNTER12_MODE_OFFSET 12 ++#define RTL8367C_COUNTER12_MODE_MASK 0x1000 ++#define RTL8367C_COUNTER11_MODE_OFFSET 11 ++#define RTL8367C_COUNTER11_MODE_MASK 0x800 ++#define RTL8367C_COUNTER10_MODE_OFFSET 10 ++#define RTL8367C_COUNTER10_MODE_MASK 0x400 ++#define RTL8367C_COUNTER9_MODE_OFFSET 9 ++#define RTL8367C_COUNTER9_MODE_MASK 0x200 ++#define RTL8367C_COUNTER8_MODE_OFFSET 8 ++#define RTL8367C_COUNTER8_MODE_MASK 0x100 ++#define RTL8367C_COUNTER7_MODE_OFFSET 7 ++#define RTL8367C_COUNTER7_MODE_MASK 0x80 ++#define RTL8367C_COUNTER6_MODE_OFFSET 6 ++#define RTL8367C_COUNTER6_MODE_MASK 0x40 ++#define RTL8367C_COUNTER5_MODE_OFFSET 5 ++#define RTL8367C_COUNTER5_MODE_MASK 0x20 ++#define RTL8367C_COUNTER4_MODE_OFFSET 4 ++#define RTL8367C_COUNTER4_MODE_MASK 0x10 ++#define RTL8367C_COUNTER3_MODE_OFFSET 3 ++#define RTL8367C_COUNTER3_MODE_MASK 0x8 ++#define RTL8367C_COUNTER2_MODE_OFFSET 2 ++#define RTL8367C_COUNTER2_MODE_MASK 0x4 ++#define RTL8367C_COUNTER1_MODE_OFFSET 1 ++#define RTL8367C_COUNTER1_MODE_MASK 0x2 ++#define RTL8367C_COUNTER0_MODE_OFFSET 0 ++#define RTL8367C_COUNTER0_MODE_MASK 0x1 ++ ++#define RTL8367C_REG_MIB_CTRL4 0x100a ++#define RTL8367C_MIB_USAGE_MODE_OFFSET 8 ++#define RTL8367C_MIB_USAGE_MODE_MASK 0x100 ++#define RTL8367C_MIB_TIMER_OFFSET 0 ++#define RTL8367C_MIB_TIMER_MASK 0xFF ++ ++#define RTL8367C_REG_MIB_CTRL5 0x100b ++#define RTL8367C_MIB_CTRL5_COUNTER15_TYPE_OFFSET 15 ++#define RTL8367C_MIB_CTRL5_COUNTER15_TYPE_MASK 0x8000 ++#define RTL8367C_MIB_CTRL5_COUNTER14_TYPE_OFFSET 14 ++#define RTL8367C_MIB_CTRL5_COUNTER14_TYPE_MASK 0x4000 ++#define RTL8367C_MIB_CTRL5_COUNTER13_TYPE_OFFSET 13 ++#define RTL8367C_MIB_CTRL5_COUNTER13_TYPE_MASK 0x2000 ++#define RTL8367C_MIB_CTRL5_COUNTER12_TYPE_OFFSET 12 ++#define RTL8367C_MIB_CTRL5_COUNTER12_TYPE_MASK 0x1000 ++#define RTL8367C_MIB_CTRL5_COUNTER11_TYPE_OFFSET 11 ++#define RTL8367C_MIB_CTRL5_COUNTER11_TYPE_MASK 0x800 ++#define RTL8367C_MIB_CTRL5_COUNTER10_TYPE_OFFSET 10 ++#define RTL8367C_MIB_CTRL5_COUNTER10_TYPE_MASK 0x400 ++#define RTL8367C_MIB_CTRL5_COUNTER9_TYPE_OFFSET 9 ++#define RTL8367C_MIB_CTRL5_COUNTER9_TYPE_MASK 0x200 ++#define RTL8367C_MIB_CTRL5_COUNTER8_TYPE_OFFSET 8 ++#define RTL8367C_MIB_CTRL5_COUNTER8_TYPE_MASK 0x100 ++#define RTL8367C_MIB_CTRL5_COUNTER7_TYPE_OFFSET 7 ++#define RTL8367C_MIB_CTRL5_COUNTER7_TYPE_MASK 0x80 ++#define RTL8367C_MIB_CTRL5_COUNTER6_TYPE_OFFSET 6 ++#define RTL8367C_MIB_CTRL5_COUNTER6_TYPE_MASK 0x40 ++#define RTL8367C_MIB_CTRL5_COUNTER5_TYPE_OFFSET 5 ++#define RTL8367C_MIB_CTRL5_COUNTER5_TYPE_MASK 0x20 ++#define RTL8367C_MIB_CTRL5_COUNTER4_TYPE_OFFSET 4 ++#define RTL8367C_MIB_CTRL5_COUNTER4_TYPE_MASK 0x10 ++#define RTL8367C_MIB_CTRL5_COUNTER3_TYPE_OFFSET 3 ++#define RTL8367C_MIB_CTRL5_COUNTER3_TYPE_MASK 0x8 ++#define RTL8367C_MIB_CTRL5_COUNTER2_TYPE_OFFSET 2 ++#define RTL8367C_MIB_CTRL5_COUNTER2_TYPE_MASK 0x4 ++#define RTL8367C_MIB_CTRL5_COUNTER1_TYPE_OFFSET 1 ++#define RTL8367C_MIB_CTRL5_COUNTER1_TYPE_MASK 0x2 ++#define RTL8367C_MIB_CTRL5_COUNTER0_TYPE_OFFSET 0 ++#define RTL8367C_MIB_CTRL5_COUNTER0_TYPE_MASK 0x1 ++ ++/* (16'h1100)intrpt_reg */ ++ ++#define RTL8367C_REG_INTR_CTRL 0x1100 ++#define RTL8367C_INTR_CTRL_OFFSET 0 ++#define RTL8367C_INTR_CTRL_MASK 0x1 ++ ++#define RTL8367C_REG_INTR_IMR 0x1101 ++#define RTL8367C_INTR_IMR_SLIENT_START_2_OFFSET 12 ++#define RTL8367C_INTR_IMR_SLIENT_START_2_MASK 0x1000 ++#define RTL8367C_INTR_IMR_SLIENT_START_OFFSET 11 ++#define RTL8367C_INTR_IMR_SLIENT_START_MASK 0x800 ++#define RTL8367C_INTR_IMR_ACL_ACTION_OFFSET 9 ++#define RTL8367C_INTR_IMR_ACL_ACTION_MASK 0x200 ++#define RTL8367C_INTR_IMR_CABLE_DIAG_FIN_OFFSET 8 ++#define RTL8367C_INTR_IMR_CABLE_DIAG_FIN_MASK 0x100 ++#define RTL8367C_INTR_IMR_INTERRUPT_8051_OFFSET 7 ++#define RTL8367C_INTR_IMR_INTERRUPT_8051_MASK 0x80 ++#define RTL8367C_INTR_IMR_LOOP_DETECTION_OFFSET 6 ++#define RTL8367C_INTR_IMR_LOOP_DETECTION_MASK 0x40 ++#define RTL8367C_INTR_IMR_GREEN_TIMER_OFFSET 5 ++#define RTL8367C_INTR_IMR_GREEN_TIMER_MASK 0x20 ++#define RTL8367C_INTR_IMR_SPECIAL_CONGEST_OFFSET 4 ++#define RTL8367C_INTR_IMR_SPECIAL_CONGEST_MASK 0x10 ++#define RTL8367C_INTR_IMR_SPEED_CHANGE_OFFSET 3 ++#define RTL8367C_INTR_IMR_SPEED_CHANGE_MASK 0x8 ++#define RTL8367C_INTR_IMR_LEARN_OVER_OFFSET 2 ++#define RTL8367C_INTR_IMR_LEARN_OVER_MASK 0x4 ++#define RTL8367C_INTR_IMR_METER_EXCEEDED_OFFSET 1 ++#define RTL8367C_INTR_IMR_METER_EXCEEDED_MASK 0x2 ++#define RTL8367C_INTR_IMR_LINK_CHANGE_OFFSET 0 ++#define RTL8367C_INTR_IMR_LINK_CHANGE_MASK 0x1 ++ ++#define RTL8367C_REG_INTR_IMS 0x1102 ++#define RTL8367C_INTR_IMS_SLIENT_START_2_OFFSET 12 ++#define RTL8367C_INTR_IMS_SLIENT_START_2_MASK 0x1000 ++#define RTL8367C_INTR_IMS_SLIENT_START_OFFSET 11 ++#define RTL8367C_INTR_IMS_SLIENT_START_MASK 0x800 ++#define RTL8367C_INTR_IMS_ACL_ACTION_OFFSET 9 ++#define RTL8367C_INTR_IMS_ACL_ACTION_MASK 0x200 ++#define RTL8367C_INTR_IMS_CABLE_DIAG_FIN_OFFSET 8 ++#define RTL8367C_INTR_IMS_CABLE_DIAG_FIN_MASK 0x100 ++#define RTL8367C_INTR_IMS_INTERRUPT_8051_OFFSET 7 ++#define RTL8367C_INTR_IMS_INTERRUPT_8051_MASK 0x80 ++#define RTL8367C_INTR_IMS_LOOP_DETECTION_OFFSET 6 ++#define RTL8367C_INTR_IMS_LOOP_DETECTION_MASK 0x40 ++#define RTL8367C_INTR_IMS_GREEN_TIMER_OFFSET 5 ++#define RTL8367C_INTR_IMS_GREEN_TIMER_MASK 0x20 ++#define RTL8367C_INTR_IMS_SPECIAL_CONGEST_OFFSET 4 ++#define RTL8367C_INTR_IMS_SPECIAL_CONGEST_MASK 0x10 ++#define RTL8367C_INTR_IMS_SPEED_CHANGE_OFFSET 3 ++#define RTL8367C_INTR_IMS_SPEED_CHANGE_MASK 0x8 ++#define RTL8367C_INTR_IMS_LEARN_OVER_OFFSET 2 ++#define RTL8367C_INTR_IMS_LEARN_OVER_MASK 0x4 ++#define RTL8367C_INTR_IMS_METER_EXCEEDED_OFFSET 1 ++#define RTL8367C_INTR_IMS_METER_EXCEEDED_MASK 0x2 ++#define RTL8367C_INTR_IMS_LINK_CHANGE_OFFSET 0 ++#define RTL8367C_INTR_IMS_LINK_CHANGE_MASK 0x1 ++ ++#define RTL8367C_REG_LEARN_OVER_INDICATOR 0x1103 ++#define RTL8367C_LEARN_OVER_INDICATOR_OFFSET 0 ++#define RTL8367C_LEARN_OVER_INDICATOR_MASK 0x7FF ++ ++#define RTL8367C_REG_SPEED_CHANGE_INDICATOR 0x1104 ++#define RTL8367C_SPEED_CHANGE_INDICATOR_OFFSET 0 ++#define RTL8367C_SPEED_CHANGE_INDICATOR_MASK 0x7FF ++ ++#define RTL8367C_REG_SPECIAL_CONGEST_INDICATOR 0x1105 ++#define RTL8367C_SPECIAL_CONGEST_INDICATOR_OFFSET 0 ++#define RTL8367C_SPECIAL_CONGEST_INDICATOR_MASK 0x7FF ++ ++#define RTL8367C_REG_PORT_LINKDOWN_INDICATOR 0x1106 ++#define RTL8367C_PORT_LINKDOWN_INDICATOR_OFFSET 0 ++#define RTL8367C_PORT_LINKDOWN_INDICATOR_MASK 0x7FF ++ ++#define RTL8367C_REG_PORT_LINKUP_INDICATOR 0x1107 ++#define RTL8367C_PORT_LINKUP_INDICATOR_OFFSET 0 ++#define RTL8367C_PORT_LINKUP_INDICATOR_MASK 0x7FF ++ ++#define RTL8367C_REG_SYSTEM_LEARN_OVER_INDICATOR 0x1108 ++#define RTL8367C_SYSTEM_LEARN_OVER_INDICATOR_OFFSET 0 ++#define RTL8367C_SYSTEM_LEARN_OVER_INDICATOR_MASK 0x1 ++ ++#define RTL8367C_REG_INTR_IMR_8051 0x1118 ++#define RTL8367C_INTR_IMR_8051_SLIENT_START_2_OFFSET 13 ++#define RTL8367C_INTR_IMR_8051_SLIENT_START_2_MASK 0x2000 ++#define RTL8367C_INTR_IMR_8051_SLIENT_START_OFFSET 12 ++#define RTL8367C_INTR_IMR_8051_SLIENT_START_MASK 0x1000 ++#define RTL8367C_INTR_IMR_8051_ACL_ACTION_OFFSET 10 ++#define RTL8367C_INTR_IMR_8051_ACL_ACTION_MASK 0x400 ++#define RTL8367C_INTR_IMR_8051_SAMOVING_8051_OFFSET 9 ++#define RTL8367C_INTR_IMR_8051_SAMOVING_8051_MASK 0x200 ++#define RTL8367C_INTR_IMR_8051_CABLE_DIAG_FIN_8051_OFFSET 8 ++#define RTL8367C_INTR_IMR_8051_CABLE_DIAG_FIN_8051_MASK 0x100 ++#define RTL8367C_INTR_IMR_8051_EEELLDP_8051_OFFSET 7 ++#define RTL8367C_INTR_IMR_8051_EEELLDP_8051_MASK 0x80 ++#define RTL8367C_INTR_IMR_8051_LOOP_DETECTION_8051_OFFSET 6 ++#define RTL8367C_INTR_IMR_8051_LOOP_DETECTION_8051_MASK 0x40 ++#define RTL8367C_INTR_IMR_8051_GREEN_TIMER_8051_OFFSET 5 ++#define RTL8367C_INTR_IMR_8051_GREEN_TIMER_8051_MASK 0x20 ++#define RTL8367C_INTR_IMR_8051_SPECIAL_CONGEST_8051_OFFSET 4 ++#define RTL8367C_INTR_IMR_8051_SPECIAL_CONGEST_8051_MASK 0x10 ++#define RTL8367C_INTR_IMR_8051_SPEED_CHANGE_8051_OFFSET 3 ++#define RTL8367C_INTR_IMR_8051_SPEED_CHANGE_8051_MASK 0x8 ++#define RTL8367C_INTR_IMR_8051_LEARN_OVER_8051_OFFSET 2 ++#define RTL8367C_INTR_IMR_8051_LEARN_OVER_8051_MASK 0x4 ++#define RTL8367C_INTR_IMR_8051_METER_EXCEEDED_8051_OFFSET 1 ++#define RTL8367C_INTR_IMR_8051_METER_EXCEEDED_8051_MASK 0x2 ++#define RTL8367C_INTR_IMR_8051_LINK_CHANGE_8051_OFFSET 0 ++#define RTL8367C_INTR_IMR_8051_LINK_CHANGE_8051_MASK 0x1 ++ ++#define RTL8367C_REG_INTR_IMS_8051 0x1119 ++#define RTL8367C_INTR_IMS_8051_SLIENT_START_2_OFFSET 13 ++#define RTL8367C_INTR_IMS_8051_SLIENT_START_2_MASK 0x2000 ++#define RTL8367C_INTR_IMS_8051_SLIENT_START_OFFSET 12 ++#define RTL8367C_INTR_IMS_8051_SLIENT_START_MASK 0x1000 ++#define RTL8367C_INTR_IMS_8051_ACL_ACTION_OFFSET 10 ++#define RTL8367C_INTR_IMS_8051_ACL_ACTION_MASK 0x400 ++#define RTL8367C_INTR_IMS_8051_SAMOVING_8051_OFFSET 9 ++#define RTL8367C_INTR_IMS_8051_SAMOVING_8051_MASK 0x200 ++#define RTL8367C_INTR_IMS_8051_CABLE_DIAG_FIN_8051_OFFSET 8 ++#define RTL8367C_INTR_IMS_8051_CABLE_DIAG_FIN_8051_MASK 0x100 ++#define RTL8367C_INTR_IMS_8051_EEELLDP_8051_OFFSET 7 ++#define RTL8367C_INTR_IMS_8051_EEELLDP_8051_MASK 0x80 ++#define RTL8367C_INTR_IMS_8051_LOOP_DETECTION_8051_OFFSET 6 ++#define RTL8367C_INTR_IMS_8051_LOOP_DETECTION_8051_MASK 0x40 ++#define RTL8367C_INTR_IMS_8051_GREEN_TIMER_8051_OFFSET 5 ++#define RTL8367C_INTR_IMS_8051_GREEN_TIMER_8051_MASK 0x20 ++#define RTL8367C_INTR_IMS_8051_SPECIAL_CONGEST_8051_OFFSET 4 ++#define RTL8367C_INTR_IMS_8051_SPECIAL_CONGEST_8051_MASK 0x10 ++#define RTL8367C_INTR_IMS_8051_SPEED_CHANGE_8051_OFFSET 3 ++#define RTL8367C_INTR_IMS_8051_SPEED_CHANGE_8051_MASK 0x8 ++#define RTL8367C_INTR_IMS_8051_LEARN_OVER_8051_OFFSET 2 ++#define RTL8367C_INTR_IMS_8051_LEARN_OVER_8051_MASK 0x4 ++#define RTL8367C_INTR_IMS_8051_METER_EXCEEDED_8051_OFFSET 1 ++#define RTL8367C_INTR_IMS_8051_METER_EXCEEDED_8051_MASK 0x2 ++#define RTL8367C_INTR_IMS_8051_LINK_CHANGE_8051_OFFSET 0 ++#define RTL8367C_INTR_IMS_8051_LINK_CHANGE_8051_MASK 0x1 ++ ++#define RTL8367C_REG_DW8051_INT_CPU 0x111a ++#define RTL8367C_DW8051_INT_CPU_OFFSET 0 ++#define RTL8367C_DW8051_INT_CPU_MASK 0x1 ++ ++#define RTL8367C_REG_LEARN_OVER_INDICATOR_8051 0x1120 ++#define RTL8367C_LEARN_OVER_INDICATOR_8051_OFFSET 0 ++#define RTL8367C_LEARN_OVER_INDICATOR_8051_MASK 0x7FF ++ ++#define RTL8367C_REG_SPEED_CHANGE_INDICATOR_8051 0x1121 ++#define RTL8367C_SPEED_CHANGE_INDICATOR_8051_OFFSET 0 ++#define RTL8367C_SPEED_CHANGE_INDICATOR_8051_MASK 0x7FF ++ ++#define RTL8367C_REG_SPECIAL_CONGEST_INDICATOR_8051 0x1122 ++#define RTL8367C_SPECIAL_CONGEST_INDICATOR_8051_OFFSET 0 ++#define RTL8367C_SPECIAL_CONGEST_INDICATOR_8051_MASK 0x7FF ++ ++#define RTL8367C_REG_PORT_LINKDOWN_INDICATOR_8051 0x1123 ++#define RTL8367C_PORT_LINKDOWN_INDICATOR_8051_OFFSET 0 ++#define RTL8367C_PORT_LINKDOWN_INDICATOR_8051_MASK 0x7FF ++ ++#define RTL8367C_REG_PORT_LINKUP_INDICATOR_8051 0x1124 ++#define RTL8367C_PORT_LINKUP_INDICATOR_8051_OFFSET 0 ++#define RTL8367C_PORT_LINKUP_INDICATOR_8051_MASK 0x7FF ++ ++#define RTL8367C_REG_DUMMY_1125 0x1125 ++ ++#define RTL8367C_REG_DUMMY_1126 0x1126 ++ ++#define RTL8367C_REG_DUMMY_1127 0x1127 ++ ++#define RTL8367C_REG_DUMMY_1128 0x1128 ++ ++#define RTL8367C_REG_DUMMY_1129 0x1129 ++ ++#define RTL8367C_REG_INTR_IMS_BUFFER_RESET 0x112a ++#define RTL8367C_INTR_IMS_BUFFER_RESET_IMR_BUFF_RESET_OFFSET 1 ++#define RTL8367C_INTR_IMS_BUFFER_RESET_IMR_BUFF_RESET_MASK 0x2 ++#define RTL8367C_INTR_IMS_BUFFER_RESET_BUFFER_RESET_OFFSET 0 ++#define RTL8367C_INTR_IMS_BUFFER_RESET_BUFFER_RESET_MASK 0x1 ++ ++#define RTL8367C_REG_INTR_IMS_8051_BUFFER_RESET 0x112b ++#define RTL8367C_INTR_IMS_8051_BUFFER_RESET_IMR_BUFF_RESET_OFFSET 1 ++#define RTL8367C_INTR_IMS_8051_BUFFER_RESET_IMR_BUFF_RESET_MASK 0x2 ++#define RTL8367C_INTR_IMS_8051_BUFFER_RESET_BUFFER_RESET_OFFSET 0 ++#define RTL8367C_INTR_IMS_8051_BUFFER_RESET_BUFFER_RESET_MASK 0x1 ++ ++#define RTL8367C_REG_GPHY_INTRPT_8051 0x112c ++#define RTL8367C_IMS_GPHY_8051_H_OFFSET 13 ++#define RTL8367C_IMS_GPHY_8051_H_MASK 0xE000 ++#define RTL8367C_IMR_GPHY_8051_H_OFFSET 10 ++#define RTL8367C_IMR_GPHY_8051_H_MASK 0x1C00 ++#define RTL8367C_IMS_GPHY_8051_OFFSET 5 ++#define RTL8367C_IMS_GPHY_8051_MASK 0x3E0 ++#define RTL8367C_IMR_GPHY_8051_OFFSET 0 ++#define RTL8367C_IMR_GPHY_8051_MASK 0x1F ++ ++#define RTL8367C_REG_GPHY_INTRPT 0x112d ++#define RTL8367C_IMS_GPHY_H_OFFSET 13 ++#define RTL8367C_IMS_GPHY_H_MASK 0xE000 ++#define RTL8367C_IMR_GPHY_H_OFFSET 10 ++#define RTL8367C_IMR_GPHY_H_MASK 0x1C00 ++#define RTL8367C_IMS_GPHY_OFFSET 5 ++#define RTL8367C_IMS_GPHY_MASK 0x3E0 ++#define RTL8367C_IMR_GPHY_OFFSET 0 ++#define RTL8367C_IMR_GPHY_MASK 0x1F ++ ++#define RTL8367C_REG_THERMAL_INTRPT 0x112e ++#define RTL8367C_IMS_TM_HIGH_OFFSET 3 ++#define RTL8367C_IMS_TM_HIGH_MASK 0x8 ++#define RTL8367C_IMR_TM_HIGH_OFFSET 2 ++#define RTL8367C_IMR_TM_HIGH_MASK 0x4 ++#define RTL8367C_IMS_TM_LOW_OFFSET 1 ++#define RTL8367C_IMS_TM_LOW_MASK 0x2 ++#define RTL8367C_IMR_TM_LOW_OFFSET 0 ++#define RTL8367C_IMR_TM_LOW_MASK 0x1 ++ ++#define RTL8367C_REG_THERMAL_INTRPT_8051 0x112f ++#define RTL8367C_IMS_TM_HIGH_8051_OFFSET 3 ++#define RTL8367C_IMS_TM_HIGH_8051_MASK 0x8 ++#define RTL8367C_IMR_TM_HIGH_8051_OFFSET 2 ++#define RTL8367C_IMR_TM_HIGH_8051_MASK 0x4 ++#define RTL8367C_IMS_TM_LOW_8051_OFFSET 1 ++#define RTL8367C_IMS_TM_LOW_8051_MASK 0x2 ++#define RTL8367C_IMR_TM_LOW_8051_OFFSET 0 ++#define RTL8367C_IMR_TM_LOW_8051_MASK 0x1 ++ ++#define RTL8367C_REG_SDS_LINK_CHG_INT 0x1130 ++#define RTL8367C_IMS_SDS_LINK_STS_C7_OFFSET 15 ++#define RTL8367C_IMS_SDS_LINK_STS_C7_MASK 0x8000 ++#define RTL8367C_IMS_SDS_LINK_STS_C6_OFFSET 14 ++#define RTL8367C_IMS_SDS_LINK_STS_C6_MASK 0x4000 ++#define RTL8367C_IMS_SDS_LINK_STS_C5_OFFSET 13 ++#define RTL8367C_IMS_SDS_LINK_STS_C5_MASK 0x2000 ++#define RTL8367C_IMS_SDS_LINK_STS_C4_OFFSET 12 ++#define RTL8367C_IMS_SDS_LINK_STS_C4_MASK 0x1000 ++#define RTL8367C_IMS_SDS_LINK_STS_C3_OFFSET 11 ++#define RTL8367C_IMS_SDS_LINK_STS_C3_MASK 0x800 ++#define RTL8367C_IMS_SDS_LINK_STS_C2_OFFSET 10 ++#define RTL8367C_IMS_SDS_LINK_STS_C2_MASK 0x400 ++#define RTL8367C_IMS_SDS_LINK_STS_C1_OFFSET 9 ++#define RTL8367C_IMS_SDS_LINK_STS_C1_MASK 0x200 ++#define RTL8367C_IMS_SDS_LINK_STS_C0_OFFSET 8 ++#define RTL8367C_IMS_SDS_LINK_STS_C0_MASK 0x100 ++#define RTL8367C_IMR_SDS_LINK_STS_C7_OFFSET 7 ++#define RTL8367C_IMR_SDS_LINK_STS_C7_MASK 0x80 ++#define RTL8367C_IMR_SDS_LINK_STS_C6_OFFSET 6 ++#define RTL8367C_IMR_SDS_LINK_STS_C6_MASK 0x40 ++#define RTL8367C_IMR_SDS_LINK_STS_C5_OFFSET 5 ++#define RTL8367C_IMR_SDS_LINK_STS_C5_MASK 0x20 ++#define RTL8367C_IMR_SDS_LINK_STS_C4_OFFSET 4 ++#define RTL8367C_IMR_SDS_LINK_STS_C4_MASK 0x10 ++#define RTL8367C_IMR_SDS_LINK_STS_C3_OFFSET 3 ++#define RTL8367C_IMR_SDS_LINK_STS_C3_MASK 0x8 ++#define RTL8367C_IMR_SDS_LINK_STS_C2_OFFSET 2 ++#define RTL8367C_IMR_SDS_LINK_STS_C2_MASK 0x4 ++#define RTL8367C_IMR_SDS_LINK_STS_C1_OFFSET 1 ++#define RTL8367C_IMR_SDS_LINK_STS_C1_MASK 0x2 ++#define RTL8367C_IMR_SDS_LINK_STS_C0_OFFSET 0 ++#define RTL8367C_IMR_SDS_LINK_STS_C0_MASK 0x1 ++ ++#define RTL8367C_REG_SDS_LINK_CHG_INT_8051 0x1131 ++#define RTL8367C_IMS_SDS_LINK_STS_C7_8051_OFFSET 15 ++#define RTL8367C_IMS_SDS_LINK_STS_C7_8051_MASK 0x8000 ++#define RTL8367C_IMS_SDS_LINK_STS_C6_8051_OFFSET 14 ++#define RTL8367C_IMS_SDS_LINK_STS_C6_8051_MASK 0x4000 ++#define RTL8367C_IMS_SDS_LINK_STS_C5_8051_OFFSET 13 ++#define RTL8367C_IMS_SDS_LINK_STS_C5_8051_MASK 0x2000 ++#define RTL8367C_IMS_SDS_LINK_STS_C4_8051_OFFSET 12 ++#define RTL8367C_IMS_SDS_LINK_STS_C4_8051_MASK 0x1000 ++#define RTL8367C_IMS_SDS_LINK_STS_C3_8051_OFFSET 11 ++#define RTL8367C_IMS_SDS_LINK_STS_C3_8051_MASK 0x800 ++#define RTL8367C_IMS_SDS_LINK_STS_C2_8051_OFFSET 10 ++#define RTL8367C_IMS_SDS_LINK_STS_C2_8051_MASK 0x400 ++#define RTL8367C_IMS_SDS_LINK_STS_C1_8051_OFFSET 9 ++#define RTL8367C_IMS_SDS_LINK_STS_C1_8051_MASK 0x200 ++#define RTL8367C_IMS_SDS_LINK_STS_C0_8051_OFFSET 8 ++#define RTL8367C_IMS_SDS_LINK_STS_C0_8051_MASK 0x100 ++#define RTL8367C_IMR_SDS_LINK_STS_C7_8051_OFFSET 7 ++#define RTL8367C_IMR_SDS_LINK_STS_C7_8051_MASK 0x80 ++#define RTL8367C_IMR_SDS_LINK_STS_C6_8051_OFFSET 6 ++#define RTL8367C_IMR_SDS_LINK_STS_C6_8051_MASK 0x40 ++#define RTL8367C_IMR_SDS_LINK_STS_C5_8051_OFFSET 5 ++#define RTL8367C_IMR_SDS_LINK_STS_C5_8051_MASK 0x20 ++#define RTL8367C_IMR_SDS_LINK_STS_C4_8051_OFFSET 4 ++#define RTL8367C_IMR_SDS_LINK_STS_C4_8051_MASK 0x10 ++#define RTL8367C_IMR_SDS_LINK_STS_C3_8051_OFFSET 3 ++#define RTL8367C_IMR_SDS_LINK_STS_C3_8051_MASK 0x8 ++#define RTL8367C_IMR_SDS_LINK_STS_C2_8051_OFFSET 2 ++#define RTL8367C_IMR_SDS_LINK_STS_C2_8051_MASK 0x4 ++#define RTL8367C_IMR_SDS_LINK_STS_C1_8051_OFFSET 1 ++#define RTL8367C_IMR_SDS_LINK_STS_C1_8051_MASK 0x2 ++#define RTL8367C_IMR_SDS_LINK_STS_C0_8051_OFFSET 0 ++#define RTL8367C_IMR_SDS_LINK_STS_C0_8051_MASK 0x1 ++ ++/* (16'h1200)swcore_reg */ ++ ++#define RTL8367C_REG_MAX_LENGTH_LIMINT_IPG 0x1200 ++#define RTL8367C_MAX_LENTH_CTRL_OFFSET 13 ++#define RTL8367C_MAX_LENTH_CTRL_MASK 0x6000 ++#define RTL8367C_PAGES_BEFORE_FCDROP_OFFSET 6 ++#define RTL8367C_PAGES_BEFORE_FCDROP_MASK 0x1FC0 ++#define RTL8367C_CHECK_MIN_IPG_RXDV_OFFSET 5 ++#define RTL8367C_CHECK_MIN_IPG_RXDV_MASK 0x20 ++#define RTL8367C_LIMIT_IPG_CFG_OFFSET 0 ++#define RTL8367C_LIMIT_IPG_CFG_MASK 0x1F ++ ++#define RTL8367C_REG_IOL_RXDROP_CFG 0x1201 ++#define RTL8367C_RX_IOL_MAX_LENGTH_CFG_OFFSET 13 ++#define RTL8367C_RX_IOL_MAX_LENGTH_CFG_MASK 0x2000 ++#define RTL8367C_RX_IOL_ERROR_LENGTH_CFG_OFFSET 12 ++#define RTL8367C_RX_IOL_ERROR_LENGTH_CFG_MASK 0x1000 ++#define RTL8367C_RX_NODROP_PAUSE_CFG_OFFSET 8 ++#define RTL8367C_RX_NODROP_PAUSE_CFG_MASK 0x100 ++#define RTL8367C_RX_DV_CNT_CFG_OFFSET 0 ++#define RTL8367C_RX_DV_CNT_CFG_MASK 0x3F ++ ++#define RTL8367C_REG_VS_TPID 0x1202 ++ ++#define RTL8367C_REG_INBW_BOUND 0x1203 ++#define RTL8367C_LBOUND_OFFSET 4 ++#define RTL8367C_LBOUND_MASK 0xF0 ++#define RTL8367C_HBOUND_OFFSET 0 ++#define RTL8367C_HBOUND_MASK 0xF ++ ++#define RTL8367C_REG_CFG_TX_ITFSP_OP 0x1204 ++#define RTL8367C_MASK_OFFSET 1 ++#define RTL8367C_MASK_MASK 0x2 ++#define RTL8367C_OP_OFFSET 0 ++#define RTL8367C_OP_MASK 0x1 ++ ++#define RTL8367C_REG_INBW_BOUND2 0x1205 ++#define RTL8367C_LBOUND2_H_OFFSET 9 ++#define RTL8367C_LBOUND2_H_MASK 0x200 ++#define RTL8367C_HBOUND2_H_OFFSET 8 ++#define RTL8367C_HBOUND2_H_MASK 0x100 ++#define RTL8367C_LBOUND2_OFFSET 4 ++#define RTL8367C_LBOUND2_MASK 0xF0 ++#define RTL8367C_HBOUND2_OFFSET 0 ++#define RTL8367C_HBOUND2_MASK 0xF ++ ++#define RTL8367C_REG_CFG_48PASS1_DROP 0x1206 ++#define RTL8367C_CFG_48PASS1_DROP_OFFSET 0 ++#define RTL8367C_CFG_48PASS1_DROP_MASK 0x1 ++ ++#define RTL8367C_REG_CFG_BACKPRESSURE 0x1207 ++#define RTL8367C_LONGTXE_OFFSET 12 ++#define RTL8367C_LONGTXE_MASK 0x1000 ++#define RTL8367C_EN_BYPASS_ERROR_OFFSET 8 ++#define RTL8367C_EN_BYPASS_ERROR_MASK 0x100 ++#define RTL8367C_EN_BACKPRESSURE_OFFSET 4 ++#define RTL8367C_EN_BACKPRESSURE_MASK 0x10 ++#define RTL8367C_EN_48_PASS_1_OFFSET 0 ++#define RTL8367C_EN_48_PASS_1_MASK 0x1 ++ ++#define RTL8367C_REG_CFG_UNHIOL 0x1208 ++#define RTL8367C_IOL_BACKOFF_OFFSET 12 ++#define RTL8367C_IOL_BACKOFF_MASK 0x1000 ++#define RTL8367C_BACKOFF_RANDOM_TIME_OFFSET 8 ++#define RTL8367C_BACKOFF_RANDOM_TIME_MASK 0x100 ++#define RTL8367C_DISABLE_BACK_OFF_OFFSET 4 ++#define RTL8367C_DISABLE_BACK_OFF_MASK 0x10 ++#define RTL8367C_IPG_COMPENSATION_OFFSET 0 ++#define RTL8367C_IPG_COMPENSATION_MASK 0x1 ++ ++#define RTL8367C_REG_SWITCH_MAC0 0x1209 ++ ++#define RTL8367C_REG_SWITCH_MAC1 0x120a ++ ++#define RTL8367C_REG_SWITCH_MAC2 0x120b ++ ++#define RTL8367C_REG_SWITCH_CTRL0 0x120c ++#define RTL8367C_REMARKING_DSCP_ENABLE_OFFSET 8 ++#define RTL8367C_REMARKING_DSCP_ENABLE_MASK 0x100 ++#define RTL8367C_SHORT_IPG_OFFSET 4 ++#define RTL8367C_SHORT_IPG_MASK 0x10 ++#define RTL8367C_PAUSE_MAX128_OFFSET 0 ++#define RTL8367C_PAUSE_MAX128_MASK 0x1 ++ ++#define RTL8367C_REG_QOS_DSCP_REMARK_CTRL0 0x120d ++#define RTL8367C_INTPRI1_DSCP_OFFSET 8 ++#define RTL8367C_INTPRI1_DSCP_MASK 0x3F00 ++#define RTL8367C_INTPRI0_DSCP_OFFSET 0 ++#define RTL8367C_INTPRI0_DSCP_MASK 0x3F ++ ++#define RTL8367C_REG_QOS_DSCP_REMARK_CTRL1 0x120e ++#define RTL8367C_INTPRI3_DSCP_OFFSET 8 ++#define RTL8367C_INTPRI3_DSCP_MASK 0x3F00 ++#define RTL8367C_INTPRI2_DSCP_OFFSET 0 ++#define RTL8367C_INTPRI2_DSCP_MASK 0x3F ++ ++#define RTL8367C_REG_QOS_DSCP_REMARK_CTRL2 0x120f ++#define RTL8367C_INTPRI5_DSCP_OFFSET 8 ++#define RTL8367C_INTPRI5_DSCP_MASK 0x3F00 ++#define RTL8367C_INTPRI4_DSCP_OFFSET 0 ++#define RTL8367C_INTPRI4_DSCP_MASK 0x3F ++ ++#define RTL8367C_REG_QOS_DSCP_REMARK_CTRL3 0x1210 ++#define RTL8367C_INTPRI7_DSCP_OFFSET 8 ++#define RTL8367C_INTPRI7_DSCP_MASK 0x3F00 ++#define RTL8367C_INTPRI6_DSCP_OFFSET 0 ++#define RTL8367C_INTPRI6_DSCP_MASK 0x3F ++ ++#define RTL8367C_REG_QOS_1Q_REMARK_CTRL0 0x1211 ++#define RTL8367C_INTPRI3_PRI_OFFSET 12 ++#define RTL8367C_INTPRI3_PRI_MASK 0x7000 ++#define RTL8367C_INTPRI2_PRI_OFFSET 8 ++#define RTL8367C_INTPRI2_PRI_MASK 0x700 ++#define RTL8367C_INTPRI1_PRI_OFFSET 4 ++#define RTL8367C_INTPRI1_PRI_MASK 0x70 ++#define RTL8367C_INTPRI0_PRI_OFFSET 0 ++#define RTL8367C_INTPRI0_PRI_MASK 0x7 ++ ++#define RTL8367C_REG_QOS_1Q_REMARK_CTRL1 0x1212 ++#define RTL8367C_INTPRI7_PRI_OFFSET 12 ++#define RTL8367C_INTPRI7_PRI_MASK 0x7000 ++#define RTL8367C_INTPRI6_PRI_OFFSET 8 ++#define RTL8367C_INTPRI6_PRI_MASK 0x700 ++#define RTL8367C_INTPRI5_PRI_OFFSET 4 ++#define RTL8367C_INTPRI5_PRI_MASK 0x70 ++#define RTL8367C_INTPRI4_PRI_OFFSET 0 ++#define RTL8367C_INTPRI4_PRI_MASK 0x7 ++ ++#define RTL8367C_REG_PKTGEN_COMMAND 0x1213 ++#define RTL8367C_PKTGEN_STOP_OFFSET 8 ++#define RTL8367C_PKTGEN_STOP_MASK 0x100 ++#define RTL8367C_PKTGEN_START_OFFSET 4 ++#define RTL8367C_PKTGEN_START_MASK 0x10 ++#define RTL8367C_PKTGEN_BYPASS_FLOWCONTROL_OFFSET 0 ++#define RTL8367C_PKTGEN_BYPASS_FLOWCONTROL_MASK 0x1 ++ ++#define RTL8367C_REG_SW_DUMMY0 0x1214 ++#define RTL8367C_SW_DUMMY0_DUMMY_OFFSET 4 ++#define RTL8367C_SW_DUMMY0_DUMMY_MASK 0xFFF0 ++#define RTL8367C_EEE_DEFER_TXLPI_OFFSET 3 ++#define RTL8367C_EEE_DEFER_TXLPI_MASK 0x8 ++#define RTL8367C_INGRESSBW_BYPASS_EN_OFFSET 2 ++#define RTL8367C_INGRESSBW_BYPASS_EN_MASK 0x4 ++#define RTL8367C_CFG_RX_MIN_OFFSET 0 ++#define RTL8367C_CFG_RX_MIN_MASK 0x3 ++ ++#define RTL8367C_REG_SW_DUMMY1 0x1215 ++ ++#define RTL8367C_REG_PKTGEN_PAUSE_TIME 0x1216 ++ ++#define RTL8367C_REG_SVLAN_UPLINK_PORTMASK 0x1218 ++#define RTL8367C_SVLAN_UPLINK_PORTMASK_OFFSET 0 ++#define RTL8367C_SVLAN_UPLINK_PORTMASK_MASK 0x7FF ++ ++#define RTL8367C_REG_CPU_PORT_MASK 0x1219 ++#define RTL8367C_CPU_PORT_MASK_OFFSET 0 ++#define RTL8367C_CPU_PORT_MASK_MASK 0x7FF ++ ++#define RTL8367C_REG_CPU_CTRL 0x121a ++#define RTL8367C_CPU_TRAP_PORT_EXT_OFFSET 10 ++#define RTL8367C_CPU_TRAP_PORT_EXT_MASK 0x400 ++#define RTL8367C_CPU_TAG_FORMAT_OFFSET 9 ++#define RTL8367C_CPU_TAG_FORMAT_MASK 0x200 ++#define RTL8367C_IOL_16DROP_OFFSET 8 ++#define RTL8367C_IOL_16DROP_MASK 0x100 ++#define RTL8367C_CPU_TAG_RXBYTECOUNT_OFFSET 7 ++#define RTL8367C_CPU_TAG_RXBYTECOUNT_MASK 0x80 ++#define RTL8367C_CPU_TAG_POSITION_OFFSET 6 ++#define RTL8367C_CPU_TAG_POSITION_MASK 0x40 ++#define RTL8367C_CPU_TRAP_PORT_OFFSET 3 ++#define RTL8367C_CPU_TRAP_PORT_MASK 0x38 ++#define RTL8367C_CPU_INSERTMODE_OFFSET 1 ++#define RTL8367C_CPU_INSERTMODE_MASK 0x6 ++#define RTL8367C_CPU_EN_OFFSET 0 ++#define RTL8367C_CPU_EN_MASK 0x1 ++ ++#define RTL8367C_REG_MIRROR_CTRL 0x121c ++#define RTL8367C_MIRROR_CTRL_DUMMY_OFFSET 12 ++#define RTL8367C_MIRROR_CTRL_DUMMY_MASK 0xF000 ++#define RTL8367C_MIRROR_ISO_OFFSET 11 ++#define RTL8367C_MIRROR_ISO_MASK 0x800 ++#define RTL8367C_MIRROR_TX_OFFSET 10 ++#define RTL8367C_MIRROR_TX_MASK 0x400 ++#define RTL8367C_MIRROR_RX_OFFSET 9 ++#define RTL8367C_MIRROR_RX_MASK 0x200 ++#define RTL8367C_MIRROR_MONITOR_PORT_OFFSET 4 ++#define RTL8367C_MIRROR_MONITOR_PORT_MASK 0xF0 ++#define RTL8367C_MIRROR_SOURCE_PORT_OFFSET 0 ++#define RTL8367C_MIRROR_SOURCE_PORT_MASK 0xF ++ ++#define RTL8367C_REG_FLOWCTRL_CTRL0 0x121d ++#define RTL8367C_FLOWCTRL_TYPE_OFFSET 15 ++#define RTL8367C_FLOWCTRL_TYPE_MASK 0x8000 ++#define RTL8367C_DROP_ALL_THRESHOLD_OFFSET 5 ++#define RTL8367C_DROP_ALL_THRESHOLD_MASK 0x7FE0 ++#define RTL8367C_DROP_ALL_THRESHOLD_MSB_OFFSET 4 ++#define RTL8367C_DROP_ALL_THRESHOLD_MSB_MASK 0x10 ++#define RTL8367C_ITFSP_REG_OFFSET 0 ++#define RTL8367C_ITFSP_REG_MASK 0x7 ++ ++#define RTL8367C_REG_FLOWCTRL_ALL_ON 0x121e ++#define RTL8367C_CFG_RLDPACT_OFFSET 12 ++#define RTL8367C_CFG_RLDPACT_MASK 0x1000 ++#define RTL8367C_FLOWCTRL_ALL_ON_THRESHOLD_OFFSET 0 ++#define RTL8367C_FLOWCTRL_ALL_ON_THRESHOLD_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_SYS_ON 0x121f ++#define RTL8367C_FLOWCTRL_SYS_ON_OFFSET 0 ++#define RTL8367C_FLOWCTRL_SYS_ON_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_SYS_OFF 0x1220 ++#define RTL8367C_FLOWCTRL_SYS_OFF_OFFSET 0 ++#define RTL8367C_FLOWCTRL_SYS_OFF_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_SHARE_ON 0x1221 ++#define RTL8367C_FLOWCTRL_SHARE_ON_OFFSET 0 ++#define RTL8367C_FLOWCTRL_SHARE_ON_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_SHARE_OFF 0x1222 ++#define RTL8367C_FLOWCTRL_SHARE_OFF_OFFSET 0 ++#define RTL8367C_FLOWCTRL_SHARE_OFF_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_FCOFF_SYS_ON 0x1223 ++#define RTL8367C_FLOWCTRL_FCOFF_SYS_ON_OFFSET 0 ++#define RTL8367C_FLOWCTRL_FCOFF_SYS_ON_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_FCOFF_SYS_OFF 0x1224 ++#define RTL8367C_FLOWCTRL_FCOFF_SYS_OFF_OFFSET 0 ++#define RTL8367C_FLOWCTRL_FCOFF_SYS_OFF_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_FCOFF_SHARE_ON 0x1225 ++#define RTL8367C_FLOWCTRL_FCOFF_SHARE_ON_OFFSET 0 ++#define RTL8367C_FLOWCTRL_FCOFF_SHARE_ON_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_FCOFF_SHARE_OFF 0x1226 ++#define RTL8367C_FLOWCTRL_FCOFF_SHARE_OFF_OFFSET 0 ++#define RTL8367C_FLOWCTRL_FCOFF_SHARE_OFF_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_PORT_ON 0x1227 ++#define RTL8367C_FLOWCTRL_PORT_ON_OFFSET 0 ++#define RTL8367C_FLOWCTRL_PORT_ON_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_PORT_OFF 0x1228 ++#define RTL8367C_FLOWCTRL_PORT_OFF_OFFSET 0 ++#define RTL8367C_FLOWCTRL_PORT_OFF_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_PORT_PRIVATE_ON 0x1229 ++#define RTL8367C_FLOWCTRL_PORT_PRIVATE_ON_OFFSET 0 ++#define RTL8367C_FLOWCTRL_PORT_PRIVATE_ON_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_PORT_PRIVATE_OFF 0x122a ++#define RTL8367C_FLOWCTRL_PORT_PRIVATE_OFF_OFFSET 0 ++#define RTL8367C_FLOWCTRL_PORT_PRIVATE_OFF_MASK 0x7FF ++ ++#define RTL8367C_REG_RRCP_CTRL0 0x122b ++#define RTL8367C_COL_SEL_OFFSET 14 ++#define RTL8367C_COL_SEL_MASK 0x4000 ++#define RTL8367C_CRS_SEL_OFFSET 13 ++#define RTL8367C_CRS_SEL_MASK 0x2000 ++#define RTL8367C_RRCP_PBVLAN_EN_OFFSET 11 ++#define RTL8367C_RRCP_PBVLAN_EN_MASK 0x800 ++#define RTL8367C_RRCPV3_SECURITY_CRC_OFFSET 10 ++#define RTL8367C_RRCPV3_SECURITY_CRC_MASK 0x400 ++#define RTL8367C_RRCPV3_HANDLE_OFFSET 8 ++#define RTL8367C_RRCPV3_HANDLE_MASK 0x300 ++#define RTL8367C_RRCPV1_MALFORMED_ACT_OFFSET 5 ++#define RTL8367C_RRCPV1_MALFORMED_ACT_MASK 0x60 ++#define RTL8367C_RRCP_VLANLEAKY_OFFSET 4 ++#define RTL8367C_RRCP_VLANLEAKY_MASK 0x10 ++#define RTL8367C_RRCPV1_SECURITY_CRC_GET_OFFSET 3 ++#define RTL8367C_RRCPV1_SECURITY_CRC_GET_MASK 0x8 ++#define RTL8367C_RRCPV1_SECURITY_CRC_SET_OFFSET 2 ++#define RTL8367C_RRCPV1_SECURITY_CRC_SET_MASK 0x4 ++#define RTL8367C_RRCPV1_HANDLE_OFFSET 1 ++#define RTL8367C_RRCPV1_HANDLE_MASK 0x2 ++#define RTL8367C_RRCP_ENABLE_OFFSET 0 ++#define RTL8367C_RRCP_ENABLE_MASK 0x1 ++ ++#define RTL8367C_REG_RRCP_CTRL1 0x122c ++#define RTL8367C_RRCP_ADMIN_PMSK_OFFSET 8 ++#define RTL8367C_RRCP_ADMIN_PMSK_MASK 0xFF00 ++#define RTL8367C_RRCP_AUTH_PMSK_OFFSET 0 ++#define RTL8367C_RRCP_AUTH_PMSK_MASK 0xFF ++ ++#define RTL8367C_REG_RRCP_CTRL2 0x122d ++#define RTL8367C_RRCPV1_HELLOFWD_TAG_OFFSET 9 ++#define RTL8367C_RRCPV1_HELLOFWD_TAG_MASK 0x600 ++#define RTL8367C_RRCP_FWD_TAG_OFFSET 7 ++#define RTL8367C_RRCP_FWD_TAG_MASK 0x180 ++#define RTL8367C_RRCPV1_REPLY_TAG_OFFSET 6 ++#define RTL8367C_RRCPV1_REPLY_TAG_MASK 0x40 ++#define RTL8367C_RRCPV1_HELLO_COUNT_OFFSET 3 ++#define RTL8367C_RRCPV1_HELLO_COUNT_MASK 0x38 ++#define RTL8367C_RRCPV1_HELLO_PEDIOD_OFFSET 0 ++#define RTL8367C_RRCPV1_HELLO_PEDIOD_MASK 0x3 ++ ++#define RTL8367C_REG_RRCP_CTRL3 0x122e ++#define RTL8367C_RRCP_TAG_PRIORITY_OFFSET 13 ++#define RTL8367C_RRCP_TAG_PRIORITY_MASK 0xE000 ++#define RTL8367C_RRCP_TAG_VID_OFFSET 0 ++#define RTL8367C_RRCP_TAG_VID_MASK 0xFFF ++ ++#define RTL8367C_REG_FLOWCTRL_FCOFF_PORT_ON 0x122f ++#define RTL8367C_FLOWCTRL_FCOFF_PORT_ON_OFFSET 0 ++#define RTL8367C_FLOWCTRL_FCOFF_PORT_ON_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_FCOFF_PORT_OFF 0x1230 ++#define RTL8367C_FLOWCTRL_FCOFF_PORT_OFF_OFFSET 0 ++#define RTL8367C_FLOWCTRL_FCOFF_PORT_OFF_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_FCOFF_PORT_PRIVATE_ON 0x1231 ++#define RTL8367C_FLOWCTRL_FCOFF_PORT_PRIVATE_ON_OFFSET 0 ++#define RTL8367C_FLOWCTRL_FCOFF_PORT_PRIVATE_ON_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_FCOFF_PORT_PRIVATE_OFF 0x1232 ++#define RTL8367C_FLOWCTRL_FCOFF_PORT_PRIVATE_OFF_OFFSET 0 ++#define RTL8367C_FLOWCTRL_FCOFF_PORT_PRIVATE_OFF_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_JUMBO_SYS_ON 0x1233 ++#define RTL8367C_FLOWCTRL_JUMBO_SYS_ON_OFFSET 0 ++#define RTL8367C_FLOWCTRL_JUMBO_SYS_ON_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_JUMBO_SYS_OFF 0x1234 ++#define RTL8367C_FLOWCTRL_JUMBO_SYS_OFF_OFFSET 0 ++#define RTL8367C_FLOWCTRL_JUMBO_SYS_OFF_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_JUMBO_SHARE_ON 0x1235 ++#define RTL8367C_FLOWCTRL_JUMBO_SHARE_ON_OFFSET 0 ++#define RTL8367C_FLOWCTRL_JUMBO_SHARE_ON_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_JUMBO_SHARE_OFF 0x1236 ++#define RTL8367C_FLOWCTRL_JUMBO_SHARE_OFF_OFFSET 0 ++#define RTL8367C_FLOWCTRL_JUMBO_SHARE_OFF_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_JUMBO_PORT_ON 0x1237 ++#define RTL8367C_FLOWCTRL_JUMBO_PORT_ON_OFFSET 0 ++#define RTL8367C_FLOWCTRL_JUMBO_PORT_ON_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_JUMBO_PORT_OFF 0x1238 ++#define RTL8367C_FLOWCTRL_JUMBO_PORT_OFF_OFFSET 0 ++#define RTL8367C_FLOWCTRL_JUMBO_PORT_OFF_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_JUMBO_PORT_PRIVATE_ON 0x1239 ++#define RTL8367C_FLOWCTRL_JUMBO_PORT_PRIVATE_ON_OFFSET 0 ++#define RTL8367C_FLOWCTRL_JUMBO_PORT_PRIVATE_ON_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_JUMBO_PORT_PRIVATE_OFF 0x123a ++#define RTL8367C_FLOWCTRL_JUMBO_PORT_PRIVATE_OFF_OFFSET 0 ++#define RTL8367C_FLOWCTRL_JUMBO_PORT_PRIVATE_OFF_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_JUMBO_SIZE 0x123b ++#define RTL8367C_JUMBO_MODE_OFFSET 2 ++#define RTL8367C_JUMBO_MODE_MASK 0x4 ++#define RTL8367C_JUMBO_SIZE_OFFSET 0 ++#define RTL8367C_JUMBO_SIZE_MASK 0x3 ++ ++#define RTL8367C_REG_FLOWCTRL_TOTAL_PAGE_COUNTER 0x124c ++#define RTL8367C_FLOWCTRL_TOTAL_PAGE_COUNTER_OFFSET 0 ++#define RTL8367C_FLOWCTRL_TOTAL_PAGE_COUNTER_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_PUBLIC_PAGE_COUNTER 0x124d ++#define RTL8367C_FLOWCTRL_PUBLIC_PAGE_COUNTER_OFFSET 0 ++#define RTL8367C_FLOWCTRL_PUBLIC_PAGE_COUNTER_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_TOTAL_PAGE_MAX 0x124e ++#define RTL8367C_FLOWCTRL_TOTAL_PAGE_MAX_OFFSET 0 ++#define RTL8367C_FLOWCTRL_TOTAL_PAGE_MAX_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_PUBLIC_PAGE_MAX 0x124f ++#define RTL8367C_FLOWCTRL_PUBLIC_PAGE_MAX_OFFSET 0 ++#define RTL8367C_FLOWCTRL_PUBLIC_PAGE_MAX_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_PORT0_PAGE_COUNTER 0x1250 ++#define RTL8367C_FLOWCTRL_PORT0_PAGE_COUNTER_OFFSET 0 ++#define RTL8367C_FLOWCTRL_PORT0_PAGE_COUNTER_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_PORT1_PAGE_COUNTER 0x1251 ++#define RTL8367C_FLOWCTRL_PORT1_PAGE_COUNTER_OFFSET 0 ++#define RTL8367C_FLOWCTRL_PORT1_PAGE_COUNTER_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_PORT2_PAGE_COUNTER 0x1252 ++#define RTL8367C_FLOWCTRL_PORT2_PAGE_COUNTER_OFFSET 0 ++#define RTL8367C_FLOWCTRL_PORT2_PAGE_COUNTER_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_PORT3_PAGE_COUNTER 0x1253 ++#define RTL8367C_FLOWCTRL_PORT3_PAGE_COUNTER_OFFSET 0 ++#define RTL8367C_FLOWCTRL_PORT3_PAGE_COUNTER_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_PORT4_PAGE_COUNTER 0x1254 ++#define RTL8367C_FLOWCTRL_PORT4_PAGE_COUNTER_OFFSET 0 ++#define RTL8367C_FLOWCTRL_PORT4_PAGE_COUNTER_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_PORT5_PAGE_COUNTER 0x1255 ++#define RTL8367C_FLOWCTRL_PORT5_PAGE_COUNTER_OFFSET 0 ++#define RTL8367C_FLOWCTRL_PORT5_PAGE_COUNTER_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_PORT6_PAGE_COUNTER 0x1256 ++#define RTL8367C_FLOWCTRL_PORT6_PAGE_COUNTER_OFFSET 0 ++#define RTL8367C_FLOWCTRL_PORT6_PAGE_COUNTER_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_PORT7_PAGE_COUNTER 0x1257 ++#define RTL8367C_FLOWCTRL_PORT7_PAGE_COUNTER_OFFSET 0 ++#define RTL8367C_FLOWCTRL_PORT7_PAGE_COUNTER_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_PUBLIC_FCOFF_PAGE_COUNTER 0x1258 ++#define RTL8367C_FLOWCTRL_PUBLIC_FCOFF_PAGE_COUNTER_OFFSET 0 ++#define RTL8367C_FLOWCTRL_PUBLIC_FCOFF_PAGE_COUNTER_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_PUBLIC_JUMBO_PAGE_COUNTER 0x1259 ++#define RTL8367C_FLOWCTRL_PUBLIC_JUMBO_PAGE_COUNTER_OFFSET 0 ++#define RTL8367C_FLOWCTRL_PUBLIC_JUMBO_PAGE_COUNTER_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_MAX_PUBLIC_FCOFF_PAGE_COUNTER 0x125a ++#define RTL8367C_FLOWCTRL_MAX_PUBLIC_FCOFF_PAGE_COUNTER_OFFSET 0 ++#define RTL8367C_FLOWCTRL_MAX_PUBLIC_FCOFF_PAGE_COUNTER_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_MAX_PUBLIC_JUMBO_PAGE_COUNTER 0x125b ++#define RTL8367C_FLOWCTRL_MAX_PUBLIC_JUMBO_PAGE_COUNTER_OFFSET 0 ++#define RTL8367C_FLOWCTRL_MAX_PUBLIC_JUMBO_PAGE_COUNTER_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_PORT0_PAGE_MAX 0x1260 ++#define RTL8367C_FLOWCTRL_PORT0_PAGE_MAX_OFFSET 0 ++#define RTL8367C_FLOWCTRL_PORT0_PAGE_MAX_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_PORT1_PAGE_MAX 0x1261 ++#define RTL8367C_FLOWCTRL_PORT1_PAGE_MAX_OFFSET 0 ++#define RTL8367C_FLOWCTRL_PORT1_PAGE_MAX_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_PORT2_PAGE_MAX 0x1262 ++#define RTL8367C_FLOWCTRL_PORT2_PAGE_MAX_OFFSET 0 ++#define RTL8367C_FLOWCTRL_PORT2_PAGE_MAX_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_PORT3_PAGE_MAX 0x1263 ++#define RTL8367C_FLOWCTRL_PORT3_PAGE_MAX_OFFSET 0 ++#define RTL8367C_FLOWCTRL_PORT3_PAGE_MAX_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_PORT4_PAGE_MAX 0x1264 ++#define RTL8367C_FLOWCTRL_PORT4_PAGE_MAX_OFFSET 0 ++#define RTL8367C_FLOWCTRL_PORT4_PAGE_MAX_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_PORT5_PAGE_MAX 0x1265 ++#define RTL8367C_FLOWCTRL_PORT5_PAGE_MAX_OFFSET 0 ++#define RTL8367C_FLOWCTRL_PORT5_PAGE_MAX_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_PORT6_PAGE_MAX 0x1266 ++#define RTL8367C_FLOWCTRL_PORT6_PAGE_MAX_OFFSET 0 ++#define RTL8367C_FLOWCTRL_PORT6_PAGE_MAX_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_PORT7_PAGE_MAX 0x1267 ++#define RTL8367C_FLOWCTRL_PORT7_PAGE_MAX_OFFSET 0 ++#define RTL8367C_FLOWCTRL_PORT7_PAGE_MAX_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_PAGE_COUNT_CLEAR 0x1268 ++#define RTL8367C_DIS_SKIP_FP_OFFSET 1 ++#define RTL8367C_DIS_SKIP_FP_MASK 0x2 ++#define RTL8367C_PAGE_COUNT_CLEAR_OFFSET 0 ++#define RTL8367C_PAGE_COUNT_CLEAR_MASK 0x1 ++ ++#define RTL8367C_REG_FLOWCTRL_PORT8_PAGE_MAX 0x1269 ++#define RTL8367C_FLOWCTRL_PORT8_PAGE_MAX_OFFSET 0 ++#define RTL8367C_FLOWCTRL_PORT8_PAGE_MAX_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_PORT9_PAGE_MAX 0x126a ++#define RTL8367C_FLOWCTRL_PORT9_PAGE_MAX_OFFSET 0 ++#define RTL8367C_FLOWCTRL_PORT9_PAGE_MAX_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_PORT10_PAGE_MAX 0x126b ++#define RTL8367C_FLOWCTRL_PORT10_PAGE_MAX_OFFSET 0 ++#define RTL8367C_FLOWCTRL_PORT10_PAGE_MAX_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_PORT8_PAGE_COUNTER 0x126c ++#define RTL8367C_FLOWCTRL_PORT8_PAGE_COUNTER_OFFSET 0 ++#define RTL8367C_FLOWCTRL_PORT8_PAGE_COUNTER_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_PORT9_PAGE_COUNTER 0x126d ++#define RTL8367C_FLOWCTRL_PORT9_PAGE_COUNTER_OFFSET 0 ++#define RTL8367C_FLOWCTRL_PORT9_PAGE_COUNTER_MASK 0x7FF ++ ++#define RTL8367C_REG_FLOWCTRL_PORT10_PAGE_COUNTER 0x126e ++#define RTL8367C_FLOWCTRL_PORT10_PAGE_COUNTER_OFFSET 0 ++#define RTL8367C_FLOWCTRL_PORT10_PAGE_COUNTER_MASK 0x7FF ++ ++#define RTL8367C_REG_RRCP_CTRL1_H 0x126f ++#define RTL8367C_RRCP_ADMIN_PMSK_P10_8_OFFSET 3 ++#define RTL8367C_RRCP_ADMIN_PMSK_P10_8_MASK 0x38 ++#define RTL8367C_RRCP_AUTH_PMSK_P10_8_OFFSET 0 ++#define RTL8367C_RRCP_AUTH_PMSK_P10_8_MASK 0x7 ++ ++#define RTL8367C_REG_EMA_CTRL0 0x1270 ++#define RTL8367C_CFG_DVSE_VIAROM_OFFSET 13 ++#define RTL8367C_CFG_DVSE_VIAROM_MASK 0x2000 ++#define RTL8367C_CFG_DVSE_MIBRAM_OFFSET 12 ++#define RTL8367C_CFG_DVSE_MIBRAM_MASK 0x1000 ++#define RTL8367C_CFG_DVSE_IROM_OFFSET 11 ++#define RTL8367C_CFG_DVSE_IROM_MASK 0x800 ++#define RTL8367C_CFG_DVSE_ERAM_OFFSET 10 ++#define RTL8367C_CFG_DVSE_ERAM_MASK 0x400 ++#define RTL8367C_CFG_DVSE_IRAM_OFFSET 9 ++#define RTL8367C_CFG_DVSE_IRAM_MASK 0x200 ++#define RTL8367C_CFG_DVSE_NICRAM_OFFSET 8 ++#define RTL8367C_CFG_DVSE_NICRAM_MASK 0x100 ++#define RTL8367C_CFG_DVSE_CVLANRAM_OFFSET 7 ++#define RTL8367C_CFG_DVSE_CVLANRAM_MASK 0x80 ++#define RTL8367C_CFG_DVSE_ACTRAM_OFFSET 6 ++#define RTL8367C_CFG_DVSE_ACTRAM_MASK 0x40 ++#define RTL8367C_CFG_DVSE_INQRAM_OFFSET 5 ++#define RTL8367C_CFG_DVSE_INQRAM_MASK 0x20 ++#define RTL8367C_CFG_DVSE_HSARAM_OFFSET 4 ++#define RTL8367C_CFG_DVSE_HSARAM_MASK 0x10 ++#define RTL8367C_CFG_DVSE_OUTQRAM_OFFSET 3 ++#define RTL8367C_CFG_DVSE_OUTQRAM_MASK 0x8 ++#define RTL8367C_CFG_DVSE_HTRAM_OFFSET 2 ++#define RTL8367C_CFG_DVSE_HTRAM_MASK 0x4 ++#define RTL8367C_CFG_DVSE_PBRAM_OFFSET 1 ++#define RTL8367C_CFG_DVSE_PBRAM_MASK 0x2 ++#define RTL8367C_CFG_DVSE_L2RAM_OFFSET 0 ++#define RTL8367C_CFG_DVSE_L2RAM_MASK 0x1 ++ ++#define RTL8367C_REG_EMA_CTRL1 0x1271 ++#define RTL8367C_CFG_DVS_OUTQRAM_OFFSET 12 ++#define RTL8367C_CFG_DVS_OUTQRAM_MASK 0xF000 ++#define RTL8367C_CFG_DVS_HTRAM_OFFSET 8 ++#define RTL8367C_CFG_DVS_HTRAM_MASK 0x700 ++#define RTL8367C_CFG_DVS_PBRAM_OFFSET 4 ++#define RTL8367C_CFG_DVS_PBRAM_MASK 0xF0 ++#define RTL8367C_CFG_DVS_L2RAM_OFFSET 0 ++#define RTL8367C_CFG_DVS_L2RAM_MASK 0xF ++ ++#define RTL8367C_REG_EMA_CTRL2 0x1272 ++#define RTL8367C_CFG_DVS_CVLANRAM_OFFSET 12 ++#define RTL8367C_CFG_DVS_CVLANRAM_MASK 0xF000 ++#define RTL8367C_CFG_DVS_ACTRAM_OFFSET 8 ++#define RTL8367C_CFG_DVS_ACTRAM_MASK 0xF00 ++#define RTL8367C_CFG_DVS_INQRAM_OFFSET 4 ++#define RTL8367C_CFG_DVS_INQRAM_MASK 0xF0 ++#define RTL8367C_CFG_DVS_HSARAM_OFFSET 0 ++#define RTL8367C_CFG_DVS_HSARAM_MASK 0xF ++ ++#define RTL8367C_REG_EMA_CTRL3 0x1273 ++#define RTL8367C_CFG_DVS_IROM_OFFSET 12 ++#define RTL8367C_CFG_DVS_IROM_MASK 0xF000 ++#define RTL8367C_CFG_DVS_ERAM_OFFSET 8 ++#define RTL8367C_CFG_DVS_ERAM_MASK 0xF00 ++#define RTL8367C_CFG_DVS_IRAM_OFFSET 4 ++#define RTL8367C_CFG_DVS_IRAM_MASK 0xF0 ++#define RTL8367C_CFG_DVS_NICRAM_OFFSET 0 ++#define RTL8367C_CFG_DVS_NICRAM_MASK 0xF ++ ++#define RTL8367C_REG_EMA_CTRL4 0x1274 ++#define RTL8367C_CFG_DVS_VIAROM_OFFSET 4 ++#define RTL8367C_CFG_DVS_VIAROM_MASK 0xF0 ++#define RTL8367C_CFG_DVS_MIBRAM_OFFSET 0 ++#define RTL8367C_CFG_DVS_MIBRAM_MASK 0xF ++ ++#define RTL8367C_REG_DIAG_MODE 0x1275 ++#define RTL8367C_DIAG_MODE_OFFSET 0 ++#define RTL8367C_DIAG_MODE_MASK 0x1F ++ ++#define RTL8367C_REG_BIST_MODE 0x1276 ++ ++#define RTL8367C_REG_STS_BIST_DONE 0x1277 ++ ++#define RTL8367C_REG_STS_BIST_RLT0 0x1278 ++#define RTL8367C_STS_BIST_RLT0_OFFSET 0 ++#define RTL8367C_STS_BIST_RLT0_MASK 0x1 ++ ++#define RTL8367C_REG_STS_BIST_RLT1 0x1279 ++ ++#define RTL8367C_REG_STS_BIST_RLT2 0x127a ++ ++#define RTL8367C_REG_STS_BIST_RLT3 0x127b ++#define RTL8367C_STS_BIST_RLT3_OFFSET 0 ++#define RTL8367C_STS_BIST_RLT3_MASK 0x3FF ++ ++#define RTL8367C_REG_STS_BIST_RLT4 0x127c ++#define RTL8367C_STS_BIST_RLT4_OFFSET 0 ++#define RTL8367C_STS_BIST_RLT4_MASK 0x7 ++ ++#define RTL8367C_REG_VIAROM_MISR 0x127d ++ ++#define RTL8367C_REG_DRF_BIST_MODE 0x1280 ++#define RTL8367C_DRF_TCAMDEL_OFFSET 15 ++#define RTL8367C_DRF_TCAMDEL_MASK 0x8000 ++#define RTL8367C_CFG_DRF_BIST_MODE_OFFSET 0 ++#define RTL8367C_CFG_DRF_BIST_MODE_MASK 0x7FFF ++ ++#define RTL8367C_REG_STS_DRF_BIST 0x1281 ++#define RTL8367C_STS_DRF_BIST_OFFSET 0 ++#define RTL8367C_STS_DRF_BIST_MASK 0x7FFF ++ ++#define RTL8367C_REG_STS_DRF_BIST_RLT0 0x1282 ++#define RTL8367C_STS_DRF_BIST_RLT0_OFFSET 0 ++#define RTL8367C_STS_DRF_BIST_RLT0_MASK 0x1 ++ ++#define RTL8367C_REG_STS_DRF_BIST_RLT1 0x1283 ++ ++#define RTL8367C_REG_STS_DRF_BIST_RLT2 0x1284 ++ ++#define RTL8367C_REG_STS_DRF_BIST_RLT3 0x1285 ++#define RTL8367C_STS_DRF_BIST_RLT3_OFFSET 0 ++#define RTL8367C_STS_DRF_BIST_RLT3_MASK 0x3FF ++ ++#define RTL8367C_REG_STS_DRF_BIST_RLT4 0x1286 ++#define RTL8367C_STS_DRF_BIST_RLT4_OFFSET 0 ++#define RTL8367C_STS_DRF_BIST_RLT4_MASK 0x7FFF ++ ++#define RTL8367C_REG_RAM_DRF_CTRL 0x1289 ++#define RTL8367C_RAM_DRF_CTRL_OFFSET 0 ++#define RTL8367C_RAM_DRF_CTRL_MASK 0x1 ++ ++#define RTL8367C_REG_MIB_RMON_LEN_CTRL 0x128a ++#define RTL8367C_RX_LENGTH_CTRL_OFFSET 1 ++#define RTL8367C_RX_LENGTH_CTRL_MASK 0x2 ++#define RTL8367C_TX_LENGTH_CTRL_OFFSET 0 ++#define RTL8367C_TX_LENGTH_CTRL_MASK 0x1 ++ ++#define RTL8367C_REG_COND0_BISR_OUT0 0x1290 ++ ++#define RTL8367C_REG_COND0_BISR_OUT1 0x1291 ++ ++#define RTL8367C_REG_COND0_BISR_OUT2 0x1292 ++ ++#define RTL8367C_REG_COND0_BISR_OUT3 0x1293 ++ ++#define RTL8367C_REG_COND0_BISR_OUT4 0x1294 ++#define RTL8367C_COND0_BISR_OUT4_OFFSET 0 ++#define RTL8367C_COND0_BISR_OUT4_MASK 0x3F ++ ++#define RTL8367C_REG_COND0_BISR_OUT5 0x1295 ++#define RTL8367C_COND0_BISR_OUT5_OFFSET 0 ++#define RTL8367C_COND0_BISR_OUT5_MASK 0x7 ++ ++#define RTL8367C_REG_CHG_DUPLEX_CFG 0x1296 ++#define RTL8367C_CHG_COL_CNT_PORT_OFFSET 13 ++#define RTL8367C_CHG_COL_CNT_PORT_MASK 0xE000 ++#define RTL8367C_CHG_COL_CNT_OFFSET 8 ++#define RTL8367C_CHG_COL_CNT_MASK 0x1F00 ++#define RTL8367C_CFG_CHG_DUP_EN_OFFSET 7 ++#define RTL8367C_CFG_CHG_DUP_EN_MASK 0x80 ++#define RTL8367C_CFG_CHG_DUP_THR_OFFSET 2 ++#define RTL8367C_CFG_CHG_DUP_THR_MASK 0x7C ++#define RTL8367C_CFG_CHG_DUP_CONGEST_OFFSET 1 ++#define RTL8367C_CFG_CHG_DUP_CONGEST_MASK 0x2 ++#define RTL8367C_CFG_CHG_DUP_REF_OFFSET 0 ++#define RTL8367C_CFG_CHG_DUP_REF_MASK 0x1 ++ ++#define RTL8367C_REG_COND0_BIST_PASS 0x1297 ++#define RTL8367C_COND0_DRF_BIST_NOFAIL_OFFSET 1 ++#define RTL8367C_COND0_DRF_BIST_NOFAIL_MASK 0x2 ++#define RTL8367C_COND0_BIST_NOFAIL_OFFSET 0 ++#define RTL8367C_COND0_BIST_NOFAIL_MASK 0x1 ++ ++#define RTL8367C_REG_COND1_BISR_OUT0 0x1298 ++ ++#define RTL8367C_REG_COND1_BISR_OUT1 0x1299 ++ ++#define RTL8367C_REG_COND1_BISR_OUT2 0x129a ++ ++#define RTL8367C_REG_COND1_BISR_OUT3 0x129b ++ ++#define RTL8367C_REG_COND1_BISR_OUT4 0x129c ++#define RTL8367C_COND1_BISR_OUT4_OFFSET 0 ++#define RTL8367C_COND1_BISR_OUT4_MASK 0x3F ++ ++#define RTL8367C_REG_COND1_BISR_OUT5 0x129d ++#define RTL8367C_COND1_BISR_OUT5_OFFSET 0 ++#define RTL8367C_COND1_BISR_OUT5_MASK 0x7 ++ ++#define RTL8367C_REG_COND1_BIST_PASS 0x129f ++#define RTL8367C_COND1_DRF_BIST_NOFAIL_OFFSET 1 ++#define RTL8367C_COND1_DRF_BIST_NOFAIL_MASK 0x2 ++#define RTL8367C_COND1_BIST_NOFAIL_OFFSET 0 ++#define RTL8367C_COND1_BIST_NOFAIL_MASK 0x1 ++ ++#define RTL8367C_REG_EEE_TX_THR_Giga_500M 0x12a0 ++ ++#define RTL8367C_REG_EEE_TX_THR_FE 0x12a1 ++ ++#define RTL8367C_REG_EEE_MISC 0x12a3 ++#define RTL8367C_EEE_REQ_SET1_OFFSET 13 ++#define RTL8367C_EEE_REQ_SET1_MASK 0x2000 ++#define RTL8367C_EEE_REQ_SET0_OFFSET 12 ++#define RTL8367C_EEE_REQ_SET0_MASK 0x1000 ++#define RTL8367C_EEE_WAKE_SET1_OFFSET 9 ++#define RTL8367C_EEE_WAKE_SET1_MASK 0x200 ++#define RTL8367C_EEE_Wake_SET0_OFFSET 8 ++#define RTL8367C_EEE_Wake_SET0_MASK 0x100 ++#define RTL8367C_EEE_TU_GIGA_500M_OFFSET 4 ++#define RTL8367C_EEE_TU_GIGA_500M_MASK 0x30 ++#define RTL8367C_EEE_TU_100M_OFFSET 2 ++#define RTL8367C_EEE_TU_100M_MASK 0xC ++ ++#define RTL8367C_REG_EEE_GIGA_CTRL0 0x12a4 ++#define RTL8367C_EEE_TW_GIGA_OFFSET 8 ++#define RTL8367C_EEE_TW_GIGA_MASK 0xFF00 ++#define RTL8367C_EEE_TR_GIGA_500M_OFFSET 0 ++#define RTL8367C_EEE_TR_GIGA_500M_MASK 0xFF ++ ++#define RTL8367C_REG_EEE_GIGA_CTRL1 0x12a5 ++#define RTL8367C_EEE_TD_GIGA_500M_OFFSET 8 ++#define RTL8367C_EEE_TD_GIGA_500M_MASK 0xFF00 ++#define RTL8367C_EEE_TP_GIGA_OFFSET 0 ++#define RTL8367C_EEE_TP_GIGA_MASK 0xFF ++ ++#define RTL8367C_REG_EEE_100M_CTRL0 0x12a6 ++#define RTL8367C_EEE_TW_100M_OFFSET 8 ++#define RTL8367C_EEE_TW_100M_MASK 0xFF00 ++#define RTL8367C_EEE_TR_100M_OFFSET 0 ++#define RTL8367C_EEE_TR_100M_MASK 0xFF ++ ++#define RTL8367C_REG_EEE_100M_CTRL1 0x12a7 ++#define RTL8367C_EEE_TD_100M_OFFSET 8 ++#define RTL8367C_EEE_TD_100M_MASK 0xFF00 ++#define RTL8367C_EEE_TP_100M_OFFSET 0 ++#define RTL8367C_EEE_TP_100M_MASK 0xFF ++ ++#define RTL8367C_REG_RX_FC_REG 0x12aa ++#define RTL8367C_EN_EEE_HALF_DUP_OFFSET 8 ++#define RTL8367C_EN_EEE_HALF_DUP_MASK 0x100 ++#define RTL8367C_RX_PGCNT_OFFSET 0 ++#define RTL8367C_RX_PGCNT_MASK 0xFF ++ ++#define RTL8367C_REG_MAX_FIFO_SIZE 0x12af ++#define RTL8367C_MAX_FIFO_SIZE_OFFSET 0 ++#define RTL8367C_MAX_FIFO_SIZE_MASK 0xF ++ ++#define RTL8367C_REG_EEEP_RX_RATE_GIGA 0x12b0 ++ ++#define RTL8367C_REG_EEEP_RX_RATE_100M 0x12b1 ++ ++#define RTL8367C_REG_DUMMY_REG_12_2 0x12b2 ++ ++#define RTL8367C_REG_EEEP_TX_RATE_GIGA 0x12b3 ++ ++#define RTL8367C_REG_EEEP_TX_RATE_100M 0x12b4 ++ ++#define RTL8367C_REG_DUMMY_REG_12_3 0x12b5 ++ ++#define RTL8367C_REG_EEEP_GIGA_CTRL0 0x12b6 ++#define RTL8367C_EEEP_TR_GIGA_OFFSET 8 ++#define RTL8367C_EEEP_TR_GIGA_MASK 0xFF00 ++#define RTL8367C_EEEP_RW_GIGA_MST_OFFSET 0 ++#define RTL8367C_EEEP_RW_GIGA_MST_MASK 0xFF ++ ++#define RTL8367C_REG_EEEP_GIGA_CTRL1 0x12b7 ++#define RTL8367C_EEEP_TW_GIGA_OFFSET 8 ++#define RTL8367C_EEEP_TW_GIGA_MASK 0xFF00 ++#define RTL8367C_EEEP_TP_GIGA_OFFSET 0 ++#define RTL8367C_EEEP_TP_GIGA_MASK 0xFF ++ ++#define RTL8367C_REG_EEEP_GIGA_CTRL2 0x12b8 ++#define RTL8367C_EEEP_TXEN_GIGA_OFFSET 12 ++#define RTL8367C_EEEP_TXEN_GIGA_MASK 0x1000 ++#define RTL8367C_EEEP_TU_GIGA_OFFSET 8 ++#define RTL8367C_EEEP_TU_GIGA_MASK 0x300 ++#define RTL8367C_EEEP_TS_GIGA_OFFSET 0 ++#define RTL8367C_EEEP_TS_GIGA_MASK 0xFF ++ ++#define RTL8367C_REG_EEEP_100M_CTRL0 0x12b9 ++#define RTL8367C_EEEP_TR_100M_OFFSET 8 ++#define RTL8367C_EEEP_TR_100M_MASK 0xFF00 ++#define RTL8367C_EEEP_RW_100M_OFFSET 0 ++#define RTL8367C_EEEP_RW_100M_MASK 0xFF ++ ++#define RTL8367C_REG_EEEP_100M_CTRL1 0x12ba ++#define RTL8367C_EEEP_TW_100M_OFFSET 8 ++#define RTL8367C_EEEP_TW_100M_MASK 0xFF00 ++#define RTL8367C_EEEP_TP_100M_OFFSET 0 ++#define RTL8367C_EEEP_TP_100M_MASK 0xFF ++ ++#define RTL8367C_REG_EEEP_100M_CTRL2 0x12bb ++#define RTL8367C_EEEP_TXEN_100M_OFFSET 12 ++#define RTL8367C_EEEP_TXEN_100M_MASK 0x1000 ++#define RTL8367C_EEEP_TU_100M_OFFSET 8 ++#define RTL8367C_EEEP_TU_100M_MASK 0x300 ++#define RTL8367C_EEEP_TS_100M_OFFSET 0 ++#define RTL8367C_EEEP_TS_100M_MASK 0xFF ++ ++#define RTL8367C_REG_EEEP_CTRL0 0x12bc ++#define RTL8367C_EEEP_CTRL0_DUMMY_OFFSET 8 ++#define RTL8367C_EEEP_CTRL0_DUMMY_MASK 0xFF00 ++#define RTL8367C_EEEP_SLEEP_STEP_OFFSET 0 ++#define RTL8367C_EEEP_SLEEP_STEP_MASK 0xFF ++ ++#define RTL8367C_REG_EEEP_CTRL1 0x12bd ++#define RTL8367C_EEEP_TXR_GIGA_OFFSET 8 ++#define RTL8367C_EEEP_TXR_GIGA_MASK 0xFF00 ++#define RTL8367C_EEEP_TXR_100M_OFFSET 0 ++#define RTL8367C_EEEP_TXR_100M_MASK 0xFF ++ ++#define RTL8367C_REG_BACK_PRESSURE_IPG 0x12be ++#define RTL8367C_BACK_PRESSURE_IPG_OFFSET 0 ++#define RTL8367C_BACK_PRESSURE_IPG_MASK 0x3 ++ ++#define RTL8367C_REG_TX_ESD_LEVEL 0x12bf ++#define RTL8367C_TX_ESD_LEVEL_MODE_OFFSET 8 ++#define RTL8367C_TX_ESD_LEVEL_MODE_MASK 0x100 ++#define RTL8367C_LEVEL_OFFSET 0 ++#define RTL8367C_LEVEL_MASK 0xFF ++ ++#define RTL8367C_REG_RRCP_CTRL4 0x12e0 ++ ++#define RTL8367C_REG_RRCP_CTRL5 0x12e1 ++ ++#define RTL8367C_REG_RRCP_CTRL6 0x12e2 ++ ++#define RTL8367C_REG_RRCP_CTRL7 0x12e3 ++ ++#define RTL8367C_REG_RRCP_CTRL8 0x12e4 ++ ++#define RTL8367C_REG_RRCP_CTRL9 0x12e5 ++ ++#define RTL8367C_REG_RRCP_CTRL10 0x12e6 ++ ++#define RTL8367C_REG_FIELD_SELECTOR0 0x12e7 ++#define RTL8367C_FIELD_SELECTOR0_FORMAT_OFFSET 8 ++#define RTL8367C_FIELD_SELECTOR0_FORMAT_MASK 0x700 ++#define RTL8367C_FIELD_SELECTOR0_OFFSET_OFFSET 0 ++#define RTL8367C_FIELD_SELECTOR0_OFFSET_MASK 0xFF ++ ++#define RTL8367C_REG_FIELD_SELECTOR1 0x12e8 ++#define RTL8367C_FIELD_SELECTOR1_FORMAT_OFFSET 8 ++#define RTL8367C_FIELD_SELECTOR1_FORMAT_MASK 0x700 ++#define RTL8367C_FIELD_SELECTOR1_OFFSET_OFFSET 0 ++#define RTL8367C_FIELD_SELECTOR1_OFFSET_MASK 0xFF ++ ++#define RTL8367C_REG_FIELD_SELECTOR2 0x12e9 ++#define RTL8367C_FIELD_SELECTOR2_FORMAT_OFFSET 8 ++#define RTL8367C_FIELD_SELECTOR2_FORMAT_MASK 0x700 ++#define RTL8367C_FIELD_SELECTOR2_OFFSET_OFFSET 0 ++#define RTL8367C_FIELD_SELECTOR2_OFFSET_MASK 0xFF ++ ++#define RTL8367C_REG_FIELD_SELECTOR3 0x12ea ++#define RTL8367C_FIELD_SELECTOR3_FORMAT_OFFSET 8 ++#define RTL8367C_FIELD_SELECTOR3_FORMAT_MASK 0x700 ++#define RTL8367C_FIELD_SELECTOR3_OFFSET_OFFSET 0 ++#define RTL8367C_FIELD_SELECTOR3_OFFSET_MASK 0xFF ++ ++#define RTL8367C_REG_FIELD_SELECTOR4 0x12eb ++#define RTL8367C_FIELD_SELECTOR4_FORMAT_OFFSET 8 ++#define RTL8367C_FIELD_SELECTOR4_FORMAT_MASK 0x700 ++#define RTL8367C_FIELD_SELECTOR4_OFFSET_OFFSET 0 ++#define RTL8367C_FIELD_SELECTOR4_OFFSET_MASK 0xFF ++ ++#define RTL8367C_REG_FIELD_SELECTOR5 0x12ec ++#define RTL8367C_FIELD_SELECTOR5_FORMAT_OFFSET 8 ++#define RTL8367C_FIELD_SELECTOR5_FORMAT_MASK 0x700 ++#define RTL8367C_FIELD_SELECTOR5_OFFSET_OFFSET 0 ++#define RTL8367C_FIELD_SELECTOR5_OFFSET_MASK 0xFF ++ ++#define RTL8367C_REG_FIELD_SELECTOR6 0x12ed ++#define RTL8367C_FIELD_SELECTOR6_FORMAT_OFFSET 8 ++#define RTL8367C_FIELD_SELECTOR6_FORMAT_MASK 0x700 ++#define RTL8367C_FIELD_SELECTOR6_OFFSET_OFFSET 0 ++#define RTL8367C_FIELD_SELECTOR6_OFFSET_MASK 0xFF ++ ++#define RTL8367C_REG_FIELD_SELECTOR7 0x12ee ++#define RTL8367C_FIELD_SELECTOR7_FORMAT_OFFSET 8 ++#define RTL8367C_FIELD_SELECTOR7_FORMAT_MASK 0x700 ++#define RTL8367C_FIELD_SELECTOR7_OFFSET_OFFSET 0 ++#define RTL8367C_FIELD_SELECTOR7_OFFSET_MASK 0xFF ++ ++#define RTL8367C_REG_FIELD_SELECTOR8 0x12ef ++#define RTL8367C_FIELD_SELECTOR8_FORMAT_OFFSET 8 ++#define RTL8367C_FIELD_SELECTOR8_FORMAT_MASK 0x700 ++#define RTL8367C_FIELD_SELECTOR8_OFFSET_OFFSET 0 ++#define RTL8367C_FIELD_SELECTOR8_OFFSET_MASK 0xFF ++ ++#define RTL8367C_REG_FIELD_SELECTOR9 0x12f0 ++#define RTL8367C_FIELD_SELECTOR9_FORMAT_OFFSET 8 ++#define RTL8367C_FIELD_SELECTOR9_FORMAT_MASK 0x700 ++#define RTL8367C_FIELD_SELECTOR9_OFFSET_OFFSET 0 ++#define RTL8367C_FIELD_SELECTOR9_OFFSET_MASK 0xFF ++ ++#define RTL8367C_REG_FIELD_SELECTOR10 0x12f1 ++#define RTL8367C_FIELD_SELECTOR10_FORMAT_OFFSET 8 ++#define RTL8367C_FIELD_SELECTOR10_FORMAT_MASK 0x700 ++#define RTL8367C_FIELD_SELECTOR10_OFFSET_OFFSET 0 ++#define RTL8367C_FIELD_SELECTOR10_OFFSET_MASK 0xFF ++ ++#define RTL8367C_REG_FIELD_SELECTOR11 0x12f2 ++#define RTL8367C_FIELD_SELECTOR11_FORMAT_OFFSET 8 ++#define RTL8367C_FIELD_SELECTOR11_FORMAT_MASK 0x700 ++#define RTL8367C_FIELD_SELECTOR11_OFFSET_OFFSET 0 ++#define RTL8367C_FIELD_SELECTOR11_OFFSET_MASK 0xFF ++ ++#define RTL8367C_REG_FIELD_SELECTOR12 0x12f3 ++#define RTL8367C_FIELD_SELECTOR12_FORMAT_OFFSET 8 ++#define RTL8367C_FIELD_SELECTOR12_FORMAT_MASK 0x700 ++#define RTL8367C_FIELD_SELECTOR12_OFFSET_OFFSET 0 ++#define RTL8367C_FIELD_SELECTOR12_OFFSET_MASK 0xFF ++ ++#define RTL8367C_REG_FIELD_SELECTOR13 0x12f4 ++#define RTL8367C_FIELD_SELECTOR13_FORMAT_OFFSET 8 ++#define RTL8367C_FIELD_SELECTOR13_FORMAT_MASK 0x700 ++#define RTL8367C_FIELD_SELECTOR13_OFFSET_OFFSET 0 ++#define RTL8367C_FIELD_SELECTOR13_OFFSET_MASK 0xFF ++ ++#define RTL8367C_REG_FIELD_SELECTOR14 0x12f5 ++#define RTL8367C_FIELD_SELECTOR14_FORMAT_OFFSET 8 ++#define RTL8367C_FIELD_SELECTOR14_FORMAT_MASK 0x700 ++#define RTL8367C_FIELD_SELECTOR14_OFFSET_OFFSET 0 ++#define RTL8367C_FIELD_SELECTOR14_OFFSET_MASK 0xFF ++ ++#define RTL8367C_REG_FIELD_SELECTOR15 0x12f6 ++#define RTL8367C_FIELD_SELECTOR15_FORMAT_OFFSET 8 ++#define RTL8367C_FIELD_SELECTOR15_FORMAT_MASK 0x700 ++#define RTL8367C_FIELD_SELECTOR15_OFFSET_OFFSET 0 ++#define RTL8367C_FIELD_SELECTOR15_OFFSET_MASK 0xFF ++ ++#define RTL8367C_REG_HWPKT_GEN_MISC_H 0x12f7 ++#define RTL8367C_PKT_GEN_SUSPEND_P10_8_OFFSET 3 ++#define RTL8367C_PKT_GEN_SUSPEND_P10_8_MASK 0x38 ++#define RTL8367C_PKT_GEN_STATUS_P10_8_OFFSET 0 ++#define RTL8367C_PKT_GEN_STATUS_P10_8_MASK 0x7 ++ ++#define RTL8367C_REG_MIRROR_SRC_PMSK 0x12fb ++#define RTL8367C_MIRROR_SRC_PMSK_OFFSET 0 ++#define RTL8367C_MIRROR_SRC_PMSK_MASK 0x7FF ++ ++#define RTL8367C_REG_EEE_BURSTSIZE 0x12fc ++ ++#define RTL8367C_REG_EEE_IFG_CFG 0x12fd ++#define RTL8367C_EEE_IFG_CFG_OFFSET 0 ++#define RTL8367C_EEE_IFG_CFG_MASK 0x1 ++ ++#define RTL8367C_REG_FPGA_VER_MAC 0x12fe ++ ++#define RTL8367C_REG_HWPKT_GEN_MISC 0x12ff ++#define RTL8367C_PKT_GEN_SUSPEND_OFFSET 8 ++#define RTL8367C_PKT_GEN_SUSPEND_MASK 0xFF00 ++#define RTL8367C_PKT_GEN_STATUS_OFFSET 0 ++#define RTL8367C_PKT_GEN_STATUS_MASK 0xFF ++ ++/* (16'h1300)chip_reg */ ++ ++#define RTL8367C_REG_CHIP_NUMBER 0x1300 ++ ++#define RTL8367C_REG_CHIP_VER 0x1301 ++#define RTL8367C_VERID_OFFSET 12 ++#define RTL8367C_VERID_MASK 0xF000 ++#define RTL8367C_MCID_OFFSET 8 ++#define RTL8367C_MCID_MASK 0xF00 ++#define RTL8367C_MODEL_ID_OFFSET 4 ++#define RTL8367C_MODEL_ID_MASK 0xF0 ++#define RTL8367C_AFE_VERSION_OFFSET 0 ++#define RTL8367C_AFE_VERSION_MASK 0x1 ++ ++#define RTL8367C_REG_CHIP_DEBUG0 0x1303 ++#define RTL8367C_SEL33_EXT2_OFFSET 10 ++#define RTL8367C_SEL33_EXT2_MASK 0x400 ++#define RTL8367C_SEL33_EXT1_OFFSET 9 ++#define RTL8367C_SEL33_EXT1_MASK 0x200 ++#define RTL8367C_SEL33_EXT0_OFFSET 8 ++#define RTL8367C_SEL33_EXT0_MASK 0x100 ++#define RTL8367C_DRI_OTHER_OFFSET 7 ++#define RTL8367C_DRI_OTHER_MASK 0x80 ++#define RTL8367C_DRI_EXT1_RG_OFFSET 6 ++#define RTL8367C_DRI_EXT1_RG_MASK 0x40 ++#define RTL8367C_DRI_EXT0_RG_OFFSET 5 ++#define RTL8367C_DRI_EXT0_RG_MASK 0x20 ++#define RTL8367C_DRI_EXT1_OFFSET 4 ++#define RTL8367C_DRI_EXT1_MASK 0x10 ++#define RTL8367C_DRI_EXT0_OFFSET 3 ++#define RTL8367C_DRI_EXT0_MASK 0x8 ++#define RTL8367C_SLR_OTHER_OFFSET 2 ++#define RTL8367C_SLR_OTHER_MASK 0x4 ++#define RTL8367C_SLR_EXT1_OFFSET 1 ++#define RTL8367C_SLR_EXT1_MASK 0x2 ++#define RTL8367C_SLR_EXT0_OFFSET 0 ++#define RTL8367C_SLR_EXT0_MASK 0x1 ++ ++#define RTL8367C_REG_CHIP_DEBUG1 0x1304 ++#define RTL8367C_RG1_DN_OFFSET 12 ++#define RTL8367C_RG1_DN_MASK 0x7000 ++#define RTL8367C_RG1_DP_OFFSET 8 ++#define RTL8367C_RG1_DP_MASK 0x700 ++#define RTL8367C_RG0_DN_OFFSET 4 ++#define RTL8367C_RG0_DN_MASK 0x70 ++#define RTL8367C_RG0_DP_OFFSET 0 ++#define RTL8367C_RG0_DP_MASK 0x7 ++ ++#define RTL8367C_REG_DIGITAL_INTERFACE_SELECT 0x1305 ++#define RTL8367C_ORG_COL_OFFSET 15 ++#define RTL8367C_ORG_COL_MASK 0x8000 ++#define RTL8367C_ORG_CRS_OFFSET 14 ++#define RTL8367C_ORG_CRS_MASK 0x4000 ++#define RTL8367C_SKIP_MII_1_RXER_OFFSET 13 ++#define RTL8367C_SKIP_MII_1_RXER_MASK 0x2000 ++#define RTL8367C_SKIP_MII_0_RXER_OFFSET 12 ++#define RTL8367C_SKIP_MII_0_RXER_MASK 0x1000 ++#define RTL8367C_SELECT_GMII_1_OFFSET 4 ++#define RTL8367C_SELECT_GMII_1_MASK 0xF0 ++#define RTL8367C_SELECT_GMII_0_OFFSET 0 ++#define RTL8367C_SELECT_GMII_0_MASK 0xF ++ ++#define RTL8367C_REG_EXT0_RGMXF 0x1306 ++#define RTL8367C_EXT0_RGTX_INV_OFFSET 6 ++#define RTL8367C_EXT0_RGTX_INV_MASK 0x40 ++#define RTL8367C_EXT0_RGRX_INV_OFFSET 5 ++#define RTL8367C_EXT0_RGRX_INV_MASK 0x20 ++#define RTL8367C_EXT0_RGMXF_OFFSET 0 ++#define RTL8367C_EXT0_RGMXF_MASK 0x1F ++ ++#define RTL8367C_REG_EXT1_RGMXF 0x1307 ++#define RTL8367C_EXT1_RGTX_INV_OFFSET 6 ++#define RTL8367C_EXT1_RGTX_INV_MASK 0x40 ++#define RTL8367C_EXT1_RGRX_INV_OFFSET 5 ++#define RTL8367C_EXT1_RGRX_INV_MASK 0x20 ++#define RTL8367C_EXT1_RGMXF_OFFSET 0 ++#define RTL8367C_EXT1_RGMXF_MASK 0x1F ++ ++#define RTL8367C_REG_BISR_CTRL 0x1308 ++#define RTL8367C_BISR_CTRL_OFFSET 0 ++#define RTL8367C_BISR_CTRL_MASK 0x7 ++ ++#define RTL8367C_REG_SLF_IF 0x1309 ++#define RTL8367C_LINK_DOWN_CLR_FIFO_OFFSET 7 ++#define RTL8367C_LINK_DOWN_CLR_FIFO_MASK 0x80 ++#define RTL8367C_LOOPBACK_OFFSET 6 ++#define RTL8367C_LOOPBACK_MASK 0x40 ++#define RTL8367C_WATER_LEVEL_OFFSET 4 ++#define RTL8367C_WATER_LEVEL_MASK 0x30 ++#define RTL8367C_SLF_IF_OFFSET 0 ++#define RTL8367C_SLF_IF_MASK 0x3 ++ ++#define RTL8367C_REG_I2C_CLOCK_DIV 0x130a ++#define RTL8367C_I2C_CLOCK_DIV_OFFSET 0 ++#define RTL8367C_I2C_CLOCK_DIV_MASK 0x3FF ++ ++#define RTL8367C_REG_MDX_MDC_DIV 0x130b ++#define RTL8367C_MDX_MDC_DIV_OFFSET 0 ++#define RTL8367C_MDX_MDC_DIV_MASK 0x3FF ++ ++#define RTL8367C_REG_MISCELLANEOUS_CONFIGURE0 0x130c ++#define RTL8367C_ADCCKI_FROM_PAD_OFFSET 14 ++#define RTL8367C_ADCCKI_FROM_PAD_MASK 0x4000 ++#define RTL8367C_ADCCKI_EN_OFFSET 13 ++#define RTL8367C_ADCCKI_EN_MASK 0x2000 ++#define RTL8367C_FLASH_ENABLE_OFFSET 12 ++#define RTL8367C_FLASH_ENABLE_MASK 0x1000 ++#define RTL8367C_EEE_ENABLE_OFFSET 11 ++#define RTL8367C_EEE_ENABLE_MASK 0x800 ++#define RTL8367C_NIC_ENABLE_OFFSET 10 ++#define RTL8367C_NIC_ENABLE_MASK 0x400 ++#define RTL8367C_FT_ENABLE_OFFSET 9 ++#define RTL8367C_FT_ENABLE_MASK 0x200 ++#define RTL8367C_OLT_ENABLE_OFFSET 8 ++#define RTL8367C_OLT_ENABLE_MASK 0x100 ++#define RTL8367C_RTCT_EN_OFFSET 7 ++#define RTL8367C_RTCT_EN_MASK 0x80 ++#define RTL8367C_PON_LIGHT_EN_OFFSET 6 ++#define RTL8367C_PON_LIGHT_EN_MASK 0x40 ++#define RTL8367C_DW8051_EN_OFFSET 5 ++#define RTL8367C_DW8051_EN_MASK 0x20 ++#define RTL8367C_AUTOLOAD_EN_OFFSET 4 ++#define RTL8367C_AUTOLOAD_EN_MASK 0x10 ++#define RTL8367C_NRESTORE_EN_OFFSET 3 ++#define RTL8367C_NRESTORE_EN_MASK 0x8 ++#define RTL8367C_DIS_PON_TABLE_INIT_OFFSET 2 ++#define RTL8367C_DIS_PON_TABLE_INIT_MASK 0x4 ++#define RTL8367C_DIS_PON_BIST_OFFSET 1 ++#define RTL8367C_DIS_PON_BIST_MASK 0x2 ++#define RTL8367C_EFUSE_EN_OFFSET 0 ++#define RTL8367C_EFUSE_EN_MASK 0x1 ++ ++#define RTL8367C_REG_MISCELLANEOUS_CONFIGURE1 0x130d ++#define RTL8367C_EEPROM_DEV_ADR_OFFSET 8 ++#define RTL8367C_EEPROM_DEV_ADR_MASK 0x7F00 ++#define RTL8367C_EEPROM_MSB_OFFSET 7 ++#define RTL8367C_EEPROM_MSB_MASK 0x80 ++#define RTL8367C_EEPROM_ADDRESS_16B_OFFSET 6 ++#define RTL8367C_EEPROM_ADDRESS_16B_MASK 0x40 ++#define RTL8367C_EEPROM_DWONLOAD_COMPLETE_OFFSET 3 ++#define RTL8367C_EEPROM_DWONLOAD_COMPLETE_MASK 0x8 ++#define RTL8367C_SPI_SLAVE_EN_OFFSET 2 ++#define RTL8367C_SPI_SLAVE_EN_MASK 0x4 ++#define RTL8367C_SMI_SEL_OFFSET 0 ++#define RTL8367C_SMI_SEL_MASK 0x3 ++ ++#define RTL8367C_REG_PHY_AD 0x130f ++#define RTL8367C_EN_PHY_MAX_POWER_OFFSET 14 ++#define RTL8367C_EN_PHY_MAX_POWER_MASK 0x4000 ++#define RTL8367C_EN_PHY_SEL_DEG_OFFSET 13 ++#define RTL8367C_EN_PHY_SEL_DEG_MASK 0x2000 ++#define RTL8367C_EXTPHY_AD_OFFSET 8 ++#define RTL8367C_EXTPHY_AD_MASK 0x1F00 ++#define RTL8367C_EN_PHY_LOW_POWER_MODE_OFFSET 7 ++#define RTL8367C_EN_PHY_LOW_POWER_MODE_MASK 0x80 ++#define RTL8367C_EN_PHY_GREEN_OFFSET 6 ++#define RTL8367C_EN_PHY_GREEN_MASK 0x40 ++#define RTL8367C_PDNPHY_OFFSET 5 ++#define RTL8367C_PDNPHY_MASK 0x20 ++#define RTL8367C_INTPHY_AD_OFFSET 0 ++#define RTL8367C_INTPHY_AD_MASK 0x1F ++ ++#define RTL8367C_REG_DIGITAL_INTERFACE0_FORCE 0x1310 ++#define RTL8367C_GMII_0_FORCE_OFFSET 12 ++#define RTL8367C_GMII_0_FORCE_MASK 0x1000 ++#define RTL8367C_RGMII_0_FORCE_OFFSET 0 ++#define RTL8367C_RGMII_0_FORCE_MASK 0xFFF ++ ++#define RTL8367C_REG_DIGITAL_INTERFACE1_FORCE 0x1311 ++#define RTL8367C_GMII_1_FORCE_OFFSET 12 ++#define RTL8367C_GMII_1_FORCE_MASK 0x1000 ++#define RTL8367C_RGMII_1_FORCE_OFFSET 0 ++#define RTL8367C_RGMII_1_FORCE_MASK 0xFFF ++ ++#define RTL8367C_REG_MAC0_FORCE_SELECT 0x1312 ++#define RTL8367C_EN_MAC0_FORCE_OFFSET 12 ++#define RTL8367C_EN_MAC0_FORCE_MASK 0x1000 ++#define RTL8367C_MAC0_FORCE_ABLTY_OFFSET 0 ++#define RTL8367C_MAC0_FORCE_ABLTY_MASK 0xFFF ++ ++#define RTL8367C_REG_MAC1_FORCE_SELECT 0x1313 ++#define RTL8367C_EN_MAC1_FORCE_OFFSET 12 ++#define RTL8367C_EN_MAC1_FORCE_MASK 0x1000 ++#define RTL8367C_MAC1_FORCE_ABLTY_OFFSET 0 ++#define RTL8367C_MAC1_FORCE_ABLTY_MASK 0xFFF ++ ++#define RTL8367C_REG_MAC2_FORCE_SELECT 0x1314 ++#define RTL8367C_EN_MAC2_FORCE_OFFSET 12 ++#define RTL8367C_EN_MAC2_FORCE_MASK 0x1000 ++#define RTL8367C_MAC2_FORCE_ABLTY_OFFSET 0 ++#define RTL8367C_MAC2_FORCE_ABLTY_MASK 0xFFF ++ ++#define RTL8367C_REG_MAC3_FORCE_SELECT 0x1315 ++#define RTL8367C_EN_MAC3_FORCE_OFFSET 12 ++#define RTL8367C_EN_MAC3_FORCE_MASK 0x1000 ++#define RTL8367C_MAC3_FORCE_ABLTY_OFFSET 0 ++#define RTL8367C_MAC3_FORCE_ABLTY_MASK 0xFFF ++ ++#define RTL8367C_REG_MAC4_FORCE_SELECT 0x1316 ++#define RTL8367C_EN_MAC4_FORCE_OFFSET 12 ++#define RTL8367C_EN_MAC4_FORCE_MASK 0x1000 ++#define RTL8367C_MAC4_FORCE_ABLTY_OFFSET 0 ++#define RTL8367C_MAC4_FORCE_ABLTY_MASK 0xFFF ++ ++#define RTL8367C_REG_MAC5_FORCE_SELECT 0x1317 ++#define RTL8367C_EN_MAC5_FORCE_OFFSET 12 ++#define RTL8367C_EN_MAC5_FORCE_MASK 0x1000 ++#define RTL8367C_MAC5_FORCE_ABLTY_OFFSET 0 ++#define RTL8367C_MAC5_FORCE_ABLTY_MASK 0xFFF ++ ++#define RTL8367C_REG_MAC6_FORCE_SELECT 0x1318 ++#define RTL8367C_EN_MAC6_FORCE_OFFSET 12 ++#define RTL8367C_EN_MAC6_FORCE_MASK 0x1000 ++#define RTL8367C_MAC6_FORCE_ABLTY_OFFSET 0 ++#define RTL8367C_MAC6_FORCE_ABLTY_MASK 0xFFF ++ ++#define RTL8367C_REG_MAC7_FORCE_SELECT 0x1319 ++#define RTL8367C_EN_MAC7_FORCE_OFFSET 12 ++#define RTL8367C_EN_MAC7_FORCE_MASK 0x1000 ++#define RTL8367C_MAC7_FORCE_ABLTY_OFFSET 0 ++#define RTL8367C_MAC7_FORCE_ABLTY_MASK 0xFFF ++ ++#define RTL8367C_REG_M10_FORCE_SELECT 0x131c ++#define RTL8367C_EN_M10_FORCE_OFFSET 12 ++#define RTL8367C_EN_M10_FORCE_MASK 0x1000 ++#define RTL8367C_M10_FORCE_ABLTY_OFFSET 0 ++#define RTL8367C_M10_FORCE_ABLTY_MASK 0xFFF ++ ++#define RTL8367C_REG_CHIP_RESET 0x1322 ++#define RTL8367C_GPHY_RESET_OFFSET 6 ++#define RTL8367C_GPHY_RESET_MASK 0x40 ++#define RTL8367C_NIC_RST_OFFSET 5 ++#define RTL8367C_NIC_RST_MASK 0x20 ++#define RTL8367C_DW8051_RST_OFFSET 4 ++#define RTL8367C_DW8051_RST_MASK 0x10 ++#define RTL8367C_SDS_RST_OFFSET 3 ++#define RTL8367C_SDS_RST_MASK 0x8 ++#define RTL8367C_CONFIG_RST_OFFSET 2 ++#define RTL8367C_CONFIG_RST_MASK 0x4 ++#define RTL8367C_SW_RST_OFFSET 1 ++#define RTL8367C_SW_RST_MASK 0x2 ++#define RTL8367C_CHIP_RST_OFFSET 0 ++#define RTL8367C_CHIP_RST_MASK 0x1 ++ ++#define RTL8367C_REG_DIGITAL_DEBUG_0 0x1323 ++ ++#define RTL8367C_REG_DIGITAL_DEBUG_1 0x1324 ++ ++#define RTL8367C_REG_INTERNAL_PHY_MDC_DRIVER 0x1325 ++#define RTL8367C_INTERNAL_PHY_MDC_DRIVER_OFFSET 0 ++#define RTL8367C_INTERNAL_PHY_MDC_DRIVER_MASK 0x3FF ++ ++#define RTL8367C_REG_LINKDOWN_TIME_CTRL 0x1326 ++#define RTL8367C_LINKDOWN_TIME_CFG_OFFSET 9 ++#define RTL8367C_LINKDOWN_TIME_CFG_MASK 0x7E00 ++#define RTL8367C_LINKDOWN_TIME_ENABLE_OFFSET 8 ++#define RTL8367C_LINKDOWN_TIME_ENABLE_MASK 0x100 ++#define RTL8367C_LINKDOWN_TIME_OFFSET 0 ++#define RTL8367C_LINKDOWN_TIME_MASK 0xFF ++ ++#define RTL8367C_REG_PHYACK_TIMEOUT 0x1331 ++ ++#define RTL8367C_REG_MDXACK_TIMEOUT 0x1333 ++ ++#define RTL8367C_REG_DW8051_RDY 0x1336 ++#define RTL8367C_VIAROM_WRITE_EN_OFFSET 9 ++#define RTL8367C_VIAROM_WRITE_EN_MASK 0x200 ++#define RTL8367C_SPIF_CK2_OFFSET 8 ++#define RTL8367C_SPIF_CK2_MASK 0x100 ++#define RTL8367C_RRCP_MDOE_OFFSET 7 ++#define RTL8367C_RRCP_MDOE_MASK 0x80 ++#define RTL8367C_DW8051_RATE_OFFSET 4 ++#define RTL8367C_DW8051_RATE_MASK 0x70 ++#define RTL8367C_IROM_MSB_OFFSET 2 ++#define RTL8367C_IROM_MSB_MASK 0xC ++#define RTL8367C_ACS_IROM_ENABLE_OFFSET 1 ++#define RTL8367C_ACS_IROM_ENABLE_MASK 0x2 ++#define RTL8367C_DW8051_READY_OFFSET 0 ++#define RTL8367C_DW8051_READY_MASK 0x1 ++ ++#define RTL8367C_REG_BIST_CTRL 0x133c ++#define RTL8367C_DRF_BIST_DONE_ALL_OFFSET 5 ++#define RTL8367C_DRF_BIST_DONE_ALL_MASK 0x20 ++#define RTL8367C_DRF_BIST_PAUSE_ALL_OFFSET 4 ++#define RTL8367C_DRF_BIST_PAUSE_ALL_MASK 0x10 ++#define RTL8367C_BIST_DOAN_ALL_OFFSET 3 ++#define RTL8367C_BIST_DOAN_ALL_MASK 0x8 ++#define RTL8367C_BIST_PASS_OFFSET 0 ++#define RTL8367C_BIST_PASS_MASK 0x7 ++ ++#define RTL8367C_REG_DIAG_MODE2 0x133d ++#define RTL8367C_DIAG_MODE2_ACTRAM_OFFSET 1 ++#define RTL8367C_DIAG_MODE2_ACTRAM_MASK 0x2 ++#define RTL8367C_DIAG_MODE2_BCAM_ACTION_OFFSET 0 ++#define RTL8367C_DIAG_MODE2_BCAM_ACTION_MASK 0x1 ++ ++#define RTL8367C_REG_MDX_PHY_REG0 0x133e ++#define RTL8367C_PHY_BRD_MASK_OFFSET 4 ++#define RTL8367C_PHY_BRD_MASK_MASK 0x1F0 ++#define RTL8367C_MDX_INDACC_PAGE_OFFSET 0 ++#define RTL8367C_MDX_INDACC_PAGE_MASK 0xF ++ ++#define RTL8367C_REG_MDX_PHY_REG1 0x133f ++#define RTL8367C_PHY_BRD_MODE_OFFSET 5 ++#define RTL8367C_PHY_BRD_MODE_MASK 0x20 ++#define RTL8367C_BRD_PHYAD_OFFSET 0 ++#define RTL8367C_BRD_PHYAD_MASK 0x1F ++ ++#define RTL8367C_REG_DEBUG_SIGNAL_SELECT_SW 0x1340 ++ ++#define RTL8367C_REG_DEBUG_SIGNAL_SELECT_B 0x1341 ++#define RTL8367C_DEBUG_MX_OFFSET 9 ++#define RTL8367C_DEBUG_MX_MASK 0xE00 ++#define RTL8367C_DEBUG_SHIFT_MISC_OFFSET 6 ++#define RTL8367C_DEBUG_SHIFT_MISC_MASK 0x1C0 ++#define RTL8367C_DEBUG_SHIFT_SW_OFFSET 3 ++#define RTL8367C_DEBUG_SHIFT_SW_MASK 0x38 ++#define RTL8367C_DEBUG_SHIFT_GPHY_OFFSET 0 ++#define RTL8367C_DEBUG_SHIFT_GPHY_MASK 0x7 ++ ++#define RTL8367C_REG_DEBUG_SIGNAL_I 0x1343 ++ ++#define RTL8367C_REG_DEBUG_SIGNAL_H 0x1344 ++ ++#define RTL8367C_REG_DBGO_SEL_GPHY 0x1345 ++ ++#define RTL8367C_REG_DBGO_SEL_MISC 0x1346 ++ ++#define RTL8367C_REG_BYPASS_ABLTY_LOCK 0x1349 ++#define RTL8367C_BYPASS_ABLTY_LOCK_OFFSET 0 ++#define RTL8367C_BYPASS_ABLTY_LOCK_MASK 0xFF ++ ++#define RTL8367C_REG_BYPASS_ABLTY_LOCK_EXT 0x134a ++#define RTL8367C_BYPASS_P10_ABILIITY_LOCK_OFFSET 3 ++#define RTL8367C_BYPASS_P10_ABILIITY_LOCK_MASK 0x8 ++#define RTL8367C_BYPASS_EXT_ABILITY_LOCK_OFFSET 0 ++#define RTL8367C_BYPASS_EXT_ABILITY_LOCK_MASK 0x7 ++ ++#define RTL8367C_REG_ACL_GPIO 0x134f ++#define RTL8367C_ACL_GPIO_13_OFFSET 13 ++#define RTL8367C_ACL_GPIO_13_MASK 0x2000 ++#define RTL8367C_ACL_GPIO_12_OFFSET 12 ++#define RTL8367C_ACL_GPIO_12_MASK 0x1000 ++#define RTL8367C_ACL_GPIO_11_OFFSET 11 ++#define RTL8367C_ACL_GPIO_11_MASK 0x800 ++#define RTL8367C_ACL_GPIO_10_OFFSET 10 ++#define RTL8367C_ACL_GPIO_10_MASK 0x400 ++#define RTL8367C_ACL_GPIO_9_OFFSET 9 ++#define RTL8367C_ACL_GPIO_9_MASK 0x200 ++#define RTL8367C_ACL_GPIO_8_OFFSET 8 ++#define RTL8367C_ACL_GPIO_8_MASK 0x100 ++#define RTL8367C_ACL_GPIO_7_OFFSET 7 ++#define RTL8367C_ACL_GPIO_7_MASK 0x80 ++#define RTL8367C_ACL_GPIO_6_OFFSET 6 ++#define RTL8367C_ACL_GPIO_6_MASK 0x40 ++#define RTL8367C_ACL_GPIO_5_OFFSET 5 ++#define RTL8367C_ACL_GPIO_5_MASK 0x20 ++#define RTL8367C_ACL_GPIO_4_OFFSET 4 ++#define RTL8367C_ACL_GPIO_4_MASK 0x10 ++#define RTL8367C_ACL_GPIO_3_OFFSET 3 ++#define RTL8367C_ACL_GPIO_3_MASK 0x8 ++#define RTL8367C_ACL_GPIO_2_OFFSET 2 ++#define RTL8367C_ACL_GPIO_2_MASK 0x4 ++#define RTL8367C_ACL_GPIO_1_OFFSET 1 ++#define RTL8367C_ACL_GPIO_1_MASK 0x2 ++#define RTL8367C_ACL_GPIO_0_OFFSET 0 ++#define RTL8367C_ACL_GPIO_0_MASK 0x1 ++ ++#define RTL8367C_REG_EN_GPIO 0x1350 ++#define RTL8367C_EN_GPIO_13_OFFSET 13 ++#define RTL8367C_EN_GPIO_13_MASK 0x2000 ++#define RTL8367C_EN_GPIO_12_OFFSET 12 ++#define RTL8367C_EN_GPIO_12_MASK 0x1000 ++#define RTL8367C_EN_GPIO_11_OFFSET 11 ++#define RTL8367C_EN_GPIO_11_MASK 0x800 ++#define RTL8367C_EN_GPIO_10_OFFSET 10 ++#define RTL8367C_EN_GPIO_10_MASK 0x400 ++#define RTL8367C_EN_GPIO_9_OFFSET 9 ++#define RTL8367C_EN_GPIO_9_MASK 0x200 ++#define RTL8367C_EN_GPIO_8_OFFSET 8 ++#define RTL8367C_EN_GPIO_8_MASK 0x100 ++#define RTL8367C_EN_GPIO_7_OFFSET 7 ++#define RTL8367C_EN_GPIO_7_MASK 0x80 ++#define RTL8367C_EN_GPIO_6_OFFSET 6 ++#define RTL8367C_EN_GPIO_6_MASK 0x40 ++#define RTL8367C_EN_GPIO_5_OFFSET 5 ++#define RTL8367C_EN_GPIO_5_MASK 0x20 ++#define RTL8367C_EN_GPIO_4_OFFSET 4 ++#define RTL8367C_EN_GPIO_4_MASK 0x10 ++#define RTL8367C_EN_GPIO_3_OFFSET 3 ++#define RTL8367C_EN_GPIO_3_MASK 0x8 ++#define RTL8367C_EN_GPIO_2_OFFSET 2 ++#define RTL8367C_EN_GPIO_2_MASK 0x4 ++#define RTL8367C_EN_GPIO_1_OFFSET 1 ++#define RTL8367C_EN_GPIO_1_MASK 0x2 ++#define RTL8367C_EN_GPIO_0_OFFSET 0 ++#define RTL8367C_EN_GPIO_0_MASK 0x1 ++ ++#define RTL8367C_REG_CFG_MULTI_PIN 0x1351 ++#define RTL8367C_CFG_MULTI_PIN_OFFSET 0 ++#define RTL8367C_CFG_MULTI_PIN_MASK 0x3 ++ ++#define RTL8367C_REG_PORT0_STATUS 0x1352 ++#define RTL8367C_PORT0_STATUS_EN_1000_LPI_OFFSET 11 ++#define RTL8367C_PORT0_STATUS_EN_1000_LPI_MASK 0x800 ++#define RTL8367C_PORT0_STATUS_EN_100_LPI_OFFSET 10 ++#define RTL8367C_PORT0_STATUS_EN_100_LPI_MASK 0x400 ++#define RTL8367C_PORT0_STATUS_NWAY_FAULT_OFFSET 9 ++#define RTL8367C_PORT0_STATUS_NWAY_FAULT_MASK 0x200 ++#define RTL8367C_PORT0_STATUS_LINK_ON_MASTER_OFFSET 8 ++#define RTL8367C_PORT0_STATUS_LINK_ON_MASTER_MASK 0x100 ++#define RTL8367C_PORT0_STATUS_NWAY_CAP_OFFSET 7 ++#define RTL8367C_PORT0_STATUS_NWAY_CAP_MASK 0x80 ++#define RTL8367C_PORT0_STATUS_TX_FLOWCTRL_CAP_OFFSET 6 ++#define RTL8367C_PORT0_STATUS_TX_FLOWCTRL_CAP_MASK 0x40 ++#define RTL8367C_PORT0_STATUS_RX_FLOWCTRL_CAP_OFFSET 5 ++#define RTL8367C_PORT0_STATUS_RX_FLOWCTRL_CAP_MASK 0x20 ++#define RTL8367C_PORT0_STATUS_LINK_STATE_OFFSET 4 ++#define RTL8367C_PORT0_STATUS_LINK_STATE_MASK 0x10 ++#define RTL8367C_PORT0_STATUS_FULL_DUPLUX_CAP_OFFSET 2 ++#define RTL8367C_PORT0_STATUS_FULL_DUPLUX_CAP_MASK 0x4 ++#define RTL8367C_PORT0_STATUS_LINK_SPEED_OFFSET 0 ++#define RTL8367C_PORT0_STATUS_LINK_SPEED_MASK 0x3 ++ ++#define RTL8367C_REG_PORT1_STATUS 0x1353 ++#define RTL8367C_PORT1_STATUS_EN_1000_LPI_OFFSET 11 ++#define RTL8367C_PORT1_STATUS_EN_1000_LPI_MASK 0x800 ++#define RTL8367C_PORT1_STATUS_EN_100_LPI_OFFSET 10 ++#define RTL8367C_PORT1_STATUS_EN_100_LPI_MASK 0x400 ++#define RTL8367C_PORT1_STATUS_NWAY_FAULT_OFFSET 9 ++#define RTL8367C_PORT1_STATUS_NWAY_FAULT_MASK 0x200 ++#define RTL8367C_PORT1_STATUS_LINK_ON_MASTER_OFFSET 8 ++#define RTL8367C_PORT1_STATUS_LINK_ON_MASTER_MASK 0x100 ++#define RTL8367C_PORT1_STATUS_NWAY_CAP_OFFSET 7 ++#define RTL8367C_PORT1_STATUS_NWAY_CAP_MASK 0x80 ++#define RTL8367C_PORT1_STATUS_TX_FLOWCTRL_CAP_OFFSET 6 ++#define RTL8367C_PORT1_STATUS_TX_FLOWCTRL_CAP_MASK 0x40 ++#define RTL8367C_PORT1_STATUS_RX_FLOWCTRL_CAP_OFFSET 5 ++#define RTL8367C_PORT1_STATUS_RX_FLOWCTRL_CAP_MASK 0x20 ++#define RTL8367C_PORT1_STATUS_LINK_STATE_OFFSET 4 ++#define RTL8367C_PORT1_STATUS_LINK_STATE_MASK 0x10 ++#define RTL8367C_PORT1_STATUS_FULL_DUPLUX_CAP_OFFSET 2 ++#define RTL8367C_PORT1_STATUS_FULL_DUPLUX_CAP_MASK 0x4 ++#define RTL8367C_PORT1_STATUS_LINK_SPEED_OFFSET 0 ++#define RTL8367C_PORT1_STATUS_LINK_SPEED_MASK 0x3 ++ ++#define RTL8367C_REG_PORT2_STATUS 0x1354 ++#define RTL8367C_PORT2_STATUS_EN_1000_LPI_OFFSET 11 ++#define RTL8367C_PORT2_STATUS_EN_1000_LPI_MASK 0x800 ++#define RTL8367C_PORT2_STATUS_EN_100_LPI_OFFSET 10 ++#define RTL8367C_PORT2_STATUS_EN_100_LPI_MASK 0x400 ++#define RTL8367C_PORT2_STATUS_NWAY_FAULT_OFFSET 9 ++#define RTL8367C_PORT2_STATUS_NWAY_FAULT_MASK 0x200 ++#define RTL8367C_PORT2_STATUS_LINK_ON_MASTER_OFFSET 8 ++#define RTL8367C_PORT2_STATUS_LINK_ON_MASTER_MASK 0x100 ++#define RTL8367C_PORT2_STATUS_NWAY_CAP_OFFSET 7 ++#define RTL8367C_PORT2_STATUS_NWAY_CAP_MASK 0x80 ++#define RTL8367C_PORT2_STATUS_TX_FLOWCTRL_CAP_OFFSET 6 ++#define RTL8367C_PORT2_STATUS_TX_FLOWCTRL_CAP_MASK 0x40 ++#define RTL8367C_PORT2_STATUS_RX_FLOWCTRL_CAP_OFFSET 5 ++#define RTL8367C_PORT2_STATUS_RX_FLOWCTRL_CAP_MASK 0x20 ++#define RTL8367C_PORT2_STATUS_LINK_STATE_OFFSET 4 ++#define RTL8367C_PORT2_STATUS_LINK_STATE_MASK 0x10 ++#define RTL8367C_PORT2_STATUS_FULL_DUPLUX_CAP_OFFSET 2 ++#define RTL8367C_PORT2_STATUS_FULL_DUPLUX_CAP_MASK 0x4 ++#define RTL8367C_PORT2_STATUS_LINK_SPEED_OFFSET 0 ++#define RTL8367C_PORT2_STATUS_LINK_SPEED_MASK 0x3 ++ ++#define RTL8367C_REG_PORT3_STATUS 0x1355 ++#define RTL8367C_PORT3_STATUS_EN_1000_LPI_OFFSET 11 ++#define RTL8367C_PORT3_STATUS_EN_1000_LPI_MASK 0x800 ++#define RTL8367C_PORT3_STATUS_EN_100_LPI_OFFSET 10 ++#define RTL8367C_PORT3_STATUS_EN_100_LPI_MASK 0x400 ++#define RTL8367C_PORT3_STATUS_NWAY_FAULT_OFFSET 9 ++#define RTL8367C_PORT3_STATUS_NWAY_FAULT_MASK 0x200 ++#define RTL8367C_PORT3_STATUS_LINK_ON_MASTER_OFFSET 8 ++#define RTL8367C_PORT3_STATUS_LINK_ON_MASTER_MASK 0x100 ++#define RTL8367C_PORT3_STATUS_NWAY_CAP_OFFSET 7 ++#define RTL8367C_PORT3_STATUS_NWAY_CAP_MASK 0x80 ++#define RTL8367C_PORT3_STATUS_TX_FLOWCTRL_CAP_OFFSET 6 ++#define RTL8367C_PORT3_STATUS_TX_FLOWCTRL_CAP_MASK 0x40 ++#define RTL8367C_PORT3_STATUS_RX_FLOWCTRL_CAP_OFFSET 5 ++#define RTL8367C_PORT3_STATUS_RX_FLOWCTRL_CAP_MASK 0x20 ++#define RTL8367C_PORT3_STATUS_LINK_STATE_OFFSET 4 ++#define RTL8367C_PORT3_STATUS_LINK_STATE_MASK 0x10 ++#define RTL8367C_PORT3_STATUS_FULL_DUPLUX_CAP_OFFSET 2 ++#define RTL8367C_PORT3_STATUS_FULL_DUPLUX_CAP_MASK 0x4 ++#define RTL8367C_PORT3_STATUS_LINK_SPEED_OFFSET 0 ++#define RTL8367C_PORT3_STATUS_LINK_SPEED_MASK 0x3 ++ ++#define RTL8367C_REG_PORT4_STATUS 0x1356 ++#define RTL8367C_PORT4_STATUS_EN_1000_LPI_OFFSET 11 ++#define RTL8367C_PORT4_STATUS_EN_1000_LPI_MASK 0x800 ++#define RTL8367C_PORT4_STATUS_EN_100_LPI_OFFSET 10 ++#define RTL8367C_PORT4_STATUS_EN_100_LPI_MASK 0x400 ++#define RTL8367C_PORT4_STATUS_NWAY_FAULT_OFFSET 9 ++#define RTL8367C_PORT4_STATUS_NWAY_FAULT_MASK 0x200 ++#define RTL8367C_PORT4_STATUS_LINK_ON_MASTER_OFFSET 8 ++#define RTL8367C_PORT4_STATUS_LINK_ON_MASTER_MASK 0x100 ++#define RTL8367C_PORT4_STATUS_NWAY_CAP_OFFSET 7 ++#define RTL8367C_PORT4_STATUS_NWAY_CAP_MASK 0x80 ++#define RTL8367C_PORT4_STATUS_TX_FLOWCTRL_CAP_OFFSET 6 ++#define RTL8367C_PORT4_STATUS_TX_FLOWCTRL_CAP_MASK 0x40 ++#define RTL8367C_PORT4_STATUS_RX_FLOWCTRL_CAP_OFFSET 5 ++#define RTL8367C_PORT4_STATUS_RX_FLOWCTRL_CAP_MASK 0x20 ++#define RTL8367C_PORT4_STATUS_LINK_STATE_OFFSET 4 ++#define RTL8367C_PORT4_STATUS_LINK_STATE_MASK 0x10 ++#define RTL8367C_PORT4_STATUS_FULL_DUPLUX_CAP_OFFSET 2 ++#define RTL8367C_PORT4_STATUS_FULL_DUPLUX_CAP_MASK 0x4 ++#define RTL8367C_PORT4_STATUS_LINK_SPEED_OFFSET 0 ++#define RTL8367C_PORT4_STATUS_LINK_SPEED_MASK 0x3 ++ ++#define RTL8367C_REG_PORT5_STATUS 0x1357 ++#define RTL8367C_PORT5_STATUS_EN_1000_LPI_OFFSET 11 ++#define RTL8367C_PORT5_STATUS_EN_1000_LPI_MASK 0x800 ++#define RTL8367C_PORT5_STATUS_EN_100_LPI_OFFSET 10 ++#define RTL8367C_PORT5_STATUS_EN_100_LPI_MASK 0x400 ++#define RTL8367C_PORT5_STATUS_NWAY_FAULT_OFFSET 9 ++#define RTL8367C_PORT5_STATUS_NWAY_FAULT_MASK 0x200 ++#define RTL8367C_PORT5_STATUS_LINK_ON_MASTER_OFFSET 8 ++#define RTL8367C_PORT5_STATUS_LINK_ON_MASTER_MASK 0x100 ++#define RTL8367C_PORT5_STATUS_NWAY_CAP_OFFSET 7 ++#define RTL8367C_PORT5_STATUS_NWAY_CAP_MASK 0x80 ++#define RTL8367C_PORT5_STATUS_TX_FLOWCTRL_CAP_OFFSET 6 ++#define RTL8367C_PORT5_STATUS_TX_FLOWCTRL_CAP_MASK 0x40 ++#define RTL8367C_PORT5_STATUS_RX_FLOWCTRL_CAP_OFFSET 5 ++#define RTL8367C_PORT5_STATUS_RX_FLOWCTRL_CAP_MASK 0x20 ++#define RTL8367C_PORT5_STATUS_LINK_STATE_OFFSET 4 ++#define RTL8367C_PORT5_STATUS_LINK_STATE_MASK 0x10 ++#define RTL8367C_PORT5_STATUS_FULL_DUPLUX_CAP_OFFSET 2 ++#define RTL8367C_PORT5_STATUS_FULL_DUPLUX_CAP_MASK 0x4 ++#define RTL8367C_PORT5_STATUS_LINK_SPEED_OFFSET 0 ++#define RTL8367C_PORT5_STATUS_LINK_SPEED_MASK 0x3 ++ ++#define RTL8367C_REG_PORT6_STATUS 0x1358 ++#define RTL8367C_PORT6_STATUS_EN_1000_LPI_OFFSET 11 ++#define RTL8367C_PORT6_STATUS_EN_1000_LPI_MASK 0x800 ++#define RTL8367C_PORT6_STATUS_EN_100_LPI_OFFSET 10 ++#define RTL8367C_PORT6_STATUS_EN_100_LPI_MASK 0x400 ++#define RTL8367C_PORT6_STATUS_NWAY_FAULT_OFFSET 9 ++#define RTL8367C_PORT6_STATUS_NWAY_FAULT_MASK 0x200 ++#define RTL8367C_PORT6_STATUS_LINK_ON_MASTER_OFFSET 8 ++#define RTL8367C_PORT6_STATUS_LINK_ON_MASTER_MASK 0x100 ++#define RTL8367C_PORT6_STATUS_NWAY_CAP_OFFSET 7 ++#define RTL8367C_PORT6_STATUS_NWAY_CAP_MASK 0x80 ++#define RTL8367C_PORT6_STATUS_TX_FLOWCTRL_CAP_OFFSET 6 ++#define RTL8367C_PORT6_STATUS_TX_FLOWCTRL_CAP_MASK 0x40 ++#define RTL8367C_PORT6_STATUS_RX_FLOWCTRL_CAP_OFFSET 5 ++#define RTL8367C_PORT6_STATUS_RX_FLOWCTRL_CAP_MASK 0x20 ++#define RTL8367C_PORT6_STATUS_LINK_STATE_OFFSET 4 ++#define RTL8367C_PORT6_STATUS_LINK_STATE_MASK 0x10 ++#define RTL8367C_PORT6_STATUS_FULL_DUPLUX_CAP_OFFSET 2 ++#define RTL8367C_PORT6_STATUS_FULL_DUPLUX_CAP_MASK 0x4 ++#define RTL8367C_PORT6_STATUS_LINK_SPEED_OFFSET 0 ++#define RTL8367C_PORT6_STATUS_LINK_SPEED_MASK 0x3 ++ ++#define RTL8367C_REG_PORT7_STATUS 0x1359 ++#define RTL8367C_PORT7_STATUS_EN_1000_LPI_OFFSET 11 ++#define RTL8367C_PORT7_STATUS_EN_1000_LPI_MASK 0x800 ++#define RTL8367C_PORT7_STATUS_EN_100_LPI_OFFSET 10 ++#define RTL8367C_PORT7_STATUS_EN_100_LPI_MASK 0x400 ++#define RTL8367C_PORT7_STATUS_NWAY_FAULT_OFFSET 9 ++#define RTL8367C_PORT7_STATUS_NWAY_FAULT_MASK 0x200 ++#define RTL8367C_PORT7_STATUS_LINK_ON_MASTER_OFFSET 8 ++#define RTL8367C_PORT7_STATUS_LINK_ON_MASTER_MASK 0x100 ++#define RTL8367C_PORT7_STATUS_NWAY_CAP_OFFSET 7 ++#define RTL8367C_PORT7_STATUS_NWAY_CAP_MASK 0x80 ++#define RTL8367C_PORT7_STATUS_TX_FLOWCTRL_CAP_OFFSET 6 ++#define RTL8367C_PORT7_STATUS_TX_FLOWCTRL_CAP_MASK 0x40 ++#define RTL8367C_PORT7_STATUS_RX_FLOWCTRL_CAP_OFFSET 5 ++#define RTL8367C_PORT7_STATUS_RX_FLOWCTRL_CAP_MASK 0x20 ++#define RTL8367C_PORT7_STATUS_LINK_STATE_OFFSET 4 ++#define RTL8367C_PORT7_STATUS_LINK_STATE_MASK 0x10 ++#define RTL8367C_PORT7_STATUS_FULL_DUPLUX_CAP_OFFSET 2 ++#define RTL8367C_PORT7_STATUS_FULL_DUPLUX_CAP_MASK 0x4 ++#define RTL8367C_PORT7_STATUS_LINK_SPEED_OFFSET 0 ++#define RTL8367C_PORT7_STATUS_LINK_SPEED_MASK 0x3 ++ ++#define RTL8367C_REG_PORT8_STATUS 0x135a ++#define RTL8367C_PORT8_STATUS_EN_1000_LPI_OFFSET 11 ++#define RTL8367C_PORT8_STATUS_EN_1000_LPI_MASK 0x800 ++#define RTL8367C_PORT8_STATUS_EN_100_LPI_OFFSET 10 ++#define RTL8367C_PORT8_STATUS_EN_100_LPI_MASK 0x400 ++#define RTL8367C_PORT8_STATUS_NWAY_FAULT_OFFSET 9 ++#define RTL8367C_PORT8_STATUS_NWAY_FAULT_MASK 0x200 ++#define RTL8367C_PORT8_STATUS_LINK_ON_MASTER_OFFSET 8 ++#define RTL8367C_PORT8_STATUS_LINK_ON_MASTER_MASK 0x100 ++#define RTL8367C_PORT8_STATUS_NWAY_CAP_OFFSET 7 ++#define RTL8367C_PORT8_STATUS_NWAY_CAP_MASK 0x80 ++#define RTL8367C_PORT8_STATUS_TX_FLOWCTRL_CAP_OFFSET 6 ++#define RTL8367C_PORT8_STATUS_TX_FLOWCTRL_CAP_MASK 0x40 ++#define RTL8367C_PORT8_STATUS_RX_FLOWCTRL_CAP_OFFSET 5 ++#define RTL8367C_PORT8_STATUS_RX_FLOWCTRL_CAP_MASK 0x20 ++#define RTL8367C_PORT8_STATUS_LINK_STATE_OFFSET 4 ++#define RTL8367C_PORT8_STATUS_LINK_STATE_MASK 0x10 ++#define RTL8367C_PORT8_STATUS_FULL_DUPLUX_CAP_OFFSET 2 ++#define RTL8367C_PORT8_STATUS_FULL_DUPLUX_CAP_MASK 0x4 ++#define RTL8367C_PORT8_STATUS_LINK_SPEED_OFFSET 0 ++#define RTL8367C_PORT8_STATUS_LINK_SPEED_MASK 0x3 ++ ++#define RTL8367C_REG_PORT9_STATUS 0x135b ++#define RTL8367C_PORT9_STATUS_EN_1000_LPI_OFFSET 11 ++#define RTL8367C_PORT9_STATUS_EN_1000_LPI_MASK 0x800 ++#define RTL8367C_PORT9_STATUS_EN_100_LPI_OFFSET 10 ++#define RTL8367C_PORT9_STATUS_EN_100_LPI_MASK 0x400 ++#define RTL8367C_PORT9_STATUS_NWAY_FAULT_OFFSET 9 ++#define RTL8367C_PORT9_STATUS_NWAY_FAULT_MASK 0x200 ++#define RTL8367C_PORT9_STATUS_LINK_ON_MASTER_OFFSET 8 ++#define RTL8367C_PORT9_STATUS_LINK_ON_MASTER_MASK 0x100 ++#define RTL8367C_PORT9_STATUS_NWAY_CAP_OFFSET 7 ++#define RTL8367C_PORT9_STATUS_NWAY_CAP_MASK 0x80 ++#define RTL8367C_PORT9_STATUS_TX_FLOWCTRL_CAP_OFFSET 6 ++#define RTL8367C_PORT9_STATUS_TX_FLOWCTRL_CAP_MASK 0x40 ++#define RTL8367C_PORT9_STATUS_RX_FLOWCTRL_CAP_OFFSET 5 ++#define RTL8367C_PORT9_STATUS_RX_FLOWCTRL_CAP_MASK 0x20 ++#define RTL8367C_PORT9_STATUS_LINK_STATE_OFFSET 4 ++#define RTL8367C_PORT9_STATUS_LINK_STATE_MASK 0x10 ++#define RTL8367C_PORT9_STATUS_FULL_DUPLUX_CAP_OFFSET 2 ++#define RTL8367C_PORT9_STATUS_FULL_DUPLUX_CAP_MASK 0x4 ++#define RTL8367C_PORT9_STATUS_LINK_SPEED_OFFSET 0 ++#define RTL8367C_PORT9_STATUS_LINK_SPEED_MASK 0x3 ++ ++#define RTL8367C_REG_PORT10_STATUS 0x135c ++#define RTL8367C_PORT10_STATUS_EN_1000_LPI_OFFSET 11 ++#define RTL8367C_PORT10_STATUS_EN_1000_LPI_MASK 0x800 ++#define RTL8367C_PORT10_STATUS_EN_100_LPI_OFFSET 10 ++#define RTL8367C_PORT10_STATUS_EN_100_LPI_MASK 0x400 ++#define RTL8367C_PORT10_STATUS_NWAY_FAULT_OFFSET 9 ++#define RTL8367C_PORT10_STATUS_NWAY_FAULT_MASK 0x200 ++#define RTL8367C_PORT10_STATUS_LINK_ON_MASTER_OFFSET 8 ++#define RTL8367C_PORT10_STATUS_LINK_ON_MASTER_MASK 0x100 ++#define RTL8367C_PORT10_STATUS_NWAY_CAP_OFFSET 7 ++#define RTL8367C_PORT10_STATUS_NWAY_CAP_MASK 0x80 ++#define RTL8367C_PORT10_STATUS_TX_FLOWCTRL_CAP_OFFSET 6 ++#define RTL8367C_PORT10_STATUS_TX_FLOWCTRL_CAP_MASK 0x40 ++#define RTL8367C_PORT10_STATUS_RX_FLOWCTRL_CAP_OFFSET 5 ++#define RTL8367C_PORT10_STATUS_RX_FLOWCTRL_CAP_MASK 0x20 ++#define RTL8367C_PORT10_STATUS_LINK_STATE_OFFSET 4 ++#define RTL8367C_PORT10_STATUS_LINK_STATE_MASK 0x10 ++#define RTL8367C_PORT10_STATUS_FULL_DUPLUX_CAP_OFFSET 2 ++#define RTL8367C_PORT10_STATUS_FULL_DUPLUX_CAP_MASK 0x4 ++#define RTL8367C_PORT10_STATUS_LINK_SPEED_OFFSET 0 ++#define RTL8367C_PORT10_STATUS_LINK_SPEED_MASK 0x3 ++ ++#define RTL8367C_REG_UPS_CTRL0 0x1362 ++#define RTL8367C_P3_REF_SD_BIT0_OFFSET 8 ++#define RTL8367C_P3_REF_SD_BIT0_MASK 0xFF00 ++#define RTL8367C_P2_REF_SD_OFFSET 0 ++#define RTL8367C_P2_REF_SD_MASK 0xFF ++ ++#define RTL8367C_REG_UPS_CTRL1 0x1363 ++#define RTL8367C_UPS_OUT_OFFSET 8 ++#define RTL8367C_UPS_OUT_MASK 0xFF00 ++#define RTL8367C_UPS_WRITE_PULSE_OFFSET 1 ++#define RTL8367C_UPS_WRITE_PULSE_MASK 0x2 ++#define RTL8367C_UPS_EN_OFFSET 0 ++#define RTL8367C_UPS_EN_MASK 0x1 ++ ++#define RTL8367C_REG_UPS_CTRL2 0x1364 ++#define RTL8367C_IGNOE_MAC8_LINK_OFFSET 15 ++#define RTL8367C_IGNOE_MAC8_LINK_MASK 0x8000 ++#define RTL8367C_AGREE_SLEEP_OFFSET 14 ++#define RTL8367C_AGREE_SLEEP_MASK 0x4000 ++#define RTL8367C_WAIT_FOR_AGREEMENT_OFFSET 13 ++#define RTL8367C_WAIT_FOR_AGREEMENT_MASK 0x2000 ++#define RTL8367C_WAKE_UP_BY_LINK_OFFSET 12 ++#define RTL8367C_WAKE_UP_BY_LINK_MASK 0x1000 ++#define RTL8367C_WAKE_UP_BY_PHY_OFFSET 11 ++#define RTL8367C_WAKE_UP_BY_PHY_MASK 0x800 ++#define RTL8367C_SLOW_CLK_TGL_RATE_OFFSET 7 ++#define RTL8367C_SLOW_CLK_TGL_RATE_MASK 0x780 ++#define RTL8367C_PLL_G1_CTRL_EN_OFFSET 6 ++#define RTL8367C_PLL_G1_CTRL_EN_MASK 0x40 ++#define RTL8367C_PLL_G0_CTRL_EN_OFFSET 5 ++#define RTL8367C_PLL_G0_CTRL_EN_MASK 0x20 ++#define RTL8367C_SLOW_DOWN_PLL_EN_OFFSET 4 ++#define RTL8367C_SLOW_DOWN_PLL_EN_MASK 0x10 ++#define RTL8367C_SLOW_DOWN_CLK_EN_OFFSET 3 ++#define RTL8367C_SLOW_DOWN_CLK_EN_MASK 0x8 ++#define RTL8367C_GATING_CLK_SDS_EN_OFFSET 2 ++#define RTL8367C_GATING_CLK_SDS_EN_MASK 0x4 ++#define RTL8367C_GATING_CLK_CHIP_EN_OFFSET 1 ++#define RTL8367C_GATING_CLK_CHIP_EN_MASK 0x2 ++#define RTL8367C_GATING_SW_EN_OFFSET 0 ++#define RTL8367C_GATING_SW_EN_MASK 0x1 ++ ++#define RTL8367C_REG_GATING_CLK_1 0x1365 ++#define RTL8367C_ALDPS_MODE_4_OFFSET 15 ++#define RTL8367C_ALDPS_MODE_4_MASK 0x8000 ++#define RTL8367C_ALDPS_MODE_3_OFFSET 14 ++#define RTL8367C_ALDPS_MODE_3_MASK 0x4000 ++#define RTL8367C_ALDPS_MODE_2_OFFSET 13 ++#define RTL8367C_ALDPS_MODE_2_MASK 0x2000 ++#define RTL8367C_ALDPS_MODE_1_OFFSET 12 ++#define RTL8367C_ALDPS_MODE_1_MASK 0x1000 ++#define RTL8367C_ALDPS_MODE_0_OFFSET 11 ++#define RTL8367C_ALDPS_MODE_0_MASK 0x800 ++#define RTL8367C_UPS_DBGO_OFFSET 10 ++#define RTL8367C_UPS_DBGO_MASK 0x400 ++#define RTL8367C_IFMX_AFF_NOT_FF_OUT_OFFSET 9 ++#define RTL8367C_IFMX_AFF_NOT_FF_OUT_MASK 0x200 ++#define RTL8367C_WATER_LEVEL_FD_OFFSET 6 ++#define RTL8367C_WATER_LEVEL_FD_MASK 0x1C0 ++#define RTL8367C_WATER_LEVEL_Y2X_OFFSET 3 ++#define RTL8367C_WATER_LEVEL_Y2X_MASK 0x38 ++#define RTL8367C_WATER_LEVEL_X2Y_2_OFFSET 2 ++#define RTL8367C_WATER_LEVEL_X2Y_2_MASK 0x4 ++#define RTL8367C_IGNOE_MAC10_LINK_OFFSET 1 ++#define RTL8367C_IGNOE_MAC10_LINK_MASK 0x2 ++#define RTL8367C_IGNOE_MAC9_LINK_OFFSET 0 ++#define RTL8367C_IGNOE_MAC9_LINK_MASK 0x1 ++ ++#define RTL8367C_REG_UPS_CTRL4 0x1366 ++#define RTL8367C_PROB_EN_OFFSET 6 ++#define RTL8367C_PROB_EN_MASK 0x40 ++#define RTL8367C_PLL_DOWN_OFFSET 1 ++#define RTL8367C_PLL_DOWN_MASK 0x2 ++#define RTL8367C_XTAL_DOWN_OFFSET 0 ++#define RTL8367C_XTAL_DOWN_MASK 0x1 ++ ++#define RTL8367C_REG_UPS_CTRL5 0x1367 ++#define RTL8367C_FRC_CPU_ACPT_OFFSET 3 ++#define RTL8367C_FRC_CPU_ACPT_MASK 0x8 ++#define RTL8367C_UPS_CPU_ACPT_OFFSET 2 ++#define RTL8367C_UPS_CPU_ACPT_MASK 0x4 ++#define RTL8367C_UPS_DBG_4_OFFSET 0 ++#define RTL8367C_UPS_DBG_4_MASK 0x3 ++ ++#define RTL8367C_REG_UPS_CTRL6 0x1368 ++#define RTL8367C_UPS_CTRL6_OFFSET 0 ++#define RTL8367C_UPS_CTRL6_MASK 0xF ++ ++#define RTL8367C_REG_EFUSE_CMD_70B 0x1369 ++ ++#define RTL8367C_REG_EFUSE_CMD 0x1370 ++#define RTL8367C_EFUSE_TIME_OUT_FLAG_OFFSET 3 ++#define RTL8367C_EFUSE_TIME_OUT_FLAG_MASK 0x8 ++#define RTL8367C_EFUSE_ACCESS_BUSY_OFFSET 2 ++#define RTL8367C_EFUSE_ACCESS_BUSY_MASK 0x4 ++#define RTL8367C_EFUSE_COMMAND_EN_OFFSET 1 ++#define RTL8367C_EFUSE_COMMAND_EN_MASK 0x2 ++#define RTL8367C_EFUSE_WR_OFFSET 0 ++#define RTL8367C_EFUSE_WR_MASK 0x1 ++ ++#define RTL8367C_REG_EFUSE_ADR 0x1371 ++#define RTL8367C_DUMMY_15_10_OFFSET 8 ++#define RTL8367C_DUMMY_15_10_MASK 0xFF00 ++#define RTL8367C_EFUSE_ADDRESS_OFFSET 0 ++#define RTL8367C_EFUSE_ADDRESS_MASK 0xFF ++ ++#define RTL8367C_REG_EFUSE_WDAT 0x1372 ++ ++#define RTL8367C_REG_EFUSE_RDAT 0x1373 ++ ++#define RTL8367C_REG_I2C_CTRL 0x1374 ++#define RTL8367C_MDX_MST_FAIL_LAT_OFFSET 1 ++#define RTL8367C_MDX_MST_FAIL_LAT_MASK 0x2 ++#define RTL8367C_MDX_MST_FAIL_CLRPS_OFFSET 0 ++#define RTL8367C_MDX_MST_FAIL_CLRPS_MASK 0x1 ++ ++#define RTL8367C_REG_EEE_CFG 0x1375 ++#define RTL8367C_CFG_BYPASS_GATELPTD_OFFSET 11 ++#define RTL8367C_CFG_BYPASS_GATELPTD_MASK 0x800 ++#define RTL8367C_EEE_ABT_ADDR2_OFFSET 6 ++#define RTL8367C_EEE_ABT_ADDR2_MASK 0x7C0 ++#define RTL8367C_EEE_ABT_ADDR1_OFFSET 1 ++#define RTL8367C_EEE_ABT_ADDR1_MASK 0x3E ++#define RTL8367C_EEE_POLL_EN_OFFSET 0 ++#define RTL8367C_EEE_POLL_EN_MASK 0x1 ++ ++#define RTL8367C_REG_EEE_PAGE 0x1376 ++ ++#define RTL8367C_REG_EEE_EXT_PAGE 0x1377 ++ ++#define RTL8367C_REG_EEE_EN_SPD1000 0x1378 ++ ++#define RTL8367C_REG_EEE_EN_SPD100 0x1379 ++ ++#define RTL8367C_REG_EEE_LP_SPD1000 0x137a ++ ++#define RTL8367C_REG_EEE_LP_SPD100 0x137b ++ ++#define RTL8367C_REG_DW8051_PRO_REG0 0x13a0 ++ ++#define RTL8367C_REG_DW8051_PRO_REG1 0x13a1 ++ ++#define RTL8367C_REG_DW8051_PRO_REG2 0x13a2 ++ ++#define RTL8367C_REG_DW8051_PRO_REG3 0x13a3 ++ ++#define RTL8367C_REG_DW8051_PRO_REG4 0x13a4 ++ ++#define RTL8367C_REG_DW8051_PRO_REG5 0x13a5 ++ ++#define RTL8367C_REG_DW8051_PRO_REG6 0x13a6 ++ ++#define RTL8367C_REG_DW8051_PRO_REG7 0x13a7 ++ ++#define RTL8367C_REG_PROTECT_ID 0x13c0 ++ ++#define RTL8367C_REG_CHIP_VER_INTL 0x13c1 ++#define RTL8367C_CHIP_VER_INTL_OFFSET 0 ++#define RTL8367C_CHIP_VER_INTL_MASK 0xF ++ ++#define RTL8367C_REG_MAGIC_ID 0x13c2 ++ ++#define RTL8367C_REG_DIGITAL_INTERFACE_SELECT_1 0x13c3 ++#define RTL8367C_SKIP_MII_2_RXER_OFFSET 4 ++#define RTL8367C_SKIP_MII_2_RXER_MASK 0x10 ++#define RTL8367C_SELECT_GMII_2_OFFSET 0 ++#define RTL8367C_SELECT_GMII_2_MASK 0xF ++ ++#define RTL8367C_REG_DIGITAL_INTERFACE2_FORCE 0x13c4 ++#define RTL8367C_GMII_2_FORCE_OFFSET 12 ++#define RTL8367C_GMII_2_FORCE_MASK 0x1000 ++#define RTL8367C_RGMII_2_FORCE_OFFSET 0 ++#define RTL8367C_RGMII_2_FORCE_MASK 0xFFF ++ ++#define RTL8367C_REG_EXT2_RGMXF 0x13c5 ++#define RTL8367C_EXT2_RGTX_INV_OFFSET 6 ++#define RTL8367C_EXT2_RGTX_INV_MASK 0x40 ++#define RTL8367C_EXT2_RGRX_INV_OFFSET 5 ++#define RTL8367C_EXT2_RGRX_INV_MASK 0x20 ++#define RTL8367C_EXT2_RGMXF_OFFSET 0 ++#define RTL8367C_EXT2_RGMXF_MASK 0x1F ++ ++#define RTL8367C_REG_ROUTER_UPS_CFG 0x13c6 ++#define RTL8367C_UPS_Status_OFFSET 1 ++#define RTL8367C_UPS_Status_MASK 0x2 ++#define RTL8367C_SoftStart_OFFSET 0 ++#define RTL8367C_SoftStart_MASK 0x1 ++ ++#define RTL8367C_REG_CTRL_GPIO 0x13c7 ++#define RTL8367C_CTRL_GPIO_13_OFFSET 13 ++#define RTL8367C_CTRL_GPIO_13_MASK 0x2000 ++#define RTL8367C_CTRL_GPIO_12_OFFSET 12 ++#define RTL8367C_CTRL_GPIO_12_MASK 0x1000 ++#define RTL8367C_CTRL_GPIO_11_OFFSET 11 ++#define RTL8367C_CTRL_GPIO_11_MASK 0x800 ++#define RTL8367C_CTRL_GPIO_10_OFFSET 10 ++#define RTL8367C_CTRL_GPIO_10_MASK 0x400 ++#define RTL8367C_CTRL_GPIO_9_OFFSET 9 ++#define RTL8367C_CTRL_GPIO_9_MASK 0x200 ++#define RTL8367C_CTRL_GPIO_8_OFFSET 8 ++#define RTL8367C_CTRL_GPIO_8_MASK 0x100 ++#define RTL8367C_CTRL_GPIO_7_OFFSET 7 ++#define RTL8367C_CTRL_GPIO_7_MASK 0x80 ++#define RTL8367C_CTRL_GPIO_6_OFFSET 6 ++#define RTL8367C_CTRL_GPIO_6_MASK 0x40 ++#define RTL8367C_CTRL_GPIO_5_OFFSET 5 ++#define RTL8367C_CTRL_GPIO_5_MASK 0x20 ++#define RTL8367C_CTRL_GPIO_4_OFFSET 4 ++#define RTL8367C_CTRL_GPIO_4_MASK 0x10 ++#define RTL8367C_CTRL_GPIO_3_OFFSET 3 ++#define RTL8367C_CTRL_GPIO_3_MASK 0x8 ++#define RTL8367C_CTRL_GPIO_2_OFFSET 2 ++#define RTL8367C_CTRL_GPIO_2_MASK 0x4 ++#define RTL8367C_CTRL_GPIO_1_OFFSET 1 ++#define RTL8367C_CTRL_GPIO_1_MASK 0x2 ++#define RTL8367C_CTRL_GPIO_0_OFFSET 0 ++#define RTL8367C_CTRL_GPIO_0_MASK 0x1 ++ ++#define RTL8367C_REG_SEL_GPIO 0x13c8 ++#define RTL8367C_SEL_GPIO_13_OFFSET 13 ++#define RTL8367C_SEL_GPIO_13_MASK 0x2000 ++#define RTL8367C_SEL_GPIO_12_OFFSET 12 ++#define RTL8367C_SEL_GPIO_12_MASK 0x1000 ++#define RTL8367C_SEL_GPIO_11_OFFSET 11 ++#define RTL8367C_SEL_GPIO_11_MASK 0x800 ++#define RTL8367C_SEL_GPIO_10_OFFSET 10 ++#define RTL8367C_SEL_GPIO_10_MASK 0x400 ++#define RTL8367C_SEL_GPIO_9_OFFSET 9 ++#define RTL8367C_SEL_GPIO_9_MASK 0x200 ++#define RTL8367C_SEL_GPIO_8_OFFSET 8 ++#define RTL8367C_SEL_GPIO_8_MASK 0x100 ++#define RTL8367C_SEL_GPIO_7_OFFSET 7 ++#define RTL8367C_SEL_GPIO_7_MASK 0x80 ++#define RTL8367C_SEL_GPIO_6_OFFSET 6 ++#define RTL8367C_SEL_GPIO_6_MASK 0x40 ++#define RTL8367C_SEL_GPIO_5_OFFSET 5 ++#define RTL8367C_SEL_GPIO_5_MASK 0x20 ++#define RTL8367C_SEL_GPIO_4_OFFSET 4 ++#define RTL8367C_SEL_GPIO_4_MASK 0x10 ++#define RTL8367C_SEL_GPIO_3_OFFSET 3 ++#define RTL8367C_SEL_GPIO_3_MASK 0x8 ++#define RTL8367C_SEL_GPIO_2_OFFSET 2 ++#define RTL8367C_SEL_GPIO_2_MASK 0x4 ++#define RTL8367C_SEL_GPIO_1_OFFSET 1 ++#define RTL8367C_SEL_GPIO_1_MASK 0x2 ++#define RTL8367C_SEL_GPIO_0_OFFSET 0 ++#define RTL8367C_SEL_GPIO_0_MASK 0x1 ++ ++#define RTL8367C_REG_STATUS_GPIO 0x13c9 ++#define RTL8367C_STATUS_GPIO_OFFSET 0 ++#define RTL8367C_STATUS_GPIO_MASK 0x3FFF ++ ++#define RTL8367C_REG_SYNC_ETH_CFG 0x13e0 ++#define RTL8367C_DUMMY2_OFFSET 9 ++#define RTL8367C_DUMMY2_MASK 0xFE00 ++#define RTL8367C_RFC2819_TYPE_OFFSET 8 ++#define RTL8367C_RFC2819_TYPE_MASK 0x100 ++#define RTL8367C_DUMMY1_OFFSET 7 ++#define RTL8367C_DUMMY1_MASK 0x80 ++#define RTL8367C_FIBER_SYNCE125_L_SEL_OFFSET 6 ++#define RTL8367C_FIBER_SYNCE125_L_SEL_MASK 0x40 ++#define RTL8367C_SYNC_ETH_EN_RTT2_OFFSET 5 ++#define RTL8367C_SYNC_ETH_EN_RTT2_MASK 0x20 ++#define RTL8367C_SYNC_ETH_EN_RTT1_OFFSET 4 ++#define RTL8367C_SYNC_ETH_EN_RTT1_MASK 0x10 ++#define RTL8367C_SYNC_ETH_SEL_DPLL_OFFSET 3 ++#define RTL8367C_SYNC_ETH_SEL_DPLL_MASK 0x8 ++#define RTL8367C_SYNC_ETH_SEL_PHYREF_OFFSET 2 ++#define RTL8367C_SYNC_ETH_SEL_PHYREF_MASK 0x4 ++#define RTL8367C_SYNC_ETH_SEL_XTAL_OFFSET 1 ++#define RTL8367C_SYNC_ETH_SEL_XTAL_MASK 0x2 ++#define RTL8367C_DUMMY0_OFFSET 0 ++#define RTL8367C_DUMMY0_MASK 0x1 ++ ++#define RTL8367C_REG_LED_DRI_CFG 0x13e1 ++#define RTL8367C_LED_DRI_CFG_DUMMY_OFFSET 1 ++#define RTL8367C_LED_DRI_CFG_DUMMY_MASK 0xFFFE ++#define RTL8367C_LED_DRIVING_OFFSET 0 ++#define RTL8367C_LED_DRIVING_MASK 0x1 ++ ++#define RTL8367C_REG_CHIP_DEBUG2 0x13e2 ++#define RTL8367C_RG2_DN_OFFSET 6 ++#define RTL8367C_RG2_DN_MASK 0x1C0 ++#define RTL8367C_RG2_DP_OFFSET 3 ++#define RTL8367C_RG2_DP_MASK 0x38 ++#define RTL8367C_DRI_EXT2_RG_OFFSET 2 ++#define RTL8367C_DRI_EXT2_RG_MASK 0x4 ++#define RTL8367C_DRI_EXT2_OFFSET 1 ++#define RTL8367C_DRI_EXT2_MASK 0x2 ++#define RTL8367C_SLR_EXT2_OFFSET 0 ++#define RTL8367C_SLR_EXT2_MASK 0x1 ++ ++#define RTL8367C_REG_DIGITAL_DEBUG_2 0x13e3 ++ ++#define RTL8367C_REG_FIBER_RTL_OUI_CFG0 0x13e4 ++#define RTL8367C_FIBER_RTL_OUI_CFG0_OFFSET 0 ++#define RTL8367C_FIBER_RTL_OUI_CFG0_MASK 0xFF ++ ++#define RTL8367C_REG_FIBER_RTL_OUI_CFG1 0x13e5 ++ ++#define RTL8367C_REG_FIBER_CFG_0 0x13e6 ++#define RTL8367C_REV_NUM_OFFSET 8 ++#define RTL8367C_REV_NUM_MASK 0xF00 ++#define RTL8367C_MODEL_NUM_OFFSET 0 ++#define RTL8367C_MODEL_NUM_MASK 0x3F ++ ++#define RTL8367C_REG_FIBER_CFG_1 0x13e7 ++#define RTL8367C_SDS_FRC_REG4_OFFSET 12 ++#define RTL8367C_SDS_FRC_REG4_MASK 0x1000 ++#define RTL8367C_SDS_FRC_REG4_FIB100_OFFSET 11 ++#define RTL8367C_SDS_FRC_REG4_FIB100_MASK 0x800 ++#define RTL8367C_SEL_MASK_ONL_OFFSET 5 ++#define RTL8367C_SEL_MASK_ONL_MASK 0x20 ++#define RTL8367C_DIS_QUALITY_IN_MASK_OFFSET 4 ++#define RTL8367C_DIS_QUALITY_IN_MASK_MASK 0x10 ++#define RTL8367C_SDS_FRC_MODE_OFFSET 3 ++#define RTL8367C_SDS_FRC_MODE_MASK 0x8 ++#define RTL8367C_SDS_MODE_OFFSET 0 ++#define RTL8367C_SDS_MODE_MASK 0x7 ++ ++#define RTL8367C_REG_FIBER_CFG_2 0x13e8 ++#define RTL8367C_SEL_SDET_PS_OFFSET 12 ++#define RTL8367C_SEL_SDET_PS_MASK 0xF000 ++#define RTL8367C_UTP_DIS_RX_OFFSET 10 ++#define RTL8367C_UTP_DIS_RX_MASK 0xC00 ++#define RTL8367C_UTP_FRC_LD_OFFSET 8 ++#define RTL8367C_UTP_FRC_LD_MASK 0x300 ++#define RTL8367C_SDS_RX_DISABLE_OFFSET 6 ++#define RTL8367C_SDS_RX_DISABLE_MASK 0xC0 ++#define RTL8367C_SDS_TX_DISABLE_OFFSET 4 ++#define RTL8367C_SDS_TX_DISABLE_MASK 0x30 ++#define RTL8367C_FIBER_CFG_2_SDS_PWR_ISO_OFFSET 2 ++#define RTL8367C_FIBER_CFG_2_SDS_PWR_ISO_MASK 0xC ++#define RTL8367C_SDS_FRC_LD_OFFSET 0 ++#define RTL8367C_SDS_FRC_LD_MASK 0x3 ++ ++#define RTL8367C_REG_FIBER_CFG_3 0x13e9 ++#define RTL8367C_FIBER_CFG_3_OFFSET 0 ++#define RTL8367C_FIBER_CFG_3_MASK 0xFFF ++ ++#define RTL8367C_REG_FIBER_CFG_4 0x13ea ++ ++#define RTL8367C_REG_UTP_FIB_DET 0x13eb ++#define RTL8367C_FORCE_SEL_FIBER_OFFSET 14 ++#define RTL8367C_FORCE_SEL_FIBER_MASK 0xC000 ++#define RTL8367C_FIB_FINAL_TIMER_OFFSET 12 ++#define RTL8367C_FIB_FINAL_TIMER_MASK 0x3000 ++#define RTL8367C_FIB_LINK_TIMER_OFFSET 10 ++#define RTL8367C_FIB_LINK_TIMER_MASK 0xC00 ++#define RTL8367C_FIB_SDET_TIMER_OFFSET 8 ++#define RTL8367C_FIB_SDET_TIMER_MASK 0x300 ++#define RTL8367C_UTP_LINK_TIMER_OFFSET 6 ++#define RTL8367C_UTP_LINK_TIMER_MASK 0xC0 ++#define RTL8367C_UTP_SDET_TIMER_OFFSET 4 ++#define RTL8367C_UTP_SDET_TIMER_MASK 0x30 ++#define RTL8367C_FORCE_AUTODET_OFFSET 3 ++#define RTL8367C_FORCE_AUTODET_MASK 0x8 ++#define RTL8367C_AUTODET_FSM_CLR_OFFSET 2 ++#define RTL8367C_AUTODET_FSM_CLR_MASK 0x4 ++#define RTL8367C_UTP_FIRST_OFFSET 1 ++#define RTL8367C_UTP_FIRST_MASK 0x2 ++#define RTL8367C_UTP_FIB_DISAUTODET_OFFSET 0 ++#define RTL8367C_UTP_FIB_DISAUTODET_MASK 0x1 ++ ++#define RTL8367C_REG_NRESTORE_MAGIC_NUM 0x13ec ++#define RTL8367C_NRESTORE_MAGIC_NUM_MASK 0xFFFF ++#define RTL8367C_EEPROM_PROGRAM_CYCLE_OFFSET 0 ++#define RTL8367C_EEPROM_PROGRAM_CYCLE_MASK 0x3 ++ ++#define RTL8367C_REG_MAC_ACTIVE 0x13ee ++#define RTL8367C_MAC_ACTIVE_H_OFFSET 9 ++#define RTL8367C_MAC_ACTIVE_H_MASK 0xE00 ++#define RTL8367C_FORCE_MAC_ACTIVE_OFFSET 8 ++#define RTL8367C_FORCE_MAC_ACTIVE_MASK 0x100 ++#define RTL8367C_MAC_ACTIVE_OFFSET 0 ++#define RTL8367C_MAC_ACTIVE_MASK 0xFF ++ ++#define RTL8367C_REG_SERDES_RESULT 0x13ef ++#define RTL8367C_FIB100_DET_1_OFFSET 12 ++#define RTL8367C_FIB100_DET_1_MASK 0x1000 ++#define RTL8367C_FIB_ISO_1_OFFSET 11 ++#define RTL8367C_FIB_ISO_1_MASK 0x800 ++#define RTL8367C_SDS_ANFAULT_1_OFFSET 10 ++#define RTL8367C_SDS_ANFAULT_1_MASK 0x400 ++#define RTL8367C_SDS_INTB_1_OFFSET 9 ++#define RTL8367C_SDS_INTB_1_MASK 0x200 ++#define RTL8367C_SDS_LINK_OK_1_OFFSET 8 ++#define RTL8367C_SDS_LINK_OK_1_MASK 0x100 ++#define RTL8367C_FIB100_DET_OFFSET 4 ++#define RTL8367C_FIB100_DET_MASK 0x10 ++#define RTL8367C_FIB_ISO_OFFSET 3 ++#define RTL8367C_FIB_ISO_MASK 0x8 ++#define RTL8367C_SDS_ANFAULT_OFFSET 2 ++#define RTL8367C_SDS_ANFAULT_MASK 0x4 ++#define RTL8367C_SDS_INTB_OFFSET 1 ++#define RTL8367C_SDS_INTB_MASK 0x2 ++#define RTL8367C_SDS_LINK_OK_OFFSET 0 ++#define RTL8367C_SDS_LINK_OK_MASK 0x1 ++ ++#define RTL8367C_REG_CHIP_ECO 0x13f0 ++#define RTL8367C_CFG_CHIP_ECO_OFFSET 1 ++#define RTL8367C_CFG_CHIP_ECO_MASK 0xFFFE ++#define RTL8367C_CFG_CKOUTEN_OFFSET 0 ++#define RTL8367C_CFG_CKOUTEN_MASK 0x1 ++ ++#define RTL8367C_REG_WAKELPI_SLOT_PRD 0x13f1 ++#define RTL8367C_WAKELPI_SLOT_PRD_OFFSET 0 ++#define RTL8367C_WAKELPI_SLOT_PRD_MASK 0x1F ++ ++#define RTL8367C_REG_WAKELPI_SLOT_PG0 0x13f2 ++#define RTL8367C_WAKELPI_SLOT_P1_OFFSET 8 ++#define RTL8367C_WAKELPI_SLOT_P1_MASK 0x1F00 ++#define RTL8367C_WAKELPI_SLOT_P0_OFFSET 0 ++#define RTL8367C_WAKELPI_SLOT_P0_MASK 0x1F ++ ++#define RTL8367C_REG_WAKELPI_SLOT_PG1 0x13f3 ++#define RTL8367C_WAKELPI_SLOT_P3_OFFSET 8 ++#define RTL8367C_WAKELPI_SLOT_P3_MASK 0x1F00 ++#define RTL8367C_WAKELPI_SLOT_P2_OFFSET 0 ++#define RTL8367C_WAKELPI_SLOT_P2_MASK 0x1F ++ ++#define RTL8367C_REG_WAKELPI_SLOT_PG2 0x13f4 ++#define RTL8367C_WAKELPI_SLOT_P5_OFFSET 8 ++#define RTL8367C_WAKELPI_SLOT_P5_MASK 0x1F00 ++#define RTL8367C_WAKELPI_SLOT_P4_OFFSET 0 ++#define RTL8367C_WAKELPI_SLOT_P4_MASK 0x1F ++ ++#define RTL8367C_REG_WAKELPI_SLOT_PG3 0x13f5 ++#define RTL8367C_WAKELPI_SLOT_P7_OFFSET 8 ++#define RTL8367C_WAKELPI_SLOT_P7_MASK 0x1F00 ++#define RTL8367C_WAKELPI_SLOT_P6_OFFSET 0 ++#define RTL8367C_WAKELPI_SLOT_P6_MASK 0x1F ++ ++#define RTL8367C_REG_SYNC_FIFO_0 0x13f6 ++#define RTL8367C_SYNC_FIFO_TX_OFFSET 8 ++#define RTL8367C_SYNC_FIFO_TX_MASK 0x700 ++#define RTL8367C_SYNC_FIFO_RX_OFFSET 0 ++#define RTL8367C_SYNC_FIFO_RX_MASK 0xFF ++ ++#define RTL8367C_REG_SYNC_FIFO_1 0x13f7 ++#define RTL8367C_SYNC_FIFO_RX_ERR_P10_8_OFFSET 11 ++#define RTL8367C_SYNC_FIFO_RX_ERR_P10_8_MASK 0x3800 ++#define RTL8367C_SYNC_FIFO_TX_ERR_OFFSET 8 ++#define RTL8367C_SYNC_FIFO_TX_ERR_MASK 0x700 ++#define RTL8367C_SYNC_FIFO_RX_ERR_OFFSET 0 ++#define RTL8367C_SYNC_FIFO_RX_ERR_MASK 0xFF ++ ++#define RTL8367C_REG_RGM_EEE 0x13f8 ++#define RTL8367C_EXT2_PAD_STOP_EN_OFFSET 14 ++#define RTL8367C_EXT2_PAD_STOP_EN_MASK 0x4000 ++#define RTL8367C_EXT1_PAD_STOP_EN_OFFSET 13 ++#define RTL8367C_EXT1_PAD_STOP_EN_MASK 0x2000 ++#define RTL8367C_EXT0_PAD_STOP_EN_OFFSET 12 ++#define RTL8367C_EXT0_PAD_STOP_EN_MASK 0x1000 ++#define RTL8367C_EXT2_CYCLE_PAD_OFFSET 8 ++#define RTL8367C_EXT2_CYCLE_PAD_MASK 0xF00 ++#define RTL8367C_EXT1_CYCLE_PAD_OFFSET 4 ++#define RTL8367C_EXT1_CYCLE_PAD_MASK 0xF0 ++#define RTL8367C_EXT0_CYCLE_PAD_OFFSET 0 ++#define RTL8367C_EXT0_CYCLE_PAD_MASK 0xF ++ ++#define RTL8367C_REG_EXT_TXC_DLY 0x13f9 ++#define RTL8367C_EXT1_GMII_TX_DELAY_OFFSET 12 ++#define RTL8367C_EXT1_GMII_TX_DELAY_MASK 0x7000 ++#define RTL8367C_EXT0_GMII_TX_DELAY_OFFSET 9 ++#define RTL8367C_EXT0_GMII_TX_DELAY_MASK 0xE00 ++#define RTL8367C_EXT2_RGMII_TX_DELAY_OFFSET 6 ++#define RTL8367C_EXT2_RGMII_TX_DELAY_MASK 0x1C0 ++#define RTL8367C_EXT1_RGMII_TX_DELAY_OFFSET 3 ++#define RTL8367C_EXT1_RGMII_TX_DELAY_MASK 0x38 ++#define RTL8367C_EXT0_RGMII_TX_DELAY_OFFSET 0 ++#define RTL8367C_EXT0_RGMII_TX_DELAY_MASK 0x7 ++ ++#define RTL8367C_REG_IO_MISC_CTRL 0x13fa ++#define RTL8367C_IO_BUZZER_EN_OFFSET 3 ++#define RTL8367C_IO_BUZZER_EN_MASK 0x8 ++#define RTL8367C_IO_INTRPT_EN_OFFSET 2 ++#define RTL8367C_IO_INTRPT_EN_MASK 0x4 ++#define RTL8367C_IO_NRESTORE_EN_OFFSET 1 ++#define RTL8367C_IO_NRESTORE_EN_MASK 0x2 ++#define RTL8367C_IO_UART_EN_OFFSET 0 ++#define RTL8367C_IO_UART_EN_MASK 0x1 ++ ++#define RTL8367C_REG_CHIP_DUMMY_NO 0x13fb ++#define RTL8367C_CHIP_DUMMY_NO_OFFSET 0 ++#define RTL8367C_CHIP_DUMMY_NO_MASK 0xF ++ ++#define RTL8367C_REG_RC_CALIB_CFG 0x13fc ++#define RTL8367C_TRIG_BURN_EFUSE_OFFSET 9 ++#define RTL8367C_TRIG_BURN_EFUSE_MASK 0x200 ++#define RTL8367C_AMP_CALIB_FAIL_OFFSET 8 ++#define RTL8367C_AMP_CALIB_FAIL_MASK 0x100 ++#define RTL8367C_R_CALIB_FAIL_OFFSET 7 ++#define RTL8367C_R_CALIB_FAIL_MASK 0x80 ++#define RTL8367C_CFG_CALIB_MODE_OFFSET 6 ++#define RTL8367C_CFG_CALIB_MODE_MASK 0x40 ++#define RTL8367C_CENTER_PORT_SEL_OFFSET 3 ++#define RTL8367C_CENTER_PORT_SEL_MASK 0x38 ++#define RTL8367C_CALIB_FINISH_OFFSET 2 ++#define RTL8367C_CALIB_FINISH_MASK 0x4 ++#define RTL8367C_CFG_CALIB_OPTION_OFFSET 1 ++#define RTL8367C_CFG_CALIB_OPTION_MASK 0x2 ++#define RTL8367C_CFG_CALIB_EN_OFFSET 0 ++#define RTL8367C_CFG_CALIB_EN_MASK 0x1 ++ ++#define RTL8367C_REG_WAKELPI_SLOT_PG4 0x13fd ++#define RTL8367C_WAKELPI_SLOT_P9_OFFSET 8 ++#define RTL8367C_WAKELPI_SLOT_P9_MASK 0x1F00 ++#define RTL8367C_WAKELPI_SLOT_P8_OFFSET 0 ++#define RTL8367C_WAKELPI_SLOT_P8_MASK 0x1F ++ ++#define RTL8367C_REG_WAKELPI_SLOT_PG5 0x13fe ++#define RTL8367C_WAKELPI_SLOT_PG5_OFFSET 0 ++#define RTL8367C_WAKELPI_SLOT_PG5_MASK 0x1F ++ ++/* (16'h1400)mtrpool_reg */ ++ ++#define RTL8367C_REG_METER0_RATE_CTRL0 0x1400 ++ ++#define RTL8367C_REG_METER0_RATE_CTRL1 0x1401 ++#define RTL8367C_METER0_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER0_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER1_RATE_CTRL0 0x1402 ++ ++#define RTL8367C_REG_METER1_RATE_CTRL1 0x1403 ++#define RTL8367C_METER1_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER1_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER2_RATE_CTRL0 0x1404 ++ ++#define RTL8367C_REG_METER2_RATE_CTRL1 0x1405 ++#define RTL8367C_METER2_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER2_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER3_RATE_CTRL0 0x1406 ++ ++#define RTL8367C_REG_METER3_RATE_CTRL1 0x1407 ++#define RTL8367C_METER3_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER3_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER4_RATE_CTRL0 0x1408 ++ ++#define RTL8367C_REG_METER4_RATE_CTRL1 0x1409 ++#define RTL8367C_METER4_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER4_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER5_RATE_CTRL0 0x140a ++ ++#define RTL8367C_REG_METER5_RATE_CTRL1 0x140b ++#define RTL8367C_METER5_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER5_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER6_RATE_CTRL0 0x140c ++ ++#define RTL8367C_REG_METER6_RATE_CTRL1 0x140d ++#define RTL8367C_METER6_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER6_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER7_RATE_CTRL0 0x140e ++ ++#define RTL8367C_REG_METER7_RATE_CTRL1 0x140f ++#define RTL8367C_METER7_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER7_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER8_RATE_CTRL0 0x1410 ++ ++#define RTL8367C_REG_METER8_RATE_CTRL1 0x1411 ++#define RTL8367C_METER8_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER8_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER9_RATE_CTRL0 0x1412 ++ ++#define RTL8367C_REG_METER9_RATE_CTRL1 0x1413 ++#define RTL8367C_METER9_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER9_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER10_RATE_CTRL0 0x1414 ++ ++#define RTL8367C_REG_METER10_RATE_CTRL1 0x1415 ++#define RTL8367C_METER10_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER10_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER11_RATE_CTRL0 0x1416 ++ ++#define RTL8367C_REG_METER11_RATE_CTRL1 0x1417 ++#define RTL8367C_METER11_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER11_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER12_RATE_CTRL0 0x1418 ++ ++#define RTL8367C_REG_METER12_RATE_CTRL1 0x1419 ++#define RTL8367C_METER12_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER12_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER13_RATE_CTRL0 0x141a ++ ++#define RTL8367C_REG_METER13_RATE_CTRL1 0x141b ++#define RTL8367C_METER13_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER13_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER14_RATE_CTRL0 0x141c ++ ++#define RTL8367C_REG_METER14_RATE_CTRL1 0x141d ++#define RTL8367C_METER14_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER14_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER15_RATE_CTRL0 0x141e ++ ++#define RTL8367C_REG_METER15_RATE_CTRL1 0x141f ++#define RTL8367C_METER15_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER15_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER16_RATE_CTRL0 0x1420 ++ ++#define RTL8367C_REG_METER16_RATE_CTRL1 0x1421 ++#define RTL8367C_METER16_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER16_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER17_RATE_CTRL0 0x1422 ++ ++#define RTL8367C_REG_METER17_RATE_CTRL1 0x1423 ++#define RTL8367C_METER17_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER17_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER18_RATE_CTRL0 0x1424 ++ ++#define RTL8367C_REG_METER18_RATE_CTRL1 0x1425 ++#define RTL8367C_METER18_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER18_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER19_RATE_CTRL0 0x1426 ++ ++#define RTL8367C_REG_METER19_RATE_CTRL1 0x1427 ++#define RTL8367C_METER19_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER19_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER20_RATE_CTRL0 0x1428 ++ ++#define RTL8367C_REG_METER20_RATE_CTRL1 0x1429 ++#define RTL8367C_METER20_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER20_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER21_RATE_CTRL0 0x142a ++ ++#define RTL8367C_REG_METER21_RATE_CTRL1 0x142b ++#define RTL8367C_METER21_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER21_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER22_RATE_CTRL0 0x142c ++ ++#define RTL8367C_REG_METER22_RATE_CTRL1 0x142d ++#define RTL8367C_METER22_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER22_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER23_RATE_CTRL0 0x142e ++ ++#define RTL8367C_REG_METER23_RATE_CTRL1 0x142f ++#define RTL8367C_METER23_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER23_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER24_RATE_CTRL0 0x1430 ++ ++#define RTL8367C_REG_METER24_RATE_CTRL1 0x1431 ++#define RTL8367C_METER24_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER24_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER25_RATE_CTRL0 0x1432 ++ ++#define RTL8367C_REG_METER25_RATE_CTRL1 0x1433 ++#define RTL8367C_METER25_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER25_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER26_RATE_CTRL0 0x1434 ++ ++#define RTL8367C_REG_METER26_RATE_CTRL1 0x1435 ++#define RTL8367C_METER26_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER26_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER27_RATE_CTRL0 0x1436 ++ ++#define RTL8367C_REG_METER27_RATE_CTRL1 0x1437 ++#define RTL8367C_METER27_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER27_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER28_RATE_CTRL0 0x1438 ++ ++#define RTL8367C_REG_METER28_RATE_CTRL1 0x1439 ++#define RTL8367C_METER28_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER28_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER29_RATE_CTRL0 0x143a ++ ++#define RTL8367C_REG_METER29_RATE_CTRL1 0x143b ++#define RTL8367C_METER29_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER29_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER30_RATE_CTRL0 0x143c ++ ++#define RTL8367C_REG_METER30_RATE_CTRL1 0x143d ++#define RTL8367C_METER30_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER30_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER31_RATE_CTRL0 0x143e ++ ++#define RTL8367C_REG_METER31_RATE_CTRL1 0x143f ++#define RTL8367C_METER31_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER31_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER_MODE_SETTING0 0x1440 ++ ++#define RTL8367C_REG_METER_MODE_SETTING1 0x1441 ++ ++#define RTL8367C_REG_METER_MODE_TOKEN_CFG 0x1442 ++#define RTL8367C_METER_MODE_TOKEN_CFG_OFFSET 0 ++#define RTL8367C_METER_MODE_TOKEN_CFG_MASK 0x7FF ++ ++#define RTL8367C_REG_METER0_BUCKET_SIZE 0x1600 ++ ++#define RTL8367C_REG_METER1_BUCKET_SIZE 0x1601 ++ ++#define RTL8367C_REG_METER2_BUCKET_SIZE 0x1602 ++ ++#define RTL8367C_REG_METER3_BUCKET_SIZE 0x1603 ++ ++#define RTL8367C_REG_METER4_BUCKET_SIZE 0x1604 ++ ++#define RTL8367C_REG_METER5_BUCKET_SIZE 0x1605 ++ ++#define RTL8367C_REG_METER6_BUCKET_SIZE 0x1606 ++ ++#define RTL8367C_REG_METER7_BUCKET_SIZE 0x1607 ++ ++#define RTL8367C_REG_METER8_BUCKET_SIZE 0x1608 ++ ++#define RTL8367C_REG_METER9_BUCKET_SIZE 0x1609 ++ ++#define RTL8367C_REG_METER10_BUCKET_SIZE 0x160a ++ ++#define RTL8367C_REG_METER11_BUCKET_SIZE 0x160b ++ ++#define RTL8367C_REG_METER12_BUCKET_SIZE 0x160c ++ ++#define RTL8367C_REG_METER13_BUCKET_SIZE 0x160d ++ ++#define RTL8367C_REG_METER14_BUCKET_SIZE 0x160e ++ ++#define RTL8367C_REG_METER15_BUCKET_SIZE 0x160f ++ ++#define RTL8367C_REG_METER16_BUCKET_SIZE 0x1610 ++ ++#define RTL8367C_REG_METER17_BUCKET_SIZE 0x1611 ++ ++#define RTL8367C_REG_METER18_BUCKET_SIZE 0x1612 ++ ++#define RTL8367C_REG_METER19_BUCKET_SIZE 0x1613 ++ ++#define RTL8367C_REG_METER20_BUCKET_SIZE 0x1614 ++ ++#define RTL8367C_REG_METER21_BUCKET_SIZE 0x1615 ++ ++#define RTL8367C_REG_METER22_BUCKET_SIZE 0x1616 ++ ++#define RTL8367C_REG_METER23_BUCKET_SIZE 0x1617 ++ ++#define RTL8367C_REG_METER24_BUCKET_SIZE 0x1618 ++ ++#define RTL8367C_REG_METER25_BUCKET_SIZE 0x1619 ++ ++#define RTL8367C_REG_METER26_BUCKET_SIZE 0x161a ++ ++#define RTL8367C_REG_METER27_BUCKET_SIZE 0x161b ++ ++#define RTL8367C_REG_METER28_BUCKET_SIZE 0x161c ++ ++#define RTL8367C_REG_METER29_BUCKET_SIZE 0x161d ++ ++#define RTL8367C_REG_METER30_BUCKET_SIZE 0x161e ++ ++#define RTL8367C_REG_METER31_BUCKET_SIZE 0x161f ++ ++#define RTL8367C_REG_METER_CTRL0 0x1700 ++#define RTL8367C_METER_OP_OFFSET 8 ++#define RTL8367C_METER_OP_MASK 0x100 ++#define RTL8367C_METER_TICK_OFFSET 0 ++#define RTL8367C_METER_TICK_MASK 0xFF ++ ++#define RTL8367C_REG_METER_CTRL1 0x1701 ++#define RTL8367C_METER_CTRL1_OFFSET 0 ++#define RTL8367C_METER_CTRL1_MASK 0xFF ++ ++#define RTL8367C_REG_METER_OVERRATE_INDICATOR0 0x1702 ++ ++#define RTL8367C_REG_METER_OVERRATE_INDICATOR1 0x1703 ++ ++#define RTL8367C_REG_METER_OVERRATE_INDICATOR0_8051 0x1704 ++ ++#define RTL8367C_REG_METER_OVERRATE_INDICATOR1_8051 0x1705 ++ ++#define RTL8367C_REG_METER_IFG_CTRL0 0x1712 ++#define RTL8367C_METER15_IFG_OFFSET 15 ++#define RTL8367C_METER15_IFG_MASK 0x8000 ++#define RTL8367C_METER14_IFG_OFFSET 14 ++#define RTL8367C_METER14_IFG_MASK 0x4000 ++#define RTL8367C_METER13_IFG_OFFSET 13 ++#define RTL8367C_METER13_IFG_MASK 0x2000 ++#define RTL8367C_METER12_IFG_OFFSET 12 ++#define RTL8367C_METER12_IFG_MASK 0x1000 ++#define RTL8367C_METER11_IFG_OFFSET 11 ++#define RTL8367C_METER11_IFG_MASK 0x800 ++#define RTL8367C_METER10_IFG_OFFSET 10 ++#define RTL8367C_METER10_IFG_MASK 0x400 ++#define RTL8367C_METER9_IFG_OFFSET 9 ++#define RTL8367C_METER9_IFG_MASK 0x200 ++#define RTL8367C_METER8_IFG_OFFSET 8 ++#define RTL8367C_METER8_IFG_MASK 0x100 ++#define RTL8367C_METER7_IFG_OFFSET 7 ++#define RTL8367C_METER7_IFG_MASK 0x80 ++#define RTL8367C_METER6_IFG_OFFSET 6 ++#define RTL8367C_METER6_IFG_MASK 0x40 ++#define RTL8367C_METER5_IFG_OFFSET 5 ++#define RTL8367C_METER5_IFG_MASK 0x20 ++#define RTL8367C_METER4_IFG_OFFSET 4 ++#define RTL8367C_METER4_IFG_MASK 0x10 ++#define RTL8367C_METER3_IFG_OFFSET 3 ++#define RTL8367C_METER3_IFG_MASK 0x8 ++#define RTL8367C_METER2_IFG_OFFSET 2 ++#define RTL8367C_METER2_IFG_MASK 0x4 ++#define RTL8367C_METER1_IFG_OFFSET 1 ++#define RTL8367C_METER1_IFG_MASK 0x2 ++#define RTL8367C_METER0_IFG_OFFSET 0 ++#define RTL8367C_METER0_IFG_MASK 0x1 ++ ++#define RTL8367C_REG_METER_IFG_CTRL1 0x1713 ++#define RTL8367C_METER31_IFG_OFFSET 15 ++#define RTL8367C_METER31_IFG_MASK 0x8000 ++#define RTL8367C_METER30_IFG_OFFSET 14 ++#define RTL8367C_METER30_IFG_MASK 0x4000 ++#define RTL8367C_METER29_IFG_OFFSET 13 ++#define RTL8367C_METER29_IFG_MASK 0x2000 ++#define RTL8367C_METER28_IFG_OFFSET 12 ++#define RTL8367C_METER28_IFG_MASK 0x1000 ++#define RTL8367C_METER27_IFG_OFFSET 11 ++#define RTL8367C_METER27_IFG_MASK 0x800 ++#define RTL8367C_METER26_IFG_OFFSET 10 ++#define RTL8367C_METER26_IFG_MASK 0x400 ++#define RTL8367C_METER25_IFG_OFFSET 9 ++#define RTL8367C_METER25_IFG_MASK 0x200 ++#define RTL8367C_METER24_IFG_OFFSET 8 ++#define RTL8367C_METER24_IFG_MASK 0x100 ++#define RTL8367C_METER23_IFG_OFFSET 7 ++#define RTL8367C_METER23_IFG_MASK 0x80 ++#define RTL8367C_METER22_IFG_OFFSET 6 ++#define RTL8367C_METER22_IFG_MASK 0x40 ++#define RTL8367C_METER21_IFG_OFFSET 5 ++#define RTL8367C_METER21_IFG_MASK 0x20 ++#define RTL8367C_METER20_IFG_OFFSET 4 ++#define RTL8367C_METER20_IFG_MASK 0x10 ++#define RTL8367C_METER19_IFG_OFFSET 3 ++#define RTL8367C_METER19_IFG_MASK 0x8 ++#define RTL8367C_METER18_IFG_OFFSET 2 ++#define RTL8367C_METER18_IFG_MASK 0x4 ++#define RTL8367C_METER17_IFG_OFFSET 1 ++#define RTL8367C_METER17_IFG_MASK 0x2 ++#define RTL8367C_METER16_IFG_OFFSET 0 ++#define RTL8367C_METER16_IFG_MASK 0x1 ++ ++#define RTL8367C_REG_METER_CTRL2 0x1722 ++#define RTL8367C_cfg_mtr_tick_8g_OFFSET 8 ++#define RTL8367C_cfg_mtr_tick_8g_MASK 0xFF00 ++#define RTL8367C_cfg_mtr_dec_cnt_8g_OFFSET 0 ++#define RTL8367C_cfg_mtr_dec_cnt_8g_MASK 0xFF ++ ++#define RTL8367C_REG_DUMMY_1723 0x1723 ++ ++#define RTL8367C_REG_DUMMY_1724 0x1724 ++ ++#define RTL8367C_REG_DUMMY_1725 0x1725 ++ ++#define RTL8367C_REG_DUMMY_1726 0x1726 ++ ++#define RTL8367C_REG_DUMMY_1727 0x1727 ++ ++#define RTL8367C_REG_DUMMY_1728 0x1728 ++ ++#define RTL8367C_REG_DUMMY_1729 0x1729 ++ ++#define RTL8367C_REG_DUMMY_172A 0x172a ++ ++#define RTL8367C_REG_DUMMY_172B 0x172b ++ ++#define RTL8367C_REG_DUMMY_172C 0x172c ++ ++#define RTL8367C_REG_DUMMY_172D 0x172d ++ ++#define RTL8367C_REG_DUMMY_172E 0x172e ++ ++#define RTL8367C_REG_DUMMY_172F 0x172f ++ ++#define RTL8367C_REG_DUMMY_1730 0x1730 ++ ++#define RTL8367C_REG_DUMMY_1731 0x1731 ++ ++#define RTL8367C_REG_METER32_RATE_CTRL0 0x1740 ++ ++#define RTL8367C_REG_METER32_RATE_CTRL1 0x1741 ++#define RTL8367C_METER32_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER32_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER33_RATE_CTRL0 0x1742 ++ ++#define RTL8367C_REG_METER33_RATE_CTRL1 0x1743 ++#define RTL8367C_METER33_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER33_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER34_RATE_CTRL0 0x1744 ++ ++#define RTL8367C_REG_METER34_RATE_CTRL1 0x1745 ++#define RTL8367C_METER34_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER34_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER35_RATE_CTRL0 0x1746 ++ ++#define RTL8367C_REG_METER35_RATE_CTRL1 0x1747 ++#define RTL8367C_METER35_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER35_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER36_RATE_CTRL0 0x1748 ++ ++#define RTL8367C_REG_METER36_RATE_CTRL1 0x1749 ++#define RTL8367C_METER36_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER36_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER37_RATE_CTRL0 0x174a ++ ++#define RTL8367C_REG_METER37_RATE_CTRL1 0x174b ++#define RTL8367C_METER37_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER37_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER38_RATE_CTRL0 0x174c ++ ++#define RTL8367C_REG_METER38_RATE_CTRL1 0x174d ++#define RTL8367C_METER38_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER38_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER39_RATE_CTRL0 0x174e ++ ++#define RTL8367C_REG_METER39_RATE_CTRL1 0x174f ++#define RTL8367C_METER39_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER39_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER40_RATE_CTRL0 0x1750 ++ ++#define RTL8367C_REG_METER40_RATE_CTRL1 0x1751 ++#define RTL8367C_METER40_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER40_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER41_RATE_CTRL0 0x1752 ++ ++#define RTL8367C_REG_METER41_RATE_CTRL1 0x1753 ++#define RTL8367C_METER41_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER41_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER42_RATE_CTRL0 0x1754 ++ ++#define RTL8367C_REG_METER42_RATE_CTRL1 0x1755 ++#define RTL8367C_METER42_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER42_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER43_RATE_CTRL0 0x1756 ++ ++#define RTL8367C_REG_METER43_RATE_CTRL1 0x1757 ++#define RTL8367C_METER43_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER43_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER44_RATE_CTRL0 0x1758 ++ ++#define RTL8367C_REG_METER44_RATE_CTRL1 0x1759 ++#define RTL8367C_METER44_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER44_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER45_RATE_CTRL0 0x175a ++ ++#define RTL8367C_REG_METER45_RATE_CTRL1 0x175b ++#define RTL8367C_METER45_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER45_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER46_RATE_CTRL0 0x175c ++ ++#define RTL8367C_REG_METER46_RATE_CTRL1 0x175d ++#define RTL8367C_METER46_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER46_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER47_RATE_CTRL0 0x175e ++ ++#define RTL8367C_REG_METER47_RATE_CTRL1 0x175f ++#define RTL8367C_METER47_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER47_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER48_RATE_CTRL0 0x1760 ++ ++#define RTL8367C_REG_METER48_RATE_CTRL1 0x1761 ++#define RTL8367C_METER48_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER48_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER49_RATE_CTRL0 0x1762 ++ ++#define RTL8367C_REG_METER49_RATE_CTRL1 0x1763 ++#define RTL8367C_METER49_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER49_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER50_RATE_CTRL0 0x1764 ++ ++#define RTL8367C_REG_METER50_RATE_CTRL1 0x1765 ++#define RTL8367C_METER50_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER50_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER51_RATE_CTRL0 0x1766 ++ ++#define RTL8367C_REG_METER51_RATE_CTRL1 0x1767 ++#define RTL8367C_METER51_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER51_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER52_RATE_CTRL0 0x1768 ++ ++#define RTL8367C_REG_METER52_RATE_CTRL1 0x1769 ++#define RTL8367C_METER52_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER52_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER53_RATE_CTRL0 0x176a ++ ++#define RTL8367C_REG_METER53_RATE_CTRL1 0x176b ++#define RTL8367C_METER53_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER53_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER54_RATE_CTRL0 0x176c ++ ++#define RTL8367C_REG_METER54_RATE_CTRL1 0x176d ++#define RTL8367C_METER54_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER54_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER55_RATE_CTRL0 0x176e ++ ++#define RTL8367C_REG_METER55_RATE_CTRL1 0x176f ++#define RTL8367C_METER55_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER55_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER56_RATE_CTRL0 0x1770 ++ ++#define RTL8367C_REG_METER56_RATE_CTRL1 0x1771 ++#define RTL8367C_METER56_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER56_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER57_RATE_CTRL0 0x1772 ++ ++#define RTL8367C_REG_METER57_RATE_CTRL1 0x1773 ++#define RTL8367C_METER57_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER57_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER58_RATE_CTRL0 0x1774 ++ ++#define RTL8367C_REG_METER58_RATE_CTRL1 0x1775 ++#define RTL8367C_METER58_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER58_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER59_RATE_CTRL0 0x1776 ++ ++#define RTL8367C_REG_METER59_RATE_CTRL1 0x1777 ++#define RTL8367C_METER59_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER59_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER60_RATE_CTRL0 0x1778 ++ ++#define RTL8367C_REG_METER60_RATE_CTRL1 0x1779 ++#define RTL8367C_METER60_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER60_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER61_RATE_CTRL0 0x177a ++ ++#define RTL8367C_REG_METER61_RATE_CTRL1 0x177b ++#define RTL8367C_METER61_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER61_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER62_RATE_CTRL0 0x177c ++ ++#define RTL8367C_REG_METER62_RATE_CTRL1 0x177d ++#define RTL8367C_METER62_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER62_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER63_RATE_CTRL0 0x177e ++ ++#define RTL8367C_REG_METER63_RATE_CTRL1 0x177f ++#define RTL8367C_METER63_RATE_CTRL1_OFFSET 0 ++#define RTL8367C_METER63_RATE_CTRL1_MASK 0x7 ++ ++#define RTL8367C_REG_METER_MODE_SETTING2 0x1780 ++ ++#define RTL8367C_REG_METER_MODE_SETTING3 0x1781 ++ ++#define RTL8367C_REG_METER32_BUCKET_SIZE 0x1790 ++ ++#define RTL8367C_REG_METER33_BUCKET_SIZE 0x1791 ++ ++#define RTL8367C_REG_METER34_BUCKET_SIZE 0x1792 ++ ++#define RTL8367C_REG_METER35_BUCKET_SIZE 0x1793 ++ ++#define RTL8367C_REG_METER36_BUCKET_SIZE 0x1794 ++ ++#define RTL8367C_REG_METER37_BUCKET_SIZE 0x1795 ++ ++#define RTL8367C_REG_METER38_BUCKET_SIZE 0x1796 ++ ++#define RTL8367C_REG_METER39_BUCKET_SIZE 0x1797 ++ ++#define RTL8367C_REG_METER40_BUCKET_SIZE 0x1798 ++ ++#define RTL8367C_REG_METER41_BUCKET_SIZE 0x1799 ++ ++#define RTL8367C_REG_METER42_BUCKET_SIZE 0x179a ++ ++#define RTL8367C_REG_METER43_BUCKET_SIZE 0x179b ++ ++#define RTL8367C_REG_METER44_BUCKET_SIZE 0x179c ++ ++#define RTL8367C_REG_METER45_BUCKET_SIZE 0x179d ++ ++#define RTL8367C_REG_METER46_BUCKET_SIZE 0x179e ++ ++#define RTL8367C_REG_METER47_BUCKET_SIZE 0x179f ++ ++#define RTL8367C_REG_METER48_BUCKET_SIZE 0x17a0 ++ ++#define RTL8367C_REG_METER49_BUCKET_SIZE 0x17a1 ++ ++#define RTL8367C_REG_METER50_BUCKET_SIZE 0x17a2 ++ ++#define RTL8367C_REG_METER51_BUCKET_SIZE 0x17a3 ++ ++#define RTL8367C_REG_METER52_BUCKET_SIZE 0x17a4 ++ ++#define RTL8367C_REG_METER53_BUCKET_SIZE 0x17a5 ++ ++#define RTL8367C_REG_METER54_BUCKET_SIZE 0x17a6 ++ ++#define RTL8367C_REG_METER55_BUCKET_SIZE 0x17a7 ++ ++#define RTL8367C_REG_METER56_BUCKET_SIZE 0x17a8 ++ ++#define RTL8367C_REG_METER57_BUCKET_SIZE 0x17a9 ++ ++#define RTL8367C_REG_METER58_BUCKET_SIZE 0x17aa ++ ++#define RTL8367C_REG_METER59_BUCKET_SIZE 0x17ab ++ ++#define RTL8367C_REG_METER60_BUCKET_SIZE 0x17ac ++ ++#define RTL8367C_REG_METER61_BUCKET_SIZE 0x17ad ++ ++#define RTL8367C_REG_METER62_BUCKET_SIZE 0x17ae ++ ++#define RTL8367C_REG_METER63_BUCKET_SIZE 0x17af ++ ++#define RTL8367C_REG_METER_OVERRATE_INDICATOR2 0x17b0 ++ ++#define RTL8367C_REG_METER_OVERRATE_INDICATOR3 0x17b1 ++ ++#define RTL8367C_REG_METER_OVERRATE_INDICATOR2_8051 0x17b2 ++ ++#define RTL8367C_REG_METER_OVERRATE_INDICATOR3_8051 0x17b3 ++ ++#define RTL8367C_REG_METER_IFG_CTRL2 0x17b4 ++#define RTL8367C_METER47_IFG_OFFSET 15 ++#define RTL8367C_METER47_IFG_MASK 0x8000 ++#define RTL8367C_METER46_IFG_OFFSET 14 ++#define RTL8367C_METER46_IFG_MASK 0x4000 ++#define RTL8367C_METER45_IFG_OFFSET 13 ++#define RTL8367C_METER45_IFG_MASK 0x2000 ++#define RTL8367C_METER44_IFG_OFFSET 12 ++#define RTL8367C_METER44_IFG_MASK 0x1000 ++#define RTL8367C_METER43_IFG_OFFSET 11 ++#define RTL8367C_METER43_IFG_MASK 0x800 ++#define RTL8367C_METER42_IFG_OFFSET 10 ++#define RTL8367C_METER42_IFG_MASK 0x400 ++#define RTL8367C_METER41_IFG_OFFSET 9 ++#define RTL8367C_METER41_IFG_MASK 0x200 ++#define RTL8367C_METER40_IFG_OFFSET 8 ++#define RTL8367C_METER40_IFG_MASK 0x100 ++#define RTL8367C_METER39_IFG_OFFSET 7 ++#define RTL8367C_METER39_IFG_MASK 0x80 ++#define RTL8367C_METER38_IFG_OFFSET 6 ++#define RTL8367C_METER38_IFG_MASK 0x40 ++#define RTL8367C_METER37_IFG_OFFSET 5 ++#define RTL8367C_METER37_IFG_MASK 0x20 ++#define RTL8367C_METER36_IFG_OFFSET 4 ++#define RTL8367C_METER36_IFG_MASK 0x10 ++#define RTL8367C_METER35_IFG_OFFSET 3 ++#define RTL8367C_METER35_IFG_MASK 0x8 ++#define RTL8367C_METER34_IFG_OFFSET 2 ++#define RTL8367C_METER34_IFG_MASK 0x4 ++#define RTL8367C_METER33_IFG_OFFSET 1 ++#define RTL8367C_METER33_IFG_MASK 0x2 ++#define RTL8367C_METER32_IFG_OFFSET 0 ++#define RTL8367C_METER32_IFG_MASK 0x1 ++ ++#define RTL8367C_REG_METER_IFG_CTRL3 0x17b5 ++#define RTL8367C_METER63_IFG_OFFSET 15 ++#define RTL8367C_METER63_IFG_MASK 0x8000 ++#define RTL8367C_METER62_IFG_OFFSET 14 ++#define RTL8367C_METER62_IFG_MASK 0x4000 ++#define RTL8367C_METER61_IFG_OFFSET 13 ++#define RTL8367C_METER61_IFG_MASK 0x2000 ++#define RTL8367C_METER60_IFG_OFFSET 12 ++#define RTL8367C_METER60_IFG_MASK 0x1000 ++#define RTL8367C_METER59_IFG_OFFSET 11 ++#define RTL8367C_METER59_IFG_MASK 0x800 ++#define RTL8367C_METER58_IFG_OFFSET 10 ++#define RTL8367C_METER58_IFG_MASK 0x400 ++#define RTL8367C_METER57_IFG_OFFSET 9 ++#define RTL8367C_METER57_IFG_MASK 0x200 ++#define RTL8367C_METER56_IFG_OFFSET 8 ++#define RTL8367C_METER56_IFG_MASK 0x100 ++#define RTL8367C_METER55_IFG_OFFSET 7 ++#define RTL8367C_METER55_IFG_MASK 0x80 ++#define RTL8367C_METER54_IFG_OFFSET 6 ++#define RTL8367C_METER54_IFG_MASK 0x40 ++#define RTL8367C_METER53_IFG_OFFSET 5 ++#define RTL8367C_METER53_IFG_MASK 0x20 ++#define RTL8367C_METER52_IFG_OFFSET 4 ++#define RTL8367C_METER52_IFG_MASK 0x10 ++#define RTL8367C_METER51_IFG_OFFSET 3 ++#define RTL8367C_METER51_IFG_MASK 0x8 ++#define RTL8367C_METER50_IFG_OFFSET 2 ++#define RTL8367C_METER50_IFG_MASK 0x4 ++#define RTL8367C_METER49_IFG_OFFSET 1 ++#define RTL8367C_METER49_IFG_MASK 0x2 ++#define RTL8367C_METER48_IFG_OFFSET 0 ++#define RTL8367C_METER48_IFG_MASK 0x1 ++ ++#define RTL8367C_REG_METER_MISC 0x17b6 ++#define RTL8367C_METER_MISC_OFFSET 0 ++#define RTL8367C_METER_MISC_MASK 0x1 ++ ++/* (16'h1800)8051_RLDP_EEE_reg */ ++ ++#define RTL8367C_REG_EEELLDP_CTRL0 0x1820 ++#define RTL8367C_EEELLDP_SUBTYPE_OFFSET 6 ++#define RTL8367C_EEELLDP_SUBTYPE_MASK 0x3FC0 ++#define RTL8367C_EEELLDP_TRAP_8051_OFFSET 2 ++#define RTL8367C_EEELLDP_TRAP_8051_MASK 0x4 ++#define RTL8367C_EEELLDP_TRAP_CPU_OFFSET 1 ++#define RTL8367C_EEELLDP_TRAP_CPU_MASK 0x2 ++#define RTL8367C_EEELLDP_ENABLE_OFFSET 0 ++#define RTL8367C_EEELLDP_ENABLE_MASK 0x1 ++ ++#define RTL8367C_REG_EEELLDP_PMSK 0x1822 ++#define RTL8367C_EEELLDP_PMSK_OFFSET 0 ++#define RTL8367C_EEELLDP_PMSK_MASK 0x7FF ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P00_08 0x1843 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P00_07 0x1844 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P00_06 0x1845 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P00_05 0x1846 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P00_04 0x1847 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P00_03 0x1848 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P00_02 0x1849 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P00_01 0x184a ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P00_00 0x184b ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P01_08 0x184c ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P01_07 0x184d ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P01_06 0x184e ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P01_05 0x184f ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P01_04 0x1850 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P01_03 0x1851 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P01_02 0x1852 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P01_01 0x1853 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P01_00 0x1854 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P02_08 0x1855 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P02_07 0x1856 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P02_06 0x1857 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P02_05 0x1858 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P02_04 0x1859 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P02_03 0x185a ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P02_02 0x185b ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P02_01 0x185c ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P02_00 0x185d ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P03_08 0x185e ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P03_07 0x185f ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P03_06 0x1860 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P03_05 0x1861 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P03_04 0x1862 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P03_03 0x1863 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P03_02 0x1864 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P03_01 0x1865 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P03_00 0x1866 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P04_08 0x1867 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P04_07 0x1868 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P04_06 0x1869 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P04_05 0x186a ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P04_04 0x186b ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P04_03 0x186c ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P04_02 0x186d ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P04_01 0x186e ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P04_00 0x186f ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P05_08 0x1870 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P05_07 0x1871 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P05_06 0x1872 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P05_05 0x1873 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P05_04 0x1874 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P05_03 0x1875 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P05_02 0x1876 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P05_01 0x1877 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P05_00 0x1878 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P06_08 0x1879 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P06_07 0x187a ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P06_06 0x187b ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P06_05 0x187c ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P06_04 0x187d ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P06_03 0x187e ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P06_02 0x187f ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P06_01 0x1880 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P06_00 0x1881 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P07_08 0x1882 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P07_07 0x1883 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P07_06 0x1884 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P07_05 0x1885 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P07_04 0x1886 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P07_03 0x1887 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P07_02 0x1888 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P07_01 0x1889 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P07_00 0x188a ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P08_08 0x188b ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P08_07 0x188c ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P08_06 0x188d ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P08_05 0x188e ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P08_04 0x188f ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P08_03 0x1890 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P08_02 0x1891 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P08_01 0x1892 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P08_00 0x1893 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P09_08 0x1894 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P09_07 0x1895 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P09_06 0x1896 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P09_05 0x1897 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P09_04 0x1898 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P09_03 0x1899 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P09_02 0x189a ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P09_01 0x189b ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P09_00 0x189c ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P10_08 0x189d ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P10_07 0x189e ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P10_06 0x189f ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P10_05 0x18a0 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P10_04 0x18a1 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P10_03 0x18a2 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P10_02 0x18a3 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P10_01 0x18a4 ++ ++#define RTL8367C_REG_EEELLDP_RX_VALUE_P10_00 0x18a5 ++ ++#define RTL8367C_REG_RLDP_CTRL0 0x18e0 ++#define RTL8367C_RLDP_TRIGGER_MODE_OFFSET 14 ++#define RTL8367C_RLDP_TRIGGER_MODE_MASK 0x4000 ++#define RTL8367C_RLDP_8051_LOOP_PORTMSK_OFFSET 6 ++#define RTL8367C_RLDP_8051_LOOP_PORTMSK_MASK 0x3FC0 ++#define RTL8367C_RLPP_8051_TRAP_OFFSET 5 ++#define RTL8367C_RLPP_8051_TRAP_MASK 0x20 ++#define RTL8367C_RLDP_INDICATOR_SOURCE_OFFSET 4 ++#define RTL8367C_RLDP_INDICATOR_SOURCE_MASK 0x10 ++#define RTL8367C_RLDP_GEN_RANDOM_OFFSET 3 ++#define RTL8367C_RLDP_GEN_RANDOM_MASK 0x8 ++#define RTL8367C_RLDP_COMP_ID_OFFSET 2 ++#define RTL8367C_RLDP_COMP_ID_MASK 0x4 ++#define RTL8367C_RLDP_8051_ENABLE_OFFSET 1 ++#define RTL8367C_RLDP_8051_ENABLE_MASK 0x2 ++#define RTL8367C_RLDP_ENABLE_OFFSET 0 ++#define RTL8367C_RLDP_ENABLE_MASK 0x1 ++ ++#define RTL8367C_REG_RLDP_CTRL1 0x18e1 ++#define RTL8367C_RLDP_RETRY_COUNT_LOOPSTATE_OFFSET 8 ++#define RTL8367C_RLDP_RETRY_COUNT_LOOPSTATE_MASK 0xFF00 ++#define RTL8367C_RLDP_RETRY_COUNT_CHKSTATE_OFFSET 0 ++#define RTL8367C_RLDP_RETRY_COUNT_CHKSTATE_MASK 0xFF ++ ++#define RTL8367C_REG_RLDP_CTRL2 0x18e2 ++ ++#define RTL8367C_REG_RLDP_CTRL3 0x18e3 ++ ++#define RTL8367C_REG_RLDP_CTRL4 0x18e4 ++#define RTL8367C_RLDP_CTRL4_OFFSET 0 ++#define RTL8367C_RLDP_CTRL4_MASK 0x7FF ++ ++#define RTL8367C_REG_RLDP_RAND_NUM0 0x18e5 ++ ++#define RTL8367C_REG_RLDP_RAND_NUM1 0x18e6 ++ ++#define RTL8367C_REG_RLDP_RAND_NUM2 0x18e7 ++ ++#define RTL8367C_REG_RLDP_MAGIC_NUM0 0x18e8 ++ ++#define RTL8367C_REG_RLDP_MAGIC_NUM1 0x18e9 ++ ++#define RTL8367C_REG_RLDP_MAGIC_NUM2 0x18ea ++ ++#define RTL8367C_REG_RLDP_LOOPED_INDICATOR 0x18eb ++#define RTL8367C_RLDP_LOOPED_INDICATOR_OFFSET 0 ++#define RTL8367C_RLDP_LOOPED_INDICATOR_MASK 0x7FF ++ ++#define RTL8367C_REG_RLDP_LOOP_PORT_REG0 0x18ec ++#define RTL8367C_RLDP_LOOP_PORT_01_OFFSET 8 ++#define RTL8367C_RLDP_LOOP_PORT_01_MASK 0xF00 ++#define RTL8367C_RLDP_LOOP_PORT_00_OFFSET 0 ++#define RTL8367C_RLDP_LOOP_PORT_00_MASK 0xF ++ ++#define RTL8367C_REG_RLDP_LOOP_PORT_REG1 0x18ed ++#define RTL8367C_RLDP_LOOP_PORT_03_OFFSET 8 ++#define RTL8367C_RLDP_LOOP_PORT_03_MASK 0xF00 ++#define RTL8367C_RLDP_LOOP_PORT_02_OFFSET 0 ++#define RTL8367C_RLDP_LOOP_PORT_02_MASK 0xF ++ ++#define RTL8367C_REG_RLDP_LOOP_PORT_REG2 0x18ee ++#define RTL8367C_RLDP_LOOP_PORT_05_OFFSET 8 ++#define RTL8367C_RLDP_LOOP_PORT_05_MASK 0xF00 ++#define RTL8367C_RLDP_LOOP_PORT_04_OFFSET 0 ++#define RTL8367C_RLDP_LOOP_PORT_04_MASK 0xF ++ ++#define RTL8367C_REG_RLDP_LOOP_PORT_REG3 0x18ef ++#define RTL8367C_RLDP_LOOP_PORT_07_OFFSET 8 ++#define RTL8367C_RLDP_LOOP_PORT_07_MASK 0xF00 ++#define RTL8367C_RLDP_LOOP_PORT_06_OFFSET 0 ++#define RTL8367C_RLDP_LOOP_PORT_06_MASK 0xF ++ ++#define RTL8367C_REG_RLDP_RELEASED_INDICATOR 0x18f0 ++#define RTL8367C_RLDP_RELEASED_INDICATOR_OFFSET 0 ++#define RTL8367C_RLDP_RELEASED_INDICATOR_MASK 0x7FF ++ ++#define RTL8367C_REG_RLDP_LOOPSTATUS_INDICATOR 0x18f1 ++#define RTL8367C_RLDP_LOOPSTATUS_INDICATOR_OFFSET 0 ++#define RTL8367C_RLDP_LOOPSTATUS_INDICATOR_MASK 0x7FF ++ ++#define RTL8367C_REG_RLDP_LOOP_PORT_REG4 0x18f2 ++#define RTL8367C_RLDP_LOOP_PORT_9_OFFSET 8 ++#define RTL8367C_RLDP_LOOP_PORT_9_MASK 0xF00 ++#define RTL8367C_RLDP_LOOP_PORT_8_OFFSET 0 ++#define RTL8367C_RLDP_LOOP_PORT_8_MASK 0xF ++ ++#define RTL8367C_REG_RLDP_LOOP_PORT_REG5 0x18f3 ++#define RTL8367C_RLDP_LOOP_PORT_REG5_OFFSET 0 ++#define RTL8367C_RLDP_LOOP_PORT_REG5_MASK 0xF ++ ++#define RTL8367C_REG_RLDP_CTRL5 0x18f4 ++#define RTL8367C_RLDP_CTRL5_OFFSET 0 ++#define RTL8367C_RLDP_CTRL5_MASK 0x7 ++ ++/* (16'h1900)EEE_EEEP_reg */ ++ ++#define RTL8367C_REG_EEE_500M_CTRL0 0x1900 ++#define RTL8367C_EEE_500M_CTRL0_OFFSET 0 ++#define RTL8367C_EEE_500M_CTRL0_MASK 0xFF ++ ++#define RTL8367C_REG_EEE_RXIDLE_GIGA_CTRL 0x1901 ++#define RTL8367C_EEE_RXIDLE_GIGA_EN_OFFSET 8 ++#define RTL8367C_EEE_RXIDLE_GIGA_EN_MASK 0x100 ++#define RTL8367C_EEE_RXIDLE_GIGA_OFFSET 0 ++#define RTL8367C_EEE_RXIDLE_GIGA_MASK 0xFF ++ ++#define RTL8367C_REG_EEE_RXIDLE_500M_CTRL 0x1902 ++#define RTL8367C_EEE_RXIDLE_500M_EN_OFFSET 8 ++#define RTL8367C_EEE_RXIDLE_500M_EN_MASK 0x100 ++#define RTL8367C_EEE_RXIDLE_500M_OFFSET 0 ++#define RTL8367C_EEE_RXIDLE_500M_MASK 0xFF ++ ++#define RTL8367C_REG_EEE_DECISION_GIGA_500M 0x1903 ++#define RTL8367C_EEE_DECISION_GIGA_OFFSET 8 ++#define RTL8367C_EEE_DECISION_GIGA_MASK 0xFF00 ++#define RTL8367C_EEE_DECISION_500M_OFFSET 0 ++#define RTL8367C_EEE_DECISION_500M_MASK 0xFF ++ ++#define RTL8367C_REG_EEE_DECISION_100M 0x1904 ++#define RTL8367C_EEE_DECISION_100M_OFFSET 0 ++#define RTL8367C_EEE_DECISION_100M_MASK 0xFF ++ ++#define RTL8367C_REG_EEEP_DEFER_TXLPI 0x1905 ++#define RTL8367C_EEEP_DEFER_TXLPI_OFFSET 0 ++#define RTL8367C_EEEP_DEFER_TXLPI_MASK 0x1 ++ ++#define RTL8367C_REG_EEEP_EN 0x1906 ++#define RTL8367C_EEEP_SLAVE_EN_OFFSET 3 ++#define RTL8367C_EEEP_SLAVE_EN_MASK 0x8 ++#define RTL8367C_EEEP_100M_OFFSET 2 ++#define RTL8367C_EEEP_100M_MASK 0x4 ++#define RTL8367C_EEEP_500M_OFFSET 1 ++#define RTL8367C_EEEP_500M_MASK 0x2 ++#define RTL8367C_EEEP_GIGA_OFFSET 0 ++#define RTL8367C_EEEP_GIGA_MASK 0x1 ++ ++#define RTL8367C_REG_EEEP_TI_GIGA_500M 0x1907 ++#define RTL8367C_EEEP_TI_GIGA_OFFSET 8 ++#define RTL8367C_EEEP_TI_GIGA_MASK 0xFF00 ++#define RTL8367C_EEEP_TI_500M_OFFSET 0 ++#define RTL8367C_EEEP_TI_500M_MASK 0xFF ++ ++#define RTL8367C_REG_EEEP_TI_100M 0x1908 ++#define RTL8367C_EEEP_TI_100M_OFFSET 0 ++#define RTL8367C_EEEP_TI_100M_MASK 0xFF ++ ++#define RTL8367C_REG_EEEP_CTRL2 0x1909 ++#define RTL8367C_EEEP_CTRL2_OFFSET 0 ++#define RTL8367C_EEEP_CTRL2_MASK 0xFF ++ ++#define RTL8367C_REG_EEEP_RX_RATE_500M 0x190b ++ ++#define RTL8367C_REG_EEEP_RW_GIGA_SLV 0x190c ++#define RTL8367C_EEEP_RW_GIGA_SLV_OFFSET 0 ++#define RTL8367C_EEEP_RW_GIGA_SLV_MASK 0xFF ++ ++#define RTL8367C_REG_EEEP_TMR_GIGA 0x190d ++#define RTL8367C_RX_IDLE_EEEP_GIGA_OFFSET 8 ++#define RTL8367C_RX_IDLE_EEEP_GIGA_MASK 0xFF00 ++#define RTL8367C_RX_MIN_SLP_TMR_GIGA_OFFSET 0 ++#define RTL8367C_RX_MIN_SLP_TMR_GIGA_MASK 0xFF ++ ++#define RTL8367C_REG_EEEP_TMR_500M 0x190e ++#define RTL8367C_RX_IDLE_EEEP_500M_OFFSET 8 ++#define RTL8367C_RX_IDLE_EEEP_500M_MASK 0xFF00 ++#define RTL8367C_RX_MIN_SLP_TMR_500M_OFFSET 0 ++#define RTL8367C_RX_MIN_SLP_TMR_500M_MASK 0xFF ++ ++#define RTL8367C_REG_EEEP_TMR_100M 0x190f ++#define RTL8367C_RX_IDLE_EEEP_100M_OFFSET 8 ++#define RTL8367C_RX_IDLE_EEEP_100M_MASK 0xFF00 ++#define RTL8367C_RX_MIN_SLP_TMR_100M_OFFSET 0 ++#define RTL8367C_RX_MIN_SLP_TMR_100M_MASK 0xFF ++ ++#define RTL8367C_REG_EEEP_RW_500M_MST_SLV 0x1910 ++#define RTL8367C_EEEP_RW_500M_MST_OFFSET 8 ++#define RTL8367C_EEEP_RW_500M_MST_MASK 0xFF00 ++#define RTL8367C_EEEP_RW_500M_SLV_OFFSET 0 ++#define RTL8367C_EEEP_RW_500M_SLV_MASK 0xFF ++ ++#define RTL8367C_REG_EEEP_500M_CTRL0 0x1911 ++#define RTL8367C_EEEP_500M_CTRL0_OFFSET 0 ++#define RTL8367C_EEEP_500M_CTRL0_MASK 0xFF ++ ++#define RTL8367C_REG_EEEP_500M_CTRL1 0x1912 ++#define RTL8367C_EEEP_TW_500M_OFFSET 8 ++#define RTL8367C_EEEP_TW_500M_MASK 0xFF00 ++#define RTL8367C_EEEP_TP_500M_OFFSET 0 ++#define RTL8367C_EEEP_TP_500M_MASK 0xFF ++ ++#define RTL8367C_REG_EEEP_500M_CTRL2 0x1913 ++#define RTL8367C_EEEP_TXEN_500M_OFFSET 12 ++#define RTL8367C_EEEP_TXEN_500M_MASK 0x1000 ++#define RTL8367C_EEEP_TU_500M_OFFSET 8 ++#define RTL8367C_EEEP_TU_500M_MASK 0x300 ++#define RTL8367C_EEEP_TS_500M_OFFSET 0 ++#define RTL8367C_EEEP_TS_500M_MASK 0xFF ++ ++#define RTL8367C_REG_EEE_NEW_CTRL0 0x1914 ++#define RTL8367C_LINK_UP_DELAY_OFFSET 3 ++#define RTL8367C_LINK_UP_DELAY_MASK 0x18 ++#define RTL8367C_EEE_TXLPI_ORI_OFFSET 2 ++#define RTL8367C_EEE_TXLPI_ORI_MASK 0x4 ++#define RTL8367C_REALTX_SEL_OFFSET 1 ++#define RTL8367C_REALTX_SEL_MASK 0x2 ++#define RTL8367C_EN_FC_EFCT_OFFSET 0 ++#define RTL8367C_EN_FC_EFCT_MASK 0x1 ++ ++#define RTL8367C_REG_EEE_LONGIDLE_100M 0x1915 ++#define RTL8367C_EEE_LONGIDLE_100M_OFFSET 0 ++#define RTL8367C_EEE_LONGIDLE_100M_MASK 0x3FF ++ ++#define RTL8367C_REG_EEE_LONGIDLE_500M 0x1916 ++#define RTL8367C_EEE_LONGIDLE_500M_OFFSET 0 ++#define RTL8367C_EEE_LONGIDLE_500M_MASK 0x3FF ++ ++#define RTL8367C_REG_EEE_LONGIDLE_GIGA 0x1917 ++#define RTL8367C_EEE_LONGIDLE_GIGA_OFFSET 0 ++#define RTL8367C_EEE_LONGIDLE_GIGA_MASK 0x3FF ++ ++#define RTL8367C_REG_EEE_MINIPG_100M 0x1918 ++ ++#define RTL8367C_REG_EEE_MINIPG_500M 0x1919 ++ ++#define RTL8367C_REG_EEE_MINIPG_GIGA 0x191A ++ ++#define RTL8367C_REG_EEE_LONGIDLE_CTRL0 0x191B ++#define RTL8367C_TX_IDLEN_REQ_100M_OFFSET 10 ++#define RTL8367C_TX_IDLEN_REQ_100M_MASK 0x400 ++#define RTL8367C_TX_IDLEN_REQ_500M_OFFSET 9 ++#define RTL8367C_TX_IDLEN_REQ_500M_MASK 0x200 ++#define RTL8367C_TX_IDLEN_REQ_GIGA_OFFSET 8 ++#define RTL8367C_TX_IDLEN_REQ_GIGA_MASK 0x100 ++#define RTL8367C_EEE_LONGIDLE_CTRL0_TX_LPI_MINIPG_100M_OFFSET 0 ++#define RTL8367C_EEE_LONGIDLE_CTRL0_TX_LPI_MINIPG_100M_MASK 0xFF ++ ++#define RTL8367C_REG_EEE_LONGIDLE_CTRL1 0x191C ++#define RTL8367C_EEE_LONGIDLE_CTRL1_TX_LPI_MINIPG_GELITE_OFFSET 8 ++#define RTL8367C_EEE_LONGIDLE_CTRL1_TX_LPI_MINIPG_GELITE_MASK 0xFF00 ++#define RTL8367C_EEE_LONGIDLE_CTRL1_TX_LPI_MINIPG_GIGA_OFFSET 0 ++#define RTL8367C_EEE_LONGIDLE_CTRL1_TX_LPI_MINIPG_GIGA_MASK 0xFF ++ ++#define RTL8367C_REG_EEE_TD_CTRL_H 0x191d ++#define RTL8367C_REF_RXLPI_OFFSET 8 ++#define RTL8367C_REF_RXLPI_MASK 0x100 ++#define RTL8367C_LOW_Q_TX_DELAY_GE_500M_H_OFFSET 4 ++#define RTL8367C_LOW_Q_TX_DELAY_GE_500M_H_MASK 0xF0 ++#define RTL8367C_LOW_Q_TX_DELAY_FE_H_OFFSET 0 ++#define RTL8367C_LOW_Q_TX_DELAY_FE_H_MASK 0xF ++ ++/* (16'h1a00)nic_reg */ ++ ++#define RTL8367C_REG_NIC_RXRDRL 0x1a04 ++#define RTL8367C_NIC_RXRDRL_OFFSET 0 ++#define RTL8367C_NIC_RXRDRL_MASK 0xFF ++ ++#define RTL8367C_REG_NIC_RXRDRH 0x1a05 ++#define RTL8367C_NIC_RXRDRH_OFFSET 0 ++#define RTL8367C_NIC_RXRDRH_MASK 0xFF ++ ++#define RTL8367C_REG_NIC_TXASRL 0x1a08 ++#define RTL8367C_NIC_TXASRL_OFFSET 0 ++#define RTL8367C_NIC_TXASRL_MASK 0xFF ++ ++#define RTL8367C_REG_NIC_TXASRH 0x1a09 ++#define RTL8367C_NIC_TXASRH_OFFSET 0 ++#define RTL8367C_NIC_TXASRH_MASK 0xFF ++ ++#define RTL8367C_REG_NIC_RXCMDR 0x1a0c ++#define RTL8367C_NIC_RXCMDR_OFFSET 0 ++#define RTL8367C_NIC_RXCMDR_MASK 0x1 ++ ++#define RTL8367C_REG_NIC_TXCMDR 0x1a0d ++#define RTL8367C_NIC_TXCMDR_OFFSET 0 ++#define RTL8367C_NIC_TXCMDR_MASK 0x1 ++ ++#define RTL8367C_REG_NIC_IMS 0x1a0e ++#define RTL8367C_NIC_RXIS_OFFSET 7 ++#define RTL8367C_NIC_RXIS_MASK 0x80 ++#define RTL8367C_NIC_TXIS_OFFSET 6 ++#define RTL8367C_NIC_TXIS_MASK 0x40 ++#define RTL8367C_NIC_TXES_OFFSET 5 ++#define RTL8367C_NIC_TXES_MASK 0x20 ++#define RTL8367C_NIC_IMS_DMY_OFFSET 4 ++#define RTL8367C_NIC_IMS_DMY_MASK 0x10 ++#define RTL8367C_NIC_RXBUS_OFFSET 3 ++#define RTL8367C_NIC_RXBUS_MASK 0x8 ++#define RTL8367C_NIC_TXBOS_OFFSET 2 ++#define RTL8367C_NIC_TXBOS_MASK 0x4 ++#define RTL8367C_NIC_RXMIS_OFFSET 1 ++#define RTL8367C_NIC_RXMIS_MASK 0x2 ++#define RTL8367C_NIC_TXNLS_OFFSET 0 ++#define RTL8367C_NIC_TXNLS_MASK 0x1 ++ ++#define RTL8367C_REG_NIC_IMR 0x1a0f ++#define RTL8367C_NIC_RXIE_OFFSET 7 ++#define RTL8367C_NIC_RXIE_MASK 0x80 ++#define RTL8367C_NIC_TXIE_OFFSET 6 ++#define RTL8367C_NIC_TXIE_MASK 0x40 ++#define RTL8367C_NIC_TXEE_OFFSET 5 ++#define RTL8367C_NIC_TXEE_MASK 0x20 ++#define RTL8367C_NIC_IMR_DMY_OFFSET 4 ++#define RTL8367C_NIC_IMR_DMY_MASK 0x10 ++#define RTL8367C_NIC_RXBUE_OFFSET 3 ++#define RTL8367C_NIC_RXBUE_MASK 0x8 ++#define RTL8367C_NIC_TXBOE_OFFSET 2 ++#define RTL8367C_NIC_TXBOE_MASK 0x4 ++#define RTL8367C_NIC_RXMIE_OFFSET 1 ++#define RTL8367C_NIC_RXMIE_MASK 0x2 ++#define RTL8367C_NIC_TXNLE_OFFSET 0 ++#define RTL8367C_NIC_TXNLE_MASK 0x1 ++ ++#define RTL8367C_REG_NIC_RXCR0 0x1a14 ++#define RTL8367C_NIC_HFPPE_OFFSET 7 ++#define RTL8367C_NIC_HFPPE_MASK 0x80 ++#define RTL8367C_NIC_HFMPE_OFFSET 6 ++#define RTL8367C_NIC_HFMPE_MASK 0x40 ++#define RTL8367C_NIC_RXBPE_OFFSET 5 ++#define RTL8367C_NIC_RXBPE_MASK 0x20 ++#define RTL8367C_NIC_RXMPE_OFFSET 4 ++#define RTL8367C_NIC_RXMPE_MASK 0x10 ++#define RTL8367C_NIC_RXPPS_OFFSET 2 ++#define RTL8367C_NIC_RXPPS_MASK 0xC ++#define RTL8367C_NIC_RXAPE_OFFSET 1 ++#define RTL8367C_NIC_RXAPE_MASK 0x2 ++#define RTL8367C_NIC_ARPPE_OFFSET 0 ++#define RTL8367C_NIC_ARPPE_MASK 0x1 ++ ++#define RTL8367C_REG_NIC_RXCR1 0x1a15 ++#define RTL8367C_NIC_RL4CEPE_OFFSET 4 ++#define RTL8367C_NIC_RL4CEPE_MASK 0x10 ++#define RTL8367C_NIC_RL3CEPE_OFFSET 3 ++#define RTL8367C_NIC_RL3CEPE_MASK 0x8 ++#define RTL8367C_NIC_RCRCEPE_OFFSET 2 ++#define RTL8367C_NIC_RCRCEPE_MASK 0x4 ++#define RTL8367C_NIC_RMCRC_OFFSET 1 ++#define RTL8367C_NIC_RMCRC_MASK 0x2 ++#define RTL8367C_NIC_RXENABLE_OFFSET 0 ++#define RTL8367C_NIC_RXENABLE_MASK 0x1 ++ ++#define RTL8367C_REG_NIC_TXCR 0x1a16 ++#define RTL8367C_NIC_LBE_OFFSET 2 ++#define RTL8367C_NIC_LBE_MASK 0x4 ++#define RTL8367C_NIC_TXMFM_OFFSET 1 ++#define RTL8367C_NIC_TXMFM_MASK 0x2 ++#define RTL8367C_NIC_TXENABLE_OFFSET 0 ++#define RTL8367C_NIC_TXENABLE_MASK 0x1 ++ ++#define RTL8367C_REG_NIC_GCR 0x1a17 ++#define RTL8367C_DUMMY_7_6_OFFSET 6 ++#define RTL8367C_DUMMY_7_6_MASK 0xC0 ++#define RTL8367C_NIC_RXMTU_OFFSET 4 ++#define RTL8367C_NIC_RXMTU_MASK 0x30 ++#define RTL8367C_NIC_GCR_DUMMY_0_OFFSET 0 ++#define RTL8367C_NIC_GCR_DUMMY_0_MASK 0x1 ++ ++#define RTL8367C_REG_NIC_MHR0 0x1a24 ++#define RTL8367C_NIC_MHR0_OFFSET 0 ++#define RTL8367C_NIC_MHR0_MASK 0xFF ++ ++#define RTL8367C_REG_NIC_MHR1 0x1a25 ++#define RTL8367C_NIC_MHR1_OFFSET 0 ++#define RTL8367C_NIC_MHR1_MASK 0xFF ++ ++#define RTL8367C_REG_NIC_MHR2 0x1a26 ++#define RTL8367C_NIC_MHR2_OFFSET 0 ++#define RTL8367C_NIC_MHR2_MASK 0xFF ++ ++#define RTL8367C_REG_NIC_MHR3 0x1a27 ++#define RTL8367C_NIC_MHR3_OFFSET 0 ++#define RTL8367C_NIC_MHR3_MASK 0xFF ++ ++#define RTL8367C_REG_NIC_MHR4 0x1a28 ++#define RTL8367C_NIC_MHR4_OFFSET 0 ++#define RTL8367C_NIC_MHR4_MASK 0xFF ++ ++#define RTL8367C_REG_NIC_MHR5 0x1a29 ++#define RTL8367C_NIC_MHR5_OFFSET 0 ++#define RTL8367C_NIC_MHR5_MASK 0xFF ++ ++#define RTL8367C_REG_NIC_MHR6 0x1a2a ++#define RTL8367C_NIC_MHR6_OFFSET 0 ++#define RTL8367C_NIC_MHR6_MASK 0xFF ++ ++#define RTL8367C_REG_NIC_MHR7 0x1a2b ++#define RTL8367C_NIC_MHR7_OFFSET 0 ++#define RTL8367C_NIC_MHR7_MASK 0xFF ++ ++#define RTL8367C_REG_NIC_PAHR0 0x1a2c ++#define RTL8367C_NIC_PAHR0_OFFSET 0 ++#define RTL8367C_NIC_PAHR0_MASK 0xFF ++ ++#define RTL8367C_REG_NIC_PAHR1 0x1a2d ++#define RTL8367C_NIC_PAHR1_OFFSET 0 ++#define RTL8367C_NIC_PAHR1_MASK 0xFF ++ ++#define RTL8367C_REG_NIC_PAHR2 0x1a2e ++#define RTL8367C_NIC_PAHR2_OFFSET 0 ++#define RTL8367C_NIC_PAHR2_MASK 0xFF ++ ++#define RTL8367C_REG_NIC_PAHR3 0x1a2f ++#define RTL8367C_NIC_PAHR3_OFFSET 0 ++#define RTL8367C_NIC_PAHR3_MASK 0xFF ++ ++#define RTL8367C_REG_NIC_PAHR4 0x1a30 ++#define RTL8367C_NIC_PAHR4_OFFSET 0 ++#define RTL8367C_NIC_PAHR4_MASK 0xFF ++ ++#define RTL8367C_REG_NIC_PAHR5 0x1a31 ++#define RTL8367C_NIC_PAHR5_OFFSET 0 ++#define RTL8367C_NIC_PAHR5_MASK 0xFF ++ ++#define RTL8367C_REG_NIC_PAHR6 0x1a32 ++#define RTL8367C_NIC_PAHR6_OFFSET 0 ++#define RTL8367C_NIC_PAHR6_MASK 0xFF ++ ++#define RTL8367C_REG_NIC_PAHR7 0x1a33 ++#define RTL8367C_NIC_PAHR7_OFFSET 0 ++#define RTL8367C_NIC_PAHR7_MASK 0xFF ++ ++#define RTL8367C_REG_NIC_TXSTOPRL 0x1a44 ++#define RTL8367C_NIC_TXSTOPRL_OFFSET 0 ++#define RTL8367C_NIC_TXSTOPRL_MASK 0xFF ++ ++#define RTL8367C_REG_NIC_TXSTOPRH 0x1a45 ++#define RTL8367C_NIC_TXSTOPRH_OFFSET 0 ++#define RTL8367C_NIC_TXSTOPRH_MASK 0x3 ++ ++#define RTL8367C_REG_NIC_RXSTOPRL 0x1a46 ++#define RTL8367C_NIC_RXSTOPRL_OFFSET 0 ++#define RTL8367C_NIC_RXSTOPRL_MASK 0xFF ++ ++#define RTL8367C_REG_NIC_RXSTOPRH 0x1a47 ++#define RTL8367C_NIC_RXSTOPRH_OFFSET 0 ++#define RTL8367C_NIC_RXSTOPRH_MASK 0x3 ++ ++#define RTL8367C_REG_NIC_RXFSTR 0x1a48 ++#define RTL8367C_NIC_RXFSTR_OFFSET 0 ++#define RTL8367C_NIC_RXFSTR_MASK 0xFF ++ ++#define RTL8367C_REG_NIC_RXMBTRL 0x1a4c ++#define RTL8367C_NIC_RXMBTRL_OFFSET 0 ++#define RTL8367C_NIC_RXMBTRL_MASK 0xFF ++ ++#define RTL8367C_REG_NIC_RXMBTRH 0x1a4d ++#define RTL8367C_NIC_RXMBTRH_OFFSET 0 ++#define RTL8367C_NIC_RXMBTRH_MASK 0x7F ++ ++#define RTL8367C_REG_NIC_RXMPTR 0x1a4e ++#define RTL8367C_NIC_RXMPTR_OFFSET 0 ++#define RTL8367C_NIC_RXMPTR_MASK 0xFF ++ ++#define RTL8367C_REG_NIC_T0TR 0x1a4f ++#define RTL8367C_NIC_T0TR_OFFSET 0 ++#define RTL8367C_NIC_T0TR_MASK 0xFF ++ ++#define RTL8367C_REG_NIC_CRXCPRL 0x1a50 ++#define RTL8367C_NIC_CRXCPRL_OFFSET 0 ++#define RTL8367C_NIC_CRXCPRL_MASK 0xFF ++ ++#define RTL8367C_REG_NIC_CRXCPRH 0x1a51 ++#define RTL8367C_NIC_CRXCPRH_OFFSET 0 ++#define RTL8367C_NIC_CRXCPRH_MASK 0xFF ++ ++#define RTL8367C_REG_NIC_CTXCPRL 0x1a52 ++#define RTL8367C_NIC_CTXCPRL_OFFSET 0 ++#define RTL8367C_NIC_CTXCPRL_MASK 0xFF ++ ++#define RTL8367C_REG_NIC_CTXPCRH 0x1a53 ++#define RTL8367C_NIC_CTXPCRH_OFFSET 0 ++#define RTL8367C_NIC_CTXPCRH_MASK 0xFF ++ ++#define RTL8367C_REG_NIC_SRXCURPKTRL 0x1a54 ++#define RTL8367C_NIC_SRXCURPKTRL_OFFSET 0 ++#define RTL8367C_NIC_SRXCURPKTRL_MASK 0xFF ++ ++#define RTL8367C_REG_NIC_SRXCURPKTRH 0x1a55 ++#define RTL8367C_NIC_SRXCURPKTRH_OFFSET 0 ++#define RTL8367C_NIC_SRXCURPKTRH_MASK 0xFF ++ ++#define RTL8367C_REG_NIC_STXCURPKTRL 0x1a56 ++#define RTL8367C_NIC_STXCURPKTRL_OFFSET 0 ++#define RTL8367C_NIC_STXCURPKTRL_MASK 0xFF ++ ++#define RTL8367C_REG_NIC_STXCURPKTRH 0x1a57 ++#define RTL8367C_NIC_STXCURPKTRH_OFFSET 0 ++#define RTL8367C_NIC_STXCURPKTRH_MASK 0xFF ++ ++#define RTL8367C_REG_NIC_STXPKTLENRL 0x1a58 ++#define RTL8367C_NIC_STXPKTLENRL_OFFSET 0 ++#define RTL8367C_NIC_STXPKTLENRL_MASK 0xFF ++ ++#define RTL8367C_REG_NIC_STXPKTLENRH 0x1a59 ++#define RTL8367C_NIC_STXPKTLENRH_OFFSET 0 ++#define RTL8367C_NIC_STXPKTLENRH_MASK 0xFF ++ ++#define RTL8367C_REG_NIC_STXCURUNITRL 0x1a5a ++#define RTL8367C_NIC_STXCURUNITRL_OFFSET 0 ++#define RTL8367C_NIC_STXCURUNITRL_MASK 0xFF ++ ++#define RTL8367C_REG_NIC_STXCURUNITRH 0x1a5b ++#define RTL8367C_NIC_STXCURUNITRH_OFFSET 0 ++#define RTL8367C_NIC_STXCURUNITRH_MASK 0xFF ++ ++#define RTL8367C_REG_NIC_DROP_MODE 0x1a5c ++#define RTL8367C_NIC_RXDV_MODE_OFFSET 1 ++#define RTL8367C_NIC_RXDV_MODE_MASK 0x2 ++#define RTL8367C_NIC_DROP_MODE_OFFSET 0 ++#define RTL8367C_NIC_DROP_MODE_MASK 0x1 ++ ++/* (16'h1b00)LED */ ++ ++#define RTL8367C_REG_LED_SYS_CONFIG 0x1b00 ++#define RTL8367C_LED_SYS_CONFIG_DUMMY_15_OFFSET 15 ++#define RTL8367C_LED_SYS_CONFIG_DUMMY_15_MASK 0x8000 ++#define RTL8367C_LED_SERIAL_OUT_MODE_OFFSET 14 ++#define RTL8367C_LED_SERIAL_OUT_MODE_MASK 0x4000 ++#define RTL8367C_LED_EEE_LPI_MODE_OFFSET 13 ++#define RTL8367C_LED_EEE_LPI_MODE_MASK 0x2000 ++#define RTL8367C_LED_EEE_LPI_EN_OFFSET 12 ++#define RTL8367C_LED_EEE_LPI_EN_MASK 0x1000 ++#define RTL8367C_LED_EEE_LPI_10_OFFSET 11 ++#define RTL8367C_LED_EEE_LPI_10_MASK 0x800 ++#define RTL8367C_LED_EEE_CAP_10_OFFSET 10 ++#define RTL8367C_LED_EEE_CAP_10_MASK 0x400 ++#define RTL8367C_LED_LPI_SEL_OFFSET 8 ++#define RTL8367C_LED_LPI_SEL_MASK 0x300 ++#define RTL8367C_SERI_LED_ACT_LOW_OFFSET 7 ++#define RTL8367C_SERI_LED_ACT_LOW_MASK 0x80 ++#define RTL8367C_LED_POWERON_2_OFFSET 6 ++#define RTL8367C_LED_POWERON_2_MASK 0x40 ++#define RTL8367C_LED_POWERON_1_OFFSET 5 ++#define RTL8367C_LED_POWERON_1_MASK 0x20 ++#define RTL8367C_LED_POWERON_0_OFFSET 4 ++#define RTL8367C_LED_POWERON_0_MASK 0x10 ++#define RTL8367C_LED_IO_DISABLE_OFFSET 3 ++#define RTL8367C_LED_IO_DISABLE_MASK 0x8 ++#define RTL8367C_DUMMY_2_2_OFFSET 2 ++#define RTL8367C_DUMMY_2_2_MASK 0x4 ++#define RTL8367C_LED_SELECT_OFFSET 0 ++#define RTL8367C_LED_SELECT_MASK 0x3 ++ ++#define RTL8367C_REG_LED_SYS_CONFIG2 0x1b01 ++#define RTL8367C_LED_SYS_CONFIG2_DUMMY_OFFSET 2 ++#define RTL8367C_LED_SYS_CONFIG2_DUMMY_MASK 0xFFFC ++#define RTL8367C_GATE_LPTD_BYPASS_OFFSET 1 ++#define RTL8367C_GATE_LPTD_BYPASS_MASK 0x2 ++#define RTL8367C_LED_SPD_MODE_OFFSET 0 ++#define RTL8367C_LED_SPD_MODE_MASK 0x1 ++ ++#define RTL8367C_REG_LED_MODE 0x1b02 ++#define RTL8367C_DLINK_TIME_OFFSET 15 ++#define RTL8367C_DLINK_TIME_MASK 0x8000 ++#define RTL8367C_LED_BUZZ_DUTY_OFFSET 14 ++#define RTL8367C_LED_BUZZ_DUTY_MASK 0x4000 ++#define RTL8367C_BUZZER_RATE_OFFSET 12 ++#define RTL8367C_BUZZER_RATE_MASK 0x3000 ++#define RTL8367C_LOOP_DETECT_MODE_OFFSET 11 ++#define RTL8367C_LOOP_DETECT_MODE_MASK 0x800 ++#define RTL8367C_SEL_PWRON_TIME_OFFSET 9 ++#define RTL8367C_SEL_PWRON_TIME_MASK 0x600 ++#define RTL8367C_EN_DLINK_LED_OFFSET 8 ++#define RTL8367C_EN_DLINK_LED_MASK 0x100 ++#define RTL8367C_LOOP_DETECT_RATE_OFFSET 6 ++#define RTL8367C_LOOP_DETECT_RATE_MASK 0xC0 ++#define RTL8367C_FORCE_RATE_OFFSET 4 ++#define RTL8367C_FORCE_RATE_MASK 0x30 ++#define RTL8367C_SEL_LEDRATE_OFFSET 1 ++#define RTL8367C_SEL_LEDRATE_MASK 0xE ++#define RTL8367C_SPEED_UP_OFFSET 0 ++#define RTL8367C_SPEED_UP_MASK 0x1 ++ ++#define RTL8367C_REG_LED_CONFIGURATION 0x1b03 ++#define RTL8367C_LED_CONFIGURATION_DUMMY_OFFSET 15 ++#define RTL8367C_LED_CONFIGURATION_DUMMY_MASK 0x8000 ++#define RTL8367C_LED_CONFIG_SEL_OFFSET 14 ++#define RTL8367C_LED_CONFIG_SEL_MASK 0x4000 ++#define RTL8367C_DATA_LED_OFFSET 12 ++#define RTL8367C_DATA_LED_MASK 0x3000 ++#define RTL8367C_LED2_CFG_OFFSET 8 ++#define RTL8367C_LED2_CFG_MASK 0xF00 ++#define RTL8367C_LED1_CFG_OFFSET 4 ++#define RTL8367C_LED1_CFG_MASK 0xF0 ++#define RTL8367C_LED0_CFG_OFFSET 0 ++#define RTL8367C_LED0_CFG_MASK 0xF ++ ++#define RTL8367C_REG_RTCT_RESULTS_CFG 0x1b04 ++#define RTL8367C_RTCT_2PAIR_FTT_OFFSET 15 ++#define RTL8367C_RTCT_2PAIR_FTT_MASK 0x8000 ++#define RTL8367C_RTCT_2PAIR_MODE_OFFSET 14 ++#define RTL8367C_RTCT_2PAIR_MODE_MASK 0x4000 ++#define RTL8367C_BLINK_EN_OFFSET 13 ++#define RTL8367C_BLINK_EN_MASK 0x2000 ++#define RTL8367C_TIMEOUT_OFFSET 12 ++#define RTL8367C_TIMEOUT_MASK 0x1000 ++#define RTL8367C_EN_CD_SAME_SHORT_OFFSET 11 ++#define RTL8367C_EN_CD_SAME_SHORT_MASK 0x800 ++#define RTL8367C_EN_CD_SAME_OPEN_OFFSET 10 ++#define RTL8367C_EN_CD_SAME_OPEN_MASK 0x400 ++#define RTL8367C_EN_CD_SAME_LINEDRIVER_OFFSET 9 ++#define RTL8367C_EN_CD_SAME_LINEDRIVER_MASK 0x200 ++#define RTL8367C_EN_CD_SAME_MISMATCH_OFFSET 8 ++#define RTL8367C_EN_CD_SAME_MISMATCH_MASK 0x100 ++#define RTL8367C_EN_CD_SHORT_OFFSET 7 ++#define RTL8367C_EN_CD_SHORT_MASK 0x80 ++#define RTL8367C_EN_AB_SHORT_OFFSET 6 ++#define RTL8367C_EN_AB_SHORT_MASK 0x40 ++#define RTL8367C_EN_CD_OPEN_OFFSET 5 ++#define RTL8367C_EN_CD_OPEN_MASK 0x20 ++#define RTL8367C_EN_AB_OPEN_OFFSET 4 ++#define RTL8367C_EN_AB_OPEN_MASK 0x10 ++#define RTL8367C_EN_CD_MISMATCH_OFFSET 3 ++#define RTL8367C_EN_CD_MISMATCH_MASK 0x8 ++#define RTL8367C_EN_AB_MISMATCH_OFFSET 2 ++#define RTL8367C_EN_AB_MISMATCH_MASK 0x4 ++#define RTL8367C_EN_CD_LINEDRIVER_OFFSET 1 ++#define RTL8367C_EN_CD_LINEDRIVER_MASK 0x2 ++#define RTL8367C_EN_AB_LINEDRIVER_OFFSET 0 ++#define RTL8367C_EN_AB_LINEDRIVER_MASK 0x1 ++ ++#define RTL8367C_REG_RTCT_LED 0x1b05 ++#define RTL8367C_DUMMY_1b05a_OFFSET 12 ++#define RTL8367C_DUMMY_1b05a_MASK 0xF000 ++#define RTL8367C_RTCT_LED2_OFFSET 8 ++#define RTL8367C_RTCT_LED2_MASK 0xF00 ++#define RTL8367C_RTCT_LED1_OFFSET 4 ++#define RTL8367C_RTCT_LED1_MASK 0xF0 ++#define RTL8367C_RTCT_LED0_OFFSET 0 ++#define RTL8367C_RTCT_LED0_MASK 0xF ++ ++#define RTL8367C_REG_CPU_FORCE_LED_CFG 0x1b07 ++#define RTL8367C_DUMMY_1b07a_OFFSET 8 ++#define RTL8367C_DUMMY_1b07a_MASK 0xFF00 ++#define RTL8367C_LED_FORCE_MODE_OFFSET 2 ++#define RTL8367C_LED_FORCE_MODE_MASK 0xFC ++#define RTL8367C_FORCE_MODE_OFFSET 0 ++#define RTL8367C_FORCE_MODE_MASK 0x3 ++ ++#define RTL8367C_REG_CPU_FORCE_LED0_CFG0 0x1b08 ++#define RTL8367C_PORT7_LED0_MODE_OFFSET 14 ++#define RTL8367C_PORT7_LED0_MODE_MASK 0xC000 ++#define RTL8367C_PORT6_LED0_MODE_OFFSET 12 ++#define RTL8367C_PORT6_LED0_MODE_MASK 0x3000 ++#define RTL8367C_PORT5_LED0_MODE_OFFSET 10 ++#define RTL8367C_PORT5_LED0_MODE_MASK 0xC00 ++#define RTL8367C_PORT4_LED0_MODE_OFFSET 8 ++#define RTL8367C_PORT4_LED0_MODE_MASK 0x300 ++#define RTL8367C_PORT3_LED0_MODE_OFFSET 6 ++#define RTL8367C_PORT3_LED0_MODE_MASK 0xC0 ++#define RTL8367C_PORT2_LED0_MODE_OFFSET 4 ++#define RTL8367C_PORT2_LED0_MODE_MASK 0x30 ++#define RTL8367C_PORT1_LED0_MODE_OFFSET 2 ++#define RTL8367C_PORT1_LED0_MODE_MASK 0xC ++#define RTL8367C_PORT0_LED0_MODE_OFFSET 0 ++#define RTL8367C_PORT0_LED0_MODE_MASK 0x3 ++ ++#define RTL8367C_REG_CPU_FORCE_LED0_CFG1 0x1b09 ++#define RTL8367C_DUMMY_1b09a_OFFSET 4 ++#define RTL8367C_DUMMY_1b09a_MASK 0xFFF0 ++#define RTL8367C_PORT9_LED0_MODE_OFFSET 2 ++#define RTL8367C_PORT9_LED0_MODE_MASK 0xC ++#define RTL8367C_PORT8_LED0_MODE_OFFSET 0 ++#define RTL8367C_PORT8_LED0_MODE_MASK 0x3 ++ ++#define RTL8367C_REG_CPU_FORCE_LED1_CFG0 0x1b0a ++#define RTL8367C_PORT7_LED1_MODE_OFFSET 14 ++#define RTL8367C_PORT7_LED1_MODE_MASK 0xC000 ++#define RTL8367C_PORT6_LED1_MODE_OFFSET 12 ++#define RTL8367C_PORT6_LED1_MODE_MASK 0x3000 ++#define RTL8367C_PORT5_LED1_MODE_OFFSET 10 ++#define RTL8367C_PORT5_LED1_MODE_MASK 0xC00 ++#define RTL8367C_PORT4_LED1_MODE_OFFSET 8 ++#define RTL8367C_PORT4_LED1_MODE_MASK 0x300 ++#define RTL8367C_PORT3_LED1_MODE_OFFSET 6 ++#define RTL8367C_PORT3_LED1_MODE_MASK 0xC0 ++#define RTL8367C_PORT2_LED1_MODE_OFFSET 4 ++#define RTL8367C_PORT2_LED1_MODE_MASK 0x30 ++#define RTL8367C_PORT1_LED1_MODE_OFFSET 2 ++#define RTL8367C_PORT1_LED1_MODE_MASK 0xC ++#define RTL8367C_PORT0_LED1_MODE_OFFSET 0 ++#define RTL8367C_PORT0_LED1_MODE_MASK 0x3 ++ ++#define RTL8367C_REG_CPU_FORCE_LED1_CFG1 0x1b0b ++#define RTL8367C_DUMMY_1b0ba_OFFSET 4 ++#define RTL8367C_DUMMY_1b0ba_MASK 0xFFF0 ++#define RTL8367C_PORT9_LED1_MODE_OFFSET 2 ++#define RTL8367C_PORT9_LED1_MODE_MASK 0xC ++#define RTL8367C_PORT8_LED1_MODE_OFFSET 0 ++#define RTL8367C_PORT8_LED1_MODE_MASK 0x3 ++ ++#define RTL8367C_REG_CPU_FORCE_LED2_CFG0 0x1b0c ++#define RTL8367C_PORT7_LED2_MODE_OFFSET 14 ++#define RTL8367C_PORT7_LED2_MODE_MASK 0xC000 ++#define RTL8367C_PORT6_LED2_MODE_OFFSET 12 ++#define RTL8367C_PORT6_LED2_MODE_MASK 0x3000 ++#define RTL8367C_PORT5_LED2_MODE_OFFSET 10 ++#define RTL8367C_PORT5_LED2_MODE_MASK 0xC00 ++#define RTL8367C_PORT4_LED2_MODE_OFFSET 8 ++#define RTL8367C_PORT4_LED2_MODE_MASK 0x300 ++#define RTL8367C_PORT3_LED2_MODE_OFFSET 6 ++#define RTL8367C_PORT3_LED2_MODE_MASK 0xC0 ++#define RTL8367C_PORT2_LED2_MODE_OFFSET 4 ++#define RTL8367C_PORT2_LED2_MODE_MASK 0x30 ++#define RTL8367C_PORT1_LED2_MODE_OFFSET 2 ++#define RTL8367C_PORT1_LED2_MODE_MASK 0xC ++#define RTL8367C_PORT0_LED2_MODE_OFFSET 0 ++#define RTL8367C_PORT0_LED2_MODE_MASK 0x3 ++ ++#define RTL8367C_REG_CPU_FORCE_LED2_CFG1 0x1b0d ++#define RTL8367C_DUMMY_1b0da_OFFSET 4 ++#define RTL8367C_DUMMY_1b0da_MASK 0xFFF0 ++#define RTL8367C_PORT9_LED2_MODE_OFFSET 2 ++#define RTL8367C_PORT9_LED2_MODE_MASK 0xC ++#define RTL8367C_PORT8_LED2_MODE_OFFSET 0 ++#define RTL8367C_PORT8_LED2_MODE_MASK 0x3 ++ ++#define RTL8367C_REG_LED_ACTIVE_LOW_CFG0 0x1b0e ++#define RTL8367C_LED_ACTIVE_LOW_CFG0_DUMMY_15_OFFSET 15 ++#define RTL8367C_LED_ACTIVE_LOW_CFG0_DUMMY_15_MASK 0x8000 ++#define RTL8367C_PORT3_LED_ACTIVE_LOW_OFFSET 12 ++#define RTL8367C_PORT3_LED_ACTIVE_LOW_MASK 0x7000 ++#define RTL8367C_LED_ACTIVE_LOW_CFG0_DUMMY_11_OFFSET 11 ++#define RTL8367C_LED_ACTIVE_LOW_CFG0_DUMMY_11_MASK 0x800 ++#define RTL8367C_PORT2_LED_ACTIVE_LOW_OFFSET 8 ++#define RTL8367C_PORT2_LED_ACTIVE_LOW_MASK 0x700 ++#define RTL8367C_DUMMY_7_OFFSET 7 ++#define RTL8367C_DUMMY_7_MASK 0x80 ++#define RTL8367C_PORT1_LED_ACTIVE_LOW_OFFSET 4 ++#define RTL8367C_PORT1_LED_ACTIVE_LOW_MASK 0x70 ++#define RTL8367C_DUMMY_3_OFFSET 3 ++#define RTL8367C_DUMMY_3_MASK 0x8 ++#define RTL8367C_PORT0_LED_ACTIVE_LOW_OFFSET 0 ++#define RTL8367C_PORT0_LED_ACTIVE_LOW_MASK 0x7 ++ ++#define RTL8367C_REG_LED_ACTIVE_LOW_CFG1 0x1b0f ++#define RTL8367C_LED_ACTIVE_LOW_CFG1_DUMMY_15_OFFSET 15 ++#define RTL8367C_LED_ACTIVE_LOW_CFG1_DUMMY_15_MASK 0x8000 ++#define RTL8367C_PORT7_LED_ACTIVE_LOW_OFFSET 12 ++#define RTL8367C_PORT7_LED_ACTIVE_LOW_MASK 0x7000 ++#define RTL8367C_LED_ACTIVE_LOW_CFG1_DUMMY_11_OFFSET 11 ++#define RTL8367C_LED_ACTIVE_LOW_CFG1_DUMMY_11_MASK 0x800 ++#define RTL8367C_PORT6_LED_ACTIVE_LOW_OFFSET 8 ++#define RTL8367C_PORT6_LED_ACTIVE_LOW_MASK 0x700 ++#define RTL8367C_DUMMY_1b0f_b_OFFSET 7 ++#define RTL8367C_DUMMY_1b0f_b_MASK 0x80 ++#define RTL8367C_PORT5_LED_ACTIVE_LOW_OFFSET 4 ++#define RTL8367C_PORT5_LED_ACTIVE_LOW_MASK 0x70 ++#define RTL8367C_DUMMY_1b0f_a_OFFSET 3 ++#define RTL8367C_DUMMY_1b0f_a_MASK 0x8 ++#define RTL8367C_PORT4_LED_ACTIVE_LOW_OFFSET 0 ++#define RTL8367C_PORT4_LED_ACTIVE_LOW_MASK 0x7 ++ ++#define RTL8367C_REG_LED_ACTIVE_LOW_CFG2 0x1b10 ++#define RTL8367C_DUMMY_1b10_b_OFFSET 7 ++#define RTL8367C_DUMMY_1b10_b_MASK 0xFF80 ++#define RTL8367C_PORT9_LED_ACTIVE_LOW_OFFSET 4 ++#define RTL8367C_PORT9_LED_ACTIVE_LOW_MASK 0x70 ++#define RTL8367C_DUMMY_1b10_a_OFFSET 3 ++#define RTL8367C_DUMMY_1b10_a_MASK 0x8 ++#define RTL8367C_PORT8_LED_ACTIVE_LOW_OFFSET 0 ++#define RTL8367C_PORT8_LED_ACTIVE_LOW_MASK 0x7 ++ ++#define RTL8367C_REG_SEL_RTCT_PARA 0x1b21 ++#define RTL8367C_DO_RTCT_COMMAND_OFFSET 15 ++#define RTL8367C_DO_RTCT_COMMAND_MASK 0x8000 ++#define RTL8367C_SEL_RTCT_PARA_DUMMY_OFFSET 12 ++#define RTL8367C_SEL_RTCT_PARA_DUMMY_MASK 0x7000 ++#define RTL8367C_SEL_RTCT_RLSTLED_TIME_OFFSET 10 ++#define RTL8367C_SEL_RTCT_RLSTLED_TIME_MASK 0xC00 ++#define RTL8367C_SEL_RTCT_TEST_LED_TIME_OFFSET 8 ++#define RTL8367C_SEL_RTCT_TEST_LED_TIME_MASK 0x300 ++#define RTL8367C_EN_SCAN_RTCT_OFFSET 7 ++#define RTL8367C_EN_SCAN_RTCT_MASK 0x80 ++#define RTL8367C_EN_RTCT_TIMOUT_OFFSET 6 ++#define RTL8367C_EN_RTCT_TIMOUT_MASK 0x40 ++#define RTL8367C_EN_ALL_RTCT_OFFSET 5 ++#define RTL8367C_EN_ALL_RTCT_MASK 0x20 ++#define RTL8367C_SEL_RTCT_PLE_WID_OFFSET 0 ++#define RTL8367C_SEL_RTCT_PLE_WID_MASK 0x1F ++ ++#define RTL8367C_REG_RTCT_ENABLE 0x1b22 ++#define RTL8367C_RTCT_ENABLE_DUMMY_OFFSET 8 ++#define RTL8367C_RTCT_ENABLE_DUMMY_MASK 0xFF00 ++#define RTL8367C_RTCT_ENABLE_PORT_MASK_OFFSET 0 ++#define RTL8367C_RTCT_ENABLE_PORT_MASK_MASK 0xFF ++ ++#define RTL8367C_REG_RTCT_TIMEOUT 0x1b23 ++ ++#define RTL8367C_REG_PARA_LED_IO_EN1 0x1b24 ++#define RTL8367C_LED1_PARA_P07_00_OFFSET 8 ++#define RTL8367C_LED1_PARA_P07_00_MASK 0xFF00 ++#define RTL8367C_LED0_PARA_P07_00_OFFSET 0 ++#define RTL8367C_LED0_PARA_P07_00_MASK 0xFF ++ ++#define RTL8367C_REG_PARA_LED_IO_EN2 0x1b25 ++#define RTL8367C_DUMMY_15_8_OFFSET 8 ++#define RTL8367C_DUMMY_15_8_MASK 0xFF00 ++#define RTL8367C_LED2_PARA_P07_00_OFFSET 0 ++#define RTL8367C_LED2_PARA_P07_00_MASK 0xFF ++ ++#define RTL8367C_REG_SCAN0_LED_IO_EN1 0x1b26 ++#define RTL8367C_SCAN0_LED_IO_EN1_DUMMY_OFFSET 3 ++#define RTL8367C_SCAN0_LED_IO_EN1_DUMMY_MASK 0xFFF8 ++#define RTL8367C_LED_LOOP_DET_BUZZER_EN_OFFSET 2 ++#define RTL8367C_LED_LOOP_DET_BUZZER_EN_MASK 0x4 ++#define RTL8367C_LED_SERI_DATA_EN_OFFSET 1 ++#define RTL8367C_LED_SERI_DATA_EN_MASK 0x2 ++#define RTL8367C_LED_SERI_CLK_EN_OFFSET 0 ++#define RTL8367C_LED_SERI_CLK_EN_MASK 0x1 ++ ++#define RTL8367C_REG_SCAN1_LED_IO_EN2 0x1b27 ++#define RTL8367C_LED_SCAN1_BI_PORT_EN_OFFSET 8 ++#define RTL8367C_LED_SCAN1_BI_PORT_EN_MASK 0xFF00 ++#define RTL8367C_LED_SCAN1_BI_STA_EN_OFFSET 7 ++#define RTL8367C_LED_SCAN1_BI_STA_EN_MASK 0x80 ++#define RTL8367C_SCAN1_LED_IO_EN2_DUMMY_0_OFFSET 6 ++#define RTL8367C_SCAN1_LED_IO_EN2_DUMMY_0_MASK 0x40 ++#define RTL8367C_LED_SCAN1_SI_PORT_EN_OFFSET 2 ++#define RTL8367C_LED_SCAN1_SI_PORT_EN_MASK 0x3C ++#define RTL8367C_LED_SCAN1_SI_STA_EN_OFFSET 0 ++#define RTL8367C_LED_SCAN1_SI_STA_EN_MASK 0x3 ++ ++#define RTL8367C_REG_LPI_LED_OPT1 0x1b28 ++#define RTL8367C_LPI_TAG4_OFFSET 12 ++#define RTL8367C_LPI_TAG4_MASK 0xF000 ++#define RTL8367C_LPI_TAG3_OFFSET 8 ++#define RTL8367C_LPI_TAG3_MASK 0xF00 ++#define RTL8367C_LPI_TAG2_OFFSET 4 ++#define RTL8367C_LPI_TAG2_MASK 0xF0 ++#define RTL8367C_LPI_TAG1_OFFSET 0 ++#define RTL8367C_LPI_TAG1_MASK 0xF ++ ++#define RTL8367C_REG_LPI_LED_OPT2 0x1b29 ++#define RTL8367C_LPI_LED_OPT2_DUMMY_OFFSET 15 ++#define RTL8367C_LPI_LED_OPT2_DUMMY_MASK 0x8000 ++#define RTL8367C_LPI_LED2_WEAK_OFFSET 14 ++#define RTL8367C_LPI_LED2_WEAK_MASK 0x4000 ++#define RTL8367C_LPI_LED1_WEAK_OFFSET 13 ++#define RTL8367C_LPI_LED1_WEAK_MASK 0x2000 ++#define RTL8367C_LPI_LED0_WEAK_OFFSET 12 ++#define RTL8367C_LPI_LED0_WEAK_MASK 0x1000 ++#define RTL8367C_LPI_LED2_OFFSET 11 ++#define RTL8367C_LPI_LED2_MASK 0x800 ++#define RTL8367C_LPI_LED1_OFFSET 10 ++#define RTL8367C_LPI_LED1_MASK 0x400 ++#define RTL8367C_LPI_LED0_OFFSET 9 ++#define RTL8367C_LPI_LED0_MASK 0x200 ++#define RTL8367C_LPI_TAG8_OFFSET 8 ++#define RTL8367C_LPI_TAG8_MASK 0x100 ++#define RTL8367C_LPI_TAG7_OFFSET 6 ++#define RTL8367C_LPI_TAG7_MASK 0xC0 ++#define RTL8367C_LPI_TAG6_OFFSET 4 ++#define RTL8367C_LPI_TAG6_MASK 0x30 ++#define RTL8367C_LPI_TAG5_OFFSET 0 ++#define RTL8367C_LPI_TAG5_MASK 0xF ++ ++#define RTL8367C_REG_LPI_LED_OPT3 0x1b2a ++#define RTL8367C_LPI_LED_OPT3_DUMMY_OFFSET 3 ++#define RTL8367C_LPI_LED_OPT3_DUMMY_MASK 0xFFF8 ++#define RTL8367C_RESTORE_LED_RATE_SEL_OFFSET 1 ++#define RTL8367C_RESTORE_LED_RATE_SEL_MASK 0x6 ++#define RTL8367C_RESTORE_LED_SEL_OFFSET 0 ++#define RTL8367C_RESTORE_LED_SEL_MASK 0x1 ++ ++#define RTL8367C_REG_P0_LED_MUX 0x1b2b ++#define RTL8367C_CFG_P0_LED2_MUX_OFFSET 10 ++#define RTL8367C_CFG_P0_LED2_MUX_MASK 0x7C00 ++#define RTL8367C_CFG_P0_LED1_MUX_OFFSET 5 ++#define RTL8367C_CFG_P0_LED1_MUX_MASK 0x3E0 ++#define RTL8367C_CFG_P0_LED0_MUX_OFFSET 0 ++#define RTL8367C_CFG_P0_LED0_MUX_MASK 0x1F ++ ++#define RTL8367C_REG_P1_LED_MUX 0x1b2c ++#define RTL8367C_CFG_P1_LED2_MUX_OFFSET 10 ++#define RTL8367C_CFG_P1_LED2_MUX_MASK 0x7C00 ++#define RTL8367C_CFG_P1_LED1_MUX_OFFSET 5 ++#define RTL8367C_CFG_P1_LED1_MUX_MASK 0x3E0 ++#define RTL8367C_CFG_P1_LED0_MUX_OFFSET 0 ++#define RTL8367C_CFG_P1_LED0_MUX_MASK 0x1F ++ ++#define RTL8367C_REG_P2_LED_MUX 0x1b2d ++#define RTL8367C_CFG_P2_LED2_MUX_OFFSET 10 ++#define RTL8367C_CFG_P2_LED2_MUX_MASK 0x7C00 ++#define RTL8367C_CFG_P2_LED1_MUX_OFFSET 5 ++#define RTL8367C_CFG_P2_LED1_MUX_MASK 0x3E0 ++#define RTL8367C_CFG_P2_LED0_MUX_OFFSET 0 ++#define RTL8367C_CFG_P2_LED0_MUX_MASK 0x1F ++ ++#define RTL8367C_REG_P3_LED_MUX 0x1b2e ++#define RTL8367C_CFG_P3_LED2_MUX_OFFSET 10 ++#define RTL8367C_CFG_P3_LED2_MUX_MASK 0x7C00 ++#define RTL8367C_CFG_P3_LED1_MUX_OFFSET 5 ++#define RTL8367C_CFG_P3_LED1_MUX_MASK 0x3E0 ++#define RTL8367C_CFG_P3_LED0_MUX_OFFSET 0 ++#define RTL8367C_CFG_P3_LED0_MUX_MASK 0x1F ++ ++#define RTL8367C_REG_P4_LED_MUX 0x1b2f ++#define RTL8367C_CFG_P4_LED2_MUX_OFFSET 10 ++#define RTL8367C_CFG_P4_LED2_MUX_MASK 0x7C00 ++#define RTL8367C_CFG_P4_LED1_MUX_OFFSET 5 ++#define RTL8367C_CFG_P4_LED1_MUX_MASK 0x3E0 ++#define RTL8367C_CFG_P4_LED0_MUX_OFFSET 0 ++#define RTL8367C_CFG_P4_LED0_MUX_MASK 0x1F ++ ++#define RTL8367C_REG_LED0_DATA_CTRL 0x1b30 ++#define RTL8367C_CFG_DATA_LED0_SEL_OFFSET 6 ++#define RTL8367C_CFG_DATA_LED0_SEL_MASK 0x40 ++#define RTL8367C_CFG_DATA_LED0_ACT_OFFSET 4 ++#define RTL8367C_CFG_DATA_LED0_ACT_MASK 0x30 ++#define RTL8367C_CFG_DATA_LED0_SPD_OFFSET 0 ++#define RTL8367C_CFG_DATA_LED0_SPD_MASK 0xF ++ ++#define RTL8367C_REG_LED1_DATA_CTRL 0x1b31 ++#define RTL8367C_CFG_DATA_LED1_SEL_OFFSET 6 ++#define RTL8367C_CFG_DATA_LED1_SEL_MASK 0x40 ++#define RTL8367C_CFG_DATA_LED1_ACT_OFFSET 4 ++#define RTL8367C_CFG_DATA_LED1_ACT_MASK 0x30 ++#define RTL8367C_CFG_DATA_LED1_SPD_OFFSET 0 ++#define RTL8367C_CFG_DATA_LED1_SPD_MASK 0xF ++ ++#define RTL8367C_REG_LED2_DATA_CTRL 0x1b32 ++#define RTL8367C_CFG_DATA_LED2_SEL_OFFSET 6 ++#define RTL8367C_CFG_DATA_LED2_SEL_MASK 0x40 ++#define RTL8367C_CFG_DATA_LED2_ACT_OFFSET 4 ++#define RTL8367C_CFG_DATA_LED2_ACT_MASK 0x30 ++#define RTL8367C_CFG_DATA_LED2_SPD_OFFSET 0 ++#define RTL8367C_CFG_DATA_LED2_SPD_MASK 0xF ++ ++#define RTL8367C_REG_PARA_LED_IO_EN3 0x1b33 ++#define RTL8367C_dummy_1b33a_OFFSET 6 ++#define RTL8367C_dummy_1b33a_MASK 0xFFC0 ++#define RTL8367C_LED2_PARA_P09_08_OFFSET 4 ++#define RTL8367C_LED2_PARA_P09_08_MASK 0x30 ++#define RTL8367C_LED1_PARA_P09_08_OFFSET 2 ++#define RTL8367C_LED1_PARA_P09_08_MASK 0xC ++#define RTL8367C_LED0_PARA_P09_08_OFFSET 0 ++#define RTL8367C_LED0_PARA_P09_08_MASK 0x3 ++ ++#define RTL8367C_REG_SCAN1_LED_IO_EN3 0x1b34 ++#define RTL8367C_dummy_1b34a_OFFSET 3 ++#define RTL8367C_dummy_1b34a_MASK 0xFFF8 ++#define RTL8367C_LED_SCAN1_BI_PORT9_8_EN_OFFSET 1 ++#define RTL8367C_LED_SCAN1_BI_PORT9_8_EN_MASK 0x6 ++#define RTL8367C_LED_SCAN1_SI_PORT9_8_EN_OFFSET 0 ++#define RTL8367C_LED_SCAN1_SI_PORT9_8_EN_MASK 0x1 ++ ++#define RTL8367C_REG_P5_LED_MUX 0x1b35 ++#define RTL8367C_CFG_P5_LED2_MUX_OFFSET 10 ++#define RTL8367C_CFG_P5_LED2_MUX_MASK 0x7C00 ++#define RTL8367C_CFG_P5_LED1_MUX_OFFSET 5 ++#define RTL8367C_CFG_P5_LED1_MUX_MASK 0x3E0 ++#define RTL8367C_CFG_P5_LED0_MUX_OFFSET 0 ++#define RTL8367C_CFG_P5_LED0_MUX_MASK 0x1F ++ ++#define RTL8367C_REG_P6_LED_MUX 0x1b36 ++#define RTL8367C_CFG_P6_LED2_MUX_OFFSET 10 ++#define RTL8367C_CFG_P6_LED2_MUX_MASK 0x7C00 ++#define RTL8367C_CFG_P6_LED1_MUX_OFFSET 5 ++#define RTL8367C_CFG_P6_LED1_MUX_MASK 0x3E0 ++#define RTL8367C_CFG_P6_LED0_MUX_OFFSET 0 ++#define RTL8367C_CFG_P6_LED0_MUX_MASK 0x1F ++ ++#define RTL8367C_REG_P7_LED_MUX 0x1b37 ++#define RTL8367C_CFG_P7_LED2_MUX_OFFSET 10 ++#define RTL8367C_CFG_P7_LED2_MUX_MASK 0x7C00 ++#define RTL8367C_CFG_P7_LED1_MUX_OFFSET 5 ++#define RTL8367C_CFG_P7_LED1_MUX_MASK 0x3E0 ++#define RTL8367C_CFG_P7_LED0_MUX_OFFSET 0 ++#define RTL8367C_CFG_P7_LED0_MUX_MASK 0x1F ++ ++#define RTL8367C_REG_P8_LED_MUX 0x1b38 ++#define RTL8367C_CFG_P8_LED2_MUX_OFFSET 10 ++#define RTL8367C_CFG_P8_LED2_MUX_MASK 0x7C00 ++#define RTL8367C_CFG_P8_LED1_MUX_OFFSET 5 ++#define RTL8367C_CFG_P8_LED1_MUX_MASK 0x3E0 ++#define RTL8367C_CFG_P8_LED0_MUX_OFFSET 0 ++#define RTL8367C_CFG_P8_LED0_MUX_MASK 0x1F ++ ++#define RTL8367C_REG_P9_LED_MUX 0x1b39 ++#define RTL8367C_CFG_P9_LED2_MUX_OFFSET 10 ++#define RTL8367C_CFG_P9_LED2_MUX_MASK 0x7C00 ++#define RTL8367C_CFG_P9_LED1_MUX_OFFSET 5 ++#define RTL8367C_CFG_P9_LED1_MUX_MASK 0x3E0 ++#define RTL8367C_CFG_P9_LED0_MUX_OFFSET 0 ++#define RTL8367C_CFG_P9_LED0_MUX_MASK 0x1F ++ ++#define RTL8367C_REG_SERIAL_LED_CTRL 0x1b3a ++#define RTL8367C_SERIAL_LED_SHIFT_SEQUENCE_OFFSET 13 ++#define RTL8367C_SERIAL_LED_SHIFT_SEQUENCE_MASK 0x6000 ++#define RTL8367C_SERIAL_LED_SHIFT_SEQUENCE_EN_OFFSET 12 ++#define RTL8367C_SERIAL_LED_SHIFT_SEQUENCE_EN_MASK 0x1000 ++#define RTL8367C_SERIAL_LED_GROUP_NUM_OFFSET 10 ++#define RTL8367C_SERIAL_LED_GROUP_NUM_MASK 0xC00 ++#define RTL8367C_SERIAL_LED_PORT_EN_OFFSET 0 ++#define RTL8367C_SERIAL_LED_PORT_EN_MASK 0x3FF ++ ++/* (16'h1c00)IGMP_EAV */ ++ ++#define RTL8367C_REG_IGMP_MLD_CFG0 0x1c00 ++#define RTL8367C_IGMP_MLD_PORTISO_LEAKY_OFFSET 15 ++#define RTL8367C_IGMP_MLD_PORTISO_LEAKY_MASK 0x8000 ++#define RTL8367C_IGMP_MLD_VLAN_LEAKY_OFFSET 14 ++#define RTL8367C_IGMP_MLD_VLAN_LEAKY_MASK 0x4000 ++#define RTL8367C_IGMP_MLD_DISCARD_STORM_FILTER_OFFSET 13 ++#define RTL8367C_IGMP_MLD_DISCARD_STORM_FILTER_MASK 0x2000 ++#define RTL8367C_REPORT_FORWARD_OFFSET 12 ++#define RTL8367C_REPORT_FORWARD_MASK 0x1000 ++#define RTL8367C_ROBUSTNESS_VAR_OFFSET 9 ++#define RTL8367C_ROBUSTNESS_VAR_MASK 0xE00 ++#define RTL8367C_LEAVE_SUPPRESSION_OFFSET 8 ++#define RTL8367C_LEAVE_SUPPRESSION_MASK 0x100 ++#define RTL8367C_REPORT_SUPPRESSION_OFFSET 7 ++#define RTL8367C_REPORT_SUPPRESSION_MASK 0x80 ++#define RTL8367C_LEAVE_TIMER_OFFSET 4 ++#define RTL8367C_LEAVE_TIMER_MASK 0x70 ++#define RTL8367C_FAST_LEAVE_EN_OFFSET 3 ++#define RTL8367C_FAST_LEAVE_EN_MASK 0x8 ++#define RTL8367C_CKS_ERR_OP_OFFSET 1 ++#define RTL8367C_CKS_ERR_OP_MASK 0x6 ++#define RTL8367C_IGMP_MLD_EN_OFFSET 0 ++#define RTL8367C_IGMP_MLD_EN_MASK 0x1 ++ ++#define RTL8367C_REG_IGMP_MLD_CFG1 0x1c01 ++#define RTL8367C_DROP_LEAVE_ZERO_OFFSET 2 ++#define RTL8367C_DROP_LEAVE_ZERO_MASK 0x4 ++#define RTL8367C_TABLE_FULL_OP_OFFSET 0 ++#define RTL8367C_TABLE_FULL_OP_MASK 0x3 ++ ++#define RTL8367C_REG_IGMP_MLD_CFG2 0x1c02 ++ ++#define RTL8367C_REG_IGMP_DYNAMIC_ROUTER_PORT 0x1c03 ++#define RTL8367C_D_ROUTER_PORT_2_OFFSET 11 ++#define RTL8367C_D_ROUTER_PORT_2_MASK 0x7800 ++#define RTL8367C_D_ROUTER_PORT_TMR_2_OFFSET 8 ++#define RTL8367C_D_ROUTER_PORT_TMR_2_MASK 0x700 ++#define RTL8367C_D_ROUTER_PORT_1_OFFSET 3 ++#define RTL8367C_D_ROUTER_PORT_1_MASK 0x78 ++#define RTL8367C_D_ROUTER_PORT_TMR_1_OFFSET 0 ++#define RTL8367C_D_ROUTER_PORT_TMR_1_MASK 0x7 ++ ++#define RTL8367C_REG_IGMP_STATIC_ROUTER_PORT 0x1c04 ++#define RTL8367C_IGMP_STATIC_ROUTER_PORT_OFFSET 0 ++#define RTL8367C_IGMP_STATIC_ROUTER_PORT_MASK 0x7FF ++ ++#define RTL8367C_REG_IGMP_PORT0_CONTROL 0x1c05 ++#define RTL8367C_IGMP_PORT0_CONTROL_ALLOW_QUERY_OFFSET 14 ++#define RTL8367C_IGMP_PORT0_CONTROL_ALLOW_QUERY_MASK 0x4000 ++#define RTL8367C_IGMP_PORT0_CONTROL_ALLOW_REPORT_OFFSET 13 ++#define RTL8367C_IGMP_PORT0_CONTROL_ALLOW_REPORT_MASK 0x2000 ++#define RTL8367C_IGMP_PORT0_CONTROL_ALLOW_LEAVE_OFFSET 12 ++#define RTL8367C_IGMP_PORT0_CONTROL_ALLOW_LEAVE_MASK 0x1000 ++#define RTL8367C_IGMP_PORT0_CONTROL_ALLOW_MRP_OFFSET 11 ++#define RTL8367C_IGMP_PORT0_CONTROL_ALLOW_MRP_MASK 0x800 ++#define RTL8367C_IGMP_PORT0_CONTROL_ALLOW_MC_DATA_OFFSET 10 ++#define RTL8367C_IGMP_PORT0_CONTROL_ALLOW_MC_DATA_MASK 0x400 ++#define RTL8367C_IGMP_PORT0_CONTROL_MLDv2_OP_OFFSET 8 ++#define RTL8367C_IGMP_PORT0_CONTROL_MLDv2_OP_MASK 0x300 ++#define RTL8367C_IGMP_PORT0_CONTROL_MLDv1_OP_OFFSET 6 ++#define RTL8367C_IGMP_PORT0_CONTROL_MLDv1_OP_MASK 0xC0 ++#define RTL8367C_IGMP_PORT0_CONTROL_IGMPV3_OP_OFFSET 4 ++#define RTL8367C_IGMP_PORT0_CONTROL_IGMPV3_OP_MASK 0x30 ++#define RTL8367C_IGMP_PORT0_CONTROL_IGMPV2_OP_OFFSET 2 ++#define RTL8367C_IGMP_PORT0_CONTROL_IGMPV2_OP_MASK 0xC ++#define RTL8367C_IGMP_PORT0_CONTROL_IGMPV1_OP_OFFSET 0 ++#define RTL8367C_IGMP_PORT0_CONTROL_IGMPV1_OP_MASK 0x3 ++ ++#define RTL8367C_REG_IGMP_PORT1_CONTROL 0x1c06 ++#define RTL8367C_IGMP_PORT1_CONTROL_ALLOW_QUERY_OFFSET 14 ++#define RTL8367C_IGMP_PORT1_CONTROL_ALLOW_QUERY_MASK 0x4000 ++#define RTL8367C_IGMP_PORT1_CONTROL_ALLOW_REPORT_OFFSET 13 ++#define RTL8367C_IGMP_PORT1_CONTROL_ALLOW_REPORT_MASK 0x2000 ++#define RTL8367C_IGMP_PORT1_CONTROL_ALLOW_LEAVE_OFFSET 12 ++#define RTL8367C_IGMP_PORT1_CONTROL_ALLOW_LEAVE_MASK 0x1000 ++#define RTL8367C_IGMP_PORT1_CONTROL_ALLOW_MRP_OFFSET 11 ++#define RTL8367C_IGMP_PORT1_CONTROL_ALLOW_MRP_MASK 0x800 ++#define RTL8367C_IGMP_PORT1_CONTROL_ALLOW_MC_DATA_OFFSET 10 ++#define RTL8367C_IGMP_PORT1_CONTROL_ALLOW_MC_DATA_MASK 0x400 ++#define RTL8367C_IGMP_PORT1_CONTROL_MLDv2_OP_OFFSET 8 ++#define RTL8367C_IGMP_PORT1_CONTROL_MLDv2_OP_MASK 0x300 ++#define RTL8367C_IGMP_PORT1_CONTROL_MLDv1_OP_OFFSET 6 ++#define RTL8367C_IGMP_PORT1_CONTROL_MLDv1_OP_MASK 0xC0 ++#define RTL8367C_IGMP_PORT1_CONTROL_IGMPV3_OP_OFFSET 4 ++#define RTL8367C_IGMP_PORT1_CONTROL_IGMPV3_OP_MASK 0x30 ++#define RTL8367C_IGMP_PORT1_CONTROL_IGMPV2_OP_OFFSET 2 ++#define RTL8367C_IGMP_PORT1_CONTROL_IGMPV2_OP_MASK 0xC ++#define RTL8367C_IGMP_PORT1_CONTROL_IGMPV1_OP_OFFSET 0 ++#define RTL8367C_IGMP_PORT1_CONTROL_IGMPV1_OP_MASK 0x3 ++ ++#define RTL8367C_REG_IGMP_PORT2_CONTROL 0x1c07 ++#define RTL8367C_IGMP_PORT2_CONTROL_ALLOW_QUERY_OFFSET 14 ++#define RTL8367C_IGMP_PORT2_CONTROL_ALLOW_QUERY_MASK 0x4000 ++#define RTL8367C_IGMP_PORT2_CONTROL_ALLOW_REPORT_OFFSET 13 ++#define RTL8367C_IGMP_PORT2_CONTROL_ALLOW_REPORT_MASK 0x2000 ++#define RTL8367C_IGMP_PORT2_CONTROL_ALLOW_LEAVE_OFFSET 12 ++#define RTL8367C_IGMP_PORT2_CONTROL_ALLOW_LEAVE_MASK 0x1000 ++#define RTL8367C_IGMP_PORT2_CONTROL_ALLOW_MRP_OFFSET 11 ++#define RTL8367C_IGMP_PORT2_CONTROL_ALLOW_MRP_MASK 0x800 ++#define RTL8367C_IGMP_PORT2_CONTROL_ALLOW_MC_DATA_OFFSET 10 ++#define RTL8367C_IGMP_PORT2_CONTROL_ALLOW_MC_DATA_MASK 0x400 ++#define RTL8367C_IGMP_PORT2_CONTROL_MLDv2_OP_OFFSET 8 ++#define RTL8367C_IGMP_PORT2_CONTROL_MLDv2_OP_MASK 0x300 ++#define RTL8367C_IGMP_PORT2_CONTROL_MLDv1_OP_OFFSET 6 ++#define RTL8367C_IGMP_PORT2_CONTROL_MLDv1_OP_MASK 0xC0 ++#define RTL8367C_IGMP_PORT2_CONTROL_IGMPV3_OP_OFFSET 4 ++#define RTL8367C_IGMP_PORT2_CONTROL_IGMPV3_OP_MASK 0x30 ++#define RTL8367C_IGMP_PORT2_CONTROL_IGMPV2_OP_OFFSET 2 ++#define RTL8367C_IGMP_PORT2_CONTROL_IGMPV2_OP_MASK 0xC ++#define RTL8367C_IGMP_PORT2_CONTROL_IGMPV1_OP_OFFSET 0 ++#define RTL8367C_IGMP_PORT2_CONTROL_IGMPV1_OP_MASK 0x3 ++ ++#define RTL8367C_REG_IGMP_PORT3_CONTROL 0x1c08 ++#define RTL8367C_IGMP_PORT3_CONTROL_ALLOW_QUERY_OFFSET 14 ++#define RTL8367C_IGMP_PORT3_CONTROL_ALLOW_QUERY_MASK 0x4000 ++#define RTL8367C_IGMP_PORT3_CONTROL_ALLOW_REPORT_OFFSET 13 ++#define RTL8367C_IGMP_PORT3_CONTROL_ALLOW_REPORT_MASK 0x2000 ++#define RTL8367C_IGMP_PORT3_CONTROL_ALLOW_LEAVE_OFFSET 12 ++#define RTL8367C_IGMP_PORT3_CONTROL_ALLOW_LEAVE_MASK 0x1000 ++#define RTL8367C_IGMP_PORT3_CONTROL_ALLOW_MRP_OFFSET 11 ++#define RTL8367C_IGMP_PORT3_CONTROL_ALLOW_MRP_MASK 0x800 ++#define RTL8367C_IGMP_PORT3_CONTROL_ALLOW_MC_DATA_OFFSET 10 ++#define RTL8367C_IGMP_PORT3_CONTROL_ALLOW_MC_DATA_MASK 0x400 ++#define RTL8367C_IGMP_PORT3_CONTROL_MLDv2_OP_OFFSET 8 ++#define RTL8367C_IGMP_PORT3_CONTROL_MLDv2_OP_MASK 0x300 ++#define RTL8367C_IGMP_PORT3_CONTROL_MLDv1_OP_OFFSET 6 ++#define RTL8367C_IGMP_PORT3_CONTROL_MLDv1_OP_MASK 0xC0 ++#define RTL8367C_IGMP_PORT3_CONTROL_IGMPV3_OP_OFFSET 4 ++#define RTL8367C_IGMP_PORT3_CONTROL_IGMPV3_OP_MASK 0x30 ++#define RTL8367C_IGMP_PORT3_CONTROL_IGMPV2_OP_OFFSET 2 ++#define RTL8367C_IGMP_PORT3_CONTROL_IGMPV2_OP_MASK 0xC ++#define RTL8367C_IGMP_PORT3_CONTROL_IGMPV1_OP_OFFSET 0 ++#define RTL8367C_IGMP_PORT3_CONTROL_IGMPV1_OP_MASK 0x3 ++ ++#define RTL8367C_REG_IGMP_PORT4_CONTROL 0x1c09 ++#define RTL8367C_IGMP_PORT4_CONTROL_ALLOW_QUERY_OFFSET 14 ++#define RTL8367C_IGMP_PORT4_CONTROL_ALLOW_QUERY_MASK 0x4000 ++#define RTL8367C_IGMP_PORT4_CONTROL_ALLOW_REPORT_OFFSET 13 ++#define RTL8367C_IGMP_PORT4_CONTROL_ALLOW_REPORT_MASK 0x2000 ++#define RTL8367C_IGMP_PORT4_CONTROL_ALLOW_LEAVE_OFFSET 12 ++#define RTL8367C_IGMP_PORT4_CONTROL_ALLOW_LEAVE_MASK 0x1000 ++#define RTL8367C_IGMP_PORT4_CONTROL_ALLOW_MRP_OFFSET 11 ++#define RTL8367C_IGMP_PORT4_CONTROL_ALLOW_MRP_MASK 0x800 ++#define RTL8367C_IGMP_PORT4_CONTROL_ALLOW_MC_DATA_OFFSET 10 ++#define RTL8367C_IGMP_PORT4_CONTROL_ALLOW_MC_DATA_MASK 0x400 ++#define RTL8367C_IGMP_PORT4_CONTROL_MLDv2_OP_OFFSET 8 ++#define RTL8367C_IGMP_PORT4_CONTROL_MLDv2_OP_MASK 0x300 ++#define RTL8367C_IGMP_PORT4_CONTROL_MLDv1_OP_OFFSET 6 ++#define RTL8367C_IGMP_PORT4_CONTROL_MLDv1_OP_MASK 0xC0 ++#define RTL8367C_IGMP_PORT4_CONTROL_IGMPV3_OP_OFFSET 4 ++#define RTL8367C_IGMP_PORT4_CONTROL_IGMPV3_OP_MASK 0x30 ++#define RTL8367C_IGMP_PORT4_CONTROL_IGMPV2_OP_OFFSET 2 ++#define RTL8367C_IGMP_PORT4_CONTROL_IGMPV2_OP_MASK 0xC ++#define RTL8367C_IGMP_PORT4_CONTROL_IGMPV1_OP_OFFSET 0 ++#define RTL8367C_IGMP_PORT4_CONTROL_IGMPV1_OP_MASK 0x3 ++ ++#define RTL8367C_REG_IGMP_PORT5_CONTROL 0x1c0a ++#define RTL8367C_IGMP_PORT5_CONTROL_ALLOW_QUERY_OFFSET 14 ++#define RTL8367C_IGMP_PORT5_CONTROL_ALLOW_QUERY_MASK 0x4000 ++#define RTL8367C_IGMP_PORT5_CONTROL_ALLOW_REPORT_OFFSET 13 ++#define RTL8367C_IGMP_PORT5_CONTROL_ALLOW_REPORT_MASK 0x2000 ++#define RTL8367C_IGMP_PORT5_CONTROL_ALLOW_LEAVE_OFFSET 12 ++#define RTL8367C_IGMP_PORT5_CONTROL_ALLOW_LEAVE_MASK 0x1000 ++#define RTL8367C_IGMP_PORT5_CONTROL_ALLOW_MRP_OFFSET 11 ++#define RTL8367C_IGMP_PORT5_CONTROL_ALLOW_MRP_MASK 0x800 ++#define RTL8367C_IGMP_PORT5_CONTROL_ALLOW_MC_DATA_OFFSET 10 ++#define RTL8367C_IGMP_PORT5_CONTROL_ALLOW_MC_DATA_MASK 0x400 ++#define RTL8367C_IGMP_PORT5_CONTROL_MLDv2_OP_OFFSET 8 ++#define RTL8367C_IGMP_PORT5_CONTROL_MLDv2_OP_MASK 0x300 ++#define RTL8367C_IGMP_PORT5_CONTROL_MLDv1_OP_OFFSET 6 ++#define RTL8367C_IGMP_PORT5_CONTROL_MLDv1_OP_MASK 0xC0 ++#define RTL8367C_IGMP_PORT5_CONTROL_IGMPV3_OP_OFFSET 4 ++#define RTL8367C_IGMP_PORT5_CONTROL_IGMPV3_OP_MASK 0x30 ++#define RTL8367C_IGMP_PORT5_CONTROL_IGMPV2_OP_OFFSET 2 ++#define RTL8367C_IGMP_PORT5_CONTROL_IGMPV2_OP_MASK 0xC ++#define RTL8367C_IGMP_PORT5_CONTROL_IGMPV1_OP_OFFSET 0 ++#define RTL8367C_IGMP_PORT5_CONTROL_IGMPV1_OP_MASK 0x3 ++ ++#define RTL8367C_REG_IGMP_PORT6_CONTROL 0x1c0b ++#define RTL8367C_IGMP_PORT6_CONTROL_ALLOW_QUERY_OFFSET 14 ++#define RTL8367C_IGMP_PORT6_CONTROL_ALLOW_QUERY_MASK 0x4000 ++#define RTL8367C_IGMP_PORT6_CONTROL_ALLOW_REPORT_OFFSET 13 ++#define RTL8367C_IGMP_PORT6_CONTROL_ALLOW_REPORT_MASK 0x2000 ++#define RTL8367C_IGMP_PORT6_CONTROL_ALLOW_LEAVE_OFFSET 12 ++#define RTL8367C_IGMP_PORT6_CONTROL_ALLOW_LEAVE_MASK 0x1000 ++#define RTL8367C_IGMP_PORT6_CONTROL_ALLOW_MRP_OFFSET 11 ++#define RTL8367C_IGMP_PORT6_CONTROL_ALLOW_MRP_MASK 0x800 ++#define RTL8367C_IGMP_PORT6_CONTROL_ALLOW_MC_DATA_OFFSET 10 ++#define RTL8367C_IGMP_PORT6_CONTROL_ALLOW_MC_DATA_MASK 0x400 ++#define RTL8367C_IGMP_PORT6_CONTROL_MLDv2_OP_OFFSET 8 ++#define RTL8367C_IGMP_PORT6_CONTROL_MLDv2_OP_MASK 0x300 ++#define RTL8367C_IGMP_PORT6_CONTROL_MLDv1_OP_OFFSET 6 ++#define RTL8367C_IGMP_PORT6_CONTROL_MLDv1_OP_MASK 0xC0 ++#define RTL8367C_IGMP_PORT6_CONTROL_IGMPV3_OP_OFFSET 4 ++#define RTL8367C_IGMP_PORT6_CONTROL_IGMPV3_OP_MASK 0x30 ++#define RTL8367C_IGMP_PORT6_CONTROL_IGMPV2_OP_OFFSET 2 ++#define RTL8367C_IGMP_PORT6_CONTROL_IGMPV2_OP_MASK 0xC ++#define RTL8367C_IGMP_PORT6_CONTROL_IGMPV1_OP_OFFSET 0 ++#define RTL8367C_IGMP_PORT6_CONTROL_IGMPV1_OP_MASK 0x3 ++ ++#define RTL8367C_REG_IGMP_PORT7_CONTROL 0x1c0c ++#define RTL8367C_IGMP_PORT7_CONTROL_ALLOW_QUERY_OFFSET 14 ++#define RTL8367C_IGMP_PORT7_CONTROL_ALLOW_QUERY_MASK 0x4000 ++#define RTL8367C_IGMP_PORT7_CONTROL_ALLOW_REPORT_OFFSET 13 ++#define RTL8367C_IGMP_PORT7_CONTROL_ALLOW_REPORT_MASK 0x2000 ++#define RTL8367C_IGMP_PORT7_CONTROL_ALLOW_LEAVE_OFFSET 12 ++#define RTL8367C_IGMP_PORT7_CONTROL_ALLOW_LEAVE_MASK 0x1000 ++#define RTL8367C_IGMP_PORT7_CONTROL_ALLOW_MRP_OFFSET 11 ++#define RTL8367C_IGMP_PORT7_CONTROL_ALLOW_MRP_MASK 0x800 ++#define RTL8367C_IGMP_PORT7_CONTROL_ALLOW_MC_DATA_OFFSET 10 ++#define RTL8367C_IGMP_PORT7_CONTROL_ALLOW_MC_DATA_MASK 0x400 ++#define RTL8367C_IGMP_PORT7_CONTROL_MLDv2_OP_OFFSET 8 ++#define RTL8367C_IGMP_PORT7_CONTROL_MLDv2_OP_MASK 0x300 ++#define RTL8367C_IGMP_PORT7_CONTROL_MLDv1_OP_OFFSET 6 ++#define RTL8367C_IGMP_PORT7_CONTROL_MLDv1_OP_MASK 0xC0 ++#define RTL8367C_IGMP_PORT7_CONTROL_IGMPV3_OP_OFFSET 4 ++#define RTL8367C_IGMP_PORT7_CONTROL_IGMPV3_OP_MASK 0x30 ++#define RTL8367C_IGMP_PORT7_CONTROL_IGMPV2_OP_OFFSET 2 ++#define RTL8367C_IGMP_PORT7_CONTROL_IGMPV2_OP_MASK 0xC ++#define RTL8367C_IGMP_PORT7_CONTROL_IGMPV1_OP_OFFSET 0 ++#define RTL8367C_IGMP_PORT7_CONTROL_IGMPV1_OP_MASK 0x3 ++ ++#define RTL8367C_REG_IGMP_PORT01_MAX_GROUP 0x1c0d ++#define RTL8367C_PORT1_MAX_GROUP_OFFSET 8 ++#define RTL8367C_PORT1_MAX_GROUP_MASK 0xFF00 ++#define RTL8367C_PORT0_MAX_GROUP_OFFSET 0 ++#define RTL8367C_PORT0_MAX_GROUP_MASK 0xFF ++ ++#define RTL8367C_REG_IGMP_PORT23_MAX_GROUP 0x1c0e ++#define RTL8367C_PORT3_MAX_GROUP_OFFSET 8 ++#define RTL8367C_PORT3_MAX_GROUP_MASK 0xFF00 ++#define RTL8367C_PORT2_MAX_GROUP_OFFSET 0 ++#define RTL8367C_PORT2_MAX_GROUP_MASK 0xFF ++ ++#define RTL8367C_REG_IGMP_PORT45_MAX_GROUP 0x1c0f ++#define RTL8367C_PORT5_MAX_GROUP_OFFSET 8 ++#define RTL8367C_PORT5_MAX_GROUP_MASK 0xFF00 ++#define RTL8367C_PORT4_MAX_GROUP_OFFSET 0 ++#define RTL8367C_PORT4_MAX_GROUP_MASK 0xFF ++ ++#define RTL8367C_REG_IGMP_PORT67_MAX_GROUP 0x1c10 ++#define RTL8367C_PORT7_MAX_GROUP_OFFSET 8 ++#define RTL8367C_PORT7_MAX_GROUP_MASK 0xFF00 ++#define RTL8367C_PORT6_MAX_GROUP_OFFSET 0 ++#define RTL8367C_PORT6_MAX_GROUP_MASK 0xFF ++ ++#define RTL8367C_REG_IGMP_PORT01_CURRENT_GROUP 0x1c11 ++#define RTL8367C_PORT1_CURRENT_GROUP_OFFSET 8 ++#define RTL8367C_PORT1_CURRENT_GROUP_MASK 0xFF00 ++#define RTL8367C_PORT0_CURRENT_GROUP_OFFSET 0 ++#define RTL8367C_PORT0_CURRENT_GROUP_MASK 0xFF ++ ++#define RTL8367C_REG_IGMP_PORT23_CURRENT_GROUP 0x1c12 ++#define RTL8367C_PORT3_CURRENT_GROUP_OFFSET 8 ++#define RTL8367C_PORT3_CURRENT_GROUP_MASK 0xFF00 ++#define RTL8367C_PORT2_CURRENT_GROUP_OFFSET 0 ++#define RTL8367C_PORT2_CURRENT_GROUP_MASK 0xFF ++ ++#define RTL8367C_REG_IGMP_PORT45_CURRENT_GROUP 0x1c13 ++#define RTL8367C_PORT5_CURRENT_GROUP_OFFSET 8 ++#define RTL8367C_PORT5_CURRENT_GROUP_MASK 0xFF00 ++#define RTL8367C_PORT4_CURRENT_GROUP_OFFSET 0 ++#define RTL8367C_PORT4_CURRENT_GROUP_MASK 0xFF ++ ++#define RTL8367C_REG_IGMP_PORT67_CURRENT_GROUP 0x1c14 ++#define RTL8367C_PORT7_CURRENT_GROUP_OFFSET 8 ++#define RTL8367C_PORT7_CURRENT_GROUP_MASK 0xFF00 ++#define RTL8367C_PORT6_CURRENT_GROUP_OFFSET 0 ++#define RTL8367C_PORT6_CURRENT_GROUP_MASK 0xFF ++ ++#define RTL8367C_REG_IGMP_MLD_CFG3 0x1c15 ++#define RTL8367C_IGMP_MLD_IP6_BYPASS_OFFSET 5 ++#define RTL8367C_IGMP_MLD_IP6_BYPASS_MASK 0x20 ++#define RTL8367C_IGMP_MLD_IP4_BYPASS_239_255_255_OFFSET 4 ++#define RTL8367C_IGMP_MLD_IP4_BYPASS_239_255_255_MASK 0x10 ++#define RTL8367C_IGMP_MLD_IP4_BYPASS_224_0_1_OFFSET 3 ++#define RTL8367C_IGMP_MLD_IP4_BYPASS_224_0_1_MASK 0x8 ++#define RTL8367C_IGMP_MLD_IP4_BYPASS_224_0_0_OFFSET 2 ++#define RTL8367C_IGMP_MLD_IP4_BYPASS_224_0_0_MASK 0x4 ++#define RTL8367C_REPORT_LEAVE_FORWARD_OFFSET 0 ++#define RTL8367C_REPORT_LEAVE_FORWARD_MASK 0x3 ++ ++#define RTL8367C_REG_IGMP_MLD_CFG4 0x1c16 ++#define RTL8367C_IGMP_MLD_CFG4_OFFSET 0 ++#define RTL8367C_IGMP_MLD_CFG4_MASK 0x7FF ++ ++#define RTL8367C_REG_IGMP_GROUP_USAGE_LIST0 0x1c20 ++ ++#define RTL8367C_REG_IGMP_GROUP_USAGE_LIST1 0x1c21 ++ ++#define RTL8367C_REG_IGMP_GROUP_USAGE_LIST2 0x1c22 ++ ++#define RTL8367C_REG_IGMP_GROUP_USAGE_LIST3 0x1c23 ++ ++#define RTL8367C_REG_IGMP_GROUP_USAGE_LIST4 0x1c24 ++ ++#define RTL8367C_REG_IGMP_GROUP_USAGE_LIST5 0x1c25 ++ ++#define RTL8367C_REG_IGMP_GROUP_USAGE_LIST6 0x1c26 ++ ++#define RTL8367C_REG_IGMP_GROUP_USAGE_LIST7 0x1c27 ++ ++#define RTL8367C_REG_IGMP_GROUP_USAGE_LIST8 0x1c28 ++ ++#define RTL8367C_REG_IGMP_GROUP_USAGE_LIST9 0x1c29 ++ ++#define RTL8367C_REG_IGMP_GROUP_USAGE_LIST10 0x1c2a ++ ++#define RTL8367C_REG_IGMP_GROUP_USAGE_LIST11 0x1c2b ++ ++#define RTL8367C_REG_IGMP_GROUP_USAGE_LIST12 0x1c2c ++ ++#define RTL8367C_REG_IGMP_GROUP_USAGE_LIST13 0x1c2d ++ ++#define RTL8367C_REG_IGMP_GROUP_USAGE_LIST14 0x1c2e ++ ++#define RTL8367C_REG_IGMP_GROUP_USAGE_LIST15 0x1c2f ++ ++#define RTL8367C_REG_EAV_CTRL0 0x1c30 ++#define RTL8367C_EAV_CTRL0_OFFSET 0 ++#define RTL8367C_EAV_CTRL0_MASK 0xFF ++ ++#define RTL8367C_REG_EAV_CTRL1 0x1c31 ++#define RTL8367C_REMAP_EAV_PRI3_REGEN_OFFSET 9 ++#define RTL8367C_REMAP_EAV_PRI3_REGEN_MASK 0xE00 ++#define RTL8367C_REMAP_EAV_PRI2_REGEN_OFFSET 6 ++#define RTL8367C_REMAP_EAV_PRI2_REGEN_MASK 0x1C0 ++#define RTL8367C_REMAP_EAV_PRI1_REGEN_OFFSET 3 ++#define RTL8367C_REMAP_EAV_PRI1_REGEN_MASK 0x38 ++#define RTL8367C_REMAP_EAV_PRI0_REGEN_OFFSET 0 ++#define RTL8367C_REMAP_EAV_PRI0_REGEN_MASK 0x7 ++ ++#define RTL8367C_REG_EAV_CTRL2 0x1c32 ++#define RTL8367C_REMAP_EAV_PRI7_REGEN_OFFSET 9 ++#define RTL8367C_REMAP_EAV_PRI7_REGEN_MASK 0xE00 ++#define RTL8367C_REMAP_EAV_PRI6_REGEN_OFFSET 6 ++#define RTL8367C_REMAP_EAV_PRI6_REGEN_MASK 0x1C0 ++#define RTL8367C_REMAP_EAV_PRI5_REGEN_OFFSET 3 ++#define RTL8367C_REMAP_EAV_PRI5_REGEN_MASK 0x38 ++#define RTL8367C_REMAP_EAV_PRI4_REGEN_OFFSET 0 ++#define RTL8367C_REMAP_EAV_PRI4_REGEN_MASK 0x7 ++ ++#define RTL8367C_REG_SYS_TIME_FREQ 0x1c43 ++ ++#define RTL8367C_REG_SYS_TIME_OFFSET_L 0x1c44 ++ ++#define RTL8367C_REG_SYS_TIME_OFFSET_H 0x1c45 ++ ++#define RTL8367C_REG_SYS_TIME_OFFSET_512NS_L 0x1c46 ++ ++#define RTL8367C_REG_SYS_TIME_OFFSET_512NS_H 0x1c47 ++#define RTL8367C_SYS_TIME_OFFSET_TUNE_OFFSET 5 ++#define RTL8367C_SYS_TIME_OFFSET_TUNE_MASK 0x20 ++#define RTL8367C_SYS_TIME_OFFSET_512NS_H_SYS_TIME_OFFSET_512NS_OFFSET 0 ++#define RTL8367C_SYS_TIME_OFFSET_512NS_H_SYS_TIME_OFFSET_512NS_MASK 0x1F ++ ++#define RTL8367C_REG_SYS_TIME_SEC_TRANSIT 0x1c48 ++#define RTL8367C_SYS_TIME_SEC_TRANSIT_OFFSET 0 ++#define RTL8367C_SYS_TIME_SEC_TRANSIT_MASK 0x1 ++ ++#define RTL8367C_REG_SYS_TIME_SEC_HIGH_L 0x1c49 ++ ++#define RTL8367C_REG_SYS_TIME_SEC_HIGH_H 0x1c4a ++ ++#define RTL8367C_REG_SYS_TIME_512NS_L 0x1c4b ++ ++#define RTL8367C_REG_SYS_TIME_512NS_H 0x1c4c ++#define RTL8367C_SYS_TIME_512NS_H_OFFSET 0 ++#define RTL8367C_SYS_TIME_512NS_H_MASK 0x1F ++ ++#define RTL8367C_REG_FALLBACK_CTRL 0x1c70 ++#define RTL8367C_FALLBACK_PL_DEC_EN_OFFSET 15 ++#define RTL8367C_FALLBACK_PL_DEC_EN_MASK 0x8000 ++#define RTL8367C_FALLBACK_MONITOR_TIMEOUT_IGNORE_OFFSET 14 ++#define RTL8367C_FALLBACK_MONITOR_TIMEOUT_IGNORE_MASK 0x4000 ++#define RTL8367C_FALLBACK_ERROR_RATIO_THRESHOLD_OFFSET 11 ++#define RTL8367C_FALLBACK_ERROR_RATIO_THRESHOLD_MASK 0x3800 ++#define RTL8367C_FALLBACK_MONITORMAX_OFFSET 8 ++#define RTL8367C_FALLBACK_MONITORMAX_MASK 0x700 ++#define RTL8367C_FALLBACK_MONITOR_TIMEOUT_OFFSET 0 ++#define RTL8367C_FALLBACK_MONITOR_TIMEOUT_MASK 0xFF ++ ++#define RTL8367C_REG_FALLBACK_PORT0_CFG0 0x1c71 ++#define RTL8367C_FALLBACK_PORT0_CFG0_RESET_POWER_LEVEL_OFFSET 15 ++#define RTL8367C_FALLBACK_PORT0_CFG0_RESET_POWER_LEVEL_MASK 0x8000 ++#define RTL8367C_FALLBACK_PORT0_CFG0_ENABLE_OFFSET 14 ++#define RTL8367C_FALLBACK_PORT0_CFG0_ENABLE_MASK 0x4000 ++ ++#define RTL8367C_REG_FALLBACK_PORT0_CFG1 0x1c72 ++ ++#define RTL8367C_REG_FALLBACK_PORT0_CFG2 0x1c73 ++#define RTL8367C_FALLBACK_PORT0_CFG2_OFFSET 0 ++#define RTL8367C_FALLBACK_PORT0_CFG2_MASK 0xFFF ++ ++#define RTL8367C_REG_FALLBACK_PORT0_CFG3 0x1c74 ++#define RTL8367C_FALLBACK_PORT0_CFG3_OFFSET 0 ++#define RTL8367C_FALLBACK_PORT0_CFG3_MASK 0xFF ++ ++#define RTL8367C_REG_FALLBACK_PORT1_CFG0 0x1c75 ++#define RTL8367C_FALLBACK_PORT1_CFG0_RESET_POWER_LEVEL_OFFSET 15 ++#define RTL8367C_FALLBACK_PORT1_CFG0_RESET_POWER_LEVEL_MASK 0x8000 ++#define RTL8367C_FALLBACK_PORT1_CFG0_ENABLE_OFFSET 14 ++#define RTL8367C_FALLBACK_PORT1_CFG0_ENABLE_MASK 0x4000 ++ ++#define RTL8367C_REG_FALLBACK_PORT1_CFG1 0x1c76 ++ ++#define RTL8367C_REG_FALLBACK_PORT1_CFG2 0x1c77 ++#define RTL8367C_FALLBACK_PORT1_CFG2_OFFSET 0 ++#define RTL8367C_FALLBACK_PORT1_CFG2_MASK 0xFFF ++ ++#define RTL8367C_REG_FALLBACK_PORT1_CFG3 0x1c78 ++#define RTL8367C_FALLBACK_PORT1_CFG3_OFFSET 0 ++#define RTL8367C_FALLBACK_PORT1_CFG3_MASK 0xFF ++ ++#define RTL8367C_REG_FALLBACK_PORT2_CFG0 0x1c79 ++#define RTL8367C_FALLBACK_PORT2_CFG0_RESET_POWER_LEVEL_OFFSET 15 ++#define RTL8367C_FALLBACK_PORT2_CFG0_RESET_POWER_LEVEL_MASK 0x8000 ++#define RTL8367C_FALLBACK_PORT2_CFG0_ENABLE_OFFSET 14 ++#define RTL8367C_FALLBACK_PORT2_CFG0_ENABLE_MASK 0x4000 ++ ++#define RTL8367C_REG_FALLBACK_PORT2_CFG1 0x1c7a ++ ++#define RTL8367C_REG_FALLBACK_PORT2_CFG2 0x1c7b ++#define RTL8367C_FALLBACK_PORT2_CFG2_OFFSET 0 ++#define RTL8367C_FALLBACK_PORT2_CFG2_MASK 0xFFF ++ ++#define RTL8367C_REG_FALLBACK_PORT2_CFG3 0x1c7c ++#define RTL8367C_FALLBACK_PORT2_CFG3_OFFSET 0 ++#define RTL8367C_FALLBACK_PORT2_CFG3_MASK 0xFF ++ ++#define RTL8367C_REG_FALLBACK_PORT3_CFG0 0x1c7d ++#define RTL8367C_FALLBACK_PORT3_CFG0_RESET_POWER_LEVEL_OFFSET 15 ++#define RTL8367C_FALLBACK_PORT3_CFG0_RESET_POWER_LEVEL_MASK 0x8000 ++#define RTL8367C_FALLBACK_PORT3_CFG0_ENABLE_OFFSET 14 ++#define RTL8367C_FALLBACK_PORT3_CFG0_ENABLE_MASK 0x4000 ++ ++#define RTL8367C_REG_FALLBACK_PORT3_CFG1 0x1c7e ++ ++#define RTL8367C_REG_FALLBACK_PORT3_CFG2 0x1c7f ++#define RTL8367C_FALLBACK_PORT3_CFG2_OFFSET 0 ++#define RTL8367C_FALLBACK_PORT3_CFG2_MASK 0xFFF ++ ++#define RTL8367C_REG_FALLBACK_PORT3_CFG3 0x1c80 ++#define RTL8367C_FALLBACK_PORT3_CFG3_OFFSET 0 ++#define RTL8367C_FALLBACK_PORT3_CFG3_MASK 0xFF ++ ++#define RTL8367C_REG_FALLBACK_PORT4_CFG0 0x1c81 ++#define RTL8367C_FALLBACK_PORT4_CFG0_RESET_POWER_LEVEL_OFFSET 15 ++#define RTL8367C_FALLBACK_PORT4_CFG0_RESET_POWER_LEVEL_MASK 0x8000 ++#define RTL8367C_FALLBACK_PORT4_CFG0_ENABLE_OFFSET 14 ++#define RTL8367C_FALLBACK_PORT4_CFG0_ENABLE_MASK 0x4000 ++ ++#define RTL8367C_REG_FALLBACK_PORT4_CFG1 0x1c82 ++ ++#define RTL8367C_REG_FALLBACK_PORT4_CFG2 0x1c83 ++#define RTL8367C_FALLBACK_PORT4_CFG2_OFFSET 0 ++#define RTL8367C_FALLBACK_PORT4_CFG2_MASK 0xFFF ++ ++#define RTL8367C_REG_FALLBACK_PORT4_CFG3 0x1c84 ++#define RTL8367C_FALLBACK_PORT4_CFG3_OFFSET 0 ++#define RTL8367C_FALLBACK_PORT4_CFG3_MASK 0xFF ++ ++#define RTL8367C_REG_FALLBACK_CTRL1 0x1c85 ++#define RTL8367C_FALLBACK_VALIDFLOW_OFFSET 8 ++#define RTL8367C_FALLBACK_VALIDFLOW_MASK 0xFF00 ++#define RTL8367C_FALLBACK_STOP_TMR_OFFSET 0 ++#define RTL8367C_FALLBACK_STOP_TMR_MASK 0x1 ++ ++#define RTL8367C_REG_FALLBACK_CPL 0x1c86 ++#define RTL8367C_PORT4_CPL_OFFSET 4 ++#define RTL8367C_PORT4_CPL_MASK 0x10 ++#define RTL8367C_PORT3_CPL_OFFSET 3 ++#define RTL8367C_PORT3_CPL_MASK 0x8 ++#define RTL8367C_PORT2_CPL_OFFSET 2 ++#define RTL8367C_PORT2_CPL_MASK 0x4 ++#define RTL8367C_PORT1_CPL_OFFSET 1 ++#define RTL8367C_PORT1_CPL_MASK 0x2 ++#define RTL8367C_PORT0_CPL_OFFSET 0 ++#define RTL8367C_PORT0_CPL_MASK 0x1 ++ ++#define RTL8367C_REG_FALLBACK_PHY_PAGE 0x1c87 ++#define RTL8367C_FALLBACK_PHY_PAGE_OFFSET 0 ++#define RTL8367C_FALLBACK_PHY_PAGE_MASK 0xFFF ++ ++#define RTL8367C_REG_FALLBACK_PHY_REG 0x1c88 ++#define RTL8367C_FALLBACK_PHY_REG_OFFSET 0 ++#define RTL8367C_FALLBACK_PHY_REG_MASK 0x1F ++ ++#define RTL8367C_REG_AFBK_INFO_X0 0x1c89 ++ ++#define RTL8367C_REG_AFBK_INFO_X1 0x1c8a ++ ++#define RTL8367C_REG_AFBK_INFO_X2 0x1c8b ++ ++#define RTL8367C_REG_AFBK_INFO_X3 0x1c8c ++ ++#define RTL8367C_REG_AFBK_INFO_X4 0x1c8d ++ ++#define RTL8367C_REG_AFBK_INFO_X5 0x1c8e ++ ++#define RTL8367C_REG_AFBK_INFO_X6 0x1c8f ++ ++#define RTL8367C_REG_AFBK_INFO_X7 0x1c90 ++ ++#define RTL8367C_REG_AFBK_INFO_X8 0x1c91 ++ ++#define RTL8367C_REG_AFBK_INFO_X9 0x1c92 ++ ++#define RTL8367C_REG_AFBK_INFO_X10 0x1c93 ++ ++#define RTL8367C_REG_AFBK_INFO_X11 0x1c94 ++ ++#define RTL8367C_REG_FALLBACK_PORT5_CFG0 0x1ca0 ++#define RTL8367C_FALLBACK_PORT5_CFG0_RESET_POWER_LEVEL_OFFSET 15 ++#define RTL8367C_FALLBACK_PORT5_CFG0_RESET_POWER_LEVEL_MASK 0x8000 ++#define RTL8367C_FALLBACK_PORT5_CFG0_ENABLE_OFFSET 14 ++#define RTL8367C_FALLBACK_PORT5_CFG0_ENABLE_MASK 0x4000 ++ ++#define RTL8367C_REG_FALLBACK_PORT5_CFG1 0x1ca1 ++ ++#define RTL8367C_REG_FALLBACK_PORT5_CFG2 0x1ca2 ++#define RTL8367C_FALLBACK_PORT5_CFG2_OFFSET 0 ++#define RTL8367C_FALLBACK_PORT5_CFG2_MASK 0xFFF ++ ++#define RTL8367C_REG_FALLBACK_PORT5_CFG3 0x1ca3 ++#define RTL8367C_FALLBACK_PORT5_CFG3_OFFSET 0 ++#define RTL8367C_FALLBACK_PORT5_CFG3_MASK 0xFF ++ ++#define RTL8367C_REG_FALLBACK_PORT6_CFG0 0x1ca4 ++#define RTL8367C_FALLBACK_PORT6_CFG0_RESET_POWER_LEVEL_OFFSET 15 ++#define RTL8367C_FALLBACK_PORT6_CFG0_RESET_POWER_LEVEL_MASK 0x8000 ++#define RTL8367C_FALLBACK_PORT6_CFG0_ENABLE_OFFSET 14 ++#define RTL8367C_FALLBACK_PORT6_CFG0_ENABLE_MASK 0x4000 ++ ++#define RTL8367C_REG_FALLBACK_PORT6_CFG1 0x1ca5 ++ ++#define RTL8367C_REG_FALLBACK_PORT6_CFG2 0x1ca6 ++#define RTL8367C_FALLBACK_PORT6_CFG2_OFFSET 0 ++#define RTL8367C_FALLBACK_PORT6_CFG2_MASK 0xFFF ++ ++#define RTL8367C_REG_FALLBACK_PORT6_CFG3 0x1ca7 ++#define RTL8367C_FALLBACK_PORT6_CFG3_OFFSET 0 ++#define RTL8367C_FALLBACK_PORT6_CFG3_MASK 0xFF ++ ++#define RTL8367C_REG_FALLBACK_PORT7_CFG0 0x1ca8 ++#define RTL8367C_FALLBACK_PORT7_CFG0_RESET_POWER_LEVEL_OFFSET 15 ++#define RTL8367C_FALLBACK_PORT7_CFG0_RESET_POWER_LEVEL_MASK 0x8000 ++#define RTL8367C_FALLBACK_PORT7_CFG0_ENABLE_OFFSET 14 ++#define RTL8367C_FALLBACK_PORT7_CFG0_ENABLE_MASK 0x4000 ++ ++#define RTL8367C_REG_FALLBACK_PORT7_CFG1 0x1ca9 ++ ++#define RTL8367C_REG_FALLBACK_PORT7_CFG2 0x1caa ++#define RTL8367C_FALLBACK_PORT7_CFG2_OFFSET 0 ++#define RTL8367C_FALLBACK_PORT7_CFG2_MASK 0xFFF ++ ++#define RTL8367C_REG_FALLBACK_PORT7_CFG3 0x1cab ++#define RTL8367C_FALLBACK_PORT7_CFG3_OFFSET 0 ++#define RTL8367C_FALLBACK_PORT7_CFG3_MASK 0xFF ++ ++#define RTL8367C_REG_IGMP_PORT8_CONTROL 0x1cb0 ++#define RTL8367C_IGMP_PORT8_CONTROL_ALLOW_QUERY_OFFSET 14 ++#define RTL8367C_IGMP_PORT8_CONTROL_ALLOW_QUERY_MASK 0x4000 ++#define RTL8367C_IGMP_PORT8_CONTROL_ALLOW_REPORT_OFFSET 13 ++#define RTL8367C_IGMP_PORT8_CONTROL_ALLOW_REPORT_MASK 0x2000 ++#define RTL8367C_IGMP_PORT8_CONTROL_ALLOW_LEAVE_OFFSET 12 ++#define RTL8367C_IGMP_PORT8_CONTROL_ALLOW_LEAVE_MASK 0x1000 ++#define RTL8367C_IGMP_PORT8_CONTROL_ALLOW_MRP_OFFSET 11 ++#define RTL8367C_IGMP_PORT8_CONTROL_ALLOW_MRP_MASK 0x800 ++#define RTL8367C_IGMP_PORT8_CONTROL_ALLOW_MC_DATA_OFFSET 10 ++#define RTL8367C_IGMP_PORT8_CONTROL_ALLOW_MC_DATA_MASK 0x400 ++#define RTL8367C_IGMP_PORT8_CONTROL_MLDv2_OP_OFFSET 8 ++#define RTL8367C_IGMP_PORT8_CONTROL_MLDv2_OP_MASK 0x300 ++#define RTL8367C_IGMP_PORT8_CONTROL_MLDv1_OP_OFFSET 6 ++#define RTL8367C_IGMP_PORT8_CONTROL_MLDv1_OP_MASK 0xC0 ++#define RTL8367C_IGMP_PORT8_CONTROL_IGMPV3_OP_OFFSET 4 ++#define RTL8367C_IGMP_PORT8_CONTROL_IGMPV3_OP_MASK 0x30 ++#define RTL8367C_IGMP_PORT8_CONTROL_IGMPV2_OP_OFFSET 2 ++#define RTL8367C_IGMP_PORT8_CONTROL_IGMPV2_OP_MASK 0xC ++#define RTL8367C_IGMP_PORT8_CONTROL_IGMPV1_OP_OFFSET 0 ++#define RTL8367C_IGMP_PORT8_CONTROL_IGMPV1_OP_MASK 0x3 ++ ++#define RTL8367C_REG_IGMP_PORT9_CONTROL 0x1cb1 ++#define RTL8367C_IGMP_PORT9_CONTROL_ALLOW_QUERY_OFFSET 14 ++#define RTL8367C_IGMP_PORT9_CONTROL_ALLOW_QUERY_MASK 0x4000 ++#define RTL8367C_IGMP_PORT9_CONTROL_ALLOW_REPORT_OFFSET 13 ++#define RTL8367C_IGMP_PORT9_CONTROL_ALLOW_REPORT_MASK 0x2000 ++#define RTL8367C_IGMP_PORT9_CONTROL_ALLOW_LEAVE_OFFSET 12 ++#define RTL8367C_IGMP_PORT9_CONTROL_ALLOW_LEAVE_MASK 0x1000 ++#define RTL8367C_IGMP_PORT9_CONTROL_ALLOW_MRP_OFFSET 11 ++#define RTL8367C_IGMP_PORT9_CONTROL_ALLOW_MRP_MASK 0x800 ++#define RTL8367C_IGMP_PORT9_CONTROL_ALLOW_MC_DATA_OFFSET 10 ++#define RTL8367C_IGMP_PORT9_CONTROL_ALLOW_MC_DATA_MASK 0x400 ++#define RTL8367C_IGMP_PORT9_CONTROL_MLDv2_OP_OFFSET 8 ++#define RTL8367C_IGMP_PORT9_CONTROL_MLDv2_OP_MASK 0x300 ++#define RTL8367C_IGMP_PORT9_CONTROL_MLDv1_OP_OFFSET 6 ++#define RTL8367C_IGMP_PORT9_CONTROL_MLDv1_OP_MASK 0xC0 ++#define RTL8367C_IGMP_PORT9_CONTROL_IGMPV3_OP_OFFSET 4 ++#define RTL8367C_IGMP_PORT9_CONTROL_IGMPV3_OP_MASK 0x30 ++#define RTL8367C_IGMP_PORT9_CONTROL_IGMPV2_OP_OFFSET 2 ++#define RTL8367C_IGMP_PORT9_CONTROL_IGMPV2_OP_MASK 0xC ++#define RTL8367C_IGMP_PORT9_CONTROL_IGMPV1_OP_OFFSET 0 ++#define RTL8367C_IGMP_PORT9_CONTROL_IGMPV1_OP_MASK 0x3 ++ ++#define RTL8367C_REG_IGMP_PORT10_CONTROL 0x1cb2 ++#define RTL8367C_IGMP_PORT10_CONTROL_ALLOW_QUERY_OFFSET 14 ++#define RTL8367C_IGMP_PORT10_CONTROL_ALLOW_QUERY_MASK 0x4000 ++#define RTL8367C_IGMP_PORT10_CONTROL_ALLOW_REPORT_OFFSET 13 ++#define RTL8367C_IGMP_PORT10_CONTROL_ALLOW_REPORT_MASK 0x2000 ++#define RTL8367C_IGMP_PORT10_CONTROL_ALLOW_LEAVE_OFFSET 12 ++#define RTL8367C_IGMP_PORT10_CONTROL_ALLOW_LEAVE_MASK 0x1000 ++#define RTL8367C_IGMP_PORT10_CONTROL_ALLOW_MRP_OFFSET 11 ++#define RTL8367C_IGMP_PORT10_CONTROL_ALLOW_MRP_MASK 0x800 ++#define RTL8367C_IGMP_PORT10_CONTROL_ALLOW_MC_DATA_OFFSET 10 ++#define RTL8367C_IGMP_PORT10_CONTROL_ALLOW_MC_DATA_MASK 0x400 ++#define RTL8367C_IGMP_PORT10_CONTROL_MLDv2_OP_OFFSET 8 ++#define RTL8367C_IGMP_PORT10_CONTROL_MLDv2_OP_MASK 0x300 ++#define RTL8367C_IGMP_PORT10_CONTROL_MLDv1_OP_OFFSET 6 ++#define RTL8367C_IGMP_PORT10_CONTROL_MLDv1_OP_MASK 0xC0 ++#define RTL8367C_IGMP_PORT10_CONTROL_IGMPV3_OP_OFFSET 4 ++#define RTL8367C_IGMP_PORT10_CONTROL_IGMPV3_OP_MASK 0x30 ++#define RTL8367C_IGMP_PORT10_CONTROL_IGMPV2_OP_OFFSET 2 ++#define RTL8367C_IGMP_PORT10_CONTROL_IGMPV2_OP_MASK 0xC ++#define RTL8367C_IGMP_PORT10_CONTROL_IGMPV1_OP_OFFSET 0 ++#define RTL8367C_IGMP_PORT10_CONTROL_IGMPV1_OP_MASK 0x3 ++ ++#define RTL8367C_REG_IGMP_PORT89_MAX_GROUP 0x1cb3 ++#define RTL8367C_PORT9_MAX_GROUP_OFFSET 8 ++#define RTL8367C_PORT9_MAX_GROUP_MASK 0xFF00 ++#define RTL8367C_PORT8_MAX_GROUP_OFFSET 0 ++#define RTL8367C_PORT8_MAX_GROUP_MASK 0xFF ++ ++#define RTL8367C_REG_IGMP_PORT10_MAX_GROUP 0x1cb4 ++#define RTL8367C_IGMP_PORT10_MAX_GROUP_OFFSET 0 ++#define RTL8367C_IGMP_PORT10_MAX_GROUP_MASK 0xFF ++ ++#define RTL8367C_REG_IGMP_PORT89_CURRENT_GROUP 0x1cb5 ++#define RTL8367C_PORT9_CURRENT_GROUP_OFFSET 8 ++#define RTL8367C_PORT9_CURRENT_GROUP_MASK 0xFF00 ++#define RTL8367C_PORT8_CURRENT_GROUP_OFFSET 0 ++#define RTL8367C_PORT8_CURRENT_GROUP_MASK 0xFF ++ ++#define RTL8367C_REG_IGMP_PORT10_CURRENT_GROUP 0x1cb6 ++#define RTL8367C_IGMP_PORT10_CURRENT_GROUP_OFFSET 0 ++#define RTL8367C_IGMP_PORT10_CURRENT_GROUP_MASK 0xFF ++ ++#define RTL8367C_REG_IGMP_L3_CHECKSUM_CHECK 0x1cb7 ++#define RTL8367C_IGMP_L3_CHECKSUM_CHECK_OFFSET 0 ++#define RTL8367C_IGMP_L3_CHECKSUM_CHECK_MASK 0x1 ++ ++/* (16'h1d00)chip_70b_reg */ ++ ++#define RTL8367C_REG_PCSXF_CFG 0x1d00 ++#define RTL8367C_PCSXF_CFG_Reserved_OFFSET 15 ++#define RTL8367C_PCSXF_CFG_Reserved_MASK 0x8000 ++#define RTL8367C_CFG_RST_RXFIFO_P7_5_OFFSET 12 ++#define RTL8367C_CFG_RST_RXFIFO_P7_5_MASK 0x7000 ++#define RTL8367C_CFG_PCSXF_OFFSET 8 ++#define RTL8367C_CFG_PCSXF_MASK 0xF00 ++#define RTL8367C_CFG_RST_RXFIFO_OFFSET 3 ++#define RTL8367C_CFG_RST_RXFIFO_MASK 0xF8 ++#define RTL8367C_CFG_COL2RXDV_OFFSET 2 ++#define RTL8367C_CFG_COL2RXDV_MASK 0x4 ++#define RTL8367C_CFG_PHY_SDET_OFFSET 0 ++#define RTL8367C_CFG_PHY_SDET_MASK 0x3 ++ ++#define RTL8367C_REG_PHYID_CFG0 0x1d01 ++#define RTL8367C_CFG_PHY_BRD_MODE_P7_5_OFFSET 11 ++#define RTL8367C_CFG_PHY_BRD_MODE_P7_5_MASK 0x3800 ++#define RTL8367C_CFG_PHYAD_14C_OFFSET 10 ++#define RTL8367C_CFG_PHYAD_14C_MASK 0x400 ++#define RTL8367C_CFG_PHY_BRD_MODE_OFFSET 5 ++#define RTL8367C_CFG_PHY_BRD_MODE_MASK 0x3E0 ++#define RTL8367C_CFG_BRD_PHYAD_OFFSET 0 ++#define RTL8367C_CFG_BRD_PHYAD_MASK 0x1F ++ ++#define RTL8367C_REG_PHYID_CFG1 0x1d02 ++#define RTL8367C_CFG_MSK_MDI_OFFSET 5 ++#define RTL8367C_CFG_MSK_MDI_MASK 0x1FE0 ++#define RTL8367C_CFG_BASE_PHYAD_OFFSET 0 ++#define RTL8367C_CFG_BASE_PHYAD_MASK 0x1F ++ ++#define RTL8367C_REG_PHY_POLL_CFG0 0x1d03 ++#define RTL8367C_CFG_HOTCMD_PRD_EN_OFFSET 15 ++#define RTL8367C_CFG_HOTCMD_PRD_EN_MASK 0x8000 ++#define RTL8367C_CFG_HOTCMD_EN_OFFSET 12 ++#define RTL8367C_CFG_HOTCMD_EN_MASK 0x7000 ++#define RTL8367C_CFG_POLL_PERIOD_OFFSET 8 ++#define RTL8367C_CFG_POLL_PERIOD_MASK 0xF00 ++#define RTL8367C_CFG_PERI_CMDS_RD_OFFSET 4 ++#define RTL8367C_CFG_PERI_CMDS_RD_MASK 0xF0 ++#define RTL8367C_CFG_PERI_CMDS_WR_OFFSET 0 ++#define RTL8367C_CFG_PERI_CMDS_WR_MASK 0xF ++ ++#define RTL8367C_REG_PHY_POLL_CFG1 0x1d04 ++ ++#define RTL8367C_REG_PHY_POLL_CFG2 0x1d05 ++ ++#define RTL8367C_REG_PHY_POLL_CFG3 0x1d06 ++ ++#define RTL8367C_REG_PHY_POLL_CFG4 0x1d07 ++ ++#define RTL8367C_REG_PHY_POLL_CFG5 0x1d08 ++ ++#define RTL8367C_REG_PHY_POLL_CFG6 0x1d09 ++ ++#define RTL8367C_REG_PHY_POLL_CFG7 0x1d0a ++ ++#define RTL8367C_REG_PHY_POLL_CFG8 0x1d0b ++ ++#define RTL8367C_REG_PHY_POLL_CFG9 0x1d0c ++ ++#define RTL8367C_REG_PHY_POLL_CFG10 0x1d0d ++ ++#define RTL8367C_REG_PHY_POLL_CFG11 0x1d0e ++ ++#define RTL8367C_REG_PHY_POLL_CFG12 0x1d0f ++ ++#define RTL8367C_REG_EFUSE_MISC 0x1d10 ++#define RTL8367C_CFG_SA_SEL_OFFSET 5 ++#define RTL8367C_CFG_SA_SEL_MASK 0x20 ++#define RTL8367C_CFG_PHYAD00_OFFSET 0 ++#define RTL8367C_CFG_PHYAD00_MASK 0x1F ++ ++#define RTL8367C_REG_SDS_MISC 0x1d11 ++#define RTL8367C_CFG_SGMII_RXFC_OFFSET 14 ++#define RTL8367C_CFG_SGMII_RXFC_MASK 0x4000 ++#define RTL8367C_CFG_SGMII_TXFC_OFFSET 13 ++#define RTL8367C_CFG_SGMII_TXFC_MASK 0x2000 ++#define RTL8367C_INB_ARB_OFFSET 12 ++#define RTL8367C_INB_ARB_MASK 0x1000 ++#define RTL8367C_CFG_MAC8_SEL_HSGMII_OFFSET 11 ++#define RTL8367C_CFG_MAC8_SEL_HSGMII_MASK 0x800 ++#define RTL8367C_CFG_SGMII_FDUP_OFFSET 10 ++#define RTL8367C_CFG_SGMII_FDUP_MASK 0x400 ++#define RTL8367C_CFG_SGMII_LINK_OFFSET 9 ++#define RTL8367C_CFG_SGMII_LINK_MASK 0x200 ++#define RTL8367C_CFG_SGMII_SPD_OFFSET 7 ++#define RTL8367C_CFG_SGMII_SPD_MASK 0x180 ++#define RTL8367C_CFG_MAC8_SEL_SGMII_OFFSET 6 ++#define RTL8367C_CFG_MAC8_SEL_SGMII_MASK 0x40 ++#define RTL8367C_CFG_INB_SEL_OFFSET 3 ++#define RTL8367C_CFG_INB_SEL_MASK 0x38 ++#define RTL8367C_CFG_SDS_MODE_18C_OFFSET 0 ++#define RTL8367C_CFG_SDS_MODE_18C_MASK 0x7 ++ ++#define RTL8367C_REG_FIFO_CTRL 0x1d12 ++#define RTL8367C_CFG_LINK_DOWN_CLR_FIFO_OFFSET 11 ++#define RTL8367C_CFG_LINK_DOWN_CLR_FIFO_MASK 0x800 ++#define RTL8367C_CFG_LPBK_OFFSET 10 ++#define RTL8367C_CFG_LPBK_MASK 0x400 ++#define RTL8367C_CFG_NOT_FF_OUT_OFFSET 9 ++#define RTL8367C_CFG_NOT_FF_OUT_MASK 0x200 ++#define RTL8367C_CFG_WATER_LEVEL_FD_OFFSET 6 ++#define RTL8367C_CFG_WATER_LEVEL_FD_MASK 0x1C0 ++#define RTL8367C_CFG_WATER_LEVEL_Y2X_OFFSET 3 ++#define RTL8367C_CFG_WATER_LEVEL_Y2X_MASK 0x38 ++#define RTL8367C_CFG_WATER_LEVEL_X2Y_OFFSET 0 ++#define RTL8367C_CFG_WATER_LEVEL_X2Y_MASK 0x7 ++ ++#define RTL8367C_REG_BCAM_SETTING 0x1d13 ++#define RTL8367C_CFG_BCAM_MDS_OFFSET 3 ++#define RTL8367C_CFG_BCAM_MDS_MASK 0x18 ++#define RTL8367C_CFG_BCAM_RDS_OFFSET 0 ++#define RTL8367C_CFG_BCAM_RDS_MASK 0x7 ++ ++#define RTL8367C_REG_GPHY_ACS_MISC 0x1d14 ++#define RTL8367C_CFG_SEL_GPHY_SMI_OFFSET 3 ++#define RTL8367C_CFG_SEL_GPHY_SMI_MASK 0x8 ++#define RTL8367C_CFG_BRD_PHYIDX_OFFSET 0 ++#define RTL8367C_CFG_BRD_PHYIDX_MASK 0x7 ++ ++#define RTL8367C_REG_GPHY_OCP_MSB_0 0x1d15 ++#define RTL8367C_CFG_CPU_OCPADR_MSB_OFFSET 6 ++#define RTL8367C_CFG_CPU_OCPADR_MSB_MASK 0xFC0 ++#define RTL8367C_CFG_DW8051_OCPADR_MSB_OFFSET 0 ++#define RTL8367C_CFG_DW8051_OCPADR_MSB_MASK 0x3F ++ ++#define RTL8367C_REG_GPHY_OCP_MSB_1 0x1d16 ++#define RTL8367C_CFG_PATCH_OCPADR_MSB_OFFSET 6 ++#define RTL8367C_CFG_PATCH_OCPADR_MSB_MASK 0xFC0 ++#define RTL8367C_CFG_PHYSTS_OCPADR_MSB_OFFSET 0 ++#define RTL8367C_CFG_PHYSTS_OCPADR_MSB_MASK 0x3F ++ ++#define RTL8367C_REG_GPHY_OCP_MSB_2 0x1d17 ++#define RTL8367C_CFG_RRCP_OCPADR_MSB_OFFSET 6 ++#define RTL8367C_CFG_RRCP_OCPADR_MSB_MASK 0xFC0 ++#define RTL8367C_CFG_RTCT_OCPADR_MSB_OFFSET 0 ++#define RTL8367C_CFG_RTCT_OCPADR_MSB_MASK 0x3F ++ ++#define RTL8367C_REG_GPHY_OCP_MSB_3 0x1d18 ++#define RTL8367C_GPHY_OCP_MSB_3_OFFSET 0 ++#define RTL8367C_GPHY_OCP_MSB_3_MASK 0x3F ++ ++#define RTL8367C_REG_GPIO_67C_I_X0 0x1d19 ++ ++#define RTL8367C_REG_GPIO_67C_I_X1 0x1d1a ++ ++#define RTL8367C_REG_GPIO_67C_I_X2 0x1d1b ++ ++#define RTL8367C_REG_GPIO_67C_I_X3 0x1d1c ++#define RTL8367C_GPIO_67C_I_X3_OFFSET 0 ++#define RTL8367C_GPIO_67C_I_X3_MASK 0x3FFF ++ ++#define RTL8367C_REG_GPIO_67C_O_X0 0x1d1d ++ ++#define RTL8367C_REG_GPIO_67C_O_X1 0x1d1e ++ ++#define RTL8367C_REG_GPIO_67C_O_X2 0x1d1f ++ ++#define RTL8367C_REG_GPIO_67C_O_X3 0x1d20 ++#define RTL8367C_GPIO_67C_O_X3_OFFSET 0 ++#define RTL8367C_GPIO_67C_O_X3_MASK 0x3FFF ++ ++#define RTL8367C_REG_GPIO_67C_OE_X0 0x1d21 ++ ++#define RTL8367C_REG_GPIO_67C_OE_X1 0x1d22 ++ ++#define RTL8367C_REG_GPIO_67C_OE_X2 0x1d23 ++ ++#define RTL8367C_REG_GPIO_67C_OE_X3 0x1d24 ++#define RTL8367C_GPIO_67C_OE_X3_OFFSET 0 ++#define RTL8367C_GPIO_67C_OE_X3_MASK 0x3FFF ++ ++#define RTL8367C_REG_GPIO_MODE_67C_X0 0x1d25 ++ ++#define RTL8367C_REG_GPIO_MODE_67C_X1 0x1d26 ++ ++#define RTL8367C_REG_GPIO_MODE_67C_X2 0x1d27 ++ ++#define RTL8367C_REG_GPIO_MODE_67C_X3 0x1d28 ++#define RTL8367C_GPIO_MODE_67C_X3_OFFSET 0 ++#define RTL8367C_GPIO_MODE_67C_X3_MASK 0x3FFF ++ ++#define RTL8367C_REG_WGPHY_MISC_0 0x1d29 ++#define RTL8367C_CFG_INIPHY_DISGIGA_P7_5_OFFSET 13 ++#define RTL8367C_CFG_INIPHY_DISGIGA_P7_5_MASK 0xE000 ++#define RTL8367C_CFG_INIPHY_PWRUP_OFFSET 5 ++#define RTL8367C_CFG_INIPHY_PWRUP_MASK 0x1FE0 ++#define RTL8367C_CFG_INIPHY_DISGIGA_OFFSET 0 ++#define RTL8367C_CFG_INIPHY_DISGIGA_MASK 0x1F ++ ++#define RTL8367C_REG_WGPHY_MISC_1 0x1d2a ++#define RTL8367C_WGPHY_MISC_1_OFFSET 0 ++#define RTL8367C_WGPHY_MISC_1_MASK 0xFF ++ ++#define RTL8367C_REG_WGPHY_MISC_2 0x1d2b ++#define RTL8367C_WGPHY_MISC_2_OFFSET 0 ++#define RTL8367C_WGPHY_MISC_2_MASK 0x3FF ++ ++#define RTL8367C_REG_CFG_AFBK_GPHY_0 0x1d2c ++#define RTL8367C_CFG_AFBK_GPHY_0_OFFSET 0 ++#define RTL8367C_CFG_AFBK_GPHY_0_MASK 0x1F ++ ++#define RTL8367C_REG_CFG_AFBK_GPHY_1 0x1d2d ++#define RTL8367C_CFG_AFBK_GPHY_1_OFFSET 0 ++#define RTL8367C_CFG_AFBK_GPHY_1_MASK 0xFFF ++ ++#define RTL8367C_REG_EF_SLV_CTRL_0 0x1d2e ++#define RTL8367C_EF_SLV_BUSY_OFFSET 11 ++#define RTL8367C_EF_SLV_BUSY_MASK 0x800 ++#define RTL8367C_EF_SLV_ACK_OFFSET 10 ++#define RTL8367C_EF_SLV_ACK_MASK 0x400 ++#define RTL8367C_EF_SLV_A_OFFSET 2 ++#define RTL8367C_EF_SLV_A_MASK 0x3FC ++#define RTL8367C_EF_SLV_WE_OFFSET 1 ++#define RTL8367C_EF_SLV_WE_MASK 0x2 ++#define RTL8367C_EF_SLV_CE_OFFSET 0 ++#define RTL8367C_EF_SLV_CE_MASK 0x1 ++ ++#define RTL8367C_REG_EF_SLV_CTRL_1 0x1d2f ++ ++#define RTL8367C_REG_EF_SLV_CTRL_2 0x1d30 ++ ++#define RTL8367C_REG_EFUSE_MISC_1 0x1d31 ++#define RTL8367C_EF_EN_EFUSE_OFFSET 10 ++#define RTL8367C_EF_EN_EFUSE_MASK 0x400 ++#define RTL8367C_EF_MODEL_ID_OFFSET 6 ++#define RTL8367C_EF_MODEL_ID_MASK 0x3C0 ++#define RTL8367C_EF_RSVD_OFFSET 2 ++#define RTL8367C_EF_RSVD_MASK 0x3C ++#define RTL8367C_EF_SYS_CLK_OFFSET 0 ++#define RTL8367C_EF_SYS_CLK_MASK 0x3 ++ ++#define RTL8367C_REG_IO_MISC_FUNC 0x1d32 ++#define RTL8367C_TST_MODE_OFFSET 3 ++#define RTL8367C_TST_MODE_MASK 0x8 ++#define RTL8367C_UART_EN_OFFSET 2 ++#define RTL8367C_UART_EN_MASK 0x4 ++#define RTL8367C_INT_EN_OFFSET 1 ++#define RTL8367C_INT_EN_MASK 0x2 ++#define RTL8367C_BUZ_EN_OFFSET 0 ++#define RTL8367C_BUZ_EN_MASK 0x1 ++ ++#define RTL8367C_REG_HTRAM_DVS 0x1d33 ++#define RTL8367C_HTRAM_DVS_OFFSET 0 ++#define RTL8367C_HTRAM_DVS_MASK 0x1 ++ ++#define RTL8367C_REG_EF_SLV_CTRL_3 0x1d34 ++#define RTL8367C_EF_SLV_CTRL_3_OFFSET 0 ++#define RTL8367C_EF_SLV_CTRL_3_MASK 0x1 ++ ++#define RTL8367C_REG_INBAND_EN14C 0x1d35 ++#define RTL8367C_INBAND_EN14C_OFFSET 0 ++#define RTL8367C_INBAND_EN14C_MASK 0x1 ++ ++#define RTL8367C_REG_CFG_SWR_L 0x1d36 ++#define RTL8367C_ANARG_RDY_SWR_L_OFFSET 14 ++#define RTL8367C_ANARG_RDY_SWR_L_MASK 0x4000 ++#define RTL8367C_ANARG_VALID_SWR_L_OFFSET 13 ++#define RTL8367C_ANARG_VALID_SWR_L_MASK 0x2000 ++#define RTL8367C_SAW_SWR_L_OFFSET 9 ++#define RTL8367C_SAW_SWR_L_MASK 0x1E00 ++#define RTL8367C_SAW_VALID_SWR_L_OFFSET 8 ++#define RTL8367C_SAW_VALID_SWR_L_MASK 0x100 ++#define RTL8367C_UPS_DBGO_L_OFFSET 0 ++#define RTL8367C_UPS_DBGO_L_MASK 0xFF ++ ++#define RTL8367C_REG_BTCAM_CTRL 0x1d37 ++#define RTL8367C_TCAM_RDS_OFFSET 2 ++#define RTL8367C_TCAM_RDS_MASK 0x1C ++#define RTL8367C_TCAM_MDS_OFFSET 0 ++#define RTL8367C_TCAM_MDS_MASK 0x3 ++ ++#define RTL8367C_REG_PBRAM_BISR_CTRL 0x1d38 ++#define RTL8367C_HAS_HLDRMP_MD_OFFSET 9 ++#define RTL8367C_HAS_HLDRMP_MD_MASK 0x200 ++#define RTL8367C_PB_HLDRMP_MD_OFFSET 8 ++#define RTL8367C_PB_HLDRMP_MD_MASK 0x100 ++#define RTL8367C_HAS_BISR_BIRSTN_OFFSET 7 ++#define RTL8367C_HAS_BISR_BIRSTN_MASK 0x80 ++#define RTL8367C_SEC_RUN_HSA_OFFSET 6 ++#define RTL8367C_SEC_RUN_HSA_MASK 0x40 ++#define RTL8367C_HAS_HLDRMP_VAL_OFFSET 5 ++#define RTL8367C_HAS_HLDRMP_VAL_MASK 0x20 ++#define RTL8367C_HAS_BISR_PWRSTN_OFFSET 4 ++#define RTL8367C_HAS_BISR_PWRSTN_MASK 0x10 ++#define RTL8367C_SEC_RUN_PB_OFFSET 3 ++#define RTL8367C_SEC_RUN_PB_MASK 0x8 ++#define RTL8367C_PB_HLDRMP_VAL_OFFSET 2 ++#define RTL8367C_PB_HLDRMP_VAL_MASK 0x4 ++#define RTL8367C_PB_BISR_BIRSTN_OFFSET 1 ++#define RTL8367C_PB_BISR_BIRSTN_MASK 0x2 ++#define RTL8367C_PB_BISR_PWRSTN_OFFSET 0 ++#define RTL8367C_PB_BISR_PWRSTN_MASK 0x1 ++ ++#define RTL8367C_REG_CVLANRAM_BISR_CTRL 0x1d39 ++#define RTL8367C_SEC_RUN_CVLAN_OFFSET 4 ++#define RTL8367C_SEC_RUN_CVLAN_MASK 0x10 ++#define RTL8367C_CVALN_HLDRMP_MD_OFFSET 3 ++#define RTL8367C_CVALN_HLDRMP_MD_MASK 0x8 ++#define RTL8367C_CVALN_HLDRMP_VAL_OFFSET 2 ++#define RTL8367C_CVALN_HLDRMP_VAL_MASK 0x4 ++#define RTL8367C_CVLAN_BISR_BIRSTN_OFFSET 1 ++#define RTL8367C_CVLAN_BISR_BIRSTN_MASK 0x2 ++#define RTL8367C_CVLAN_BISR_PWRSTN_OFFSET 0 ++#define RTL8367C_CVLAN_BISR_PWRSTN_MASK 0x1 ++ ++#define RTL8367C_REG_CFG_1588_TIMER_EN_GPI 0x1d3a ++#define RTL8367C_CFG_1588_TIMER_EN_GPI_OFFSET 0 ++#define RTL8367C_CFG_1588_TIMER_EN_GPI_MASK 0x1 ++ ++#define RTL8367C_REG_MDIO_PRMB_SUPP 0x1d3b ++#define RTL8367C_FIB_HIPRI_OFFSET 14 ++#define RTL8367C_FIB_HIPRI_MASK 0x4000 ++#define RTL8367C_SMT_EN_OFFSET 13 ++#define RTL8367C_SMT_EN_MASK 0x2000 ++#define RTL8367C_P4_FB_CPL_OFFSET 12 ++#define RTL8367C_P4_FB_CPL_MASK 0x1000 ++#define RTL8367C_P3_FB_CPL_OFFSET 11 ++#define RTL8367C_P3_FB_CPL_MASK 0x800 ++#define RTL8367C_P2_FB_CPL_OFFSET 10 ++#define RTL8367C_P2_FB_CPL_MASK 0x400 ++#define RTL8367C_P1_FB_CPL_OFFSET 9 ++#define RTL8367C_P1_FB_CPL_MASK 0x200 ++#define RTL8367C_P0_FB_CPL_OFFSET 8 ++#define RTL8367C_P0_FB_CPL_MASK 0x100 ++#define RTL8367C_DBG_PKG_8367N_OFFSET 7 ++#define RTL8367C_DBG_PKG_8367N_MASK 0x80 ++#define RTL8367C_DBG_PKG_8367VB_OFFSET 6 ++#define RTL8367C_DBG_PKG_8367VB_MASK 0x40 ++#define RTL8367C_CFG_DEBUG_EN_OFFSET 5 ++#define RTL8367C_CFG_DEBUG_EN_MASK 0x20 ++#define RTL8367C_CFG_TMR_ACK_OFFSET 1 ++#define RTL8367C_CFG_TMR_ACK_MASK 0x1E ++#define RTL8367C_CFG_PRMB_SUPP_OFFSET 0 ++#define RTL8367C_CFG_PRMB_SUPP_MASK 0x1 ++ ++#define RTL8367C_REG_BOND4READ 0x1d3c ++#define RTL8367C_BOND_BOID0_OFFSET 8 ++#define RTL8367C_BOND_BOID0_MASK 0x100 ++#define RTL8367C_BOND_SYSCLK_OFFSET 7 ++#define RTL8367C_BOND_SYSCLK_MASK 0x80 ++#define RTL8367C_BOND_PHYMODE_OFFSET 6 ++#define RTL8367C_BOND_PHYMODE_MASK 0x40 ++#define RTL8367C_BOND_DIS_PON_BIST_OFFSET 5 ++#define RTL8367C_BOND_DIS_PON_BIST_MASK 0x20 ++#define RTL8367C_BOND_DIS_TABLE_INIT_OFFSET 4 ++#define RTL8367C_BOND_DIS_TABLE_INIT_MASK 0x10 ++#define RTL8367C_BOND_BYP_AFE_PLL_OFFSET 3 ++#define RTL8367C_BOND_BYP_AFE_PLL_MASK 0x8 ++#define RTL8367C_BOND_BYP_AFE_POR_OFFSET 2 ++#define RTL8367C_BOND_BYP_AFE_POR_MASK 0x4 ++#define RTL8367C_BOND_BISR_COND_OFFSET 1 ++#define RTL8367C_BOND_BISR_COND_MASK 0x2 ++#define RTL8367C_BOND_EF_EN_OFFSET 0 ++#define RTL8367C_BOND_EF_EN_MASK 0x1 ++ ++#define RTL8367C_REG_REG_TO_ECO0 0x1d3d ++ ++#define RTL8367C_REG_REG_TO_ECO1 0x1d3e ++ ++#define RTL8367C_REG_REG_TO_ECO2 0x1d3f ++ ++#define RTL8367C_REG_REG_TO_ECO3 0x1d40 ++ ++#define RTL8367C_REG_REG_TO_ECO4 0x1d41 ++ ++#define RTL8367C_REG_PHYSTS_CTRL0 0x1d42 ++#define RTL8367C_MACRX_DUPDET_EN_OFFSET 5 ++#define RTL8367C_MACRX_DUPDET_EN_MASK 0x20 ++#define RTL8367C_LNKUP_DLY_EN_OFFSET 4 ++#define RTL8367C_LNKUP_DLY_EN_MASK 0x10 ++#define RTL8367C_GE_100M_LNKUP_DLY_OFFSET 2 ++#define RTL8367C_GE_100M_LNKUP_DLY_MASK 0xC ++#define RTL8367C_PHYSTS_10M_LNKUP_DLY_OFFSET 0 ++#define RTL8367C_PHYSTS_10M_LNKUP_DLY_MASK 0x3 ++ ++#define RTL8367C_REG_SSC_CTRL0_0 0x1d44 ++#define RTL8367C_SSC_CTRL0_0_SSC_TYPE_OFFSET 13 ++#define RTL8367C_SSC_CTRL0_0_SSC_TYPE_MASK 0x2000 ++#define RTL8367C_SSC_CTRL0_0_PHASE_LIM_SEL_OFFSET 5 ++#define RTL8367C_SSC_CTRL0_0_PHASE_LIM_SEL_MASK 0x1FE0 ++#define RTL8367C_SSC_CTRL0_0_PHASE_LIM_EN_OFFSET 4 ++#define RTL8367C_SSC_CTRL0_0_PHASE_LIM_EN_MASK 0x10 ++#define RTL8367C_SSC_CTRL0_0_DLL_MODE_OFFSET 2 ++#define RTL8367C_SSC_CTRL0_0_DLL_MODE_MASK 0xC ++#define RTL8367C_SSC_CTRL0_0_SSC_EN_OFFSET 1 ++#define RTL8367C_SSC_CTRL0_0_SSC_EN_MASK 0x2 ++#define RTL8367C_SSC_CTRL0_0_SSC_MODE_OFFSET 0 ++#define RTL8367C_SSC_CTRL0_0_SSC_MODE_MASK 0x1 ++ ++#define RTL8367C_REG_SSC_RDM_SEED 0x1d45 ++ ++#define RTL8367C_REG_SSC_PN_POLY_SEL 0x1d46 ++ ++#define RTL8367C_REG_SSC_CTRL0_3 0x1d47 ++#define RTL8367C_SSC_CTRL0_3_PHSFT_CNT_OFFSET 8 ++#define RTL8367C_SSC_CTRL0_3_PHSFT_CNT_MASK 0x7F00 ++#define RTL8367C_SSC_CTRL0_3_PHSFT_A_OFFSET 7 ++#define RTL8367C_SSC_CTRL0_3_PHSFT_A_MASK 0x80 ++#define RTL8367C_SSC_CTRL0_3_PHSFT_B_OFFSET 6 ++#define RTL8367C_SSC_CTRL0_3_PHSFT_B_MASK 0x40 ++#define RTL8367C_SSC_CTRL0_3_PHSFT_UPDN_OFFSET 5 ++#define RTL8367C_SSC_CTRL0_3_PHSFT_UPDN_MASK 0x20 ++#define RTL8367C_SSC_CTRL0_3_PHSFT_PRD_OFFSET 4 ++#define RTL8367C_SSC_CTRL0_3_PHSFT_PRD_MASK 0x10 ++#define RTL8367C_SSC_CTRL0_3_PN_POLY_DEG_OFFSET 0 ++#define RTL8367C_SSC_CTRL0_3_PN_POLY_DEG_MASK 0xF ++ ++#define RTL8367C_REG_SSC_CTRL0_4 0x1d48 ++#define RTL8367C_SSC_CTRL0_4_SSC_UP1DN0_OFFSET 15 ++#define RTL8367C_SSC_CTRL0_4_SSC_UP1DN0_MASK 0x8000 ++#define RTL8367C_SSC_CTRL0_4_SSC_PERIOD_OFFSET 8 ++#define RTL8367C_SSC_CTRL0_4_SSC_PERIOD_MASK 0x7F00 ++#define RTL8367C_SSC_CTRL0_4_SSC_OFFSET_OFFSET 0 ++#define RTL8367C_SSC_CTRL0_4_SSC_OFFSET_MASK 0xFF ++ ++#define RTL8367C_REG_SSC_CTRL0_5 0x1d49 ++#define RTL8367C_SSC_CTRL0_5_PH_OFS_TOG_OFFSET 15 ++#define RTL8367C_SSC_CTRL0_5_PH_OFS_TOG_MASK 0x8000 ++#define RTL8367C_SSC_CTRL0_5_PH_OFS_OFFSET 10 ++#define RTL8367C_SSC_CTRL0_5_PH_OFS_MASK 0x7C00 ++#define RTL8367C_SSC_CTRL0_5_SSC_STEP_OFFSET 4 ++#define RTL8367C_SSC_CTRL0_5_SSC_STEP_MASK 0x3F0 ++#define RTL8367C_SSC_CTRL0_5_SSC_TEST_MODE_OFFSET 2 ++#define RTL8367C_SSC_CTRL0_5_SSC_TEST_MODE_MASK 0xC ++#define RTL8367C_SSC_CTRL0_5_SSC_PH_CFG_OFFSET 0 ++#define RTL8367C_SSC_CTRL0_5_SSC_PH_CFG_MASK 0x3 ++ ++#define RTL8367C_REG_SSC_STS0 0x1d4a ++#define RTL8367C_SSC_STS0_OFS_BUSY_OFFSET 13 ++#define RTL8367C_SSC_STS0_OFS_BUSY_MASK 0x2000 ++#define RTL8367C_SSC_STS0_OFS_TOTAL_R_OFFSET 8 ++#define RTL8367C_SSC_STS0_OFS_TOTAL_R_MASK 0x1F00 ++#define RTL8367C_SSC_STS0_CNT_GRY0_OFFSET 4 ++#define RTL8367C_SSC_STS0_CNT_GRY0_MASK 0xF0 ++#define RTL8367C_SSC_STS0_OFS_GRY0_OFFSET 0 ++#define RTL8367C_SSC_STS0_OFS_GRY0_MASK 0xF ++ ++#define RTL8367C_REG_SSC_CTRL1_0 0x1d4b ++#define RTL8367C_SSC_CTRL1_0_SSC_TYPE_OFFSET 13 ++#define RTL8367C_SSC_CTRL1_0_SSC_TYPE_MASK 0x2000 ++#define RTL8367C_SSC_CTRL1_0_PHASE_LIM_SEL_OFFSET 5 ++#define RTL8367C_SSC_CTRL1_0_PHASE_LIM_SEL_MASK 0x1FE0 ++#define RTL8367C_SSC_CTRL1_0_PHASE_LIM_EN_OFFSET 4 ++#define RTL8367C_SSC_CTRL1_0_PHASE_LIM_EN_MASK 0x10 ++#define RTL8367C_SSC_CTRL1_0_DLL_MODE_OFFSET 2 ++#define RTL8367C_SSC_CTRL1_0_DLL_MODE_MASK 0xC ++#define RTL8367C_SSC_CTRL1_0_SSC_EN_OFFSET 1 ++#define RTL8367C_SSC_CTRL1_0_SSC_EN_MASK 0x2 ++#define RTL8367C_SSC_CTRL1_0_SSC_MODE_OFFSET 0 ++#define RTL8367C_SSC_CTRL1_0_SSC_MODE_MASK 0x1 ++ ++#define RTL8367C_REG_SSC_RDM_SEED1 0x1d4c ++ ++#define RTL8367C_REG_SSC_PN_POLY_SEL1 0x1d4d ++ ++#define RTL8367C_REG_SSC_CTRL1_3 0x1d4e ++#define RTL8367C_SSC_CTRL1_3_PHSFT_CNT_OFFSET 8 ++#define RTL8367C_SSC_CTRL1_3_PHSFT_CNT_MASK 0x7F00 ++#define RTL8367C_SSC_CTRL1_3_PHSFT_A_OFFSET 7 ++#define RTL8367C_SSC_CTRL1_3_PHSFT_A_MASK 0x80 ++#define RTL8367C_SSC_CTRL1_3_PHSFT_B_OFFSET 6 ++#define RTL8367C_SSC_CTRL1_3_PHSFT_B_MASK 0x40 ++#define RTL8367C_SSC_CTRL1_3_PHSFT_UPDN_OFFSET 5 ++#define RTL8367C_SSC_CTRL1_3_PHSFT_UPDN_MASK 0x20 ++#define RTL8367C_SSC_CTRL1_3_PHSFT_PRD_OFFSET 4 ++#define RTL8367C_SSC_CTRL1_3_PHSFT_PRD_MASK 0x10 ++#define RTL8367C_SSC_CTRL1_3_PN_POLY_DEG_OFFSET 0 ++#define RTL8367C_SSC_CTRL1_3_PN_POLY_DEG_MASK 0xF ++ ++#define RTL8367C_REG_SSC_CTRL1_4 0x1d4f ++#define RTL8367C_SSC_CTRL1_4_SSC_UP1DN0_OFFSET 15 ++#define RTL8367C_SSC_CTRL1_4_SSC_UP1DN0_MASK 0x8000 ++#define RTL8367C_SSC_CTRL1_4_SSC_PERIOD_OFFSET 8 ++#define RTL8367C_SSC_CTRL1_4_SSC_PERIOD_MASK 0x7F00 ++#define RTL8367C_SSC_CTRL1_4_SSC_OFFSET_OFFSET 0 ++#define RTL8367C_SSC_CTRL1_4_SSC_OFFSET_MASK 0xFF ++ ++#define RTL8367C_REG_SSC_CTRL1_5 0x1d50 ++#define RTL8367C_SSC_CTRL1_5_PH_OFS_TOG_OFFSET 15 ++#define RTL8367C_SSC_CTRL1_5_PH_OFS_TOG_MASK 0x8000 ++#define RTL8367C_SSC_CTRL1_5_PH_OFS_OFFSET 10 ++#define RTL8367C_SSC_CTRL1_5_PH_OFS_MASK 0x7C00 ++#define RTL8367C_SSC_CTRL1_5_SSC_STEP_OFFSET 4 ++#define RTL8367C_SSC_CTRL1_5_SSC_STEP_MASK 0x3F0 ++#define RTL8367C_SSC_CTRL1_5_SSC_TEST_MODE_OFFSET 2 ++#define RTL8367C_SSC_CTRL1_5_SSC_TEST_MODE_MASK 0xC ++#define RTL8367C_SSC_CTRL1_5_SSC_PH_CFG_OFFSET 0 ++#define RTL8367C_SSC_CTRL1_5_SSC_PH_CFG_MASK 0x3 ++ ++#define RTL8367C_REG_SSC_STS1 0x1d51 ++#define RTL8367C_SSC_STS1_OFS_BUSY_OFFSET 13 ++#define RTL8367C_SSC_STS1_OFS_BUSY_MASK 0x2000 ++#define RTL8367C_SSC_STS1_OFS_TOTAL_R_OFFSET 8 ++#define RTL8367C_SSC_STS1_OFS_TOTAL_R_MASK 0x1F00 ++#define RTL8367C_SSC_STS1_CNT_GRY0_OFFSET 4 ++#define RTL8367C_SSC_STS1_CNT_GRY0_MASK 0xF0 ++#define RTL8367C_SSC_STS1_OFS_GRY0_OFFSET 0 ++#define RTL8367C_SSC_STS1_OFS_GRY0_MASK 0xF ++ ++#define RTL8367C_REG_SSC_CTRL2_0 0x1d52 ++#define RTL8367C_SSC_CTRL2_0_SSC_TYPE_OFFSET 13 ++#define RTL8367C_SSC_CTRL2_0_SSC_TYPE_MASK 0x2000 ++#define RTL8367C_SSC_CTRL2_0_PHASE_LIM_SEL_OFFSET 5 ++#define RTL8367C_SSC_CTRL2_0_PHASE_LIM_SEL_MASK 0x1FE0 ++#define RTL8367C_SSC_CTRL2_0_PHASE_LIM_EN_OFFSET 4 ++#define RTL8367C_SSC_CTRL2_0_PHASE_LIM_EN_MASK 0x10 ++#define RTL8367C_SSC_CTRL2_0_DLL_MODE_OFFSET 2 ++#define RTL8367C_SSC_CTRL2_0_DLL_MODE_MASK 0xC ++#define RTL8367C_SSC_CTRL2_0_SSC_EN_OFFSET 1 ++#define RTL8367C_SSC_CTRL2_0_SSC_EN_MASK 0x2 ++#define RTL8367C_SSC_CTRL2_0_SSC_MODE_OFFSET 0 ++#define RTL8367C_SSC_CTRL2_0_SSC_MODE_MASK 0x1 ++ ++#define RTL8367C_REG_SSC_RDM_SEED2 0x1d53 ++ ++#define RTL8367C_REG_SSC_PN_POLY_SEL2 0x1d54 ++ ++#define RTL8367C_REG_SSC_CTRL2_3 0x1d55 ++#define RTL8367C_SSC_CTRL2_3_PHSFT_CNT_OFFSET 8 ++#define RTL8367C_SSC_CTRL2_3_PHSFT_CNT_MASK 0x7F00 ++#define RTL8367C_SSC_CTRL2_3_PHSFT_A_OFFSET 7 ++#define RTL8367C_SSC_CTRL2_3_PHSFT_A_MASK 0x80 ++#define RTL8367C_SSC_CTRL2_3_PHSFT_B_OFFSET 6 ++#define RTL8367C_SSC_CTRL2_3_PHSFT_B_MASK 0x40 ++#define RTL8367C_SSC_CTRL2_3_PHSFT_UPDN_OFFSET 5 ++#define RTL8367C_SSC_CTRL2_3_PHSFT_UPDN_MASK 0x20 ++#define RTL8367C_SSC_CTRL2_3_PHSFT_PRD_OFFSET 4 ++#define RTL8367C_SSC_CTRL2_3_PHSFT_PRD_MASK 0x10 ++#define RTL8367C_SSC_CTRL2_3_PN_POLY_DEG_OFFSET 0 ++#define RTL8367C_SSC_CTRL2_3_PN_POLY_DEG_MASK 0xF ++ ++#define RTL8367C_REG_SSC_CTRL2_4 0x1d56 ++#define RTL8367C_SSC_CTRL2_4_SSC_UP1DN0_OFFSET 15 ++#define RTL8367C_SSC_CTRL2_4_SSC_UP1DN0_MASK 0x8000 ++#define RTL8367C_SSC_CTRL2_4_SSC_PERIOD_OFFSET 8 ++#define RTL8367C_SSC_CTRL2_4_SSC_PERIOD_MASK 0x7F00 ++#define RTL8367C_SSC_CTRL2_4_SSC_OFFSET_OFFSET 0 ++#define RTL8367C_SSC_CTRL2_4_SSC_OFFSET_MASK 0xFF ++ ++#define RTL8367C_REG_SSC_CTRL2_5 0x1d57 ++#define RTL8367C_SSC_CTRL2_5_PH_OFS_TOG_OFFSET 15 ++#define RTL8367C_SSC_CTRL2_5_PH_OFS_TOG_MASK 0x8000 ++#define RTL8367C_SSC_CTRL2_5_PH_OFS_OFFSET 10 ++#define RTL8367C_SSC_CTRL2_5_PH_OFS_MASK 0x7C00 ++#define RTL8367C_SSC_CTRL2_5_SSC_STEP_OFFSET 4 ++#define RTL8367C_SSC_CTRL2_5_SSC_STEP_MASK 0x3F0 ++#define RTL8367C_SSC_CTRL2_5_SSC_TEST_MODE_OFFSET 2 ++#define RTL8367C_SSC_CTRL2_5_SSC_TEST_MODE_MASK 0xC ++#define RTL8367C_SSC_CTRL2_5_SSC_PH_CFG_OFFSET 0 ++#define RTL8367C_SSC_CTRL2_5_SSC_PH_CFG_MASK 0x3 ++ ++#define RTL8367C_REG_SSC_STS2 0x1d58 ++#define RTL8367C_SSC_STS2_OFS_BUSY_OFFSET 13 ++#define RTL8367C_SSC_STS2_OFS_BUSY_MASK 0x2000 ++#define RTL8367C_SSC_STS2_OFS_TOTAL_R_OFFSET 8 ++#define RTL8367C_SSC_STS2_OFS_TOTAL_R_MASK 0x1F00 ++#define RTL8367C_SSC_STS2_CNT_GRY0_OFFSET 4 ++#define RTL8367C_SSC_STS2_CNT_GRY0_MASK 0xF0 ++#define RTL8367C_SSC_STS2_OFS_GRY0_OFFSET 0 ++#define RTL8367C_SSC_STS2_OFS_GRY0_MASK 0xF ++ ++#define RTL8367C_REG_SSC_CTRL3_0 0x1d59 ++#define RTL8367C_SSC_CTRL3_0_SSC_TYPE_OFFSET 13 ++#define RTL8367C_SSC_CTRL3_0_SSC_TYPE_MASK 0x2000 ++#define RTL8367C_SSC_CTRL3_0_PHASE_LIM_SEL_OFFSET 5 ++#define RTL8367C_SSC_CTRL3_0_PHASE_LIM_SEL_MASK 0x1FE0 ++#define RTL8367C_SSC_CTRL3_0_PHASE_LIM_EN_OFFSET 4 ++#define RTL8367C_SSC_CTRL3_0_PHASE_LIM_EN_MASK 0x10 ++#define RTL8367C_SSC_CTRL3_0_DLL_MODE_OFFSET 2 ++#define RTL8367C_SSC_CTRL3_0_DLL_MODE_MASK 0xC ++#define RTL8367C_SSC_CTRL3_0_SSC_EN_OFFSET 1 ++#define RTL8367C_SSC_CTRL3_0_SSC_EN_MASK 0x2 ++#define RTL8367C_SSC_CTRL3_0_SSC_MODE_OFFSET 0 ++#define RTL8367C_SSC_CTRL3_0_SSC_MODE_MASK 0x1 ++ ++#define RTL8367C_REG_SSC_RDM_SEED3 0x1d5a ++ ++#define RTL8367C_REG_SSC_PN_POLY_SEL3 0x1d5b ++ ++#define RTL8367C_REG_SSC_CTRL3_3 0x1d5c ++#define RTL8367C_SSC_CTRL3_3_PHSFT_CNT_OFFSET 8 ++#define RTL8367C_SSC_CTRL3_3_PHSFT_CNT_MASK 0x7F00 ++#define RTL8367C_SSC_CTRL3_3_PHSFT_A_OFFSET 7 ++#define RTL8367C_SSC_CTRL3_3_PHSFT_A_MASK 0x80 ++#define RTL8367C_SSC_CTRL3_3_PHSFT_B_OFFSET 6 ++#define RTL8367C_SSC_CTRL3_3_PHSFT_B_MASK 0x40 ++#define RTL8367C_SSC_CTRL3_3_PHSFT_UPDN_OFFSET 5 ++#define RTL8367C_SSC_CTRL3_3_PHSFT_UPDN_MASK 0x20 ++#define RTL8367C_SSC_CTRL3_3_PHSFT_PRD_OFFSET 4 ++#define RTL8367C_SSC_CTRL3_3_PHSFT_PRD_MASK 0x10 ++#define RTL8367C_SSC_CTRL3_3_PN_POLY_DEG_OFFSET 0 ++#define RTL8367C_SSC_CTRL3_3_PN_POLY_DEG_MASK 0xF ++ ++#define RTL8367C_REG_SSC_CTRL3_4 0x1d5d ++#define RTL8367C_SSC_CTRL3_4_SSC_UP1DN0_OFFSET 15 ++#define RTL8367C_SSC_CTRL3_4_SSC_UP1DN0_MASK 0x8000 ++#define RTL8367C_SSC_CTRL3_4_SSC_PERIOD_OFFSET 8 ++#define RTL8367C_SSC_CTRL3_4_SSC_PERIOD_MASK 0x7F00 ++#define RTL8367C_SSC_CTRL3_4_SSC_OFFSET_OFFSET 0 ++#define RTL8367C_SSC_CTRL3_4_SSC_OFFSET_MASK 0xFF ++ ++#define RTL8367C_REG_SSC_CTRL3_5 0x1d5e ++#define RTL8367C_SSC_CTRL3_5_PH_OFS_TOG_OFFSET 15 ++#define RTL8367C_SSC_CTRL3_5_PH_OFS_TOG_MASK 0x8000 ++#define RTL8367C_SSC_CTRL3_5_PH_OFS_OFFSET 10 ++#define RTL8367C_SSC_CTRL3_5_PH_OFS_MASK 0x7C00 ++#define RTL8367C_SSC_CTRL3_5_SSC_STEP_OFFSET 4 ++#define RTL8367C_SSC_CTRL3_5_SSC_STEP_MASK 0x3F0 ++#define RTL8367C_SSC_CTRL3_5_SSC_TEST_MODE_OFFSET 2 ++#define RTL8367C_SSC_CTRL3_5_SSC_TEST_MODE_MASK 0xC ++#define RTL8367C_SSC_CTRL3_5_SSC_PH_CFG_OFFSET 0 ++#define RTL8367C_SSC_CTRL3_5_SSC_PH_CFG_MASK 0x3 ++ ++#define RTL8367C_REG_SSC_STS3 0x1d5f ++#define RTL8367C_SSC_STS3_OFS_BUSY_OFFSET 13 ++#define RTL8367C_SSC_STS3_OFS_BUSY_MASK 0x2000 ++#define RTL8367C_SSC_STS3_OFS_TOTAL_R_OFFSET 8 ++#define RTL8367C_SSC_STS3_OFS_TOTAL_R_MASK 0x1F00 ++#define RTL8367C_SSC_STS3_CNT_GRY0_OFFSET 4 ++#define RTL8367C_SSC_STS3_CNT_GRY0_MASK 0xF0 ++#define RTL8367C_SSC_STS3_OFS_GRY0_OFFSET 0 ++#define RTL8367C_SSC_STS3_OFS_GRY0_MASK 0xF ++ ++#define RTL8367C_REG_PHY_POLL_CFG13 0x1d60 ++ ++#define RTL8367C_REG_PHY_POLL_CFG14 0x1d61 ++ ++#define RTL8367C_REG_FRC_SYS_CLK 0x1d62 ++#define RTL8367C_SYSCLK_FRC_MD_OFFSET 1 ++#define RTL8367C_SYSCLK_FRC_MD_MASK 0x2 ++#define RTL8367C_SYSCLK_FRC_VAL_OFFSET 0 ++#define RTL8367C_SYSCLK_FRC_VAL_MASK 0x1 ++ ++#define RTL8367C_REG_AFE_SSC_CTRL 0x1d63 ++#define RTL8367C_PH_RSTB_TXD1_OFFSET 9 ++#define RTL8367C_PH_RSTB_TXD1_MASK 0x200 ++#define RTL8367C_PH_RSTB_TXC1_OFFSET 8 ++#define RTL8367C_PH_RSTB_TXC1_MASK 0x100 ++#define RTL8367C_PH_RSTB_TXD0_OFFSET 7 ++#define RTL8367C_PH_RSTB_TXD0_MASK 0x80 ++#define RTL8367C_PH_RSTB_TXC0_OFFSET 6 ++#define RTL8367C_PH_RSTB_TXC0_MASK 0x40 ++#define RTL8367C_PH_RSTBSYS_OFFSET 5 ++#define RTL8367C_PH_RSTBSYS_MASK 0x20 ++#define RTL8367C_PH_RSTB8051_OFFSET 4 ++#define RTL8367C_PH_RSTB8051_MASK 0x10 ++#define RTL8367C_OREG_SSC_OFFSET 0 ++#define RTL8367C_OREG_SSC_MASK 0xF ++ ++#define RTL8367C_REG_BUFF_RST_CTRL0 0x1d64 ++#define RTL8367C_BUFFRST_TXESD_EN_OFFSET 13 ++#define RTL8367C_BUFFRST_TXESD_EN_MASK 0x2000 ++#define RTL8367C_BUFF_RST_TIME_LONG_OFFSET 8 ++#define RTL8367C_BUFF_RST_TIME_LONG_MASK 0x1F00 ++#define RTL8367C_BUFF_RST_TIME_SHORT_OFFSET 3 ++#define RTL8367C_BUFF_RST_TIME_SHORT_MASK 0xF8 ++#define RTL8367C_SW_BUFF_RST_OFFSET 2 ++#define RTL8367C_SW_BUFF_RST_MASK 0x4 ++#define RTL8367C_IMS_BUFF_RST_OFFSET 1 ++#define RTL8367C_IMS_BUFF_RST_MASK 0x2 ++#define RTL8367C_IMR_BUFF_RST_OFFSET 0 ++#define RTL8367C_IMR_BUFF_RST_MASK 0x1 ++ ++#define RTL8367C_REG_BUFF_RST_CTRL1 0x1d65 ++#define RTL8367C_BUFFRST_SYSOVER_EN_OFFSET 10 ++#define RTL8367C_BUFFRST_SYSOVER_EN_MASK 0x400 ++#define RTL8367C_BUFFRST_SYSOVER_THR_OFFSET 0 ++#define RTL8367C_BUFFRST_SYSOVER_THR_MASK 0x3FF ++ ++#define RTL8367C_REG_BUFF_RST_CTRL2 0x1d66 ++#define RTL8367C_BUFFRST_QOVER_EN_OFFSET 10 ++#define RTL8367C_BUFFRST_QOVER_EN_MASK 0x400 ++#define RTL8367C_BUFFRST_QOVER_THR_OFFSET 0 ++#define RTL8367C_BUFFRST_QOVER_THR_MASK 0x3FF ++ ++#define RTL8367C_REG_BUFF_RST_CTRL3 0x1d67 ++#define RTL8367C_DSC_TIMER_OFFSET 11 ++#define RTL8367C_DSC_TIMER_MASK 0x7800 ++#define RTL8367C_BUFFRST_DSCOVER_THR_OFFSET 1 ++#define RTL8367C_BUFFRST_DSCOVER_THR_MASK 0x7FE ++#define RTL8367C_BUFFRST_DSCOVER_EN_OFFSET 0 ++#define RTL8367C_BUFFRST_DSCOVER_EN_MASK 0x1 ++ ++#define RTL8367C_REG_BUFF_RST_CTRL4 0x1d68 ++#define RTL8367C_INDSC_TIMER_OFFSET 11 ++#define RTL8367C_INDSC_TIMER_MASK 0x7800 ++#define RTL8367C_BUFFRST_INDSCOVER_THR_OFFSET 1 ++#define RTL8367C_BUFFRST_INDSCOVER_THR_MASK 0x7FE ++#define RTL8367C_BUFFRST_INDSCOVER_EN_OFFSET 0 ++#define RTL8367C_BUFFRST_INDSCOVER_EN_MASK 0x1 ++ ++#define RTL8367C_REG_BUFF_RST_CTRL5 0x1d69 ++#define RTL8367C_TX_ESD_MODE_OFFSET 8 ++#define RTL8367C_TX_ESD_MODE_MASK 0x100 ++#define RTL8367C_TX_ESD_LVL_OFFSET 0 ++#define RTL8367C_TX_ESD_LVL_MASK 0xFF ++ ++#define RTL8367C_REG_TOP_CON0 0x1d70 ++#define RTL8367C_TOP_CON0_SDS_PWR_ISO_1_OFFSET 15 ++#define RTL8367C_TOP_CON0_SDS_PWR_ISO_1_MASK 0x8000 ++#define RTL8367C_OCP_TIMEOUT_P7_5_OFFSET 12 ++#define RTL8367C_OCP_TIMEOUT_P7_5_MASK 0x7000 ++#define RTL8367C_FIB_EEE_AB_OFFSET 11 ++#define RTL8367C_FIB_EEE_AB_MASK 0x800 ++#define RTL8367C_ADCCKIEN_OFFSET 10 ++#define RTL8367C_ADCCKIEN_MASK 0x400 ++#define RTL8367C_OCP_TIMEOUT_OFFSET 5 ++#define RTL8367C_OCP_TIMEOUT_MASK 0x3E0 ++#define RTL8367C_TOP_CON0_SDS_PWR_ISO_OFFSET 4 ++#define RTL8367C_TOP_CON0_SDS_PWR_ISO_MASK 0x10 ++#define RTL8367C_RG2_TXC_SEL_OFFSET 3 ++#define RTL8367C_RG2_TXC_SEL_MASK 0x8 ++#define RTL8367C_RG1TXC_SEL_OFFSET 2 ++#define RTL8367C_RG1TXC_SEL_MASK 0x4 ++#define RTL8367C_SYNC_1588_EN_OFFSET 1 ++#define RTL8367C_SYNC_1588_EN_MASK 0x2 ++#define RTL8367C_LS_MODE_OFFSET 0 ++#define RTL8367C_LS_MODE_MASK 0x1 ++ ++#define RTL8367C_REG_TOP_CON1 0x1d71 ++#define RTL8367C_TA_CHK_EN_OFFSET 2 ++#define RTL8367C_TA_CHK_EN_MASK 0x4 ++#define RTL8367C_SLV_EG_SEL_OFFSET 1 ++#define RTL8367C_SLV_EG_SEL_MASK 0x2 ++#define RTL8367C_IIC_OP_DRAIN_OFFSET 0 ++#define RTL8367C_IIC_OP_DRAIN_MASK 0x1 ++ ++#define RTL8367C_REG_SWR_FPWM 0x1d72 ++#define RTL8367C_SWR_FPWM_OFFSET 0 ++#define RTL8367C_SWR_FPWM_MASK 0x1 ++ ++#define RTL8367C_REG_EEEP_CTRL_500M 0x1d73 ++ ++#define RTL8367C_REG_SHORT_PRMB 0x1d74 ++#define RTL8367C_SHORT_PRMB_OFFSET 0 ++#define RTL8367C_SHORT_PRMB_MASK 0x1 ++ ++#define RTL8367C_REG_INDSC_THR_CTRL 0x1d75 ++#define RTL8367C_INDSC_THR_CTRL_OFFSET 0 ++#define RTL8367C_INDSC_THR_CTRL_MASK 0x7FF ++ ++#define RTL8367C_REG_SET_PAD_CTRL_NEW 0x1d80 ++#define RTL8367C_SET_PAD_CTRL_NEW_OFFSET 0 ++#define RTL8367C_SET_PAD_CTRL_NEW_MASK 0x1 ++ ++#define RTL8367C_REG_SET_PAD_DRI_0 0x1d81 ++ ++#define RTL8367C_REG_SET_PAD_DRI_1 0x1d82 ++ ++#define RTL8367C_REG_SET_PAD_DRI_2 0x1d83 ++ ++#define RTL8367C_REG_SET_PAD_SLEW_0 0x1d84 ++ ++#define RTL8367C_REG_SET_PAD_SLEW_1 0x1d85 ++ ++#define RTL8367C_REG_SET_PAD_SLEW_2 0x1d86 ++ ++#define RTL8367C_REG_SET_PAD_SMT_0 0x1d87 ++ ++#define RTL8367C_REG_SET_PAD_SMT_1 0x1d88 ++ ++#define RTL8367C_REG_SET_PAD_SMT_2 0x1d89 ++ ++#define RTL8367C_REG_M_I2C_CTL_STA_REG 0x1d8a ++#define RTL8367C_TX_RX_DATA_OFFSET 8 ++#define RTL8367C_TX_RX_DATA_MASK 0xFF00 ++#define RTL8367C_DUMB_RW_ERR_OFFSET 7 ++#define RTL8367C_DUMB_RW_ERR_MASK 0x80 ++#define RTL8367C_SLV_ACK_FLAG_OFFSET 6 ++#define RTL8367C_SLV_ACK_FLAG_MASK 0x40 ++#define RTL8367C_M_I2C_BUS_IDLE_OFFSET 5 ++#define RTL8367C_M_I2C_BUS_IDLE_MASK 0x20 ++#define RTL8367C_I2C_CMD_TYPE_OFFSET 1 ++#define RTL8367C_I2C_CMD_TYPE_MASK 0x1E ++#define RTL8367C_I2C_CMD_EXEC_OFFSET 0 ++#define RTL8367C_I2C_CMD_EXEC_MASK 0x1 ++ ++#define RTL8367C_REG_M_I2C_DUMB_RW_ADDR_0 0x1d8b ++ ++#define RTL8367C_REG_M_I2C_DUMB_RW_ADDR_1 0x1d8c ++ ++#define RTL8367C_REG_M_I2C_DUMB_RW_DATA_0 0x1d8d ++ ++#define RTL8367C_REG_M_I2C_DUMB_RW_DATA_1 0x1d8e ++ ++#define RTL8367C_REG_M_I2C_DUMB_RW_CTL 0x1d8f ++#define RTL8367C_DUMB_I2C_CTL_CODE_OFFSET 8 ++#define RTL8367C_DUMB_I2C_CTL_CODE_MASK 0x7F00 ++#define RTL8367C_DUMB_RW_I2C_FORMAT_OFFSET 4 ++#define RTL8367C_DUMB_RW_I2C_FORMAT_MASK 0x10 ++#define RTL8367C_DUMB_RW_DATA_MODE_OFFSET 2 ++#define RTL8367C_DUMB_RW_DATA_MODE_MASK 0xC ++#define RTL8367C_DUMB_RW_ADDR_MODE_OFFSET 0 ++#define RTL8367C_DUMB_RW_ADDR_MODE_MASK 0x3 ++ ++#define RTL8367C_REG_M_I2C_SYS_CTL 0x1d90 ++#define RTL8367C_M_I2C_SCL_IO_MUX_OFFSET 12 ++#define RTL8367C_M_I2C_SCL_IO_MUX_MASK 0x3000 ++#define RTL8367C_M_I2C_SDA_IO_MUX_OFFSET 10 ++#define RTL8367C_M_I2C_SDA_IO_MUX_MASK 0xC00 ++#define RTL8367C_M_I2C_SDA_OD_EN_OFFSET 9 ++#define RTL8367C_M_I2C_SDA_OD_EN_MASK 0x200 ++#define RTL8367C_M_I2C_SCL_OD_EN_OFFSET 8 ++#define RTL8367C_M_I2C_SCL_OD_EN_MASK 0x100 ++#define RTL8367C_M_I2C_SCL_F_DIV_OFFSET 0 ++#define RTL8367C_M_I2C_SCL_F_DIV_MASK 0xFF ++ ++#define RTL8367C_REG_HT_PB_SRAM_CTRL 0x1da0 ++#define RTL8367C_HTPB_RW_OFFSET 2 ++#define RTL8367C_HTPB_RW_MASK 0x4 ++#define RTL8367C_HTPB_SEL_OFFSET 1 ++#define RTL8367C_HTPB_SEL_MASK 0x2 ++#define RTL8367C_HTPB_CE_OFFSET 0 ++#define RTL8367C_HTPB_CE_MASK 0x1 ++ ++#define RTL8367C_REG_HT_PB_SRAM_ADDR 0x1da1 ++ ++#define RTL8367C_REG_HT_PB_SRAM_DIN0 0x1da2 ++ ++#define RTL8367C_REG_HT_PB_SRAM_DIN1 0x1da3 ++ ++#define RTL8367C_REG_HT_PB_SRAM_DOUT0 0x1da4 ++ ++#define RTL8367C_REG_HT_PB_SRAM_DOUT1 0x1da5 ++ ++#define RTL8367C_REG_PHY_STAT_0 0x1db0 ++ ++#define RTL8367C_REG_PHY_STAT_1 0x1db1 ++ ++#define RTL8367C_REG_PHY_STAT_2 0x1db2 ++ ++#define RTL8367C_REG_PHY_STAT_3 0x1db3 ++ ++#define RTL8367C_REG_PHY_STAT_4 0x1db4 ++ ++#define RTL8367C_REG_PHY_STAT_5 0x1db5 ++ ++#define RTL8367C_REG_PHY_STAT_6 0x1db6 ++ ++#define RTL8367C_REG_PHY_STAT_7 0x1db7 ++ ++#define RTL8367C_REG_SDS_STAT_0 0x1db8 ++ ++#define RTL8367C_REG_SDS_STAT_1 0x1db9 ++ ++#define RTL8367C_REG_MAC_LINK_STAT_0 0x1dba ++#define RTL8367C_MAC_LINK_STAT_CUR_0_OFFSET 8 ++#define RTL8367C_MAC_LINK_STAT_CUR_0_MASK 0xFF00 ++#define RTL8367C_MAC_LINK_STAT_LATCH_0_OFFSET 0 ++#define RTL8367C_MAC_LINK_STAT_LATCH_0_MASK 0xFF ++ ++#define RTL8367C_REG_MAC_LINK_STAT_1 0x1dbb ++#define RTL8367C_MAC_LINK_STAT_1_Reserved_OFFSET 6 ++#define RTL8367C_MAC_LINK_STAT_1_Reserved_MASK 0xFFC0 ++#define RTL8367C_MAC_LINK_STAT_CUR_1_OFFSET 3 ++#define RTL8367C_MAC_LINK_STAT_CUR_1_MASK 0x38 ++#define RTL8367C_MAC_LINK_STAT_LATCH_1_OFFSET 0 ++#define RTL8367C_MAC_LINK_STAT_LATCH_1_MASK 0x7 ++ ++#define RTL8367C_REG_MISC_CONTROL_1 0x1dc0 ++#define RTL8367C_P7_FB_CPL_OFFSET 2 ++#define RTL8367C_P7_FB_CPL_MASK 0x4 ++#define RTL8367C_P6_FB_CPL_OFFSET 1 ++#define RTL8367C_P6_FB_CPL_MASK 0x2 ++#define RTL8367C_P5_FB_CPL_OFFSET 0 ++#define RTL8367C_P5_FB_CPL_MASK 0x1 ++ ++#define RTL8367C_REG_SDS_MISC_1 0x1dc1 ++#define RTL8367C_CFG_SGMII_RXFC_1_OFFSET 14 ++#define RTL8367C_CFG_SGMII_RXFC_1_MASK 0x4000 ++#define RTL8367C_CFG_SGMII_TXFC_1_OFFSET 13 ++#define RTL8367C_CFG_SGMII_TXFC_1_MASK 0x2000 ++#define RTL8367C_CFG_MAC9_SEL_HSGMII_OFFSET 11 ++#define RTL8367C_CFG_MAC9_SEL_HSGMII_MASK 0x800 ++#define RTL8367C_CFG_SGMII_FDUP_1_OFFSET 10 ++#define RTL8367C_CFG_SGMII_FDUP_1_MASK 0x400 ++#define RTL8367C_CFG_SGMII_LINK_1_OFFSET 9 ++#define RTL8367C_CFG_SGMII_LINK_1_MASK 0x200 ++#define RTL8367C_CFG_SGMII_SPD_1_OFFSET 7 ++#define RTL8367C_CFG_SGMII_SPD_1_MASK 0x180 ++#define RTL8367C_CFG_MAC9_SEL_SGMII_OFFSET 6 ++#define RTL8367C_CFG_MAC9_SEL_SGMII_MASK 0x40 ++#define RTL8367C_CFG_SDS_MODE_14C_1_OFFSET 0 ++#define RTL8367C_CFG_SDS_MODE_14C_1_MASK 0x7 ++ ++#define RTL8367C_REG_FIBER_CFG_2_1 0x1dc2 ++#define RTL8367C_SDS_RX_DISABLE_1_OFFSET 6 ++#define RTL8367C_SDS_RX_DISABLE_1_MASK 0xC0 ++#define RTL8367C_SDS_TX_DISABLE_1_OFFSET 4 ++#define RTL8367C_SDS_TX_DISABLE_1_MASK 0x30 ++#define RTL8367C_FIBER_CFG_2_1_SDS_PWR_ISO_1_OFFSET 2 ++#define RTL8367C_FIBER_CFG_2_1_SDS_PWR_ISO_1_MASK 0xC ++#define RTL8367C_SDS_FRC_LD_1_OFFSET 0 ++#define RTL8367C_SDS_FRC_LD_1_MASK 0x3 ++ ++#define RTL8367C_REG_FIBER_CFG_1_1 0x1dc3 ++#define RTL8367C_SDS_FRC_REG4_1_OFFSET 12 ++#define RTL8367C_SDS_FRC_REG4_1_MASK 0x1000 ++#define RTL8367C_SDS_FRC_REG4_FIB100_1_OFFSET 11 ++#define RTL8367C_SDS_FRC_REG4_FIB100_1_MASK 0x800 ++#define RTL8367C_SDS_FRC_MODE_1_OFFSET 3 ++#define RTL8367C_SDS_FRC_MODE_1_MASK 0x8 ++#define RTL8367C_SDS_MODE_1_OFFSET 0 ++#define RTL8367C_SDS_MODE_1_MASK 0x7 ++ ++#define RTL8367C_REG_PHYSTS_CTRL0_1 0x1dc4 ++#define RTL8367C_LNKUP_DLY_EN_EXT2_OFFSET 9 ++#define RTL8367C_LNKUP_DLY_EN_EXT2_MASK 0x200 ++#define RTL8367C_GE_100M_LNKUP_DLY_EXT2_OFFSET 7 ++#define RTL8367C_GE_100M_LNKUP_DLY_EXT2_MASK 0x180 ++#define RTL8367C_PHYSTS_10M_LNKUP_DLY_EXT2_OFFSET 5 ++#define RTL8367C_PHYSTS_10M_LNKUP_DLY_EXT2_MASK 0x60 ++#define RTL8367C_LNKUP_DLY_EN_EXT1_OFFSET 4 ++#define RTL8367C_LNKUP_DLY_EN_EXT1_MASK 0x10 ++#define RTL8367C_GE_100M_LNKUP_DLY_EXT1_OFFSET 2 ++#define RTL8367C_GE_100M_LNKUP_DLY_EXT1_MASK 0xC ++#define RTL8367C_PHYSTS_10M_LNKUP_DLY_EXT1_OFFSET 0 ++#define RTL8367C_PHYSTS_10M_LNKUP_DLY_EXT1_MASK 0x3 ++ ++#define RTL8367C_REG_FIBER_CFG_3_1 0x1dc5 ++#define RTL8367C_FIBER_CFG_3_1_OFFSET 0 ++#define RTL8367C_FIBER_CFG_3_1_MASK 0xFFF ++ ++#define RTL8367C_REG_FIBER_CFG_4_1 0x1dc6 ++ ++#define RTL8367C_REG_BUFF_RST_CTRL2_2 0x1dc7 ++#define RTL8367C_Cfg_buffrst_sysover_thr_1_OFFSET 3 ++#define RTL8367C_Cfg_buffrst_sysover_thr_1_MASK 0x8 ++#define RTL8367C_Cfg_buffrst_qover_thr_OFFSET 2 ++#define RTL8367C_Cfg_buffrst_qover_thr_MASK 0x4 ++#define RTL8367C_Cfg_buffrst_indscover_thr_1_OFFSET 1 ++#define RTL8367C_Cfg_buffrst_indscover_thr_1_MASK 0x2 ++#define RTL8367C_Cfg_buffrst_dscover_thr_1_OFFSET 0 ++#define RTL8367C_Cfg_buffrst_dscover_thr_1_MASK 0x1 ++ ++#define RTL8367C_REG_PHY_DEBUG_CNT_CTRL 0x1dc8 ++#define RTL8367C_PHY_MIB_RST_7_OFFSET 15 ++#define RTL8367C_PHY_MIB_RST_7_MASK 0x8000 ++#define RTL8367C_PHY_MIB_RST_6_OFFSET 14 ++#define RTL8367C_PHY_MIB_RST_6_MASK 0x4000 ++#define RTL8367C_PHY_MIB_RST_5_OFFSET 13 ++#define RTL8367C_PHY_MIB_RST_5_MASK 0x2000 ++#define RTL8367C_PHY_MIB_RST_4_OFFSET 12 ++#define RTL8367C_PHY_MIB_RST_4_MASK 0x1000 ++#define RTL8367C_PHY_MIB_RST_3_OFFSET 11 ++#define RTL8367C_PHY_MIB_RST_3_MASK 0x800 ++#define RTL8367C_PHY_MIB_RST_2_OFFSET 10 ++#define RTL8367C_PHY_MIB_RST_2_MASK 0x400 ++#define RTL8367C_PHY_MIB_RST_1_OFFSET 9 ++#define RTL8367C_PHY_MIB_RST_1_MASK 0x200 ++#define RTL8367C_PHY_MIB_RST_0_OFFSET 8 ++#define RTL8367C_PHY_MIB_RST_0_MASK 0x100 ++#define RTL8367C_PHY_MIB_EN_7_OFFSET 7 ++#define RTL8367C_PHY_MIB_EN_7_MASK 0x80 ++#define RTL8367C_PHY_MIB_EN_6_OFFSET 6 ++#define RTL8367C_PHY_MIB_EN_6_MASK 0x40 ++#define RTL8367C_PHY_MIB_EN_5_OFFSET 5 ++#define RTL8367C_PHY_MIB_EN_5_MASK 0x20 ++#define RTL8367C_PHY_MIB_EN_4_OFFSET 4 ++#define RTL8367C_PHY_MIB_EN_4_MASK 0x10 ++#define RTL8367C_PHY_MIB_EN_3_OFFSET 3 ++#define RTL8367C_PHY_MIB_EN_3_MASK 0x8 ++#define RTL8367C_PHY_MIB_EN_2_OFFSET 2 ++#define RTL8367C_PHY_MIB_EN_2_MASK 0x4 ++#define RTL8367C_PHY_MIB_EN_1_OFFSET 1 ++#define RTL8367C_PHY_MIB_EN_1_MASK 0x2 ++#define RTL8367C_PHY_MIB_EN_0_OFFSET 0 ++#define RTL8367C_PHY_MIB_EN_0_MASK 0x1 ++ ++#define RTL8367C_REG_TXPKT_CNT_L_0 0x1dc9 ++ ++#define RTL8367C_REG_TXPKT_CNT_H_0 0x1dca ++ ++#define RTL8367C_REG_RXPKT_CNT_L_0 0x1dcb ++ ++#define RTL8367C_REG_RXPKT_CNT_H_0 0x1dcc ++ ++#define RTL8367C_REG_TX_CRC_0 0x1dcd ++ ++#define RTL8367C_REG_RX_CRC_0 0x1dce ++ ++#define RTL8367C_REG_TXPKT_CNT_L_1 0x1dcf ++ ++#define RTL8367C_REG_TXPKT_CNT_H_1 0x1dd0 ++ ++#define RTL8367C_REG_RXPKT_CNT_L_1 0x1dd1 ++ ++#define RTL8367C_REG_RXPKT_CNT_H_1 0x1dd2 ++ ++#define RTL8367C_REG_TX_CRC_1 0x1dd3 ++ ++#define RTL8367C_REG_RX_CRC_1 0x1dd4 ++ ++#define RTL8367C_REG_TXPKT_CNT_L_2 0x1dd5 ++ ++#define RTL8367C_REG_TXPKT_CNT_H_2 0x1dd6 ++ ++#define RTL8367C_REG_RXPKT_CNT_L_2 0x1dd7 ++ ++#define RTL8367C_REG_RXPKT_CNT_H_2 0x1dd8 ++ ++#define RTL8367C_REG_TX_CRC_2 0x1dd9 ++ ++#define RTL8367C_REG_RX_CRC_2 0x1dda ++ ++#define RTL8367C_REG_TXPKT_CNT_L_3 0x1ddb ++ ++#define RTL8367C_REG_TXPKT_CNT_H_3 0x1ddc ++ ++#define RTL8367C_REG_RXPKT_CNT_L_3 0x1ddd ++ ++#define RTL8367C_REG_RXPKT_CNT_H_3 0x1dde ++ ++#define RTL8367C_REG_TX_CRC_3 0x1ddf ++ ++#define RTL8367C_REG_RX_CRC_3 0x1de0 ++ ++#define RTL8367C_REG_TXPKT_CNT_L_4 0x1de1 ++ ++#define RTL8367C_REG_TXPKT_CNT_H_4 0x1de2 ++ ++#define RTL8367C_REG_RXPKT_CNT_L_4 0x1de3 ++ ++#define RTL8367C_REG_RXPKT_CNT_H_4 0x1de4 ++ ++#define RTL8367C_REG_TX_CRC_4 0x1de5 ++ ++#define RTL8367C_REG_RX_CRC_4 0x1de6 ++ ++#define RTL8367C_REG_TXPKT_CNT_L_5 0x1de7 ++ ++#define RTL8367C_REG_TXPKT_CNT_H_5 0x1de8 ++ ++#define RTL8367C_REG_RXPKT_CNT_L_5 0x1de9 ++ ++#define RTL8367C_REG_RXPKT_CNT_H_5 0x1dea ++ ++#define RTL8367C_REG_TX_CRC_5 0x1deb ++ ++#define RTL8367C_REG_RX_CRC_5 0x1dec ++ ++#define RTL8367C_REG_TXPKT_CNT_L_6 0x1ded ++ ++#define RTL8367C_REG_TXPKT_CNT_H_6 0x1dee ++ ++#define RTL8367C_REG_RXPKT_CNT_L_6 0x1def ++ ++#define RTL8367C_REG_RXPKT_CNT_H_6 0x1df0 ++ ++#define RTL8367C_REG_TX_CRC_6 0x1df1 ++ ++#define RTL8367C_REG_RX_CRC_6 0x1df2 ++ ++#define RTL8367C_REG_TXPKT_CNT_L_7 0x1df3 ++ ++#define RTL8367C_REG_TXPKT_CNT_H_7 0x1df4 ++ ++#define RTL8367C_REG_RXPKT_CNT_L_7 0x1df5 ++ ++#define RTL8367C_REG_RXPKT_CNT_H_7 0x1df6 ++ ++#define RTL8367C_REG_TX_CRC_7 0x1df7 ++ ++#define RTL8367C_REG_RX_CRC_7 0x1df8 ++ ++#define RTL8367C_REG_BOND_DBG_0 0x1df9 ++ ++#define RTL8367C_REG_BOND_DBG_1 0x1dfa ++ ++#define RTL8367C_REG_STRP_DBG_0 0x1dfb ++ ++#define RTL8367C_REG_STRP_DBG_1 0x1dfc ++ ++#define RTL8367C_REG_STRP_DBG_2 0x1dfd ++ ++/* (16'h1f00)patch_reg */ ++ ++#define RTL8367C_REG_INDRECT_ACCESS_CTRL 0x1f00 ++#define RTL8367C_RW_OFFSET 1 ++#define RTL8367C_RW_MASK 0x2 ++#define RTL8367C_CMD_OFFSET 0 ++#define RTL8367C_CMD_MASK 0x1 ++ ++#define RTL8367C_REG_INDRECT_ACCESS_STATUS 0x1f01 ++#define RTL8367C_INDRECT_ACCESS_STATUS_OFFSET 2 ++#define RTL8367C_INDRECT_ACCESS_STATUS_MASK 0x7 ++ ++#define RTL8367C_REG_INDRECT_ACCESS_ADDRESS 0x1f02 ++ ++#define RTL8367C_REG_INDRECT_ACCESS_WRITE_DATA 0x1f03 ++ ++#define RTL8367C_REG_INDRECT_ACCESS_READ_DATA 0x1f04 ++ ++/* (16'h6200)fib_page */ ++ ++#define RTL8367C_REG_FIB0_CFG00 0x6200 ++#define RTL8367C_FIB0_CFG00_CFG_FIB_RST_OFFSET 15 ++#define RTL8367C_FIB0_CFG00_CFG_FIB_RST_MASK 0x8000 ++#define RTL8367C_FIB0_CFG00_CFG_FIB_LPK_OFFSET 14 ++#define RTL8367C_FIB0_CFG00_CFG_FIB_LPK_MASK 0x4000 ++#define RTL8367C_FIB0_CFG00_CFG_FIB_SPD_RD_0_OFFSET 13 ++#define RTL8367C_FIB0_CFG00_CFG_FIB_SPD_RD_0_MASK 0x2000 ++#define RTL8367C_FIB0_CFG00_CFG_FIB_ANEN_OFFSET 12 ++#define RTL8367C_FIB0_CFG00_CFG_FIB_ANEN_MASK 0x1000 ++#define RTL8367C_FIB0_CFG00_CFG_FIB_PDOWN_OFFSET 11 ++#define RTL8367C_FIB0_CFG00_CFG_FIB_PDOWN_MASK 0x800 ++#define RTL8367C_FIB0_CFG00_CFG_FIB_ISO_OFFSET 10 ++#define RTL8367C_FIB0_CFG00_CFG_FIB_ISO_MASK 0x400 ++#define RTL8367C_FIB0_CFG00_CFG_FIB_RESTART_OFFSET 9 ++#define RTL8367C_FIB0_CFG00_CFG_FIB_RESTART_MASK 0x200 ++#define RTL8367C_FIB0_CFG00_CFG_FIB_FULLDUP_OFFSET 8 ++#define RTL8367C_FIB0_CFG00_CFG_FIB_FULLDUP_MASK 0x100 ++#define RTL8367C_FIB0_CFG00_CFG_FIB_SPD_RD_1_OFFSET 6 ++#define RTL8367C_FIB0_CFG00_CFG_FIB_SPD_RD_1_MASK 0x40 ++#define RTL8367C_FIB0_CFG00_CFG_FIB_FRCTX_OFFSET 5 ++#define RTL8367C_FIB0_CFG00_CFG_FIB_FRCTX_MASK 0x20 ++ ++#define RTL8367C_REG_FIB0_CFG01 0x6201 ++#define RTL8367C_FIB0_CFG01_CAPBILITY_OFFSET 6 ++#define RTL8367C_FIB0_CFG01_CAPBILITY_MASK 0xFFC0 ++#define RTL8367C_FIB0_CFG01_AN_COMPLETE_OFFSET 5 ++#define RTL8367C_FIB0_CFG01_AN_COMPLETE_MASK 0x20 ++#define RTL8367C_FIB0_CFG01_R_FAULT_OFFSET 4 ++#define RTL8367C_FIB0_CFG01_R_FAULT_MASK 0x10 ++#define RTL8367C_FIB0_CFG01_NWAY_ABILITY_OFFSET 3 ++#define RTL8367C_FIB0_CFG01_NWAY_ABILITY_MASK 0x8 ++#define RTL8367C_FIB0_CFG01_LINK_STATUS_OFFSET 2 ++#define RTL8367C_FIB0_CFG01_LINK_STATUS_MASK 0x4 ++#define RTL8367C_FIB0_CFG01_JABBER_DETECT_OFFSET 1 ++#define RTL8367C_FIB0_CFG01_JABBER_DETECT_MASK 0x2 ++#define RTL8367C_FIB0_CFG01_EXTENDED_CAPBILITY_OFFSET 0 ++#define RTL8367C_FIB0_CFG01_EXTENDED_CAPBILITY_MASK 0x1 ++ ++#define RTL8367C_REG_FIB0_CFG02 0x6202 ++ ++#define RTL8367C_REG_FIB0_CFG03 0x6203 ++#define RTL8367C_FIB0_CFG03_REALTEK_OUI5_0_OFFSET 10 ++#define RTL8367C_FIB0_CFG03_REALTEK_OUI5_0_MASK 0xFC00 ++#define RTL8367C_FIB0_CFG03_MODEL_NO_OFFSET 4 ++#define RTL8367C_FIB0_CFG03_MODEL_NO_MASK 0x3F0 ++#define RTL8367C_FIB0_CFG03_REVISION_NO_OFFSET 0 ++#define RTL8367C_FIB0_CFG03_REVISION_NO_MASK 0xF ++ ++#define RTL8367C_REG_FIB0_CFG04 0x6204 ++ ++#define RTL8367C_REG_FIB0_CFG05 0x6205 ++ ++#define RTL8367C_REG_FIB0_CFG06 0x6206 ++#define RTL8367C_FIB0_CFG06_FIB_NP_EN_OFFSET 2 ++#define RTL8367C_FIB0_CFG06_FIB_NP_EN_MASK 0x4 ++#define RTL8367C_FIB0_CFG06_RXPAGE_OFFSET 1 ++#define RTL8367C_FIB0_CFG06_RXPAGE_MASK 0x2 ++ ++#define RTL8367C_REG_FIB0_CFG07 0x6207 ++ ++#define RTL8367C_REG_FIB0_CFG08 0x6208 ++ ++#define RTL8367C_REG_FIB0_CFG09 0x6209 ++ ++#define RTL8367C_REG_FIB0_CFG10 0x620a ++ ++#define RTL8367C_REG_FIB0_CFG11 0x620b ++ ++#define RTL8367C_REG_FIB0_CFG12 0x620c ++ ++#define RTL8367C_REG_FIB0_CFG13 0x620d ++#define RTL8367C_FIB0_CFG13_INDR_FUNC_OFFSET 14 ++#define RTL8367C_FIB0_CFG13_INDR_FUNC_MASK 0xC000 ++#define RTL8367C_FIB0_CFG13_DUMMY_OFFSET 5 ++#define RTL8367C_FIB0_CFG13_DUMMY_MASK 0x3FE0 ++#define RTL8367C_FIB0_CFG13_INDR_DEVAD_OFFSET 0 ++#define RTL8367C_FIB0_CFG13_INDR_DEVAD_MASK 0x1F ++ ++#define RTL8367C_REG_FIB0_CFG14 0x620e ++ ++#define RTL8367C_REG_FIB0_CFG15 0x620f ++ ++#define RTL8367C_REG_FIB1_CFG00 0x6210 ++#define RTL8367C_FIB1_CFG00_CFG_FIB_RST_OFFSET 15 ++#define RTL8367C_FIB1_CFG00_CFG_FIB_RST_MASK 0x8000 ++#define RTL8367C_FIB1_CFG00_CFG_FIB_LPK_OFFSET 14 ++#define RTL8367C_FIB1_CFG00_CFG_FIB_LPK_MASK 0x4000 ++#define RTL8367C_FIB1_CFG00_CFG_FIB_SPD_RD_0_OFFSET 13 ++#define RTL8367C_FIB1_CFG00_CFG_FIB_SPD_RD_0_MASK 0x2000 ++#define RTL8367C_FIB1_CFG00_CFG_FIB_ANEN_OFFSET 12 ++#define RTL8367C_FIB1_CFG00_CFG_FIB_ANEN_MASK 0x1000 ++#define RTL8367C_FIB1_CFG00_CFG_FIB_PDOWN_OFFSET 11 ++#define RTL8367C_FIB1_CFG00_CFG_FIB_PDOWN_MASK 0x800 ++#define RTL8367C_FIB1_CFG00_CFG_FIB_ISO_OFFSET 10 ++#define RTL8367C_FIB1_CFG00_CFG_FIB_ISO_MASK 0x400 ++#define RTL8367C_FIB1_CFG00_CFG_FIB_RESTART_OFFSET 9 ++#define RTL8367C_FIB1_CFG00_CFG_FIB_RESTART_MASK 0x200 ++#define RTL8367C_FIB1_CFG00_CFG_FIB_FULLDUP_OFFSET 8 ++#define RTL8367C_FIB1_CFG00_CFG_FIB_FULLDUP_MASK 0x100 ++#define RTL8367C_FIB1_CFG00_CFG_FIB_SPD_RD_1_OFFSET 6 ++#define RTL8367C_FIB1_CFG00_CFG_FIB_SPD_RD_1_MASK 0x40 ++#define RTL8367C_FIB1_CFG00_CFG_FIB_FRCTX_OFFSET 5 ++#define RTL8367C_FIB1_CFG00_CFG_FIB_FRCTX_MASK 0x20 ++ ++#define RTL8367C_REG_FIB1_CFG01 0x6211 ++#define RTL8367C_FIB1_CFG01_CAPBILITY_OFFSET 6 ++#define RTL8367C_FIB1_CFG01_CAPBILITY_MASK 0xFFC0 ++#define RTL8367C_FIB1_CFG01_AN_COMPLETE_OFFSET 5 ++#define RTL8367C_FIB1_CFG01_AN_COMPLETE_MASK 0x20 ++#define RTL8367C_FIB1_CFG01_R_FAULT_OFFSET 4 ++#define RTL8367C_FIB1_CFG01_R_FAULT_MASK 0x10 ++#define RTL8367C_FIB1_CFG01_NWAY_ABILITY_OFFSET 3 ++#define RTL8367C_FIB1_CFG01_NWAY_ABILITY_MASK 0x8 ++#define RTL8367C_FIB1_CFG01_LINK_STATUS_OFFSET 2 ++#define RTL8367C_FIB1_CFG01_LINK_STATUS_MASK 0x4 ++#define RTL8367C_FIB1_CFG01_JABBER_DETECT_OFFSET 1 ++#define RTL8367C_FIB1_CFG01_JABBER_DETECT_MASK 0x2 ++#define RTL8367C_FIB1_CFG01_EXTENDED_CAPBILITY_OFFSET 0 ++#define RTL8367C_FIB1_CFG01_EXTENDED_CAPBILITY_MASK 0x1 ++ ++#define RTL8367C_REG_FIB1_CFG02 0x6212 ++ ++#define RTL8367C_REG_FIB1_CFG03 0x6213 ++#define RTL8367C_FIB1_CFG03_REALTEK_OUI5_0_OFFSET 10 ++#define RTL8367C_FIB1_CFG03_REALTEK_OUI5_0_MASK 0xFC00 ++#define RTL8367C_FIB1_CFG03_MODEL_NO_OFFSET 4 ++#define RTL8367C_FIB1_CFG03_MODEL_NO_MASK 0x3F0 ++#define RTL8367C_FIB1_CFG03_REVISION_NO_OFFSET 0 ++#define RTL8367C_FIB1_CFG03_REVISION_NO_MASK 0xF ++ ++#define RTL8367C_REG_FIB1_CFG04 0x6214 ++ ++#define RTL8367C_REG_FIB1_CFG05 0x6215 ++ ++#define RTL8367C_REG_FIB1_CFG06 0x6216 ++#define RTL8367C_FIB1_CFG06_FIB_NP_EN_OFFSET 2 ++#define RTL8367C_FIB1_CFG06_FIB_NP_EN_MASK 0x4 ++#define RTL8367C_FIB1_CFG06_RXPAGE_OFFSET 1 ++#define RTL8367C_FIB1_CFG06_RXPAGE_MASK 0x2 ++ ++#define RTL8367C_REG_FIB1_CFG07 0x6217 ++ ++#define RTL8367C_REG_FIB1_CFG08 0x6218 ++ ++#define RTL8367C_REG_FIB1_CFG09 0x6219 ++ ++#define RTL8367C_REG_FIB1_CFG10 0x621a ++ ++#define RTL8367C_REG_FIB1_CFG11 0x621b ++ ++#define RTL8367C_REG_FIB1_CFG12 0x621c ++ ++#define RTL8367C_REG_FIB1_CFG13 0x621d ++#define RTL8367C_FIB1_CFG13_INDR_FUNC_OFFSET 14 ++#define RTL8367C_FIB1_CFG13_INDR_FUNC_MASK 0xC000 ++#define RTL8367C_FIB1_CFG13_DUMMY_OFFSET 5 ++#define RTL8367C_FIB1_CFG13_DUMMY_MASK 0x3FE0 ++#define RTL8367C_FIB1_CFG13_INDR_DEVAD_OFFSET 0 ++#define RTL8367C_FIB1_CFG13_INDR_DEVAD_MASK 0x1F ++ ++#define RTL8367C_REG_FIB1_CFG14 0x621e ++ ++#define RTL8367C_REG_FIB1_CFG15 0x621f ++ ++/* (16'h6400)timer_1588 */ ++ ++#define RTL8367C_REG_PTP_TIME_NSEC_L_NSEC 0x6400 ++ ++#define RTL8367C_REG_PTP_TIME_NSEC_H_NSEC 0x6401 ++#define RTL8367C_PTP_TIME_NSEC_H_EXEC_OFFSET 15 ++#define RTL8367C_PTP_TIME_NSEC_H_EXEC_MASK 0x8000 ++#define RTL8367C_PTP_TIME_NSEC_H_CMD_OFFSET 12 ++#define RTL8367C_PTP_TIME_NSEC_H_CMD_MASK 0x3000 ++#define RTL8367C_PTP_TIME_NSEC_H_NSEC_OFFSET 0 ++#define RTL8367C_PTP_TIME_NSEC_H_NSEC_MASK 0x7FF ++ ++#define RTL8367C_REG_PTP_TIME_SEC_L_SEC 0x6402 ++ ++#define RTL8367C_REG_PTP_TIME_SEC_H_SEC 0x6403 ++ ++#define RTL8367C_REG_PTP_TIME_CFG 0x6404 ++#define RTL8367C_CFG_TIMER_EN_FRC_OFFSET 2 ++#define RTL8367C_CFG_TIMER_EN_FRC_MASK 0x4 ++#define RTL8367C_CFG_TIMER_1588_EN_OFFSET 1 ++#define RTL8367C_CFG_TIMER_1588_EN_MASK 0x2 ++#define RTL8367C_CFG_CLK_SRC_OFFSET 0 ++#define RTL8367C_CFG_CLK_SRC_MASK 0x1 ++ ++#define RTL8367C_REG_OTAG_TPID 0x6405 ++ ++#define RTL8367C_REG_ITAG_TPID 0x6406 ++ ++#define RTL8367C_REG_MAC_ADDR_L 0x6407 ++ ++#define RTL8367C_REG_MAC_ADDR_M 0x6408 ++ ++#define RTL8367C_REG_MAC_ADDR_H 0x6409 ++ ++#define RTL8367C_REG_PTP_TIME_NSEC_L_NSEC_RD 0x640a ++ ++#define RTL8367C_REG_PTP_TIME_NSEC_H_NSEC_RD 0x640b ++#define RTL8367C_PTP_TIME_NSEC_H_NSEC_RD_OFFSET 0 ++#define RTL8367C_PTP_TIME_NSEC_H_NSEC_RD_MASK 0x7FF ++ ++#define RTL8367C_REG_PTP_TIME_SEC_L_SEC_RD 0x640c ++ ++#define RTL8367C_REG_PTP_TIME_SEC_H_SEC_RD 0x640d ++ ++#define RTL8367C_REG_PTP_TIME_CFG2 0x640e ++#define RTL8367C_CFG_EN_OFFLOAD_OFFSET 9 ++#define RTL8367C_CFG_EN_OFFLOAD_MASK 0x200 ++#define RTL8367C_CFG_SAVE_OFF_TS_OFFSET 8 ++#define RTL8367C_CFG_SAVE_OFF_TS_MASK 0x100 ++#define RTL8367C_CFG_IMR_OFFSET 0 ++#define RTL8367C_CFG_IMR_MASK 0xFF ++ ++#define RTL8367C_REG_PTP_INTERRUPT_CFG 0x640f ++#define RTL8367C_P9_INTERRUPT_OFFSET 9 ++#define RTL8367C_P9_INTERRUPT_MASK 0x200 ++#define RTL8367C_P8_INTERRUPT_OFFSET 8 ++#define RTL8367C_P8_INTERRUPT_MASK 0x100 ++#define RTL8367C_P7_INTERRUPT_OFFSET 7 ++#define RTL8367C_P7_INTERRUPT_MASK 0x80 ++#define RTL8367C_P6_INTERRUPT_OFFSET 6 ++#define RTL8367C_P6_INTERRUPT_MASK 0x40 ++#define RTL8367C_P5_INTERRUPT_OFFSET 5 ++#define RTL8367C_P5_INTERRUPT_MASK 0x20 ++#define RTL8367C_P4_INTERRUPT_OFFSET 4 ++#define RTL8367C_P4_INTERRUPT_MASK 0x10 ++#define RTL8367C_P3_INTERRUPT_OFFSET 3 ++#define RTL8367C_P3_INTERRUPT_MASK 0x8 ++#define RTL8367C_P2_INTERRUPT_OFFSET 2 ++#define RTL8367C_P2_INTERRUPT_MASK 0x4 ++#define RTL8367C_P1_INTERRUPT_OFFSET 1 ++#define RTL8367C_P1_INTERRUPT_MASK 0x2 ++#define RTL8367C_P0_INTERRUPT_OFFSET 0 ++#define RTL8367C_P0_INTERRUPT_MASK 0x1 ++ ++#define RTL8367C_REG_P0_TX_SYNC_SEQ_ID 0x6410 ++ ++#define RTL8367C_REG_P0_TX_DELAY_REQ_SEQ_ID 0x6411 ++ ++#define RTL8367C_REG_P0_TX_PDELAY_REQ_SEQ_ID 0x6412 ++ ++#define RTL8367C_REG_P0_TX_PDELAY_RESP_SEQ_ID 0x6413 ++ ++#define RTL8367C_REG_P0_RX_SYNC_SEQ_ID 0x6414 ++ ++#define RTL8367C_REG_P0_RX_DELAY_REQ_SEQ_ID 0x6415 ++ ++#define RTL8367C_REG_P0_RX_PDELAY_REQ_SEQ_ID 0x6416 ++ ++#define RTL8367C_REG_P0_RX_PDELAY_RESP_SEQ_ID 0x6417 ++ ++#define RTL8367C_REG_P0_PORT_NSEC_15_0 0x6418 ++ ++#define RTL8367C_REG_P0_PORT_NSEC_26_16 0x6419 ++#define RTL8367C_P0_PORT_NSEC_26_16_OFFSET 0 ++#define RTL8367C_P0_PORT_NSEC_26_16_MASK 0x7FF ++ ++#define RTL8367C_REG_P0_PORT_SEC_15_0 0x641a ++ ++#define RTL8367C_REG_P0_PORT_SEC_31_16 0x641b ++ ++#define RTL8367C_REG_P0_EAV_CFG 0x641c ++#define RTL8367C_P0_EAV_CFG_PTP_PHY_EN_EN_OFFSET 8 ++#define RTL8367C_P0_EAV_CFG_PTP_PHY_EN_EN_MASK 0x100 ++#define RTL8367C_P0_EAV_CFG_RX_PDELAY_RESP_OFFSET 7 ++#define RTL8367C_P0_EAV_CFG_RX_PDELAY_RESP_MASK 0x80 ++#define RTL8367C_P0_EAV_CFG_RX_PDELAY_REQ_OFFSET 6 ++#define RTL8367C_P0_EAV_CFG_RX_PDELAY_REQ_MASK 0x40 ++#define RTL8367C_P0_EAV_CFG_RX_DELAY_REQ_OFFSET 5 ++#define RTL8367C_P0_EAV_CFG_RX_DELAY_REQ_MASK 0x20 ++#define RTL8367C_P0_EAV_CFG_RX_SYNC_OFFSET 4 ++#define RTL8367C_P0_EAV_CFG_RX_SYNC_MASK 0x10 ++#define RTL8367C_P0_EAV_CFG_TX_PDELAY_RESP_OFFSET 3 ++#define RTL8367C_P0_EAV_CFG_TX_PDELAY_RESP_MASK 0x8 ++#define RTL8367C_P0_EAV_CFG_TX_PDELAY_REQ_OFFSET 2 ++#define RTL8367C_P0_EAV_CFG_TX_PDELAY_REQ_MASK 0x4 ++#define RTL8367C_P0_EAV_CFG_TX_DELAY_REQ_OFFSET 1 ++#define RTL8367C_P0_EAV_CFG_TX_DELAY_REQ_MASK 0x2 ++#define RTL8367C_P0_EAV_CFG_TX_SYNC_OFFSET 0 ++#define RTL8367C_P0_EAV_CFG_TX_SYNC_MASK 0x1 ++ ++#define RTL8367C_REG_P1_TX_SYNC_SEQ_ID 0x6420 ++ ++#define RTL8367C_REG_P1_TX_DELAY_REQ_SEQ_ID 0x6421 ++ ++#define RTL8367C_REG_P1_TX_PDELAY_REQ_SEQ_ID 0x6422 ++ ++#define RTL8367C_REG_P1_TX_PDELAY_RESP_SEQ_ID 0x6423 ++ ++#define RTL8367C_REG_P1_RX_SYNC_SEQ_ID 0x6424 ++ ++#define RTL8367C_REG_P1_RX_DELAY_REQ_SEQ_ID 0x6425 ++ ++#define RTL8367C_REG_P1_RX_PDELAY_REQ_SEQ_ID 0x6426 ++ ++#define RTL8367C_REG_P1_RX_PDELAY_RESP_SEQ_ID 0x6427 ++ ++#define RTL8367C_REG_P1_PORT_NSEC_15_0 0x6428 ++ ++#define RTL8367C_REG_P1_PORT_NSEC_26_16 0x6429 ++#define RTL8367C_P1_PORT_NSEC_26_16_OFFSET 0 ++#define RTL8367C_P1_PORT_NSEC_26_16_MASK 0x7FF ++ ++#define RTL8367C_REG_P1_PORT_SEC_15_0 0x642a ++ ++#define RTL8367C_REG_P1_PORT_SEC_31_16 0x642b ++ ++#define RTL8367C_REG_P1_EAV_CFG 0x642c ++#define RTL8367C_P1_EAV_CFG_PTP_PHY_EN_EN_OFFSET 8 ++#define RTL8367C_P1_EAV_CFG_PTP_PHY_EN_EN_MASK 0x100 ++#define RTL8367C_P1_EAV_CFG_RX_PDELAY_RESP_OFFSET 7 ++#define RTL8367C_P1_EAV_CFG_RX_PDELAY_RESP_MASK 0x80 ++#define RTL8367C_P1_EAV_CFG_RX_PDELAY_REQ_OFFSET 6 ++#define RTL8367C_P1_EAV_CFG_RX_PDELAY_REQ_MASK 0x40 ++#define RTL8367C_P1_EAV_CFG_RX_DELAY_REQ_OFFSET 5 ++#define RTL8367C_P1_EAV_CFG_RX_DELAY_REQ_MASK 0x20 ++#define RTL8367C_P1_EAV_CFG_RX_SYNC_OFFSET 4 ++#define RTL8367C_P1_EAV_CFG_RX_SYNC_MASK 0x10 ++#define RTL8367C_P1_EAV_CFG_TX_PDELAY_RESP_OFFSET 3 ++#define RTL8367C_P1_EAV_CFG_TX_PDELAY_RESP_MASK 0x8 ++#define RTL8367C_P1_EAV_CFG_TX_PDELAY_REQ_OFFSET 2 ++#define RTL8367C_P1_EAV_CFG_TX_PDELAY_REQ_MASK 0x4 ++#define RTL8367C_P1_EAV_CFG_TX_DELAY_REQ_OFFSET 1 ++#define RTL8367C_P1_EAV_CFG_TX_DELAY_REQ_MASK 0x2 ++#define RTL8367C_P1_EAV_CFG_TX_SYNC_OFFSET 0 ++#define RTL8367C_P1_EAV_CFG_TX_SYNC_MASK 0x1 ++ ++#define RTL8367C_REG_P2_TX_SYNC_SEQ_ID 0x6430 ++ ++#define RTL8367C_REG_P2_TX_DELAY_REQ_SEQ_ID 0x6431 ++ ++#define RTL8367C_REG_P2_TX_PDELAY_REQ_SEQ_ID 0x6432 ++ ++#define RTL8367C_REG_P2_TX_PDELAY_RESP_SEQ_ID 0x6433 ++ ++#define RTL8367C_REG_P2_RX_SYNC_SEQ_ID 0x6434 ++ ++#define RTL8367C_REG_P2_RX_DELAY_REQ_SEQ_ID 0x6435 ++ ++#define RTL8367C_REG_P2_RX_PDELAY_REQ_SEQ_ID 0x6436 ++ ++#define RTL8367C_REG_P2_RX_PDELAY_RESP_SEQ_ID 0x6437 ++ ++#define RTL8367C_REG_P2_PORT_NSEC_15_0 0x6438 ++ ++#define RTL8367C_REG_P2_PORT_NSEC_26_16 0x6439 ++#define RTL8367C_P2_PORT_NSEC_26_16_OFFSET 0 ++#define RTL8367C_P2_PORT_NSEC_26_16_MASK 0x7FF ++ ++#define RTL8367C_REG_P2_PORT_SEC_15_0 0x643a ++ ++#define RTL8367C_REG_P2_PORT_SEC_31_16 0x643b ++ ++#define RTL8367C_REG_P2_EAV_CFG 0x643c ++#define RTL8367C_P2_EAV_CFG_PTP_PHY_EN_EN_OFFSET 8 ++#define RTL8367C_P2_EAV_CFG_PTP_PHY_EN_EN_MASK 0x100 ++#define RTL8367C_P2_EAV_CFG_RX_PDELAY_RESP_OFFSET 7 ++#define RTL8367C_P2_EAV_CFG_RX_PDELAY_RESP_MASK 0x80 ++#define RTL8367C_P2_EAV_CFG_RX_PDELAY_REQ_OFFSET 6 ++#define RTL8367C_P2_EAV_CFG_RX_PDELAY_REQ_MASK 0x40 ++#define RTL8367C_P2_EAV_CFG_RX_DELAY_REQ_OFFSET 5 ++#define RTL8367C_P2_EAV_CFG_RX_DELAY_REQ_MASK 0x20 ++#define RTL8367C_P2_EAV_CFG_RX_SYNC_OFFSET 4 ++#define RTL8367C_P2_EAV_CFG_RX_SYNC_MASK 0x10 ++#define RTL8367C_P2_EAV_CFG_TX_PDELAY_RESP_OFFSET 3 ++#define RTL8367C_P2_EAV_CFG_TX_PDELAY_RESP_MASK 0x8 ++#define RTL8367C_P2_EAV_CFG_TX_PDELAY_REQ_OFFSET 2 ++#define RTL8367C_P2_EAV_CFG_TX_PDELAY_REQ_MASK 0x4 ++#define RTL8367C_P2_EAV_CFG_TX_DELAY_REQ_OFFSET 1 ++#define RTL8367C_P2_EAV_CFG_TX_DELAY_REQ_MASK 0x2 ++#define RTL8367C_P2_EAV_CFG_TX_SYNC_OFFSET 0 ++#define RTL8367C_P2_EAV_CFG_TX_SYNC_MASK 0x1 ++ ++#define RTL8367C_REG_P3_TX_SYNC_SEQ_ID 0x6440 ++ ++#define RTL8367C_REG_P3_TX_DELAY_REQ_SEQ_ID 0x6441 ++ ++#define RTL8367C_REG_P3_TX_PDELAY_REQ_SEQ_ID 0x6442 ++ ++#define RTL8367C_REG_P3_TX_PDELAY_RESP_SEQ_ID 0x6443 ++ ++#define RTL8367C_REG_P3_RX_SYNC_SEQ_ID 0x6444 ++ ++#define RTL8367C_REG_P3_RX_DELAY_REQ_SEQ_ID 0x6445 ++ ++#define RTL8367C_REG_P3_RX_PDELAY_REQ_SEQ_ID 0x6446 ++ ++#define RTL8367C_REG_P3_RX_PDELAY_RESP_SEQ_ID 0x6447 ++ ++#define RTL8367C_REG_P3_PORT_NSEC_15_0 0x6448 ++ ++#define RTL8367C_REG_P3_PORT_NSEC_26_16 0x6449 ++#define RTL8367C_P3_PORT_NSEC_26_16_OFFSET 0 ++#define RTL8367C_P3_PORT_NSEC_26_16_MASK 0x7FF ++ ++#define RTL8367C_REG_P3_PORT_SEC_15_0 0x644a ++ ++#define RTL8367C_REG_P3_PORT_SEC_31_16 0x644b ++ ++#define RTL8367C_REG_P3_EAV_CFG 0x644c ++#define RTL8367C_P3_EAV_CFG_PTP_PHY_EN_EN_OFFSET 8 ++#define RTL8367C_P3_EAV_CFG_PTP_PHY_EN_EN_MASK 0x100 ++#define RTL8367C_P3_EAV_CFG_RX_PDELAY_RESP_OFFSET 7 ++#define RTL8367C_P3_EAV_CFG_RX_PDELAY_RESP_MASK 0x80 ++#define RTL8367C_P3_EAV_CFG_RX_PDELAY_REQ_OFFSET 6 ++#define RTL8367C_P3_EAV_CFG_RX_PDELAY_REQ_MASK 0x40 ++#define RTL8367C_P3_EAV_CFG_RX_DELAY_REQ_OFFSET 5 ++#define RTL8367C_P3_EAV_CFG_RX_DELAY_REQ_MASK 0x20 ++#define RTL8367C_P3_EAV_CFG_RX_SYNC_OFFSET 4 ++#define RTL8367C_P3_EAV_CFG_RX_SYNC_MASK 0x10 ++#define RTL8367C_P3_EAV_CFG_TX_PDELAY_RESP_OFFSET 3 ++#define RTL8367C_P3_EAV_CFG_TX_PDELAY_RESP_MASK 0x8 ++#define RTL8367C_P3_EAV_CFG_TX_PDELAY_REQ_OFFSET 2 ++#define RTL8367C_P3_EAV_CFG_TX_PDELAY_REQ_MASK 0x4 ++#define RTL8367C_P3_EAV_CFG_TX_DELAY_REQ_OFFSET 1 ++#define RTL8367C_P3_EAV_CFG_TX_DELAY_REQ_MASK 0x2 ++#define RTL8367C_P3_EAV_CFG_TX_SYNC_OFFSET 0 ++#define RTL8367C_P3_EAV_CFG_TX_SYNC_MASK 0x1 ++ ++#define RTL8367C_REG_P4_TX_SYNC_SEQ_ID 0x6450 ++ ++#define RTL8367C_REG_P4_TX_DELAY_REQ_SEQ_ID 0x6451 ++ ++#define RTL8367C_REG_P4_TX_PDELAY_REQ_SEQ_ID 0x6452 ++ ++#define RTL8367C_REG_P4_TX_PDELAY_RESP_SEQ_ID 0x6453 ++ ++#define RTL8367C_REG_P4_RX_SYNC_SEQ_ID 0x6454 ++ ++#define RTL8367C_REG_P4_RX_DELAY_REQ_SEQ_ID 0x6455 ++ ++#define RTL8367C_REG_P4_RX_PDELAY_REQ_SEQ_ID 0x6456 ++ ++#define RTL8367C_REG_P4_RX_PDELAY_RESP_SEQ_ID 0x6457 ++ ++#define RTL8367C_REG_P4_PORT_NSEC_15_0 0x6458 ++ ++#define RTL8367C_REG_P4_PORT_NSEC_26_16 0x6459 ++#define RTL8367C_P4_PORT_NSEC_26_16_OFFSET 0 ++#define RTL8367C_P4_PORT_NSEC_26_16_MASK 0x7FF ++ ++#define RTL8367C_REG_P4_PORT_SEC_15_0 0x645a ++ ++#define RTL8367C_REG_P4_PORT_SEC_31_16 0x645b ++ ++#define RTL8367C_REG_P4_EAV_CFG 0x645c ++#define RTL8367C_P4_EAV_CFG_PTP_PHY_EN_EN_OFFSET 8 ++#define RTL8367C_P4_EAV_CFG_PTP_PHY_EN_EN_MASK 0x100 ++#define RTL8367C_P4_EAV_CFG_RX_PDELAY_RESP_OFFSET 7 ++#define RTL8367C_P4_EAV_CFG_RX_PDELAY_RESP_MASK 0x80 ++#define RTL8367C_P4_EAV_CFG_RX_PDELAY_REQ_OFFSET 6 ++#define RTL8367C_P4_EAV_CFG_RX_PDELAY_REQ_MASK 0x40 ++#define RTL8367C_P4_EAV_CFG_RX_DELAY_REQ_OFFSET 5 ++#define RTL8367C_P4_EAV_CFG_RX_DELAY_REQ_MASK 0x20 ++#define RTL8367C_P4_EAV_CFG_RX_SYNC_OFFSET 4 ++#define RTL8367C_P4_EAV_CFG_RX_SYNC_MASK 0x10 ++#define RTL8367C_P4_EAV_CFG_TX_PDELAY_RESP_OFFSET 3 ++#define RTL8367C_P4_EAV_CFG_TX_PDELAY_RESP_MASK 0x8 ++#define RTL8367C_P4_EAV_CFG_TX_PDELAY_REQ_OFFSET 2 ++#define RTL8367C_P4_EAV_CFG_TX_PDELAY_REQ_MASK 0x4 ++#define RTL8367C_P4_EAV_CFG_TX_DELAY_REQ_OFFSET 1 ++#define RTL8367C_P4_EAV_CFG_TX_DELAY_REQ_MASK 0x2 ++#define RTL8367C_P4_EAV_CFG_TX_SYNC_OFFSET 0 ++#define RTL8367C_P4_EAV_CFG_TX_SYNC_MASK 0x1 ++ ++#define RTL8367C_REG_P6_TX_SYNC_SEQ_ID 0x6460 ++ ++#define RTL8367C_REG_P6_TX_DELAY_REQ_SEQ_ID 0x6461 ++ ++#define RTL8367C_REG_P6_TX_PDELAY_REQ_SEQ_ID 0x6462 ++ ++#define RTL8367C_REG_P6_TX_PDELAY_RESP_SEQ_ID 0x6463 ++ ++#define RTL8367C_REG_P6_RX_SYNC_SEQ_ID 0x6464 ++ ++#define RTL8367C_REG_P6_RX_DELAY_REQ_SEQ_ID 0x6465 ++ ++#define RTL8367C_REG_P6_RX_PDELAY_REQ_SEQ_ID 0x6466 ++ ++#define RTL8367C_REG_P6_RX_PDELAY_RESP_SEQ_ID 0x6467 ++ ++#define RTL8367C_REG_P6_PORT_NSEC_15_0 0x6468 ++ ++#define RTL8367C_REG_P6_PORT_NSEC_26_16 0x6469 ++#define RTL8367C_P6_PORT_NSEC_26_16_OFFSET 0 ++#define RTL8367C_P6_PORT_NSEC_26_16_MASK 0x7FF ++ ++#define RTL8367C_REG_P6_PORT_SEC_15_0 0x646a ++ ++#define RTL8367C_REG_P6_PORT_SEC_31_16 0x646b ++ ++#define RTL8367C_REG_P6_EAV_CFG 0x646c ++#define RTL8367C_P6_EAV_CFG_PTP_PHY_EN_EN_OFFSET 8 ++#define RTL8367C_P6_EAV_CFG_PTP_PHY_EN_EN_MASK 0x100 ++#define RTL8367C_P6_EAV_CFG_RX_PDELAY_RESP_OFFSET 7 ++#define RTL8367C_P6_EAV_CFG_RX_PDELAY_RESP_MASK 0x80 ++#define RTL8367C_P6_EAV_CFG_RX_PDELAY_REQ_OFFSET 6 ++#define RTL8367C_P6_EAV_CFG_RX_PDELAY_REQ_MASK 0x40 ++#define RTL8367C_P6_EAV_CFG_RX_DELAY_REQ_OFFSET 5 ++#define RTL8367C_P6_EAV_CFG_RX_DELAY_REQ_MASK 0x20 ++#define RTL8367C_P6_EAV_CFG_RX_SYNC_OFFSET 4 ++#define RTL8367C_P6_EAV_CFG_RX_SYNC_MASK 0x10 ++#define RTL8367C_P6_EAV_CFG_TX_PDELAY_RESP_OFFSET 3 ++#define RTL8367C_P6_EAV_CFG_TX_PDELAY_RESP_MASK 0x8 ++#define RTL8367C_P6_EAV_CFG_TX_PDELAY_REQ_OFFSET 2 ++#define RTL8367C_P6_EAV_CFG_TX_PDELAY_REQ_MASK 0x4 ++#define RTL8367C_P6_EAV_CFG_TX_DELAY_REQ_OFFSET 1 ++#define RTL8367C_P6_EAV_CFG_TX_DELAY_REQ_MASK 0x2 ++#define RTL8367C_P6_EAV_CFG_TX_SYNC_OFFSET 0 ++#define RTL8367C_P6_EAV_CFG_TX_SYNC_MASK 0x1 ++ ++#define RTL8367C_REG_P7_TX_SYNC_SEQ_ID 0x6470 ++ ++#define RTL8367C_REG_P7_TX_DELAY_REQ_SEQ_ID 0x6471 ++ ++#define RTL8367C_REG_P7_TX_PDELAY_REQ_SEQ_ID 0x6472 ++ ++#define RTL8367C_REG_P7_TX_PDELAY_RESP_SEQ_ID 0x6473 ++ ++#define RTL8367C_REG_P7_RX_SYNC_SEQ_ID 0x6474 ++ ++#define RTL8367C_REG_P7_RX_DELAY_REQ_SEQ_ID 0x6475 ++ ++#define RTL8367C_REG_P7_RX_PDELAY_REQ_SEQ_ID 0x6476 ++ ++#define RTL8367C_REG_P7_RX_PDELAY_RESP_SEQ_ID 0x6477 ++ ++#define RTL8367C_REG_P7_PORT_NSEC_15_0 0x6478 ++ ++#define RTL8367C_REG_P7_PORT_NSEC_26_16 0x6479 ++#define RTL8367C_P7_PORT_NSEC_26_16_OFFSET 0 ++#define RTL8367C_P7_PORT_NSEC_26_16_MASK 0x7FF ++ ++#define RTL8367C_REG_P7_PORT_SEC_15_0 0x647a ++ ++#define RTL8367C_REG_P7_PORT_SEC_31_16 0x647b ++ ++#define RTL8367C_REG_P7_EAV_CFG 0x647c ++#define RTL8367C_P7_EAV_CFG_PTP_PHY_EN_EN_OFFSET 8 ++#define RTL8367C_P7_EAV_CFG_PTP_PHY_EN_EN_MASK 0x100 ++#define RTL8367C_P7_EAV_CFG_RX_PDELAY_RESP_OFFSET 7 ++#define RTL8367C_P7_EAV_CFG_RX_PDELAY_RESP_MASK 0x80 ++#define RTL8367C_P7_EAV_CFG_RX_PDELAY_REQ_OFFSET 6 ++#define RTL8367C_P7_EAV_CFG_RX_PDELAY_REQ_MASK 0x40 ++#define RTL8367C_P7_EAV_CFG_RX_DELAY_REQ_OFFSET 5 ++#define RTL8367C_P7_EAV_CFG_RX_DELAY_REQ_MASK 0x20 ++#define RTL8367C_P7_EAV_CFG_RX_SYNC_OFFSET 4 ++#define RTL8367C_P7_EAV_CFG_RX_SYNC_MASK 0x10 ++#define RTL8367C_P7_EAV_CFG_TX_PDELAY_RESP_OFFSET 3 ++#define RTL8367C_P7_EAV_CFG_TX_PDELAY_RESP_MASK 0x8 ++#define RTL8367C_P7_EAV_CFG_TX_PDELAY_REQ_OFFSET 2 ++#define RTL8367C_P7_EAV_CFG_TX_PDELAY_REQ_MASK 0x4 ++#define RTL8367C_P7_EAV_CFG_TX_DELAY_REQ_OFFSET 1 ++#define RTL8367C_P7_EAV_CFG_TX_DELAY_REQ_MASK 0x2 ++#define RTL8367C_P7_EAV_CFG_TX_SYNC_OFFSET 0 ++#define RTL8367C_P7_EAV_CFG_TX_SYNC_MASK 0x1 ++ ++#define RTL8367C_REG_P5_TX_SYNC_SEQ_ID 0x6480 ++ ++#define RTL8367C_REG_P5_TX_DELAY_REQ_SEQ_ID 0x6481 ++ ++#define RTL8367C_REG_P5_TX_PDELAY_REQ_SEQ_ID 0x6482 ++ ++#define RTL8367C_REG_P5_TX_PDELAY_RESP_SEQ_ID 0x6483 ++ ++#define RTL8367C_REG_P5_RX_SYNC_SEQ_ID 0x6484 ++ ++#define RTL8367C_REG_P5_RX_DELAY_REQ_SEQ_ID 0x6485 ++ ++#define RTL8367C_REG_P5_RX_PDELAY_REQ_SEQ_ID 0x6486 ++ ++#define RTL8367C_REG_P5_RX_PDELAY_RESP_SEQ_ID 0x6487 ++ ++#define RTL8367C_REG_P5_PORT_NSEC_15_0 0x6488 ++ ++#define RTL8367C_REG_P5_PORT_NSEC_26_16 0x6489 ++#define RTL8367C_P5_PORT_NSEC_26_16_OFFSET 0 ++#define RTL8367C_P5_PORT_NSEC_26_16_MASK 0x7FF ++ ++#define RTL8367C_REG_P5_PORT_SEC_15_0 0x648a ++ ++#define RTL8367C_REG_P5_PORT_SEC_31_16 0x648b ++ ++#define RTL8367C_REG_P5_EAV_CFG 0x648c ++#define RTL8367C_P5_EAV_CFG_PTP_PHY_EN_EN_OFFSET 8 ++#define RTL8367C_P5_EAV_CFG_PTP_PHY_EN_EN_MASK 0x100 ++#define RTL8367C_P5_EAV_CFG_RX_PDELAY_RESP_OFFSET 7 ++#define RTL8367C_P5_EAV_CFG_RX_PDELAY_RESP_MASK 0x80 ++#define RTL8367C_P5_EAV_CFG_RX_PDELAY_REQ_OFFSET 6 ++#define RTL8367C_P5_EAV_CFG_RX_PDELAY_REQ_MASK 0x40 ++#define RTL8367C_P5_EAV_CFG_RX_DELAY_REQ_OFFSET 5 ++#define RTL8367C_P5_EAV_CFG_RX_DELAY_REQ_MASK 0x20 ++#define RTL8367C_P5_EAV_CFG_RX_SYNC_OFFSET 4 ++#define RTL8367C_P5_EAV_CFG_RX_SYNC_MASK 0x10 ++#define RTL8367C_P5_EAV_CFG_TX_PDELAY_RESP_OFFSET 3 ++#define RTL8367C_P5_EAV_CFG_TX_PDELAY_RESP_MASK 0x8 ++#define RTL8367C_P5_EAV_CFG_TX_PDELAY_REQ_OFFSET 2 ++#define RTL8367C_P5_EAV_CFG_TX_PDELAY_REQ_MASK 0x4 ++#define RTL8367C_P5_EAV_CFG_TX_DELAY_REQ_OFFSET 1 ++#define RTL8367C_P5_EAV_CFG_TX_DELAY_REQ_MASK 0x2 ++#define RTL8367C_P5_EAV_CFG_TX_SYNC_OFFSET 0 ++#define RTL8367C_P5_EAV_CFG_TX_SYNC_MASK 0x1 ++ ++#define RTL8367C_REG_P8_TX_SYNC_SEQ_ID 0x6490 ++ ++#define RTL8367C_REG_P8_TX_DELAY_REQ_SEQ_ID 0x6491 ++ ++#define RTL8367C_REG_P8_TX_PDELAY_REQ_SEQ_ID 0x6492 ++ ++#define RTL8367C_REG_P8_TX_PDELAY_RESP_SEQ_ID 0x6493 ++ ++#define RTL8367C_REG_P8_RX_SYNC_SEQ_ID 0x6494 ++ ++#define RTL8367C_REG_P8_RX_DELAY_REQ_SEQ_ID 0x6495 ++ ++#define RTL8367C_REG_P8_RX_PDELAY_REQ_SEQ_ID 0x6496 ++ ++#define RTL8367C_REG_P8_RX_PDELAY_RESP_SEQ_ID 0x6497 ++ ++#define RTL8367C_REG_P8_PORT_NSEC_15_0 0x6498 ++ ++#define RTL8367C_REG_P8_PORT_NSEC_26_16 0x6499 ++#define RTL8367C_P8_PORT_NSEC_26_16_OFFSET 0 ++#define RTL8367C_P8_PORT_NSEC_26_16_MASK 0x7FF ++ ++#define RTL8367C_REG_P8_PORT_SEC_15_0 0x649a ++ ++#define RTL8367C_REG_P8_PORT_SEC_31_16 0x649b ++ ++#define RTL8367C_REG_P8_EAV_CFG 0x649c ++#define RTL8367C_P8_EAV_CFG_PTP_PHY_EN_EN_OFFSET 8 ++#define RTL8367C_P8_EAV_CFG_PTP_PHY_EN_EN_MASK 0x100 ++#define RTL8367C_P8_EAV_CFG_RX_PDELAY_RESP_OFFSET 7 ++#define RTL8367C_P8_EAV_CFG_RX_PDELAY_RESP_MASK 0x80 ++#define RTL8367C_P8_EAV_CFG_RX_PDELAY_REQ_OFFSET 6 ++#define RTL8367C_P8_EAV_CFG_RX_PDELAY_REQ_MASK 0x40 ++#define RTL8367C_P8_EAV_CFG_RX_DELAY_REQ_OFFSET 5 ++#define RTL8367C_P8_EAV_CFG_RX_DELAY_REQ_MASK 0x20 ++#define RTL8367C_P8_EAV_CFG_RX_SYNC_OFFSET 4 ++#define RTL8367C_P8_EAV_CFG_RX_SYNC_MASK 0x10 ++#define RTL8367C_P8_EAV_CFG_TX_PDELAY_RESP_OFFSET 3 ++#define RTL8367C_P8_EAV_CFG_TX_PDELAY_RESP_MASK 0x8 ++#define RTL8367C_P8_EAV_CFG_TX_PDELAY_REQ_OFFSET 2 ++#define RTL8367C_P8_EAV_CFG_TX_PDELAY_REQ_MASK 0x4 ++#define RTL8367C_P8_EAV_CFG_TX_DELAY_REQ_OFFSET 1 ++#define RTL8367C_P8_EAV_CFG_TX_DELAY_REQ_MASK 0x2 ++#define RTL8367C_P8_EAV_CFG_TX_SYNC_OFFSET 0 ++#define RTL8367C_P8_EAV_CFG_TX_SYNC_MASK 0x1 ++ ++#define RTL8367C_REG_P9_TX_SYNC_SEQ_ID 0x64a0 ++ ++#define RTL8367C_REG_P9_TX_DELAY_REQ_SEQ_ID 0x64a1 ++ ++#define RTL8367C_REG_P9_TX_PDELAY_REQ_SEQ_ID 0x64a2 ++ ++#define RTL8367C_REG_P9_TX_PDELAY_RESP_SEQ_ID 0x64a3 ++ ++#define RTL8367C_REG_P9_RX_SYNC_SEQ_ID 0x64a4 ++ ++#define RTL8367C_REG_P9_RX_DELAY_REQ_SEQ_ID 0x64a5 ++ ++#define RTL8367C_REG_P9_RX_PDELAY_REQ_SEQ_ID 0x64a6 ++ ++#define RTL8367C_REG_P9_RX_PDELAY_RESP_SEQ_ID 0x64a7 ++ ++#define RTL8367C_REG_P9_PORT_NSEC_15_0 0x64a8 ++ ++#define RTL8367C_REG_P9_PORT_NSEC_26_16 0x64a9 ++#define RTL8367C_P9_PORT_NSEC_26_16_OFFSET 0 ++#define RTL8367C_P9_PORT_NSEC_26_16_MASK 0x7FF ++ ++#define RTL8367C_REG_P9_PORT_SEC_15_0 0x64aa ++ ++#define RTL8367C_REG_P9_PORT_SEC_31_16 0x64ab ++ ++#define RTL8367C_REG_P9_EAV_CFG 0x64ac ++#define RTL8367C_P9_EAV_CFG_PTP_PHY_EN_EN_OFFSET 8 ++#define RTL8367C_P9_EAV_CFG_PTP_PHY_EN_EN_MASK 0x100 ++#define RTL8367C_P9_EAV_CFG_RX_PDELAY_RESP_OFFSET 7 ++#define RTL8367C_P9_EAV_CFG_RX_PDELAY_RESP_MASK 0x80 ++#define RTL8367C_P9_EAV_CFG_RX_PDELAY_REQ_OFFSET 6 ++#define RTL8367C_P9_EAV_CFG_RX_PDELAY_REQ_MASK 0x40 ++#define RTL8367C_P9_EAV_CFG_RX_DELAY_REQ_OFFSET 5 ++#define RTL8367C_P9_EAV_CFG_RX_DELAY_REQ_MASK 0x20 ++#define RTL8367C_P9_EAV_CFG_RX_SYNC_OFFSET 4 ++#define RTL8367C_P9_EAV_CFG_RX_SYNC_MASK 0x10 ++#define RTL8367C_P9_EAV_CFG_TX_PDELAY_RESP_OFFSET 3 ++#define RTL8367C_P9_EAV_CFG_TX_PDELAY_RESP_MASK 0x8 ++#define RTL8367C_P9_EAV_CFG_TX_PDELAY_REQ_OFFSET 2 ++#define RTL8367C_P9_EAV_CFG_TX_PDELAY_REQ_MASK 0x4 ++#define RTL8367C_P9_EAV_CFG_TX_DELAY_REQ_OFFSET 1 ++#define RTL8367C_P9_EAV_CFG_TX_DELAY_REQ_MASK 0x2 ++#define RTL8367C_P9_EAV_CFG_TX_SYNC_OFFSET 0 ++#define RTL8367C_P9_EAV_CFG_TX_SYNC_MASK 0x1 ++ ++/* (16'h6600)sds_indacs_reg */ ++ ++#define RTL8367C_REG_SDS_INDACS_CMD 0x6600 ++#define RTL8367C_SDS_CMD_BUSY_OFFSET 8 ++#define RTL8367C_SDS_CMD_BUSY_MASK 0x100 ++#define RTL8367C_SDS_CMD_OFFSET 7 ++#define RTL8367C_SDS_CMD_MASK 0x80 ++#define RTL8367C_SDS_RWOP_OFFSET 6 ++#define RTL8367C_SDS_RWOP_MASK 0x40 ++#define RTL8367C_SDS_INDEX_OFFSET 0 ++#define RTL8367C_SDS_INDEX_MASK 0x3F ++ ++#define RTL8367C_REG_SDS_INDACS_ADR 0x6601 ++#define RTL8367C_SDS_PAGE_OFFSET 5 ++#define RTL8367C_SDS_PAGE_MASK 0x7E0 ++#define RTL8367C_SDS_REGAD_OFFSET 0 ++#define RTL8367C_SDS_REGAD_MASK 0x1F ++ ++#define RTL8367C_REG_SDS_INDACS_DATA 0x6602 ++ ++ ++#endif /*#ifndef _RTL8367C_REG_H_*/ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/include/smi.h b/drivers/net/phy/rtk/rtl8367c/include/smi.h +new file mode 100644 +index 000000000000..b77d7607113e +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/smi.h +@@ -0,0 +1,54 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * Purpose : RTL8367C switch low-level function for access register ++ * Feature : SMI related functions ++ * ++ */ ++ ++#ifndef __SMI_H__ ++#define __SMI_H__ ++ ++#include ++#include "rtk_error.h" ++ ++#define MDC_MDIO_CTRL0_REG 31 ++#define MDC_MDIO_START_REG 29 ++#define MDC_MDIO_CTRL1_REG 21 ++#define MDC_MDIO_ADDRESS_REG 23 ++#define MDC_MDIO_DATA_WRITE_REG 24 ++#define MDC_MDIO_DATA_READ_REG 25 ++#define MDC_MDIO_PREAMBLE_LEN 32 ++ ++#define MDC_MDIO_START_OP 0xFFFF ++#define MDC_MDIO_ADDR_OP 0x000E ++#define MDC_MDIO_READ_OP 0x0001 ++#define MDC_MDIO_WRITE_OP 0x0003 ++ ++#define SPI_READ_OP 0x3 ++#define SPI_WRITE_OP 0x2 ++#define SPI_READ_OP_LEN 0x8 ++#define SPI_WRITE_OP_LEN 0x8 ++#define SPI_REG_LEN 16 ++#define SPI_DATA_LEN 16 ++ ++#define GPIO_DIR_IN 1 ++#define GPIO_DIR_OUT 0 ++ ++#define ack_timer 5 ++ ++#define DELAY 10000 ++#define CLK_DURATION(clk) { int i; for(i=0; isvid is SVID of SVLAN member configuration. ++ * - rtk_svlan_memberCfg_t->memberport is member port mask of SVLAN member configuration. ++ * - rtk_svlan_memberCfg_t->fid is filtering database of SVLAN member configuration. ++ * - rtk_svlan_memberCfg_t->priority is priority of SVLAN member configuration. ++ */ ++extern rtk_api_ret_t rtk_svlan_memberPortEntry_set(rtk_uint32 svid_idx, rtk_svlan_memberCfg_t *psvlan_cfg); ++ ++/* Function Name: ++ * rtk_svlan_memberPortEntry_get ++ * Description: ++ * Get SVLAN member Configure. ++ * Input: ++ * svid - SVLAN id ++ * Output: ++ * pSvlan_cfg - SVLAN member configuration ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_SVLAN_ENTRY_NOT_FOUND - specified svlan entry not found. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can get system 64 accepted s-tag frame format. Only 64 SVID S-tag frame will be accpeted ++ * to receiving from uplink ports. Other SVID S-tag frame or S-untagged frame will be droped. ++ */ ++extern rtk_api_ret_t rtk_svlan_memberPortEntry_get(rtk_uint32 svid_idx, rtk_svlan_memberCfg_t *pSvlan_cfg); ++ ++/* Function Name: ++ * rtk_svlan_memberPortEntry_adv_set ++ * Description: ++ * Configure system SVLAN member by index ++ * Input: ++ * idx - Index (0 ~ 63) ++ * psvlan_cfg - SVLAN member configuration ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameter. ++ * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. ++ * RT_ERR_PORT_MASK - Invalid portmask. ++ * RT_ERR_SVLAN_TABLE_FULL - SVLAN configuration is full. ++ * Note: ++ * The API can set system 64 accepted s-tag frame format by index. ++ * - rtk_svlan_memberCfg_t->svid is SVID of SVLAN member configuration. ++ * - rtk_svlan_memberCfg_t->memberport is member port mask of SVLAN member configuration. ++ * - rtk_svlan_memberCfg_t->fid is filtering database of SVLAN member configuration. ++ * - rtk_svlan_memberCfg_t->priority is priority of SVLAN member configuration. ++ */ ++extern rtk_api_ret_t rtk_svlan_memberPortEntry_adv_set(rtk_uint32 idx, rtk_svlan_memberCfg_t *pSvlan_cfg); ++ ++/* Function Name: ++ * rtk_svlan_memberPortEntry_adv_get ++ * Description: ++ * Get SVLAN member Configure by index. ++ * Input: ++ * idx - Index (0 ~ 63) ++ * Output: ++ * pSvlan_cfg - SVLAN member configuration ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_SVLAN_ENTRY_NOT_FOUND - specified svlan entry not found. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can get system 64 accepted s-tag frame format. Only 64 SVID S-tag frame will be accpeted ++ * to receiving from uplink ports. Other SVID S-tag frame or S-untagged frame will be droped. ++ */ ++extern rtk_api_ret_t rtk_svlan_memberPortEntry_adv_get(rtk_uint32 idx, rtk_svlan_memberCfg_t *pSvlan_cfg); ++ ++/* Function Name: ++ * rtk_svlan_defaultSvlan_set ++ * Description: ++ * Configure default egress SVLAN. ++ * Input: ++ * port - Source port ++ * svid - SVLAN id ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameter. ++ * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. ++ * RT_ERR_SVLAN_ENTRY_NOT_FOUND - specified svlan entry not found. ++ * Note: ++ * The API can set port n S-tag format index while receiving frame from port n ++ * is transmit through uplink port with s-tag field ++ */ ++extern rtk_api_ret_t rtk_svlan_defaultSvlan_set(rtk_port_t port, rtk_vlan_t svid); ++ ++/* Function Name: ++ * rtk_svlan_defaultSvlan_get ++ * Description: ++ * Get the configure default egress SVLAN. ++ * Input: ++ * port - Source port ++ * Output: ++ * pSvid - SVLAN VID ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can get port n S-tag format index while receiving frame from port n ++ * is transmit through uplink port with s-tag field ++ */ ++extern rtk_api_ret_t rtk_svlan_defaultSvlan_get(rtk_port_t port, rtk_vlan_t *pSvid); ++ ++/* Function Name: ++ * rtk_svlan_c2s_add ++ * Description: ++ * Configure SVLAN C2S table ++ * Input: ++ * vid - VLAN ID ++ * src_port - Ingress Port ++ * svid - SVLAN VID ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port ID. ++ * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. ++ * RT_ERR_VLAN_VID - Invalid VID parameter. ++ * RT_ERR_OUT_OF_RANGE - input out of range. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can set system C2S configuration. ASIC will check upstream's VID and assign related ++ * SVID to mathed packet. There are 128 SVLAN C2S configurations. ++ */ ++extern rtk_api_ret_t rtk_svlan_c2s_add(rtk_vlan_t vid, rtk_port_t src_port, rtk_vlan_t svid); ++ ++/* Function Name: ++ * rtk_svlan_c2s_del ++ * Description: ++ * Delete one C2S entry ++ * Input: ++ * vid - VLAN ID ++ * src_port - Ingress Port ++ * svid - SVLAN VID ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_VLAN_VID - Invalid VID parameter. ++ * RT_ERR_PORT_ID - Invalid port ID. ++ * RT_ERR_OUT_OF_RANGE - input out of range. ++ * Note: ++ * The API can delete system C2S configuration. There are 128 SVLAN C2S configurations. ++ */ ++extern rtk_api_ret_t rtk_svlan_c2s_del(rtk_vlan_t vid, rtk_port_t src_port); ++ ++/* Function Name: ++ * rtk_svlan_c2s_get ++ * Description: ++ * Get configure SVLAN C2S table ++ * Input: ++ * vid - VLAN ID ++ * src_port - Ingress Port ++ * Output: ++ * pSvid - SVLAN ID ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_PORT_ID - Invalid port ID. ++ * RT_ERR_OUT_OF_RANGE - input out of range. ++ * Note: ++ * The API can get system C2S configuration. There are 128 SVLAN C2S configurations. ++ */ ++extern rtk_api_ret_t rtk_svlan_c2s_get(rtk_vlan_t vid, rtk_port_t src_port, rtk_vlan_t *pSvid); ++ ++/* Function Name: ++ * rtk_svlan_untag_action_set ++ * Description: ++ * Configure Action of downstream Un-Stag packet ++ * Input: ++ * action - Action for UnStag ++ * svid - The SVID assigned to UnStag packet ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. ++ * RT_ERR_SVLAN_ENTRY_NOT_FOUND - specified svlan entry not found. ++ * RT_ERR_OUT_OF_RANGE - input out of range. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can configure action of downstream Un-Stag packet. A SVID assigned ++ * to the un-stag is also supported by this API. The parameter of svid is ++ * only referenced when the action is set to UNTAG_ASSIGN ++ */ ++extern rtk_api_ret_t rtk_svlan_untag_action_set(rtk_svlan_untag_action_t action, rtk_vlan_t svid); ++ ++/* Function Name: ++ * rtk_svlan_untag_action_get ++ * Description: ++ * Get Action of downstream Un-Stag packet ++ * Input: ++ * None ++ * Output: ++ * pAction - Action for UnStag ++ * pSvid - The SVID assigned to UnStag packet ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. ++ * RT_ERR_SVLAN_ENTRY_NOT_FOUND - specified svlan entry not found. ++ * RT_ERR_OUT_OF_RANGE - input out of range. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can Get action of downstream Un-Stag packet. A SVID assigned ++ * to the un-stag is also retrieved by this API. The parameter pSvid is ++ * only refernced when the action is UNTAG_ASSIGN ++ */ ++extern rtk_api_ret_t rtk_svlan_untag_action_get(rtk_svlan_untag_action_t *pAction, rtk_vlan_t *pSvid); ++ ++/* Function Name: ++ * rtk_svlan_unmatch_action_set ++ * Description: ++ * Configure Action of downstream Unmatch packet ++ * Input: ++ * action - Action for Unmatch ++ * svid - The SVID assigned to Unmatch packet ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. ++ * RT_ERR_SVLAN_ENTRY_NOT_FOUND - specified svlan entry not found. ++ * RT_ERR_OUT_OF_RANGE - input out of range. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can configure action of downstream Un-match packet. A SVID assigned ++ * to the un-match is also supported by this API. The parameter od svid is ++ * only refernced when the action is set to UNMATCH_ASSIGN ++ */ ++extern rtk_api_ret_t rtk_svlan_unmatch_action_set(rtk_svlan_unmatch_action_t action, rtk_vlan_t svid); ++ ++/* Function Name: ++ * rtk_svlan_unmatch_action_get ++ * Description: ++ * Get Action of downstream Unmatch packet ++ * Input: ++ * None ++ * Output: ++ * pAction - Action for Unmatch ++ * pSvid - The SVID assigned to Unmatch packet ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. ++ * RT_ERR_SVLAN_ENTRY_NOT_FOUND - specified svlan entry not found. ++ * RT_ERR_OUT_OF_RANGE - input out of range. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can Get action of downstream Un-match packet. A SVID assigned ++ * to the un-match is also retrieved by this API. The parameter pSvid is ++ * only refernced when the action is UNMATCH_ASSIGN ++ */ ++extern rtk_api_ret_t rtk_svlan_unmatch_action_get(rtk_svlan_unmatch_action_t *pAction, rtk_vlan_t *pSvid); ++ ++/* Function Name: ++ * rtk_svlan_dmac_vidsel_set ++ * Description: ++ * Set DMAC CVID selection ++ * Input: ++ * port - Port ++ * enable - state of DMAC CVID Selection ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. ++ * RT_ERR_SVLAN_ENTRY_NOT_FOUND - specified svlan entry not found. ++ * RT_ERR_OUT_OF_RANGE - input out of range. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * This API can set DMAC CVID Selection state ++ */ ++extern rtk_api_ret_t rtk_svlan_dmac_vidsel_set(rtk_port_t port, rtk_enable_t enable); ++ ++/* Function Name: ++ * rtk_svlan_dmac_vidsel_get ++ * Description: ++ * Get DMAC CVID selection ++ * Input: ++ * port - Port ++ * Output: ++ * pEnable - state of DMAC CVID Selection ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. ++ * RT_ERR_SVLAN_ENTRY_NOT_FOUND - specified svlan entry not found. ++ * RT_ERR_OUT_OF_RANGE - input out of range. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * This API can get DMAC CVID Selection state ++ */ ++extern rtk_api_ret_t rtk_svlan_dmac_vidsel_get(rtk_port_t port, rtk_enable_t *pEnable); ++ ++/* Function Name: ++ * rtk_svlan_ipmc2s_add ++ * Description: ++ * add ip multicast address to SVLAN ++ * Input: ++ * svid - SVLAN VID ++ * ipmc - ip multicast address ++ * ipmcMsk - ip multicast mask ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. ++ * RT_ERR_SVLAN_ENTRY_NOT_FOUND - specified svlan entry not found. ++ * RT_ERR_OUT_OF_RANGE - input out of range. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can set IP mutlicast to SVID configuration. If upstream packet is IPv4 multicast ++ * packet and DIP is matched MC2S configuration, ASIC will assign egress SVID to the packet. ++ * There are 32 SVLAN multicast configurations for IP and L2 multicast. ++ */ ++extern rtk_api_ret_t rtk_svlan_ipmc2s_add(ipaddr_t ipmc, ipaddr_t ipmcMsk, rtk_vlan_t svid); ++ ++/* Function Name: ++ * rtk_svlan_ipmc2s_del ++ * Description: ++ * delete ip multicast address to SVLAN ++ * Input: ++ * ipmc - ip multicast address ++ * ipmcMsk - ip multicast mask ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. ++ * RT_ERR_OUT_OF_RANGE - input out of range. ++ * Note: ++ * The API can delete IP mutlicast to SVID configuration. There are 32 SVLAN multicast configurations for IP and L2 multicast. ++ */ ++extern rtk_api_ret_t rtk_svlan_ipmc2s_del(ipaddr_t ipmc, ipaddr_t ipmcMsk); ++ ++/* Function Name: ++ * rtk_svlan_ipmc2s_get ++ * Description: ++ * Get ip multicast address to SVLAN ++ * Input: ++ * ipmc - ip multicast address ++ * ipmcMsk - ip multicast mask ++ * Output: ++ * pSvid - SVLAN VID ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_OUT_OF_RANGE - input out of range. ++ * Note: ++ * The API can get IP mutlicast to SVID configuration. There are 32 SVLAN multicast configurations for IP and L2 multicast. ++ */ ++extern rtk_api_ret_t rtk_svlan_ipmc2s_get(ipaddr_t ipmc, ipaddr_t ipmcMsk, rtk_vlan_t *pSvid); ++ ++/* Function Name: ++ * rtk_svlan_l2mc2s_add ++ * Description: ++ * Add L2 multicast address to SVLAN ++ * Input: ++ * mac - L2 multicast address ++ * macMsk - L2 multicast address mask ++ * svid - SVLAN VID ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. ++ * RT_ERR_SVLAN_ENTRY_NOT_FOUND - specified svlan entry not found. ++ * RT_ERR_OUT_OF_RANGE - input out of range. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can set L2 Mutlicast to SVID configuration. If upstream packet is L2 multicast ++ * packet and DMAC is matched, ASIC will assign egress SVID to the packet. There are 32 ++ * SVLAN multicast configurations for IP and L2 multicast. ++ */ ++extern rtk_api_ret_t rtk_svlan_l2mc2s_add(rtk_mac_t mac, rtk_mac_t macMsk, rtk_vlan_t svid); ++ ++/* Function Name: ++ * rtk_svlan_l2mc2s_del ++ * Description: ++ * delete L2 multicast address to SVLAN ++ * Input: ++ * mac - L2 multicast address ++ * macMsk - L2 multicast address mask ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. ++ * RT_ERR_OUT_OF_RANGE - input out of range. ++ * Note: ++ * The API can delete Mutlicast to SVID configuration. There are 32 SVLAN multicast configurations for IP and L2 multicast. ++ */ ++extern rtk_api_ret_t rtk_svlan_l2mc2s_del(rtk_mac_t mac, rtk_mac_t macMsk); ++ ++/* Function Name: ++ * rtk_svlan_l2mc2s_get ++ * Description: ++ * Get L2 multicast address to SVLAN ++ * Input: ++ * mac - L2 multicast address ++ * macMsk - L2 multicast address mask ++ * Output: ++ * pSvid - SVLAN VID ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_OUT_OF_RANGE - input out of range. ++ * Note: ++ * The API can get L2 mutlicast to SVID configuration. There are 32 SVLAN multicast configurations for IP and L2 multicast. ++ */ ++extern rtk_api_ret_t rtk_svlan_l2mc2s_get(rtk_mac_t mac, rtk_mac_t macMsk, rtk_vlan_t *pSvid); ++ ++/* Function Name: ++ * rtk_svlan_sp2c_add ++ * Description: ++ * Add system SP2C configuration ++ * Input: ++ * cvid - VLAN ID ++ * dst_port - Destination port of SVLAN to CVLAN configuration ++ * svid - SVLAN VID ++ * ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. ++ * RT_ERR_VLAN_VID - Invalid VID parameter. ++ * RT_ERR_OUT_OF_RANGE - input out of range. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can add SVID & Destination Port to CVLAN configuration. The downstream frames with assigned ++ * SVID will be add C-tag with assigned CVID if the output port is the assigned destination port. ++ * There are 128 SP2C configurations. ++ */ ++extern rtk_api_ret_t rtk_svlan_sp2c_add(rtk_vlan_t svid, rtk_port_t dst_port, rtk_vlan_t cvid); ++ ++/* Function Name: ++ * rtk_svlan_sp2c_get ++ * Description: ++ * Get configure system SP2C content ++ * Input: ++ * svid - SVLAN VID ++ * dst_port - Destination port of SVLAN to CVLAN configuration ++ * Output: ++ * pCvid - VLAN ID ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_OUT_OF_RANGE - input out of range. ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. ++ * Note: ++ * The API can get SVID & Destination Port to CVLAN configuration. There are 128 SP2C configurations. ++ */ ++extern rtk_api_ret_t rtk_svlan_sp2c_get(rtk_vlan_t svid, rtk_port_t dst_port, rtk_vlan_t *pCvid); ++ ++/* Function Name: ++ * rtk_svlan_sp2c_del ++ * Description: ++ * Delete system SP2C configuration ++ * Input: ++ * svid - SVLAN VID ++ * dst_port - Destination port of SVLAN to CVLAN configuration ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. ++ * RT_ERR_OUT_OF_RANGE - input out of range. ++ * Note: ++ * The API can delete SVID & Destination Port to CVLAN configuration. There are 128 SP2C configurations. ++ */ ++extern rtk_api_ret_t rtk_svlan_sp2c_del(rtk_vlan_t svid, rtk_port_t dst_port); ++ ++ ++/* Function Name: ++ * rtk_svlan_lookupType_set ++ * Description: ++ * Set lookup type of SVLAN ++ * Input: ++ * type - lookup type ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * Note: ++ * none ++ */ ++extern rtk_api_ret_t rtk_svlan_lookupType_set(rtk_svlan_lookupType_t type); ++ ++/* Function Name: ++ * rtk_svlan_lookupType_get ++ * Description: ++ * Get lookup type of SVLAN ++ * Input: ++ * pType - lookup type ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * Note: ++ * none ++ */ ++extern rtk_api_ret_t rtk_svlan_lookupType_get(rtk_svlan_lookupType_t *pType); ++ ++/* Function Name: ++ * rtk_svlan_trapPri_set ++ * Description: ++ * Set svlan trap priority ++ * Input: ++ * priority - priority for trap packets ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_QOS_INT_PRIORITY ++ * Note: ++ * None ++ */ ++extern rtk_api_ret_t rtk_svlan_trapPri_set(rtk_pri_t priority); ++ ++/* Function Name: ++ * rtk_svlan_trapPri_get ++ * Description: ++ * Get svlan trap priority ++ * Input: ++ * None ++ * Output: ++ * pPriority - priority for trap packets ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_NULL_POINTER - input parameter may be null pointer ++ * Note: ++ * None ++ */ ++extern rtk_api_ret_t rtk_svlan_trapPri_get(rtk_pri_t *pPriority); ++ ++/* Function Name: ++ * rtk_svlan_unassign_action_set ++ * Description: ++ * Configure Action of upstream without svid assign action ++ * Input: ++ * action - Action for Un-assign ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_OUT_OF_RANGE - input out of range. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can configure action of upstream Un-assign svid packet. If action is not ++ * trap to CPU, the port-based SVID sure be assign as system need ++ */ ++extern rtk_api_ret_t rtk_svlan_unassign_action_set(rtk_svlan_unassign_action_t action); ++ ++/* Function Name: ++ * rtk_svlan_unassign_action_get ++ * Description: ++ * Get action of upstream without svid assignment ++ * Input: ++ * None ++ * Output: ++ * pAction - Action for Un-assign ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * Note: ++ * None ++ */ ++extern rtk_api_ret_t rtk_svlan_unassign_action_get(rtk_svlan_unassign_action_t *pAction); ++ ++ ++/* Function Name: ++ * rtk_svlan_checkAndCreateMbr ++ * Description: ++ * Check and create Member configuration and return index ++ * Input: ++ * vid - VLAN id. ++ * Output: ++ * pIndex - Member configuration index ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_VLAN_VID - Invalid VLAN ID. ++ * RT_ERR_TBL_FULL - Member Configuration table full ++ * Note: ++ * ++ */ ++extern rtk_api_ret_t rtk_svlan_checkAndCreateMbr(rtk_vlan_t vid, rtk_uint32 *pIndex); ++ ++ ++#endif /* __RTK_API_SVLAN_H__ */ +diff --git a/drivers/net/phy/rtk/rtl8367c/include/trap.h b/drivers/net/phy/rtk/rtl8367c/include/trap.h +new file mode 100644 +index 000000000000..0cdb64a77b15 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/trap.h +@@ -0,0 +1,757 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * Purpose : RTL8367/RTL8367C switch high-level API ++ * ++ * Feature : The file includes Trap module high-layer API defination ++ * ++ */ ++ ++#ifndef __RTK_API_TRAP_H__ ++#define __RTK_API_TRAP_H__ ++ ++ ++typedef enum rtk_trap_type_e ++{ ++ TRAP_BRG_GROUP = 0, ++ TRAP_FD_PAUSE, ++ TRAP_SP_MCAST, ++ TRAP_1X_PAE, ++ TRAP_UNDEF_BRG_04, ++ TRAP_UNDEF_BRG_05, ++ TRAP_UNDEF_BRG_06, ++ TRAP_UNDEF_BRG_07, ++ TRAP_PROVIDER_BRIDGE_GROUP_ADDRESS, ++ TRAP_UNDEF_BRG_09, ++ TRAP_UNDEF_BRG_0A, ++ TRAP_UNDEF_BRG_0B, ++ TRAP_UNDEF_BRG_0C, ++ TRAP_PROVIDER_BRIDGE_GVRP_ADDRESS, ++ TRAP_8021AB, ++ TRAP_UNDEF_BRG_0F, ++ TRAP_BRG_MNGEMENT, ++ TRAP_UNDEFINED_11, ++ TRAP_UNDEFINED_12, ++ TRAP_UNDEFINED_13, ++ TRAP_UNDEFINED_14, ++ TRAP_UNDEFINED_15, ++ TRAP_UNDEFINED_16, ++ TRAP_UNDEFINED_17, ++ TRAP_UNDEFINED_18, ++ TRAP_UNDEFINED_19, ++ TRAP_UNDEFINED_1A, ++ TRAP_UNDEFINED_1B, ++ TRAP_UNDEFINED_1C, ++ TRAP_UNDEFINED_1D, ++ TRAP_UNDEFINED_1E, ++ TRAP_UNDEFINED_1F, ++ TRAP_GMRP, ++ TRAP_GVRP, ++ TRAP_UNDEF_GARP_22, ++ TRAP_UNDEF_GARP_23, ++ TRAP_UNDEF_GARP_24, ++ TRAP_UNDEF_GARP_25, ++ TRAP_UNDEF_GARP_26, ++ TRAP_UNDEF_GARP_27, ++ TRAP_UNDEF_GARP_28, ++ TRAP_UNDEF_GARP_29, ++ TRAP_UNDEF_GARP_2A, ++ TRAP_UNDEF_GARP_2B, ++ TRAP_UNDEF_GARP_2C, ++ TRAP_UNDEF_GARP_2D, ++ TRAP_UNDEF_GARP_2E, ++ TRAP_UNDEF_GARP_2F, ++ TRAP_CDP, ++ TRAP_CSSTP, ++ TRAP_LLDP, ++ TRAP_END, ++}rtk_trap_type_t; ++ ++ ++typedef enum rtk_mcast_type_e ++{ ++ MCAST_L2 = 0, ++ MCAST_IPV4, ++ MCAST_IPV6, ++ MCAST_END ++} rtk_mcast_type_t; ++ ++typedef enum rtk_trap_mcast_action_e ++{ ++ MCAST_ACTION_FORWARD = 0, ++ MCAST_ACTION_DROP, ++ MCAST_ACTION_TRAP2CPU, ++ MCAST_ACTION_ROUTER_PORT, ++ MCAST_ACTION_DROP_EX_RMA, ++ MCAST_ACTION_END ++} rtk_trap_mcast_action_t; ++ ++typedef enum rtk_trap_rma_action_e ++{ ++ RMA_ACTION_FORWARD = 0, ++ RMA_ACTION_TRAP2CPU, ++ RMA_ACTION_DROP, ++ RMA_ACTION_FORWARD_EXCLUDE_CPU, ++ RMA_ACTION_END ++} rtk_trap_rma_action_t; ++ ++typedef enum rtk_trap_ucast_action_e ++{ ++ UCAST_ACTION_FORWARD_PMASK = 0, ++ UCAST_ACTION_DROP, ++ UCAST_ACTION_TRAP2CPU, ++ UCAST_ACTION_FLOODING, ++ UCAST_ACTION_END ++} rtk_trap_ucast_action_t; ++ ++typedef enum rtk_trap_ucast_type_e ++{ ++ UCAST_UNKNOWNDA = 0, ++ UCAST_UNKNOWNSA, ++ UCAST_UNMATCHSA, ++ UCAST_END ++} rtk_trap_ucast_type_t; ++ ++typedef enum rtk_trap_reason_type_e ++{ ++ TRAP_REASON_RMA = 0, ++ TRAP_REASON_OAM, ++ TRAP_REASON_1XUNAUTH, ++ TRAP_REASON_VLANSTACK, ++ TRAP_REASON_UNKNOWNMC, ++ TRAP_REASON_END, ++} rtk_trap_reason_type_t; ++ ++ ++/* Function Name: ++ * rtk_trap_unknownUnicastPktAction_set ++ * Description: ++ * Set unknown unicast packet action configuration. ++ * Input: ++ * port - ingress port ID for unknown unicast packet ++ * ucast_action - Unknown unicast action. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_NOT_ALLOWED - Invalid action. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * This API can set unknown unicast packet action configuration. ++ * The unknown unicast action is as following: ++ * - UCAST_ACTION_FORWARD_PMASK ++ * - UCAST_ACTION_DROP ++ * - UCAST_ACTION_TRAP2CPU ++ * - UCAST_ACTION_FLOODING ++ */ ++rtk_api_ret_t rtk_trap_unknownUnicastPktAction_set(rtk_port_t port, rtk_trap_ucast_action_t ucast_action); ++ ++/* Function Name: ++ * rtk_trap_unknownUnicastPktAction_get ++ * Description: ++ * Get unknown unicast packet action configuration. ++ * Input: ++ * port - ingress port ID for unknown unicast packet ++ * Output: ++ * pUcast_action - Unknown unicast action. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_NOT_ALLOWED - Invalid action. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_NULL_POINTER - Null pointer ++ * Note: ++ * This API can get unknown unicast packet action configuration. ++ * The unknown unicast action is as following: ++ * - UCAST_ACTION_FORWARD_PMASK ++ * - UCAST_ACTION_DROP ++ * - UCAST_ACTION_TRAP2CPU ++ * - UCAST_ACTION_FLOODING ++ */ ++rtk_api_ret_t rtk_trap_unknownUnicastPktAction_get(rtk_port_t port, rtk_trap_ucast_action_t *pUcast_action); ++ ++/* Function Name: ++ * rtk_trap_unknownMacPktAction_set ++ * Description: ++ * Set unknown source MAC packet action configuration. ++ * Input: ++ * ucast_action - Unknown source MAC action. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_NOT_ALLOWED - Invalid action. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * This API can set unknown unicast packet action configuration. ++ * The unknown unicast action is as following: ++ * - UCAST_ACTION_FORWARD_PMASK ++ * - UCAST_ACTION_DROP ++ * - UCAST_ACTION_TRAP2CPU ++ */ ++extern rtk_api_ret_t rtk_trap_unknownMacPktAction_set(rtk_trap_ucast_action_t ucast_action); ++ ++/* Function Name: ++ * rtk_trap_unknownMacPktAction_get ++ * Description: ++ * Get unknown source MAC packet action configuration. ++ * Input: ++ * None. ++ * Output: ++ * pUcast_action - Unknown source MAC action. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_NULL_POINTER - Null Pointer. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * ++ */ ++extern rtk_api_ret_t rtk_trap_unknownMacPktAction_get(rtk_trap_ucast_action_t *pUcast_action); ++ ++/* Function Name: ++ * rtk_trap_unmatchMacPktAction_set ++ * Description: ++ * Set unmatch source MAC packet action configuration. ++ * Input: ++ * ucast_action - Unknown source MAC action. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_NOT_ALLOWED - Invalid action. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * This API can set unknown unicast packet action configuration. ++ * The unknown unicast action is as following: ++ * - UCAST_ACTION_FORWARD_PMASK ++ * - UCAST_ACTION_DROP ++ * - UCAST_ACTION_TRAP2CPU ++ */ ++extern rtk_api_ret_t rtk_trap_unmatchMacPktAction_set(rtk_trap_ucast_action_t ucast_action); ++ ++/* Function Name: ++ * rtk_trap_unmatchMacPktAction_get ++ * Description: ++ * Get unmatch source MAC packet action configuration. ++ * Input: ++ * None. ++ * Output: ++ * pUcast_action - Unknown source MAC action. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_NOT_ALLOWED - Invalid action. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * This API can set unknown unicast packet action configuration. ++ * The unknown unicast action is as following: ++ * - UCAST_ACTION_FORWARD_PMASK ++ * - UCAST_ACTION_DROP ++ * - UCAST_ACTION_TRAP2CPU ++ */ ++extern rtk_api_ret_t rtk_trap_unmatchMacPktAction_get(rtk_trap_ucast_action_t *pUcast_action); ++ ++/* Function Name: ++ * rtk_trap_unmatchMacMoving_set ++ * Description: ++ * Set unmatch source MAC packet moving state. ++ * Input: ++ * port - Port ID. ++ * enable - ENABLED: allow SA moving, DISABLE: don't allow SA moving. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_NOT_ALLOWED - Invalid action. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ */ ++extern rtk_api_ret_t rtk_trap_unmatchMacMoving_set(rtk_port_t port, rtk_enable_t enable); ++ ++/* Function Name: ++ * rtk_trap_unmatchMacMoving_get ++ * Description: ++ * Set unmatch source MAC packet moving state. ++ * Input: ++ * port - Port ID. ++ * Output: ++ * pEnable - ENABLED: allow SA moving, DISABLE: don't allow SA moving. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_NOT_ALLOWED - Invalid action. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ */ ++extern rtk_api_ret_t rtk_trap_unmatchMacMoving_get(rtk_port_t port, rtk_enable_t *pEnable); ++ ++/* Function Name: ++ * rtk_trap_unknownMcastPktAction_set ++ * Description: ++ * Set behavior of unknown multicast ++ * Input: ++ * port - Port id. ++ * type - unknown multicast packet type. ++ * mcast_action - unknown multicast action. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_NOT_ALLOWED - Invalid action. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * When receives an unknown multicast packet, switch may trap, drop or flood this packet ++ * (1) The unknown multicast packet type is as following: ++ * - MCAST_L2 ++ * - MCAST_IPV4 ++ * - MCAST_IPV6 ++ * (2) The unknown multicast action is as following: ++ * - MCAST_ACTION_FORWARD ++ * - MCAST_ACTION_DROP ++ * - MCAST_ACTION_TRAP2CPU ++ */ ++extern rtk_api_ret_t rtk_trap_unknownMcastPktAction_set(rtk_port_t port, rtk_mcast_type_t type, rtk_trap_mcast_action_t mcast_action); ++ ++/* Function Name: ++ * rtk_trap_unknownMcastPktAction_get ++ * Description: ++ * Get behavior of unknown multicast ++ * Input: ++ * type - unknown multicast packet type. ++ * Output: ++ * pMcast_action - unknown multicast action. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_NOT_ALLOWED - Invalid operation. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * When receives an unknown multicast packet, switch may trap, drop or flood this packet ++ * (1) The unknown multicast packet type is as following: ++ * - MCAST_L2 ++ * - MCAST_IPV4 ++ * - MCAST_IPV6 ++ * (2) The unknown multicast action is as following: ++ * - MCAST_ACTION_FORWARD ++ * - MCAST_ACTION_DROP ++ * - MCAST_ACTION_TRAP2CPU ++ */ ++extern rtk_api_ret_t rtk_trap_unknownMcastPktAction_get(rtk_port_t port, rtk_mcast_type_t type, rtk_trap_mcast_action_t *pMcast_action); ++ ++/* Function Name: ++ * rtk_trap_lldpEnable_set ++ * Description: ++ * Set LLDP enable. ++ * Input: ++ * enabled - LLDP enable, 0: follow RMA, 1: use LLDP action. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_NOT_ALLOWED - Invalid action. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * - DMAC Assignment ++ * - 01:80:c2:00:00:0e ethertype = 0x88CC LLDP ++ * - 01:80:c2:00:00:03 ethertype = 0x88CC ++ * - 01:80:c2:00:00:00 ethertype = 0x88CC ++ ++ */ ++extern rtk_api_ret_t rtk_trap_lldpEnable_set(rtk_enable_t enabled); ++ ++/* Function Name: ++ * rtk_trap_lldpEnable_get ++ * Description: ++ * Get LLDP status. ++ * Input: ++ * None ++ * Output: ++ * pEnabled - LLDP enable, 0: follow RMA, 1: use LLDP action. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * LLDP is as following definition. ++ * - DMAC Assignment ++ * - 01:80:c2:00:00:0e ethertype = 0x88CC LLDP ++ * - 01:80:c2:00:00:03 ethertype = 0x88CC ++ * - 01:80:c2:00:00:00 ethertype = 0x88CC ++ */ ++extern rtk_api_ret_t rtk_trap_lldpEnable_get(rtk_enable_t *pEnabled); ++ ++/* Function Name: ++ * rtk_trap_reasonTrapToCpuPriority_set ++ * Description: ++ * Set priority value of a packet that trapped to CPU port according to specific reason. ++ * Input: ++ * type - reason that trap to CPU port. ++ * priority - internal priority that is going to be set for specific trap reason. ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_NOT_INIT - The module is not initial ++ * RT_ERR_INPUT - Invalid input parameter ++ * Note: ++ * Currently the trap reason that supported are listed as follows: ++ * - TRAP_REASON_RMA ++ * - TRAP_REASON_OAM ++ * - TRAP_REASON_1XUNAUTH ++ * - TRAP_REASON_VLANSTACK ++ * - TRAP_REASON_UNKNOWNMC ++ */ ++extern rtk_api_ret_t rtk_trap_reasonTrapToCpuPriority_set(rtk_trap_reason_type_t type, rtk_pri_t priority); ++ ++/* Function Name: ++ * rtk_trap_reasonTrapToCpuPriority_get ++ * Description: ++ * Get priority value of a packet that trapped to CPU port according to specific reason. ++ * Input: ++ * type - reason that trap to CPU port. ++ * Output: ++ * pPriority - configured internal priority for such reason. ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_NOT_INIT - The module is not initial ++ * RT_ERR_INPUT - Invalid input parameter ++ * RT_ERR_NULL_POINTER - NULL pointer ++ * Note: ++ * Currently the trap reason that supported are listed as follows: ++ * - TRAP_REASON_RMA ++ * - TRAP_REASON_OAM ++ * - TRAP_REASON_1XUNAUTH ++ * - TRAP_REASON_VLANSTACK ++ * - TRAP_REASON_UNKNOWNMC ++ */ ++extern rtk_api_ret_t rtk_trap_reasonTrapToCpuPriority_get(rtk_trap_reason_type_t type, rtk_pri_t *pPriority); ++ ++/* Function Name: ++ * rtk_trap_rmaAction_set ++ * Description: ++ * Set Reserved multicast address action configuration. ++ * Input: ++ * type - rma type. ++ * rma_action - RMA action. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_ENABLE - Invalid IFG parameter ++ * Note: ++ * ++ * There are 48 types of Reserved Multicast Address frame for application usage. ++ * (1)They are as following definition. ++ * - TRAP_BRG_GROUP, ++ * - TRAP_FD_PAUSE, ++ * - TRAP_SP_MCAST, ++ * - TRAP_1X_PAE, ++ * - TRAP_UNDEF_BRG_04, ++ * - TRAP_UNDEF_BRG_05, ++ * - TRAP_UNDEF_BRG_06, ++ * - TRAP_UNDEF_BRG_07, ++ * - TRAP_PROVIDER_BRIDGE_GROUP_ADDRESS, ++ * - TRAP_UNDEF_BRG_09, ++ * - TRAP_UNDEF_BRG_0A, ++ * - TRAP_UNDEF_BRG_0B, ++ * - TRAP_UNDEF_BRG_0C, ++ * - TRAP_PROVIDER_BRIDGE_GVRP_ADDRESS, ++ * - TRAP_8021AB, ++ * - TRAP_UNDEF_BRG_0F, ++ * - TRAP_BRG_MNGEMENT, ++ * - TRAP_UNDEFINED_11, ++ * - TRAP_UNDEFINED_12, ++ * - TRAP_UNDEFINED_13, ++ * - TRAP_UNDEFINED_14, ++ * - TRAP_UNDEFINED_15, ++ * - TRAP_UNDEFINED_16, ++ * - TRAP_UNDEFINED_17, ++ * - TRAP_UNDEFINED_18, ++ * - TRAP_UNDEFINED_19, ++ * - TRAP_UNDEFINED_1A, ++ * - TRAP_UNDEFINED_1B, ++ * - TRAP_UNDEFINED_1C, ++ * - TRAP_UNDEFINED_1D, ++ * - TRAP_UNDEFINED_1E, ++ * - TRAP_UNDEFINED_1F, ++ * - TRAP_GMRP, ++ * - TRAP_GVRP, ++ * - TRAP_UNDEF_GARP_22, ++ * - TRAP_UNDEF_GARP_23, ++ * - TRAP_UNDEF_GARP_24, ++ * - TRAP_UNDEF_GARP_25, ++ * - TRAP_UNDEF_GARP_26, ++ * - TRAP_UNDEF_GARP_27, ++ * - TRAP_UNDEF_GARP_28, ++ * - TRAP_UNDEF_GARP_29, ++ * - TRAP_UNDEF_GARP_2A, ++ * - TRAP_UNDEF_GARP_2B, ++ * - TRAP_UNDEF_GARP_2C, ++ * - TRAP_UNDEF_GARP_2D, ++ * - TRAP_UNDEF_GARP_2E, ++ * - TRAP_UNDEF_GARP_2F, ++ * - TRAP_CDP. ++ * - TRAP_CSSTP. ++ * - TRAP_LLDP. ++ * (2) The RMA action is as following: ++ * - RMA_ACTION_FORWARD ++ * - RMA_ACTION_TRAP2CPU ++ * - RMA_ACTION_DROP ++ * - RMA_ACTION_FORWARD_EXCLUDE_CPU ++ */ ++extern rtk_api_ret_t rtk_trap_rmaAction_set(rtk_trap_type_t type, rtk_trap_rma_action_t rma_action); ++ ++/* Function Name: ++ * rtk_trap_rmaAction_get ++ * Description: ++ * Get Reserved multicast address action configuration. ++ * Input: ++ * type - rma type. ++ * Output: ++ * pRma_action - RMA action. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * There are 48 types of Reserved Multicast Address frame for application usage. ++ * (1)They are as following definition. ++ * - TRAP_BRG_GROUP, ++ * - TRAP_FD_PAUSE, ++ * - TRAP_SP_MCAST, ++ * - TRAP_1X_PAE, ++ * - TRAP_UNDEF_BRG_04, ++ * - TRAP_UNDEF_BRG_05, ++ * - TRAP_UNDEF_BRG_06, ++ * - TRAP_UNDEF_BRG_07, ++ * - TRAP_PROVIDER_BRIDGE_GROUP_ADDRESS, ++ * - TRAP_UNDEF_BRG_09, ++ * - TRAP_UNDEF_BRG_0A, ++ * - TRAP_UNDEF_BRG_0B, ++ * - TRAP_UNDEF_BRG_0C, ++ * - TRAP_PROVIDER_BRIDGE_GVRP_ADDRESS, ++ * - TRAP_8021AB, ++ * - TRAP_UNDEF_BRG_0F, ++ * - TRAP_BRG_MNGEMENT, ++ * - TRAP_UNDEFINED_11, ++ * - TRAP_UNDEFINED_12, ++ * - TRAP_UNDEFINED_13, ++ * - TRAP_UNDEFINED_14, ++ * - TRAP_UNDEFINED_15, ++ * - TRAP_UNDEFINED_16, ++ * - TRAP_UNDEFINED_17, ++ * - TRAP_UNDEFINED_18, ++ * - TRAP_UNDEFINED_19, ++ * - TRAP_UNDEFINED_1A, ++ * - TRAP_UNDEFINED_1B, ++ * - TRAP_UNDEFINED_1C, ++ * - TRAP_UNDEFINED_1D, ++ * - TRAP_UNDEFINED_1E, ++ * - TRAP_UNDEFINED_1F, ++ * - TRAP_GMRP, ++ * - TRAP_GVRP, ++ * - TRAP_UNDEF_GARP_22, ++ * - TRAP_UNDEF_GARP_23, ++ * - TRAP_UNDEF_GARP_24, ++ * - TRAP_UNDEF_GARP_25, ++ * - TRAP_UNDEF_GARP_26, ++ * - TRAP_UNDEF_GARP_27, ++ * - TRAP_UNDEF_GARP_28, ++ * - TRAP_UNDEF_GARP_29, ++ * - TRAP_UNDEF_GARP_2A, ++ * - TRAP_UNDEF_GARP_2B, ++ * - TRAP_UNDEF_GARP_2C, ++ * - TRAP_UNDEF_GARP_2D, ++ * - TRAP_UNDEF_GARP_2E, ++ * - TRAP_UNDEF_GARP_2F, ++ * - TRAP_CDP. ++ * - TRAP_CSSTP. ++ * - TRAP_LLDP. ++ * (2) The RMA action is as following: ++ * - RMA_ACTION_FORWARD ++ * - RMA_ACTION_TRAP2CPU ++ * - RMA_ACTION_DROP ++ * - RMA_ACTION_FORWARD_EXCLUDE_CPU ++ */ ++extern rtk_api_ret_t rtk_trap_rmaAction_get(rtk_trap_type_t type, rtk_trap_rma_action_t *pRma_action); ++ ++/* Function Name: ++ * rtk_trap_rmaKeepFormat_set ++ * Description: ++ * Set Reserved multicast address keep format configuration. ++ * Input: ++ * type - rma type. ++ * enable - enable keep format. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_ENABLE - Invalid IFG parameter ++ * Note: ++ * ++ * There are 48 types of Reserved Multicast Address frame for application usage. ++ * They are as following definition. ++ * - TRAP_BRG_GROUP, ++ * - TRAP_FD_PAUSE, ++ * - TRAP_SP_MCAST, ++ * - TRAP_1X_PAE, ++ * - TRAP_UNDEF_BRG_04, ++ * - TRAP_UNDEF_BRG_05, ++ * - TRAP_UNDEF_BRG_06, ++ * - TRAP_UNDEF_BRG_07, ++ * - TRAP_PROVIDER_BRIDGE_GROUP_ADDRESS, ++ * - TRAP_UNDEF_BRG_09, ++ * - TRAP_UNDEF_BRG_0A, ++ * - TRAP_UNDEF_BRG_0B, ++ * - TRAP_UNDEF_BRG_0C, ++ * - TRAP_PROVIDER_BRIDGE_GVRP_ADDRESS, ++ * - TRAP_8021AB, ++ * - TRAP_UNDEF_BRG_0F, ++ * - TRAP_BRG_MNGEMENT, ++ * - TRAP_UNDEFINED_11, ++ * - TRAP_UNDEFINED_12, ++ * - TRAP_UNDEFINED_13, ++ * - TRAP_UNDEFINED_14, ++ * - TRAP_UNDEFINED_15, ++ * - TRAP_UNDEFINED_16, ++ * - TRAP_UNDEFINED_17, ++ * - TRAP_UNDEFINED_18, ++ * - TRAP_UNDEFINED_19, ++ * - TRAP_UNDEFINED_1A, ++ * - TRAP_UNDEFINED_1B, ++ * - TRAP_UNDEFINED_1C, ++ * - TRAP_UNDEFINED_1D, ++ * - TRAP_UNDEFINED_1E, ++ * - TRAP_UNDEFINED_1F, ++ * - TRAP_GMRP, ++ * - TRAP_GVRP, ++ * - TRAP_UNDEF_GARP_22, ++ * - TRAP_UNDEF_GARP_23, ++ * - TRAP_UNDEF_GARP_24, ++ * - TRAP_UNDEF_GARP_25, ++ * - TRAP_UNDEF_GARP_26, ++ * - TRAP_UNDEF_GARP_27, ++ * - TRAP_UNDEF_GARP_28, ++ * - TRAP_UNDEF_GARP_29, ++ * - TRAP_UNDEF_GARP_2A, ++ * - TRAP_UNDEF_GARP_2B, ++ * - TRAP_UNDEF_GARP_2C, ++ * - TRAP_UNDEF_GARP_2D, ++ * - TRAP_UNDEF_GARP_2E, ++ * - TRAP_UNDEF_GARP_2F, ++ * - TRAP_CDP. ++ * - TRAP_CSSTP. ++ * - TRAP_LLDP. ++ */ ++extern rtk_api_ret_t rtk_trap_rmaKeepFormat_set(rtk_trap_type_t type, rtk_enable_t enable); ++ ++/* Function Name: ++ * rtk_trap_rmaKeepFormat_get ++ * Description: ++ * Get Reserved multicast address action configuration. ++ * Input: ++ * type - rma type. ++ * Output: ++ * pEnable - keep format status. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * There are 48 types of Reserved Multicast Address frame for application usage. ++ * They are as following definition. ++ * - TRAP_BRG_GROUP, ++ * - TRAP_FD_PAUSE, ++ * - TRAP_SP_MCAST, ++ * - TRAP_1X_PAE, ++ * - TRAP_UNDEF_BRG_04, ++ * - TRAP_UNDEF_BRG_05, ++ * - TRAP_UNDEF_BRG_06, ++ * - TRAP_UNDEF_BRG_07, ++ * - TRAP_PROVIDER_BRIDGE_GROUP_ADDRESS, ++ * - TRAP_UNDEF_BRG_09, ++ * - TRAP_UNDEF_BRG_0A, ++ * - TRAP_UNDEF_BRG_0B, ++ * - TRAP_UNDEF_BRG_0C, ++ * - TRAP_PROVIDER_BRIDGE_GVRP_ADDRESS, ++ * - TRAP_8021AB, ++ * - TRAP_UNDEF_BRG_0F, ++ * - TRAP_BRG_MNGEMENT, ++ * - TRAP_UNDEFINED_11, ++ * - TRAP_UNDEFINED_12, ++ * - TRAP_UNDEFINED_13, ++ * - TRAP_UNDEFINED_14, ++ * - TRAP_UNDEFINED_15, ++ * - TRAP_UNDEFINED_16, ++ * - TRAP_UNDEFINED_17, ++ * - TRAP_UNDEFINED_18, ++ * - TRAP_UNDEFINED_19, ++ * - TRAP_UNDEFINED_1A, ++ * - TRAP_UNDEFINED_1B, ++ * - TRAP_UNDEFINED_1C, ++ * - TRAP_UNDEFINED_1D, ++ * - TRAP_UNDEFINED_1E, ++ * - TRAP_UNDEFINED_1F, ++ * - TRAP_GMRP, ++ * - TRAP_GVRP, ++ * - TRAP_UNDEF_GARP_22, ++ * - TRAP_UNDEF_GARP_23, ++ * - TRAP_UNDEF_GARP_24, ++ * - TRAP_UNDEF_GARP_25, ++ * - TRAP_UNDEF_GARP_26, ++ * - TRAP_UNDEF_GARP_27, ++ * - TRAP_UNDEF_GARP_28, ++ * - TRAP_UNDEF_GARP_29, ++ * - TRAP_UNDEF_GARP_2A, ++ * - TRAP_UNDEF_GARP_2B, ++ * - TRAP_UNDEF_GARP_2C, ++ * - TRAP_UNDEF_GARP_2D, ++ * - TRAP_UNDEF_GARP_2E, ++ * - TRAP_UNDEF_GARP_2F, ++ * - TRAP_CDP. ++ * - TRAP_CSSTP. ++ * - TRAP_LLDP. ++ */ ++extern rtk_api_ret_t rtk_trap_rmaKeepFormat_get(rtk_trap_type_t type, rtk_enable_t *pEnable); ++ ++ ++#endif /* __RTK_API_TRAP_H__ */ ++ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/include/trunk.h b/drivers/net/phy/rtk/rtl8367c/include/trunk.h +new file mode 100644 +index 000000000000..dff61769dfd2 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/trunk.h +@@ -0,0 +1,328 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * Purpose : RTL8367/RTL8367C switch high-level API ++ * ++ * Feature : The file includes Trunk module high-layer TRUNK defination ++ * ++ */ ++ ++#ifndef __RTK_API_TRUNK_H__ ++#define __RTK_API_TRUNK_H__ ++ ++/* ++ * Data Type Declaration ++ */ ++#define RTK_TRUNK_DPORT_HASH_MASK 0x40 ++#define RTK_TRUNK_SPORT_HASH_MASK 0x20 ++#define RTK_TRUNK_DIP_HASH_MASK 0x10 ++#define RTK_TRUNK_SIP_HASH_MASK 0x8 ++#define RTK_TRUNK_DMAC_HASH_MASK 0x4 ++#define RTK_TRUNK_SMAC_HASH_MASK 0x2 ++#define RTK_TRUNK_SPA_HASH_MASK 0x1 ++ ++ ++#define RTK_MAX_NUM_OF_TRUNK_HASH_VAL 16 ++ ++typedef struct rtk_trunk_hashVal2Port_s ++{ ++ rtk_uint8 value[RTK_MAX_NUM_OF_TRUNK_HASH_VAL]; ++} rtk_trunk_hashVal2Port_t; ++ ++typedef enum rtk_trunk_group_e ++{ ++ TRUNK_GROUP0 = 0, ++ TRUNK_GROUP1, ++ TRUNK_GROUP2, ++ TRUNK_GROUP3, ++ TRUNK_GROUP_END ++} rtk_trunk_group_t; ++ ++typedef enum rtk_trunk_separateType_e ++{ ++ SEPARATE_NONE = 0, ++ SEPARATE_FLOOD, ++ SEPARATE_END ++ ++} rtk_trunk_separateType_t; ++ ++typedef enum rtk_trunk_mode_e ++{ ++ TRUNK_MODE_NORMAL = 0, ++ TRUNK_MODE_DUMB, ++ TRUNK_MODE_END ++} rtk_trunk_mode_t; ++ ++/* Function Name: ++ * rtk_trunk_port_set ++ * Description: ++ * Set trunking group available port mask ++ * Input: ++ * trk_gid - trunk group id ++ * pTrunk_member_portmask - Logic trunking member port mask ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_LA_TRUNK_ID - Invalid trunking group ++ * RT_ERR_PORT_MASK - Invalid portmask. ++ * Note: ++ * The API can set port trunking group port mask. Each port trunking group has max 4 ports. ++ * If enabled port mask has less than 2 ports available setting, then this trunking group function is disabled. ++ */ ++extern rtk_api_ret_t rtk_trunk_port_set(rtk_trunk_group_t trk_gid, rtk_portmask_t *pTrunk_member_portmask); ++ ++/* Function Name: ++ * rtk_trunk_port_get ++ * Description: ++ * Get trunking group available port mask ++ * Input: ++ * trk_gid - trunk group id ++ * Output: ++ * pTrunk_member_portmask - Logic trunking member port mask ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_LA_TRUNK_ID - Invalid trunking group ++ * Note: ++ * The API can get 2 port trunking group. ++ */ ++extern rtk_api_ret_t rtk_trunk_port_get(rtk_trunk_group_t trk_gid, rtk_portmask_t *pTrunk_member_portmask); ++ ++/* Function Name: ++ * rtk_trunk_distributionAlgorithm_set ++ * Description: ++ * Set port trunking hash select sources ++ * Input: ++ * trk_gid - trunk group id ++ * algo_bitmask - Bitmask of the distribution algorithm ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_LA_TRUNK_ID - Invalid trunking group ++ * RT_ERR_LA_HASHMASK - Hash algorithm selection error. ++ * RT_ERR_PORT_MASK - Invalid portmask. ++ * Note: ++ * The API can set port trunking hash algorithm sources. ++ * 7 bits mask for link aggregation group0 hash parameter selection {DIP, SIP, DMAC, SMAC, SPA} ++ * - 0b0000001: SPA ++ * - 0b0000010: SMAC ++ * - 0b0000100: DMAC ++ * - 0b0001000: SIP ++ * - 0b0010000: DIP ++ * - 0b0100000: TCP/UDP Source Port ++ * - 0b1000000: TCP/UDP Destination Port ++ * Example: ++ * - 0b0000011: SMAC & SPA ++ * - Note that it could be an arbitrary combination or independent set ++ */ ++extern rtk_api_ret_t rtk_trunk_distributionAlgorithm_set(rtk_trunk_group_t trk_gid, rtk_uint32 algo_bitmask); ++ ++/* Function Name: ++ * rtk_trunk_distributionAlgorithm_get ++ * Description: ++ * Get port trunking hash select sources ++ * Input: ++ * trk_gid - trunk group id ++ * Output: ++ * pAlgo_bitmask - Bitmask of the distribution algorithm ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_LA_TRUNK_ID - Invalid trunking group ++ * Note: ++ * The API can get port trunking hash algorithm sources. ++ */ ++extern rtk_api_ret_t rtk_trunk_distributionAlgorithm_get(rtk_trunk_group_t trk_gid, rtk_uint32 *pAlgo_bitmask); ++ ++/* Function Name: ++ * rtk_trunk_trafficSeparate_set ++ * Description: ++ * Set the traffic separation setting of a trunk group from the specified device. ++ * Input: ++ * trk_gid - trunk group id ++ * separateType - traffic separation setting ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_UNIT_ID - invalid unit id ++ * RT_ERR_LA_TRUNK_ID - invalid trunk ID ++ * RT_ERR_LA_HASHMASK - invalid hash mask ++ * Note: ++ * SEPARATE_NONE: disable traffic separation ++ * SEPARATE_FLOOD: trunk MSB link up port is dedicated to TX flooding (L2 lookup miss) traffic ++ */ ++extern rtk_api_ret_t rtk_trunk_trafficSeparate_set(rtk_trunk_group_t trk_gid, rtk_trunk_separateType_t separateType); ++ ++/* Function Name: ++ * rtk_trunk_trafficSeparate_get ++ * Description: ++ * Get the traffic separation setting of a trunk group from the specified device. ++ * Input: ++ * trk_gid - trunk group id ++ * Output: ++ * pSeparateType - pointer separated traffic type ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_UNIT_ID - invalid unit id ++ * RT_ERR_LA_TRUNK_ID - invalid trunk ID ++ * RT_ERR_NULL_POINTER - input parameter may be null pointer ++ * Note: ++ * SEPARATE_NONE: disable traffic separation ++ * SEPARATE_FLOOD: trunk MSB link up port is dedicated to TX flooding (L2 lookup miss) traffic ++ */ ++extern rtk_api_ret_t rtk_trunk_trafficSeparate_get(rtk_trunk_group_t trk_gid, rtk_trunk_separateType_t *pSeparateType); ++ ++ ++/* Function Name: ++ * rtk_trunk_mode_set ++ * Description: ++ * Set the trunk mode to the specified device. ++ * Input: ++ * mode - trunk mode ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_INPUT - invalid input parameter ++ * Note: ++ * The enum of the trunk mode as following ++ * - TRUNK_MODE_NORMAL ++ * - TRUNK_MODE_DUMB ++ */ ++extern rtk_api_ret_t rtk_trunk_mode_set(rtk_trunk_mode_t mode); ++ ++/* Function Name: ++ * rtk_trunk_mode_get ++ * Description: ++ * Get the trunk mode from the specified device. ++ * Input: ++ * None ++ * Output: ++ * pMode - pointer buffer of trunk mode ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_NULL_POINTER - input parameter may be null pointer ++ * Note: ++ * The enum of the trunk mode as following ++ * - TRUNK_MODE_NORMAL ++ * - TRUNK_MODE_DUMB ++ */ ++extern rtk_api_ret_t rtk_trunk_mode_get(rtk_trunk_mode_t *pMode); ++ ++/* Function Name: ++ * rtk_trunk_trafficPause_set ++ * Description: ++ * Set the traffic pause setting of a trunk group. ++ * Input: ++ * trk_gid - trunk group id ++ * enable - traffic pause state ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_LA_TRUNK_ID - invalid trunk ID ++ * Note: ++ * None. ++ */ ++extern rtk_api_ret_t rtk_trunk_trafficPause_set(rtk_trunk_group_t trk_gid, rtk_enable_t enable); ++ ++/* Function Name: ++ * rtk_trunk_trafficPause_get ++ * Description: ++ * Get the traffic pause setting of a trunk group. ++ * Input: ++ * trk_gid - trunk group id ++ * Output: ++ * pEnable - pointer of traffic pause state. ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_LA_TRUNK_ID - invalid trunk ID ++ * RT_ERR_NULL_POINTER - input parameter may be null pointer ++ * Note: ++ * None. ++ */ ++extern rtk_api_ret_t rtk_trunk_trafficPause_get(rtk_trunk_group_t trk_gid, rtk_enable_t *pEnable); ++ ++/* Function Name: ++ * rtk_trunk_hashMappingTable_set ++ * Description: ++ * Set hash value to port array in the trunk group id from the specified device. ++ * Input: ++ * trk_gid - trunk group id ++ * pHash2Port_array - ports associate with the hash value ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_UNIT_ID - invalid unit id ++ * RT_ERR_LA_TRUNK_ID - invalid trunk ID ++ * RT_ERR_NULL_POINTER - input parameter may be null pointer ++ * RT_ERR_LA_TRUNK_NOT_EXIST - the trunk doesn't exist ++ * RT_ERR_LA_NOT_MEMBER_PORT - the port is not a member port of the trunk ++ * RT_ERR_LA_CPUPORT - CPU port can not be aggregated port ++ * Note: ++ * Trunk group 0 & 1 shares the same hash mapping table. ++ * Trunk group 2 uses a independent table. ++ */ ++extern rtk_api_ret_t rtk_trunk_hashMappingTable_set(rtk_trunk_group_t trk_gid, rtk_trunk_hashVal2Port_t *pHash2Port_array); ++ ++/* Function Name: ++ * rtk_trunk_hashMappingTable_get ++ * Description: ++ * Get hash value to port array in the trunk group id from the specified device. ++ * Input: ++ * trk_gid - trunk group id ++ * Output: ++ * pHash2Port_array - pointer buffer of ports associate with the hash value ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_UNIT_ID - invalid unit id ++ * RT_ERR_LA_TRUNK_ID - invalid trunk ID ++ * RT_ERR_NULL_POINTER - input parameter may be null pointer ++ * Note: ++ * Trunk group 0 & 1 shares the same hash mapping table. ++ * Trunk group 2 uses a independent table. ++ */ ++extern rtk_api_ret_t rtk_trunk_hashMappingTable_get(rtk_trunk_group_t trk_gid, rtk_trunk_hashVal2Port_t *pHash2Port_array); ++ ++/* Function Name: ++ * rtk_trunk_portQueueEmpty_get ++ * Description: ++ * Get the port mask which all queues are empty. ++ * Input: ++ * None. ++ * Output: ++ * pEmpty_portmask - pointer empty port mask ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_NULL_POINTER - input parameter may be null pointer ++ * Note: ++ * None. ++ */ ++extern rtk_api_ret_t rtk_trunk_portQueueEmpty_get(rtk_portmask_t *pEmpty_portmask); ++ ++#endif /* __RTK_API_TRUNK_H__ */ +diff --git a/drivers/net/phy/rtk/rtl8367c/include/vlan.h b/drivers/net/phy/rtk/rtl8367c/include/vlan.h +new file mode 100644 +index 000000000000..8569fc0d40f4 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/include/vlan.h +@@ -0,0 +1,892 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * Purpose : RTL8367/RTL8367C switch high-level API ++ * ++ * Feature : The file includes Trap module high-layer VLAN defination ++ * ++ */ ++ ++#ifndef __RTK_API_VLAN_H__ ++#define __RTK_API_VLAN_H__ ++ ++ ++/* ++ * Data Type Declaration ++ */ ++#define RTK_MAX_NUM_OF_PROTO_TYPE 0xFFFF ++#define RTK_MAX_NUM_OF_MSTI 0xF ++#define RTK_FID_MAX 0xF ++ ++typedef struct rtk_vlan_cfg_s ++{ ++ rtk_portmask_t mbr; ++ rtk_portmask_t untag; ++ rtk_uint16 ivl_en; ++ rtk_uint16 fid_msti; ++ rtk_uint16 envlanpol; ++ rtk_uint16 meteridx; ++ rtk_uint16 vbpen; ++ rtk_uint16 vbpri; ++}rtk_vlan_cfg_t; ++ ++typedef struct rtk_vlan_mbrcfg_s ++{ ++ rtk_uint16 evid; ++ rtk_portmask_t mbr; ++ rtk_uint16 fid_msti; ++ rtk_uint16 envlanpol; ++ rtk_uint16 meteridx; ++ rtk_uint16 vbpen; ++ rtk_uint16 vbpri; ++}rtk_vlan_mbrcfg_t; ++ ++typedef rtk_uint32 rtk_stp_msti_id_t; /* MSTI ID */ ++ ++typedef enum rtk_stp_state_e ++{ ++ STP_STATE_DISABLED = 0, ++ STP_STATE_BLOCKING, ++ STP_STATE_LEARNING, ++ STP_STATE_FORWARDING, ++ STP_STATE_END ++} rtk_stp_state_t; ++ ++typedef rtk_uint32 rtk_vlan_proto_type_t; /* protocol and port based VLAN protocol type */ ++ ++ ++typedef enum rtk_vlan_acceptFrameType_e ++{ ++ ACCEPT_FRAME_TYPE_ALL = 0, /* untagged, priority-tagged and tagged */ ++ ACCEPT_FRAME_TYPE_TAG_ONLY, /* tagged */ ++ ACCEPT_FRAME_TYPE_UNTAG_ONLY, /* untagged and priority-tagged */ ++ ACCEPT_FRAME_TYPE_END ++} rtk_vlan_acceptFrameType_t; ++ ++ ++/* frame type of protocol vlan - reference 802.1v standard */ ++typedef enum rtk_vlan_protoVlan_frameType_e ++{ ++ FRAME_TYPE_ETHERNET = 0, ++ FRAME_TYPE_LLCOTHER, ++ FRAME_TYPE_RFC1042, ++ FRAME_TYPE_END ++} rtk_vlan_protoVlan_frameType_t; ++ ++/* Protocol-and-port-based Vlan structure */ ++typedef struct rtk_vlan_protoAndPortInfo_s ++{ ++ rtk_uint32 proto_type; ++ rtk_vlan_protoVlan_frameType_t frame_type; ++ rtk_vlan_t cvid; ++ rtk_pri_t cpri; ++}rtk_vlan_protoAndPortInfo_t; ++ ++/* tagged mode of VLAN - reference realtek private specification */ ++typedef enum rtk_vlan_tagMode_e ++{ ++ VLAN_TAG_MODE_ORIGINAL = 0, ++ VLAN_TAG_MODE_KEEP_FORMAT, ++ VLAN_TAG_MODE_PRI, ++ VLAN_TAG_MODE_REAL_KEEP_FORMAT, ++ VLAN_TAG_MODE_END ++} rtk_vlan_tagMode_t; ++ ++typedef enum rtk_vlan_resVidAction_e ++{ ++ RESVID_ACTION_UNTAG = 0, ++ RESVID_ACTION_TAG, ++ RESVID_ACTION_END ++} ++rtk_vlan_resVidAction_t; ++ ++/* Function Name: ++ * rtk_vlan_init ++ * Description: ++ * Initialize VLAN. ++ * Input: ++ * None ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * VLAN is disabled by default. User has to call this API to enable VLAN before ++ * using it. And It will set a default VLAN(vid 1) including all ports and set ++ * all ports PVID to the default VLAN. ++ */ ++extern rtk_api_ret_t rtk_vlan_init(void); ++ ++/* Function Name: ++ * rtk_vlan_set ++ * Description: ++ * Set a VLAN entry. ++ * Input: ++ * vid - VLAN ID to configure. ++ * pVlanCfg - VLAN Configuration ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_L2_FID - Invalid FID. ++ * RT_ERR_VLAN_PORT_MBR_EXIST - Invalid member port mask. ++ * RT_ERR_VLAN_VID - Invalid VID parameter. ++ * Note: ++ * ++ */ ++extern rtk_api_ret_t rtk_vlan_set(rtk_vlan_t vid, rtk_vlan_cfg_t *pVlanCfg); ++ ++/* Function Name: ++ * rtk_vlan_get ++ * Description: ++ * Get a VLAN entry. ++ * Input: ++ * vid - VLAN ID to configure. ++ * Output: ++ * pVlanCfg - VLAN Configuration ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_VLAN_VID - Invalid VID parameter. ++ * Note: ++ * ++ */ ++extern rtk_api_ret_t rtk_vlan_get(rtk_vlan_t vid, rtk_vlan_cfg_t *pVlanCfg); ++ ++/* Function Name: ++ * rtk_vlan_egrFilterEnable_set ++ * Description: ++ * Set VLAN egress filter. ++ * Input: ++ * egrFilter - Egress filtering ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_ENABLE - Invalid input parameters. ++ * Note: ++ * ++ */ ++extern rtk_api_ret_t rtk_vlan_egrFilterEnable_set(rtk_enable_t egrFilter); ++ ++/* Function Name: ++ * rtk_vlan_egrFilterEnable_get ++ * Description: ++ * Get VLAN egress filter. ++ * Input: ++ * pEgrFilter - Egress filtering ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_NULL_POINTER - NULL Pointer. ++ * Note: ++ * ++ */ ++extern rtk_api_ret_t rtk_vlan_egrFilterEnable_get(rtk_enable_t *pEgrFilter); ++ ++/* Function Name: ++ * rtk_vlan_mbrCfg_set ++ * Description: ++ * Set a VLAN Member Configuration entry by index. ++ * Input: ++ * idx - Index of VLAN Member Configuration. ++ * pMbrcfg - VLAN member Configuration. ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_VLAN_VID - Invalid VID parameter. ++ * Note: ++ * Set a VLAN Member Configuration entry by index. ++ */ ++extern rtk_api_ret_t rtk_vlan_mbrCfg_set(rtk_uint32 idx, rtk_vlan_mbrcfg_t *pMbrcfg); ++ ++/* Function Name: ++ * rtk_vlan_mbrCfg_get ++ * Description: ++ * Get a VLAN Member Configuration entry by index. ++ * Input: ++ * idx - Index of VLAN Member Configuration. ++ * Output: ++ * pMbrcfg - VLAN member Configuration. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_VLAN_VID - Invalid VID parameter. ++ * Note: ++ * Get a VLAN Member Configuration entry by index. ++ */ ++extern rtk_api_ret_t rtk_vlan_mbrCfg_get(rtk_uint32 idx, rtk_vlan_mbrcfg_t *pMbrcfg); ++ ++/* Function Name: ++ * rtk_vlan_portPvid_set ++ * Description: ++ * Set port to specified VLAN ID(PVID). ++ * Input: ++ * port - Port id. ++ * pvid - Specified VLAN ID. ++ * priority - 802.1p priority for the PVID. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_VLAN_PRIORITY - Invalid priority. ++ * RT_ERR_VLAN_ENTRY_NOT_FOUND - VLAN entry not found. ++ * RT_ERR_VLAN_VID - Invalid VID parameter. ++ * Note: ++ * The API is used for Port-based VLAN. The untagged frame received from the ++ * port will be classified to the specified VLAN and assigned to the specified priority. ++ */ ++extern rtk_api_ret_t rtk_vlan_portPvid_set(rtk_port_t port, rtk_vlan_t pvid, rtk_pri_t priority); ++ ++/* Function Name: ++ * rtk_vlan_portPvid_get ++ * Description: ++ * Get VLAN ID(PVID) on specified port. ++ * Input: ++ * port - Port id. ++ * Output: ++ * pPvid - Specified VLAN ID. ++ * pPriority - 802.1p priority for the PVID. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * The API can get the PVID and 802.1p priority for the PVID of Port-based VLAN. ++ */ ++extern rtk_api_ret_t rtk_vlan_portPvid_get(rtk_port_t port, rtk_vlan_t *pPvid, rtk_pri_t *pPriority); ++ ++/* Function Name: ++ * rtk_vlan_portIgrFilterEnable_set ++ * Description: ++ * Set VLAN ingress for each port. ++ * Input: ++ * port - Port id. ++ * igr_filter - VLAN ingress function enable status. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * RT_ERR_ENABLE - Invalid enable input ++ * Note: ++ * The status of vlan ingress filter is as following: ++ * - DISABLED ++ * - ENABLED ++ * While VLAN function is enabled, ASIC will decide VLAN ID for each received frame and get belonged member ++ * ports from VLAN table. If received port is not belonged to VLAN member ports, ASIC will drop received frame if VLAN ingress function is enabled. ++ */ ++extern rtk_api_ret_t rtk_vlan_portIgrFilterEnable_set(rtk_port_t port, rtk_enable_t igr_filter); ++ ++/* Function Name: ++ * rtk_vlan_portIgrFilterEnable_get ++ * Description: ++ * Get VLAN Ingress Filter ++ * Input: ++ * port - Port id. ++ * Output: ++ * pIgr_filter - VLAN ingress function enable status. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * The API can Get the VLAN ingress filter status. ++ * The status of vlan ingress filter is as following: ++ * - DISABLED ++ * - ENABLED ++ */ ++extern rtk_api_ret_t rtk_vlan_portIgrFilterEnable_get(rtk_port_t port, rtk_enable_t *pIgr_filter); ++ ++/* Function Name: ++ * rtk_vlan_portAcceptFrameType_set ++ * Description: ++ * Set VLAN accept_frame_type ++ * Input: ++ * port - Port id. ++ * accept_frame_type - accept frame type ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_VLAN_ACCEPT_FRAME_TYPE - Invalid frame type. ++ * Note: ++ * The API is used for checking 802.1Q tagged frames. ++ * The accept frame type as following: ++ * - ACCEPT_FRAME_TYPE_ALL ++ * - ACCEPT_FRAME_TYPE_TAG_ONLY ++ * - ACCEPT_FRAME_TYPE_UNTAG_ONLY ++ */ ++extern rtk_api_ret_t rtk_vlan_portAcceptFrameType_set(rtk_port_t port, rtk_vlan_acceptFrameType_t accept_frame_type); ++ ++/* Function Name: ++ * rtk_vlan_portAcceptFrameType_get ++ * Description: ++ * Get VLAN accept_frame_type ++ * Input: ++ * port - Port id. ++ * Output: ++ * pAccept_frame_type - accept frame type ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * The API can Get the VLAN ingress filter. ++ * The accept frame type as following: ++ * - ACCEPT_FRAME_TYPE_ALL ++ * - ACCEPT_FRAME_TYPE_TAG_ONLY ++ * - ACCEPT_FRAME_TYPE_UNTAG_ONLY ++ */ ++extern rtk_api_ret_t rtk_vlan_portAcceptFrameType_get(rtk_port_t port, rtk_vlan_acceptFrameType_t *pAccept_frame_type); ++ ++/* Function Name: ++ * rtk_vlan_tagMode_set ++ * Description: ++ * Set CVLAN egress tag mode ++ * Input: ++ * port - Port id. ++ * tag_mode - The egress tag mode. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_INPUT - Invalid input parameter. ++ * RT_ERR_ENABLE - Invalid enable input. ++ * Note: ++ * The API can set Egress tag mode. There are 4 mode for egress tag: ++ * - VLAN_TAG_MODE_ORIGINAL, ++ * - VLAN_TAG_MODE_KEEP_FORMAT, ++ * - VLAN_TAG_MODE_PRI. ++ * - VLAN_TAG_MODE_REAL_KEEP_FORMAT, ++ */ ++extern rtk_api_ret_t rtk_vlan_tagMode_set(rtk_port_t port, rtk_vlan_tagMode_t tag_mode); ++ ++/* Function Name: ++ * rtk_vlan_tagMode_get ++ * Description: ++ * Get CVLAN egress tag mode ++ * Input: ++ * port - Port id. ++ * Output: ++ * pTag_mode - The egress tag mode. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * The API can get Egress tag mode. There are 4 mode for egress tag: ++ * - VLAN_TAG_MODE_ORIGINAL, ++ * - VLAN_TAG_MODE_KEEP_FORMAT, ++ * - VLAN_TAG_MODE_PRI. ++ * - VLAN_TAG_MODE_REAL_KEEP_FORMAT, ++ */ ++extern rtk_api_ret_t rtk_vlan_tagMode_get(rtk_port_t port, rtk_vlan_tagMode_t *pTag_mode); ++ ++/* Function Name: ++ * rtk_vlan_transparent_set ++ * Description: ++ * Set VLAN transparent mode ++ * Input: ++ * egr_port - Egress Port id. ++ * pIgr_pmask - Ingress Port Mask. ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * None. ++ */ ++extern rtk_api_ret_t rtk_vlan_transparent_set(rtk_port_t egr_port, rtk_portmask_t *pIgr_pmask); ++ ++/* Function Name: ++ * rtk_vlan_transparent_get ++ * Description: ++ * Get VLAN transparent mode ++ * Input: ++ * egr_port - Egress Port id. ++ * Output: ++ * pIgr_pmask - Ingress Port Mask ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * None. ++ */ ++extern rtk_api_ret_t rtk_vlan_transparent_get(rtk_port_t egr_port, rtk_portmask_t *pIgr_pmask); ++ ++/* Function Name: ++ * rtk_vlan_keep_set ++ * Description: ++ * Set VLAN egress keep mode ++ * Input: ++ * egr_port - Egress Port id. ++ * pIgr_pmask - Ingress Port Mask. ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * None. ++ */ ++extern rtk_api_ret_t rtk_vlan_keep_set(rtk_port_t egr_port, rtk_portmask_t *pIgr_pmask); ++ ++/* Function Name: ++ * rtk_vlan_keep_get ++ * Description: ++ * Get VLAN egress keep mode ++ * Input: ++ * egr_port - Egress Port id. ++ * Output: ++ * pIgr_pmask - Ingress Port Mask ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * None. ++ */ ++extern rtk_api_ret_t rtk_vlan_keep_get(rtk_port_t egr_port, rtk_portmask_t *pIgr_pmask); ++ ++/* Function Name: ++ * rtk_vlan_stg_set ++ * Description: ++ * Set spanning tree group instance of the vlan to the specified device ++ * Input: ++ * vid - Specified VLAN ID. ++ * stg - spanning tree group instance. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_MSTI - Invalid msti parameter ++ * RT_ERR_INPUT - Invalid input parameter. ++ * RT_ERR_VLAN_VID - Invalid VID parameter. ++ * Note: ++ * The API can set spanning tree group instance of the vlan to the specified device. ++ */ ++extern rtk_api_ret_t rtk_vlan_stg_set(rtk_vlan_t vid, rtk_stp_msti_id_t stg); ++ ++/* Function Name: ++ * rtk_vlan_stg_get ++ * Description: ++ * Get spanning tree group instance of the vlan to the specified device ++ * Input: ++ * vid - Specified VLAN ID. ++ * Output: ++ * pStg - spanning tree group instance. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_VLAN_VID - Invalid VID parameter. ++ * Note: ++ * The API can get spanning tree group instance of the vlan to the specified device. ++ */ ++extern rtk_api_ret_t rtk_vlan_stg_get(rtk_vlan_t vid, rtk_stp_msti_id_t *pStg); ++ ++/* Function Name: ++ * rtk_vlan_protoAndPortBasedVlan_add ++ * Description: ++ * Add the protocol-and-port-based vlan to the specified port of device. ++ * Input: ++ * port - Port id. ++ * pInfo - Protocol and port based VLAN configuration information. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_VLAN_VID - Invalid VID parameter. ++ * RT_ERR_VLAN_PRIORITY - Invalid priority. ++ * RT_ERR_TBL_FULL - Table is full. ++ * RT_ERR_OUT_OF_RANGE - input out of range. ++ * Note: ++ * The incoming packet which match the protocol-and-port-based vlan will use the configure vid for ingress pipeline ++ * The frame type is shown in the following: ++ * - FRAME_TYPE_ETHERNET ++ * - FRAME_TYPE_RFC1042 ++ * - FRAME_TYPE_LLCOTHER ++ */ ++extern rtk_api_ret_t rtk_vlan_protoAndPortBasedVlan_add(rtk_port_t port, rtk_vlan_protoAndPortInfo_t *pInfo); ++ ++/* Function Name: ++ * rtk_vlan_protoAndPortBasedVlan_get ++ * Description: ++ * Get the protocol-and-port-based vlan to the specified port of device. ++ * Input: ++ * port - Port id. ++ * proto_type - protocol-and-port-based vlan protocol type. ++ * frame_type - protocol-and-port-based vlan frame type. ++ * Output: ++ * pInfo - Protocol and port based VLAN configuration information. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_OUT_OF_RANGE - input out of range. ++ * RT_ERR_TBL_FULL - Table is full. ++ * Note: ++ * The incoming packet which match the protocol-and-port-based vlan will use the configure vid for ingress pipeline ++ * The frame type is shown in the following: ++ * - FRAME_TYPE_ETHERNET ++ * - FRAME_TYPE_RFC1042 ++ * - FRAME_TYPE_LLCOTHER ++ */ ++extern rtk_api_ret_t rtk_vlan_protoAndPortBasedVlan_get(rtk_port_t port, rtk_vlan_proto_type_t proto_type, rtk_vlan_protoVlan_frameType_t frame_type, rtk_vlan_protoAndPortInfo_t *pInfo); ++ ++/* Function Name: ++ * rtk_vlan_protoAndPortBasedVlan_del ++ * Description: ++ * Delete the protocol-and-port-based vlan from the specified port of device. ++ * Input: ++ * port - Port id. ++ * proto_type - protocol-and-port-based vlan protocol type. ++ * frame_type - protocol-and-port-based vlan frame type. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_OUT_OF_RANGE - input out of range. ++ * RT_ERR_TBL_FULL - Table is full. ++ * Note: ++ * The incoming packet which match the protocol-and-port-based vlan will use the configure vid for ingress pipeline ++ * The frame type is shown in the following: ++ * - FRAME_TYPE_ETHERNET ++ * - FRAME_TYPE_RFC1042 ++ * - FRAME_TYPE_LLCOTHER ++ */ ++extern rtk_api_ret_t rtk_vlan_protoAndPortBasedVlan_del(rtk_port_t port, rtk_vlan_proto_type_t proto_type, rtk_vlan_protoVlan_frameType_t frame_type); ++ ++/* Function Name: ++ * rtk_vlan_protoAndPortBasedVlan_delAll ++ * Description: ++ * Delete all protocol-and-port-based vlans from the specified port of device. ++ * Input: ++ * port - Port id. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_OUT_OF_RANGE - input out of range. ++ * Note: ++ * The incoming packet which match the protocol-and-port-based vlan will use the configure vid for ingress pipeline ++ * Delete all flow table protocol-and-port-based vlan entries. ++ */ ++extern rtk_api_ret_t rtk_vlan_protoAndPortBasedVlan_delAll(rtk_port_t port); ++ ++/* Function Name: ++ * rtk_vlan_portFid_set ++ * Description: ++ * Set port-based filtering database ++ * Input: ++ * port - Port id. ++ * enable - ebable port-based FID ++ * fid - Specified filtering database. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_L2_FID - Invalid fid. ++ * RT_ERR_INPUT - Invalid input parameter. ++ * RT_ERR_PORT_ID - Invalid port ID. ++ * Note: ++ * The API can set port-based filtering database. If the function is enabled, all input ++ * packets will be assigned to the port-based fid regardless vlan tag. ++ */ ++extern rtk_api_ret_t rtk_vlan_portFid_set(rtk_port_t port, rtk_enable_t enable, rtk_fid_t fid); ++ ++/* Function Name: ++ * rtk_vlan_portFid_get ++ * Description: ++ * Get port-based filtering database ++ * Input: ++ * port - Port id. ++ * Output: ++ * pEnable - ebable port-based FID ++ * pFid - Specified filtering database. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_PORT_ID - Invalid port ID. ++ * Note: ++ * The API can get port-based filtering database status. If the function is enabled, all input ++ * packets will be assigned to the port-based fid regardless vlan tag. ++ */ ++extern rtk_api_ret_t rtk_vlan_portFid_get(rtk_port_t port, rtk_enable_t *pEnable, rtk_fid_t *pFid); ++ ++/* Function Name: ++ * rtk_vlan_UntagDscpPriorityEnable_set ++ * Description: ++ * Set Untag DSCP priority assign ++ * Input: ++ * enable - state of Untag DSCP priority assign ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_ENABLE - Invalid input parameters. ++ * Note: ++ * ++ */ ++extern rtk_api_ret_t rtk_vlan_UntagDscpPriorityEnable_set(rtk_enable_t enable); ++ ++/* Function Name: ++ * rtk_vlan_UntagDscpPriorityEnable_get ++ * Description: ++ * Get Untag DSCP priority assign ++ * Input: ++ * None ++ * Output: ++ * pEnable - state of Untag DSCP priority assign ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_NULL_POINTER - Null pointer ++ * Note: ++ * ++ */ ++extern rtk_api_ret_t rtk_vlan_UntagDscpPriorityEnable_get(rtk_enable_t *pEnable); ++ ++ ++/*Spanning Tree*/ ++/* Function Name: ++ * rtk_stp_mstpState_set ++ * Description: ++ * Configure spanning tree state per each port. ++ * Input: ++ * port - Port id ++ * msti - Multiple spanning tree instance. ++ * stp_state - Spanning tree state for msti ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_MSTI - Invalid msti parameter. ++ * RT_ERR_MSTP_STATE - Invalid STP state. ++ * Note: ++ * System supports per-port multiple spanning tree state for each msti. ++ * There are four states supported by ASIC. ++ * - STP_STATE_DISABLED ++ * - STP_STATE_BLOCKING ++ * - STP_STATE_LEARNING ++ * - STP_STATE_FORWARDING ++ */ ++extern rtk_api_ret_t rtk_stp_mstpState_set(rtk_stp_msti_id_t msti, rtk_port_t port, rtk_stp_state_t stp_state); ++ ++/* Function Name: ++ * rtk_stp_mstpState_get ++ * Description: ++ * Get spanning tree state per each port. ++ * Input: ++ * port - Port id. ++ * msti - Multiple spanning tree instance. ++ * Output: ++ * pStp_state - Spanning tree state for msti ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_MSTI - Invalid msti parameter. ++ * Note: ++ * System supports per-port multiple spanning tree state for each msti. ++ * There are four states supported by ASIC. ++ * - STP_STATE_DISABLED ++ * - STP_STATE_BLOCKING ++ * - STP_STATE_LEARNING ++ * - STP_STATE_FORWARDING ++ */ ++extern rtk_api_ret_t rtk_stp_mstpState_get(rtk_stp_msti_id_t msti, rtk_port_t port, rtk_stp_state_t *pStp_state); ++ ++/* Function Name: ++ * rtk_vlan_checkAndCreateMbr ++ * Description: ++ * Check and create Member configuration and return index ++ * Input: ++ * vid - VLAN id. ++ * Output: ++ * pIndex - Member configuration index ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_VLAN_VID - Invalid VLAN ID. ++ * RT_ERR_VLAN_ENTRY_NOT_FOUND - VLAN not found ++ * RT_ERR_TBL_FULL - Member Configuration table full ++ * Note: ++ * ++ */ ++extern rtk_api_ret_t rtk_vlan_checkAndCreateMbr(rtk_vlan_t vid, rtk_uint32 *pIndex); ++ ++/* Function Name: ++ * rtk_vlan_reservedVidAction_set ++ * Description: ++ * Set Action of VLAN ID = 0 & 4095 tagged packet ++ * Input: ++ * action_vid0 - Action for VID 0. ++ * action_vid4095 - Action for VID 4095. ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Error Input ++ * Note: ++ * ++ */ ++extern rtk_api_ret_t rtk_vlan_reservedVidAction_set(rtk_vlan_resVidAction_t action_vid0, rtk_vlan_resVidAction_t action_vid4095); ++ ++/* Function Name: ++ * rtk_vlan_reservedVidAction_get ++ * Description: ++ * Get Action of VLAN ID = 0 & 4095 tagged packet ++ * Input: ++ * pAction_vid0 - Action for VID 0. ++ * pAction_vid4095 - Action for VID 4095. ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_NULL_POINTER - NULL Pointer ++ * Note: ++ * ++ */ ++extern rtk_api_ret_t rtk_vlan_reservedVidAction_get(rtk_vlan_resVidAction_t *pAction_vid0, rtk_vlan_resVidAction_t *pAction_vid4095); ++ ++/* Function Name: ++ * rtk_vlan_realKeepRemarkEnable_set ++ * Description: ++ * Set Real keep 1p remarking feature ++ * Input: ++ * enabled - State of 1p remarking at real keep packet ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Error Input ++ * Note: ++ * ++ */ ++extern rtk_api_ret_t rtk_vlan_realKeepRemarkEnable_set(rtk_enable_t enabled); ++ ++/* Function Name: ++ * rtk_vlan_realKeepRemarkEnable_get ++ * Description: ++ * Get Real keep 1p remarking feature ++ * Input: ++ * None. ++ * Output: ++ * pEnabled - State of 1p remarking at real keep packet ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Error Input ++ * Note: ++ * ++ */ ++extern rtk_api_ret_t rtk_vlan_realKeepRemarkEnable_get(rtk_enable_t *pEnabled); ++ ++/* Function Name: ++ * rtk_vlan_reset ++ * Description: ++ * Reset VLAN ++ * Input: ++ * None. ++ * Output: ++ * pEnabled - State of 1p remarking at real keep packet ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Error Input ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_vlan_reset(void); ++ ++#endif /* __RTK_API_VLAN_H__ */ +diff --git a/drivers/net/phy/rtk/rtl8367c/interrupt.c b/drivers/net/phy/rtk/rtl8367c/interrupt.c +new file mode 100644 +index 000000000000..165ee41721b8 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/interrupt.c +@@ -0,0 +1,434 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ ++ * ++ * Purpose : RTK switch high-level API for RTL8367/RTL8367C ++ * Feature : Here is a list of all functions and variables in Interrupt module. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++/* Function Name: ++ * rtk_int_polarity_set ++ * Description: ++ * Set interrupt polarity configuration. ++ * Input: ++ * type - Interruptpolarity type. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can set interrupt polarity configuration. ++ */ ++rtk_api_ret_t rtk_int_polarity_set(rtk_int_polarity_t type) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(type >= INT_POLAR_END) ++ return RT_ERR_INPUT; ++ ++ if ((retVal = rtl8367c_setAsicInterruptPolarity(type)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_int_polarity_get ++ * Description: ++ * Get interrupt polarity configuration. ++ * Input: ++ * None ++ * Output: ++ * pType - Interruptpolarity type. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * The API can get interrupt polarity configuration. ++ */ ++rtk_api_ret_t rtk_int_polarity_get(rtk_int_polarity_t *pType) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pType) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicInterruptPolarity(pType)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_int_control_set ++ * Description: ++ * Set interrupt trigger status configuration. ++ * Input: ++ * type - Interrupt type. ++ * enable - Interrupt status. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_ENABLE - Invalid enable input. ++ * Note: ++ * The API can set interrupt status configuration. ++ * The interrupt trigger status is shown in the following: ++ * - INT_TYPE_LINK_STATUS ++ * - INT_TYPE_METER_EXCEED ++ * - INT_TYPE_LEARN_LIMIT ++ * - INT_TYPE_LINK_SPEED ++ * - INT_TYPE_CONGEST ++ * - INT_TYPE_GREEN_FEATURE ++ * - INT_TYPE_LOOP_DETECT ++ * - INT_TYPE_8051, ++ * - INT_TYPE_CABLE_DIAG, ++ * - INT_TYPE_ACL, ++ * - INT_TYPE_SLIENT ++ */ ++rtk_api_ret_t rtk_int_control_set(rtk_int_type_t type, rtk_enable_t enable) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 mask; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (type >= INT_TYPE_END) ++ return RT_ERR_INPUT; ++ ++ if (type == INT_TYPE_RESERVED) ++ return RT_ERR_INPUT; ++ ++ if ((retVal = rtl8367c_getAsicInterruptMask(&mask)) != RT_ERR_OK) ++ return retVal; ++ ++ if (ENABLED == enable) ++ mask = mask | (1<value[0] & (0x0001 << INT_TYPE_RESERVED)) ++ return RT_ERR_INPUT; ++ ++ if(pStatusMask->value[0] >= (0x0001 << INT_TYPE_END)) ++ return RT_ERR_INPUT; ++ ++ if ((retVal = rtl8367c_setAsicInterruptStatus((rtk_uint32)pStatusMask->value[0]))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_int_status_get ++ * Description: ++ * Get interrupt trigger status. ++ * Input: ++ * None ++ * Output: ++ * pStatusMask - Interrupt status bit mask. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can get interrupt trigger status when interrupt happened. ++ * The interrupt trigger status is shown in the following: ++ * - INT_TYPE_LINK_STATUS (value[0] (Bit0)) ++ * - INT_TYPE_METER_EXCEED (value[0] (Bit1)) ++ * - INT_TYPE_LEARN_LIMIT (value[0] (Bit2)) ++ * - INT_TYPE_LINK_SPEED (value[0] (Bit3)) ++ * - INT_TYPE_CONGEST (value[0] (Bit4)) ++ * - INT_TYPE_GREEN_FEATURE (value[0] (Bit5)) ++ * - INT_TYPE_LOOP_DETECT (value[0] (Bit6)) ++ * - INT_TYPE_8051 (value[0] (Bit7)) ++ * - INT_TYPE_CABLE_DIAG (value[0] (Bit8)) ++ * - INT_TYPE_ACL (value[0] (Bit9)) ++ * - INT_TYPE_SLIENT (value[0] (Bit11)) ++ * ++ */ ++rtk_api_ret_t rtk_int_status_get(rtk_int_status_t* pStatusMask) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 ims_mask; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pStatusMask) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicInterruptStatus(&ims_mask)) != RT_ERR_OK) ++ return retVal; ++ ++ pStatusMask->value[0] = (ims_mask & 0x00000FFF); ++ return RT_ERR_OK; ++} ++ ++#define ADV_NOT_SUPPORT (0xFFFF) ++static rtk_api_ret_t _rtk_int_Advidx_get(rtk_int_advType_t adv_type, rtk_uint32 *pAsic_idx) ++{ ++ rtk_uint32 asic_idx[ADV_END] = ++ { ++ INTRST_L2_LEARN, ++ INTRST_SPEED_CHANGE, ++ INTRST_SPECIAL_CONGESTION, ++ INTRST_PORT_LINKDOWN, ++ INTRST_PORT_LINKUP, ++ ADV_NOT_SUPPORT, ++ INTRST_RLDP_LOOPED, ++ INTRST_RLDP_RELEASED, ++ }; ++ ++ if(adv_type >= ADV_END) ++ return RT_ERR_INPUT; ++ ++ if(asic_idx[adv_type] == ADV_NOT_SUPPORT) ++ return RT_ERR_CHIP_NOT_SUPPORTED; ++ ++ *pAsic_idx = asic_idx[adv_type]; ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_int_advanceInfo_get ++ * Description: ++ * Get interrupt advanced information. ++ * Input: ++ * adv_type - Advanced interrupt type. ++ * Output: ++ * info - Information per type. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * This API can get advanced information when interrupt happened. ++ * The status will be cleared after execute this API. ++ */ ++rtk_api_ret_t rtk_int_advanceInfo_get(rtk_int_advType_t adv_type, rtk_int_info_t *pInfo) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 data; ++ rtk_uint32 intAdvType; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(adv_type >= ADV_END) ++ return RT_ERR_INPUT; ++ ++ if(NULL == pInfo) ++ return RT_ERR_NULL_POINTER; ++ ++ if(adv_type != ADV_METER_EXCEED_MASK) ++ { ++ if((retVal = _rtk_int_Advidx_get(adv_type, &intAdvType)) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ switch(adv_type) ++ { ++ case ADV_L2_LEARN_PORT_MASK: ++ /* Get physical portmask */ ++ if((retVal = rtl8367c_getAsicInterruptRelatedStatus(intAdvType, &data)) != RT_ERR_OK) ++ return retVal; ++ ++ /* Clear Advanced Info */ ++ if((retVal = rtl8367c_setAsicInterruptRelatedStatus(intAdvType, 0xFFFF)) != RT_ERR_OK) ++ return retVal; ++ ++ /* Translate to logical portmask */ ++ if((retVal = rtk_switch_portmask_P2L_get(data, &(pInfo->portMask))) != RT_ERR_OK) ++ return retVal; ++ ++ /* Get system learn */ ++ if((retVal = rtl8367c_getAsicInterruptRelatedStatus(INTRST_SYS_LEARN, &data)) != RT_ERR_OK) ++ return retVal; ++ ++ /* Clear system learn */ ++ if((retVal = rtl8367c_setAsicInterruptRelatedStatus(INTRST_SYS_LEARN, 0x0001)) != RT_ERR_OK) ++ return retVal; ++ ++ pInfo->systemLearnOver = data; ++ break; ++ case ADV_SPEED_CHANGE_PORT_MASK: ++ case ADV_SPECIAL_CONGESTION_PORT_MASK: ++ case ADV_PORT_LINKDOWN_PORT_MASK: ++ case ADV_PORT_LINKUP_PORT_MASK: ++ case ADV_RLDP_LOOPED: ++ case ADV_RLDP_RELEASED: ++ /* Get physical portmask */ ++ if((retVal = rtl8367c_getAsicInterruptRelatedStatus(intAdvType, &data)) != RT_ERR_OK) ++ return retVal; ++ ++ /* Clear Advanced Info */ ++ if((retVal = rtl8367c_setAsicInterruptRelatedStatus(intAdvType, 0xFFFF)) != RT_ERR_OK) ++ return retVal; ++ ++ /* Translate to logical portmask */ ++ if((retVal = rtk_switch_portmask_P2L_get(data, &(pInfo->portMask))) != RT_ERR_OK) ++ return retVal; ++ ++ break; ++ case ADV_METER_EXCEED_MASK: ++ /* Get Meter Mask */ ++ if((retVal = rtl8367c_getAsicInterruptRelatedStatus(INTRST_METER0_15, &data)) != RT_ERR_OK) ++ return retVal; ++ ++ /* Clear Advanced Info */ ++ if((retVal = rtl8367c_setAsicInterruptRelatedStatus(INTRST_METER0_15, 0xFFFF)) != RT_ERR_OK) ++ return retVal; ++ ++ pInfo->meterMask = data & 0xFFFF; ++ ++ /* Get Meter Mask */ ++ if((retVal = rtl8367c_getAsicInterruptRelatedStatus(INTRST_METER16_31, &data)) != RT_ERR_OK) ++ return retVal; ++ ++ /* Clear Advanced Info */ ++ if((retVal = rtl8367c_setAsicInterruptRelatedStatus(INTRST_METER16_31, 0xFFFF)) != RT_ERR_OK) ++ return retVal; ++ ++ pInfo->meterMask = pInfo->meterMask | ((data << 16) & 0xFFFF0000); ++ ++ break; ++ default: ++ return RT_ERR_INPUT; ++ } ++ ++ return RT_ERR_OK; ++} ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/l2.c b/drivers/net/phy/rtk/rtl8367c/l2.c +new file mode 100644 +index 000000000000..e73199a4e93d +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/l2.c +@@ -0,0 +1,2911 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ ++ * ++ * Purpose : RTK switch high-level API for RTL8367/RTL8367C ++ * Feature : Here is a list of all functions and variables in L2 module. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++/* Function Name: ++ * rtk_l2_init ++ * Description: ++ * Initialize l2 module of the specified device. ++ * Input: ++ * None ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * Initialize l2 module before calling any l2 APIs. ++ */ ++rtk_api_ret_t rtk_l2_init(void) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 port; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if ((retVal = rtl8367c_setAsicLutIpMulticastLookup(DISABLED)) != RT_ERR_OK) ++ return retVal; ++ ++ /*Enable CAM Usage*/ ++ if ((retVal = rtl8367c_setAsicLutCamTbUsage(ENABLED)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicLutAgeTimerSpeed(6,2)) != RT_ERR_OK) ++ return retVal; ++ ++ RTK_SCAN_ALL_LOG_PORT(port) ++ { ++ if ((retVal = rtl8367c_setAsicLutLearnLimitNo(rtk_switch_port_L2P_get(port), rtk_switch_maxLutAddrNumber_get())) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ return RT_ERR_OK; ++} ++ ++ ++/* Function Name: ++ * rtk_l2_addr_add ++ * Description: ++ * Add LUT unicast entry. ++ * Input: ++ * pMac - 6 bytes unicast(I/G bit is 0) mac address to be written into LUT. ++ * pL2_data - Unicast entry parameter ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_MAC - Invalid MAC address. ++ * RT_ERR_L2_FID - Invalid FID . ++ * RT_ERR_L2_INDEXTBL_FULL - hashed index is full of entries. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * If the unicast mac address already existed in LUT, it will update the status of the entry. ++ * Otherwise, it will find an empty or asic auto learned entry to write. If all the entries ++ * with the same hash value can't be replaced, ASIC will return a RT_ERR_L2_INDEXTBL_FULL error. ++ */ ++rtk_api_ret_t rtk_l2_addr_add(rtk_mac_t *pMac, rtk_l2_ucastAddr_t *pL2_data) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 method; ++ rtl8367c_luttb l2Table; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* must be unicast address */ ++ if ((pMac == NULL) || (pMac->octet[0] & 0x1)) ++ return RT_ERR_MAC; ++ ++ if(pL2_data == NULL) ++ return RT_ERR_MAC; ++ ++ RTK_CHK_PORT_VALID(pL2_data->port); ++ ++ if (pL2_data->ivl >= RTK_ENABLE_END) ++ return RT_ERR_INPUT; ++ ++ if (pL2_data->cvid > RTL8367C_VIDMAX) ++ return RT_ERR_L2_VID; ++ ++ if (pL2_data->fid > RTL8367C_FIDMAX) ++ return RT_ERR_L2_FID; ++ ++ if (pL2_data->is_static>= RTK_ENABLE_END) ++ return RT_ERR_INPUT; ++ ++ if (pL2_data->sa_block>= RTK_ENABLE_END) ++ return RT_ERR_INPUT; ++ ++ if (pL2_data->da_block>= RTK_ENABLE_END) ++ return RT_ERR_INPUT; ++ ++ if (pL2_data->auth>= RTK_ENABLE_END) ++ return RT_ERR_INPUT; ++ ++ if (pL2_data->efid> RTL8367C_EFIDMAX) ++ return RT_ERR_INPUT; ++ ++ if (pL2_data->priority > RTL8367C_PRIMAX) ++ return RT_ERR_INPUT; ++ ++ if (pL2_data->sa_pri_en >= RTK_ENABLE_END) ++ return RT_ERR_INPUT; ++ ++ if (pL2_data->fwd_pri_en >= RTK_ENABLE_END) ++ return RT_ERR_INPUT; ++ ++ memset(&l2Table, 0, sizeof(rtl8367c_luttb)); ++ ++ /* fill key (MAC,FID) to get L2 entry */ ++ memcpy(l2Table.mac.octet, pMac->octet, ETHER_ADDR_LEN); ++ l2Table.ivl_svl = pL2_data->ivl; ++ l2Table.fid = pL2_data->fid; ++ l2Table.cvid_fid = pL2_data->cvid; ++ l2Table.efid = pL2_data->efid; ++ method = LUTREADMETHOD_MAC; ++ retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table); ++ if (RT_ERR_OK == retVal ) ++ { ++ memcpy(l2Table.mac.octet, pMac->octet, ETHER_ADDR_LEN); ++ l2Table.ivl_svl = pL2_data->ivl; ++ l2Table.cvid_fid = pL2_data->cvid; ++ l2Table.fid = pL2_data->fid; ++ l2Table.efid = pL2_data->efid; ++ l2Table.spa = rtk_switch_port_L2P_get(pL2_data->port); ++ l2Table.nosalearn = pL2_data->is_static; ++ l2Table.sa_block = pL2_data->sa_block; ++ l2Table.da_block = pL2_data->da_block; ++ l2Table.l3lookup = 0; ++ l2Table.auth = pL2_data->auth; ++ l2Table.age = 6; ++ l2Table.lut_pri = pL2_data->priority; ++ l2Table.sa_en = pL2_data->sa_pri_en; ++ l2Table.fwd_en = pL2_data->fwd_pri_en; ++ if((retVal = rtl8367c_setAsicL2LookupTb(&l2Table)) != RT_ERR_OK) ++ return retVal; ++ ++ pL2_data->address = l2Table.address; ++ return RT_ERR_OK; ++ } ++ else if (RT_ERR_L2_ENTRY_NOTFOUND == retVal ) ++ { ++ memset(&l2Table, 0, sizeof(rtl8367c_luttb)); ++ memcpy(l2Table.mac.octet, pMac->octet, ETHER_ADDR_LEN); ++ l2Table.ivl_svl = pL2_data->ivl; ++ l2Table.cvid_fid = pL2_data->cvid; ++ l2Table.fid = pL2_data->fid; ++ l2Table.efid = pL2_data->efid; ++ l2Table.spa = rtk_switch_port_L2P_get(pL2_data->port); ++ l2Table.nosalearn = pL2_data->is_static; ++ l2Table.sa_block = pL2_data->sa_block; ++ l2Table.da_block = pL2_data->da_block; ++ l2Table.l3lookup = 0; ++ l2Table.auth = pL2_data->auth; ++ l2Table.age = 6; ++ l2Table.lut_pri = pL2_data->priority; ++ l2Table.sa_en = pL2_data->sa_pri_en; ++ l2Table.fwd_en = pL2_data->fwd_pri_en; ++ ++ if ((retVal = rtl8367c_setAsicL2LookupTb(&l2Table)) != RT_ERR_OK) ++ return retVal; ++ ++ pL2_data->address = l2Table.address; ++ ++ method = LUTREADMETHOD_MAC; ++ retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table); ++ if (RT_ERR_L2_ENTRY_NOTFOUND == retVal ) ++ return RT_ERR_L2_INDEXTBL_FULL; ++ else ++ return retVal; ++ } ++ else ++ return retVal; ++ ++} ++ ++/* Function Name: ++ * rtk_l2_addr_get ++ * Description: ++ * Get LUT unicast entry. ++ * Input: ++ * pMac - 6 bytes unicast(I/G bit is 0) mac address to be written into LUT. ++ * Output: ++ * pL2_data - Unicast entry parameter ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_MAC - Invalid MAC address. ++ * RT_ERR_L2_FID - Invalid FID . ++ * RT_ERR_L2_ENTRY_NOTFOUND - No such LUT entry. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * If the unicast mac address existed in LUT, it will return the port and fid where ++ * the mac is learned. Otherwise, it will return a RT_ERR_L2_ENTRY_NOTFOUND error. ++ */ ++rtk_api_ret_t rtk_l2_addr_get(rtk_mac_t *pMac, rtk_l2_ucastAddr_t *pL2_data) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 method; ++ rtl8367c_luttb l2Table; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* must be unicast address */ ++ if ((pMac == NULL) || (pMac->octet[0] & 0x1)) ++ return RT_ERR_MAC; ++ ++ if (pL2_data->fid > RTL8367C_FIDMAX || pL2_data->efid > RTL8367C_EFIDMAX) ++ return RT_ERR_L2_FID; ++ ++ memset(&l2Table, 0, sizeof(rtl8367c_luttb)); ++ ++ memcpy(l2Table.mac.octet, pMac->octet, ETHER_ADDR_LEN); ++ l2Table.ivl_svl = pL2_data->ivl; ++ l2Table.cvid_fid = pL2_data->cvid; ++ l2Table.fid = pL2_data->fid; ++ l2Table.efid = pL2_data->efid; ++ method = LUTREADMETHOD_MAC; ++ ++ if ((retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table)) != RT_ERR_OK) ++ return retVal; ++ ++ memcpy(pL2_data->mac.octet, pMac->octet,ETHER_ADDR_LEN); ++ pL2_data->port = rtk_switch_port_P2L_get(l2Table.spa); ++ pL2_data->fid = l2Table.fid; ++ pL2_data->efid = l2Table.efid; ++ pL2_data->ivl = l2Table.ivl_svl; ++ pL2_data->cvid = l2Table.cvid_fid; ++ pL2_data->is_static = l2Table.nosalearn; ++ pL2_data->auth = l2Table.auth; ++ pL2_data->sa_block = l2Table.sa_block; ++ pL2_data->da_block = l2Table.da_block; ++ pL2_data->priority = l2Table.lut_pri; ++ pL2_data->sa_pri_en = l2Table.sa_en; ++ pL2_data->fwd_pri_en= l2Table.fwd_en; ++ pL2_data->address = l2Table.address; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_l2_addr_next_get ++ * Description: ++ * Get Next LUT unicast entry. ++ * Input: ++ * read_method - The reading method. ++ * port - The port number if the read_metohd is READMETHOD_NEXT_L2UCSPA ++ * pAddress - The Address ID ++ * Output: ++ * pL2_data - Unicast entry parameter ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_MAC - Invalid MAC address. ++ * RT_ERR_L2_FID - Invalid FID . ++ * RT_ERR_L2_ENTRY_NOTFOUND - No such LUT entry. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * Get the next unicast entry after the current entry pointed by pAddress. ++ * The address of next entry is returned by pAddress. User can use (address + 1) ++ * as pAddress to call this API again for dumping all entries is LUT. ++ */ ++rtk_api_ret_t rtk_l2_addr_next_get(rtk_l2_read_method_t read_method, rtk_port_t port, rtk_uint32 *pAddress, rtk_l2_ucastAddr_t *pL2_data) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 method; ++ rtl8367c_luttb l2Table; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Error Checking */ ++ if ((pL2_data == NULL) || (pAddress == NULL)) ++ return RT_ERR_MAC; ++ ++ if(read_method == READMETHOD_NEXT_L2UC) ++ method = LUTREADMETHOD_NEXT_L2UC; ++ else if(read_method == READMETHOD_NEXT_L2UCSPA) ++ method = LUTREADMETHOD_NEXT_L2UCSPA; ++ else ++ return RT_ERR_INPUT; ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if(*pAddress > RTK_MAX_LUT_ADDR_ID ) ++ return RT_ERR_L2_L2UNI_PARAM; ++ ++ memset(&l2Table, 0, sizeof(rtl8367c_luttb)); ++ l2Table.address = *pAddress; ++ ++ if(read_method == READMETHOD_NEXT_L2UCSPA) ++ l2Table.spa = rtk_switch_port_L2P_get(port); ++ ++ if ((retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table)) != RT_ERR_OK) ++ return retVal; ++ ++ if(l2Table.address < *pAddress) ++ return RT_ERR_L2_ENTRY_NOTFOUND; ++ ++ memcpy(pL2_data->mac.octet, l2Table.mac.octet, ETHER_ADDR_LEN); ++ pL2_data->port = rtk_switch_port_P2L_get(l2Table.spa); ++ pL2_data->fid = l2Table.fid; ++ pL2_data->efid = l2Table.efid; ++ pL2_data->ivl = l2Table.ivl_svl; ++ pL2_data->cvid = l2Table.cvid_fid; ++ pL2_data->is_static = l2Table.nosalearn; ++ pL2_data->auth = l2Table.auth; ++ pL2_data->sa_block = l2Table.sa_block; ++ pL2_data->da_block = l2Table.da_block; ++ pL2_data->priority = l2Table.lut_pri; ++ pL2_data->sa_pri_en = l2Table.sa_en; ++ pL2_data->fwd_pri_en= l2Table.fwd_en; ++ pL2_data->address = l2Table.address; ++ ++ *pAddress = l2Table.address; ++ ++ return RT_ERR_OK; ++ ++} ++ ++/* Function Name: ++ * rtk_l2_addr_del ++ * Description: ++ * Delete LUT unicast entry. ++ * Input: ++ * pMac - 6 bytes unicast(I/G bit is 0) mac address to be written into LUT. ++ * fid - Filtering database ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_MAC - Invalid MAC address. ++ * RT_ERR_L2_FID - Invalid FID . ++ * RT_ERR_L2_ENTRY_NOTFOUND - No such LUT entry. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * If the mac has existed in the LUT, it will be deleted. Otherwise, it will return RT_ERR_L2_ENTRY_NOTFOUND. ++ */ ++rtk_api_ret_t rtk_l2_addr_del(rtk_mac_t *pMac, rtk_l2_ucastAddr_t *pL2_data) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 method; ++ rtl8367c_luttb l2Table; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* must be unicast address */ ++ if ((pMac == NULL) || (pMac->octet[0] & 0x1)) ++ return RT_ERR_MAC; ++ ++ if (pL2_data->fid > RTL8367C_FIDMAX || pL2_data->efid > RTL8367C_EFIDMAX) ++ return RT_ERR_L2_FID; ++ ++ memset(&l2Table, 0, sizeof(rtl8367c_luttb)); ++ ++ /* fill key (MAC,FID) to get L2 entry */ ++ memcpy(l2Table.mac.octet, pMac->octet, ETHER_ADDR_LEN); ++ l2Table.ivl_svl = pL2_data->ivl; ++ l2Table.cvid_fid = pL2_data->cvid; ++ l2Table.fid = pL2_data->fid; ++ l2Table.efid = pL2_data->efid; ++ method = LUTREADMETHOD_MAC; ++ retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table); ++ if (RT_ERR_OK == retVal) ++ { ++ memcpy(l2Table.mac.octet, pMac->octet, ETHER_ADDR_LEN); ++ l2Table.ivl_svl = pL2_data->ivl; ++ l2Table.cvid_fid = pL2_data->cvid; ++ l2Table.fid = pL2_data->fid; ++ l2Table.efid = pL2_data->efid; ++ l2Table.spa = 0; ++ l2Table.nosalearn = 0; ++ l2Table.sa_block = 0; ++ l2Table.da_block = 0; ++ l2Table.auth = 0; ++ l2Table.age = 0; ++ l2Table.lut_pri = 0; ++ l2Table.sa_en = 0; ++ l2Table.fwd_en = 0; ++ if((retVal = rtl8367c_setAsicL2LookupTb(&l2Table)) != RT_ERR_OK) ++ return retVal; ++ ++ pL2_data->address = l2Table.address; ++ return RT_ERR_OK; ++ } ++ else ++ return retVal; ++} ++ ++/* Function Name: ++ * rtk_l2_mcastAddr_add ++ * Description: ++ * Add LUT multicast entry. ++ * Input: ++ * pMcastAddr - L2 multicast entry structure ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_MAC - Invalid MAC address. ++ * RT_ERR_L2_FID - Invalid FID . ++ * RT_ERR_L2_VID - Invalid VID . ++ * RT_ERR_L2_INDEXTBL_FULL - hashed index is full of entries. ++ * RT_ERR_PORT_MASK - Invalid portmask. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * If the multicast mac address already existed in the LUT, it will update the ++ * port mask of the entry. Otherwise, it will find an empty or asic auto learned ++ * entry to write. If all the entries with the same hash value can't be replaced, ++ * ASIC will return a RT_ERR_L2_INDEXTBL_FULL error. ++ */ ++rtk_api_ret_t rtk_l2_mcastAddr_add(rtk_l2_mcastAddr_t *pMcastAddr) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 method; ++ rtl8367c_luttb l2Table; ++ rtk_uint32 pmask; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pMcastAddr) ++ return RT_ERR_NULL_POINTER; ++ ++ /* must be L2 multicast address */ ++ if( (pMcastAddr->mac.octet[0] & 0x01) != 0x01) ++ return RT_ERR_MAC; ++ ++ RTK_CHK_PORTMASK_VALID(&pMcastAddr->portmask); ++ ++ if(pMcastAddr->ivl == 1) ++ { ++ if (pMcastAddr->vid > RTL8367C_VIDMAX) ++ return RT_ERR_L2_VID; ++ } ++ else if(pMcastAddr->ivl == 0) ++ { ++ if (pMcastAddr->fid > RTL8367C_FIDMAX) ++ return RT_ERR_L2_FID; ++ } ++ else ++ return RT_ERR_INPUT; ++ ++ if(pMcastAddr->fwd_pri_en >= RTK_ENABLE_END) ++ return RT_ERR_INPUT; ++ ++ if(pMcastAddr->priority > RTL8367C_PRIMAX) ++ return RT_ERR_INPUT; ++ ++ /* Get physical port mask */ ++ if ((retVal = rtk_switch_portmask_L2P_get(&pMcastAddr->portmask, &pmask)) != RT_ERR_OK) ++ return retVal; ++ ++ memset(&l2Table, 0, sizeof(rtl8367c_luttb)); ++ ++ /* fill key (MAC,FID) to get L2 entry */ ++ memcpy(l2Table.mac.octet, pMcastAddr->mac.octet, ETHER_ADDR_LEN); ++ l2Table.ivl_svl = pMcastAddr->ivl; ++ ++ if(pMcastAddr->ivl) ++ l2Table.cvid_fid = pMcastAddr->vid; ++ else ++ l2Table.cvid_fid = pMcastAddr->fid; ++ ++ method = LUTREADMETHOD_MAC; ++ retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table); ++ if (RT_ERR_OK == retVal) ++ { ++ memcpy(l2Table.mac.octet, pMcastAddr->mac.octet, ETHER_ADDR_LEN); ++ l2Table.ivl_svl = pMcastAddr->ivl; ++ ++ if(pMcastAddr->ivl) ++ l2Table.cvid_fid = pMcastAddr->vid; ++ else ++ l2Table.cvid_fid = pMcastAddr->fid; ++ ++ l2Table.mbr = pmask; ++ l2Table.nosalearn = 1; ++ l2Table.l3lookup = 0; ++ l2Table.lut_pri = pMcastAddr->priority; ++ l2Table.fwd_en = pMcastAddr->fwd_pri_en; ++ if((retVal = rtl8367c_setAsicL2LookupTb(&l2Table)) != RT_ERR_OK) ++ return retVal; ++ ++ pMcastAddr->address = l2Table.address; ++ return RT_ERR_OK; ++ } ++ else if (RT_ERR_L2_ENTRY_NOTFOUND == retVal) ++ { ++ memset(&l2Table, 0, sizeof(rtl8367c_luttb)); ++ memcpy(l2Table.mac.octet, pMcastAddr->mac.octet, ETHER_ADDR_LEN); ++ l2Table.ivl_svl = pMcastAddr->ivl; ++ if(pMcastAddr->ivl) ++ l2Table.cvid_fid = pMcastAddr->vid; ++ else ++ l2Table.cvid_fid = pMcastAddr->fid; ++ ++ l2Table.mbr = pmask; ++ l2Table.nosalearn = 1; ++ l2Table.l3lookup = 0; ++ l2Table.lut_pri = pMcastAddr->priority; ++ l2Table.fwd_en = pMcastAddr->fwd_pri_en; ++ if ((retVal = rtl8367c_setAsicL2LookupTb(&l2Table)) != RT_ERR_OK) ++ return retVal; ++ ++ pMcastAddr->address = l2Table.address; ++ ++ method = LUTREADMETHOD_MAC; ++ retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table); ++ if (RT_ERR_L2_ENTRY_NOTFOUND == retVal) ++ return RT_ERR_L2_INDEXTBL_FULL; ++ else ++ return retVal; ++ } ++ else ++ return retVal; ++ ++} ++ ++/* Function Name: ++ * rtk_l2_mcastAddr_get ++ * Description: ++ * Get LUT multicast entry. ++ * Input: ++ * pMcastAddr - L2 multicast entry structure ++ * Output: ++ * pMcastAddr - L2 multicast entry structure ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_MAC - Invalid MAC address. ++ * RT_ERR_L2_FID - Invalid FID . ++ * RT_ERR_L2_VID - Invalid VID . ++ * RT_ERR_L2_ENTRY_NOTFOUND - No such LUT entry. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * If the multicast mac address existed in the LUT, it will return the port where ++ * the mac is learned. Otherwise, it will return a RT_ERR_L2_ENTRY_NOTFOUND error. ++ */ ++rtk_api_ret_t rtk_l2_mcastAddr_get(rtk_l2_mcastAddr_t *pMcastAddr) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 method; ++ rtl8367c_luttb l2Table; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pMcastAddr) ++ return RT_ERR_NULL_POINTER; ++ ++ /* must be L2 multicast address */ ++ if( (pMcastAddr->mac.octet[0] & 0x01) != 0x01) ++ return RT_ERR_MAC; ++ ++ if(pMcastAddr->ivl == 1) ++ { ++ if (pMcastAddr->vid > RTL8367C_VIDMAX) ++ return RT_ERR_L2_VID; ++ } ++ else if(pMcastAddr->ivl == 0) ++ { ++ if (pMcastAddr->fid > RTL8367C_FIDMAX) ++ return RT_ERR_L2_FID; ++ } ++ else ++ return RT_ERR_INPUT; ++ ++ memset(&l2Table, 0, sizeof(rtl8367c_luttb)); ++ memcpy(l2Table.mac.octet, pMcastAddr->mac.octet, ETHER_ADDR_LEN); ++ l2Table.ivl_svl = pMcastAddr->ivl; ++ ++ if(pMcastAddr->ivl) ++ l2Table.cvid_fid = pMcastAddr->vid; ++ else ++ l2Table.cvid_fid = pMcastAddr->fid; ++ ++ method = LUTREADMETHOD_MAC; ++ ++ if ((retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table)) != RT_ERR_OK) ++ return retVal; ++ ++ pMcastAddr->priority = l2Table.lut_pri; ++ pMcastAddr->fwd_pri_en = l2Table.fwd_en; ++ pMcastAddr->igmp_asic = l2Table.igmp_asic; ++ pMcastAddr->igmp_index = l2Table.igmpidx; ++ pMcastAddr->address = l2Table.address; ++ ++ /* Get Logical port mask */ ++ if ((retVal = rtk_switch_portmask_P2L_get(l2Table.mbr, &pMcastAddr->portmask)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_l2_mcastAddr_next_get ++ * Description: ++ * Get Next L2 Multicast entry. ++ * Input: ++ * pAddress - The Address ID ++ * Output: ++ * pMcastAddr - L2 multicast entry structure ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_L2_ENTRY_NOTFOUND - No such LUT entry. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * Get the next L2 multicast entry after the current entry pointed by pAddress. ++ * The address of next entry is returned by pAddress. User can use (address + 1) ++ * as pAddress to call this API again for dumping all multicast entries is LUT. ++ */ ++rtk_api_ret_t rtk_l2_mcastAddr_next_get(rtk_uint32 *pAddress, rtk_l2_mcastAddr_t *pMcastAddr) ++{ ++ rtk_api_ret_t retVal; ++ rtl8367c_luttb l2Table; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Error Checking */ ++ if ((pAddress == NULL) || (pMcastAddr == NULL)) ++ return RT_ERR_INPUT; ++ ++ if(*pAddress > RTK_MAX_LUT_ADDR_ID ) ++ return RT_ERR_L2_L2UNI_PARAM; ++ ++ memset(&l2Table, 0, sizeof(rtl8367c_luttb)); ++ l2Table.address = *pAddress; ++ ++ if ((retVal = rtl8367c_getAsicL2LookupTb(LUTREADMETHOD_NEXT_L2MC, &l2Table)) != RT_ERR_OK) ++ return retVal; ++ ++ if(l2Table.address < *pAddress) ++ return RT_ERR_L2_ENTRY_NOTFOUND; ++ ++ memcpy(pMcastAddr->mac.octet, l2Table.mac.octet, ETHER_ADDR_LEN); ++ pMcastAddr->ivl = l2Table.ivl_svl; ++ ++ if(pMcastAddr->ivl) ++ pMcastAddr->vid = l2Table.cvid_fid; ++ else ++ pMcastAddr->fid = l2Table.cvid_fid; ++ ++ pMcastAddr->priority = l2Table.lut_pri; ++ pMcastAddr->fwd_pri_en = l2Table.fwd_en; ++ pMcastAddr->igmp_asic = l2Table.igmp_asic; ++ pMcastAddr->igmp_index = l2Table.igmpidx; ++ pMcastAddr->address = l2Table.address; ++ ++ /* Get Logical port mask */ ++ if ((retVal = rtk_switch_portmask_P2L_get(l2Table.mbr, &pMcastAddr->portmask)) != RT_ERR_OK) ++ return retVal; ++ ++ *pAddress = l2Table.address; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_l2_mcastAddr_del ++ * Description: ++ * Delete LUT multicast entry. ++ * Input: ++ * pMcastAddr - L2 multicast entry structure ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_MAC - Invalid MAC address. ++ * RT_ERR_L2_FID - Invalid FID . ++ * RT_ERR_L2_VID - Invalid VID . ++ * RT_ERR_L2_ENTRY_NOTFOUND - No such LUT entry. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * If the mac has existed in the LUT, it will be deleted. Otherwise, it will return RT_ERR_L2_ENTRY_NOTFOUND. ++ */ ++rtk_api_ret_t rtk_l2_mcastAddr_del(rtk_l2_mcastAddr_t *pMcastAddr) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 method; ++ rtl8367c_luttb l2Table; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pMcastAddr) ++ return RT_ERR_NULL_POINTER; ++ ++ /* must be L2 multicast address */ ++ if( (pMcastAddr->mac.octet[0] & 0x01) != 0x01) ++ return RT_ERR_MAC; ++ ++ if(pMcastAddr->ivl == 1) ++ { ++ if (pMcastAddr->vid > RTL8367C_VIDMAX) ++ return RT_ERR_L2_VID; ++ } ++ else if(pMcastAddr->ivl == 0) ++ { ++ if (pMcastAddr->fid > RTL8367C_FIDMAX) ++ return RT_ERR_L2_FID; ++ } ++ else ++ return RT_ERR_INPUT; ++ ++ memset(&l2Table, 0, sizeof(rtl8367c_luttb)); ++ ++ /* fill key (MAC,FID) to get L2 entry */ ++ memcpy(l2Table.mac.octet, pMcastAddr->mac.octet, ETHER_ADDR_LEN); ++ l2Table.ivl_svl = pMcastAddr->ivl; ++ ++ if(pMcastAddr->ivl) ++ l2Table.cvid_fid = pMcastAddr->vid; ++ else ++ l2Table.cvid_fid = pMcastAddr->fid; ++ ++ method = LUTREADMETHOD_MAC; ++ retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table); ++ if (RT_ERR_OK == retVal) ++ { ++ memcpy(l2Table.mac.octet, pMcastAddr->mac.octet, ETHER_ADDR_LEN); ++ l2Table.ivl_svl = pMcastAddr->ivl; ++ ++ if(pMcastAddr->ivl) ++ l2Table.cvid_fid = pMcastAddr->vid; ++ else ++ l2Table.cvid_fid = pMcastAddr->fid; ++ ++ l2Table.mbr = 0; ++ l2Table.nosalearn = 0; ++ l2Table.sa_block = 0; ++ l2Table.l3lookup = 0; ++ l2Table.lut_pri = 0; ++ l2Table.fwd_en = 0; ++ if((retVal = rtl8367c_setAsicL2LookupTb(&l2Table)) != RT_ERR_OK) ++ return retVal; ++ ++ pMcastAddr->address = l2Table.address; ++ return RT_ERR_OK; ++ } ++ else ++ return retVal; ++} ++ ++/* Function Name: ++ * rtk_l2_ipMcastAddr_add ++ * Description: ++ * Add LUT IP multicast entry ++ * Input: ++ * pIpMcastAddr - IP Multicast entry ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_L2_INDEXTBL_FULL - hashed index is full of entries. ++ * RT_ERR_PORT_MASK - Invalid portmask. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * System supports L2 entry with IP multicast DIP/SIP to forward IP multicasting frame as user ++ * desired. If this function is enabled, then system will be looked up L2 IP multicast entry to ++ * forward IP multicast frame directly without flooding. ++ */ ++rtk_api_ret_t rtk_l2_ipMcastAddr_add(rtk_l2_ipMcastAddr_t *pIpMcastAddr) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 method; ++ rtl8367c_luttb l2Table; ++ rtk_uint32 pmask; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pIpMcastAddr) ++ return RT_ERR_NULL_POINTER; ++ ++ /* check port mask */ ++ RTK_CHK_PORTMASK_VALID(&pIpMcastAddr->portmask); ++ ++ if( (pIpMcastAddr->dip & 0xF0000000) != 0xE0000000) ++ return RT_ERR_INPUT; ++ ++ if(pIpMcastAddr->fwd_pri_en >= RTK_ENABLE_END) ++ return RT_ERR_ENABLE; ++ ++ if(pIpMcastAddr->priority > RTL8367C_PRIMAX) ++ return RT_ERR_INPUT; ++ ++ /* Get Physical port mask */ ++ if ((retVal = rtk_switch_portmask_L2P_get(&pIpMcastAddr->portmask, &pmask)) != RT_ERR_OK) ++ return retVal; ++ ++ memset(&l2Table, 0x00, sizeof(rtl8367c_luttb)); ++ l2Table.sip = pIpMcastAddr->sip; ++ l2Table.dip = pIpMcastAddr->dip; ++ l2Table.l3lookup = 1; ++ l2Table.l3vidlookup = 0; ++ method = LUTREADMETHOD_MAC; ++ retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table); ++ if (RT_ERR_OK == retVal) ++ { ++ l2Table.sip = pIpMcastAddr->sip; ++ l2Table.dip = pIpMcastAddr->dip; ++ l2Table.mbr = pmask; ++ l2Table.nosalearn = 1; ++ l2Table.l3lookup = 1; ++ l2Table.l3vidlookup = 0; ++ l2Table.lut_pri = pIpMcastAddr->priority; ++ l2Table.fwd_en = pIpMcastAddr->fwd_pri_en; ++ if((retVal = rtl8367c_setAsicL2LookupTb(&l2Table)) != RT_ERR_OK) ++ return retVal; ++ ++ pIpMcastAddr->address = l2Table.address; ++ return RT_ERR_OK; ++ } ++ else if (RT_ERR_L2_ENTRY_NOTFOUND == retVal) ++ { ++ memset(&l2Table, 0, sizeof(rtl8367c_luttb)); ++ l2Table.sip = pIpMcastAddr->sip; ++ l2Table.dip = pIpMcastAddr->dip; ++ l2Table.mbr = pmask; ++ l2Table.nosalearn = 1; ++ l2Table.l3lookup = 1; ++ l2Table.l3vidlookup = 0; ++ l2Table.lut_pri = pIpMcastAddr->priority; ++ l2Table.fwd_en = pIpMcastAddr->fwd_pri_en; ++ if ((retVal = rtl8367c_setAsicL2LookupTb(&l2Table)) != RT_ERR_OK) ++ return retVal; ++ ++ pIpMcastAddr->address = l2Table.address; ++ ++ method = LUTREADMETHOD_MAC; ++ retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table); ++ if (RT_ERR_L2_ENTRY_NOTFOUND == retVal) ++ return RT_ERR_L2_INDEXTBL_FULL; ++ else ++ return retVal; ++ ++ } ++ else ++ return retVal; ++ ++} ++ ++/* Function Name: ++ * rtk_l2_ipMcastAddr_get ++ * Description: ++ * Get LUT IP multicast entry. ++ * Input: ++ * pIpMcastAddr - IP Multicast entry ++ * Output: ++ * pIpMcastAddr - IP Multicast entry ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_L2_ENTRY_NOTFOUND - No such LUT entry. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can get LUT table of IP multicast entry. ++ */ ++rtk_api_ret_t rtk_l2_ipMcastAddr_get(rtk_l2_ipMcastAddr_t *pIpMcastAddr) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 method; ++ rtl8367c_luttb l2Table; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pIpMcastAddr) ++ return RT_ERR_NULL_POINTER; ++ ++ if( (pIpMcastAddr->dip & 0xF0000000) != 0xE0000000) ++ return RT_ERR_INPUT; ++ ++ memset(&l2Table, 0x00, sizeof(rtl8367c_luttb)); ++ l2Table.sip = pIpMcastAddr->sip; ++ l2Table.dip = pIpMcastAddr->dip; ++ l2Table.l3lookup = 1; ++ l2Table.l3vidlookup = 0; ++ method = LUTREADMETHOD_MAC; ++ if ((retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table)) != RT_ERR_OK) ++ return retVal; ++ ++ /* Get Logical port mask */ ++ if ((retVal = rtk_switch_portmask_P2L_get(l2Table.mbr, &pIpMcastAddr->portmask)) != RT_ERR_OK) ++ return retVal; ++ ++ pIpMcastAddr->priority = l2Table.lut_pri; ++ pIpMcastAddr->fwd_pri_en = l2Table.fwd_en; ++ pIpMcastAddr->igmp_asic = l2Table.igmp_asic; ++ pIpMcastAddr->igmp_index = l2Table.igmpidx; ++ pIpMcastAddr->address = l2Table.address; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_l2_ipMcastAddr_next_get ++ * Description: ++ * Get Next IP Multicast entry. ++ * Input: ++ * pAddress - The Address ID ++ * Output: ++ * pIpMcastAddr - IP Multicast entry ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_L2_ENTRY_NOTFOUND - No such LUT entry. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * Get the next IP multicast entry after the current entry pointed by pAddress. ++ * The address of next entry is returned by pAddress. User can use (address + 1) ++ * as pAddress to call this API again for dumping all IP multicast entries is LUT. ++ */ ++rtk_api_ret_t rtk_l2_ipMcastAddr_next_get(rtk_uint32 *pAddress, rtk_l2_ipMcastAddr_t *pIpMcastAddr) ++{ ++ rtk_api_ret_t retVal; ++ rtl8367c_luttb l2Table; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Error Checking */ ++ if ((pAddress == NULL) || (pIpMcastAddr == NULL) ) ++ return RT_ERR_INPUT; ++ ++ if(*pAddress > RTK_MAX_LUT_ADDR_ID ) ++ return RT_ERR_L2_L2UNI_PARAM; ++ ++ memset(&l2Table, 0, sizeof(rtl8367c_luttb)); ++ l2Table.address = *pAddress; ++ ++ do ++ { ++ if ((retVal = rtl8367c_getAsicL2LookupTb(LUTREADMETHOD_NEXT_L3MC, &l2Table)) != RT_ERR_OK) ++ return retVal; ++ ++ if(l2Table.address < *pAddress) ++ return RT_ERR_L2_ENTRY_NOTFOUND; ++ ++ }while(l2Table.l3vidlookup == 1); ++ ++ pIpMcastAddr->sip = l2Table.sip; ++ pIpMcastAddr->dip = l2Table.dip; ++ ++ /* Get Logical port mask */ ++ if ((retVal = rtk_switch_portmask_P2L_get(l2Table.mbr, &pIpMcastAddr->portmask)) != RT_ERR_OK) ++ return retVal; ++ ++ pIpMcastAddr->priority = l2Table.lut_pri; ++ pIpMcastAddr->fwd_pri_en = l2Table.fwd_en; ++ pIpMcastAddr->igmp_asic = l2Table.igmp_asic; ++ pIpMcastAddr->igmp_index = l2Table.igmpidx; ++ pIpMcastAddr->address = l2Table.address; ++ *pAddress = l2Table.address; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_l2_ipMcastAddr_del ++ * Description: ++ * Delete a ip multicast address entry from the specified device. ++ * Input: ++ * pIpMcastAddr - IP Multicast entry ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_L2_ENTRY_NOTFOUND - No such LUT entry. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can delete a IP multicast address entry from the specified device. ++ */ ++rtk_api_ret_t rtk_l2_ipMcastAddr_del(rtk_l2_ipMcastAddr_t *pIpMcastAddr) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 method; ++ rtl8367c_luttb l2Table; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Error Checking */ ++ if (pIpMcastAddr == NULL) ++ return RT_ERR_INPUT; ++ ++ if( (pIpMcastAddr->dip & 0xF0000000) != 0xE0000000) ++ return RT_ERR_INPUT; ++ ++ memset(&l2Table, 0x00, sizeof(rtl8367c_luttb)); ++ l2Table.sip = pIpMcastAddr->sip; ++ l2Table.dip = pIpMcastAddr->dip; ++ l2Table.l3lookup = 1; ++ l2Table.l3vidlookup = 0; ++ method = LUTREADMETHOD_MAC; ++ retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table); ++ if (RT_ERR_OK == retVal) ++ { ++ l2Table.sip = pIpMcastAddr->sip; ++ l2Table.dip = pIpMcastAddr->dip; ++ l2Table.mbr = 0; ++ l2Table.nosalearn = 0; ++ l2Table.l3lookup = 1; ++ l2Table.l3vidlookup = 0; ++ l2Table.lut_pri = 0; ++ l2Table.fwd_en = 0; ++ if((retVal = rtl8367c_setAsicL2LookupTb(&l2Table)) != RT_ERR_OK) ++ return retVal; ++ ++ pIpMcastAddr->address = l2Table.address; ++ return RT_ERR_OK; ++ } ++ else ++ return retVal; ++} ++ ++/* Function Name: ++ * rtk_l2_ipVidMcastAddr_add ++ * Description: ++ * Add LUT IP multicast+VID entry ++ * Input: ++ * pIpVidMcastAddr - IP & VID multicast Entry ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_L2_INDEXTBL_FULL - hashed index is full of entries. ++ * RT_ERR_PORT_MASK - Invalid portmask. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_l2_ipVidMcastAddr_add(rtk_l2_ipVidMcastAddr_t *pIpVidMcastAddr) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 method; ++ rtl8367c_luttb l2Table; ++ rtk_uint32 pmask; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pIpVidMcastAddr) ++ return RT_ERR_NULL_POINTER; ++ ++ /* check port mask */ ++ RTK_CHK_PORTMASK_VALID(&pIpVidMcastAddr->portmask); ++ ++ if (pIpVidMcastAddr->vid > RTL8367C_VIDMAX) ++ return RT_ERR_L2_VID; ++ ++ if( (pIpVidMcastAddr->dip & 0xF0000000) != 0xE0000000) ++ return RT_ERR_INPUT; ++ ++ /* Get Physical port mask */ ++ if ((retVal = rtk_switch_portmask_L2P_get(&pIpVidMcastAddr->portmask, &pmask)) != RT_ERR_OK) ++ return retVal; ++ ++ memset(&l2Table, 0x00, sizeof(rtl8367c_luttb)); ++ l2Table.sip = pIpVidMcastAddr->sip; ++ l2Table.dip = pIpVidMcastAddr->dip; ++ l2Table.l3lookup = 1; ++ l2Table.l3vidlookup = 1; ++ l2Table.l3_vid = pIpVidMcastAddr->vid; ++ method = LUTREADMETHOD_MAC; ++ retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table); ++ if (RT_ERR_OK == retVal) ++ { ++ l2Table.sip = pIpVidMcastAddr->sip; ++ l2Table.dip = pIpVidMcastAddr->dip; ++ l2Table.mbr = pmask; ++ l2Table.nosalearn = 1; ++ l2Table.l3lookup = 1; ++ l2Table.l3vidlookup = 1; ++ l2Table.l3_vid = pIpVidMcastAddr->vid; ++ if((retVal = rtl8367c_setAsicL2LookupTb(&l2Table)) != RT_ERR_OK) ++ return retVal; ++ ++ pIpVidMcastAddr->address = l2Table.address; ++ return RT_ERR_OK; ++ } ++ else if (RT_ERR_L2_ENTRY_NOTFOUND == retVal) ++ { ++ memset(&l2Table, 0, sizeof(rtl8367c_luttb)); ++ l2Table.sip = pIpVidMcastAddr->sip; ++ l2Table.dip = pIpVidMcastAddr->dip; ++ l2Table.mbr = pmask; ++ l2Table.nosalearn = 1; ++ l2Table.l3lookup = 1; ++ l2Table.l3vidlookup = 1; ++ l2Table.l3_vid = pIpVidMcastAddr->vid; ++ if ((retVal = rtl8367c_setAsicL2LookupTb(&l2Table)) != RT_ERR_OK) ++ return retVal; ++ ++ pIpVidMcastAddr->address = l2Table.address; ++ ++ method = LUTREADMETHOD_MAC; ++ retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table); ++ if (RT_ERR_L2_ENTRY_NOTFOUND == retVal) ++ return RT_ERR_L2_INDEXTBL_FULL; ++ else ++ return retVal; ++ ++ } ++ else ++ return retVal; ++} ++ ++/* Function Name: ++ * rtk_l2_ipVidMcastAddr_get ++ * Description: ++ * Get LUT IP multicast+VID entry. ++ * Input: ++ * pIpVidMcastAddr - IP & VID multicast Entry ++ * Output: ++ * pIpVidMcastAddr - IP & VID multicast Entry ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_L2_ENTRY_NOTFOUND - No such LUT entry. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_l2_ipVidMcastAddr_get(rtk_l2_ipVidMcastAddr_t *pIpVidMcastAddr) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 method; ++ rtl8367c_luttb l2Table; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pIpVidMcastAddr) ++ return RT_ERR_NULL_POINTER; ++ ++ if (pIpVidMcastAddr->vid > RTL8367C_VIDMAX) ++ return RT_ERR_L2_VID; ++ ++ if( (pIpVidMcastAddr->dip & 0xF0000000) != 0xE0000000) ++ return RT_ERR_INPUT; ++ ++ memset(&l2Table, 0x00, sizeof(rtl8367c_luttb)); ++ l2Table.sip = pIpVidMcastAddr->sip; ++ l2Table.dip = pIpVidMcastAddr->dip; ++ l2Table.l3lookup = 1; ++ l2Table.l3vidlookup = 1; ++ l2Table.l3_vid = pIpVidMcastAddr->vid; ++ method = LUTREADMETHOD_MAC; ++ if ((retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table)) != RT_ERR_OK) ++ return retVal; ++ ++ pIpVidMcastAddr->address = l2Table.address; ++ ++ /* Get Logical port mask */ ++ if ((retVal = rtk_switch_portmask_P2L_get(l2Table.mbr, &pIpVidMcastAddr->portmask)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_l2_ipVidMcastAddr_next_get ++ * Description: ++ * Get Next IP Multicast+VID entry. ++ * Input: ++ * pAddress - The Address ID ++ * Output: ++ * pIpVidMcastAddr - IP & VID multicast Entry ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_L2_ENTRY_NOTFOUND - No such LUT entry. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * Get the next IP multicast entry after the current entry pointed by pAddress. ++ * The address of next entry is returned by pAddress. User can use (address + 1) ++ * as pAddress to call this API again for dumping all IP multicast entries is LUT. ++ */ ++rtk_api_ret_t rtk_l2_ipVidMcastAddr_next_get(rtk_uint32 *pAddress, rtk_l2_ipVidMcastAddr_t *pIpVidMcastAddr) ++{ ++ rtk_api_ret_t retVal; ++ rtl8367c_luttb l2Table; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Error Checking */ ++ if ((pAddress == NULL) || (pIpVidMcastAddr == NULL)) ++ return RT_ERR_INPUT; ++ ++ if(*pAddress > RTK_MAX_LUT_ADDR_ID ) ++ return RT_ERR_L2_L2UNI_PARAM; ++ ++ memset(&l2Table, 0, sizeof(rtl8367c_luttb)); ++ l2Table.address = *pAddress; ++ ++ do ++ { ++ if ((retVal = rtl8367c_getAsicL2LookupTb(LUTREADMETHOD_NEXT_L3MC, &l2Table)) != RT_ERR_OK) ++ return retVal; ++ ++ if(l2Table.address < *pAddress) ++ return RT_ERR_L2_ENTRY_NOTFOUND; ++ ++ }while(l2Table.l3vidlookup == 0); ++ ++ pIpVidMcastAddr->sip = l2Table.sip; ++ pIpVidMcastAddr->dip = l2Table.dip; ++ pIpVidMcastAddr->vid = l2Table.l3_vid; ++ pIpVidMcastAddr->address = l2Table.address; ++ ++ /* Get Logical port mask */ ++ if ((retVal = rtk_switch_portmask_P2L_get(l2Table.mbr, &pIpVidMcastAddr->portmask)) != RT_ERR_OK) ++ return retVal; ++ ++ *pAddress = l2Table.address; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_l2_ipVidMcastAddr_del ++ * Description: ++ * Delete a ip multicast+VID address entry from the specified device. ++ * Input: ++ * pIpVidMcastAddr - IP & VID multicast Entry ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_L2_ENTRY_NOTFOUND - No such LUT entry. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_l2_ipVidMcastAddr_del(rtk_l2_ipVidMcastAddr_t *pIpVidMcastAddr) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 method; ++ rtl8367c_luttb l2Table; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pIpVidMcastAddr) ++ return RT_ERR_NULL_POINTER; ++ ++ if (pIpVidMcastAddr->vid > RTL8367C_VIDMAX) ++ return RT_ERR_L2_VID; ++ ++ if( (pIpVidMcastAddr->dip & 0xF0000000) != 0xE0000000) ++ return RT_ERR_INPUT; ++ ++ memset(&l2Table, 0x00, sizeof(rtl8367c_luttb)); ++ l2Table.sip = pIpVidMcastAddr->sip; ++ l2Table.dip = pIpVidMcastAddr->dip; ++ l2Table.l3lookup = 1; ++ l2Table.l3vidlookup = 1; ++ l2Table.l3_vid = pIpVidMcastAddr->vid; ++ method = LUTREADMETHOD_MAC; ++ retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table); ++ if (RT_ERR_OK == retVal) ++ { ++ l2Table.sip = pIpVidMcastAddr->sip; ++ l2Table.dip = pIpVidMcastAddr->dip; ++ l2Table.mbr= 0; ++ l2Table.nosalearn = 0; ++ l2Table.l3lookup = 1; ++ l2Table.l3vidlookup = 1; ++ l2Table.l3_vid = pIpVidMcastAddr->vid; ++ if((retVal = rtl8367c_setAsicL2LookupTb(&l2Table)) != RT_ERR_OK) ++ return retVal; ++ ++ pIpVidMcastAddr->address = l2Table.address; ++ return RT_ERR_OK; ++ } ++ else ++ return retVal; ++} ++ ++/* Function Name: ++ * rtk_l2_ucastAddr_flush ++ * Description: ++ * Flush L2 mac address by type in the specified device (both dynamic and static). ++ * Input: ++ * pConfig - flush configuration ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_VLAN_VID - Invalid VID parameter. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * flushByVid - 1: Flush by VID, 0: Don't flush by VID ++ * vid - VID (0 ~ 4095) ++ * flushByFid - 1: Flush by FID, 0: Don't flush by FID ++ * fid - FID (0 ~ 15) ++ * flushByPort - 1: Flush by Port, 0: Don't flush by Port ++ * port - Port ID ++ * flushByMac - Not Supported ++ * ucastAddr - Not Supported ++ * flushStaticAddr - 1: Flush both Static and Dynamic entries, 0: Flush only Dynamic entries ++ * flushAddrOnAllPorts - 1: Flush VID-matched entries at all ports, 0: Flush VID-matched entries per port. ++ */ ++rtk_api_ret_t rtk_l2_ucastAddr_flush(rtk_l2_flushCfg_t *pConfig) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(pConfig == NULL) ++ return RT_ERR_NULL_POINTER; ++ ++ if(pConfig->flushByVid >= RTK_ENABLE_END) ++ return RT_ERR_ENABLE; ++ ++ if(pConfig->flushByFid >= RTK_ENABLE_END) ++ return RT_ERR_ENABLE; ++ ++ if(pConfig->flushByPort >= RTK_ENABLE_END) ++ return RT_ERR_ENABLE; ++ ++ if(pConfig->flushByMac >= RTK_ENABLE_END) ++ return RT_ERR_ENABLE; ++ ++ if(pConfig->flushStaticAddr >= RTK_ENABLE_END) ++ return RT_ERR_ENABLE; ++ ++ if(pConfig->flushAddrOnAllPorts >= RTK_ENABLE_END) ++ return RT_ERR_ENABLE; ++ ++ if(pConfig->vid > RTL8367C_VIDMAX) ++ return RT_ERR_VLAN_VID; ++ ++ if(pConfig->fid > RTL8367C_FIDMAX) ++ return RT_ERR_INPUT; ++ ++ /* check port valid */ ++ RTK_CHK_PORT_VALID(pConfig->port); ++ ++ if(pConfig->flushByVid == ENABLED) ++ { ++ if ((retVal = rtl8367c_setAsicLutFlushMode(FLUSHMDOE_VID)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicLutFlushVid(pConfig->vid)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicLutFlushType((pConfig->flushStaticAddr == ENABLED) ? FLUSHTYPE_BOTH : FLUSHTYPE_DYNAMIC)) != RT_ERR_OK) ++ return retVal; ++ ++ if(pConfig->flushAddrOnAllPorts == ENABLED) ++ { ++ if ((retVal = rtl8367c_setAsicLutForceFlush(RTL8367C_PORTMASK)) != RT_ERR_OK) ++ return retVal; ++ } ++ else if(pConfig->flushByPort == ENABLED) ++ { ++ if ((retVal = rtl8367c_setAsicLutForceFlush(1 << rtk_switch_port_L2P_get(pConfig->port))) != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ return RT_ERR_INPUT; ++ } ++ else if(pConfig->flushByFid == ENABLED) ++ { ++ if ((retVal = rtl8367c_setAsicLutFlushMode(FLUSHMDOE_FID)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicLutFlushFid(pConfig->fid)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicLutFlushType((pConfig->flushStaticAddr == ENABLED) ? FLUSHTYPE_BOTH : FLUSHTYPE_DYNAMIC)) != RT_ERR_OK) ++ return retVal; ++ ++ if(pConfig->flushAddrOnAllPorts == ENABLED) ++ { ++ if ((retVal = rtl8367c_setAsicLutForceFlush(RTL8367C_PORTMASK)) != RT_ERR_OK) ++ return retVal; ++ } ++ else if(pConfig->flushByPort == ENABLED) ++ { ++ if ((retVal = rtl8367c_setAsicLutForceFlush(1 << rtk_switch_port_L2P_get(pConfig->port))) != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ return RT_ERR_INPUT; ++ } ++ else if(pConfig->flushByPort == ENABLED) ++ { ++ if ((retVal = rtl8367c_setAsicLutFlushType((pConfig->flushStaticAddr == ENABLED) ? FLUSHTYPE_BOTH : FLUSHTYPE_DYNAMIC)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicLutFlushMode(FLUSHMDOE_PORT)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicLutForceFlush(1 << rtk_switch_port_L2P_get(pConfig->port))) != RT_ERR_OK) ++ return retVal; ++ } ++ else if(pConfig->flushByMac == ENABLED) ++ { ++ /* Should use API "rtk_l2_addr_del" to remove a specified entry*/ ++ return RT_ERR_CHIP_NOT_SUPPORTED; ++ } ++ else ++ return RT_ERR_INPUT; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_l2_table_clear ++ * Description: ++ * Flush all static & dynamic entries in LUT. ++ * Input: ++ * None ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_l2_table_clear(void) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if ((retVal = rtl8367c_setAsicLutFlushAll()) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_l2_table_clearStatus_get ++ * Description: ++ * Get table clear status ++ * Input: ++ * None ++ * Output: ++ * pStatus - Clear status, 1:Busy, 0:finish ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_l2_table_clearStatus_get(rtk_l2_clearStatus_t *pStatus) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pStatus) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicLutFlushAllStatus((rtk_uint32 *)pStatus)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_l2_flushLinkDownPortAddrEnable_set ++ * Description: ++ * Set HW flush linkdown port mac configuration of the specified device. ++ * Input: ++ * port - Port id. ++ * enable - link down flush status ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_ENABLE - Invalid enable input. ++ * Note: ++ * The status of flush linkdown port address is as following: ++ * - DISABLED ++ * - ENABLED ++ */ ++rtk_api_ret_t rtk_l2_flushLinkDownPortAddrEnable_set(rtk_port_t port, rtk_enable_t enable) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (port != RTK_WHOLE_SYSTEM) ++ return RT_ERR_PORT_ID; ++ ++ if (enable >= RTK_ENABLE_END) ++ return RT_ERR_ENABLE; ++ ++ if ((retVal = rtl8367c_setAsicLutLinkDownForceAging(enable)) != RT_ERR_OK) ++ return retVal; ++ ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_l2_flushLinkDownPortAddrEnable_get ++ * Description: ++ * Get HW flush linkdown port mac configuration of the specified device. ++ * Input: ++ * port - Port id. ++ * Output: ++ * pEnable - link down flush status ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * The status of flush linkdown port address is as following: ++ * - DISABLED ++ * - ENABLED ++ */ ++rtk_api_ret_t rtk_l2_flushLinkDownPortAddrEnable_get(rtk_port_t port, rtk_enable_t *pEnable) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (port != RTK_WHOLE_SYSTEM) ++ return RT_ERR_PORT_ID; ++ ++ if(NULL == pEnable) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicLutLinkDownForceAging(pEnable)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_l2_agingEnable_set ++ * Description: ++ * Set L2 LUT aging status per port setting. ++ * Input: ++ * port - Port id. ++ * enable - Aging status ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_ENABLE - Invalid enable input. ++ * Note: ++ * This API can be used to set L2 LUT aging status per port. ++ */ ++rtk_api_ret_t rtk_l2_agingEnable_set(rtk_port_t port, rtk_enable_t enable) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* check port valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if (enable >= RTK_ENABLE_END) ++ return RT_ERR_ENABLE; ++ ++ if(enable == 1) ++ enable = 0; ++ else ++ enable = 1; ++ ++ if ((retVal = rtl8367c_setAsicLutDisableAging(rtk_switch_port_L2P_get(port), enable)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_l2_agingEnable_get ++ * Description: ++ * Get L2 LUT aging status per port setting. ++ * Input: ++ * port - Port id. ++ * Output: ++ * pEnable - Aging status ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * This API can be used to get L2 LUT aging function per port. ++ */ ++rtk_api_ret_t rtk_l2_agingEnable_get(rtk_port_t port, rtk_enable_t *pEnable) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* check port valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if(NULL == pEnable) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicLutDisableAging(rtk_switch_port_L2P_get(port), pEnable)) != RT_ERR_OK) ++ return retVal; ++ ++ if(*pEnable == 1) ++ *pEnable = 0; ++ else ++ *pEnable = 1; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_l2_limitLearningCnt_set ++ * Description: ++ * Set per-Port auto learning limit number ++ * Input: ++ * port - Port id. ++ * mac_cnt - Auto learning entries limit number ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_LIMITED_L2ENTRY_NUM - Invalid auto learning limit number ++ * Note: ++ * The API can set per-port ASIC auto learning limit number from 0(disable learning) ++ * to 2112. ++ */ ++rtk_api_ret_t rtk_l2_limitLearningCnt_set(rtk_port_t port, rtk_mac_cnt_t mac_cnt) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* check port valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if (mac_cnt > rtk_switch_maxLutAddrNumber_get()) ++ return RT_ERR_LIMITED_L2ENTRY_NUM; ++ ++ if ((retVal = rtl8367c_setAsicLutLearnLimitNo(rtk_switch_port_L2P_get(port), mac_cnt)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_l2_limitLearningCnt_get ++ * Description: ++ * Get per-Port auto learning limit number ++ * Input: ++ * port - Port id. ++ * Output: ++ * pMac_cnt - Auto learning entries limit number ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * The API can get per-port ASIC auto learning limit number. ++ */ ++rtk_api_ret_t rtk_l2_limitLearningCnt_get(rtk_port_t port, rtk_mac_cnt_t *pMac_cnt) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* check port valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if(NULL == pMac_cnt) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicLutLearnLimitNo(rtk_switch_port_L2P_get(port), pMac_cnt)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_l2_limitSystemLearningCnt_set ++ * Description: ++ * Set System auto learning limit number ++ * Input: ++ * mac_cnt - Auto learning entries limit number ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_LIMITED_L2ENTRY_NUM - Invalid auto learning limit number ++ * Note: ++ * The API can set system ASIC auto learning limit number from 0(disable learning) ++ * to 2112. ++ */ ++rtk_api_ret_t rtk_l2_limitSystemLearningCnt_set(rtk_mac_cnt_t mac_cnt) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (mac_cnt > rtk_switch_maxLutAddrNumber_get()) ++ return RT_ERR_LIMITED_L2ENTRY_NUM; ++ ++ if ((retVal = rtl8367c_setAsicSystemLutLearnLimitNo(mac_cnt)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_l2_limitSystemLearningCnt_get ++ * Description: ++ * Get System auto learning limit number ++ * Input: ++ * None ++ * Output: ++ * pMac_cnt - Auto learning entries limit number ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * The API can get system ASIC auto learning limit number. ++ */ ++rtk_api_ret_t rtk_l2_limitSystemLearningCnt_get(rtk_mac_cnt_t *pMac_cnt) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pMac_cnt) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicSystemLutLearnLimitNo(pMac_cnt)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_l2_limitLearningCntAction_set ++ * Description: ++ * Configure auto learn over limit number action. ++ * Input: ++ * port - Port id. ++ * action - Auto learning entries limit number ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_NOT_ALLOWED - Invalid learn over action ++ * Note: ++ * The API can set SA unknown packet action while auto learn limit number is over ++ * The action symbol as following: ++ * - LIMIT_LEARN_CNT_ACTION_DROP, ++ * - LIMIT_LEARN_CNT_ACTION_FORWARD, ++ * - LIMIT_LEARN_CNT_ACTION_TO_CPU, ++ */ ++rtk_api_ret_t rtk_l2_limitLearningCntAction_set(rtk_port_t port, rtk_l2_limitLearnCntAction_t action) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 data; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (port != RTK_WHOLE_SYSTEM) ++ return RT_ERR_PORT_ID; ++ ++ if ( LIMIT_LEARN_CNT_ACTION_DROP == action ) ++ data = 1; ++ else if ( LIMIT_LEARN_CNT_ACTION_FORWARD == action ) ++ data = 0; ++ else if ( LIMIT_LEARN_CNT_ACTION_TO_CPU == action ) ++ data = 2; ++ else ++ return RT_ERR_NOT_ALLOWED; ++ ++ if ((retVal = rtl8367c_setAsicLutLearnOverAct(data)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_l2_limitLearningCntAction_get ++ * Description: ++ * Get auto learn over limit number action. ++ * Input: ++ * port - Port id. ++ * Output: ++ * pAction - Learn over action ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * The API can get SA unknown packet action while auto learn limit number is over ++ * The action symbol as following: ++ * - LIMIT_LEARN_CNT_ACTION_DROP, ++ * - LIMIT_LEARN_CNT_ACTION_FORWARD, ++ * - LIMIT_LEARN_CNT_ACTION_TO_CPU, ++ */ ++rtk_api_ret_t rtk_l2_limitLearningCntAction_get(rtk_port_t port, rtk_l2_limitLearnCntAction_t *pAction) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 action; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (port != RTK_WHOLE_SYSTEM) ++ return RT_ERR_PORT_ID; ++ ++ if(NULL == pAction) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicLutLearnOverAct(&action)) != RT_ERR_OK) ++ return retVal; ++ ++ if ( 1 == action ) ++ *pAction = LIMIT_LEARN_CNT_ACTION_DROP; ++ else if ( 0 == action ) ++ *pAction = LIMIT_LEARN_CNT_ACTION_FORWARD; ++ else if ( 2 == action ) ++ *pAction = LIMIT_LEARN_CNT_ACTION_TO_CPU; ++ else ++ *pAction = action; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_l2_limitSystemLearningCntAction_set ++ * Description: ++ * Configure system auto learn over limit number action. ++ * Input: ++ * port - Port id. ++ * action - Auto learning entries limit number ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_NOT_ALLOWED - Invalid learn over action ++ * Note: ++ * The API can set SA unknown packet action while auto learn limit number is over ++ * The action symbol as following: ++ * - LIMIT_LEARN_CNT_ACTION_DROP, ++ * - LIMIT_LEARN_CNT_ACTION_FORWARD, ++ * - LIMIT_LEARN_CNT_ACTION_TO_CPU, ++ */ ++rtk_api_ret_t rtk_l2_limitSystemLearningCntAction_set(rtk_l2_limitLearnCntAction_t action) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 data; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if ( LIMIT_LEARN_CNT_ACTION_DROP == action ) ++ data = 1; ++ else if ( LIMIT_LEARN_CNT_ACTION_FORWARD == action ) ++ data = 0; ++ else if ( LIMIT_LEARN_CNT_ACTION_TO_CPU == action ) ++ data = 2; ++ else ++ return RT_ERR_NOT_ALLOWED; ++ ++ if ((retVal = rtl8367c_setAsicSystemLutLearnOverAct(data)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_l2_limitSystemLearningCntAction_get ++ * Description: ++ * Get system auto learn over limit number action. ++ * Input: ++ * None. ++ * Output: ++ * pAction - Learn over action ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * The API can get SA unknown packet action while auto learn limit number is over ++ * The action symbol as following: ++ * - LIMIT_LEARN_CNT_ACTION_DROP, ++ * - LIMIT_LEARN_CNT_ACTION_FORWARD, ++ * - LIMIT_LEARN_CNT_ACTION_TO_CPU, ++ */ ++rtk_api_ret_t rtk_l2_limitSystemLearningCntAction_get(rtk_l2_limitLearnCntAction_t *pAction) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 action; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pAction) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicSystemLutLearnOverAct(&action)) != RT_ERR_OK) ++ return retVal; ++ ++ if ( 1 == action ) ++ *pAction = LIMIT_LEARN_CNT_ACTION_DROP; ++ else if ( 0 == action ) ++ *pAction = LIMIT_LEARN_CNT_ACTION_FORWARD; ++ else if ( 2 == action ) ++ *pAction = LIMIT_LEARN_CNT_ACTION_TO_CPU; ++ else ++ *pAction = action; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_l2_limitSystemLearningCntPortMask_set ++ * Description: ++ * Configure system auto learn portmask ++ * Input: ++ * pPortmask - Port Mask ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_MASK - Invalid port mask. ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_l2_limitSystemLearningCntPortMask_set(rtk_portmask_t *pPortmask) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 pmask; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pPortmask) ++ return RT_ERR_NULL_POINTER; ++ ++ /* Check port mask */ ++ RTK_CHK_PORTMASK_VALID(pPortmask); ++ ++ if ((retVal = rtk_switch_portmask_L2P_get(pPortmask, &pmask)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicSystemLutLearnPortMask(pmask)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_l2_limitSystemLearningCntPortMask_get ++ * Description: ++ * get system auto learn portmask ++ * Input: ++ * None ++ * Output: ++ * pPortmask - Port Mask ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_NULL_POINTER - Null pointer. ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_l2_limitSystemLearningCntPortMask_get(rtk_portmask_t *pPortmask) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 pmask; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pPortmask) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicSystemLutLearnPortMask(&pmask)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtk_switch_portmask_P2L_get(pmask, pPortmask)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_l2_learningCnt_get ++ * Description: ++ * Get per-Port current auto learning number ++ * Input: ++ * port - Port id. ++ * Output: ++ * pMac_cnt - ASIC auto learning entries number ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * The API can get per-port ASIC auto learning number ++ */ ++rtk_api_ret_t rtk_l2_learningCnt_get(rtk_port_t port, rtk_mac_cnt_t *pMac_cnt) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* check port valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if(NULL == pMac_cnt) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicLutLearnNo(rtk_switch_port_L2P_get(port), pMac_cnt)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_l2_floodPortMask_set ++ * Description: ++ * Set flooding portmask ++ * Input: ++ * type - flooding type. ++ * pFlood_portmask - flooding portmask ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_MASK - Invalid portmask. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * This API can set the flooding mask. ++ * The flooding type is as following: ++ * - FLOOD_UNKNOWNDA ++ * - FLOOD_UNKNOWNMC ++ * - FLOOD_BC ++ */ ++rtk_api_ret_t rtk_l2_floodPortMask_set(rtk_l2_flood_type_t floood_type, rtk_portmask_t *pFlood_portmask) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 pmask; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (floood_type >= FLOOD_END) ++ return RT_ERR_INPUT; ++ ++ /* check port valid */ ++ RTK_CHK_PORTMASK_VALID(pFlood_portmask); ++ ++ /* Get Physical port mask */ ++ if ((retVal = rtk_switch_portmask_L2P_get(pFlood_portmask, &pmask))!=RT_ERR_OK) ++ return retVal; ++ ++ switch (floood_type) ++ { ++ case FLOOD_UNKNOWNDA: ++ if ((retVal = rtl8367c_setAsicPortUnknownDaFloodingPortmask(pmask)) != RT_ERR_OK) ++ return retVal; ++ break; ++ case FLOOD_UNKNOWNMC: ++ if ((retVal = rtl8367c_setAsicPortUnknownMulticastFloodingPortmask(pmask)) != RT_ERR_OK) ++ return retVal; ++ break; ++ case FLOOD_BC: ++ if ((retVal = rtl8367c_setAsicPortBcastFloodingPortmask(pmask)) != RT_ERR_OK) ++ return retVal; ++ break; ++ default: ++ break; ++ } ++ ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtk_l2_floodPortMask_get ++ * Description: ++ * Get flooding portmask ++ * Input: ++ * type - flooding type. ++ * Output: ++ * pFlood_portmask - flooding portmask ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * This API can get the flooding mask. ++ * The flooding type is as following: ++ * - FLOOD_UNKNOWNDA ++ * - FLOOD_UNKNOWNMC ++ * - FLOOD_BC ++ */ ++rtk_api_ret_t rtk_l2_floodPortMask_get(rtk_l2_flood_type_t floood_type, rtk_portmask_t *pFlood_portmask) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 pmask; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (floood_type >= FLOOD_END) ++ return RT_ERR_INPUT; ++ ++ if(NULL == pFlood_portmask) ++ return RT_ERR_NULL_POINTER; ++ ++ switch (floood_type) ++ { ++ case FLOOD_UNKNOWNDA: ++ if ((retVal = rtl8367c_getAsicPortUnknownDaFloodingPortmask(&pmask)) != RT_ERR_OK) ++ return retVal; ++ break; ++ case FLOOD_UNKNOWNMC: ++ if ((retVal = rtl8367c_getAsicPortUnknownMulticastFloodingPortmask(&pmask)) != RT_ERR_OK) ++ return retVal; ++ break; ++ case FLOOD_BC: ++ if ((retVal = rtl8367c_getAsicPortBcastFloodingPortmask(&pmask)) != RT_ERR_OK) ++ return retVal; ++ break; ++ default: ++ break; ++ } ++ ++ /* Get Logical port mask */ ++ if ((retVal = rtk_switch_portmask_P2L_get(pmask, pFlood_portmask))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_l2_localPktPermit_set ++ * Description: ++ * Set permission of frames if source port and destination port are the same. ++ * Input: ++ * port - Port id. ++ * permit - permission status ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_ENABLE - Invalid permit value. ++ * Note: ++ * This API is set to permit frame if its source port is equal to destination port. ++ */ ++rtk_api_ret_t rtk_l2_localPktPermit_set(rtk_port_t port, rtk_enable_t permit) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* check port valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if (permit >= RTK_ENABLE_END) ++ return RT_ERR_ENABLE; ++ ++ if ((retVal = rtl8367c_setAsicPortBlockSpa(rtk_switch_port_L2P_get(port), permit)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_l2_localPktPermit_get ++ * Description: ++ * Get permission of frames if source port and destination port are the same. ++ * Input: ++ * port - Port id. ++ * Output: ++ * pPermit - permission status ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * This API is to get permission status for frames if its source port is equal to destination port. ++ */ ++rtk_api_ret_t rtk_l2_localPktPermit_get(rtk_port_t port, rtk_enable_t *pPermit) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* check port valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if(NULL == pPermit) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicPortBlockSpa(rtk_switch_port_L2P_get(port), pPermit)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_l2_aging_set ++ * Description: ++ * Set LUT ageing out speed ++ * Input: ++ * aging_time - Ageing out time. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - input out of range. ++ * Note: ++ * The API can set LUT ageing out period for each entry and the range is from 45s to 458s. ++ */ ++rtk_api_ret_t rtk_l2_aging_set(rtk_l2_age_time_t aging_time) ++{ ++ rtk_uint32 i; ++ CONST_T rtk_uint32 agePara[10][3] = { ++ {45, 0, 1}, {88, 0, 2}, {133, 0, 3}, {177, 0, 4}, {221, 0, 5}, {266, 0, 6}, {310, 0, 7}, ++ {354, 2, 6}, {413, 2, 7}, {458, 3, 7}}; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (aging_time>agePara[9][0]) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ for (i = 0; i<10; i++) ++ { ++ if (aging_time<=agePara[i][0]) ++ { ++ return rtl8367c_setAsicLutAgeTimerSpeed(agePara[i][2], agePara[i][1]); ++ } ++ } ++ ++ return RT_ERR_FAILED; ++} ++ ++/* Function Name: ++ * rtk_l2_aging_get ++ * Description: ++ * Get LUT ageing out time ++ * Input: ++ * None ++ * Output: ++ * pEnable - Aging status ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * The API can get LUT ageing out period for each entry. ++ */ ++rtk_api_ret_t rtk_l2_aging_get(rtk_l2_age_time_t *pAging_time) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 i,time, speed; ++ CONST_T rtk_uint32 agePara[10][3] = { ++ {45, 0, 1}, {88, 0, 2}, {133, 0, 3}, {177, 0, 4}, {221, 0, 5}, {266, 0, 6}, {310, 0, 7}, ++ {354, 2, 6}, {413, 2, 7}, {458, 3, 7}}; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pAging_time) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicLutAgeTimerSpeed(&time, &speed)) != RT_ERR_OK) ++ return retVal; ++ ++ for (i = 0; i<10; i++) ++ { ++ if (time==agePara[i][2]&&speed==agePara[i][1]) ++ { ++ *pAging_time = agePara[i][0]; ++ return RT_ERR_OK; ++ } ++ } ++ ++ return RT_ERR_FAILED; ++} ++ ++/* Function Name: ++ * rtk_l2_ipMcastAddrLookup_set ++ * Description: ++ * Set LUT IP multicast lookup function ++ * Input: ++ * type - Lookup type for IPMC packet. ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * LOOKUP_MAC - Lookup by MAC address ++ * LOOKUP_IP - Lookup by IP address ++ * LOOKUP_IP_VID - Lookup by IP address & VLAN ID ++ */ ++rtk_api_ret_t rtk_l2_ipMcastAddrLookup_set(rtk_l2_ipmc_lookup_type_t type) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(type == LOOKUP_MAC) ++ { ++ if((retVal = rtl8367c_setAsicLutIpMulticastLookup(DISABLED)) != RT_ERR_OK) ++ return retVal; ++ } ++ else if(type == LOOKUP_IP) ++ { ++ if((retVal = rtl8367c_setAsicLutIpMulticastLookup(ENABLED)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicLutIpMulticastVidLookup(DISABLED))!=RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicLutIpLookupMethod(1))!=RT_ERR_OK) ++ return retVal; ++ } ++ else if(type == LOOKUP_IP_VID) ++ { ++ if((retVal = rtl8367c_setAsicLutIpMulticastLookup(ENABLED)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicLutIpMulticastVidLookup(ENABLED))!=RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicLutIpLookupMethod(1))!=RT_ERR_OK) ++ return retVal; ++ } ++ else ++ return RT_ERR_INPUT; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_l2_ipMcastAddrLookup_get ++ * Description: ++ * Get LUT IP multicast lookup function ++ * Input: ++ * None. ++ * Output: ++ * pType - Lookup type for IPMC packet. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None. ++ */ ++rtk_api_ret_t rtk_l2_ipMcastAddrLookup_get(rtk_l2_ipmc_lookup_type_t *pType) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 enabled, vid_lookup; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pType) ++ return RT_ERR_NULL_POINTER; ++ ++ if((retVal = rtl8367c_getAsicLutIpMulticastLookup(&enabled)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_getAsicLutIpMulticastVidLookup(&vid_lookup))!=RT_ERR_OK) ++ return retVal; ++ ++ if(enabled == ENABLED) ++ { ++ if(vid_lookup == ENABLED) ++ *pType = LOOKUP_IP_VID; ++ else ++ *pType = LOOKUP_IP; ++ } ++ else ++ *pType = LOOKUP_MAC; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_l2_ipMcastForwardRouterPort_set ++ * Description: ++ * Set IPMC packet forward to router port also or not ++ * Input: ++ * enabled - 1: Include router port, 0, exclude router port ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_l2_ipMcastForwardRouterPort_set(rtk_enable_t enabled) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (enabled >= RTK_ENABLE_END) ++ return RT_ERR_ENABLE; ++ ++ if((retVal = rtl8367c_setAsicLutIpmcFwdRouterPort(enabled)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_l2_ipMcastForwardRouterPort_get ++ * Description: ++ * Get IPMC packet forward to router port also or not ++ * Input: ++ * None. ++ * Output: ++ * pEnabled - 1: Include router port, 0, exclude router port ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_NULL_POINTER - Null pointer ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_l2_ipMcastForwardRouterPort_get(rtk_enable_t *pEnabled) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (NULL == pEnabled) ++ return RT_ERR_NULL_POINTER; ++ ++ if((retVal = rtl8367c_getAsicLutIpmcFwdRouterPort(pEnabled)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_l2_ipMcastGroupEntry_add ++ * Description: ++ * Add an IP Multicast entry to group table ++ * Input: ++ * ip_addr - IP address ++ * vid - VLAN ID ++ * pPortmask - portmask ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_TBL_FULL - Table Full ++ * Note: ++ * Add an entry to IP Multicast Group table. ++ */ ++rtk_api_ret_t rtk_l2_ipMcastGroupEntry_add(ipaddr_t ip_addr, rtk_uint32 vid, rtk_portmask_t *pPortmask) ++{ ++ rtk_uint32 empty_idx = 0xFFFF; ++ rtk_int32 index; ++ ipaddr_t group_addr; ++ rtk_uint32 group_vid; ++ rtk_uint32 pmask; ++ rtk_uint32 valid; ++ rtk_uint32 physicalPortmask; ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (vid > RTL8367C_VIDMAX) ++ return RT_ERR_L2_VID; ++ ++ if(NULL == pPortmask) ++ return RT_ERR_NULL_POINTER; ++ ++ if((ip_addr & 0xF0000000) != 0xE0000000) ++ return RT_ERR_INPUT; ++ ++ /* Get Physical port mask */ ++ if ((retVal = rtk_switch_portmask_L2P_get(pPortmask, &physicalPortmask))!=RT_ERR_OK) ++ return retVal; ++ ++ for(index = 0; index <= RTL8367C_LUT_IPMCGRP_TABLE_MAX; index++) ++ { ++ if ((retVal = rtl8367c_getAsicLutIPMCGroup((rtk_uint32)index, &group_addr, &group_vid, &pmask, &valid))!=RT_ERR_OK) ++ return retVal; ++ ++ if( (valid == ENABLED) && (group_addr == ip_addr) && (group_vid == vid) ) ++ { ++ if(pmask != physicalPortmask) ++ { ++ pmask = physicalPortmask; ++ if ((retVal = rtl8367c_setAsicLutIPMCGroup(index, ip_addr, vid, pmask, valid))!=RT_ERR_OK) ++ return retVal; ++ } ++ ++ return RT_ERR_OK; ++ } ++ ++ if( (valid == DISABLED) && (empty_idx == 0xFFFF) ) /* Unused */ ++ empty_idx = (rtk_uint32)index; ++ } ++ ++ if(empty_idx == 0xFFFF) ++ return RT_ERR_TBL_FULL; ++ ++ pmask = physicalPortmask; ++ if ((retVal = rtl8367c_setAsicLutIPMCGroup(empty_idx, ip_addr, vid, pmask, ENABLED))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_l2_ipMcastGroupEntry_del ++ * Description: ++ * Delete an entry from IP Multicast group table ++ * Input: ++ * ip_addr - IP address ++ * vid - VLAN ID ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_TBL_FULL - Table Full ++ * Note: ++ * Delete an entry from IP Multicast group table. ++ */ ++rtk_api_ret_t rtk_l2_ipMcastGroupEntry_del(ipaddr_t ip_addr, rtk_uint32 vid) ++{ ++ rtk_int32 index; ++ ipaddr_t group_addr; ++ rtk_uint32 group_vid; ++ rtk_uint32 pmask; ++ rtk_uint32 valid; ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (vid > RTL8367C_VIDMAX) ++ return RT_ERR_L2_VID; ++ ++ if((ip_addr & 0xF0000000) != 0xE0000000) ++ return RT_ERR_INPUT; ++ ++ for(index = 0; index <= RTL8367C_LUT_IPMCGRP_TABLE_MAX; index++) ++ { ++ if ((retVal = rtl8367c_getAsicLutIPMCGroup((rtk_uint32)index, &group_addr, &group_vid, &pmask, &valid))!=RT_ERR_OK) ++ return retVal; ++ ++ if( (valid == ENABLED) && (group_addr == ip_addr) && (group_vid == vid) ) ++ { ++ group_addr = 0xE0000000; ++ group_vid = 0; ++ pmask = 0; ++ if ((retVal = rtl8367c_setAsicLutIPMCGroup(index, group_addr, group_vid, pmask, DISABLED))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++ } ++ } ++ ++ return RT_ERR_FAILED; ++} ++ ++/* Function Name: ++ * rtk_l2_ipMcastGroupEntry_get ++ * Description: ++ * get an entry from IP Multicast group table ++ * Input: ++ * ip_addr - IP address ++ * vid - VLAN ID ++ * Output: ++ * pPortmask - member port mask ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_TBL_FULL - Table Full ++ * Note: ++ * Delete an entry from IP Multicast group table. ++ */ ++rtk_api_ret_t rtk_l2_ipMcastGroupEntry_get(ipaddr_t ip_addr, rtk_uint32 vid, rtk_portmask_t *pPortmask) ++{ ++ rtk_int32 index; ++ ipaddr_t group_addr; ++ rtk_uint32 group_vid; ++ rtk_uint32 valid; ++ rtk_uint32 pmask; ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if((ip_addr & 0xF0000000) != 0xE0000000) ++ return RT_ERR_INPUT; ++ ++ if (vid > RTL8367C_VIDMAX) ++ return RT_ERR_L2_VID; ++ ++ if(NULL == pPortmask) ++ return RT_ERR_NULL_POINTER; ++ ++ for(index = 0; index <= RTL8367C_LUT_IPMCGRP_TABLE_MAX; index++) ++ { ++ if ((retVal = rtl8367c_getAsicLutIPMCGroup((rtk_uint32)index, &group_addr, &group_vid, &pmask, &valid))!=RT_ERR_OK) ++ return retVal; ++ ++ if( (valid == ENABLED) && (group_addr == ip_addr) && (group_vid == vid) ) ++ { ++ if ((retVal = rtk_switch_portmask_P2L_get(pmask, pPortmask))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++ } ++ } ++ ++ return RT_ERR_FAILED; ++} ++ ++/* Function Name: ++ * rtk_l2_entry_get ++ * Description: ++ * Get LUT unicast entry. ++ * Input: ++ * pL2_entry - Index field in the structure. ++ * Output: ++ * pL2_entry - other fields such as MAC, port, age... ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_L2_EMPTY_ENTRY - Empty LUT entry. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * This API is used to get address by index from 0~2111. ++ */ ++rtk_api_ret_t rtk_l2_entry_get(rtk_l2_addr_table_t *pL2_entry) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 method; ++ rtl8367c_luttb l2Table; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (pL2_entry->index >= rtk_switch_maxLutAddrNumber_get()) ++ return RT_ERR_INPUT; ++ ++ memset(&l2Table, 0x00, sizeof(rtl8367c_luttb)); ++ l2Table.address= pL2_entry->index; ++ method = LUTREADMETHOD_ADDRESS; ++ if ((retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((pL2_entry->index>0x800)&&(l2Table.lookup_hit==0)) ++ return RT_ERR_L2_EMPTY_ENTRY; ++ ++ if(l2Table.l3lookup) ++ { ++ if(l2Table.l3vidlookup) ++ { ++ memset(&pL2_entry->mac, 0, sizeof(rtk_mac_t)); ++ pL2_entry->is_ipmul = l2Table.l3lookup; ++ pL2_entry->sip = l2Table.sip; ++ pL2_entry->dip = l2Table.dip; ++ pL2_entry->is_static = l2Table.nosalearn; ++ ++ /* Get Logical port mask */ ++ if ((retVal = rtk_switch_portmask_P2L_get(l2Table.mbr, &(pL2_entry->portmask)))!=RT_ERR_OK) ++ return retVal; ++ ++ pL2_entry->fid = 0; ++ pL2_entry->age = 0; ++ pL2_entry->auth = 0; ++ pL2_entry->sa_block = 0; ++ pL2_entry->is_ipvidmul = 1; ++ pL2_entry->l3_vid = l2Table.l3_vid; ++ } ++ else ++ { ++ memset(&pL2_entry->mac, 0, sizeof(rtk_mac_t)); ++ pL2_entry->is_ipmul = l2Table.l3lookup; ++ pL2_entry->sip = l2Table.sip; ++ pL2_entry->dip = l2Table.dip; ++ pL2_entry->is_static = l2Table.nosalearn; ++ ++ /* Get Logical port mask */ ++ if ((retVal = rtk_switch_portmask_P2L_get(l2Table.mbr, &(pL2_entry->portmask)))!=RT_ERR_OK) ++ return retVal; ++ ++ pL2_entry->fid = 0; ++ pL2_entry->age = 0; ++ pL2_entry->auth = 0; ++ pL2_entry->sa_block = 0; ++ pL2_entry->is_ipvidmul = 0; ++ pL2_entry->l3_vid = 0; ++ } ++ } ++ else if(l2Table.mac.octet[0]&0x01) ++ { ++ memset(&pL2_entry->sip, 0, sizeof(ipaddr_t)); ++ memset(&pL2_entry->dip, 0, sizeof(ipaddr_t)); ++ pL2_entry->mac.octet[0] = l2Table.mac.octet[0]; ++ pL2_entry->mac.octet[1] = l2Table.mac.octet[1]; ++ pL2_entry->mac.octet[2] = l2Table.mac.octet[2]; ++ pL2_entry->mac.octet[3] = l2Table.mac.octet[3]; ++ pL2_entry->mac.octet[4] = l2Table.mac.octet[4]; ++ pL2_entry->mac.octet[5] = l2Table.mac.octet[5]; ++ pL2_entry->is_ipmul = l2Table.l3lookup; ++ pL2_entry->is_static = l2Table.nosalearn; ++ ++ /* Get Logical port mask */ ++ if ((retVal = rtk_switch_portmask_P2L_get(l2Table.mbr, &(pL2_entry->portmask)))!=RT_ERR_OK) ++ return retVal; ++ ++ pL2_entry->ivl = l2Table.ivl_svl; ++ if(l2Table.ivl_svl == 1) /* IVL */ ++ { ++ pL2_entry->cvid = l2Table.cvid_fid; ++ pL2_entry->fid = 0; ++ } ++ else /* SVL*/ ++ { ++ pL2_entry->cvid = 0; ++ pL2_entry->fid = l2Table.cvid_fid; ++ } ++ pL2_entry->auth = l2Table.auth; ++ pL2_entry->sa_block = l2Table.sa_block; ++ pL2_entry->age = 0; ++ pL2_entry->is_ipvidmul = 0; ++ pL2_entry->l3_vid = 0; ++ } ++ else if((l2Table.age != 0)||(l2Table.nosalearn == 1)) ++ { ++ memset(&pL2_entry->sip, 0, sizeof(ipaddr_t)); ++ memset(&pL2_entry->dip, 0, sizeof(ipaddr_t)); ++ pL2_entry->mac.octet[0] = l2Table.mac.octet[0]; ++ pL2_entry->mac.octet[1] = l2Table.mac.octet[1]; ++ pL2_entry->mac.octet[2] = l2Table.mac.octet[2]; ++ pL2_entry->mac.octet[3] = l2Table.mac.octet[3]; ++ pL2_entry->mac.octet[4] = l2Table.mac.octet[4]; ++ pL2_entry->mac.octet[5] = l2Table.mac.octet[5]; ++ pL2_entry->is_ipmul = l2Table.l3lookup; ++ pL2_entry->is_static = l2Table.nosalearn; ++ ++ /* Get Logical port mask */ ++ if ((retVal = rtk_switch_portmask_P2L_get(1<<(l2Table.spa), &(pL2_entry->portmask)))!=RT_ERR_OK) ++ return retVal; ++ ++ pL2_entry->ivl = l2Table.ivl_svl; ++ pL2_entry->cvid = l2Table.cvid_fid; ++ pL2_entry->fid = l2Table.fid; ++ pL2_entry->auth = l2Table.auth; ++ pL2_entry->sa_block = l2Table.sa_block; ++ pL2_entry->age = l2Table.age; ++ pL2_entry->is_ipvidmul = 0; ++ pL2_entry->l3_vid = 0; ++ } ++ else ++ return RT_ERR_L2_EMPTY_ENTRY; ++ ++ return RT_ERR_OK; ++} ++ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/leaky.c b/drivers/net/phy/rtk/rtl8367c/leaky.c +new file mode 100644 +index 000000000000..1b7d50a9e547 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/leaky.c +@@ -0,0 +1,590 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ ++ * ++ * Purpose : RTK switch high-level API for RTL8367/RTL8367C ++ * Feature : Here is a list of all functions and variables in Leaky module. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++ ++/* Function Name: ++ * rtk_leaky_vlan_set ++ * Description: ++ * Set VLAN leaky. ++ * Input: ++ * type - Packet type for VLAN leaky. ++ * enable - Leaky status. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_ENABLE - Invalid enable input ++ * Note: ++ * This API can set VLAN leaky for RMA ,IGMP/MLD, CDP, CSSTP, and LLDP packets. ++ * The leaky frame types are as following: ++ * - LEAKY_BRG_GROUP, ++ * - LEAKY_FD_PAUSE, ++ * - LEAKY_SP_MCAST, ++ * - LEAKY_1X_PAE, ++ * - LEAKY_UNDEF_BRG_04, ++ * - LEAKY_UNDEF_BRG_05, ++ * - LEAKY_UNDEF_BRG_06, ++ * - LEAKY_UNDEF_BRG_07, ++ * - LEAKY_PROVIDER_BRIDGE_GROUP_ADDRESS, ++ * - LEAKY_UNDEF_BRG_09, ++ * - LEAKY_UNDEF_BRG_0A, ++ * - LEAKY_UNDEF_BRG_0B, ++ * - LEAKY_UNDEF_BRG_0C, ++ * - LEAKY_PROVIDER_BRIDGE_GVRP_ADDRESS, ++ * - LEAKY_8021AB, ++ * - LEAKY_UNDEF_BRG_0F, ++ * - LEAKY_BRG_MNGEMENT, ++ * - LEAKY_UNDEFINED_11, ++ * - LEAKY_UNDEFINED_12, ++ * - LEAKY_UNDEFINED_13, ++ * - LEAKY_UNDEFINED_14, ++ * - LEAKY_UNDEFINED_15, ++ * - LEAKY_UNDEFINED_16, ++ * - LEAKY_UNDEFINED_17, ++ * - LEAKY_UNDEFINED_18, ++ * - LEAKY_UNDEFINED_19, ++ * - LEAKY_UNDEFINED_1A, ++ * - LEAKY_UNDEFINED_1B, ++ * - LEAKY_UNDEFINED_1C, ++ * - LEAKY_UNDEFINED_1D, ++ * - LEAKY_UNDEFINED_1E, ++ * - LEAKY_UNDEFINED_1F, ++ * - LEAKY_GMRP, ++ * - LEAKY_GVRP, ++ * - LEAKY_UNDEF_GARP_22, ++ * - LEAKY_UNDEF_GARP_23, ++ * - LEAKY_UNDEF_GARP_24, ++ * - LEAKY_UNDEF_GARP_25, ++ * - LEAKY_UNDEF_GARP_26, ++ * - LEAKY_UNDEF_GARP_27, ++ * - LEAKY_UNDEF_GARP_28, ++ * - LEAKY_UNDEF_GARP_29, ++ * - LEAKY_UNDEF_GARP_2A, ++ * - LEAKY_UNDEF_GARP_2B, ++ * - LEAKY_UNDEF_GARP_2C, ++ * - LEAKY_UNDEF_GARP_2D, ++ * - LEAKY_UNDEF_GARP_2E, ++ * - LEAKY_UNDEF_GARP_2F, ++ * - LEAKY_IGMP, ++ * - LEAKY_IPMULTICAST. ++ * - LEAKY_CDP, ++ * - LEAKY_CSSTP, ++ * - LEAKY_LLDP. ++ */ ++rtk_api_ret_t rtk_leaky_vlan_set(rtk_leaky_type_t type, rtk_enable_t enable) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 port; ++ rtl8367c_rma_t rmacfg; ++ rtk_uint32 tmp; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (type >= LEAKY_END) ++ return RT_ERR_INPUT; ++ ++ if (enable >= RTK_ENABLE_END) ++ return RT_ERR_INPUT; ++ ++ if (type >= 0 && type <= LEAKY_UNDEF_GARP_2F) ++ { ++ if ((retVal = rtl8367c_getAsicRma(type, &rmacfg)) != RT_ERR_OK) ++ return retVal; ++ ++ rmacfg.vlan_leaky = enable; ++ ++ if ((retVal = rtl8367c_setAsicRma(type, &rmacfg)) != RT_ERR_OK) ++ return retVal; ++ } ++ else if (LEAKY_IPMULTICAST == type) ++ { ++ for (port = 0; port <= RTK_PORT_ID_MAX; port++) ++ { ++ if ((retVal = rtl8367c_setAsicIpMulticastVlanLeaky(port,enable)) != RT_ERR_OK) ++ return retVal; ++ } ++ } ++ else if (LEAKY_IGMP == type) ++ { ++ if ((retVal = rtl8367c_setAsicIGMPVLANLeaky(enable)) != RT_ERR_OK) ++ return retVal; ++ } ++ else if (LEAKY_CDP == type) ++ { ++ if ((retVal = rtl8367c_getAsicRmaCdp(&rmacfg)) != RT_ERR_OK) ++ return retVal; ++ ++ rmacfg.vlan_leaky = enable; ++ ++ if ((retVal = rtl8367c_setAsicRmaCdp(&rmacfg)) != RT_ERR_OK) ++ return retVal; ++ } ++ else if (LEAKY_CSSTP == type) ++ { ++ if ((retVal = rtl8367c_getAsicRmaCsstp(&rmacfg)) != RT_ERR_OK) ++ return retVal; ++ ++ rmacfg.vlan_leaky = enable; ++ ++ if ((retVal = rtl8367c_setAsicRmaCsstp(&rmacfg)) != RT_ERR_OK) ++ return retVal; ++ } ++ else if (LEAKY_LLDP == type) ++ { ++ if ((retVal = rtl8367c_getAsicRmaLldp(&tmp,&rmacfg)) != RT_ERR_OK) ++ return retVal; ++ ++ rmacfg.vlan_leaky = enable; ++ ++ if ((retVal = rtl8367c_setAsicRmaLldp(tmp, &rmacfg)) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_leaky_vlan_get ++ * Description: ++ * Get VLAN leaky. ++ * Input: ++ * type - Packet type for VLAN leaky. ++ * Output: ++ * pEnable - Leaky status. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * This API can get VLAN leaky status for RMA ,IGMP/MLD, CDP, CSSTP, and LLDP packets. ++ * The leaky frame types are as following: ++ * - LEAKY_BRG_GROUP, ++ * - LEAKY_FD_PAUSE, ++ * - LEAKY_SP_MCAST, ++ * - LEAKY_1X_PAE, ++ * - LEAKY_UNDEF_BRG_04, ++ * - LEAKY_UNDEF_BRG_05, ++ * - LEAKY_UNDEF_BRG_06, ++ * - LEAKY_UNDEF_BRG_07, ++ * - LEAKY_PROVIDER_BRIDGE_GROUP_ADDRESS, ++ * - LEAKY_UNDEF_BRG_09, ++ * - LEAKY_UNDEF_BRG_0A, ++ * - LEAKY_UNDEF_BRG_0B, ++ * - LEAKY_UNDEF_BRG_0C, ++ * - LEAKY_PROVIDER_BRIDGE_GVRP_ADDRESS, ++ * - LEAKY_8021AB, ++ * - LEAKY_UNDEF_BRG_0F, ++ * - LEAKY_BRG_MNGEMENT, ++ * - LEAKY_UNDEFINED_11, ++ * - LEAKY_UNDEFINED_12, ++ * - LEAKY_UNDEFINED_13, ++ * - LEAKY_UNDEFINED_14, ++ * - LEAKY_UNDEFINED_15, ++ * - LEAKY_UNDEFINED_16, ++ * - LEAKY_UNDEFINED_17, ++ * - LEAKY_UNDEFINED_18, ++ * - LEAKY_UNDEFINED_19, ++ * - LEAKY_UNDEFINED_1A, ++ * - LEAKY_UNDEFINED_1B, ++ * - LEAKY_UNDEFINED_1C, ++ * - LEAKY_UNDEFINED_1D, ++ * - LEAKY_UNDEFINED_1E, ++ * - LEAKY_UNDEFINED_1F, ++ * - LEAKY_GMRP, ++ * - LEAKY_GVRP, ++ * - LEAKY_UNDEF_GARP_22, ++ * - LEAKY_UNDEF_GARP_23, ++ * - LEAKY_UNDEF_GARP_24, ++ * - LEAKY_UNDEF_GARP_25, ++ * - LEAKY_UNDEF_GARP_26, ++ * - LEAKY_UNDEF_GARP_27, ++ * - LEAKY_UNDEF_GARP_28, ++ * - LEAKY_UNDEF_GARP_29, ++ * - LEAKY_UNDEF_GARP_2A, ++ * - LEAKY_UNDEF_GARP_2B, ++ * - LEAKY_UNDEF_GARP_2C, ++ * - LEAKY_UNDEF_GARP_2D, ++ * - LEAKY_UNDEF_GARP_2E, ++ * - LEAKY_UNDEF_GARP_2F, ++ * - LEAKY_IGMP, ++ * - LEAKY_IPMULTICAST. ++ * - LEAKY_CDP, ++ * - LEAKY_CSSTP, ++ * - LEAKY_LLDP. ++ */ ++rtk_api_ret_t rtk_leaky_vlan_get(rtk_leaky_type_t type, rtk_enable_t *pEnable) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 port,tmp; ++ rtl8367c_rma_t rmacfg; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (type >= LEAKY_END) ++ return RT_ERR_INPUT; ++ ++ if(NULL == pEnable) ++ return RT_ERR_NULL_POINTER; ++ ++ if (type >= 0 && type <= LEAKY_UNDEF_GARP_2F) ++ { ++ if ((retVal = rtl8367c_getAsicRma(type, &rmacfg)) != RT_ERR_OK) ++ return retVal; ++ ++ *pEnable = rmacfg.vlan_leaky; ++ ++ } ++ else if (LEAKY_IPMULTICAST == type) ++ { ++ for (port = 0; port <= RTK_PORT_ID_MAX; port++) ++ { ++ if ((retVal = rtl8367c_getAsicIpMulticastVlanLeaky(port, &tmp)) != RT_ERR_OK) ++ return retVal; ++ if (port>0&&(tmp!=*pEnable)) ++ return RT_ERR_FAILED; ++ *pEnable = tmp; ++ } ++ } ++ else if (LEAKY_IGMP == type) ++ { ++ if ((retVal = rtl8367c_getAsicIGMPVLANLeaky(&tmp)) != RT_ERR_OK) ++ return retVal; ++ ++ *pEnable = tmp; ++ } ++ else if (LEAKY_CDP == type) ++ { ++ if ((retVal = rtl8367c_getAsicRmaCdp(&rmacfg)) != RT_ERR_OK) ++ return retVal; ++ ++ *pEnable = rmacfg.vlan_leaky; ++ } ++ else if (LEAKY_CSSTP == type) ++ { ++ if ((retVal = rtl8367c_getAsicRmaCsstp(&rmacfg)) != RT_ERR_OK) ++ return retVal; ++ ++ *pEnable = rmacfg.vlan_leaky; ++ } ++ else if (LEAKY_LLDP == type) ++ { ++ if ((retVal = rtl8367c_getAsicRmaLldp(&tmp, &rmacfg)) != RT_ERR_OK) ++ return retVal; ++ ++ *pEnable = rmacfg.vlan_leaky; ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_leaky_portIsolation_set ++ * Description: ++ * Set port isolation leaky. ++ * Input: ++ * type - Packet type for port isolation leaky. ++ * enable - Leaky status. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_ENABLE - Invalid enable input ++ * Note: ++ * This API can set port isolation leaky for RMA ,IGMP/MLD, CDP, CSSTP, and LLDP packets. ++ * The leaky frame types are as following: ++ * - LEAKY_BRG_GROUP, ++ * - LEAKY_FD_PAUSE, ++ * - LEAKY_SP_MCAST, ++ * - LEAKY_1X_PAE, ++ * - LEAKY_UNDEF_BRG_04, ++ * - LEAKY_UNDEF_BRG_05, ++ * - LEAKY_UNDEF_BRG_06, ++ * - LEAKY_UNDEF_BRG_07, ++ * - LEAKY_PROVIDER_BRIDGE_GROUP_ADDRESS, ++ * - LEAKY_UNDEF_BRG_09, ++ * - LEAKY_UNDEF_BRG_0A, ++ * - LEAKY_UNDEF_BRG_0B, ++ * - LEAKY_UNDEF_BRG_0C, ++ * - LEAKY_PROVIDER_BRIDGE_GVRP_ADDRESS, ++ * - LEAKY_8021AB, ++ * - LEAKY_UNDEF_BRG_0F, ++ * - LEAKY_BRG_MNGEMENT, ++ * - LEAKY_UNDEFINED_11, ++ * - LEAKY_UNDEFINED_12, ++ * - LEAKY_UNDEFINED_13, ++ * - LEAKY_UNDEFINED_14, ++ * - LEAKY_UNDEFINED_15, ++ * - LEAKY_UNDEFINED_16, ++ * - LEAKY_UNDEFINED_17, ++ * - LEAKY_UNDEFINED_18, ++ * - LEAKY_UNDEFINED_19, ++ * - LEAKY_UNDEFINED_1A, ++ * - LEAKY_UNDEFINED_1B, ++ * - LEAKY_UNDEFINED_1C, ++ * - LEAKY_UNDEFINED_1D, ++ * - LEAKY_UNDEFINED_1E, ++ * - LEAKY_UNDEFINED_1F, ++ * - LEAKY_GMRP, ++ * - LEAKY_GVRP, ++ * - LEAKY_UNDEF_GARP_22, ++ * - LEAKY_UNDEF_GARP_23, ++ * - LEAKY_UNDEF_GARP_24, ++ * - LEAKY_UNDEF_GARP_25, ++ * - LEAKY_UNDEF_GARP_26, ++ * - LEAKY_UNDEF_GARP_27, ++ * - LEAKY_UNDEF_GARP_28, ++ * - LEAKY_UNDEF_GARP_29, ++ * - LEAKY_UNDEF_GARP_2A, ++ * - LEAKY_UNDEF_GARP_2B, ++ * - LEAKY_UNDEF_GARP_2C, ++ * - LEAKY_UNDEF_GARP_2D, ++ * - LEAKY_UNDEF_GARP_2E, ++ * - LEAKY_UNDEF_GARP_2F, ++ * - LEAKY_IGMP, ++ * - LEAKY_IPMULTICAST. ++ * - LEAKY_CDP, ++ * - LEAKY_CSSTP, ++ * - LEAKY_LLDP. ++ */ ++rtk_api_ret_t rtk_leaky_portIsolation_set(rtk_leaky_type_t type, rtk_enable_t enable) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 port; ++ rtl8367c_rma_t rmacfg; ++ rtk_uint32 tmp; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (type >= LEAKY_END) ++ return RT_ERR_INPUT; ++ ++ if (enable >= RTK_ENABLE_END) ++ return RT_ERR_INPUT; ++ ++ if (type >= 0 && type <= LEAKY_UNDEF_GARP_2F) ++ { ++ if ((retVal = rtl8367c_getAsicRma(type, &rmacfg)) != RT_ERR_OK) ++ return retVal; ++ ++ rmacfg.portiso_leaky = enable; ++ ++ if ((retVal = rtl8367c_setAsicRma(type, &rmacfg)) != RT_ERR_OK) ++ return retVal; ++ } ++ else if (LEAKY_IPMULTICAST == type) ++ { ++ for (port = 0; port < RTK_MAX_NUM_OF_PORT; port++) ++ { ++ if ((retVal = rtl8367c_setAsicIpMulticastPortIsoLeaky(port,enable)) != RT_ERR_OK) ++ return retVal; ++ } ++ } ++ else if (LEAKY_IGMP == type) ++ { ++ if ((retVal = rtl8367c_setAsicIGMPIsoLeaky(enable)) != RT_ERR_OK) ++ return retVal; ++ } ++ else if (LEAKY_CDP == type) ++ { ++ if ((retVal = rtl8367c_getAsicRmaCdp(&rmacfg)) != RT_ERR_OK) ++ return retVal; ++ ++ rmacfg.portiso_leaky = enable; ++ ++ if ((retVal = rtl8367c_setAsicRmaCdp(&rmacfg)) != RT_ERR_OK) ++ return retVal; ++ } ++ else if (LEAKY_CSSTP == type) ++ { ++ if ((retVal = rtl8367c_getAsicRmaCsstp(&rmacfg)) != RT_ERR_OK) ++ return retVal; ++ ++ rmacfg.portiso_leaky = enable; ++ ++ if ((retVal = rtl8367c_setAsicRmaCsstp(&rmacfg)) != RT_ERR_OK) ++ return retVal; ++ } ++ else if (LEAKY_LLDP == type) ++ { ++ if ((retVal = rtl8367c_getAsicRmaLldp(&tmp, &rmacfg)) != RT_ERR_OK) ++ return retVal; ++ ++ rmacfg.portiso_leaky = enable; ++ ++ if ((retVal = rtl8367c_setAsicRmaLldp(tmp, &rmacfg)) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_leaky_portIsolation_get ++ * Description: ++ * Get port isolation leaky. ++ * Input: ++ * type - Packet type for port isolation leaky. ++ * Output: ++ * pEnable - Leaky status. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * This API can get port isolation leaky status for RMA ,IGMP/MLD, CDP, CSSTP, and LLDP packets. ++ * The leaky frame types are as following: ++ * - LEAKY_BRG_GROUP, ++ * - LEAKY_FD_PAUSE, ++ * - LEAKY_SP_MCAST, ++ * - LEAKY_1X_PAE, ++ * - LEAKY_UNDEF_BRG_04, ++ * - LEAKY_UNDEF_BRG_05, ++ * - LEAKY_UNDEF_BRG_06, ++ * - LEAKY_UNDEF_BRG_07, ++ * - LEAKY_PROVIDER_BRIDGE_GROUP_ADDRESS, ++ * - LEAKY_UNDEF_BRG_09, ++ * - LEAKY_UNDEF_BRG_0A, ++ * - LEAKY_UNDEF_BRG_0B, ++ * - LEAKY_UNDEF_BRG_0C, ++ * - LEAKY_PROVIDER_BRIDGE_GVRP_ADDRESS, ++ * - LEAKY_8021AB, ++ * - LEAKY_UNDEF_BRG_0F, ++ * - LEAKY_BRG_MNGEMENT, ++ * - LEAKY_UNDEFINED_11, ++ * - LEAKY_UNDEFINED_12, ++ * - LEAKY_UNDEFINED_13, ++ * - LEAKY_UNDEFINED_14, ++ * - LEAKY_UNDEFINED_15, ++ * - LEAKY_UNDEFINED_16, ++ * - LEAKY_UNDEFINED_17, ++ * - LEAKY_UNDEFINED_18, ++ * - LEAKY_UNDEFINED_19, ++ * - LEAKY_UNDEFINED_1A, ++ * - LEAKY_UNDEFINED_1B, ++ * - LEAKY_UNDEFINED_1C, ++ * - LEAKY_UNDEFINED_1D, ++ * - LEAKY_UNDEFINED_1E, ++ * - LEAKY_UNDEFINED_1F, ++ * - LEAKY_GMRP, ++ * - LEAKY_GVRP, ++ * - LEAKY_UNDEF_GARP_22, ++ * - LEAKY_UNDEF_GARP_23, ++ * - LEAKY_UNDEF_GARP_24, ++ * - LEAKY_UNDEF_GARP_25, ++ * - LEAKY_UNDEF_GARP_26, ++ * - LEAKY_UNDEF_GARP_27, ++ * - LEAKY_UNDEF_GARP_28, ++ * - LEAKY_UNDEF_GARP_29, ++ * - LEAKY_UNDEF_GARP_2A, ++ * - LEAKY_UNDEF_GARP_2B, ++ * - LEAKY_UNDEF_GARP_2C, ++ * - LEAKY_UNDEF_GARP_2D, ++ * - LEAKY_UNDEF_GARP_2E, ++ * - LEAKY_UNDEF_GARP_2F, ++ * - LEAKY_IGMP, ++ * - LEAKY_IPMULTICAST. ++ * - LEAKY_CDP, ++ * - LEAKY_CSSTP, ++ * - LEAKY_LLDP. ++ */ ++rtk_api_ret_t rtk_leaky_portIsolation_get(rtk_leaky_type_t type, rtk_enable_t *pEnable) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 port, tmp; ++ rtl8367c_rma_t rmacfg; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (type >= LEAKY_END) ++ return RT_ERR_INPUT; ++ ++ if(NULL == pEnable) ++ return RT_ERR_NULL_POINTER; ++ ++ if (type >= 0 && type <= LEAKY_UNDEF_GARP_2F) ++ { ++ if ((retVal = rtl8367c_getAsicRma(type, &rmacfg)) != RT_ERR_OK) ++ return retVal; ++ ++ *pEnable = rmacfg.portiso_leaky; ++ ++ } ++ else if (LEAKY_IPMULTICAST == type) ++ { ++ for (port = 0; port < RTK_MAX_NUM_OF_PORT; port++) ++ { ++ if ((retVal = rtl8367c_getAsicIpMulticastPortIsoLeaky(port, &tmp)) != RT_ERR_OK) ++ return retVal; ++ if (port > 0 &&(tmp != *pEnable)) ++ return RT_ERR_FAILED; ++ *pEnable = tmp; ++ } ++ } ++ else if (LEAKY_IGMP == type) ++ { ++ if ((retVal = rtl8367c_getAsicIGMPIsoLeaky(&tmp)) != RT_ERR_OK) ++ return retVal; ++ ++ *pEnable = tmp; ++ } ++ else if (LEAKY_CDP == type) ++ { ++ if ((retVal = rtl8367c_getAsicRmaCdp(&rmacfg)) != RT_ERR_OK) ++ return retVal; ++ ++ *pEnable = rmacfg.portiso_leaky; ++ } ++ else if (LEAKY_CSSTP == type) ++ { ++ if ((retVal = rtl8367c_getAsicRmaCsstp(&rmacfg)) != RT_ERR_OK) ++ return retVal; ++ ++ *pEnable = rmacfg.portiso_leaky; ++ } ++ else if (LEAKY_LLDP == type) ++ { ++ if ((retVal = rtl8367c_getAsicRmaLldp(&tmp, &rmacfg)) != RT_ERR_OK) ++ return retVal; ++ ++ *pEnable = rmacfg.portiso_leaky; ++ } ++ ++ ++ return RT_ERR_OK; ++} +diff --git a/drivers/net/phy/rtk/rtl8367c/led.c b/drivers/net/phy/rtk/rtl8367c/led.c +new file mode 100644 +index 000000000000..02e0829dc6e6 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/led.c +@@ -0,0 +1,792 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ ++ * ++ * Purpose : RTK switch high-level API for RTL8367/RTL8367C ++ * Feature : Here is a list of all functions and variables in LED module. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++ ++/* Function Name: ++ * rtk_led_enable_set ++ * Description: ++ * Set Led enable configuration ++ * Input: ++ * group - LED group id. ++ * pPortmask - LED enable port mask. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_PORT_MASK - Error portmask ++ * Note: ++ * The API can be used to enable LED per port per group. ++ */ ++rtk_api_ret_t rtk_led_enable_set(rtk_led_group_t group, rtk_portmask_t *pPortmask) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 pmask; ++ rtk_port_t port; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (group >= LED_GROUP_END) ++ return RT_ERR_INPUT; ++ ++ RTK_CHK_PORTMASK_VALID(pPortmask); ++ ++ RTK_PORTMASK_SCAN((*pPortmask), port) ++ { ++ if(rtk_switch_isCPUPort(port) == RT_ERR_OK) ++ return RT_ERR_PORT_MASK; ++ } ++ ++ if((retVal = rtk_switch_portmask_L2P_get(pPortmask, &pmask)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicLedGroupEnable(group, pmask)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_led_enable_get ++ * Description: ++ * Get Led enable configuration ++ * Input: ++ * group - LED group id. ++ * Output: ++ * pPortmask - LED enable port mask. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can be used to get LED enable status. ++ */ ++rtk_api_ret_t rtk_led_enable_get(rtk_led_group_t group, rtk_portmask_t *pPortmask) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 pmask; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (group >= LED_GROUP_END) ++ return RT_ERR_INPUT; ++ ++ if ((retVal = rtl8367c_getAsicLedGroupEnable(group, &pmask)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtk_switch_portmask_P2L_get(pmask, pPortmask)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++ ++} ++ ++/* Function Name: ++ * rtk_led_operation_set ++ * Description: ++ * Set Led operation mode ++ * Input: ++ * mode - LED operation mode. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can set Led operation mode. ++ * The modes that can be set are as following: ++ * - LED_OP_SCAN, ++ * - LED_OP_PARALLEL, ++ * - LED_OP_SERIAL, ++ */ ++rtk_api_ret_t rtk_led_operation_set(rtk_led_operation_t mode) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 regData; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if ( mode >= LED_OP_END) ++ return RT_ERR_INPUT; ++ ++ switch (mode) ++ { ++ case LED_OP_PARALLEL: ++ regData = LEDOP_PARALLEL; ++ break; ++ case LED_OP_SERIAL: ++ regData = LEDOP_SERIAL; ++ break; ++ default: ++ return RT_ERR_CHIP_NOT_SUPPORTED; ++ break; ++ } ++ ++ if ((retVal = rtl8367c_setAsicLedOperationMode(regData)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_led_operation_get ++ * Description: ++ * Get Led operation mode ++ * Input: ++ * None ++ * Output: ++ * pMode - Support LED operation mode. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can get Led operation mode. ++ * The modes that can be set are as following: ++ * - LED_OP_SCAN, ++ * - LED_OP_PARALLEL, ++ * - LED_OP_SERIAL, ++ */ ++rtk_api_ret_t rtk_led_operation_get(rtk_led_operation_t *pMode) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 regData; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pMode) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicLedOperationMode(®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ if (regData == LEDOP_SERIAL) ++ *pMode = LED_OP_SERIAL; ++ else if (regData ==LEDOP_PARALLEL) ++ *pMode = LED_OP_PARALLEL; ++ else ++ return RT_ERR_FAILED; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_led_modeForce_set ++ * Description: ++ * Set Led group to configuration force mode ++ * Input: ++ * port - port ID ++ * group - Support LED group id. ++ * mode - Support LED force mode. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_PORT_ID - Error Port ID ++ * Note: ++ * The API can force to one force mode. ++ * The force modes that can be set are as following: ++ * - LED_FORCE_NORMAL, ++ * - LED_FORCE_BLINK, ++ * - LED_FORCE_OFF, ++ * - LED_FORCE_ON. ++ */ ++rtk_api_ret_t rtk_led_modeForce_set(rtk_port_t port, rtk_led_group_t group, rtk_led_force_mode_t mode) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ /* No LED for CPU port */ ++ if(rtk_switch_isCPUPort(port) == RT_ERR_OK) ++ return RT_ERR_PORT_ID; ++ ++ if (group >= LED_GROUP_END) ++ return RT_ERR_INPUT; ++ ++ if (mode >= LED_FORCE_END) ++ return RT_ERR_NOT_ALLOWED; ++ ++ if ((retVal = rtl8367c_setAsicForceLed(rtk_switch_port_L2P_get(port), group, mode)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_led_modeForce_get ++ * Description: ++ * Get Led group to configuration force mode ++ * Input: ++ * port - port ID ++ * group - Support LED group id. ++ * pMode - Support LED force mode. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_PORT_ID - Error Port ID ++ * Note: ++ * The API can get forced Led group mode. ++ * The force modes that can be set are as following: ++ * - LED_FORCE_NORMAL, ++ * - LED_FORCE_BLINK, ++ * - LED_FORCE_OFF, ++ * - LED_FORCE_ON. ++ */ ++rtk_api_ret_t rtk_led_modeForce_get(rtk_port_t port, rtk_led_group_t group, rtk_led_force_mode_t *pMode) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ /* No LED for CPU port */ ++ if(rtk_switch_isCPUPort(port) == RT_ERR_OK) ++ return RT_ERR_PORT_ID; ++ ++ if (group >= LED_GROUP_END) ++ return RT_ERR_INPUT; ++ ++ if (NULL == pMode) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicForceLed(rtk_switch_port_L2P_get(port), group, pMode)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_led_blinkRate_set ++ * Description: ++ * Set LED blinking rate ++ * Input: ++ * blinkRate - blinking rate. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * ASIC support 6 types of LED blinking rates at 43ms, 84ms, 120ms, 170ms, 340ms and 670ms. ++ */ ++rtk_api_ret_t rtk_led_blinkRate_set(rtk_led_blink_rate_t blinkRate) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (blinkRate >= LED_BLINKRATE_END) ++ return RT_ERR_FAILED; ++ ++ if ((retVal = rtl8367c_setAsicLedBlinkRate(blinkRate)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_led_blinkRate_get ++ * Description: ++ * Get LED blinking rate at mode 0 to mode 3 ++ * Input: ++ * None ++ * Output: ++ * pBlinkRate - blinking rate. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * There are 6 types of LED blinking rates at 43ms, 84ms, 120ms, 170ms, 340ms and 670ms. ++ */ ++rtk_api_ret_t rtk_led_blinkRate_get(rtk_led_blink_rate_t *pBlinkRate) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pBlinkRate) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicLedBlinkRate(pBlinkRate)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_led_groupConfig_set ++ * Description: ++ * Set per group Led to configuration mode ++ * Input: ++ * group - LED group. ++ * config - LED configuration ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can set LED indicated information configuration for each LED group with 1 to 1 led mapping to each port. ++ * - Definition LED Statuses Description ++ * - 0000 LED_Off LED pin Tri-State. ++ * - 0001 Dup/Col Collision, Full duplex Indicator. ++ * - 0010 Link/Act Link, Activity Indicator. ++ * - 0011 Spd1000 1000Mb/s Speed Indicator. ++ * - 0100 Spd100 100Mb/s Speed Indicator. ++ * - 0101 Spd10 10Mb/s Speed Indicator. ++ * - 0110 Spd1000/Act 1000Mb/s Speed/Activity Indicator. ++ * - 0111 Spd100/Act 100Mb/s Speed/Activity Indicator. ++ * - 1000 Spd10/Act 10Mb/s Speed/Activity Indicator. ++ * - 1001 Spd100 (10)/Act 10/100Mb/s Speed/Activity Indicator. ++ * - 1010 LoopDetect LoopDetect Indicator. ++ * - 1011 EEE EEE Indicator. ++ * - 1100 Link/Rx Link, Activity Indicator. ++ * - 1101 Link/Tx Link, Activity Indicator. ++ * - 1110 Master Link on Master Indicator. ++ * - 1111 Act Activity Indicator. Low for link established. ++ */ ++rtk_api_ret_t rtk_led_groupConfig_set(rtk_led_group_t group, rtk_led_congig_t config) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (LED_GROUP_END <= group) ++ return RT_ERR_FAILED; ++ ++ if (LED_CONFIG_END <= config) ++ return RT_ERR_FAILED; ++ ++ if ((retVal = rtl8367c_setAsicLedIndicateInfoConfig(group, config)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_led_groupConfig_get ++ * Description: ++ * Get Led group configuration mode ++ * Input: ++ * group - LED group. ++ * Output: ++ * pConfig - LED configuration. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can get LED indicated information configuration for each LED group. ++ */ ++rtk_api_ret_t rtk_led_groupConfig_get(rtk_led_group_t group, rtk_led_congig_t *pConfig) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (LED_GROUP_END <= group) ++ return RT_ERR_FAILED; ++ ++ if(NULL == pConfig) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicLedIndicateInfoConfig(group, pConfig)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_led_groupAbility_set ++ * Description: ++ * Configure per group Led ability ++ * Input: ++ * group - LED group. ++ * pAbility - LED ability ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * None. ++ */ ++ ++rtk_api_ret_t rtk_led_groupAbility_set(rtk_led_group_t group, rtk_led_ability_t *pAbility) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 regData; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (LED_GROUP_END <= group) ++ return RT_ERR_FAILED; ++ ++ if(pAbility == NULL) ++ return RT_ERR_NULL_POINTER; ++ ++ if( (pAbility->link_10m >= RTK_ENABLE_END) || (pAbility->link_100m >= RTK_ENABLE_END)|| ++ (pAbility->link_500m >= RTK_ENABLE_END) || (pAbility->link_1000m >= RTK_ENABLE_END)|| ++ (pAbility->act_rx >= RTK_ENABLE_END) || (pAbility->act_tx >= RTK_ENABLE_END) ) ++ { ++ return RT_ERR_INPUT; ++ } ++ ++ if ((retVal = rtl8367c_getAsicReg(RTL8367C_REG_LED0_DATA_CTRL + (rtk_uint32)group, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ if(pAbility->link_10m == ENABLED) ++ regData |= 0x0001; ++ else ++ regData &= ~0x0001; ++ ++ if(pAbility->link_100m == ENABLED) ++ regData |= 0x0002; ++ else ++ regData &= ~0x0002; ++ ++ if(pAbility->link_500m == ENABLED) ++ regData |= 0x0004; ++ else ++ regData &= ~0x0004; ++ ++ if(pAbility->link_1000m == ENABLED) ++ regData |= 0x0008; ++ else ++ regData &= ~0x0008; ++ ++ if(pAbility->act_rx == ENABLED) ++ regData |= 0x0010; ++ else ++ regData &= ~0x0010; ++ ++ if(pAbility->act_tx == ENABLED) ++ regData |= 0x0020; ++ else ++ regData &= ~0x0020; ++ ++ regData |= (0x0001 << 6); ++ ++ if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_LED0_DATA_CTRL + (rtk_uint32)group, regData)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_led_groupAbility_get ++ * Description: ++ * Get per group Led ability ++ * Input: ++ * group - LED group. ++ * pAbility - LED ability ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * None. ++ */ ++ ++rtk_api_ret_t rtk_led_groupAbility_get(rtk_led_group_t group, rtk_led_ability_t *pAbility) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 regData; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (LED_GROUP_END <= group) ++ return RT_ERR_FAILED; ++ ++ if(pAbility == NULL) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicReg(RTL8367C_REG_LED0_DATA_CTRL + (rtk_uint32)group, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ pAbility->link_10m = (regData & 0x0001) ? ENABLED : DISABLED; ++ pAbility->link_100m = (regData & 0x0002) ? ENABLED : DISABLED; ++ pAbility->link_500m = (regData & 0x0004) ? ENABLED : DISABLED; ++ pAbility->link_1000m = (regData & 0x0008) ? ENABLED : DISABLED; ++ pAbility->act_rx = (regData & 0x0010) ? ENABLED : DISABLED; ++ pAbility->act_tx = (regData & 0x0020) ? ENABLED : DISABLED; ++ ++ return RT_ERR_OK; ++} ++ ++ ++/* Function Name: ++ * rtk_led_serialMode_set ++ * Description: ++ * Set Led serial mode active configuration ++ * Input: ++ * active - LED group. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can set LED serial mode active configuration. ++ */ ++rtk_api_ret_t rtk_led_serialMode_set(rtk_led_active_t active) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if ( active >= LED_ACTIVE_END) ++ return RT_ERR_INPUT; ++ ++ if ((retVal = rtl8367c_setAsicLedSerialModeConfig(active,1))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_led_serialMode_get ++ * Description: ++ * Get Led group congiuration mode ++ * Input: ++ * group - LED group. ++ * Output: ++ * pConfig - LED configuration. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can get LED serial mode active configuration. ++ */ ++rtk_api_ret_t rtk_led_serialMode_get(rtk_led_active_t *pActive) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 regData; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pActive) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicLedSerialModeConfig(pActive,®Data))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_led_OutputEnable_set ++ * Description: ++ * This API set LED I/O state. ++ * Input: ++ * enabled - LED I/O state ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Error parameter ++ * Note: ++ * This API set LED I/O state. ++ */ ++rtk_api_ret_t rtk_led_OutputEnable_set(rtk_enable_t state) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (state >= RTK_ENABLE_END) ++ return RT_ERR_INPUT; ++ ++ if ((retVal = rtl8367c_setAsicLedOutputEnable(state))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_led_OutputEnable_get ++ * Description: ++ * This API get LED I/O state. ++ * Input: ++ * None. ++ * Output: ++ * pEnabled - LED I/O state ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Error parameter ++ * Note: ++ * This API set current LED I/O state. ++ */ ++rtk_api_ret_t rtk_led_OutputEnable_get(rtk_enable_t *pState) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(pState == NULL) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicLedOutputEnable(pState))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++ ++} ++ ++/* Function Name: ++ * rtk_led_serialModePortmask_set ++ * Description: ++ * This API configure Serial LED output Group and portmask ++ * Input: ++ * output - output group ++ * pPortmask - output portmask ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Error parameter ++ * Note: ++ * None. ++ */ ++rtk_api_ret_t rtk_led_serialModePortmask_set(rtk_led_serialOutput_t output, rtk_portmask_t *pPortmask) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 pmask; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(output >= SERIAL_LED_END) ++ return RT_ERR_INPUT; ++ ++ if(pPortmask == NULL) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtk_switch_portmask_L2P_get(pPortmask, &pmask)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicLedSerialOutput((rtk_uint32)output, pmask))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_led_serialModePortmask_get ++ * Description: ++ * This API get Serial LED output Group and portmask ++ * Input: ++ * None. ++ * Output: ++ * pOutput - output group ++ * pPortmask - output portmask ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Error parameter ++ * Note: ++ * None. ++ */ ++rtk_api_ret_t rtk_led_serialModePortmask_get(rtk_led_serialOutput_t *pOutput, rtk_portmask_t *pPortmask) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 pmask; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(pOutput == NULL) ++ return RT_ERR_NULL_POINTER; ++ ++ if(pPortmask == NULL) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicLedSerialOutput((rtk_uint32 *)pOutput, &pmask))!=RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtk_switch_portmask_P2L_get(pmask, pPortmask)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/mirror.c b/drivers/net/phy/rtk/rtl8367c/mirror.c +new file mode 100644 +index 000000000000..3bbad8adb65d +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/mirror.c +@@ -0,0 +1,548 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ ++ * ++ * Purpose : RTK switch high-level API for RTL8367/RTL8367C ++ * Feature : Here is a list of all functions and variables in Mirror module. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Function Name: ++ * rtk_mirror_portBased_set ++ * Description: ++ * Set port mirror function. ++ * Input: ++ * mirroring_port - Monitor port. ++ * pMirrored_rx_portmask - Rx mirror port mask. ++ * pMirrored_tx_portmask - Tx mirror port mask. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * RT_ERR_PORT_MASK - Invalid portmask. ++ * Note: ++ * The API is to set mirror function of source port and mirror port. ++ * The mirror port can only be set to one port and the TX and RX mirror ports ++ * should be identical. ++ */ ++rtk_api_ret_t rtk_mirror_portBased_set(rtk_port_t mirroring_port, rtk_portmask_t *pMirrored_rx_portmask, rtk_portmask_t *pMirrored_tx_portmask) ++{ ++ rtk_api_ret_t retVal; ++ rtk_enable_t mirRx, mirTx; ++ rtk_uint32 i, pmask; ++ rtk_port_t source_port; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check port valid */ ++ RTK_CHK_PORT_VALID(mirroring_port); ++ ++ if(NULL == pMirrored_rx_portmask) ++ return RT_ERR_NULL_POINTER; ++ ++ if(NULL == pMirrored_tx_portmask) ++ return RT_ERR_NULL_POINTER; ++ ++ RTK_CHK_PORTMASK_VALID(pMirrored_rx_portmask); ++ ++ RTK_CHK_PORTMASK_VALID(pMirrored_tx_portmask); ++ ++ /*Mirror Source Port Mask Check*/ ++ if (pMirrored_tx_portmask->bits[0]!=pMirrored_rx_portmask->bits[0]&&pMirrored_tx_portmask->bits[0]!=0&&pMirrored_rx_portmask->bits[0]!=0) ++ return RT_ERR_PORT_MASK; ++ ++ /*mirror port != source port*/ ++ if(RTK_PORTMASK_IS_PORT_SET((*pMirrored_tx_portmask), mirroring_port) || RTK_PORTMASK_IS_PORT_SET((*pMirrored_rx_portmask), mirroring_port)) ++ return RT_ERR_PORT_MASK; ++ ++ source_port = rtk_switch_maxLogicalPort_get(); ++ ++ RTK_SCAN_ALL_LOG_PORT(i) ++ { ++ if (pMirrored_tx_portmask->bits[0]&(1<bits[0]&(1<bits[0] != 0) ++ { ++ if ((retVal = rtk_switch_portmask_L2P_get(pMirrored_rx_portmask, &pmask)) != RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicPortMirrorMask(pmask)) != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ { ++ if ((retVal = rtk_switch_portmask_L2P_get(pMirrored_tx_portmask, &pmask)) != RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicPortMirrorMask(pmask)) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ ++ if (pMirrored_rx_portmask->bits[0]) ++ mirRx = ENABLED; ++ else ++ mirRx = DISABLED; ++ ++ if ((retVal = rtl8367c_setAsicPortMirrorRxFunction(mirRx)) != RT_ERR_OK) ++ return retVal; ++ ++ if (pMirrored_tx_portmask->bits[0]) ++ mirTx = ENABLED; ++ else ++ mirTx = DISABLED; ++ ++ if ((retVal = rtl8367c_setAsicPortMirrorTxFunction(mirTx)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++ ++} ++ ++/* Function Name: ++ * rtk_mirror_portBased_get ++ * Description: ++ * Get port mirror function. ++ * Input: ++ * None ++ * Output: ++ * pMirroring_port - Monitor port. ++ * pMirrored_rx_portmask - Rx mirror port mask. ++ * pMirrored_tx_portmask - Tx mirror port mask. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API is to get mirror function of source port and mirror port. ++ */ ++rtk_api_ret_t rtk_mirror_portBased_get(rtk_port_t *pMirroring_port, rtk_portmask_t *pMirrored_rx_portmask, rtk_portmask_t *pMirrored_tx_portmask) ++{ ++ rtk_api_ret_t retVal; ++ rtk_port_t source_port; ++ rtk_enable_t mirRx, mirTx; ++ rtk_uint32 sport, mport, pmask; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pMirrored_rx_portmask) ++ return RT_ERR_NULL_POINTER; ++ ++ if(NULL == pMirrored_tx_portmask) ++ return RT_ERR_NULL_POINTER; ++ ++ if(NULL == pMirroring_port) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicPortMirror(&sport, &mport)) != RT_ERR_OK) ++ return retVal; ++ source_port = rtk_switch_port_P2L_get(sport); ++ *pMirroring_port = rtk_switch_port_P2L_get(mport); ++ ++ if ((retVal = rtl8367c_getAsicPortMirrorRxFunction((rtk_uint32*)&mirRx)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_getAsicPortMirrorTxFunction((rtk_uint32*)&mirTx)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_getAsicPortMirrorMask(&pmask)) != RT_ERR_OK) ++ return retVal; ++ ++ if (DISABLED == mirRx) ++ pMirrored_rx_portmask->bits[0]=0; ++ else ++ { ++ if ((retVal = rtk_switch_portmask_P2L_get(pmask, pMirrored_rx_portmask)) != RT_ERR_OK) ++ return retVal; ++ pMirrored_rx_portmask->bits[0] |= 1<bits[0]=0; ++ else ++ { ++ if ((retVal = rtk_switch_portmask_P2L_get(pmask, pMirrored_tx_portmask)) != RT_ERR_OK) ++ return retVal; ++ pMirrored_tx_portmask->bits[0] |= 1<= RTK_ENABLE_END) ++ return RT_ERR_ENABLE; ++ ++ if ((retVal = rtl8367c_setAsicPortMirrorIsolation(enable)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_mirror_portIso_get ++ * Description: ++ * Get mirror port isolation. ++ * Input: ++ * None ++ * Output: ++ * pEnable |Mirror isolation status. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API is to get mirror isolation status. ++ */ ++rtk_api_ret_t rtk_mirror_portIso_get(rtk_enable_t *pEnable) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pEnable) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicPortMirrorIsolation(pEnable)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_mirror_vlanLeaky_set ++ * Description: ++ * Set mirror VLAN leaky. ++ * Input: ++ * txenable -TX leaky enable. ++ * rxenable - RX leaky enable. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_ENABLE - Invalid enable input ++ * Note: ++ * The API is to set mirror VLAN leaky function forwarding packets to miror port. ++ */ ++rtk_api_ret_t rtk_mirror_vlanLeaky_set(rtk_enable_t txenable, rtk_enable_t rxenable) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if ((txenable >= RTK_ENABLE_END) ||(rxenable >= RTK_ENABLE_END)) ++ return RT_ERR_ENABLE; ++ ++ if ((retVal = rtl8367c_setAsicPortMirrorVlanTxLeaky(txenable)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicPortMirrorVlanRxLeaky(rxenable)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_mirror_vlanLeaky_get ++ * Description: ++ * Get mirror VLAN leaky. ++ * Input: ++ * None ++ * Output: ++ * pTxenable - TX leaky enable. ++ * pRxenable - RX leaky enable. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API is to get mirror VLAN leaky status. ++ */ ++rtk_api_ret_t rtk_mirror_vlanLeaky_get(rtk_enable_t *pTxenable, rtk_enable_t *pRxenable) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if( (NULL == pTxenable) || (NULL == pRxenable) ) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicPortMirrorVlanTxLeaky(pTxenable)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_getAsicPortMirrorVlanRxLeaky(pRxenable)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_mirror_isolationLeaky_set ++ * Description: ++ * Set mirror Isolation leaky. ++ * Input: ++ * txenable -TX leaky enable. ++ * rxenable - RX leaky enable. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_ENABLE - Invalid enable input ++ * Note: ++ * The API is to set mirror VLAN leaky function forwarding packets to mirror port. ++ */ ++rtk_api_ret_t rtk_mirror_isolationLeaky_set(rtk_enable_t txenable, rtk_enable_t rxenable) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if ((txenable >= RTK_ENABLE_END) ||(rxenable >= RTK_ENABLE_END)) ++ return RT_ERR_ENABLE; ++ ++ if ((retVal = rtl8367c_setAsicPortMirrorIsolationTxLeaky(txenable)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicPortMirrorIsolationRxLeaky(rxenable)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_mirror_isolationLeaky_get ++ * Description: ++ * Get mirror isolation leaky. ++ * Input: ++ * None ++ * Output: ++ * pTxenable - TX leaky enable. ++ * pRxenable - RX leaky enable. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API is to get mirror isolation leaky status. ++ */ ++rtk_api_ret_t rtk_mirror_isolationLeaky_get(rtk_enable_t *pTxenable, rtk_enable_t *pRxenable) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if( (NULL == pTxenable) || (NULL == pRxenable) ) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicPortMirrorIsolationTxLeaky(pTxenable)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_getAsicPortMirrorIsolationRxLeaky(pRxenable)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_mirror_keep_set ++ * Description: ++ * Set mirror packet format keep. ++ * Input: ++ * mode - -mirror keep mode. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_ENABLE - Invalid enable input ++ * Note: ++ * The API is to set -mirror keep mode. ++ * The mirror keep mode is as following: ++ * - MIRROR_FOLLOW_VLAN ++ * - MIRROR_KEEP_ORIGINAL ++ * - MIRROR_KEEP_END ++ */ ++rtk_api_ret_t rtk_mirror_keep_set(rtk_mirror_keep_t mode) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (mode >= MIRROR_KEEP_END) ++ return RT_ERR_ENABLE; ++ ++ if ((retVal = rtl8367c_setAsicPortMirrorRealKeep(mode)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_mirror_keep_get ++ * Description: ++ * Get mirror packet format keep. ++ * Input: ++ * None ++ * Output: ++ * pMode -mirror keep mode. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API is to get mirror keep mode. ++ * The mirror keep mode is as following: ++ * - MIRROR_FOLLOW_VLAN ++ * - MIRROR_KEEP_ORIGINAL ++ * - MIRROR_KEEP_END ++ */ ++rtk_api_ret_t rtk_mirror_keep_get(rtk_mirror_keep_t *pMode) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pMode) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicPortMirrorRealKeep(pMode)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_mirror_override_set ++ * Description: ++ * Set port mirror override function. ++ * Input: ++ * rxMirror - 1: output mirrored packet, 0: output normal forward packet ++ * txMirror - 1: output mirrored packet, 0: output normal forward packet ++ * aclMirror - 1: output mirrored packet, 0: output normal forward packet ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * The API is to set mirror override function. ++ * This function control the output format when a port output ++ * normal forward & mirrored packet at the same time. ++ */ ++rtk_api_ret_t rtk_mirror_override_set(rtk_enable_t rxMirror, rtk_enable_t txMirror, rtk_enable_t aclMirror) ++{ ++ rtk_api_ret_t retVal; ++ ++ if( (rxMirror >= RTK_ENABLE_END) || (txMirror >= RTK_ENABLE_END) || (aclMirror >= RTK_ENABLE_END)) ++ return RT_ERR_ENABLE; ++ ++ if ((retVal = rtl8367c_setAsicPortMirrorOverride((rtk_uint32)rxMirror, (rtk_uint32)txMirror, (rtk_uint32)aclMirror)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_mirror_override_get ++ * Description: ++ * Get port mirror override function. ++ * Input: ++ * None ++ * Output: ++ * pRxMirror - 1: output mirrored packet, 0: output normal forward packet ++ * pTxMirror - 1: output mirrored packet, 0: output normal forward packet ++ * pAclMirror - 1: output mirrored packet, 0: output normal forward packet ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_NULL_POINTER - Null Pointer ++ * Note: ++ * The API is to Get mirror override function. ++ * This function control the output format when a port output ++ * normal forward & mirrored packet at the same time. ++ */ ++rtk_api_ret_t rtk_mirror_override_get(rtk_enable_t *pRxMirror, rtk_enable_t *pTxMirror, rtk_enable_t *pAclMirror) ++{ ++ rtk_api_ret_t retVal; ++ ++ if( (pRxMirror == NULL) || (pTxMirror == NULL) || (pAclMirror == NULL)) ++ return RT_ERR_ENABLE; ++ ++ if ((retVal = rtl8367c_getAsicPortMirrorOverride((rtk_uint32 *)pRxMirror, (rtk_uint32 *)pTxMirror, (rtk_uint32 *)pAclMirror)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} +diff --git a/drivers/net/phy/rtk/rtl8367c/oam.c b/drivers/net/phy/rtk/rtl8367c/oam.c +new file mode 100644 +index 000000000000..dc1559ae3ef8 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/oam.c +@@ -0,0 +1,245 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ ++ * ++ * Purpose : RTK switch high-level API for RTL8367/RTL8367C ++ * Feature : Here is a list of all functions and variables in OAM(802.3ah) module. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++ ++/* Module Name : OAM */ ++ ++/* Function Name: ++ * rtk_oam_init ++ * Description: ++ * Initialize oam module. ++ * Input: ++ * None ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * Note: ++ * Must initialize oam module before calling any oam APIs. ++ */ ++rtk_api_ret_t rtk_oam_init(void) ++{ ++ return RT_ERR_OK; ++} /* end of rtk_oam_init */ ++ ++ ++/* Function Name: ++ * rtk_oam_state_set ++ * Description: ++ * This API set OAM state. ++ * Input: ++ * enabled -OAMstate ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Error parameter ++ * Note: ++ * This API set OAM state. ++ */ ++rtk_api_ret_t rtk_oam_state_set(rtk_enable_t enabled) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (enabled >= RTK_ENABLE_END) ++ return RT_ERR_INPUT; ++ ++ if ((retVal = rtl8367c_setAsicOamEnable(enabled))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_oam_state_get ++ * Description: ++ * This API get OAM state. ++ * Input: ++ * None. ++ * Output: ++ * pEnabled - H/W IGMP state ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Error parameter ++ * Note: ++ * This API set current OAM state. ++ */ ++rtk_api_ret_t rtk_oam_state_get(rtk_enable_t *pEnabled) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if ((retVal = rtl8367c_getAsicOamEnable(pEnabled))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++ ++ ++/* Function Name: ++ * rtk_oam_parserAction_set ++ * Description: ++ * Set OAM parser action ++ * Input: ++ * port - port id ++ * action - parser action ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_PORT_ID - invalid port id ++ * Note: ++ * None ++ */ ++rtk_api_ret_t rtk_oam_parserAction_set(rtk_port_t port, rtk_oam_parser_act_t action) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if (action >= OAM_PARSER_ACTION_END) ++ return RT_ERR_INPUT; ++ ++ if ((retVal = rtl8367c_setAsicOamParser(rtk_switch_port_L2P_get(port), action))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_oam_parserAction_set ++ * Description: ++ * Get OAM parser action ++ * Input: ++ * port - port id ++ * Output: ++ * pAction - parser action ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_PORT_ID - invalid port id ++ * Note: ++ * None ++ */ ++rtk_api_ret_t rtk_oam_parserAction_get(rtk_port_t port, rtk_oam_parser_act_t *pAction) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if ((retVal = rtl8367c_getAsicOamParser(rtk_switch_port_L2P_get(port), pAction))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++ ++/* Function Name: ++ * rtk_oam_multiplexerAction_set ++ * Description: ++ * Set OAM multiplexer action ++ * Input: ++ * port - port id ++ * action - parser action ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_PORT_ID - invalid port id ++ * Note: ++ * None ++ */ ++rtk_api_ret_t rtk_oam_multiplexerAction_set(rtk_port_t port, rtk_oam_multiplexer_act_t action) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if (action >= OAM_MULTIPLEXER_ACTION_END) ++ return RT_ERR_INPUT; ++ ++ if ((retVal = rtl8367c_setAsicOamMultiplexer(rtk_switch_port_L2P_get(port), action))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_oam_parserAction_set ++ * Description: ++ * Get OAM multiplexer action ++ * Input: ++ * port - port id ++ * Output: ++ * pAction - parser action ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_PORT_ID - invalid port id ++ * Note: ++ * None ++ */ ++rtk_api_ret_t rtk_oam_multiplexerAction_get(rtk_port_t port, rtk_oam_multiplexer_act_t *pAction) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if ((retVal = rtl8367c_getAsicOamMultiplexer(rtk_switch_port_L2P_get(port), pAction))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/port.c b/drivers/net/phy/rtk/rtl8367c/port.c +new file mode 100644 +index 000000000000..9c7bcd0e38a1 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/port.c +@@ -0,0 +1,2467 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ ++ * ++ * Purpose : RTK switch high-level API for RTL8367/RTL8367C ++ * Feature : Here is a list of all functions and variables in Port module. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#define FIBER_INIT_SIZE 1507 ++CONST_T rtk_uint8 Fiber[FIBER_INIT_SIZE] = { ++0x02,0x04,0x41,0xE4,0xF5,0xA8,0xD2,0xAF, ++0x22,0x00,0x00,0x02,0x05,0x2D,0xE4,0x90, ++0x06,0x2A,0xF0,0xFD,0x7C,0x01,0x7F,0x3F, ++0x7E,0x1D,0x12,0x05,0xAF,0x7D,0x40,0x12, ++0x02,0x5F,0xE4,0xFF,0xFE,0xFD,0x80,0x08, ++0x12,0x05,0x9E,0x50,0x0C,0x12,0x05,0x8B, ++0xFC,0x90,0x06,0x24,0x12,0x03,0x76,0x80, ++0xEF,0xE4,0xF5,0xA8,0xD2,0xAF,0x7D,0x1F, ++0xFC,0x7F,0x49,0x7E,0x13,0x12,0x05,0xAF, ++0x12,0x05,0xD6,0x7D,0xD7,0x12,0x02,0x1E, ++0x7D,0x80,0x12,0x01,0xCA,0x7D,0x94,0x7C, ++0xF9,0x12,0x02,0x3B,0x7D,0x81,0x12,0x01, ++0xCA,0x7D,0xA2,0x7C,0x31,0x12,0x02,0x3B, ++0x7D,0x82,0x12,0x01,0xDF,0x7D,0x60,0x7C, ++0x69,0x12,0x02,0x43,0x7D,0x83,0x12,0x01, ++0xDF,0x7D,0x28,0x7C,0x97,0x12,0x02,0x43, ++0x7D,0x84,0x12,0x01,0xF4,0x7D,0x85,0x7C, ++0x9D,0x12,0x02,0x57,0x7D,0x23,0x12,0x01, ++0xF4,0x7D,0x10,0x7C,0xD8,0x12,0x02,0x57, ++0x7D,0x24,0x7C,0x04,0x12,0x02,0x28,0x7D, ++0x00,0x12,0x02,0x1E,0x7D,0x2F,0x12,0x02, ++0x09,0x7D,0x20,0x7C,0x0F,0x7F,0x02,0x7E, ++0x66,0x12,0x05,0xAF,0x7D,0x01,0x12,0x02, ++0x09,0x7D,0x04,0x7C,0x00,0x7F,0x01,0x7E, ++0x66,0x12,0x05,0xAF,0x7D,0x80,0x7C,0x00, ++0x7F,0x00,0x7E,0x66,0x12,0x05,0xAF,0x7F, ++0x02,0x7E,0x66,0x12,0x02,0x4B,0x44,0x02, ++0xFF,0x90,0x06,0x28,0xEE,0xF0,0xA3,0xEF, ++0xF0,0x44,0x04,0xFF,0x90,0x06,0x28,0xEE, ++0xF0,0xFC,0xA3,0xEF,0xF0,0xFD,0x7F,0x02, ++0x7E,0x66,0x12,0x05,0xAF,0x7D,0x04,0x7C, ++0x00,0x12,0x02,0x28,0x7D,0xB9,0x7C,0x15, ++0x7F,0xEB,0x7E,0x13,0x12,0x05,0xAF,0x7D, ++0x07,0x7C,0x00,0x7F,0xE7,0x7E,0x13,0x12, ++0x05,0xAF,0x7D,0x40,0x7C,0x11,0x7F,0x00, ++0x7E,0x62,0x12,0x05,0xAF,0x12,0x03,0x82, ++0x7D,0x41,0x12,0x02,0x5F,0xE4,0xFF,0xFE, ++0xFD,0x80,0x08,0x12,0x05,0x9E,0x50,0x0C, ++0x12,0x05,0x8B,0xFC,0x90,0x06,0x24,0x12, ++0x03,0x76,0x80,0xEF,0xC2,0x00,0xC2,0x01, ++0xD2,0xA9,0xD2,0x8C,0x7F,0x01,0x7E,0x62, ++0x12,0x02,0x4B,0x30,0xE2,0x05,0xE4,0xA3, ++0xF0,0x80,0xF1,0x90,0x06,0x2A,0xE0,0x70, ++0x12,0x12,0x01,0x89,0x90,0x06,0x2A,0x74, ++0x01,0xF0,0xE4,0x90,0x06,0x2D,0xF0,0xA3, ++0xF0,0x80,0xD9,0xC3,0x90,0x06,0x2E,0xE0, ++0x94,0x64,0x90,0x06,0x2D,0xE0,0x94,0x00, ++0x40,0xCA,0xE4,0xF0,0xA3,0xF0,0x12,0x01, ++0x89,0x90,0x06,0x2A,0x74,0x01,0xF0,0x80, ++0xBB,0x7D,0x04,0xFC,0x7F,0x02,0x7E,0x66, ++0x12,0x05,0xAF,0x7D,0x00,0x7C,0x04,0x7F, ++0x01,0x7E,0x66,0x12,0x05,0xAF,0x7D,0xC0, ++0x7C,0x00,0x7F,0x00,0x7E,0x66,0x12,0x05, ++0xAF,0xE4,0xFD,0xFC,0x7F,0x02,0x7E,0x66, ++0x12,0x05,0xAF,0x7D,0x00,0x7C,0x04,0x7F, ++0x01,0x7E,0x66,0x12,0x05,0xAF,0x7D,0xC0, ++0x7C,0x00,0x7F,0x00,0x7E,0x66,0x12,0x05, ++0xAF,0x22,0x7C,0x04,0x7F,0x01,0x7E,0x66, ++0x12,0x05,0xAF,0x7D,0xC0,0x7C,0x00,0x7F, ++0x00,0x7E,0x66,0x12,0x05,0xAF,0x22,0x7C, ++0x04,0x7F,0x01,0x7E,0x66,0x12,0x05,0xAF, ++0x7D,0xC0,0x7C,0x00,0x7F,0x00,0x7E,0x66, ++0x12,0x05,0xAF,0x22,0x7C,0x04,0x7F,0x01, ++0x7E,0x66,0x12,0x05,0xAF,0x7D,0xC0,0x7C, ++0x00,0x7F,0x00,0x7E,0x66,0x12,0x05,0xAF, ++0x22,0x7C,0x00,0x7F,0x01,0x7E,0x66,0x12, ++0x05,0xAF,0x7D,0xC0,0x7C,0x00,0x7F,0x00, ++0x7E,0x66,0x12,0x05,0xAF,0x22,0x7C,0x04, ++0x7F,0x02,0x7E,0x66,0x12,0x05,0xAF,0x22, ++0x7F,0x01,0x7E,0x66,0x12,0x05,0xAF,0x7D, ++0xC0,0x7C,0x00,0x7F,0x00,0x7E,0x66,0x12, ++0x05,0xAF,0x22,0x7F,0x02,0x7E,0x66,0x12, ++0x05,0xAF,0x22,0x7F,0x02,0x7E,0x66,0x12, ++0x05,0xAF,0x22,0x12,0x05,0x67,0x90,0x06, ++0x28,0xEE,0xF0,0xA3,0xEF,0xF0,0x22,0x7F, ++0x02,0x7E,0x66,0x12,0x05,0xAF,0x22,0x7C, ++0x00,0x7F,0x36,0x7E,0x13,0x12,0x05,0xAF, ++0x22,0xC5,0xF0,0xF8,0xA3,0xE0,0x28,0xF0, ++0xC5,0xF0,0xF8,0xE5,0x82,0x15,0x82,0x70, ++0x02,0x15,0x83,0xE0,0x38,0xF0,0x22,0x75, ++0xF0,0x08,0x75,0x82,0x00,0xEF,0x2F,0xFF, ++0xEE,0x33,0xFE,0xCD,0x33,0xCD,0xCC,0x33, ++0xCC,0xC5,0x82,0x33,0xC5,0x82,0x9B,0xED, ++0x9A,0xEC,0x99,0xE5,0x82,0x98,0x40,0x0C, ++0xF5,0x82,0xEE,0x9B,0xFE,0xED,0x9A,0xFD, ++0xEC,0x99,0xFC,0x0F,0xD5,0xF0,0xD6,0xE4, ++0xCE,0xFB,0xE4,0xCD,0xFA,0xE4,0xCC,0xF9, ++0xA8,0x82,0x22,0xB8,0x00,0xC1,0xB9,0x00, ++0x59,0xBA,0x00,0x2D,0xEC,0x8B,0xF0,0x84, ++0xCF,0xCE,0xCD,0xFC,0xE5,0xF0,0xCB,0xF9, ++0x78,0x18,0xEF,0x2F,0xFF,0xEE,0x33,0xFE, ++0xED,0x33,0xFD,0xEC,0x33,0xFC,0xEB,0x33, ++0xFB,0x10,0xD7,0x03,0x99,0x40,0x04,0xEB, ++0x99,0xFB,0x0F,0xD8,0xE5,0xE4,0xF9,0xFA, ++0x22,0x78,0x18,0xEF,0x2F,0xFF,0xEE,0x33, ++0xFE,0xED,0x33,0xFD,0xEC,0x33,0xFC,0xC9, ++0x33,0xC9,0x10,0xD7,0x05,0x9B,0xE9,0x9A, ++0x40,0x07,0xEC,0x9B,0xFC,0xE9,0x9A,0xF9, ++0x0F,0xD8,0xE0,0xE4,0xC9,0xFA,0xE4,0xCC, ++0xFB,0x22,0x75,0xF0,0x10,0xEF,0x2F,0xFF, ++0xEE,0x33,0xFE,0xED,0x33,0xFD,0xCC,0x33, ++0xCC,0xC8,0x33,0xC8,0x10,0xD7,0x07,0x9B, ++0xEC,0x9A,0xE8,0x99,0x40,0x0A,0xED,0x9B, ++0xFD,0xEC,0x9A,0xFC,0xE8,0x99,0xF8,0x0F, ++0xD5,0xF0,0xDA,0xE4,0xCD,0xFB,0xE4,0xCC, ++0xFA,0xE4,0xC8,0xF9,0x22,0xEB,0x9F,0xF5, ++0xF0,0xEA,0x9E,0x42,0xF0,0xE9,0x9D,0x42, ++0xF0,0xE8,0x9C,0x45,0xF0,0x22,0xE0,0xFC, ++0xA3,0xE0,0xFD,0xA3,0xE0,0xFE,0xA3,0xE0, ++0xFF,0x22,0xE0,0xF8,0xA3,0xE0,0xF9,0xA3, ++0xE0,0xFA,0xA3,0xE0,0xFB,0x22,0xEC,0xF0, ++0xA3,0xED,0xF0,0xA3,0xEE,0xF0,0xA3,0xEF, ++0xF0,0x22,0x12,0x03,0xF8,0x12,0x04,0x1A, ++0x44,0x40,0x12,0x04,0x0F,0x7D,0x03,0x7C, ++0x00,0x12,0x04,0x23,0x12,0x05,0xAF,0x12, ++0x03,0xF8,0x12,0x04,0x1A,0x54,0xBF,0x12, ++0x04,0x0F,0x7D,0x03,0x7C,0x00,0x12,0x03, ++0xD0,0x7F,0x02,0x7E,0x66,0x12,0x05,0x67, ++0xEF,0x54,0xFD,0x54,0xFE,0x12,0x04,0x33, ++0x12,0x03,0xD0,0x7F,0x02,0x7E,0x66,0x12, ++0x05,0x67,0xEF,0x44,0x02,0x44,0x01,0x12, ++0x04,0x33,0x12,0x04,0x23,0x02,0x05,0xAF, ++0x7F,0x01,0x7E,0x66,0x12,0x05,0xAF,0x7D, ++0xC0,0x7C,0x00,0x7F,0x00,0x7E,0x66,0x12, ++0x05,0xAF,0xE4,0xFD,0xFC,0x7F,0x01,0x7E, ++0x66,0x12,0x05,0xAF,0x7D,0x80,0x7C,0x00, ++0x7F,0x00,0x7E,0x66,0x12,0x05,0xAF,0x22, ++0x7D,0x03,0x7C,0x00,0x7F,0x01,0x7E,0x66, ++0x12,0x05,0xAF,0x7D,0x80,0x7C,0x00,0x7F, ++0x00,0x7E,0x66,0x12,0x05,0xAF,0x22,0xFD, ++0xAC,0x06,0x7F,0x02,0x7E,0x66,0x12,0x05, ++0xAF,0x22,0x7F,0x02,0x7E,0x66,0x12,0x05, ++0x67,0xEF,0x22,0x7F,0x01,0x7E,0x66,0x12, ++0x05,0xAF,0x7D,0xC0,0x7C,0x00,0x7F,0x00, ++0x7E,0x66,0x22,0xFD,0xAC,0x06,0x7F,0x02, ++0x7E,0x66,0x12,0x05,0xAF,0xE4,0xFD,0xFC, ++0x22,0x78,0x7F,0xE4,0xF6,0xD8,0xFD,0x75, ++0x81,0x3C,0x02,0x04,0x88,0x02,0x00,0x0E, ++0xE4,0x93,0xA3,0xF8,0xE4,0x93,0xA3,0x40, ++0x03,0xF6,0x80,0x01,0xF2,0x08,0xDF,0xF4, ++0x80,0x29,0xE4,0x93,0xA3,0xF8,0x54,0x07, ++0x24,0x0C,0xC8,0xC3,0x33,0xC4,0x54,0x0F, ++0x44,0x20,0xC8,0x83,0x40,0x04,0xF4,0x56, ++0x80,0x01,0x46,0xF6,0xDF,0xE4,0x80,0x0B, ++0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80, ++0x90,0x05,0xCB,0xE4,0x7E,0x01,0x93,0x60, ++0xBC,0xA3,0xFF,0x54,0x3F,0x30,0xE5,0x09, ++0x54,0x1F,0xFE,0xE4,0x93,0xA3,0x60,0x01, ++0x0E,0xCF,0x54,0xC0,0x25,0xE0,0x60,0xA8, ++0x40,0xB8,0xE4,0x93,0xA3,0xFA,0xE4,0x93, ++0xA3,0xF8,0xE4,0x93,0xA3,0xC8,0xC5,0x82, ++0xC8,0xCA,0xC5,0x83,0xCA,0xF0,0xA3,0xC8, ++0xC5,0x82,0xC8,0xCA,0xC5,0x83,0xCA,0xDF, ++0xE9,0xDE,0xE7,0x80,0xBE,0x75,0x0F,0x80, ++0x75,0x0E,0x7E,0x75,0x0D,0xAA,0x75,0x0C, ++0x83,0xE4,0xF5,0x10,0x75,0x0B,0xA0,0x75, ++0x0A,0xAC,0x75,0x09,0xB9,0x75,0x08,0x03, ++0x75,0x89,0x11,0x7B,0x60,0x7A,0x09,0xF9, ++0xF8,0xAF,0x0B,0xAE,0x0A,0xAD,0x09,0xAC, ++0x08,0x12,0x02,0xBB,0xAD,0x07,0xAC,0x06, ++0xC3,0xE4,0x9D,0xFD,0xE4,0x9C,0xFC,0x78, ++0x17,0xF6,0xAF,0x05,0xEF,0x08,0xF6,0x18, ++0xE6,0xF5,0x8C,0x08,0xE6,0xF5,0x8A,0x74, ++0x0D,0x2D,0xFD,0xE4,0x3C,0x18,0xF6,0xAF, ++0x05,0xEF,0x08,0xF6,0x75,0x88,0x10,0x53, ++0x8E,0xC7,0xD2,0xA9,0x22,0xC0,0xE0,0xC0, ++0xF0,0xC0,0x83,0xC0,0x82,0xC0,0xD0,0x75, ++0xD0,0x00,0xC0,0x00,0x78,0x17,0xE6,0xF5, ++0x8C,0x78,0x18,0xE6,0xF5,0x8A,0x90,0x06, ++0x2B,0xE4,0x75,0xF0,0x01,0x12,0x02,0x69, ++0x90,0x06,0x2D,0xE4,0x75,0xF0,0x01,0x12, ++0x02,0x69,0xD0,0x00,0xD0,0xD0,0xD0,0x82, ++0xD0,0x83,0xD0,0xF0,0xD0,0xE0,0x32,0xC2, ++0xAF,0xAD,0x07,0xAC,0x06,0x8C,0xA2,0x8D, ++0xA3,0x75,0xA0,0x01,0x00,0x00,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xAE, ++0xA1,0xBE,0x00,0xF0,0xAE,0xA6,0xAF,0xA7, ++0xD2,0xAF,0x22,0x90,0x06,0x24,0x12,0x03, ++0x5E,0xEF,0x24,0x01,0xFF,0xE4,0x3E,0xFE, ++0xE4,0x3D,0xFD,0xE4,0x3C,0x22,0xE4,0x7F, ++0x20,0x7E,0x4E,0xFD,0xFC,0x90,0x06,0x24, ++0x12,0x03,0x6A,0xC3,0x02,0x03,0x4D,0xC2, ++0xAF,0xAB,0x07,0xAA,0x06,0x8A,0xA2,0x8B, ++0xA3,0x8C,0xA4,0x8D,0xA5,0x75,0xA0,0x03, ++0x00,0x00,0x00,0xAA,0xA1,0xBA,0x00,0xF8, ++0xD2,0xAF,0x22,0x42,0x06,0x2D,0x00,0x00, ++0x42,0x06,0x2B,0x00,0x00,0x00,0x12,0x05, ++0xDF,0x12,0x04,0xCD,0x02,0x00,0x03,0xE4, ++0xF5,0x8E,0x22}; ++ ++static rtk_api_ret_t _rtk_port_FiberModeAbility_set(rtk_port_t port, rtk_port_phy_ability_t *pAbility) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 regData; ++ ++ /* Check Combo port or not */ ++ RTK_CHK_PORT_IS_COMBO(port); ++ ++ /* Flow Control */ ++ if ((retVal = rtl8367c_getAsicReg(RTL8367C_REG_FIB0_CFG04, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ if (pAbility->AsyFC == 1) ++ regData |= (0x0001 << 8); ++ else ++ regData &= ~(0x0001 << 8); ++ ++ if (pAbility->FC == 1) ++ regData |= (0x0001 << 7); ++ else ++ regData &= ~(0x0001 << 7); ++ ++ if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_FIB0_CFG04, regData)) != RT_ERR_OK) ++ return retVal; ++ ++ /* Speed ability */ ++ if( (pAbility->Full_1000 == 1) && (pAbility->Full_100 == 1) && (pAbility->AutoNegotiation == 1) ) ++ { ++ if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_FIBER_CFG_1, RTL8367C_SDS_FRC_MODE_OFFSET, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FIBER_CFG_1, RTL8367C_SDS_MODE_MASK, 7)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_FIB0_CFG00, 0x1140)) != RT_ERR_OK) ++ return retVal; ++ } ++ else if(pAbility->Full_1000 == 1) ++ { ++ if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_FIBER_CFG_1, RTL8367C_SDS_FRC_MODE_OFFSET, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FIBER_CFG_1, RTL8367C_SDS_MODE_MASK, 4)) != RT_ERR_OK) ++ return retVal; ++ ++ if(pAbility->AutoNegotiation == 1) ++ { ++ if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_FIB0_CFG00, 0x1140)) != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ { ++ if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_FIB0_CFG00, 0x0140)) != RT_ERR_OK) ++ return retVal; ++ } ++ } ++ else if(pAbility->Full_100 == 1) ++ { ++ if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_FIBER_CFG_1, RTL8367C_SDS_FRC_MODE_OFFSET, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FIBER_CFG_1, RTL8367C_SDS_MODE_MASK, 5)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_FIB0_CFG00, 0x2100)) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ /* Digital software reset */ ++ if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, 0x0003)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x0080)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_getAsicReg(RTL8367C_REG_SDS_INDACS_DATA, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ regData |= (0x0001 << 6); ++ ++ if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, regData)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, 0x0003)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK) ++ return retVal; ++ ++ regData &= ~(0x0001 << 6); ++ ++ if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, regData)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, 0x0003)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK) ++ return retVal; ++ ++ /* CDR reset */ ++ if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, 0x1401))!=RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, 0x0000))!=RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0))!=RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, 0x1403))!=RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, 0x0000))!=RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++static rtk_api_ret_t _rtk_port_FiberModeAbility_get(rtk_port_t port, rtk_port_phy_ability_t *pAbility) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 data, regData; ++ ++ /* Check Combo port or not */ ++ RTK_CHK_PORT_IS_COMBO(port); ++ ++ memset(pAbility, 0x00, sizeof(rtk_port_phy_ability_t)); ++ ++ /* Flow Control */ ++ if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_FIBER_CFG_1, RTL8367C_SDS_FRC_REG4_OFFSET, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_FIBER_CFG_1, RTL8367C_SDS_FRC_REG4_FIB100_OFFSET, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, 0x0044)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x0080)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_getAsicReg(RTL8367C_REG_SDS_INDACS_DATA, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ if(regData & (0x0001 << 8)) ++ pAbility->AsyFC = 1; ++ ++ if(regData & (0x0001 << 7)) ++ pAbility->FC = 1; ++ ++ /* Speed ability */ ++ if ((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_FIBER_CFG_1, RTL8367C_SDS_FRC_MODE_OFFSET, &data)) != RT_ERR_OK) ++ return retVal; ++ ++ if(data == 0) ++ { ++ pAbility->AutoNegotiation = 1; ++ pAbility->Full_1000 = 1; ++ pAbility->Full_100 = 1; ++ } ++ else ++ { ++ if ((retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FIBER_CFG_1, RTL8367C_SDS_MODE_MASK, &data)) != RT_ERR_OK) ++ return retVal; ++ ++ if(data == 4) ++ { ++ pAbility->Full_1000 = 1; ++ ++ if ((retVal = rtl8367c_getAsicReg(RTL8367C_REG_FIB0_CFG00, &data)) != RT_ERR_OK) ++ return retVal; ++ ++ if(data & 0x1000) ++ pAbility->AutoNegotiation = 1; ++ else ++ pAbility->AutoNegotiation = 0; ++ } ++ else if(data == 5) ++ pAbility->Full_100 = 1; ++ else ++ return RT_ERR_FAILED; ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_port_phyAutoNegoAbility_set ++ * Description: ++ * Set Ethernet PHY auto-negotiation desired ability. ++ * Input: ++ * port - port id. ++ * pAbility - Ability structure ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_PHY_REG_ID - Invalid PHY address ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy ++ * Note: ++ * If Full_1000 bit is set to 1, the AutoNegotiation will be automatic set to 1. While both AutoNegotiation and Full_1000 are set to 0, the PHY speed and duplex selection will ++ * be set as following 100F > 100H > 10F > 10H priority sequence. ++ */ ++rtk_api_ret_t rtk_port_phyAutoNegoAbility_set(rtk_port_t port, rtk_port_phy_ability_t *pAbility) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 phyData; ++ rtk_uint32 phyEnMsk0; ++ rtk_uint32 phyEnMsk4; ++ rtk_uint32 phyEnMsk9; ++ rtk_port_media_t media_type; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_IS_UTP(port); ++ ++ if(NULL == pAbility) ++ return RT_ERR_NULL_POINTER; ++ ++ if (pAbility->Half_10 >= RTK_ENABLE_END || pAbility->Full_10 >= RTK_ENABLE_END || ++ pAbility->Half_100 >= RTK_ENABLE_END || pAbility->Full_100 >= RTK_ENABLE_END || ++ pAbility->Full_1000 >= RTK_ENABLE_END || pAbility->AutoNegotiation >= RTK_ENABLE_END || ++ pAbility->AsyFC >= RTK_ENABLE_END || pAbility->FC >= RTK_ENABLE_END) ++ return RT_ERR_INPUT; ++ ++ if (rtk_switch_isComboPort(port) == RT_ERR_OK) ++ { ++ if ((retVal = rtk_port_phyComboPortMedia_get(port, &media_type)) != RT_ERR_OK) ++ return retVal; ++ ++ if(media_type == PORT_MEDIA_FIBER) ++ { ++ return _rtk_port_FiberModeAbility_set(port, pAbility); ++ } ++ } ++ ++ /*for PHY auto mode setup*/ ++ pAbility->AutoNegotiation = 1; ++ ++ phyEnMsk0 = 0; ++ phyEnMsk4 = 0; ++ phyEnMsk9 = 0; ++ ++ if (1 == pAbility->Half_10) ++ { ++ /*10BASE-TX half duplex capable in reg 4.5*/ ++ phyEnMsk4 = phyEnMsk4 | (1 << 5); ++ ++ /*Speed selection [1:0] */ ++ /* 11=Reserved*/ ++ /* 10= 1000Mpbs*/ ++ /* 01= 100Mpbs*/ ++ /* 00= 10Mpbs*/ ++ phyEnMsk0 = phyEnMsk0 & (~(1 << 6)); ++ phyEnMsk0 = phyEnMsk0 & (~(1 << 13)); ++ } ++ ++ if (1 == pAbility->Full_10) ++ { ++ /*10BASE-TX full duplex capable in reg 4.6*/ ++ phyEnMsk4 = phyEnMsk4 | (1 << 6); ++ /*Speed selection [1:0] */ ++ /* 11=Reserved*/ ++ /* 10= 1000Mpbs*/ ++ /* 01= 100Mpbs*/ ++ /* 00= 10Mpbs*/ ++ phyEnMsk0 = phyEnMsk0 & (~(1 << 6)); ++ phyEnMsk0 = phyEnMsk0 & (~(1 << 13)); ++ ++ /*Full duplex mode in reg 0.8*/ ++ phyEnMsk0 = phyEnMsk0 | (1 << 8); ++ ++ } ++ ++ if (1 == pAbility->Half_100) ++ { ++ /*100BASE-TX half duplex capable in reg 4.7*/ ++ phyEnMsk4 = phyEnMsk4 | (1 << 7); ++ /*Speed selection [1:0] */ ++ /* 11=Reserved*/ ++ /* 10= 1000Mpbs*/ ++ /* 01= 100Mpbs*/ ++ /* 00= 10Mpbs*/ ++ phyEnMsk0 = phyEnMsk0 & (~(1 << 6)); ++ phyEnMsk0 = phyEnMsk0 | (1 << 13); ++ } ++ ++ ++ if (1 == pAbility->Full_100) ++ { ++ /*100BASE-TX full duplex capable in reg 4.8*/ ++ phyEnMsk4 = phyEnMsk4 | (1 << 8); ++ /*Speed selection [1:0] */ ++ /* 11=Reserved*/ ++ /* 10= 1000Mpbs*/ ++ /* 01= 100Mpbs*/ ++ /* 00= 10Mpbs*/ ++ phyEnMsk0 = phyEnMsk0 & (~(1 << 6)); ++ phyEnMsk0 = phyEnMsk0 | (1 << 13); ++ /*Full duplex mode in reg 0.8*/ ++ phyEnMsk0 = phyEnMsk0 | (1 << 8); ++ } ++ ++ ++ if (1 == pAbility->Full_1000) ++ { ++ /*1000 BASE-T FULL duplex capable setting in reg 9.9*/ ++ phyEnMsk9 = phyEnMsk9 | (1 << 9); ++ ++ /*Speed selection [1:0] */ ++ /* 11=Reserved*/ ++ /* 10= 1000Mpbs*/ ++ /* 01= 100Mpbs*/ ++ /* 00= 10Mpbs*/ ++ phyEnMsk0 = phyEnMsk0 | (1 << 6); ++ phyEnMsk0 = phyEnMsk0 & (~(1 << 13)); ++ ++ ++ /*Auto-Negotiation setting in reg 0.12*/ ++ phyEnMsk0 = phyEnMsk0 | (1 << 12); ++ ++ } ++ ++ if (1 == pAbility->AutoNegotiation) ++ { ++ /*Auto-Negotiation setting in reg 0.12*/ ++ phyEnMsk0 = phyEnMsk0 | (1 << 12); ++ } ++ ++ if (1 == pAbility->AsyFC) ++ { ++ /*Asymetric flow control in reg 4.11*/ ++ phyEnMsk4 = phyEnMsk4 | (1 << 11); ++ } ++ if (1 == pAbility->FC) ++ { ++ /*Flow control in reg 4.10*/ ++ phyEnMsk4 = phyEnMsk4 | (1 << 10); ++ } ++ ++ /*1000 BASE-T control register setting*/ ++ if ((retVal = rtl8367c_getAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_1000_BASET_CONTROL_REG, &phyData)) != RT_ERR_OK) ++ return retVal; ++ ++ phyData = (phyData & (~0x0200)) | phyEnMsk9 ; ++ ++ if ((retVal = rtl8367c_setAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_1000_BASET_CONTROL_REG, phyData)) != RT_ERR_OK) ++ return retVal; ++ ++ /*Auto-Negotiation control register setting*/ ++ if ((retVal = rtl8367c_getAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_AN_ADVERTISEMENT_REG, &phyData)) != RT_ERR_OK) ++ return retVal; ++ ++ phyData = (phyData & (~0x0DE0)) | phyEnMsk4; ++ if ((retVal = rtl8367c_setAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_AN_ADVERTISEMENT_REG, phyData)) != RT_ERR_OK) ++ return retVal; ++ ++ /*Control register setting and restart auto*/ ++ if ((retVal = rtl8367c_getAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_CONTROL_REG, &phyData)) != RT_ERR_OK) ++ return retVal; ++ ++ phyData = (phyData & (~0x3140)) | phyEnMsk0; ++ /*If have auto-negotiation capable, then restart auto negotiation*/ ++ if (1 == pAbility->AutoNegotiation) ++ { ++ phyData = phyData | (1 << 9); ++ } ++ ++ if ((retVal = rtl8367c_setAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_CONTROL_REG, phyData)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_port_phyAutoNegoAbility_get ++ * Description: ++ * Get PHY ability through PHY registers. ++ * Input: ++ * port - Port id. ++ * Output: ++ * pAbility - Ability structure ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_PHY_REG_ID - Invalid PHY address ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy ++ * Note: ++ * Get the capability of specified PHY. ++ */ ++rtk_api_ret_t rtk_port_phyAutoNegoAbility_get(rtk_port_t port, rtk_port_phy_ability_t *pAbility) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 phyData0; ++ rtk_uint32 phyData4; ++ rtk_uint32 phyData9; ++ rtk_port_media_t media_type; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_IS_UTP(port); ++ ++ if(NULL == pAbility) ++ return RT_ERR_NULL_POINTER; ++ ++ if (rtk_switch_isComboPort(port) == RT_ERR_OK) ++ { ++ if ((retVal = rtk_port_phyComboPortMedia_get(port, &media_type)) != RT_ERR_OK) ++ return retVal; ++ ++ if(media_type == PORT_MEDIA_FIBER) ++ { ++ return _rtk_port_FiberModeAbility_get(port, pAbility); ++ } ++ } ++ ++ /*Control register setting and restart auto*/ ++ if ((retVal = rtl8367c_getAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_CONTROL_REG, &phyData0)) != RT_ERR_OK) ++ return retVal; ++ ++ /*Auto-Negotiation control register setting*/ ++ if ((retVal = rtl8367c_getAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_AN_ADVERTISEMENT_REG, &phyData4)) != RT_ERR_OK) ++ return retVal; ++ ++ /*1000 BASE-T control register setting*/ ++ if ((retVal = rtl8367c_getAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_1000_BASET_CONTROL_REG, &phyData9)) != RT_ERR_OK) ++ return retVal; ++ ++ if (phyData9 & (1 << 9)) ++ pAbility->Full_1000 = 1; ++ else ++ pAbility->Full_1000 = 0; ++ ++ if (phyData4 & (1 << 11)) ++ pAbility->AsyFC = 1; ++ else ++ pAbility->AsyFC = 0; ++ ++ if (phyData4 & (1 << 10)) ++ pAbility->FC = 1; ++ else ++ pAbility->FC = 0; ++ ++ ++ if (phyData4 & (1 << 8)) ++ pAbility->Full_100 = 1; ++ else ++ pAbility->Full_100 = 0; ++ ++ if (phyData4 & (1 << 7)) ++ pAbility->Half_100 = 1; ++ else ++ pAbility->Half_100 = 0; ++ ++ if (phyData4 & (1 << 6)) ++ pAbility->Full_10 = 1; ++ else ++ pAbility->Full_10 = 0; ++ ++ if (phyData4 & (1 << 5)) ++ pAbility->Half_10 = 1; ++ else ++ pAbility->Half_10 = 0; ++ ++ ++ if (phyData0 & (1 << 12)) ++ pAbility->AutoNegotiation = 1; ++ else ++ pAbility->AutoNegotiation = 0; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_port_phyForceModeAbility_set ++ * Description: ++ * Set the port speed/duplex mode/pause/asy_pause in the PHY force mode. ++ * Input: ++ * port - port id. ++ * pAbility - Ability structure ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_PHY_REG_ID - Invalid PHY address ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy ++ * Note: ++ * While both AutoNegotiation and Full_1000 are set to 0, the PHY speed and duplex selection will ++ * be set as following 100F > 100H > 10F > 10H priority sequence. ++ * This API can be used to configure combo port in fiber mode. ++ * The possible parameters in fiber mode are Full_1000 and Full 100. ++ * All the other fields in rtk_port_phy_ability_t will be ignored in fiber port. ++ */ ++rtk_api_ret_t rtk_port_phyForceModeAbility_set(rtk_port_t port, rtk_port_phy_ability_t *pAbility) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 phyData; ++ rtk_uint32 phyEnMsk0; ++ rtk_uint32 phyEnMsk4; ++ rtk_uint32 phyEnMsk9; ++ rtk_port_media_t media_type; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_IS_UTP(port); ++ ++ if(NULL == pAbility) ++ return RT_ERR_NULL_POINTER; ++ ++ if (pAbility->Half_10 >= RTK_ENABLE_END || pAbility->Full_10 >= RTK_ENABLE_END || ++ pAbility->Half_100 >= RTK_ENABLE_END || pAbility->Full_100 >= RTK_ENABLE_END || ++ pAbility->Full_1000 >= RTK_ENABLE_END || pAbility->AutoNegotiation >= RTK_ENABLE_END || ++ pAbility->AsyFC >= RTK_ENABLE_END || pAbility->FC >= RTK_ENABLE_END) ++ return RT_ERR_INPUT; ++ ++ if (rtk_switch_isComboPort(port) == RT_ERR_OK) ++ { ++ if ((retVal = rtk_port_phyComboPortMedia_get(port, &media_type)) != RT_ERR_OK) ++ return retVal; ++ ++ if(media_type == PORT_MEDIA_FIBER) ++ { ++ return _rtk_port_FiberModeAbility_set(port, pAbility); ++ } ++ } ++ ++ if (1 == pAbility->Full_1000) ++ return RT_ERR_INPUT; ++ ++ /*for PHY force mode setup*/ ++ pAbility->AutoNegotiation = 0; ++ ++ phyEnMsk0 = 0; ++ phyEnMsk4 = 0; ++ phyEnMsk9 = 0; ++ ++ if (1 == pAbility->Half_10) ++ { ++ /*10BASE-TX half duplex capable in reg 4.5*/ ++ phyEnMsk4 = phyEnMsk4 | (1 << 5); ++ ++ /*Speed selection [1:0] */ ++ /* 11=Reserved*/ ++ /* 10= 1000Mpbs*/ ++ /* 01= 100Mpbs*/ ++ /* 00= 10Mpbs*/ ++ phyEnMsk0 = phyEnMsk0 & (~(1 << 6)); ++ phyEnMsk0 = phyEnMsk0 & (~(1 << 13)); ++ } ++ ++ if (1 == pAbility->Full_10) ++ { ++ /*10BASE-TX full duplex capable in reg 4.6*/ ++ phyEnMsk4 = phyEnMsk4 | (1 << 6); ++ /*Speed selection [1:0] */ ++ /* 11=Reserved*/ ++ /* 10= 1000Mpbs*/ ++ /* 01= 100Mpbs*/ ++ /* 00= 10Mpbs*/ ++ phyEnMsk0 = phyEnMsk0 & (~(1 << 6)); ++ phyEnMsk0 = phyEnMsk0 & (~(1 << 13)); ++ ++ /*Full duplex mode in reg 0.8*/ ++ phyEnMsk0 = phyEnMsk0 | (1 << 8); ++ ++ } ++ ++ if (1 == pAbility->Half_100) ++ { ++ /*100BASE-TX half duplex capable in reg 4.7*/ ++ phyEnMsk4 = phyEnMsk4 | (1 << 7); ++ /*Speed selection [1:0] */ ++ /* 11=Reserved*/ ++ /* 10= 1000Mpbs*/ ++ /* 01= 100Mpbs*/ ++ /* 00= 10Mpbs*/ ++ phyEnMsk0 = phyEnMsk0 & (~(1 << 6)); ++ phyEnMsk0 = phyEnMsk0 | (1 << 13); ++ } ++ ++ ++ if (1 == pAbility->Full_100) ++ { ++ /*100BASE-TX full duplex capable in reg 4.8*/ ++ phyEnMsk4 = phyEnMsk4 | (1 << 8); ++ /*Speed selection [1:0] */ ++ /* 11=Reserved*/ ++ /* 10= 1000Mpbs*/ ++ /* 01= 100Mpbs*/ ++ /* 00= 10Mpbs*/ ++ phyEnMsk0 = phyEnMsk0 & (~(1 << 6)); ++ phyEnMsk0 = phyEnMsk0 | (1 << 13); ++ /*Full duplex mode in reg 0.8*/ ++ phyEnMsk0 = phyEnMsk0 | (1 << 8); ++ } ++ ++ if (1 == pAbility->AsyFC) ++ { ++ /*Asymmetric flow control in reg 4.11*/ ++ phyEnMsk4 = phyEnMsk4 | (1 << 11); ++ } ++ if (1 == pAbility->FC) ++ { ++ /*Flow control in reg 4.10*/ ++ phyEnMsk4 = phyEnMsk4 | ((1 << 10)); ++ } ++ ++ /*1000 BASE-T control register setting*/ ++ if ((retVal = rtl8367c_getAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_1000_BASET_CONTROL_REG, &phyData)) != RT_ERR_OK) ++ return retVal; ++ ++ phyData = (phyData & (~0x0200)) | phyEnMsk9 ; ++ ++ if ((retVal = rtl8367c_setAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_1000_BASET_CONTROL_REG, phyData)) != RT_ERR_OK) ++ return retVal; ++ ++ /*Auto-Negotiation control register setting*/ ++ if ((retVal = rtl8367c_getAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_AN_ADVERTISEMENT_REG, &phyData)) != RT_ERR_OK) ++ return retVal; ++ ++ phyData = (phyData & (~0x0DE0)) | phyEnMsk4; ++ if ((retVal = rtl8367c_setAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_AN_ADVERTISEMENT_REG, phyData)) != RT_ERR_OK) ++ return retVal; ++ ++ /*Control register setting and power off/on*/ ++ phyData = phyEnMsk0 & (~(1 << 12)); ++ phyData |= (1 << 11); /* power down PHY, bit 11 should be set to 1 */ ++ if ((retVal = rtl8367c_setAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_CONTROL_REG, phyData)) != RT_ERR_OK) ++ return retVal; ++ ++ phyData = phyData & (~(1 << 11)); /* power on PHY, bit 11 should be set to 0*/ ++ if ((retVal = rtl8367c_setAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_CONTROL_REG, phyData)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_port_phyForceModeAbility_get ++ * Description: ++ * Get PHY ability through PHY registers. ++ * Input: ++ * port - Port id. ++ * Output: ++ * pAbility - Ability structure ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_PHY_REG_ID - Invalid PHY address ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy ++ * Note: ++ * Get the capability of specified PHY. ++ */ ++rtk_api_ret_t rtk_port_phyForceModeAbility_get(rtk_port_t port, rtk_port_phy_ability_t *pAbility) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 phyData0; ++ rtk_uint32 phyData4; ++ rtk_uint32 phyData9; ++ rtk_port_media_t media_type; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_IS_UTP(port); ++ ++ if(NULL == pAbility) ++ return RT_ERR_NULL_POINTER; ++ ++ if (rtk_switch_isComboPort(port) == RT_ERR_OK) ++ { ++ if ((retVal = rtk_port_phyComboPortMedia_get(port, &media_type)) != RT_ERR_OK) ++ return retVal; ++ ++ if(media_type == PORT_MEDIA_FIBER) ++ { ++ return _rtk_port_FiberModeAbility_get(port, pAbility); ++ } ++ } ++ ++ /*Control register setting and restart auto*/ ++ if ((retVal = rtl8367c_getAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_CONTROL_REG, &phyData0)) != RT_ERR_OK) ++ return retVal; ++ ++ /*Auto-Negotiation control register setting*/ ++ if ((retVal = rtl8367c_getAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_AN_ADVERTISEMENT_REG, &phyData4)) != RT_ERR_OK) ++ return retVal; ++ ++ /*1000 BASE-T control register setting*/ ++ if ((retVal = rtl8367c_getAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_1000_BASET_CONTROL_REG, &phyData9)) != RT_ERR_OK) ++ return retVal; ++ ++ if (phyData9 & (1 << 9)) ++ pAbility->Full_1000 = 1; ++ else ++ pAbility->Full_1000 = 0; ++ ++ if (phyData4 & (1 << 11)) ++ pAbility->AsyFC = 1; ++ else ++ pAbility->AsyFC = 0; ++ ++ if (phyData4 & ((1 << 10))) ++ pAbility->FC = 1; ++ else ++ pAbility->FC = 0; ++ ++ ++ if (phyData4 & (1 << 8)) ++ pAbility->Full_100 = 1; ++ else ++ pAbility->Full_100 = 0; ++ ++ if (phyData4 & (1 << 7)) ++ pAbility->Half_100 = 1; ++ else ++ pAbility->Half_100 = 0; ++ ++ if (phyData4 & (1 << 6)) ++ pAbility->Full_10 = 1; ++ else ++ pAbility->Full_10 = 0; ++ ++ if (phyData4 & (1 << 5)) ++ pAbility->Half_10 = 1; ++ else ++ pAbility->Half_10 = 0; ++ ++ ++ if (phyData0 & (1 << 12)) ++ pAbility->AutoNegotiation = 1; ++ else ++ pAbility->AutoNegotiation = 0; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_port_phyStatus_get ++ * Description: ++ * Get Ethernet PHY linking status ++ * Input: ++ * port - Port id. ++ * Output: ++ * linkStatus - PHY link status ++ * speed - PHY link speed ++ * duplex - PHY duplex mode ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_PHY_REG_ID - Invalid PHY address ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy ++ * Note: ++ * API will return auto negotiation status of phy. ++ */ ++rtk_api_ret_t rtk_port_phyStatus_get(rtk_port_t port, rtk_port_linkStatus_t *pLinkStatus, rtk_port_speed_t *pSpeed, rtk_port_duplex_t *pDuplex) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 phyData; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_IS_UTP(port); ++ ++ if( (NULL == pLinkStatus) || (NULL == pSpeed) || (NULL == pDuplex) ) ++ return RT_ERR_NULL_POINTER; ++ ++ /*Get PHY resolved register*/ ++ if ((retVal = rtl8367c_getAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_RESOLVED_REG, &phyData)) != RT_ERR_OK) ++ return retVal; ++ ++ /*check link status*/ ++ if (phyData & (1<<2)) ++ { ++ *pLinkStatus = 1; ++ ++ /*check link speed*/ ++ *pSpeed = (phyData&0x0030) >> 4; ++ ++ /*check link duplex*/ ++ *pDuplex = (phyData&0x0008) >> 3; ++ } ++ else ++ { ++ *pLinkStatus = 0; ++ *pSpeed = 0; ++ *pDuplex = 0; ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_port_macForceLink_set ++ * Description: ++ * Set port force linking configuration. ++ * Input: ++ * port - port id. ++ * pPortability - port ability configuration ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * This API can set Port/MAC force mode properties. ++ */ ++rtk_api_ret_t rtk_port_macForceLink_set(rtk_port_t port, rtk_port_mac_ability_t *pPortability) ++{ ++ rtk_api_ret_t retVal; ++ rtl8367c_port_ability_t ability; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_IS_UTP(port); ++ ++ if(NULL == pPortability) ++ return RT_ERR_NULL_POINTER; ++ ++ if (pPortability->forcemode >1|| pPortability->speed > 2 || pPortability->duplex > 1 || ++ pPortability->link > 1 || pPortability->nway > 1 || pPortability->txpause > 1 || pPortability->rxpause > 1) ++ return RT_ERR_INPUT; ++ ++ if ((retVal = rtl8367c_getAsicPortForceLink(rtk_switch_port_L2P_get(port), &ability)) != RT_ERR_OK) ++ return retVal; ++ ++ ability.forcemode = pPortability->forcemode; ++ ability.speed = pPortability->speed; ++ ability.duplex = pPortability->duplex; ++ ability.link = pPortability->link; ++ ability.nway = pPortability->nway; ++ ability.txpause = pPortability->txpause; ++ ability.rxpause = pPortability->rxpause; ++ ++ if ((retVal = rtl8367c_setAsicPortForceLink(rtk_switch_port_L2P_get(port), &ability)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_port_macForceLink_get ++ * Description: ++ * Get port force linking configuration. ++ * Input: ++ * port - Port id. ++ * Output: ++ * pPortability - port ability configuration ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * This API can get Port/MAC force mode properties. ++ */ ++rtk_api_ret_t rtk_port_macForceLink_get(rtk_port_t port, rtk_port_mac_ability_t *pPortability) ++{ ++ rtk_api_ret_t retVal; ++ rtl8367c_port_ability_t ability; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_IS_UTP(port); ++ ++ if(NULL == pPortability) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicPortForceLink(rtk_switch_port_L2P_get(port), &ability)) != RT_ERR_OK) ++ return retVal; ++ ++ pPortability->forcemode = ability.forcemode; ++ pPortability->speed = ability.speed; ++ pPortability->duplex = ability.duplex; ++ pPortability->link = ability.link; ++ pPortability->nway = ability.nway; ++ pPortability->txpause = ability.txpause; ++ pPortability->rxpause = ability.rxpause; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_port_macForceLinkExt_set ++ * Description: ++ * Set external interface force linking configuration. ++ * Input: ++ * port - external port ID ++ * mode - external interface mode ++ * pPortability - port ability configuration ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * This API can set external interface force mode properties. ++ * The external interface can be set to: ++ * - MODE_EXT_DISABLE, ++ * - MODE_EXT_RGMII, ++ * - MODE_EXT_MII_MAC, ++ * - MODE_EXT_MII_PHY, ++ * - MODE_EXT_TMII_MAC, ++ * - MODE_EXT_TMII_PHY, ++ * - MODE_EXT_GMII, ++ * - MODE_EXT_RMII_MAC, ++ * - MODE_EXT_RMII_PHY, ++ * - MODE_EXT_SGMII, ++ * - MODE_EXT_HSGMII, ++ * - MODE_EXT_1000X_100FX, ++ * - MODE_EXT_1000X, ++ * - MODE_EXT_100FX, ++ */ ++rtk_api_ret_t rtk_port_macForceLinkExt_set(rtk_port_t port, rtk_mode_ext_t mode, rtk_port_mac_ability_t *pPortability) ++{ ++ rtk_api_ret_t retVal; ++ rtl8367c_port_ability_t ability; ++ rtk_uint32 ext_id; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_IS_EXT(port); ++ ++ if(NULL == pPortability) ++ return RT_ERR_NULL_POINTER; ++ ++ if (mode >=MODE_EXT_END) ++ return RT_ERR_INPUT; ++ ++ if(mode == MODE_EXT_HSGMII) ++ { ++ if (pPortability->forcemode > 1 || pPortability->speed != PORT_SPEED_2500M || pPortability->duplex != PORT_FULL_DUPLEX || ++ pPortability->link >= PORT_LINKSTATUS_END || pPortability->nway > 1 || pPortability->txpause > 1 || pPortability->rxpause > 1) ++ return RT_ERR_INPUT; ++ ++ if(rtk_switch_isHsgPort(port) != RT_ERR_OK) ++ return RT_ERR_PORT_ID; ++ } ++ else ++ { ++ if (pPortability->forcemode > 1 || pPortability->speed > PORT_SPEED_1000M || pPortability->duplex >= PORT_DUPLEX_END || ++ pPortability->link >= PORT_LINKSTATUS_END || pPortability->nway > 1 || pPortability->txpause > 1 || pPortability->rxpause > 1) ++ return RT_ERR_INPUT; ++ } ++ ++ ext_id = port - 15; ++ ++ if(mode == MODE_EXT_DISABLE) ++ { ++ memset(&ability, 0x00, sizeof(rtl8367c_port_ability_t)); ++ if ((retVal = rtl8367c_setAsicPortForceLinkExt(ext_id, &ability)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicPortExtMode(ext_id, mode)) != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ { ++ if ((retVal = rtl8367c_setAsicPortExtMode(ext_id, mode)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_getAsicPortForceLinkExt(ext_id, &ability)) != RT_ERR_OK) ++ return retVal; ++ ++ ability.forcemode = pPortability->forcemode; ++ ability.speed = (mode == MODE_EXT_HSGMII) ? PORT_SPEED_1000M : pPortability->speed; ++ ability.duplex = pPortability->duplex; ++ ability.link = pPortability->link; ++ ability.nway = pPortability->nway; ++ ability.txpause = pPortability->txpause; ++ ability.rxpause = pPortability->rxpause; ++ ++ if ((retVal = rtl8367c_setAsicPortForceLinkExt(ext_id, &ability)) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_port_macForceLinkExt_get ++ * Description: ++ * Set external interface force linking configuration. ++ * Input: ++ * port - external port ID ++ * Output: ++ * pMode - external interface mode ++ * pPortability - port ability configuration ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * This API can get external interface force mode properties. ++ */ ++rtk_api_ret_t rtk_port_macForceLinkExt_get(rtk_port_t port, rtk_mode_ext_t *pMode, rtk_port_mac_ability_t *pPortability) ++{ ++ rtk_api_ret_t retVal; ++ rtl8367c_port_ability_t ability; ++ rtk_uint32 ext_id; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_IS_EXT(port); ++ ++ if(NULL == pMode) ++ return RT_ERR_NULL_POINTER; ++ ++ if(NULL == pPortability) ++ return RT_ERR_NULL_POINTER; ++ ++ ext_id = port - 15; ++ ++ if ((retVal = rtl8367c_getAsicPortExtMode(ext_id, (rtk_uint32 *)pMode)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_getAsicPortForceLinkExt(ext_id, &ability)) != RT_ERR_OK) ++ return retVal; ++ ++ pPortability->forcemode = ability.forcemode; ++ pPortability->speed = (*pMode == MODE_EXT_HSGMII) ? PORT_SPEED_2500M : ability.speed; ++ pPortability->duplex = ability.duplex; ++ pPortability->link = ability.link; ++ pPortability->nway = ability.nway; ++ pPortability->txpause = ability.txpause; ++ pPortability->rxpause = ability.rxpause; ++ ++ return RT_ERR_OK; ++ ++} ++ ++/* Function Name: ++ * rtk_port_macStatus_get ++ * Description: ++ * Get port link status. ++ * Input: ++ * port - Port id. ++ * Output: ++ * pPortstatus - port ability configuration ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * This API can get Port/PHY properties. ++ */ ++rtk_api_ret_t rtk_port_macStatus_get(rtk_port_t port, rtk_port_mac_ability_t *pPortstatus) ++{ ++ rtk_api_ret_t retVal; ++ rtl8367c_port_status_t status; ++ rtk_uint32 hsgsel; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if(NULL == pPortstatus) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicPortStatus(rtk_switch_port_L2P_get(port), &status)) != RT_ERR_OK) ++ return retVal; ++ ++ ++ pPortstatus->duplex = status.duplex; ++ pPortstatus->link = status.link; ++ pPortstatus->nway = status.nway; ++ pPortstatus->txpause = status.txpause; ++ pPortstatus->rxpause = status.rxpause; ++ ++ if( (retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_MAC8_SEL_HSGMII_OFFSET, &hsgsel)) != RT_ERR_OK) ++ return retVal; ++ ++ if( (rtk_switch_isHsgPort(port) == RT_ERR_OK) && (hsgsel == 1) ) ++ pPortstatus->speed = PORT_SPEED_2500M; ++ else ++ pPortstatus->speed = status.speed; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_port_macLocalLoopbackEnable_set ++ * Description: ++ * Set Port Local Loopback. (Redirect TX to RX.) ++ * Input: ++ * port - Port id. ++ * enable - Loopback state, 0:disable, 1:enable ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * This API can enable/disable Local loopback in MAC. ++ * For UTP port, This API will also enable the digital ++ * loopback bit in PHY register for sync of speed between ++ * PHY and MAC. For EXT port, users need to force the ++ * link state by themselves. ++ */ ++rtk_api_ret_t rtk_port_macLocalLoopbackEnable_set(rtk_port_t port, rtk_enable_t enable) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 data; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if(enable >= RTK_ENABLE_END) ++ return RT_ERR_INPUT; ++ ++ if ((retVal = rtl8367c_setAsicPortLoopback(rtk_switch_port_L2P_get(port), enable)) != RT_ERR_OK) ++ return retVal; ++ ++ if(rtk_switch_isUtpPort(port) == RT_ERR_OK) ++ { ++ if ((retVal = rtl8367c_getAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_CONTROL_REG, &data)) != RT_ERR_OK) ++ return retVal; ++ ++ if(enable == ENABLED) ++ data |= (0x0001 << 14); ++ else ++ data &= ~(0x0001 << 14); ++ ++ if ((retVal = rtl8367c_setAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_CONTROL_REG, data)) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_port_macLocalLoopbackEnable_get ++ * Description: ++ * Get Port Local Loopback. (Redirect TX to RX.) ++ * Input: ++ * port - Port id. ++ * Output: ++ * pEnable - Loopback state, 0:disable, 1:enable ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * None. ++ */ ++rtk_api_ret_t rtk_port_macLocalLoopbackEnable_get(rtk_port_t port, rtk_enable_t *pEnable) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if(NULL == pEnable) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicPortLoopback(rtk_switch_port_L2P_get(port), pEnable)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_port_phyReg_set ++ * Description: ++ * Set PHY register data of the specific port. ++ * Input: ++ * port - port id. ++ * reg - Register id ++ * regData - Register data ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_PHY_REG_ID - Invalid PHY address ++ * RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy ++ * Note: ++ * This API can set PHY register data of the specific port. ++ */ ++rtk_api_ret_t rtk_port_phyReg_set(rtk_port_t port, rtk_port_phy_reg_t reg, rtk_port_phy_data_t regData) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_IS_UTP(port); ++ ++ if ((retVal = rtl8367c_setAsicPHYReg(rtk_switch_port_L2P_get(port), reg, regData)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_port_phyReg_get ++ * Description: ++ * Get PHY register data of the specific port. ++ * Input: ++ * port - Port id. ++ * reg - Register id ++ * Output: ++ * pData - Register data ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_PHY_REG_ID - Invalid PHY address ++ * RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy ++ * Note: ++ * This API can get PHY register data of the specific port. ++ */ ++rtk_api_ret_t rtk_port_phyReg_get(rtk_port_t port, rtk_port_phy_reg_t reg, rtk_port_phy_data_t *pData) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_IS_UTP(port); ++ ++ if ((retVal = rtl8367c_getAsicPHYReg(rtk_switch_port_L2P_get(port), reg, pData)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_port_backpressureEnable_set ++ * Description: ++ * Set the half duplex back-pressure enable status of the specific port. ++ * Input: ++ * port - port id. ++ * enable - Back pressure status. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_ENABLE - Invalid enable input. ++ * Note: ++ * This API can set the half duplex back-pressure enable status of the specific port. ++ * The half duplex back-pressure enable status of the port is as following: ++ * - DISABLE(Defer) ++ * - ENABLE (Back-pressure) ++ */ ++rtk_api_ret_t rtk_port_backpressureEnable_set(rtk_port_t port, rtk_enable_t enable) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (port != RTK_WHOLE_SYSTEM) ++ return RT_ERR_PORT_ID; ++ ++ if (enable >= RTK_ENABLE_END) ++ return RT_ERR_INPUT; ++ ++ if ((retVal = rtl8367c_setAsicPortJamMode(!enable)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_port_backpressureEnable_get ++ * Description: ++ * Get the half duplex back-pressure enable status of the specific port. ++ * Input: ++ * port - Port id. ++ * Output: ++ * pEnable - Back pressure status. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * This API can get the half duplex back-pressure enable status of the specific port. ++ * The half duplex back-pressure enable status of the port is as following: ++ * - DISABLE(Defer) ++ * - ENABLE (Back-pressure) ++ */ ++rtk_api_ret_t rtk_port_backpressureEnable_get(rtk_port_t port, rtk_enable_t *pEnable) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 regData; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (port != RTK_WHOLE_SYSTEM) ++ return RT_ERR_PORT_ID; ++ ++ if(NULL == pEnable) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicPortJamMode(®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ *pEnable = !regData; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_port_adminEnable_set ++ * Description: ++ * Set port admin configuration of the specific port. ++ * Input: ++ * port - port id. ++ * enable - Back pressure status. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_ENABLE - Invalid enable input. ++ * Note: ++ * This API can set port admin configuration of the specific port. ++ * The port admin configuration of the port is as following: ++ * - DISABLE ++ * - ENABLE ++ */ ++rtk_api_ret_t rtk_port_adminEnable_set(rtk_port_t port, rtk_enable_t enable) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 data; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_IS_UTP(port); ++ ++ if (enable >= RTK_ENABLE_END) ++ return RT_ERR_INPUT; ++ ++ if ((retVal = rtk_port_phyReg_get(port, PHY_CONTROL_REG, &data)) != RT_ERR_OK) ++ return retVal; ++ ++ if (ENABLED == enable) ++ { ++ data &= 0xF7FF; ++ data |= 0x0200; ++ } ++ else if (DISABLED == enable) ++ { ++ data |= 0x0800; ++ } ++ ++ if ((retVal = rtk_port_phyReg_set(port, PHY_CONTROL_REG, data)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_port_adminEnable_get ++ * Description: ++ * Get port admin configuration of the specific port. ++ * Input: ++ * port - Port id. ++ * Output: ++ * pEnable - Back pressure status. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * This API can get port admin configuration of the specific port. ++ * The port admin configuration of the port is as following: ++ * - DISABLE ++ * - ENABLE ++ */ ++rtk_api_ret_t rtk_port_adminEnable_get(rtk_port_t port, rtk_enable_t *pEnable) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 data; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_IS_UTP(port); ++ ++ if(NULL == pEnable) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtk_port_phyReg_get(port, PHY_CONTROL_REG, &data)) != RT_ERR_OK) ++ return retVal; ++ ++ if ( (data & 0x0800) == 0x0800) ++ { ++ *pEnable = DISABLED; ++ } ++ else ++ { ++ *pEnable = ENABLED; ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_port_isolation_set ++ * Description: ++ * Set permitted port isolation portmask ++ * Input: ++ * port - port id. ++ * pPortmask - Permit port mask ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_PORT_MASK - Invalid portmask. ++ * Note: ++ * This API set the port mask that a port can transmit packet to of each port ++ * A port can only transmit packet to ports included in permitted portmask ++ */ ++rtk_api_ret_t rtk_port_isolation_set(rtk_port_t port, rtk_portmask_t *pPortmask) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 pmask; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if(NULL == pPortmask) ++ return RT_ERR_NULL_POINTER; ++ ++ /* check port mask */ ++ RTK_CHK_PORTMASK_VALID(pPortmask); ++ ++ if ((retVal = rtk_switch_portmask_L2P_get(pPortmask, &pmask)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicPortIsolationPermittedPortmask(rtk_switch_port_L2P_get(port), pmask)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_port_isolation_get ++ * Description: ++ * Get permitted port isolation portmask ++ * Input: ++ * port - Port id. ++ * Output: ++ * pPortmask - Permit port mask ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * This API get the port mask that a port can transmit packet to of each port ++ * A port can only transmit packet to ports included in permitted portmask ++ */ ++rtk_api_ret_t rtk_port_isolation_get(rtk_port_t port, rtk_portmask_t *pPortmask) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 pmask; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if(NULL == pPortmask) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicPortIsolationPermittedPortmask(rtk_switch_port_L2P_get(port), &pmask)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtk_switch_portmask_P2L_get(pmask, pPortmask)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_port_rgmiiDelayExt_set ++ * Description: ++ * Set RGMII interface delay value for TX and RX. ++ * Input: ++ * txDelay - TX delay value, 1 for delay 2ns and 0 for no-delay ++ * rxDelay - RX delay value, 0~7 for delay setup. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * This API can set external interface 2 RGMII delay. ++ * In TX delay, there are 2 selection: no-delay and 2ns delay. ++ * In RX delay, there are 8 steps for delay tuning. 0 for no-delay, and 7 for maximum delay. ++ */ ++rtk_api_ret_t rtk_port_rgmiiDelayExt_set(rtk_port_t port, rtk_data_t txDelay, rtk_data_t rxDelay) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 regAddr, regData; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_IS_EXT(port); ++ ++ if ((txDelay > 1) || (rxDelay > 7)) ++ return RT_ERR_INPUT; ++ ++ if(port == EXT_PORT0) ++ regAddr = RTL8367C_REG_EXT1_RGMXF; ++ else if(port == EXT_PORT1) ++ regAddr = RTL8367C_REG_EXT2_RGMXF; ++ else ++ return RT_ERR_INPUT; ++ ++ if ((retVal = rtl8367c_getAsicReg(regAddr, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ regData = (regData & 0xFFF0) | ((txDelay << 3) & 0x0008) | (rxDelay & 0x0007); ++ ++ if ((retVal = rtl8367c_setAsicReg(regAddr, regData)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_port_rgmiiDelayExt_get ++ * Description: ++ * Get RGMII interface delay value for TX and RX. ++ * Input: ++ * None ++ * Output: ++ * pTxDelay - TX delay value ++ * pRxDelay - RX delay value ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * This API can set external interface 2 RGMII delay. ++ * In TX delay, there are 2 selection: no-delay and 2ns delay. ++ * In RX delay, there are 8 steps for delay tuning. 0 for n0-delay, and 7 for maximum delay. ++ */ ++rtk_api_ret_t rtk_port_rgmiiDelayExt_get(rtk_port_t port, rtk_data_t *pTxDelay, rtk_data_t *pRxDelay) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 regAddr, regData; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_IS_EXT(port); ++ ++ if( (NULL == pTxDelay) || (NULL == pRxDelay) ) ++ return RT_ERR_NULL_POINTER; ++ ++ if(port == EXT_PORT0) ++ regAddr = RTL8367C_REG_EXT1_RGMXF; ++ else if(port == EXT_PORT1) ++ regAddr = RTL8367C_REG_EXT2_RGMXF; ++ else ++ return RT_ERR_INPUT; ++ ++ if ((retVal = rtl8367c_getAsicReg(regAddr, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ *pTxDelay = (regData & 0x0008) >> 3; ++ *pRxDelay = regData & 0x0007; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_port_phyEnableAll_set ++ * Description: ++ * Set all PHY enable status. ++ * Input: ++ * enable - PHY Enable State. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_ENABLE - Invalid enable input. ++ * Note: ++ * This API can set all PHY status. ++ * The configuration of all PHY is as following: ++ * - DISABLE ++ * - ENABLE ++ */ ++rtk_api_ret_t rtk_port_phyEnableAll_set(rtk_enable_t enable) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 data; ++ rtk_uint32 port; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (enable >= RTK_ENABLE_END) ++ return RT_ERR_ENABLE; ++ ++ if ((retVal = rtl8367c_setAsicPortEnableAll(enable)) != RT_ERR_OK) ++ return retVal; ++ ++ RTK_SCAN_ALL_LOG_PORT(port) ++ { ++ if(rtk_switch_isUtpPort(port) == RT_ERR_OK) ++ { ++ if ((retVal = rtk_port_phyReg_get(port, PHY_CONTROL_REG, &data)) != RT_ERR_OK) ++ return retVal; ++ ++ if (ENABLED == enable) ++ { ++ data &= 0xF7FF; ++ data |= 0x0200; ++ } ++ else ++ { ++ data |= 0x0800; ++ } ++ ++ if ((retVal = rtk_port_phyReg_set(port, PHY_CONTROL_REG, data)) != RT_ERR_OK) ++ return retVal; ++ } ++ } ++ ++ return RT_ERR_OK; ++ ++} ++ ++/* Function Name: ++ * rtk_port_phyEnableAll_get ++ * Description: ++ * Get all PHY enable status. ++ * Input: ++ * None ++ * Output: ++ * pEnable - PHY Enable State. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * This API can set all PHY status. ++ * The configuration of all PHY is as following: ++ * - DISABLE ++ * - ENABLE ++ */ ++rtk_api_ret_t rtk_port_phyEnableAll_get(rtk_enable_t *pEnable) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pEnable) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicPortEnableAll(pEnable)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_port_efid_set ++ * Description: ++ * Set port-based enhanced filtering database ++ * Input: ++ * port - Port id. ++ * efid - Specified enhanced filtering database. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_L2_FID - Invalid fid. ++ * RT_ERR_INPUT - Invalid input parameter. ++ * RT_ERR_PORT_ID - Invalid port ID. ++ * Note: ++ * The API can set port-based enhanced filtering database. ++ */ ++rtk_api_ret_t rtk_port_efid_set(rtk_port_t port, rtk_data_t efid) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ /* efid must be 0~7 */ ++ if (efid > RTK_EFID_MAX) ++ return RT_ERR_INPUT; ++ ++ if ((retVal = rtl8367c_setAsicPortIsolationEfid(rtk_switch_port_L2P_get(port), efid))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_port_efid_get ++ * Description: ++ * Get port-based enhanced filtering database ++ * Input: ++ * port - Port id. ++ * Output: ++ * pEfid - Specified enhanced filtering database. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_PORT_ID - Invalid port ID. ++ * Note: ++ * The API can get port-based enhanced filtering database status. ++ */ ++rtk_api_ret_t rtk_port_efid_get(rtk_port_t port, rtk_data_t *pEfid) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if(NULL == pEfid) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicPortIsolationEfid(rtk_switch_port_L2P_get(port), pEfid))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_port_phyComboPortMedia_set ++ * Description: ++ * Set Combo port media type ++ * Input: ++ * port - Port id. ++ * media - Media (COPPER or FIBER) ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_PORT_ID - Invalid port ID. ++ * Note: ++ * The API can Set Combo port media type. ++ */ ++rtk_api_ret_t rtk_port_phyComboPortMedia_set(rtk_port_t port, rtk_port_media_t media) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 regData; ++ rtk_uint32 idx; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_IS_UTP(port); ++ ++ /* Check Combo Port ID */ ++ RTK_CHK_PORT_IS_COMBO(port); ++ ++ if (media >= PORT_MEDIA_END) ++ return RT_ERR_INPUT; ++ ++ if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0249)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_getAsicReg(0x1300, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0000)) != RT_ERR_OK) ++ return retVal; ++ ++ if(regData != 0x6367) ++ return RT_ERR_CHIP_NOT_SUPPORTED; ++ ++ if(media == PORT_MEDIA_FIBER) ++ { ++ /* software init */ ++ if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_CHIP_RESET, RTL8367C_DW8051_RST_OFFSET, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_MISCELLANEOUS_CONFIGURE0, RTL8367C_DW8051_EN_OFFSET, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_DW8051_RDY, RTL8367C_ACS_IROM_ENABLE_OFFSET, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_DW8051_RDY, RTL8367C_IROM_MSB_OFFSET, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ for(idx = 0; idx < FIBER_INIT_SIZE; idx++) ++ { ++ if ((retVal = rtl8367c_setAsicReg(0xE000 + idx, (rtk_uint32)Fiber[idx])) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_DW8051_RDY, RTL8367C_IROM_MSB_OFFSET, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_DW8051_RDY, RTL8367C_ACS_IROM_ENABLE_OFFSET, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_CHIP_RESET, RTL8367C_DW8051_RST_OFFSET, 0)) != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ { ++ if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_UTP_FIB_DET, RTL8367C_UTP_FIRST_OFFSET, 1))!=RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_DW8051_RDY, RTL8367C_DW8051_READY_OFFSET, 0)) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_port_phyComboPortMedia_get ++ * Description: ++ * Get Combo port media type ++ * Input: ++ * port - Port id. ++ * Output: ++ * pMedia - Media (COPPER or FIBER) ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_PORT_ID - Invalid port ID. ++ * Note: ++ * The API can Set Combo port media type. ++ */ ++rtk_api_ret_t rtk_port_phyComboPortMedia_get(rtk_port_t port, rtk_port_media_t *pMedia) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 regData; ++ rtk_uint32 data; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_IS_UTP(port); ++ ++ /* Check Combo Port ID */ ++ RTK_CHK_PORT_IS_COMBO(port); ++ ++ if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0249)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_getAsicReg(0x1300, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0000)) != RT_ERR_OK) ++ return retVal; ++ ++ if(regData != 0x6367) ++ { ++ *pMedia = PORT_MEDIA_COPPER; ++ } ++ else ++ { ++ if ((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_UTP_FIB_DET, RTL8367C_UTP_FIRST_OFFSET, &data))!=RT_ERR_OK) ++ return retVal; ++ ++ if(data == 1) ++ *pMedia = PORT_MEDIA_COPPER; ++ else ++ *pMedia = PORT_MEDIA_FIBER; ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_port_rtctEnable_set ++ * Description: ++ * Enable RTCT test ++ * Input: ++ * pPortmask - Port mask of RTCT enabled port ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_MASK - Invalid port mask. ++ * Note: ++ * The API can enable RTCT Test ++ */ ++rtk_api_ret_t rtk_port_rtctEnable_set(rtk_portmask_t *pPortmask) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Mask Valid */ ++ RTK_CHK_PORTMASK_VALID_ONLY_UTP(pPortmask); ++ ++ if ((retVal = rtl8367c_setAsicPortRTCTEnable(pPortmask->bits[0]))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_port_rtctDisable_set ++ * Description: ++ * Disable RTCT test ++ * Input: ++ * pPortmask - Port mask of RTCT disabled port ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_MASK - Invalid port mask. ++ * Note: ++ * The API can disable RTCT Test ++ */ ++rtk_api_ret_t rtk_port_rtctDisable_set(rtk_portmask_t *pPortmask) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Mask Valid */ ++ RTK_CHK_PORTMASK_VALID_ONLY_UTP(pPortmask); ++ ++ if ((retVal = rtl8367c_setAsicPortRTCTDisable(pPortmask->bits[0]))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++ ++/* Function Name: ++ * rtk_port_rtctResult_get ++ * Description: ++ * Get the result of RTCT test ++ * Input: ++ * port - Port ID ++ * Output: ++ * pRtctResult - The result of RTCT result ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port ID. ++ * RT_ERR_PHY_RTCT_NOT_FINISH - Testing does not finish. ++ * Note: ++ * The API can get RTCT test result. ++ * RTCT test may takes 4.8 seconds to finish its test at most. ++ * Thus, if this API return RT_ERR_PHY_RTCT_NOT_FINISH or ++ * other error code, the result can not be referenced and ++ * user should call this API again until this API returns ++ * a RT_ERR_OK. ++ * The result is stored at pRtctResult->ge_result ++ * pRtctResult->linkType is unused. ++ * The unit of channel length is 2.5cm. Ex. 300 means 300 * 2.5 = 750cm = 7.5M ++ */ ++rtk_api_ret_t rtk_port_rtctResult_get(rtk_port_t port, rtk_rtctResult_t *pRtctResult) ++{ ++ rtk_api_ret_t retVal; ++ rtl8367c_port_rtct_result_t result; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_IS_UTP(port); ++ ++ memset(pRtctResult, 0x00, sizeof(rtk_rtctResult_t)); ++ if ((retVal = rtl8367c_getAsicPortRTCTResult(port, &result))!=RT_ERR_OK) ++ return retVal; ++ ++ pRtctResult->result.ge_result.channelALen = result.channelALen; ++ pRtctResult->result.ge_result.channelBLen = result.channelBLen; ++ pRtctResult->result.ge_result.channelCLen = result.channelCLen; ++ pRtctResult->result.ge_result.channelDLen = result.channelDLen; ++ ++ pRtctResult->result.ge_result.channelALinedriver = result.channelALinedriver; ++ pRtctResult->result.ge_result.channelBLinedriver = result.channelBLinedriver; ++ pRtctResult->result.ge_result.channelCLinedriver = result.channelCLinedriver; ++ pRtctResult->result.ge_result.channelDLinedriver = result.channelDLinedriver; ++ ++ pRtctResult->result.ge_result.channelAMismatch = result.channelAMismatch; ++ pRtctResult->result.ge_result.channelBMismatch = result.channelBMismatch; ++ pRtctResult->result.ge_result.channelCMismatch = result.channelCMismatch; ++ pRtctResult->result.ge_result.channelDMismatch = result.channelDMismatch; ++ ++ pRtctResult->result.ge_result.channelAOpen = result.channelAOpen; ++ pRtctResult->result.ge_result.channelBOpen = result.channelBOpen; ++ pRtctResult->result.ge_result.channelCOpen = result.channelCOpen; ++ pRtctResult->result.ge_result.channelDOpen = result.channelDOpen; ++ ++ pRtctResult->result.ge_result.channelAShort = result.channelAShort; ++ pRtctResult->result.ge_result.channelBShort = result.channelBShort; ++ pRtctResult->result.ge_result.channelCShort = result.channelCShort; ++ pRtctResult->result.ge_result.channelDShort = result.channelDShort; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_port_sds_reset ++ * Description: ++ * Reset Serdes ++ * Input: ++ * port - Port ID ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port ID. ++ * Note: ++ * The API can reset Serdes ++ */ ++rtk_api_ret_t rtk_port_sds_reset(rtk_port_t port) ++{ ++ rtk_uint32 ext_id; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ if(rtk_switch_isSgmiiPort(port) != RT_ERR_OK) ++ return RT_ERR_PORT_ID; ++ ++ ext_id = port - 15; ++ return rtl8367c_sdsReset(ext_id); ++} ++ ++/* Function Name: ++ * rtk_port_sgmiiLinkStatus_get ++ * Description: ++ * Get SGMII status ++ * Input: ++ * port - Port ID ++ * Output: ++ * pSignalDetect - Signal detect ++ * pSync - Sync ++ * pLink - Link ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port ID. ++ * Note: ++ * The API can reset Serdes ++ */ ++rtk_api_ret_t rtk_port_sgmiiLinkStatus_get(rtk_port_t port, rtk_data_t *pSignalDetect, rtk_data_t *pSync, rtk_port_linkStatus_t *pLink) ++{ ++ rtk_uint32 ext_id; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ if(rtk_switch_isSgmiiPort(port) != RT_ERR_OK) ++ return RT_ERR_PORT_ID; ++ ++ if(NULL == pSignalDetect) ++ return RT_ERR_NULL_POINTER; ++ ++ if(NULL == pSync) ++ return RT_ERR_NULL_POINTER; ++ ++ if(NULL == pLink) ++ return RT_ERR_NULL_POINTER; ++ ++ ext_id = port - 15; ++ return rtl8367c_getSdsLinkStatus(ext_id, (rtk_uint32 *)pSignalDetect, (rtk_uint32 *)pSync, (rtk_uint32 *)pLink); ++} ++ ++/* Function Name: ++ * rtk_port_sgmiiNway_set ++ * Description: ++ * Configure SGMII/HSGMII port Nway state ++ * Input: ++ * port - Port ID ++ * state - Nway state ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port ID. ++ * Note: ++ * The API configure SGMII/HSGMII port Nway state ++ */ ++rtk_api_ret_t rtk_port_sgmiiNway_set(rtk_port_t port, rtk_enable_t state) ++{ ++ rtk_uint32 ext_id; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ if(rtk_switch_isSgmiiPort(port) != RT_ERR_OK) ++ return RT_ERR_PORT_ID; ++ ++ if(state >= RTK_ENABLE_END) ++ return RT_ERR_INPUT; ++ ++ ext_id = port - 15; ++ return rtl8367c_setSgmiiNway(ext_id, (rtk_uint32)state); ++} ++ ++/* Function Name: ++ * rtk_port_sgmiiNway_get ++ * Description: ++ * Get SGMII/HSGMII port Nway state ++ * Input: ++ * port - Port ID ++ * Output: ++ * pState - Nway state ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port ID. ++ * Note: ++ * The API can get SGMII/HSGMII port Nway state ++ */ ++rtk_api_ret_t rtk_port_sgmiiNway_get(rtk_port_t port, rtk_enable_t *pState) ++{ ++ rtk_uint32 ext_id; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ if(rtk_switch_isSgmiiPort(port) != RT_ERR_OK) ++ return RT_ERR_PORT_ID; ++ ++ if(NULL == pState) ++ return RT_ERR_NULL_POINTER; ++ ++ ext_id = port - 15; ++ return rtl8367c_getSgmiiNway(ext_id, (rtk_uint32 *)pState); ++} +diff --git a/drivers/net/phy/rtk/rtl8367c/ptp.c b/drivers/net/phy/rtk/rtl8367c/ptp.c +new file mode 100644 +index 000000000000..af8ce30912dc +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/ptp.c +@@ -0,0 +1,759 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 39583 $ ++ * $Date: 2013-05-20 16:59:23 +0800 (星期一, 20 五月 2013) $ ++ * ++ * Purpose : RTK switch high-level API for RTL8367/RTL8367C ++ * Feature : Here is a list of all functions and variables in time module. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++/* Function Name: ++ * rtk_ptp_init ++ * Description: ++ * PTP function initialization. ++ * Input: ++ * None ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * This API is used to initialize PTP status. ++ */ ++rtk_api_ret_t rtk_ptp_init(void) ++{ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_ptp_mac_set ++ * Description: ++ * Configure PTP mac address. ++ * Input: ++ * mac - mac address to parser PTP packets. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameter. ++ * Note: ++ * None ++ */ ++rtk_api_ret_t rtk_ptp_mac_set(rtk_mac_t mac) ++{ ++ rtk_api_ret_t retVal; ++ ether_addr_t sw_mac; ++ ++ memcpy(sw_mac.octet, mac.octet, ETHER_ADDR_LEN); ++ ++ if((retVal=rtl8367c_setAsicEavMacAddress(sw_mac))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_ptp_mac_get ++ * Description: ++ * Get PTP mac address. ++ * Input: ++ * None ++ * Output: ++ * pMac - mac address to parser PTP packets. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameter. ++ * Note: ++ * None ++ */ ++rtk_api_ret_t rtk_ptp_mac_get(rtk_mac_t *pMac) ++{ ++ rtk_api_ret_t retVal; ++ ether_addr_t sw_mac; ++ ++ if((retVal=rtl8367c_getAsicEavMacAddress(&sw_mac))!=RT_ERR_OK) ++ return retVal; ++ ++ memcpy(pMac->octet, sw_mac.octet, ETHER_ADDR_LEN); ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_ptp_tpid_set ++ * Description: ++ * Configure PTP accepted outer & inner tag TPID. ++ * Input: ++ * outerId - Ether type of S-tag frame parsing in PTP ports. ++ * innerId - Ether type of C-tag frame parsing in PTP ports. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameter. ++ * Note: ++ * None ++ */ ++rtk_api_ret_t rtk_ptp_tpid_set(rtk_ptp_tpid_t outerId, rtk_ptp_tpid_t innerId) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if ((outerId>RTK_MAX_NUM_OF_TPID) ||(innerId>RTK_MAX_NUM_OF_TPID)) ++ return RT_ERR_INPUT; ++ ++ if ((retVal = rtl8367c_setAsicEavTpid(outerId, innerId)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_ptp_tpid_get ++ * Description: ++ * Get PTP accepted outer & inner tag TPID. ++ * Input: ++ * None ++ * Output: ++ * pOuterId - Ether type of S-tag frame parsing in PTP ports. ++ * pInnerId - Ether type of C-tag frame parsing in PTP ports. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++rtk_api_ret_t rtk_ptp_tpid_get(rtk_ptp_tpid_t *pOuterId, rtk_ptp_tpid_t *pInnerId) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if ((retVal = rtl8367c_getAsicEavTpid(pOuterId, pInnerId)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_ptp_refTime_set ++ * Description: ++ * Set the reference time of the specified device. ++ * Input: ++ * timeStamp - reference timestamp value ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_INPUT - invalid input parameter ++ * Applicable: ++ * 8390, 8380 ++ * Note: ++ * None ++ */ ++rtk_api_ret_t rtk_ptp_refTime_set(rtk_ptp_timeStamp_t timeStamp) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (timeStamp.nsec > RTK_MAX_NUM_OF_NANO_SECOND) ++ return RT_ERR_INPUT; ++ ++ if ((retVal = rtl8367c_setAsicEavSysTime(timeStamp.sec, timeStamp.nsec))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_ptp_refTime_get ++ * Description: ++ * Get the reference time of the specified device. ++ * Input: ++ * Output: ++ * pTimeStamp - pointer buffer of the reference time ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_UNIT_ID - invalid unit id ++ * RT_ERR_NOT_INIT - The module is not initial ++ * RT_ERR_NULL_POINTER - input parameter may be null pointer ++ * Applicable: ++ * 8390, 8380 ++ * Note: ++ * None ++ */ ++rtk_api_ret_t rtk_ptp_refTime_get(rtk_ptp_timeStamp_t *pTimeStamp) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if ((retVal = rtl8367c_getAsicEavSysTime(&pTimeStamp->sec, &pTimeStamp->nsec))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_ptp_refTimeAdjust_set ++ * Description: ++ * Adjust the reference time. ++ * Input: ++ * unit - unit id ++ * sign - significant ++ * timeStamp - reference timestamp value ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_UNIT_ID - invalid unit id ++ * RT_ERR_NOT_INIT - The module is not initial ++ * RT_ERR_INPUT - invalid input parameter ++ * Note: ++ * sign=0 for positive adjustment, sign=1 for negative adjustment. ++ */ ++rtk_api_ret_t rtk_ptp_refTimeAdjust_set(rtk_ptp_sys_adjust_t sign, rtk_ptp_timeStamp_t timeStamp) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (timeStamp.nsec > RTK_MAX_NUM_OF_NANO_SECOND) ++ return RT_ERR_INPUT; ++ ++ if ((retVal = rtl8367c_setAsicEavSysTimeAdjust(sign, timeStamp.sec, timeStamp.nsec))!=RT_ERR_OK) ++ return retVal; ++ ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_ptp_refTimeEnable_set ++ * Description: ++ * Set the enable state of reference time of the specified device. ++ * Input: ++ * enable - status ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_INPUT - invalid input parameter ++ * Note: ++ * None ++ */ ++rtk_api_ret_t rtk_ptp_refTimeEnable_set(rtk_enable_t enable) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (enable >= RTK_ENABLE_END) ++ return RT_ERR_ENABLE; ++ ++ if ((retVal = rtl8367c_setAsicEavSysTimeCtrl(enable))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_ptp_refTimeEnable_get ++ * Description: ++ * Get the enable state of reference time of the specified device. ++ * Input: ++ * Output: ++ * pEnable - status ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_UNIT_ID - invalid unit id ++ * RT_ERR_NOT_INIT - The module is not initial ++ * RT_ERR_NULL_POINTER - input parameter may be null pointer ++ * Applicable: ++ * 8390, 8380 ++ * Note: ++ * None ++ */ ++rtk_api_ret_t rtk_ptp_refTimeEnable_get(rtk_enable_t *pEnable) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if ((retVal = rtl8367c_getAsicEavSysTimeCtrl(pEnable))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_ptp_portEnable_set ++ * Description: ++ * Set PTP status of the specified port. ++ * Input: ++ * port - port id ++ * enable - status ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_PORT - invalid port id ++ * RT_ERR_INPUT - invalid input parameter ++ * Note: ++ * None ++ */ ++rtk_api_ret_t rtk_ptp_portEnable_set(rtk_port_t port, rtk_enable_t enable) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check port is PTP port */ ++ RTK_CHK_PORT_IS_PTP(port); ++ ++ if (enable>=RTK_ENABLE_END) ++ return RT_ERR_INPUT; ++ ++ if ((retVal = rtl8367c_setAsicEavPortEnable(rtk_switch_port_L2P_get(port), enable)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_ptp_portEnable_get ++ * Description: ++ * Get PTP status of the specified port. ++ * Input: ++ * port - port id ++ * Output: ++ * pEnable - status ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_PORT - invalid port id ++ * RT_ERR_NULL_POINTER - input parameter may be null pointer ++ * Note: ++ * None ++ */ ++rtk_api_ret_t rtk_ptp_portEnable_get(rtk_port_t port, rtk_enable_t *pEnable) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check port is PTP port */ ++ RTK_CHK_PORT_IS_PTP(port); ++ ++ if ((retVal = rtl8367c_getAsicEavPortEnable(rtk_switch_port_L2P_get(port), pEnable)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++ ++/* Function Name: ++ * rtk_ptp_portTimestamp_get ++ * Description: ++ * Get PTP timestamp according to the PTP identifier on the dedicated port from the specified device. ++ * Input: ++ * unit - unit id ++ * port - port id ++ * type - PTP message type ++ * Output: ++ * pInfo - pointer buffer of sequence ID and timestamp ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_PORT_ID - invalid port id ++ * RT_ERR_INPUT - invalid input parameter ++ * RT_ERR_NULL_POINTER - input parameter may be null pointer ++ * Applicable: ++ * 8390, 8380 ++ * Note: ++ * None ++ */ ++rtk_api_ret_t rtk_ptp_portTimestamp_get( rtk_port_t port, rtk_ptp_msgType_t type, rtk_ptp_info_t *pInfo) ++{ ++ rtk_api_ret_t retVal; ++ rtl8367c_ptp_time_stamp_t time; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check port is PTP port */ ++ RTK_CHK_PORT_IS_PTP(port); ++ ++ if ((retVal = rtl8367c_getAsicEavPortTimeStamp(rtk_switch_port_L2P_get(port), type, &time)) != RT_ERR_OK) ++ return retVal; ++ ++ pInfo->sequenceId = time.sequence_id; ++ pInfo->timeStamp.sec = time.second; ++ pInfo->timeStamp.nsec = time.nano_second; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_ptp_intControl_set ++ * Description: ++ * Set PTP interrupt trigger status configuration. ++ * Input: ++ * type - Interrupt type. ++ * enable - Interrupt status. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_ENABLE - Invalid enable input. ++ * Note: ++ * The API can set PTP interrupt status configuration. ++ * The interrupt trigger status is shown in the following: ++ * PTP_INT_TYPE_TX_SYNC = 0, ++ * PTP_INT_TYPE_TX_DELAY_REQ, ++ * PTP_INT_TYPE_TX_PDELAY_REQ, ++ * PTP_INT_TYPE_TX_PDELAY_RESP, ++ * PTP_INT_TYPE_RX_SYNC, ++ * PTP_INT_TYPE_RX_DELAY_REQ, ++ * PTP_INT_TYPE_RX_PDELAY_REQ, ++ * PTP_INT_TYPE_RX_PDELAY_RESP, ++ * PTP_INT_TYPE_ALL, ++ */ ++rtk_api_ret_t rtk_ptp_intControl_set(rtk_ptp_intType_t type, rtk_enable_t enable) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 mask; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (type>=PTP_INT_TYPE_END) ++ return RT_ERR_INPUT; ++ ++ if (PTP_INT_TYPE_ALL!=type) ++ { ++ if ((retVal = rtl8367c_getAsicEavInterruptMask(&mask)) != RT_ERR_OK) ++ return retVal; ++ ++ if (ENABLED == enable) ++ mask = mask | (1<=PTP_INT_TYPE_ALL) ++ return RT_ERR_INPUT; ++ ++ if ((retVal = rtl8367c_getAsicEavInterruptMask(&mask)) != RT_ERR_OK) ++ return retVal; ++ ++ if (0 == (mask&(1<=RTK_ENABLE_END) ++ return RT_ERR_INPUT; ++ ++ if ((retVal = rtl8367c_setAsicEavTrap(rtk_switch_port_L2P_get(port), enable)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_ptp_portPtpEnable_get ++ * Description: ++ * Get PTP packet trap of the specified port. ++ * Input: ++ * port - port id ++ * Output: ++ * pEnable - status ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_PORT - invalid port id ++ * RT_ERR_NULL_POINTER - input parameter may be null pointer ++ * Note: ++ * None ++ */ ++rtk_api_ret_t rtk_ptp_portTrap_get(rtk_port_t port, rtk_enable_t *pEnable) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if ((retVal = rtl8367c_getAsicEavTrap(rtk_switch_port_L2P_get(port), pEnable)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/qos.c b/drivers/net/phy/rtk/rtl8367c/qos.c +new file mode 100644 +index 000000000000..9bcb49cfbd64 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/qos.c +@@ -0,0 +1,1452 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ ++ * ++ * Purpose : RTK switch high-level API for RTL8367/RTL8367C ++ * Feature : Here is a list of all functions and variables in QoS module. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++/* Function Name: ++ * rtk_qos_init ++ * Description: ++ * Configure QoS default settings with queue number assignment to each port. ++ * Input: ++ * queueNum - Queue number of each port. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_QUEUE_NUM - Invalid queue number. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * This API will initialize related QoS setting with queue number assignment. ++ * The queue number is from 1 to 8. ++ */ ++rtk_api_ret_t rtk_qos_init(rtk_queue_num_t queueNum) ++{ ++ CONST_T rtk_uint16 g_prioritytToQid[8][8]= { ++ {0, 0,0,0,0,0,0,0}, ++ {0, 0,0,0,7,7,7,7}, ++ {0, 0,0,0,1,1,7,7}, ++ {0, 0,1,1,2,2,7,7}, ++ {0, 0,1,1,2,3,7,7}, ++ {0, 0,1,2,3,4,7,7}, ++ {0, 0,1,2,3,4,5,7}, ++ {0,1,2,3,4,5,6,7} ++ }; ++ ++ CONST_T rtk_uint32 g_priorityDecision[8] = {0x01, 0x80,0x04,0x02,0x20,0x40,0x10,0x08}; ++ CONST_T rtk_uint32 g_prioritytRemap[8] = {0,1,2,3,4,5,6,7}; ++ ++ rtk_api_ret_t retVal; ++ rtk_uint32 qmapidx; ++ rtk_uint32 priority; ++ rtk_uint32 priDec; ++ rtk_uint32 port; ++ rtk_uint32 dscp; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (queueNum <= 0 || queueNum > RTK_MAX_NUM_OF_QUEUE) ++ return RT_ERR_QUEUE_NUM; ++ ++ /*Set Output Queue Number*/ ++ if (RTK_MAX_NUM_OF_QUEUE == queueNum) ++ qmapidx = 0; ++ else ++ qmapidx = queueNum; ++ ++ RTK_SCAN_ALL_PHY_PORTMASK(port) ++ { ++ if ((retVal = rtl8367c_setAsicOutputQueueMappingIndex(port, qmapidx)) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ /*Set Priority to Qid*/ ++ for (priority = 0; priority <= RTK_PRIMAX; priority++) ++ { ++ if ((retVal = rtl8367c_setAsicPriorityToQIDMappingTable(queueNum - 1, priority, g_prioritytToQid[queueNum - 1][priority])) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ /*Set Flow Control Type to Ingress Flow Control*/ ++ if ((retVal = rtl8367c_setAsicFlowControlSelect(FC_INGRESS)) != RT_ERR_OK) ++ return retVal; ++ ++ ++ /*Priority Decision Order*/ ++ for (priDec = 0;priDec < PRIDEC_END;priDec++) ++ { ++ if ((retVal = rtl8367c_setAsicPriorityDecision(PRIDECTBL_IDX0, priDec, g_priorityDecision[priDec])) != RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicPriorityDecision(PRIDECTBL_IDX1, priDec, g_priorityDecision[priDec])) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ /*Set Port-based Priority to 0*/ ++ RTK_SCAN_ALL_PHY_PORTMASK(port) ++ { ++ if ((retVal = rtl8367c_setAsicPriorityPortBased(port, 0)) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ /*Disable 1p Remarking*/ ++ RTK_SCAN_ALL_PHY_PORTMASK(port) ++ { ++ if ((retVal = rtl8367c_setAsicRemarkingDot1pAbility(port, DISABLED)) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ /*Disable DSCP Remarking*/ ++ if ((retVal = rtl8367c_setAsicRemarkingDscpAbility(DISABLED)) != RT_ERR_OK) ++ return retVal; ++ ++ /*Set 1p & DSCP Priority Remapping & Remarking*/ ++ for (priority = 0; priority <= RTL8367C_PRIMAX; priority++) ++ { ++ if ((retVal = rtl8367c_setAsicPriorityDot1qRemapping(priority, g_prioritytRemap[priority])) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicRemarkingDot1pParameter(priority, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicRemarkingDscpParameter(priority, 0)) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ /*Set DSCP Priority*/ ++ for (dscp = 0; dscp <= 63; dscp++) ++ { ++ if ((retVal = rtl8367c_setAsicPriorityDscpBased(dscp, 0)) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ /* Fine-tune B/T value */ ++ if((retVal = rtl8367c_setAsicReg(0x1722, 0x1158)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_qos_priSel_set ++ * Description: ++ * Configure the priority order among different priority mechanism. ++ * Input: ++ * index - Priority decision table index (0~1) ++ * pPriDec - Priority assign for port, dscp, 802.1p, cvlan, svlan, acl based priority decision. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_QOS_SEL_PRI_SOURCE - Invalid priority decision source parameter. ++ * Note: ++ * ASIC will follow user priority setting of mechanisms to select mapped queue priority for receiving frame. ++ * If two priority mechanisms are the same, the ASIC will chose the highest priority from mechanisms to ++ * assign queue priority to receiving frame. ++ * The priority sources are: ++ * - PRIDEC_PORT ++ * - PRIDEC_ACL ++ * - PRIDEC_DSCP ++ * - PRIDEC_1Q ++ * - PRIDEC_1AD ++ * - PRIDEC_CVLAN ++ * - PRIDEC_DA ++ * - PRIDEC_SA ++ */ ++rtk_api_ret_t rtk_qos_priSel_set(rtk_qos_priDecTbl_t index, rtk_priority_select_t *pPriDec) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 port_pow; ++ rtk_uint32 dot1q_pow; ++ rtk_uint32 dscp_pow; ++ rtk_uint32 acl_pow; ++ rtk_uint32 svlan_pow; ++ rtk_uint32 cvlan_pow; ++ rtk_uint32 smac_pow; ++ rtk_uint32 dmac_pow; ++ rtk_uint32 i; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (index < 0 || index >= PRIDECTBL_END) ++ return RT_ERR_ENTRY_INDEX; ++ ++ if (pPriDec->port_pri >= 8 || pPriDec->dot1q_pri >= 8 || pPriDec->acl_pri >= 8 || pPriDec->dscp_pri >= 8 || ++ pPriDec->cvlan_pri >= 8 || pPriDec->svlan_pri >= 8 || pPriDec->dmac_pri >= 8 || pPriDec->smac_pri >= 8) ++ return RT_ERR_QOS_SEL_PRI_SOURCE; ++ ++ port_pow = 1; ++ for (i = pPriDec->port_pri; i > 0; i--) ++ port_pow = (port_pow)*2; ++ ++ dot1q_pow = 1; ++ for (i = pPriDec->dot1q_pri; i > 0; i--) ++ dot1q_pow = (dot1q_pow)*2; ++ ++ acl_pow = 1; ++ for (i = pPriDec->acl_pri; i > 0; i--) ++ acl_pow = (acl_pow)*2; ++ ++ dscp_pow = 1; ++ for (i = pPriDec->dscp_pri; i > 0; i--) ++ dscp_pow = (dscp_pow)*2; ++ ++ svlan_pow = 1; ++ for (i = pPriDec->svlan_pri; i > 0; i--) ++ svlan_pow = (svlan_pow)*2; ++ ++ cvlan_pow = 1; ++ for (i = pPriDec->cvlan_pri; i > 0; i--) ++ cvlan_pow = (cvlan_pow)*2; ++ ++ dmac_pow = 1; ++ for (i = pPriDec->dmac_pri; i > 0; i--) ++ dmac_pow = (dmac_pow)*2; ++ ++ smac_pow = 1; ++ for (i = pPriDec->smac_pri; i > 0; i--) ++ smac_pow = (smac_pow)*2; ++ ++ if ((retVal = rtl8367c_setAsicPriorityDecision(index, PRIDEC_PORT, port_pow)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicPriorityDecision(index, PRIDEC_ACL, acl_pow)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicPriorityDecision(index, PRIDEC_DSCP, dscp_pow)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicPriorityDecision(index, PRIDEC_1Q, dot1q_pow)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicPriorityDecision(index, PRIDEC_1AD, svlan_pow)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicPriorityDecision(index, PRIDEC_CVLAN, cvlan_pow)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicPriorityDecision(index, PRIDEC_DA, dmac_pow)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicPriorityDecision(index, PRIDEC_SA, smac_pow)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_qos_priSel_get ++ * Description: ++ * Get the priority order configuration among different priority mechanism. ++ * Input: ++ * index - Priority decision table index (0~1) ++ * Output: ++ * pPriDec - Priority assign for port, dscp, 802.1p, cvlan, svlan, acl based priority decision . ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * ASIC will follow user priority setting of mechanisms to select mapped queue priority for receiving frame. ++ * If two priority mechanisms are the same, the ASIC will chose the highest priority from mechanisms to ++ * assign queue priority to receiving frame. ++ * The priority sources are: ++ * - PRIDEC_PORT, ++ * - PRIDEC_ACL, ++ * - PRIDEC_DSCP, ++ * - PRIDEC_1Q, ++ * - PRIDEC_1AD, ++ * - PRIDEC_CVLAN, ++ * - PRIDEC_DA, ++ * - PRIDEC_SA, ++ */ ++rtk_api_ret_t rtk_qos_priSel_get(rtk_qos_priDecTbl_t index, rtk_priority_select_t *pPriDec) ++{ ++ ++ rtk_api_ret_t retVal; ++ rtk_int32 i; ++ rtk_uint32 port_pow; ++ rtk_uint32 dot1q_pow; ++ rtk_uint32 dscp_pow; ++ rtk_uint32 acl_pow; ++ rtk_uint32 svlan_pow; ++ rtk_uint32 cvlan_pow; ++ rtk_uint32 smac_pow; ++ rtk_uint32 dmac_pow; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (index < 0 || index >= PRIDECTBL_END) ++ return RT_ERR_ENTRY_INDEX; ++ ++ if ((retVal = rtl8367c_getAsicPriorityDecision(index, PRIDEC_PORT, &port_pow)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_getAsicPriorityDecision(index, PRIDEC_ACL, &acl_pow)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_getAsicPriorityDecision(index, PRIDEC_DSCP, &dscp_pow)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_getAsicPriorityDecision(index, PRIDEC_1Q, &dot1q_pow)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_getAsicPriorityDecision(index, PRIDEC_1AD, &svlan_pow)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_getAsicPriorityDecision(index, PRIDEC_CVLAN, &cvlan_pow)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_getAsicPriorityDecision(index, PRIDEC_DA, &dmac_pow)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_getAsicPriorityDecision(index, PRIDEC_SA, &smac_pow)) != RT_ERR_OK) ++ return retVal; ++ ++ for (i = 31; i >= 0; i--) ++ { ++ if (port_pow & (1 << i)) ++ { ++ pPriDec->port_pri = i; ++ break; ++ } ++ } ++ ++ for (i = 31; i >= 0; i--) ++ { ++ if (dot1q_pow & (1 << i)) ++ { ++ pPriDec->dot1q_pri = i; ++ break; ++ } ++ } ++ ++ for (i = 31; i >= 0; i--) ++ { ++ if (acl_pow & (1 << i)) ++ { ++ pPriDec->acl_pri = i; ++ break; ++ } ++ } ++ ++ for (i = 31; i >= 0; i--) ++ { ++ if (dscp_pow & (1 << i)) ++ { ++ pPriDec->dscp_pri = i; ++ break; ++ } ++ } ++ ++ for (i = 31; i >= 0; i--) ++ { ++ if (svlan_pow & (1 << i)) ++ { ++ pPriDec->svlan_pri = i; ++ break; ++ } ++ } ++ ++ for (i = 31;i >= 0; i--) ++ { ++ if (cvlan_pow & (1 << i)) ++ { ++ pPriDec->cvlan_pri = i; ++ break; ++ } ++ } ++ ++ for (i = 31; i >= 0; i--) ++ { ++ if (dmac_pow&(1<dmac_pri = i; ++ break; ++ } ++ } ++ ++ for (i = 31; i >= 0; i--) ++ { ++ if (smac_pow & (1 << i)) ++ { ++ pPriDec->smac_pri = i; ++ break; ++ } ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_qos_1pPriRemap_set ++ * Description: ++ * Configure 1Q priorities mapping to internal absolute priority. ++ * Input: ++ * dot1p_pri - 802.1p priority value. ++ * int_pri - internal priority value. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_VLAN_PRIORITY - Invalid 1p priority. ++ * RT_ERR_QOS_INT_PRIORITY - Invalid priority. ++ * Note: ++ * Priority of 802.1Q assignment for internal asic priority, and it is used for queue usage and packet scheduling. ++ */ ++rtk_api_ret_t rtk_qos_1pPriRemap_set(rtk_pri_t dot1p_pri, rtk_pri_t int_pri) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (dot1p_pri > RTL8367C_PRIMAX || int_pri > RTL8367C_PRIMAX) ++ return RT_ERR_VLAN_PRIORITY; ++ ++ if ((retVal = rtl8367c_setAsicPriorityDot1qRemapping(dot1p_pri, int_pri)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_qos_1pPriRemap_get ++ * Description: ++ * Get 1Q priorities mapping to internal absolute priority. ++ * Input: ++ * dot1p_pri - 802.1p priority value . ++ * Output: ++ * pInt_pri - internal priority value. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_VLAN_PRIORITY - Invalid priority. ++ * RT_ERR_QOS_INT_PRIORITY - Invalid priority. ++ * Note: ++ * Priority of 802.1Q assignment for internal asic priority, and it is used for queue usage and packet scheduling. ++ */ ++rtk_api_ret_t rtk_qos_1pPriRemap_get(rtk_pri_t dot1p_pri, rtk_pri_t *pInt_pri) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (dot1p_pri > RTL8367C_PRIMAX) ++ return RT_ERR_QOS_INT_PRIORITY; ++ ++ if ((retVal = rtl8367c_getAsicPriorityDot1qRemapping(dot1p_pri, pInt_pri)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_qos_dscpPriRemap_set ++ * Description: ++ * Map dscp value to internal priority. ++ * Input: ++ * dscp - Dscp value of receiving frame ++ * int_pri - internal priority value . ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_QOS_DSCP_VALUE - Invalid DSCP value. ++ * RT_ERR_QOS_INT_PRIORITY - Invalid priority. ++ * Note: ++ * The Differentiated Service Code Point is a selector for router's per-hop behaviors. As a selector, there is no implication that a numerically ++ * greater DSCP implies a better network service. As can be seen, the DSCP totally overlaps the old precedence field of TOS. So if values of ++ * DSCP are carefully chosen then backward compatibility can be achieved. ++ */ ++rtk_api_ret_t rtk_qos_dscpPriRemap_set(rtk_dscp_t dscp, rtk_pri_t int_pri) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (int_pri > RTL8367C_PRIMAX ) ++ return RT_ERR_QOS_INT_PRIORITY; ++ ++ if (dscp > RTL8367C_DSCPMAX) ++ return RT_ERR_QOS_DSCP_VALUE; ++ ++ if ((retVal = rtl8367c_setAsicPriorityDscpBased(dscp, int_pri)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_qos_dscpPriRemap_get ++ * Description: ++ * Get dscp value to internal priority. ++ * Input: ++ * dscp - Dscp value of receiving frame ++ * Output: ++ * pInt_pri - internal priority value. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_QOS_DSCP_VALUE - Invalid DSCP value. ++ * Note: ++ * The Differentiated Service Code Point is a selector for router's per-hop behaviors. As a selector, there is no implication that a numerically ++ * greater DSCP implies a better network service. As can be seen, the DSCP totally overlaps the old precedence field of TOS. So if values of ++ * DSCP are carefully chosen then backward compatibility can be achieved. ++ */ ++rtk_api_ret_t rtk_qos_dscpPriRemap_get(rtk_dscp_t dscp, rtk_pri_t *pInt_pri) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (dscp > RTL8367C_DSCPMAX) ++ return RT_ERR_QOS_DSCP_VALUE; ++ ++ if ((retVal = rtl8367c_getAsicPriorityDscpBased(dscp, pInt_pri)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_qos_portPri_set ++ * Description: ++ * Configure priority usage to each port. ++ * Input: ++ * port - Port id. ++ * int_pri - internal priority value. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_QOS_SEL_PORT_PRI - Invalid port priority. ++ * RT_ERR_QOS_INT_PRIORITY - Invalid priority. ++ * Note: ++ * The API can set priority of port assignments for queue usage and packet scheduling. ++ */ ++rtk_api_ret_t rtk_qos_portPri_set(rtk_port_t port, rtk_pri_t int_pri) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if (int_pri > RTL8367C_PRIMAX ) ++ return RT_ERR_QOS_INT_PRIORITY; ++ ++ if ((retVal = rtl8367c_setAsicPriorityPortBased(rtk_switch_port_L2P_get(port), int_pri)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_qos_portPri_get ++ * Description: ++ * Get priority usage to each port. ++ * Input: ++ * port - Port id. ++ * Output: ++ * pInt_pri - internal priority value. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can get priority of port assignments for queue usage and packet scheduling. ++ */ ++rtk_api_ret_t rtk_qos_portPri_get(rtk_port_t port, rtk_pri_t *pInt_pri) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if ((retVal = rtl8367c_getAsicPriorityPortBased(rtk_switch_port_L2P_get(port), pInt_pri)) != RT_ERR_OK) ++ return retVal; ++ ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_qos_queueNum_set ++ * Description: ++ * Set output queue number for each port. ++ * Input: ++ * port - Port id. ++ * index - Mapping queue number (1~8) ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_QUEUE_NUM - Invalid queue number. ++ * Note: ++ * The API can set the output queue number of the specified port. The queue number is from 1 to 8. ++ */ ++rtk_api_ret_t rtk_qos_queueNum_set(rtk_port_t port, rtk_queue_num_t queue_num) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if ((0 == queue_num) || (queue_num > RTK_MAX_NUM_OF_QUEUE)) ++ return RT_ERR_FAILED; ++ ++ if (RTK_MAX_NUM_OF_QUEUE == queue_num) ++ queue_num = 0; ++ ++ if ((retVal = rtl8367c_setAsicOutputQueueMappingIndex(rtk_switch_port_L2P_get(port), queue_num)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_qos_queueNum_get ++ * Description: ++ * Get output queue number. ++ * Input: ++ * port - Port id. ++ * Output: ++ * pQueue_num - Mapping queue number ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * The API will return the output queue number of the specified port. The queue number is from 1 to 8. ++ */ ++rtk_api_ret_t rtk_qos_queueNum_get(rtk_port_t port, rtk_queue_num_t *pQueue_num) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 qidx; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if ((retVal = rtl8367c_getAsicOutputQueueMappingIndex(rtk_switch_port_L2P_get(port), &qidx)) != RT_ERR_OK) ++ return retVal; ++ ++ if (0 == qidx) ++ *pQueue_num = 8; ++ else ++ *pQueue_num = qidx; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_qos_priMap_set ++ * Description: ++ * Set output queue number for each port. ++ * Input: ++ * queue_num - Queue number usage. ++ * pPri2qid - Priority mapping to queue ID. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_QUEUE_NUM - Invalid queue number. ++ * RT_ERR_QUEUE_ID - Invalid queue id. ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_QOS_INT_PRIORITY - Invalid priority. ++ * Note: ++ * ASIC supports priority mapping to queue with different queue number from 1 to 8. ++ * For different queue numbers usage, ASIC supports different internal available queue IDs. ++ */ ++rtk_api_ret_t rtk_qos_priMap_set(rtk_queue_num_t queue_num, rtk_qos_pri2queue_t *pPri2qid) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 pri; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if ((0 == queue_num) || (queue_num > RTK_MAX_NUM_OF_QUEUE)) ++ return RT_ERR_QUEUE_NUM; ++ ++ for (pri = 0; pri <= RTK_PRIMAX; pri++) ++ { ++ if (pPri2qid->pri2queue[pri] > RTK_QIDMAX) ++ return RT_ERR_QUEUE_ID; ++ ++ if ((retVal = rtl8367c_setAsicPriorityToQIDMappingTable(queue_num - 1, pri, pPri2qid->pri2queue[pri])) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_qos_priMap_get ++ * Description: ++ * Get priority to queue ID mapping table parameters. ++ * Input: ++ * queue_num - Queue number usage. ++ * Output: ++ * pPri2qid - Priority mapping to queue ID. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_QUEUE_NUM - Invalid queue number. ++ * Note: ++ * The API can return the mapping queue id of the specified priority and queue number. ++ * The queue number is from 1 to 8. ++ */ ++rtk_api_ret_t rtk_qos_priMap_get(rtk_queue_num_t queue_num, rtk_qos_pri2queue_t *pPri2qid) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 pri; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if ((0 == queue_num) || (queue_num > RTK_MAX_NUM_OF_QUEUE)) ++ return RT_ERR_QUEUE_NUM; ++ ++ for (pri = 0; pri <= RTK_PRIMAX; pri++) ++ { ++ if ((retVal = rtl8367c_getAsicPriorityToQIDMappingTable(queue_num-1, pri, &pPri2qid->pri2queue[pri])) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_qos_schedulingQueue_set ++ * Description: ++ * Set weight and type of queues in dedicated port. ++ * Input: ++ * port - Port id. ++ * pQweights - The array of weights for WRR/WFQ queue (0 for STRICT_PRIORITY queue). ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_QOS_QUEUE_WEIGHT - Invalid queue weight. ++ * Note: ++ * The API can set weight and type, strict priority or weight fair queue (WFQ) for ++ * dedicated port for using queues. If queue id is not included in queue usage, ++ * then its type and weight setting in dummy for setting. There are priorities ++ * as queue id in strict queues. It means strict queue id 5 carrying higher priority ++ * than strict queue id 4. The WFQ queue weight is from 1 to 127, and weight 0 is ++ * for strict priority queue type. ++ */ ++rtk_api_ret_t rtk_qos_schedulingQueue_set(rtk_port_t port, rtk_qos_queue_weights_t *pQweights) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 qid; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ for (qid = 0; qid < RTL8367C_QUEUENO; qid ++) ++ { ++ ++ if (pQweights->weights[qid] > QOS_WEIGHT_MAX) ++ return RT_ERR_QOS_QUEUE_WEIGHT; ++ ++ if (0 == pQweights->weights[qid]) ++ { ++ if ((retVal = rtl8367c_setAsicQueueType(rtk_switch_port_L2P_get(port), qid, QTYPE_STRICT)) != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ { ++ if ((retVal = rtl8367c_setAsicQueueType(rtk_switch_port_L2P_get(port), qid, QTYPE_WFQ)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicWFQWeight(rtk_switch_port_L2P_get(port),qid, pQweights->weights[qid])) != RT_ERR_OK) ++ return retVal; ++ } ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_qos_schedulingQueue_get ++ * Description: ++ * Get weight and type of queues in dedicated port. ++ * Input: ++ * port - Port id. ++ * Output: ++ * pQweights - The array of weights for WRR/WFQ queue (0 for STRICT_PRIORITY queue). ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * The API can get weight and type, strict priority or weight fair queue (WFQ) for dedicated port for using queues. ++ * The WFQ queue weight is from 1 to 127, and weight 0 is for strict priority queue type. ++ */ ++rtk_api_ret_t rtk_qos_schedulingQueue_get(rtk_port_t port, rtk_qos_queue_weights_t *pQweights) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 qid,qtype,qweight; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ for (qid = 0; qid < RTL8367C_QUEUENO; qid++) ++ { ++ if ((retVal = rtl8367c_getAsicQueueType(rtk_switch_port_L2P_get(port), qid, &qtype)) != RT_ERR_OK) ++ return retVal; ++ ++ if (QTYPE_STRICT == qtype) ++ { ++ pQweights->weights[qid] = 0; ++ } ++ else if (QTYPE_WFQ == qtype) ++ { ++ if ((retVal = rtl8367c_getAsicWFQWeight(rtk_switch_port_L2P_get(port), qid, &qweight)) != RT_ERR_OK) ++ return retVal; ++ pQweights->weights[qid] = qweight; ++ } ++ } ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_qos_1pRemarkEnable_set ++ * Description: ++ * Set 1p Remarking state ++ * Input: ++ * port - Port id. ++ * enable - State of per-port 1p Remarking ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_ENABLE - Invalid enable parameter. ++ * Note: ++ * The API can enable or disable 802.1p remarking ability for whole system. ++ * The status of 802.1p remark: ++ * - DISABLED ++ * - ENABLED ++ */ ++rtk_api_ret_t rtk_qos_1pRemarkEnable_set(rtk_port_t port, rtk_enable_t enable) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if (enable >= RTK_ENABLE_END) ++ return RT_ERR_INPUT; ++ ++ if ((retVal = rtl8367c_setAsicRemarkingDot1pAbility(rtk_switch_port_L2P_get(port), enable)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_qos_1pRemarkEnable_get ++ * Description: ++ * Get 802.1p remarking ability. ++ * Input: ++ * port - Port id. ++ * Output: ++ * pEnable - Status of 802.1p remark. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * The API can get 802.1p remarking ability. ++ * The status of 802.1p remark: ++ * - DISABLED ++ * - ENABLED ++ */ ++rtk_api_ret_t rtk_qos_1pRemarkEnable_get(rtk_port_t port, rtk_enable_t *pEnable) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if ((retVal = rtl8367c_getAsicRemarkingDot1pAbility(rtk_switch_port_L2P_get(port), pEnable)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_qos_1pRemark_set ++ * Description: ++ * Set 802.1p remarking parameter. ++ * Input: ++ * int_pri - Internal priority value. ++ * dot1p_pri - 802.1p priority value. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_VLAN_PRIORITY - Invalid 1p priority. ++ * RT_ERR_QOS_INT_PRIORITY - Invalid priority. ++ * Note: ++ * The API can set 802.1p parameters source priority and new priority. ++ */ ++rtk_api_ret_t rtk_qos_1pRemark_set(rtk_pri_t int_pri, rtk_pri_t dot1p_pri) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (int_pri > RTL8367C_PRIMAX ) ++ return RT_ERR_QOS_INT_PRIORITY; ++ ++ if (dot1p_pri > RTL8367C_PRIMAX) ++ return RT_ERR_VLAN_PRIORITY; ++ ++ if ((retVal = rtl8367c_setAsicRemarkingDot1pParameter(int_pri, dot1p_pri)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_qos_1pRemark_get ++ * Description: ++ * Get 802.1p remarking parameter. ++ * Input: ++ * int_pri - Internal priority value. ++ * Output: ++ * pDot1p_pri - 802.1p priority value. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_QOS_INT_PRIORITY - Invalid priority. ++ * Note: ++ * The API can get 802.1p remarking parameters. It would return new priority of ingress priority. ++ */ ++rtk_api_ret_t rtk_qos_1pRemark_get(rtk_pri_t int_pri, rtk_pri_t *pDot1p_pri) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (int_pri > RTL8367C_PRIMAX ) ++ return RT_ERR_QOS_INT_PRIORITY; ++ ++ if ((retVal = rtl8367c_getAsicRemarkingDot1pParameter(int_pri, pDot1p_pri)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_qos_1pRemarkSrcSel_set ++ * Description: ++ * Set remarking source of 802.1p remarking. ++ * Input: ++ * type - remarking source ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_NOT_INIT - The module is not initial ++ * RT_ERR_PORT_ID - invalid port id ++ * RT_ERR_INPUT - invalid input parameter ++ ++ * Note: ++ * The API can configure 802.1p remark functionality to map original 802.1p value or internal ++ * priority to TX DSCP value. ++ */ ++rtk_api_ret_t rtk_qos_1pRemarkSrcSel_set(rtk_qos_1pRmkSrc_t type) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (type >= DOT1P_RMK_SRC_END ) ++ return RT_ERR_QOS_INT_PRIORITY; ++ ++ if ((retVal = rtl8367c_setAsicRemarkingDot1pSrc(type)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_qos_1pRemarkSrcSel_get ++ * Description: ++ * Get remarking source of 802.1p remarking. ++ * Input: ++ * none ++ * Output: ++ * pType - remarking source ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_NOT_INIT - The module is not initial ++ * RT_ERR_PORT_ID - invalid port id ++ * RT_ERR_INPUT - invalid input parameter ++ * RT_ERR_NULL_POINTER - input parameter may be null pointer ++ ++ * Note: ++ * None ++ */ ++rtk_api_ret_t rtk_qos_1pRemarkSrcSel_get(rtk_qos_1pRmkSrc_t *pType) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if ((retVal = rtl8367c_getAsicRemarkingDot1pSrc(pType)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++ ++/* Function Name: ++ * rtk_qos_dscpRemarkEnable_set ++ * Description: ++ * Set DSCP remarking ability. ++ * Input: ++ * port - Port id. ++ * enable - status of DSCP remark. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_QOS_INT_PRIORITY - Invalid priority. ++ * RT_ERR_ENABLE - Invalid enable parameter. ++ * Note: ++ * The API can enable or disable DSCP remarking ability for whole system. ++ * The status of DSCP remark: ++ * - DISABLED ++ * - ENABLED ++ */ ++rtk_api_ret_t rtk_qos_dscpRemarkEnable_set(rtk_port_t port, rtk_enable_t enable) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /*for whole system function, the port value should be 0xFF*/ ++ if (port != RTK_WHOLE_SYSTEM) ++ return RT_ERR_PORT_ID; ++ ++ if (enable >= RTK_ENABLE_END) ++ return RT_ERR_INPUT; ++ ++ if ((retVal = rtl8367c_setAsicRemarkingDscpAbility(enable)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_qos_dscpRemarkEnable_get ++ * Description: ++ * Get DSCP remarking ability. ++ * Input: ++ * port - Port id. ++ * Output: ++ * pEnable - status of DSCP remarking. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * The API can get DSCP remarking ability. ++ * The status of DSCP remark: ++ * - DISABLED ++ * - ENABLED ++ */ ++rtk_api_ret_t rtk_qos_dscpRemarkEnable_get(rtk_port_t port, rtk_enable_t *pEnable) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /*for whole system function, the port value should be 0xFF*/ ++ if (port != RTK_WHOLE_SYSTEM) ++ return RT_ERR_PORT_ID; ++ ++ if ((retVal = rtl8367c_getAsicRemarkingDscpAbility(pEnable)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_qos_dscpRemark_set ++ * Description: ++ * Set DSCP remarking parameter. ++ * Input: ++ * int_pri - Internal priority value. ++ * dscp - DSCP value. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_QOS_INT_PRIORITY - Invalid priority. ++ * RT_ERR_QOS_DSCP_VALUE - Invalid DSCP value. ++ * Note: ++ * The API can set DSCP value and mapping priority. ++ */ ++rtk_api_ret_t rtk_qos_dscpRemark_set(rtk_pri_t int_pri, rtk_dscp_t dscp) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (int_pri > RTK_PRIMAX ) ++ return RT_ERR_QOS_INT_PRIORITY; ++ ++ if (dscp > RTK_DSCPMAX) ++ return RT_ERR_QOS_DSCP_VALUE; ++ ++ if ((retVal = rtl8367c_setAsicRemarkingDscpParameter(int_pri, dscp)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++ ++/* Function Name: ++ * rtk_qos_dscpRemark_get ++ * Description: ++ * Get DSCP remarking parameter. ++ * Input: ++ * int_pri - Internal priority value. ++ * Output: ++ * Dscp - DSCP value. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_QOS_INT_PRIORITY - Invalid priority. ++ * Note: ++ * The API can get DSCP parameters. It would return DSCP value for mapping priority. ++ */ ++rtk_api_ret_t rtk_qos_dscpRemark_get(rtk_pri_t int_pri, rtk_dscp_t *pDscp) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (int_pri > RTK_PRIMAX ) ++ return RT_ERR_QOS_INT_PRIORITY; ++ ++ if ((retVal = rtl8367c_getAsicRemarkingDscpParameter(int_pri, pDscp)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_qos_dscpRemarkSrcSel_set ++ * Description: ++ * Set remarking source of DSCP remarking. ++ * Input: ++ * type - remarking source ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_NOT_INIT - The module is not initial ++ * RT_ERR_PORT_ID - invalid port id ++ * RT_ERR_INPUT - invalid input parameter ++ ++ * Note: ++ * The API can configure DSCP remark functionality to map original DSCP value or internal ++ * priority to TX DSCP value. ++ */ ++rtk_api_ret_t rtk_qos_dscpRemarkSrcSel_set(rtk_qos_dscpRmkSrc_t type) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (type >= DSCP_RMK_SRC_END ) ++ return RT_ERR_QOS_INT_PRIORITY; ++ ++ if ((retVal = rtl8367c_setAsicRemarkingDscpSrc(type)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_qos_dcpRemarkSrcSel_get ++ * Description: ++ * Get remarking source of DSCP remarking. ++ * Input: ++ * none ++ * Output: ++ * pType - remarking source ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_NOT_INIT - The module is not initial ++ * RT_ERR_PORT_ID - invalid port id ++ * RT_ERR_INPUT - invalid input parameter ++ * RT_ERR_NULL_POINTER - input parameter may be null pointer ++ ++ * Note: ++ * None ++ */ ++rtk_api_ret_t rtk_qos_dscpRemarkSrcSel_get(rtk_qos_dscpRmkSrc_t *pType) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if ((retVal = rtl8367c_getAsicRemarkingDscpSrc(pType)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_qos_dscpRemark2Dscp_set ++ * Description: ++ * Set DSCP to remarked DSCP mapping. ++ * Input: ++ * dscp - DSCP value ++ * rmkDscp - remarked DSCP value ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_QOS_DSCP_VALUE - Invalid dscp value ++ * Note: ++ * dscp parameter can be DSCP value or internal priority according to configuration of API ++ * dal_apollomp_qos_dscpRemarkSrcSel_set(), because DSCP remark functionality can map original DSCP ++ * value or internal priority to TX DSCP value. ++ */ ++rtk_api_ret_t rtk_qos_dscpRemark2Dscp_set(rtk_dscp_t dscp, rtk_dscp_t rmkDscp) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if ((dscp > RTK_DSCPMAX) || (rmkDscp > RTK_DSCPMAX)) ++ return RT_ERR_QOS_DSCP_VALUE; ++ ++ if ((retVal = rtl8367c_setAsicRemarkingDscp2Dscp(dscp, rmkDscp)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_qos_dscpRemark2Dscp_get ++ * Description: ++ * Get DSCP to remarked DSCP mapping. ++ * Input: ++ * dscp - DSCP value ++ * Output: ++ * pDscp - remarked DSCP value ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_QOS_DSCP_VALUE - Invalid dscp value ++ * RT_ERR_NULL_POINTER - NULL pointer ++ * Note: ++ * None. ++ */ ++rtk_api_ret_t rtk_qos_dscpRemark2Dscp_get(rtk_dscp_t dscp, rtk_dscp_t *pDscp) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (dscp > RTK_DSCPMAX) ++ return RT_ERR_QOS_DSCP_VALUE; ++ ++ if ((retVal = rtl8367c_getAsicRemarkingDscp2Dscp(dscp, pDscp)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_qos_portPriSelIndex_set ++ * Description: ++ * Configure priority decision index to each port. ++ * Input: ++ * port - Port id. ++ * index - priority decision index. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_ENTRY_INDEX - Invalid entry index. ++ * Note: ++ * The API can set priority of port assignments for queue usage and packet scheduling. ++ */ ++rtk_api_ret_t rtk_qos_portPriSelIndex_set(rtk_port_t port, rtk_qos_priDecTbl_t index) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if (index >= PRIDECTBL_END ) ++ return RT_ERR_ENTRY_INDEX; ++ ++ if ((retVal = rtl8367c_setAsicPortPriorityDecisionIndex(rtk_switch_port_L2P_get(port), index)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_qos_portPriSelIndex_get ++ * Description: ++ * Get priority decision index from each port. ++ * Input: ++ * port - Port id. ++ * Output: ++ * pIndex - priority decision index. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * The API can get priority of port assignments for queue usage and packet scheduling. ++ */ ++rtk_api_ret_t rtk_qos_portPriSelIndex_get(rtk_port_t port, rtk_qos_priDecTbl_t *pIndex) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if ((retVal = rtl8367c_getAsicPortPriorityDecisionIndex(rtk_switch_port_L2P_get(port), pIndex)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/rate.c b/drivers/net/phy/rtk/rtl8367c/rate.c +new file mode 100644 +index 000000000000..a077e0c5cc16 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/rate.c +@@ -0,0 +1,607 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ ++ * ++ * Purpose : RTK switch high-level API for RTL8367/RTL8367C ++ * Feature : Here is a list of all functions and variables in rate module. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++/* Function Name: ++ * rtk_rate_shareMeter_set ++ * Description: ++ * Set meter configuration ++ * Input: ++ * index - shared meter index ++ * type - shared meter type ++ * rate - rate of share meter ++ * ifg_include - include IFG or not, ENABLE:include DISABLE:exclude ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_FILTER_METER_ID - Invalid meter ++ * RT_ERR_RATE - Invalid rate ++ * RT_ERR_INPUT - Invalid input parameters ++ * Note: ++ * The API can set shared meter rate and ifg include for each meter. ++ * The rate unit is 1 kbps and the range is from 8k to 1048568k if type is METER_TYPE_KBPS and ++ * the granularity of rate is 8 kbps. ++ * The rate unit is packets per second and the range is 1 ~ 0x1FFF if type is METER_TYPE_PPS. ++ * The ifg_include parameter is used ++ * for rate calculation with/without inter-frame-gap and preamble. ++ */ ++rtk_api_ret_t rtk_rate_shareMeter_set(rtk_meter_id_t index, rtk_meter_type_t type, rtk_rate_t rate, rtk_enable_t ifg_include) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (index > RTK_MAX_METER_ID) ++ return RT_ERR_FILTER_METER_ID; ++ ++ if (type >= METER_TYPE_END) ++ return RT_ERR_INPUT; ++ ++ if (ifg_include >= RTK_ENABLE_END) ++ return RT_ERR_INPUT; ++ ++ switch (type) ++ { ++ case METER_TYPE_KBPS: ++ if (rate > RTL8367C_QOS_RATE_INPUT_MAX_HSG || rate < RTL8367C_QOS_RATE_INPUT_MIN) ++ return RT_ERR_RATE ; ++ ++ if ((retVal = rtl8367c_setAsicShareMeter(index, rate >> 3, ifg_include)) != RT_ERR_OK) ++ return retVal; ++ ++ break; ++ case METER_TYPE_PPS: ++ if (rate > RTL8367C_QOS_PPS_INPUT_MAX || rate < RTL8367C_QOS_PPS_INPUT_MIN) ++ return RT_ERR_RATE ; ++ ++ if ((retVal = rtl8367c_setAsicShareMeter(index, rate, ifg_include)) != RT_ERR_OK) ++ return retVal; ++ ++ break; ++ default: ++ return RT_ERR_INPUT; ++ } ++ ++ /* Set Type */ ++ if ((retVal = rtl8367c_setAsicShareMeterType(index, (rtk_uint32)type)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_rate_shareMeter_get ++ * Description: ++ * Get meter configuration ++ * Input: ++ * index - shared meter index ++ * Output: ++ * pType - Meter Type ++ * pRate - pointer of rate of share meter ++ * pIfg_include - include IFG or not, ENABLE:include DISABLE:exclude ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_FILTER_METER_ID - Invalid meter ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_rate_shareMeter_get(rtk_meter_id_t index, rtk_meter_type_t *pType, rtk_rate_t *pRate, rtk_enable_t *pIfg_include) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 regData; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (index > RTK_MAX_METER_ID) ++ return RT_ERR_FILTER_METER_ID; ++ ++ if(NULL == pType) ++ return RT_ERR_NULL_POINTER; ++ ++ if(NULL == pRate) ++ return RT_ERR_NULL_POINTER; ++ ++ if(NULL == pIfg_include) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicShareMeter(index, ®Data, pIfg_include)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_getAsicShareMeterType(index, (rtk_uint32 *)pType)) != RT_ERR_OK) ++ return retVal; ++ ++ if(*pType == METER_TYPE_KBPS) ++ *pRate = regData<<3; ++ else ++ *pRate = regData; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_rate_shareMeterBucket_set ++ * Description: ++ * Set meter Bucket Size ++ * Input: ++ * index - shared meter index ++ * bucket_size - Bucket Size ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_INPUT - Error Input ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_FILTER_METER_ID - Invalid meter ++ * Note: ++ * The API can set shared meter bucket size. ++ */ ++rtk_api_ret_t rtk_rate_shareMeterBucket_set(rtk_meter_id_t index, rtk_uint32 bucket_size) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (index > RTK_MAX_METER_ID) ++ return RT_ERR_FILTER_METER_ID; ++ ++ if(bucket_size > RTL8367C_METERBUCKETSIZEMAX) ++ return RT_ERR_INPUT; ++ ++ if ((retVal = rtl8367c_setAsicShareMeterBucketSize(index, bucket_size)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_rate_shareMeterBucket_get ++ * Description: ++ * Get meter Bucket Size ++ * Input: ++ * index - shared meter index ++ * Output: ++ * pBucket_size - Bucket Size ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_FILTER_METER_ID - Invalid meter ++ * Note: ++ * The API can get shared meter bucket size. ++ */ ++rtk_api_ret_t rtk_rate_shareMeterBucket_get(rtk_meter_id_t index, rtk_uint32 *pBucket_size) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (index > RTK_MAX_METER_ID) ++ return RT_ERR_FILTER_METER_ID; ++ ++ if(NULL == pBucket_size) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicShareMeterBucketSize(index, pBucket_size)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_rate_igrBandwidthCtrlRate_set ++ * Description: ++ * Set port ingress bandwidth control ++ * Input: ++ * port - Port id ++ * rate - Rate of share meter ++ * ifg_include - include IFG or not, ENABLE:include DISABLE:exclude ++ * fc_enable - enable flow control or not, ENABLE:use flow control DISABLE:drop ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_ENABLE - Invalid IFG parameter. ++ * RT_ERR_INBW_RATE - Invalid ingress rate parameter. ++ * Note: ++ * The rate unit is 1 kbps and the range is from 8k to 1048568k. The granularity of rate is 8 kbps. ++ * The ifg_include parameter is used for rate calculation with/without inter-frame-gap and preamble. ++ */ ++rtk_api_ret_t rtk_rate_igrBandwidthCtrlRate_set(rtk_port_t port, rtk_rate_t rate, rtk_enable_t ifg_include, rtk_enable_t fc_enable) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if(ifg_include >= RTK_ENABLE_END) ++ return RT_ERR_INPUT; ++ ++ if(fc_enable >= RTK_ENABLE_END) ++ return RT_ERR_INPUT; ++ ++ if(rtk_switch_isHsgPort(port) == RT_ERR_OK) ++ { ++ if ((rate > RTL8367C_QOS_RATE_INPUT_MAX_HSG) || (rate < RTL8367C_QOS_RATE_INPUT_MIN)) ++ return RT_ERR_QOS_EBW_RATE ; ++ } ++ else ++ { ++ if ((rate > RTL8367C_QOS_RATE_INPUT_MAX) || (rate < RTL8367C_QOS_RATE_INPUT_MIN)) ++ return RT_ERR_QOS_EBW_RATE ; ++ } ++ ++ if ((retVal = rtl8367c_setAsicPortIngressBandwidth(rtk_switch_port_L2P_get(port), rate>>3, ifg_include,fc_enable)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_rate_igrBandwidthCtrlRate_get ++ * Description: ++ * Get port ingress bandwidth control ++ * Input: ++ * port - Port id ++ * Output: ++ * pRate - Rate of share meter ++ * pIfg_include - Rate's calculation including IFG, ENABLE:include DISABLE:exclude ++ * pFc_enable - enable flow control or not, ENABLE:use flow control DISABLE:drop ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The rate unit is 1 kbps and the range is from 8k to 1048568k. The granularity of rate is 8 kbps. ++ * The ifg_include parameter is used for rate calculation with/without inter-frame-gap and preamble. ++ */ ++rtk_api_ret_t rtk_rate_igrBandwidthCtrlRate_get(rtk_port_t port, rtk_rate_t *pRate, rtk_enable_t *pIfg_include, rtk_enable_t *pFc_enable) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 regData; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if(NULL == pIfg_include) ++ return RT_ERR_NULL_POINTER; ++ ++ if(NULL == pFc_enable) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicPortIngressBandwidth(rtk_switch_port_L2P_get(port), ®Data, pIfg_include, pFc_enable)) != RT_ERR_OK) ++ return retVal; ++ ++ *pRate = regData<<3; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_rate_egrBandwidthCtrlRate_set ++ * Description: ++ * Set port egress bandwidth control ++ * Input: ++ * port - Port id ++ * rate - Rate of egress bandwidth ++ * ifg_include - include IFG or not, ENABLE:include DISABLE:exclude ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_QOS_EBW_RATE - Invalid egress bandwidth/rate ++ * Note: ++ * The rate unit is 1 kbps and the range is from 8k to 1048568k. The granularity of rate is 8 kbps. ++ * The ifg_include parameter is used for rate calculation with/without inter-frame-gap and preamble. ++ */ ++rtk_api_ret_t rtk_rate_egrBandwidthCtrlRate_set( rtk_port_t port, rtk_rate_t rate, rtk_enable_t ifg_include) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if(rtk_switch_isHsgPort(port) == RT_ERR_OK) ++ { ++ if ((rate > RTL8367C_QOS_RATE_INPUT_MAX_HSG) || (rate < RTL8367C_QOS_RATE_INPUT_MIN)) ++ return RT_ERR_QOS_EBW_RATE ; ++ } ++ else ++ { ++ if ((rate > RTL8367C_QOS_RATE_INPUT_MAX) || (rate < RTL8367C_QOS_RATE_INPUT_MIN)) ++ return RT_ERR_QOS_EBW_RATE ; ++ } ++ ++ if (ifg_include >= RTK_ENABLE_END) ++ return RT_ERR_ENABLE; ++ ++ if ((retVal = rtl8367c_setAsicPortEgressRate(rtk_switch_port_L2P_get(port), rate>>3)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicPortEgressRateIfg(ifg_include)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_rate_egrBandwidthCtrlRate_get ++ * Description: ++ * Get port egress bandwidth control ++ * Input: ++ * port - Port id ++ * Output: ++ * pRate - Rate of egress bandwidth ++ * pIfg_include - Rate's calculation including IFG, ENABLE:include DISABLE:exclude ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The rate unit is 1 kbps and the range is from 8k to 1048568k. The granularity of rate is 8 kbps. ++ * The ifg_include parameter is used for rate calculation with/without inter-frame-gap and preamble. ++ */ ++rtk_api_ret_t rtk_rate_egrBandwidthCtrlRate_get(rtk_port_t port, rtk_rate_t *pRate, rtk_enable_t *pIfg_include) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 regData; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if(NULL == pRate) ++ return RT_ERR_NULL_POINTER; ++ ++ if(NULL == pIfg_include) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicPortEgressRate(rtk_switch_port_L2P_get(port), ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ *pRate = regData << 3; ++ ++ if ((retVal = rtl8367c_getAsicPortEgressRateIfg((rtk_uint32*)pIfg_include)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++ ++/* Function Name: ++ * rtk_rate_egrQueueBwCtrlEnable_get ++ * Description: ++ * Get enable status of egress bandwidth control on specified queue. ++ * Input: ++ * unit - unit id ++ * port - port id ++ * queue - queue id ++ * Output: ++ * pEnable - Pointer to enable status of egress queue bandwidth control ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_PORT_ID - invalid port id ++ * RT_ERR_QUEUE_ID - invalid queue id ++ * RT_ERR_NULL_POINTER - input parameter may be null pointer ++ * Note: ++ * None ++ */ ++rtk_api_ret_t rtk_rate_egrQueueBwCtrlEnable_get(rtk_port_t port, rtk_qid_t queue, rtk_enable_t *pEnable) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ /*for whole port function, the queue value should be 0xFF*/ ++ if (queue != RTK_WHOLE_SYSTEM) ++ return RT_ERR_QUEUE_ID; ++ ++ if(NULL == pEnable) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicAprEnable(rtk_switch_port_L2P_get(port),pEnable))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_rate_egrQueueBwCtrlEnable_set ++ * Description: ++ * Set enable status of egress bandwidth control on specified queue. ++ * Input: ++ * port - port id ++ * queue - queue id ++ * enable - enable status of egress queue bandwidth control ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_PORT_ID - invalid port id ++ * RT_ERR_QUEUE_ID - invalid queue id ++ * RT_ERR_INPUT - invalid input parameter ++ * Note: ++ * None ++ */ ++rtk_api_ret_t rtk_rate_egrQueueBwCtrlEnable_set(rtk_port_t port, rtk_qid_t queue, rtk_enable_t enable) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ /*for whole port function, the queue value should be 0xFF*/ ++ if (queue != RTK_WHOLE_SYSTEM) ++ return RT_ERR_QUEUE_ID; ++ ++ if (enable>=RTK_ENABLE_END) ++ return RT_ERR_INPUT; ++ ++ if ((retVal = rtl8367c_setAsicAprEnable(rtk_switch_port_L2P_get(port), enable))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_rate_egrQueueBwCtrlRate_get ++ * Description: ++ * Get rate of egress bandwidth control on specified queue. ++ * Input: ++ * port - port id ++ * queue - queue id ++ * pIndex - shared meter index ++ * Output: ++ * pRate - pointer to rate of egress queue bandwidth control ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_PORT_ID - invalid port id ++ * RT_ERR_QUEUE_ID - invalid queue id ++ * RT_ERR_FILTER_METER_ID - Invalid meter id ++ * Note: ++ * The actual rate control is set in shared meters. ++ * The unit of granularity is 8Kbps. ++ */ ++rtk_api_ret_t rtk_rate_egrQueueBwCtrlRate_get(rtk_port_t port, rtk_qid_t queue, rtk_meter_id_t *pIndex) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 offset_idx; ++ rtk_uint32 phy_port; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if (queue >= RTK_MAX_NUM_OF_QUEUE) ++ return RT_ERR_QUEUE_ID; ++ ++ if(NULL == pIndex) ++ return RT_ERR_NULL_POINTER; ++ ++ phy_port = rtk_switch_port_L2P_get(port); ++ if ((retVal=rtl8367c_getAsicAprMeter(phy_port, queue,&offset_idx))!=RT_ERR_OK) ++ return retVal; ++ ++ *pIndex = offset_idx + ((phy_port%4)*8); ++ ++ return RT_ERR_OK; ++} ++ ++ ++/* Function Name: ++ * rtk_rate_egrQueueBwCtrlRate_set ++ * Description: ++ * Set rate of egress bandwidth control on specified queue. ++ * Input: ++ * port - port id ++ * queue - queue id ++ * index - shared meter index ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_PORT_ID - invalid port id ++ * RT_ERR_QUEUE_ID - invalid queue id ++ * RT_ERR_FILTER_METER_ID - Invalid meter id ++ * Note: ++ * The actual rate control is set in shared meters. ++ * The unit of granularity is 8Kbps. ++ */ ++rtk_api_ret_t rtk_rate_egrQueueBwCtrlRate_set(rtk_port_t port, rtk_qid_t queue, rtk_meter_id_t index) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 offset_idx; ++ rtk_uint32 phy_port; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if (queue >= RTK_MAX_NUM_OF_QUEUE) ++ return RT_ERR_QUEUE_ID; ++ ++ if (index > RTK_MAX_METER_ID) ++ return RT_ERR_FILTER_METER_ID; ++ ++ phy_port = rtk_switch_port_L2P_get(port); ++ if (index < ((phy_port%4)*8) || index > (7 + (phy_port%4)*8)) ++ return RT_ERR_FILTER_METER_ID; ++ ++ offset_idx = index - ((phy_port%4)*8); ++ ++ if ((retVal=rtl8367c_setAsicAprMeter(phy_port,queue,offset_idx))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/rldp.c b/drivers/net/phy/rtk/rtl8367c/rldp.c +new file mode 100644 +index 000000000000..0ecc32a6b571 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/rldp.c +@@ -0,0 +1,468 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ ++ * ++ * Purpose : Declaration of RLDP and RLPP API ++ * ++ * Feature : The file have include the following module and sub-modules ++ * 1) RLDP and RLPP configuration and status ++ * ++ */ ++ ++ ++/* ++ * Include Files ++ */ ++#include ++#include ++//#include ++#include ++ ++#include ++#include ++ ++/* ++ * Symbol Definition ++ */ ++ ++ ++/* ++ * Data Declaration ++ */ ++ ++ ++/* ++ * Macro Declaration ++ */ ++ ++ ++/* ++ * Function Declaration ++ */ ++ ++/* Module Name : RLDP */ ++ ++/* Function Name: ++ * rtk_rldp_config_set ++ * Description: ++ * Set RLDP module configuration ++ * Input: ++ * pConfig - configuration structure of RLDP ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_INPUT ++ * RT_ERR_NULL_POINTER ++ * Note: ++ * None ++ */ ++rtk_api_ret_t rtk_rldp_config_set(rtk_rldp_config_t *pConfig) ++{ ++ rtk_api_ret_t retVal; ++ ether_addr_t magic; ++ rtk_uint32 pmsk; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (pConfig->rldp_enable >= RTK_ENABLE_END) ++ return RT_ERR_INPUT; ++ ++ if (pConfig->trigger_mode >= RTK_RLDP_TRIGGER_END) ++ return RT_ERR_INPUT; ++ ++ if (pConfig->compare_type >= RTK_RLDP_CMPTYPE_END) ++ return RT_ERR_INPUT; ++ ++ if (pConfig->num_check >= RTK_RLDP_NUM_MAX) ++ return RT_ERR_INPUT; ++ ++ if (pConfig->interval_check >= RTK_RLDP_INTERVAL_MAX) ++ return RT_ERR_INPUT; ++ ++ if (pConfig->num_loop >= RTK_RLDP_NUM_MAX) ++ return RT_ERR_INPUT; ++ ++ if (pConfig->interval_loop >= RTK_RLDP_INTERVAL_MAX) ++ return RT_ERR_INPUT; ++ ++ if ((retVal = rtl8367c_getAsicRldpTxPortmask(&pmsk))!=RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicRldpTxPortmask(0x00))!=RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicRldpTxPortmask(pmsk))!=RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicRldp(pConfig->rldp_enable))!=RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicRldpTriggerMode(pConfig->trigger_mode))!=RT_ERR_OK) ++ return retVal; ++ ++ memcpy(&magic, &pConfig->magic, sizeof(ether_addr_t)); ++ if ((retVal = rtl8367c_setAsicRldpMagicNum(magic))!=RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicRldpCompareRandomNumber(pConfig->compare_type))!=RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicRldpCompareRandomNumber(pConfig->compare_type))!=RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicRldpCheckingStatePara(pConfig->num_check, pConfig->interval_check))!=RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicRldpLoopStatePara(pConfig->num_loop, pConfig->interval_loop))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++ ++/* Function Name: ++ * rtk_rldp_config_get ++ * Description: ++ * Get RLDP module configuration ++ * Input: ++ * None ++ * Output: ++ * pConfig - configuration structure of RLDP ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_INPUT ++ * RT_ERR_NULL_POINTER ++ * Note: ++ * None ++ */ ++rtk_api_ret_t rtk_rldp_config_get(rtk_rldp_config_t *pConfig) ++{ ++ rtk_api_ret_t retVal; ++ ether_addr_t magic; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if ((retVal = rtl8367c_getAsicRldp(&pConfig->rldp_enable))!=RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_getAsicRldpTriggerMode(&pConfig->trigger_mode))!=RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_getAsicRldpMagicNum(&magic))!=RT_ERR_OK) ++ return retVal; ++ memcpy(&pConfig->magic, &magic, sizeof(ether_addr_t)); ++ ++ if ((retVal = rtl8367c_getAsicRldpCompareRandomNumber(&pConfig->compare_type))!=RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_getAsicRldpCompareRandomNumber(&pConfig->compare_type))!=RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_getAsicRldpCheckingStatePara(&pConfig->num_check, &pConfig->interval_check))!=RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_getAsicRldpLoopStatePara(&pConfig->num_loop, &pConfig->interval_loop))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++ ++/* Function Name: ++ * rtk_rldp_portConfig_set ++ * Description: ++ * Set per port RLDP module configuration ++ * Input: ++ * port - port number to be configured ++ * pPortConfig - per port configuration structure of RLDP ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_INPUT ++ * RT_ERR_NULL_POINTER ++ * Note: ++ * None ++ */ ++rtk_api_ret_t rtk_rldp_portConfig_set(rtk_port_t port, rtk_rldp_portConfig_t *pPortConfig) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 pmsk; ++ rtk_uint32 phy_port; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if (pPortConfig->tx_enable>= RTK_ENABLE_END) ++ return RT_ERR_INPUT; ++ ++ phy_port = rtk_switch_port_L2P_get(port); ++ ++ if ((retVal = rtl8367c_getAsicRldpTxPortmask(&pmsk))!=RT_ERR_OK) ++ return retVal; ++ ++ if (pPortConfig->tx_enable) ++ { ++ pmsk |=(1<tx_enable = ENABLED; ++ } ++ else ++ { ++ pPortConfig->tx_enable = DISABLED; ++ } ++ ++ return RT_ERR_OK; ++} /* end of rtk_rldp_portConfig_get */ ++ ++ ++/* Function Name: ++ * rtk_rldp_status_get ++ * Description: ++ * Get RLDP module status ++ * Input: ++ * None ++ * Output: ++ * pStatus - status structure of RLDP ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_NULL_POINTER ++ * Note: ++ * None ++ */ ++rtk_api_ret_t rtk_rldp_status_get(rtk_rldp_status_t *pStatus) ++{ ++ rtk_api_ret_t retVal; ++ ether_addr_t seed; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if ((retVal = rtl8367c_getAsicRldpRandomNumber(&seed))!=RT_ERR_OK) ++ return retVal; ++ memcpy(&pStatus->id, &seed, sizeof(ether_addr_t)); ++ ++ return RT_ERR_OK; ++} /* end of rtk_rldp_status_get */ ++ ++ ++/* Function Name: ++ * rtk_rldp_portStatus_get ++ * Description: ++ * Get RLDP module status ++ * Input: ++ * port - port number to be get ++ * Output: ++ * pPortStatus - per port status structure of RLDP ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_INPUT ++ * RT_ERR_NULL_POINTER ++ * Note: ++ * None ++ */ ++rtk_api_ret_t rtk_rldp_portStatus_get(rtk_port_t port, rtk_rldp_portStatus_t *pPortStatus) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 pmsk; ++ rtk_portmask_t logicalPmask; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if ((retVal = rtl8367c_getAsicRldpLoopedPortmask(&pmsk))!=RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtk_switch_portmask_P2L_get(pmsk, &logicalPmask)) != RT_ERR_OK) ++ return retVal; ++ ++ if (logicalPmask.bits[0] & (1<loop_status = RTK_RLDP_LOOPSTS_LOOPING; ++ } ++ else ++ { ++ pPortStatus->loop_status = RTK_RLDP_LOOPSTS_NONE; ++ } ++ ++ if ((retVal = rtl8367c_getAsicRldpEnterLoopedPortmask(&pmsk))!=RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtk_switch_portmask_P2L_get(pmsk, &logicalPmask)) != RT_ERR_OK) ++ return retVal; ++ ++ if (logicalPmask.bits[0] & (1<loop_enter = RTK_RLDP_LOOPSTS_LOOPING; ++ } ++ else ++ { ++ pPortStatus->loop_enter = RTK_RLDP_LOOPSTS_NONE; ++ } ++ ++ if ((retVal = rtl8367c_getAsicRldpLeaveLoopedPortmask(&pmsk))!=RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtk_switch_portmask_P2L_get(pmsk, &logicalPmask)) != RT_ERR_OK) ++ return retVal; ++ ++ if (logicalPmask.bits[0] & (1<loop_leave = RTK_RLDP_LOOPSTS_LOOPING; ++ } ++ else ++ { ++ pPortStatus->loop_leave = RTK_RLDP_LOOPSTS_NONE; ++ } ++ ++ return RT_ERR_OK; ++} ++ ++ ++/* Function Name: ++ * rtk_rldp_portStatus_clear ++ * Description: ++ * Clear RLDP module status ++ * Input: ++ * port - port number to be clear ++ * pPortStatus - per port status structure of RLDP ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_INPUT ++ * RT_ERR_NULL_POINTER ++ * Note: ++ * Clear operation effect loop_enter and loop_leave only, other field in ++ * the structure are don't care. Loop status can't be clean. ++ */ ++rtk_api_ret_t rtk_rldp_portStatus_set(rtk_port_t port, rtk_rldp_portStatus_t *pPortStatus) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 pmsk; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ pmsk = (pPortStatus->loop_enter)<loop_leave)< ++#include ++#include "./include/rtk_switch.h" ++#include "./include/vlan.h" ++#include "./include/port.h" ++#include "./include/rate.h" ++#include "./include/rtk_hal.h" ++#include "./include/l2.h" ++#include "./include/stat.h" ++#include "./include/igmp.h" ++#include "./include/trap.h" ++#include "./include/leaky.h" ++#include "./include/mirror.h" ++#include "./include/rtl8367c_asicdrv_port.h" ++#include "./include/rtl8367c_asicdrv_mib.h" ++#include "./include/smi.h" ++#include "./include/qos.h" ++#include "./include/trunk.h" ++ ++void rtk_hal_switch_init(void) ++{ ++ if(rtk_switch_init() != 0) ++ printk("rtk_switch_init failed\n"); ++ mdelay(500); ++ /*vlan init */ ++ if (rtk_vlan_init() != 0) ++ printk("rtk_vlan_init failed\n"); ++} ++ ++void rtk_hal_dump_full_mib(void) ++{ ++ rtk_port_t port; ++ rtk_stat_counter_t Cntr; ++ rtk_stat_port_type_t cntr_idx; ++ ++ for (port = UTP_PORT0; port < (UTP_PORT0 + 5); port++) { ++ printk("\nPort%d\n", port); ++ for (cntr_idx = STAT_IfInOctets; cntr_idx < STAT_PORT_CNTR_END; cntr_idx ++) { ++ rtk_stat_port_get(port, cntr_idx, &Cntr); ++ printk("%8llu ", Cntr); ++ if (((cntr_idx%10) == 9)) ++ printk("\n"); ++ } ++ } ++ ++ for (port = EXT_PORT0; port < (EXT_PORT0 + 2); port++) { ++ printk("\nPort%d\n", port); ++ for (cntr_idx = STAT_IfInOctets; cntr_idx < STAT_PORT_CNTR_END; cntr_idx ++) { ++ rtk_stat_port_get(port, cntr_idx, &Cntr); ++ printk("%8llu ", Cntr); ++ if (((cntr_idx%10) == 9)) ++ printk("\n"); ++ } ++ } ++ rtk_stat_global_reset(); ++} ++void rtk_dump_mib_type(rtk_stat_port_type_t cntr_idx) ++{ ++ rtk_port_t port; ++ rtk_stat_counter_t Cntr; ++ ++ for (port = UTP_PORT0; port < (UTP_PORT0 + 5); port++) { ++ rtk_stat_port_get(port, cntr_idx, &Cntr); ++ printk("%8llu", Cntr); ++ } ++ for (port = EXT_PORT0; port < (EXT_PORT0 + 2); port++) { ++ rtk_stat_port_get(port, cntr_idx, &Cntr); ++ printk("%8llu", Cntr); ++ } ++ printk("\n"); ++} ++ ++void rtk_hal_dump_mib(void) ++{ ++ ++ printk("==================%8s%8s%8s%8s%8s%8s%8s\n", "Port0", "Port1", ++ "Port2", "Port3", "Port4", "Port16", "Port17"); ++ /* Get TX Unicast Pkts */ ++ printk("TX Unicast Pkts :"); ++ rtk_dump_mib_type(STAT_IfOutUcastPkts); ++ /* Get TX Multicast Pkts */ ++ printk("TX Multicast Pkts:"); ++ rtk_dump_mib_type(STAT_IfOutMulticastPkts); ++ /* Get TX BroadCast Pkts */ ++ printk("TX BroadCast Pkts:"); ++ rtk_dump_mib_type(STAT_IfOutBroadcastPkts); ++ /* Get TX Collisions */ ++ /* Get TX Puase Frames */ ++ printk("TX Pause Frames :"); ++ rtk_dump_mib_type(STAT_Dot3OutPauseFrames); ++ /* Get TX Drop Events */ ++ /* Get RX Unicast Pkts */ ++ printk("RX Unicast Pkts :"); ++ rtk_dump_mib_type(STAT_IfInUcastPkts); ++ /* Get RX Multicast Pkts */ ++ printk("RX Multicast Pkts:"); ++ rtk_dump_mib_type(STAT_IfInMulticastPkts); ++ /* Get RX Broadcast Pkts */ ++ printk("RX Broadcast Pkts:"); ++ rtk_dump_mib_type(STAT_IfInBroadcastPkts); ++ /* Get RX FCS Erros */ ++ printk("RX FCS Errors :"); ++ rtk_dump_mib_type(STAT_Dot3StatsFCSErrors); ++ /* Get RX Undersize Pkts */ ++ printk("RX Undersize Pkts:"); ++ rtk_dump_mib_type(STAT_EtherStatsUnderSizePkts); ++ /* Get RX Discard Pkts */ ++ printk("RX Discard Pkts :"); ++ rtk_dump_mib_type(STAT_Dot1dTpPortInDiscards); ++ /* Get RX Fragments */ ++ printk("RX Fragments :"); ++ rtk_dump_mib_type(STAT_EtherStatsFragments); ++ /* Get RX Oversize Pkts */ ++ printk("RX Oversize Pkts :"); ++ rtk_dump_mib_type(STAT_EtherOversizeStats); ++ /* Get RX Jabbers */ ++ printk("RX Jabbers :"); ++ rtk_dump_mib_type(STAT_EtherStatsJabbers); ++ /* Get RX Pause Frames */ ++ printk("RX Pause Frames :"); ++ rtk_dump_mib_type(STAT_Dot3InPauseFrames); ++ /* clear MIB */ ++ rtk_stat_global_reset(); ++} ++EXPORT_SYMBOL(rtk_hal_dump_mib); ++ ++int rtk_hal_dump_vlan(void) ++{ ++ rtk_vlan_cfg_t vlan; ++ int i; ++ ++ printk("vid portmap\n"); ++ for (i = 0; i < RTK_SW_VID_RANGE; i++) { ++ rtk_vlan_get(i, &vlan); ++ printk("%3d ", i); ++ printk("%c", ++ RTK_PORTMASK_IS_PORT_SET(vlan.mbr, ++ UTP_PORT0) ? '1' : '-'); ++ printk("%c", ++ RTK_PORTMASK_IS_PORT_SET(vlan.mbr, ++ UTP_PORT1) ? '1' : '-'); ++ printk("%c", ++ RTK_PORTMASK_IS_PORT_SET(vlan.mbr, ++ UTP_PORT2) ? '1' : '-'); ++ printk("%c", ++ RTK_PORTMASK_IS_PORT_SET(vlan.mbr, ++ UTP_PORT3) ? '1' : '-'); ++ printk("%c", ++ RTK_PORTMASK_IS_PORT_SET(vlan.mbr, ++ UTP_PORT4) ? '1' : '-'); ++ printk("%c", ++ RTK_PORTMASK_IS_PORT_SET(vlan.mbr, ++ EXT_PORT0) ? '1' : '-'); ++ printk("%c", ++ RTK_PORTMASK_IS_PORT_SET(vlan.mbr, ++ EXT_PORT1) ? '1' : '-'); ++ printk("\n"); ++ } ++ return 0; ++} ++ ++void rtk_hal_clear_vlan(void) ++{ ++ rtk_api_ret_t ret; ++ ++ ret = rtk_vlan_reset(); ++ if (ret != RT_ERR_OK) ++ printk("rtk_vlan_reset failed\n"); ++} ++ ++int rtk_hal_set_vlan(struct ra_switch_ioctl_data *data) ++{ ++ rtk_vlan_cfg_t vlan; ++ rtk_api_ret_t ret; ++ int i; ++ ++ /* clear vlan entry first */ ++ memset(&vlan, 0x00, sizeof(rtk_vlan_cfg_t)); ++ RTK_PORTMASK_CLEAR(vlan.mbr); ++ RTK_PORTMASK_CLEAR(vlan.untag); ++ rtk_vlan_set(data->vid, &vlan); ++ ++ memset(&vlan, 0x00, sizeof(rtk_vlan_cfg_t)); ++ for (i = 0; i < 5; i++) { ++ if (data->port_map & (1 << i)) { ++ RTK_PORTMASK_PORT_SET(vlan.mbr, i); ++ RTK_PORTMASK_PORT_SET(vlan.untag, i); ++ rtk_vlan_portPvid_set(i, data->vid, 0); ++ } ++ } ++ for (i = 0; i < 2; i++) { ++ if (data->port_map & (1 << (i + 5))) { ++ RTK_PORTMASK_PORT_SET(vlan.mbr, (i + EXT_PORT0)); ++ RTK_PORTMASK_PORT_SET(vlan.untag, (i + EXT_PORT0)); ++ rtk_vlan_portPvid_set((i + EXT_PORT0), data->vid, 0); ++ } ++ } ++ vlan.ivl_en = 1; ++ ret = rtk_vlan_set(data->vid, &vlan); ++ ++ return 0; ++} ++ ++void rtk_hal_vlan_portpvid_set(rtk_port_t port, rtk_vlan_t pvid, rtk_pri_t priority) ++{ ++ rtk_vlan_portPvid_set(port, pvid, priority); ++} ++ ++int rtk_hal_set_ingress_rate(struct ra_switch_ioctl_data *data) ++{ ++ rtk_api_ret_t ret; ++ ++ if (data->on_off == 1) ++ ret = ++ rtk_rate_igrBandwidthCtrlRate_set(data->port, data->bw, 0, ++ 1); ++ else ++ ret = ++ rtk_rate_igrBandwidthCtrlRate_set(data->port, 1048568, 0, ++ 1); ++ ++ return ret; ++} ++ ++int rtk_hal_set_egress_rate(struct ra_switch_ioctl_data *data) ++{ ++ rtk_api_ret_t ret; ++ ++ if (data->on_off == 1) ++ ret = ++ rtk_rate_egrBandwidthCtrlRate_set(data->port, data->bw, 1); ++ else ++ ret = rtk_rate_egrBandwidthCtrlRate_set(data->port, 1048568, 1); ++ ++ return ret; ++} ++ ++void rtk_hal_dump_table(void) ++{ ++ rtk_uint32 i; ++ rtk_uint32 address = 0; ++ rtk_l2_ucastAddr_t l2_data; ++ rtk_l2_ipMcastAddr_t ipMcastAddr; ++ ++ printk("hash port(0:17) fid vid mac-address\n"); ++ while (1) { ++ if (rtk_l2_addr_next_get(READMETHOD_NEXT_L2UC, UTP_PORT0, &address, &l2_data) != RT_ERR_OK) { ++ break; ++ } else { ++ printk("%03x ", l2_data.address); ++ for (i = 0; i < 5; i++) ++ if ( l2_data.port == i) ++ printk("1"); ++ else ++ printk("-"); ++ for (i = 16; i < 18; i++) ++ if ( l2_data.port == i) ++ printk("1"); ++ else ++ printk("-"); ++ ++ printk(" %2d", l2_data.fid); ++ printk(" %4d", l2_data.cvid); ++ printk(" %02x%02x%02x%02x%02x%02x\n", l2_data.mac.octet[0], ++ l2_data.mac.octet[1], l2_data.mac.octet[2], l2_data.mac.octet[3], ++ l2_data.mac.octet[4], l2_data.mac.octet[5]); ++ address ++; ++ } ++ } ++ ++ address = 0; ++ while (1) { ++ if (rtk_l2_ipMcastAddr_next_get(&address, &ipMcastAddr) != RT_ERR_OK) { ++ break; ++ } else { ++ printk("%03x ", ipMcastAddr.address); ++ for (i = 0; i < 5; i++) ++ printk("%c", RTK_PORTMASK_IS_PORT_SET(ipMcastAddr.portmask, i) ? '1' : '-'); ++ for (i = 16; i < 18; i++) ++ printk("%c", RTK_PORTMASK_IS_PORT_SET(ipMcastAddr.portmask, i) ? '1' : '-'); ++ printk(" "); ++ printk("01005E%06x\n", (ipMcastAddr.dip & 0xefffff)); ++ address ++; ++ } ++ } ++} ++ ++void rtk_hal_clear_table(void) ++{ ++ rtk_api_ret_t ret; ++ ++ ret = rtk_l2_table_clear(); ++ if (ret != RT_ERR_OK) ++ printk("rtk_l2_table_clear failed\n"); ++} ++ ++void rtk_hal_add_table(struct ra_switch_ioctl_data *data) ++{ ++ rtk_api_ret_t ret; ++ rtk_l2_ucastAddr_t l2_entry; ++ rtk_mac_t mac; ++ ++ mac.octet[0] =data->mac[0]; ++ mac.octet[1] =data->mac[1]; ++ mac.octet[2] =data->mac[2]; ++ mac.octet[3] =data->mac[3]; ++ mac.octet[4] =data->mac[4]; ++ mac.octet[5] =data->mac[5]; ++ ++ memset(&l2_entry, 0x00, sizeof(rtk_l2_ucastAddr_t)); ++ l2_entry.port = data->port; ++ l2_entry.ivl = 1; ++ l2_entry.cvid = data->vid; ++ l2_entry.fid = 0; ++ l2_entry.efid = 0; ++ l2_entry.is_static = 1; ++ ret = rtk_l2_addr_add(&mac, &l2_entry); ++ if (ret != RT_ERR_OK) ++ printk("rtk_hal_add_table failed\n"); ++} ++ ++void rtk_hal_del_table(struct ra_switch_ioctl_data *data) ++{ ++ rtk_api_ret_t ret; ++ rtk_l2_ucastAddr_t l2_entry; ++ rtk_mac_t mac; ++ ++ mac.octet[0] =data->mac[0]; ++ mac.octet[1] =data->mac[1]; ++ mac.octet[2] =data->mac[2]; ++ mac.octet[3] =data->mac[3]; ++ mac.octet[4] =data->mac[4]; ++ mac.octet[5] =data->mac[5]; ++ ++ memset(&l2_entry, 0x00, sizeof(rtk_l2_ucastAddr_t)); ++ l2_entry.port = data->port; ++ l2_entry.ivl = 1; ++ l2_entry.cvid = data->vid; ++ l2_entry.fid = 0; ++ l2_entry.efid = 0; ++ ret = rtk_l2_addr_del(&mac, &l2_entry); ++ if (ret != RT_ERR_OK) ++ printk("rtk_hal_add_table failed\n"); ++} ++void rtk_hal_get_phy_status(struct ra_switch_ioctl_data *data) ++{ ++ rtk_port_linkStatus_t linkStatus; ++ rtk_port_speed_t speed; ++ rtk_port_duplex_t duplex; ++ ++ rtk_port_phyStatus_get(data->port, &linkStatus, &speed, &duplex); ++ printk("Port%d Status:\n", data->port); ++ if (linkStatus == 1) { ++ printk("Link Up"); ++ if (speed == 0) ++ printk(" 10M"); ++ else if (speed == 1) ++ printk(" 100M"); ++ else if (speed == 2) ++ printk(" 1000M"); ++ if (duplex == 0) ++ printk(" Half Duplex\n"); ++ else ++ printk(" Full Duplex\n"); ++ } else ++ printk("Link Down\n"); ++ ++} ++ ++void rtk_hal_set_port_mirror(struct ra_switch_ioctl_data *data) ++{ ++ rtk_portmask_t rx_portmask; ++ rtk_portmask_t tx_portmask; ++ rtk_api_ret_t ret; ++ int i; ++ ++ rtk_mirror_portIso_set(ENABLED); ++ RTK_PORTMASK_CLEAR(rx_portmask); ++ RTK_PORTMASK_CLEAR(tx_portmask); ++ for (i = 0; i < 5; i++) ++ if (data->rx_port_map & (1 << i)) ++ RTK_PORTMASK_PORT_SET(rx_portmask, i); ++ for (i = 0; i < 2; i++) ++ if (data->rx_port_map & (1 << (i + 5))) ++ RTK_PORTMASK_PORT_SET(rx_portmask, (i + EXT_PORT0)); ++ ++ RTK_PORTMASK_CLEAR(tx_portmask); ++ for (i = 0; i < 5; i++) ++ if (data->tx_port_map & (1 << i)) ++ RTK_PORTMASK_PORT_SET(tx_portmask, i); ++ for (i = 0; i < 2; i++) ++ if (data->tx_port_map & (1 << (i + 5))) ++ RTK_PORTMASK_PORT_SET(tx_portmask, (i + EXT_PORT0)); ++ ++ ret = rtk_mirror_portBased_set(data->port, &rx_portmask, &tx_portmask); ++ if (!ret) ++ printk("rtk_mirror_portBased_set success\n"); ++} ++ ++void rtk_hal_read_reg(struct ra_switch_ioctl_data *data) ++{ ++ ret_t retVal; ++ ++ retVal = smi_read(data->reg_addr, &data->reg_val); ++ if(retVal != RT_ERR_OK) ++ printk("switch reg read failed\n"); ++ else ++ printk("reg0x%x = 0x%x\n", data->reg_addr, data->reg_val); ++} ++ ++void rtk_hal_write_reg(struct ra_switch_ioctl_data *data) ++{ ++ ret_t retVal; ++ ++ retVal = smi_write(data->reg_addr, data->reg_val); ++ if(retVal != RT_ERR_OK) ++ printk("switch reg write failed\n"); ++ else ++ printk("write switch reg0x%x 0x%x success\n", data->reg_addr, data->reg_val); ++} ++ ++void rtk_hal_get_phy_reg(struct ra_switch_ioctl_data *data) ++{ ++ ret_t retVal; ++ rtk_port_phy_data_t Data; ++ ++ retVal = rtk_port_phyReg_get(data->port, data->reg_addr, &Data); ++ if (retVal == RT_ERR_OK) ++ printk("Get: phy[%d].reg[%d] = 0x%04x\n", data->port, data->reg_addr, Data); ++ else ++ printk("read phy reg failed\n"); ++} ++ ++void rtk_hal_set_phy_reg(struct ra_switch_ioctl_data *data) ++{ ++ ret_t retVal; ++ ++ retVal = rtk_port_phyReg_set(data->port, data->reg_addr, data->reg_val); ++ if (retVal == RT_ERR_OK) ++ printk("Set: phy[%d].reg[%d] = 0x%04x\n", data->port, data->reg_addr, data->reg_val); ++ else ++ printk("write phy reg failed\n"); ++} ++void rtk_hal_qos_en(struct ra_switch_ioctl_data *data) ++{ ++ ++ if (data->on_off == 1) { ++ if (rtk_qos_init(8) != 0) ++ printk("rtk_qos_init(8) failed\n"); ++ } ++ else { ++ if (rtk_qos_init(1) != 0) ++ printk("rtk_qos_init(1) failed\n"); ++ } ++} ++ ++void rtk_hal_qos_set_table2type(struct ra_switch_ioctl_data *data) ++{ ++ rtk_api_ret_t ret; ++ rtk_priority_select_t PriDec; ++ ++ /* write all pri to 0 */ ++ PriDec.port_pri = 0; ++ PriDec.dot1q_pri = 0; ++ PriDec.acl_pri = 0; ++ PriDec.cvlan_pri = 0; ++ PriDec.svlan_pri = 0; ++ PriDec.dscp_pri = 0; ++ PriDec.dmac_pri = 0; ++ PriDec.smac_pri = 0; ++ ++ if (data->qos_type == 0) ++ PriDec.port_pri = 1; ++ else if (data->qos_type == 1) ++ PriDec.dot1q_pri = 1; ++ else if (data->qos_type == 2) ++ PriDec.acl_pri = 1; ++ else if (data->qos_type == 3) ++ PriDec.dscp_pri = 1; ++ else if (data->qos_type == 4) ++ PriDec.cvlan_pri = 1; ++ else if (data->qos_type == 5) ++ PriDec.svlan_pri = 1; ++ else if (data->qos_type == 6) ++ PriDec.dmac_pri = 1; ++ else if (data->qos_type == 7) ++ PriDec.smac_pri = 1; ++ ++ if (data->qos_table_idx == 0) ++ ret = rtk_qos_priSel_set(PRIDECTBL_IDX0, &PriDec); ++ else ++ ret = rtk_qos_priSel_set(PRIDECTBL_IDX1, &PriDec); ++ ++ if (ret != 0) ++ printk("rtk_qos_priSel_set failed\n"); ++ ++} ++ ++void rtk_hal_qos_get_table2type(struct ra_switch_ioctl_data *data) ++{ ++ rtk_api_ret_t ret; ++ rtk_priority_select_t PriDec; ++ ++ if (data->qos_table_idx == 0) ++ ret = rtk_qos_priSel_get(PRIDECTBL_IDX0, &PriDec); ++ else ++ ret = rtk_qos_priSel_get(PRIDECTBL_IDX1, &PriDec); ++ ++ if (ret != 0) ++ printk("rtk_qos_priSel_set failed\n"); ++ else { ++ printk("port_pri = %d\n", PriDec.port_pri); ++ printk("dot1q_pri = %d\n", PriDec.dot1q_pri); ++ printk("acl_pri = %d\n", PriDec.acl_pri); ++ printk("dscp_pri = %d\n", PriDec.dscp_pri); ++ printk("cvlan_pri = %d\n", PriDec.cvlan_pri); ++ printk("svlan_pri = %d\n", PriDec.svlan_pri); ++ printk("dmac_pri = %d\n", PriDec.dmac_pri); ++ printk("smac_pri = %d\n", PriDec.smac_pri); ++ } ++} ++ ++void rtk_hal_qos_set_port2table(struct ra_switch_ioctl_data *data) ++{ ++ rtk_api_ret_t ret; ++ ++ ret = rtk_qos_portPriSelIndex_set(data->port, data->qos_table_idx); ++ if (ret != 0) ++ printk("rtk_qos_portPriSelIndex_set failed\n"); ++} ++ ++void rtk_hal_qos_get_port2table(struct ra_switch_ioctl_data *data) ++{ ++ rtk_api_ret_t ret; ++ rtk_qos_priDecTbl_t Index; ++ ++ ret = rtk_qos_portPriSelIndex_get(data->port, &Index); ++ if (ret != 0) ++ printk("rtk_qos_portPriSelIndex_set failed\n"); ++ else ++ printk("port%d belongs to table%d\n", data->port, Index); ++} ++ ++void rtk_hal_qos_set_port2pri(struct ra_switch_ioctl_data *data) ++{ ++ rtk_api_ret_t ret; ++ ++ ret = rtk_qos_portPri_set(data->port, data->qos_pri); ++ if (ret != 0) ++ printk("rtk_qos_portPri_set failed\n"); ++} ++ ++void rtk_hal_qos_get_port2pri(struct ra_switch_ioctl_data *data) ++{ ++ rtk_api_ret_t ret; ++ rtk_pri_t Int_pri; ++ ++ ret = rtk_qos_portPri_get(data->port, &Int_pri); ++ if (ret != 0) ++ printk("rtk_qos_portPri_set failed\n"); ++ else ++ printk("port%d priority = %d\n", data->port, Int_pri); ++} ++ ++void rtk_hal_qos_set_dscp2pri(struct ra_switch_ioctl_data *data) ++{ ++ rtk_api_ret_t ret; ++ ++ ret = rtk_qos_dscpPriRemap_set(data->qos_dscp, data->qos_pri); ++ if (ret != 0) ++ printk("rtk_qos_dscpPriRemap_set failed\n"); ++} ++ ++void rtk_hal_qos_get_dscp2pri(struct ra_switch_ioctl_data *data) ++{ ++ rtk_api_ret_t ret; ++ rtk_pri_t Int_pri; ++ ++ ret = rtk_qos_dscpPriRemap_get(data->qos_dscp, &Int_pri); ++ if (ret != 0) ++ printk("rtk_qos_dscpPriRemap_set failed\n"); ++ else ++ printk("dscp%d priority is %d\n", data->qos_dscp, Int_pri); ++} ++ ++void rtk_hal_qos_set_pri2queue(struct ra_switch_ioctl_data *data) ++{ ++ rtk_api_ret_t ret; ++ rtk_qos_pri2queue_t pri2qid; ++ ++ ret = rtk_qos_priMap_get(8, &pri2qid); ++ pri2qid.pri2queue[data->qos_queue_num] = data->qos_pri; ++ ret = rtk_qos_priMap_set(8, &pri2qid); ++ if (ret != 0) ++ printk("rtk_qos_priMap_set failed\n"); ++} ++ ++void rtk_hal_qos_get_pri2queue(struct ra_switch_ioctl_data *data) ++{ ++ int i; ++ rtk_api_ret_t ret; ++ rtk_qos_pri2queue_t pri2qid; ++ ++ ret = rtk_qos_priMap_get(8, &pri2qid); ++ if (ret != 0) ++ printk("rtk_qos_priMap_get failed\n"); ++ else { ++ for (i = 0; i < 8; i++) ++ printk("pri2qid.pri2queue[%d] = %d\n", i, pri2qid.pri2queue[i]); ++ } ++} ++ ++void rtk_hal_qos_set_queue_weight(struct ra_switch_ioctl_data *data) ++{ ++ rtk_api_ret_t ret; ++ rtk_qos_queue_weights_t qweights; ++ ++ ret = rtk_qos_schedulingQueue_get(data->port, &qweights); ++ qweights.weights[data->qos_queue_num] = data->qos_weight; ++ ret = rtk_qos_schedulingQueue_set(data->port, &qweights); ++ if (ret != 0) ++ printk("rtk_qos_schedulingQueue_set failed\n"); ++} ++ ++void rtk_hal_qos_get_queue_weight(struct ra_switch_ioctl_data *data) ++{ ++ int i; ++ rtk_api_ret_t ret; ++ rtk_qos_queue_weights_t qweights; ++ ++ ret = rtk_qos_schedulingQueue_get(data->port, &qweights); ++ if (ret != 0) ++ printk("rtk_qos_schedulingQueue_get failed\n"); ++ else { ++ printk("=== Port%d queue weight ===\n", data->port); ++ for (i = 0; i < 8; i++) ++ printk("qweights.weights[%d] = %d\n",i ,qweights.weights[i]); ++ } ++} ++ ++void rtk_hal_enable_igmpsnoop(struct ra_switch_ioctl_data *data) ++{ ++ rtk_api_ret_t ret; ++ rtk_portmask_t pmask; ++ ++ ++ ret = rtk_igmp_init(); ++ if (data->on_off == 1) { ++ RTK_PORTMASK_CLEAR(pmask); ++ RTK_PORTMASK_PORT_SET(pmask, EXT_PORT0); ++ ret |= rtk_igmp_static_router_port_set(&pmask); ++ ret |= rtk_igmp_protocol_set(UTP_PORT4, PROTOCOL_IGMPv1, IGMP_ACTION_FORWARD); ++ ret |= rtk_igmp_protocol_set(UTP_PORT4, PROTOCOL_IGMPv2, IGMP_ACTION_FORWARD); ++ ret |= rtk_igmp_protocol_set(UTP_PORT4, PROTOCOL_MLDv1, IGMP_ACTION_FORWARD); ++ ret |= rtk_igmp_protocol_set(EXT_PORT1, PROTOCOL_IGMPv1, IGMP_ACTION_FORWARD); ++ ret |= rtk_igmp_protocol_set(EXT_PORT1, PROTOCOL_IGMPv2, IGMP_ACTION_FORWARD); ++ ret |= rtk_igmp_protocol_set(EXT_PORT1, PROTOCOL_MLDv1, IGMP_ACTION_FORWARD); ++ ret |= rtk_igmp_protocol_set(UTP_PORT0, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC); ++ ret |= rtk_igmp_protocol_set(UTP_PORT1, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC); ++ ret |= rtk_igmp_protocol_set(UTP_PORT2, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC); ++ ret |= rtk_igmp_protocol_set(UTP_PORT3, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC); ++ ret |= rtk_igmp_protocol_set(EXT_PORT0, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC); ++ ++ ret |= rtk_leaky_vlan_set(LEAKY_IPMULTICAST, ENABLED); ++ ret |= rtk_l2_ipMcastForwardRouterPort_set(DISABLED); ++ /* drop unknown multicast packets*/ ++ /* ret |= rtk_trap_unknownMcastPktAction_set(UTP_PORT4, MCAST_IPV4, MCAST_ACTION_DROP);*/ ++ } else { ++ RTK_PORTMASK_CLEAR(pmask); ++ RTK_PORTMASK_PORT_SET(pmask, EXT_PORT0); ++ RTK_PORTMASK_PORT_SET(pmask, EXT_PORT1); ++ ret |= rtk_igmp_protocol_set(UTP_PORT0, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC); ++ ret |= rtk_igmp_protocol_set(UTP_PORT1, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC); ++ ret |= rtk_igmp_protocol_set(UTP_PORT2, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC); ++ ret |= rtk_igmp_protocol_set(UTP_PORT3, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC); ++ ret |= rtk_igmp_protocol_set(EXT_PORT0, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC); ++ ++ ret |= rtk_igmp_static_router_port_set(&pmask); ++ } ++ if(ret != RT_ERR_OK) ++ printk("enable switch igmpsnoop failed\n"); ++} ++ ++void rtk_hal_disable_igmpsnoop(void) ++{ ++ if (rtk_igmp_state_set(DISABLED) != RT_ERR_OK) ++ printk("Disable IGMP SNOOPING failed\n"); ++} ++ ++rtk_api_ret_t rtk_port_phyTestMode_set(rtk_port_t port, rtk_port_phy_test_mode_t mode) ++{ ++ rtk_uint32 data, regData, i; ++ rtk_api_ret_t retVal; ++ ++ RTK_CHK_PORT_IS_UTP(port); ++ ++ if(mode >= PHY_TEST_MODE_END) ++ return RT_ERR_INPUT; ++ ++ if( (mode == PHY_TEST_MODE_2) || (mode == PHY_TEST_MODE_3) ) ++ return RT_ERR_INPUT; ++ ++ if (PHY_TEST_MODE_NORMAL != mode) ++ { ++ /* Other port should be Normal mode */ ++ RTK_SCAN_ALL_LOG_PORT(i) ++ { ++ if(rtk_switch_isUtpPort(i) == RT_ERR_OK) ++ { ++ if(i != port) ++ { ++ if ((retVal = rtl8367c_getAsicPHYReg(rtk_switch_port_L2P_get(i), 9, &data)) != RT_ERR_OK) ++ return retVal; ++ ++ if((data & 0xE000) != 0) ++ return RT_ERR_NOT_ALLOWED; ++ } ++ } ++ } ++ } ++ ++ if ((retVal = rtl8367c_getAsicPHYReg(rtk_switch_port_L2P_get(port), 9, &data)) != RT_ERR_OK) ++ return retVal; ++ ++ data &= ~0xE000; ++ data |= (mode << 13); ++ if ((retVal = rtl8367c_setAsicPHYReg(rtk_switch_port_L2P_get(port), 9, data)) != RT_ERR_OK) ++ return retVal; ++ ++ if (PHY_TEST_MODE_4 == mode) ++ { ++ if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0249)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_getAsicReg(0x1300, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ if( (regData == 0x0276) || (regData == 0x0597) ) ++ { ++ if ((retVal = rtl8367c_setAsicPHYOCPReg(rtk_switch_port_L2P_get(port), 0xbcc2, 0xF4F4)) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ if( (regData == 0x6367) ) ++ { ++ if ((retVal = rtl8367c_setAsicPHYOCPReg(rtk_switch_port_L2P_get(port), 0xa436, 0x80c1)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicPHYOCPReg(rtk_switch_port_L2P_get(port), 0xa438, 0xfe00)) != RT_ERR_OK) ++ return retVal; ++ } ++ } ++ ++ return RT_ERR_OK; ++} ++ ++void rtk_hal_set_phy_test_mode(struct ra_switch_ioctl_data *data) ++{ ++ rtk_api_ret_t ret; ++ ++ ret = rtk_port_phyTestMode_set(data->port, data->mode); ++ if (ret != RT_ERR_OK) ++ printk("rtk_port_phyTestMode_set failed\n"); ++ else ++ printk("set port%d in test mode %d.\n", data->port, data->mode); ++} ++ ++void rtk_hal_set_port_trunk(struct ra_switch_ioctl_data *data) ++{ ++ ++ rtk_api_ret_t ret; ++ rtk_portmask_t member; ++ int i; ++ ++ RTK_PORTMASK_CLEAR(member); ++ for (i = 0; i < 4; i++) { ++ if (data->port_map & (1 << i)) ++ RTK_PORTMASK_PORT_SET(member, i); ++ } ++ ++ ret = rtk_trunk_port_set(TRUNK_GROUP0, &member); ++ if (ret != RT_ERR_OK) ++ printk("rtk_trunk_port_set failed\n"); ++ ++ ret = rtk_trunk_distributionAlgorithm_set(RTK_WHOLE_SYSTEM, 0x7F); ++ if (ret != RT_ERR_OK) ++ printk("rtk_trunk_distributionAlgorithm_set failed\n"); ++} ++ ++void rtk_hal_vlan_tag(struct ra_switch_ioctl_data *data) ++{ ++ rtk_api_ret_t ret; ++ rtk_vlan_cfg_t vlan; ++ ++ ret = rtk_vlan_get(data->vid, &vlan); ++ if (ret != RT_ERR_OK) ++ printk("rtk_vlan_get failed\n"); ++ else { ++ if (data->on_off == 0) ++ RTK_PORTMASK_PORT_SET(vlan.untag, data->port); ++ else ++ RTK_PORTMASK_PORT_CLEAR(vlan.untag, data->port); ++ ++ ret = rtk_vlan_set(data->vid, &vlan); ++ if (ret != RT_ERR_OK) ++ printk("rtk_vlan_set failed\n"); ++ } ++} ++ ++void rtk_hal_vlan_mode(struct ra_switch_ioctl_data *data) ++{ ++ rtk_vlan_cfg_t vlan1, vlan2; ++ rtk_api_ret_t ret; ++ ++ ret = rtk_vlan_get(1, &vlan1); ++ if (ret != RT_ERR_OK) ++ printk("rtk_vlan_get failed\n"); ++ ++ ret = rtk_vlan_get(2, &vlan2); ++ if (ret != RT_ERR_OK) ++ printk("rtk_vlan_get failed\n"); ++ ++ if (data->mode == 0) { //ivl ++ vlan1.ivl_en = 1; ++ vlan1.fid_msti = 0; ++ rtk_vlan_set(1, &vlan1); ++ vlan2.ivl_en = 1; ++ vlan2.fid_msti = 0; ++ rtk_vlan_set(2, &vlan2); ++ } else if(data->mode == 1) {//svl ++ vlan1.ivl_en = 0; ++ vlan1.fid_msti = 0; ++ rtk_vlan_set(1, &vlan1); ++ vlan2.ivl_en = 0; ++ vlan2.fid_msti = 1; ++ rtk_vlan_set(2, &vlan2); ++ } else ++ printk("mode not supported\n"); ++} +diff --git a/drivers/net/phy/rtk/rtl8367c/rtk_switch.c b/drivers/net/phy/rtk/rtl8367c/rtk_switch.c +new file mode 100644 +index 000000000000..afa3385f3098 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/rtk_switch.c +@@ -0,0 +1,1794 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76336 $ ++ * $Date: 2017-03-09 10:41:21 +0800 (週四, 09 三月 2017) $ ++ * ++ * Purpose : RTK switch high-level API ++ * Feature : Here is a list of all functions and variables in this module. ++ * ++ */ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#if defined(FORCE_PROBE_RTL8367C) ++static init_state_t init_state = INIT_COMPLETED; ++#elif defined(FORCE_PROBE_RTL8370B) ++static init_state_t init_state = INIT_COMPLETED; ++#elif defined(FORCE_PROBE_RTL8364B) ++static init_state_t init_state = INIT_COMPLETED; ++#elif defined(FORCE_PROBE_RTL8363SC_VB) ++static init_state_t init_state = INIT_COMPLETED; ++#else ++static init_state_t init_state = INIT_NOT_COMPLETED; ++#endif ++ ++#if ((!defined(FORCE_PROBE_RTL8367C) && !defined(FORCE_PROBE_RTL8370B) && !defined(FORCE_PROBE_RTL8364B) && !defined(FORCE_PROBE_RTL8363SC_VB)) || defined(FORCE_PROBE_RTL8367C)) ++static rtk_switch_halCtrl_t rtl8367c_hal_Ctrl = ++{ ++ /* Switch Chip */ ++ CHIP_RTL8367C, ++ ++ /* Logical to Physical */ ++ {0, 1, 2, 3, 4, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, ++ 6, 7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, ++ ++ /* Physical to Logical */ ++ {UTP_PORT0, UTP_PORT1, UTP_PORT2, UTP_PORT3, UTP_PORT4, UNDEFINE_PORT, EXT_PORT0, EXT_PORT1, ++ UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, ++ UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, ++ UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT}, ++ ++ /* Port Type */ ++ {UTP_PORT, UTP_PORT, UTP_PORT, UTP_PORT, UTP_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, ++ UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, ++ EXT_PORT, EXT_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, ++ UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT}, ++ ++ /* PTP port */ ++ {1, 1, 1, 1, 1, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0 }, ++ ++ /* Valid port mask */ ++ ( (0x1 << UTP_PORT0) | (0x1 << UTP_PORT1) | (0x1 << UTP_PORT2) | (0x1 << UTP_PORT3) | (0x1 << UTP_PORT4) | (0x1 << EXT_PORT0) | (0x1 << EXT_PORT1) ), ++ ++ /* Valid UTP port mask */ ++ ( (0x1 << UTP_PORT0) | (0x1 << UTP_PORT1) | (0x1 << UTP_PORT2) | (0x1 << UTP_PORT3) | (0x1 << UTP_PORT4) ), ++ ++ /* Valid EXT port mask */ ++ ( (0x1 << EXT_PORT0) | (0x1 << EXT_PORT1) ), ++ ++ /* Valid CPU port mask */ ++ 0x00, ++ ++ /* Minimum physical port number */ ++ 0, ++ ++ /* Maxmum physical port number */ ++ 7, ++ ++ /* Physical port mask */ ++ 0xDF, ++ ++ /* Combo Logical port ID */ ++ 4, ++ ++ /* HSG Logical port ID */ ++ EXT_PORT0, ++ ++ /* SGMII Logical portmask */ ++ (0x1 << EXT_PORT0), ++ ++ /* Max Meter ID */ ++ 31, ++ ++ /* MAX LUT Address Number */ ++ 2112, ++ ++ /* Trunk Group Mask */ ++ 0x03 ++}; ++#endif ++ ++#if ((!defined(FORCE_PROBE_RTL8367C) && !defined(FORCE_PROBE_RTL8370B) && !defined(FORCE_PROBE_RTL8364B) && !defined(FORCE_PROBE_RTL8363SC_VB)) || defined(FORCE_PROBE_RTL8370B)) ++static rtk_switch_halCtrl_t rtl8370b_hal_Ctrl = ++{ ++ /* Switch Chip */ ++ CHIP_RTL8370B, ++ ++ /* Logical to Physical */ ++ {0, 1, 2, 3, 4, 5, 6, 7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, ++ 8, 9, 10, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, ++ ++ /* Physical to Logical */ ++ {UTP_PORT0, UTP_PORT1, UTP_PORT2, UTP_PORT3, UTP_PORT4, UTP_PORT5, UTP_PORT6, UTP_PORT7, ++ EXT_PORT0, EXT_PORT1, EXT_PORT2, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, ++ UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, ++ UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT}, ++ ++ /* Port Type */ ++ {UTP_PORT, UTP_PORT, UTP_PORT, UTP_PORT, UTP_PORT, UTP_PORT, UTP_PORT, UTP_PORT, ++ UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, ++ EXT_PORT, EXT_PORT, EXT_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, ++ UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT}, ++ ++ /* PTP port */ ++ {1, 1, 1, 1, 1, 1, 1, 1, ++ 0, 0, 0, 0, 0, 0, 0, 0, ++ 1, 1, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0 }, ++ ++ /* Valid port mask */ ++ ( (0x1 << UTP_PORT0) | (0x1 << UTP_PORT1) | (0x1 << UTP_PORT2) | (0x1 << UTP_PORT3) | (0x1 << UTP_PORT4) | (0x1 << UTP_PORT5) | (0x1 << UTP_PORT6) | (0x1 << UTP_PORT7) | (0x1 << EXT_PORT0) | (0x1 << EXT_PORT1) | (0x1 << EXT_PORT2) ), ++ ++ /* Valid UTP port mask */ ++ ( (0x1 << UTP_PORT0) | (0x1 << UTP_PORT1) | (0x1 << UTP_PORT2) | (0x1 << UTP_PORT3) | (0x1 << UTP_PORT4) | (0x1 << UTP_PORT5) | (0x1 << UTP_PORT6) | (0x1 << UTP_PORT7) ), ++ ++ /* Valid EXT port mask */ ++ ( (0x1 << EXT_PORT0) | (0x1 << EXT_PORT1) | (0x1 << EXT_PORT2) ), ++ ++ /* Valid CPU port mask */ ++ (0x1 << EXT_PORT2), ++ ++ /* Minimum physical port number */ ++ 0, ++ ++ /* Maximum physical port number */ ++ 10, ++ ++ /* Physical port mask */ ++ 0x7FF, ++ ++ /* Combo Logical port ID */ ++ 7, ++ ++ /* HSG Logical port ID */ ++ EXT_PORT1, ++ ++ /* SGMII Logical portmask */ ++ ( (0x1 << EXT_PORT0) | (0x1 << EXT_PORT1) ), ++ ++ /* Max Meter ID */ ++ 63, ++ ++ /* MAX LUT Address Number 4096 + 64*/ ++ 4160, ++ ++ /* Trunk Group Mask */ ++ 0x07 ++}; ++#endif ++ ++#if ((!defined(FORCE_PROBE_RTL8367C) && !defined(FORCE_PROBE_RTL8370B) && !defined(FORCE_PROBE_RTL8364B) && !defined(FORCE_PROBE_RTL8363SC_VB)) || defined(FORCE_PROBE_RTL8364B)) ++static rtk_switch_halCtrl_t rtl8364b_hal_Ctrl = ++{ ++ /* Switch Chip */ ++ CHIP_RTL8364B, ++ ++ /* Logical to Physical */ ++ {0xFF, 1, 0xFF, 3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, ++ 6, 7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, ++ ++ /* Physical to Logical */ ++ {UNDEFINE_PORT, UTP_PORT1, UNDEFINE_PORT, UTP_PORT3, UNDEFINE_PORT, UNDEFINE_PORT, EXT_PORT0, EXT_PORT1, ++ UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, ++ UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, ++ UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT}, ++ ++ /* Port Type */ ++ {UNKNOWN_PORT, UTP_PORT, UNKNOWN_PORT, UTP_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, ++ UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, ++ EXT_PORT, EXT_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, ++ UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT}, ++ ++ /* PTP port */ ++ {0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0 }, ++ ++ /* Valid port mask */ ++ ( (0x1 << UTP_PORT1) | (0x1 << UTP_PORT3) | (0x1 << EXT_PORT0) | (0x1 << EXT_PORT1) ), ++ ++ /* Valid UTP port mask */ ++ ( (0x1 << UTP_PORT1) | (0x1 << UTP_PORT3) ), ++ ++ /* Valid EXT port mask */ ++ ( (0x1 << EXT_PORT0) | (0x1 << EXT_PORT1) ), ++ ++ /* Valid CPU port mask */ ++ 0x00, ++ ++ /* Minimum physical port number */ ++ 0, ++ ++ /* Maximum physical port number */ ++ 7, ++ ++ /* Physical port mask */ ++ 0xCA, ++ ++ /* Combo Logical port ID */ ++ 4, ++ ++ /* HSG Logical port ID */ ++ EXT_PORT0, ++ ++ /* SGMII Logical portmask */ ++ ( (0x1 << EXT_PORT0) | (0x1 << EXT_PORT1) ), ++ ++ /* Max Meter ID */ ++ 32, ++ ++ /* MAX LUT Address Number */ ++ 2112, ++ ++ /* Trunk Group Mask */ ++ 0x01 ++}; ++#endif ++ ++#if ((!defined(FORCE_PROBE_RTL8367C) && !defined(FORCE_PROBE_RTL8370B) && !defined(FORCE_PROBE_RTL8364B) && !defined(FORCE_PROBE_RTL8363SC_VB)) || defined(FORCE_PROBE_RTL8363SC_VB)) ++static rtk_switch_halCtrl_t rtl8363sc_vb_hal_Ctrl = ++{ ++ /* Switch Chip */ ++ CHIP_RTL8363SC_VB, ++ ++ /* Logical to Physical */ ++ {0xFF, 0xFF, 1, 3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, ++ 6, 7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, ++ ++ /* Physical to Logical */ ++ {UNDEFINE_PORT, UTP_PORT2, UNDEFINE_PORT, UTP_PORT3, UNDEFINE_PORT, UNDEFINE_PORT, EXT_PORT0, EXT_PORT1, ++ UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, ++ UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, ++ UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT}, ++ ++ /* Port Type */ ++ {UNKNOWN_PORT, UNKNOWN_PORT, UTP_PORT, UTP_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, ++ UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, ++ EXT_PORT, EXT_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, ++ UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT}, ++ ++ /* PTP port */ ++ {0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0 }, ++ ++ /* Valid port mask */ ++ ( (0x1 << UTP_PORT2) | (0x1 << UTP_PORT3) | (0x1 << EXT_PORT0) | (0x1 << EXT_PORT1) ), ++ ++ /* Valid UTP port mask */ ++ ( (0x1 << UTP_PORT2) | (0x1 << UTP_PORT3) ), ++ ++ /* Valid EXT port mask */ ++ ( (0x1 << EXT_PORT0) | (0x1 << EXT_PORT1) ), ++ ++ /* Valid CPU port mask */ ++ 0x00, ++ ++ /* Minimum physical port number */ ++ 0, ++ ++ /* Maximum physical port number */ ++ 7, ++ ++ /* Physical port mask */ ++ 0xCA, ++ ++ /* Combo Logical port ID */ ++ 4, ++ ++ /* HSG Logical port ID */ ++ EXT_PORT0, ++ ++ /* SGMII Logical portmask */ ++ ( (0x1 << EXT_PORT0) | (0x1 << EXT_PORT1) ), ++ ++ /* Max Meter ID */ ++ 32, ++ ++ /* MAX LUT Address Number */ ++ 2112, ++ ++ /* Trunk Group Mask */ ++ 0x01 ++}; ++#endif ++ ++#if defined(FORCE_PROBE_RTL8367C) ++static rtk_switch_halCtrl_t *halCtrl = &rtl8367c_hal_Ctrl; ++#elif defined(FORCE_PROBE_RTL8370B) ++static rtk_switch_halCtrl_t *halCtrl = &rtl8370b_hal_Ctrl; ++#elif defined(FORCE_PROBE_RTL8364B) ++static rtk_switch_halCtrl_t *halCtrl = &rtl8364b_hal_Ctrl; ++#elif defined(FORCE_PROBE_RTL8363SC_VB) ++static rtk_switch_halCtrl_t *halCtrl = &rtl8363sc_vb_hal_Ctrl; ++#else ++static rtk_switch_halCtrl_t *halCtrl = NULL; ++#endif ++ ++static rtk_uint32 PatchChipData[210][2] = ++{ ++ {0xa436, 0x8028}, {0xa438, 0x6800}, {0xb82e, 0x0001}, {0xa436, 0xb820}, {0xa438, 0x0090}, {0xa436, 0xa012}, {0xa438, 0x0000}, {0xa436, 0xa014}, {0xa438, 0x2c04}, {0xa438, 0x2c6c}, ++ {0xa438, 0x2c75}, {0xa438, 0x2c77}, {0xa438, 0x1414}, {0xa438, 0x1579}, {0xa438, 0x1536}, {0xa438, 0xc432}, {0xa438, 0x32c0}, {0xa438, 0x42d6}, {0xa438, 0x32b5}, {0xa438, 0x003e}, ++ {0xa438, 0x614c}, {0xa438, 0x1569}, {0xa438, 0xd705}, {0xa438, 0x318c}, {0xa438, 0x42d6}, {0xa438, 0xd702}, {0xa438, 0x31ef}, {0xa438, 0x42d6}, {0xa438, 0x629c}, {0xa438, 0x2c04}, ++ {0xa438, 0x653c}, {0xa438, 0x422a}, {0xa438, 0x5d83}, {0xa438, 0xd06a}, {0xa438, 0xd1b0}, {0xa438, 0x1536}, {0xa438, 0xc43a}, {0xa438, 0x32c0}, {0xa438, 0x42d6}, {0xa438, 0x32b5}, ++ {0xa438, 0x003e}, {0xa438, 0x314a}, {0xa438, 0x42fe}, {0xa438, 0x337b}, {0xa438, 0x02d6}, {0xa438, 0x3063}, {0xa438, 0x0c1b}, {0xa438, 0x22fe}, {0xa438, 0xc435}, {0xa438, 0xd0be}, ++ {0xa438, 0xd1f7}, {0xa438, 0xe0f0}, {0xa438, 0x1a40}, {0xa438, 0xa320}, {0xa438, 0xd702}, {0xa438, 0x154a}, {0xa438, 0xc434}, {0xa438, 0x32c0}, {0xa438, 0x42d6}, {0xa438, 0x32b5}, ++ {0xa438, 0x003e}, {0xa438, 0x60ec}, {0xa438, 0x1569}, {0xa438, 0xd705}, {0xa438, 0x619f}, {0xa438, 0xd702}, {0xa438, 0x414f}, {0xa438, 0x2c2e}, {0xa438, 0x610a}, {0xa438, 0xd705}, ++ {0xa438, 0x5e1f}, {0xa438, 0xc43f}, {0xa438, 0xc88b}, {0xa438, 0xd702}, {0xa438, 0x7fe0}, {0xa438, 0x22f3}, {0xa438, 0xd0a0}, {0xa438, 0xd1b2}, {0xa438, 0xd0c3}, {0xa438, 0xd1c3}, ++ {0xa438, 0x8d01}, {0xa438, 0x1536}, {0xa438, 0xc438}, {0xa438, 0xe0f0}, {0xa438, 0x1a80}, {0xa438, 0xd706}, {0xa438, 0x60c0}, {0xa438, 0xd710}, {0xa438, 0x409e}, {0xa438, 0xa804}, ++ {0xa438, 0xad01}, {0xa438, 0x8804}, {0xa438, 0xd702}, {0xa438, 0x32c0}, {0xa438, 0x42d6}, {0xa438, 0x32b5}, {0xa438, 0x003e}, {0xa438, 0x405b}, {0xa438, 0x1576}, {0xa438, 0x7c9c}, ++ {0xa438, 0x60ec}, {0xa438, 0x1569}, {0xa438, 0xd702}, {0xa438, 0x5d43}, {0xa438, 0x31ef}, {0xa438, 0x02fe}, {0xa438, 0x22d6}, {0xa438, 0x590a}, {0xa438, 0xd706}, {0xa438, 0x5c80}, ++ {0xa438, 0xd702}, {0xa438, 0x5c44}, {0xa438, 0x3063}, {0xa438, 0x02d6}, {0xa438, 0x5be2}, {0xa438, 0x22fb}, {0xa438, 0xa240}, {0xa438, 0xa104}, {0xa438, 0x8c03}, {0xa438, 0x8178}, ++ {0xa438, 0xd701}, {0xa438, 0x31ad}, {0xa438, 0x4917}, {0xa438, 0x8102}, {0xa438, 0x2917}, {0xa438, 0xc302}, {0xa438, 0x268a}, {0xa436, 0xA01A}, {0xa438, 0x0000}, {0xa436, 0xA006}, ++ {0xa438, 0x0fff}, {0xa436, 0xA004}, {0xa438, 0x0689}, {0xa436, 0xA002}, {0xa438, 0x0911}, {0xa436, 0xA000}, {0xa438, 0x7302}, {0xa436, 0xB820}, {0xa438, 0x0010}, {0xa436, 0x8412}, ++ {0xa438, 0xaf84}, {0xa438, 0x1eaf}, {0xa438, 0x8427}, {0xa438, 0xaf84}, {0xa438, 0x27af}, {0xa438, 0x8427}, {0xa438, 0x0251}, {0xa438, 0x6802}, {0xa438, 0x8427}, {0xa438, 0xaf04}, ++ {0xa438, 0x0af8}, {0xa438, 0xf9bf}, {0xa438, 0x5581}, {0xa438, 0x0255}, {0xa438, 0x27ef}, {0xa438, 0x310d}, {0xa438, 0x345b}, {0xa438, 0x0fa3}, {0xa438, 0x032a}, {0xa438, 0xe087}, ++ {0xa438, 0xffac}, {0xa438, 0x2040}, {0xa438, 0xbf56}, {0xa438, 0x7402}, {0xa438, 0x5527}, {0xa438, 0xef31}, {0xa438, 0xef20}, {0xa438, 0xe787}, {0xa438, 0xfee6}, {0xa438, 0x87fd}, ++ {0xa438, 0xd488}, {0xa438, 0x88bf}, {0xa438, 0x5674}, {0xa438, 0x0254}, {0xa438, 0xe3e0}, {0xa438, 0x87ff}, {0xa438, 0xf720}, {0xa438, 0xe487}, {0xa438, 0xffaf}, {0xa438, 0x847e}, ++ {0xa438, 0xe087}, {0xa438, 0xffad}, {0xa438, 0x2016}, {0xa438, 0xe387}, {0xa438, 0xfee2}, {0xa438, 0x87fd}, {0xa438, 0xef45}, {0xa438, 0xbf56}, {0xa438, 0x7402}, {0xa438, 0x54e3}, ++ {0xa438, 0xe087}, {0xa438, 0xfff6}, {0xa438, 0x20e4}, {0xa438, 0x87ff}, {0xa438, 0xfdfc}, {0xa438, 0x0400}, {0xa436, 0xb818}, {0xa438, 0x0407}, {0xa436, 0xb81a}, {0xa438, 0xfffd}, ++ {0xa436, 0xb81c}, {0xa438, 0xfffd}, {0xa436, 0xb81e}, {0xa438, 0xfffd}, {0xa436, 0xb832}, {0xa438, 0x0001}, {0xb820, 0x0000}, {0xb82e, 0x0000}, {0xa436, 0x8028}, {0xa438, 0x0000} ++}; ++ ++static rtk_api_ret_t _rtk_switch_init_8367c(void) ++{ ++ rtk_port_t port; ++ rtk_uint32 retVal; ++ rtk_uint32 regData; ++ rtk_uint32 regValue; ++ ++ if( (retVal = rtl8367c_setAsicReg(0x13c2, 0x0249)) != RT_ERR_OK) ++ return retVal; ++ ++ if( (retVal = rtl8367c_getAsicReg(0x1301, ®Value)) != RT_ERR_OK) ++ return retVal; ++ ++ if( (retVal = rtl8367c_setAsicReg(0x13c2, 0x0000)) != RT_ERR_OK) ++ return retVal; ++ ++ RTK_SCAN_ALL_LOG_PORT(port) ++ { ++ if(rtk_switch_isUtpPort(port) == RT_ERR_OK) ++ { ++ if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_PORT0_EEECFG + (0x20 * port), RTL8367C_PORT0_EEECFG_EEE_100M_OFFSET, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_PORT0_EEECFG + (0x20 * port), RTL8367C_PORT0_EEECFG_EEE_GIGA_500M_OFFSET, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_PORT0_EEECFG + (0x20 * port), RTL8367C_PORT0_EEECFG_EEE_TX_OFFSET, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_PORT0_EEECFG + (0x20 * port), RTL8367C_PORT0_EEECFG_EEE_RX_OFFSET, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xA428, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ regData &= ~(0x0200); ++ if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xA428, regData)) != RT_ERR_OK) ++ return retVal; ++ ++ if((regValue & 0x00F0) == 0x00A0) ++ { ++ if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xA5D0, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ regData |= 0x0006; ++ if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xA5D0, regData)) != RT_ERR_OK) ++ return retVal; ++ } ++ } ++ } ++ ++ if((retVal = rtl8367c_setAsicReg(RTL8367C_REG_UTP_FIB_DET, 0x15BB)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicReg(0x1303, 0x06D6)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicReg(0x1304, 0x0700)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicReg(0x13E2, 0x003F)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicReg(0x13F9, 0x0090)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicReg(0x121e, 0x03CA)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicReg(0x1233, 0x0352)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicReg(0x1237, 0x00a0)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicReg(0x123a, 0x0030)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicReg(0x1239, 0x0084)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicReg(0x0301, 0x1000)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicReg(0x1349, 0x001F)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBit(0x18e0, 0, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBit(0x122b, 14, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBits(0x1305, 0xC000, 3)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++static rtk_api_ret_t _rtk_switch_init_8370b(void) ++{ ++ ret_t retVal; ++ rtk_uint32 regData, tmp = 0; ++ rtk_uint32 i, prf, counter; ++ rtk_uint32 long_link[8] = {0x0210, 0x03e8, 0x0218, 0x03f0, 0x0220, 0x03f8, 0x0208, 0x03e0 }; ++ ++ if((retVal = rtl8367c_setAsicRegBits(0x1205, 0x0300, 3)) != RT_ERR_OK) ++ return retVal; ++ ++ ++ for(i=0; i<8; i++) ++ { ++ if ((retVal = rtl8367c_getAsicPHYOCPReg(i, 0xa420, ®Data)) != RT_ERR_OK) ++ return retVal; ++ tmp = regData & 0x7 ; ++ if(tmp == 0x3) ++ { ++ prf = 1; ++ if((retVal = rtl8367c_setAsicPHYOCPReg(i, 0xb83e, 0x6fa9)) != RT_ERR_OK) ++ return retVal; ++ if((retVal = rtl8367c_setAsicPHYOCPReg(i, 0xb840, 0xa9)) != RT_ERR_OK) ++ return retVal; ++ for(counter = 0; counter < 10000; counter++); //delay ++ ++ if ((retVal = rtl8367c_getAsicPHYOCPReg(i, 0xb820, ®Data)) != RT_ERR_OK) ++ return retVal; ++ tmp = regData | 0x10; ++ if ((retVal = rtl8367c_setAsicPHYOCPReg(i, 0xb820, tmp)) != RT_ERR_OK) ++ return retVal; ++ for(counter = 0; counter < 10000; counter++); //delay ++ counter = 0; ++ do{ ++ counter = counter + 1; ++ if ((retVal = rtl8367c_getAsicPHYOCPReg(i, 0xb800, ®Data)) != RT_ERR_OK) ++ return retVal; ++ tmp = regData & 0x40; ++ if(tmp != 0) ++ break; ++ } while (counter < 20); //Wait for patch ready = 1... ++ } ++ } ++ if ((retVal = rtl8367c_getAsicReg(0x1d01, ®Data)) != RT_ERR_OK) ++ return retVal; ++ tmp = regData; ++ tmp = tmp | 0x3BE0; /*Broadcast port enable*/ ++ tmp = tmp & 0xFFE0; /*Phy_id = 0 */ ++ if((retVal = rtl8367c_setAsicReg(0x1d01, tmp)) != RT_ERR_OK) ++ return retVal; ++ ++ for(i=0;i < 210; i++) ++ { ++ if((retVal = rtl8367c_setAsicPHYOCPReg(0, PatchChipData[i][0], PatchChipData[i][1])) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ if((retVal = rtl8367c_setAsicReg(0x1d01, regData)) != RT_ERR_OK) ++ return retVal; ++ ++ for(i=0; i < 8; i++) ++ { ++ if((retVal = rtl8367c_setAsicPHYOCPReg(i, 0xa4b4, long_link[i])) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ if (prf == 0x1) ++ { ++ for(i=0; i<8; i++) ++ { ++ if ((retVal = rtl8367c_getAsicPHYOCPReg(i, 0xb820, ®Data)) != RT_ERR_OK) ++ return retVal; ++ tmp = regData & 0xFFEF; ++ if ((retVal = rtl8367c_setAsicPHYOCPReg(i, 0xb820, tmp)) != RT_ERR_OK) ++ return retVal; ++ ++ for(counter = 0; counter < 10000; counter++); //delay ++ ++ counter = 0; ++ do{ ++ counter = counter + 1; ++ if ((retVal = rtl8367c_getAsicPHYOCPReg(i, 0xb800, ®Data)) != RT_ERR_OK) ++ return retVal; ++ tmp = regData & 0x40; ++ if( tmp == 0 ) ++ break; ++ } while (counter < 20); //Wait for patch ready = 1... ++ if ((retVal = rtl8367c_setAsicPHYOCPReg(i, 0xb83e, 0x6f48)) != RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicPHYOCPReg(i, 0xb840, 0xfa)) != RT_ERR_OK) ++ return retVal; ++ } ++ } ++ ++ /*Check phy link status*/ ++ for(i=0; i<8; i++) ++ { ++ if ((retVal = rtl8367c_getAsicPHYOCPReg(i, 0xa400, ®Data)) != RT_ERR_OK) ++ return retVal; ++ tmp = regData & 0x800; ++ if(tmp == 0x0) ++ { ++ tmp = regData | 0x200; ++ if ((retVal = rtl8367c_setAsicPHYOCPReg(i, 0xa400, tmp)) != RT_ERR_OK) ++ return retVal; ++ } ++ } ++ ++ for(counter = 0; counter < 10000; counter++); //delay ++ ++ return RT_ERR_OK; ++} ++ ++static rtk_api_ret_t _rtk_switch_init_8364b(void) ++{ ++ ret_t retVal; ++ rtk_uint32 regData; ++ ++ /*enable EEE, include mac & phy*/ ++ ++ if ((retVal = rtl8367c_setAsicRegBits(0x38, 0x300, 3)) != RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicRegBits(0x78, 0x300, 3)) != RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicRegBits(0xd8, 0x300, 0)) != RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicRegBits(0xf8, 0x300, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicPHYOCPReg(1, 0xa5d0, 6)) != RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicPHYOCPReg(3, 0xa5d0, 6)) != RT_ERR_OK) ++ return retVal; ++ ++ /*PAD para*/ ++ ++ /*EXT1 PAD Para*/ ++ if ((retVal = rtl8367c_getAsicReg(0x1303, ®Data)) != RT_ERR_OK) ++ return retVal; ++ regData &= 0xFFFFFFFE; ++ regData |= 0x250; ++ if((retVal = rtl8367c_setAsicReg(0x1303, regData)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicRegBits(0x1304, 0x7000, 0)) != RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicRegBits(0x1304, 0x700, 7)) != RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicRegBits(0x13f9, 0x38, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ /*EXT2 PAD Para*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1303, 10, 1)) != RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicRegBits(0x13E2, 0x1ff, 0x26)) != RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicRegBits(0x13f9, 0x1c0, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ ++ /*SDS PATCH*/ ++ /*SP_CFG_EN_LINK_FIB1G*/ ++ if((retVal = rtl8367c_getAsicSdsReg(0, 4, 0, ®Data)) != RT_ERR_OK) ++ return retVal; ++ regData |= 0x4; ++ if((retVal = rtl8367c_setAsicSdsReg(0,4,0, regData)) != RT_ERR_OK) ++ return retVal; ++ ++ /*FIB100 Down-speed*/ ++ if((retVal = rtl8367c_getAsicSdsReg(0, 1, 0, ®Data)) != RT_ERR_OK) ++ return retVal; ++ regData |= 0x20; ++ if((retVal = rtl8367c_setAsicSdsReg(0,1,0, regData)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++static rtk_api_ret_t _rtk_switch_init_8363sc_vb(void) ++{ ++ ++ ret_t retVal; ++ rtk_uint32 regData; ++ ++ /*enable EEE, include mac & phy*/ ++ ++ if ((retVal = rtl8367c_setAsicRegBits(0x38, 0x300, 3)) != RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicRegBits(0x78, 0x300, 3)) != RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicRegBits(0xd8, 0x300, 0)) != RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicRegBits(0xf8, 0x300, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicPHYOCPReg(1, 0xa5d0, 6)) != RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicPHYOCPReg(3, 0xa5d0, 6)) != RT_ERR_OK) ++ return retVal; ++ ++ /*PAD para*/ ++ ++ /*EXT1 PAD Para*/ ++ if ((retVal = rtl8367c_getAsicReg(0x1303, ®Data)) != RT_ERR_OK) ++ return retVal; ++ regData &= 0xFFFFFFFE; ++ regData |= 0x250; ++ if((retVal = rtl8367c_setAsicReg(0x1303, regData)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicRegBits(0x1304, 0x7000, 0)) != RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicRegBits(0x1304, 0x700, 7)) != RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicRegBits(0x13f9, 0x38, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ /*EXT2 PAD Para*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1303, 10, 1)) != RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicRegBits(0x13E2, 0x1ff, 0x26)) != RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicRegBits(0x13f9, 0x1c0, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ ++ /*SDS PATCH*/ ++ /*SP_CFG_EN_LINK_FIB1G*/ ++ if((retVal = rtl8367c_getAsicSdsReg(0, 4, 0, ®Data)) != RT_ERR_OK) ++ return retVal; ++ regData |= 0x4; ++ if((retVal = rtl8367c_setAsicSdsReg(0,4,0, regData)) != RT_ERR_OK) ++ return retVal; ++ ++ /*FIB100 Down-speed*/ ++ if((retVal = rtl8367c_getAsicSdsReg(0, 1, 0, ®Data)) != RT_ERR_OK) ++ return retVal; ++ regData |= 0x20; ++ if((retVal = rtl8367c_setAsicSdsReg(0,1,0, regData)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_switch_probe ++ * Description: ++ * Probe switch ++ * Input: ++ * None ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Switch probed ++ * RT_ERR_FAILED - Switch Unprobed. ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_switch_probe(switch_chip_t *pSwitchChip) ++{ ++#if defined(FORCE_PROBE_RTL8367C) ++ ++ *pSwitchChip = CHIP_RTL8367C; ++ halCtrl = &rtl8367c_hal_Ctrl; ++ ++#elif defined(FORCE_PROBE_RTL8370B) ++ ++ *pSwitchChip = CHIP_RTL8370B; ++ halCtrl = &rtl8370b_hal_Ctrl; ++ ++#elif defined(FORCE_PROBE_RTL8364B) ++ ++ *pSwitchChip = CHIP_RTL8364B; ++ halCtrl = &rtl8364b_hal_Ctrl; ++ ++#elif defined(FORCE_PROBE_RTL8363SC_VB) ++ ++ *pSwitchChip = CHIP_RTL8363SC_VB; ++ halCtrl = &rtl8363sc_vb_hal_Ctrl; ++ ++#else ++ rtk_uint32 retVal; ++ rtk_uint32 data, regValue; ++ ++ if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0249)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_getAsicReg(0x1300, &data)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_getAsicReg(0x1301, ®Value)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0000)) != RT_ERR_OK) ++ return retVal; ++ ++ switch (data) ++ { ++ case 0x0276: ++ case 0x0597: ++ case 0x6367: ++ *pSwitchChip = CHIP_RTL8367C; ++ halCtrl = &rtl8367c_hal_Ctrl; ++ break; ++ case 0x0652: ++ case 0x6368: ++ *pSwitchChip = CHIP_RTL8370B; ++ halCtrl = &rtl8370b_hal_Ctrl; ++ break; ++ case 0x0801: ++ case 0x6511: ++ if( (regValue & 0x00F0) == 0x0080) ++ { ++ *pSwitchChip = CHIP_RTL8363SC_VB; ++ halCtrl = &rtl8363sc_vb_hal_Ctrl; ++ } ++ else ++ { ++ *pSwitchChip = CHIP_RTL8364B; ++ halCtrl = &rtl8364b_hal_Ctrl; ++ } ++ break; ++ default: ++ return RT_ERR_FAILED; ++ } ++#endif ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_switch_initialState_set ++ * Description: ++ * Set initial status ++ * Input: ++ * state - Initial state; ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Initialized ++ * RT_ERR_FAILED - Uninitialized ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_switch_initialState_set(init_state_t state) ++{ ++ if(state >= INIT_STATE_END) ++ return RT_ERR_FAILED; ++ ++ init_state = state; ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_switch_initialState_get ++ * Description: ++ * Get initial status ++ * Input: ++ * None ++ * Output: ++ * None ++ * Return: ++ * INIT_COMPLETED - Initialized ++ * INIT_NOT_COMPLETED - Uninitialized ++ * Note: ++ * ++ */ ++init_state_t rtk_switch_initialState_get(void) ++{ ++ return init_state; ++} ++ ++/* Function Name: ++ * rtk_switch_logicalPortCheck ++ * Description: ++ * Check logical port ID. ++ * Input: ++ * logicalPort - logical port ID ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Port ID is correct ++ * RT_ERR_FAILED - Port ID is not correct ++ * RT_ERR_NOT_INIT - Not Initialize ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_switch_logicalPortCheck(rtk_port_t logicalPort) ++{ ++ if(init_state != INIT_COMPLETED) ++ return RT_ERR_NOT_INIT; ++ ++ if(logicalPort >= RTK_SWITCH_PORT_NUM) ++ return RT_ERR_FAILED; ++ ++ if(halCtrl->l2p_port[logicalPort] == 0xFF) ++ return RT_ERR_FAILED; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_switch_isUtpPort ++ * Description: ++ * Check is logical port a UTP port ++ * Input: ++ * logicalPort - logical port ID ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Port ID is a UTP port ++ * RT_ERR_FAILED - Port ID is not a UTP port ++ * RT_ERR_NOT_INIT - Not Initialize ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_switch_isUtpPort(rtk_port_t logicalPort) ++{ ++ if(init_state != INIT_COMPLETED) ++ return RT_ERR_NOT_INIT; ++ ++ if(logicalPort >= RTK_SWITCH_PORT_NUM) ++ return RT_ERR_FAILED; ++ ++ if(halCtrl->log_port_type[logicalPort] == UTP_PORT) ++ return RT_ERR_OK; ++ else ++ return RT_ERR_FAILED; ++} ++ ++/* Function Name: ++ * rtk_switch_isExtPort ++ * Description: ++ * Check is logical port a Extension port ++ * Input: ++ * logicalPort - logical port ID ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Port ID is a EXT port ++ * RT_ERR_FAILED - Port ID is not a EXT port ++ * RT_ERR_NOT_INIT - Not Initialize ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_switch_isExtPort(rtk_port_t logicalPort) ++{ ++ if(init_state != INIT_COMPLETED) ++ return RT_ERR_NOT_INIT; ++ ++ if(logicalPort >= RTK_SWITCH_PORT_NUM) ++ return RT_ERR_FAILED; ++ ++ if(halCtrl->log_port_type[logicalPort] == EXT_PORT) ++ return RT_ERR_OK; ++ else ++ return RT_ERR_FAILED; ++} ++ ++ ++/* Function Name: ++ * rtk_switch_isHsgPort ++ * Description: ++ * Check is logical port a HSG port ++ * Input: ++ * logicalPort - logical port ID ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Port ID is a HSG port ++ * RT_ERR_FAILED - Port ID is not a HSG port ++ * RT_ERR_NOT_INIT - Not Initialize ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_switch_isHsgPort(rtk_port_t logicalPort) ++{ ++ if(init_state != INIT_COMPLETED) ++ return RT_ERR_NOT_INIT; ++ ++ if(logicalPort >= RTK_SWITCH_PORT_NUM) ++ return RT_ERR_FAILED; ++ ++ if(logicalPort == halCtrl->hsg_logical_port) ++ return RT_ERR_OK; ++ else ++ return RT_ERR_FAILED; ++} ++ ++/* Function Name: ++ * rtk_switch_isSgmiiPort ++ * Description: ++ * Check is logical port a SGMII port ++ * Input: ++ * logicalPort - logical port ID ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Port ID is a SGMII port ++ * RT_ERR_FAILED - Port ID is not a SGMII port ++ * RT_ERR_NOT_INIT - Not Initialize ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_switch_isSgmiiPort(rtk_port_t logicalPort) ++{ ++ if(init_state != INIT_COMPLETED) ++ return RT_ERR_NOT_INIT; ++ ++ if(logicalPort >= RTK_SWITCH_PORT_NUM) ++ return RT_ERR_FAILED; ++ ++ if( ((0x01 << logicalPort) & halCtrl->sg_logical_portmask) != 0) ++ return RT_ERR_OK; ++ else ++ return RT_ERR_FAILED; ++} ++ ++/* Function Name: ++ * rtk_switch_isCPUPort ++ * Description: ++ * Check is logical port a CPU port ++ * Input: ++ * logicalPort - logical port ID ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Port ID is a CPU port ++ * RT_ERR_FAILED - Port ID is not a CPU port ++ * RT_ERR_NOT_INIT - Not Initialize ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_switch_isCPUPort(rtk_port_t logicalPort) ++{ ++ if(init_state != INIT_COMPLETED) ++ return RT_ERR_NOT_INIT; ++ ++ if(logicalPort >= RTK_SWITCH_PORT_NUM) ++ return RT_ERR_FAILED; ++ ++ if( ((0x01 << logicalPort) & halCtrl->valid_cpu_portmask) != 0) ++ return RT_ERR_OK; ++ else ++ return RT_ERR_FAILED; ++} ++ ++/* Function Name: ++ * rtk_switch_isComboPort ++ * Description: ++ * Check is logical port a Combo port ++ * Input: ++ * logicalPort - logical port ID ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Port ID is a combo port ++ * RT_ERR_FAILED - Port ID is not a combo port ++ * RT_ERR_NOT_INIT - Not Initialize ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_switch_isComboPort(rtk_port_t logicalPort) ++{ ++ if(init_state != INIT_COMPLETED) ++ return RT_ERR_NOT_INIT; ++ ++ if(logicalPort >= RTK_SWITCH_PORT_NUM) ++ return RT_ERR_FAILED; ++ ++ if(halCtrl->combo_logical_port == logicalPort) ++ return RT_ERR_OK; ++ else ++ return RT_ERR_FAILED; ++} ++ ++/* Function Name: ++ * rtk_switch_ComboPort_get ++ * Description: ++ * Get Combo port ID ++ * Input: ++ * None ++ * Output: ++ * None ++ * Return: ++ * Port ID of combo port ++ * Note: ++ * ++ */ ++rtk_uint32 rtk_switch_ComboPort_get(void) ++{ ++ return halCtrl->combo_logical_port; ++} ++ ++/* Function Name: ++ * rtk_switch_isPtpPort ++ * Description: ++ * Check is logical port a PTP port ++ * Input: ++ * logicalPort - logical port ID ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Port ID is a PTP port ++ * RT_ERR_FAILED - Port ID is not a PTP port ++ * RT_ERR_NOT_INIT - Not Initialize ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_switch_isPtpPort(rtk_port_t logicalPort) ++{ ++ if(init_state != INIT_COMPLETED) ++ return RT_ERR_NOT_INIT; ++ ++ if(logicalPort >= RTK_SWITCH_PORT_NUM) ++ return RT_ERR_FAILED; ++ ++ if(halCtrl->ptp_port[logicalPort] == 1) ++ return RT_ERR_OK; ++ else ++ return RT_ERR_FAILED; ++} ++ ++/* Function Name: ++ * rtk_switch_port_L2P_get ++ * Description: ++ * Get physical port ID ++ * Input: ++ * logicalPort - logical port ID ++ * Output: ++ * None ++ * Return: ++ * Physical port ID ++ * Note: ++ * ++ */ ++rtk_uint32 rtk_switch_port_L2P_get(rtk_port_t logicalPort) ++{ ++ if(init_state != INIT_COMPLETED) ++ return UNDEFINE_PHY_PORT; ++ ++ if(logicalPort >= RTK_SWITCH_PORT_NUM) ++ return UNDEFINE_PHY_PORT; ++ ++ return (halCtrl->l2p_port[logicalPort]); ++} ++ ++/* Function Name: ++ * rtk_switch_port_P2L_get ++ * Description: ++ * Get logical port ID ++ * Input: ++ * physicalPort - physical port ID ++ * Output: ++ * None ++ * Return: ++ * logical port ID ++ * Note: ++ * ++ */ ++rtk_port_t rtk_switch_port_P2L_get(rtk_uint32 physicalPort) ++{ ++ if(init_state != INIT_COMPLETED) ++ return UNDEFINE_PORT; ++ ++ if(physicalPort >= RTK_SWITCH_PORT_NUM) ++ return UNDEFINE_PORT; ++ ++ return (halCtrl->p2l_port[physicalPort]); ++} ++ ++/* Function Name: ++ * rtk_switch_isPortMaskValid ++ * Description: ++ * Check portmask is valid or not ++ * Input: ++ * pPmask - logical port mask ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - port mask is valid ++ * RT_ERR_FAILED - port mask is not valid ++ * RT_ERR_NOT_INIT - Not Initialize ++ * RT_ERR_NULL_POINTER - Null pointer ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_switch_isPortMaskValid(rtk_portmask_t *pPmask) ++{ ++ if(init_state != INIT_COMPLETED) ++ return RT_ERR_NOT_INIT; ++ ++ if(NULL == pPmask) ++ return RT_ERR_NULL_POINTER; ++ ++ if( (pPmask->bits[0] | halCtrl->valid_portmask) != halCtrl->valid_portmask ) ++ return RT_ERR_FAILED; ++ else ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_switch_isPortMaskUtp ++ * Description: ++ * Check all ports in portmask are only UTP port ++ * Input: ++ * pPmask - logical port mask ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Only UTP port in port mask ++ * RT_ERR_FAILED - Not only UTP port in port mask ++ * RT_ERR_NOT_INIT - Not Initialize ++ * RT_ERR_NULL_POINTER - Null pointer ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_switch_isPortMaskUtp(rtk_portmask_t *pPmask) ++{ ++ if(init_state != INIT_COMPLETED) ++ return RT_ERR_NOT_INIT; ++ ++ if(NULL == pPmask) ++ return RT_ERR_NULL_POINTER; ++ ++ if( (pPmask->bits[0] | halCtrl->valid_utp_portmask) != halCtrl->valid_utp_portmask ) ++ return RT_ERR_FAILED; ++ else ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_switch_isPortMaskExt ++ * Description: ++ * Check all ports in portmask are only EXT port ++ * Input: ++ * pPmask - logical port mask ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Only EXT port in port mask ++ * RT_ERR_FAILED - Not only EXT port in port mask ++ * RT_ERR_NOT_INIT - Not Initialize ++ * RT_ERR_NULL_POINTER - Null pointer ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_switch_isPortMaskExt(rtk_portmask_t *pPmask) ++{ ++ if(init_state != INIT_COMPLETED) ++ return RT_ERR_NOT_INIT; ++ ++ if(NULL == pPmask) ++ return RT_ERR_NULL_POINTER; ++ ++ if( (pPmask->bits[0] | halCtrl->valid_ext_portmask) != halCtrl->valid_ext_portmask ) ++ return RT_ERR_FAILED; ++ else ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_switch_portmask_L2P_get ++ * Description: ++ * Get physical portmask from logical portmask ++ * Input: ++ * pLogicalPmask - logical port mask ++ * Output: ++ * pPhysicalPortmask - physical port mask ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_NOT_INIT - Not Initialize ++ * RT_ERR_NULL_POINTER - Null pointer ++ * RT_ERR_PORT_MASK - Error port mask ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_switch_portmask_L2P_get(rtk_portmask_t *pLogicalPmask, rtk_uint32 *pPhysicalPortmask) ++{ ++ rtk_uint32 log_port, phy_port; ++ ++ if(init_state != INIT_COMPLETED) ++ return RT_ERR_NOT_INIT; ++ ++ if(NULL == pLogicalPmask) ++ return RT_ERR_NULL_POINTER; ++ ++ if(NULL == pPhysicalPortmask) ++ return RT_ERR_NULL_POINTER; ++ ++ if(rtk_switch_isPortMaskValid(pLogicalPmask) != RT_ERR_OK) ++ return RT_ERR_PORT_MASK; ++ ++ /* reset physical port mask */ ++ *pPhysicalPortmask = 0; ++ ++ RTK_PORTMASK_SCAN((*pLogicalPmask), log_port) ++ { ++ phy_port = rtk_switch_port_L2P_get((rtk_port_t)log_port); ++ *pPhysicalPortmask |= (0x0001 << phy_port); ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_switch_portmask_P2L_get ++ * Description: ++ * Get logical portmask from physical portmask ++ * Input: ++ * physicalPortmask - physical port mask ++ * Output: ++ * pLogicalPmask - logical port mask ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_NOT_INIT - Not Initialize ++ * RT_ERR_NULL_POINTER - Null pointer ++ * RT_ERR_PORT_MASK - Error port mask ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_switch_portmask_P2L_get(rtk_uint32 physicalPortmask, rtk_portmask_t *pLogicalPmask) ++{ ++ rtk_uint32 log_port, phy_port; ++ ++ if(init_state != INIT_COMPLETED) ++ return RT_ERR_NOT_INIT; ++ ++ if(NULL == pLogicalPmask) ++ return RT_ERR_NULL_POINTER; ++ ++ RTK_PORTMASK_CLEAR(*pLogicalPmask); ++ ++ for(phy_port = halCtrl->min_phy_port; phy_port <= halCtrl->max_phy_port; phy_port++) ++ { ++ if(physicalPortmask & (0x0001 << phy_port)) ++ { ++ log_port = rtk_switch_port_P2L_get(phy_port); ++ if(log_port != UNDEFINE_PORT) ++ { ++ RTK_PORTMASK_PORT_SET(*pLogicalPmask, log_port); ++ } ++ } ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_switch_phyPortMask_get ++ * Description: ++ * Get physical portmask ++ * Input: ++ * None ++ * Output: ++ * None ++ * Return: ++ * 0x00 - Not Initialize ++ * Other value - Physical port mask ++ * Note: ++ * ++ */ ++rtk_uint32 rtk_switch_phyPortMask_get(void) ++{ ++ if(init_state != INIT_COMPLETED) ++ return 0x00; /* No port in portmask */ ++ ++ return (halCtrl->phy_portmask); ++} ++ ++/* Function Name: ++ * rtk_switch_logPortMask_get ++ * Description: ++ * Get Logical portmask ++ * Input: ++ * None ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_NOT_INIT - Not Initialize ++ * RT_ERR_NULL_POINTER - Null pointer ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_switch_logPortMask_get(rtk_portmask_t *pPortmask) ++{ ++ if(init_state != INIT_COMPLETED) ++ return RT_ERR_FAILED; ++ ++ if(NULL == pPortmask) ++ return RT_ERR_NULL_POINTER; ++ ++ pPortmask->bits[0] = halCtrl->valid_portmask; ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_switch_init ++ * Description: ++ * Set chip to default configuration environment ++ * Input: ++ * None ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * The API can set chip registers to default configuration for different release chip model. ++ */ ++rtk_api_ret_t rtk_switch_init(void) ++{ ++ rtk_uint32 retVal; ++ rtl8367c_rma_t rmaCfg; ++ switch_chip_t switchChip; ++ ++ /* probe switch */ ++ if((retVal = rtk_switch_probe(&switchChip)) != RT_ERR_OK) ++ return retVal; ++ ++ /* Set initial state */ ++ ++ if((retVal = rtk_switch_initialState_set(INIT_COMPLETED)) != RT_ERR_OK) ++ return retVal; ++ ++ /* Initial */ ++ switch(switchChip) ++ { ++ case CHIP_RTL8367C: ++ if((retVal = _rtk_switch_init_8367c()) != RT_ERR_OK) ++ return retVal; ++ break; ++ case CHIP_RTL8370B: ++ if((retVal = _rtk_switch_init_8370b()) != RT_ERR_OK) ++ return retVal; ++ break; ++ case CHIP_RTL8364B: ++ if((retVal = _rtk_switch_init_8364b()) != RT_ERR_OK) ++ return retVal; ++ break; ++ case CHIP_RTL8363SC_VB: ++ if((retVal = _rtk_switch_init_8363sc_vb()) != RT_ERR_OK) ++ return retVal; ++ break; ++ default: ++ return RT_ERR_CHIP_NOT_FOUND; ++ } ++ ++ /* Set Old max packet length to 16K */ ++ if((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_MAX_LENGTH_LIMINT_IPG, RTL8367C_MAX_LENTH_CTRL_MASK, 3)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_MAX_LEN_RX_TX, RTL8367C_MAX_LEN_RX_TX_MASK, 3)) != RT_ERR_OK) ++ return retVal; ++ ++ /* ACL Mode */ ++ if((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_ACL_ACCESS_MODE, RTL8367C_ACL_ACCESS_MODE_MASK, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ /* Max rate */ ++ if((retVal = rtk_rate_igrBandwidthCtrlRate_set(halCtrl->hsg_logical_port, RTL8367C_QOS_RATE_INPUT_MAX_HSG, DISABLED, ENABLED)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtk_rate_egrBandwidthCtrlRate_set(halCtrl->hsg_logical_port, RTL8367C_QOS_RATE_INPUT_MAX_HSG, ENABLED)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicReg(0x03fa, 0x0007)) != RT_ERR_OK) ++ return retVal; ++ ++ /* Change unknown DA to per port setting */ ++ if((retVal = rtl8367c_setAsicRegBits(RTL8367C_PORT_SECURIT_CTRL_REG, RTL8367C_UNKNOWN_UNICAST_DA_BEHAVE_MASK, 3)) != RT_ERR_OK) ++ return retVal; ++ ++ /* LUT lookup OP = 1 */ ++ if ((retVal = rtl8367c_setAsicLutIpLookupMethod(1))!=RT_ERR_OK) ++ return retVal; ++ ++ /* Set RMA */ ++ rmaCfg.portiso_leaky = 0; ++ rmaCfg.vlan_leaky = 0; ++ rmaCfg.keep_format = 0; ++ rmaCfg.trap_priority = 0; ++ rmaCfg.discard_storm_filter = 0; ++ rmaCfg.operation = 0; ++ if ((retVal = rtl8367c_setAsicRma(2, &rmaCfg))!=RT_ERR_OK) ++ return retVal; ++ ++ /* Enable TX Mirror isolation leaky */ ++ if ((retVal = rtl8367c_setAsicPortMirrorIsolationTxLeaky(ENABLED)) != RT_ERR_OK) ++ return retVal; ++ ++ /* INT EN */ ++ if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_IO_MISC_FUNC, RTL8367C_INT_EN_OFFSET, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_switch_portMaxPktLen_set ++ * Description: ++ * Set Max packet length ++ * Input: ++ * port - Port ID ++ * speed - Speed ++ * cfgId - Configuration ID ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Error Input ++ * Note: ++ */ ++rtk_api_ret_t rtk_switch_portMaxPktLen_set(rtk_port_t port, rtk_switch_maxPktLen_linkSpeed_t speed, rtk_uint32 cfgId) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if(speed >= MAXPKTLEN_LINK_SPEED_END) ++ return RT_ERR_INPUT; ++ ++ if(cfgId > MAXPKTLEN_CFG_ID_MAX) ++ return RT_ERR_INPUT; ++ ++ if((retVal = rtl8367c_setAsicMaxLength(rtk_switch_port_L2P_get(port), (rtk_uint32)speed, cfgId)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_switch_portMaxPktLen_get ++ * Description: ++ * Get Max packet length ++ * Input: ++ * port - Port ID ++ * speed - Speed ++ * Output: ++ * pCfgId - Configuration ID ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Error Input ++ * Note: ++ */ ++rtk_api_ret_t rtk_switch_portMaxPktLen_get(rtk_port_t port, rtk_switch_maxPktLen_linkSpeed_t speed, rtk_uint32 *pCfgId) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if(speed >= MAXPKTLEN_LINK_SPEED_END) ++ return RT_ERR_INPUT; ++ ++ if(NULL == pCfgId) ++ return RT_ERR_NULL_POINTER; ++ ++ if((retVal = rtl8367c_getAsicMaxLength(rtk_switch_port_L2P_get(port), (rtk_uint32)speed, pCfgId)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_switch_maxPktLenCfg_set ++ * Description: ++ * Set Max packet length configuration ++ * Input: ++ * cfgId - Configuration ID ++ * pktLen - Max packet length ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Error Input ++ * Note: ++ */ ++rtk_api_ret_t rtk_switch_maxPktLenCfg_set(rtk_uint32 cfgId, rtk_uint32 pktLen) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(cfgId > MAXPKTLEN_CFG_ID_MAX) ++ return RT_ERR_INPUT; ++ ++ if(pktLen > RTK_SWITCH_MAX_PKTLEN) ++ return RT_ERR_INPUT; ++ ++ if((retVal = rtl8367c_setAsicMaxLengthCfg(cfgId, pktLen)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_switch_maxPktLenCfg_get ++ * Description: ++ * Get Max packet length configuration ++ * Input: ++ * cfgId - Configuration ID ++ * pPktLen - Max packet length ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Error Input ++ * Note: ++ */ ++rtk_api_ret_t rtk_switch_maxPktLenCfg_get(rtk_uint32 cfgId, rtk_uint32 *pPktLen) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(cfgId > MAXPKTLEN_CFG_ID_MAX) ++ return RT_ERR_INPUT; ++ ++ if(NULL == pPktLen) ++ return RT_ERR_NULL_POINTER; ++ ++ if((retVal = rtl8367c_getAsicMaxLengthCfg(cfgId, pPktLen)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_switch_greenEthernet_set ++ * Description: ++ * Set all Ports Green Ethernet state. ++ * Input: ++ * enable - Green Ethernet state. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_ENABLE - Invalid enable input. ++ * Note: ++ * This API can set all Ports Green Ethernet state. ++ * The configuration is as following: ++ * - DISABLE ++ * - ENABLE ++ */ ++rtk_api_ret_t rtk_switch_greenEthernet_set(rtk_enable_t enable) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 port; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ RTK_SCAN_ALL_LOG_PORT(port) ++ { ++ if(rtk_switch_isUtpPort(port) == RT_ERR_OK) ++ { ++ if ((retVal = rtl8367c_setAsicPowerSaving(rtk_switch_port_L2P_get(port),enable))!=RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicGreenEthernet(rtk_switch_port_L2P_get(port), enable))!=RT_ERR_OK) ++ return retVal; ++ } ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_switch_greenEthernet_get ++ * Description: ++ * Get all Ports Green Ethernet state. ++ * Input: ++ * None ++ * Output: ++ * pEnable - Green Ethernet state. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * This API can get Green Ethernet state. ++ */ ++rtk_api_ret_t rtk_switch_greenEthernet_get(rtk_enable_t *pEnable) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 port; ++ rtk_uint32 state; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ RTK_SCAN_ALL_LOG_PORT(port) ++ { ++ if(rtk_switch_isUtpPort(port) == RT_ERR_OK) ++ { ++ if ((retVal = rtl8367c_getAsicPowerSaving(rtk_switch_port_L2P_get(port), &state))!=RT_ERR_OK) ++ return retVal; ++ ++ if(state == DISABLED) ++ { ++ *pEnable = DISABLED; ++ return RT_ERR_OK; ++ } ++ ++ if ((retVal = rtl8367c_getAsicGreenEthernet(rtk_switch_port_L2P_get(port), &state))!=RT_ERR_OK) ++ return retVal; ++ ++ if(state == DISABLED) ++ { ++ *pEnable = DISABLED; ++ return RT_ERR_OK; ++ } ++ } ++ } ++ ++ *pEnable = ENABLED; ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_switch_maxLogicalPort_get ++ * Description: ++ * Get Max logical port ID ++ * Input: ++ * None ++ * Output: ++ * None ++ * Return: ++ * Max logical port ++ * Note: ++ * This API can get max logical port ++ */ ++rtk_port_t rtk_switch_maxLogicalPort_get(void) ++{ ++ rtk_port_t port, maxLogicalPort = 0; ++ ++ /* Check initialization state */ ++ if(rtk_switch_initialState_get() != INIT_COMPLETED) ++ { ++ return UNDEFINE_PORT; ++ } ++ ++ for(port = 0; port < RTK_SWITCH_PORT_NUM; port++) ++ { ++ if( (halCtrl->log_port_type[port] == UTP_PORT) || (halCtrl->log_port_type[port] == EXT_PORT) ) ++ maxLogicalPort = port; ++ } ++ ++ return maxLogicalPort; ++} ++ ++/* Function Name: ++ * rtk_switch_maxMeterId_get ++ * Description: ++ * Get Max Meter ID ++ * Input: ++ * None ++ * Output: ++ * None ++ * Return: ++ * 0x00 - Not Initialize ++ * Other value - Max Meter ID ++ * Note: ++ * ++ */ ++rtk_uint32 rtk_switch_maxMeterId_get(void) ++{ ++ if(init_state != INIT_COMPLETED) ++ return 0x00; ++ ++ return (halCtrl->max_meter_id); ++} ++ ++/* Function Name: ++ * rtk_switch_maxLutAddrNumber_get ++ * Description: ++ * Get Max LUT Address number ++ * Input: ++ * None ++ * Output: ++ * None ++ * Return: ++ * 0x00 - Not Initialize ++ * Other value - Max LUT Address number ++ * Note: ++ * ++ */ ++rtk_uint32 rtk_switch_maxLutAddrNumber_get(void) ++{ ++ if(init_state != INIT_COMPLETED) ++ return 0x00; ++ ++ return (halCtrl->max_lut_addr_num); ++} ++ ++/* Function Name: ++ * rtk_switch_isValidTrunkGrpId ++ * Description: ++ * Check if trunk group is valid or not ++ * Input: ++ * grpId - Group ID ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Trunk Group ID is valid ++ * RT_ERR_LA_TRUNK_ID - Trunk Group ID is not valid ++ * Note: ++ * ++ */ ++rtk_uint32 rtk_switch_isValidTrunkGrpId(rtk_uint32 grpId) ++{ ++ if(init_state != INIT_COMPLETED) ++ return 0x00; ++ ++ if( (halCtrl->trunk_group_mask & (0x01 << grpId) ) != 0) ++ return RT_ERR_OK; ++ else ++ return RT_ERR_LA_TRUNK_ID; ++ ++} ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv.c +new file mode 100644 +index 000000000000..7858edcf530a +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv.c +@@ -0,0 +1,639 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : ++ * ++ */ ++ ++#include ++ ++#if defined(RTK_X86_ASICDRV) ++#include ++#else ++#include ++#endif ++ ++/*for driver verify testing only*/ ++#ifdef CONFIG_RTL8367C_ASICDRV_TEST ++#define CLE_VIRTUAL_REG_SIZE 0x10000 ++rtk_uint16 CleVirtualReg[CLE_VIRTUAL_REG_SIZE]; ++#endif ++ ++#if defined(CONFIG_RTL865X_CLE) || defined (RTK_X86_CLE) ++rtk_uint32 cleDebuggingDisplay; ++#endif ++ ++#ifdef EMBEDDED_SUPPORT ++extern void setReg(rtk_uint16, rtk_uint16); ++extern rtk_uint16 getReg(rtk_uint16); ++#endif ++ ++/* Function Name: ++ * rtl8367c_setAsicRegBit ++ * Description: ++ * Set a bit value of a specified register ++ * Input: ++ * reg - register's address ++ * bit - bit location ++ * value - value to set. It can be value 0 or 1. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameter ++ * Note: ++ * Set a bit of a specified register to 1 or 0. ++ */ ++ret_t rtl8367c_setAsicRegBit(rtk_uint32 reg, rtk_uint32 bit, rtk_uint32 value) ++{ ++ ++#if defined(RTK_X86_ASICDRV) ++ rtk_uint32 regData; ++ ret_t retVal; ++ ++ if(bit >= RTL8367C_REGBITLENGTH) ++ return RT_ERR_INPUT; ++ ++ retVal = Access_Read(reg, 2, ®Data); ++ if(TRUE != retVal) ++ return RT_ERR_SMI; ++ ++ if(0x8367B == cleDebuggingDisplay) ++ PRINT("R[0x%4.4x]=0x%4.4x\n", reg, regData); ++ ++ if(value) ++ regData = regData | (1 << bit); ++ else ++ regData = regData & (~(1 << bit)); ++ ++ retVal = Access_Write(reg,2, regData); ++ if(TRUE != retVal) ++ return RT_ERR_SMI; ++ ++ if(0x8367B == cleDebuggingDisplay) ++ PRINT("W[0x%4.4x]=0x%4.4x\n", reg, regData); ++ ++ ++#elif defined(CONFIG_RTL8367C_ASICDRV_TEST) ++ ++ if(bit >= RTL8367C_REGBITLENGTH) ++ return RT_ERR_INPUT; ++ ++ else if(reg >= CLE_VIRTUAL_REG_SIZE) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ if(value) ++ { ++ CleVirtualReg[reg] = CleVirtualReg[reg] | (1 << bit); ++ } ++ else ++ { ++ CleVirtualReg[reg] = CleVirtualReg[reg] & (~(1 << bit)); ++ } ++ ++ if(0x8367B == cleDebuggingDisplay) ++ PRINT("W[0x%4.4x]=0x%4.4x\n", reg, CleVirtualReg[reg]); ++ ++#elif defined(EMBEDDED_SUPPORT) ++ rtk_uint16 tmp; ++ ++ if(reg > RTL8367C_REGDATAMAX || value > 1) ++ return RT_ERR_INPUT; ++ ++ tmp = getReg(reg); ++ tmp &= (1 << bitIdx); ++ tmp |= (value << bitIdx); ++ setReg(reg, tmp); ++ ++#else ++ rtk_uint32 regData; ++ ret_t retVal; ++ ++ if(bit >= RTL8367C_REGBITLENGTH) ++ return RT_ERR_INPUT; ++ ++ retVal = smi_read(reg, ®Data); ++ if(retVal != RT_ERR_OK) ++ return RT_ERR_SMI; ++ ++ #ifdef CONFIG_RTL865X_CLE ++ if(0x8367B == cleDebuggingDisplay) ++ PRINT("R[0x%4.4x]=0x%4.4x\n", reg, regData); ++ #endif ++ if(value) ++ regData = regData | (1 << bit); ++ else ++ regData = regData & (~(1 << bit)); ++ ++ retVal = smi_write(reg, regData); ++ if(retVal != RT_ERR_OK) ++ return RT_ERR_SMI; ++ ++ #ifdef CONFIG_RTL865X_CLE ++ if(0x8367B == cleDebuggingDisplay) ++ PRINT("W[0x%4.4x]=0x%4.4x\n", reg, regData); ++ #endif ++ ++#endif ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_getAsicRegBit ++ * Description: ++ * Get a bit value of a specified register ++ * Input: ++ * reg - register's address ++ * bit - bit location ++ * value - value to get. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameter ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicRegBit(rtk_uint32 reg, rtk_uint32 bit, rtk_uint32 *pValue) ++{ ++ ++#if defined(RTK_X86_ASICDRV) ++ ++ rtk_uint32 regData; ++ ret_t retVal; ++ ++ if(bit >= RTL8367C_REGBITLENGTH) ++ return RT_ERR_INPUT; ++ ++ retVal = Access_Read(reg, 2, ®Data); ++ if(TRUE != retVal) ++ return RT_ERR_SMI; ++ ++ *pValue = (regData & (0x1 << bit)) >> bit; ++ ++ if(0x8367B == cleDebuggingDisplay) ++ PRINT("R[0x%4.4x]=0x%4.4x\n", reg, regData); ++ ++#elif defined(CONFIG_RTL8367C_ASICDRV_TEST) ++ ++ if(bit >= RTL8367C_REGBITLENGTH) ++ return RT_ERR_INPUT; ++ ++ if(reg >= CLE_VIRTUAL_REG_SIZE) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ *pValue = (CleVirtualReg[reg] & (0x1 << bit)) >> bit; ++ ++ if(0x8367B == cleDebuggingDisplay) ++ PRINT("R[0x%4.4x]=0x%4.4x\n", reg, CleVirtualReg[reg]); ++ ++#elif defined(EMBEDDED_SUPPORT) ++ rtk_uint16 tmp; ++ ++ if(reg > RTL8367C_REGDATAMAX ) ++ return RT_ERR_INPUT; ++ ++ tmp = getReg(reg); ++ tmp = tmp >> bitIdx; ++ tmp &= 1; ++ *value = tmp; ++#else ++ rtk_uint32 regData; ++ ret_t retVal; ++ ++ retVal = smi_read(reg, ®Data); ++ if(retVal != RT_ERR_OK) ++ return RT_ERR_SMI; ++ ++ #ifdef CONFIG_RTL865X_CLE ++ if(0x8367B == cleDebuggingDisplay) ++ PRINT("R[0x%4.4x]=0x%4.4x\n", reg, regData); ++ #endif ++ ++ *pValue = (regData & (0x1 << bit)) >> bit; ++ ++#endif ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_setAsicRegBits ++ * Description: ++ * Set bits value of a specified register ++ * Input: ++ * reg - register's address ++ * bits - bits mask for setting ++ * value - bits value for setting ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameter ++ * Note: ++ * Set bits of a specified register to value. Both bits and value are be treated as bit-mask ++ */ ++ret_t rtl8367c_setAsicRegBits(rtk_uint32 reg, rtk_uint32 bits, rtk_uint32 value) ++{ ++ ++#if defined(RTK_X86_ASICDRV) ++ ++ rtk_uint32 regData; ++ ret_t retVal; ++ rtk_uint32 bitsShift; ++ rtk_uint32 valueShifted; ++ ++ if(bits >= (1 << RTL8367C_REGBITLENGTH) ) ++ return RT_ERR_INPUT; ++ ++ bitsShift = 0; ++ while(!(bits & (1 << bitsShift))) ++ { ++ bitsShift++; ++ if(bitsShift >= RTL8367C_REGBITLENGTH) ++ return RT_ERR_INPUT; ++ } ++ ++ valueShifted = value << bitsShift; ++ if(valueShifted > RTL8367C_REGDATAMAX) ++ return RT_ERR_INPUT; ++ ++ retVal = Access_Read(reg, 2, ®Data); ++ if(TRUE != retVal) ++ return RT_ERR_SMI; ++ ++ if(0x8367B == cleDebuggingDisplay) ++ PRINT("R[0x%4.4x]=0x%4.4x\n", reg, regData); ++ ++ regData = regData & (~bits); ++ regData = regData | (valueShifted & bits); ++ ++ retVal = Access_Write(reg,2, regData); ++ if(TRUE != retVal) ++ return RT_ERR_SMI; ++ ++ if(0x8367B == cleDebuggingDisplay) ++ PRINT("W[0x%4.4x]=0x%4.4x\n", reg, regData); ++ ++#elif defined(CONFIG_RTL8367C_ASICDRV_TEST) ++ rtk_uint32 regData; ++ rtk_uint32 bitsShift; ++ rtk_uint32 valueShifted; ++ ++ if(bits >= (1 << RTL8367C_REGBITLENGTH) ) ++ return RT_ERR_INPUT; ++ ++ bitsShift = 0; ++ while(!(bits & (1 << bitsShift))) ++ { ++ bitsShift++; ++ if(bitsShift >= RTL8367C_REGBITLENGTH) ++ return RT_ERR_INPUT; ++ } ++ valueShifted = value << bitsShift; ++ ++ if(valueShifted > RTL8367C_REGDATAMAX) ++ return RT_ERR_INPUT; ++ ++ if(reg >= CLE_VIRTUAL_REG_SIZE) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ regData = CleVirtualReg[reg] & (~bits); ++ regData = regData | (valueShifted & bits); ++ ++ CleVirtualReg[reg] = regData; ++ ++ if(0x8367B == cleDebuggingDisplay) ++ PRINT("W[0x%4.4x]=0x%4.4x\n", reg, regData); ++ ++#elif defined(EMBEDDED_SUPPORT) ++ rtk_uint32 regData; ++ rtk_uint32 bitsShift; ++ rtk_uint32 valueShifted; ++ ++ if(reg > RTL8367C_REGDATAMAX ) ++ return RT_ERR_INPUT; ++ ++ if(bits >= (1 << RTL8367C_REGBITLENGTH) ) ++ return RT_ERR_INPUT; ++ ++ bitsShift = 0; ++ while(!(bits & (1 << bitsShift))) ++ { ++ bitsShift++; ++ if(bitsShift >= RTL8367C_REGBITLENGTH) ++ return RT_ERR_INPUT; ++ } ++ ++ valueShifted = value << bitsShift; ++ if(valueShifted > RTL8367C_REGDATAMAX) ++ return RT_ERR_INPUT; ++ ++ regData = getReg(reg); ++ regData = regData & (~bits); ++ regData = regData | (valueShifted & bits); ++ ++ setReg(reg, regData); ++ ++#else ++ rtk_uint32 regData; ++ ret_t retVal; ++ rtk_uint32 bitsShift; ++ rtk_uint32 valueShifted; ++ ++ if(bits >= (1 << RTL8367C_REGBITLENGTH) ) ++ return RT_ERR_INPUT; ++ ++ bitsShift = 0; ++ while(!(bits & (1 << bitsShift))) ++ { ++ bitsShift++; ++ if(bitsShift >= RTL8367C_REGBITLENGTH) ++ return RT_ERR_INPUT; ++ } ++ valueShifted = value << bitsShift; ++ ++ if(valueShifted > RTL8367C_REGDATAMAX) ++ return RT_ERR_INPUT; ++ ++ retVal = smi_read(reg, ®Data); ++ if(retVal != RT_ERR_OK) ++ return RT_ERR_SMI; ++ #ifdef CONFIG_RTL865X_CLE ++ if(0x8367B == cleDebuggingDisplay) ++ PRINT("R[0x%4.4x]=0x%4.4x\n", reg, regData); ++ #endif ++ ++ regData = regData & (~bits); ++ regData = regData | (valueShifted & bits); ++ ++ retVal = smi_write(reg, regData); ++ if(retVal != RT_ERR_OK) ++ return RT_ERR_SMI; ++ #ifdef CONFIG_RTL865X_CLE ++ if(0x8367B == cleDebuggingDisplay) ++ PRINT("W[0x%4.4x]=0x%4.4x\n", reg, regData); ++ #endif ++#endif ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_getAsicRegBits ++ * Description: ++ * Get bits value of a specified register ++ * Input: ++ * reg - register's address ++ * bits - bits mask for setting ++ * value - bits value for setting ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameter ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicRegBits(rtk_uint32 reg, rtk_uint32 bits, rtk_uint32 *pValue) ++{ ++ ++#if defined(RTK_X86_ASICDRV) ++ ++ rtk_uint32 regData; ++ ret_t retVal; ++ rtk_uint32 bitsShift; ++ ++ if(bits >= (1 << RTL8367C_REGBITLENGTH) ) ++ return RT_ERR_INPUT; ++ ++ bitsShift = 0; ++ while(!(bits & (1 << bitsShift))) ++ { ++ bitsShift++; ++ if(bitsShift >= RTL8367C_REGBITLENGTH) ++ return RT_ERR_INPUT; ++ } ++ ++ retVal = Access_Read(reg, 2, ®Data); ++ if(TRUE != retVal) ++ return RT_ERR_SMI; ++ ++ *pValue = (regData & bits) >> bitsShift; ++ ++ if(0x8367B == cleDebuggingDisplay) ++ PRINT("R[0x%4.4x]=0x%4.4x\n", reg, regData); ++ ++#elif defined(CONFIG_RTL8367C_ASICDRV_TEST) ++ rtk_uint32 bitsShift; ++ ++ if(bits >= (1 << RTL8367C_REGBITLENGTH) ) ++ return RT_ERR_INPUT; ++ ++ bitsShift = 0; ++ while(!(bits & (1 << bitsShift))) ++ { ++ bitsShift++; ++ if(bitsShift >= RTL8367C_REGBITLENGTH) ++ return RT_ERR_INPUT; ++ } ++ ++ if(reg >= CLE_VIRTUAL_REG_SIZE) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ *pValue = (CleVirtualReg[reg] & bits) >> bitsShift; ++ ++ if(0x8367B == cleDebuggingDisplay) ++ PRINT("R[0x%4.4x]=0x%4.4x\n", reg, CleVirtualReg[reg]); ++ ++#elif defined(EMBEDDED_SUPPORT) ++ rtk_uint32 regData; ++ rtk_uint32 bitsShift; ++ ++ if(reg > RTL8367C_REGDATAMAX ) ++ return RT_ERR_INPUT; ++ ++ if(bits >= (1UL << RTL8367C_REGBITLENGTH) ) ++ return RT_ERR_INPUT; ++ ++ bitsShift = 0; ++ while(!(bits & (1UL << bitsShift))) ++ { ++ bitsShift++; ++ if(bitsShift >= RTL8367C_REGBITLENGTH) ++ return RT_ERR_INPUT; ++ } ++ ++ regData = getReg(reg); ++ *value = (regData & bits) >> bitsShift; ++ ++#else ++ rtk_uint32 regData; ++ ret_t retVal; ++ rtk_uint32 bitsShift; ++ ++ if(bits>= (1<= RTL8367C_REGBITLENGTH) ++ return RT_ERR_INPUT; ++ } ++ ++ retVal = smi_read(reg, ®Data); ++ if(retVal != RT_ERR_OK) return RT_ERR_SMI; ++ ++ *pValue = (regData & bits) >> bitsShift; ++ #ifdef CONFIG_RTL865X_CLE ++ if(0x8367B == cleDebuggingDisplay) ++ PRINT("R[0x%4.4x]=0x%4.4x\n",reg, regData); ++ #endif ++ ++#endif ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_setAsicReg ++ * Description: ++ * Set content of asic register ++ * Input: ++ * reg - register's address ++ * value - Value setting to register ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * The value will be set to ASIC mapping address only and it is always return RT_ERR_OK while setting un-mapping address registers ++ */ ++ret_t rtl8367c_setAsicReg(rtk_uint32 reg, rtk_uint32 value) ++{ ++#if defined(RTK_X86_ASICDRV)/*RTK-CNSD2-NickWu-20061222: for x86 compile*/ ++ ++ ret_t retVal; ++ ++ retVal = Access_Write(reg,2,value); ++ if(TRUE != retVal) return RT_ERR_SMI; ++ ++ if(0x8367B == cleDebuggingDisplay) ++ PRINT("W[0x%4.4x]=0x%4.4x\n",reg,value); ++ ++#elif defined(CONFIG_RTL8367C_ASICDRV_TEST) ++ ++ /*MIBs emulating*/ ++ if(reg == RTL8367C_REG_MIB_ADDRESS) ++ { ++ CleVirtualReg[RTL8367C_MIB_COUNTER_BASE_REG] = 0x1; ++ CleVirtualReg[RTL8367C_MIB_COUNTER_BASE_REG+1] = 0x2; ++ CleVirtualReg[RTL8367C_MIB_COUNTER_BASE_REG+2] = 0x3; ++ CleVirtualReg[RTL8367C_MIB_COUNTER_BASE_REG+3] = 0x4; ++ } ++ ++ if(reg >= CLE_VIRTUAL_REG_SIZE) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ CleVirtualReg[reg] = value; ++ ++ if(0x8367B == cleDebuggingDisplay) ++ PRINT("W[0x%4.4x]=0x%4.4x\n",reg,CleVirtualReg[reg]); ++ ++#elif defined(EMBEDDED_SUPPORT) ++ if(reg > RTL8367C_REGDATAMAX || value > RTL8367C_REGDATAMAX ) ++ return RT_ERR_INPUT; ++ ++ setReg(reg, value); ++ ++#else ++ ret_t retVal; ++ ++ retVal = smi_write(reg, value); ++ if(retVal != RT_ERR_OK) ++ return RT_ERR_SMI; ++ #ifdef CONFIG_RTL865X_CLE ++ if(0x8367B == cleDebuggingDisplay) ++ PRINT("W[0x%4.4x]=0x%4.4x\n",reg,value); ++ #endif ++ ++#endif ++ ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_getAsicReg ++ * Description: ++ * Get content of asic register ++ * Input: ++ * reg - register's address ++ * value - Value setting to register ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * Value 0x0000 will be returned for ASIC un-mapping address ++ */ ++ret_t rtl8367c_getAsicReg(rtk_uint32 reg, rtk_uint32 *pValue) ++{ ++ ++#if defined(RTK_X86_ASICDRV) ++ ++ rtk_uint32 regData; ++ ret_t retVal; ++ ++ retVal = Access_Read(reg, 2, ®Data); ++ if(TRUE != retVal) ++ return RT_ERR_SMI; ++ ++ *pValue = regData; ++ ++ if(0x8367B == cleDebuggingDisplay) ++ PRINT("R[0x%4.4x]=0x%4.4x\n", reg, regData); ++ ++#elif defined(CONFIG_RTL8367C_ASICDRV_TEST) ++ if(reg >= CLE_VIRTUAL_REG_SIZE) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ *pValue = CleVirtualReg[reg]; ++ ++ if(0x8367B == cleDebuggingDisplay) ++ PRINT("R[0x%4.4x]=0x%4.4x\n", reg, CleVirtualReg[reg]); ++ ++#elif defined(EMBEDDED_SUPPORT) ++ if(reg > RTL8367C_REGDATAMAX ) ++ return RT_ERR_INPUT; ++ ++ *value = getReg(reg); ++ ++#else ++ rtk_uint32 regData; ++ ret_t retVal; ++ ++ retVal = smi_read(reg, ®Data); ++ if(retVal != RT_ERR_OK) ++ return RT_ERR_SMI; ++ ++ *pValue = regData; ++ #ifdef CONFIG_RTL865X_CLE ++ if(0x8367B == cleDebuggingDisplay) ++ PRINT("R[0x%4.4x]=0x%4.4x\n", reg, regData); ++ #endif ++ ++#endif ++ ++ return RT_ERR_OK; ++} ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_acl.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_acl.c +new file mode 100644 +index 000000000000..1e4d2961e7d1 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_acl.c +@@ -0,0 +1,1173 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : ACL related function drivers ++ * ++ */ ++#include ++ ++#include ++ ++#if defined(CONFIG_RTL8367C_ASICDRV_TEST) ++rtl8367c_aclrulesmi Rtl8370sVirtualAclRuleTable[RTL8367C_ACLRULENO]; ++rtk_uint16 Rtl8370sVirtualAclActTable[RTL8367C_ACLRULENO][RTL8367C_ACL_ACT_TABLE_LEN]; ++#endif ++ ++/* ++ Exchange structure type define with MMI and SMI ++*/ ++static void _rtl8367c_aclRuleStSmi2User( rtl8367c_aclrule *pAclUser, rtl8367c_aclrulesmi *pAclSmi) ++{ ++ rtk_uint8 *care_ptr, *data_ptr; ++ rtk_uint8 care_tmp, data_tmp; ++ rtk_uint32 i; ++ ++ pAclUser->data_bits.active_portmsk = (((pAclSmi->data_bits_ext.rule_info >> 1) & 0x0007) << 8) | ((pAclSmi->data_bits.rule_info >> 8) & 0x00FF); ++ pAclUser->data_bits.type = (pAclSmi->data_bits.rule_info & 0x0007); ++ pAclUser->data_bits.tag_exist = (pAclSmi->data_bits.rule_info & 0x00F8) >> 3; ++ ++ care_ptr = (rtk_uint8*)&pAclSmi->care_bits; ++ data_ptr = (rtk_uint8*)&pAclSmi->data_bits; ++ ++ for ( i = 0; i < sizeof(struct acl_rule_smi_st); i++) ++ { ++ care_tmp = *(care_ptr + i) ^ (*(data_ptr + i)); ++ data_tmp = *(data_ptr + i); ++ ++ *(care_ptr + i) = care_tmp; ++ *(data_ptr + i) = data_tmp; ++ } ++ ++ care_ptr = (rtk_uint8*)&pAclSmi->care_bits_ext; ++ data_ptr = (rtk_uint8*)&pAclSmi->data_bits_ext; ++ care_tmp = (*care_ptr) ^ (*data_ptr); ++ data_tmp = (*data_ptr); ++ *care_ptr = care_tmp; ++ *data_ptr = data_tmp; ++ ++ for(i = 0; i < RTL8367C_ACLRULEFIELDNO; i++) ++ pAclUser->data_bits.field[i] = pAclSmi->data_bits.field[i]; ++ ++ pAclUser->valid = pAclSmi->valid; ++ ++ pAclUser->care_bits.active_portmsk = (((pAclSmi->care_bits_ext.rule_info >> 1) & 0x0007) << 8) | ((pAclSmi->care_bits.rule_info >> 8) & 0x00FF); ++ pAclUser->care_bits.type = (pAclSmi->care_bits.rule_info & 0x0007); ++ pAclUser->care_bits.tag_exist = (pAclSmi->care_bits.rule_info & 0x00F8) >> 3; ++ ++ for(i = 0; i < RTL8367C_ACLRULEFIELDNO; i++) ++ pAclUser->care_bits.field[i] = pAclSmi->care_bits.field[i]; ++} ++ ++/* ++ Exchange structure type define with MMI and SMI ++*/ ++static void _rtl8367c_aclRuleStUser2Smi(rtl8367c_aclrule *pAclUser, rtl8367c_aclrulesmi *pAclSmi) ++{ ++ rtk_uint8 *care_ptr, *data_ptr; ++ rtk_uint8 care_tmp, data_tmp; ++ rtk_uint32 i; ++ ++ pAclSmi->data_bits_ext.rule_info = ((pAclUser->data_bits.active_portmsk >> 8) & 0x7) << 1; ++ pAclSmi->data_bits.rule_info = ((pAclUser->data_bits.active_portmsk & 0xff) << 8) | ((pAclUser->data_bits.tag_exist & 0x1F) << 3) | (pAclUser->data_bits.type & 0x07); ++ ++ for(i = 0;i < RTL8367C_ACLRULEFIELDNO; i++) ++ pAclSmi->data_bits.field[i] = pAclUser->data_bits.field[i]; ++ ++ pAclSmi->valid = pAclUser->valid; ++ ++ pAclSmi->care_bits_ext.rule_info = ((pAclUser->care_bits.active_portmsk >> 8) & 0x7) << 1; ++ pAclSmi->care_bits.rule_info = ((pAclUser->care_bits.active_portmsk & 0xff) << 8) | ((pAclUser->care_bits.tag_exist & 0x1F) << 3) | (pAclUser->care_bits.type & 0x07); ++ ++ for(i = 0; i < RTL8367C_ACLRULEFIELDNO; i++) ++ pAclSmi->care_bits.field[i] = pAclUser->care_bits.field[i]; ++ ++ care_ptr = (rtk_uint8*)&pAclSmi->care_bits; ++ data_ptr = (rtk_uint8*)&pAclSmi->data_bits; ++ ++ for ( i = 0; i < sizeof(struct acl_rule_smi_st); i++) ++ { ++ care_tmp = *(care_ptr + i) & ~(*(data_ptr + i)); ++ data_tmp = *(care_ptr + i) & *(data_ptr + i); ++ ++ *(care_ptr + i) = care_tmp; ++ *(data_ptr + i) = data_tmp; ++ } ++ ++ care_ptr = (rtk_uint8*)&pAclSmi->care_bits_ext; ++ data_ptr = (rtk_uint8*)&pAclSmi->data_bits_ext; ++ care_tmp = *care_ptr & ~(*data_ptr); ++ data_tmp = *care_ptr & *data_ptr; ++ ++ *care_ptr = care_tmp; ++ *data_ptr = data_tmp; ++} ++ ++/* ++ Exchange structure type define with MMI and SMI ++*/ ++static void _rtl8367c_aclActStSmi2User(rtl8367c_acl_act_t *pAclUser, rtk_uint16 *pAclSmi) ++{ ++ pAclUser->cact = (pAclSmi[0] & 0x00C0) >> 6; ++ pAclUser->cvidx_cact = (pAclSmi[0] & 0x003F) | (((pAclSmi[3] & 0x0008) >> 3) << 6); ++ ++ pAclUser->sact = (pAclSmi[0] & 0xC000) >> 14; ++ pAclUser->svidx_sact = ((pAclSmi[0] & 0x3F00) >> 8) | (((pAclSmi[3] & 0x0010) >> 4) << 6); ++ ++ pAclUser->aclmeteridx = (pAclSmi[1] & 0x003F) | (((pAclSmi[3] & 0x0020) >> 5) << 6); ++ ++ pAclUser->fwdact = (pAclSmi[1] & 0xC000) >> 14; ++ pAclUser->fwdpmask = ((pAclSmi[1] & 0x3FC0) >> 6) | (((pAclSmi[3] & 0x01C0) >> 6) << 8); ++ ++ pAclUser->priact = (pAclSmi[2] & 0x00C0) >> 6; ++ pAclUser->pridx = (pAclSmi[2] & 0x003F) | (((pAclSmi[3] & 0x0200) >> 9) << 6); ++ ++ pAclUser->aclint = (pAclSmi[2] & 0x2000) >> 13; ++ pAclUser->gpio_en = (pAclSmi[2] & 0x1000) >> 12; ++ pAclUser->gpio_pin = (pAclSmi[2] & 0x0F00) >> 8; ++ ++ pAclUser->cact_ext = (pAclSmi[2] & 0xC000) >> 14; ++ pAclUser->tag_fmt = (pAclSmi[3] & 0x0003); ++ pAclUser->fwdact_ext = (pAclSmi[3] & 0x0004) >> 2; ++} ++ ++/* ++ Exchange structure type define with MMI and SMI ++*/ ++static void _rtl8367c_aclActStUser2Smi(rtl8367c_acl_act_t *pAclUser, rtk_uint16 *pAclSmi) ++{ ++ pAclSmi[0] |= (pAclUser->cvidx_cact & 0x003F); ++ pAclSmi[0] |= (pAclUser->cact & 0x0003) << 6; ++ pAclSmi[0] |= (pAclUser->svidx_sact & 0x003F) << 8; ++ pAclSmi[0] |= (pAclUser->sact & 0x0003) << 14; ++ ++ pAclSmi[1] |= (pAclUser->aclmeteridx & 0x003F); ++ pAclSmi[1] |= (pAclUser->fwdpmask & 0x00FF) << 6; ++ pAclSmi[1] |= (pAclUser->fwdact & 0x0003) << 14; ++ ++ pAclSmi[2] |= (pAclUser->pridx & 0x003F); ++ pAclSmi[2] |= (pAclUser->priact & 0x0003) << 6; ++ pAclSmi[2] |= (pAclUser->gpio_pin & 0x000F) << 8; ++ pAclSmi[2] |= (pAclUser->gpio_en & 0x0001) << 12; ++ pAclSmi[2] |= (pAclUser->aclint & 0x0001) << 13; ++ pAclSmi[2] |= (pAclUser->cact_ext & 0x0003) << 14; ++ ++ pAclSmi[3] |= (pAclUser->tag_fmt & 0x0003); ++ pAclSmi[3] |= (pAclUser->fwdact_ext & 0x0001) << 2; ++ pAclSmi[3] |= ((pAclUser->cvidx_cact & 0x0040) >> 6) << 3; ++ pAclSmi[3] |= ((pAclUser->svidx_sact & 0x0040) >> 6) << 4; ++ pAclSmi[3] |= ((pAclUser->aclmeteridx & 0x0040) >> 6) << 5; ++ pAclSmi[3] |= ((pAclUser->fwdpmask & 0x0700) >> 8) << 6; ++ pAclSmi[3] |= ((pAclUser->pridx & 0x0040) >> 6) << 9; ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicAcl ++ * Description: ++ * Set port ACL function enable/disable ++ * Input: ++ * port - Physical port number (0~10) ++ * enabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicAcl(rtk_uint32 port, rtk_uint32 enabled) ++{ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ return rtl8367c_setAsicRegBit(RTL8367C_ACL_ENABLE_REG, port, enabled); ++} ++/* Function Name: ++ * rtl8367c_getAsicAcl ++ * Description: ++ * Get port ACL function enable/disable ++ * Input: ++ * port - Physical port number (0~10) ++ * enabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicAcl(rtk_uint32 port, rtk_uint32* pEnabled) ++{ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ return rtl8367c_getAsicRegBit(RTL8367C_ACL_ENABLE_REG, port, pEnabled); ++} ++/* Function Name: ++ * rtl8367c_setAsicAclUnmatchedPermit ++ * Description: ++ * Set port ACL function unmatched permit action ++ * Input: ++ * port - Physical port number (0~10) ++ * enabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicAclUnmatchedPermit(rtk_uint32 port, rtk_uint32 enabled) ++{ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ return rtl8367c_setAsicRegBit(RTL8367C_ACL_UNMATCH_PERMIT_REG, port, enabled); ++} ++/* Function Name: ++ * rtl8367c_getAsicAclUnmatchedPermit ++ * Description: ++ * Get port ACL function unmatched permit action ++ * Input: ++ * port - Physical port number (0~10) ++ * enabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicAclUnmatchedPermit(rtk_uint32 port, rtk_uint32* pEnabled) ++{ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ return rtl8367c_getAsicRegBit(RTL8367C_ACL_UNMATCH_PERMIT_REG, port, pEnabled); ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicAclRule ++ * Description: ++ * Set ACL rule content ++ * Input: ++ * index - ACL rule index (0-95) of 96 ACL rules ++ * pAclRule - ACL rule structure for setting ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - Invalid ACL rule index (0-95) ++ * Note: ++ * System supported 95 shared 289-bit ACL ingress rule. Index was available at range 0-95 only. ++ * If software want to modify ACL rule, the ACL function should be disabled at first or unspecified ++ * ACL action will be executed. ++ * One ACL rule structure has three parts setting: ++ * Bit 0-147 Data Bits of this Rule ++ * Bit 148 Valid Bit ++ * Bit 149-296 Care Bits of this Rule ++ * There are four kinds of field in Data Bits and Care Bits: Active Portmask, Type, Tag Exist, and 8 fields ++ */ ++ret_t rtl8367c_setAsicAclRule(rtk_uint32 index, rtl8367c_aclrule* pAclRule) ++{ ++ rtl8367c_aclrulesmi aclRuleSmi; ++ rtk_uint16* tableAddr; ++ rtk_uint32 regAddr; ++ rtk_uint32 regData; ++ rtk_uint32 i; ++ ret_t retVal; ++ ++ if(index > RTL8367C_ACLRULEMAX) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ memset(&aclRuleSmi, 0x00, sizeof(rtl8367c_aclrulesmi)); ++ ++ _rtl8367c_aclRuleStUser2Smi(pAclRule, &aclRuleSmi); ++ ++ /* Write valid bit = 0 */ ++ regAddr = RTL8367C_TABLE_ACCESS_ADDR_REG; ++ if(index >= 64) ++ regData = RTL8367C_ACLRULETBADDR2(DATABITS, index); ++ else ++ regData = RTL8367C_ACLRULETBADDR(DATABITS, index); ++ retVal = rtl8367c_setAsicReg(regAddr,regData); ++ if(retVal !=RT_ERR_OK) ++ return retVal; ++ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_TABLE_ACCESS_WRDATA_REG(RTL8367C_ACLRULETBLEN), 0x1, 0); ++ if(retVal !=RT_ERR_OK) ++ return retVal; ++ ++ regAddr = RTL8367C_TABLE_ACCESS_CTRL_REG; ++ regData = RTL8367C_TABLE_ACCESS_REG_DATA(TB_OP_WRITE, TB_TARGET_ACLRULE); ++ retVal = rtl8367c_setAsicReg(regAddr, regData); ++ if(retVal !=RT_ERR_OK) ++ return retVal; ++ ++ ++ ++ /* Write ACS_ADR register */ ++ regAddr = RTL8367C_TABLE_ACCESS_ADDR_REG; ++ if(index >= 64) ++ regData = RTL8367C_ACLRULETBADDR2(CAREBITS, index); ++ else ++ regData = RTL8367C_ACLRULETBADDR(CAREBITS, index); ++ retVal = rtl8367c_setAsicReg(regAddr, regData); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ /* Write Care Bits to ACS_DATA registers */ ++ tableAddr = (rtk_uint16*)&aclRuleSmi.care_bits; ++ regAddr = RTL8367C_TABLE_ACCESS_WRDATA_BASE; ++ ++ for(i = 0; i < RTL8367C_ACLRULETBLEN; i++) ++ { ++ regData = *tableAddr; ++ retVal = rtl8367c_setAsicReg(regAddr, regData); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ regAddr++; ++ tableAddr++; ++ } ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_TABLE_ACCESS_WRDATA_REG(RTL8367C_ACLRULETBLEN), (0x0007 << 1), (aclRuleSmi.care_bits_ext.rule_info >> 1) & 0x0007); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ /* Write ACS_CMD register */ ++ regAddr = RTL8367C_TABLE_ACCESS_CTRL_REG; ++ regData = RTL8367C_TABLE_ACCESS_REG_DATA(TB_OP_WRITE, TB_TARGET_ACLRULE); ++ retVal = rtl8367c_setAsicRegBits(regAddr, RTL8367C_TABLE_TYPE_MASK | RTL8367C_COMMAND_TYPE_MASK,regData); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ ++ ++ /* Write ACS_ADR register for data bits */ ++ regAddr = RTL8367C_TABLE_ACCESS_ADDR_REG; ++ if(index >= 64) ++ regData = RTL8367C_ACLRULETBADDR2(DATABITS, index); ++ else ++ regData = RTL8367C_ACLRULETBADDR(DATABITS, index); ++ ++ retVal = rtl8367c_setAsicReg(regAddr, regData); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ /* Write Data Bits to ACS_DATA registers */ ++ tableAddr = (rtk_uint16*)&aclRuleSmi.data_bits; ++ regAddr = RTL8367C_TABLE_ACCESS_WRDATA_BASE; ++ ++ for(i = 0; i < RTL8367C_ACLRULETBLEN; i++) ++ { ++ regData = *tableAddr; ++ retVal = rtl8367c_setAsicReg(regAddr, regData); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ regAddr++; ++ tableAddr++; ++ } ++ ++ retVal = rtl8367c_setAsicRegBit(RTL8367C_TABLE_ACCESS_WRDATA_REG(RTL8367C_ACLRULETBLEN), 0, aclRuleSmi.valid); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_TABLE_ACCESS_WRDATA_REG(RTL8367C_ACLRULETBLEN), (0x0007 << 1), (aclRuleSmi.data_bits_ext.rule_info >> 1) & 0x0007); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ /* Write ACS_CMD register for care bits*/ ++ regAddr = RTL8367C_TABLE_ACCESS_CTRL_REG; ++ regData = RTL8367C_TABLE_ACCESS_REG_DATA(TB_OP_WRITE, TB_TARGET_ACLRULE); ++ retVal = rtl8367c_setAsicRegBits(regAddr, RTL8367C_TABLE_TYPE_MASK | RTL8367C_COMMAND_TYPE_MASK, regData); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++#ifdef CONFIG_RTL8367C_ASICDRV_TEST ++ memcpy(&Rtl8370sVirtualAclRuleTable[index], &aclRuleSmi, sizeof(rtl8367c_aclrulesmi)); ++#endif ++ ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_getAsicAclRule ++ * Description: ++ * Get ACL rule content ++ * Input: ++ * index - ACL rule index (0-63) of 64 ACL rules ++ * pAclRule - ACL rule structure for setting ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - Invalid ACL rule index (0-63) ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicAclRule(rtk_uint32 index, rtl8367c_aclrule *pAclRule) ++{ ++ rtl8367c_aclrulesmi aclRuleSmi; ++ rtk_uint32 regAddr, regData; ++ ret_t retVal; ++ rtk_uint16* tableAddr; ++ rtk_uint32 i; ++ ++ if(index > RTL8367C_ACLRULEMAX) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ memset(&aclRuleSmi, 0x00, sizeof(rtl8367c_aclrulesmi)); ++ ++ /* Write ACS_ADR register for data bits */ ++ regAddr = RTL8367C_TABLE_ACCESS_ADDR_REG; ++ if(index >= 64) ++ regData = RTL8367C_ACLRULETBADDR2(DATABITS, index); ++ else ++ regData = RTL8367C_ACLRULETBADDR(DATABITS, index); ++ ++ retVal = rtl8367c_setAsicReg(regAddr, regData); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ ++ /* Write ACS_CMD register */ ++ regAddr = RTL8367C_TABLE_ACCESS_CTRL_REG; ++ regData = RTL8367C_TABLE_ACCESS_REG_DATA(TB_OP_READ, TB_TARGET_ACLRULE); ++ retVal = rtl8367c_setAsicRegBits(regAddr, RTL8367C_TABLE_TYPE_MASK | RTL8367C_COMMAND_TYPE_MASK, regData); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ /* Read Data Bits */ ++ regAddr = RTL8367C_TABLE_ACCESS_RDDATA_BASE; ++ tableAddr = (rtk_uint16*)&aclRuleSmi.data_bits; ++ for(i = 0; i < RTL8367C_ACLRULETBLEN; i++) ++ { ++ retVal = rtl8367c_getAsicReg(regAddr, ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ *tableAddr = regData; ++ ++ regAddr ++; ++ tableAddr ++; ++ } ++ ++ /* Read Valid Bit */ ++ retVal = rtl8367c_getAsicRegBit(RTL8367C_TABLE_ACCESS_RDDATA_REG(RTL8367C_ACLRULETBLEN), 0, ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ aclRuleSmi.valid = regData & 0x1; ++ /* Read active_portmsk_ext Bits */ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_TABLE_ACCESS_RDDATA_REG(RTL8367C_ACLRULETBLEN), 0x7<<1, ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ aclRuleSmi.data_bits_ext.rule_info = (regData % 0x0007) << 1; ++ ++ ++ /* Write ACS_ADR register for carebits*/ ++ regAddr = RTL8367C_TABLE_ACCESS_ADDR_REG; ++ if(index >= 64) ++ regData = RTL8367C_ACLRULETBADDR2(CAREBITS, index); ++ else ++ regData = RTL8367C_ACLRULETBADDR(CAREBITS, index); ++ ++ retVal = rtl8367c_setAsicReg(regAddr, regData); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ /* Write ACS_CMD register */ ++ regAddr = RTL8367C_TABLE_ACCESS_CTRL_REG; ++ regData = RTL8367C_TABLE_ACCESS_REG_DATA(TB_OP_READ, TB_TARGET_ACLRULE); ++ retVal = rtl8367c_setAsicRegBits(regAddr, RTL8367C_TABLE_TYPE_MASK | RTL8367C_COMMAND_TYPE_MASK, regData); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ /* Read Care Bits */ ++ regAddr = RTL8367C_TABLE_ACCESS_RDDATA_BASE; ++ tableAddr = (rtk_uint16*)&aclRuleSmi.care_bits; ++ for(i = 0; i < RTL8367C_ACLRULETBLEN; i++) ++ { ++ retVal = rtl8367c_getAsicReg(regAddr, ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ *tableAddr = regData; ++ ++ regAddr ++; ++ tableAddr ++; ++ } ++ /* Read active_portmsk_ext care Bits */ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_TABLE_ACCESS_RDDATA_REG(RTL8367C_ACLRULETBLEN), 0x7<<1, ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ aclRuleSmi.care_bits_ext.rule_info = (regData & 0x0007) << 1; ++ ++#ifdef CONFIG_RTL8367C_ASICDRV_TEST ++ memcpy(&aclRuleSmi,&Rtl8370sVirtualAclRuleTable[index], sizeof(rtl8367c_aclrulesmi)); ++#endif ++ ++ _rtl8367c_aclRuleStSmi2User(pAclRule, &aclRuleSmi); ++ ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_setAsicAclNot ++ * Description: ++ * Set rule comparison result inversion / no inversion ++ * Input: ++ * index - ACL rule index (0-95) of 96 ACL rules ++ * not - 1: inverse, 0: don't inverse ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - Invalid ACL rule index (0-95) ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicAclNot(rtk_uint32 index, rtk_uint32 not) ++{ ++ if(index > RTL8367C_ACLRULEMAX) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ if(index < 64) ++ return rtl8367c_setAsicRegBit(RTL8367C_ACL_ACTION_CTRL_REG(index), RTL8367C_ACL_OP_NOT_OFFSET(index), not); ++ else ++ return rtl8367c_setAsicRegBit(RTL8367C_ACL_ACTION_CTRL2_REG(index), RTL8367C_ACL_OP_NOT_OFFSET(index), not); ++ ++} ++/* Function Name: ++ * rtl8367c_getAsicAcl ++ * Description: ++ * Get rule comparison result inversion / no inversion ++ * Input: ++ * index - ACL rule index (0-95) of 95 ACL rules ++ * pNot - 1: inverse, 0: don't inverse ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - Invalid ACL rule index (0-95) ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicAclNot(rtk_uint32 index, rtk_uint32* pNot) ++{ ++ if(index > RTL8367C_ACLRULEMAX) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ if(index < 64) ++ return rtl8367c_getAsicRegBit(RTL8367C_ACL_ACTION_CTRL_REG(index), RTL8367C_ACL_OP_NOT_OFFSET(index), pNot); ++ else ++ return rtl8367c_getAsicRegBit(RTL8367C_ACL_ACTION_CTRL2_REG(index), RTL8367C_ACL_OP_NOT_OFFSET(index), pNot); ++ ++} ++/* Function Name: ++ * rtl8367c_setAsicAclTemplate ++ * Description: ++ * Set fields of a ACL Template ++ * Input: ++ * index - ACL template index(0~4) ++ * pAclType - ACL type structure for setting ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - Invalid ACL template index(0~4) ++ * Note: ++ * The API can set type field of the 5 ACL rule templates. ++ * Each type has 8 fields. One field means what data in one field of a ACL rule means ++ * 8 fields of ACL rule 0~95 is described by one type in ACL group ++ */ ++ret_t rtl8367c_setAsicAclTemplate(rtk_uint32 index, rtl8367c_acltemplate_t* pAclType) ++{ ++ ret_t retVal; ++ rtk_uint32 i; ++ rtk_uint32 regAddr, regData; ++ ++ if(index >= RTL8367C_ACLTEMPLATENO) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ regAddr = RTL8367C_ACL_RULE_TEMPLATE_CTRL_REG(index); ++ ++ for(i = 0; i < (RTL8367C_ACLRULEFIELDNO/2); i++) ++ { ++ regData = pAclType->field[i*2+1]; ++ regData = regData << 8 | pAclType->field[i*2]; ++ ++ retVal = rtl8367c_setAsicReg(regAddr + i, regData); ++ ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ ++ return retVal; ++} ++/* Function Name: ++ * rtl8367c_getAsicAclTemplate ++ * Description: ++ * Get fields of a ACL Template ++ * Input: ++ * index - ACL template index(0~4) ++ * pAclType - ACL type structure for setting ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - Invalid ACL template index(0~4) ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicAclTemplate(rtk_uint32 index, rtl8367c_acltemplate_t *pAclType) ++{ ++ ret_t retVal; ++ rtk_uint32 i; ++ rtk_uint32 regData, regAddr; ++ ++ if(index >= RTL8367C_ACLTEMPLATENO) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ regAddr = RTL8367C_ACL_RULE_TEMPLATE_CTRL_REG(index); ++ ++ for(i = 0; i < (RTL8367C_ACLRULEFIELDNO/2); i++) ++ { ++ retVal = rtl8367c_getAsicReg(regAddr + i,®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ pAclType->field[i*2] = regData & 0xFF; ++ pAclType->field[i*2 + 1] = (regData >> 8) & 0xFF; ++ } ++ ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_setAsicAclAct ++ * Description: ++ * Set ACL rule matched Action ++ * Input: ++ * index - ACL rule index (0-95) of 96 ACL rules ++ * pAclAct - ACL action structure for setting ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - Invalid ACL rule index (0-95) ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicAclAct(rtk_uint32 index, rtl8367c_acl_act_t* pAclAct) ++{ ++ rtk_uint16 aclActSmi[RTL8367C_ACL_ACT_TABLE_LEN]; ++ ret_t retVal; ++ rtk_uint32 regAddr, regData; ++ rtk_uint16* tableAddr; ++ rtk_uint32 i; ++ ++ if(index > RTL8367C_ACLRULEMAX) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ memset(aclActSmi, 0x00, sizeof(rtk_uint16) * RTL8367C_ACL_ACT_TABLE_LEN); ++ _rtl8367c_aclActStUser2Smi(pAclAct, aclActSmi); ++ ++ /* Write ACS_ADR register for data bits */ ++ regAddr = RTL8367C_TABLE_ACCESS_ADDR_REG; ++ regData = index; ++ retVal = rtl8367c_setAsicReg(regAddr, regData); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ /* Write Data Bits to ACS_DATA registers */ ++ tableAddr = aclActSmi; ++ regAddr = RTL8367C_TABLE_ACCESS_WRDATA_BASE; ++ ++ for(i = 0; i < RTL8367C_ACLACTTBLEN; i++) ++ { ++ regData = *tableAddr; ++ retVal = rtl8367c_setAsicReg(regAddr, regData); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ regAddr++; ++ tableAddr++; ++ } ++ ++ /* Write ACS_CMD register for care bits*/ ++ regAddr = RTL8367C_TABLE_ACCESS_CTRL_REG; ++ regData = RTL8367C_TABLE_ACCESS_REG_DATA(TB_OP_WRITE, TB_TARGET_ACLACT); ++ retVal = rtl8367c_setAsicRegBits(regAddr, RTL8367C_TABLE_TYPE_MASK | RTL8367C_COMMAND_TYPE_MASK, regData); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++#ifdef CONFIG_RTL8367C_ASICDRV_TEST ++ memcpy(&Rtl8370sVirtualAclActTable[index][0], aclActSmi, sizeof(rtk_uint16) * RTL8367C_ACL_ACT_TABLE_LEN); ++#endif ++ ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_getAsicAclAct ++ * Description: ++ * Get ACL rule matched Action ++ * Input: ++ * index - ACL rule index (0-95) of 96 ACL rules ++ * pAclAct - ACL action structure for setting ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - Invalid ACL rule index (0-95) ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicAclAct(rtk_uint32 index, rtl8367c_acl_act_t *pAclAct) ++{ ++ rtk_uint16 aclActSmi[RTL8367C_ACL_ACT_TABLE_LEN]; ++ ret_t retVal; ++ rtk_uint32 regAddr, regData; ++ rtk_uint16 *tableAddr; ++ rtk_uint32 i; ++ ++ if(index > RTL8367C_ACLRULEMAX) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ memset(aclActSmi, 0x00, sizeof(rtk_uint16) * RTL8367C_ACL_ACT_TABLE_LEN); ++ ++ /* Write ACS_ADR register for data bits */ ++ regAddr = RTL8367C_TABLE_ACCESS_ADDR_REG; ++ regData = index; ++ retVal = rtl8367c_setAsicReg(regAddr, regData); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ /* Write ACS_CMD register */ ++ regAddr = RTL8367C_TABLE_ACCESS_CTRL_REG; ++ regData = RTL8367C_TABLE_ACCESS_REG_DATA(TB_OP_READ, TB_TARGET_ACLACT); ++ retVal = rtl8367c_setAsicRegBits(regAddr, RTL8367C_TABLE_TYPE_MASK | RTL8367C_COMMAND_TYPE_MASK, regData); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ /* Read Data Bits */ ++ regAddr = RTL8367C_TABLE_ACCESS_RDDATA_BASE; ++ tableAddr = aclActSmi; ++ for(i = 0; i < RTL8367C_ACLACTTBLEN; i++) ++ { ++ retVal = rtl8367c_getAsicReg(regAddr, ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ *tableAddr = regData; ++ ++ regAddr ++; ++ tableAddr ++; ++ } ++ ++#ifdef CONFIG_RTL8367C_ASICDRV_TEST ++ memcpy(aclActSmi, &Rtl8370sVirtualAclActTable[index][0], sizeof(rtk_uint16) * RTL8367C_ACL_ACT_TABLE_LEN); ++#endif ++ ++ _rtl8367c_aclActStSmi2User(pAclAct, aclActSmi); ++ ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_setAsicAclActCtrl ++ * Description: ++ * Set ACL rule matched Action Control Bits ++ * Input: ++ * index - ACL rule index (0-95) of 96 ACL rules ++ * aclActCtrl - 6 ACL Control Bits ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - Invalid ACL rule index (0-95) ++ * Note: ++ * ACL Action Control Bits Indicate which actions will be take when a rule matches ++ */ ++ret_t rtl8367c_setAsicAclActCtrl(rtk_uint32 index, rtk_uint32 aclActCtrl) ++{ ++ ret_t retVal; ++ ++ if(index > RTL8367C_ACLRULEMAX) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ if(index >= 64) ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_ACL_ACTION_CTRL2_REG(index), RTL8367C_ACL_OP_ACTION_MASK(index), aclActCtrl); ++ else ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_ACL_ACTION_CTRL_REG(index), RTL8367C_ACL_OP_ACTION_MASK(index), aclActCtrl); ++ ++ return retVal; ++} ++/* Function Name: ++ * rtl8367c_getAsicAclActCtrl ++ * Description: ++ * Get ACL rule matched Action Control Bits ++ * Input: ++ * index - ACL rule index (0-95) of 96 ACL rules ++ * pAclActCtrl - 6 ACL Control Bits ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - Invalid ACL rule index (0-95) ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicAclActCtrl(rtk_uint32 index, rtk_uint32 *pAclActCtrl) ++{ ++ ret_t retVal; ++ rtk_uint32 regData; ++ ++ if(index > RTL8367C_ACLRULEMAX) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ if(index >= 64) ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_ACL_ACTION_CTRL2_REG(index), RTL8367C_ACL_OP_ACTION_MASK(index), ®Data); ++ else ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_ACL_ACTION_CTRL_REG(index), RTL8367C_ACL_OP_ACTION_MASK(index), ®Data); ++ ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ *pAclActCtrl = regData; ++ ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_setAsicAclPortRange ++ * Description: ++ * Set ACL TCP/UDP range check ++ * Input: ++ * index - TCP/UDP port range check table index ++ * type - Range check type ++ * upperPort - TCP/UDP port range upper bound ++ * lowerPort - TCP/UDP port range lower bound ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - Invalid TCP/UDP port range check table index ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicAclPortRange(rtk_uint32 index, rtk_uint32 type, rtk_uint32 upperPort, rtk_uint32 lowerPort) ++{ ++ ret_t retVal; ++ ++ if(index > RTL8367C_ACLRANGEMAX) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY0_CTRL2 + index*3, RTL8367C_ACL_SDPORT_RANGE_ENTRY0_CTRL2_MASK, type); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ retVal = rtl8367c_setAsicReg(RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY0_CTRL1 + index*3, upperPort); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ retVal = rtl8367c_setAsicReg(RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY0_CTRL0 + index*3, lowerPort); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_getAsicAclPortRange ++ * Description: ++ * Get ACL TCP/UDP range check ++ * Input: ++ * index - TCP/UDP port range check table index ++ * pType - Range check type ++ * pUpperPort - TCP/UDP port range upper bound ++ * pLowerPort - TCP/UDP port range lower bound ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - Invalid TCP/UDP port range check table index ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicAclPortRange(rtk_uint32 index, rtk_uint32* pType, rtk_uint32* pUpperPort, rtk_uint32* pLowerPort) ++{ ++ ret_t retVal; ++ ++ if(index > RTL8367C_ACLRANGEMAX) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY0_CTRL2 + index*3, RTL8367C_ACL_SDPORT_RANGE_ENTRY0_CTRL2_MASK, pType); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ retVal = rtl8367c_getAsicReg(RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY0_CTRL1 + index*3, pUpperPort); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ retVal = rtl8367c_getAsicReg(RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY0_CTRL0 + index*3, pLowerPort); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_setAsicAclVidRange ++ * Description: ++ * Set ACL VID range check ++ * Input: ++ * index - ACL VID range check index(0~15) ++ * type - Range check type ++ * upperVid - VID range upper bound ++ * lowerVid - VID range lower bound ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - Invalid ACL VID range check index(0~15) ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicAclVidRange(rtk_uint32 index, rtk_uint32 type, rtk_uint32 upperVid, rtk_uint32 lowerVid) ++{ ++ ret_t retVal; ++ rtk_uint32 regData; ++ ++ if(index > RTL8367C_ACLRANGEMAX) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ regData = ((type << RTL8367C_ACL_VID_RANGE_ENTRY0_CTRL1_CHECK0_TYPE_OFFSET) & RTL8367C_ACL_VID_RANGE_ENTRY0_CTRL1_CHECK0_TYPE_MASK) | ++ (upperVid & RTL8367C_ACL_VID_RANGE_ENTRY0_CTRL1_CHECK0_HIGH_MASK); ++ ++ retVal = rtl8367c_setAsicReg(RTL8367C_REG_ACL_VID_RANGE_ENTRY0_CTRL1 + index*2, regData); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ retVal = rtl8367c_setAsicReg(RTL8367C_REG_ACL_VID_RANGE_ENTRY0_CTRL0 + index*2, lowerVid); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_getAsicAclVidRange ++ * Description: ++ * Get ACL VID range check ++ * Input: ++ * index - ACL VID range check index(0~15) ++ * pType - Range check type ++ * pUpperVid - VID range upper bound ++ * pLowerVid - VID range lower bound ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - Invalid ACL VID range check index(0~15) ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicAclVidRange(rtk_uint32 index, rtk_uint32* pType, rtk_uint32* pUpperVid, rtk_uint32* pLowerVid) ++{ ++ ret_t retVal; ++ rtk_uint32 regData; ++ ++ if(index > RTL8367C_ACLRANGEMAX) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ retVal = rtl8367c_getAsicReg(RTL8367C_REG_ACL_VID_RANGE_ENTRY0_CTRL1 + index*2, ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ *pType = (regData & RTL8367C_ACL_VID_RANGE_ENTRY0_CTRL1_CHECK0_TYPE_MASK) >> RTL8367C_ACL_VID_RANGE_ENTRY0_CTRL1_CHECK0_TYPE_OFFSET; ++ *pUpperVid = regData & RTL8367C_ACL_VID_RANGE_ENTRY0_CTRL1_CHECK0_HIGH_MASK; ++ ++ retVal = rtl8367c_getAsicReg(RTL8367C_REG_ACL_VID_RANGE_ENTRY0_CTRL0 + index*2, pLowerVid); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_setAsicAclIpRange ++ * Description: ++ * Set ACL IP range check ++ * Input: ++ * index - ACL IP range check index(0~15) ++ * type - Range check type ++ * upperIp - IP range upper bound ++ * lowerIp - IP range lower bound ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - Invalid ACL IP range check index(0~15) ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicAclIpRange(rtk_uint32 index, rtk_uint32 type, ipaddr_t upperIp, ipaddr_t lowerIp) ++{ ++ ret_t retVal; ++ rtk_uint32 regData; ++ ipaddr_t ipData; ++ ++ if(index > RTL8367C_ACLRANGEMAX) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_ACL_IP_RANGE_ENTRY0_CTRL4 + index*5, RTL8367C_ACL_IP_RANGE_ENTRY0_CTRL4_MASK, type); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ ipData = upperIp; ++ ++ regData = ipData & 0xFFFF; ++ retVal = rtl8367c_setAsicReg(RTL8367C_REG_ACL_IP_RANGE_ENTRY0_CTRL2 + index*5, regData); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ regData = (ipData>>16) & 0xFFFF; ++ retVal = rtl8367c_setAsicReg(RTL8367C_REG_ACL_IP_RANGE_ENTRY0_CTRL3 + index*5, regData); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ ipData = lowerIp; ++ ++ regData = ipData & 0xFFFF; ++ retVal = rtl8367c_setAsicReg(RTL8367C_REG_ACL_IP_RANGE_ENTRY0_CTRL0 + index*5, regData); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ regData = (ipData>>16) & 0xFFFF; ++ retVal = rtl8367c_setAsicReg(RTL8367C_REG_ACL_IP_RANGE_ENTRY0_CTRL1 + index*5, regData); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_getAsicAclIpRange ++ * Description: ++ * Get ACL IP range check ++ * Input: ++ * index - ACL IP range check index(0~15) ++ * pType - Range check type ++ * pUpperIp - IP range upper bound ++ * pLowerIp - IP range lower bound ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - Invalid ACL IP range check index(0~15) ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicAclIpRange(rtk_uint32 index, rtk_uint32* pType, ipaddr_t* pUpperIp, ipaddr_t* pLowerIp) ++{ ++ ret_t retVal; ++ rtk_uint32 regData; ++ ipaddr_t ipData; ++ ++ if(index > RTL8367C_ACLRANGEMAX) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_ACL_IP_RANGE_ENTRY0_CTRL4 + index*5, RTL8367C_ACL_IP_RANGE_ENTRY0_CTRL4_MASK, pType); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ retVal = rtl8367c_getAsicReg(RTL8367C_REG_ACL_IP_RANGE_ENTRY0_CTRL2 + index*5, ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ipData = regData; ++ ++ ++ retVal = rtl8367c_getAsicReg(RTL8367C_REG_ACL_IP_RANGE_ENTRY0_CTRL3 + index*5, ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ ipData = (regData <<16) | ipData; ++ *pUpperIp = ipData; ++ ++ ++ retVal = rtl8367c_getAsicReg(RTL8367C_REG_ACL_IP_RANGE_ENTRY0_CTRL0 + index*5, ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ipData = regData; ++ ++ ++ retVal = rtl8367c_getAsicReg(RTL8367C_REG_ACL_IP_RANGE_ENTRY0_CTRL1 + index*5, ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ ipData = (regData << 16) | ipData; ++ *pLowerIp = ipData; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicAclGpioPolarity ++ * Description: ++ * Set ACL Goip control polarity ++ * Input: ++ * polarity - 1: High, 0: Low ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * none ++ */ ++ret_t rtl8367c_setAsicAclGpioPolarity(rtk_uint32 polarity) ++{ ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_ACL_GPIO_POLARITY, RTL8367C_ACL_GPIO_POLARITY_OFFSET, polarity); ++} ++/* Function Name: ++ * rtl8367c_getAsicAclGpioPolarity ++ * Description: ++ * Get ACL Goip control polarity ++ * Input: ++ * pPolarity - 1: High, 0: Low ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * none ++ */ ++ret_t rtl8367c_getAsicAclGpioPolarity(rtk_uint32* pPolarity) ++{ ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_ACL_GPIO_POLARITY, RTL8367C_ACL_GPIO_POLARITY_OFFSET, pPolarity); ++} ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_cputag.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_cputag.c +new file mode 100644 +index 000000000000..ec9c332e1620 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_cputag.c +@@ -0,0 +1,369 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : Proprietary CPU-tag related function drivers ++ * ++ */ ++#include ++/* Function Name: ++ * rtl8367c_setAsicCputagEnable ++ * Description: ++ * Set CPU tag function enable/disable ++ * Input: ++ * enabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_ENABLE - Invalid enable/disable input ++ * Note: ++ * If CPU tag function is disabled, CPU tag will not be added to frame ++ * forwarded to CPU port, and all ports cannot parse CPU tag. ++ */ ++ret_t rtl8367c_setAsicCputagEnable(rtk_uint32 enabled) ++{ ++ if(enabled > 1) ++ return RT_ERR_ENABLE; ++ ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_CPU_CTRL, RTL8367C_CPU_EN_OFFSET, enabled); ++} ++/* Function Name: ++ * rtl8367c_getAsicCputagEnable ++ * Description: ++ * Get CPU tag function enable/disable ++ * Input: ++ * pEnabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicCputagEnable(rtk_uint32 *pEnabled) ++{ ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_CPU_CTRL, RTL8367C_CPU_EN_OFFSET, pEnabled); ++} ++/* Function Name: ++ * rtl8367c_setAsicCputagTrapPort ++ * Description: ++ * Set CPU tag trap port ++ * Input: ++ * port - port number ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * API can set destination port of trapping frame ++ */ ++ret_t rtl8367c_setAsicCputagTrapPort(rtk_uint32 port) ++{ ++ ret_t retVal; ++ ++ if(port >= RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_CPU_CTRL, RTL8367C_CPU_TRAP_PORT_MASK, port & 7); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_CPU_CTRL, RTL8367C_CPU_TRAP_PORT_EXT_MASK, (port>>3) & 1); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_getAsicCputagTrapPort ++ * Description: ++ * Get CPU tag trap port ++ * Input: ++ * pPort - port number ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicCputagTrapPort(rtk_uint32 *pPort) ++{ ++ ret_t retVal; ++ rtk_uint32 tmpPort; ++ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_CPU_CTRL, RTL8367C_CPU_TRAP_PORT_MASK, &tmpPort); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ *pPort = tmpPort; ++ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_CPU_CTRL, RTL8367C_CPU_TRAP_PORT_EXT_MASK, &tmpPort); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ *pPort |= (tmpPort & 1) << 3; ++ ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_setAsicCputagPortmask ++ * Description: ++ * Set ports that can parse CPU tag ++ * Input: ++ * portmask - port mask ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_MASK - Invalid portmask ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicCputagPortmask(rtk_uint32 portmask) ++{ ++ if(portmask > RTL8367C_PORTMASK) ++ return RT_ERR_PORT_MASK; ++ ++ return rtl8367c_setAsicReg(RTL8367C_CPU_PORT_MASK_REG, portmask); ++} ++/* Function Name: ++ * rtl8367c_getAsicCputagPortmask ++ * Description: ++ * Get ports that can parse CPU tag ++ * Input: ++ * pPortmask - port mask ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicCputagPortmask(rtk_uint32 *pPortmask) ++{ ++ return rtl8367c_getAsicReg(RTL8367C_CPU_PORT_MASK_REG, pPortmask); ++} ++/* Function Name: ++ * rtl8367c_setAsicCputagInsertMode ++ * Description: ++ * Set CPU-tag insert mode ++ * Input: ++ * mode - 0: insert to all packets; 1: insert to trapped packets; 2: don't insert ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_NOT_ALLOWED - Actions not allowed by the function ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicCputagInsertMode(rtk_uint32 mode) ++{ ++ if(mode >= CPUTAG_INSERT_END) ++ return RT_ERR_NOT_ALLOWED; ++ ++ return rtl8367c_setAsicRegBits(RTL8367C_REG_CPU_CTRL, RTL8367C_CPU_INSERTMODE_MASK, mode); ++} ++/* Function Name: ++ * rtl8367c_getAsicCputagInsertMode ++ * Description: ++ * Get CPU-tag insert mode ++ * Input: ++ * pMode - 0: insert to all packets; 1: insert to trapped packets; 2: don't insert ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicCputagInsertMode(rtk_uint32 *pMode) ++{ ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_CPU_CTRL, RTL8367C_CPU_INSERTMODE_MASK, pMode); ++} ++/* Function Name: ++ * rtl8367c_setAsicCputagPriorityRemapping ++ * Description: ++ * Set queue assignment of CPU port ++ * Input: ++ * srcPri - internal priority (0~7) ++ * newPri - internal priority after remapping (0~7) ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_QOS_INT_PRIORITY - Invalid priority ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicCputagPriorityRemapping(rtk_uint32 srcPri, rtk_uint32 newPri) ++{ ++ if((srcPri > RTL8367C_PRIMAX) || (newPri > RTL8367C_PRIMAX)) ++ return RT_ERR_QOS_INT_PRIORITY; ++ ++ return rtl8367c_setAsicRegBits(RTL8367C_QOS_PRIPORITY_REMAPPING_IN_CPU_REG(srcPri), RTL8367C_QOS_PRIPORITY_REMAPPING_IN_CPU_MASK(srcPri), newPri); ++} ++/* Function Name: ++ * rtl8367c_getAsicCputagPriorityRemapping ++ * Description: ++ * Get queue assignment of CPU port ++ * Input: ++ * srcPri - internal priority (0~7) ++ * pNewPri - internal priority after remapping (0~7) ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_QOS_INT_PRIORITY - Invalid priority ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicCputagPriorityRemapping(rtk_uint32 srcPri, rtk_uint32 *pNewPri) ++{ ++ if(srcPri > RTL8367C_PRIMAX) ++ return RT_ERR_QOS_INT_PRIORITY; ++ ++ return rtl8367c_getAsicRegBits(RTL8367C_QOS_PRIPORITY_REMAPPING_IN_CPU_REG(srcPri), RTL8367C_QOS_PRIPORITY_REMAPPING_IN_CPU_MASK(srcPri), pNewPri); ++} ++/* Function Name: ++ * rtl8367c_setAsicCputagPosition ++ * Description: ++ * Set CPU tag insert position ++ * Input: ++ * position - 1: After entire packet(before CRC field), 0: After MAC_SA (Default) ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicCputagPosition(rtk_uint32 position) ++{ ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_CPU_CTRL, RTL8367C_CPU_TAG_POSITION_OFFSET, position); ++} ++/* Function Name: ++ * rtl8367c_getAsicCputagPosition ++ * Description: ++ * Get CPU tag insert position ++ * Input: ++ * pPostion - 1: After entire packet(before CRC field), 0: After MAC_SA (Default) ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicCputagPosition(rtk_uint32* pPostion) ++{ ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_CPU_CTRL, RTL8367C_CPU_TAG_POSITION_OFFSET, pPostion); ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicCputagMode ++ * Description: ++ * Set CPU tag mode ++ * Input: ++ * mode - 1: 4bytes mode, 0: 8bytes mode ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters ++ * Note: ++ * If CPU tag function is disabled, CPU tag will not be added to frame ++ * forwarded to CPU port, and all ports cannot parse CPU tag. ++ */ ++ret_t rtl8367c_setAsicCputagMode(rtk_uint32 mode) ++{ ++ if(mode > 1) ++ return RT_ERR_INPUT; ++ ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_CPU_CTRL, RTL8367C_CPU_TAG_FORMAT_OFFSET, mode); ++} ++/* Function Name: ++ * rtl8367c_getAsicCputagMode ++ * Description: ++ * Get CPU tag mode ++ * Input: ++ * pMode - 1: 4bytes mode, 0: 8bytes mode ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicCputagMode(rtk_uint32 *pMode) ++{ ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_CPU_CTRL, RTL8367C_CPU_TAG_FORMAT_OFFSET, pMode); ++} ++/* Function Name: ++ * rtl8367c_setAsicCputagRxMinLength ++ * Description: ++ * Set CPU tag mode ++ * Input: ++ * mode - 1: 64bytes, 0: 72bytes ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters ++ * Note: ++ * If CPU tag function is disabled, CPU tag will not be added to frame ++ * forwarded to CPU port, and all ports cannot parse CPU tag. ++ */ ++ret_t rtl8367c_setAsicCputagRxMinLength(rtk_uint32 mode) ++{ ++ if(mode > 1) ++ return RT_ERR_INPUT; ++ ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_CPU_CTRL, RTL8367C_CPU_TAG_RXBYTECOUNT_OFFSET, mode); ++} ++/* Function Name: ++ * rtl8367c_getAsicCputagRxMinLength ++ * Description: ++ * Get CPU tag mode ++ * Input: ++ * pMode - 1: 64bytes, 0: 72bytes ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicCputagRxMinLength(rtk_uint32 *pMode) ++{ ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_CPU_CTRL, RTL8367C_CPU_TAG_RXBYTECOUNT_OFFSET, pMode); ++} ++ ++ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_dot1x.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_dot1x.c +new file mode 100644 +index 000000000000..73153e177ee9 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_dot1x.c +@@ -0,0 +1,415 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : 802.1X related functions ++ * ++ */ ++#include ++/* Function Name: ++ * rtl8367c_setAsic1xPBEnConfig ++ * Description: ++ * Set 802.1x port-based port enable configuration ++ * Input: ++ * port - Physical port number (0~7) ++ * enabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsic1xPBEnConfig(rtk_uint32 port, rtk_uint32 enabled) ++{ ++ if(port >= RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ return rtl8367c_setAsicRegBit(RTL8367C_DOT1X_PORT_ENABLE_REG, port, enabled); ++} ++/* Function Name: ++ * rtl8367c_getAsic1xPBEnConfig ++ * Description: ++ * Get 802.1x port-based port enable configuration ++ * Input: ++ * port - Physical port number (0~7) ++ * pEnabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsic1xPBEnConfig(rtk_uint32 port, rtk_uint32 *pEnabled) ++{ ++ if(port >= RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ return rtl8367c_getAsicRegBit(RTL8367C_DOT1X_PORT_ENABLE_REG, port, pEnabled); ++} ++/* Function Name: ++ * rtl8367c_setAsic1xPBAuthConfig ++ * Description: ++ * Set 802.1x port-based authorised port configuration ++ * Input: ++ * port - Physical port number (0~7) ++ * auth - 1: authorised, 0: non-authorised ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsic1xPBAuthConfig(rtk_uint32 port, rtk_uint32 auth) ++{ ++ if(port >= RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ return rtl8367c_setAsicRegBit(RTL8367C_DOT1X_PORT_AUTH_REG, port, auth); ++} ++/* Function Name: ++ * rtl8367c_getAsic1xPBAuthConfig ++ * Description: ++ * Get 802.1x port-based authorised port configuration ++ * Input: ++ * port - Physical port number (0~7) ++ * pAuth - 1: authorised, 0: non-authorised ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsic1xPBAuthConfig(rtk_uint32 port, rtk_uint32 *pAuth) ++{ ++ if(port >= RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ return rtl8367c_getAsicRegBit(RTL8367C_DOT1X_PORT_AUTH_REG, port, pAuth); ++} ++/* Function Name: ++ * rtl8367c_setAsic1xPBOpdirConfig ++ * Description: ++ * Set 802.1x port-based operational direction ++ * Input: ++ * port - Physical port number (0~7) ++ * opdir - Operation direction 1: IN, 0:BOTH ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsic1xPBOpdirConfig(rtk_uint32 port, rtk_uint32 opdir) ++{ ++ if(port >= RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ return rtl8367c_setAsicRegBit(RTL8367C_DOT1X_PORT_OPDIR_REG, port, opdir); ++} ++/* Function Name: ++ * rtl8367c_getAsic1xPBOpdirConfig ++ * Description: ++ * Get 802.1x port-based operational direction ++ * Input: ++ * port - Physical port number (0~7) ++ * pOpdir - Operation direction 1: IN, 0:BOTH ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsic1xPBOpdirConfig(rtk_uint32 port, rtk_uint32* pOpdir) ++{ ++ if(port >= RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ return rtl8367c_getAsicRegBit(RTL8367C_DOT1X_PORT_OPDIR_REG, port, pOpdir); ++} ++/* Function Name: ++ * rtl8367c_setAsic1xMBEnConfig ++ * Description: ++ * Set 802.1x mac-based port enable configuration ++ * Input: ++ * port - Physical port number (0~7) ++ * enabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsic1xMBEnConfig(rtk_uint32 port, rtk_uint32 enabled) ++{ ++ if(port >= RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ return rtl8367c_setAsicRegBit(RTL8367C_DOT1X_MAC_ENABLE_REG, port, enabled); ++} ++/* Function Name: ++ * rtl8367c_getAsic1xMBEnConfig ++ * Description: ++ * Get 802.1x mac-based port enable configuration ++ * Input: ++ * port - Physical port number (0~7) ++ * pEnabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsic1xMBEnConfig(rtk_uint32 port, rtk_uint32 *pEnabled) ++{ ++ if(port >= RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ return rtl8367c_getAsicRegBit(RTL8367C_DOT1X_MAC_ENABLE_REG, port, pEnabled); ++} ++/* Function Name: ++ * rtl8367c_setAsic1xMBOpdirConfig ++ * Description: ++ * Set 802.1x mac-based operational direction ++ * Input: ++ * opdir - Operation direction 1: IN, 0:BOTH ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsic1xMBOpdirConfig(rtk_uint32 opdir) ++{ ++ return rtl8367c_setAsicRegBit(RTL8367C_DOT1X_CFG_REG, RTL8367C_DOT1X_MAC_OPDIR_OFFSET, opdir); ++} ++/* Function Name: ++ * rtl8367c_getAsic1xMBOpdirConfig ++ * Description: ++ * Get 802.1x mac-based operational direction ++ * Input: ++ * pOpdir - Operation direction 1: IN, 0:BOTH ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsic1xMBOpdirConfig(rtk_uint32 *pOpdir) ++{ ++ return rtl8367c_getAsicRegBit(RTL8367C_DOT1X_CFG_REG, RTL8367C_DOT1X_MAC_OPDIR_OFFSET, pOpdir); ++} ++/* Function Name: ++ * rtl8367c_setAsic1xProcConfig ++ * Description: ++ * Set 802.1x unauth. behavior configuration ++ * Input: ++ * port - Physical port number (0~7) ++ * proc - 802.1x unauth. behavior configuration 0:drop 1:trap to CPU 2:Guest VLAN ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * RT_ERR_DOT1X_PROC - Unauthorized behavior error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsic1xProcConfig(rtk_uint32 port, rtk_uint32 proc) ++{ ++ ++ if(port >= RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ if(proc >= DOT1X_UNAUTH_END) ++ return RT_ERR_DOT1X_PROC; ++ ++ if(port < 8) ++ { ++ return rtl8367c_setAsicRegBits(RTL8367C_DOT1X_UNAUTH_ACT_BASE, RTL8367C_DOT1X_UNAUTH_ACT_MASK(port),proc); ++ } ++ else ++ { ++ return rtl8367c_setAsicRegBits(RTL8367C_REG_DOT1X_UNAUTH_ACT_W1, RTL8367C_DOT1X_UNAUTH_ACT_MASK(port),proc); ++ } ++} ++/* Function Name: ++ * rtl8367c_getAsic1xProcConfig ++ * Description: ++ * Get 802.1x unauth. behavior configuration ++ * Input: ++ * port - Physical port number (0~7) ++ * pProc - 802.1x unauth. behavior configuration 0:drop 1:trap to CPU 2:Guest VLAN ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsic1xProcConfig(rtk_uint32 port, rtk_uint32* pProc) ++{ ++ if(port >= RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ if(port < 8) ++ return rtl8367c_getAsicRegBits(RTL8367C_DOT1X_UNAUTH_ACT_BASE, RTL8367C_DOT1X_UNAUTH_ACT_MASK(port),pProc); ++ else ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_DOT1X_UNAUTH_ACT_W1, RTL8367C_DOT1X_UNAUTH_ACT_MASK(port),pProc); ++} ++/* Function Name: ++ * rtl8367c_setAsic1xGuestVidx ++ * Description: ++ * Set 802.1x guest vlan index ++ * Input: ++ * index - 802.1x guest vlan index (0~31) ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_DOT1X_GVLANIDX - Invalid cvid index ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsic1xGuestVidx(rtk_uint32 index) ++{ ++ if(index >= RTL8367C_CVIDXNO) ++ return RT_ERR_DOT1X_GVLANIDX; ++ ++ return rtl8367c_setAsicRegBits(RTL8367C_DOT1X_CFG_REG, RTL8367C_DOT1X_GVIDX_MASK, index); ++} ++/* Function Name: ++ * rtl8367c_getAsic1xGuestVidx ++ * Description: ++ * Get 802.1x guest vlan index ++ * Input: ++ * pIndex - 802.1x guest vlan index (0~31) ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsic1xGuestVidx(rtk_uint32 *pIndex) ++{ ++ return rtl8367c_getAsicRegBits(RTL8367C_DOT1X_CFG_REG, RTL8367C_DOT1X_GVIDX_MASK, pIndex); ++} ++/* Function Name: ++ * rtl8367c_setAsic1xGVOpdir ++ * Description: ++ * Set 802.1x guest vlan talk to auth. DA ++ * Input: ++ * enabled - 0:disable 1:enable ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsic1xGVOpdir(rtk_uint32 enabled) ++{ ++ return rtl8367c_setAsicRegBit(RTL8367C_DOT1X_CFG_REG, RTL8367C_DOT1X_GVOPDIR_OFFSET, enabled); ++} ++/* Function Name: ++ * rtl8367c_getAsic1xGVOpdir ++ * Description: ++ * Get 802.1x guest vlan talk to auth. DA ++ * Input: ++ * pEnabled - 0:disable 1:enable ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsic1xGVOpdir(rtk_uint32 *pEnabled) ++{ ++ return rtl8367c_getAsicRegBit(RTL8367C_DOT1X_CFG_REG, RTL8367C_DOT1X_GVOPDIR_OFFSET, pEnabled); ++} ++/* Function Name: ++ * rtl8367c_setAsic1xTrapPriority ++ * Description: ++ * Set 802.1x Trap priority ++ * Input: ++ * priority - priority (0~7) ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_QOS_INT_PRIORITY - Invalid priority ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsic1xTrapPriority(rtk_uint32 priority) ++{ ++ if(priority > RTL8367C_PRIMAX) ++ return RT_ERR_QOS_INT_PRIORITY; ++ ++ return rtl8367c_setAsicRegBits(RTL8367C_REG_QOS_TRAP_PRIORITY0, RTL8367C_DOT1X_PRIORTY_MASK,priority); ++} ++/* Function Name: ++ * rtl8367c_getAsic1xTrapPriority ++ * Description: ++ * Get 802.1x Trap priority ++ * Input: ++ * pPriority - priority (0~7) ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsic1xTrapPriority(rtk_uint32 *pPriority) ++{ ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_QOS_TRAP_PRIORITY0, RTL8367C_DOT1X_PRIORTY_MASK, pPriority); ++} ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_eav.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_eav.c +new file mode 100644 +index 000000000000..811ee4795441 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_eav.c +@@ -0,0 +1,877 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : Ethernet AV related functions ++ * ++ */ ++ ++#include ++/* Function Name: ++ * rtl8367c_setAsicEavMacAddress ++ * Description: ++ * Set PTP MAC address ++ * Input: ++ * mac - PTP mac ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicEavMacAddress(ether_addr_t mac) ++{ ++ ret_t retVal; ++ rtk_uint32 regData; ++ rtk_uint8 *accessPtr; ++ rtk_uint32 i; ++ ++ accessPtr = (rtk_uint8*)&mac; ++ ++ regData = *accessPtr; ++ accessPtr ++; ++ regData = (regData << 8) | *accessPtr; ++ accessPtr ++; ++ for(i = 0; i <=2; i++) ++ { ++ retVal = rtl8367c_setAsicReg(RTL8367C_REG_MAC_ADDR_H - i, regData); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ regData = *accessPtr; ++ accessPtr ++; ++ regData = (regData << 8) | *accessPtr; ++ accessPtr ++; ++ } ++ ++ return retVal; ++} ++/* Function Name: ++ * rtl8367c_getAsicEavMacAddress ++ * Description: ++ * Get PTP MAC address ++ * Input: ++ * None ++ * Output: ++ * pMac - PTP mac ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicEavMacAddress(ether_addr_t *pMac) ++{ ++ ret_t retVal; ++ rtk_uint32 regData; ++ rtk_uint8 *accessPtr; ++ rtk_uint32 i; ++ ++ accessPtr = (rtk_uint8*)pMac; ++ ++ for(i = 0; i <= 2; i++) ++ { ++ retVal = rtl8367c_getAsicReg(RTL8367C_REG_MAC_ADDR_H - i, ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ *accessPtr = (regData & 0xFF00) >> 8; ++ accessPtr ++; ++ *accessPtr = regData & 0xFF; ++ accessPtr ++; ++ } ++ ++ return retVal; ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicEavTpid ++ * Description: ++ * Set PTP parser tag TPID. ++ * Input: ++ * outerTag - outer tag TPID ++ * innerTag - inner tag TPID ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicEavTpid(rtk_uint32 outerTag, rtk_uint32 innerTag) ++{ ++ ret_t retVal; ++ ++ if((retVal = rtl8367c_setAsicReg(RTL8367C_REG_OTAG_TPID, outerTag)) != RT_ERR_OK) ++ return retVal; ++ if((retVal = rtl8367c_setAsicReg(RTL8367C_REG_ITAG_TPID, innerTag)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_getAsicEavTpid ++ * Description: ++ * Get PTP parser tag TPID. ++ * Input: ++ * None ++ * Output: ++ * pOuterTag - outer tag TPID ++ * pInnerTag - inner tag TPID ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicEavTpid(rtk_uint32* pOuterTag, rtk_uint32* pInnerTag) ++{ ++ ret_t retVal; ++ ++ if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_OTAG_TPID, pOuterTag)) != RT_ERR_OK) ++ return retVal; ++ if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_ITAG_TPID, pInnerTag)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicEavSysTime ++ * Description: ++ * Set PTP system time ++ * Input: ++ * second - seconds ++ * nanoSecond - nano seconds ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * The time granularity is 8 nano seconds. ++ */ ++ret_t rtl8367c_setAsicEavSysTime(rtk_uint32 second, rtk_uint32 nanoSecond) ++{ ++ ret_t retVal; ++ rtk_uint32 sec_h, sec_l, nsec8_h, nsec8_l; ++ rtk_uint32 nano_second_8; ++ rtk_uint32 regData, busyFlag, count; ++ ++ if(nanoSecond > RTL8367C_EAV_NANOSECONDMAX) ++ return RT_ERR_INPUT; ++ ++ regData = 0; ++ sec_h = second >>16; ++ sec_l = second & 0xFFFF; ++ nano_second_8 = nanoSecond >> 3; ++ nsec8_h = (nano_second_8 >>16) & RTL8367C_PTP_TIME_NSEC_H_NSEC_MASK; ++ nsec8_l = nano_second_8 &0xFFFF; ++ ++ if((retVal = rtl8367c_setAsicReg(RTL8367C_REG_PTP_TIME_SEC_H_SEC, sec_h)) != RT_ERR_OK) ++ return retVal; ++ if((retVal = rtl8367c_setAsicReg(RTL8367C_REG_PTP_TIME_SEC_L_SEC, sec_l)) != RT_ERR_OK) ++ return retVal; ++ if((retVal = rtl8367c_setAsicReg(RTL8367C_REG_PTP_TIME_NSEC_L_NSEC, nsec8_l)) != RT_ERR_OK) ++ return retVal; ++ ++ regData = nsec8_h | (PTP_TIME_WRITE<= PTP_TIME_ADJ_END) ++ return RT_ERR_INPUT; ++ if(nanoSecond > RTL8367C_EAV_NANOSECONDMAX) ++ return RT_ERR_INPUT; ++ ++ regData = 0; ++ sec_h = second >>16; ++ sec_l = second & 0xFFFF; ++ nano_second_8 = nanoSecond >> 3; ++ nsec8_h = (nano_second_8 >>16) & RTL8367C_PTP_TIME_NSEC_H_NSEC_MASK; ++ nsec8_l = nano_second_8 &0xFFFF; ++ ++ if((retVal = rtl8367c_setAsicReg(RTL8367C_REG_PTP_TIME_SEC_H_SEC, sec_h)) != RT_ERR_OK) ++ return retVal; ++ if((retVal = rtl8367c_setAsicReg(RTL8367C_REG_PTP_TIME_SEC_L_SEC, sec_l)) != RT_ERR_OK) ++ return retVal; ++ if((retVal = rtl8367c_setAsicReg(RTL8367C_REG_PTP_TIME_NSEC_L_NSEC, nsec8_l)) != RT_ERR_OK) ++ return retVal; ++ ++ if (PTP_TIME_ADJ_INC == type) ++ regData = nsec8_h | (PTP_TIME_INC<=PTP_TIME_CTRL_END) ++ return RT_ERR_INPUT; ++ ++ regData = 0; ++ if (PTP_TIME_CTRL_START == control) ++ regData = RTL8367C_CFG_TIMER_EN_FRC_MASK | RTL8367C_CFG_TIMER_1588_EN_MASK; ++ else ++ regData = 0; ++ ++ if((retVal = rtl8367c_setAsicReg(RTL8367C_REG_PTP_TIME_CFG, regData)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicEavSysTimeCtrl ++ * Description: ++ * Get PTP system time control ++ * Input: ++ * None ++ * Output: ++ * pControl - start or stop ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicEavSysTimeCtrl(rtk_uint32* pControl) ++{ ++ ret_t retVal; ++ rtk_uint32 regData; ++ rtk_uint32 mask; ++ ++ mask = RTL8367C_CFG_TIMER_EN_FRC_MASK | RTL8367C_CFG_TIMER_1588_EN_MASK; ++ ++ if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_PTP_TIME_CFG, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ if( (regData & mask) == mask) ++ *pControl = PTP_TIME_CTRL_START; ++ else if( (regData & mask) == 0) ++ *pControl = PTP_TIME_CTRL_STOP; ++ else ++ return RT_ERR_NOT_ALLOWED; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicEavInterruptMask ++ * Description: ++ * Set PTP interrupt enable mask ++ * Input: ++ * imr - Interrupt mask ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * [0]:TX_SYNC, ++ * [1]:TX_DELAY, ++ * [2]:TX_PDELAY_REQ, ++ * [3]:TX_PDELAY_RESP, ++ * [4]:RX_SYNC, ++ * [5]:RX_DELAY, ++ * [6]:RX_PDELAY_REQ, ++ * [7]:RX_PDELAY_RESP, ++ */ ++ret_t rtl8367c_setAsicEavInterruptMask(rtk_uint32 imr) ++{ ++ if ((imr&(RTL8367C_PTP_INTR_MASK<<8))>0) ++ return RT_ERR_INPUT; ++ ++ return rtl8367c_setAsicRegBits(RTL8367C_REG_PTP_TIME_CFG2, RTL8367C_PTP_INTR_MASK, imr); ++} ++/* Function Name: ++ * rtl8367c_getAsicEavInterruptMask ++ * Description: ++ * Get PTP interrupt enable mask ++ * Input: ++ * pImr - Interrupt mask ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * [0]:TX_SYNC, ++ * [1]:TX_DELAY, ++ * [2]:TX_PDELAY_REQ, ++ * [3]:TX_PDELAY_RESP, ++ * [4]:RX_SYNC, ++ * [5]:RX_DELAY, ++ * [6]:RX_PDELAY_REQ, ++ * [7]:RX_PDELAY_RESP, ++ */ ++ret_t rtl8367c_getAsicEavInterruptMask(rtk_uint32* pImr) ++{ ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_PTP_TIME_CFG2, RTL8367C_PTP_INTR_MASK, pImr); ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicEavInterruptStatus ++ * Description: ++ * Get PTP interrupt port status mask ++ * Input: ++ * pIms - Interrupt mask ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * [0]:p0 interrupt, ++ * [1]:p1 interrupt, ++ * [2]:p2 interrupt, ++ * [3]:p3 interrupt, ++ * [4]:p4 interrupt, ++ */ ++ret_t rtl8367c_getAsicEavInterruptStatus(rtk_uint32* pIms) ++{ ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_PTP_INTERRUPT_CFG, RTL8367C_PTP_PORT_MASK, pIms); ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicInterruptMask ++ * Description: ++ * Clear interrupt enable mask ++ * Input: ++ * ims - Interrupt status mask ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * This API can be used to clear ASIC interrupt status and register will be cleared by writing 1. ++ * [0]:TX_SYNC, ++ * [1]:TX_DELAY, ++ * [2]:TX_PDELAY_REQ, ++ * [3]:TX_PDELAY_RESP, ++ * [4]:RX_SYNC, ++ * [5]:RX_DELAY, ++ * [6]:RX_PDELAY_REQ, ++ * [7]:RX_PDELAY_RESP, ++ */ ++ret_t rtl8367c_setAsicEavPortInterruptStatus(rtk_uint32 port, rtk_uint32 ims) ++{ ++ ++ if(port > RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ if(port < 5) ++ return rtl8367c_setAsicRegBits(RTL8367C_EAV_PORT_CFG_REG(port), RTL8367C_PTP_INTR_MASK,ims); ++ else if(port == 5) ++ return rtl8367c_setAsicRegBits(RTL8367C_REG_P5_EAV_CFG, RTL8367C_PTP_INTR_MASK,ims); ++ else if(port == 6) ++ return rtl8367c_setAsicRegBits(RTL8367C_REG_P6_EAV_CFG, RTL8367C_PTP_INTR_MASK,ims); ++ else if(port == 7) ++ return rtl8367c_setAsicRegBits(RTL8367C_REG_P7_EAV_CFG, RTL8367C_PTP_INTR_MASK,ims); ++ else if(port == 8) ++ return rtl8367c_setAsicRegBits(RTL8367C_REG_P8_EAV_CFG, RTL8367C_PTP_INTR_MASK,ims); ++ else if(port == 9) ++ return rtl8367c_setAsicRegBits(RTL8367C_REG_P9_EAV_CFG, RTL8367C_PTP_INTR_MASK,ims); ++ ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_getAsicInterruptStatus ++ * Description: ++ * Get interrupt enable mask ++ * Input: ++ * pIms - Interrupt status mask ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * [0]:TX_SYNC, ++ * [1]:TX_DELAY, ++ * [2]:TX_PDELAY_REQ, ++ * [3]:TX_PDELAY_RESP, ++ * [4]:RX_SYNC, ++ * [5]:RX_DELAY, ++ * [6]:RX_PDELAY_REQ, ++ * [7]:RX_PDELAY_RESP, ++ */ ++ret_t rtl8367c_getAsicEavPortInterruptStatus(rtk_uint32 port, rtk_uint32* pIms) ++{ ++ ++ if(port > RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ if(port < 5) ++ return rtl8367c_getAsicRegBits(RTL8367C_EAV_PORT_CFG_REG(port), RTL8367C_PTP_INTR_MASK, pIms); ++ else if(port == 5) ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_P5_EAV_CFG, RTL8367C_PTP_INTR_MASK, pIms); ++ else if(port == 6) ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_P6_EAV_CFG, RTL8367C_PTP_INTR_MASK,pIms); ++ else if(port == 7) ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_P7_EAV_CFG, RTL8367C_PTP_INTR_MASK,pIms); ++ else if(port == 8) ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_P8_EAV_CFG, RTL8367C_PTP_INTR_MASK,pIms); ++ else if(port == 9) ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_P9_EAV_CFG, RTL8367C_PTP_INTR_MASK,pIms); ++ ++ return RT_ERR_OK; ++ ++} ++ ++ ++/* Function Name: ++ * rtl8367c_setAsicEavPortEnable ++ * Description: ++ * Set per-port EAV function enable/disable ++ * Input: ++ * port - Physical port number (0~9) ++ * enabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * If EAV function is enabled, PTP event message packet will be attached PTP timestamp for trapping ++ */ ++ret_t rtl8367c_setAsicEavPortEnable(rtk_uint32 port, rtk_uint32 enabled) ++{ ++ if(port > RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ if(port < 5) ++ return rtl8367c_setAsicRegBit(RTL8367C_EAV_PORT_CFG_REG(port), RTL8367C_EAV_CFG_PTP_PHY_EN_EN_OFFSET, enabled); ++ else if(port == 5) ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_P5_EAV_CFG, RTL8367C_EAV_CFG_PTP_PHY_EN_EN_OFFSET, enabled); ++ else if(port == 6) ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_P6_EAV_CFG, RTL8367C_EAV_CFG_PTP_PHY_EN_EN_OFFSET, enabled); ++ else if(port == 7) ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_P7_EAV_CFG, RTL8367C_EAV_CFG_PTP_PHY_EN_EN_OFFSET, enabled); ++ else if(port == 8) ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_P8_EAV_CFG, RTL8367C_EAV_CFG_PTP_PHY_EN_EN_OFFSET, enabled); ++ else if(port == 9) ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_P9_EAV_CFG, RTL8367C_EAV_CFG_PTP_PHY_EN_EN_OFFSET, enabled); ++ ++ ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_getAsicEavPortEnable ++ * Description: ++ * Get per-port EAV function enable/disable ++ * Input: ++ * port - Physical port number (0~9) ++ * pEnabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicEavPortEnable(rtk_uint32 port, rtk_uint32 *pEnabled) ++{ ++ if(port > RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ ++ ++ if(port < 5) ++ return rtl8367c_getAsicRegBit(RTL8367C_EAV_PORT_CFG_REG(port), RTL8367C_EAV_CFG_PTP_PHY_EN_EN_OFFSET, pEnabled); ++ else if(port == 5) ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_P5_EAV_CFG, RTL8367C_EAV_CFG_PTP_PHY_EN_EN_OFFSET, pEnabled); ++ else if(port == 6) ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_P6_EAV_CFG, RTL8367C_EAV_CFG_PTP_PHY_EN_EN_OFFSET, pEnabled); ++ else if(port == 7) ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_P7_EAV_CFG, RTL8367C_EAV_CFG_PTP_PHY_EN_EN_OFFSET, pEnabled); ++ else if(port == 8) ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_P8_EAV_CFG, RTL8367C_EAV_CFG_PTP_PHY_EN_EN_OFFSET, pEnabled); ++ else if(port == 9) ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_P9_EAV_CFG, RTL8367C_EAV_CFG_PTP_PHY_EN_EN_OFFSET, pEnabled); ++ ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicEavPortTimeStamp ++ * Description: ++ * Get PTP port time stamp ++ * Input: ++ * port - Physical port number (0~9) ++ * type - PTP packet type ++ * Output: ++ * timeStamp - seconds ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * The time granularity is 8 nano seconds. ++ */ ++ret_t rtl8367c_getAsicEavPortTimeStamp(rtk_uint32 port, rtk_uint32 type, rtl8367c_ptp_time_stamp_t* timeStamp) ++{ ++ ret_t retVal; ++ rtk_uint32 sec_h, sec_l, nsec8_h, nsec8_l; ++ rtk_uint32 nano_second_8; ++ ++ if(port > 9) ++ return RT_ERR_PORT_ID; ++ if(type >= PTP_PKT_TYPE_END) ++ return RT_ERR_INPUT; ++ ++ if(port < 5){ ++ if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_SEQ_ID(port, type), &timeStamp->sequence_id))!= RT_ERR_OK) ++ return retVal; ++ if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_PORT_SEC_H(port) , &sec_h)) != RT_ERR_OK) ++ return retVal; ++ if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_PORT_SEC_L(port), &sec_l)) != RT_ERR_OK) ++ return retVal; ++ if((retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_PORT_NSEC_H(port) , RTL8367C_PORT_NSEC_H_MASK,&nsec8_h)) != RT_ERR_OK) ++ return retVal; ++ if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_PORT_NSEC_L(port) , &nsec8_l)) != RT_ERR_OK) ++ return retVal; ++ }else if(port == 5){ ++ if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P5_TX_SYNC_SEQ_ID+type, &timeStamp->sequence_id))!= RT_ERR_OK) ++ return retVal; ++ if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P5_PORT_SEC_31_16, &sec_h)) != RT_ERR_OK) ++ return retVal; ++ if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P5_PORT_SEC_15_0, &sec_l)) != RT_ERR_OK) ++ return retVal; ++ if((retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_P5_PORT_NSEC_26_16 , RTL8367C_PORT_NSEC_H_MASK,&nsec8_h)) != RT_ERR_OK) ++ return retVal; ++ if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P5_PORT_NSEC_15_0, &nsec8_l)) != RT_ERR_OK) ++ return retVal; ++ }else if(port == 6){ ++ if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P6_TX_SYNC_SEQ_ID+type, &timeStamp->sequence_id))!= RT_ERR_OK) ++ return retVal; ++ if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P6_PORT_SEC_31_16, &sec_h)) != RT_ERR_OK) ++ return retVal; ++ if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P6_PORT_SEC_15_0, &sec_l)) != RT_ERR_OK) ++ return retVal; ++ if((retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_P6_PORT_NSEC_26_16 , RTL8367C_PORT_NSEC_H_MASK,&nsec8_h)) != RT_ERR_OK) ++ return retVal; ++ if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P6_PORT_NSEC_15_0, &nsec8_l)) != RT_ERR_OK) ++ return retVal; ++ }else if(port == 7){ ++ if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P7_TX_SYNC_SEQ_ID+type, &timeStamp->sequence_id))!= RT_ERR_OK) ++ return retVal; ++ if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P7_PORT_SEC_31_16, &sec_h)) != RT_ERR_OK) ++ return retVal; ++ if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P7_PORT_SEC_15_0, &sec_l)) != RT_ERR_OK) ++ return retVal; ++ if((retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_P7_PORT_NSEC_26_16 , RTL8367C_PORT_NSEC_H_MASK,&nsec8_h)) != RT_ERR_OK) ++ return retVal; ++ if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P7_PORT_NSEC_15_0, &nsec8_l)) != RT_ERR_OK) ++ return retVal; ++ }else if(port == 8){ ++ if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P8_TX_SYNC_SEQ_ID+type, &timeStamp->sequence_id))!= RT_ERR_OK) ++ return retVal; ++ if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P8_PORT_SEC_31_16, &sec_h)) != RT_ERR_OK) ++ return retVal; ++ if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P8_PORT_SEC_15_0, &sec_l)) != RT_ERR_OK) ++ return retVal; ++ if((retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_P8_PORT_NSEC_26_16 , RTL8367C_PORT_NSEC_H_MASK,&nsec8_h)) != RT_ERR_OK) ++ return retVal; ++ if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P8_PORT_NSEC_15_0, &nsec8_l)) != RT_ERR_OK) ++ return retVal; ++ }else if(port == 9){ ++ if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P9_TX_SYNC_SEQ_ID+type, &timeStamp->sequence_id))!= RT_ERR_OK) ++ return retVal; ++ if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P9_PORT_SEC_31_16, &sec_h)) != RT_ERR_OK) ++ return retVal; ++ if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P9_PORT_SEC_15_0, &sec_l)) != RT_ERR_OK) ++ return retVal; ++ if((retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_P9_PORT_NSEC_26_16 , RTL8367C_PORT_NSEC_H_MASK,&nsec8_h)) != RT_ERR_OK) ++ return retVal; ++ if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P9_PORT_NSEC_15_0, &nsec8_l)) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ timeStamp->second = (sec_h<<16) | sec_l; ++ nano_second_8 = (nsec8_h<<16) | nsec8_l; ++ timeStamp->nano_second = nano_second_8<<3; ++ ++ return RT_ERR_OK; ++} ++ ++ ++/* Function Name: ++ * rtl8367c_setAsicEavTrap ++ * Description: ++ * Set per-port PTP packet trap to CPU ++ * Input: ++ * port - Physical port number (0~5) ++ * enabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * If EAV trap enabled, switch will trap PTP packet to CPU ++ */ ++ret_t rtl8367c_setAsicEavTrap(rtk_uint32 port, rtk_uint32 enabled) ++{ ++ if(port > RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_PTP_PORT0_CFG1 + (port * 0x20), RTL8367C_PTP_PORT0_CFG1_OFFSET, enabled); ++} ++/* Function Name: ++ * rtl8367c_getAsicEavTimeSyncEn ++ * Description: ++ * Get per-port EPTP packet trap to CPU ++ * Input: ++ * port - Physical port number (0~5) ++ * pEnabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicEavTrap(rtk_uint32 port, rtk_uint32 *pEnabled) ++{ ++ if(port > RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_PTP_PORT0_CFG1 + (port * 0x20), RTL8367C_PTP_PORT0_CFG1_OFFSET, pEnabled); ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicEavEnable ++ * Description: ++ * Set per-port EAV function enable/disable ++ * Input: ++ * port - Physical port number (0~5) ++ * enabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * If EAV function is enabled, PTP event message packet will be attached PTP timestamp for trapping ++ */ ++ret_t rtl8367c_setAsicEavEnable(rtk_uint32 port, rtk_uint32 enabled) ++{ ++ if(port > RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_EAV_CTRL0, port, enabled); ++} ++/* Function Name: ++ * rtl8367c_getAsicEavEnable ++ * Description: ++ * Get per-port EAV function enable/disable ++ * Input: ++ * port - Physical port number (0~5) ++ * pEnabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicEavEnable(rtk_uint32 port, rtk_uint32 *pEnabled) ++{ ++ if(port > RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_EAV_CTRL0, port, pEnabled); ++} ++/* Function Name: ++ * rtl8367c_setAsicEavPriRemapping ++ * Description: ++ * Set non-EAV streaming priority remapping ++ * Input: ++ * srcpriority - Priority value ++ * priority - Absolute priority value ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_QOS_INT_PRIORITY - Invalid priority ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicEavPriRemapping(rtk_uint32 srcpriority, rtk_uint32 priority) ++{ ++ if(srcpriority > RTL8367C_PRIMAX || priority > RTL8367C_PRIMAX) ++ return RT_ERR_QOS_INT_PRIORITY; ++ ++ return rtl8367c_setAsicRegBits(RTL8367C_EAV_PRIORITY_REMAPPING_REG(srcpriority), RTL8367C_EAV_PRIORITY_REMAPPING_MASK(srcpriority),priority); ++} ++/* Function Name: ++ * rtl8367c_getAsicEavPriRemapping ++ * Description: ++ * Get non-EAV streaming priority remapping ++ * Input: ++ * srcpriority - Priority value ++ * pPriority - Absolute priority value ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_QOS_INT_PRIORITY - Invalid priority ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicEavPriRemapping(rtk_uint32 srcpriority, rtk_uint32 *pPriority) ++{ ++ if(srcpriority > RTL8367C_PRIMAX ) ++ return RT_ERR_QOS_INT_PRIORITY; ++ ++ return rtl8367c_getAsicRegBits(RTL8367C_EAV_PRIORITY_REMAPPING_REG(srcpriority), RTL8367C_EAV_PRIORITY_REMAPPING_MASK(srcpriority),pPriority); ++} ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_eee.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_eee.c +new file mode 100644 +index 000000000000..f4dda6a6ae6d +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_eee.c +@@ -0,0 +1,141 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 48989 $ ++ * $Date: 2014-07-01 15:45:24 +0800 (週二, 01 七月 2014) $ ++ * ++ * Purpose : RTL8370 switch high-level API for RTL8367C ++ * Feature : ++ * ++ */ ++ ++#include ++#include ++ ++/* ++@func ret_t | rtl8367c_setAsicEee100M | Set eee force mode function enable/disable. ++@parm rtk_uint32 | port | The port number. ++@parm rtk_uint32 | enabled | 1: enabled, 0: disabled. ++@rvalue RT_ERR_OK | Success. ++@rvalue RT_ERR_SMI | SMI access error. ++@rvalue RT_ERR_INPUT | Invalid input parameter. ++@comm ++ This API set the 100M EEE enable function. ++ ++*/ ++ret_t rtl8367c_setAsicEee100M(rtk_uint32 port, rtk_uint32 enable) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 regData; ++ ++ if(port >= RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ if (enable > 1) ++ return RT_ERR_INPUT; ++ ++ if((retVal = rtl8367c_getAsicPHYOCPReg(port, EEE_OCP_PHY_ADDR, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ if(enable) ++ regData |= (0x0001 << 1); ++ else ++ regData &= ~(0x0001 << 1); ++ ++ if((retVal = rtl8367c_setAsicPHYOCPReg(port, EEE_OCP_PHY_ADDR, regData)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* ++@func ret_t | rtl8367c_getAsicEee100M | Get 100M eee enable/disable. ++@parm rtk_uint32 | port | The port number. ++@parm rtk_uint32* | enabled | 1: enabled, 0: disabled. ++@rvalue RT_ERR_OK | Success. ++@rvalue RT_ERR_SMI | SMI access error. ++@rvalue RT_ERR_INPUT | Invalid input parameter. ++@comm ++ This API get the 100M EEE function. ++*/ ++ret_t rtl8367c_getAsicEee100M(rtk_uint32 port, rtk_uint32 *enable) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 regData; ++ ++ if(port >= RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ if((retVal = rtl8367c_getAsicPHYOCPReg(port, EEE_OCP_PHY_ADDR, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ *enable = (regData & (0x0001 << 1)) ? ENABLED : DISABLED; ++ return RT_ERR_OK; ++} ++ ++/* ++@func ret_t | rtl8367c_setAsicEeeGiga | Set eee force mode function enable/disable. ++@parm rtk_uint32 | port | The port number. ++@parm rtk_uint32 | enabled | 1: enabled, 0: disabled. ++@rvalue RT_ERR_OK | Success. ++@rvalue RT_ERR_SMI | SMI access error. ++@rvalue RT_ERR_INPUT | Invalid input parameter. ++@comm ++ This API set the 100M EEE enable function. ++ ++*/ ++ret_t rtl8367c_setAsicEeeGiga(rtk_uint32 port, rtk_uint32 enable) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 regData; ++ ++ if(port >= RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ if (enable > 1) ++ return RT_ERR_INPUT; ++ ++ if((retVal = rtl8367c_getAsicPHYOCPReg(port, EEE_OCP_PHY_ADDR, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ if(enable) ++ regData |= (0x0001 << 2); ++ else ++ regData &= ~(0x0001 << 2); ++ ++ if((retVal = rtl8367c_setAsicPHYOCPReg(port, EEE_OCP_PHY_ADDR, regData)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* ++@func ret_t | rtl8367c_getAsicEeeGiga | Get 100M eee enable/disable. ++@parm rtk_uint32 | port | The port number. ++@parm rtk_uint32* | enabled | 1: enabled, 0: disabled. ++@rvalue RT_ERR_OK | Success. ++@rvalue RT_ERR_SMI | SMI access error. ++@rvalue RT_ERR_INPUT | Invalid input parameter. ++@comm ++ This API get the 100M EEE function. ++*/ ++ret_t rtl8367c_getAsicEeeGiga(rtk_uint32 port, rtk_uint32 *enable) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 regData; ++ ++ if(port >= RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ if((retVal = rtl8367c_getAsicPHYOCPReg(port, EEE_OCP_PHY_ADDR, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ *enable = (regData & (0x0001 << 2)) ? ENABLED : DISABLED; ++ return RT_ERR_OK; ++} +diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_fc.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_fc.c +new file mode 100644 +index 000000000000..b7b102243903 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_fc.c +@@ -0,0 +1,1354 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : Flow control related functions ++ * ++ */ ++ ++#include ++/* Function Name: ++ * rtl8367c_setAsicFlowControlSelect ++ * Description: ++ * Set system flow control type ++ * Input: ++ * select - System flow control type 1: Ingress flow control 0:Egress flow control ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicFlowControlSelect(rtk_uint32 select) ++{ ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_FLOWCTRL_CTRL0, RTL8367C_FLOWCTRL_TYPE_OFFSET, select); ++} ++/* Function Name: ++ * rtl8367c_getAsicFlowControlSelect ++ * Description: ++ * Get system flow control type ++ * Input: ++ * pSelect - System flow control type 1: Ingress flow control 0:Egress flow control ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicFlowControlSelect(rtk_uint32 *pSelect) ++{ ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_FLOWCTRL_CTRL0, RTL8367C_FLOWCTRL_TYPE_OFFSET, pSelect); ++} ++/* Function Name: ++ * rtl8367c_setAsicFlowControlJumboMode ++ * Description: ++ * Set Jumbo threshold for flow control ++ * Input: ++ * enabled - Jumbo mode flow control 1: Enable 0:Disable ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicFlowControlJumboMode(rtk_uint32 enabled) ++{ ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_FLOWCTRL_JUMBO_SIZE, RTL8367C_JUMBO_MODE_OFFSET, enabled); ++} ++/* Function Name: ++ * rtl8367c_getAsicFlowControlJumboMode ++ * Description: ++ * Get Jumbo threshold for flow control ++ * Input: ++ * pEnabled - Jumbo mode flow control 1: Enable 0:Disable ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicFlowControlJumboMode(rtk_uint32* pEnabled) ++{ ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_FLOWCTRL_JUMBO_SIZE, RTL8367C_JUMBO_MODE_OFFSET, pEnabled); ++} ++/* Function Name: ++ * rtl8367c_setAsicFlowControlJumboModeSize ++ * Description: ++ * Set Jumbo size for Jumbo mode flow control ++ * Input: ++ * size - Jumbo size 0:3Kbytes 1:4Kbytes 2:6Kbytes 3:9Kbytes ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - input parameter out of range ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicFlowControlJumboModeSize(rtk_uint32 size) ++{ ++ if(size >= FC_JUMBO_SIZE_END) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ return rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_JUMBO_SIZE, RTL8367C_JUMBO_SIZE_MASK, size); ++} ++/* Function Name: ++ * rtl8367c_getAsicFlowControlJumboModeSize ++ * Description: ++ * Get Jumbo size for Jumbo mode flow control ++ * Input: ++ * pSize - Jumbo size 0:3Kbytes 1:4Kbytes 2:6Kbytes 3:9Kbytes ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicFlowControlJumboModeSize(rtk_uint32* pSize) ++{ ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_JUMBO_SIZE, RTL8367C_JUMBO_SIZE_MASK, pSize); ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicFlowControlQueueEgressEnable ++ * Description: ++ * Set flow control ability for each queue ++ * Input: ++ * port - Physical port number (0~7) ++ * qid - Queue id ++ * enabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * RT_ERR_QUEUE_ID - Invalid queue id ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicFlowControlQueueEgressEnable(rtk_uint32 port, rtk_uint32 qid, rtk_uint32 enabled) ++{ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ if(qid > RTL8367C_QIDMAX) ++ return RT_ERR_QUEUE_ID; ++ ++ return rtl8367c_setAsicRegBit(RTL8367C_FLOWCRTL_EGRESS_QUEUE_ENABLE_REG(port), RTL8367C_FLOWCRTL_EGRESS_QUEUE_ENABLE_REG_OFFSET(port)+ qid, enabled); ++} ++/* Function Name: ++ * rtl8367c_getAsicFlowControlQueueEgressEnable ++ * Description: ++ * Get flow control ability for each queue ++ * Input: ++ * port - Physical port number (0~7) ++ * qid - Queue id ++ * pEnabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * RT_ERR_QUEUE_ID - Invalid queue id ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicFlowControlQueueEgressEnable(rtk_uint32 port, rtk_uint32 qid, rtk_uint32* pEnabled) ++{ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ if(qid > RTL8367C_QIDMAX) ++ return RT_ERR_QUEUE_ID; ++ ++ return rtl8367c_getAsicRegBit(RTL8367C_FLOWCRTL_EGRESS_QUEUE_ENABLE_REG(port), RTL8367C_FLOWCRTL_EGRESS_QUEUE_ENABLE_REG_OFFSET(port)+ qid, pEnabled); ++} ++/* Function Name: ++ * rtl8367c_setAsicFlowControlDropAll ++ * Description: ++ * Set system-based drop parameters ++ * Input: ++ * dropall - Whole system drop threshold ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - input parameter out of range ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicFlowControlDropAll(rtk_uint32 dropall) ++{ ++ if(dropall >= RTL8367C_PAGE_NUMBER) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ return rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_CTRL0, RTL8367C_DROP_ALL_THRESHOLD_MASK, dropall); ++} ++/* Function Name: ++ * rtl8367c_getAsicFlowControlDropAll ++ * Description: ++ * Get system-based drop parameters ++ * Input: ++ * pDropall - Whole system drop threshold ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicFlowControlDropAll(rtk_uint32* pDropall) ++{ ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_CTRL0, RTL8367C_DROP_ALL_THRESHOLD_MASK, pDropall); ++} ++/* Function Name: ++ * rtl8367c_setAsicFlowControlPauseAll ++ * Description: ++ * Set system-based all ports enable flow control parameters ++ * Input: ++ * threshold - Whole system pause all threshold ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - input parameter out of range ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicFlowControlPauseAllThreshold(rtk_uint32 threshold) ++{ ++ if(threshold >= RTL8367C_PAGE_NUMBER) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ return rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_ALL_ON, RTL8367C_FLOWCTRL_ALL_ON_THRESHOLD_MASK, threshold); ++} ++/* Function Name: ++ * rtl8367c_getAsicFlowControlPauseAllThreshold ++ * Description: ++ * Get system-based all ports enable flow control parameters ++ * Input: ++ * pThreshold - Whole system pause all threshold ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicFlowControlPauseAllThreshold(rtk_uint32 *pThreshold) ++{ ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_ALL_ON, RTL8367C_FLOWCTRL_ALL_ON_THRESHOLD_MASK, pThreshold); ++} ++/* Function Name: ++ * rtl8367c_setAsicFlowControlSystemThreshold ++ * Description: ++ * Set system-based flow control parameters ++ * Input: ++ * onThreshold - Flow control turn ON threshold ++ * offThreshold - Flow control turn OFF threshold ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - input parameter out of range ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicFlowControlSystemThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold) ++{ ++ ret_t retVal; ++ ++ if((onThreshold >= RTL8367C_PAGE_NUMBER) || (offThreshold >= RTL8367C_PAGE_NUMBER)) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_SYS_OFF, RTL8367C_FLOWCTRL_SYS_OFF_MASK, offThreshold); ++ ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_SYS_ON, RTL8367C_FLOWCTRL_SYS_ON_MASK, onThreshold); ++ ++ return retVal; ++} ++/* Function Name: ++ * rtl8367c_getAsicFlowControlSystemThreshold ++ * Description: ++ * Get system-based flow control parameters ++ * Input: ++ * pOnThreshold - Flow control turn ON threshold ++ * pOffThreshold - Flow control turn OFF threshold ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicFlowControlSystemThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold) ++{ ++ ret_t retVal; ++ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_SYS_OFF, RTL8367C_FLOWCTRL_SYS_OFF_MASK, pOffThreshold); ++ ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_SYS_ON, RTL8367C_FLOWCTRL_SYS_ON_MASK, pOnThreshold); ++ ++ return retVal; ++} ++/* Function Name: ++ * rtl8367c_setAsicFlowControlSharedThreshold ++ * Description: ++ * Set share-based flow control parameters ++ * Input: ++ * onThreshold - Flow control turn ON threshold ++ * offThreshold - Flow control turn OFF threshold ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - input parameter out of range ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicFlowControlSharedThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold) ++{ ++ ret_t retVal; ++ ++ if((onThreshold >= RTL8367C_PAGE_NUMBER) || (offThreshold >= RTL8367C_PAGE_NUMBER)) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_SHARE_OFF, RTL8367C_FLOWCTRL_SHARE_OFF_MASK, offThreshold); ++ ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_SHARE_ON, RTL8367C_FLOWCTRL_SHARE_ON_MASK, onThreshold); ++ ++ return retVal; ++} ++/* Function Name: ++ * rtl8367c_getAsicFlowControlSharedThreshold ++ * Description: ++ * Get share-based flow control parameters ++ * Input: ++ * pOnThreshold - Flow control turn ON threshold ++ * pOffThreshold - Flow control turn OFF threshold ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicFlowControlSharedThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold) ++{ ++ ret_t retVal; ++ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_SHARE_OFF, RTL8367C_FLOWCTRL_SHARE_OFF_MASK, pOffThreshold); ++ ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_SHARE_ON, RTL8367C_FLOWCTRL_SHARE_ON_MASK, pOnThreshold); ++ ++ return retVal; ++} ++/* Function Name: ++ * rtl8367c_setAsicFlowControlPortThreshold ++ * Description: ++ * Set Port-based flow control parameters ++ * Input: ++ * onThreshold - Flow control turn ON threshold ++ * offThreshold - Flow control turn OFF threshold ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - input parameter out of range ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicFlowControlPortThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold) ++{ ++ ret_t retVal; ++ ++ if((onThreshold >= RTL8367C_PAGE_NUMBER) || (offThreshold >= RTL8367C_PAGE_NUMBER)) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_PORT_OFF, RTL8367C_FLOWCTRL_PORT_OFF_MASK, offThreshold); ++ ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_PORT_ON, RTL8367C_FLOWCTRL_PORT_ON_MASK, onThreshold); ++ ++ return retVal; ++} ++/* Function Name: ++ * rtl8367c_getAsicFlowControlPortThreshold ++ * Description: ++ * Get Port-based flow control parameters ++ * Input: ++ * pOnThreshold - Flow control turn ON threshold ++ * pOffThreshold - Flow control turn OFF threshold ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicFlowControlPortThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold) ++{ ++ ret_t retVal; ++ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_PORT_OFF, RTL8367C_FLOWCTRL_PORT_OFF_MASK, pOffThreshold); ++ ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_PORT_ON, RTL8367C_FLOWCTRL_PORT_ON_MASK, pOnThreshold); ++ ++ return retVal; ++} ++/* Function Name: ++ * rtl8367c_setAsicFlowControlPortPrivateThreshold ++ * Description: ++ * Set Port-private-based flow control parameters ++ * Input: ++ * onThreshold - Flow control turn ON threshold ++ * offThreshold - Flow control turn OFF threshold ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - input parameter out of range ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicFlowControlPortPrivateThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold) ++{ ++ ret_t retVal; ++ ++ if((onThreshold >= RTL8367C_PAGE_NUMBER) || (offThreshold >= RTL8367C_PAGE_NUMBER)) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_PORT_PRIVATE_OFF, RTL8367C_FLOWCTRL_PORT_PRIVATE_OFF_MASK, offThreshold); ++ ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_PORT_PRIVATE_ON, RTL8367C_FLOWCTRL_PORT_PRIVATE_ON_MASK, onThreshold); ++ ++ return retVal; ++} ++/* Function Name: ++ * rtl8367c_getAsicFlowControlPortPrivateThreshold ++ * Description: ++ * Get Port-private-based flow control parameters ++ * Input: ++ * pOnThreshold - Flow control turn ON threshold ++ * pOffThreshold - Flow control turn OFF threshold ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicFlowControlPortPrivateThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold) ++{ ++ ret_t retVal; ++ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_PORT_PRIVATE_OFF, RTL8367C_FLOWCTRL_PORT_PRIVATE_OFF_MASK, pOffThreshold); ++ ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_PORT_PRIVATE_ON, RTL8367C_FLOWCTRL_PORT_PRIVATE_ON_MASK, pOnThreshold); ++ ++ return retVal; ++} ++/* Function Name: ++ * rtl8367c_setAsicFlowControlSystemDropThreshold ++ * Description: ++ * Set system-based drop parameters ++ * Input: ++ * onThreshold - Drop turn ON threshold ++ * offThreshold - Drop turn OFF threshold ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - input parameter out of range ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicFlowControlSystemDropThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold) ++{ ++ ret_t retVal; ++ ++ if((onThreshold >= RTL8367C_PAGE_NUMBER) || (offThreshold >= RTL8367C_PAGE_NUMBER)) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_FCOFF_SYS_OFF, RTL8367C_FLOWCTRL_FCOFF_SYS_OFF_MASK, offThreshold); ++ ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_FCOFF_SYS_ON, RTL8367C_FLOWCTRL_FCOFF_SYS_ON_MASK, onThreshold); ++ ++ return retVal; ++} ++/* Function Name: ++ * rtl8367c_getAsicFlowControlSystemDropThreshold ++ * Description: ++ * Get system-based drop parameters ++ * Input: ++ * pOnThreshold - Drop turn ON threshold ++ * pOffThreshold - Drop turn OFF threshold ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicFlowControlSystemDropThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold) ++{ ++ ret_t retVal; ++ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_FCOFF_SYS_OFF, RTL8367C_FLOWCTRL_FCOFF_SYS_OFF_MASK, pOffThreshold); ++ ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_FCOFF_SYS_ON, RTL8367C_FLOWCTRL_FCOFF_SYS_ON_MASK, pOnThreshold); ++ ++ return retVal; ++} ++/* Function Name: ++ * rtl8367c_setAsicFlowControlSharedDropThreshold ++ * Description: ++ * Set share-based fdrop parameters ++ * Input: ++ * onThreshold - Drop turn ON threshold ++ * offThreshold - Drop turn OFF threshold ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - input parameter out of range ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicFlowControlSharedDropThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold) ++{ ++ ret_t retVal; ++ ++ if((onThreshold >= RTL8367C_PAGE_NUMBER) || (offThreshold >= RTL8367C_PAGE_NUMBER)) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_FCOFF_SHARE_OFF, RTL8367C_FLOWCTRL_FCOFF_SHARE_OFF_MASK, offThreshold); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_FCOFF_SHARE_ON, RTL8367C_FLOWCTRL_FCOFF_SHARE_ON_MASK, onThreshold); ++ ++ return retVal; ++} ++/* Function Name: ++ * rtl8367c_getAsicFlowControlSharedDropThreshold ++ * Description: ++ * Get share-based fdrop parameters ++ * Input: ++ * pOnThreshold - Drop turn ON threshold ++ * pOffThreshold - Drop turn OFF threshold ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicFlowControlSharedDropThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold) ++{ ++ ret_t retVal; ++ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_FCOFF_SHARE_OFF, RTL8367C_FLOWCTRL_FCOFF_SHARE_OFF_MASK, pOffThreshold); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_FCOFF_SHARE_ON, RTL8367C_FLOWCTRL_FCOFF_SHARE_ON_MASK, pOnThreshold); ++ ++ return retVal; ++} ++/* Function Name: ++ * rtl8367c_setAsicFlowControlPortDropThreshold ++ * Description: ++ * Set Port-based drop parameters ++ * Input: ++ * onThreshold - Drop turn ON threshold ++ * offThreshold - Drop turn OFF threshold ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - input parameter out of range ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicFlowControlPortDropThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold) ++{ ++ ret_t retVal; ++ ++ if((onThreshold >= RTL8367C_PAGE_NUMBER) || (offThreshold >= RTL8367C_PAGE_NUMBER)) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_FCOFF_PORT_OFF, RTL8367C_FLOWCTRL_FCOFF_PORT_OFF_MASK, offThreshold); ++ ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_FCOFF_PORT_ON, RTL8367C_FLOWCTRL_FCOFF_PORT_ON_MASK, onThreshold); ++ ++ return retVal; ++} ++/* Function Name: ++ * rtl8367c_getAsicFlowControlPortDropThreshold ++ * Description: ++ * Get Port-based drop parameters ++ * Input: ++ * pOnThreshold - Drop turn ON threshold ++ * pOffThreshold - Drop turn OFF threshold ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicFlowControlPortDropThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold) ++{ ++ ret_t retVal; ++ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_FCOFF_PORT_OFF, RTL8367C_FLOWCTRL_FCOFF_PORT_OFF_MASK, pOffThreshold); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_FCOFF_PORT_ON, RTL8367C_FLOWCTRL_FCOFF_PORT_ON_MASK, pOnThreshold); ++ ++ return retVal; ++} ++/* Function Name: ++ * rtl8367c_setAsicFlowControlPortPrivateDropThreshold ++ * Description: ++ * Set Port-private-based drop parameters ++ * Input: ++ * onThreshold - Drop turn ON threshold ++ * offThreshold - Drop turn OFF threshold ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - input parameter out of range ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicFlowControlPortPrivateDropThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold) ++{ ++ ret_t retVal; ++ ++ if((onThreshold >= RTL8367C_PAGE_NUMBER) || (offThreshold >= RTL8367C_PAGE_NUMBER)) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_FCOFF_PORT_PRIVATE_OFF, RTL8367C_FLOWCTRL_FCOFF_PORT_PRIVATE_OFF_MASK, offThreshold); ++ ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_FCOFF_PORT_PRIVATE_ON, RTL8367C_FLOWCTRL_FCOFF_PORT_PRIVATE_ON_MASK, onThreshold); ++ ++ return retVal; ++} ++/* Function Name: ++ * rtl8367c_getAsicFlowControlPortPrivateDropThreshold ++ * Description: ++ * Get Port-private-based drop parameters ++ * Input: ++ * pOnThreshold - Drop turn ON threshold ++ * pOffThreshold - Drop turn OFF threshold ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicFlowControlPortPrivateDropThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold) ++{ ++ ret_t retVal; ++ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_FCOFF_PORT_PRIVATE_OFF, RTL8367C_FLOWCTRL_FCOFF_PORT_PRIVATE_OFF_MASK, pOffThreshold); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_FCOFF_PORT_PRIVATE_ON, RTL8367C_FLOWCTRL_FCOFF_PORT_PRIVATE_ON_MASK, pOnThreshold); ++ ++ return retVal; ++} ++/* Function Name: ++ * rtl8367c_setAsicFlowControlSystemJumboThreshold ++ * Description: ++ * Set Jumbo system-based flow control parameters ++ * Input: ++ * onThreshold - Flow control turn ON threshold ++ * offThreshold - Flow control turn OFF threshold ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - input parameter out of range ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicFlowControlSystemJumboThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold) ++{ ++ ret_t retVal; ++ ++ if((onThreshold >= RTL8367C_PAGE_NUMBER) || (offThreshold >= RTL8367C_PAGE_NUMBER)) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_JUMBO_SYS_OFF, RTL8367C_FLOWCTRL_JUMBO_SYS_OFF_MASK, offThreshold); ++ ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_JUMBO_SYS_ON, RTL8367C_FLOWCTRL_JUMBO_SYS_ON_MASK, onThreshold); ++ ++ return retVal; ++} ++/* Function Name: ++ * rtl8367c_getAsicFlowControlSystemJumboThreshold ++ * Description: ++ * Get Jumbo system-based flow control parameters ++ * Input: ++ * pOnThreshold - Flow control turn ON threshold ++ * pOffThreshold - Flow control turn OFF threshold ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicFlowControlSystemJumboThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold) ++{ ++ ret_t retVal; ++ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_JUMBO_SYS_OFF, RTL8367C_FLOWCTRL_JUMBO_SYS_OFF_MASK, pOffThreshold); ++ ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_JUMBO_SYS_ON, RTL8367C_FLOWCTRL_JUMBO_SYS_ON_MASK, pOnThreshold); ++ ++ return retVal; ++} ++/* Function Name: ++ * rtl8367c_setAsicFlowControlSharedJumboThreshold ++ * Description: ++ * Set Jumbo share-based flow control parameters ++ * Input: ++ * onThreshold - Flow control turn ON threshold ++ * offThreshold - Flow control turn OFF threshold ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - input parameter out of range ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicFlowControlSharedJumboThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold) ++{ ++ ret_t retVal; ++ ++ if((onThreshold >= RTL8367C_PAGE_NUMBER) || (offThreshold >= RTL8367C_PAGE_NUMBER)) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_JUMBO_SHARE_OFF, RTL8367C_FLOWCTRL_JUMBO_SHARE_OFF_MASK, offThreshold); ++ ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_JUMBO_SHARE_ON, RTL8367C_FLOWCTRL_JUMBO_SHARE_ON_MASK, onThreshold); ++ ++ return retVal; ++} ++/* Function Name: ++ * rtl8367c_getAsicFlowControlSharedJumboThreshold ++ * Description: ++ * Get Jumbo share-based flow control parameters ++ * Input: ++ * pOnThreshold - Flow control turn ON threshold ++ * pOffThreshold - Flow control turn OFF threshold ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicFlowControlSharedJumboThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold) ++{ ++ ret_t retVal; ++ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_JUMBO_SHARE_OFF, RTL8367C_FLOWCTRL_JUMBO_SHARE_OFF_MASK, pOffThreshold); ++ ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_JUMBO_SHARE_ON, RTL8367C_FLOWCTRL_JUMBO_SHARE_ON_MASK, pOnThreshold); ++ ++ return retVal; ++} ++/* Function Name: ++ * rtl8367c_setAsicFlowControlPortJumboThreshold ++ * Description: ++ * Set Jumbo Port-based flow control parameters ++ * Input: ++ * onThreshold - Flow control turn ON threshold ++ * offThreshold - Flow control turn OFF threshold ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - input parameter out of range ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicFlowControlPortJumboThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold) ++{ ++ ret_t retVal; ++ ++ if((onThreshold >= RTL8367C_PAGE_NUMBER) || (offThreshold >= RTL8367C_PAGE_NUMBER)) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_JUMBO_PORT_OFF, RTL8367C_FLOWCTRL_JUMBO_PORT_OFF_MASK, offThreshold); ++ ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_JUMBO_PORT_ON, RTL8367C_FLOWCTRL_JUMBO_PORT_ON_MASK, onThreshold); ++ ++ return retVal; ++} ++/* Function Name: ++ * rtl8367c_getAsicFlowControlPortJumboThreshold ++ * Description: ++ * Get Jumbo Port-based flow control parameters ++ * Input: ++ * pOnThreshold - Flow control turn ON threshold ++ * pOffThreshold - Flow control turn OFF threshold ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicFlowControlPortJumboThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold) ++{ ++ ret_t retVal; ++ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_JUMBO_PORT_OFF, RTL8367C_FLOWCTRL_JUMBO_PORT_OFF_MASK, pOffThreshold); ++ ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_JUMBO_PORT_ON, RTL8367C_FLOWCTRL_JUMBO_PORT_ON_MASK, pOnThreshold); ++ ++ return retVal; ++} ++/* Function Name: ++ * rtl8367c_setAsicFlowControlPortPrivateJumboThreshold ++ * Description: ++ * Set Jumbo Port-private-based flow control parameters ++ * Input: ++ * onThreshold - Flow control turn ON threshold ++ * offThreshold - Flow control turn OFF threshold ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - input parameter out of range ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicFlowControlPortPrivateJumboThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold) ++{ ++ ret_t retVal; ++ ++ if((onThreshold >= RTL8367C_PAGE_NUMBER) || (offThreshold >= RTL8367C_PAGE_NUMBER)) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_JUMBO_PORT_PRIVATE_OFF, RTL8367C_FLOWCTRL_JUMBO_PORT_PRIVATE_OFF_MASK, offThreshold); ++ ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_JUMBO_PORT_PRIVATE_ON, RTL8367C_FLOWCTRL_JUMBO_PORT_PRIVATE_ON_MASK, onThreshold); ++ ++ return retVal; ++} ++/* Function Name: ++ * rtl8367c_getAsicFlowControlPortPrivateJumboThreshold ++ * Description: ++ * Get Jumbo Port-private-based flow control parameters ++ * Input: ++ * pOnThreshold - Flow control turn ON threshold ++ * pOffThreshold - Flow control turn OFF threshold ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicFlowControlPortPrivateJumboThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold) ++{ ++ ret_t retVal; ++ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_JUMBO_PORT_PRIVATE_OFF, RTL8367C_FLOWCTRL_JUMBO_PORT_PRIVATE_OFF_MASK, pOffThreshold); ++ ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_JUMBO_PORT_PRIVATE_ON, RTL8367C_FLOWCTRL_JUMBO_PORT_PRIVATE_ON_MASK, pOnThreshold); ++ ++ return retVal; ++} ++ ++ ++ ++/* Function Name: ++ * rtl8367c_setAsicEgressFlowControlQueueDropThreshold ++ * Description: ++ * Set Queue-based egress flow control turn on or ingress flow control drop on threshold ++ * Input: ++ * qid - The queue id ++ * threshold - Queue-based flown control/drop turn ON threshold ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - input parameter out of range ++ * RT_ERR_QUEUE_ID - Invalid queue id ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicEgressFlowControlQueueDropThreshold(rtk_uint32 qid, rtk_uint32 threshold) ++{ ++ if( threshold >= RTL8367C_PAGE_NUMBER) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ if(qid > RTL8367C_QIDMAX) ++ return RT_ERR_QUEUE_ID; ++ ++ return rtl8367c_setAsicRegBits(RTL8367C_FLOWCTRL_QUEUE_DROP_ON_REG(qid), RTL8367C_FLOWCTRL_QUEUE_DROP_ON_MASK, threshold); ++} ++/* Function Name: ++ * rtl8367c_getAsicEgressFlowControlQueueDropThreshold ++ * Description: ++ * Get Queue-based egress flow control turn on or ingress flow control drop on threshold ++ * Input: ++ * qid - The queue id ++ * pThreshold - Queue-based flown control/drop turn ON threshold ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_QUEUE_ID - Invalid queue id ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicEgressFlowControlQueueDropThreshold(rtk_uint32 qid, rtk_uint32 *pThreshold) ++{ ++ if(qid > RTL8367C_QIDMAX) ++ return RT_ERR_QUEUE_ID; ++ ++ return rtl8367c_getAsicRegBits(RTL8367C_FLOWCTRL_QUEUE_DROP_ON_REG(qid), RTL8367C_FLOWCTRL_QUEUE_DROP_ON_MASK, pThreshold); ++} ++/* Function Name: ++ * rtl8367c_setAsicEgressFlowControlPortDropThreshold ++ * Description: ++ * Set port-based egress flow control turn on or ingress flow control drop on threshold ++ * Input: ++ * port - Physical port number (0~7) ++ * threshold - Queue-based flown control/drop turn ON threshold ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * RT_ERR_OUT_OF_RANGE - input parameter out of range ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicEgressFlowControlPortDropThreshold(rtk_uint32 port, rtk_uint32 threshold) ++{ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ if(threshold >= RTL8367C_PAGE_NUMBER) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ return rtl8367c_setAsicRegBits(RTL8367C_FLOWCTRL_PORT_DROP_ON_REG(port), RTL8367C_FLOWCTRL_PORT_DROP_ON_MASK, threshold); ++} ++/* Function Name: ++ * rtl8367c_setAsicEgressFlowControlPortDropThreshold ++ * Description: ++ * Set port-based egress flow control turn on or ingress flow control drop on threshold ++ * Input: ++ * port - Physical port number (0~7) ++ * pThreshold - Queue-based flown control/drop turn ON threshold ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicEgressFlowControlPortDropThreshold(rtk_uint32 port, rtk_uint32 *pThreshold) ++{ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ return rtl8367c_getAsicRegBits(RTL8367C_FLOWCTRL_PORT_DROP_ON_REG(port), RTL8367C_FLOWCTRL_PORT_DROP_ON_MASK, pThreshold); ++} ++/* Function Name: ++ * rtl8367c_setAsicEgressFlowControlPortDropGap ++ * Description: ++ * Set port-based egress flow control turn off or ingress flow control drop off gap ++ * Input: ++ * gap - Flow control/drop turn OFF threshold = turn ON threshold - gap ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - input parameter out of range ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicEgressFlowControlPortDropGap(rtk_uint32 gap) ++{ ++ if(gap >= RTL8367C_PAGE_NUMBER) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ return rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_PORT_GAP, RTL8367C_FLOWCTRL_PORT_GAP_MASK, gap); ++} ++/* Function Name: ++ * rtl8367c_getAsicEgressFlowControlPortDropGap ++ * Description: ++ * Get port-based egress flow control turn off or ingress flow control drop off gap ++ * Input: ++ * pGap - Flow control/drop turn OFF threshold = turn ON threshold - gap ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicEgressFlowControlPortDropGap(rtk_uint32 *pGap) ++{ ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_PORT_GAP, RTL8367C_FLOWCTRL_PORT_GAP_MASK, pGap); ++} ++/* Function Name: ++ * rtl8367c_setAsicEgressFlowControlQueueDropGap ++ * Description: ++ * Set Queue-based egress flow control turn off or ingress flow control drop off gap ++ * Input: ++ * gap - Flow control/drop turn OFF threshold = turn ON threshold - gap ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - input parameter out of range ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicEgressFlowControlQueueDropGap(rtk_uint32 gap) ++{ ++ if(gap >= RTL8367C_PAGE_NUMBER) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ return rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_QUEUE_GAP, RTL8367C_FLOWCTRL_QUEUE_GAP_MASK, gap); ++} ++/* Function Name: ++ * rtl8367c_getAsicEgressFlowControlQueueDropGap ++ * Description: ++ * Get Queue-based egress flow control turn off or ingress flow control drop off gap ++ * Input: ++ * pGap - Flow control/drop turn OFF threshold = turn ON threshold - gap ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicEgressFlowControlQueueDropGap(rtk_uint32 *pGap) ++{ ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_QUEUE_GAP, RTL8367C_FLOWCTRL_QUEUE_GAP_MASK, pGap); ++} ++/* Function Name: ++ * rtl8367c_getAsicEgressQueueEmptyPortMask ++ * Description: ++ * Get queue empty port mask ++ * Input: ++ * pPortmask - Queue empty port mask ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicEgressQueueEmptyPortMask(rtk_uint32 *pPortmask) ++{ ++ return rtl8367c_getAsicReg(RTL8367C_REG_PORT_QEMPTY, pPortmask); ++} ++/* Function Name: ++ * rtl8367c_getAsicTotalPage ++ * Description: ++ * Get system total page usage number ++ * Input: ++ * pPageCount - page usage number ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicTotalPage(rtk_uint32 *pPageCount) ++{ ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_TOTAL_PAGE_COUNTER, RTL8367C_FLOWCTRL_TOTAL_PAGE_COUNTER_MASK, pPageCount); ++} ++/* Function Name: ++ * rtl8367c_getAsicPulbicPage ++ * Description: ++ * Get system public page usage number ++ * Input: ++ * pPageCount - page usage number ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicPulbicPage(rtk_uint32 *pPageCount) ++{ ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_PUBLIC_PAGE_COUNTER, RTL8367C_FLOWCTRL_PUBLIC_PAGE_COUNTER_MASK, pPageCount); ++} ++/* Function Name: ++ * rtl8367c_getAsicMaxTotalPage ++ * Description: ++ * Get system total page max usage number ++ * Input: ++ * pPageCount - page usage number ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicMaxTotalPage(rtk_uint32 *pPageCount) ++{ ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_TOTAL_PAGE_MAX, RTL8367C_FLOWCTRL_TOTAL_PAGE_MAX_MASK, pPageCount); ++} ++/* Function Name: ++ * rtl8367c_getAsicPulbicPage ++ * Description: ++ * Get system public page max usage number ++ * Input: ++ * pPageCount - page usage number ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicMaxPulbicPage(rtk_uint32 *pPageCount) ++{ ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_PUBLIC_PAGE_MAX, RTL8367C_FLOWCTRL_PUBLIC_PAGE_MAX_MASK, pPageCount); ++} ++/* Function Name: ++ * rtl8367c_getAsicPortPage ++ * Description: ++ * Get per-port page usage number ++ * Input: ++ * port - Physical port number (0~7) ++ * pPageCount - page usage number ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicPortPage(rtk_uint32 port, rtk_uint32 *pPageCount) ++{ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ if(port < 8) ++ return rtl8367c_getAsicRegBits(RTL8367C_FLOWCTRL_PORT_PAGE_COUNTER_REG(port), RTL8367C_FLOWCTRL_PORT_PAGE_COUNTER_MASK, pPageCount); ++ else ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_PORT8_PAGE_COUNTER+port - 8, RTL8367C_FLOWCTRL_PORT_PAGE_COUNTER_MASK, pPageCount); ++} ++/* Function Name: ++ * rtl8367c_getAsicPortPage ++ * Description: ++ * Get per-port page max usage number ++ * Input: ++ * port - Physical port number (0~7) ++ * pPageCount - page usage number ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicPortPageMax(rtk_uint32 port, rtk_uint32 *pPageCount) ++{ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ if(port < 8) ++ return rtl8367c_getAsicRegBits(RTL8367C_FLOWCTRL_PORT_PAGE_MAX_REG(port), RTL8367C_FLOWCTRL_PORT_PAGE_MAX_MASK, pPageCount); ++ else ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_PORT0_PAGE_MAX+port-8, RTL8367C_FLOWCTRL_PORT_PAGE_MAX_MASK, pPageCount); ++ ++ ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicFlowControlEgressPortIndep ++ * Description: ++ * Set per-port egress flow control independent ++ * Input: ++ * port - Physical port number (0~7) ++ * enabled - Egress port flow control usage 1:enable 0:disable. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicFlowControlEgressPortIndep(rtk_uint32 port, rtk_uint32 enable) ++{ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_PORT0_MISC_CFG + (port *0x20), RTL8367C_PORT0_MISC_CFG_FLOWCTRL_INDEP_OFFSET,enable); ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicFlowControlEgressPortIndep ++ * Description: ++ * Get per-port egress flow control independent ++ * Input: ++ * port - Physical port number (0~7) ++ * enabled - Egress port flow control usage 1:enable 0:disable. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicFlowControlEgressPortIndep(rtk_uint32 port, rtk_uint32 *pEnable) ++{ ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_PORT0_MISC_CFG + (port *0x20),RTL8367C_PORT0_MISC_CFG_FLOWCTRL_INDEP_OFFSET,pEnable); ++} +diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_green.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_green.c +new file mode 100644 +index 000000000000..3fb5f57b914b +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_green.c +@@ -0,0 +1,445 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : Green Ethernet related functions ++ * ++ */ ++#include ++ ++/* Function Name: ++ * rtl8367c_getAsicGreenPortPage ++ * Description: ++ * Get per-Port ingress page usage per second ++ * Input: ++ * port - Physical port number (0~7) ++ * pPage - page number of ingress packet occurring per second ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * Ingress traffic occurring page number per second for high layer green feature usage ++ */ ++ret_t rtl8367c_getAsicGreenPortPage(rtk_uint32 port, rtk_uint32* pPage) ++{ ++ ret_t retVal; ++ rtk_uint32 regData; ++ rtk_uint32 pageMeter; ++ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ retVal = rtl8367c_getAsicReg(RTL8367C_PAGEMETER_PORT_REG(port), ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ pageMeter = regData; ++ ++ retVal = rtl8367c_getAsicReg(RTL8367C_PAGEMETER_PORT_REG(port) + 1, ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ pageMeter = pageMeter + (regData << 16); ++ ++ *pPage = pageMeter; ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_setAsicGreenTrafficType ++ * Description: ++ * Set traffic type for each priority ++ * Input: ++ * priority - internal priority (0~7) ++ * traffictype - high/low traffic type, 1:high priority traffic type, 0:low priority traffic type ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_QOS_INT_PRIORITY - Invalid priority ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicGreenTrafficType(rtk_uint32 priority, rtk_uint32 traffictype) ++{ ++ ++ if(priority > RTL8367C_PRIMAX) ++ return RT_ERR_QOS_INT_PRIORITY; ++ ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_HIGHPRI_CFG, priority, (traffictype?1:0)); ++} ++/* Function Name: ++ * rtl8367c_getAsicGreenTrafficType ++ * Description: ++ * Get traffic type for each priority ++ * Input: ++ * priority - internal priority (0~7) ++ * pTraffictype - high/low traffic type, 1:high priority traffic type, 0:low priority traffic type ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_QOS_INT_PRIORITY - Invalid priority ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicGreenTrafficType(rtk_uint32 priority, rtk_uint32* pTraffictype) ++{ ++ if(priority > RTL8367C_PRIMAX) ++ return RT_ERR_QOS_INT_PRIORITY; ++ ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_HIGHPRI_CFG, priority, pTraffictype); ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicGreenHighPriorityTraffic ++ * Description: ++ * Set indicator which ASIC had received high priority traffic ++ * Input: ++ * port - Physical port number (0~7) ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicGreenHighPriorityTraffic(rtk_uint32 port) ++{ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_HIGHPRI_INDICATOR, port, 1); ++} ++ ++ ++/* Function Name: ++ * rtl8367c_getAsicGreenHighPriorityTraffic ++ * Description: ++ * Get indicator which ASIC had received high priority traffic or not ++ * Input: ++ * port - Physical port number (0~7) ++ * pIndicator - Have received high priority traffic indicator. If 1 means ASCI had received high priority in 1second checking period ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicGreenHighPriorityTraffic(rtk_uint32 port, rtk_uint32* pIndicator) ++{ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_HIGHPRI_INDICATOR, port, pIndicator); ++} ++ ++/* ++@func rtk_int32 | rtl8367c_setAsicGreenEthernet | Set green Ethernet function. ++@parm rtk_uint32 | green | Green feature function usage 1:enable 0:disable. ++@rvalue RT_ERR_OK | Success. ++@rvalue RT_ERR_SMI | SMI access error. ++@comm ++ The API can set Green Ethernet function to reduce power consumption. While green feature is enabled, ASIC will automatic ++ detect the cable length and then select different power mode for best performance with minimums power consumption. Link down ++ ports will enter power saving mode in 10 seconds after the cable disconnected if power saving function is enabled. ++*/ ++ret_t rtl8367c_setAsicGreenEthernet(rtk_uint32 port, rtk_uint32 green) ++{ ++ ret_t retVal; ++ rtk_uint32 checkCounter; ++ rtk_uint32 regData; ++ rtk_uint32 phy_status; ++ rtk_uint32 patchData[6][2] = { {0x809A, 0x8911}, {0x80A3, 0x9233}, {0x80AC, 0xA444}, {0x809F, 0x6B20}, {0x80A8, 0x6B22}, {0x80B1, 0x6B23} }; ++ rtk_uint32 idx; ++ rtk_uint32 data; ++ ++ if (green > 1) ++ return RT_ERR_INPUT; ++ ++ /* 0xa420[2:0] */ ++ if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xA420, ®Data)) != RT_ERR_OK) ++ return retVal; ++ phy_status = (regData & 0x0007); ++ ++ if(phy_status == 3) ++ { ++ /* 0xb820[4] = 1 */ ++ if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xB820, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ regData |= (0x0001 << 4); ++ ++ if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xB820, regData)) != RT_ERR_OK) ++ return retVal; ++ ++ /* wait 0xb800[6] = 1 */ ++ checkCounter = 100; ++ while(checkCounter) ++ { ++ retVal = rtl8367c_getAsicPHYOCPReg(port, 0xB800, ®Data); ++ if( (retVal != RT_ERR_OK) || ((regData & 0x0040) != 0x0040) ) ++ { ++ checkCounter --; ++ if(0 == checkCounter) ++ return RT_ERR_BUSYWAIT_TIMEOUT; ++ } ++ else ++ checkCounter = 0; ++ } ++ } ++ ++ if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0249)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_getAsicReg(0x1300, &data)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0000)) != RT_ERR_OK) ++ return retVal; ++ ++ switch (data) ++ { ++ case 0x0276: ++ case 0x0597: ++ case 0x6367: ++ if(green) ++ { ++ for(idx = 0; idx < 6; idx++ ) ++ { ++ if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xA436, patchData[idx][0])) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xA438, patchData[idx][1])) != RT_ERR_OK) ++ return retVal; ++ } ++ } ++ break; ++ default: ++ break;; ++ } ++ ++ ++ ++ /* 0xa436 = 0x8011 */ ++ if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xA436, 0x8011)) != RT_ERR_OK) ++ return retVal; ++ ++ /* wr 0xa438[15] = 0: disable, 1: enable */ ++ if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xA438, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ if(green) ++ regData |= 0x8000; ++ else ++ regData &= 0x7FFF; ++ ++ if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xA438, regData)) != RT_ERR_OK) ++ return retVal; ++ ++ if(phy_status == 3) ++ { ++ /* 0xb820[4] = 0 */ ++ if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xB820, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ regData &= ~(0x0001 << 4); ++ ++ if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xB820, regData)) != RT_ERR_OK) ++ return retVal; ++ ++ /* wait 0xb800[6] = 0 */ ++ checkCounter = 100; ++ while(checkCounter) ++ { ++ retVal = rtl8367c_getAsicPHYOCPReg(port, 0xB800, ®Data); ++ if( (retVal != RT_ERR_OK) || ((regData & 0x0040) != 0x0000) ) ++ { ++ checkCounter --; ++ if(0 == checkCounter) ++ return RT_ERR_BUSYWAIT_TIMEOUT; ++ } ++ else ++ checkCounter = 0; ++ } ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* ++@func rtk_int32 | rtl8367c_getAsicGreenEthernet | Get green Ethernet function. ++@parm rtk_uint32 | *green | Green feature function usage 1:enable 0:disable. ++@rvalue RT_ERR_OK | Success. ++@rvalue RT_ERR_SMI | SMI access error. ++@comm ++ The API can set Green Ethernet function to reduce power consumption. While green feature is enabled, ASIC will automatic ++ detect the cable length and then select different power mode for best performance with minimums power consumption. Link down ++ ports will enter power saving mode in 10 seconds after the cable disconnected if power saving function is enabled. ++*/ ++ret_t rtl8367c_getAsicGreenEthernet(rtk_uint32 port, rtk_uint32* green) ++{ ++ ret_t retVal; ++ rtk_uint32 regData; ++ ++ /* 0xa436 = 0x8011 */ ++ if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xA436, 0x8011)) != RT_ERR_OK) ++ return retVal; ++ ++ /* wr 0xa438[15] = 0: disable, 1: enable */ ++ if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xA438, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ if(regData & 0x8000) ++ *green = ENABLED; ++ else ++ *green = DISABLED; ++ ++ return RT_ERR_OK; ++} ++ ++ ++/* ++@func ret_t | rtl8367c_setAsicPowerSaving | Set power saving mode ++@parm rtk_uint32 | phy | phy number ++@parm rtk_uint32 | enable | enable power saving mode. ++@rvalue RT_ERR_OK | Success. ++@rvalue RT_ERR_SMI | SMI access error. ++@rvalue RT_ERR_PORT_ID | Invalid port number. ++@comm ++ The API can set power saving mode per phy. ++*/ ++ret_t rtl8367c_setAsicPowerSaving(rtk_uint32 phy, rtk_uint32 enable) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 phyData; ++ rtk_uint32 regData; ++ rtk_uint32 phy_status; ++ rtk_uint32 checkCounter; ++ ++ if (enable > 1) ++ return RT_ERR_INPUT; ++ ++ /* 0xa420[2:0] */ ++ if((retVal = rtl8367c_getAsicPHYOCPReg(phy, 0xA420, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ phy_status = (regData & 0x0007); ++ ++ if(phy_status == 3) ++ { ++ /* 0xb820[4] = 1 */ ++ if((retVal = rtl8367c_getAsicPHYOCPReg(phy, 0xB820, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ regData |= (0x0001 << 4); ++ ++ if((retVal = rtl8367c_setAsicPHYOCPReg(phy, 0xB820, regData)) != RT_ERR_OK) ++ return retVal; ++ ++ /* wait 0xb800[6] = 1 */ ++ checkCounter = 100; ++ while(checkCounter) ++ { ++ retVal = rtl8367c_getAsicPHYOCPReg(phy, 0xB800, ®Data); ++ if( (retVal != RT_ERR_OK) || ((regData & 0x0040) != 0x0040) ) ++ { ++ checkCounter --; ++ if(0 == checkCounter) ++ { ++ return RT_ERR_BUSYWAIT_TIMEOUT; ++ } ++ } ++ else ++ checkCounter = 0; ++ } ++ } ++ ++ if ((retVal = rtl8367c_getAsicPHYReg(phy,PHY_POWERSAVING_REG,&phyData))!=RT_ERR_OK) ++ return retVal; ++ ++ phyData = phyData & ~(0x0001 << 2); ++ phyData = phyData | (enable << 2); ++ ++ if ((retVal = rtl8367c_setAsicPHYReg(phy,PHY_POWERSAVING_REG,phyData))!=RT_ERR_OK) ++ return retVal; ++ ++ if(phy_status == 3) ++ { ++ /* 0xb820[4] = 0 */ ++ if((retVal = rtl8367c_getAsicPHYOCPReg(phy, 0xB820, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ regData &= ~(0x0001 << 4); ++ ++ if((retVal = rtl8367c_setAsicPHYOCPReg(phy, 0xB820, regData)) != RT_ERR_OK) ++ return retVal; ++ ++ /* wait 0xb800[6] = 0 */ ++ checkCounter = 100; ++ while(checkCounter) ++ { ++ retVal = rtl8367c_getAsicPHYOCPReg(phy, 0xB800, ®Data); ++ if( (retVal != RT_ERR_OK) || ((regData & 0x0040) != 0x0000) ) ++ { ++ checkCounter --; ++ if(0 == checkCounter) ++ { ++ return RT_ERR_BUSYWAIT_TIMEOUT; ++ } ++ } ++ else ++ checkCounter = 0; ++ } ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* ++@func ret_t | rtl8367c_getAsicPowerSaving | Get power saving mode ++@parm rtk_uint32 | port | The port number ++@parm rtk_uint32* | enable | enable power saving mode. ++@rvalue RT_ERR_OK | Success. ++@rvalue RT_ERR_SMI | SMI access error. ++@rvalue RT_ERR_PORT_ID | Invalid port number. ++@comm ++ The API can get power saving mode per phy. ++*/ ++ret_t rtl8367c_getAsicPowerSaving(rtk_uint32 phy, rtk_uint32* enable) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 phyData; ++ ++ if(NULL == enable) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicPHYReg(phy,PHY_POWERSAVING_REG,&phyData))!=RT_ERR_OK) ++ return retVal; ++ ++ if ((phyData & 0x0004) > 0) ++ *enable = 1; ++ else ++ *enable = 0; ++ ++ return RT_ERR_OK; ++} ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_hsb.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_hsb.c +new file mode 100644 +index 000000000000..1b8ef59d9537 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_hsb.c +@@ -0,0 +1,81 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : Field selector related functions ++ * ++ */ ++#include ++/* Function Name: ++ * rtl8367c_setAsicFieldSelector ++ * Description: ++ * Set user defined field selectors in HSB ++ * Input: ++ * index - index of field selector 0-15 ++ * format - Format of field selector ++ * offset - Retrieving data offset ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - input parameter out of range ++ * Note: ++ * System support 16 user defined field selectors. ++ * Each selector can be enabled or disable. User can defined retrieving 16-bits in many predefiend ++ * standard l2/l3/l4 payload. ++ */ ++ret_t rtl8367c_setAsicFieldSelector(rtk_uint32 index, rtk_uint32 format, rtk_uint32 offset) ++{ ++ rtk_uint32 regData; ++ ++ if(index > RTL8367C_FIELDSEL_FORMAT_NUMBER) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ if(format >= FIELDSEL_FORMAT_END) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ regData = (((format << RTL8367C_FIELD_SELECTOR_FORMAT_OFFSET) & RTL8367C_FIELD_SELECTOR_FORMAT_MASK ) | ++ ((offset << RTL8367C_FIELD_SELECTOR_OFFSET_OFFSET) & RTL8367C_FIELD_SELECTOR_OFFSET_MASK )); ++ ++ return rtl8367c_setAsicReg(RTL8367C_FIELD_SELECTOR_REG(index), regData); ++} ++/* Function Name: ++ * rtl8367c_getAsicFieldSelector ++ * Description: ++ * Get user defined field selectors in HSB ++ * Input: ++ * index - index of field selector 0-15 ++ * pFormat - Format of field selector ++ * pOffset - Retrieving data offset ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicFieldSelector(rtk_uint32 index, rtk_uint32* pFormat, rtk_uint32* pOffset) ++{ ++ ret_t retVal; ++ rtk_uint32 regData; ++ ++ retVal = rtl8367c_getAsicReg(RTL8367C_FIELD_SELECTOR_REG(index), ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ *pFormat = ((regData & RTL8367C_FIELD_SELECTOR_FORMAT_MASK) >> RTL8367C_FIELD_SELECTOR_FORMAT_OFFSET); ++ *pOffset = ((regData & RTL8367C_FIELD_SELECTOR_OFFSET_MASK) >> RTL8367C_FIELD_SELECTOR_OFFSET_OFFSET); ++ ++ return RT_ERR_OK; ++} +diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_i2c.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_i2c.c +new file mode 100644 +index 000000000000..69f20a0188b5 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_i2c.c +@@ -0,0 +1,474 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 38651 $ ++ * $Date: 2016-02-27 14:32:56 +0800 (周三, 17 四月 2016) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : I2C related functions ++ * ++ */ ++ ++ ++#include ++#include ++#include ++ ++ ++ ++/* Function Name: ++ * rtl8367c_setAsicI2C_checkBusIdle ++ * Description: ++ * Check i2c bus status idle or not ++ * Input: ++ * None ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_BUSYWAIT_TIMEOUT - i2c bus is busy ++ * Note: ++ * This API can check i2c bus status. ++ */ ++ret_t rtl8367c_setAsicI2C_checkBusIdle(void) ++{ ++ rtk_uint32 regData; ++ ret_t retVal; ++ ++ if ((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_M_I2C_CTL_STA_REG, RTL8367C_M_I2C_BUS_IDLE_OFFSET, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ if(regData == 0x0001) ++ return RT_ERR_OK; /*i2c is idle*/ ++ else ++ return RT_ERR_BUSYWAIT_TIMEOUT; /*i2c is busy*/ ++} ++ ++ ++/* Function Name: ++ * rtl8367c_setAsicI2CStartCmd ++ * Description: ++ * Set I2C start command ++ * Input: ++ * None ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * Note: ++ * This API can set i2c start command ,start a i2c traffic . ++ */ ++ret_t rtl8367c_setAsicI2CStartCmd(void) ++{ ++ rtk_uint32 regData; ++ ret_t retVal; ++ ++ /* Bits [4-1] = 0b0000, Start Command; Bit [0] = 1, Trigger the Command */ ++ if ((retVal = rtl8367c_getAsicReg(RTL8367C_REG_M_I2C_CTL_STA_REG, ®Data)) != RT_ERR_OK) ++ return retVal; ++ regData &= 0xFFE0; ++ regData |= 0x0001; ++ ++ if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_M_I2C_CTL_STA_REG, regData)) != RT_ERR_OK) ++ return retVal; ++ ++ /* wait for command finished */ ++ do{ ++ if ((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_M_I2C_CTL_STA_REG, RTL8367C_I2C_CMD_EXEC_OFFSET, ®Data)) != RT_ERR_OK) ++ return retVal; ++ }while( regData != 0x0); ++ ++ return RT_ERR_OK ; ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicI2CStopCmd ++ * Description: ++ * Set I2C stop command ++ * Input: ++ * None ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * Note: ++ * This API can set i2c stop command ,stop a i2c traffic. ++ */ ++ret_t rtl8367c_setAsicI2CStopCmd(void) ++{ ++ ++ rtk_uint32 regData; ++ ret_t retVal; ++ ++ /* Bits [4-1] = 0b0001, Stop Command; Bit [0] = 1, Trigger the Command */ ++ if ((retVal = rtl8367c_getAsicReg(RTL8367C_REG_M_I2C_CTL_STA_REG, ®Data)) != RT_ERR_OK) ++ return retVal; ++ regData &= 0xFFE0; ++ regData |= 0x0003; ++ ++ if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_M_I2C_CTL_STA_REG, regData)) != RT_ERR_OK) ++ return retVal; ++ ++ ++ /* wait for command finished */ ++ do{ ++ if ((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_M_I2C_CTL_STA_REG, RTL8367C_I2C_CMD_EXEC_OFFSET, ®Data)) != RT_ERR_OK) ++ return retVal; ++ }while( regData != 0x0); ++ ++ return RT_ERR_OK ; ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicI2CTxOneCharCmd ++ * Description: ++ * Set I2C Tx a char command, with a 8-bit data ++ * Input: ++ * oneChar - 8-bit data ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * Note: ++ * This API can set i2c Tx command and with a 8-bit data. ++ */ ++ret_t rtl8367c_setAsicI2CTxOneCharCmd(rtk_uint8 oneChar) ++{ ++ rtk_uint32 regData; ++ ret_t retVal; ++ ++ /* Bits [4-1] = 0b0010, tx one char; Bit [0] = 1, Trigger the Command */ ++ if ((retVal = rtl8367c_getAsicReg(RTL8367C_REG_M_I2C_CTL_STA_REG, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ regData &= 0xFFE0; ++ regData |= 0x0005; ++ regData &= 0x00FF; ++ regData |= (rtk_uint16) (oneChar << 8); ++ ++ if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_M_I2C_CTL_STA_REG, regData)) != RT_ERR_OK) ++ return retVal; ++ ++ ++ /* wait for command finished */ ++ do{ ++ if ((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_M_I2C_CTL_STA_REG, RTL8367C_I2C_CMD_EXEC_OFFSET, ®Data)) != RT_ERR_OK) ++ return retVal; ++ }while( regData != 0x0); ++ ++ return RT_ERR_OK ; ++} ++ ++ ++/* Function Name: ++ * rtl8367c_setAsicI2CcheckRxAck ++ * Description: ++ * Check if rx an Ack ++ * Input: ++ * None ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * Note: ++ * This API can check if rx an ack from i2c slave. ++ */ ++ret_t rtl8367c_setAsicI2CcheckRxAck(void) ++{ ++ rtk_uint32 regData; ++ ret_t retVal; ++ rtk_uint32 count = 0; ++ ++ do{ ++ count++; ++ if ((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_M_I2C_CTL_STA_REG, RTL8367C_SLV_ACK_FLAG_OFFSET, ®Data)) != RT_ERR_OK) ++ return retVal; ++ }while( (regData != 0x1) && (count < TIMEROUT_FOR_MICROSEMI) ); ++ ++ if(regData != 0x1) ++ return RT_ERR_FAILED; ++ else ++ return RT_ERR_OK; ++} ++ ++ ++/* Function Name: ++ * rtl8367c_setAsicI2CRxOneCharCmd ++ * Description: ++ * Set I2C Rx command and get 8-bit data ++ * Input: ++ * None ++ * Output: ++ * pValue - 8bit-data ++ * Return: ++ * RT_ERR_OK - Success ++ * Note: ++ * This API can set I2C Rx command and get 8-bit data. ++ */ ++ret_t rtl8367c_setAsicI2CRxOneCharCmd(rtk_uint8 *pValue) ++{ ++ rtk_uint32 regData; ++ ret_t retVal; ++ ++ /* Bits [4-1] = 0b0011, Rx one char; Bit [0] = 1, Trigger the Command */ ++ if ((retVal = rtl8367c_getAsicReg(RTL8367C_REG_M_I2C_CTL_STA_REG, ®Data)) != RT_ERR_OK) ++ return retVal; ++ regData &= 0xFFE0; ++ regData |= 0x0007; ++ if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_M_I2C_CTL_STA_REG, regData)) != RT_ERR_OK) ++ return retVal; ++ ++ /* wait for command finished */ ++ do{ ++ if ((retVal = rtl8367c_getAsicReg(RTL8367C_REG_M_I2C_CTL_STA_REG, ®Data)) != RT_ERR_OK) ++ return retVal; ++ }while( (regData & 0x1) != 0x0); ++ ++ *pValue = (rtk_uint8)(regData >> 8); ++ return RT_ERR_OK ; ++ ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicI2CTxAckCmd ++ * Description: ++ * Set I2C Tx ACK command ++ * Input: ++ * None ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * Note: ++ * This API can set I2C Tx ack command. ++ */ ++ret_t rtl8367c_setAsicI2CTxAckCmd(void) ++{ ++ rtk_uint32 regData; ++ ret_t retVal; ++ ++ /* Bits [4-1] = 0b0100, tx ACK Command; Bit [0] = 1, Trigger the Command */ ++ if ((retVal = rtl8367c_getAsicReg(RTL8367C_REG_M_I2C_CTL_STA_REG, ®Data)) != RT_ERR_OK) ++ return retVal; ++ regData &= 0xFFE0; ++ regData |= 0x0009; ++ if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_M_I2C_CTL_STA_REG, regData)) != RT_ERR_OK) ++ return retVal; ++ ++ /* wait for command finished */ ++ do{ ++ if ((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_M_I2C_CTL_STA_REG, RTL8367C_I2C_CMD_EXEC_OFFSET, ®Data)) != RT_ERR_OK) ++ return retVal; ++ }while( regData != 0x0); ++ ++ return RT_ERR_OK ; ++ ++} ++ ++ ++/* Function Name: ++ * rtl8367c_setAsicI2CTxNoAckCmd ++ * Description: ++ * Set I2C master Tx noACK command ++ * Input: ++ * None ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * Note: ++ * This API can set I2C master Tx noACK command. ++ */ ++ret_t rtl8367c_setAsicI2CTxNoAckCmd(void) ++{ ++ rtk_uint32 regData; ++ ret_t retVal; ++ ++ /* Bits [4-1] = 0b0101, tx noACK Command; Bit [0] = 1, Trigger the Command */ ++ if ((retVal = rtl8367c_getAsicReg(RTL8367C_REG_M_I2C_CTL_STA_REG, ®Data)) != RT_ERR_OK) ++ return retVal; ++ regData &= 0xFFE0; ++ regData |= 0x000b; ++ if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_M_I2C_CTL_STA_REG, regData)) != RT_ERR_OK) ++ return retVal; ++ ++ /* wait for command finished */ ++ do{ ++ if ((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_M_I2C_CTL_STA_REG, RTL8367C_I2C_CMD_EXEC_OFFSET, ®Data)) != RT_ERR_OK) ++ return retVal; ++ }while( regData != 0x0); ++ ++ return RT_ERR_OK ; ++ ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicI2CSoftRSTseqCmd ++ * Description: ++ * set I2C master tx soft reset command ++ * Input: ++ * None ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * Note: ++ * This API can set I2C master tx soft reset command. ++ */ ++ret_t rtl8367c_setAsicI2CSoftRSTseqCmd(void) ++{ ++ ++ rtk_uint32 regData; ++ ret_t retVal; ++ ++ /*Bits [4-1] = 0b0110, tx soft reset Command; Bit [0] = 1, Trigger the Command */ ++ if ((retVal = rtl8367c_getAsicReg(RTL8367C_REG_M_I2C_CTL_STA_REG, ®Data)) != RT_ERR_OK) ++ return retVal; ++ regData &= 0xFFE0; ++ regData |= 0x000d; ++ ++ if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_M_I2C_CTL_STA_REG, regData)) != RT_ERR_OK) ++ return retVal; ++ ++ ++ /* wait for command finished */ ++ do{ ++ if ((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_M_I2C_CTL_STA_REG, RTL8367C_I2C_CMD_EXEC_OFFSET, ®Data)) != RT_ERR_OK) ++ return retVal; ++ }while( regData != 0x0); ++ ++ return RT_ERR_OK ; ++} ++ ++ ++/* Function Name: ++ * rtl8367c_setAsicI2CGpioPinGroup ++ * Description: ++ * set I2C function used gpio pins ++ * Input: ++ * pinGroup_ID - gpio pins group ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_INPUT _ Invalid input parameter ++ * Note: ++ * This API can set I2C function used gpio pins. ++ * There are three group gpio pins ++ */ ++ret_t rtl8367c_setAsicI2CGpioPinGroup(rtk_uint32 pinGroup_ID) ++{ ++ rtk_uint32 regData; ++ ret_t retVal; ++ ++ if ((retVal = rtl8367c_getAsicReg(RTL8367C_REG_M_I2C_SYS_CTL, ®Data)) != RT_ERR_OK) ++ return retVal; ++ if( pinGroup_ID==0 ) ++ { ++ regData &= 0x0FFF; ++ regData |= 0x5000; ++ ++ if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_M_I2C_SYS_CTL, regData)) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ else if( pinGroup_ID==1 ) ++ { ++ regData &= 0x0FFF; ++ regData |= 0xA000; ++ ++ if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_M_I2C_SYS_CTL, regData)) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ else if( pinGroup_ID==2 ) ++ { ++ regData &= 0x0FFF; ++ regData |= 0xF000; ++ ++ if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_M_I2C_SYS_CTL, regData)) != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ return RT_ERR_INPUT; ++ ++ return RT_ERR_OK ; ++ ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicI2CGpioPinGroup ++ * Description: ++ * set I2C function used gpio pins ++ * Input: ++ * pinGroup_ID - gpio pins group ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_INPUT _ Invalid input parameter ++ * Note: ++ * This API can set I2C function used gpio pins. ++ * There are three group gpio pins ++ */ ++ret_t rtl8367c_getAsicI2CGpioPinGroup(rtk_uint32 * pPinGroup_ID) ++{ ++ ++ rtk_uint32 regData; ++ ret_t retVal; ++ if( (retVal = rtl8367c_getAsicReg(RTL8367C_REG_M_I2C_SYS_CTL, ®Data)) != RT_ERR_OK) ++ return retVal; ++ regData &= 0xF000 ; ++ regData = (regData >> 12); ++ ++ if( regData == 0x5 ) ++ *pPinGroup_ID = 0; ++ else if(regData == 0xA) ++ *pPinGroup_ID = 1; ++ else if(regData == 0xF) ++ *pPinGroup_ID = 2; ++ else ++ return RT_ERR_FAILED; ++ return RT_ERR_OK ; ++} ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_igmp.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_igmp.c +new file mode 100644 +index 000000000000..c915d2d61878 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_igmp.c +@@ -0,0 +1,2109 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : IGMP related functions ++ * ++ */ ++#include ++/* Function Name: ++ * rtl8367c_setAsicIgmp ++ * Description: ++ * Set IGMP/MLD state ++ * Input: ++ * enabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicIgmp(rtk_uint32 enabled) ++{ ++ ret_t retVal; ++ ++ /* Enable/Disable H/W IGMP/MLD */ ++ retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_IGMP_MLD_EN_OFFSET, enabled); ++ ++ return retVal; ++} ++/* Function Name: ++ * rtl8367c_getAsicIgmp ++ * Description: ++ * Get IGMP/MLD state ++ * Input: ++ * enabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicIgmp(rtk_uint32 *ptr_enabled) ++{ ++ ret_t retVal; ++ ++ retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_IGMP_MLD_EN_OFFSET, ptr_enabled); ++ return retVal; ++} ++/* Function Name: ++ * rtl8367c_setAsicIpMulticastVlanLeaky ++ * Description: ++ * Set IP multicast VLAN Leaky function ++ * Input: ++ * port - Physical port number (0~7) ++ * enabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * When enabling this function, ++ * if the lookup result(forwarding portmap) of IP Multicast packet is over VLAN boundary, ++ * the packet can be forwarded across VLAN ++ */ ++ret_t rtl8367c_setAsicIpMulticastVlanLeaky(rtk_uint32 port, rtk_uint32 enabled) ++{ ++ ret_t retVal; ++ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_IPMCAST_VLAN_LEAKY, port, enabled); ++ ++ return retVal; ++} ++/* Function Name: ++ * rtl8367c_getAsicIpMulticastVlanLeaky ++ * Description: ++ * Get IP multicast VLAN Leaky function ++ * Input: ++ * port - Physical port number (0~7) ++ * enabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicIpMulticastVlanLeaky(rtk_uint32 port, rtk_uint32 *ptr_enabled) ++{ ++ ret_t retVal; ++ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_IPMCAST_VLAN_LEAKY, port, ptr_enabled); ++ ++ return retVal; ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicIGMPTableFullOP ++ * Description: ++ * Set Table Full operation ++ * Input: ++ * operation - The operation should be taken when the IGMP table is full. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - input parameter is out of range ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicIGMPTableFullOP(rtk_uint32 operation) ++{ ++ ret_t retVal; ++ ++ if(operation >= TABLE_FULL_OP_END) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ /* Table full Operation */ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_MLD_CFG1, RTL8367C_TABLE_FULL_OP_MASK, operation); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicIGMPTableFullOP ++ * Description: ++ * Get Table Full operation ++ * Input: ++ * None ++ * Output: ++ * poperation - The operation should be taken when the IGMP table is full. ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicIGMPTableFullOP(rtk_uint32 *poperation) ++{ ++ ret_t retVal; ++ rtk_uint32 value; ++ ++ /* Table full Operation */ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_MLD_CFG1, RTL8367C_TABLE_FULL_OP_MASK, &value); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ *poperation = value; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicIGMPCRCErrOP ++ * Description: ++ * Set the operation when ASIC receive a Checksum error packet ++ * Input: ++ * operation -The operation when ASIC receive a Checksum error packet ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - input parameter is out of range ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicIGMPCRCErrOP(rtk_uint32 operation) ++{ ++ ret_t retVal; ++ ++ if(operation >= CRC_ERR_OP_END) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ /* CRC Error Operation */ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_CKS_ERR_OP_MASK, operation); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicIGMPCRCErrOP ++ * Description: ++ * Get the operation when ASIC receive a Checksum error packet ++ * Input: ++ * None ++ * Output: ++ * poperation - The operation of Checksum error packet ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicIGMPCRCErrOP(rtk_uint32 *poperation) ++{ ++ ret_t retVal; ++ rtk_uint32 value; ++ ++ /* CRC Error Operation */ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_CKS_ERR_OP_MASK, &value); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ *poperation = value; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicIGMPFastLeaveEn ++ * Description: ++ * Enable/Disable Fast Leave ++ * Input: ++ * enabled - 1:enable Fast Leave; 0:disable Fast Leave ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicIGMPFastLeaveEn(rtk_uint32 enabled) ++{ ++ ret_t retVal; ++ ++ /* Fast Leave */ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_FAST_LEAVE_EN_MASK, (enabled >= 1) ? 1 : 0); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicIGMPFastLeaveEn ++ * Description: ++ * Get Fast Leave state ++ * Input: ++ * None ++ * Output: ++ * penabled - 1:enable Fast Leave; 0:disable Fast Leave ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicIGMPFastLeaveEn(rtk_uint32 *penabled) ++{ ++ ret_t retVal; ++ rtk_uint32 value; ++ ++ /* Fast Leave */ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_FAST_LEAVE_EN_MASK, &value); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ *penabled = value; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicIGMPLeaveTimer ++ * Description: ++ * Set the Leave timer of IGMP/MLD ++ * Input: ++ * leave_timer - Leave timer ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - input parameter is out of range ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicIGMPLeaveTimer(rtk_uint32 leave_timer) ++{ ++ ret_t retVal; ++ ++ if(leave_timer > RTL8367C_MAX_LEAVE_TIMER) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ /* Leave timer */ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_LEAVE_TIMER_MASK, leave_timer); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicIGMPLeaveTimer ++ * Description: ++ * Get the Leave timer of IGMP/MLD ++ * Input: ++ * None ++ * Output: ++ * pleave_timer - Leave timer ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicIGMPLeaveTimer(rtk_uint32 *pleave_timer) ++{ ++ ret_t retVal; ++ rtk_uint32 value; ++ ++ /* Leave timer */ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_LEAVE_TIMER_MASK, &value); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ *pleave_timer = value; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicIGMPQueryInterval ++ * Description: ++ * Set Query Interval of IGMP/MLD ++ * Input: ++ * interval - Query Interval ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - input parameter is out of range ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicIGMPQueryInterval(rtk_uint32 interval) ++{ ++ ret_t retVal; ++ ++ if(interval > RTL8367C_MAX_QUERY_INT) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ /* Query Interval */ ++ retVal = rtl8367c_setAsicReg(RTL8367C_REG_IGMP_MLD_CFG2, interval); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicIGMPQueryInterval ++ * Description: ++ * Get Query Interval of IGMP/MLD ++ * Input: ++ * None ++ * Output: ++ * pinterval - Query Interval ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicIGMPQueryInterval(rtk_uint32 *pinterval) ++{ ++ ret_t retVal; ++ rtk_uint32 value; ++ ++ /* Query Interval */ ++ retVal = rtl8367c_getAsicReg(RTL8367C_REG_IGMP_MLD_CFG2, &value); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ *pinterval = value; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicIGMPRobVar ++ * Description: ++ * Set Robustness Variable of IGMP/MLD ++ * Input: ++ * rob_var - Robustness Variable ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - input parameter is out of range ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicIGMPRobVar(rtk_uint32 rob_var) ++{ ++ ret_t retVal; ++ ++ if(rob_var > RTL8367C_MAX_ROB_VAR) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ /* Robustness variable */ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_ROBUSTNESS_VAR_MASK, rob_var); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicIGMPRobVar ++ * Description: ++ * Get Robustness Variable of IGMP/MLD ++ * Input: ++ * none ++ * Output: ++ * prob_var - Robustness Variable ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicIGMPRobVar(rtk_uint32 *prob_var) ++{ ++ ret_t retVal; ++ rtk_uint32 value; ++ ++ /* Robustness variable */ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_ROBUSTNESS_VAR_MASK, &value); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ *prob_var = value; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicIGMPStaticRouterPort ++ * Description: ++ * Set IGMP static router port mask ++ * Input: ++ * pmsk - Static portmask ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_MASK - Invalid port mask ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicIGMPStaticRouterPort(rtk_uint32 pmsk) ++{ ++ if(pmsk > RTL8367C_PORTMASK) ++ return RT_ERR_PORT_MASK; ++ ++ return rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_STATIC_ROUTER_PORT, RTL8367C_IGMP_STATIC_ROUTER_PORT_MASK, pmsk); ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicIGMPStaticRouterPort ++ * Description: ++ * Get IGMP static router port mask ++ * Input: ++ * pmsk - Static portmask ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicIGMPStaticRouterPort(rtk_uint32 *pmsk) ++{ ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_STATIC_ROUTER_PORT, RTL8367C_IGMP_STATIC_ROUTER_PORT_MASK, pmsk); ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicIGMPAllowDynamicRouterPort ++ * Description: ++ * Set IGMP dynamic router port allow mask ++ * Input: ++ * pmsk - Allow dynamic router port mask ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_MASK - Invalid port mask ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicIGMPAllowDynamicRouterPort(rtk_uint32 pmsk) ++{ ++ return rtl8367c_setAsicReg(RTL8367C_REG_IGMP_MLD_CFG4, pmsk); ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicIGMPAllowDynamicRouterPort ++ * Description: ++ * Get IGMP dynamic router port allow mask ++ * Input: ++ * None. ++ * Output: ++ * pPmsk - Allow dynamic router port mask ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_MASK - Invalid port mask ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicIGMPAllowDynamicRouterPort(rtk_uint32 *pPmsk) ++{ ++ return rtl8367c_getAsicReg(RTL8367C_REG_IGMP_MLD_CFG4, pPmsk); ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicIGMPdynamicRouterPort1 ++ * Description: ++ * Get 1st dynamic router port and timer ++ * Input: ++ * port - Physical port number (0~7) ++ * timer - router port timer ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicIGMPdynamicRouterPort1(rtk_uint32 *port, rtk_uint32 *timer) ++{ ++ ret_t retVal; ++ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_DYNAMIC_ROUTER_PORT, RTL8367C_D_ROUTER_PORT_1_MASK, port); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_DYNAMIC_ROUTER_PORT, RTL8367C_D_ROUTER_PORT_TMR_1_MASK, timer); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicIGMPdynamicRouterPort2 ++ * Description: ++ * Get 2nd dynamic router port and timer ++ * Input: ++ * port - Physical port number (0~7) ++ * timer - router port timer ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicIGMPdynamicRouterPort2(rtk_uint32 *port, rtk_uint32 *timer) ++{ ++ ret_t retVal; ++ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_DYNAMIC_ROUTER_PORT, RTL8367C_D_ROUTER_PORT_2_MASK, port); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_DYNAMIC_ROUTER_PORT, RTL8367C_D_ROUTER_PORT_TMR_2_MASK, timer); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicIGMPSuppression ++ * Description: ++ * Set the suppression function ++ * Input: ++ * report_supp_enabled - Report suppression, 1:Enable, 0:disable ++ * leave_supp_enabled - Leave suppression, 1:Enable, 0:disable ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicIGMPSuppression(rtk_uint32 report_supp_enabled, rtk_uint32 leave_supp_enabled) ++{ ++ ret_t retVal; ++ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_REPORT_SUPPRESSION_MASK, report_supp_enabled); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_LEAVE_SUPPRESSION_MASK, leave_supp_enabled); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicIGMPSuppression ++ * Description: ++ * Get the suppression function ++ * Input: ++ * report_supp_enabled - Report suppression, 1:Enable, 0:disable ++ * leave_supp_enabled - Leave suppression, 1:Enable, 0:disable ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicIGMPSuppression(rtk_uint32 *report_supp_enabled, rtk_uint32 *leave_supp_enabled) ++{ ++ ret_t retVal; ++ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_REPORT_SUPPRESSION_MASK, report_supp_enabled); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_LEAVE_SUPPRESSION_MASK, leave_supp_enabled); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicIGMPQueryRX ++ * Description: ++ * Set port-based Query packet RX allowance ++ * Input: ++ * port - port number ++ * allow_query - allowance of Query packet RX, 1:Allow, 0:Drop ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_PORT_ID - Error PORT ID ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicIGMPQueryRX(rtk_uint32 port, rtk_uint32 allow_query) ++{ ++ ret_t retVal; ++ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ /* Allow Query */ ++ if (port < 8) ++ { ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_QUERY_MASK, allow_query); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ { ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_QUERY_MASK, allow_query); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicIGMPQueryRX ++ * Description: ++ * Get port-based Query packet RX allowance ++ * Input: ++ * port - port number ++ * Output: ++ * allow_query - allowance of Query packet RX, 1:Allow, 0:Drop ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_PORT_ID - Error PORT ID ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicIGMPQueryRX(rtk_uint32 port, rtk_uint32 *allow_query) ++{ ++ ret_t retVal; ++ rtk_uint32 value; ++ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ /* Allow Query */ ++ if (port < 8) ++ { ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_QUERY_MASK, &value); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ { ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_QUERY_MASK, &value); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ *allow_query = value; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicIGMPReportRX ++ * Description: ++ * Set port-based Report packet RX allowance ++ * Input: ++ * port - port number ++ * allow_report - allowance of Report packet RX, 1:Allow, 0:Drop ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_PORT_ID - Error PORT ID ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicIGMPReportRX(rtk_uint32 port, rtk_uint32 allow_report) ++{ ++ ret_t retVal; ++ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ if(port < 8) ++ { ++ /* Allow Report */ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_REPORT_MASK, allow_report); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ { ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_REPORT_MASK, allow_report); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicIGMPReportRX ++ * Description: ++ * Get port-based Report packet RX allowance ++ * Input: ++ * port - port number ++ * Output: ++ * allow_report - allowance of Report packet RX, 1:Allow, 0:Drop ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_PORT_ID - Error PORT ID ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicIGMPReportRX(rtk_uint32 port, rtk_uint32 *allow_report) ++{ ++ ret_t retVal; ++ rtk_uint32 value; ++ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ if(port < 8) ++ { ++ /* Allow Report */ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_REPORT_MASK, &value); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ { ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_REPORT_MASK, &value); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ *allow_report = value; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicIGMPLeaveRX ++ * Description: ++ * Set port-based Leave packet RX allowance ++ * Input: ++ * port - port number ++ * allow_leave - allowance of Leave packet RX, 1:Allow, 0:Drop ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_PORT_ID - Error PORT ID ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicIGMPLeaveRX(rtk_uint32 port, rtk_uint32 allow_leave) ++{ ++ ret_t retVal; ++ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ if(port < 8) ++ { ++ /* Allow Leave */ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_LEAVE_MASK, allow_leave); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ { ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_LEAVE_MASK, allow_leave); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicIGMPLeaveRX ++ * Description: ++ * Get port-based Leave packet RX allowance ++ * Input: ++ * port - port number ++ * Output: ++ * allow_leave - allowance of Leave packet RX, 1:Allow, 0:Drop ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_PORT_ID - Error PORT ID ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicIGMPLeaveRX(rtk_uint32 port, rtk_uint32 *allow_leave) ++{ ++ ret_t retVal; ++ rtk_uint32 value; ++ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ if(port < 8) ++ { ++ /* Allow Leave */ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_LEAVE_MASK, &value); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ { ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_LEAVE_MASK, &value); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ ++ *allow_leave = value; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicIGMPMRPRX ++ * Description: ++ * Set port-based Multicast Routing Protocol packet RX allowance ++ * Input: ++ * port - port number ++ * allow_mrp - allowance of Multicast Routing Protocol packet RX, 1:Allow, 0:Drop ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_PORT_ID - Error PORT ID ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicIGMPMRPRX(rtk_uint32 port, rtk_uint32 allow_mrp) ++{ ++ ret_t retVal; ++ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ if(port < 8) ++ { ++ /* Allow Multicast Routing Protocol */ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_MRP_MASK, allow_mrp); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ { ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_MRP_MASK, allow_mrp); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicIGMPMRPRX ++ * Description: ++ * Get port-based Multicast Routing Protocol packet RX allowance ++ * Input: ++ * port - port number ++ * Output: ++ * allow_mrp - allowance of Multicast Routing Protocol packet RX, 1:Allow, 0:Drop ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_PORT_ID - Error PORT ID ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicIGMPMRPRX(rtk_uint32 port, rtk_uint32 *allow_mrp) ++{ ++ ret_t retVal; ++ rtk_uint32 value; ++ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ /* Allow Multicast Routing Protocol */ ++ if(port < 8) ++ { ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_MRP_MASK, &value); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ { ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_MRP_MASK, &value); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ *allow_mrp = value; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicIGMPMcDataRX ++ * Description: ++ * Set port-based Multicast data packet RX allowance ++ * Input: ++ * port - port number ++ * allow_mcdata - allowance of Multicast data packet RX, 1:Allow, 0:Drop ++ * Output: ++ * none ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_PORT_ID - Error PORT ID ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicIGMPMcDataRX(rtk_uint32 port, rtk_uint32 allow_mcdata) ++{ ++ ret_t retVal; ++ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ /* Allow Multicast Data */ ++ if(port < 8) ++ { ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_MC_DATA_MASK, allow_mcdata); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ { ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_MC_DATA_MASK, allow_mcdata); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicIGMPMcDataRX ++ * Description: ++ * Get port-based Multicast data packet RX allowance ++ * Input: ++ * port - port number ++ * Output: ++ * allow_mcdata - allowance of Multicast data packet RX, 1:Allow, 0:Drop ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_PORT_ID - Error PORT ID ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicIGMPMcDataRX(rtk_uint32 port, rtk_uint32 *allow_mcdata) ++{ ++ ret_t retVal; ++ rtk_uint32 value; ++ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ /* Allow Multicast data */ ++ if(port < 8) ++ { ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_MC_DATA_MASK, &value); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ { ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_MC_DATA_MASK, &value); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ ++ *allow_mcdata = value; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicIGMPv1Opeartion ++ * Description: ++ * Set port-based IGMPv1 Control packet action ++ * Input: ++ * port - port number ++ * igmpv1_op - IGMPv1 control packet action ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_PORT_ID - Error PORT ID ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicIGMPv1Opeartion(rtk_uint32 port, rtk_uint32 igmpv1_op) ++{ ++ ret_t retVal; ++ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ if(igmpv1_op >= PROTOCOL_OP_END) ++ return RT_ERR_INPUT; ++ ++ /* IGMPv1 operation */ ++ if(port < 8) ++ { ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_IGMPV1_OP_MASK, igmpv1_op); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ { ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_IGMPV1_OP_MASK, igmpv1_op); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicIGMPv1Opeartion ++ * Description: ++ * Get port-based IGMPv1 Control packet action ++ * Input: ++ * port - port number ++ * Output: ++ * igmpv1_op - IGMPv1 control packet action ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_PORT_ID - Error PORT ID ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicIGMPv1Opeartion(rtk_uint32 port, rtk_uint32 *igmpv1_op) ++{ ++ ret_t retVal; ++ rtk_uint32 value; ++ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ /* IGMPv1 operation */ ++ if(port < 8) ++ { ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_IGMPV1_OP_MASK, &value); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ { ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_IGMPV1_OP_MASK, &value); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ ++ *igmpv1_op = value; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicIGMPv2Opeartion ++ * Description: ++ * Set port-based IGMPv2 Control packet action ++ * Input: ++ * port - port number ++ * igmpv2_op - IGMPv2 control packet action ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_PORT_ID - Error PORT ID ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicIGMPv2Opeartion(rtk_uint32 port, rtk_uint32 igmpv2_op) ++{ ++ ret_t retVal; ++ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ if(igmpv2_op >= PROTOCOL_OP_END) ++ return RT_ERR_INPUT; ++ ++ /* IGMPv2 operation */ ++ if(port < 8) ++ { ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_IGMPV2_OP_MASK, igmpv2_op); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ { ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_IGMPV2_OP_MASK, igmpv2_op); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicIGMPv2Opeartion ++ * Description: ++ * Get port-based IGMPv2 Control packet action ++ * Input: ++ * port - port number ++ * Output: ++ * igmpv2_op - IGMPv2 control packet action ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_PORT_ID - Error PORT ID ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicIGMPv2Opeartion(rtk_uint32 port, rtk_uint32 *igmpv2_op) ++{ ++ ret_t retVal; ++ rtk_uint32 value; ++ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ /* IGMPv2 operation */ ++ if(port < 8) ++ { ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_IGMPV2_OP_MASK, &value); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ { ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_IGMPV2_OP_MASK, &value); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ ++ *igmpv2_op = value; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicIGMPv3Opeartion ++ * Description: ++ * Set port-based IGMPv3 Control packet action ++ * Input: ++ * port - port number ++ * igmpv3_op - IGMPv3 control packet action ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_PORT_ID - Error PORT ID ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicIGMPv3Opeartion(rtk_uint32 port, rtk_uint32 igmpv3_op) ++{ ++ ret_t retVal; ++ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ if(igmpv3_op >= PROTOCOL_OP_END) ++ return RT_ERR_INPUT; ++ ++ /* IGMPv3 operation */ ++ if(port < 8) ++ { ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_IGMPV3_OP_MASK, igmpv3_op); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ { ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_IGMPV3_OP_MASK, igmpv3_op); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicIGMPv3Opeartion ++ * Description: ++ * Get port-based IGMPv3 Control packet action ++ * Input: ++ * port - port number ++ * Output: ++ * igmpv3_op - IGMPv3 control packet action ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_PORT_ID - Error PORT ID ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicIGMPv3Opeartion(rtk_uint32 port, rtk_uint32 *igmpv3_op) ++{ ++ ret_t retVal; ++ rtk_uint32 value; ++ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ /* IGMPv3 operation */ ++ if(port < 8) ++ { ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_IGMPV3_OP_MASK, &value); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ { ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_IGMPV3_OP_MASK, &value); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ ++ *igmpv3_op = value; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicMLDv1Opeartion ++ * Description: ++ * Set port-based MLDv1 Control packet action ++ * Input: ++ * port - port number ++ * mldv1_op - MLDv1 control packet action ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_PORT_ID - Error PORT ID ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicMLDv1Opeartion(rtk_uint32 port, rtk_uint32 mldv1_op) ++{ ++ ret_t retVal; ++ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ if(mldv1_op >= PROTOCOL_OP_END) ++ return RT_ERR_INPUT; ++ ++ /* MLDv1 operation */ ++ if(port < 8) ++ { ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_MLDv1_OP_MASK, mldv1_op); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ { ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_MLDv1_OP_MASK, mldv1_op); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicMLDv1Opeartion ++ * Description: ++ * Get port-based MLDv1 Control packet action ++ * Input: ++ * port - port number ++ * Output: ++ * mldv1_op - MLDv1 control packet action ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_PORT_ID - Error PORT ID ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicMLDv1Opeartion(rtk_uint32 port, rtk_uint32 *mldv1_op) ++{ ++ ret_t retVal; ++ rtk_uint32 value; ++ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ /* MLDv1 operation */ ++ if(port < 8) ++ { ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_MLDv1_OP_MASK, &value); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ { ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_MLDv1_OP_MASK, &value); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ ++ *mldv1_op = value; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicMLDv2Opeartion ++ * Description: ++ * Set port-based MLDv2 Control packet action ++ * Input: ++ * port - port number ++ * mldv2_op - MLDv2 control packet action ++ * Output: ++ * none ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_PORT_ID - Error PORT ID ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicMLDv2Opeartion(rtk_uint32 port, rtk_uint32 mldv2_op) ++{ ++ ret_t retVal; ++ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ if(mldv2_op >= PROTOCOL_OP_END) ++ return RT_ERR_INPUT; ++ ++ /* MLDv2 operation */ ++ if(port < 8) ++ { ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_MLDv2_OP_MASK, mldv2_op); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ { ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_MLDv2_OP_MASK, mldv2_op); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicMLDv2Opeartion ++ * Description: ++ * Get port-based MLDv2 Control packet action ++ * Input: ++ * port - port number ++ * Output: ++ * mldv2_op - MLDv2 control packet action ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_PORT_ID - Error PORT ID ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicMLDv2Opeartion(rtk_uint32 port, rtk_uint32 *mldv2_op) ++{ ++ ret_t retVal; ++ rtk_uint32 value; ++ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ /* MLDv2 operation */ ++ if(port < 8) ++ { ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_MLDv2_OP_MASK, &value); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ { ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_MLDv2_OP_MASK, &value); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ ++ *mldv2_op = value; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicIGMPPortMAXGroup ++ * Description: ++ * Set per-port Max group number ++ * Input: ++ * port - Physical port number (0~7) ++ * max_group - max IGMP group ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * RT_ERR_OUT_OF_RANGE - input parameter out of range ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicIGMPPortMAXGroup(rtk_uint32 port, rtk_uint32 max_group) ++{ ++ ret_t retVal; ++ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ if(max_group > RTL8367C_IGMP_MAX_GOUP) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ if(port < 8) ++ { ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT01_MAX_GROUP + (port/2), RTL8367C_PORT0_MAX_GROUP_MASK << (RTL8367C_PORT1_MAX_GROUP_OFFSET * (port%2)), max_group); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ { ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT89_MAX_GROUP + (port/2), RTL8367C_PORT0_MAX_GROUP_MASK << (RTL8367C_PORT1_MAX_GROUP_OFFSET * (port%2)), max_group); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_getAsicIGMPPortMAXGroup ++ * Description: ++ * Get per-port Max group number ++ * Input: ++ * port - Physical port number (0~7) ++ * max_group - max IGMP group ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicIGMPPortMAXGroup(rtk_uint32 port, rtk_uint32 *max_group) ++{ ++ ret_t retVal; ++ rtk_uint32 value; ++ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ if(port < 8) ++ { ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT01_MAX_GROUP + (port/2), RTL8367C_PORT0_MAX_GROUP_MASK << (RTL8367C_PORT1_MAX_GROUP_OFFSET * (port%2)), &value); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ { ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT89_MAX_GROUP + (port/2), RTL8367C_PORT0_MAX_GROUP_MASK << (RTL8367C_PORT1_MAX_GROUP_OFFSET * (port%2)), &value); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ ++ *max_group = value; ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_getAsicIGMPPortCurrentGroup ++ * Description: ++ * Get per-port current group number ++ * Input: ++ * port - Physical port number (0~7) ++ * current_group - current IGMP group ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicIGMPPortCurrentGroup(rtk_uint32 port, rtk_uint32 *current_group) ++{ ++ ret_t retVal; ++ rtk_uint32 value; ++ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ if(port < 8) ++ { ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT01_CURRENT_GROUP + (port/2), RTL8367C_PORT0_CURRENT_GROUP_MASK << (RTL8367C_PORT1_CURRENT_GROUP_OFFSET * (port%2)), &value); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ { ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT89_CURRENT_GROUP + ((port - 8)/2), RTL8367C_PORT0_CURRENT_GROUP_MASK << (RTL8367C_PORT1_CURRENT_GROUP_OFFSET * (port%2)), &value); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ ++ *current_group = value; ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_getAsicIGMPGroup ++ * Description: ++ * Get IGMP group ++ * Input: ++ * idx - Group index (0~255) ++ * valid - valid bit ++ * grp - IGMP group ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - Group index is out of range ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicIGMPGroup(rtk_uint32 idx, rtk_uint32 *valid, rtl8367c_igmpgroup *grp) ++{ ++ ret_t retVal; ++ rtk_uint32 regAddr, regData; ++ rtk_uint32 i; ++ rtk_uint32 groupInfo = 0; ++ ++ if(idx > RTL8367C_IGMP_MAX_GOUP) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ /* Write ACS_ADR register for data bits */ ++ regAddr = RTL8367C_TABLE_ACCESS_ADDR_REG; ++ regData = idx; ++ retVal = rtl8367c_setAsicReg(regAddr, regData); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ /* Write ACS_CMD register */ ++ regAddr = RTL8367C_TABLE_ACCESS_CTRL_REG; ++ regData = RTL8367C_TABLE_ACCESS_REG_DATA(TB_OP_READ, TB_TARGET_IGMP_GROUP); ++ retVal = rtl8367c_setAsicRegBits(regAddr, RTL8367C_TABLE_TYPE_MASK | RTL8367C_COMMAND_TYPE_MASK, regData); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ /* Read Data Bits */ ++ regAddr = RTL8367C_TABLE_ACCESS_RDDATA_BASE; ++ for(i = 0 ;i <= 1; i++) ++ { ++ retVal = rtl8367c_getAsicReg(regAddr, ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ groupInfo |= ((regData & 0xFFFF) << (i * 16)); ++ regAddr ++; ++ } ++ ++ grp->p0_timer = groupInfo & 0x00000007; ++ grp->p1_timer = (groupInfo >> 3) & 0x00000007; ++ grp->p2_timer = (groupInfo >> 6) & 0x00000007; ++ grp->p3_timer = (groupInfo >> 9) & 0x00000007; ++ grp->p4_timer = (groupInfo >> 12) & 0x00000007; ++ grp->p5_timer = (groupInfo >> 15) & 0x00000007; ++ grp->p6_timer = (groupInfo >> 18) & 0x00000007; ++ grp->p7_timer = (groupInfo >> 21) & 0x00000007; ++ grp->report_supp_flag = (groupInfo >> 24) & 0x00000001; ++ grp->p8_timer = (groupInfo >> 25) & 0x00000007; ++ grp->p9_timer = (groupInfo >> 28) & 0x00000007; ++ grp->p10_timer = (groupInfo >> 31) & 0x00000001; ++ ++ regAddr = RTL8367C_TABLE_ACCESS_RDDATA_BASE + 2; ++ retVal = rtl8367c_getAsicReg(regAddr, ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ grp->p10_timer |= (regData & 0x00000003) << 1; ++ ++ /* Valid bit */ ++ retVal = rtl8367c_getAsicReg(RTL8367C_IGMP_GROUP_USAGE_REG(idx), ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ *valid = ((regData & (0x0001 << (idx %16))) != 0) ? 1 : 0; ++ ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_setAsicIpMulticastPortIsoLeaky ++ * Description: ++ * Set IP multicast Port Isolation leaky ++ * Input: ++ * port - Physical port number (0~7) ++ * enabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicIpMulticastPortIsoLeaky(rtk_uint32 port, rtk_uint32 enabled) ++{ ++ ret_t retVal; ++ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_IPMCAST_PORTISO_LEAKY_REG, (0x0001 << port), enabled); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicIpMulticastPortIsoLeaky ++ * Description: ++ * Get IP multicast Port Isolation leaky ++ * Input: ++ * port - Physical port number (0~7) ++ * enabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicIpMulticastPortIsoLeaky(rtk_uint32 port, rtk_uint32 *enabled) ++{ ++ ret_t retVal; ++ rtk_uint32 regData; ++ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_IPMCAST_PORTISO_LEAKY_REG, (0x0001 << port), ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ *enabled = regData; ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicIGMPReportLeaveFlood ++ * Description: ++ * Set IGMP/MLD Report/Leave flood ++ * Input: ++ * flood - 0: Reserved, 1: flooding to router ports, 2: flooding to all ports, 3: flooding to router port or to all ports if there is no router port ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicIGMPReportLeaveFlood(rtk_uint32 flood) ++{ ++ ret_t retVal; ++ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_MLD_CFG3, RTL8367C_REPORT_LEAVE_FORWARD_MASK, flood); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicIGMPReportLeaveFlood ++ * Description: ++ * Get IGMP/MLD Report/Leave flood ++ * Input: ++ * None ++ * Output: ++ * pflood - 0: Reserved, 1: flooding to router ports, 2: flooding to all ports, 3: flooding to router port or to all ports if there is no router port ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicIGMPReportLeaveFlood(rtk_uint32 *pFlood) ++{ ++ ret_t retVal; ++ rtk_uint32 regData; ++ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_MLD_CFG3, RTL8367C_REPORT_LEAVE_FORWARD_MASK, ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ *pFlood = regData; ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicIGMPDropLeaveZero ++ * Description: ++ * Set the function of dropping Leave packet with group IP = 0.0.0.0 ++ * Input: ++ * drop - 1: Drop, 0:Bypass ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicIGMPDropLeaveZero(rtk_uint32 drop) ++{ ++ ret_t retVal; ++ ++ retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_IGMP_MLD_CFG1, RTL8367C_DROP_LEAVE_ZERO_OFFSET, drop); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicIGMPDropLeaveZero ++ * Description: ++ * Get the function of dropping Leave packet with group IP = 0.0.0.0 ++ * Input: ++ * None ++ * Output: ++ * pDrop - 1: Drop, 0:Bypass ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicIGMPDropLeaveZero(rtk_uint32 *pDrop) ++{ ++ ret_t retVal; ++ rtk_uint32 regData; ++ ++ retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_IGMP_MLD_CFG1, RTL8367C_DROP_LEAVE_ZERO_OFFSET, ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ *pDrop = regData; ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicIGMPBypassStormCTRL ++ * Description: ++ * Set the function of bypass storm control for IGMP/MLD packet ++ * Input: ++ * bypass - 1: Bypass, 0:not bypass ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicIGMPBypassStormCTRL(rtk_uint32 bypass) ++{ ++ ret_t retVal; ++ ++ retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_IGMP_MLD_DISCARD_STORM_FILTER_OFFSET, bypass); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicIGMPBypassStormCTRL ++ * Description: ++ * Set the function of bypass storm control for IGMP/MLD packet ++ * Input: ++ * None ++ * Output: ++ * pBypass - 1: Bypass, 0:not bypass ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicIGMPBypassStormCTRL(rtk_uint32 *pBypass) ++{ ++ ret_t retVal; ++ rtk_uint32 regData; ++ ++ retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_IGMP_MLD_DISCARD_STORM_FILTER_OFFSET, ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ *pBypass = regData; ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicIGMPIsoLeaky ++ * Description: ++ * Set Port Isolation leaky for IGMP/MLD packet ++ * Input: ++ * leaky - 1: Leaky, 0:not leaky ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicIGMPIsoLeaky(rtk_uint32 leaky) ++{ ++ ret_t retVal; ++ ++ retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_IGMP_MLD_PORTISO_LEAKY_OFFSET, leaky); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicIGMPIsoLeaky ++ * Description: ++ * Get Port Isolation leaky for IGMP/MLD packet ++ * Input: ++ * None ++ * Output: ++ * pLeaky - 1: Leaky, 0:not leaky ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicIGMPIsoLeaky(rtk_uint32 *pLeaky) ++{ ++ ret_t retVal; ++ rtk_uint32 regData; ++ ++ retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_IGMP_MLD_PORTISO_LEAKY_OFFSET, ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ *pLeaky = regData; ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicIGMPVLANLeaky ++ * Description: ++ * Set VLAN leaky for IGMP/MLD packet ++ * Input: ++ * leaky - 1: Leaky, 0:not leaky ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicIGMPVLANLeaky(rtk_uint32 leaky) ++{ ++ ret_t retVal; ++ ++ retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_IGMP_MLD_VLAN_LEAKY_OFFSET, leaky); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicIGMPVLANLeaky ++ * Description: ++ * Get VLAN leaky for IGMP/MLD packet ++ * Input: ++ * None ++ * Output: ++ * pLeaky - 1: Leaky, 0:not leaky ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicIGMPVLANLeaky(rtk_uint32 *pLeaky) ++{ ++ ret_t retVal; ++ rtk_uint32 regData; ++ ++ retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_IGMP_MLD_VLAN_LEAKY_OFFSET, ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ *pLeaky = regData; ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicIGMPBypassGroup ++ * Description: ++ * Set IGMP/MLD Bypass group ++ * Input: ++ * bypassType - Bypass type ++ * enabled - enabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicIGMPBypassGroup(rtk_uint32 bypassType, rtk_uint32 enabled) ++{ ++ ret_t retVal; ++ rtk_uint32 offset; ++ ++ switch(bypassType) ++ { ++ case BYPASS_224_0_0_X: ++ offset = RTL8367C_IGMP_MLD_IP4_BYPASS_224_0_0_OFFSET; ++ break; ++ case BYPASS_224_0_1_X: ++ offset = RTL8367C_IGMP_MLD_IP4_BYPASS_224_0_1_OFFSET; ++ break; ++ case BYPASS_239_255_255_X: ++ offset = RTL8367C_IGMP_MLD_IP4_BYPASS_239_255_255_OFFSET; ++ break; ++ case BYPASS_IPV6_00XX: ++ offset = RTL8367C_IGMP_MLD_IP6_BYPASS_OFFSET; ++ break; ++ default: ++ return RT_ERR_INPUT; ++ } ++ ++ retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_IGMP_MLD_CFG3, offset, enabled); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicIGMPBypassGroup ++ * Description: ++ * Get IGMP/MLD Bypass group ++ * Input: ++ * bypassType - Bypass type ++ * Output: ++ * pEnabled - enabled ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicIGMPBypassGroup(rtk_uint32 bypassType, rtk_uint32 *pEnabled) ++{ ++ ret_t retVal; ++ rtk_uint32 offset; ++ ++ switch(bypassType) ++ { ++ case BYPASS_224_0_0_X: ++ offset = RTL8367C_IGMP_MLD_IP4_BYPASS_224_0_0_OFFSET; ++ break; ++ case BYPASS_224_0_1_X: ++ offset = RTL8367C_IGMP_MLD_IP4_BYPASS_224_0_1_OFFSET; ++ break; ++ case BYPASS_239_255_255_X: ++ offset = RTL8367C_IGMP_MLD_IP4_BYPASS_239_255_255_OFFSET; ++ break; ++ case BYPASS_IPV6_00XX: ++ offset = RTL8367C_IGMP_MLD_IP6_BYPASS_OFFSET; ++ break; ++ default: ++ return RT_ERR_INPUT; ++ } ++ ++ retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_IGMP_MLD_CFG3, offset, pEnabled); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_inbwctrl.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_inbwctrl.c +new file mode 100644 +index 000000000000..13a7b14246a1 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_inbwctrl.c +@@ -0,0 +1,164 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : Ingress bandwidth control related functions ++ * ++ */ ++#include ++/* Function Name: ++ * rtl8367c_setAsicPortIngressBandwidth ++ * Description: ++ * Set per-port total ingress bandwidth ++ * Input: ++ * port - Physical port number (0~7) ++ * bandwidth - The total ingress bandwidth (unit: 8Kbps), 0x1FFFF:disable ++ * preifg - Include preamble and IFG, 0:Exclude, 1:Include ++ * enableFC - Action when input rate exceeds. 0: Drop 1: Flow Control ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * RT_ERR_OUT_OF_RANGE - input parameter out of range ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicPortIngressBandwidth(rtk_uint32 port, rtk_uint32 bandwidth, rtk_uint32 preifg, rtk_uint32 enableFC) ++{ ++ ret_t retVal; ++ rtk_uint32 regData; ++ rtk_uint32 regAddr; ++ ++ /* Invalid input parameter */ ++ if(port >= RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ if(bandwidth > RTL8367C_QOS_GRANULARTY_MAX) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ regAddr = RTL8367C_INGRESSBW_PORT_RATE_LSB_REG(port); ++ regData = bandwidth & RTL8367C_QOS_GRANULARTY_LSB_MASK; ++ retVal = rtl8367c_setAsicReg(regAddr, regData); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ regAddr += 1; ++ regData = (bandwidth & RTL8367C_QOS_GRANULARTY_MSB_MASK) >> RTL8367C_QOS_GRANULARTY_MSB_OFFSET; ++ retVal = rtl8367c_setAsicRegBits(regAddr, RTL8367C_INGRESSBW_PORT0_RATE_CTRL1_INGRESSBW_RATE16_MASK, regData); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ regAddr = RTL8367C_PORT_MISC_CFG_REG(port); ++ retVal = rtl8367c_setAsicRegBit(regAddr, RTL8367C_PORT0_MISC_CFG_INGRESSBW_IFG_OFFSET, preifg); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ regAddr = RTL8367C_PORT_MISC_CFG_REG(port); ++ retVal = rtl8367c_setAsicRegBit(regAddr, RTL8367C_PORT0_MISC_CFG_INGRESSBW_FLOWCTRL_OFFSET, enableFC); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_getAsicPortIngressBandwidth ++ * Description: ++ * Get per-port total ingress bandwidth ++ * Input: ++ * port - Physical port number (0~7) ++ * pBandwidth - The total ingress bandwidth (unit: 8Kbps), 0x1FFFF:disable ++ * pPreifg - Include preamble and IFG, 0:Exclude, 1:Include ++ * pEnableFC - Action when input rate exceeds. 0: Drop 1: Flow Control ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicPortIngressBandwidth(rtk_uint32 port, rtk_uint32* pBandwidth, rtk_uint32* pPreifg, rtk_uint32* pEnableFC) ++{ ++ ret_t retVal; ++ rtk_uint32 regData; ++ rtk_uint32 regAddr; ++ ++ /* Invalid input parameter */ ++ if(port >= RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ regAddr = RTL8367C_INGRESSBW_PORT_RATE_LSB_REG(port); ++ retVal = rtl8367c_getAsicReg(regAddr, ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ *pBandwidth = regData; ++ ++ regAddr += 1; ++ retVal = rtl8367c_getAsicRegBits(regAddr, RTL8367C_INGRESSBW_PORT0_RATE_CTRL1_INGRESSBW_RATE16_MASK, ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ *pBandwidth |= (regData << RTL8367C_QOS_GRANULARTY_MSB_OFFSET); ++ ++ regAddr = RTL8367C_PORT_MISC_CFG_REG(port); ++ retVal = rtl8367c_getAsicRegBit(regAddr, RTL8367C_PORT0_MISC_CFG_INGRESSBW_IFG_OFFSET, pPreifg); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ regAddr = RTL8367C_PORT_MISC_CFG_REG(port); ++ retVal = rtl8367c_getAsicRegBit(regAddr, RTL8367C_PORT0_MISC_CFG_INGRESSBW_FLOWCTRL_OFFSET, pEnableFC); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_setAsicPortIngressBandwidthBypass ++ * Description: ++ * Set ingress bandwidth control bypass 8899, RMA 01-80-C2-00-00-xx and IGMP ++ * Input: ++ * enabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicPortIngressBandwidthBypass(rtk_uint32 enabled) ++{ ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_SW_DUMMY0, RTL8367C_INGRESSBW_BYPASS_EN_OFFSET, enabled); ++} ++/* Function Name: ++ * rtl8367c_getAsicPortIngressBandwidthBypass ++ * Description: ++ * Set ingress bandwidth control bypass 8899, RMA 01-80-C2-00-00-xx and IGMP ++ * Input: ++ * pEnabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicPortIngressBandwidthBypass(rtk_uint32* pEnabled) ++{ ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_SW_DUMMY0, RTL8367C_INGRESSBW_BYPASS_EN_OFFSET, pEnabled); ++} ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_interrupt.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_interrupt.c +new file mode 100644 +index 000000000000..1d5ccfc904ae +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_interrupt.c +@@ -0,0 +1,205 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : Interrupt related functions ++ * ++ */ ++#include ++/* Function Name: ++ * rtl8367c_setAsicInterruptPolarity ++ * Description: ++ * Set interrupt trigger polarity ++ * Input: ++ * polarity - 0:pull high 1: pull low ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicInterruptPolarity(rtk_uint32 polarity) ++{ ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_INTR_CTRL, RTL8367C_INTR_CTRL_OFFSET, polarity); ++} ++/* Function Name: ++ * rtl8367c_getAsicInterruptPolarity ++ * Description: ++ * Get interrupt trigger polarity ++ * Input: ++ * pPolarity - 0:pull high 1: pull low ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicInterruptPolarity(rtk_uint32* pPolarity) ++{ ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_INTR_CTRL, RTL8367C_INTR_CTRL_OFFSET, pPolarity); ++} ++/* Function Name: ++ * rtl8367c_setAsicInterruptMask ++ * Description: ++ * Set interrupt enable mask ++ * Input: ++ * imr - Interrupt mask ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicInterruptMask(rtk_uint32 imr) ++{ ++ return rtl8367c_setAsicReg(RTL8367C_REG_INTR_IMR, imr); ++} ++/* Function Name: ++ * rtl8367c_getAsicInterruptMask ++ * Description: ++ * Get interrupt enable mask ++ * Input: ++ * pImr - Interrupt mask ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicInterruptMask(rtk_uint32* pImr) ++{ ++ return rtl8367c_getAsicReg(RTL8367C_REG_INTR_IMR, pImr); ++} ++/* Function Name: ++ * rtl8367c_setAsicInterruptMask ++ * Description: ++ * Clear interrupt enable mask ++ * Input: ++ * ims - Interrupt status mask ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * This API can be used to clear ASIC interrupt status and register will be cleared by writing 1. ++ * [0]:Link change, ++ * [1]:Share meter exceed, ++ * [2]:Learn number over, ++ * [3]:Speed Change, ++ * [4]:Tx special congestion ++ * [5]:1 second green feature ++ * [6]:loop detection ++ * [7]:interrupt from 8051 ++ * [8]:Cable diagnostic finish ++ * [9]:ACL action interrupt trigger ++ * [11]: Silent Start ++ */ ++ret_t rtl8367c_setAsicInterruptStatus(rtk_uint32 ims) ++{ ++ return rtl8367c_setAsicReg(RTL8367C_REG_INTR_IMS, ims); ++} ++/* Function Name: ++ * rtl8367c_getAsicInterruptStatus ++ * Description: ++ * Get interrupt enable mask ++ * Input: ++ * pIms - Interrupt status mask ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicInterruptStatus(rtk_uint32* pIms) ++{ ++ return rtl8367c_getAsicReg(RTL8367C_REG_INTR_IMS, pIms); ++} ++/* Function Name: ++ * rtl8367c_setAsicInterruptRelatedStatus ++ * Description: ++ * Clear interrupt status ++ * Input: ++ * type - per port Learn over, per-port speed change, per-port special congest, share meter exceed status ++ * status - exceed status, write 1 to clear ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - input parameter out of range ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicInterruptRelatedStatus(rtk_uint32 type, rtk_uint32 status) ++{ ++ CONST rtk_uint32 indicatorAddress[INTRST_END] = {RTL8367C_REG_LEARN_OVER_INDICATOR, ++ RTL8367C_REG_SPEED_CHANGE_INDICATOR, ++ RTL8367C_REG_SPECIAL_CONGEST_INDICATOR, ++ RTL8367C_REG_PORT_LINKDOWN_INDICATOR, ++ RTL8367C_REG_PORT_LINKUP_INDICATOR, ++ RTL8367C_REG_METER_OVERRATE_INDICATOR0, ++ RTL8367C_REG_METER_OVERRATE_INDICATOR1, ++ RTL8367C_REG_RLDP_LOOPED_INDICATOR, ++ RTL8367C_REG_RLDP_RELEASED_INDICATOR, ++ RTL8367C_REG_SYSTEM_LEARN_OVER_INDICATOR}; ++ ++ if(type >= INTRST_END ) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ return rtl8367c_setAsicReg(indicatorAddress[type], status); ++} ++/* Function Name: ++ * rtl8367c_getAsicInterruptRelatedStatus ++ * Description: ++ * Get interrupt status ++ * Input: ++ * type - per port Learn over, per-port speed change, per-port special congest, share meter exceed status ++ * pStatus - exceed status, write 1 to clear ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - input parameter out of range ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicInterruptRelatedStatus(rtk_uint32 type, rtk_uint32* pStatus) ++{ ++ CONST rtk_uint32 indicatorAddress[INTRST_END] = {RTL8367C_REG_LEARN_OVER_INDICATOR, ++ RTL8367C_REG_SPEED_CHANGE_INDICATOR, ++ RTL8367C_REG_SPECIAL_CONGEST_INDICATOR, ++ RTL8367C_REG_PORT_LINKDOWN_INDICATOR, ++ RTL8367C_REG_PORT_LINKUP_INDICATOR, ++ RTL8367C_REG_METER_OVERRATE_INDICATOR0, ++ RTL8367C_REG_METER_OVERRATE_INDICATOR1, ++ RTL8367C_REG_RLDP_LOOPED_INDICATOR, ++ RTL8367C_REG_RLDP_RELEASED_INDICATOR, ++ RTL8367C_REG_SYSTEM_LEARN_OVER_INDICATOR}; ++ ++ if(type >= INTRST_END ) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ return rtl8367c_getAsicReg(indicatorAddress[type], pStatus); ++} ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_led.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_led.c +new file mode 100644 +index 000000000000..6f2617f5aa02 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_led.c +@@ -0,0 +1,727 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : LED related functions ++ * ++ */ ++#include ++/* Function Name: ++ * rtl8367c_setAsicLedIndicateInfoConfig ++ * Description: ++ * Set Leds indicated information mode ++ * Input: ++ * ledno - LED group number. There are 1 to 1 led mapping to each port in each led group ++ * config - Support 16 types configuration ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - input parameter out of range ++ * Note: ++ * The API can set LED indicated information configuration for each LED group with 1 to 1 led mapping to each port. ++ * Definition LED Statuses Description ++ * 0000 LED_Off LED pin Tri-State. ++ * 0001 Dup/Col Collision, Full duplex Indicator. Blinking every 43ms when collision happens. Low for full duplex, and high for half duplex mode. ++ * 0010 Link/Act Link, Activity Indicator. Low for link established. Link/Act Blinks every 43ms when the corresponding port is transmitting or receiving. ++ * 0011 Spd1000 1000Mb/s Speed Indicator. Low for 1000Mb/s. ++ * 0100 Spd100 100Mb/s Speed Indicator. Low for 100Mb/s. ++ * 0101 Spd10 10Mb/s Speed Indicator. Low for 10Mb/s. ++ * 0110 Spd1000/Act 1000Mb/s Speed/Activity Indicator. Low for 1000Mb/s. Blinks every 43ms when the corresponding port is transmitting or receiving. ++ * 0111 Spd100/Act 100Mb/s Speed/Activity Indicator. Low for 100Mb/s. Blinks every 43ms when the corresponding port is transmitting or receiving. ++ * 1000 Spd10/Act 10Mb/s Speed/Activity Indicator. Low for 10Mb/s. Blinks every 43ms when the corresponding port is transmitting or receiving. ++ * 1001 Spd100 (10)/Act 10/100Mb/s Speed/Activity Indicator. Low for 10/100Mb/s. Blinks every 43ms when the corresponding port is transmitting or receiving. ++ * 1010 Fiber Fiber link Indicator. Low for Fiber. ++ * 1011 Fault Auto-negotiation Fault Indicator. Low for Fault. ++ * 1100 Link/Rx Link, Activity Indicator. Low for link established. Link/Rx Blinks every 43ms when the corresponding port is transmitting. ++ * 1101 Link/Tx Link, Activity Indicator. Low for link established. Link/Tx Blinks every 43ms when the corresponding port is receiving. ++ * 1110 Master Link on Master Indicator. Low for link Master established. ++ * 1111 LED_Force Force LED output, LED output value reference ++ */ ++ret_t rtl8367c_setAsicLedIndicateInfoConfig(rtk_uint32 ledno, rtk_uint32 config) ++{ ++ ret_t retVal; ++ CONST rtk_uint16 bits[RTL8367C_LEDGROUPNO] = {RTL8367C_LED0_CFG_MASK, RTL8367C_LED1_CFG_MASK, RTL8367C_LED2_CFG_MASK}; ++ ++ if(ledno >= RTL8367C_LEDGROUPNO) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ if(config >= LEDCONF_END) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_LED_CONFIGURATION, RTL8367C_LED_CONFIG_SEL_OFFSET, 0); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ return rtl8367c_setAsicRegBits(RTL8367C_REG_LED_CONFIGURATION, bits[ledno], config); ++} ++/* Function Name: ++ * rtl8367c_getAsicLedIndicateInfoConfig ++ * Description: ++ * Get Leds indicated information mode ++ * Input: ++ * ledno - LED group number. There are 1 to 1 led mapping to each port in each led group ++ * pConfig - Support 16 types configuration ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - input parameter out of range ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicLedIndicateInfoConfig(rtk_uint32 ledno, rtk_uint32* pConfig) ++{ ++ CONST rtk_uint16 bits[RTL8367C_LEDGROUPNO]= {RTL8367C_LED0_CFG_MASK, RTL8367C_LED1_CFG_MASK, RTL8367C_LED2_CFG_MASK}; ++ ++ if(ledno >= RTL8367C_LEDGROUPNO) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ /* Get register value */ ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_LED_CONFIGURATION, bits[ledno], pConfig); ++} ++/* Function Name: ++ * rtl8367c_setAsicLedGroupMode ++ * Description: ++ * Set Led Group mode ++ * Input: ++ * mode - LED mode ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - input parameter out of range ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicLedGroupMode(rtk_uint32 mode) ++{ ++ ret_t retVal; ++ ++ /* Invalid input parameter */ ++ if(mode >= RTL8367C_LED_MODE_END) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_LED_CONFIGURATION, RTL8367C_LED_CONFIG_SEL_OFFSET, 1); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ return rtl8367c_setAsicRegBits(RTL8367C_REG_LED_CONFIGURATION, RTL8367C_DATA_LED_MASK, mode); ++} ++/* Function Name: ++ * rtl8367c_getAsicLedGroupMode ++ * Description: ++ * Get Led Group mode ++ * Input: ++ * pMode - LED mode ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicLedGroupMode(rtk_uint32* pMode) ++{ ++ ret_t retVal; ++ rtk_uint32 regData; ++ ++ retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_LED_CONFIGURATION, RTL8367C_LED_CONFIG_SEL_OFFSET, ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ if(regData!=1) ++ return RT_ERR_FAILED; ++ ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_LED_CONFIGURATION, RTL8367C_DATA_LED_MASK, pMode); ++} ++/* Function Name: ++ * rtl8367c_setAsicForceLeds ++ * Description: ++ * Set group LED mode ++ * Input: ++ * port - Physical port number (0~7) ++ * group - LED group number ++ * mode - LED mode ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * RT_ERR_OUT_OF_RANGE - input parameter out of range ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicForceLed(rtk_uint32 port, rtk_uint32 group, rtk_uint32 mode) ++{ ++ rtk_uint16 regAddr; ++ ret_t retVal; ++ ++ /* Invalid input parameter */ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ if(group >= RTL8367C_LEDGROUPNO) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ if(mode >= LEDFORCEMODE_END) ++ return RT_ERR_OUT_OF_RANGE; ++ /* Set Related Registers */ ++ if(port < 8){ ++ regAddr = RTL8367C_LED_FORCE_MODE_BASE + (group << 1); ++ if((retVal = rtl8367c_setAsicRegBits(regAddr, 0x3 << (port * 2), mode)) != RT_ERR_OK) ++ return retVal; ++ }else if(port >= 8){ ++ regAddr = RTL8367C_REG_CPU_FORCE_LED0_CFG1 + (group << 1); ++ if((retVal = rtl8367c_setAsicRegBits(regAddr, 0x3 << ((port-8) * 2), mode)) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_getAsicForceLed ++ * Description: ++ * Get group LED mode ++ * Input: ++ * port - Physical port number (0~7) ++ * group - LED group number ++ * pMode - LED mode ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * RT_ERR_OUT_OF_RANGE - input parameter out of range ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicForceLed(rtk_uint32 port, rtk_uint32 group, rtk_uint32* pMode) ++{ ++ rtk_uint16 regAddr; ++ ret_t retVal; ++ ++ /* Invalid input parameter */ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ if(group >= RTL8367C_LEDGROUPNO) ++ return RT_ERR_INPUT; ++ ++ /* Get Related Registers */ ++ if(port < 8){ ++ regAddr = RTL8367C_LED_FORCE_MODE_BASE + (group << 1); ++ if((retVal = rtl8367c_getAsicRegBits(regAddr, 0x3 << (port * 2), pMode)) != RT_ERR_OK) ++ return retVal; ++ }else if(port >= 8){ ++ regAddr = RTL8367C_REG_CPU_FORCE_LED0_CFG1 + (group << 1); ++ if((retVal = rtl8367c_getAsicRegBits(regAddr, 0x3 << ((port-8) * 2), pMode)) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_setAsicForceGroupLed ++ * Description: ++ * Turn on/off Led of all ports ++ * Input: ++ * group - LED group number ++ * mode - 0b00:normal mode, 0b01:force blink, 0b10:force off, 0b11:force on ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - input parameter out of range ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicForceGroupLed(rtk_uint32 groupmask, rtk_uint32 mode) ++{ ++ ret_t retVal; ++ rtk_uint32 i,bitmask; ++ CONST rtk_uint16 bits[3]= {0x0004,0x0010,0x0040}; ++ ++ /* Invalid input parameter */ ++ if(groupmask > RTL8367C_LEDGROUPMASK) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ if(mode >= LEDFORCEMODE_END) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ bitmask = 0; ++ for(i = 0; i < RTL8367C_LEDGROUPNO; i++) ++ { ++ if(groupmask & (1 << i)) ++ { ++ bitmask = bitmask | bits[i]; ++ } ++ ++ } ++ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_LED_FORCE_CTRL, RTL8367C_LED_FORCE_MODE_MASK, bitmask); ++ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_LED_FORCE_CTRL, RTL8367C_FORCE_MODE_MASK, mode); ++ ++ if(LEDFORCEMODE_NORMAL == mode) ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_LED_FORCE_CTRL, RTL8367C_LED_FORCE_MODE_MASK, 0); ++ ++ return retVal; ++} ++/* Function Name: ++ * rtl8367c_getAsicForceGroupLed ++ * Description: ++ * Turn on/off Led of all ports ++ * Input: ++ * group - LED group number ++ * pMode - 0b00:normal mode, 0b01:force blink, 0b10:force off, 0b11:force on ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicForceGroupLed(rtk_uint32* groupmask, rtk_uint32* pMode) ++{ ++ ret_t retVal; ++ rtk_uint32 i,regData; ++ CONST rtk_uint16 bits[3] = {0x0004,0x0010,0x0040}; ++ ++ /* Get Related Registers */ ++ if((retVal = rtl8367c_getAsicRegBits(RTL8367C_LED_FORCE_CTRL, RTL8367C_LED_FORCE_MODE_MASK, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ for(i = 0; i< RTL8367C_LEDGROUPNO; i++) ++ { ++ if((regData & bits[i]) == bits[i]) ++ { ++ *groupmask = *groupmask | (1 << i); ++ } ++ } ++ ++ return rtl8367c_getAsicRegBits(RTL8367C_LED_FORCE_CTRL, RTL8367C_FORCE_MODE_MASK, pMode); ++} ++/* Function Name: ++ * rtl8367c_setAsicLedBlinkRate ++ * Description: ++ * Set led blinking rate at mode 0 to mode 3 ++ * Input: ++ * blinkRate - Support 6 blink rates ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - input parameter out of range ++ * Note: ++ * LED blink rate can be at 43ms, 84ms, 120ms, 170ms, 340ms and 670ms ++ */ ++ret_t rtl8367c_setAsicLedBlinkRate(rtk_uint32 blinkRate) ++{ ++ if(blinkRate >= LEDBLINKRATE_END) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ return rtl8367c_setAsicRegBits(RTL8367C_REG_LED_MODE, RTL8367C_SEL_LEDRATE_MASK, blinkRate); ++} ++/* Function Name: ++ * rtl8367c_getAsicLedBlinkRate ++ * Description: ++ * Get led blinking rate at mode 0 to mode 3 ++ * Input: ++ * pBlinkRate - Support 6 blink rates ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicLedBlinkRate(rtk_uint32* pBlinkRate) ++{ ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_LED_MODE, RTL8367C_SEL_LEDRATE_MASK, pBlinkRate); ++} ++/* Function Name: ++ * rtl8367c_setAsicLedForceBlinkRate ++ * Description: ++ * Set LEd blinking rate for force mode led ++ * Input: ++ * blinkRate - Support 6 blink rates ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - input parameter out of range ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicLedForceBlinkRate(rtk_uint32 blinkRate) ++{ ++ if(blinkRate >= LEDFORCERATE_END) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ return rtl8367c_setAsicRegBits(RTL8367C_REG_LED_MODE, RTL8367C_FORCE_RATE_MASK, blinkRate); ++} ++/* Function Name: ++ * rtl8367c_getAsicLedForceBlinkRate ++ * Description: ++ * Get LED blinking rate for force mode led ++ * Input: ++ * pBlinkRate - Support 6 blink rates ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicLedForceBlinkRate(rtk_uint32* pBlinkRate) ++{ ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_LED_MODE, RTL8367C_FORCE_RATE_MASK, pBlinkRate); ++} ++ ++/* ++@func ret_t | rtl8367c_setAsicLedGroupEnable | Turn on/off Led of all system ports ++@parm rtk_uint32 | group | LED group id. ++@parm rtk_uint32 | portmask | LED port mask. ++@rvalue RT_ERR_OK | Success. ++@rvalue RT_ERR_SMI | SMI access error. ++@rvalue RT_ERR_PORT_ID | Invalid port number. ++@rvalue RT_ERR_INPUT | Invalid input value. ++@comm ++ The API can turn on/off leds of dedicated port while indicated information configuration of LED group is set to force mode. ++ */ ++ret_t rtl8367c_setAsicLedGroupEnable(rtk_uint32 group, rtk_uint32 portmask) ++{ ++ ret_t retVal; ++ rtk_uint32 regAddr; ++ rtk_uint32 regDataMask; ++ ++ if ( group >= RTL8367C_LEDGROUPNO ) ++ return RT_ERR_INPUT; ++ ++ regAddr = RTL8367C_REG_PARA_LED_IO_EN1 + group/2; ++ regDataMask = 0xFF << ((group%2)*8); ++ retVal = rtl8367c_setAsicRegBits(regAddr, regDataMask, portmask&0xff); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ regAddr = RTL8367C_REG_PARA_LED_IO_EN3; ++ regDataMask = 0x3 << (group*2); ++ retVal = rtl8367c_setAsicRegBits(regAddr, regDataMask, (portmask>>8)&0x7); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ ++ return RT_ERR_OK; ++} ++ ++/* ++@func ret_t | rtl8367c_getAsicLedGroupEnable | Get on/off status of Led of all system ports ++@parm rtk_uint32 | group | LED group id. ++@parm rtk_uint32 | *portmask | LED port mask. ++@rvalue RT_ERR_OK | Success. ++@rvalue RT_ERR_SMI | SMI access error. ++@rvalue RT_ERR_PORT_ID | Invalid port number. ++@rvalue RT_ERR_INPUT | Invalid input value. ++@comm ++ The API can turn on/off leds of dedicated port while indicated information configuration of LED group is set to force mode. ++ */ ++ret_t rtl8367c_getAsicLedGroupEnable(rtk_uint32 group, rtk_uint32 *portmask) ++{ ++ ret_t retVal; ++ rtk_uint32 regAddr; ++ rtk_uint32 regDataMask,regData; ++ ++ if ( group >= RTL8367C_LEDGROUPNO ) ++ return RT_ERR_INPUT; ++ ++ regAddr = RTL8367C_REG_PARA_LED_IO_EN1 + group/2; ++ regDataMask = 0xFF << ((group%2)*8); ++ retVal = rtl8367c_getAsicRegBits(regAddr, regDataMask, portmask); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ ++ regAddr = RTL8367C_REG_PARA_LED_IO_EN3; ++ regDataMask = 0x3 << (group*2); ++ retVal = rtl8367c_getAsicRegBits(regAddr, regDataMask, ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ *portmask = (regData << 8) | *portmask; ++ ++ return RT_ERR_OK; ++} ++ ++/* ++@func ret_t | rtl8367c_setAsicLedOperationMode | Set LED operation mode ++@parm rtk_uint32 | mode | LED mode. 1:scan mode 1, 2:parallel mode, 3:mdx mode (serial mode) ++@rvalue RT_ERR_OK | Success. ++@rvalue RT_ERR_SMI | SMI access error. ++@rvalue RT_ERR_INPUT | Invalid input value. ++@comm ++ The API can turn on/off led serial mode and set signal to active high/low. ++ */ ++ret_t rtl8367c_setAsicLedOperationMode(rtk_uint32 mode) ++{ ++ ret_t retVal; ++ ++ /* Invalid input parameter */ ++ if( mode >= LEDOP_END) ++ return RT_ERR_INPUT; ++ ++ switch(mode) ++ { ++ case LEDOP_PARALLEL: ++ if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_LED_SYS_CONFIG, RTL8367C_LED_SELECT_OFFSET, 0))!= RT_ERR_OK) ++ return retVal; ++ /*Disable serial CLK mode*/ ++ if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SCAN0_LED_IO_EN1,RTL8367C_LED_SERI_CLK_EN_OFFSET, 0))!= RT_ERR_OK) ++ return retVal; ++ /*Disable serial DATA mode*/ ++ if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SCAN0_LED_IO_EN1,RTL8367C_LED_SERI_DATA_EN_OFFSET, 0))!= RT_ERR_OK) ++ return retVal; ++ break; ++ case LEDOP_SERIAL: ++ if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_LED_SYS_CONFIG, RTL8367C_LED_SELECT_OFFSET, 1))!= RT_ERR_OK) ++ return retVal; ++ /*Enable serial CLK mode*/ ++ if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SCAN0_LED_IO_EN1,RTL8367C_LED_SERI_CLK_EN_OFFSET, 1))!= RT_ERR_OK) ++ return retVal; ++ /*Enable serial DATA mode*/ ++ if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SCAN0_LED_IO_EN1,RTL8367C_LED_SERI_DATA_EN_OFFSET, 1))!= RT_ERR_OK) ++ return retVal; ++ break; ++ default: ++ return RT_ERR_INPUT; ++ break; ++ } ++ ++ return RT_ERR_OK; ++} ++ ++ ++/* ++@func ret_t | rtl8367c_getAsicLedOperationMode | Get LED OP mode setup ++@parm rtk_uint32*| mode | LED mode. 1:scan mode 1, 2:parallel mode, 3:mdx mode (serial mode) ++@rvalue RT_ERR_OK | Success. ++@rvalue RT_ERR_SMI | SMI access error. ++@rvalue RT_ERR_INPUT | Invalid input value. ++@comm ++ The API can get LED serial mode setup and get signal active high/low. ++ */ ++ret_t rtl8367c_getAsicLedOperationMode(rtk_uint32 *mode) ++{ ++ ret_t retVal; ++ rtk_uint32 regData; ++ ++ if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_LED_SYS_CONFIG, RTL8367C_LED_SELECT_OFFSET, ®Data))!= RT_ERR_OK) ++ return retVal; ++ ++ if (regData == 1) ++ *mode = LEDOP_SERIAL; ++ else if (regData == 0) ++ *mode = LEDOP_PARALLEL; ++ else ++ return RT_ERR_FAILED; ++ ++ return RT_ERR_OK; ++} ++ ++/* ++@func ret_t | rtl8367c_setAsicLedSerialModeConfig | Set LED serial mode ++@parm rtk_uint32 | active | Active High or Low. ++@rvalue RT_ERR_OK | Success. ++@rvalue RT_ERR_SMI | SMI access error. ++@rvalue RT_ERR_INPUT | Invalid input value. ++@comm ++ The API can turn on/off led serial mode and set signal to active high/low. ++ */ ++ret_t rtl8367c_setAsicLedSerialModeConfig(rtk_uint32 active, rtk_uint32 serimode) ++{ ++ ret_t retVal; ++ ++ /* Invalid input parameter */ ++ if( active >= LEDSERACT_MAX) ++ return RT_ERR_INPUT; ++ if( serimode >= LEDSER_MAX) ++ return RT_ERR_INPUT; ++ ++ /* Set Active High or Low */ ++ if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_LED_SYS_CONFIG, RTL8367C_SERI_LED_ACT_LOW_OFFSET, active)) != RT_ERR_OK) ++ return retVal; ++ ++ /*set to 8G mode (not 16G mode)*/ ++ if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_LED_MODE, RTL8367C_DLINK_TIME_OFFSET, serimode))!= RT_ERR_OK) ++ return retVal; ++ ++ ++ return RT_ERR_OK; ++} ++ ++ ++/* ++@func ret_t | rtl8367c_getAsicLedSerialModeConfig | Get LED serial mode setup ++@parm rtk_uint32*| active | Active High or Low. ++@rvalue RT_ERR_OK | Success. ++@rvalue RT_ERR_SMI | SMI access error. ++@rvalue RT_ERR_INPUT | Invalid input value. ++@comm ++ The API can get LED serial mode setup and get signal active high/low. ++ */ ++ret_t rtl8367c_getAsicLedSerialModeConfig(rtk_uint32 *active, rtk_uint32 *serimode) ++{ ++ ret_t retVal; ++ ++ if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_LED_SYS_CONFIG, RTL8367C_SERI_LED_ACT_LOW_OFFSET, active))!= RT_ERR_OK) ++ return retVal; ++ ++ /*get to 8G mode (not 16G mode)*/ ++ if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_LED_MODE, RTL8367C_DLINK_TIME_OFFSET, serimode))!= RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++ ++/* ++@func ret_t | rtl8367c_setAsicLedOutputEnable | Set LED output enable ++@parm rtk_uint32 | enabled | enable or disable. ++@rvalue RT_ERR_OK | Success. ++@rvalue RT_ERR_SMI | SMI access error. ++@rvalue RT_ERR_INPUT | Invalid input value. ++@comm ++ The API can turn on/off LED output Enable ++ */ ++ret_t rtl8367c_setAsicLedOutputEnable(rtk_uint32 enabled) ++{ ++ ret_t retVal; ++ rtk_uint32 regdata; ++ ++ if (enabled == 1) ++ regdata = 0; ++ else ++ regdata = 1; ++ ++ /* Enable/Disable H/W IGMP/MLD */ ++ retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_LED_SYS_CONFIG, RTL8367C_LED_IO_DISABLE_OFFSET, regdata); ++ ++ return retVal; ++} ++ ++ ++/* ++@func ret_t | rtl8367c_getAsicLedOutputEnable | Get LED serial mode setup ++@parm rtk_uint32*| active | Active High or Low. ++@rvalue RT_ERR_OK | Success. ++@rvalue RT_ERR_SMI | SMI access error. ++@rvalue RT_ERR_INPUT | Invalid input value. ++@comm ++ The API can get LED serial mode setup and get signal active high/low. ++ */ ++ret_t rtl8367c_getAsicLedOutputEnable(rtk_uint32 *ptr_enabled) ++{ ++ ret_t retVal; ++ rtk_uint32 regdata; ++ ++ retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_LED_SYS_CONFIG, RTL8367C_LED_IO_DISABLE_OFFSET, ®data); ++ if (retVal != RT_ERR_OK) ++ return retVal; ++ ++ if (regdata == 1) ++ *ptr_enabled = 0; ++ else ++ *ptr_enabled = 1; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicLedSerialOutput ++ * Description: ++ * Set serial LED output group and portmask. ++ * Input: ++ * output - Serial LED output group ++ * pmask - Serial LED output portmask ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - input parameter out of range ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicLedSerialOutput(rtk_uint32 output, rtk_uint32 pmask) ++{ ++ ret_t retVal; ++ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_SERIAL_LED_CTRL, RTL8367C_SERIAL_LED_GROUP_NUM_MASK, output); ++ if (retVal != RT_ERR_OK) ++ return retVal; ++ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_SERIAL_LED_CTRL, RTL8367C_SERIAL_LED_PORT_EN_MASK, pmask); ++ if (retVal != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicLedSerialOutput ++ * Description: ++ * Get serial LED output group and portmask. ++ * Input: ++ * None ++ * Output: ++ * pOutput - Serial LED output group ++ * pPmask - Serial LED output portmask ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - input parameter out of range ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicLedSerialOutput(rtk_uint32 *pOutput, rtk_uint32 *pPmask) ++{ ++ ret_t retVal; ++ ++ if(pOutput == NULL) ++ return RT_ERR_NULL_POINTER; ++ ++ if(pPmask == NULL) ++ return RT_ERR_NULL_POINTER; ++ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_SERIAL_LED_CTRL, RTL8367C_SERIAL_LED_GROUP_NUM_MASK, pOutput); ++ if (retVal != RT_ERR_OK) ++ return retVal; ++ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_SERIAL_LED_CTRL, RTL8367C_SERIAL_LED_PORT_EN_MASK, pPmask); ++ if (retVal != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_lut.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_lut.c +new file mode 100644 +index 000000000000..1521467aa8b4 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_lut.c +@@ -0,0 +1,1549 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : LUT related functions ++ * ++ */ ++ ++#include ++ ++#include ++ ++static void _rtl8367c_fdbStUser2Smi( rtl8367c_luttb *pLutSt, rtk_uint16 *pFdbSmi) ++{ ++ /* L3 lookup */ ++ if(pLutSt->l3lookup) ++ { ++ if(pLutSt->l3vidlookup) ++ { ++ pFdbSmi[0] = (pLutSt->sip & 0x0000FFFF); ++ pFdbSmi[1] = (pLutSt->sip & 0xFFFF0000) >> 16; ++ ++ pFdbSmi[2] = (pLutSt->dip & 0x0000FFFF); ++ pFdbSmi[3] = (pLutSt->dip & 0x0FFF0000) >> 16; ++ ++ pFdbSmi[3] |= (pLutSt->l3lookup & 0x0001) << 12; ++ pFdbSmi[3] |= (pLutSt->l3vidlookup & 0x0001) << 13; ++ pFdbSmi[3] |= ((pLutSt->mbr & 0x0300) >> 8) << 14; ++ ++ pFdbSmi[4] |= (pLutSt->mbr & 0x00FF); ++ pFdbSmi[4] |= (pLutSt->l3_vid & 0x00FF) << 8; ++ ++ pFdbSmi[5] |= ((pLutSt->l3_vid & 0x0F00) >> 8); ++ pFdbSmi[5] |= (pLutSt->nosalearn & 0x0001) << 5; ++ pFdbSmi[5] |= ((pLutSt->mbr & 0x0400) >> 10) << 7; ++ } ++ else ++ { ++ pFdbSmi[0] = (pLutSt->sip & 0x0000FFFF); ++ pFdbSmi[1] = (pLutSt->sip & 0xFFFF0000) >> 16; ++ ++ pFdbSmi[2] = (pLutSt->dip & 0x0000FFFF); ++ pFdbSmi[3] = (pLutSt->dip & 0x0FFF0000) >> 16; ++ ++ pFdbSmi[3] |= (pLutSt->l3lookup & 0x0001) << 12; ++ pFdbSmi[3] |= (pLutSt->l3vidlookup & 0x0001) << 13; ++ pFdbSmi[3] |= ((pLutSt->mbr & 0x0300) >> 8) << 14; ++ ++ pFdbSmi[4] |= (pLutSt->mbr & 0x00FF); ++ pFdbSmi[4] |= (pLutSt->igmpidx & 0x00FF) << 8; ++ ++ pFdbSmi[5] |= (pLutSt->igmp_asic & 0x0001); ++ pFdbSmi[5] |= (pLutSt->lut_pri & 0x0007) << 1; ++ pFdbSmi[5] |= (pLutSt->fwd_en & 0x0001) << 4; ++ pFdbSmi[5] |= (pLutSt->nosalearn & 0x0001) << 5; ++ pFdbSmi[5] |= ((pLutSt->mbr & 0x0400) >> 10) << 7; ++ } ++ } ++ else if(pLutSt->mac.octet[0] & 0x01) /*Multicast L2 Lookup*/ ++ { ++ pFdbSmi[0] |= pLutSt->mac.octet[5]; ++ pFdbSmi[0] |= pLutSt->mac.octet[4] << 8; ++ ++ pFdbSmi[1] |= pLutSt->mac.octet[3]; ++ pFdbSmi[1] |= pLutSt->mac.octet[2] << 8; ++ ++ pFdbSmi[2] |= pLutSt->mac.octet[1]; ++ pFdbSmi[2] |= pLutSt->mac.octet[0] << 8; ++ ++ pFdbSmi[3] |= pLutSt->cvid_fid; ++ pFdbSmi[3] |= (pLutSt->l3lookup & 0x0001) << 12; ++ pFdbSmi[3] |= (pLutSt->ivl_svl & 0x0001) << 13; ++ pFdbSmi[3] |= ((pLutSt->mbr & 0x0300) >> 8) << 14; ++ ++ pFdbSmi[4] |= (pLutSt->mbr & 0x00FF); ++ pFdbSmi[4] |= (pLutSt->igmpidx & 0x00FF) << 8; ++ ++ pFdbSmi[5] |= pLutSt->igmp_asic; ++ pFdbSmi[5] |= (pLutSt->lut_pri & 0x0007) << 1; ++ pFdbSmi[5] |= (pLutSt->fwd_en & 0x0001) << 4; ++ pFdbSmi[5] |= (pLutSt->nosalearn & 0x0001) << 5; ++ pFdbSmi[5] |= ((pLutSt->mbr & 0x0400) >> 10) << 7; ++ } ++ else /*Asic auto-learning*/ ++ { ++ pFdbSmi[0] |= pLutSt->mac.octet[5]; ++ pFdbSmi[0] |= pLutSt->mac.octet[4] << 8; ++ ++ pFdbSmi[1] |= pLutSt->mac.octet[3]; ++ pFdbSmi[1] |= pLutSt->mac.octet[2] << 8; ++ ++ pFdbSmi[2] |= pLutSt->mac.octet[1]; ++ pFdbSmi[2] |= pLutSt->mac.octet[0] << 8; ++ ++ pFdbSmi[3] |= pLutSt->cvid_fid; ++ pFdbSmi[3] |= (pLutSt->l3lookup & 0x0001) << 12; ++ pFdbSmi[3] |= (pLutSt->ivl_svl & 0x0001) << 13; ++ pFdbSmi[3] |= ((pLutSt->spa & 0x0008) >> 3) << 15; ++ ++ pFdbSmi[4] |= pLutSt->efid; ++ pFdbSmi[4] |= (pLutSt->fid & 0x000F) << 3; ++ pFdbSmi[4] |= (pLutSt->sa_en & 0x0001) << 7; ++ pFdbSmi[4] |= (pLutSt->spa & 0x0007) << 8; ++ pFdbSmi[4] |= (pLutSt->age & 0x0007) << 11; ++ pFdbSmi[4] |= (pLutSt->auth & 0x0001) << 14; ++ pFdbSmi[4] |= (pLutSt->sa_block & 0x0001) << 15; ++ ++ pFdbSmi[5] |= pLutSt->da_block; ++ pFdbSmi[5] |= (pLutSt->lut_pri & 0x0007) << 1; ++ pFdbSmi[5] |= (pLutSt->fwd_en & 0x0001) << 4; ++ pFdbSmi[5] |= (pLutSt->nosalearn & 0x0001) << 5; ++ } ++} ++ ++ ++static void _rtl8367c_fdbStSmi2User( rtl8367c_luttb *pLutSt, rtk_uint16 *pFdbSmi) ++{ ++ /*L3 lookup*/ ++ if(pFdbSmi[3] & 0x1000) ++ { ++ if(pFdbSmi[3] & 0x2000) ++ { ++ pLutSt->sip = pFdbSmi[0] | (pFdbSmi[1] << 16); ++ pLutSt->dip = pFdbSmi[2] | ((pFdbSmi[3] & 0x0FFF) << 16); ++ ++ pLutSt->mbr = (pFdbSmi[4] & 0x00FF) | (((pFdbSmi[3] & 0xC000) >> 14) << 8) | (((pFdbSmi[5] & 0x0080) >> 7) << 10); ++ pLutSt->l3_vid = ((pFdbSmi[4] & 0xFF00) >> 8) | (pFdbSmi[5] & 0x000F); ++ ++ pLutSt->l3lookup = (pFdbSmi[3] & 0x1000) >> 12; ++ pLutSt->l3vidlookup = (pFdbSmi[3] & 0x2000) >> 13; ++ pLutSt->nosalearn = (pFdbSmi[5] & 0x0020) >> 5; ++ } ++ else ++ { ++ pLutSt->sip = pFdbSmi[0] | (pFdbSmi[1] << 16); ++ pLutSt->dip = pFdbSmi[2] | ((pFdbSmi[3] & 0x0FFF) << 16); ++ ++ pLutSt->lut_pri = (pFdbSmi[5] & 0x000E) >> 1; ++ pLutSt->fwd_en = (pFdbSmi[5] & 0x0010) >> 4; ++ ++ pLutSt->mbr = (pFdbSmi[4] & 0x00FF) | (((pFdbSmi[3] & 0xC000) >> 14) << 8) | (((pFdbSmi[5] & 0x0080) >> 7) << 10); ++ pLutSt->igmpidx = (pFdbSmi[4] & 0xFF00) >> 8; ++ ++ pLutSt->igmp_asic = (pFdbSmi[5] & 0x0001); ++ pLutSt->l3lookup = (pFdbSmi[3] & 0x1000) >> 12; ++ pLutSt->nosalearn = (pFdbSmi[5] & 0x0020) >> 5; ++ } ++ } ++ else if(pFdbSmi[2] & 0x0100) /*Multicast L2 Lookup*/ ++ { ++ pLutSt->mac.octet[0] = (pFdbSmi[2] & 0xFF00) >> 8; ++ pLutSt->mac.octet[1] = (pFdbSmi[2] & 0x00FF); ++ pLutSt->mac.octet[2] = (pFdbSmi[1] & 0xFF00) >> 8; ++ pLutSt->mac.octet[3] = (pFdbSmi[1] & 0x00FF); ++ pLutSt->mac.octet[4] = (pFdbSmi[0] & 0xFF00) >> 8; ++ pLutSt->mac.octet[5] = (pFdbSmi[0] & 0x00FF); ++ ++ pLutSt->cvid_fid = pFdbSmi[3] & 0x0FFF; ++ pLutSt->lut_pri = (pFdbSmi[5] & 0x000E) >> 1; ++ pLutSt->fwd_en = (pFdbSmi[5] & 0x0010) >> 4; ++ ++ pLutSt->mbr = (pFdbSmi[4] & 0x00FF) | (((pFdbSmi[3] & 0xC000) >> 14) << 8) | (((pFdbSmi[5] & 0x0080) >> 7) << 10); ++ pLutSt->igmpidx = (pFdbSmi[4] & 0xFF00) >> 8; ++ ++ pLutSt->igmp_asic = (pFdbSmi[5] & 0x0001); ++ pLutSt->l3lookup = (pFdbSmi[3] & 0x1000) >> 12; ++ pLutSt->ivl_svl = (pFdbSmi[3] & 0x2000) >> 13; ++ pLutSt->nosalearn = (pFdbSmi[5] & 0x0020) >> 5; ++ } ++ else /*Asic auto-learning*/ ++ { ++ pLutSt->mac.octet[0] = (pFdbSmi[2] & 0xFF00) >> 8; ++ pLutSt->mac.octet[1] = (pFdbSmi[2] & 0x00FF); ++ pLutSt->mac.octet[2] = (pFdbSmi[1] & 0xFF00) >> 8; ++ pLutSt->mac.octet[3] = (pFdbSmi[1] & 0x00FF); ++ pLutSt->mac.octet[4] = (pFdbSmi[0] & 0xFF00) >> 8; ++ pLutSt->mac.octet[5] = (pFdbSmi[0] & 0x00FF); ++ ++ pLutSt->cvid_fid = pFdbSmi[3] & 0x0FFF; ++ pLutSt->lut_pri = (pFdbSmi[5] & 0x000E) >> 1; ++ pLutSt->fwd_en = (pFdbSmi[5] & 0x0010) >> 4; ++ ++ pLutSt->sa_en = (pFdbSmi[4] & 0x0080) >> 7; ++ pLutSt->auth = (pFdbSmi[4] & 0x4000) >> 14; ++ pLutSt->spa = ((pFdbSmi[4] & 0x0700) >> 8) | (((pFdbSmi[3] & 0x8000) >> 15) << 3); ++ pLutSt->age = (pFdbSmi[4] & 0x3800) >> 11; ++ pLutSt->fid = (pFdbSmi[4] & 0x0078) >> 3; ++ pLutSt->efid = (pFdbSmi[4] & 0x0007); ++ pLutSt->sa_block = (pFdbSmi[4] & 0x8000) >> 15; ++ ++ pLutSt->da_block = (pFdbSmi[5] & 0x0001); ++ pLutSt->l3lookup = (pFdbSmi[3] & 0x1000) >> 12; ++ pLutSt->ivl_svl = (pFdbSmi[3] & 0x2000) >> 13; ++ pLutSt->nosalearn = (pFdbSmi[3] & 0x0020) >> 5; ++ } ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicLutIpMulticastLookup ++ * Description: ++ * Set LUT IP multicast lookup function ++ * Input: ++ * enabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicLutIpMulticastLookup(rtk_uint32 enabled) ++{ ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_LUT_CFG, RTL8367C_LUT_IPMC_HASH_OFFSET, enabled); ++} ++/* Function Name: ++ * rtl8367c_getAsicLutIpMulticastLookup ++ * Description: ++ * Get LUT IP multicast lookup function ++ * Input: ++ * pEnabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicLutIpMulticastLookup(rtk_uint32* pEnabled) ++{ ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_LUT_CFG, RTL8367C_LUT_IPMC_HASH_OFFSET, pEnabled); ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicLutIpMulticastLookup ++ * Description: ++ * Set LUT IP multicast + VID lookup function ++ * Input: ++ * enabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicLutIpMulticastVidLookup(rtk_uint32 enabled) ++{ ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_LUT_CFG2, RTL8367C_LUT_IPMC_VID_HASH_OFFSET, enabled); ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicLutIpMulticastVidLookup ++ * Description: ++ * Get LUT IP multicast lookup function ++ * Input: ++ * pEnabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicLutIpMulticastVidLookup(rtk_uint32* pEnabled) ++{ ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_LUT_CFG2, RTL8367C_LUT_IPMC_VID_HASH_OFFSET, pEnabled); ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicLutIpLookupMethod ++ * Description: ++ * Set LUT IP lookup hash with DIP or {DIP,SIP} pair ++ * Input: ++ * type - 1: When DIP can be found in IPMC_GROUP_TABLE, use DIP+SIP Hash, otherwise, use DIP+(SIP=0.0.0.0) Hash. ++ * 0: When DIP can be found in IPMC_GROUP_TABLE, use DIP+(SIP=0.0.0.0) Hash, otherwise use DIP+SIP Hash. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicLutIpLookupMethod(rtk_uint32 type) ++{ ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_LUT_CFG, RTL8367C_LUT_IPMC_LOOKUP_OP_OFFSET, type); ++} ++/* Function Name: ++ * rtl8367c_getAsicLutIpLookupMethod ++ * Description: ++ * Get LUT IP lookup hash with DIP or {DIP,SIP} pair ++ * Input: ++ * pType - 1: When DIP can be found in IPMC_GROUP_TABLE, use DIP+SIP Hash, otherwise, use DIP+(SIP=0.0.0.0) Hash. ++ * 0: When DIP can be found in IPMC_GROUP_TABLE, use DIP+(SIP=0.0.0.0) Hash, otherwise use DIP+SIP Hash. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicLutIpLookupMethod(rtk_uint32* pType) ++{ ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_LUT_CFG, RTL8367C_LUT_IPMC_LOOKUP_OP_OFFSET, pType); ++} ++/* Function Name: ++ * rtl8367c_setAsicLutAgeTimerSpeed ++ * Description: ++ * Set LUT ageing out speed ++ * Input: ++ * timer - Ageing out timer 0:Has been aged out ++ * speed - Ageing out speed 0-fastest 3-slowest ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - input parameter out of range ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicLutAgeTimerSpeed(rtk_uint32 timer, rtk_uint32 speed) ++{ ++ if(timer>RTL8367C_LUT_AGETIMERMAX) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ if(speed >RTL8367C_LUT_AGESPEEDMAX) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ return rtl8367c_setAsicRegBits(RTL8367C_REG_LUT_CFG, RTL8367C_AGE_TIMER_MASK | RTL8367C_AGE_SPEED_MASK, (timer << RTL8367C_AGE_TIMER_OFFSET) | (speed << RTL8367C_AGE_SPEED_OFFSET)); ++} ++/* Function Name: ++ * rtl8367c_getAsicLutAgeTimerSpeed ++ * Description: ++ * Get LUT ageing out speed ++ * Input: ++ * pTimer - Ageing out timer 0:Has been aged out ++ * pSpeed - Ageing out speed 0-fastest 3-slowest ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - input parameter out of range ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicLutAgeTimerSpeed(rtk_uint32* pTimer, rtk_uint32* pSpeed) ++{ ++ rtk_uint32 regData; ++ ret_t retVal; ++ ++ retVal = rtl8367c_getAsicReg(RTL8367C_REG_LUT_CFG, ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ *pTimer = (regData & RTL8367C_AGE_TIMER_MASK) >> RTL8367C_AGE_TIMER_OFFSET; ++ ++ *pSpeed = (regData & RTL8367C_AGE_SPEED_MASK) >> RTL8367C_AGE_SPEED_OFFSET; ++ ++ return RT_ERR_OK; ++ ++} ++/* Function Name: ++ * rtl8367c_setAsicLutCamTbUsage ++ * Description: ++ * Configure LUT CAM table usage ++ * Input: ++ * enabled - L2 CAM table usage 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicLutCamTbUsage(rtk_uint32 enabled) ++{ ++ ret_t retVal; ++ ++ retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_LUT_CFG, RTL8367C_BCAM_DISABLE_OFFSET, enabled ? 0 : 1); ++ ++ return retVal; ++} ++/* Function Name: ++ * rtl8367c_getAsicLutCamTbUsage ++ * Description: ++ * Get LUT CAM table usage ++ * Input: ++ * pEnabled - L2 CAM table usage 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicLutCamTbUsage(rtk_uint32* pEnabled) ++{ ++ ret_t retVal; ++ rtk_uint32 regData; ++ ++ if ((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_LUT_CFG, RTL8367C_BCAM_DISABLE_OFFSET, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ *pEnabled = regData ? 0 : 1; ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_setAsicLutLearnLimitNo ++ * Description: ++ * Set per-Port auto learning limit number ++ * Input: ++ * port - Physical port number (0~7) ++ * number - ASIC auto learning entries limit number ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * RT_ERR_LIMITED_L2ENTRY_NUM - Invalid auto learning limit number ++ * Note: ++ * None ++ */ ++ /*modification: RTL8367C_PORTIDMAX, RTL8367C_LUT_LEARNLIMITMAX, RTL8367C_LUT_PORT_LEARN_LIMITNO_REG*/ ++ret_t rtl8367c_setAsicLutLearnLimitNo(rtk_uint32 port, rtk_uint32 number) ++{ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ if(number > RTL8367C_LUT_LEARNLIMITMAX) ++ return RT_ERR_LIMITED_L2ENTRY_NUM; ++ ++ if(port < 8) ++ return rtl8367c_setAsicReg(RTL8367C_LUT_PORT_LEARN_LIMITNO_REG(port), number); ++ else ++ return rtl8367c_setAsicReg(RTL8367C_REG_LUT_PORT8_LEARN_LIMITNO+port-8, number); ++ ++} ++/* Function Name: ++ * rtl8367c_getAsicLutLearnLimitNo ++ * Description: ++ * Get per-Port auto learning limit number ++ * Input: ++ * port - Physical port number (0~7) ++ * pNumber - ASIC auto learning entries limit number ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ /*modification: RTL8367C_PORTIDMAX, RTL8367C_LUT_PORT_LEARN_LIMITNO_REG*/ ++ret_t rtl8367c_getAsicLutLearnLimitNo(rtk_uint32 port, rtk_uint32* pNumber) ++{ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ if(port < 8) ++ return rtl8367c_getAsicReg(RTL8367C_LUT_PORT_LEARN_LIMITNO_REG(port), pNumber); ++ else ++ return rtl8367c_getAsicReg(RTL8367C_REG_LUT_PORT8_LEARN_LIMITNO+port-8, pNumber); ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicSystemLutLearnLimitNo ++ * Description: ++ * Set system auto learning limit number ++ * Input: ++ * number - ASIC auto learning entries limit number ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * RT_ERR_LIMITED_L2ENTRY_NUM - Invalid auto learning limit number ++ * Note: ++ * None ++ */ ++ /*modification: RTL8367C_LUT_LEARNLIMITMAX*/ ++ret_t rtl8367c_setAsicSystemLutLearnLimitNo(rtk_uint32 number) ++{ ++ if(number > RTL8367C_LUT_LEARNLIMITMAX) ++ return RT_ERR_LIMITED_L2ENTRY_NUM; ++ ++ return rtl8367c_setAsicReg(RTL8367C_REG_LUT_SYS_LEARN_LIMITNO, number); ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicSystemLutLearnLimitNo ++ * Description: ++ * Get system auto learning limit number ++ * Input: ++ * port - Physical port number (0~7) ++ * pNumber - ASIC auto learning entries limit number ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicSystemLutLearnLimitNo(rtk_uint32 *pNumber) ++{ ++ if(NULL == pNumber) ++ return RT_ERR_NULL_POINTER; ++ ++ return rtl8367c_getAsicReg(RTL8367C_REG_LUT_SYS_LEARN_LIMITNO, pNumber); ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicLutLearnOverAct ++ * Description: ++ * Set auto learn over limit number action ++ * Input: ++ * action - Learn over action 0:normal, 1:drop 2:trap ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_NOT_ALLOWED - Invalid learn over action ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicLutLearnOverAct(rtk_uint32 action) ++{ ++ if(action >= LRNOVERACT_END) ++ return RT_ERR_NOT_ALLOWED; ++ ++ return rtl8367c_setAsicRegBits(RTL8367C_REG_PORT_SECURITY_CTRL, RTL8367C_LUT_LEARN_OVER_ACT_MASK, action); ++} ++/* Function Name: ++ * rtl8367c_getAsicLutLearnOverAct ++ * Description: ++ * Get auto learn over limit number action ++ * Input: ++ * pAction - Learn over action 0:normal, 1:drop 2:trap ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicLutLearnOverAct(rtk_uint32* pAction) ++{ ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_PORT_SECURITY_CTRL, RTL8367C_LUT_LEARN_OVER_ACT_MASK, pAction); ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicSystemLutLearnOverAct ++ * Description: ++ * Set system auto learn over limit number action ++ * Input: ++ * action - Learn over action 0:normal, 1:drop, 2:trap ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_NOT_ALLOWED - Invalid learn over action ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicSystemLutLearnOverAct(rtk_uint32 action) ++{ ++ if(action >= LRNOVERACT_END) ++ return RT_ERR_NOT_ALLOWED; ++ ++ return rtl8367c_setAsicRegBits(RTL8367C_REG_LUT_LRN_SYS_LMT_CTRL, RTL8367C_LUT_SYSTEM_LEARN_OVER_ACT_MASK, action); ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicSystemLutLearnOverAct ++ * Description: ++ * Get system auto learn over limit number action ++ * Input: ++ * pAction - Learn over action 0:normal, 1:drop 2:trap ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicSystemLutLearnOverAct(rtk_uint32 *pAction) ++{ ++ if(NULL == pAction) ++ return RT_ERR_NULL_POINTER; ++ ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_LUT_LRN_SYS_LMT_CTRL, RTL8367C_LUT_SYSTEM_LEARN_OVER_ACT_MASK, pAction); ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicSystemLutLearnPortMask ++ * Description: ++ * Set system auto learn limit port mask ++ * Input: ++ * portmask - port mask of system learning limit ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_MASK - Error port mask ++ * Note: ++ * None ++ */ ++ /*modification: RTL8367C_LUT_SYSTEM_LEARN_PMASK_MASK*/ ++ret_t rtl8367c_setAsicSystemLutLearnPortMask(rtk_uint32 portmask) ++{ ++ ret_t retVal; ++ ++ if(portmask > RTL8367C_PORTMASK) ++ return RT_ERR_PORT_MASK; ++ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_LUT_LRN_SYS_LMT_CTRL, RTL8367C_LUT_SYSTEM_LEARN_PMASK_MASK, portmask & 0xff); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_LUT_LRN_SYS_LMT_CTRL, RTL8367C_LUT_SYSTEM_LEARN_PMASK1_MASK, (portmask>>8) & 0x7); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++ ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicSystemLutLearnPortMask ++ * Description: ++ * Get system auto learn limit port mask ++ * Input: ++ * None ++ * Output: ++ * pPortmask - port mask of system learning limit ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_NULL_POINTER - NULL pointer ++ * Note: ++ * None ++ */ ++ /*modification: RTL8367C_LUT_SYSTEM_LEARN_PMASK_MASK*/ ++ret_t rtl8367c_getAsicSystemLutLearnPortMask(rtk_uint32 *pPortmask) ++{ ++ rtk_uint32 tmpmask; ++ ret_t retVal; ++ ++ if(NULL == pPortmask) ++ return RT_ERR_NULL_POINTER; ++ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_LUT_LRN_SYS_LMT_CTRL, RTL8367C_LUT_SYSTEM_LEARN_PMASK_MASK, &tmpmask); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ *pPortmask = tmpmask & 0xff; ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_LUT_LRN_SYS_LMT_CTRL, RTL8367C_LUT_SYSTEM_LEARN_PMASK1_MASK, &tmpmask); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ *pPortmask |= (tmpmask & 0x7) << 8; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicL2LookupTb ++ * Description: ++ * Set filtering database entry ++ * Input: ++ * pL2Table - L2 table entry writing to 8K+64 filtering database ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicL2LookupTb(rtl8367c_luttb *pL2Table) ++{ ++ ret_t retVal; ++ rtk_uint32 regData; ++ rtk_uint16 *accessPtr; ++ rtk_uint32 i; ++ rtk_uint16 smil2Table[RTL8367C_LUT_TABLE_SIZE]; ++ rtk_uint32 tblCmd; ++ rtk_uint32 busyCounter; ++ ++ memset(smil2Table, 0x00, sizeof(rtk_uint16) * RTL8367C_LUT_TABLE_SIZE); ++ _rtl8367c_fdbStUser2Smi(pL2Table, smil2Table); ++ ++ if(pL2Table->wait_time == 0) ++ busyCounter = RTL8367C_LUT_BUSY_CHECK_NO; ++ else ++ busyCounter = pL2Table->wait_time; ++ ++ while(busyCounter) ++ { ++ retVal = rtl8367c_getAsicRegBit(RTL8367C_TABLE_ACCESS_STATUS_REG, RTL8367C_TABLE_LUT_ADDR_BUSY_FLAG_OFFSET,®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ pL2Table->lookup_busy = regData; ++ if(!regData) ++ break; ++ ++ busyCounter --; ++ if(busyCounter == 0) ++ return RT_ERR_BUSYWAIT_TIMEOUT; ++ } ++ ++ accessPtr = smil2Table; ++ regData = *accessPtr; ++ for(i = 0; i < RTL8367C_LUT_ENTRY_SIZE; i++) ++ { ++ retVal = rtl8367c_setAsicReg(RTL8367C_TABLE_ACCESS_WRDATA_BASE + i, regData); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ accessPtr ++; ++ regData = *accessPtr; ++ ++ } ++ ++ tblCmd = (RTL8367C_TABLE_ACCESS_REG_DATA(TB_OP_WRITE,TB_TARGET_L2)) & (RTL8367C_TABLE_TYPE_MASK | RTL8367C_COMMAND_TYPE_MASK); ++ /* Write Command */ ++ retVal = rtl8367c_setAsicReg(RTL8367C_TABLE_ACCESS_CTRL_REG, tblCmd); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ if(pL2Table->wait_time == 0) ++ busyCounter = RTL8367C_LUT_BUSY_CHECK_NO; ++ else ++ busyCounter = pL2Table->wait_time; ++ ++ while(busyCounter) ++ { ++ retVal = rtl8367c_getAsicRegBit(RTL8367C_TABLE_ACCESS_STATUS_REG, RTL8367C_TABLE_LUT_ADDR_BUSY_FLAG_OFFSET,®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ pL2Table->lookup_busy = regData; ++ if(!regData) ++ break; ++ ++ busyCounter --; ++ if(busyCounter == 0) ++ return RT_ERR_BUSYWAIT_TIMEOUT; ++ } ++ ++ /*Read access status*/ ++ retVal = rtl8367c_getAsicRegBit(RTL8367C_TABLE_ACCESS_STATUS_REG, RTL8367C_HIT_STATUS_OFFSET, ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ pL2Table->lookup_hit = regData; ++ if(!pL2Table->lookup_hit) ++ return RT_ERR_FAILED; ++ ++ /*Read access address*/ ++ /* ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_TABLE_ACCESS_STATUS_REG, RTL8367C_TABLE_LUT_ADDR_TYPE_MASK | RTL8367C_TABLE_LUT_ADDR_ADDRESS_MASK,®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ pL2Table->address = regData;*/ ++ ++ retVal = rtl8367c_getAsicReg(RTL8367C_TABLE_ACCESS_STATUS_REG, ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ pL2Table->address = (regData & 0x7ff) | ((regData & 0x4000) >> 3) | ((regData & 0x800) << 1); ++ pL2Table->lookup_busy = 0; ++ ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_getAsicL2LookupTb ++ * Description: ++ * Get filtering database entry ++ * Input: ++ * pL2Table - L2 table entry writing to 2K+64 filtering database ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameter ++ * RT_ERR_BUSYWAIT_TIMEOUT - LUT is busy at retrieving ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicL2LookupTb(rtk_uint32 method, rtl8367c_luttb *pL2Table) ++{ ++ ret_t retVal; ++ rtk_uint32 regData; ++ rtk_uint16* accessPtr; ++ rtk_uint32 i; ++ rtk_uint16 smil2Table[RTL8367C_LUT_TABLE_SIZE]; ++ rtk_uint32 busyCounter; ++ rtk_uint32 tblCmd; ++ ++ if(pL2Table->wait_time == 0) ++ busyCounter = RTL8367C_LUT_BUSY_CHECK_NO; ++ else ++ busyCounter = pL2Table->wait_time; ++ ++ while(busyCounter) ++ { ++ retVal = rtl8367c_getAsicRegBit(RTL8367C_TABLE_ACCESS_STATUS_REG, RTL8367C_TABLE_LUT_ADDR_BUSY_FLAG_OFFSET,®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ pL2Table->lookup_busy = regData; ++ if(!pL2Table->lookup_busy) ++ break; ++ ++ busyCounter --; ++ if(busyCounter == 0) ++ return RT_ERR_BUSYWAIT_TIMEOUT; ++ } ++ ++ ++ tblCmd = (method << RTL8367C_ACCESS_METHOD_OFFSET) & RTL8367C_ACCESS_METHOD_MASK; ++ ++ switch(method) ++ { ++ case LUTREADMETHOD_ADDRESS: ++ case LUTREADMETHOD_NEXT_ADDRESS: ++ case LUTREADMETHOD_NEXT_L2UC: ++ case LUTREADMETHOD_NEXT_L2MC: ++ case LUTREADMETHOD_NEXT_L3MC: ++ case LUTREADMETHOD_NEXT_L2L3MC: ++ retVal = rtl8367c_setAsicReg(RTL8367C_TABLE_ACCESS_ADDR_REG, pL2Table->address); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ break; ++ case LUTREADMETHOD_MAC: ++ memset(smil2Table, 0x00, sizeof(rtk_uint16) * RTL8367C_LUT_TABLE_SIZE); ++ _rtl8367c_fdbStUser2Smi(pL2Table, smil2Table); ++ ++ accessPtr = smil2Table; ++ regData = *accessPtr; ++ for(i=0; iaddress); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ tblCmd = tblCmd | ((pL2Table->spa << RTL8367C_TABLE_ACCESS_CTRL_SPA_OFFSET) & RTL8367C_TABLE_ACCESS_CTRL_SPA_MASK); ++ ++ break; ++ default: ++ return RT_ERR_INPUT; ++ } ++ ++ tblCmd = tblCmd | ((RTL8367C_TABLE_ACCESS_REG_DATA(TB_OP_READ,TB_TARGET_L2)) & (RTL8367C_TABLE_TYPE_MASK | RTL8367C_COMMAND_TYPE_MASK)); ++ /* Read Command */ ++ retVal = rtl8367c_setAsicReg(RTL8367C_TABLE_ACCESS_CTRL_REG, tblCmd); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ if(pL2Table->wait_time == 0) ++ busyCounter = RTL8367C_LUT_BUSY_CHECK_NO; ++ else ++ busyCounter = pL2Table->wait_time; ++ ++ while(busyCounter) ++ { ++ retVal = rtl8367c_getAsicRegBit(RTL8367C_TABLE_ACCESS_STATUS_REG, RTL8367C_TABLE_LUT_ADDR_BUSY_FLAG_OFFSET,®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ pL2Table->lookup_busy = regData; ++ if(!pL2Table->lookup_busy) ++ break; ++ ++ busyCounter --; ++ if(busyCounter == 0) ++ return RT_ERR_BUSYWAIT_TIMEOUT; ++ } ++ ++ retVal = rtl8367c_getAsicRegBit(RTL8367C_TABLE_ACCESS_STATUS_REG, RTL8367C_HIT_STATUS_OFFSET,®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ pL2Table->lookup_hit = regData; ++ if(!pL2Table->lookup_hit) ++ return RT_ERR_L2_ENTRY_NOTFOUND; ++ ++ /*Read access address*/ ++ //retVal = rtl8367c_getAsicRegBits(RTL8367C_TABLE_ACCESS_STATUS_REG, RTL8367C_TABLE_LUT_ADDR_TYPE_MASK | RTL8367C_TABLE_LUT_ADDR_ADDRESS_MASK,®Data); ++ retVal = rtl8367c_getAsicReg(RTL8367C_TABLE_ACCESS_STATUS_REG, ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ pL2Table->address = (regData & 0x7ff) | ((regData & 0x4000) >> 3) | ((regData & 0x800) << 1); ++ ++ /*read L2 entry */ ++ memset(smil2Table, 0x00, sizeof(rtk_uint16) * RTL8367C_LUT_TABLE_SIZE); ++ ++ accessPtr = smil2Table; ++ ++ for(i = 0; i < RTL8367C_LUT_ENTRY_SIZE; i++) ++ { ++ retVal = rtl8367c_getAsicReg(RTL8367C_TABLE_ACCESS_RDDATA_BASE + i, ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ *accessPtr = regData; ++ ++ accessPtr ++; ++ } ++ ++ _rtl8367c_fdbStSmi2User(pL2Table, smil2Table); ++ ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_getAsicLutLearnNo ++ * Description: ++ * Get per-Port auto learning number ++ * Input: ++ * port - Physical port number (0~7) ++ * pNumber - ASIC auto learning entries number ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ /*modification:RTL8367C_PORTIDMAX, RTL8367C_REG_L2_LRN_CNT_REG, port10 reg is not continuous, wait for updating of base.h*/ ++ret_t rtl8367c_getAsicLutLearnNo(rtk_uint32 port, rtk_uint32* pNumber) ++{ ++ ret_t retVal; ++ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ if(port < 10) ++ { ++ retVal = rtl8367c_getAsicReg(RTL8367C_REG_L2_LRN_CNT_REG(port), pNumber); ++ if (retVal != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ { ++ retVal = rtl8367c_getAsicReg(RTL8367C_REG_L2_LRN_CNT_CTRL10, pNumber); ++ if (retVal != RT_ERR_OK) ++ return retVal; ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicLutFlushAll ++ * Description: ++ * Flush all entries in LUT. Includes static & dynamic entries ++ * Input: ++ * None ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicLutFlushAll(void) ++{ ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_L2_FLUSH_CTRL3, RTL8367C_L2_FLUSH_CTRL3_OFFSET, 1); ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicLutFlushAllStatus ++ * Description: ++ * Get Flush all status, 1:Busy, 0 normal ++ * Input: ++ * None ++ * Output: ++ * pBusyStatus - Busy state ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_NULL_POINTER - Null pointer ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicLutFlushAllStatus(rtk_uint32 *pBusyStatus) ++{ ++ if(NULL == pBusyStatus) ++ return RT_ERR_NULL_POINTER; ++ ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_L2_FLUSH_CTRL3, RTL8367C_L2_FLUSH_CTRL3_OFFSET, pBusyStatus); ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicLutForceFlush ++ * Description: ++ * Set per port force flush setting ++ * Input: ++ * portmask - portmask(0~0xFF) ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_MASK - Invalid portmask ++ * Note: ++ * None ++ */ ++ /*port8~port10 setup is done in a separate register, wait for updating of base.h, reg.h*/ ++ret_t rtl8367c_setAsicLutForceFlush(rtk_uint32 portmask) ++{ ++ ret_t retVal; ++ ++ if(portmask > RTL8367C_PORTMASK) ++ return RT_ERR_PORT_MASK; ++ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_FORCE_FLUSH_REG, RTL8367C_FORCE_FLUSH_PORTMASK_MASK, portmask & 0xff); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FORCE_FLUSH1, RTL8367C_PORTMASK1_MASK, (portmask >> 8) & 0x7); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_getAsicLutForceFlushStatus ++ * Description: ++ * Get per port force flush status ++ * Input: ++ * pPortmask - portmask(0~0xFF) ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ /*port8~port10 setup is done in a separate register, wait for updating of base.h, reg.h*/ ++ret_t rtl8367c_getAsicLutForceFlushStatus(rtk_uint32 *pPortmask) ++{ ++ rtk_uint32 tmpMask; ++ ret_t retVal; ++ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_FORCE_FLUSH_REG, RTL8367C_BUSY_STATUS_MASK,&tmpMask); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ *pPortmask = tmpMask & 0xff; ++ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FORCE_FLUSH1, RTL8367C_BUSY_STATUS1_MASK,&tmpMask); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ *pPortmask |= (tmpMask & 7) << 8; ++ ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_setAsicLutFlushMode ++ * Description: ++ * Set user force L2 pLutSt table flush mode ++ * Input: ++ * mode - 0:Port based 1: Port + VLAN based 2:Port + FID/MSTI based ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_NOT_ALLOWED - Actions not allowed by the function ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicLutFlushMode(rtk_uint32 mode) ++{ ++ if( mode >= FLUSHMDOE_END ) ++ return RT_ERR_NOT_ALLOWED; ++ ++ return rtl8367c_setAsicRegBits(RTL8367C_REG_L2_FLUSH_CTRL2, RTL8367C_LUT_FLUSH_MODE_MASK, mode); ++} ++/* Function Name: ++ * rtl8367c_getAsicLutFlushMode ++ * Description: ++ * Get user force L2 pLutSt table flush mode ++ * Input: ++ * pMode - 0:Port based 1: Port + VLAN based 2:Port + FID/MSTI based ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicLutFlushMode(rtk_uint32* pMode) ++{ ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_L2_FLUSH_CTRL2, RTL8367C_LUT_FLUSH_MODE_MASK, pMode); ++} ++/* Function Name: ++ * rtl8367c_setAsicLutFlushType ++ * Description: ++ * Get L2 LUT flush type ++ * Input: ++ * type - 0: dynamic unicast; 1: both dynamic and static unicast entry ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicLutFlushType(rtk_uint32 type) ++{ ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_L2_FLUSH_CTRL2, RTL8367C_LUT_FLUSH_TYPE_OFFSET,type); ++} ++/* Function Name: ++ * rtl8367c_getAsicLutFlushType ++ * Description: ++ * Set L2 LUT flush type ++ * Input: ++ * pType - 0: dynamic unicast; 1: both dynamic and static unicast entry ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicLutFlushType(rtk_uint32* pType) ++{ ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_L2_FLUSH_CTRL2, RTL8367C_LUT_FLUSH_TYPE_OFFSET,pType); ++} ++ ++ ++/* Function Name: ++ * rtl8367c_setAsicLutFlushVid ++ * Description: ++ * Set VID of Port + VID pLutSt flush mode ++ * Input: ++ * vid - Vid (0~4095) ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_VLAN_VID - Invalid VID parameter (0~4095) ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicLutFlushVid(rtk_uint32 vid) ++{ ++ if( vid > RTL8367C_VIDMAX ) ++ return RT_ERR_VLAN_VID; ++ ++ return rtl8367c_setAsicRegBits(RTL8367C_REG_L2_FLUSH_CTRL1, RTL8367C_LUT_FLUSH_VID_MASK, vid); ++} ++/* Function Name: ++ * rtl8367c_getAsicLutFlushVid ++ * Description: ++ * Get VID of Port + VID pLutSt flush mode ++ * Input: ++ * pVid - Vid (0~4095) ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicLutFlushVid(rtk_uint32* pVid) ++{ ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_L2_FLUSH_CTRL1, RTL8367C_LUT_FLUSH_VID_MASK, pVid); ++} ++/* Function Name: ++ * rtl8367c_setAsicPortFlusdFid ++ * Description: ++ * Set FID of Port + FID pLutSt flush mode ++ * Input: ++ * fid - FID/MSTI for force flush ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_L2_FID - Invalid FID (0~15) ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicLutFlushFid(rtk_uint32 fid) ++{ ++ if( fid > RTL8367C_FIDMAX ) ++ return RT_ERR_L2_FID; ++ ++ return rtl8367c_setAsicRegBits(RTL8367C_REG_L2_FLUSH_CTRL1, RTL8367C_LUT_FLUSH_FID_MASK, fid); ++} ++/* Function Name: ++ * rtl8367c_getAsicLutFlushFid ++ * Description: ++ * Get FID of Port + FID pLutSt flush mode ++ * Input: ++ * pFid - FID/MSTI for force flush ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicLutFlushFid(rtk_uint32* pFid) ++{ ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_L2_FLUSH_CTRL1, RTL8367C_LUT_FLUSH_FID_MASK, pFid); ++} ++/* Function Name: ++ * rtl8367c_setAsicLutDisableAging ++ * Description: ++ * Set L2 LUT aging per port setting ++ * Input: ++ * port - Physical port number (0~7) ++ * disabled - 0: enable aging; 1: disabling aging ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ /*modification:RTL8367C_PORTIDMAX*/ ++ret_t rtl8367c_setAsicLutDisableAging(rtk_uint32 port, rtk_uint32 disabled) ++{ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ return rtl8367c_setAsicRegBit(RTL8367C_LUT_AGEOUT_CTRL_REG, port, disabled); ++} ++/* Function Name: ++ * rtl8367c_getAsicLutDisableAging ++ * Description: ++ * Get L2 LUT aging per port setting ++ * Input: ++ * port - Physical port number (0~7) ++ * pDisabled - 0: enable aging; 1: disabling aging ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ /*modification:RTL8367C_PORTIDMAX*/ ++ret_t rtl8367c_getAsicLutDisableAging(rtk_uint32 port, rtk_uint32 *pDisabled) ++{ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ return rtl8367c_getAsicRegBit(RTL8367C_LUT_AGEOUT_CTRL_REG, port, pDisabled); ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicLutIPMCGroup ++ * Description: ++ * Set IPMC Group Table ++ * Input: ++ * index - the entry index in table (0 ~ 63) ++ * group_addr - the multicast group address (224.0.0.0 ~ 239.255.255.255) ++ * vid - VLAN ID ++ * pmask - portmask ++ * valid - valid bit ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid parameter ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicLutIPMCGroup(rtk_uint32 index, ipaddr_t group_addr, rtk_uint32 vid, rtk_uint32 pmask, rtk_uint32 valid) ++{ ++ rtk_uint32 regAddr, regData, bitoffset; ++ ipaddr_t ipData; ++ ret_t retVal; ++ ++ if(index > RTL8367C_LUT_IPMCGRP_TABLE_MAX) ++ return RT_ERR_INPUT; ++ ++ if (vid > RTL8367C_VIDMAX) ++ return RT_ERR_VLAN_VID; ++ ++ ipData = group_addr; ++ ++ if( (ipData & 0xF0000000) != 0xE0000000) /* not in 224.0.0.0 ~ 239.255.255.255 */ ++ return RT_ERR_INPUT; ++ ++ /* Group Address */ ++ regAddr = RTL8367C_REG_IPMC_GROUP_ENTRY0_H + (index * 2); ++ regData = ((ipData & 0x0FFFFFFF) >> 16); ++ ++ if( (retVal = rtl8367c_setAsicReg(regAddr, regData)) != RT_ERR_OK) ++ return retVal; ++ ++ regAddr++; ++ regData = (ipData & 0x0000FFFF); ++ ++ if( (retVal = rtl8367c_setAsicReg(regAddr, regData)) != RT_ERR_OK) ++ return retVal; ++ ++ /* VID */ ++ regAddr = RTL8367C_REG_IPMC_GROUP_VID_00 + index; ++ regData = vid; ++ ++ if( (retVal = rtl8367c_setAsicReg(regAddr, regData)) != RT_ERR_OK) ++ return retVal; ++ ++ /* portmask */ ++ regAddr = RTL8367C_REG_IPMC_GROUP_PMSK_00 + index; ++ regData = pmask; ++ ++ if( (retVal = rtl8367c_setAsicReg(regAddr, regData)) != RT_ERR_OK) ++ return retVal; ++ ++ /* valid */ ++ regAddr = RTL8367C_REG_IPMC_GROUP_VALID_15_0 + (index / 16); ++ bitoffset = index % 16; ++ if( (retVal = rtl8367c_setAsicRegBit(regAddr, bitoffset, valid)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicLutIPMCGroup ++ * Description: ++ * Set IPMC Group Table ++ * Input: ++ * index - the entry index in table (0 ~ 63) ++ * Output: ++ * pGroup_addr - the multicast group address (224.0.0.0 ~ 239.255.255.255) ++ * pVid - VLAN ID ++ * pPmask - portmask ++ * pValid - Valid bit ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid parameter ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicLutIPMCGroup(rtk_uint32 index, ipaddr_t *pGroup_addr, rtk_uint32 *pVid, rtk_uint32 *pPmask, rtk_uint32 *pValid) ++{ ++ rtk_uint32 regAddr, regData, bitoffset; ++ ipaddr_t ipData; ++ ret_t retVal; ++ ++ if(index > RTL8367C_LUT_IPMCGRP_TABLE_MAX) ++ return RT_ERR_INPUT; ++ ++ if (NULL == pGroup_addr) ++ return RT_ERR_NULL_POINTER; ++ ++ if (NULL == pVid) ++ return RT_ERR_NULL_POINTER; ++ ++ if (NULL == pPmask) ++ return RT_ERR_NULL_POINTER; ++ ++ /* Group address */ ++ regAddr = RTL8367C_REG_IPMC_GROUP_ENTRY0_H + (index * 2); ++ if( (retVal = rtl8367c_getAsicReg(regAddr, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ *pGroup_addr = (((regData & 0x00000FFF) << 16) | 0xE0000000); ++ ++ regAddr++; ++ if( (retVal = rtl8367c_getAsicReg(regAddr, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ ipData = (*pGroup_addr | (regData & 0x0000FFFF)); ++ *pGroup_addr = ipData; ++ ++ /* VID */ ++ regAddr = RTL8367C_REG_IPMC_GROUP_VID_00 + index; ++ if( (retVal = rtl8367c_getAsicReg(regAddr, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ *pVid = regData; ++ ++ /* portmask */ ++ regAddr = RTL8367C_REG_IPMC_GROUP_PMSK_00 + index; ++ if( (retVal = rtl8367c_getAsicReg(regAddr, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ *pPmask = regData; ++ ++ /* valid */ ++ regAddr = RTL8367C_REG_IPMC_GROUP_VALID_15_0 + (index / 16); ++ bitoffset = index % 16; ++ if( (retVal = rtl8367c_getAsicRegBit(regAddr, bitoffset, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ *pValid = regData; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicLutLinkDownForceAging ++ * Description: ++ * Set LUT link down aging setting. ++ * Input: ++ * enable - link down aging setting ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_ENABLE - Invalid parameter ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicLutLinkDownForceAging(rtk_uint32 enable) ++{ ++ if(enable > 1) ++ return RT_ERR_ENABLE; ++ ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_LUT_CFG, RTL8367C_LINKDOWN_AGEOUT_OFFSET, enable ? 0 : 1); ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicLutLinkDownForceAging ++ * Description: ++ * Get LUT link down aging setting. ++ * Input: ++ * pEnable - link down aging setting ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_ENABLE - Invalid parameter ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicLutLinkDownForceAging(rtk_uint32 *pEnable) ++{ ++ rtk_uint32 value; ++ ret_t retVal; ++ ++ if ((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_LUT_CFG, RTL8367C_LINKDOWN_AGEOUT_OFFSET, &value)) != RT_ERR_OK) ++ return retVal; ++ ++ *pEnable = value ? 0 : 1; ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicLutIpmcFwdRouterPort ++ * Description: ++ * Set IPMC packet forward to router port also or not ++ * Input: ++ * enable - 1: Include router port, 0, exclude router port ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_ENABLE Invalid parameter ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicLutIpmcFwdRouterPort(rtk_uint32 enable) ++{ ++ if(enable > 1) ++ return RT_ERR_ENABLE; ++ ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_LUT_CFG2, RTL8367C_LUT_IPMC_FWD_RPORT_OFFSET, enable); ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicLutIpmcFwdRouterPort ++ * Description: ++ * Get IPMC packet forward to router port also or not ++ * Input: ++ * None ++ * Output: ++ * pEnable - 1: Include router port, 0, exclude router port ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_NULL_POINTER - Null pointer ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicLutIpmcFwdRouterPort(rtk_uint32 *pEnable) ++{ ++ if(NULL == pEnable) ++ return RT_ERR_NULL_POINTER; ++ ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_LUT_CFG2, RTL8367C_LUT_IPMC_FWD_RPORT_OFFSET, pEnable); ++} ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_meter.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_meter.c +new file mode 100644 +index 000000000000..5412591a8245 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_meter.c +@@ -0,0 +1,305 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : Shared meter related functions ++ * ++ */ ++#include ++/* Function Name: ++ * rtl8367c_setAsicShareMeter ++ * Description: ++ * Set meter configuration ++ * Input: ++ * index - hared meter index (0-31) ++ * rate - 17-bits rate of share meter, unit is 8Kpbs ++ * ifg - Including IFG in rate calculation, 1:include 0:exclude ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_FILTER_METER_ID - Invalid meter ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicShareMeter(rtk_uint32 index, rtk_uint32 rate, rtk_uint32 ifg) ++{ ++ ret_t retVal; ++ ++ if(index > RTL8367C_METERMAX) ++ return RT_ERR_FILTER_METER_ID; ++ ++ if(index < 32) ++ { ++ /*19-bits Rate*/ ++ retVal = rtl8367c_setAsicReg(RTL8367C_METER_RATE_REG(index), rate&0xFFFF); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ retVal = rtl8367c_setAsicReg(RTL8367C_METER_RATE_REG(index) + 1, (rate &0x70000) >> 16); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ retVal = rtl8367c_setAsicRegBit(RTL8367C_METER_IFG_CTRL_REG(index), RTL8367C_METER_IFG_OFFSET(index), ifg); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ { ++ /*19-bits Rate*/ ++ retVal = rtl8367c_setAsicReg(RTL8367C_REG_METER32_RATE_CTRL0 + ((index-32) << 1), rate&0xFFFF); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ retVal = rtl8367c_setAsicReg(RTL8367C_REG_METER32_RATE_CTRL0 + ((index-32) << 1) + 1, (rate &0x70000) >> 16); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_METER_IFG_CTRL2 + ((index-32) >> 4), RTL8367C_METER_IFG_OFFSET(index), ifg); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_getAsicShareMeter ++ * Description: ++ * Get meter configuration ++ * Input: ++ * index - hared meter index (0-31) ++ * pRate - 17-bits rate of share meter, unit is 8Kpbs ++ * pIfg - Including IFG in rate calculation, 1:include 0:exclude ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_FILTER_METER_ID - Invalid meter ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicShareMeter(rtk_uint32 index, rtk_uint32 *pRate, rtk_uint32 *pIfg) ++{ ++ rtk_uint32 regData; ++ rtk_uint32 regData2; ++ ret_t retVal; ++ ++ if(index > RTL8367C_METERMAX) ++ return RT_ERR_FILTER_METER_ID; ++ ++ if(index < 32) ++ { ++ /*17-bits Rate*/ ++ retVal = rtl8367c_getAsicReg(RTL8367C_METER_RATE_REG(index), ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ retVal = rtl8367c_getAsicReg(RTL8367C_METER_RATE_REG(index) + 1, ®Data2); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ *pRate = ((regData2 << 16) & 0x70000) | regData; ++ /*IFG*/ ++ retVal = rtl8367c_getAsicRegBit(RTL8367C_METER_IFG_CTRL_REG(index), RTL8367C_METER_IFG_OFFSET(index), pIfg); ++ ++ return retVal; ++ } ++ else ++ { ++ /*17-bits Rate*/ ++ retVal = rtl8367c_getAsicReg(RTL8367C_REG_METER32_RATE_CTRL0 + ((index-32) << 1), ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ retVal = rtl8367c_getAsicReg(RTL8367C_REG_METER32_RATE_CTRL0 + ((index-32) << 1) + 1, ®Data2); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ *pRate = ((regData2 << 16) & 0x70000) | regData; ++ /*IFG*/ ++ retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_METER_IFG_CTRL2 + ((index-32) >> 4), RTL8367C_METER_IFG_OFFSET(index), pIfg); ++ ++ return retVal; ++ } ++} ++/* Function Name: ++ * rtl8367c_setAsicShareMeterBucketSize ++ * Description: ++ * Set meter related leaky bucket threshold ++ * Input: ++ * index - hared meter index (0-31) ++ * lbthreshold - Leaky bucket threshold of meter ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_FILTER_METER_ID - Invalid meter ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicShareMeterBucketSize(rtk_uint32 index, rtk_uint32 lbthreshold) ++{ ++ ++ if(index > RTL8367C_METERMAX) ++ return RT_ERR_FILTER_METER_ID; ++ ++ if(index < 32) ++ return rtl8367c_setAsicReg(RTL8367C_METER_BUCKET_SIZE_REG(index), lbthreshold); ++ else ++ return rtl8367c_setAsicReg(RTL8367C_REG_METER32_BUCKET_SIZE + index - 32, lbthreshold); ++} ++/* Function Name: ++ * rtl8367c_getAsicShareMeterBucketSize ++ * Description: ++ * Get meter related leaky bucket threshold ++ * Input: ++ * index - hared meter index (0-31) ++ * pLbthreshold - Leaky bucket threshold of meter ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_FILTER_METER_ID - Invalid meter ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicShareMeterBucketSize(rtk_uint32 index, rtk_uint32 *pLbthreshold) ++{ ++ if(index > RTL8367C_METERMAX) ++ return RT_ERR_FILTER_METER_ID; ++ ++ if(index < 32) ++ return rtl8367c_getAsicReg(RTL8367C_METER_BUCKET_SIZE_REG(index), pLbthreshold); ++ else ++ return rtl8367c_getAsicReg(RTL8367C_REG_METER32_BUCKET_SIZE + index - 32, pLbthreshold); ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicShareMeterType ++ * Description: ++ * Set meter Type ++ * Input: ++ * index - shared meter index (0-31) ++ * Type - 0: kbps, 1: pps ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_FILTER_METER_ID - Invalid meter ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicShareMeterType(rtk_uint32 index, rtk_uint32 type) ++{ ++ rtk_uint32 reg; ++ ++ if(index > RTL8367C_METERMAX) ++ return RT_ERR_FILTER_METER_ID; ++ ++ if(index < 32) ++ reg = RTL8367C_REG_METER_MODE_SETTING0 + (index / 16); ++ else ++ reg = RTL8367C_REG_METER_MODE_SETTING2 + ((index - 32) / 16); ++ return rtl8367c_setAsicRegBit(reg, index % 16, type); ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicShareMeterType ++ * Description: ++ * Get meter Type ++ * Input: ++ * index - shared meter index (0-31) ++ * Output: ++ * pType - 0: kbps, 1: pps ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_FILTER_METER_ID - Invalid meter ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicShareMeterType(rtk_uint32 index, rtk_uint32 *pType) ++{ ++ rtk_uint32 reg; ++ ++ if(index > RTL8367C_METERMAX) ++ return RT_ERR_FILTER_METER_ID; ++ ++ if(NULL == pType) ++ return RT_ERR_NULL_POINTER; ++ ++ if(index < 32) ++ reg = RTL8367C_REG_METER_MODE_SETTING0 + (index / 16); ++ else ++ reg = RTL8367C_REG_METER_MODE_SETTING2 + ((index - 32) / 16); ++ return rtl8367c_getAsicRegBit(reg, index % 16, pType); ++} ++ ++ ++/* Function Name: ++ * rtl8367c_setAsicMeterExceedStatus ++ * Description: ++ * Clear shared meter status ++ * Input: ++ * index - hared meter index (0-31) ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_FILTER_METER_ID - Invalid meter ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicMeterExceedStatus(rtk_uint32 index) ++{ ++ if(index > RTL8367C_METERMAX) ++ return RT_ERR_FILTER_METER_ID; ++ ++ if(index < 32) ++ return rtl8367c_setAsicRegBit(RTL8367C_METER_OVERRATE_INDICATOR_REG(index), RTL8367C_METER_EXCEED_OFFSET(index), 1); ++ else ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_METER_OVERRATE_INDICATOR2 + ((index - 32) >> 4), RTL8367C_METER_EXCEED_OFFSET(index), 1); ++ ++} ++/* Function Name: ++ * rtl8367c_getAsicMeterExceedStatus ++ * Description: ++ * Get shared meter status ++ * Input: ++ * index - hared meter index (0-31) ++ * pStatus - 0: rate doesn't exceed 1: rate exceeds ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_FILTER_METER_ID - Invalid meter ++ * Note: ++ * If rate is over rate*8Kbps of a meter, the state bit of this meter is set to 1. ++ */ ++ret_t rtl8367c_getAsicMeterExceedStatus(rtk_uint32 index, rtk_uint32* pStatus) ++{ ++ if(index > RTL8367C_METERMAX) ++ return RT_ERR_FILTER_METER_ID; ++ ++ if(index < 32) ++ return rtl8367c_getAsicRegBit(RTL8367C_METER_OVERRATE_INDICATOR_REG(index), RTL8367C_METER_EXCEED_OFFSET(index), pStatus); ++ else ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_METER_OVERRATE_INDICATOR2 + ((index - 32) >> 4), RTL8367C_METER_EXCEED_OFFSET(index), pStatus); ++} ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_mib.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_mib.c +new file mode 100644 +index 000000000000..7da098c49fc9 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_mib.c +@@ -0,0 +1,570 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : MIB related functions ++ * ++ */ ++ ++#include ++/* Function Name: ++ * rtl8367c_setAsicMIBsCounterReset ++ * Description: ++ * Reset global/queue manage or per-port MIB counter ++ * Input: ++ * greset - Global reset ++ * qmreset - Queue management reset ++ * portmask - Port reset mask ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicMIBsCounterReset(rtk_uint32 greset, rtk_uint32 qmreset, rtk_uint32 portmask) ++{ ++ ret_t retVal; ++ rtk_uint32 regData; ++ rtk_uint32 regBits; ++ ++ regBits = RTL8367C_GLOBAL_RESET_MASK | ++ RTL8367C_QM_RESET_MASK | ++ RTL8367C_MIB_PORT07_MASK | ++ ((rtk_uint32)0x7 << 13); ++ regData = ((greset << RTL8367C_GLOBAL_RESET_OFFSET) & RTL8367C_GLOBAL_RESET_MASK) | ++ ((qmreset << RTL8367C_QM_RESET_OFFSET) & RTL8367C_QM_RESET_MASK) | ++ (((portmask & 0xFF) << RTL8367C_PORT0_RESET_OFFSET) & RTL8367C_MIB_PORT07_MASK) | ++ (((portmask >> 8)&0x7) << 13); ++ ++ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_MIB_CTRL0, regBits, (regData >> RTL8367C_PORT0_RESET_OFFSET)); ++ ++ return retVal; ++} ++/* Function Name: ++ * rtl8367c_getAsicMIBsCounter ++ * Description: ++ * Get MIBs counter ++ * Input: ++ * port - Physical port number (0~7) ++ * mibIdx - MIB counter index ++ * pCounter - MIB retrieved counter ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * RT_ERR_BUSYWAIT_TIMEOUT - MIB is busy at retrieving ++ * RT_ERR_STAT_CNTR_FAIL - MIB is resetting ++ * Note: ++ * Before MIBs counter retrieving, writing accessing address to ASIC at first and check the MIB ++ * control register status. If busy bit of MIB control is set, that means MIB counter have been ++ * waiting for preparing, then software must wait after this busy flag reset by ASIC. This driver ++ * did not recycle reading user desired counter. Software must use driver again to get MIB counter ++ * if return value is not RT_ERR_OK. ++ */ ++ret_t rtl8367c_getAsicMIBsCounter(rtk_uint32 port, RTL8367C_MIBCOUNTER mibIdx, rtk_uint64* pCounter) ++{ ++ ret_t retVal; ++ rtk_uint32 regAddr; ++ rtk_uint32 regData; ++ rtk_uint32 mibAddr; ++ rtk_uint32 mibOff=0; ++ ++ /* address offset to MIBs counter */ ++ CONST rtk_uint16 mibLength[RTL8367C_MIBS_NUMBER]= { ++ 4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, ++ 4,2,2,2,2,2,2,2,2, ++ 4,2,2,2,2,2,2,2,2,2,2,2,2,2,2, ++ 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}; ++ ++ rtk_uint16 i; ++ rtk_uint64 mibCounter; ++ ++ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ if(mibIdx >= RTL8367C_MIBS_NUMBER) ++ return RT_ERR_STAT_INVALID_CNTR; ++ ++ if(dot1dTpLearnedEntryDiscards == mibIdx) ++ { ++ mibAddr = RTL8367C_MIB_LEARNENTRYDISCARD_OFFSET; ++ } ++ else ++ { ++ i = 0; ++ mibOff = RTL8367C_MIB_PORT_OFFSET * port; ++ ++ if(port > 7) ++ mibOff = mibOff + 68; ++ ++ while(i < mibIdx) ++ { ++ mibOff += mibLength[i]; ++ i++; ++ } ++ ++ mibAddr = mibOff; ++ } ++ ++ ++ /*writing access counter address first*/ ++ /*This address is SRAM address, and SRAM address = MIB register address >> 2*/ ++ /*then ASIC will prepare 64bits counter wait for being retrieved*/ ++ /*Write Mib related address to access control register*/ ++ retVal = rtl8367c_setAsicReg(RTL8367C_REG_MIB_ADDRESS, (mibAddr >> 2)); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ ++ ++ /* polling busy flag */ ++ i = 100; ++ while(i > 0) ++ { ++ /*read MIB control register*/ ++ retVal = rtl8367c_getAsicReg(RTL8367C_MIB_CTRL_REG,®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ if((regData & RTL8367C_MIB_CTRL0_BUSY_FLAG_MASK) == 0) ++ { ++ break; ++ } ++ ++ i--; ++ } ++ ++ if(regData & RTL8367C_MIB_CTRL0_BUSY_FLAG_MASK) ++ return RT_ERR_BUSYWAIT_TIMEOUT; ++ ++ if(regData & RTL8367C_RESET_FLAG_MASK) ++ return RT_ERR_STAT_CNTR_FAIL; ++ ++ mibCounter = 0; ++ i = mibLength[mibIdx]; ++ if(4 == i) ++ regAddr = RTL8367C_MIB_COUNTER_BASE_REG + 3; ++ else ++ regAddr = RTL8367C_MIB_COUNTER_BASE_REG + ((mibOff + 1) % 4); ++ ++ while(i) ++ { ++ retVal = rtl8367c_getAsicReg(regAddr, ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ mibCounter = (mibCounter << 16) | (regData & 0xFFFF); ++ ++ regAddr --; ++ i --; ++ ++ } ++ ++ *pCounter = mibCounter; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicMIBsLogCounter ++ * Description: ++ * Get MIBs Logging counter ++ * Input: ++ * index - The index of 32 logging counter (0 ~ 31) ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_ENTRY_INDEX - Wrong index ++ * RT_ERR_BUSYWAIT_TIMEOUT - MIB is busy at retrieving ++ * RT_ERR_STAT_CNTR_FAIL - MIB is resetting ++ * Note: ++ * This API get 32 logging counter ++ */ ++ret_t rtl8367c_getAsicMIBsLogCounter(rtk_uint32 index, rtk_uint32 *pCounter) ++{ ++ ret_t retVal; ++ rtk_uint32 regAddr; ++ rtk_uint32 regData; ++ rtk_uint32 mibAddr; ++ rtk_uint16 i; ++ rtk_uint64 mibCounter; ++ ++ if(index > RTL8367C_MIB_MAX_LOG_CNT_IDX) ++ return RT_ERR_ENTRY_INDEX; ++ ++ mibAddr = RTL8367C_MIB_LOG_CNT_OFFSET + ((index / 2) * 4); ++ ++ retVal = rtl8367c_setAsicReg(RTL8367C_REG_MIB_ADDRESS, (mibAddr >> 2)); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ /*read MIB control register*/ ++ retVal = rtl8367c_getAsicReg(RTL8367C_MIB_CTRL_REG, ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ if(regData & RTL8367C_MIB_CTRL0_BUSY_FLAG_MASK) ++ return RT_ERR_BUSYWAIT_TIMEOUT; ++ ++ if(regData & RTL8367C_RESET_FLAG_MASK) ++ return RT_ERR_STAT_CNTR_FAIL; ++ ++ mibCounter = 0; ++ if((index % 2) == 1) ++ regAddr = RTL8367C_MIB_COUNTER_BASE_REG + 3; ++ else ++ regAddr = RTL8367C_MIB_COUNTER_BASE_REG + 1; ++ ++ for(i = 0; i <= 1; i++) ++ { ++ retVal = rtl8367c_getAsicReg(regAddr, ®Data); ++ ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ mibCounter = (mibCounter << 16) | (regData & 0xFFFF); ++ ++ regAddr --; ++ } ++ ++ *pCounter = mibCounter; ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicMIBsControl ++ * Description: ++ * Get MIB control register ++ * Input: ++ * pMask - MIB control status mask bit[0]-busy bit[1] ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * Software need to check this control register after doing port resetting or global resetting ++ */ ++ret_t rtl8367c_getAsicMIBsControl(rtk_uint32* pMask) ++{ ++ ret_t retVal; ++ rtk_uint32 regData; ++ ++ retVal = rtl8367c_getAsicReg(RTL8367C_MIB_CTRL_REG, ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ *pMask = regData & (RTL8367C_MIB_CTRL0_BUSY_FLAG_MASK | RTL8367C_RESET_FLAG_MASK); ++ ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_setAsicMIBsResetValue ++ * Description: ++ * Reset all counter to 0 or 1 ++ * Input: ++ * value - Reset to value 0 or 1 ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicMIBsResetValue(rtk_uint32 value) ++{ ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_MIB_CTRL0, RTL8367C_RESET_VALUE_OFFSET, value); ++} ++/* Function Name: ++ * rtl8367c_getAsicMIBsResetValue ++ * Description: ++ * Reset all counter to 0 or 1 ++ * Input: ++ * value - Reset to value 0 or 1 ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicMIBsResetValue(rtk_uint32* value) ++{ ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_MIB_CTRL0, RTL8367C_RESET_VALUE_OFFSET, value); ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicMIBsUsageMode ++ * Description: ++ * MIB update mode ++ * Input: ++ * mode - 1: latch all MIBs by timer 0:normal free run counting ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicMIBsUsageMode(rtk_uint32 mode) ++{ ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_MIB_CTRL4, RTL8367C_MIB_USAGE_MODE_OFFSET, mode); ++} ++/* Function Name: ++ * rtl8367c_getAsicMIBsUsageMode ++ * Description: ++ * MIB update mode ++ * Input: ++ * pMode - 1: latch all MIBs by timer 0:normal free run counting ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicMIBsUsageMode(rtk_uint32* pMode) ++{ ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_MIB_CTRL4, RTL8367C_MIB_USAGE_MODE_OFFSET, pMode); ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicMIBsTimer ++ * Description: ++ * MIB latching timer ++ * Input: ++ * timer - latch timer, unit 1 second ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicMIBsTimer(rtk_uint32 timer) ++{ ++ return rtl8367c_setAsicRegBits(RTL8367C_REG_MIB_CTRL4, RTL8367C_MIB_TIMER_MASK, timer); ++} ++/* Function Name: ++ * rtl8367c_getAsicMIBsTimer ++ * Description: ++ * MIB latching timer ++ * Input: ++ * pTimer - latch timer, unit 1 second ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicMIBsTimer(rtk_uint32* pTimer) ++{ ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_MIB_CTRL4, RTL8367C_MIB_TIMER_MASK, pTimer); ++} ++/* Function Name: ++ * rtl8367c_setAsicMIBsLoggingMode ++ * Description: ++ * MIB logging counter mode ++ * Input: ++ * index - logging counter mode index (0~15) ++ * mode - 0:32-bits mode 1:64-bits mode ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - input parameter out of range ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicMIBsLoggingMode(rtk_uint32 index, rtk_uint32 mode) ++{ ++ if(index > RTL8367C_MIB_MAX_LOG_MODE_IDX) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_MIB_CTRL3, index,mode); ++} ++/* Function Name: ++ * rtl8367c_getAsicMIBsLoggingMode ++ * Description: ++ * MIB logging counter mode ++ * Input: ++ * index - logging counter mode index (0~15) ++ * pMode - 0:32-bits mode 1:64-bits mode ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - input parameter out of range ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicMIBsLoggingMode(rtk_uint32 index, rtk_uint32* pMode) ++{ ++ if(index > RTL8367C_MIB_MAX_LOG_MODE_IDX) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_MIB_CTRL3, index,pMode); ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicMIBsLoggingType ++ * Description: ++ * MIB logging counter type ++ * Input: ++ * index - logging counter mode index (0~15) ++ * type - 0:Packet count 1:Byte count ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - input parameter out of range ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicMIBsLoggingType(rtk_uint32 index, rtk_uint32 type) ++{ ++ if(index > RTL8367C_MIB_MAX_LOG_MODE_IDX) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_MIB_CTRL5, index,type); ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicMIBsLoggingType ++ * Description: ++ * MIB logging counter type ++ * Input: ++ * index - logging counter mode index (0~15) ++ * pType - 0:Packet count 1:Byte count ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - input parameter out of range ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicMIBsLoggingType(rtk_uint32 index, rtk_uint32* pType) ++{ ++ if(index > RTL8367C_MIB_MAX_LOG_MODE_IDX) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_MIB_CTRL5, index,pType); ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicMIBsResetLoggingCounter ++ * Description: ++ * MIB logging counter type ++ * Input: ++ * index - logging counter index (0~31) ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - input parameter out of range ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicMIBsResetLoggingCounter(rtk_uint32 index) ++{ ++ ret_t retVal; ++ ++ if(index > RTL8367C_MIB_MAX_LOG_CNT_IDX) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ if(index < 16) ++ retVal = rtl8367c_setAsicReg(RTL8367C_REG_MIB_CTRL1, 1< ++/* Function Name: ++ * rtl8367c_setAsicPortMirror ++ * Description: ++ * Set port mirror function ++ * Input: ++ * source - Source port ++ * monitor - Monitor (destination) port ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicPortMirror(rtk_uint32 source, rtk_uint32 monitor) ++{ ++ ret_t retVal; ++ ++ if((source > RTL8367C_PORTIDMAX) || (monitor > RTL8367C_PORTIDMAX)) ++ return RT_ERR_PORT_ID; ++ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_MIRROR_CTRL_REG, RTL8367C_MIRROR_SOURCE_PORT_MASK, source); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ ++ return rtl8367c_setAsicRegBits(RTL8367C_MIRROR_CTRL_REG, RTL8367C_MIRROR_MONITOR_PORT_MASK, monitor); ++} ++/* Function Name: ++ * rtl8367c_getAsicPortMirror ++ * Description: ++ * Get port mirror function ++ * Input: ++ * pSource - Source port ++ * pMonitor - Monitor (destination) port ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicPortMirror(rtk_uint32 *pSource, rtk_uint32 *pMonitor) ++{ ++ ret_t retVal; ++ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_MIRROR_CTRL_REG, RTL8367C_MIRROR_SOURCE_PORT_MASK, pSource); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ return rtl8367c_getAsicRegBits(RTL8367C_MIRROR_CTRL_REG, RTL8367C_MIRROR_MONITOR_PORT_MASK, pMonitor); ++} ++/* Function Name: ++ * rtl8367c_setAsicPortMirrorRxFunction ++ * Description: ++ * Set the mirror function on RX of the mirrored ++ * Input: ++ * enabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicPortMirrorRxFunction(rtk_uint32 enabled) ++{ ++ return rtl8367c_setAsicRegBit(RTL8367C_MIRROR_CTRL_REG, RTL8367C_MIRROR_RX_OFFSET, enabled); ++} ++/* Function Name: ++ * rtl8367c_getAsicPortMirrorRxFunction ++ * Description: ++ * Get the mirror function on RX of the mirrored ++ * Input: ++ * pEnabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicPortMirrorRxFunction(rtk_uint32* pEnabled) ++{ ++ return rtl8367c_getAsicRegBit(RTL8367C_MIRROR_CTRL_REG, RTL8367C_MIRROR_RX_OFFSET, pEnabled); ++} ++/* Function Name: ++ * rtl8367c_setAsicPortMirrorTxFunction ++ * Description: ++ * Set the mirror function on TX of the mirrored ++ * Input: ++ * enabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicPortMirrorTxFunction(rtk_uint32 enabled) ++{ ++ return rtl8367c_setAsicRegBit(RTL8367C_MIRROR_CTRL_REG, RTL8367C_MIRROR_TX_OFFSET, enabled); ++} ++/* Function Name: ++ * rtl8367c_getAsicPortMirrorTxFunction ++ * Description: ++ * Get the mirror function on TX of the mirrored ++ * Input: ++ * pEnabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicPortMirrorTxFunction(rtk_uint32* pEnabled) ++{ ++ return rtl8367c_getAsicRegBit(RTL8367C_MIRROR_CTRL_REG, RTL8367C_MIRROR_TX_OFFSET, pEnabled); ++} ++/* Function Name: ++ * rtl8367c_setAsicPortMirrorIsolation ++ * Description: ++ * Set the traffic isolation on monitor port ++ * Input: ++ * enabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicPortMirrorIsolation(rtk_uint32 enabled) ++{ ++ return rtl8367c_setAsicRegBit(RTL8367C_MIRROR_CTRL_REG, RTL8367C_MIRROR_ISO_OFFSET, enabled); ++} ++/* Function Name: ++ * rtl8367c_getAsicPortMirrorIsolation ++ * Description: ++ * Get the traffic isolation on monitor port ++ * Input: ++ * pEnabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicPortMirrorIsolation(rtk_uint32* pEnabled) ++{ ++ return rtl8367c_getAsicRegBit(RTL8367C_MIRROR_CTRL_REG, RTL8367C_MIRROR_ISO_OFFSET, pEnabled); ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicPortMirrorMask ++ * Description: ++ * Set mirror source port mask ++ * Input: ++ * SourcePortmask - Source Portmask ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_MASK- Port Mask Error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicPortMirrorMask(rtk_uint32 SourcePortmask) ++{ ++ if( SourcePortmask > RTL8367C_PORTMASK) ++ return RT_ERR_PORT_MASK; ++ ++ return rtl8367c_setAsicRegBits(RTL8367C_REG_MIRROR_SRC_PMSK, RTL8367C_MIRROR_SRC_PMSK_MASK, SourcePortmask); ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicPortMirrorMask ++ * Description: ++ * Get mirror source port mask ++ * Input: ++ * None ++ * Output: ++ * pSourcePortmask - Source Portmask ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_MASK- Port Mask Error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicPortMirrorMask(rtk_uint32 *pSourcePortmask) ++{ ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_MIRROR_SRC_PMSK, RTL8367C_MIRROR_SRC_PMSK_MASK, pSourcePortmask); ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicPortMirrorVlanRxLeaky ++ * Description: ++ * Set the mirror function of VLAN RX leaky ++ * Input: ++ * enabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicPortMirrorVlanRxLeaky(rtk_uint32 enabled) ++{ ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_MIRROR_CTRL2, RTL8367C_MIRROR_RX_VLAN_LEAKY_OFFSET, enabled); ++} ++/* Function Name: ++ * rtl8367c_getAsicPortMirrorVlanRxLeaky ++ * Description: ++ * Get the mirror function of VLAN RX leaky ++ * Input: ++ * pEnabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicPortMirrorVlanRxLeaky(rtk_uint32* pEnabled) ++{ ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_MIRROR_CTRL2, RTL8367C_MIRROR_RX_VLAN_LEAKY_OFFSET, pEnabled); ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicPortMirrorVlanTxLeaky ++ * Description: ++ * Set the mirror function of VLAN TX leaky ++ * Input: ++ * enabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicPortMirrorVlanTxLeaky(rtk_uint32 enabled) ++{ ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_MIRROR_CTRL2, RTL8367C_MIRROR_TX_VLAN_LEAKY_OFFSET, enabled); ++} ++/* Function Name: ++ * rtl8367c_getAsicPortMirrorVlanTxLeaky ++ * Description: ++ * Get the mirror function of VLAN TX leaky ++ * Input: ++ * pEnabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicPortMirrorVlanTxLeaky(rtk_uint32* pEnabled) ++{ ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_MIRROR_CTRL2, RTL8367C_MIRROR_TX_VLAN_LEAKY_OFFSET, pEnabled); ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicPortMirrorIsolationRxLeaky ++ * Description: ++ * Set the mirror function of Isolation RX leaky ++ * Input: ++ * enabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicPortMirrorIsolationRxLeaky(rtk_uint32 enabled) ++{ ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_MIRROR_CTRL2, RTL8367C_MIRROR_RX_ISOLATION_LEAKY_OFFSET, enabled); ++} ++/* Function Name: ++ * rtl8367c_getAsicPortMirrorIsolationRxLeaky ++ * Description: ++ * Get the mirror function of VLAN RX leaky ++ * Input: ++ * pEnabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicPortMirrorIsolationRxLeaky(rtk_uint32* pEnabled) ++{ ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_MIRROR_CTRL2, RTL8367C_MIRROR_RX_ISOLATION_LEAKY_OFFSET, pEnabled); ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicPortMirrorIsolationTxLeaky ++ * Description: ++ * Set the mirror function of Isolation TX leaky ++ * Input: ++ * enabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicPortMirrorIsolationTxLeaky(rtk_uint32 enabled) ++{ ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_MIRROR_CTRL2, RTL8367C_MIRROR_TX_ISOLATION_LEAKY_OFFSET, enabled); ++} ++/* Function Name: ++ * rtl8367c_getAsicPortMirrorIsolationTxLeaky ++ * Description: ++ * Get the mirror function of VLAN TX leaky ++ * Input: ++ * pEnabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicPortMirrorIsolationTxLeaky(rtk_uint32* pEnabled) ++{ ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_MIRROR_CTRL2, RTL8367C_MIRROR_TX_ISOLATION_LEAKY_OFFSET, pEnabled); ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicPortMirrorRealKeep ++ * Description: ++ * Set the mirror function of keep format ++ * Input: ++ * mode - 1: keep original format, 0: follow VLAN config ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicPortMirrorRealKeep(rtk_uint32 mode) ++{ ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_MIRROR_CTRL2, RTL8367C_MIRROR_REALKEEP_EN_OFFSET, mode); ++} ++/* Function Name: ++ * rtl8367c_getAsicPortMirrorRealKeep ++ * Description: ++ * Get the mirror function of keep format ++ * Input: ++ * pMode - 1: keep original format, 0: follow VLAN config ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicPortMirrorRealKeep(rtk_uint32* pMode) ++{ ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_MIRROR_CTRL2, RTL8367C_MIRROR_REALKEEP_EN_OFFSET, pMode); ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicPortMirrorOverride ++ * Description: ++ * Set the mirror function of override ++ * Input: ++ * rxMirror - 1: output rx Mirror format, 0: output forward format ++ * txMirror - 1: output tx Mirror format, 0: output forward format ++ * aclMirror - 1: output ACL Mirror format, 0: output forward format ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicPortMirrorOverride(rtk_uint32 rxMirror, rtk_uint32 txMirror, rtk_uint32 aclMirror) ++{ ++ ret_t retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_MIRROR_CTRL3, RTL8367C_MIRROR_RX_OVERRIDE_EN_OFFSET, rxMirror)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_MIRROR_CTRL3, RTL8367C_MIRROR_TX_OVERRIDE_EN_OFFSET, txMirror)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_MIRROR_CTRL3, RTL8367C_MIRROR_ACL_OVERRIDE_EN_OFFSET, aclMirror)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicPortMirrorOverride ++ * Description: ++ * Get the mirror function of override ++ * Input: ++ * None ++ * Output: ++ * pRxMirror - 1: output rx Mirror format, 0: output forward format ++ * pTxMirror - 1: output tx Mirror format, 0: output forward format ++ * pAclMirror - 1: output ACL Mirror format, 0: output forward format ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicPortMirrorOverride(rtk_uint32 *pRxMirror, rtk_uint32 *pTxMirror, rtk_uint32 *pAclMirror) ++{ ++ ret_t retVal; ++ ++ if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_MIRROR_CTRL3, RTL8367C_MIRROR_RX_OVERRIDE_EN_OFFSET, pRxMirror)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_MIRROR_CTRL3, RTL8367C_MIRROR_TX_OVERRIDE_EN_OFFSET, pTxMirror)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_MIRROR_CTRL3, RTL8367C_MIRROR_ACL_OVERRIDE_EN_OFFSET, pAclMirror)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} +diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_misc.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_misc.c +new file mode 100644 +index 000000000000..2189b151c387 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_misc.c +@@ -0,0 +1,268 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : Miscellaneous functions ++ * ++ */ ++ ++#include ++/* Function Name: ++ * rtl8367c_setAsicMacAddress ++ * Description: ++ * Set switch MAC address ++ * Input: ++ * mac - switch mac ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicMacAddress(ether_addr_t mac) ++{ ++ ret_t retVal; ++ rtk_uint32 regData; ++ rtk_uint8 *accessPtr; ++ rtk_uint32 i; ++ ++ accessPtr = (rtk_uint8*)&mac; ++ ++ regData = *accessPtr; ++ accessPtr ++; ++ regData = (regData << 8) | *accessPtr; ++ accessPtr ++; ++ for(i = 0; i <=2; i++) ++ { ++ retVal = rtl8367c_setAsicReg(RTL8367C_REG_SWITCH_MAC2 - i, regData); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ regData = *accessPtr; ++ accessPtr ++; ++ regData = (regData << 8) | *accessPtr; ++ accessPtr ++; ++ } ++ ++ return retVal; ++} ++/* Function Name: ++ * rtl8367c_getAsicMacAddress ++ * Description: ++ * Get switch MAC address ++ * Input: ++ * pMac - switch mac ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicMacAddress(ether_addr_t *pMac) ++{ ++ ret_t retVal; ++ rtk_uint32 regData; ++ rtk_uint8 *accessPtr; ++ rtk_uint32 i; ++ ++ ++ accessPtr = (rtk_uint8*)pMac; ++ ++ for(i = 0; i <= 2; i++) ++ { ++ retVal = rtl8367c_getAsicReg(RTL8367C_REG_SWITCH_MAC2 - i, ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ *accessPtr = (regData & 0xFF00) >> 8; ++ accessPtr ++; ++ *accessPtr = regData & 0xFF; ++ accessPtr ++; ++ } ++ ++ return retVal; ++} ++/* Function Name: ++ * rtl8367c_getAsicDebugInfo ++ * Description: ++ * Get per-port packet forward debugging information ++ * Input: ++ * port - Physical port number (0~7) ++ * pDebugifo - per-port packet trap/drop/forward reason ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicDebugInfo(rtk_uint32 port, rtk_uint32 *pDebugifo) ++{ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ return rtl8367c_getAsicRegBits(RTL8367C_DEBUG_INFO_REG(port), RTL8367C_DEBUG_INFO_MASK(port), pDebugifo); ++} ++/* Function Name: ++ * rtl8367c_setAsicPortJamMode ++ * Description: ++ * Set half duplex flow control setting ++ * Input: ++ * mode - 0: Back-Pressure 1: DEFER ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicPortJamMode(rtk_uint32 mode) ++{ ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_CFG_BACKPRESSURE, RTL8367C_LONGTXE_OFFSET,mode); ++} ++/* Function Name: ++ * rtl8367c_getAsicPortJamMode ++ * Description: ++ * Get half duplex flow control setting ++ * Input: ++ * pMode - 0: Back-Pressure 1: DEFER ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicPortJamMode(rtk_uint32* pMode) ++{ ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_CFG_BACKPRESSURE, RTL8367C_LONGTXE_OFFSET, pMode); ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicMaxLengthCfg ++ * Description: ++ * Set Max packet length configuration ++ * Input: ++ * cfgId - Configuration ID ++ * maxLength - Max Length ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicMaxLengthCfg(rtk_uint32 cfgId, rtk_uint32 maxLength) ++{ ++ return rtl8367c_setAsicRegBits(RTL8367C_REG_MAX_LEN_RX_TX_CFG0 + cfgId, RTL8367C_MAX_LEN_RX_TX_CFG0_MASK, maxLength); ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicMaxLengthCfg ++ * Description: ++ * Get Max packet length configuration ++ * Input: ++ * cfgId - Configuration ID ++ * maxLength - Max Length ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicMaxLengthCfg(rtk_uint32 cfgId, rtk_uint32 *pMaxLength) ++{ ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_MAX_LEN_RX_TX_CFG0 + cfgId, RTL8367C_MAX_LEN_RX_TX_CFG0_MASK, pMaxLength); ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicMaxLength ++ * Description: ++ * Set Max packet length ++ * Input: ++ * port - port ID ++ * type - 0: 10M/100M speed, 1: giga speed ++ * cfgId - Configuration ID ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicMaxLength(rtk_uint32 port, rtk_uint32 type, rtk_uint32 cfgId) ++{ ++ ret_t retVal; ++ ++ if(port < 8) ++ { ++ retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_MAX_LENGTH_CFG, (type * 8) + port, cfgId); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ { ++ retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_MAX_LENGTH_CFG_EXT, (type * 3) + port - 8, cfgId); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicMaxLength ++ * Description: ++ * Get Max packet length ++ * Input: ++ * port - port ID ++ * type - 0: 10M/100M speed, 1: giga speed ++ * cfgId - Configuration ID ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicMaxLength(rtk_uint32 port, rtk_uint32 type, rtk_uint32 *pCfgId) ++{ ++ ret_t retVal; ++ ++ if(port < 8) ++ { ++ retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_MAX_LENGTH_CFG, (type * 8) + port, pCfgId); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ { ++ retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_MAX_LENGTH_CFG_EXT, (type * 3) + port - 8, pCfgId); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ return RT_ERR_OK; ++} ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_oam.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_oam.c +new file mode 100644 +index 000000000000..1556f4500d40 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_oam.c +@@ -0,0 +1,194 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 42321 $ ++ * $Date: 2013-08-26 13:51:29 +0800 (週一, 26 八月 2013) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : OAM related functions ++ * ++ */ ++ ++#include ++/* Function Name: ++ * rtl8367c_setAsicOamParser ++ * Description: ++ * Set OAM parser state ++ * Input: ++ * port - Physical port number (0~7) ++ * parser - Per-Port OAM parser state ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * RT_ERR_NOT_ALLOWED - Invalid paser state ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicOamParser(rtk_uint32 port, rtk_uint32 parser) ++{ ++ if(port >= RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ if(parser > OAM_PARFWDCPU) ++ return RT_ERR_NOT_ALLOWED; ++ ++ return rtl8367c_setAsicRegBits(RTL8367C_REG_OAM_PARSER_CTRL0 + port/8, RTL8367C_OAM_PARSER_MASK(port % 8), parser); ++} ++/* Function Name: ++ * rtl8367c_getAsicOamParser ++ * Description: ++ * Get OAM parser state ++ * Input: ++ * port - Physical port number (0~7) ++ * pParser - Per-Port OAM parser state ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicOamParser(rtk_uint32 port, rtk_uint32* pParser) ++{ ++ if(port >= RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_OAM_PARSER_CTRL0 + port/8, RTL8367C_OAM_PARSER_MASK(port%8), pParser); ++} ++/* Function Name: ++ * rtl8367c_setAsicOamMultiplexer ++ * Description: ++ * Set OAM multiplexer state ++ * Input: ++ * port - Physical port number (0~7) ++ * multiplexer - Per-Port OAM multiplexer state ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * RT_ERR_NOT_ALLOWED - Invalid multiplexer state ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicOamMultiplexer(rtk_uint32 port, rtk_uint32 multiplexer) ++{ ++ if(port >= RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ if(multiplexer > OAM_MULCPU) ++ return RT_ERR_NOT_ALLOWED; ++ ++ return rtl8367c_setAsicRegBits(RTL8367C_REG_OAM_MULTIPLEXER_CTRL0 + port/8, RTL8367C_OAM_MULTIPLEXER_MASK(port%8), multiplexer); ++} ++/* Function Name: ++ * rtl8367c_getAsicOamMultiplexer ++ * Description: ++ * Get OAM multiplexer state ++ * Input: ++ * port - Physical port number (0~7) ++ * pMultiplexer - Per-Port OAM multiplexer state ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicOamMultiplexer(rtk_uint32 port, rtk_uint32* pMultiplexer) ++{ ++ if(port >= RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_OAM_MULTIPLEXER_CTRL0 + port/8, RTL8367C_OAM_MULTIPLEXER_MASK(port%8), pMultiplexer); ++} ++/* Function Name: ++ * rtl8367c_setAsicOamCpuPri ++ * Description: ++ * Set trap priority for OAM packet ++ * Input: ++ * priority - priority (0~7) ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_QOS_INT_PRIORITY - Invalid priority ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicOamCpuPri(rtk_uint32 priority) ++{ ++ if(priority > RTL8367C_PRIMAX) ++ return RT_ERR_QOS_INT_PRIORITY; ++ ++ return rtl8367c_setAsicRegBits(RTL8367C_REG_QOS_TRAP_PRIORITY0, RTL8367C_OAM_PRIOIRTY_MASK, priority); ++} ++/* Function Name: ++ * rtl8367c_getAsicOamCpuPri ++ * Description: ++ * Get trap priority for OAM packet ++ * Input: ++ * pPriority - priority (0~7) ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicOamCpuPri(rtk_uint32 *pPriority) ++{ ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_QOS_TRAP_PRIORITY0, RTL8367C_OAM_PRIOIRTY_MASK, pPriority); ++} ++/* Function Name: ++ * rtl8367c_setAsicOamEnable ++ * Description: ++ * Set OAM function state ++ * Input: ++ * enabled - OAM function usage 1:enable, 0:disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicOamEnable(rtk_uint32 enabled) ++{ ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_OAM_CTRL, RTL8367C_OAM_CTRL_OFFSET, enabled); ++} ++/* Function Name: ++ * rtl8367c_getAsicOamEnable ++ * Description: ++ * Get OAM function state ++ * Input: ++ * pEnabled - OAM function usage 1:enable, 0:disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicOamEnable(rtk_uint32 *pEnabled) ++{ ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_OAM_CTRL, RTL8367C_OAM_CTRL_OFFSET, pEnabled); ++} +diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_phy.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_phy.c +new file mode 100644 +index 000000000000..fb4db113a987 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_phy.c +@@ -0,0 +1,394 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : PHY related functions ++ * ++ */ ++#include ++ ++#if defined(MDC_MDIO_OPERATION) ++/* Function Name: ++ * rtl8367c_setAsicPHYOCPReg ++ * Description: ++ * Set PHY OCP registers ++ * Input: ++ * phyNo - Physical port number (0~7) ++ * ocpAddr - OCP address ++ * ocpData - Writing data ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PHY_REG_ID - invalid PHY address ++ * RT_ERR_PHY_ID - invalid PHY no ++ * RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicPHYOCPReg(rtk_uint32 phyNo, rtk_uint32 ocpAddr, rtk_uint32 ocpData ) ++{ ++ ret_t retVal; ++ rtk_uint32 regAddr; ++ rtk_uint32 ocpAddrPrefix, ocpAddr9_6, ocpAddr5_1; ++ ++ /* OCP prefix */ ++ ocpAddrPrefix = ((ocpAddr & 0xFC00) >> 10); ++ if((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_GPHY_OCP_MSB_0, RTL8367C_CFG_CPU_OCPADR_MSB_MASK, ocpAddrPrefix)) != RT_ERR_OK) ++ return retVal; ++ ++ /*prepare access address*/ ++ ocpAddr9_6 = ((ocpAddr >> 6) & 0x000F); ++ ocpAddr5_1 = ((ocpAddr >> 1) & 0x001F); ++ regAddr = RTL8367C_PHY_BASE | (ocpAddr9_6 << 8) | (phyNo << RTL8367C_PHY_OFFSET) | ocpAddr5_1; ++ if((retVal = rtl8367c_setAsicReg(regAddr, ocpData)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicPHYOCPReg ++ * Description: ++ * Get PHY OCP registers ++ * Input: ++ * phyNo - Physical port number (0~7) ++ * ocpAddr - PHY address ++ * pRegData - read data ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PHY_REG_ID - invalid PHY address ++ * RT_ERR_PHY_ID - invalid PHY no ++ * RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicPHYOCPReg(rtk_uint32 phyNo, rtk_uint32 ocpAddr, rtk_uint32 *pRegData ) ++{ ++ ret_t retVal; ++ rtk_uint32 regAddr; ++ rtk_uint32 ocpAddrPrefix, ocpAddr9_6, ocpAddr5_1; ++ /* OCP prefix */ ++ ocpAddrPrefix = ((ocpAddr & 0xFC00) >> 10); ++ if((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_GPHY_OCP_MSB_0, RTL8367C_CFG_CPU_OCPADR_MSB_MASK, ocpAddrPrefix)) != RT_ERR_OK) ++ return retVal; ++ ++ /*prepare access address*/ ++ ocpAddr9_6 = ((ocpAddr >> 6) & 0x000F); ++ ocpAddr5_1 = ((ocpAddr >> 1) & 0x001F); ++ regAddr = RTL8367C_PHY_BASE | (ocpAddr9_6 << 8) | (phyNo << RTL8367C_PHY_OFFSET) | ocpAddr5_1; ++ if((retVal = rtl8367c_getAsicReg(regAddr, pRegData)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++#else ++ ++/* Function Name: ++ * rtl8367c_setAsicPHYOCPReg ++ * Description: ++ * Set PHY OCP registers ++ * Input: ++ * phyNo - Physical port number (0~7) ++ * ocpAddr - OCP address ++ * ocpData - Writing data ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PHY_REG_ID - invalid PHY address ++ * RT_ERR_PHY_ID - invalid PHY no ++ * RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicPHYOCPReg(rtk_uint32 phyNo, rtk_uint32 ocpAddr, rtk_uint32 ocpData ) ++{ ++ ret_t retVal; ++ rtk_uint32 regData; ++ rtk_uint32 busyFlag, checkCounter; ++ rtk_uint32 ocpAddrPrefix, ocpAddr9_6, ocpAddr5_1; ++ ++ /*Check internal phy access busy or not*/ ++ /*retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_INDRECT_ACCESS_STATUS, RTL8367C_INDRECT_ACCESS_STATUS_OFFSET,&busyFlag);*/ ++ retVal = rtl8367c_getAsicReg(RTL8367C_REG_INDRECT_ACCESS_STATUS,&busyFlag); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ if(busyFlag) ++ return RT_ERR_BUSYWAIT_TIMEOUT; ++ ++ /* OCP prefix */ ++ ocpAddrPrefix = ((ocpAddr & 0xFC00) >> 10); ++ if((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_GPHY_OCP_MSB_0, RTL8367C_CFG_CPU_OCPADR_MSB_MASK, ocpAddrPrefix)) != RT_ERR_OK) ++ return retVal; ++ ++ /*prepare access data*/ ++ retVal = rtl8367c_setAsicReg(RTL8367C_REG_INDRECT_ACCESS_WRITE_DATA, ocpData); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ /*prepare access address*/ ++ ocpAddr9_6 = ((ocpAddr >> 6) & 0x000F); ++ ocpAddr5_1 = ((ocpAddr >> 1) & 0x001F); ++ regData = RTL8367C_PHY_BASE | (ocpAddr9_6 << 8) | (phyNo << RTL8367C_PHY_OFFSET) | ocpAddr5_1; ++ retVal = rtl8367c_setAsicReg(RTL8367C_REG_INDRECT_ACCESS_ADDRESS, regData); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ /*Set WRITE Command*/ ++ retVal = rtl8367c_setAsicReg(RTL8367C_REG_INDRECT_ACCESS_CTRL, RTL8367C_CMD_MASK | RTL8367C_RW_MASK); ++ ++ checkCounter = 100; ++ while(checkCounter) ++ { ++ retVal = rtl8367c_getAsicReg(RTL8367C_REG_INDRECT_ACCESS_STATUS,&busyFlag); ++ if((retVal != RT_ERR_OK) || busyFlag) ++ { ++ checkCounter --; ++ if(0 == checkCounter) ++ return RT_ERR_BUSYWAIT_TIMEOUT; ++ } ++ else ++ { ++ checkCounter = 0; ++ } ++ } ++ ++ return retVal; ++} ++/* Function Name: ++ * rtl8367c_getAsicPHYOCPReg ++ * Description: ++ * Get PHY OCP registers ++ * Input: ++ * phyNo - Physical port number (0~7) ++ * ocpAddr - PHY address ++ * pRegData - read data ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PHY_REG_ID - invalid PHY address ++ * RT_ERR_PHY_ID - invalid PHY no ++ * RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicPHYOCPReg(rtk_uint32 phyNo, rtk_uint32 ocpAddr, rtk_uint32 *pRegData ) ++{ ++ ret_t retVal; ++ rtk_uint32 regData; ++ rtk_uint32 busyFlag,checkCounter; ++ rtk_uint32 ocpAddrPrefix, ocpAddr9_6, ocpAddr5_1; ++ /*Check internal phy access busy or not*/ ++ /*retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_INDRECT_ACCESS_STATUS, RTL8367C_INDRECT_ACCESS_STATUS_OFFSET,&busyFlag);*/ ++ retVal = rtl8367c_getAsicReg(RTL8367C_REG_INDRECT_ACCESS_STATUS,&busyFlag); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ if(busyFlag) ++ return RT_ERR_BUSYWAIT_TIMEOUT; ++ ++ /* OCP prefix */ ++ ocpAddrPrefix = ((ocpAddr & 0xFC00) >> 10); ++ if((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_GPHY_OCP_MSB_0, RTL8367C_CFG_CPU_OCPADR_MSB_MASK, ocpAddrPrefix)) != RT_ERR_OK) ++ return retVal; ++ ++ /*prepare access address*/ ++ ocpAddr9_6 = ((ocpAddr >> 6) & 0x000F); ++ ocpAddr5_1 = ((ocpAddr >> 1) & 0x001F); ++ regData = RTL8367C_PHY_BASE | (ocpAddr9_6 << 8) | (phyNo << RTL8367C_PHY_OFFSET) | ocpAddr5_1; ++ retVal = rtl8367c_setAsicReg(RTL8367C_REG_INDRECT_ACCESS_ADDRESS, regData); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ /*Set READ Command*/ ++ retVal = rtl8367c_setAsicReg(RTL8367C_REG_INDRECT_ACCESS_CTRL, RTL8367C_CMD_MASK ); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ checkCounter = 100; ++ while(checkCounter) ++ { ++ retVal = rtl8367c_getAsicReg(RTL8367C_REG_INDRECT_ACCESS_STATUS,&busyFlag); ++ if((retVal != RT_ERR_OK) || busyFlag) ++ { ++ checkCounter --; ++ if(0 == checkCounter) ++ return RT_ERR_FAILED; ++ } ++ else ++ { ++ checkCounter = 0; ++ } ++ } ++ ++ /*get PHY register*/ ++ retVal = rtl8367c_getAsicReg(RTL8367C_REG_INDRECT_ACCESS_READ_DATA, ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ *pRegData = regData; ++ ++ return RT_ERR_OK; ++} ++ ++#endif ++ ++/* Function Name: ++ * rtl8367c_setAsicPHYReg ++ * Description: ++ * Set PHY registers ++ * Input: ++ * phyNo - Physical port number (0~7) ++ * phyAddr - PHY address (0~31) ++ * phyData - Writing data ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PHY_REG_ID - invalid PHY address ++ * RT_ERR_PHY_ID - invalid PHY no ++ * RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicPHYReg(rtk_uint32 phyNo, rtk_uint32 phyAddr, rtk_uint32 phyData ) ++{ ++ rtk_uint32 ocp_addr; ++ ++ if(phyAddr > RTL8367C_PHY_REGNOMAX) ++ return RT_ERR_PHY_REG_ID; ++ ++ ocp_addr = 0xa400 + phyAddr*2; ++ ++ return rtl8367c_setAsicPHYOCPReg(phyNo, ocp_addr, phyData); ++} ++/* Function Name: ++ * rtl8367c_getAsicPHYReg ++ * Description: ++ * Get PHY registers ++ * Input: ++ * phyNo - Physical port number (0~7) ++ * phyAddr - PHY address (0~31) ++ * pRegData - Writing data ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PHY_REG_ID - invalid PHY address ++ * RT_ERR_PHY_ID - invalid PHY no ++ * RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicPHYReg(rtk_uint32 phyNo, rtk_uint32 phyAddr, rtk_uint32 *pRegData ) ++{ ++ rtk_uint32 ocp_addr; ++ ++ if(phyAddr > RTL8367C_PHY_REGNOMAX) ++ return RT_ERR_PHY_REG_ID; ++ ++ ocp_addr = 0xa400 + phyAddr*2; ++ ++ return rtl8367c_getAsicPHYOCPReg(phyNo, ocp_addr, pRegData); ++} ++ ++ ++/* Function Name: ++ * rtl8367c_setAsicSdsReg ++ * Description: ++ * Set Serdes registers ++ * Input: ++ * sdsId - sdsid (0~1) ++ * sdsReg - reg address (0~31) ++ * sdsPage - Writing data ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ ++ * Note: ++ * None ++ */ ++ ++ret_t rtl8367c_setAsicSdsReg(rtk_uint32 sdsId, rtk_uint32 sdsReg, rtk_uint32 sdsPage, rtk_uint32 value) ++{ ++ rtk_uint32 retVal; ++ ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, value)) != RT_ERR_OK) ++ return retVal; ++ ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, (sdsPage<<5) | sdsReg)) != RT_ERR_OK) ++ return retVal; ++ ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0|sdsId)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++ ++} ++ ++/* Function Name: ++ * rtl8367c_getAiscSdsReg ++ * Description: ++ * Get Serdes registers ++ * Input: ++ * sdsId - sdsid (0~1) ++ * sdsReg - reg address (0~31) ++ * sdsPage - Writing data ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicSdsReg(rtk_uint32 sdsId, rtk_uint32 sdsReg, rtk_uint32 sdsPage, rtk_uint32 *value) ++{ ++ rtk_uint32 retVal, busy; ++ ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, (sdsPage<<5) | sdsReg)) != RT_ERR_OK) ++ return retVal; ++ ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x0080|sdsId)) != RT_ERR_OK) ++ return retVal; ++ ++ while(1) ++ { ++ if ((retVal = rtl8367c_getAsicReg(RTL8367C_REG_SDS_INDACS_CMD, &busy))!=RT_ERR_OK) ++ return retVal; ++ ++ if ((busy & 0x100) == 0) ++ break; ++ } ++ ++ if ((retVal = rtl8367c_getAsicReg(RTL8367C_REG_SDS_INDACS_DATA, value))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++ ++ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_port.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_port.c +new file mode 100644 +index 000000000000..fae046639d78 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_port.c +@@ -0,0 +1,5752 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76333 $ ++ * $Date: 2017-03-09 09:33:15 +0800 (週四, 09 三月 2017) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : Port security related functions ++ * ++ */ ++ ++#include ++ ++#include ++ ++ ++#define FIBER2_AUTO_INIT_SIZE 2038 ++rtk_uint8 Fiber2_Auto[FIBER2_AUTO_INIT_SIZE] = { ++0x02,0x05,0x8F,0xE4,0xF5,0xA8,0xD2,0xAF, ++0x22,0x00,0x00,0x02,0x07,0x2C,0xC5,0xF0, ++0xF8,0xA3,0xE0,0x28,0xF0,0xC5,0xF0,0xF8, ++0xE5,0x82,0x15,0x82,0x70,0x02,0x15,0x83, ++0xE0,0x38,0xF0,0x22,0x75,0xF0,0x08,0x75, ++0x82,0x00,0xEF,0x2F,0xFF,0xEE,0x33,0xFE, ++0xCD,0x33,0xCD,0xCC,0x33,0xCC,0xC5,0x82, ++0x33,0xC5,0x82,0x9B,0xED,0x9A,0xEC,0x99, ++0xE5,0x82,0x98,0x40,0x0C,0xF5,0x82,0xEE, ++0x9B,0xFE,0xED,0x9A,0xFD,0xEC,0x99,0xFC, ++0x0F,0xD5,0xF0,0xD6,0xE4,0xCE,0xFB,0xE4, ++0xCD,0xFA,0xE4,0xCC,0xF9,0xA8,0x82,0x22, ++0xB8,0x00,0xC1,0xB9,0x00,0x59,0xBA,0x00, ++0x2D,0xEC,0x8B,0xF0,0x84,0xCF,0xCE,0xCD, ++0xFC,0xE5,0xF0,0xCB,0xF9,0x78,0x18,0xEF, ++0x2F,0xFF,0xEE,0x33,0xFE,0xED,0x33,0xFD, ++0xEC,0x33,0xFC,0xEB,0x33,0xFB,0x10,0xD7, ++0x03,0x99,0x40,0x04,0xEB,0x99,0xFB,0x0F, ++0xD8,0xE5,0xE4,0xF9,0xFA,0x22,0x78,0x18, ++0xEF,0x2F,0xFF,0xEE,0x33,0xFE,0xED,0x33, ++0xFD,0xEC,0x33,0xFC,0xC9,0x33,0xC9,0x10, ++0xD7,0x05,0x9B,0xE9,0x9A,0x40,0x07,0xEC, ++0x9B,0xFC,0xE9,0x9A,0xF9,0x0F,0xD8,0xE0, ++0xE4,0xC9,0xFA,0xE4,0xCC,0xFB,0x22,0x75, ++0xF0,0x10,0xEF,0x2F,0xFF,0xEE,0x33,0xFE, ++0xED,0x33,0xFD,0xCC,0x33,0xCC,0xC8,0x33, ++0xC8,0x10,0xD7,0x07,0x9B,0xEC,0x9A,0xE8, ++0x99,0x40,0x0A,0xED,0x9B,0xFD,0xEC,0x9A, ++0xFC,0xE8,0x99,0xF8,0x0F,0xD5,0xF0,0xDA, ++0xE4,0xCD,0xFB,0xE4,0xCC,0xFA,0xE4,0xC8, ++0xF9,0x22,0xEB,0x9F,0xF5,0xF0,0xEA,0x9E, ++0x42,0xF0,0xE9,0x9D,0x42,0xF0,0xE8,0x9C, ++0x45,0xF0,0x22,0xE0,0xFC,0xA3,0xE0,0xFD, ++0xA3,0xE0,0xFE,0xA3,0xE0,0xFF,0x22,0xE0, ++0xF8,0xA3,0xE0,0xF9,0xA3,0xE0,0xFA,0xA3, ++0xE0,0xFB,0x22,0xEC,0xF0,0xA3,0xED,0xF0, ++0xA3,0xEE,0xF0,0xA3,0xEF,0xF0,0x22,0x7D, ++0xD7,0x7C,0x04,0x7F,0x02,0x7E,0x66,0x12, ++0x07,0xAB,0x7D,0x80,0x7C,0x04,0x7F,0x01, ++0x7E,0x66,0x12,0x07,0xAB,0x7D,0xC0,0x7C, ++0x00,0x7F,0x00,0x7E,0x66,0x12,0x07,0xAB, ++0x7D,0x94,0x7C,0xF9,0x7F,0x02,0x7E,0x66, ++0x12,0x07,0xAB,0x7D,0x81,0x7C,0x04,0x7F, ++0x01,0x7E,0x66,0x12,0x07,0xAB,0x7D,0xC0, ++0x7C,0x00,0x7F,0x00,0x7E,0x66,0x12,0x07, ++0xAB,0x7D,0xA2,0x7C,0x31,0x7F,0x02,0x7E, ++0x66,0x12,0x07,0xAB,0x7D,0x82,0x7C,0x04, ++0x7F,0x01,0x7E,0x66,0x12,0x07,0xAB,0x7D, ++0xC0,0x7C,0x00,0x7F,0x00,0x7E,0x66,0x12, ++0x07,0xAB,0x7D,0x60,0x7C,0x69,0x7F,0x02, ++0x7E,0x66,0x12,0x07,0xAB,0x7D,0x83,0x7C, ++0x04,0x7F,0x01,0x7E,0x66,0x12,0x07,0xAB, ++0x7D,0xC0,0x7C,0x00,0x7F,0x00,0x7E,0x66, ++0x12,0x07,0xAB,0x7D,0x28,0x7C,0x97,0x7F, ++0x02,0x7E,0x66,0x12,0x07,0xAB,0x7D,0x84, ++0x7C,0x04,0x7F,0x01,0x7E,0x66,0x12,0x07, ++0xAB,0x7D,0xC0,0x7C,0x00,0x7F,0x00,0x7E, ++0x66,0x12,0x07,0xAB,0x7D,0x85,0x7C,0x9D, ++0x7F,0x02,0x7E,0x66,0x12,0x07,0xAB,0x7D, ++0x23,0x7C,0x04,0x7F,0x01,0x7E,0x66,0x12, ++0x07,0xAB,0x7D,0xC0,0x7C,0x00,0x7F,0x00, ++0x7E,0x66,0x12,0x07,0xAB,0x7D,0x10,0x7C, ++0xD8,0x7F,0x02,0x7E,0x66,0x12,0x07,0xAB, ++0x7D,0x24,0x7C,0x04,0x7F,0x01,0x7E,0x66, ++0x12,0x07,0xAB,0x7D,0xC0,0x7C,0x00,0x7F, ++0x00,0x7E,0x66,0x12,0x07,0xAB,0x7D,0x00, ++0x7C,0x04,0x7F,0x02,0x7E,0x66,0x12,0x07, ++0xAB,0x7D,0x2F,0x7C,0x00,0x7F,0x01,0x7E, ++0x66,0x12,0x07,0xAB,0x7D,0xC0,0x7C,0x00, ++0x7F,0x00,0x7E,0x66,0x02,0x07,0xAB,0x7D, ++0x03,0x7C,0x00,0x7F,0x01,0x7E,0x66,0x12, ++0x07,0xAB,0x7D,0x80,0x7C,0x00,0x7F,0x00, ++0x7E,0x66,0x12,0x07,0xAB,0x7F,0x02,0x7E, ++0x66,0x12,0x07,0x66,0xEF,0x44,0x40,0xFD, ++0xAC,0x06,0x7F,0x02,0x7E,0x66,0x12,0x07, ++0xAB,0x7D,0x03,0x7C,0x00,0x7F,0x01,0x7E, ++0x66,0x12,0x07,0xAB,0x7D,0xC0,0x7C,0x00, ++0x7F,0x00,0x7E,0x66,0x12,0x07,0xAB,0x7D, ++0x03,0x7C,0x00,0x7F,0x01,0x7E,0x66,0x12, ++0x07,0xAB,0x7D,0x80,0x7C,0x00,0x7F,0x00, ++0x7E,0x66,0x12,0x07,0xAB,0x7F,0x02,0x7E, ++0x66,0x12,0x07,0x66,0xEF,0x54,0xBF,0xFD, ++0xAC,0x06,0x7F,0x02,0x7E,0x66,0x12,0x07, ++0xAB,0x7D,0x03,0x7C,0x00,0x7F,0x01,0x7E, ++0x66,0x12,0x07,0xAB,0x7D,0xC0,0x7C,0x00, ++0x7F,0x00,0x7E,0x66,0x12,0x07,0xAB,0xE4, ++0xFD,0xFC,0x7F,0x01,0x7E,0x66,0x12,0x07, ++0xAB,0x7D,0x80,0x7C,0x00,0x7F,0x00,0x7E, ++0x66,0x12,0x07,0xAB,0x7F,0x02,0x7E,0x66, ++0x12,0x07,0x66,0xEF,0x54,0xFD,0x54,0xFE, ++0xFD,0xAC,0x06,0x7F,0x02,0x7E,0x66,0x12, ++0x07,0xAB,0xE4,0xFD,0xFC,0x7F,0x01,0x7E, ++0x66,0x12,0x07,0xAB,0x7D,0xC0,0x7C,0x00, ++0x7F,0x00,0x7E,0x66,0x12,0x07,0xAB,0xE4, ++0xFD,0xFC,0x7F,0x01,0x7E,0x66,0x12,0x07, ++0xAB,0x7D,0x80,0x7C,0x00,0x7F,0x00,0x7E, ++0x66,0x12,0x07,0xAB,0x7F,0x02,0x7E,0x66, ++0x12,0x07,0x66,0xEF,0x44,0x02,0x44,0x01, ++0xFD,0xAC,0x06,0x7F,0x02,0x7E,0x66,0x12, ++0x07,0xAB,0xE4,0xFD,0xFC,0x7F,0x01,0x7E, ++0x66,0x12,0x07,0xAB,0x7D,0xC0,0x7C,0x00, ++0x7F,0x00,0x7E,0x66,0x02,0x07,0xAB,0xE4, ++0x90,0x06,0x2C,0xF0,0xFD,0x7C,0x01,0x7F, ++0x3F,0x7E,0x1D,0x12,0x07,0xAB,0x7D,0x40, ++0x7C,0x00,0x7F,0x36,0x7E,0x13,0x12,0x07, ++0xAB,0xE4,0xFF,0xFE,0xFD,0x80,0x25,0xE4, ++0x7F,0xFF,0x7E,0xFF,0xFD,0xFC,0x90,0x06, ++0x24,0x12,0x01,0x0F,0xC3,0x12,0x00,0xF2, ++0x50,0x1B,0x90,0x06,0x24,0x12,0x01,0x03, ++0xEF,0x24,0x01,0xFF,0xE4,0x3E,0xFE,0xE4, ++0x3D,0xFD,0xE4,0x3C,0xFC,0x90,0x06,0x24, ++0x12,0x01,0x1B,0x80,0xD2,0xE4,0xF5,0xA8, ++0xD2,0xAF,0x7D,0x1F,0xFC,0x7F,0x49,0x7E, ++0x13,0x12,0x07,0xAB,0x12,0x07,0xDB,0x12, ++0x01,0x27,0x12,0x06,0x1B,0x12,0x07,0x8A, ++0x12,0x06,0xEA,0x7D,0x41,0x7C,0x00,0x7F, ++0x36,0x7E,0x13,0x12,0x07,0xAB,0xE4,0xFF, ++0xFE,0xFD,0x80,0x26,0x7F,0xFF,0x7E,0xFF, ++0x7D,0x05,0x7C,0x00,0x90,0x06,0x24,0x12, ++0x01,0x0F,0xC3,0x12,0x00,0xF2,0x50,0x1B, ++0x90,0x06,0x24,0x12,0x01,0x03,0xEF,0x24, ++0x01,0xFF,0xE4,0x3E,0xFE,0xE4,0x3D,0xFD, ++0xE4,0x3C,0xFC,0x90,0x06,0x24,0x12,0x01, ++0x1B,0x80,0xD1,0xC2,0x00,0xC2,0x01,0xD2, ++0xA9,0xD2,0x8C,0x7F,0x01,0x7E,0x62,0x12, ++0x07,0x66,0xEF,0x30,0xE2,0x07,0xE4,0x90, ++0x06,0x2C,0xF0,0x80,0xEE,0x90,0x06,0x2C, ++0xE0,0x70,0x12,0x12,0x04,0xF0,0x90,0x06, ++0x2C,0x74,0x01,0xF0,0xE4,0x90,0x06,0x33, ++0xF0,0xA3,0xF0,0x80,0xD6,0xC3,0x90,0x06, ++0x34,0xE0,0x94,0x62,0x90,0x06,0x33,0xE0, ++0x94,0x00,0x40,0xC7,0xE4,0xF0,0xA3,0xF0, ++0x12,0x04,0xF0,0x90,0x06,0x2C,0x74,0x01, ++0xF0,0x80,0xB8,0x75,0x0F,0x80,0x75,0x0E, ++0x7E,0x75,0x0D,0xAA,0x75,0x0C,0x83,0xE4, ++0xF5,0x10,0x7F,0x36,0x7E,0x13,0x12,0x07, ++0x66,0xEE,0xC4,0xF8,0x54,0xF0,0xC8,0xEF, ++0xC4,0x54,0x0F,0x48,0x54,0x07,0xFB,0x7A, ++0x00,0xEA,0x70,0x4A,0xEB,0x14,0x60,0x1C, ++0x14,0x60,0x27,0x24,0xFE,0x60,0x31,0x14, ++0x60,0x3C,0x24,0x05,0x70,0x38,0x75,0x0B, ++0x00,0x75,0x0A,0xC2,0x75,0x09,0xEB,0x75, ++0x08,0x0B,0x80,0x36,0x75,0x0B,0x40,0x75, ++0x0A,0x59,0x75,0x09,0x73,0x75,0x08,0x07, ++0x80,0x28,0x75,0x0B,0x00,0x75,0x0A,0xE1, ++0x75,0x09,0xF5,0x75,0x08,0x05,0x80,0x1A, ++0x75,0x0B,0xA0,0x75,0x0A,0xAC,0x75,0x09, ++0xB9,0x75,0x08,0x03,0x80,0x0C,0x75,0x0B, ++0x00,0x75,0x0A,0x62,0x75,0x09,0x3D,0x75, ++0x08,0x01,0x75,0x89,0x11,0xE4,0x7B,0x60, ++0x7A,0x09,0xF9,0xF8,0xAF,0x0B,0xAE,0x0A, ++0xAD,0x09,0xAC,0x08,0x12,0x00,0x60,0xAA, ++0x06,0xAB,0x07,0xC3,0xE4,0x9B,0xFB,0xE4, ++0x9A,0xFA,0x78,0x17,0xF6,0xAF,0x03,0xEF, ++0x08,0xF6,0x18,0xE6,0xF5,0x8C,0x08,0xE6, ++0xF5,0x8A,0x74,0x0D,0x2B,0xFB,0xE4,0x3A, ++0x18,0xF6,0xAF,0x03,0xEF,0x08,0xF6,0x75, ++0x88,0x10,0x53,0x8E,0xC7,0xD2,0xA9,0x22, ++0x7F,0x10,0x7E,0x13,0x12,0x07,0x66,0x90, ++0x06,0x2D,0xEE,0xF0,0xA3,0xEF,0xF0,0xEE, ++0x44,0x10,0xFE,0x90,0x06,0x2D,0xF0,0xA3, ++0xEF,0xF0,0x54,0xEF,0xFF,0x90,0x06,0x2D, ++0xEE,0xF0,0xFC,0xA3,0xEF,0xF0,0xFD,0x7F, ++0x10,0x7E,0x13,0x12,0x07,0xAB,0xE4,0xFF, ++0xFE,0x0F,0xBF,0x00,0x01,0x0E,0xEF,0x64, ++0x64,0x4E,0x70,0xF5,0x7D,0x04,0x7C,0x00, ++0x7F,0x02,0x7E,0x66,0x12,0x07,0xAB,0x7D, ++0x00,0x7C,0x04,0x7F,0x01,0x7E,0x66,0x12, ++0x07,0xAB,0x7D,0xC0,0x7C,0x00,0x7F,0x00, ++0x7E,0x66,0x12,0x07,0xAB,0xE4,0xFD,0xFC, ++0x7F,0x02,0x7E,0x66,0x12,0x07,0xAB,0x7D, ++0x00,0x7C,0x04,0x7F,0x01,0x7E,0x66,0x12, ++0x07,0xAB,0x7D,0xC0,0x7C,0x00,0x7F,0x00, ++0x7E,0x66,0x12,0x07,0xAB,0x7F,0x10,0x7E, ++0x13,0x12,0x07,0x66,0x90,0x06,0x2D,0xEE, ++0xF0,0xA3,0xEF,0xF0,0xEE,0x54,0xEF,0x90, ++0x06,0x2D,0xF0,0xFC,0xA3,0xEF,0xF0,0xFD, ++0x7F,0x10,0x7E,0x13,0x02,0x07,0xAB,0x78, ++0x7F,0xE4,0xF6,0xD8,0xFD,0x75,0x81,0x3C, ++0x02,0x05,0xD6,0x02,0x03,0x2F,0xE4,0x93, ++0xA3,0xF8,0xE4,0x93,0xA3,0x40,0x03,0xF6, ++0x80,0x01,0xF2,0x08,0xDF,0xF4,0x80,0x29, ++0xE4,0x93,0xA3,0xF8,0x54,0x07,0x24,0x0C, ++0xC8,0xC3,0x33,0xC4,0x54,0x0F,0x44,0x20, ++0xC8,0x83,0x40,0x04,0xF4,0x56,0x80,0x01, ++0x46,0xF6,0xDF,0xE4,0x80,0x0B,0x01,0x02, ++0x04,0x08,0x10,0x20,0x40,0x80,0x90,0x07, ++0xE7,0xE4,0x7E,0x01,0x93,0x60,0xBC,0xA3, ++0xFF,0x54,0x3F,0x30,0xE5,0x09,0x54,0x1F, ++0xFE,0xE4,0x93,0xA3,0x60,0x01,0x0E,0xCF, ++0x54,0xC0,0x25,0xE0,0x60,0xA8,0x40,0xB8, ++0xE4,0x93,0xA3,0xFA,0xE4,0x93,0xA3,0xF8, ++0xE4,0x93,0xA3,0xC8,0xC5,0x82,0xC8,0xCA, ++0xC5,0x83,0xCA,0xF0,0xA3,0xC8,0xC5,0x82, ++0xC8,0xCA,0xC5,0x83,0xCA,0xDF,0xE9,0xDE, ++0xE7,0x80,0xBE,0x7D,0x40,0x7C,0x17,0x7F, ++0x11,0x7E,0x1D,0x12,0x07,0xAB,0x7F,0x41, ++0x7E,0x1D,0x12,0x07,0x66,0xEF,0x44,0x20, ++0x44,0x80,0xFD,0xAC,0x06,0x7F,0x41,0x7E, ++0x1D,0x12,0x07,0xAB,0x7D,0xBB,0x7C,0x15, ++0x7F,0xEB,0x7E,0x13,0x12,0x07,0xAB,0x7D, ++0x07,0x7C,0x00,0x7F,0xE7,0x7E,0x13,0x12, ++0x07,0xAB,0x7D,0x40,0x7C,0x11,0x7F,0x00, ++0x7E,0x62,0x12,0x07,0xAB,0x02,0x02,0x2F, ++0x7D,0xC0,0x7C,0x16,0x7F,0x11,0x7E,0x1D, ++0x12,0x07,0xAB,0x7D,0xBB,0x7C,0x15,0x7F, ++0xEB,0x7E,0x13,0x12,0x07,0xAB,0x7D,0x0D, ++0x7C,0x00,0x7F,0xE7,0x7E,0x13,0x12,0x07, ++0xAB,0x7F,0x41,0x7E,0x1D,0x12,0x07,0x66, ++0xEF,0x44,0x20,0x44,0x80,0xFD,0xAC,0x06, ++0x7F,0x41,0x7E,0x1D,0x12,0x07,0xAB,0x7D, ++0x00,0x7C,0x21,0x7F,0x00,0x7E,0x62,0x12, ++0x07,0xAB,0x02,0x02,0x2F,0x7D,0x40,0x7C, ++0x17,0x7F,0x11,0x7E,0x1D,0x12,0x07,0xAB, ++0x7D,0xBB,0x7C,0x15,0x7F,0xEB,0x7E,0x13, ++0x12,0x07,0xAB,0x7D,0x0C,0x7C,0x00,0x7F, ++0xE7,0x7E,0x13,0x12,0x07,0xAB,0x7F,0x41, ++0x7E,0x1D,0x12,0x07,0x66,0xEF,0x44,0x20, ++0x44,0x80,0xFD,0xAC,0x06,0x7F,0x41,0x7E, ++0x1D,0x12,0x07,0xAB,0x7D,0x40,0x7C,0x11, ++0x7F,0x00,0x7E,0x62,0x12,0x07,0xAB,0x02, ++0x02,0x2F,0x7D,0x04,0x7C,0x00,0x7F,0x01, ++0x7E,0x66,0x12,0x07,0xAB,0x7D,0x80,0x7C, ++0x00,0x7F,0x00,0x7E,0x66,0x12,0x07,0xAB, ++0x7F,0x02,0x7E,0x66,0x12,0x07,0x66,0xEF, ++0x44,0x02,0x44,0x04,0xFD,0xAC,0x06,0x7F, ++0x02,0x7E,0x66,0x12,0x07,0xAB,0x7D,0x04, ++0x7C,0x00,0x7F,0x01,0x7E,0x66,0x12,0x07, ++0xAB,0x7D,0xC0,0x7C,0x00,0x7F,0x00,0x7E, ++0x66,0x02,0x07,0xAB,0xC0,0xE0,0xC0,0xF0, ++0xC0,0x83,0xC0,0x82,0xC0,0xD0,0x75,0xD0, ++0x00,0xC0,0x00,0x78,0x17,0xE6,0xF5,0x8C, ++0x78,0x18,0xE6,0xF5,0x8A,0x90,0x06,0x31, ++0xE4,0x75,0xF0,0x01,0x12,0x00,0x0E,0x90, ++0x06,0x33,0xE4,0x75,0xF0,0x01,0x12,0x00, ++0x0E,0xD0,0x00,0xD0,0xD0,0xD0,0x82,0xD0, ++0x83,0xD0,0xF0,0xD0,0xE0,0x32,0xC2,0xAF, ++0xAD,0x07,0xAC,0x06,0x8C,0xA2,0x8D,0xA3, ++0x75,0xA0,0x01,0x00,0x00,0x00,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x00,0xAE,0xA1, ++0xBE,0x00,0xF0,0xAE,0xA6,0xAF,0xA7,0xD2, ++0xAF,0x22,0x7D,0x20,0x7C,0x0F,0x7F,0x02, ++0x7E,0x66,0x12,0x07,0xAB,0x7D,0x01,0x7C, ++0x00,0x7F,0x01,0x7E,0x66,0x12,0x07,0xAB, ++0x7D,0xC0,0x7C,0x00,0x7F,0x00,0x7E,0x66, ++0x02,0x07,0xAB,0xC2,0xAF,0xAB,0x07,0xAA, ++0x06,0x8A,0xA2,0x8B,0xA3,0x8C,0xA4,0x8D, ++0xA5,0x75,0xA0,0x03,0x00,0x00,0x00,0xAA, ++0xA1,0xBA,0x00,0xF8,0xD2,0xAF,0x22,0x7F, ++0x0C,0x7E,0x13,0x12,0x07,0x66,0xEF,0x44, ++0x50,0xFD,0xAC,0x06,0x7F,0x0C,0x7E,0x13, ++0x02,0x07,0xAB,0x12,0x07,0xC7,0x12,0x07, ++0xF2,0x12,0x04,0x2B,0x02,0x00,0x03,0x42, ++0x06,0x33,0x00,0x00,0x42,0x06,0x31,0x00, ++0x00,0x00,0xE4,0xF5,0x8E,0x22,}; ++ ++#define FIBER2_1G_INIT_SIZE 2032 ++rtk_uint8 Fiber2_1G[FIBER2_1G_INIT_SIZE] = { ++0x02,0x05,0x89,0xE4,0xF5,0xA8,0xD2,0xAF, ++0x22,0x00,0x00,0x02,0x07,0x26,0xC5,0xF0, ++0xF8,0xA3,0xE0,0x28,0xF0,0xC5,0xF0,0xF8, ++0xE5,0x82,0x15,0x82,0x70,0x02,0x15,0x83, ++0xE0,0x38,0xF0,0x22,0x75,0xF0,0x08,0x75, ++0x82,0x00,0xEF,0x2F,0xFF,0xEE,0x33,0xFE, ++0xCD,0x33,0xCD,0xCC,0x33,0xCC,0xC5,0x82, ++0x33,0xC5,0x82,0x9B,0xED,0x9A,0xEC,0x99, ++0xE5,0x82,0x98,0x40,0x0C,0xF5,0x82,0xEE, ++0x9B,0xFE,0xED,0x9A,0xFD,0xEC,0x99,0xFC, ++0x0F,0xD5,0xF0,0xD6,0xE4,0xCE,0xFB,0xE4, ++0xCD,0xFA,0xE4,0xCC,0xF9,0xA8,0x82,0x22, ++0xB8,0x00,0xC1,0xB9,0x00,0x59,0xBA,0x00, ++0x2D,0xEC,0x8B,0xF0,0x84,0xCF,0xCE,0xCD, ++0xFC,0xE5,0xF0,0xCB,0xF9,0x78,0x18,0xEF, ++0x2F,0xFF,0xEE,0x33,0xFE,0xED,0x33,0xFD, ++0xEC,0x33,0xFC,0xEB,0x33,0xFB,0x10,0xD7, ++0x03,0x99,0x40,0x04,0xEB,0x99,0xFB,0x0F, ++0xD8,0xE5,0xE4,0xF9,0xFA,0x22,0x78,0x18, ++0xEF,0x2F,0xFF,0xEE,0x33,0xFE,0xED,0x33, ++0xFD,0xEC,0x33,0xFC,0xC9,0x33,0xC9,0x10, ++0xD7,0x05,0x9B,0xE9,0x9A,0x40,0x07,0xEC, ++0x9B,0xFC,0xE9,0x9A,0xF9,0x0F,0xD8,0xE0, ++0xE4,0xC9,0xFA,0xE4,0xCC,0xFB,0x22,0x75, ++0xF0,0x10,0xEF,0x2F,0xFF,0xEE,0x33,0xFE, ++0xED,0x33,0xFD,0xCC,0x33,0xCC,0xC8,0x33, ++0xC8,0x10,0xD7,0x07,0x9B,0xEC,0x9A,0xE8, ++0x99,0x40,0x0A,0xED,0x9B,0xFD,0xEC,0x9A, ++0xFC,0xE8,0x99,0xF8,0x0F,0xD5,0xF0,0xDA, ++0xE4,0xCD,0xFB,0xE4,0xCC,0xFA,0xE4,0xC8, ++0xF9,0x22,0xEB,0x9F,0xF5,0xF0,0xEA,0x9E, ++0x42,0xF0,0xE9,0x9D,0x42,0xF0,0xE8,0x9C, ++0x45,0xF0,0x22,0xE0,0xFC,0xA3,0xE0,0xFD, ++0xA3,0xE0,0xFE,0xA3,0xE0,0xFF,0x22,0xE0, ++0xF8,0xA3,0xE0,0xF9,0xA3,0xE0,0xFA,0xA3, ++0xE0,0xFB,0x22,0xEC,0xF0,0xA3,0xED,0xF0, ++0xA3,0xEE,0xF0,0xA3,0xEF,0xF0,0x22,0x7D, ++0xD7,0x7C,0x04,0x7F,0x02,0x7E,0x66,0x12, ++0x07,0xA5,0x7D,0x80,0x7C,0x04,0x7F,0x01, ++0x7E,0x66,0x12,0x07,0xA5,0x7D,0xC0,0x7C, ++0x00,0x7F,0x00,0x7E,0x66,0x12,0x07,0xA5, ++0x7D,0x94,0x7C,0xF9,0x7F,0x02,0x7E,0x66, ++0x12,0x07,0xA5,0x7D,0x81,0x7C,0x04,0x7F, ++0x01,0x7E,0x66,0x12,0x07,0xA5,0x7D,0xC0, ++0x7C,0x00,0x7F,0x00,0x7E,0x66,0x12,0x07, ++0xA5,0x7D,0xA2,0x7C,0x31,0x7F,0x02,0x7E, ++0x66,0x12,0x07,0xA5,0x7D,0x82,0x7C,0x04, ++0x7F,0x01,0x7E,0x66,0x12,0x07,0xA5,0x7D, ++0xC0,0x7C,0x00,0x7F,0x00,0x7E,0x66,0x12, ++0x07,0xA5,0x7D,0x60,0x7C,0x69,0x7F,0x02, ++0x7E,0x66,0x12,0x07,0xA5,0x7D,0x83,0x7C, ++0x04,0x7F,0x01,0x7E,0x66,0x12,0x07,0xA5, ++0x7D,0xC0,0x7C,0x00,0x7F,0x00,0x7E,0x66, ++0x12,0x07,0xA5,0x7D,0x28,0x7C,0x97,0x7F, ++0x02,0x7E,0x66,0x12,0x07,0xA5,0x7D,0x84, ++0x7C,0x04,0x7F,0x01,0x7E,0x66,0x12,0x07, ++0xA5,0x7D,0xC0,0x7C,0x00,0x7F,0x00,0x7E, ++0x66,0x12,0x07,0xA5,0x7D,0x85,0x7C,0x9D, ++0x7F,0x02,0x7E,0x66,0x12,0x07,0xA5,0x7D, ++0x23,0x7C,0x04,0x7F,0x01,0x7E,0x66,0x12, ++0x07,0xA5,0x7D,0xC0,0x7C,0x00,0x7F,0x00, ++0x7E,0x66,0x12,0x07,0xA5,0x7D,0x10,0x7C, ++0xD8,0x7F,0x02,0x7E,0x66,0x12,0x07,0xA5, ++0x7D,0x24,0x7C,0x04,0x7F,0x01,0x7E,0x66, ++0x12,0x07,0xA5,0x7D,0xC0,0x7C,0x00,0x7F, ++0x00,0x7E,0x66,0x12,0x07,0xA5,0x7D,0x00, ++0x7C,0x04,0x7F,0x02,0x7E,0x66,0x12,0x07, ++0xA5,0x7D,0x2F,0x7C,0x00,0x7F,0x01,0x7E, ++0x66,0x12,0x07,0xA5,0x7D,0xC0,0x7C,0x00, ++0x7F,0x00,0x7E,0x66,0x02,0x07,0xA5,0x7D, ++0x03,0x7C,0x00,0x7F,0x01,0x7E,0x66,0x12, ++0x07,0xA5,0x7D,0x80,0x7C,0x00,0x7F,0x00, ++0x7E,0x66,0x12,0x07,0xA5,0x7F,0x02,0x7E, ++0x66,0x12,0x07,0x60,0xEF,0x44,0x40,0xFD, ++0xAC,0x06,0x7F,0x02,0x7E,0x66,0x12,0x07, ++0xA5,0x7D,0x03,0x7C,0x00,0x7F,0x01,0x7E, ++0x66,0x12,0x07,0xA5,0x7D,0xC0,0x7C,0x00, ++0x7F,0x00,0x7E,0x66,0x12,0x07,0xA5,0x7D, ++0x03,0x7C,0x00,0x7F,0x01,0x7E,0x66,0x12, ++0x07,0xA5,0x7D,0x80,0x7C,0x00,0x7F,0x00, ++0x7E,0x66,0x12,0x07,0xA5,0x7F,0x02,0x7E, ++0x66,0x12,0x07,0x60,0xEF,0x54,0xBF,0xFD, ++0xAC,0x06,0x7F,0x02,0x7E,0x66,0x12,0x07, ++0xA5,0x7D,0x03,0x7C,0x00,0x7F,0x01,0x7E, ++0x66,0x12,0x07,0xA5,0x7D,0xC0,0x7C,0x00, ++0x7F,0x00,0x7E,0x66,0x12,0x07,0xA5,0xE4, ++0xFD,0xFC,0x7F,0x01,0x7E,0x66,0x12,0x07, ++0xA5,0x7D,0x80,0x7C,0x00,0x7F,0x00,0x7E, ++0x66,0x12,0x07,0xA5,0x7F,0x02,0x7E,0x66, ++0x12,0x07,0x60,0xEF,0x54,0xFD,0x54,0xFE, ++0xFD,0xAC,0x06,0x7F,0x02,0x7E,0x66,0x12, ++0x07,0xA5,0xE4,0xFD,0xFC,0x7F,0x01,0x7E, ++0x66,0x12,0x07,0xA5,0x7D,0xC0,0x7C,0x00, ++0x7F,0x00,0x7E,0x66,0x12,0x07,0xA5,0xE4, ++0xFD,0xFC,0x7F,0x01,0x7E,0x66,0x12,0x07, ++0xA5,0x7D,0x80,0x7C,0x00,0x7F,0x00,0x7E, ++0x66,0x12,0x07,0xA5,0x7F,0x02,0x7E,0x66, ++0x12,0x07,0x60,0xEF,0x44,0x02,0x44,0x01, ++0xFD,0xAC,0x06,0x7F,0x02,0x7E,0x66,0x12, ++0x07,0xA5,0xE4,0xFD,0xFC,0x7F,0x01,0x7E, ++0x66,0x12,0x07,0xA5,0x7D,0xC0,0x7C,0x00, ++0x7F,0x00,0x7E,0x66,0x02,0x07,0xA5,0xE4, ++0x90,0x06,0x2C,0xF0,0xFD,0x7C,0x01,0x7F, ++0x3F,0x7E,0x1D,0x12,0x07,0xA5,0x7D,0x40, ++0x7C,0x00,0x7F,0x36,0x7E,0x13,0x12,0x07, ++0xA5,0xE4,0xFF,0xFE,0xFD,0x80,0x25,0xE4, ++0x7F,0xFF,0x7E,0xFF,0xFD,0xFC,0x90,0x06, ++0x24,0x12,0x01,0x0F,0xC3,0x12,0x00,0xF2, ++0x50,0x1B,0x90,0x06,0x24,0x12,0x01,0x03, ++0xEF,0x24,0x01,0xFF,0xE4,0x3E,0xFE,0xE4, ++0x3D,0xFD,0xE4,0x3C,0xFC,0x90,0x06,0x24, ++0x12,0x01,0x1B,0x80,0xD2,0xE4,0xF5,0xA8, ++0xD2,0xAF,0x7D,0x1F,0xFC,0x7F,0x49,0x7E, ++0x13,0x12,0x07,0xA5,0x12,0x07,0xD5,0x12, ++0x01,0x27,0x12,0x06,0x9F,0x7D,0x41,0x7C, ++0x00,0x7F,0x36,0x7E,0x13,0x12,0x07,0xA5, ++0xE4,0xFF,0xFE,0xFD,0x80,0x26,0x7F,0xFF, ++0x7E,0xFF,0x7D,0x05,0x7C,0x00,0x90,0x06, ++0x24,0x12,0x01,0x0F,0xC3,0x12,0x00,0xF2, ++0x50,0x1B,0x90,0x06,0x24,0x12,0x01,0x03, ++0xEF,0x24,0x01,0xFF,0xE4,0x3E,0xFE,0xE4, ++0x3D,0xFD,0xE4,0x3C,0xFC,0x90,0x06,0x24, ++0x12,0x01,0x1B,0x80,0xD1,0xC2,0x00,0xC2, ++0x01,0xD2,0xA9,0xD2,0x8C,0x7F,0x01,0x7E, ++0x62,0x12,0x07,0x60,0xEF,0x30,0xE2,0x07, ++0xE4,0x90,0x06,0x2C,0xF0,0x80,0xEE,0x90, ++0x06,0x2C,0xE0,0x70,0x12,0x12,0x04,0xEA, ++0x90,0x06,0x2C,0x74,0x01,0xF0,0xE4,0x90, ++0x06,0x33,0xF0,0xA3,0xF0,0x80,0xD6,0xC3, ++0x90,0x06,0x34,0xE0,0x94,0x62,0x90,0x06, ++0x33,0xE0,0x94,0x00,0x40,0xC7,0xE4,0xF0, ++0xA3,0xF0,0x12,0x04,0xEA,0x90,0x06,0x2C, ++0x74,0x01,0xF0,0x80,0xB8,0x75,0x0F,0x80, ++0x75,0x0E,0x7E,0x75,0x0D,0xAA,0x75,0x0C, ++0x83,0xE4,0xF5,0x10,0x7F,0x36,0x7E,0x13, ++0x12,0x07,0x60,0xEE,0xC4,0xF8,0x54,0xF0, ++0xC8,0xEF,0xC4,0x54,0x0F,0x48,0x54,0x07, ++0xFB,0x7A,0x00,0xEA,0x70,0x4A,0xEB,0x14, ++0x60,0x1C,0x14,0x60,0x27,0x24,0xFE,0x60, ++0x31,0x14,0x60,0x3C,0x24,0x05,0x70,0x38, ++0x75,0x0B,0x00,0x75,0x0A,0xC2,0x75,0x09, ++0xEB,0x75,0x08,0x0B,0x80,0x36,0x75,0x0B, ++0x40,0x75,0x0A,0x59,0x75,0x09,0x73,0x75, ++0x08,0x07,0x80,0x28,0x75,0x0B,0x00,0x75, ++0x0A,0xE1,0x75,0x09,0xF5,0x75,0x08,0x05, ++0x80,0x1A,0x75,0x0B,0xA0,0x75,0x0A,0xAC, ++0x75,0x09,0xB9,0x75,0x08,0x03,0x80,0x0C, ++0x75,0x0B,0x00,0x75,0x0A,0x62,0x75,0x09, ++0x3D,0x75,0x08,0x01,0x75,0x89,0x11,0xE4, ++0x7B,0x60,0x7A,0x09,0xF9,0xF8,0xAF,0x0B, ++0xAE,0x0A,0xAD,0x09,0xAC,0x08,0x12,0x00, ++0x60,0xAA,0x06,0xAB,0x07,0xC3,0xE4,0x9B, ++0xFB,0xE4,0x9A,0xFA,0x78,0x17,0xF6,0xAF, ++0x03,0xEF,0x08,0xF6,0x18,0xE6,0xF5,0x8C, ++0x08,0xE6,0xF5,0x8A,0x74,0x0D,0x2B,0xFB, ++0xE4,0x3A,0x18,0xF6,0xAF,0x03,0xEF,0x08, ++0xF6,0x75,0x88,0x10,0x53,0x8E,0xC7,0xD2, ++0xA9,0x22,0x7F,0x10,0x7E,0x13,0x12,0x07, ++0x60,0x90,0x06,0x2D,0xEE,0xF0,0xA3,0xEF, ++0xF0,0xEE,0x44,0x10,0xFE,0x90,0x06,0x2D, ++0xF0,0xA3,0xEF,0xF0,0x54,0xEF,0xFF,0x90, ++0x06,0x2D,0xEE,0xF0,0xFC,0xA3,0xEF,0xF0, ++0xFD,0x7F,0x10,0x7E,0x13,0x12,0x07,0xA5, ++0xE4,0xFF,0xFE,0x0F,0xBF,0x00,0x01,0x0E, ++0xEF,0x64,0x64,0x4E,0x70,0xF5,0x7D,0x04, ++0x7C,0x00,0x7F,0x02,0x7E,0x66,0x12,0x07, ++0xA5,0x7D,0x00,0x7C,0x04,0x7F,0x01,0x7E, ++0x66,0x12,0x07,0xA5,0x7D,0xC0,0x7C,0x00, ++0x7F,0x00,0x7E,0x66,0x12,0x07,0xA5,0xE4, ++0xFD,0xFC,0x7F,0x02,0x7E,0x66,0x12,0x07, ++0xA5,0x7D,0x00,0x7C,0x04,0x7F,0x01,0x7E, ++0x66,0x12,0x07,0xA5,0x7D,0xC0,0x7C,0x00, ++0x7F,0x00,0x7E,0x66,0x12,0x07,0xA5,0x7F, ++0x10,0x7E,0x13,0x12,0x07,0x60,0x90,0x06, ++0x2D,0xEE,0xF0,0xA3,0xEF,0xF0,0xEE,0x54, ++0xEF,0x90,0x06,0x2D,0xF0,0xFC,0xA3,0xEF, ++0xF0,0xFD,0x7F,0x10,0x7E,0x13,0x02,0x07, ++0xA5,0x78,0x7F,0xE4,0xF6,0xD8,0xFD,0x75, ++0x81,0x3C,0x02,0x05,0xD0,0x02,0x03,0x2F, ++0xE4,0x93,0xA3,0xF8,0xE4,0x93,0xA3,0x40, ++0x03,0xF6,0x80,0x01,0xF2,0x08,0xDF,0xF4, ++0x80,0x29,0xE4,0x93,0xA3,0xF8,0x54,0x07, ++0x24,0x0C,0xC8,0xC3,0x33,0xC4,0x54,0x0F, ++0x44,0x20,0xC8,0x83,0x40,0x04,0xF4,0x56, ++0x80,0x01,0x46,0xF6,0xDF,0xE4,0x80,0x0B, ++0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80, ++0x90,0x07,0xE1,0xE4,0x7E,0x01,0x93,0x60, ++0xBC,0xA3,0xFF,0x54,0x3F,0x30,0xE5,0x09, ++0x54,0x1F,0xFE,0xE4,0x93,0xA3,0x60,0x01, ++0x0E,0xCF,0x54,0xC0,0x25,0xE0,0x60,0xA8, ++0x40,0xB8,0xE4,0x93,0xA3,0xFA,0xE4,0x93, ++0xA3,0xF8,0xE4,0x93,0xA3,0xC8,0xC5,0x82, ++0xC8,0xCA,0xC5,0x83,0xCA,0xF0,0xA3,0xC8, ++0xC5,0x82,0xC8,0xCA,0xC5,0x83,0xCA,0xDF, ++0xE9,0xDE,0xE7,0x80,0xBE,0x7D,0x40,0x7C, ++0x17,0x7F,0x11,0x7E,0x1D,0x12,0x07,0xA5, ++0x7F,0x41,0x7E,0x1D,0x12,0x07,0x60,0xEF, ++0x44,0x20,0x44,0x80,0xFD,0xAC,0x06,0x7F, ++0x41,0x7E,0x1D,0x12,0x07,0xA5,0x7D,0xBB, ++0x7C,0x15,0x7F,0xEB,0x7E,0x13,0x12,0x07, ++0xA5,0x7D,0x07,0x7C,0x00,0x7F,0xE7,0x7E, ++0x13,0x12,0x07,0xA5,0x7D,0x40,0x7C,0x11, ++0x7F,0x00,0x7E,0x62,0x12,0x07,0xA5,0x02, ++0x02,0x2F,0x7D,0xC0,0x7C,0x16,0x7F,0x11, ++0x7E,0x1D,0x12,0x07,0xA5,0x7D,0xBB,0x7C, ++0x15,0x7F,0xEB,0x7E,0x13,0x12,0x07,0xA5, ++0x7D,0x0D,0x7C,0x00,0x7F,0xE7,0x7E,0x13, ++0x12,0x07,0xA5,0x7F,0x41,0x7E,0x1D,0x12, ++0x07,0x60,0xEF,0x44,0x20,0x44,0x80,0xFD, ++0xAC,0x06,0x7F,0x41,0x7E,0x1D,0x12,0x07, ++0xA5,0x7D,0x00,0x7C,0x21,0x7F,0x00,0x7E, ++0x62,0x12,0x07,0xA5,0x02,0x02,0x2F,0x7D, ++0x40,0x7C,0x17,0x7F,0x11,0x7E,0x1D,0x12, ++0x07,0xA5,0x7D,0xBB,0x7C,0x15,0x7F,0xEB, ++0x7E,0x13,0x12,0x07,0xA5,0x7D,0x0C,0x7C, ++0x00,0x7F,0xE7,0x7E,0x13,0x12,0x07,0xA5, ++0x7F,0x41,0x7E,0x1D,0x12,0x07,0x60,0xEF, ++0x44,0x20,0x44,0x80,0xFD,0xAC,0x06,0x7F, ++0x41,0x7E,0x1D,0x12,0x07,0xA5,0x7D,0x40, ++0x7C,0x11,0x7F,0x00,0x7E,0x62,0x12,0x07, ++0xA5,0x02,0x02,0x2F,0x7D,0x04,0x7C,0x00, ++0x7F,0x01,0x7E,0x66,0x12,0x07,0xA5,0x7D, ++0x80,0x7C,0x00,0x7F,0x00,0x7E,0x66,0x12, ++0x07,0xA5,0x7F,0x02,0x7E,0x66,0x12,0x07, ++0x60,0xEF,0x44,0x02,0x44,0x04,0xFD,0xAC, ++0x06,0x7F,0x02,0x7E,0x66,0x12,0x07,0xA5, ++0x7D,0x04,0x7C,0x00,0x7F,0x01,0x7E,0x66, ++0x12,0x07,0xA5,0x7D,0xC0,0x7C,0x00,0x7F, ++0x00,0x7E,0x66,0x02,0x07,0xA5,0xC0,0xE0, ++0xC0,0xF0,0xC0,0x83,0xC0,0x82,0xC0,0xD0, ++0x75,0xD0,0x00,0xC0,0x00,0x78,0x17,0xE6, ++0xF5,0x8C,0x78,0x18,0xE6,0xF5,0x8A,0x90, ++0x06,0x31,0xE4,0x75,0xF0,0x01,0x12,0x00, ++0x0E,0x90,0x06,0x33,0xE4,0x75,0xF0,0x01, ++0x12,0x00,0x0E,0xD0,0x00,0xD0,0xD0,0xD0, ++0x82,0xD0,0x83,0xD0,0xF0,0xD0,0xE0,0x32, ++0xC2,0xAF,0xAD,0x07,0xAC,0x06,0x8C,0xA2, ++0x8D,0xA3,0x75,0xA0,0x01,0x00,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++0xAE,0xA1,0xBE,0x00,0xF0,0xAE,0xA6,0xAF, ++0xA7,0xD2,0xAF,0x22,0x7D,0x20,0x7C,0x0F, ++0x7F,0x02,0x7E,0x66,0x12,0x07,0xA5,0x7D, ++0x01,0x7C,0x00,0x7F,0x01,0x7E,0x66,0x12, ++0x07,0xA5,0x7D,0xC0,0x7C,0x00,0x7F,0x00, ++0x7E,0x66,0x02,0x07,0xA5,0xC2,0xAF,0xAB, ++0x07,0xAA,0x06,0x8A,0xA2,0x8B,0xA3,0x8C, ++0xA4,0x8D,0xA5,0x75,0xA0,0x03,0x00,0x00, ++0x00,0xAA,0xA1,0xBA,0x00,0xF8,0xD2,0xAF, ++0x22,0x7F,0x0C,0x7E,0x13,0x12,0x07,0x60, ++0xEF,0x44,0x50,0xFD,0xAC,0x06,0x7F,0x0C, ++0x7E,0x13,0x02,0x07,0xA5,0x12,0x07,0xC1, ++0x12,0x07,0xEC,0x12,0x04,0x25,0x02,0x00, ++0x03,0x42,0x06,0x33,0x00,0x00,0x42,0x06, ++0x31,0x00,0x00,0x00,0xE4,0xF5,0x8E,0x22,}; ++ ++#define FIBER2_100M_INIT_SIZE 2032 ++rtk_uint8 Fiber2_100M[FIBER2_100M_INIT_SIZE] = { ++0x02,0x05,0x89,0xE4,0xF5,0xA8,0xD2,0xAF, ++0x22,0x00,0x00,0x02,0x07,0x26,0xC5,0xF0, ++0xF8,0xA3,0xE0,0x28,0xF0,0xC5,0xF0,0xF8, ++0xE5,0x82,0x15,0x82,0x70,0x02,0x15,0x83, ++0xE0,0x38,0xF0,0x22,0x75,0xF0,0x08,0x75, ++0x82,0x00,0xEF,0x2F,0xFF,0xEE,0x33,0xFE, ++0xCD,0x33,0xCD,0xCC,0x33,0xCC,0xC5,0x82, ++0x33,0xC5,0x82,0x9B,0xED,0x9A,0xEC,0x99, ++0xE5,0x82,0x98,0x40,0x0C,0xF5,0x82,0xEE, ++0x9B,0xFE,0xED,0x9A,0xFD,0xEC,0x99,0xFC, ++0x0F,0xD5,0xF0,0xD6,0xE4,0xCE,0xFB,0xE4, ++0xCD,0xFA,0xE4,0xCC,0xF9,0xA8,0x82,0x22, ++0xB8,0x00,0xC1,0xB9,0x00,0x59,0xBA,0x00, ++0x2D,0xEC,0x8B,0xF0,0x84,0xCF,0xCE,0xCD, ++0xFC,0xE5,0xF0,0xCB,0xF9,0x78,0x18,0xEF, ++0x2F,0xFF,0xEE,0x33,0xFE,0xED,0x33,0xFD, ++0xEC,0x33,0xFC,0xEB,0x33,0xFB,0x10,0xD7, ++0x03,0x99,0x40,0x04,0xEB,0x99,0xFB,0x0F, ++0xD8,0xE5,0xE4,0xF9,0xFA,0x22,0x78,0x18, ++0xEF,0x2F,0xFF,0xEE,0x33,0xFE,0xED,0x33, ++0xFD,0xEC,0x33,0xFC,0xC9,0x33,0xC9,0x10, ++0xD7,0x05,0x9B,0xE9,0x9A,0x40,0x07,0xEC, ++0x9B,0xFC,0xE9,0x9A,0xF9,0x0F,0xD8,0xE0, ++0xE4,0xC9,0xFA,0xE4,0xCC,0xFB,0x22,0x75, ++0xF0,0x10,0xEF,0x2F,0xFF,0xEE,0x33,0xFE, ++0xED,0x33,0xFD,0xCC,0x33,0xCC,0xC8,0x33, ++0xC8,0x10,0xD7,0x07,0x9B,0xEC,0x9A,0xE8, ++0x99,0x40,0x0A,0xED,0x9B,0xFD,0xEC,0x9A, ++0xFC,0xE8,0x99,0xF8,0x0F,0xD5,0xF0,0xDA, ++0xE4,0xCD,0xFB,0xE4,0xCC,0xFA,0xE4,0xC8, ++0xF9,0x22,0xEB,0x9F,0xF5,0xF0,0xEA,0x9E, ++0x42,0xF0,0xE9,0x9D,0x42,0xF0,0xE8,0x9C, ++0x45,0xF0,0x22,0xE0,0xFC,0xA3,0xE0,0xFD, ++0xA3,0xE0,0xFE,0xA3,0xE0,0xFF,0x22,0xE0, ++0xF8,0xA3,0xE0,0xF9,0xA3,0xE0,0xFA,0xA3, ++0xE0,0xFB,0x22,0xEC,0xF0,0xA3,0xED,0xF0, ++0xA3,0xEE,0xF0,0xA3,0xEF,0xF0,0x22,0x7D, ++0xD7,0x7C,0x04,0x7F,0x02,0x7E,0x66,0x12, ++0x07,0xA5,0x7D,0x80,0x7C,0x04,0x7F,0x01, ++0x7E,0x66,0x12,0x07,0xA5,0x7D,0xC0,0x7C, ++0x00,0x7F,0x00,0x7E,0x66,0x12,0x07,0xA5, ++0x7D,0x94,0x7C,0xF9,0x7F,0x02,0x7E,0x66, ++0x12,0x07,0xA5,0x7D,0x81,0x7C,0x04,0x7F, ++0x01,0x7E,0x66,0x12,0x07,0xA5,0x7D,0xC0, ++0x7C,0x00,0x7F,0x00,0x7E,0x66,0x12,0x07, ++0xA5,0x7D,0xA2,0x7C,0x31,0x7F,0x02,0x7E, ++0x66,0x12,0x07,0xA5,0x7D,0x82,0x7C,0x04, ++0x7F,0x01,0x7E,0x66,0x12,0x07,0xA5,0x7D, ++0xC0,0x7C,0x00,0x7F,0x00,0x7E,0x66,0x12, ++0x07,0xA5,0x7D,0x60,0x7C,0x69,0x7F,0x02, ++0x7E,0x66,0x12,0x07,0xA5,0x7D,0x83,0x7C, ++0x04,0x7F,0x01,0x7E,0x66,0x12,0x07,0xA5, ++0x7D,0xC0,0x7C,0x00,0x7F,0x00,0x7E,0x66, ++0x12,0x07,0xA5,0x7D,0x28,0x7C,0x97,0x7F, ++0x02,0x7E,0x66,0x12,0x07,0xA5,0x7D,0x84, ++0x7C,0x04,0x7F,0x01,0x7E,0x66,0x12,0x07, ++0xA5,0x7D,0xC0,0x7C,0x00,0x7F,0x00,0x7E, ++0x66,0x12,0x07,0xA5,0x7D,0x85,0x7C,0x9D, ++0x7F,0x02,0x7E,0x66,0x12,0x07,0xA5,0x7D, ++0x23,0x7C,0x04,0x7F,0x01,0x7E,0x66,0x12, ++0x07,0xA5,0x7D,0xC0,0x7C,0x00,0x7F,0x00, ++0x7E,0x66,0x12,0x07,0xA5,0x7D,0x10,0x7C, ++0xD8,0x7F,0x02,0x7E,0x66,0x12,0x07,0xA5, ++0x7D,0x24,0x7C,0x04,0x7F,0x01,0x7E,0x66, ++0x12,0x07,0xA5,0x7D,0xC0,0x7C,0x00,0x7F, ++0x00,0x7E,0x66,0x12,0x07,0xA5,0x7D,0x00, ++0x7C,0x04,0x7F,0x02,0x7E,0x66,0x12,0x07, ++0xA5,0x7D,0x2F,0x7C,0x00,0x7F,0x01,0x7E, ++0x66,0x12,0x07,0xA5,0x7D,0xC0,0x7C,0x00, ++0x7F,0x00,0x7E,0x66,0x02,0x07,0xA5,0x7D, ++0x03,0x7C,0x00,0x7F,0x01,0x7E,0x66,0x12, ++0x07,0xA5,0x7D,0x80,0x7C,0x00,0x7F,0x00, ++0x7E,0x66,0x12,0x07,0xA5,0x7F,0x02,0x7E, ++0x66,0x12,0x07,0x60,0xEF,0x44,0x40,0xFD, ++0xAC,0x06,0x7F,0x02,0x7E,0x66,0x12,0x07, ++0xA5,0x7D,0x03,0x7C,0x00,0x7F,0x01,0x7E, ++0x66,0x12,0x07,0xA5,0x7D,0xC0,0x7C,0x00, ++0x7F,0x00,0x7E,0x66,0x12,0x07,0xA5,0x7D, ++0x03,0x7C,0x00,0x7F,0x01,0x7E,0x66,0x12, ++0x07,0xA5,0x7D,0x80,0x7C,0x00,0x7F,0x00, ++0x7E,0x66,0x12,0x07,0xA5,0x7F,0x02,0x7E, ++0x66,0x12,0x07,0x60,0xEF,0x54,0xBF,0xFD, ++0xAC,0x06,0x7F,0x02,0x7E,0x66,0x12,0x07, ++0xA5,0x7D,0x03,0x7C,0x00,0x7F,0x01,0x7E, ++0x66,0x12,0x07,0xA5,0x7D,0xC0,0x7C,0x00, ++0x7F,0x00,0x7E,0x66,0x12,0x07,0xA5,0xE4, ++0xFD,0xFC,0x7F,0x01,0x7E,0x66,0x12,0x07, ++0xA5,0x7D,0x80,0x7C,0x00,0x7F,0x00,0x7E, ++0x66,0x12,0x07,0xA5,0x7F,0x02,0x7E,0x66, ++0x12,0x07,0x60,0xEF,0x54,0xFD,0x54,0xFE, ++0xFD,0xAC,0x06,0x7F,0x02,0x7E,0x66,0x12, ++0x07,0xA5,0xE4,0xFD,0xFC,0x7F,0x01,0x7E, ++0x66,0x12,0x07,0xA5,0x7D,0xC0,0x7C,0x00, ++0x7F,0x00,0x7E,0x66,0x12,0x07,0xA5,0xE4, ++0xFD,0xFC,0x7F,0x01,0x7E,0x66,0x12,0x07, ++0xA5,0x7D,0x80,0x7C,0x00,0x7F,0x00,0x7E, ++0x66,0x12,0x07,0xA5,0x7F,0x02,0x7E,0x66, ++0x12,0x07,0x60,0xEF,0x44,0x02,0x44,0x01, ++0xFD,0xAC,0x06,0x7F,0x02,0x7E,0x66,0x12, ++0x07,0xA5,0xE4,0xFD,0xFC,0x7F,0x01,0x7E, ++0x66,0x12,0x07,0xA5,0x7D,0xC0,0x7C,0x00, ++0x7F,0x00,0x7E,0x66,0x02,0x07,0xA5,0xE4, ++0x90,0x06,0x2C,0xF0,0xFD,0x7C,0x01,0x7F, ++0x3F,0x7E,0x1D,0x12,0x07,0xA5,0x7D,0x40, ++0x7C,0x00,0x7F,0x36,0x7E,0x13,0x12,0x07, ++0xA5,0xE4,0xFF,0xFE,0xFD,0x80,0x25,0xE4, ++0x7F,0xFF,0x7E,0xFF,0xFD,0xFC,0x90,0x06, ++0x24,0x12,0x01,0x0F,0xC3,0x12,0x00,0xF2, ++0x50,0x1B,0x90,0x06,0x24,0x12,0x01,0x03, ++0xEF,0x24,0x01,0xFF,0xE4,0x3E,0xFE,0xE4, ++0x3D,0xFD,0xE4,0x3C,0xFC,0x90,0x06,0x24, ++0x12,0x01,0x1B,0x80,0xD2,0xE4,0xF5,0xA8, ++0xD2,0xAF,0x7D,0x1F,0xFC,0x7F,0x49,0x7E, ++0x13,0x12,0x07,0xA5,0x12,0x07,0xD5,0x12, ++0x01,0x27,0x12,0x06,0x5A,0x7D,0x41,0x7C, ++0x00,0x7F,0x36,0x7E,0x13,0x12,0x07,0xA5, ++0xE4,0xFF,0xFE,0xFD,0x80,0x26,0x7F,0xFF, ++0x7E,0xFF,0x7D,0x05,0x7C,0x00,0x90,0x06, ++0x24,0x12,0x01,0x0F,0xC3,0x12,0x00,0xF2, ++0x50,0x1B,0x90,0x06,0x24,0x12,0x01,0x03, ++0xEF,0x24,0x01,0xFF,0xE4,0x3E,0xFE,0xE4, ++0x3D,0xFD,0xE4,0x3C,0xFC,0x90,0x06,0x24, ++0x12,0x01,0x1B,0x80,0xD1,0xC2,0x00,0xC2, ++0x01,0xD2,0xA9,0xD2,0x8C,0x7F,0x01,0x7E, ++0x62,0x12,0x07,0x60,0xEF,0x30,0xE2,0x07, ++0xE4,0x90,0x06,0x2C,0xF0,0x80,0xEE,0x90, ++0x06,0x2C,0xE0,0x70,0x12,0x12,0x04,0xEA, ++0x90,0x06,0x2C,0x74,0x01,0xF0,0xE4,0x90, ++0x06,0x33,0xF0,0xA3,0xF0,0x80,0xD6,0xC3, ++0x90,0x06,0x34,0xE0,0x94,0x62,0x90,0x06, ++0x33,0xE0,0x94,0x00,0x40,0xC7,0xE4,0xF0, ++0xA3,0xF0,0x12,0x04,0xEA,0x90,0x06,0x2C, ++0x74,0x01,0xF0,0x80,0xB8,0x75,0x0F,0x80, ++0x75,0x0E,0x7E,0x75,0x0D,0xAA,0x75,0x0C, ++0x83,0xE4,0xF5,0x10,0x7F,0x36,0x7E,0x13, ++0x12,0x07,0x60,0xEE,0xC4,0xF8,0x54,0xF0, ++0xC8,0xEF,0xC4,0x54,0x0F,0x48,0x54,0x07, ++0xFB,0x7A,0x00,0xEA,0x70,0x4A,0xEB,0x14, ++0x60,0x1C,0x14,0x60,0x27,0x24,0xFE,0x60, ++0x31,0x14,0x60,0x3C,0x24,0x05,0x70,0x38, ++0x75,0x0B,0x00,0x75,0x0A,0xC2,0x75,0x09, ++0xEB,0x75,0x08,0x0B,0x80,0x36,0x75,0x0B, ++0x40,0x75,0x0A,0x59,0x75,0x09,0x73,0x75, ++0x08,0x07,0x80,0x28,0x75,0x0B,0x00,0x75, ++0x0A,0xE1,0x75,0x09,0xF5,0x75,0x08,0x05, ++0x80,0x1A,0x75,0x0B,0xA0,0x75,0x0A,0xAC, ++0x75,0x09,0xB9,0x75,0x08,0x03,0x80,0x0C, ++0x75,0x0B,0x00,0x75,0x0A,0x62,0x75,0x09, ++0x3D,0x75,0x08,0x01,0x75,0x89,0x11,0xE4, ++0x7B,0x60,0x7A,0x09,0xF9,0xF8,0xAF,0x0B, ++0xAE,0x0A,0xAD,0x09,0xAC,0x08,0x12,0x00, ++0x60,0xAA,0x06,0xAB,0x07,0xC3,0xE4,0x9B, ++0xFB,0xE4,0x9A,0xFA,0x78,0x17,0xF6,0xAF, ++0x03,0xEF,0x08,0xF6,0x18,0xE6,0xF5,0x8C, ++0x08,0xE6,0xF5,0x8A,0x74,0x0D,0x2B,0xFB, ++0xE4,0x3A,0x18,0xF6,0xAF,0x03,0xEF,0x08, ++0xF6,0x75,0x88,0x10,0x53,0x8E,0xC7,0xD2, ++0xA9,0x22,0x7F,0x10,0x7E,0x13,0x12,0x07, ++0x60,0x90,0x06,0x2D,0xEE,0xF0,0xA3,0xEF, ++0xF0,0xEE,0x44,0x10,0xFE,0x90,0x06,0x2D, ++0xF0,0xA3,0xEF,0xF0,0x54,0xEF,0xFF,0x90, ++0x06,0x2D,0xEE,0xF0,0xFC,0xA3,0xEF,0xF0, ++0xFD,0x7F,0x10,0x7E,0x13,0x12,0x07,0xA5, ++0xE4,0xFF,0xFE,0x0F,0xBF,0x00,0x01,0x0E, ++0xEF,0x64,0x64,0x4E,0x70,0xF5,0x7D,0x04, ++0x7C,0x00,0x7F,0x02,0x7E,0x66,0x12,0x07, ++0xA5,0x7D,0x00,0x7C,0x04,0x7F,0x01,0x7E, ++0x66,0x12,0x07,0xA5,0x7D,0xC0,0x7C,0x00, ++0x7F,0x00,0x7E,0x66,0x12,0x07,0xA5,0xE4, ++0xFD,0xFC,0x7F,0x02,0x7E,0x66,0x12,0x07, ++0xA5,0x7D,0x00,0x7C,0x04,0x7F,0x01,0x7E, ++0x66,0x12,0x07,0xA5,0x7D,0xC0,0x7C,0x00, ++0x7F,0x00,0x7E,0x66,0x12,0x07,0xA5,0x7F, ++0x10,0x7E,0x13,0x12,0x07,0x60,0x90,0x06, ++0x2D,0xEE,0xF0,0xA3,0xEF,0xF0,0xEE,0x54, ++0xEF,0x90,0x06,0x2D,0xF0,0xFC,0xA3,0xEF, ++0xF0,0xFD,0x7F,0x10,0x7E,0x13,0x02,0x07, ++0xA5,0x78,0x7F,0xE4,0xF6,0xD8,0xFD,0x75, ++0x81,0x3C,0x02,0x05,0xD0,0x02,0x03,0x2F, ++0xE4,0x93,0xA3,0xF8,0xE4,0x93,0xA3,0x40, ++0x03,0xF6,0x80,0x01,0xF2,0x08,0xDF,0xF4, ++0x80,0x29,0xE4,0x93,0xA3,0xF8,0x54,0x07, ++0x24,0x0C,0xC8,0xC3,0x33,0xC4,0x54,0x0F, ++0x44,0x20,0xC8,0x83,0x40,0x04,0xF4,0x56, ++0x80,0x01,0x46,0xF6,0xDF,0xE4,0x80,0x0B, ++0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80, ++0x90,0x07,0xE1,0xE4,0x7E,0x01,0x93,0x60, ++0xBC,0xA3,0xFF,0x54,0x3F,0x30,0xE5,0x09, ++0x54,0x1F,0xFE,0xE4,0x93,0xA3,0x60,0x01, ++0x0E,0xCF,0x54,0xC0,0x25,0xE0,0x60,0xA8, ++0x40,0xB8,0xE4,0x93,0xA3,0xFA,0xE4,0x93, ++0xA3,0xF8,0xE4,0x93,0xA3,0xC8,0xC5,0x82, ++0xC8,0xCA,0xC5,0x83,0xCA,0xF0,0xA3,0xC8, ++0xC5,0x82,0xC8,0xCA,0xC5,0x83,0xCA,0xDF, ++0xE9,0xDE,0xE7,0x80,0xBE,0x7D,0x40,0x7C, ++0x17,0x7F,0x11,0x7E,0x1D,0x12,0x07,0xA5, ++0x7F,0x41,0x7E,0x1D,0x12,0x07,0x60,0xEF, ++0x44,0x20,0x44,0x80,0xFD,0xAC,0x06,0x7F, ++0x41,0x7E,0x1D,0x12,0x07,0xA5,0x7D,0xBB, ++0x7C,0x15,0x7F,0xEB,0x7E,0x13,0x12,0x07, ++0xA5,0x7D,0x07,0x7C,0x00,0x7F,0xE7,0x7E, ++0x13,0x12,0x07,0xA5,0x7D,0x40,0x7C,0x11, ++0x7F,0x00,0x7E,0x62,0x12,0x07,0xA5,0x02, ++0x02,0x2F,0x7D,0xC0,0x7C,0x16,0x7F,0x11, ++0x7E,0x1D,0x12,0x07,0xA5,0x7D,0xBB,0x7C, ++0x15,0x7F,0xEB,0x7E,0x13,0x12,0x07,0xA5, ++0x7D,0x0D,0x7C,0x00,0x7F,0xE7,0x7E,0x13, ++0x12,0x07,0xA5,0x7F,0x41,0x7E,0x1D,0x12, ++0x07,0x60,0xEF,0x44,0x20,0x44,0x80,0xFD, ++0xAC,0x06,0x7F,0x41,0x7E,0x1D,0x12,0x07, ++0xA5,0x7D,0x00,0x7C,0x21,0x7F,0x00,0x7E, ++0x62,0x12,0x07,0xA5,0x02,0x02,0x2F,0x7D, ++0x40,0x7C,0x17,0x7F,0x11,0x7E,0x1D,0x12, ++0x07,0xA5,0x7D,0xBB,0x7C,0x15,0x7F,0xEB, ++0x7E,0x13,0x12,0x07,0xA5,0x7D,0x0C,0x7C, ++0x00,0x7F,0xE7,0x7E,0x13,0x12,0x07,0xA5, ++0x7F,0x41,0x7E,0x1D,0x12,0x07,0x60,0xEF, ++0x44,0x20,0x44,0x80,0xFD,0xAC,0x06,0x7F, ++0x41,0x7E,0x1D,0x12,0x07,0xA5,0x7D,0x40, ++0x7C,0x11,0x7F,0x00,0x7E,0x62,0x12,0x07, ++0xA5,0x02,0x02,0x2F,0x7D,0x04,0x7C,0x00, ++0x7F,0x01,0x7E,0x66,0x12,0x07,0xA5,0x7D, ++0x80,0x7C,0x00,0x7F,0x00,0x7E,0x66,0x12, ++0x07,0xA5,0x7F,0x02,0x7E,0x66,0x12,0x07, ++0x60,0xEF,0x44,0x02,0x44,0x04,0xFD,0xAC, ++0x06,0x7F,0x02,0x7E,0x66,0x12,0x07,0xA5, ++0x7D,0x04,0x7C,0x00,0x7F,0x01,0x7E,0x66, ++0x12,0x07,0xA5,0x7D,0xC0,0x7C,0x00,0x7F, ++0x00,0x7E,0x66,0x02,0x07,0xA5,0xC0,0xE0, ++0xC0,0xF0,0xC0,0x83,0xC0,0x82,0xC0,0xD0, ++0x75,0xD0,0x00,0xC0,0x00,0x78,0x17,0xE6, ++0xF5,0x8C,0x78,0x18,0xE6,0xF5,0x8A,0x90, ++0x06,0x31,0xE4,0x75,0xF0,0x01,0x12,0x00, ++0x0E,0x90,0x06,0x33,0xE4,0x75,0xF0,0x01, ++0x12,0x00,0x0E,0xD0,0x00,0xD0,0xD0,0xD0, ++0x82,0xD0,0x83,0xD0,0xF0,0xD0,0xE0,0x32, ++0xC2,0xAF,0xAD,0x07,0xAC,0x06,0x8C,0xA2, ++0x8D,0xA3,0x75,0xA0,0x01,0x00,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++0xAE,0xA1,0xBE,0x00,0xF0,0xAE,0xA6,0xAF, ++0xA7,0xD2,0xAF,0x22,0x7D,0x20,0x7C,0x0F, ++0x7F,0x02,0x7E,0x66,0x12,0x07,0xA5,0x7D, ++0x01,0x7C,0x00,0x7F,0x01,0x7E,0x66,0x12, ++0x07,0xA5,0x7D,0xC0,0x7C,0x00,0x7F,0x00, ++0x7E,0x66,0x02,0x07,0xA5,0xC2,0xAF,0xAB, ++0x07,0xAA,0x06,0x8A,0xA2,0x8B,0xA3,0x8C, ++0xA4,0x8D,0xA5,0x75,0xA0,0x03,0x00,0x00, ++0x00,0xAA,0xA1,0xBA,0x00,0xF8,0xD2,0xAF, ++0x22,0x7F,0x0C,0x7E,0x13,0x12,0x07,0x60, ++0xEF,0x44,0x50,0xFD,0xAC,0x06,0x7F,0x0C, ++0x7E,0x13,0x02,0x07,0xA5,0x12,0x07,0xC1, ++0x12,0x07,0xEC,0x12,0x04,0x25,0x02,0x00, ++0x03,0x42,0x06,0x33,0x00,0x00,0x42,0x06, ++0x31,0x00,0x00,0x00,0xE4,0xF5,0x8E,0x22,}; ++ ++ ++#define SGMII_INIT_SIZE 1183 ++rtk_uint8 Sgmii_Init[SGMII_INIT_SIZE] = { ++0x02,0x03,0x81,0xE4,0xF5,0xA8,0xD2,0xAF, ++0x22,0x00,0x00,0x02,0x04,0x0D,0xC5,0xF0, ++0xF8,0xA3,0xE0,0x28,0xF0,0xC5,0xF0,0xF8, ++0xE5,0x82,0x15,0x82,0x70,0x02,0x15,0x83, ++0xE0,0x38,0xF0,0x22,0x75,0xF0,0x08,0x75, ++0x82,0x00,0xEF,0x2F,0xFF,0xEE,0x33,0xFE, ++0xCD,0x33,0xCD,0xCC,0x33,0xCC,0xC5,0x82, ++0x33,0xC5,0x82,0x9B,0xED,0x9A,0xEC,0x99, ++0xE5,0x82,0x98,0x40,0x0C,0xF5,0x82,0xEE, ++0x9B,0xFE,0xED,0x9A,0xFD,0xEC,0x99,0xFC, ++0x0F,0xD5,0xF0,0xD6,0xE4,0xCE,0xFB,0xE4, ++0xCD,0xFA,0xE4,0xCC,0xF9,0xA8,0x82,0x22, ++0xB8,0x00,0xC1,0xB9,0x00,0x59,0xBA,0x00, ++0x2D,0xEC,0x8B,0xF0,0x84,0xCF,0xCE,0xCD, ++0xFC,0xE5,0xF0,0xCB,0xF9,0x78,0x18,0xEF, ++0x2F,0xFF,0xEE,0x33,0xFE,0xED,0x33,0xFD, ++0xEC,0x33,0xFC,0xEB,0x33,0xFB,0x10,0xD7, ++0x03,0x99,0x40,0x04,0xEB,0x99,0xFB,0x0F, ++0xD8,0xE5,0xE4,0xF9,0xFA,0x22,0x78,0x18, ++0xEF,0x2F,0xFF,0xEE,0x33,0xFE,0xED,0x33, ++0xFD,0xEC,0x33,0xFC,0xC9,0x33,0xC9,0x10, ++0xD7,0x05,0x9B,0xE9,0x9A,0x40,0x07,0xEC, ++0x9B,0xFC,0xE9,0x9A,0xF9,0x0F,0xD8,0xE0, ++0xE4,0xC9,0xFA,0xE4,0xCC,0xFB,0x22,0x75, ++0xF0,0x10,0xEF,0x2F,0xFF,0xEE,0x33,0xFE, ++0xED,0x33,0xFD,0xCC,0x33,0xCC,0xC8,0x33, ++0xC8,0x10,0xD7,0x07,0x9B,0xEC,0x9A,0xE8, ++0x99,0x40,0x0A,0xED,0x9B,0xFD,0xEC,0x9A, ++0xFC,0xE8,0x99,0xF8,0x0F,0xD5,0xF0,0xDA, ++0xE4,0xCD,0xFB,0xE4,0xCC,0xFA,0xE4,0xC8, ++0xF9,0x22,0xEB,0x9F,0xF5,0xF0,0xEA,0x9E, ++0x42,0xF0,0xE9,0x9D,0x42,0xF0,0xE8,0x9C, ++0x45,0xF0,0x22,0xE0,0xFC,0xA3,0xE0,0xFD, ++0xA3,0xE0,0xFE,0xA3,0xE0,0xFF,0x22,0xE0, ++0xF8,0xA3,0xE0,0xF9,0xA3,0xE0,0xFA,0xA3, ++0xE0,0xFB,0x22,0xEC,0xF0,0xA3,0xED,0xF0, ++0xA3,0xEE,0xF0,0xA3,0xEF,0xF0,0x22,0xE4, ++0x90,0x06,0x2C,0xF0,0xFD,0x7C,0x01,0x7F, ++0x3F,0x7E,0x1D,0x12,0x04,0x6B,0x7D,0x40, ++0x7C,0x00,0x7F,0x36,0x7E,0x13,0x12,0x04, ++0x6B,0xE4,0xFF,0xFE,0xFD,0x80,0x25,0xE4, ++0x7F,0xFF,0x7E,0xFF,0xFD,0xFC,0x90,0x06, ++0x24,0x12,0x01,0x0F,0xC3,0x12,0x00,0xF2, ++0x50,0x1B,0x90,0x06,0x24,0x12,0x01,0x03, ++0xEF,0x24,0x01,0xFF,0xE4,0x3E,0xFE,0xE4, ++0x3D,0xFD,0xE4,0x3C,0xFC,0x90,0x06,0x24, ++0x12,0x01,0x1B,0x80,0xD2,0xE4,0xF5,0xA8, ++0xD2,0xAF,0x7D,0x1F,0xFC,0x7F,0x49,0x7E, ++0x13,0x12,0x04,0x6B,0x12,0x04,0x92,0x7D, ++0x41,0x7C,0x00,0x7F,0x36,0x7E,0x13,0x12, ++0x04,0x6B,0xE4,0xFF,0xFE,0xFD,0x80,0x25, ++0xE4,0x7F,0x20,0x7E,0x4E,0xFD,0xFC,0x90, ++0x06,0x24,0x12,0x01,0x0F,0xC3,0x12,0x00, ++0xF2,0x50,0x1B,0x90,0x06,0x24,0x12,0x01, ++0x03,0xEF,0x24,0x01,0xFF,0xE4,0x3E,0xFE, ++0xE4,0x3D,0xFD,0xE4,0x3C,0xFC,0x90,0x06, ++0x24,0x12,0x01,0x1B,0x80,0xD2,0xC2,0x00, ++0xC2,0x01,0xD2,0xA9,0xD2,0x8C,0x7F,0x01, ++0x7E,0x62,0x12,0x04,0x47,0xEF,0x30,0xE2, ++0x07,0xE4,0x90,0x06,0x2C,0xF0,0x80,0xEE, ++0x90,0x06,0x2C,0xE0,0x70,0x12,0x12,0x02, ++0xDB,0x90,0x06,0x2C,0x74,0x01,0xF0,0xE4, ++0x90,0x06,0x2F,0xF0,0xA3,0xF0,0x80,0xD6, ++0xC3,0x90,0x06,0x30,0xE0,0x94,0x62,0x90, ++0x06,0x2F,0xE0,0x94,0x00,0x40,0xC7,0xE4, ++0xF0,0xA3,0xF0,0x12,0x02,0xDB,0x90,0x06, ++0x2C,0x74,0x01,0xF0,0x80,0xB8,0x75,0x0F, ++0x80,0x75,0x0E,0x7E,0x75,0x0D,0xAA,0x75, ++0x0C,0x83,0xE4,0xF5,0x10,0x7F,0x36,0x7E, ++0x13,0x12,0x04,0x47,0xEE,0xC4,0xF8,0x54, ++0xF0,0xC8,0xEF,0xC4,0x54,0x0F,0x48,0x54, ++0x07,0xFB,0x7A,0x00,0xEA,0x70,0x4A,0xEB, ++0x14,0x60,0x1C,0x14,0x60,0x27,0x24,0xFE, ++0x60,0x31,0x14,0x60,0x3C,0x24,0x05,0x70, ++0x38,0x75,0x0B,0x00,0x75,0x0A,0xC2,0x75, ++0x09,0xEB,0x75,0x08,0x0B,0x80,0x36,0x75, ++0x0B,0x40,0x75,0x0A,0x59,0x75,0x09,0x73, ++0x75,0x08,0x07,0x80,0x28,0x75,0x0B,0x00, ++0x75,0x0A,0xE1,0x75,0x09,0xF5,0x75,0x08, ++0x05,0x80,0x1A,0x75,0x0B,0xA0,0x75,0x0A, ++0xAC,0x75,0x09,0xB9,0x75,0x08,0x03,0x80, ++0x0C,0x75,0x0B,0x00,0x75,0x0A,0x62,0x75, ++0x09,0x3D,0x75,0x08,0x01,0x75,0x89,0x11, ++0xE4,0x7B,0x60,0x7A,0x09,0xF9,0xF8,0xAF, ++0x0B,0xAE,0x0A,0xAD,0x09,0xAC,0x08,0x12, ++0x00,0x60,0xAA,0x06,0xAB,0x07,0xC3,0xE4, ++0x9B,0xFB,0xE4,0x9A,0xFA,0x78,0x17,0xF6, ++0xAF,0x03,0xEF,0x08,0xF6,0x18,0xE6,0xF5, ++0x8C,0x08,0xE6,0xF5,0x8A,0x74,0x0D,0x2B, ++0xFB,0xE4,0x3A,0x18,0xF6,0xAF,0x03,0xEF, ++0x08,0xF6,0x75,0x88,0x10,0x53,0x8E,0xC7, ++0xD2,0xA9,0x22,0x7D,0x02,0x7C,0x00,0x7F, ++0x4A,0x7E,0x13,0x12,0x04,0x6B,0x7D,0x46, ++0x7C,0x71,0x7F,0x02,0x7E,0x66,0x12,0x04, ++0x6B,0x7D,0x03,0x7C,0x00,0x7F,0x01,0x7E, ++0x66,0x12,0x04,0x6B,0x7D,0xC0,0x7C,0x00, ++0x7F,0x00,0x7E,0x66,0x12,0x04,0x6B,0xE4, ++0xFF,0xFE,0x0F,0xBF,0x00,0x01,0x0E,0xEF, ++0x64,0x64,0x4E,0x70,0xF5,0x7D,0x04,0x7C, ++0x00,0x7F,0x02,0x7E,0x66,0x12,0x04,0x6B, ++0x7D,0x00,0x7C,0x04,0x7F,0x01,0x7E,0x66, ++0x12,0x04,0x6B,0x7D,0xC0,0x7C,0x00,0x7F, ++0x00,0x7E,0x66,0x12,0x04,0x6B,0xE4,0xFD, ++0xFC,0x7F,0x02,0x7E,0x66,0x12,0x04,0x6B, ++0x7D,0x00,0x7C,0x04,0x7F,0x01,0x7E,0x66, ++0x12,0x04,0x6B,0x7D,0xC0,0x7C,0x00,0x7F, ++0x00,0x7E,0x66,0x12,0x04,0x6B,0xE4,0xFD, ++0xFC,0x7F,0x4A,0x7E,0x13,0x12,0x04,0x6B, ++0x7D,0x06,0x7C,0x71,0x7F,0x02,0x7E,0x66, ++0x12,0x04,0x6B,0x7D,0x03,0x7C,0x00,0x7F, ++0x01,0x7E,0x66,0x12,0x04,0x6B,0x7D,0xC0, ++0x7C,0x00,0x7F,0x00,0x7E,0x66,0x02,0x04, ++0x6B,0x78,0x7F,0xE4,0xF6,0xD8,0xFD,0x75, ++0x81,0x3C,0x02,0x03,0xC8,0x02,0x01,0x27, ++0xE4,0x93,0xA3,0xF8,0xE4,0x93,0xA3,0x40, ++0x03,0xF6,0x80,0x01,0xF2,0x08,0xDF,0xF4, ++0x80,0x29,0xE4,0x93,0xA3,0xF8,0x54,0x07, ++0x24,0x0C,0xC8,0xC3,0x33,0xC4,0x54,0x0F, ++0x44,0x20,0xC8,0x83,0x40,0x04,0xF4,0x56, ++0x80,0x01,0x46,0xF6,0xDF,0xE4,0x80,0x0B, ++0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80, ++0x90,0x04,0x87,0xE4,0x7E,0x01,0x93,0x60, ++0xBC,0xA3,0xFF,0x54,0x3F,0x30,0xE5,0x09, ++0x54,0x1F,0xFE,0xE4,0x93,0xA3,0x60,0x01, ++0x0E,0xCF,0x54,0xC0,0x25,0xE0,0x60,0xA8, ++0x40,0xB8,0xE4,0x93,0xA3,0xFA,0xE4,0x93, ++0xA3,0xF8,0xE4,0x93,0xA3,0xC8,0xC5,0x82, ++0xC8,0xCA,0xC5,0x83,0xCA,0xF0,0xA3,0xC8, ++0xC5,0x82,0xC8,0xCA,0xC5,0x83,0xCA,0xDF, ++0xE9,0xDE,0xE7,0x80,0xBE,0xC0,0xE0,0xC0, ++0xF0,0xC0,0x83,0xC0,0x82,0xC0,0xD0,0x75, ++0xD0,0x00,0xC0,0x00,0x78,0x17,0xE6,0xF5, ++0x8C,0x78,0x18,0xE6,0xF5,0x8A,0x90,0x06, ++0x2D,0xE4,0x75,0xF0,0x01,0x12,0x00,0x0E, ++0x90,0x06,0x2F,0xE4,0x75,0xF0,0x01,0x12, ++0x00,0x0E,0xD0,0x00,0xD0,0xD0,0xD0,0x82, ++0xD0,0x83,0xD0,0xF0,0xD0,0xE0,0x32,0xC2, ++0xAF,0xAD,0x07,0xAC,0x06,0x8C,0xA2,0x8D, ++0xA3,0x75,0xA0,0x01,0x00,0x00,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xAE, ++0xA1,0xBE,0x00,0xF0,0xAE,0xA6,0xAF,0xA7, ++0xD2,0xAF,0x22,0xC2,0xAF,0xAB,0x07,0xAA, ++0x06,0x8A,0xA2,0x8B,0xA3,0x8C,0xA4,0x8D, ++0xA5,0x75,0xA0,0x03,0x00,0x00,0x00,0xAA, ++0xA1,0xBA,0x00,0xF8,0xD2,0xAF,0x22,0x42, ++0x06,0x2F,0x00,0x00,0x42,0x06,0x2D,0x00, ++0x00,0x00,0x12,0x04,0x9B,0x12,0x02,0x16, ++0x02,0x00,0x03,0xE4,0xF5,0x8E,0x22,}; ++ ++ ++/* Function Name: ++ * rtl8367c_setAsicPortUnknownDaBehavior ++ * Description: ++ * Set UNDA behavior ++ * Input: ++ * port - port ID ++ * behavior - 0: flooding to unknown DA portmask; 1: drop; 2:trap; 3: flooding ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_NOT_ALLOWED - Invalid behavior ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicPortUnknownDaBehavior(rtk_uint32 port, rtk_uint32 behavior) ++{ ++ if(port >= RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ if(behavior >= L2_UNDA_BEHAVE_END) ++ return RT_ERR_NOT_ALLOWED; ++ ++ if(port < 8) ++ return rtl8367c_setAsicRegBits(RTL8367C_REG_UNKNOWN_UNICAST_DA_PORT_BEHAVE, RTL8367C_Port0_ACTION_MASK << (port * 2), behavior); ++ else ++ return rtl8367c_setAsicRegBits(RTL8367C_REG_UNKNOWN_UNICAST_DA_PORT_BEHAVE_EXT, RTL8367C_PORT8_ACTION_MASK << ((port-8) * 2), behavior); ++} ++/* Function Name: ++ * rtl8367c_getAsicPortUnknownDaBehavior ++ * Description: ++ * Get UNDA behavior ++ * Input: ++ * port - port ID ++ * Output: ++ * pBehavior - 0: flooding to unknown DA portmask; 1: drop; 2:trap; 3: flooding ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicPortUnknownDaBehavior(rtk_uint32 port, rtk_uint32 *pBehavior) ++{ ++ if(port >= RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ if(port < 8) ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_UNKNOWN_UNICAST_DA_PORT_BEHAVE, RTL8367C_Port0_ACTION_MASK << (port * 2), pBehavior); ++ else ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_UNKNOWN_UNICAST_DA_PORT_BEHAVE_EXT, RTL8367C_PORT8_ACTION_MASK << ((port-8) * 2), pBehavior); ++} ++/* Function Name: ++ * rtl8367c_setAsicPortUnknownSaBehavior ++ * Description: ++ * Set UNSA behavior ++ * Input: ++ * behavior - 0: flooding; 1: drop; 2:trap ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_NOT_ALLOWED - Invalid behavior ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicPortUnknownSaBehavior(rtk_uint32 behavior) ++{ ++ if(behavior >= L2_BEHAVE_SA_END) ++ return RT_ERR_NOT_ALLOWED; ++ ++ return rtl8367c_setAsicRegBits(RTL8367C_PORT_SECURIT_CTRL_REG, RTL8367C_UNKNOWN_SA_BEHAVE_MASK, behavior); ++} ++/* Function Name: ++ * rtl8367c_getAsicPortUnknownSaBehavior ++ * Description: ++ * Get UNSA behavior ++ * Input: ++ * pBehavior - 0: flooding; 1: drop; 2:trap ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicPortUnknownSaBehavior(rtk_uint32 *pBehavior) ++{ ++ return rtl8367c_getAsicRegBits(RTL8367C_PORT_SECURIT_CTRL_REG, RTL8367C_UNKNOWN_SA_BEHAVE_MASK, pBehavior); ++} ++/* Function Name: ++ * rtl8367c_setAsicPortUnmatchedSaBehavior ++ * Description: ++ * Set Unmatched SA behavior ++ * Input: ++ * behavior - 0: flooding; 1: drop; 2:trap ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_NOT_ALLOWED - Invalid behavior ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicPortUnmatchedSaBehavior(rtk_uint32 behavior) ++{ ++ if(behavior >= L2_BEHAVE_SA_END) ++ return RT_ERR_NOT_ALLOWED; ++ ++ return rtl8367c_setAsicRegBits(RTL8367C_PORT_SECURIT_CTRL_REG, RTL8367C_UNMATCHED_SA_BEHAVE_MASK, behavior); ++} ++/* Function Name: ++ * rtl8367c_getAsicPortUnmatchedSaBehavior ++ * Description: ++ * Get Unmatched SA behavior ++ * Input: ++ * pBehavior - 0: flooding; 1: drop; 2:trap ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicPortUnmatchedSaBehavior(rtk_uint32 *pBehavior) ++{ ++ return rtl8367c_getAsicRegBits(RTL8367C_PORT_SECURIT_CTRL_REG, RTL8367C_UNMATCHED_SA_BEHAVE_MASK, pBehavior); ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicPortUnmatchedSaMoving ++ * Description: ++ * Set Unmatched SA moving state ++ * Input: ++ * port - Port ID ++ * enabled - 0: can't move to new port; 1: can move to new port ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Error Port ID ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicPortUnmatchedSaMoving(rtk_uint32 port, rtk_uint32 enabled) ++{ ++ if(port >= RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_L2_SA_MOVING_FORBID, port, (enabled == 1) ? 0 : 1); ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicPortUnmatchedSaMoving ++ * Description: ++ * Get Unmatched SA moving state ++ * Input: ++ * port - Port ID ++ * Output: ++ * pEnabled - 0: can't move to new port; 1: can move to new port ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Error Port ID ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicPortUnmatchedSaMoving(rtk_uint32 port, rtk_uint32 *pEnabled) ++{ ++ rtk_uint32 data; ++ ret_t retVal; ++ ++ if(port >= RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_L2_SA_MOVING_FORBID, port, &data)) != RT_ERR_OK) ++ return retVal; ++ ++ *pEnabled = (data == 1) ? 0 : 1; ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicPortUnknownDaFloodingPortmask ++ * Description: ++ * Set UNDA flooding portmask ++ * Input: ++ * portmask - portmask(0~0xFF) ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_MASK - Invalid portmask ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicPortUnknownDaFloodingPortmask(rtk_uint32 portmask) ++{ ++ if(portmask > RTL8367C_PORTMASK) ++ return RT_ERR_PORT_MASK; ++ ++ return rtl8367c_setAsicReg(RTL8367C_UNUCAST_FLOADING_PMSK_REG, portmask); ++} ++/* Function Name: ++ * rtl8367c_getAsicPortUnknownDaFloodingPortmask ++ * Description: ++ * Get UNDA flooding portmask ++ * Input: ++ * pPortmask - portmask(0~0xFF) ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicPortUnknownDaFloodingPortmask(rtk_uint32 *pPortmask) ++{ ++ return rtl8367c_getAsicReg(RTL8367C_UNUCAST_FLOADING_PMSK_REG, pPortmask); ++} ++/* Function Name: ++ * rtl8367c_setAsicPortUnknownMulticastFloodingPortmask ++ * Description: ++ * Set UNMC flooding portmask ++ * Input: ++ * portmask - portmask(0~0xFF) ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_MASK - Invalid portmask ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicPortUnknownMulticastFloodingPortmask(rtk_uint32 portmask) ++{ ++ if(portmask > RTL8367C_PORTMASK) ++ return RT_ERR_PORT_MASK; ++ ++ return rtl8367c_setAsicReg(RTL8367C_UNMCAST_FLOADING_PMSK_REG, portmask); ++} ++/* Function Name: ++ * rtl8367c_getAsicPortUnknownMulticastFloodingPortmask ++ * Description: ++ * Get UNMC flooding portmask ++ * Input: ++ * pPortmask - portmask(0~0xFF) ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicPortUnknownMulticastFloodingPortmask(rtk_uint32 *pPortmask) ++{ ++ return rtl8367c_getAsicReg(RTL8367C_UNMCAST_FLOADING_PMSK_REG, pPortmask); ++} ++/* Function Name: ++ * rtl8367c_setAsicPortBcastFloodingPortmask ++ * Description: ++ * Set Bcast flooding portmask ++ * Input: ++ * portmask - portmask(0~0xFF) ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_MASK - Invalid portmask ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicPortBcastFloodingPortmask(rtk_uint32 portmask) ++{ ++ if(portmask > RTL8367C_PORTMASK) ++ return RT_ERR_PORT_MASK; ++ ++ return rtl8367c_setAsicReg(RTL8367C_BCAST_FLOADING_PMSK_REG, portmask); ++} ++/* Function Name: ++ * rtl8367c_getAsicPortBcastFloodingPortmask ++ * Description: ++ * Get Bcast flooding portmask ++ * Input: ++ * pPortmask - portmask(0~0xFF) ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicPortBcastFloodingPortmask(rtk_uint32 *pPortmask) ++{ ++ return rtl8367c_getAsicReg(RTL8367C_BCAST_FLOADING_PMSK_REG, pPortmask); ++} ++/* Function Name: ++ * rtl8367c_setAsicPortBlockSpa ++ * Description: ++ * Set disabling blocking frame if source port and destination port are the same ++ * Input: ++ * port - Physical port number (0~7) ++ * permit - 0: block; 1: permit ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicPortBlockSpa(rtk_uint32 port, rtk_uint32 permit) ++{ ++ if(port >= RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ return rtl8367c_setAsicRegBit(RTL8367C_SOURCE_PORT_BLOCK_REG, port, permit); ++} ++/* Function Name: ++ * rtl8367c_getAsicPortBlockSpa ++ * Description: ++ * Get disabling blocking frame if source port and destination port are the same ++ * Input: ++ * port - Physical port number (0~7) ++ * pPermit - 0: block; 1: permit ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicPortBlockSpa(rtk_uint32 port, rtk_uint32* pPermit) ++{ ++ if(port >= RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ return rtl8367c_getAsicRegBit(RTL8367C_SOURCE_PORT_BLOCK_REG, port, pPermit); ++} ++/* Function Name: ++ * rtl8367c_setAsicPortDos ++ * Description: ++ * Set DOS function ++ * Input: ++ * type - DOS type ++ * drop - 0: permit; 1: drop ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - Invalid payload index ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicPortDos(rtk_uint32 type, rtk_uint32 drop) ++{ ++ if(type >= DOS_END) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_DOS_CFG, RTL8367C_DROP_DAEQSA_OFFSET + type, drop); ++} ++/* Function Name: ++ * rtl8367c_getAsicPortDos ++ * Description: ++ * Get DOS function ++ * Input: ++ * type - DOS type ++ * pDrop - 0: permit; 1: drop ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - Invalid payload index ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicPortDos(rtk_uint32 type, rtk_uint32* pDrop) ++{ ++ if(type >= DOS_END) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_DOS_CFG, RTL8367C_DROP_DAEQSA_OFFSET + type,pDrop); ++} ++/* Function Name: ++ * rtl8367c_setAsicPortForceLink ++ * Description: ++ * Set port force linking configuration ++ * Input: ++ * port - Physical port number (0~7) ++ * pPortAbility - port ability configuration ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicPortForceLink(rtk_uint32 port, rtl8367c_port_ability_t *pPortAbility) ++{ ++ rtk_uint32 regData = 0; ++ ++ /* Invalid input parameter */ ++ if(port >= RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ regData |= pPortAbility->forcemode << 12; ++ regData |= pPortAbility->mstfault << 9; ++ regData |= pPortAbility->mstmode << 8; ++ regData |= pPortAbility->nway << 7; ++ regData |= pPortAbility->txpause << 6; ++ regData |= pPortAbility->rxpause << 5; ++ regData |= pPortAbility->link << 4; ++ regData |= pPortAbility->duplex << 2; ++ regData |= pPortAbility->speed; ++ ++ return rtl8367c_setAsicReg(RTL8367C_REG_MAC0_FORCE_SELECT+port, regData); ++} ++/* Function Name: ++ * rtl8367c_getAsicPortForceLink ++ * Description: ++ * Get port force linking configuration ++ * Input: ++ * port - Physical port number (0~7) ++ * pPortAbility - port ability configuration ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicPortForceLink(rtk_uint32 port, rtl8367c_port_ability_t *pPortAbility) ++{ ++ ret_t retVal; ++ rtk_uint32 regData; ++ ++ /* Invalid input parameter */ ++ if(port >= RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ retVal = rtl8367c_getAsicReg(RTL8367C_REG_MAC0_FORCE_SELECT + port, ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ pPortAbility->forcemode = (regData >> 12) & 0x0001; ++ pPortAbility->mstfault = (regData >> 9) & 0x0001; ++ pPortAbility->mstmode = (regData >> 8) & 0x0001; ++ pPortAbility->nway = (regData >> 7) & 0x0001; ++ pPortAbility->txpause = (regData >> 6) & 0x0001; ++ pPortAbility->rxpause = (regData >> 5) & 0x0001; ++ pPortAbility->link = (regData >> 4) & 0x0001; ++ pPortAbility->duplex = (regData >> 2) & 0x0001; ++ pPortAbility->speed = regData & 0x0003; ++ ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_getAsicPortStatus ++ * Description: ++ * Get port link status ++ * Input: ++ * port - Physical port number (0~7) ++ * pPortAbility - port ability configuration ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicPortStatus(rtk_uint32 port, rtl8367c_port_status_t *pPortStatus) ++{ ++ ret_t retVal; ++ rtk_uint32 regData; ++ ++ /* Invalid input parameter */ ++ if(port >= RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ retVal = rtl8367c_getAsicReg(RTL8367C_REG_PORT0_STATUS+port,®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ pPortStatus->lpi1000 = (regData >> 11) & 0x0001; ++ pPortStatus->lpi100 = (regData >> 10) & 0x0001; ++ pPortStatus->mstfault = (regData >> 9) & 0x0001; ++ pPortStatus->mstmode = (regData >> 8) & 0x0001; ++ pPortStatus->nway = (regData >> 7) & 0x0001; ++ pPortStatus->txpause = (regData >> 6) & 0x0001; ++ pPortStatus->rxpause = (regData >> 5) & 0x0001; ++ pPortStatus->link = (regData >> 4) & 0x0001; ++ pPortStatus->duplex = (regData >> 2) & 0x0001; ++ pPortStatus->speed = regData & 0x0003; ++ ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_setAsicPortForceLinkExt ++ * Description: ++ * Set external interface force linking configuration ++ * Input: ++ * id - external interface id (0~2) ++ * portAbility - port ability configuration ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - input parameter out of range ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicPortForceLinkExt(rtk_uint32 id, rtl8367c_port_ability_t *pPortAbility) ++{ ++ rtk_uint32 retVal, regValue, regValue2, type, sgmiibit, hisgmiibit; ++ rtk_uint32 reg_data = 0; ++ rtk_uint32 i = 0; ++ ++ /* Invalid input parameter */ ++ if(id >= RTL8367C_EXTNO) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ reg_data |= pPortAbility->forcemode << 12; ++ reg_data |= pPortAbility->mstfault << 9; ++ reg_data |= pPortAbility->mstmode << 8; ++ reg_data |= pPortAbility->nway << 7; ++ reg_data |= pPortAbility->txpause << 6; ++ reg_data |= pPortAbility->rxpause << 5; ++ reg_data |= pPortAbility->link << 4; ++ reg_data |= pPortAbility->duplex << 2; ++ reg_data |= pPortAbility->speed; ++ ++ if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0249)) != RT_ERR_OK) ++ return retVal; ++ /*get chip ID */ ++ if((retVal = rtl8367c_getAsicReg(0x1300, ®Value)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0000)) != RT_ERR_OK) ++ return retVal; ++ ++ type = 0; ++ ++ switch (regValue) ++ { ++ case 0x0276: ++ case 0x0597: ++ case 0x6367: ++ type = 1; ++ break; ++ case 0x0652: ++ case 0x6368: ++ type = 2; ++ break; ++ case 0x0801: ++ case 0x6511: ++ type = 3; ++ break; ++ default: ++ return RT_ERR_FAILED; ++ } ++ ++ if (1 == type) ++ { ++ if(1 == id) ++ { ++ if ((retVal = rtl8367c_getAsicReg(RTL8367C_REG_REG_TO_ECO4, ®Value)) != RT_ERR_OK) ++ return retVal; ++ ++ if((regValue & (0x0001 << 5)) && (regValue & (0x0001 << 7))) ++ { ++ return RT_ERR_OK; ++ } ++ ++ if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_FDUP_OFFSET, pPortAbility->duplex)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_SPD_MASK, pPortAbility->speed)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_LINK_OFFSET, pPortAbility->link)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_TXFC_OFFSET, pPortAbility->txpause)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_RXFC_OFFSET, pPortAbility->rxpause)) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ if(0 == id || 1 == id) ++ return rtl8367c_setAsicReg(RTL8367C_REG_DIGITAL_INTERFACE0_FORCE + id, reg_data); ++ else ++ return rtl8367c_setAsicReg(RTL8367C_REG_DIGITAL_INTERFACE2_FORCE, reg_data); ++ } ++ else if (2 == type) ++ { ++ if (1 == id) ++ { ++ if((retVal = rtl8367c_setAsicRegBit(0x1311, 2, pPortAbility->duplex)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBits(0x1311, 0x3, pPortAbility->speed)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBit(0x1311, 4, pPortAbility->link)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBit(0x1311, 6, pPortAbility->txpause)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBit(0x1311, 5, pPortAbility->rxpause)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBit(0x1311, 12, pPortAbility->forcemode)) != RT_ERR_OK) ++ return retVal; ++ ++ if (pPortAbility->link == 1) ++ { ++ if((retVal = rtl8367c_setAsicRegBit(0x1311, 4, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBit(0x1311, 4, 1)) != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ { ++ if((retVal = rtl8367c_setAsicRegBits(0x1311, 0x3, 2)) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ ++ if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_FDUP_OFFSET, pPortAbility->duplex)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_SPD_MASK, pPortAbility->speed)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_LINK_OFFSET, pPortAbility->link)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_TXFC_OFFSET, pPortAbility->txpause)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_RXFC_OFFSET, pPortAbility->rxpause)) != RT_ERR_OK) ++ return retVal; ++ } ++ else if (2 == id) ++ { ++ if((retVal = rtl8367c_setAsicRegBit(0x13c4, 2, pPortAbility->duplex)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBits(0x13c4, 0x3, pPortAbility->speed)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBit(0x13c4, 4, pPortAbility->link)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBit(0x13c4, 6, pPortAbility->txpause)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBit(0x13c4, 5, pPortAbility->rxpause)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBit(0x13c4, 12, pPortAbility->forcemode)) != RT_ERR_OK) ++ return retVal; ++ ++ if (pPortAbility->link == 1) ++ { ++ if((retVal = rtl8367c_setAsicRegBit(0x13c4, 4, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBit(0x13c4, 4, 1)) != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ { ++ if((retVal = rtl8367c_setAsicRegBits(0x13c4, 0x3, 2)) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ if((retVal = rtl8367c_setAsicRegBit(0x1dc1, RTL8367C_CFG_SGMII_FDUP_OFFSET, pPortAbility->duplex)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBits(0x1dc1, RTL8367C_CFG_SGMII_SPD_MASK, pPortAbility->speed)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBit(0x1dc1, RTL8367C_CFG_SGMII_LINK_OFFSET, pPortAbility->link)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBit(0x1dc1, RTL8367C_CFG_SGMII_TXFC_OFFSET, pPortAbility->txpause)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBit(0x1dc1, RTL8367C_CFG_SGMII_RXFC_OFFSET, pPortAbility->rxpause)) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ } ++ else if(3 == type) ++ { ++ if(1 == id) ++ { ++ if((retVal = rtl8367c_getAsicRegBit(0x1d11, 6, &sgmiibit)) != RT_ERR_OK) ++ return retVal; ++ if((retVal = rtl8367c_getAsicRegBit(0x1d11, 11, &hisgmiibit)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((sgmiibit == 1) || (hisgmiibit == 1)) ++ { ++ /*for 1000x/100fx/1000x_100fx, param has to be set to serdes registers*/ ++ if((retVal = rtl8367c_getAsicReg(0x1d41, ®Value)) != RT_ERR_OK) ++ return retVal; ++ ++ /*bit5: cfg_mac6_fib =1, bit7: cfg_mac6_fib2=1*/ ++ if((regValue & 0xa0) == 0xa0) ++ { ++ /* new_cfg_sds_mode */ ++ if((retVal = rtl8367c_getAsicRegBits(0x1d95, 0x1f00, ®Value2)) != RT_ERR_OK) ++ return retVal; ++ ++ /*1000X*/ ++ if(regValue2 == 0x4) ++ { ++#if 0 ++ /* new_cfg_sds_mode:reset mode */ ++ if((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x1f)) != RT_ERR_OK) ++ return retVal; ++#endif ++ /* Enable new sds mode config */ ++ if((retVal = rtl8367c_setAsicRegBit(0x1d95, 13, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ /* 0 4 0 bit 12 set 1, bit15~13 = 4*/ ++ if((retVal = rtl8367c_getAsicSdsReg(0, 4, 0, ®_data)) != RT_ERR_OK) ++ return retVal; ++ reg_data &= 0xFFFF0FFF; ++ reg_data |= 0x9000; ++ if((retVal = rtl8367c_setAsicSdsReg(0,4,0, reg_data)) != RT_ERR_OK) ++ return retVal; ++ ++ /* 0 0 2 bit 6 set 1, bit13 set to 0, bit12 nway_en*/ ++ if((retVal = rtl8367c_getAsicSdsReg(0, 0, 2, ®_data)) != RT_ERR_OK) ++ return retVal; ++ reg_data &= 0xFFFFDFFF; ++ reg_data |= 0x40; ++ if(pPortAbility->forcemode) ++ reg_data &= 0xffffefff; ++ else ++ reg_data |= 0x1000; ++ ++ if((retVal = rtl8367c_setAsicSdsReg(0,0,2, reg_data)) != RT_ERR_OK) ++ return retVal; ++ ++ /* 0 4 2 bit 8 rx pause, bit7 tx pause*/ ++ if((retVal = rtl8367c_getAsicSdsReg(0, 4, 2, ®_data)) != RT_ERR_OK) ++ return retVal; ++ ++ if (pPortAbility->txpause) ++ reg_data |= 0x80; ++ else ++ reg_data &= (~0x80); ++ ++ if (pPortAbility->rxpause) ++ reg_data |= 0x100; ++ else ++ reg_data &= (~0x100); ++ ++ if((retVal = rtl8367c_setAsicSdsReg(0,4,2, reg_data)) != RT_ERR_OK) ++ return retVal; ++ ++ /* 0 4 0 bit 12 set 0*/ ++ if((retVal = rtl8367c_getAsicSdsReg(0, 4, 0, ®_data)) != RT_ERR_OK) ++ return retVal; ++ reg_data &= 0xFFFFEFFF; ++ if((retVal = rtl8367c_setAsicSdsReg(0,4,0, reg_data)) != RT_ERR_OK) ++ return retVal; ++ ++ /*new_cfg_sds_mode=1000x*/ ++ if((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x4)) != RT_ERR_OK) ++ return retVal; ++ ++ } ++ else if(regValue2 == 0x5) ++ { ++#if 0 ++ /*100FX*/ ++ if((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x1f)) != RT_ERR_OK) ++ return retVal; ++#endif ++ /*cfg_sds_mode_sel_new=1 */ ++ if((retVal = rtl8367c_setAsicRegBit(0x1d95, 13, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ /* 0 4 0 bit 12 set 1, bit15~13 = 5*/ ++ if((retVal = rtl8367c_getAsicSdsReg(0, 4, 0, ®_data)) != RT_ERR_OK) ++ return retVal; ++ reg_data &= 0xFFFF0FFF; ++ reg_data |= 0xB000; ++ if((retVal = rtl8367c_setAsicSdsReg(0,4,0, reg_data)) != RT_ERR_OK) ++ return retVal; ++ ++ /* 0 0 2 bit 6 set 0, bit13 set to 1, bit12 0*/ ++ if((retVal = rtl8367c_getAsicSdsReg(0, 0, 2, ®_data)) != RT_ERR_OK) ++ return retVal; ++ reg_data &= 0xFFFFFFBF; ++ reg_data |= 0x2000; ++ reg_data &= 0xffffefff; ++ ++ if((retVal = rtl8367c_setAsicSdsReg(0,0,2, reg_data)) != RT_ERR_OK) ++ return retVal; ++ ++ /* 0 4 2 bit 8 rx pause, bit7 tx pause*/ ++ if((retVal = rtl8367c_getAsicSdsReg(0, 4, 2, ®_data)) != RT_ERR_OK) ++ return retVal; ++ if (pPortAbility->txpause) ++ reg_data |= 0x80; ++ else ++ reg_data &= (~0x80); ++ if (pPortAbility->rxpause) ++ reg_data |= 0x100; ++ else ++ reg_data &= (~0x100); ++ if((retVal = rtl8367c_setAsicSdsReg(0,4,2, reg_data)) != RT_ERR_OK) ++ return retVal; ++ ++ /* 0 4 0 bit 12 set 0*/ ++ if((retVal = rtl8367c_getAsicSdsReg(0, 4, 0, ®_data)) != RT_ERR_OK) ++ return retVal; ++ reg_data &= 0xFFFFEFFF; ++ if((retVal = rtl8367c_setAsicSdsReg(0,4,0, reg_data)) != RT_ERR_OK) ++ return retVal; ++ /* new_cfg_sds_mode=1000x */ ++ if((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x5)) != RT_ERR_OK) ++ return retVal; ++ ++ } ++ else if(regValue2 == 0x7) ++ { ++#if 0 ++ /*100FX*/ ++ if((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x1f)) != RT_ERR_OK) ++ return retVal; ++#endif ++ if((retVal = rtl8367c_setAsicRegBit(0x1d95, 13, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ /* 0 4 0 bit 12 set 1, bit15~13 = 4*/ ++ if((retVal = rtl8367c_getAsicSdsReg(0, 4, 0, ®_data)) != RT_ERR_OK) ++ return retVal; ++ reg_data &= 0xFFFF0FFF; ++ reg_data |= 0x9000; ++ if((retVal = rtl8367c_setAsicSdsReg(0,4,0, reg_data)) != RT_ERR_OK) ++ return retVal; ++ ++ /* 0 0 2 bit 6 set 1, bit13 set to 0, bit12 nway_en*/ ++ if((retVal = rtl8367c_getAsicSdsReg(0, 0, 2, ®_data)) != RT_ERR_OK) ++ return retVal; ++ reg_data &= 0xFFFFDFFF; ++ reg_data |= 0x40; ++ if(pPortAbility->forcemode) ++ reg_data &= 0xffffefff; ++ else ++ reg_data |= 0x1000; ++ ++ if((retVal = rtl8367c_setAsicSdsReg(0,0,2, reg_data)) != RT_ERR_OK) ++ return retVal; ++ ++ /* 0 4 2 bit 8 rx pause, bit7 tx pause*/ ++ if((retVal = rtl8367c_getAsicSdsReg(0, 4, 2, ®_data)) != RT_ERR_OK) ++ return retVal; ++ if (pPortAbility->txpause) ++ reg_data |= 0x80; ++ else ++ reg_data &= (~0x80); ++ if (pPortAbility->rxpause) ++ reg_data |= 0x100; ++ else ++ reg_data &=(~0x100); ++ if((retVal = rtl8367c_setAsicSdsReg(0,4,2, reg_data)) != RT_ERR_OK) ++ return retVal; ++ ++ /* 0 4 0 bit 12 set 0*/ ++ if((retVal = rtl8367c_getAsicSdsReg(0, 4, 0, ®_data)) != RT_ERR_OK) ++ return retVal; ++ reg_data &= 0xFFFFEFFF; ++ if((retVal = rtl8367c_setAsicSdsReg(0,4,0, reg_data)) != RT_ERR_OK) ++ return retVal; ++ ++ /* 0 4 0 bit 12 set 1, bit15~13 = 5*/ ++ if((retVal = rtl8367c_getAsicSdsReg(0, 4, 0, ®_data)) != RT_ERR_OK) ++ return retVal; ++ reg_data &= 0xFFFF0FFF; ++ reg_data |= 0xB000; ++ if((retVal = rtl8367c_setAsicSdsReg(0,4,0, reg_data)) != RT_ERR_OK) ++ return retVal; ++ ++ /* 0 0 2 bit 6 set 0, bit13 set to 1, bit12 0*/ ++ if((retVal = rtl8367c_getAsicSdsReg(0, 0, 2, ®_data)) != RT_ERR_OK) ++ return retVal; ++ reg_data &= 0xFFFFFFBF; ++ reg_data |= 0x2000; ++ reg_data &= 0xffffefff; ++ ++ if((retVal = rtl8367c_setAsicSdsReg(0,0,2, reg_data)) != RT_ERR_OK) ++ return retVal; ++ ++ /* 0 4 2 bit 8 rx pause, bit7 tx pause*/ ++ if((retVal = rtl8367c_getAsicSdsReg(0, 4, 2, ®_data)) != RT_ERR_OK) ++ return retVal; ++ if (pPortAbility->txpause) ++ reg_data |= 0x80; ++ else ++ reg_data &= 0xffffff7f; ++ if (pPortAbility->rxpause) ++ reg_data |= 0x100; ++ else ++ reg_data &= 0xfffffeff; ++ if((retVal = rtl8367c_setAsicSdsReg(0,4,2, reg_data)) != RT_ERR_OK) ++ return retVal; ++ ++ /* 0 4 0 bit 12 set 0*/ ++ if((retVal = rtl8367c_getAsicSdsReg(0, 4, 0, ®_data)) != RT_ERR_OK) ++ return retVal; ++ reg_data &= 0xFFFFEFFF; ++ if((retVal = rtl8367c_setAsicSdsReg(0,4,0, reg_data)) != RT_ERR_OK) ++ return retVal; ++ /*sds_mode:*/ ++ if((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x7)) != RT_ERR_OK) ++ return retVal; ++ ++ } ++ ++ /*disable force ability --- */ ++ if((retVal = rtl8367c_setAsicRegBit(0x137c, 12, 0)) != RT_ERR_OK) ++ return retVal; ++ return RT_ERR_OK; ++ ++ } ++ ++ /* new_cfg_sds_mode */ ++ if((retVal = rtl8367c_getAsicRegBits(0x1d95, 0x1f00, ®Value2)) != RT_ERR_OK) ++ return retVal; ++ if(regValue2 == 0x2) ++ { ++#if 0 ++ /*SGMII*/ ++ if((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x1f)) != RT_ERR_OK) ++ return retVal; ++#endif ++ if((retVal = rtl8367c_setAsicRegBit(0x1d95, 13, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ for(i=0;i<0xfff; i++); ++ ++ /* 0 2 0 bit 8-9 nway*/ ++ if((retVal = rtl8367c_getAsicSdsReg(0, 2, 0, ®_data)) != RT_ERR_OK) ++ return retVal; ++ reg_data &= 0xfffffcff; ++ if (pPortAbility->nway) ++ reg_data &= 0xfffffcff; ++ else ++ reg_data |= 0x100; ++ if((retVal = rtl8367c_setAsicSdsReg(0,2,0, reg_data)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x2)) != RT_ERR_OK) ++ return retVal; ++ ++ for(i=0;i<0xfff; i++); ++ ++ if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_FDUP_OFFSET, pPortAbility->duplex)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_SPD_MASK, pPortAbility->speed)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_TXFC_OFFSET, pPortAbility->txpause)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_RXFC_OFFSET, pPortAbility->rxpause)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_LINK_OFFSET, pPortAbility->link)) != RT_ERR_OK) ++ return retVal; ++ ++ /*disable force ability --- */ ++ if((retVal = rtl8367c_setAsicRegBit(0x137c, 12, 0)) != RT_ERR_OK) ++ return retVal; ++ return RT_ERR_OK; ++ } ++ else if(regValue2 == 0x12) ++ { ++#if 0 ++ /*HiSGMII*/ ++ if((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x1f)) != RT_ERR_OK) ++ return retVal; ++#endif ++ if((retVal = rtl8367c_setAsicRegBit(0x1d95, 13, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ for(i=0;i<0xfff; i++); ++ ++ /* 0 2 0 bit 8-9 nway*/ ++ if((retVal = rtl8367c_getAsicSdsReg(0, 2, 0, ®_data)) != RT_ERR_OK) ++ return retVal; ++ reg_data &= 0xfffffcff; ++ if (pPortAbility->nway) ++ reg_data &= 0xfffffcff; ++ else ++ reg_data |= 0x100; ++ if((retVal = rtl8367c_setAsicSdsReg(0,2,0, reg_data)) != RT_ERR_OK) ++ return retVal; ++ ++ ++ if((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x12)) != RT_ERR_OK) ++ return retVal; ++ ++ for(i=0;i<0xfff; i++); ++ ++ if((retVal = rtl8367c_setAsicRegBit(0x1d11, 11, 0x1)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_FDUP_OFFSET, pPortAbility->duplex)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_SPD_MASK, pPortAbility->speed)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_TXFC_OFFSET, pPortAbility->txpause)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_RXFC_OFFSET, pPortAbility->rxpause)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_LINK_OFFSET, pPortAbility->link)) != RT_ERR_OK) ++ return retVal; ++ ++ /*disable force ability --- */ ++ if((retVal = rtl8367c_setAsicRegBit(0x137c, 12, 0)) != RT_ERR_OK) ++ return retVal; ++ return RT_ERR_OK; ++ ++ } ++ } ++ else ++ { ++ if((retVal = rtl8367c_getAsicRegBits(0x1d3d, 10, ®Value2)) != RT_ERR_OK) ++ return retVal; ++ if (regValue2 == 0) ++ { ++ /*ext1_force_ablty*/ ++ if((retVal = rtl8367c_setAsicRegBit(0x1311, 2, pPortAbility->duplex)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBits(0x1311, 0x3, pPortAbility->speed)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBit(0x1311, 4, pPortAbility->link)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBit(0x1311, 6, pPortAbility->txpause)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBit(0x1311, 5, pPortAbility->rxpause)) != RT_ERR_OK) ++ return retVal; ++ ++ /*force mode for ext1*/ ++ if((retVal = rtl8367c_setAsicRegBit(0x1311, 12, pPortAbility->forcemode)) != RT_ERR_OK) ++ return retVal; ++ ++ if (pPortAbility->link == 1) ++ { ++ if((retVal = rtl8367c_setAsicRegBit(0x1311, 4, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBit(0x1311, 4, 1)) != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ { ++ if((retVal = rtl8367c_setAsicRegBits(0x1311, 0x3, 2)) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ /*disable force ability --- */ ++ if((retVal = rtl8367c_setAsicRegBit(0x137c, 12, 0)) != RT_ERR_OK) ++ return retVal; ++ return RT_ERR_OK; ++ } ++ } ++ ++ ++ } ++ else if (2 == id) ++ { ++ ++ if((retVal = rtl8367c_getAsicRegBit(0x1d95, 0, &sgmiibit)) != RT_ERR_OK) ++ return retVal; ++ if (sgmiibit == 1) ++ { ++ /*for 1000x/100fx/1000x_100fx, param has to bet set to serdes registers*/ ++ if((retVal = rtl8367c_getAsicReg(0x1d95, ®Value)) != RT_ERR_OK) ++ return retVal; ++ /*cfg_mac7_sel_sgmii=1 & cfg_mac7_fib =1*/ ++ if((regValue & 0x3) == 0x3) ++ { ++ if((retVal = rtl8367c_getAsicRegBits(0x1d95, 0x1f00, ®Value2)) != RT_ERR_OK) ++ return retVal; ++ ++ if(regValue2 == 0x4) ++ { ++ /*1000X*/ ++#if 0 ++ if((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x1f)) != RT_ERR_OK) ++ return retVal; ++#endif ++ if((retVal = rtl8367c_setAsicRegBit(0x1d95, 13, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ /* 0 4 0 bit 12 set 1, bit15~13 = 4*/ ++ if((retVal = rtl8367c_getAsicSdsReg(0, 4, 0, ®_data)) != RT_ERR_OK) ++ return retVal; ++ reg_data &= 0xFFFF0FFF; ++ reg_data |= 0x9000; ++ if((retVal = rtl8367c_setAsicSdsReg(0,4,0, reg_data)) != RT_ERR_OK) ++ return retVal; ++ ++ /* 0 0 2 bit 6 set 1, bit13 set to 0, bit12 nway_en*/ ++ if((retVal = rtl8367c_getAsicSdsReg(0, 0, 2, ®_data)) != RT_ERR_OK) ++ return retVal; ++ reg_data &= 0xFFFFDFFF; ++ reg_data |= 0x40; ++ if(pPortAbility->forcemode) ++ reg_data &= 0xffffefff; ++ else ++ reg_data |= 0x1000; ++ ++ if((retVal = rtl8367c_setAsicSdsReg(0,0,2, reg_data)) != RT_ERR_OK) ++ return retVal; ++ ++ /* 0 4 2 bit 8 rx pause, bit7 tx pause*/ ++ if((retVal = rtl8367c_getAsicSdsReg(0, 4, 2, ®_data)) != RT_ERR_OK) ++ return retVal; ++ if (pPortAbility->txpause) ++ reg_data |= 0x80; ++ else ++ reg_data &= 0xffffff7f; ++ if (pPortAbility->rxpause) ++ reg_data |= 0x100; ++ else ++ reg_data &= 0xfffffeff; ++ if((retVal = rtl8367c_setAsicSdsReg(0,4,2, reg_data)) != RT_ERR_OK) ++ return retVal; ++ ++ /* 0 4 0 bit 12 set 0*/ ++ if((retVal = rtl8367c_getAsicSdsReg(0, 4, 0, ®_data)) != RT_ERR_OK) ++ return retVal; ++ reg_data &= 0xFFFFEFFF; ++ if((retVal = rtl8367c_setAsicSdsReg(0,4,0, reg_data)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x4)) != RT_ERR_OK) ++ return retVal; ++ ++ } ++ else if(regValue2 == 0x5) ++ { ++ /*100FX*/ ++#if 0 ++ if((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x1f)) != RT_ERR_OK) ++ return retVal; ++#endif ++ if((retVal = rtl8367c_setAsicRegBit(0x1d95, 13, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ /* 0 4 0 bit 12 set 1, bit15~13 = 5*/ ++ if((retVal = rtl8367c_getAsicSdsReg(0, 4, 0, ®_data)) != RT_ERR_OK) ++ return retVal; ++ reg_data &= 0xFFFF0FFF; ++ reg_data |= 0xB000; ++ if((retVal = rtl8367c_setAsicSdsReg(0,4,0, reg_data)) != RT_ERR_OK) ++ return retVal; ++ ++ /* 0 0 2 bit 6 set 0, bit13 set to 1, bit12 0*/ ++ if((retVal = rtl8367c_getAsicSdsReg(0, 0, 2, ®_data)) != RT_ERR_OK) ++ return retVal; ++ reg_data &= 0xFFFFFFBF; ++ reg_data |= 0x2000; ++ reg_data &= 0xffffefff; ++ ++ if((retVal = rtl8367c_setAsicSdsReg(0,0,2, reg_data)) != RT_ERR_OK) ++ return retVal; ++ ++ /* 0 4 2 bit 8 rx pause, bit7 tx pause*/ ++ if((retVal = rtl8367c_getAsicSdsReg(0, 4, 2, ®_data)) != RT_ERR_OK) ++ return retVal; ++ if (pPortAbility->txpause) ++ reg_data |= 0x80; ++ else ++ reg_data &= 0xffffff7f; ++ if (pPortAbility->rxpause) ++ reg_data |= 0x100; ++ else ++ reg_data &= 0xfffffeff; ++ if((retVal = rtl8367c_setAsicSdsReg(0,4,2, reg_data)) != RT_ERR_OK) ++ return retVal; ++ ++ /* 0 4 0 bit 12 set 0*/ ++ if((retVal = rtl8367c_getAsicSdsReg(0, 4, 0, ®_data)) != RT_ERR_OK) ++ return retVal; ++ reg_data &= 0xFFFFEFFF; ++ if((retVal = rtl8367c_setAsicSdsReg(0,4,0, reg_data)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x5)) != RT_ERR_OK) ++ return retVal; ++ ++ } ++ else if(regValue2 == 0x7) ++ { ++ /*100FX*/ ++#if 0 ++ if((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x1f)) != RT_ERR_OK) ++ return retVal; ++#endif ++ if((retVal = rtl8367c_setAsicRegBit(0x1d95, 13, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ /* 0 4 0 bit 12 set 1, bit15~13 = 4*/ ++ if((retVal = rtl8367c_getAsicSdsReg(0, 4, 0, ®_data)) != RT_ERR_OK) ++ return retVal; ++ reg_data &= 0xFFFF0FFF; ++ reg_data |= 0x9000; ++ if((retVal = rtl8367c_setAsicSdsReg(0,4,0, reg_data)) != RT_ERR_OK) ++ return retVal; ++ ++ /* 0 0 2 bit 6 set 1, bit13 set to 0, bit12 nway_en*/ ++ if((retVal = rtl8367c_getAsicSdsReg(0, 0, 2, ®_data)) != RT_ERR_OK) ++ return retVal; ++ reg_data &= 0xFFFFDFFF; ++ reg_data |= 0x40; ++ if(pPortAbility->forcemode) ++ reg_data &= 0xffffefff; ++ else ++ reg_data |= 0x1000; ++ ++ if((retVal = rtl8367c_setAsicSdsReg(0,0,2, reg_data)) != RT_ERR_OK) ++ return retVal; ++ ++ /* 0 4 2 bit 8 rx pause, bit7 tx pause*/ ++ if((retVal = rtl8367c_getAsicSdsReg(0, 4, 2, ®_data)) != RT_ERR_OK) ++ return retVal; ++ if (pPortAbility->txpause) ++ reg_data |= 0x80; ++ else ++ reg_data &= 0xffffff7f; ++ if (pPortAbility->rxpause) ++ reg_data |= 0x100; ++ else ++ reg_data &= 0xfffffeff; ++ if((retVal = rtl8367c_setAsicSdsReg(0,4,2, reg_data)) != RT_ERR_OK) ++ return retVal; ++ ++ /* 0 4 0 bit 12 set 0*/ ++ if((retVal = rtl8367c_getAsicSdsReg(0, 4, 0, ®_data)) != RT_ERR_OK) ++ return retVal; ++ reg_data &= 0xFFFFEFFF; ++ if((retVal = rtl8367c_setAsicSdsReg(0,4,0, reg_data)) != RT_ERR_OK) ++ return retVal; ++ ++ /* 0 4 0 bit 12 set 1, bit15~13 = 5*/ ++ if((retVal = rtl8367c_getAsicSdsReg(0, 4, 0, ®_data)) != RT_ERR_OK) ++ return retVal; ++ reg_data &= 0xFFFF0FFF; ++ reg_data |= 0xB000; ++ if((retVal = rtl8367c_setAsicSdsReg(0,4,0, reg_data)) != RT_ERR_OK) ++ return retVal; ++ ++ /* 0 0 2 bit 6 set 0, bit13 set to 1, bit12 0*/ ++ if((retVal = rtl8367c_getAsicSdsReg(0, 0, 2, ®_data)) != RT_ERR_OK) ++ return retVal; ++ reg_data &= 0xFFFFFFBF; ++ reg_data |= 0x2000; ++ reg_data &= 0xffffefff; ++ ++ if((retVal = rtl8367c_setAsicSdsReg(0,0,2, reg_data)) != RT_ERR_OK) ++ return retVal; ++ ++ /* 0 4 2 bit 8 rx pause, bit7 tx pause*/ ++ if((retVal = rtl8367c_getAsicSdsReg(0, 4, 2, ®_data)) != RT_ERR_OK) ++ return retVal; ++ if (pPortAbility->txpause) ++ reg_data |= 0x80; ++ else ++ reg_data &= 0xffffff7f; ++ if (pPortAbility->rxpause) ++ reg_data |= 0x100; ++ else ++ reg_data &= 0xfffffeff; ++ if((retVal = rtl8367c_setAsicSdsReg(0,4,2, reg_data)) != RT_ERR_OK) ++ return retVal; ++ ++ /* 0 4 0 bit 12 set 0*/ ++ if((retVal = rtl8367c_getAsicSdsReg(0, 4, 0, ®_data)) != RT_ERR_OK) ++ return retVal; ++ reg_data &= 0xFFFFEFFF; ++ if((retVal = rtl8367c_setAsicSdsReg(0,4,0, reg_data)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x7)) != RT_ERR_OK) ++ return retVal; ++ ++ } ++ ++ if((retVal = rtl8367c_setAsicRegBit(0x137d, 12, 0)) != RT_ERR_OK) ++ return retVal; ++ return RT_ERR_OK; ++ ++ } ++ /* new_cfg_sds_mode */ ++ if((retVal = rtl8367c_getAsicRegBits(0x1d95, 0x1f00, ®Value2)) != RT_ERR_OK) ++ return retVal; ++ if(regValue2 == 0x2) ++ { ++ /*SGMII*/ ++#if 0 ++ if((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x1f)) != RT_ERR_OK) ++ return retVal; ++#endif ++ if((retVal = rtl8367c_setAsicRegBit(0x1d95, 13, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ for(i=0;i<0xfff; i++); ++ ++ /* 0 2 0 bit 8-9 nway*/ ++ if((retVal = rtl8367c_getAsicSdsReg(0, 2, 0, ®_data)) != RT_ERR_OK) ++ return retVal; ++ reg_data &= 0xfffffcff; ++ if (pPortAbility->nway) ++ reg_data &= 0xfffffcff; ++ else ++ reg_data |= 0x100; ++ if((retVal = rtl8367c_setAsicSdsReg(0,2,0, reg_data)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x2)) != RT_ERR_OK) ++ return retVal; ++ ++ for(i=0;i<0xfff; i++); ++ ++ if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_FDUP_OFFSET, pPortAbility->duplex)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_SPD_MASK, pPortAbility->speed)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_TXFC_OFFSET, pPortAbility->txpause)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_RXFC_OFFSET, pPortAbility->rxpause)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_LINK_OFFSET, pPortAbility->link)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBit(0x137d, 12, 0)) != RT_ERR_OK) ++ return retVal; ++ return RT_ERR_OK; ++ } ++ } ++ else ++ { ++ ++ /*ext2_force_ablty*/ ++ if((retVal = rtl8367c_setAsicRegBit(0x13c4, 2, pPortAbility->duplex)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBits(0x13c4, 0x3, pPortAbility->speed)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBit(0x13c4, 4, pPortAbility->link)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBit(0x13c4, 6, pPortAbility->txpause)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBit(0x13c4, 5, pPortAbility->rxpause)) != RT_ERR_OK) ++ return retVal; ++ ++ /*force mode for ext2*/ ++ if((retVal = rtl8367c_setAsicRegBit(0x13c4, 12, pPortAbility->forcemode)) != RT_ERR_OK) ++ return retVal; ++ ++ if (pPortAbility->link == 1) ++ { ++ if((retVal = rtl8367c_setAsicRegBit(0x13c4, 4, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBit(0x13c4, 4, 1)) != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ { ++ if((retVal = rtl8367c_setAsicRegBits(0x13c4, 0x3, 2)) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ ++ if((retVal = rtl8367c_getAsicRegBit(0x1d3d, 10, ®_data)) != RT_ERR_OK) ++ return retVal; ++ if(reg_data == 1) ++ { ++ if((retVal = rtl8367c_setAsicRegBit(0x1311, 2, pPortAbility->duplex)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBits(0x1311, 0x3, pPortAbility->speed)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBit(0x1311, 4, pPortAbility->link)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBit(0x1311, 6, pPortAbility->txpause)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBit(0x1311, 5, pPortAbility->rxpause)) != RT_ERR_OK) ++ return retVal; ++ ++ /*force mode for ext1*/ ++ if((retVal = rtl8367c_setAsicRegBit(0x1311, 12, pPortAbility->forcemode)) != RT_ERR_OK) ++ return retVal; ++ ++ if (pPortAbility->link == 1) ++ { ++ if((retVal = rtl8367c_setAsicRegBit(0x1311, 4, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBit(0x1311, 4, 1)) != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ { ++ if((retVal = rtl8367c_setAsicRegBits(0x1311, 0x3, 2)) != RT_ERR_OK) ++ return retVal; ++ } ++ } ++ ++ ++ } ++ ++ /*disable force ability --- */ ++ if((retVal = rtl8367c_setAsicRegBit(0x137d, 12, 0)) != RT_ERR_OK) ++ return retVal; ++ } ++#if 0 ++ if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_FDUP_OFFSET, pPortAbility->duplex)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_SPD_MASK, pPortAbility->speed)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_TXFC_OFFSET, pPortAbility->txpause)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_RXFC_OFFSET, pPortAbility->rxpause)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_LINK_OFFSET, pPortAbility->link)) != RT_ERR_OK) ++ return retVal; ++#endif ++ } ++ ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_getAsicPortForceLinkExt ++ * Description: ++ * Get external interface force linking configuration ++ * Input: ++ * id - external interface id (0~1) ++ * pPortAbility - port ability configuration ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - input parameter out of range ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicPortForceLinkExt(rtk_uint32 id, rtl8367c_port_ability_t *pPortAbility) ++{ ++ rtk_uint32 reg_data, regValue, type; ++ rtk_uint32 sgmiiSel; ++ rtk_uint32 hsgmiiSel; ++ ret_t retVal; ++ ++ /* Invalid input parameter */ ++ if(id >= RTL8367C_EXTNO) ++ return RT_ERR_OUT_OF_RANGE; ++ /*cfg_magic_id & get chip_id*/ ++ if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0249)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_getAsicReg(0x1300, ®Value)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0000)) != RT_ERR_OK) ++ return retVal; ++ ++ type = 0; ++ ++ switch (regValue) ++ { ++ case 0x0276: ++ case 0x0597: ++ case 0x6367: ++ type = 1; ++ break; ++ case 0x0652: ++ case 0x6368: ++ type = 2; ++ break; ++ case 0x0801: ++ case 0x6511: ++ type = 3; ++ break; ++ default: ++ return RT_ERR_FAILED; ++ } ++ ++ if (1 == type) ++ { ++ if(1 == id) ++ { ++ if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_MAC8_SEL_SGMII_OFFSET, &sgmiiSel)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_MAC8_SEL_HSGMII_OFFSET, &hsgmiiSel)) != RT_ERR_OK) ++ return retVal; ++ ++ if( (sgmiiSel == 1) || (hsgmiiSel == 1) ) ++ { ++ memset(pPortAbility, 0x00, sizeof(rtl8367c_port_ability_t)); ++ pPortAbility->forcemode = 1; ++ ++ if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_FDUP_OFFSET, ®_data)) != RT_ERR_OK) ++ return retVal; ++ ++ pPortAbility->duplex = reg_data; ++ ++ if((retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_SPD_MASK, ®_data)) != RT_ERR_OK) ++ return retVal; ++ ++ pPortAbility->speed = reg_data; ++ ++ if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_LINK_OFFSET, ®_data)) != RT_ERR_OK) ++ return retVal; ++ ++ pPortAbility->link = reg_data; ++ ++ if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_TXFC_OFFSET, ®_data)) != RT_ERR_OK) ++ return retVal; ++ ++ pPortAbility->txpause = reg_data; ++ ++ if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_RXFC_OFFSET, ®_data)) != RT_ERR_OK) ++ return retVal; ++ ++ pPortAbility->rxpause = reg_data; ++ ++ return RT_ERR_OK; ++ } ++ } ++ ++ if(0 == id || 1 == id) ++ retVal = rtl8367c_getAsicReg(RTL8367C_REG_DIGITAL_INTERFACE0_FORCE+id, ®_data); ++ else ++ retVal = rtl8367c_getAsicReg(RTL8367C_REG_DIGITAL_INTERFACE2_FORCE, ®_data); ++ ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ pPortAbility->forcemode = (reg_data >> 12) & 0x0001; ++ pPortAbility->mstfault = (reg_data >> 9) & 0x0001; ++ pPortAbility->mstmode = (reg_data >> 8) & 0x0001; ++ pPortAbility->nway = (reg_data >> 7) & 0x0001; ++ pPortAbility->txpause = (reg_data >> 6) & 0x0001; ++ pPortAbility->rxpause = (reg_data >> 5) & 0x0001; ++ pPortAbility->link = (reg_data >> 4) & 0x0001; ++ pPortAbility->duplex = (reg_data >> 2) & 0x0001; ++ pPortAbility->speed = reg_data & 0x0003; ++ } ++ else if (2 == type) ++ { ++ if (id == 1) ++ { ++ if ((retVal = rtl8367c_getAsicReg(0x1311, ®_data))!=RT_ERR_OK) ++ return retVal; ++ ++ pPortAbility->forcemode = (reg_data >> 12) & 1; ++ pPortAbility->duplex = (reg_data >> 2) & 1; ++ pPortAbility->link = (reg_data >> 4) & 1; ++ pPortAbility->speed = reg_data & 3; ++ pPortAbility->rxpause = (reg_data >> 5) & 1; ++ pPortAbility->txpause = (reg_data >> 6) & 1; ++ } ++ else if (2 == id) ++ { ++ if ((retVal = rtl8367c_getAsicReg(0x13c4, ®_data))!=RT_ERR_OK) ++ return retVal; ++ ++ pPortAbility->forcemode = (reg_data >> 12) & 1; ++ pPortAbility->duplex = (reg_data >> 2) & 1; ++ pPortAbility->link = (reg_data >> 4) & 1; ++ pPortAbility->speed = reg_data & 3; ++ pPortAbility->rxpause = (reg_data >> 5) & 1; ++ pPortAbility->txpause = (reg_data >> 6) & 1; ++ } ++ } ++ else if (3 == type) ++ { ++ if (id == 1) ++ { ++ if ((retVal = rtl8367c_getAsicReg(0x1311, ®_data))!=RT_ERR_OK) ++ return retVal; ++ ++ pPortAbility->forcemode = (reg_data >> 12) & 1; ++ pPortAbility->duplex = (reg_data >> 2) & 1; ++ pPortAbility->link = (reg_data >> 4) & 1; ++ pPortAbility->speed = reg_data & 3; ++ pPortAbility->rxpause = (reg_data >> 5) & 1; ++ pPortAbility->txpause = (reg_data >> 6) & 1; ++ } ++ else if (2 == id) ++ { ++ if ((retVal = rtl8367c_getAsicReg(0x13c4, ®_data))!=RT_ERR_OK) ++ return retVal; ++ ++ pPortAbility->forcemode = (reg_data >> 12) & 1; ++ pPortAbility->duplex = (reg_data >> 2) & 1; ++ pPortAbility->link = (reg_data >> 4) & 1; ++ pPortAbility->speed = reg_data & 3; ++ pPortAbility->rxpause = (reg_data >> 5) & 1; ++ pPortAbility->txpause = (reg_data >> 6) & 1; ++ } ++ } ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_setAsicPortExtMode ++ * Description: ++ * Set external interface mode configuration ++ * Input: ++ * id - external interface id (0~2) ++ * mode - external interface mode ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - input parameter out of range ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicPortExtMode(rtk_uint32 id, rtk_uint32 mode) ++{ ++ ret_t retVal; ++ rtk_uint32 i, regValue, type, option,reg_data; ++ rtk_uint32 idx; ++ rtk_uint32 redData[][2] = { {0x04D7, 0x0480}, {0xF994, 0x0481}, {0x21A2, 0x0482}, {0x6960, 0x0483}, {0x9728, 0x0484}, {0x9D85, 0x0423}, {0xD810, 0x0424}, {0x83F2, 0x002E} }; ++ rtk_uint32 redDataSB[][2] = { {0x04D7, 0x0480}, {0xF994, 0x0481}, {0x31A2, 0x0482}, {0x6960, 0x0483}, {0x9728, 0x0484}, {0x9D85, 0x0423}, {0xD810, 0x0424}, {0x83F2, 0x002E} }; ++ rtk_uint32 redData1[][2] = { {0x82F1, 0x0500}, {0xF195, 0x0501}, {0x31A2, 0x0502}, {0x796C, 0x0503}, {0x9728, 0x0504}, {0x9D85, 0x0423}, {0xD810, 0x0424}, {0x0F80, 0x0001}, {0x83F2, 0x002E} }; ++ rtk_uint32 redData5[][2] = { {0x82F1, 0x0500}, {0xF195, 0x0501}, {0x31A2, 0x0502}, {0x796C, 0x0503}, {0x9728, 0x0504}, {0x9D85, 0x0423}, {0xD810, 0x0424}, {0x0F80, 0x0001}, {0x83F2, 0x002E} }; ++ rtk_uint32 redData6[][2] = { {0x82F1, 0x0500}, {0xF195, 0x0501}, {0x31A2, 0x0502}, {0x796C, 0x0503}, {0x9728, 0x0504}, {0x9D85, 0x0423}, {0xD810, 0x0424}, {0x0F80, 0x0001}, {0x83F2, 0x002E} }; ++ rtk_uint32 redData8[][2] = { {0x82F1, 0x0500}, {0xF995, 0x0501}, {0x31A2, 0x0502}, {0x796C, 0x0503}, {0x9728, 0x0504}, {0x9D85, 0x0423}, {0xD810, 0x0424}, {0x0F80, 0x0001}, {0x83F2, 0x002E} }; ++ rtk_uint32 redData9[][2] = { {0x82F1, 0x0500}, {0xF995, 0x0501}, {0x31A2, 0x0502}, {0x796C, 0x0503}, {0x9728, 0x0504}, {0x9D85, 0x0423}, {0xD810, 0x0424}, {0x0F80, 0x0001}, {0x83F2, 0x002E} }; ++ rtk_uint32 redDataHB[][2] = { {0x82F0, 0x0500}, {0xF195, 0x0501}, {0x31A2, 0x0502}, {0x7960, 0x0503}, {0x9728, 0x0504}, {0x9D85, 0x0423}, {0xD810, 0x0424}, {0x0F80, 0x0001}, {0x83F2, 0x002E} }; ++ ++ if(id >= RTL8367C_EXTNO) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ if(mode >= EXT_END) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ /* magic number*/ ++ if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0249)) != RT_ERR_OK) ++ return retVal; ++ /* Chip num */ ++ if((retVal = rtl8367c_getAsicReg(0x1300, ®Value)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0000)) != RT_ERR_OK) ++ return retVal; ++ ++ type = 0; ++ ++ switch (regValue) ++ { ++ case 0x0276: ++ case 0x0597: ++ case 0x6367: ++ type = 1; ++ break; ++ case 0x0652: ++ case 0x6368: ++ type = 2; ++ break; ++ case 0x0801: ++ case 0x6511: ++ type = 3; ++ break; ++ default: ++ return RT_ERR_FAILED; ++ } ++ ++ ++ if (1==type) ++ { ++ if((mode == EXT_1000X_100FX) || (mode == EXT_1000X) || (mode == EXT_100FX)) ++ { ++ if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_REG_TO_ECO4, 5, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_REG_TO_ECO4, 7, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_CHIP_RESET, RTL8367C_DW8051_RST_OFFSET, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_MISCELLANEOUS_CONFIGURE0, RTL8367C_DW8051_EN_OFFSET, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_DW8051_RDY, RTL8367C_ACS_IROM_ENABLE_OFFSET, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_DW8051_RDY, RTL8367C_IROM_MSB_OFFSET, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ if(mode == EXT_1000X_100FX) ++ { ++ for(idx = 0; idx < FIBER2_AUTO_INIT_SIZE; idx++) ++ { ++ if ((retVal = rtl8367c_setAsicReg(0xE000 + idx, (rtk_uint32)Fiber2_Auto[idx])) != RT_ERR_OK) ++ return retVal; ++ } ++ } ++ ++ if(mode == EXT_1000X) ++ { ++ for(idx = 0; idx < FIBER2_1G_INIT_SIZE; idx++) ++ { ++ if ((retVal = rtl8367c_setAsicReg(0xE000 + idx, (rtk_uint32)Fiber2_1G[idx])) != RT_ERR_OK) ++ return retVal; ++ } ++ } ++ ++ if(mode == EXT_100FX) ++ { ++ for(idx = 0; idx < FIBER2_100M_INIT_SIZE; idx++) ++ { ++ if ((retVal = rtl8367c_setAsicReg(0xE000 + idx, (rtk_uint32)Fiber2_100M[idx])) != RT_ERR_OK) ++ return retVal; ++ } ++ } ++ ++ if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_DW8051_RDY, RTL8367C_IROM_MSB_OFFSET, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_DW8051_RDY, RTL8367C_ACS_IROM_ENABLE_OFFSET, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_CHIP_RESET, RTL8367C_DW8051_RST_OFFSET, 0)) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ if(mode == EXT_GMII) ++ { ++ if( (retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_EXT0_RGMXF, RTL8367C_EXT0_RGTX_INV_OFFSET, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ if( (retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_EXT1_RGMXF, RTL8367C_EXT1_RGTX_INV_OFFSET, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ if( (retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_EXT_TXC_DLY, RTL8367C_EXT1_GMII_TX_DELAY_MASK, 5)) != RT_ERR_OK) ++ return retVal; ++ ++ if( (retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_EXT_TXC_DLY, RTL8367C_EXT0_GMII_TX_DELAY_MASK, 6)) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ /* Serdes reset */ ++ if( (mode == EXT_TMII_MAC) || (mode == EXT_TMII_PHY) ) ++ { ++ if( (retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_BYPASS_LINE_RATE, id, 1)) != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ { ++ if( (retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_BYPASS_LINE_RATE, id, 0)) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ if( (mode == EXT_SGMII) || (mode == EXT_HSGMII) ) ++ { ++ if(id != 1) ++ return RT_ERR_PORT_ID; ++ ++ if((retVal = rtl8367c_setAsicReg(0x13C0, 0x0249)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_getAsicReg(0x13C1, &option)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicReg(0x13C0, 0x0000)) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ if(mode == EXT_SGMII) ++ { ++ if(option == 0) ++ { ++ for(i = 0; i <= 7; i++) ++ { ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, redData[i][0])) != RT_ERR_OK) ++ return retVal; ++ ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, redData[i][1])) != RT_ERR_OK) ++ return retVal; ++ ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK) ++ return retVal; ++ } ++ } ++ else ++ { ++ for(i = 0; i <= 7; i++) ++ { ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, redDataSB[i][0])) != RT_ERR_OK) ++ return retVal; ++ ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, redDataSB[i][1])) != RT_ERR_OK) ++ return retVal; ++ ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK) ++ return retVal; ++ } ++ } ++ } ++ ++ if(mode == EXT_HSGMII) ++ { ++ if(option == 0) ++ { ++ if( (retVal = rtl8367c_setAsicReg(0x13c2, 0x0249)) != RT_ERR_OK) ++ return retVal; ++ ++ if( (retVal = rtl8367c_getAsicReg(0x1301, ®Value)) != RT_ERR_OK) ++ return retVal; ++ ++ if( (retVal = rtl8367c_setAsicReg(0x13c2, 0x0000)) != RT_ERR_OK) ++ return retVal; ++ ++ if ( ((regValue & 0x00F0) >> 4) == 0x0001) ++ { ++ for(i = 0; i <= 8; i++) ++ { ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, redData1[i][0])) != RT_ERR_OK) ++ return retVal; ++ ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, redData1[i][1])) != RT_ERR_OK) ++ return retVal; ++ ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK) ++ return retVal; ++ } ++ } ++ else if ( ((regValue & 0x00F0) >> 4) == 0x0005) ++ { ++ for(i = 0; i <= 8; i++) ++ { ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, redData5[i][0])) != RT_ERR_OK) ++ return retVal; ++ ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, redData5[i][1])) != RT_ERR_OK) ++ return retVal; ++ ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK) ++ return retVal; ++ } ++ } ++ else if ( ((regValue & 0x00F0) >> 4) == 0x0006) ++ { ++ for(i = 0; i <= 8; i++) ++ { ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, redData6[i][0])) != RT_ERR_OK) ++ return retVal; ++ ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, redData6[i][1])) != RT_ERR_OK) ++ return retVal; ++ ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK) ++ return retVal; ++ } ++ } ++ else if ( ((regValue & 0x00F0) >> 4) == 0x0008) ++ { ++ for(i = 0; i <= 8; i++) ++ { ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, redData8[i][0])) != RT_ERR_OK) ++ return retVal; ++ ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, redData8[i][1])) != RT_ERR_OK) ++ return retVal; ++ ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK) ++ return retVal; ++ } ++ } ++ else if ( ((regValue & 0x00F0) >> 4) == 0x0009) ++ { ++ for(i = 0; i <= 8; i++) ++ { ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, redData9[i][0])) != RT_ERR_OK) ++ return retVal; ++ ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, redData9[i][1])) != RT_ERR_OK) ++ return retVal; ++ ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK) ++ return retVal; ++ } ++ } ++ } ++ else ++ { ++ for(i = 0; i <= 8; i++) ++ { ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, redDataHB[i][0])) != RT_ERR_OK) ++ return retVal; ++ ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, redDataHB[i][1])) != RT_ERR_OK) ++ return retVal; ++ ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK) ++ return retVal; ++ } ++ } ++ } ++ ++ /* Only one ext port should care SGMII setting */ ++ if(id == 1) ++ { ++ ++ if(mode == EXT_SGMII) ++ { ++ if( (retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_MAC8_SEL_SGMII_OFFSET, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ if( (retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_MAC8_SEL_HSGMII_OFFSET, 0)) != RT_ERR_OK) ++ return retVal; ++ } ++ else if(mode == EXT_HSGMII) ++ { ++ if( (retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_MAC8_SEL_SGMII_OFFSET, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ if( (retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_MAC8_SEL_HSGMII_OFFSET, 1)) != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ { ++ ++ if((mode != EXT_1000X_100FX) && (mode != EXT_1000X) && (mode != EXT_100FX)) ++ { ++ if( (retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_MAC8_SEL_SGMII_OFFSET, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ if( (retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_MAC8_SEL_HSGMII_OFFSET, 0)) != RT_ERR_OK) ++ return retVal; ++ } ++ } ++ } ++ ++ if(0 == id || 1 == id) ++ { ++ if((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_DIGITAL_INTERFACE_SELECT, RTL8367C_SELECT_GMII_0_MASK << (id * RTL8367C_SELECT_GMII_1_OFFSET), mode)) != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ { ++ if((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_DIGITAL_INTERFACE_SELECT_1, RTL8367C_SELECT_GMII_2_MASK, mode)) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ /* Serdes not reset */ ++ if( (mode == EXT_SGMII) || (mode == EXT_HSGMII) ) ++ { ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, 0x7106)) != RT_ERR_OK) ++ return retVal; ++ ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, 0x0003)) != RT_ERR_OK) ++ return retVal; ++ ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ if( (mode == EXT_SGMII) || (mode == EXT_HSGMII) ) ++ { ++ if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_CHIP_RESET, RTL8367C_DW8051_RST_OFFSET, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_MISCELLANEOUS_CONFIGURE0, RTL8367C_DW8051_EN_OFFSET, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_DW8051_RDY, RTL8367C_ACS_IROM_ENABLE_OFFSET, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_DW8051_RDY, RTL8367C_IROM_MSB_OFFSET, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ for(idx = 0; idx < SGMII_INIT_SIZE; idx++) ++ { ++ if ((retVal = rtl8367c_setAsicReg(0xE000 + idx, (rtk_uint32)Sgmii_Init[idx])) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_DW8051_RDY, RTL8367C_IROM_MSB_OFFSET, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_DW8051_RDY, RTL8367C_ACS_IROM_ENABLE_OFFSET, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_CHIP_RESET, RTL8367C_DW8051_RST_OFFSET, 0)) != RT_ERR_OK) ++ return retVal; ++ } ++ } ++ else if (2 == type) ++ { ++ /* Serdes reset */ ++ if( (mode == EXT_TMII_MAC) || (mode == EXT_TMII_PHY) ) ++ { ++ if( (retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_BYPASS_LINE_RATE, id+2, 1)) != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ { ++ if( (retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_BYPASS_LINE_RATE, id+2, 0)) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ /*set MAC mode*/ ++ if (id == 1) ++ { ++ if(mode == EXT_HSGMII) ++ return RT_ERR_PORT_ID; ++ ++ if (mode == EXT_SGMII) ++ { ++ /*cfg port8 with MII mac mode*/ ++ if ((retVal = rtl8367c_setAsicRegBits(0x1305, 0xf0, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ /*enable port8 SGMII*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d92, 14, 1)) != RT_ERR_OK) ++ return retVal; ++ } ++ else if (mode == EXT_1000X || mode == EXT_100FX || mode == EXT_1000X_100FX) ++ { ++ /*cfg port8 with MII mac mode*/ ++ if ((retVal = rtl8367c_setAsicRegBits(0x1305, 0xf0, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ /*disable port8 SGMII*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d92, 14, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ /*set fiber link up*/ ++ if((retVal = rtl8367c_setAsicRegBit(0x6210, 11, 0)) != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ { ++ /*cfg port8 with MII mac mode*/ ++ if ((retVal = rtl8367c_setAsicRegBits(0x1305, 0xf0, mode)) != RT_ERR_OK) ++ return retVal; ++ ++ /*disable port8 SGMII*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d92, 14, 0)) != RT_ERR_OK) ++ return retVal; ++ } ++ /*disable SDS 1*/ ++ if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x1f00, 0x1f)) != RT_ERR_OK) ++ return retVal; ++ } ++ else if(id == 2) ++ { ++ if (mode == EXT_HSGMII) ++ { ++ if ((retVal = rtl8367c_setAsicReg(0x130, 7)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicReg(0x39f, 7)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicReg(0x3fa, 7)) != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ { ++ if ((retVal = rtl8367c_setAsicReg(0x130, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicReg(0x39f, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicReg(0x3fa, 4)) != RT_ERR_OK) ++ return retVal; ++ ++ } ++ ++ ++ if (mode == EXT_SGMII) ++ { ++ /*cfg port9 with MII mac mode*/ ++ if ((retVal = rtl8367c_setAsicRegBits(0x13c3, 0xf, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ /*enable port9 SGMII*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d92, 6, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ /*disable port9 HSGMII*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d92, 7, 0)) != RT_ERR_OK) ++ return retVal; ++ } ++ else if (mode == EXT_HSGMII) ++ { ++ /*cfg port9 with MII mac mode*/ ++ if ((retVal = rtl8367c_setAsicRegBits(0x13c3, 0xf, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ /*disable port9 SGMII*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d92, 6, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ /*enable port9 HSGMII*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d92, 7, 1)) != RT_ERR_OK) ++ return retVal; ++ } ++ else if (mode == EXT_1000X || mode == EXT_100FX || mode == EXT_1000X_100FX) ++ { ++ /*cfg port9 with MII mac mode*/ ++ if ((retVal = rtl8367c_setAsicRegBits(0x13c3, 0xf, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ /*disable port9 SGMII*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d92, 6, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ /*disable port9 HSGMII*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d92, 7, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ /*set fiber link up*/ ++ if((retVal = rtl8367c_setAsicRegBit(0x6200, 11, 0)) != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ { ++ /*cfg port9 with MII mac mode*/ ++ if ((retVal = rtl8367c_setAsicRegBits(0x13c3, 0xf, mode)) != RT_ERR_OK) ++ return retVal; ++ ++ /*disable port9 SGMII*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d92, 6, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ /*disable port9 HSGMII*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d92, 7, 0)) != RT_ERR_OK) ++ return retVal; ++ } ++ /*disable SDS 0*/ ++ if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x1f, 0x1f)) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ /*SET TO RGMII MODE*/ ++ if (mode == EXT_RGMII) ++ { ++ /*disable paral led pad*/ ++ if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_PARA_LED_IO_EN3, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_PARA_LED_IO_EN1, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_PARA_LED_IO_EN2, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ /*set MAC8 mode*/ ++ if (id == 1) ++ { ++ /*1: RGMII1 bias work at 3.3V, 0: RGMII1 bias work at 2.5V*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1303, 9, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ /*drving 1*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1303, 6, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ /*drving 1*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1303, 4, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ /*show rate = 0*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1303, 1, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ /*EXT1 RGMII TXC delay 2ns*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1307, 3, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ /*cfg_Ext1_rgtxc_dly = 0*/ ++ if ((retVal = rtl8367c_setAsicRegBits(0x13f9, 0x38, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ /*RXDLY = 0*/ ++ if ((retVal = rtl8367c_setAsicRegBits(0x1307, 0x7, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ /*cfg_rg1_dn = 4*/ ++ if ((retVal = rtl8367c_setAsicRegBits(0x1304, 0x7000, 4)) != RT_ERR_OK) ++ return retVal; ++ ++ /*cfg_rg1_dp = 4*/ ++ if ((retVal = rtl8367c_setAsicRegBits(0x13f9, 0x700, 4)) != RT_ERR_OK) ++ return retVal; ++ } ++ else if (id == 2) ++ { ++ /*1: RGMII1 bias work at 3.3V, 0: RGMII1 bias work at 2.5V*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1303, 10, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ /*drving 1*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x13e2, 2, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ /*drving 1*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x13e2, 1, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ /*show rate = 0*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x13e2, 0, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ /*EXT1 RGMII TXC delay 2ns*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x13c5, 3, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ /*cfg_Ext1_rgtxc_dly = 0*/ ++ if ((retVal = rtl8367c_setAsicRegBits(0x13f9, 0x1c0, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ /*RXDLY = 0*/ ++ if ((retVal = rtl8367c_setAsicRegBits(0x13c5, 0x7, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ /*cfg_rg1_dn = 4*/ ++ if ((retVal = rtl8367c_setAsicRegBits(0x13e2, 0x1c0, 4)) != RT_ERR_OK) ++ return retVal; ++ ++ /*cfg_rg1_dp = 4*/ ++ if ((retVal = rtl8367c_setAsicRegBits(0x13e2, 0x38, 4)) != RT_ERR_OK) ++ return retVal; ++ } ++ } ++ else if (mode == EXT_SGMII) ++ { ++ if (id == 1) ++ { ++ /*sds 1 reg 1 page 0x21 write value 0xec91*/ ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, 0xec91)) != RT_ERR_OK) ++ return retVal; ++ ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, (0x21<<5) | 1)) != RT_ERR_OK) ++ return retVal; ++ ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C1)) != RT_ERR_OK) ++ return retVal; ++ ++ /*sds 1 reg 5 page 0x24 write value 0x5825*/ ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, 0x5825)) != RT_ERR_OK) ++ return retVal; ++ ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, (0x24<<5) | 5)) != RT_ERR_OK) ++ return retVal; ++ ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C1)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x1f00, 2)) != RT_ERR_OK) ++ return retVal; ++ ++ /*?????????????????*/ ++ ++ } ++ else if (id == 2) ++ { ++ /*sds 0 reg 0 page 0x28 write value 0x942c*/ ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, 0x942c)) != RT_ERR_OK) ++ return retVal; ++ ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, (0x28<<5) | 0)) != RT_ERR_OK) ++ return retVal; ++ ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK) ++ return retVal; ++ ++ /*sds 0 reg 0 page 0x24 write value 0x942c*/ ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, 0x942c)) != RT_ERR_OK) ++ return retVal; ++ ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, (0x24<<5) | 0)) != RT_ERR_OK) ++ return retVal; ++ ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK) ++ return retVal; ++ ++ /*sds 0 reg 5 page 0x21 write value 0x8dc3*/ ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, 0x8dc3)) != RT_ERR_OK) ++ return retVal; ++ ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, (0x21<<5) | 5)) != RT_ERR_OK) ++ return retVal; ++ ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x1f, 2)) != RT_ERR_OK) ++ return retVal; ++ ++ /*?????????????????*/ ++ } ++ } ++ else if (mode == EXT_HSGMII) ++ { ++ if (id == 2) ++ { ++ /*sds 0 reg 0 page 0x28 write value 0x942c*/ ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, 0x942c)) != RT_ERR_OK) ++ return retVal; ++ ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, (0x28<<5) | 0)) != RT_ERR_OK) ++ return retVal; ++ ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK) ++ return retVal; ++ ++ /*sds 0 reg 0 page 0x24 write value 0x942c*/ ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, 0x942c)) != RT_ERR_OK) ++ return retVal; ++ ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, (0x24<<5) | 0)) != RT_ERR_OK) ++ return retVal; ++ ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK) ++ return retVal; ++ ++ /*sds 0 reg 5 page 0x21 write value 0x8dc3*/ ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, 0x8dc3)) != RT_ERR_OK) ++ return retVal; ++ ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, (0x21<<5) | 5)) != RT_ERR_OK) ++ return retVal; ++ ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK) ++ return retVal; ++ ++ ++ /* optimizing HISGMII performance while RGMII used & */ ++ /*sds 0 reg 9 page 0x21 write value 0x3931*/ ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, 0x3931)) != RT_ERR_OK) ++ return retVal; ++ ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, (0x21<<5)|9) ) != RT_ERR_OK) ++ return retVal; ++ ++ if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK) ++ return retVal; ++ ++ ++ if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x1f, 0x12)) != RT_ERR_OK) ++ return retVal; ++ ++ /*?????????????????*/ ++ } ++ } ++ else if (mode == EXT_1000X) ++ { ++ if (id == 1) ++ { ++ ++ if( (retVal = rtl8367c_setAsicSdsReg(1, 1, 0x21, 0xec91)) != RT_ERR_OK) ++ return retVal; ++ if( (retVal = rtl8367c_setAsicSdsReg(1, 5, 0x24, 0x5825)) != RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x1f00, 4)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x1f00, 0x1f)) != RT_ERR_OK) ++ return retVal; ++ ++ /*patch speed change sds1 1000M*/ ++ if( (retVal = rtl8367c_getAsicSdsReg(1, 4, 0, ®Value)) != RT_ERR_OK) ++ return retVal; ++ regValue &= 0xFFFF0FFF; ++ regValue |= 0x9000; ++ if( (retVal = rtl8367c_setAsicSdsReg(1, 4, 0, regValue)) != RT_ERR_OK) ++ return retVal; ++ ++ if( (retVal = rtl8367c_getAsicSdsReg(1, 0, 2, ®Value)) != RT_ERR_OK) ++ return retVal; ++ regValue &= 0xFFFFdFFF; ++ regValue |= 0x40; ++ if( (retVal = rtl8367c_setAsicSdsReg(1, 0, 2, regValue)) != RT_ERR_OK) ++ return retVal; ++ ++ ++ if( (retVal = rtl8367c_getAsicSdsReg(1, 4, 0, ®Value)) != RT_ERR_OK) ++ return retVal; ++ regValue &= 0xFFFFEFFF; ++ if( (retVal = rtl8367c_setAsicSdsReg(1, 4, 0, regValue)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x1f00, 4)) != RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x6000, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ } ++ else if (id == 2) ++ { ++ if( (retVal = rtl8367c_setAsicSdsReg(0, 0, 0x28, 0x942c)) != RT_ERR_OK) ++ return retVal; ++ if( (retVal = rtl8367c_setAsicSdsReg(0, 0, 0x24, 0x942c)) != RT_ERR_OK) ++ return retVal; ++ if( (retVal = rtl8367c_setAsicSdsReg(0, 5, 0x21, 0x8dc3)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x1f, 4)) != RT_ERR_OK) ++ return retVal; ++ ++ /*patch speed change sds0 1000M*/ ++ if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x1f, 0x1f)) != RT_ERR_OK) ++ return retVal; ++ ++ if( (retVal = rtl8367c_getAsicSdsReg(0, 4, 0, ®Value)) != RT_ERR_OK) ++ return retVal; ++ regValue &= 0xFFFF0FFF; ++ regValue |= 0x9000; ++ if( (retVal = rtl8367c_setAsicSdsReg(0, 4, 0, regValue)) != RT_ERR_OK) ++ return retVal; ++ ++ if( (retVal = rtl8367c_getAsicSdsReg(0, 0, 2, ®Value)) != RT_ERR_OK) ++ return retVal; ++ regValue &= 0xFFFFDFFF; ++ regValue |= 0x40; ++ if( (retVal = rtl8367c_setAsicSdsReg(0, 0, 2, regValue)) != RT_ERR_OK) ++ return retVal; ++ ++ if( (retVal = rtl8367c_getAsicSdsReg(0, 4, 0, ®Value)) != RT_ERR_OK) ++ return retVal; ++ regValue &= 0xFFFFEFFF; ++ if( (retVal = rtl8367c_setAsicSdsReg(0, 4, 0, regValue)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x1f, 4)) != RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0xe0, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ } ++ } ++ else if (mode == EXT_100FX) ++ { ++ if (id == 1) ++ { ++ if( (retVal = rtl8367c_setAsicSdsReg(1, 1, 0x21, 0xec91)) != RT_ERR_OK) ++ return retVal; ++ if( (retVal = rtl8367c_setAsicSdsReg(1, 5, 0x24, 0x5825)) != RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x1f00, 5)) != RT_ERR_OK) ++ return retVal; ++ ++ /*patch speed change sds1 100M*/ ++ if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x1f00, 0x1f)) != RT_ERR_OK) ++ return retVal; ++ if( (retVal = rtl8367c_getAsicSdsReg(1, 4, 0, ®Value)) != RT_ERR_OK) ++ return retVal; ++ regValue &= 0xFFFF0FFF; ++ regValue |= 0xb000; ++ if( (retVal = rtl8367c_setAsicSdsReg(1, 4, 0, regValue)) != RT_ERR_OK) ++ return retVal; ++ ++ if( (retVal = rtl8367c_getAsicSdsReg(1, 0, 2, ®Value)) != RT_ERR_OK) ++ return retVal; ++ regValue &= 0xFFFFFFBF; ++ regValue |= 0x2000; ++ if( (retVal = rtl8367c_setAsicSdsReg(1, 0, 2, regValue)) != RT_ERR_OK) ++ return retVal; ++#if 0 ++ if( (retVal = rtl8367c_setAsicReg(0x6214, 0x1a0)) != RT_ERR_OK) ++ return retVal; ++#endif ++ if( (retVal = rtl8367c_getAsicSdsReg(1, 4, 0, ®Value)) != RT_ERR_OK) ++ return retVal; ++ regValue &= 0xFFFFEFFF; ++ if( (retVal = rtl8367c_setAsicSdsReg(1, 4, 0, regValue)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x1f00, 5)) != RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x6000, 0)) != RT_ERR_OK) ++ return retVal; ++ } ++ else if (id == 2) ++ { ++ if( (retVal = rtl8367c_setAsicSdsReg(0, 0, 0x28, 0x942c)) != RT_ERR_OK) ++ return retVal; ++ if( (retVal = rtl8367c_setAsicSdsReg(0, 0, 0x24, 0x942c)) != RT_ERR_OK) ++ return retVal; ++ if( (retVal = rtl8367c_setAsicSdsReg(0, 5, 0x21, 0x8dc3)) != RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x1f, 5)) != RT_ERR_OK) ++ return retVal; ++ ++ /*patch speed change sds0 100M*/ ++ if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x1f, 0x1f)) != RT_ERR_OK) ++ return retVal; ++ ++ if( (retVal = rtl8367c_getAsicSdsReg(0, 4, 0, ®Value)) != RT_ERR_OK) ++ return retVal; ++ regValue &= 0xFFFF0FFF; ++ regValue |= 0xb000; ++ if( (retVal = rtl8367c_setAsicSdsReg(0, 4, 0, regValue)) != RT_ERR_OK) ++ return retVal; ++ ++ if( (retVal = rtl8367c_getAsicSdsReg(0, 0, 2, ®Value)) != RT_ERR_OK) ++ return retVal; ++ regValue &= 0xFFFFFFBF; ++ regValue |= 0x2000; ++ if( (retVal = rtl8367c_setAsicSdsReg(0, 0, 2, regValue)) != RT_ERR_OK) ++ return retVal; ++ ++ if( (retVal = rtl8367c_getAsicSdsReg(0, 4, 0, ®Value)) != RT_ERR_OK) ++ return retVal; ++ regValue &= 0xFFFFEFFF; ++ if( (retVal = rtl8367c_setAsicSdsReg(0, 4, 0, regValue)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x1f, 5)) != RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0xe0, 0)) != RT_ERR_OK) ++ return retVal; ++ } ++ } ++ else if (mode == EXT_1000X_100FX) ++ { ++ if (id == 1) ++ { ++ if( (retVal = rtl8367c_setAsicSdsReg(1, 1, 0x21, 0xec91)) != RT_ERR_OK) ++ return retVal; ++ if( (retVal = rtl8367c_setAsicSdsReg(1, 5, 0x24, 0x5825)) != RT_ERR_OK) ++ return retVal; ++ if( (retVal = rtl8367c_setAsicSdsReg(1, 13, 0, 0x4616)) != RT_ERR_OK) ++ return retVal; ++ if( (retVal = rtl8367c_setAsicSdsReg(1, 1, 0, 0xf20)) != RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x1f00, 7)) != RT_ERR_OK) ++ return retVal; ++ } ++ else if (id == 2) ++ { ++ if( (retVal = rtl8367c_setAsicSdsReg(0, 0, 0x28, 0x942c)) != RT_ERR_OK) ++ return retVal; ++ if( (retVal = rtl8367c_setAsicSdsReg(0, 0, 0x24, 0x942c)) != RT_ERR_OK) ++ return retVal; ++ if( (retVal = rtl8367c_setAsicSdsReg(0, 5, 0x21, 0x8dc3)) != RT_ERR_OK) ++ return retVal; ++ if( (retVal = rtl8367c_setAsicSdsReg(0, 13, 0, 0x4616)) != RT_ERR_OK) ++ return retVal; ++ if( (retVal = rtl8367c_setAsicSdsReg(0, 1, 0, 0xf20)) != RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x1f, 7)) != RT_ERR_OK) ++ return retVal; ++ } ++ } ++ ++ } ++ else if (3 == type) ++ { ++ ++ /*restore patch, by designer. patch Tx FIFO issue, when not HSGMII 2.5G mode ++ #sds0, page 1, reg 1, bit4=0*/ ++ if( (retVal = rtl8367c_getAsicSdsReg(0, 1, 1, ®Value)) != RT_ERR_OK) ++ return retVal; ++ regValue &= 0xFFFFFFEF; ++ if( (retVal = rtl8367c_setAsicSdsReg(0, 1, 1, regValue)) != RT_ERR_OK) ++ return retVal; ++ ++ /*set for mac 6*/ ++ if (1 == id) ++ { ++ /*force port6 linkdown*/ ++ if ((retVal = rtl8367c_setAsicReg(0x137c, 0x1000)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_getAsicRegBit(0x1d9d, 6, ®_data)) != RT_ERR_OK) ++ return retVal; ++ while(reg_data == 0) ++ { ++ if ((retVal = rtl8367c_getAsicRegBit(0x1d9d, 6, ®_data)) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ if (mode == EXT_SGMII) ++ { ++ /* disable mac6 mode_ext1 mode*/ ++ if ((retVal = rtl8367c_getAsicRegBit(0x1d3d, 10, ®_data)) != RT_ERR_OK) ++ return retVal; ++ if(reg_data == 0) ++ { ++ if ((retVal = rtl8367c_setAsicRegBits(0x1305, 0xf0, 0)) != RT_ERR_OK) ++ return retVal; ++ } ++ /*cfg_bypass_line_rate[1]=0*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x3f7, 1, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ ++ ++ /*bit5: cfg_mac6_fib=0 & bit7: cfg_mac6_fib2=0*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 5, 0)) != RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 7, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ /*cfg_mac7_fib=0*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d95, 1, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ /*cfg_mac7_sel_sgmii= 0: MAC7 is not SGMII mode*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d95, 0, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ /*#cfg_sgmii_link=0*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d11, 9, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ /*cfg_mac6_sel_hsgmii=0*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d11, 11, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ ++ /*bit13: cfg_sds_mode_sel_new=1 :Enable new sds mode config method*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d95, 13, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ /* bit[12:8]: Only valid when cfg_sds_mode_sel_new=1 ++ new_cfg_sds_mode=0x1F (reset mode) */ ++ if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x1f)) != RT_ERR_OK) ++ return retVal; ++ ++ /*cfg_mac6_sel_sgmii= 1*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d11, 6, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ /* bit[12:8]: Only valid when cfg_sds_mode_sel_new=1 ++ new_cfg_sds_mode=0x12 */ ++ if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x2)) != RT_ERR_OK) ++ return retVal; ++ ++ /* MAC link source*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d95, 2, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ ++ } ++ else if (mode == EXT_HSGMII) ++ { ++ ++ /*restore patch, by designer. patch Tx FIFO issue, when HSGMII 2.5G mode ++ #sds0, page 1, reg 1, bit4=1*/ ++ if( (retVal = rtl8367c_getAsicSdsReg(0, 1, 1, ®Value)) != RT_ERR_OK) ++ return retVal; ++ regValue |= 0x10; ++ if( (retVal = rtl8367c_setAsicSdsReg(0, 1, 1, regValue)) != RT_ERR_OK) ++ return retVal; ++ ++ /* mode_ext1 = disable*/ ++ /* disable mac6 mode_ext1 mode*/ ++ if ((retVal = rtl8367c_getAsicRegBit(0x1d3d, 10, ®_data)) != RT_ERR_OK) ++ return retVal; ++ if(reg_data == 0) ++ { ++ if ((retVal = rtl8367c_setAsicRegBits(0x1305, 0xf0, 0)) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ if ((retVal = rtl8367c_setAsicRegBit(0x3f7, 1, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ /*bit5: cfg_mac6_fib=0 & bit7: cfg_mac6_fib2=0*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 5, 0)) != RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 7, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ /*cfg_mac7_fib=0*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d95, 1, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ /*cfg_mac7_sel_sgmii= 0*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d95, 0, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ /*cfg_mac6_sel_sgmii=0*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d11, 9, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ /*cfg_mac6_sel_hsgmii=1*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d11, 11, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ /*cfg_mac6_sel_sgmii= 0*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d11, 6, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicReg(0xd0,7)) != RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicReg(0x399, 7)) != RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicReg(0x3fa, 7)) != RT_ERR_OK) ++ return retVal; ++ ++ /*bit13: cfg_sds_mode_sel_new=1 :Enable new sds mode config method*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d95, 13, 1)) != RT_ERR_OK) ++ return retVal; ++ /* bit[12:8]: Only valid when cfg_sds_mode_sel_new=1 ++ new_cfg_sds_mode=0x12 */ ++ if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x12)) != RT_ERR_OK) ++ return retVal; ++ /* ++ 1: MAC link = SGMII SerDes link ++ 0: MAC link = SGMII config link (cfg_sgmii_link) ++ */ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d95, 2, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ } ++ else if(mode == EXT_1000X) ++ { ++ /* 0 2 0 bit 8~9 set 0, force n-way*/ ++ if((retVal = rtl8367c_getAsicSdsReg(0, 2, 0, ®_data)) != RT_ERR_OK) ++ return retVal; ++ reg_data &= 0xFFFFFCFF; ++ if((retVal = rtl8367c_setAsicSdsReg(0,2,0, reg_data)) != RT_ERR_OK) ++ return retVal; ++ ++ /* disable mac6 mode_ext1 mode*/ ++ if ((retVal = rtl8367c_getAsicRegBit(0x1d3d, 10, ®_data)) != RT_ERR_OK) ++ return retVal; ++ if(reg_data == 0) ++ { ++ if ((retVal = rtl8367c_setAsicRegBits(0x1305, 0xf0, 0)) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ if ((retVal = rtl8367c_setAsicRegBit(0x3f7, 1, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicReg(0x1d11, 0x1500)) != RT_ERR_OK) ++ return retVal; ++ ++ /*bit13: cfg_sds_mode_sel_new=1 :Enable new sds mode config method ++ bit[1:0]:cfg_mac7_fib= 0 & cfg_mac7_sel_sgmii=0 ++ */ ++ if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x1f)) != RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d95, 13, 1)) != RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 3, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ /* bit0 :UTP/Fiber auto detect function enable or not, cfg_dis_det=1:disable ++ bit3:Force UTP/Fiber auto detect function enable or not, cfg_force_auto-detect=1 */ ++ if ((retVal = rtl8367c_setAsicReg(0x13eb, 0x15bb)) != RT_ERR_OK) ++ return retVal; ++ ++ /*bit3: Serdes force mode:cfg_sds_frc_mode=1 ++ bit[2:0]: Serdes chip mode, cfg_sds_mode=3b'100 (force sds FIB1G mode) */ ++ if ((retVal = rtl8367c_setAsicReg(0x13e7, 0xc)) != RT_ERR_OK) ++ return retVal; ++ ++ ++ /*bit5: cfg_mac6_fib=1 & bit7: cfg_mac6_fib2=1*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 5, 1)) != RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 7, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ /*cfg_mac6_sel_hsgmii=0*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d11, 11, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ /*cfg_mac6_sel_sgmii= 1*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d11, 6, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ /* bit[12:8]: Only valid when cfg_sds_mode_sel_new=1 ++ new_cfg_sds_mode=0x4 */ ++ if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x4)) != RT_ERR_OK) ++ return retVal; ++ } ++ else if(mode == EXT_100FX) ++ { ++ /* 0 2 0 bit 8~9 set 0, force n-way*/ ++ if((retVal = rtl8367c_getAsicSdsReg(0, 2, 0, ®_data)) != RT_ERR_OK) ++ return retVal; ++ reg_data &= 0xFFFFFCFF; ++ if((retVal = rtl8367c_setAsicSdsReg(0,2,0, reg_data)) != RT_ERR_OK) ++ return retVal; ++ ++ /* disable mac6 mode_ext1 mode*/ ++ if ((retVal = rtl8367c_getAsicRegBit(0x1d3d, 10, ®_data)) != RT_ERR_OK) ++ return retVal; ++ if(reg_data == 0) ++ { ++ if ((retVal = rtl8367c_setAsicRegBits(0x1305, 0xf0, 0)) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ if ((retVal = rtl8367c_setAsicRegBit(0x3f7, 1, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicReg(0x1d11, 0x1500)) != RT_ERR_OK) ++ return retVal; ++ ++ /*bit13: cfg_sds_mode_sel_new=1 :Enable new sds mode config method ++ bit[1:0]:cfg_mac7_fib= 0 & cfg_mac7_sel_sgmii=0 ++ */ ++ if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x1f)) != RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d95, 13, 1)) != RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 3, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ /* bit0 :UTP/Fiber auto detect function enable or not, cfg_dis_det=1:disable ++ bit3:Force UTP/Fiber auto detect function enable or not, cfg_force_auto-detect=1 */ ++ if ((retVal = rtl8367c_setAsicReg(0x13eb, 0x15bb)) != RT_ERR_OK) ++ return retVal; ++ ++ /*!!!!! cfg_sds_frc_mode=1 & cfg_sds_mode=3b'101 (force sds fib100M mode)*/ ++ if ((retVal = rtl8367c_setAsicReg(0x13e7, 0xc)) != RT_ERR_OK) ++ return retVal; ++ ++ ++ /*bit5: cfg_mac6_fib=1 & bit7: cfg_mac6_fib2=1*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 5, 1)) != RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 7, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ /*cfg_mac6_sel_hsgmii=0*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d11, 11, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ /*cfg_mac6_sel_sgmii= 1*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d11, 6, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ /* bit[12:8]: Only valid when cfg_sds_mode_sel_new=1 ++ new_cfg_sds_mode=0x5 */ ++ if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x5)) != RT_ERR_OK) ++ return retVal; ++ } ++ else if(mode == EXT_1000X_100FX) ++ { ++ /* 0 2 0 bit 8~9 set 0, force n-way*/ ++ if((retVal = rtl8367c_getAsicSdsReg(0, 2, 0, ®_data)) != RT_ERR_OK) ++ return retVal; ++ reg_data &= 0xFFFFFCFF; ++ if((retVal = rtl8367c_setAsicSdsReg(0,2,0, reg_data)) != RT_ERR_OK) ++ return retVal; ++ ++ /* disable mac6 mode_ext1 mode*/ ++ if ((retVal = rtl8367c_getAsicRegBit(0x1d3d, 10, ®_data)) != RT_ERR_OK) ++ return retVal; ++ if(reg_data == 0) ++ { ++ if ((retVal = rtl8367c_setAsicRegBits(0x1305, 0xf0, 0)) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ if ((retVal = rtl8367c_setAsicRegBit(0x3f7, 1, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicReg(0x1d11, 0x1500)) != RT_ERR_OK) ++ return retVal; ++ ++ /*bit13: cfg_sds_mode_sel_new=1 :Enable new sds mode config method ++ bit[1:0]:cfg_mac7_fib= 0 & cfg_mac7_sel_sgmii=0 ++ */ ++ if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x1f)) != RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d95, 13, 0)) != RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 3, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ /* bit0 :UTP/Fiber auto detect function enable or not, cfg_dis_det=1:disable ++ bit3:Force UTP/Fiber auto detect function enable or not, cfg_force_auto-detect=1 */ ++ if ((retVal = rtl8367c_setAsicReg(0x13eb, 0x15bb)) != RT_ERR_OK) ++ return retVal; ++ ++ /*!!!!!! cfg_sds_frc_mode=1 & cfg_sds_mode=3'b111: Fib1G/Fib100M auto detect */ ++ if ((retVal = rtl8367c_setAsicReg(0x13e7, 0xc)) != RT_ERR_OK) ++ return retVal; ++ ++ ++ /*bit5: cfg_mac6_fib=1 & bit7: cfg_mac6_fib2=1*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 5, 1)) != RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 7, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ /*cfg_mac6_sel_hsgmii=0*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d11, 11, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ /*cfg_mac6_sel_sgmii= 1*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d11, 6, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ /* bit[12:8]: Only valid when cfg_sds_mode_sel_new=1 ++ new_cfg_sds_mode=0x7 */ ++ if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x7)) != RT_ERR_OK) ++ return retVal; ++ } ++ else if(mode < EXT_SGMII) ++ { ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d3d, 10, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicRegBit(0x3f7, 1, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ /* keep default setting, disable mac6 sel SerDes mode,*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d11, 11, 0)) != RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d11, 6, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ /*bit5: cfg_mac6_fib=0 & bit7: cfg_mac6_fib2=0*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 5, 0)) != RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 7, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ if (mode < EXT_GMII) ++ { ++ /* set mac6 mode*/ ++ if ((retVal = rtl8367c_setAsicRegBits(0x1305, 0xf0, mode)) != RT_ERR_OK) ++ return retVal; ++ } ++ else if(mode == EXT_RMII_MAC) ++ { ++ /*!!!!!!*/ ++ if ((retVal = rtl8367c_setAsicRegBits(0x1305, 0xf0, 7)) != RT_ERR_OK) ++ return retVal; ++ } ++ else if(mode == EXT_RMII_PHY) ++ { ++ if ((retVal = rtl8367c_setAsicRegBits(0x1305, 0xf0, 8)) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ if ((mode == EXT_TMII_MAC) || (mode == EXT_TMII_PHY)) ++ { ++ if ((retVal = rtl8367c_setAsicRegBit(0x3f7, 1, 1)) != RT_ERR_OK) ++ return retVal; ++ } ++ } ++ ++ } ++ else if (2 == id) ++ { ++ ++ /*force port7 linkdown*/ ++ if ((retVal = rtl8367c_setAsicReg(0x137d, 0x1000)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_getAsicRegBit(0x1d9d, 7, ®_data)) != RT_ERR_OK) ++ return retVal; ++ while(reg_data == 0) ++ { ++ if ((retVal = rtl8367c_getAsicRegBit(0x1d9d, 7, ®_data)) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ if (mode == EXT_SGMII) ++ { ++ /*disable mac7 sel ext2 xMII mode*/ ++ if ((retVal = rtl8367c_setAsicRegBits(0x13c3, 0xf,0)) != RT_ERR_OK) ++ return retVal; ++ ++ /*restore ext2 ability*/ ++ if ((retVal = rtl8367c_setAsicReg(0x13c4, 0)) != RT_ERR_OK) ++ return retVal; ++ /* disable mac7 mode_ext2 */ ++ if ((retVal = rtl8367c_setAsicRegBit(0x3f7, 2, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ /*bit5: cfg_mac6_fib=0 & bit7: cfg_mac6_fib2=0*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 5, 0)) != RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 7, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ /* ++ bit0:cfg_mac7_sel_sgmii=0,MAC7 is not SGMII mode ++ bit1:cfg_mac7_fib= 0 */ ++ if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 3, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ /*cfg_mac6_sel_hsgmii=0*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d11, 11, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ /*cfg_mac6_sel_sgmii= 1*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d11, 6, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ /*Enable new sds mode config method, cfg_sds_mode_sel_new=1*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d95, 13, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ /* bit[12:8]: Only valid when cfg_sds_mode_sel_new=1 ++ new_cfg_sds_mode=0x1F (reset mode) */ ++ if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x1f)) != RT_ERR_OK) ++ return retVal; ++ ++ /*cfg_mac7_sel_sgmii= 1*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d95, 0, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ /* bit[12:8]: Only valid when cfg_sds_mode_sel_new=1 ++ new_cfg_sds_mode=0x2 (SGMII mode)*/ ++ if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x2)) != RT_ERR_OK) ++ return retVal; ++ ++ /*select MAC link source when port6/7 be set sgmii mode (cfg_sgmii_link)*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d95, 2, 0)) != RT_ERR_OK) ++ return retVal; ++ } ++ else if (mode == EXT_1000X) ++ { ++ /* disable mac7 MII/TMM/RMII/GMII/RGMII mode, mode_ext2 = disable */ ++ if ((retVal = rtl8367c_setAsicRegBits(0x13c3, 0xf, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ /*restore ext2 ability*/ ++ if ((retVal = rtl8367c_setAsicReg(0x13c4, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ /* 0 2 0 bit 8~9 set 0, force n-way*/ ++ if((retVal = rtl8367c_getAsicSdsReg(0, 2, 0, ®_data)) != RT_ERR_OK) ++ return retVal; ++ reg_data &= 0xFFFFFCFF; ++ if((retVal = rtl8367c_setAsicSdsReg(0,2,0, reg_data)) != RT_ERR_OK) ++ return retVal; ++ ++ /*restore ext2 ability*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x3f7, 2, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ /* keep default setting, disable mac6 sel serdes*/ ++ if ((retVal = rtl8367c_setAsicReg(0x1d11, 0x1500)) != RT_ERR_OK) ++ return retVal; ++ ++ /*Enable new sds mode config method, cfg_sds_mode_sel_new=1*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d95, 13, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ /* bit[12:8]: Only valid when cfg_sds_mode_sel_new=1 ++ new_cfg_sds_mode=0x1F (reset mode) */ ++ if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x1f)) != RT_ERR_OK) ++ return retVal; ++ ++ /*bit5: cfg_mac6_fib=0 & bit7: cfg_mac6_fib2=0*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 5, 0)) != RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 7, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ /*cfg_mac7_sel_sgmii= 1 & cfg_mac7_fib=1*/ ++ if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 3, 3)) != RT_ERR_OK) ++ return retVal; ++ ++ /*new_cfg_sds_mode=0x4 (FIB1000 mode)*/ ++ if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x4)) != RT_ERR_OK) ++ return retVal; ++ ++ } ++ else if (mode == EXT_100FX) ++ { ++ /* disable mac7 MII/TMM/RMII/GMII/RGMII mode, mode_ext2 = disable */ ++ if ((retVal = rtl8367c_setAsicRegBits(0x13c3, 0xf, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ /*restore ext2 ability*/ ++ if ((retVal = rtl8367c_setAsicReg(0x13c4, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ /* 0 2 0 bit 8~9 set 0, force n-way*/ ++ if((retVal = rtl8367c_getAsicSdsReg(0, 2, 0, ®_data)) != RT_ERR_OK) ++ return retVal; ++ reg_data &= 0xFFFFFCFF; ++ if((retVal = rtl8367c_setAsicSdsReg(0,2,0, reg_data)) != RT_ERR_OK) ++ return retVal; ++ ++ /*restore ext2 ability*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x3f7, 2, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ /* keep default setting, disable mac6 sel serdes*/ ++ if ((retVal = rtl8367c_setAsicReg(0x1d11, 0x1500)) != RT_ERR_OK) ++ return retVal; ++ ++ /*Enable new sds mode config method, cfg_sds_mode_sel_new=1*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d95, 13, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ /* bit[12:8]: Only valid when cfg_sds_mode_sel_new=1 ++ new_cfg_sds_mode=0x1F (reset mode) */ ++ if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x1f)) != RT_ERR_OK) ++ return retVal; ++ ++ /*bit5: cfg_mac6_fib=0 & bit7: cfg_mac6_fib2=0*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 5, 0)) != RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 7, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ /*cfg_mac7_sel_sgmii= 1 & cfg_mac7_fib=1*/ ++ if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 3, 3)) != RT_ERR_OK) ++ return retVal; ++ ++ /* bit[12:8]: Only valid when cfg_sds_mode_sel_new=1 ++ new_cfg_sds_mode=0x5 */ ++ if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x5)) != RT_ERR_OK) ++ return retVal; ++ } ++ else if (mode == EXT_1000X_100FX) ++ { ++ /* disable mac7 MII/TMM/RMII/GMII/RGMII mode, mode_ext2 = disable */ ++ if ((retVal = rtl8367c_setAsicRegBits(0x13c3, 0xf, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ /*restore ext2 ability*/ ++ if ((retVal = rtl8367c_setAsicReg(0x13c4, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ /* 0 2 0 bit 8~9 set 0, force n-way*/ ++ if((retVal = rtl8367c_getAsicSdsReg(0, 2, 0, ®_data)) != RT_ERR_OK) ++ return retVal; ++ reg_data &= 0xFFFFFCFF; ++ if((retVal = rtl8367c_setAsicSdsReg(0,2,0, reg_data)) != RT_ERR_OK) ++ return retVal; ++ ++ /*restore ext2 ability*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x3f7, 2, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ /* keep default setting, disable mac6 sel serdes*/ ++ if ((retVal = rtl8367c_setAsicReg(0x1d11, 0x1500)) != RT_ERR_OK) ++ return retVal; ++ ++ /*Enable new sds mode config method, cfg_sds_mode_sel_new=1*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d95, 13, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ /* bit[12:8]: Only valid when cfg_sds_mode_sel_new=1 ++ new_cfg_sds_mode=0x1F (reset mode) */ ++ if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x1f)) != RT_ERR_OK) ++ return retVal; ++ ++ /*bit5: cfg_mac6_fib=0 & bit7: cfg_mac6_fib2=0*/ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 5, 0)) != RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 7, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ /*cfg_mac7_sel_sgmii= 1 & cfg_mac7_fib=1*/ ++ if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 3, 3)) != RT_ERR_OK) ++ return retVal; ++ ++ /* bit[12:8]: Only valid when cfg_sds_mode_sel_new=1 ++ new_cfg_sds_mode=0x7 */ ++ if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x7)) != RT_ERR_OK) ++ return retVal; ++ } ++ else if (mode < EXT_SGMII) ++ { ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d3d, 10, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicRegBit(0x3f7, 2, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ /* keep default setting, disable mac7 sel SerDes mode*/ ++ if ((retVal = rtl8367c_setAsicReg(0x1d95, 0x1f00)) != RT_ERR_OK) ++ return retVal; ++ ++ /*cfg_mac7_sel_sgmii= 0 & cfg_mac7_fib=0*/ ++ if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 3, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ /* set port7 mode*/ ++ if ((retVal = rtl8367c_setAsicRegBits(0x13c3, 0xf, mode)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((mode == EXT_TMII_MAC) || (mode == EXT_TMII_PHY)) ++ { ++ if ((retVal = rtl8367c_setAsicRegBit(0x3f7, 2, 1)) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ } ++ else if ((mode < EXT_END) && (mode > EXT_100FX)) ++ { ++ if ((retVal = rtl8367c_setAsicRegBits(0x13C3, 0xf, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicRegBit(0x3f7, 2, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ /*cfg_mac7_sel_sgmii= 0 & cfg_mac7_fib=0*/ ++ if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 3, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d3d, 10, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_getAsicRegBit(0x1d11, 11, ®_data)) != RT_ERR_OK) ++ return retVal; ++ if(reg_data == 0) ++ { ++ if ((retVal = rtl8367c_setAsicRegBit(0x1d11, 6, 1)) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ /* set port7 mode*/ ++ if (mode < EXT_RMII_MAC_2) ++ { ++ if ((retVal = rtl8367c_setAsicRegBits(0x1305, 0xf0, (mode-13))) != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ { ++ if ((retVal = rtl8367c_setAsicRegBits(0x1305, 0xf0, (mode-12))) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ if ((mode == EXT_TMII_MAC_2) || (mode == EXT_TMII_PHY_2)) ++ { ++ if ((retVal = rtl8367c_setAsicRegBit(0x3f7, 2, 1)) != RT_ERR_OK) ++ return retVal; ++ } ++ } ++ ++ } ++ ++ } ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_getAsicPortExtMode ++ * Description: ++ * Get external interface mode configuration ++ * Input: ++ * id - external interface id (0~1) ++ * pMode - external interface mode ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - input parameter out of range ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicPortExtMode(rtk_uint32 id, rtk_uint32 *pMode) ++{ ++ ret_t retVal; ++ rtk_uint32 regData, regValue, type; ++ ++ if(id >= RTL8367C_EXTNO) ++ return RT_ERR_OUT_OF_RANGE; ++ /*cfg_magic_id & get chip_id*/ ++ if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0249)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_getAsicReg(0x1300, ®Value)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0000)) != RT_ERR_OK) ++ return retVal; ++ ++ type = 0; ++ ++ switch (regValue) ++ { ++ case 0x0276: ++ case 0x0597: ++ case 0x6367: ++ type = 1; ++ break; ++ case 0x0652: ++ case 0x6368: ++ type = 2; ++ break; ++ case 0x0801: ++ case 0x6511: ++ type = 3; ++ break; ++ default: ++ return RT_ERR_FAILED; ++ } ++ ++ ++ if (1 == type) ++ { ++ ++ if (1 == id) ++ { ++ if( (retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_MAC8_SEL_SGMII_OFFSET, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ if(1 == regData) ++ { ++ *pMode = EXT_SGMII; ++ return RT_ERR_OK; ++ } ++ ++ if( (retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_MAC8_SEL_HSGMII_OFFSET, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ if(1 == regData) ++ { ++ *pMode = EXT_HSGMII; ++ return RT_ERR_OK; ++ } ++ } ++ ++ if(0 == id || 1 == id) ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_DIGITAL_INTERFACE_SELECT, RTL8367C_SELECT_GMII_0_MASK << (id * RTL8367C_SELECT_GMII_1_OFFSET), pMode); ++ else ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_DIGITAL_INTERFACE_SELECT_1, RTL8367C_SELECT_GMII_2_MASK, pMode); ++ ++ } ++ else if (2 == type) ++ { ++ if (1 == id) ++ { ++ if ((retVal = rtl8367c_getAsicReg(0x1d92, ®Data))!=RT_ERR_OK) ++ return retVal; ++ ++ if (regData & 0x4000) ++ { ++ *pMode = EXT_SGMII; ++ return RT_ERR_OK; ++ } ++ ++ else if (((regData >> 8) & 0x1f) == 4) ++ { ++ *pMode = EXT_1000X; ++ return RT_ERR_OK; ++ } ++ else if (((regData >> 8) & 0x1f) == 5) ++ { ++ *pMode = EXT_100FX; ++ return RT_ERR_OK; ++ } ++ else if (((regData >> 8) & 0x1f) == 7) ++ { ++ *pMode = EXT_1000X_100FX; ++ return RT_ERR_OK; ++ } ++ ++ return rtl8367c_getAsicRegBits(0x1305, 0xf0, pMode); ++ } ++ else if (2 == id) ++ { ++#if 0 ++ if ((retVal = rtl8367c_getAsicRegBit(0x1d92, 6, ®Data))!=RT_ERR_OK) ++ return retVal; ++ ++ if (regData == 1) ++ { ++ *pMode = EXT_SGMII; ++ return RT_ERR_OK; ++ } ++ ++ if ((retVal = rtl8367c_getAsicRegBit(0x1d92, 7, ®Data))!=RT_ERR_OK) ++ return retVal; ++ ++ if (regData == 1) ++ { ++ *pMode = EXT_HSGMII; ++ return RT_ERR_OK; ++ } ++#endif ++ if ((retVal = rtl8367c_getAsicReg(0x1d92, ®Data))!=RT_ERR_OK) ++ return retVal; ++ ++ if (regData & 0x40) ++ { ++ *pMode = EXT_SGMII; ++ return RT_ERR_OK; ++ } ++ else if (regData & 0x80) ++ { ++ *pMode = EXT_HSGMII; ++ return RT_ERR_OK; ++ } ++ else if ((regData & 0x1f) == 4) ++ { ++ *pMode = EXT_1000X; ++ return RT_ERR_OK; ++ } ++ else if ((regData & 0x1f) == 5) ++ { ++ *pMode = EXT_100FX; ++ return RT_ERR_OK; ++ } ++ else if ((regData & 0x1f) == 7) ++ { ++ *pMode = EXT_1000X_100FX; ++ return RT_ERR_OK; ++ } ++ ++ return rtl8367c_getAsicRegBits(0x1305, 0xf, pMode); ++ } ++ } ++ else if(3 == type) ++ { ++ if (1 == id) ++ { ++ /* SDS_CFG_NEW */ ++ if ((retVal = rtl8367c_getAsicReg(0x1d95, ®Data))!=RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_getAsicReg(0x1d41, ®Value))!=RT_ERR_OK) ++ return retVal; ++ ++ /* bit5: cfg_mac6_fib=1 && bit7: cfg_mac6_fib2 =1 */ ++ if((regValue & 0xa0) == 0xa0 ) ++ { ++ /* new_cfg_sds_mode */ ++ regData = regData >> 8; ++ if((regData & 0x1f) == 4) ++ { ++ *pMode = EXT_1000X; ++ return RT_ERR_OK; ++ } ++ else if((regData & 0x1f) == 5) ++ { ++ *pMode = EXT_100FX; ++ return RT_ERR_OK; ++ } ++ else if((regData & 0x1f) == 7) ++ { ++ *pMode = EXT_1000X_100FX; ++ return RT_ERR_OK; ++ } ++ ++ } ++ ++ ++ if ((retVal = rtl8367c_getAsicReg(0x1d11, ®Data))!=RT_ERR_OK) ++ return retVal; ++ ++ /* check cfg_mac6_sel_sgmii */ ++ if((regData >> 6) & 1) ++ { ++ *pMode = EXT_SGMII; ++ return RT_ERR_OK; ++ } ++ else if((regData >> 11) & 1) ++ { ++ *pMode = EXT_HSGMII; ++ return RT_ERR_OK; ++ } ++ else ++ { ++ /* check port6 MAC mode */ ++ if ((retVal = rtl8367c_getAsicRegBits(0x1305, 0xf0, ®Data))!=RT_ERR_OK) ++ return retVal; ++ ++ if(regData < 6) ++ *pMode = regData; ++ else if(regData == 6) ++ *pMode = EXT_RMII_MAC; ++ else if(regData == 7) ++ *pMode = EXT_RMII_PHY; ++ ++ return RT_ERR_OK; ++ } ++ } ++ else if (2 == id) ++ { ++ if ((retVal = rtl8367c_getAsicReg(0x1d95, ®Data))!=RT_ERR_OK) ++ return retVal; ++ ++ /* bit0: cfg_mac7_sel_sgmii ++ bit1: cfg_mac7_fib ++ bit[12:8]: new_cfg_sds_mode*/ ++ if(((regData & 0x3) == 3) && (((regData >> 8) & 0x1f) == 0x4)) ++ { ++ *pMode = EXT_1000X; ++ return RT_ERR_OK; ++ } ++ else if (((regData & 0x3) == 3) && (((regData >> 8) & 0x1f) == 0x5)) ++ { ++ *pMode = EXT_100FX; ++ return RT_ERR_OK; ++ } ++ else if (((regData & 0x3) == 3) && (((regData >> 8) & 0x1f) == 0x7)) ++ { ++ *pMode = EXT_1000X_100FX; ++ return RT_ERR_OK; ++ } ++ else if(regData & 1) ++ { ++ *pMode = EXT_SGMII; ++ return RT_ERR_OK; ++ } ++ else ++ { ++ /* check port7 MAC mode */ ++ if ((retVal = rtl8367c_getAsicRegBits(0x13c3, 0xf, ®Data))!=RT_ERR_OK) ++ return retVal; ++ ++ *pMode = regData; ++ ++ return RT_ERR_OK; ++ } ++ } ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8370_setAsicPortEnableAll ++ * Description: ++ * Set ALL ports enable. ++ * Input: ++ * enable - enable all ports. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicPortEnableAll(rtk_uint32 enable) ++{ ++ if(enable >= 2) ++ return RT_ERR_INPUT; ++ ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_PHY_AD, RTL8367C_PDNPHY_OFFSET, !enable); ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicPortEnableAll ++ * Description: ++ * Set ALL ports enable. ++ * Input: ++ * enable - enable all ports. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicPortEnableAll(rtk_uint32 *pEnable) ++{ ++ ret_t retVal; ++ rtk_uint32 regData; ++ ++ retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_PHY_AD, RTL8367C_PDNPHY_OFFSET, ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ if (regData==0) ++ *pEnable = 1; ++ else ++ *pEnable = 0; ++ ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_setAsicPortSmallIpg ++ * Description: ++ * Set small ipg egress mode ++ * Input: ++ * port - Physical port number (0~7) ++ * enable - 0: normal, 1: small ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicPortSmallIpg(rtk_uint32 port, rtk_uint32 enable) ++{ ++ if(port >= RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ return rtl8367c_setAsicRegBit(RTL8367C_PORT_SMALL_IPG_REG(port), RTL8367C_PORT0_MISC_CFG_SMALL_TAG_IPG_OFFSET, enable); ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicPortSmallIpg ++ * Description: ++ * Get small ipg egress mode ++ * Input: ++ * port - Physical port number (0~7) ++ * pEnable - 0: normal, 1: small ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicPortSmallIpg(rtk_uint32 port, rtk_uint32* pEnable) ++{ ++ if(port >= RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ return rtl8367c_getAsicRegBit(RTL8367C_PORT_SMALL_IPG_REG(port), RTL8367C_PORT0_MISC_CFG_SMALL_TAG_IPG_OFFSET, pEnable); ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicPortLoopback ++ * Description: ++ * Set MAC loopback ++ * Input: ++ * port - Physical port number (0~7) ++ * enable - 0: Disable, 1: enable ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicPortLoopback(rtk_uint32 port, rtk_uint32 enable) ++{ ++ if(port >= RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ return rtl8367c_setAsicRegBit(RTL8367C_PORT_MISC_CFG_REG(port), RTL8367C_PORT0_MISC_CFG_MAC_LOOPBACK_OFFSET, enable); ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicPortLoopback ++ * Description: ++ * Set MAC loopback ++ * Input: ++ * port - Physical port number (0~7) ++ * Output: ++ * pEnable - 0: Disable, 1: enable ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicPortLoopback(rtk_uint32 port, rtk_uint32 *pEnable) ++{ ++ if(port >= RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ return rtl8367c_getAsicRegBit(RTL8367C_PORT_MISC_CFG_REG(port), RTL8367C_PORT0_MISC_CFG_MAC_LOOPBACK_OFFSET, pEnable); ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicPortRTCTEnable ++ * Description: ++ * Set RTCT Enable echo response mode ++ * Input: ++ * portmask - Port mask of RTCT enabled (0-4) ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_MASK - Invalid port mask ++ * Note: ++ * RTCT test takes 4.8 seconds at most. ++ */ ++ret_t rtl8367c_setAsicPortRTCTEnable(rtk_uint32 portmask) ++{ ++ ret_t retVal; ++ rtk_uint32 regData; ++ rtk_uint32 port; ++ ++ if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0249)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_getAsicReg(0x1300, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ if( (regData == 0x0276) || (regData == 0x0597) ) ++ return RT_ERR_CHIP_NOT_SUPPORTED; ++ ++ for(port = 0; port <= 10 ; port++) ++ { ++ if(portmask & (0x0001 << port)) ++ { ++ if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa422, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ regData &= 0x7FFF; ++ if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa422, regData)) != RT_ERR_OK) ++ return retVal; ++ ++ regData |= 0x00F2;/*RTCT set to echo response mode*/ ++ if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa422, regData)) != RT_ERR_OK) ++ return retVal; ++ ++ regData |= 0x0001; ++ if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa422, regData)) != RT_ERR_OK) ++ return retVal; ++ } ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicPortRTCTDisable ++ * Description: ++ * Set RTCT Disable ++ * Input: ++ * portmask - Port mask of RTCT enabled (0-4) ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_MASK - Invalid port mask ++ * Note: ++ * RTCT test takes 4.8 seconds at most. ++ */ ++ret_t rtl8367c_setAsicPortRTCTDisable(rtk_uint32 portmask) ++{ ++ ret_t retVal; ++ rtk_uint32 regData; ++ rtk_uint32 port; ++ ++ if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0249)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_getAsicReg(0x1300, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ if( (regData == 0x0276) || (regData == 0x0597) ) ++ return RT_ERR_CHIP_NOT_SUPPORTED; ++ ++ for(port = 0; port <= 10 ; port++) ++ { ++ if(portmask & (0x0001 << port)) ++ { ++ if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa422, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ regData &= 0x7FFF; ++ if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa422, regData)) != RT_ERR_OK) ++ return retVal; ++ ++ regData |= 0x00F0; ++ if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa422, regData)) != RT_ERR_OK) ++ return retVal; ++ ++ regData &= ~0x0001; ++ if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa422, regData)) != RT_ERR_OK) ++ return retVal; ++ } ++ } ++ ++ return RT_ERR_OK; ++} ++ ++ ++/* Function Name: ++ * rtl8367c_getAsicPortRTCTResult ++ * Description: ++ * Get RTCT result ++ * Input: ++ * port - Port ID of RTCT result ++ * Output: ++ * pResult - The result of port ID ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_MASK - Invalid port mask ++ * RT_ERR_PHY_RTCT_NOT_FINISH - RTCT test doesn't finish. ++ * Note: ++ * RTCT test takes 4.8 seconds at most. ++ * If this API returns RT_ERR_PHY_RTCT_NOT_FINISH, ++ * users should wait a whole then read it again. ++ */ ++ret_t rtl8367c_getAsicPortRTCTResult(rtk_uint32 port, rtl8367c_port_rtct_result_t *pResult) ++{ ++ ret_t retVal; ++ rtk_uint32 regData, finish = 1; ++ ++ if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0249)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_getAsicReg(0x1300, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ if( (regData == 0x6367) ) ++ { ++ if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa422, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ if((regData & 0x8000) == 0x8000) ++ { ++ /* Channel A */ ++ if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x802a)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ pResult->channelAOpen = (regData == 0x0048) ? 1 : 0; ++ pResult->channelAShort = (regData == 0x0050) ? 1 : 0; ++ pResult->channelAMismatch = ((regData == 0x0042) || (regData == 0x0044)) ? 1 : 0; ++ pResult->channelALinedriver = (regData == 0x0041) ? 1 : 0; ++ ++ /* Channel B */ ++ if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x802e)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ pResult->channelBOpen = (regData == 0x0048) ? 1 : 0; ++ pResult->channelBShort = (regData == 0x0050) ? 1 : 0; ++ pResult->channelBMismatch = ((regData == 0x0042) || (regData == 0x0044)) ? 1 : 0; ++ pResult->channelBLinedriver = (regData == 0x0041) ? 1 : 0; ++ ++ /* Channel C */ ++ if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x8032)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ pResult->channelCOpen = (regData == 0x0048) ? 1 : 0; ++ pResult->channelCShort = (regData == 0x0050) ? 1 : 0; ++ pResult->channelCMismatch = ((regData == 0x0042) || (regData == 0x0044)) ? 1 : 0; ++ pResult->channelCLinedriver = (regData == 0x0041) ? 1 : 0; ++ ++ /* Channel D */ ++ if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x8036)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ pResult->channelDOpen = (regData == 0x0048) ? 1 : 0; ++ pResult->channelDShort = (regData == 0x0050) ? 1 : 0; ++ pResult->channelDMismatch = ((regData == 0x0042) || (regData == 0x0044)) ? 1 : 0; ++ pResult->channelDLinedriver = (regData == 0x0041) ? 1 : 0; ++ ++ /* Channel A Length */ ++ if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x802c)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ pResult->channelALen = (regData / 2); ++ ++ /* Channel B Length */ ++ if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x8030)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ pResult->channelBLen = (regData / 2); ++ ++ /* Channel C Length */ ++ if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x8034)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ pResult->channelCLen = (regData / 2); ++ ++ /* Channel D Length */ ++ if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x8038)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ pResult->channelDLen = (regData / 2); ++ } ++ else ++ finish = 0; ++ } ++ else if(regData == 0x6368) ++ { ++ if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa422, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ if((regData & 0x8000) == 0x8000) ++ { ++ /* Channel A */ ++ if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x802b)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ pResult->channelAOpen = (regData == 0x0048) ? 1 : 0; ++ pResult->channelAShort = (regData == 0x0050) ? 1 : 0; ++ pResult->channelAMismatch = ((regData == 0x0042) || (regData == 0x0044)) ? 1 : 0; ++ pResult->channelALinedriver = (regData == 0x0041) ? 1 : 0; ++ ++ /* Channel B */ ++ if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x802f)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ pResult->channelBOpen = (regData == 0x0048) ? 1 : 0; ++ pResult->channelBShort = (regData == 0x0050) ? 1 : 0; ++ pResult->channelBMismatch = ((regData == 0x0042) || (regData == 0x0044)) ? 1 : 0; ++ pResult->channelBLinedriver = (regData == 0x0041) ? 1 : 0; ++ ++ /* Channel C */ ++ if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x8033)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ pResult->channelCOpen = (regData == 0x0048) ? 1 : 0; ++ pResult->channelCShort = (regData == 0x0050) ? 1 : 0; ++ pResult->channelCMismatch = ((regData == 0x0042) || (regData == 0x0044)) ? 1 : 0; ++ pResult->channelCLinedriver = (regData == 0x0041) ? 1 : 0; ++ ++ /* Channel D */ ++ if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x8037)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ pResult->channelDOpen = (regData == 0x0048) ? 1 : 0; ++ pResult->channelDShort = (regData == 0x0050) ? 1 : 0; ++ pResult->channelDMismatch = ((regData == 0x0042) || (regData == 0x0044)) ? 1 : 0; ++ pResult->channelDLinedriver = (regData == 0x0041) ? 1 : 0; ++ ++ /* Channel A Length */ ++ if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x802d)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ pResult->channelALen = (regData / 2); ++ ++ /* Channel B Length */ ++ if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x8031)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ pResult->channelBLen = (regData / 2); ++ ++ /* Channel C Length */ ++ if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x8035)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ pResult->channelCLen = (regData / 2); ++ ++ /* Channel D Length */ ++ if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x8039)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ pResult->channelDLen = (regData / 2); ++ } ++ else ++ finish = 0; ++ ++ } ++ else if((regData == 0x6511) || (regData == 0x0801)) ++ { ++ if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa422, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ if((regData & 0x8000) == 0x8000) ++ { ++ /* Channel A */ ++ if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x802a)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ pResult->channelAOpen = (regData == 0x0048) ? 1 : 0; ++ pResult->channelAShort = (regData == 0x0050) ? 1 : 0; ++ pResult->channelAMismatch = ((regData == 0x0042) || (regData == 0x0044)) ? 1 : 0; ++ pResult->channelALinedriver = (regData == 0x0041) ? 1 : 0; ++ ++ /* Channel B */ ++ if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x802e)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ pResult->channelBOpen = (regData == 0x0048) ? 1 : 0; ++ pResult->channelBShort = (regData == 0x0050) ? 1 : 0; ++ pResult->channelBMismatch = ((regData == 0x0042) || (regData == 0x0044)) ? 1 : 0; ++ pResult->channelBLinedriver = (regData == 0x0041) ? 1 : 0; ++ ++ /* Channel C */ ++ if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x8032)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ pResult->channelCOpen = (regData == 0x0048) ? 1 : 0; ++ pResult->channelCShort = (regData == 0x0050) ? 1 : 0; ++ pResult->channelCMismatch = ((regData == 0x0042) || (regData == 0x0044)) ? 1 : 0; ++ pResult->channelCLinedriver = (regData == 0x0041) ? 1 : 0; ++ ++ /* Channel D */ ++ if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x8036)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ pResult->channelDOpen = (regData == 0x0048) ? 1 : 0; ++ pResult->channelDShort = (regData == 0x0050) ? 1 : 0; ++ pResult->channelDMismatch = ((regData == 0x0042) || (regData == 0x0044)) ? 1 : 0; ++ pResult->channelDLinedriver = (regData == 0x0041) ? 1 : 0; ++ ++ /* Channel A Length */ ++ if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x802c)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ pResult->channelALen = (regData / 2); ++ ++ /* Channel B Length */ ++ if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x8030)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ pResult->channelBLen = (regData / 2); ++ ++ /* Channel C Length */ ++ if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x8034)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ pResult->channelCLen = (regData / 2); ++ ++ /* Channel D Length */ ++ if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x8038)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ pResult->channelDLen = (regData / 2); ++ } ++ else ++ finish = 0; ++ ++ } ++ else ++ return RT_ERR_CHIP_NOT_SUPPORTED; ++ ++ if(finish == 0) ++ return RT_ERR_PHY_RTCT_NOT_FINISH; ++ else ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_sdsReset ++ * Description: ++ * Reset Serdes ++ * Input: ++ * id - EXT ID ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None. ++ */ ++ret_t rtl8367c_sdsReset(rtk_uint32 id) ++{ ++ rtk_uint32 retVal, regValue, state, i, option, running = 0, retVal2; ++ ++ if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0249)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_getAsicReg(0x1300, ®Value)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0000)) != RT_ERR_OK) ++ return retVal; ++ ++ switch (regValue) ++ { ++ case 0x0276: ++ case 0x0597: ++ case 0x6367: ++ option = 0; ++ break; ++ case 0x0652: ++ case 0x6368: ++ option = 1; ++ break; ++ case 0x0801: ++ case 0x6511: ++ option = 2; ++ break; ++ default: ++ return RT_ERR_FAILED; ++ } ++ ++ if(option == 0) ++ { ++ if (1 == id) ++ { ++ if ((retVal = rtl8367c_getAsicRegBit(0x130c, 5, &running))!=RT_ERR_OK) ++ return retVal; ++ ++ if(running == 1) ++ { ++ if ((retVal = rtl8367c_setAsicRegBit(0x130c, 5, 0))!=RT_ERR_OK) ++ return retVal; ++ } ++ ++ retVal = rtl8367c_setAsicReg(0x6601, 0x0000); ++ ++ if(retVal == RT_ERR_OK) ++ retVal = rtl8367c_setAsicReg(0x6602, 0x1401); ++ ++ if(retVal == RT_ERR_OK) ++ retVal = rtl8367c_setAsicReg(0x6600, 0x00C0); ++ ++ if(retVal == RT_ERR_OK) ++ retVal = rtl8367c_setAsicReg(0x6601, 0x0000); ++ ++ if(retVal == RT_ERR_OK) ++ retVal = rtl8367c_setAsicReg(0x6602, 0x1403); ++ ++ if(retVal == RT_ERR_OK) ++ retVal = rtl8367c_setAsicReg(0x6600, 0x00C0); ++ ++ if(running == 1) ++ { ++ if ((retVal2 = rtl8367c_setAsicRegBit(0x130c, 5, 1))!=RT_ERR_OK) ++ return retVal2; ++ } ++ ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ return RT_ERR_PORT_ID; ++ } ++ else if(option == 1) ++ { ++ if (1 == id) ++ { ++ if((retVal = rtl8367c_getAsicReg(0x1311, &state)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicReg(0x1311, 0x66)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicReg(0x1311, 0x1066)) != RT_ERR_OK) ++ return retVal; ++ ++ while(1) ++ { ++ if((retVal = rtl8367c_getAsicReg(0x1d9d, ®Value)) != RT_ERR_OK) ++ return retVal; ++ if((regValue >> 8) & 1) ++ break; ++ } ++ ++ for (i=0; i<0xffff; i++); ++ ++ if((retVal = rtl8367c_setAsicReg(0x133d, 0x2)) != RT_ERR_OK) ++ return retVal; ++ ++ for (i=0; i<0xffff; i++); ++ ++ if((retVal = rtl8367c_setAsicReg(0x6601, 0x0)) != RT_ERR_OK) ++ return retVal; ++ if((retVal = rtl8367c_setAsicReg(0x6602, 0x1401)) != RT_ERR_OK) ++ return retVal; ++ if((retVal = rtl8367c_setAsicReg(0x6600, 0xc1)) != RT_ERR_OK) ++ return retVal; ++ if((retVal = rtl8367c_setAsicReg(0x6601, 0x0)) != RT_ERR_OK) ++ return retVal; ++ if((retVal = rtl8367c_setAsicReg(0x6602, 0x1403)) != RT_ERR_OK) ++ return retVal; ++ if((retVal = rtl8367c_setAsicReg(0x6600, 0xc1)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicReg(0x133d, 0x0)) != RT_ERR_OK) ++ return retVal; ++ ++ for (i=0; i<0xffff; i++); ++ ++ if((retVal = rtl8367c_setAsicReg(0x1311, state)) != RT_ERR_OK) ++ return retVal; ++ ++ ++ } ++ else if (2== id) ++ { ++ if((retVal = rtl8367c_getAsicReg(0x13c4, &state)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicReg(0x13c4, 0x66)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicReg(0x13c4, 0x1066)) != RT_ERR_OK) ++ return retVal; ++ ++ while(1) ++ { ++ if((retVal = rtl8367c_getAsicReg(0x1d9d, ®Value)) != RT_ERR_OK) ++ return retVal; ++ if((regValue >> 9) & 1) ++ break; ++ } ++ ++ for (i=0; i<0xffff; i++); ++ ++ if((retVal = rtl8367c_setAsicReg(0x133d, 0x2)) != RT_ERR_OK) ++ return retVal; ++ ++ for (i=0; i<0xffff; i++); ++ ++ if((retVal = rtl8367c_setAsicReg(0x6601, 0x0)) != RT_ERR_OK) ++ return retVal; ++ if((retVal = rtl8367c_setAsicReg(0x6602, 0x1401)) != RT_ERR_OK) ++ return retVal; ++ if((retVal = rtl8367c_setAsicReg(0x6600, 0xc0)) != RT_ERR_OK) ++ return retVal; ++ if((retVal = rtl8367c_setAsicReg(0x6601, 0x0)) != RT_ERR_OK) ++ return retVal; ++ if((retVal = rtl8367c_setAsicReg(0x6602, 0x1403)) != RT_ERR_OK) ++ return retVal; ++ if((retVal = rtl8367c_setAsicReg(0x6600, 0xc0)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicReg(0x133d, 0x0)) != RT_ERR_OK) ++ return retVal; ++ ++ for (i=0; i<0xffff; i++); ++ ++ if((retVal = rtl8367c_setAsicReg(0x13c4, state)) != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ return RT_ERR_PORT_ID; ++ } ++ else if(option == 2) ++ { ++ if ((retVal = rtl8367c_getAsicSdsReg(0, 3, 0, ®Value))!=RT_ERR_OK) ++ return retVal; ++ regValue |= 0x40; ++ if ((retVal = rtl8367c_setAsicSdsReg(0, 3, 0, regValue))!=RT_ERR_OK) ++ return retVal; ++ ++ for (i=0; i<0xffff; i++); ++ ++ regValue &= ~(0x40); ++ if ((retVal = rtl8367c_setAsicSdsReg(0, 3, 0, regValue))!=RT_ERR_OK) ++ return retVal; ++ ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_getSdsLinkStatus ++ * Description: ++ * Get SGMII status ++ * Input: ++ * id - EXT ID ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None. ++ */ ++ret_t rtl8367c_getSdsLinkStatus(rtk_uint32 ext_id, rtk_uint32 *pSignalDetect, rtk_uint32 *pSync, rtk_uint32 *pLink) ++{ ++ rtk_uint32 retVal, regValue, type, running = 0, retVal2; ++ ++ ++ if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0249)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_getAsicReg(0x1300, ®Value)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0000)) != RT_ERR_OK) ++ return retVal; ++ ++ switch (regValue) ++ { ++ case 0x0276: ++ case 0x0597: ++ case 0x6367: ++ type = 0; ++ break; ++ case 0x0652: ++ case 0x6368: ++ type = 1; ++ break; ++ case 0x0801: ++ case 0x6511: ++ type = 2; ++ break; ++ default: ++ return RT_ERR_FAILED; ++ } ++ ++ if(type == 0) ++ { ++ if (1 == ext_id) ++ { ++ if ((retVal = rtl8367c_getAsicRegBit(0x130c, 5, &running))!=RT_ERR_OK) ++ return retVal; ++ ++ if(running == 1) ++ { ++ if ((retVal = rtl8367c_setAsicRegBit(0x130c, 5, 0))!=RT_ERR_OK) ++ return retVal; ++ } ++ ++ retVal = rtl8367c_setAsicReg(0x6601, 0x003D); ++ ++ if(retVal == RT_ERR_OK) ++ retVal = rtl8367c_setAsicReg(0x6600, 0x0080); ++ ++ if(retVal == RT_ERR_OK) ++ retVal = rtl8367c_getAsicReg(0x6602, ®Value); ++ ++ if(running == 1) ++ { ++ if ((retVal2 = rtl8367c_setAsicRegBit(0x130c, 5, 1))!=RT_ERR_OK) ++ return retVal2; ++ } ++ ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ *pSignalDetect = (regValue & 0x0100) ? 1 : 0; ++ *pSync = (regValue & 0x0001) ? 1 : 0; ++ *pLink = (regValue & 0x0010) ? 1 : 0; ++ } ++ else ++ return RT_ERR_PORT_ID; ++ } ++ else if(type == 1) ++ { ++ if (1 == ext_id) ++ { ++ if ((retVal = rtl8367c_setAsicReg(0x6601, 0x003D))!=RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicReg(0x6600, 0x0081))!=RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_getAsicReg(0x6602, ®Value))!=RT_ERR_OK) ++ return retVal; ++ ++ *pSignalDetect = (regValue & 0x0100) ? 1 : 0; ++ *pSync = (regValue & 0x0001) ? 1 : 0; ++ *pLink = (regValue & 0x0010) ? 1 : 0; ++ } ++ else if (2 == ext_id) ++ { ++ if ((retVal = rtl8367c_setAsicReg(0x6601, 0x003D))!=RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicReg(0x6600, 0x0080))!=RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_getAsicReg(0x6602, ®Value))!=RT_ERR_OK) ++ return retVal; ++ ++ *pSignalDetect = (regValue & 0x0100) ? 1 : 0; ++ *pSync = (regValue & 0x0001) ? 1 : 0; ++ *pLink = (regValue & 0x0010) ? 1 : 0; ++ } ++ else ++ return RT_ERR_PORT_ID; ++ } ++ else if(type == 2) ++ { ++ if((retVal = rtl8367c_getAsicSdsReg(0, 30, 1, ®Value)) != RT_ERR_OK) ++ return retVal; ++ if((retVal = rtl8367c_getAsicSdsReg(0, 30, 1, ®Value)) != RT_ERR_OK) ++ return retVal; ++ ++ *pSignalDetect = (regValue & 0x0100) ? 1 : 0; ++ *pSync = (regValue & 0x0001) ? 1 : 0; ++ *pLink = (regValue & 0x0010) ? 1 : 0; ++ ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_setSgmiiNway ++ * Description: ++ * Set SGMII Nway ++ * Input: ++ * ext_id - EXT ID ++ * state - SGMII Nway state ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None. ++ */ ++ret_t rtl8367c_setSgmiiNway(rtk_uint32 ext_id, rtk_uint32 state) ++{ ++ rtk_uint32 retVal, regValue, type, running = 0, retVal2; ++ ++ if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0249)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_getAsicReg(0x1300, ®Value)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0000)) != RT_ERR_OK) ++ return retVal; ++ ++ switch (regValue) ++ { ++ case 0x0276: ++ case 0x0597: ++ case 0x6367: ++ type = 0; ++ break; ++ case 0x0652: ++ case 0x6368: ++ type = 1; ++ break; ++ case 0x0801: ++ case 0x6511: ++ type = 2; ++ break; ++ default: ++ return RT_ERR_FAILED; ++ } ++ ++ if(type == 0) ++ { ++ if (1 == ext_id) ++ { ++ if ((retVal = rtl8367c_getAsicRegBit(0x130c, 5, &running))!=RT_ERR_OK) ++ return retVal; ++ ++ if(running == 1) ++ { ++ if ((retVal = rtl8367c_setAsicRegBit(0x130c, 5, 0))!=RT_ERR_OK) ++ return retVal; ++ } ++ ++ retVal = rtl8367c_setAsicReg(0x6601, 0x0002); ++ ++ if(retVal == RT_ERR_OK) ++ retVal = rtl8367c_setAsicReg(0x6600, 0x0080); ++ ++ if(retVal == RT_ERR_OK) ++ retVal = rtl8367c_getAsicReg(0x6602, ®Value); ++ ++ if(retVal == RT_ERR_OK) ++ { ++ if(state) ++ regValue |= 0x0200; ++ else ++ regValue &= ~0x0200; ++ ++ regValue |= 0x0100; ++ } ++ ++ if(retVal == RT_ERR_OK) ++ retVal = rtl8367c_setAsicReg(0x6602, regValue); ++ ++ if(retVal == RT_ERR_OK) ++ retVal = rtl8367c_setAsicReg(0x6601, 0x0002); ++ ++ if(retVal == RT_ERR_OK) ++ retVal = rtl8367c_setAsicReg(0x6600, 0x00C0); ++ ++ if(running == 1) ++ { ++ if ((retVal2 = rtl8367c_setAsicRegBit(0x130c, 5, 1))!=RT_ERR_OK) ++ return retVal2; ++ } ++ ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ return RT_ERR_PORT_ID; ++ } ++ else if(type == 1) ++ { ++ if (1 == ext_id) ++ { ++ if ((retVal = rtl8367c_setAsicReg(0x6601, 0x0002))!=RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicReg(0x6600, 0x0081))!=RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_getAsicReg(0x6602, ®Value))!=RT_ERR_OK) ++ return retVal; ++ ++ if(state) ++ regValue |= 0x0200; ++ else ++ regValue &= ~0x0200; ++ ++ regValue |= 0x0100; ++ ++ if ((retVal = rtl8367c_setAsicReg(0x6602, regValue))!=RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicReg(0x6601, 0x0002))!=RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicReg(0x6600, 0x00C1))!=RT_ERR_OK) ++ return retVal; ++ } ++ else if (2 == ext_id) ++ { ++ if ((retVal = rtl8367c_setAsicReg(0x6601, 0x0002))!=RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicReg(0x6600, 0x0080))!=RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_getAsicReg(0x6602, ®Value))!=RT_ERR_OK) ++ return retVal; ++ ++ if(state) ++ regValue |= 0x0200; ++ else ++ regValue &= ~0x0200; ++ ++ regValue |= 0x0100; ++ ++ if ((retVal = rtl8367c_setAsicReg(0x6602, regValue))!=RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicReg(0x6601, 0x0002))!=RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicReg(0x6600, 0x00C0))!=RT_ERR_OK) ++ return retVal; ++ } ++ else ++ return RT_ERR_PORT_ID; ++ } ++ else if(type == 2) ++ { ++ if ((retVal = rtl8367c_getAsicSdsReg(0, 2, 0, ®Value))!=RT_ERR_OK) ++ return retVal; ++ ++ if(state & 1) ++ regValue &= ~0x100; ++ else ++ regValue |= 0x100; ++ ++ if ((retVal = rtl8367c_setAsicSdsReg(0, 2, 0, regValue))!=RT_ERR_OK) ++ return retVal; ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_getSgmiiNway ++ * Description: ++ * Get SGMII Nway ++ * Input: ++ * ext_id - EXT ID ++ * state - SGMII Nway state ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None. ++ */ ++ret_t rtl8367c_getSgmiiNway(rtk_uint32 ext_id, rtk_uint32 *pState) ++{ ++ rtk_uint32 retVal, regValue, type, running = 0, retVal2; ++ ++ if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0249)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_getAsicReg(0x1300, ®Value)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0000)) != RT_ERR_OK) ++ return retVal; ++ ++ switch (regValue) ++ { ++ case 0x0276: ++ case 0x0597: ++ case 0x6367: ++ type = 0; ++ break; ++ case 0x0652: ++ case 0x6368: ++ type = 1; ++ break; ++ case 0x0801: ++ case 0x6511: ++ type = 2; ++ break; ++ default: ++ return RT_ERR_FAILED; ++ } ++ ++ if(type == 0) ++ { ++ if (1 == ext_id) ++ { ++ if ((retVal = rtl8367c_getAsicRegBit(0x130c, 5, &running))!=RT_ERR_OK) ++ return retVal; ++ ++ if(running == 1) ++ { ++ if ((retVal = rtl8367c_setAsicRegBit(0x130c, 5, 0))!=RT_ERR_OK) ++ return retVal; ++ } ++ ++ retVal = rtl8367c_setAsicReg(0x6601, 0x0002); ++ ++ if(retVal == RT_ERR_OK) ++ retVal = rtl8367c_setAsicReg(0x6600, 0x0080); ++ ++ if(retVal == RT_ERR_OK) ++ retVal = rtl8367c_getAsicReg(0x6602, ®Value); ++ ++ if(running == 1) ++ { ++ if ((retVal2 = rtl8367c_setAsicRegBit(0x130c, 5, 1))!=RT_ERR_OK) ++ return retVal2; ++ } ++ ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ if(regValue & 0x0200) ++ *pState = 1; ++ else ++ *pState = 0; ++ } ++ else ++ return RT_ERR_PORT_ID; ++ } ++ else if(type == 1) ++ { ++ if (1 == ext_id) ++ { ++ if ((retVal = rtl8367c_setAsicReg(0x6601, 0x0002))!=RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicReg(0x6600, 0x0081))!=RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_getAsicReg(0x6602, ®Value))!=RT_ERR_OK) ++ return retVal; ++ ++ if(regValue & 0x0200) ++ *pState = 1; ++ else ++ *pState = 0; ++ } ++ else if (2 == ext_id) ++ { ++ if ((retVal = rtl8367c_setAsicReg(0x6601, 0x0002))!=RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicReg(0x6600, 0x0080))!=RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_getAsicReg(0x6602, ®Value))!=RT_ERR_OK) ++ return retVal; ++ ++ if(regValue & 0x0200) ++ *pState = 1; ++ else ++ *pState = 0; ++ } ++ else ++ return RT_ERR_PORT_ID; ++ } ++ else if(type == 2) ++ { ++ if ((retVal = rtl8367c_getAsicSdsReg(0, 2, 0, ®Value))!=RT_ERR_OK) ++ return retVal; ++ ++ if(regValue & 0x100) ++ *pState = 0; ++ else ++ *pState = 1; ++ } ++ ++ return RT_ERR_OK; ++} +diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_portIsolation.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_portIsolation.c +new file mode 100644 +index 000000000000..e0b9db4bfbeb +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_portIsolation.c +@@ -0,0 +1,119 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : Port isolation related functions ++ * ++ */ ++ ++#include ++/* Function Name: ++ * rtl8367c_setAsicPortIsolationPermittedPortmask ++ * Description: ++ * Set permitted port isolation portmask ++ * Input: ++ * port - Physical port number (0~10) ++ * permitPortmask - port mask ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * RT_ERR_PORT_MASK - Invalid portmask ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicPortIsolationPermittedPortmask(rtk_uint32 port, rtk_uint32 permitPortmask) ++{ ++ if(port >= RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ if( permitPortmask > RTL8367C_PORTMASK) ++ return RT_ERR_PORT_MASK; ++ ++ return rtl8367c_setAsicReg(RTL8367C_PORT_ISOLATION_PORT_MASK_REG(port), permitPortmask); ++} ++/* Function Name: ++ * rtl8367c_getAsicPortIsolationPermittedPortmask ++ * Description: ++ * Get permitted port isolation portmask ++ * Input: ++ * port - Physical port number (0~10) ++ * pPermitPortmask - port mask ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicPortIsolationPermittedPortmask(rtk_uint32 port, rtk_uint32 *pPermitPortmask) ++{ ++ if(port >= RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ return rtl8367c_getAsicReg(RTL8367C_PORT_ISOLATION_PORT_MASK_REG(port), pPermitPortmask); ++} ++/* Function Name: ++ * rtl8367c_setAsicPortIsolationEfid ++ * Description: ++ * Set port isolation EFID ++ * Input: ++ * port - Physical port number (0~10) ++ * efid - EFID (0~7) ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * RT_ERR_OUT_OF_RANGE - Input parameter out of range ++ * Note: ++ * EFID is used in individual learning in filtering database ++ */ ++ret_t rtl8367c_setAsicPortIsolationEfid(rtk_uint32 port, rtk_uint32 efid) ++{ ++ if(port >= RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ if( efid > RTL8367C_EFIDMAX) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ return rtl8367c_setAsicRegBits(RTL8367C_PORT_EFID_REG(port), RTL8367C_PORT_EFID_MASK(port), efid); ++} ++/* Function Name: ++ * rtl8367c_getAsicPortIsolationEfid ++ * Description: ++ * Get port isolation EFID ++ * Input: ++ * port - Physical port number (0~10) ++ * pEfid - EFID (0~7) ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicPortIsolationEfid(rtk_uint32 port, rtk_uint32 *pEfid) ++{ ++ if(port >= RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ return rtl8367c_getAsicRegBits(RTL8367C_PORT_EFID_REG(port), RTL8367C_PORT_EFID_MASK(port), pEfid); ++} ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_qos.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_qos.c +new file mode 100644 +index 000000000000..69081049e336 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_qos.c +@@ -0,0 +1,778 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : QoS related functions ++ * ++ */ ++ ++#include ++/* Function Name: ++ * rtl8367c_setAsicPriorityDot1qRemapping ++ * Description: ++ * Set 802.1Q absolutely priority ++ * Input: ++ * srcpriority - Priority value ++ * priority - Absolute priority value ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_QOS_INT_PRIORITY - Invalid priority ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicPriorityDot1qRemapping(rtk_uint32 srcpriority, rtk_uint32 priority ) ++{ ++ if((srcpriority > RTL8367C_PRIMAX) || (priority > RTL8367C_PRIMAX)) ++ return RT_ERR_QOS_INT_PRIORITY; ++ ++ return rtl8367c_setAsicRegBits(RTL8367C_QOS_1Q_PRIORITY_REMAPPING_REG(srcpriority), RTL8367C_QOS_1Q_PRIORITY_REMAPPING_MASK(srcpriority),priority); ++} ++/* Function Name: ++ * rtl8367c_getAsicPriorityDot1qRemapping ++ * Description: ++ * Get 802.1Q absolutely priority ++ * Input: ++ * srcpriority - Priority value ++ * pPriority - Absolute priority value ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicPriorityDot1qRemapping(rtk_uint32 srcpriority, rtk_uint32 *pPriority ) ++{ ++ if(srcpriority > RTL8367C_PRIMAX ) ++ return RT_ERR_QOS_INT_PRIORITY; ++ ++ return rtl8367c_getAsicRegBits(RTL8367C_QOS_1Q_PRIORITY_REMAPPING_REG(srcpriority), RTL8367C_QOS_1Q_PRIORITY_REMAPPING_MASK(srcpriority), pPriority); ++} ++/* Function Name: ++ * rtl8367c_setAsicPriorityPortBased ++ * Description: ++ * Set port based priority ++ * Input: ++ * port - Physical port number (0~7) ++ * priority - Priority value ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * RT_ERR_QOS_INT_PRIORITY - Invalid priority ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicPriorityPortBased(rtk_uint32 port, rtk_uint32 priority ) ++{ ++ ret_t retVal; ++ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ if(priority > RTL8367C_PRIMAX ) ++ return RT_ERR_QOS_INT_PRIORITY; ++ ++ if(port < 8) ++ { ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_QOS_PORTBASED_PRIORITY_REG(port), RTL8367C_QOS_PORTBASED_PRIORITY_MASK(port), priority); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ { ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_QOS_PORTBASED_PRIORITY_CTRL2, 0x7 << ((port - 8) << 2), priority); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_getAsicPriorityPortBased ++ * Description: ++ * Get port based priority ++ * Input: ++ * port - Physical port number (0~7) ++ * pPriority - Priority value ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicPriorityPortBased(rtk_uint32 port, rtk_uint32 *pPriority ) ++{ ++ ret_t retVal; ++ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ if(port < 8) ++ { ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_QOS_PORTBASED_PRIORITY_REG(port), RTL8367C_QOS_PORTBASED_PRIORITY_MASK(port), pPriority); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ { ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_QOS_PORTBASED_PRIORITY_CTRL2, 0x7 << ((port - 8) << 2), pPriority); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_setAsicPriorityDscpBased ++ * Description: ++ * Set DSCP-based priority ++ * Input: ++ * dscp - DSCP value ++ * priority - Priority value ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_QOS_DSCP_VALUE - Invalid DSCP value ++ * RT_ERR_QOS_INT_PRIORITY - Invalid priority ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicPriorityDscpBased(rtk_uint32 dscp, rtk_uint32 priority ) ++{ ++ if(priority > RTL8367C_PRIMAX ) ++ return RT_ERR_QOS_INT_PRIORITY; ++ ++ if(dscp > RTL8367C_DSCPMAX) ++ return RT_ERR_QOS_DSCP_VALUE; ++ ++ return rtl8367c_setAsicRegBits(RTL8367C_QOS_DSCP_TO_PRIORITY_REG(dscp), RTL8367C_QOS_DSCP_TO_PRIORITY_MASK(dscp), priority); ++} ++/* Function Name: ++ * rtl8367c_getAsicPriorityDscpBased ++ * Description: ++ * Get DSCP-based priority ++ * Input: ++ * dscp - DSCP value ++ * pPriority - Priority value ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_QOS_INT_PRIORITY - Invalid priority ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicPriorityDscpBased(rtk_uint32 dscp, rtk_uint32 *pPriority ) ++{ ++ if(dscp > RTL8367C_DSCPMAX) ++ return RT_ERR_QOS_DSCP_VALUE; ++ ++ return rtl8367c_getAsicRegBits(RTL8367C_QOS_DSCP_TO_PRIORITY_REG(dscp), RTL8367C_QOS_DSCP_TO_PRIORITY_MASK(dscp), pPriority); ++} ++/* Function Name: ++ * rtl8367c_setAsicPriorityDecision ++ * Description: ++ * Set priority decision table ++ * Input: ++ * prisrc - Priority decision source ++ * decisionPri - Decision priority assignment ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_QOS_INT_PRIORITY - Invalid priority ++ * RT_ERR_QOS_SEL_PRI_SOURCE - Invalid priority decision source parameter ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicPriorityDecision(rtk_uint32 index, rtk_uint32 prisrc, rtk_uint32 decisionPri) ++{ ++ ret_t retVal; ++ ++ if(index >= PRIDEC_IDX_END ) ++ return RT_ERR_ENTRY_INDEX; ++ ++ if(prisrc >= PRIDEC_END ) ++ return RT_ERR_QOS_SEL_PRI_SOURCE; ++ ++ if(decisionPri > RTL8367C_DECISIONPRIMAX ) ++ return RT_ERR_QOS_INT_PRIORITY; ++ ++ switch(index) ++ { ++ case PRIDEC_IDX0: ++ if((retVal = rtl8367c_setAsicRegBits(RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_REG(prisrc), RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_MASK(prisrc), decisionPri))!= RT_ERR_OK) ++ return retVal; ++ break; ++ case PRIDEC_IDX1: ++ if((retVal = rtl8367c_setAsicRegBits(RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_REG(prisrc), RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_MASK(prisrc), decisionPri))!= RT_ERR_OK) ++ return retVal; ++ break; ++ default: ++ break; ++ }; ++ ++ return RT_ERR_OK; ++ ++ ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicPriorityDecision ++ * Description: ++ * Get priority decision table ++ * Input: ++ * prisrc - Priority decision source ++ * pDecisionPri - Decision priority assignment ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_QOS_SEL_PRI_SOURCE - Invalid priority decision source parameter ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicPriorityDecision(rtk_uint32 index, rtk_uint32 prisrc, rtk_uint32* pDecisionPri) ++{ ++ ret_t retVal; ++ ++ if(index >= PRIDEC_IDX_END ) ++ return RT_ERR_ENTRY_INDEX; ++ ++ if(prisrc >= PRIDEC_END ) ++ return RT_ERR_QOS_SEL_PRI_SOURCE; ++ ++ switch(index) ++ { ++ case PRIDEC_IDX0: ++ if((retVal = rtl8367c_getAsicRegBits(RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_REG(prisrc), RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_MASK(prisrc), pDecisionPri))!= RT_ERR_OK) ++ return retVal; ++ break; ++ case PRIDEC_IDX1: ++ if((retVal = rtl8367c_getAsicRegBits(RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_REG(prisrc), RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_MASK(prisrc), pDecisionPri))!= RT_ERR_OK) ++ return retVal; ++ break; ++ default: ++ break; ++ }; ++ ++ return RT_ERR_OK; ++ ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicPortPriorityDecisionIndex ++ * Description: ++ * Set priority decision index for each port ++ * Input: ++ * port - Physical port number (0~7) ++ * index - Table index ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * RT_ERR_QUEUE_NUM - Invalid queue number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicPortPriorityDecisionIndex(rtk_uint32 port, rtk_uint32 index ) ++{ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ if(index >= PRIDEC_IDX_END) ++ return RT_ERR_ENTRY_INDEX; ++ ++ return rtl8367c_setAsicRegBit(RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_IDX_CTRL, port, index); ++} ++/* Function Name: ++ * rtl8367c_getAsicPortPriorityDecisionIndex ++ * Description: ++ * Get priority decision index for each port ++ * Input: ++ * port - Physical port number (0~7) ++ * pIndex - Table index ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicPortPriorityDecisionIndex(rtk_uint32 port, rtk_uint32 *pIndex ) ++{ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ return rtl8367c_getAsicRegBit(RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_IDX_CTRL, port, pIndex); ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicOutputQueueMappingIndex ++ * Description: ++ * Set output queue number for each port ++ * Input: ++ * port - Physical port number (0~7) ++ * index - Mapping table index ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * RT_ERR_QUEUE_NUM - Invalid queue number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicOutputQueueMappingIndex(rtk_uint32 port, rtk_uint32 index ) ++{ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ if(index >= RTL8367C_QUEUENO) ++ return RT_ERR_QUEUE_NUM; ++ ++ return rtl8367c_setAsicRegBits(RTL8367C_QOS_PORT_QUEUE_NUMBER_REG(port), RTL8367C_QOS_PORT_QUEUE_NUMBER_MASK(port), index); ++} ++/* Function Name: ++ * rtl8367c_getAsicOutputQueueMappingIndex ++ * Description: ++ * Get output queue number for each port ++ * Input: ++ * port - Physical port number (0~7) ++ * pIndex - Mapping table index ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicOutputQueueMappingIndex(rtk_uint32 port, rtk_uint32 *pIndex ) ++{ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ return rtl8367c_getAsicRegBits(RTL8367C_QOS_PORT_QUEUE_NUMBER_REG(port), RTL8367C_QOS_PORT_QUEUE_NUMBER_MASK(port), pIndex); ++} ++/* Function Name: ++ * rtl8367c_setAsicPriorityToQIDMappingTable ++ * Description: ++ * Set priority to QID mapping table parameters ++ * Input: ++ * index - Mapping table index ++ * priority - The priority value ++ * qid - Queue id ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_QUEUE_ID - Invalid queue id ++ * RT_ERR_QUEUE_NUM - Invalid queue number ++ * RT_ERR_QOS_INT_PRIORITY - Invalid priority ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicPriorityToQIDMappingTable(rtk_uint32 index, rtk_uint32 priority, rtk_uint32 qid ) ++{ ++ if(index >= RTL8367C_QUEUENO) ++ return RT_ERR_QUEUE_NUM; ++ ++ if(priority > RTL8367C_PRIMAX) ++ return RT_ERR_QOS_INT_PRIORITY; ++ ++ if(qid > RTL8367C_QIDMAX) ++ return RT_ERR_QUEUE_ID; ++ ++ return rtl8367c_setAsicRegBits(RTL8367C_QOS_1Q_PRIORITY_TO_QID_REG(index, priority), RTL8367C_QOS_1Q_PRIORITY_TO_QID_MASK(priority), qid); ++} ++/* Function Name: ++ * rtl8367c_getAsicPriorityToQIDMappingTable ++ * Description: ++ * Get priority to QID mapping table parameters ++ * Input: ++ * index - Mapping table index ++ * priority - The priority value ++ * pQid - Queue id ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_QUEUE_NUM - Invalid queue number ++ * RT_ERR_QOS_INT_PRIORITY - Invalid priority ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicPriorityToQIDMappingTable(rtk_uint32 index, rtk_uint32 priority, rtk_uint32* pQid) ++{ ++ if(index >= RTL8367C_QUEUENO) ++ return RT_ERR_QUEUE_NUM; ++ ++ if(priority > RTL8367C_PRIMAX) ++ return RT_ERR_QOS_INT_PRIORITY; ++ ++ return rtl8367c_getAsicRegBits(RTL8367C_QOS_1Q_PRIORITY_TO_QID_REG(index, priority), RTL8367C_QOS_1Q_PRIORITY_TO_QID_MASK(priority), pQid); ++} ++/* Function Name: ++ * rtl8367c_setAsicRemarkingDot1pAbility ++ * Description: ++ * Set 802.1p remarking ability ++ * Input: ++ * port - Physical port number (0~7) ++ * enabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicRemarkingDot1pAbility(rtk_uint32 port, rtk_uint32 enabled) ++{ ++ return rtl8367c_setAsicRegBit(RTL8367C_PORT_MISC_CFG_REG(port), RTL8367C_1QREMARK_ENABLE_OFFSET, enabled); ++} ++/* Function Name: ++ * rtl8367c_getAsicRemarkingDot1pAbility ++ * Description: ++ * Get 802.1p remarking ability ++ * Input: ++ * port - Physical port number (0~7) ++ * pEnabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicRemarkingDot1pAbility(rtk_uint32 port, rtk_uint32* pEnabled) ++{ ++ return rtl8367c_getAsicRegBit(RTL8367C_PORT_MISC_CFG_REG(port), RTL8367C_1QREMARK_ENABLE_OFFSET, pEnabled); ++} ++/* Function Name: ++ * rtl8367c_setAsicRemarkingDot1pParameter ++ * Description: ++ * Set 802.1p remarking parameter ++ * Input: ++ * priority - Priority value ++ * newPriority - New priority value ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_QOS_INT_PRIORITY - Invalid priority ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicRemarkingDot1pParameter(rtk_uint32 priority, rtk_uint32 newPriority ) ++{ ++ if(priority > RTL8367C_PRIMAX || newPriority > RTL8367C_PRIMAX) ++ return RT_ERR_QOS_INT_PRIORITY; ++ ++ return rtl8367c_setAsicRegBits(RTL8367C_QOS_1Q_REMARK_REG(priority), RTL8367C_QOS_1Q_REMARK_MASK(priority), newPriority); ++} ++/* Function Name: ++ * rtl8367c_getAsicRemarkingDot1pParameter ++ * Description: ++ * Get 802.1p remarking parameter ++ * Input: ++ * priority - Priority value ++ * pNewPriority - New priority value ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_QOS_INT_PRIORITY - Invalid priority ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicRemarkingDot1pParameter(rtk_uint32 priority, rtk_uint32 *pNewPriority ) ++{ ++ if(priority > RTL8367C_PRIMAX ) ++ return RT_ERR_QOS_INT_PRIORITY; ++ ++ return rtl8367c_getAsicRegBits(RTL8367C_QOS_1Q_REMARK_REG(priority), RTL8367C_QOS_1Q_REMARK_MASK(priority), pNewPriority); ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicRemarkingDot1pSrc ++ * Description: ++ * Set remarking source of 802.1p remarking. ++ * Input: ++ * type - remarking source ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_NOT_INIT - The module is not initial ++ * RT_ERR_PORT_ID - invalid port id ++ * RT_ERR_INPUT - invalid input parameter ++ ++ * Note: ++ * The API can configure 802.1p remark functionality to map original DSCP value or internal ++ * priority to TX DSCP value. ++ */ ++ret_t rtl8367c_setAsicRemarkingDot1pSrc(rtk_uint32 type) ++{ ++ ++ if(type >= DOT1P_PRISEL_END ) ++ return RT_ERR_QOS_SEL_PRI_SOURCE; ++ ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_RMK_CFG_SEL_CTRL, RTL8367C_RMK_1Q_CFG_SEL_OFFSET, type); ++} ++ ++ ++/* Function Name: ++ * rtl8367c_getAsicRemarkingDot1pSrc ++ * Description: ++ * Get remarking source of 802.1p remarking. ++ * Output: ++ * pType - remarking source ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_NOT_INIT - The module is not initial ++ * RT_ERR_PORT_ID - invalid port id ++ * RT_ERR_INPUT - invalid input parameter ++ * RT_ERR_NULL_POINTER - input parameter may be null pointer ++ ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicRemarkingDot1pSrc(rtk_uint32 *pType) ++{ ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_RMK_CFG_SEL_CTRL, RTL8367C_RMK_1Q_CFG_SEL_OFFSET, pType); ++} ++ ++ ++ ++ ++ ++/* Function Name: ++ * rtl8367c_setAsicRemarkingDscpAbility ++ * Description: ++ * Set DSCP remarking ability ++ * Input: ++ * enabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicRemarkingDscpAbility(rtk_uint32 enabled) ++{ ++ return rtl8367c_setAsicRegBit(RTL8367C_REMARKING_CTRL_REG, RTL8367C_REMARKING_DSCP_ENABLE_OFFSET, enabled); ++} ++/* Function Name: ++ * rtl8367c_getAsicRemarkingDscpAbility ++ * Description: ++ * Get DSCP remarking ability ++ * Input: ++ * enabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicRemarkingDscpAbility(rtk_uint32* pEnabled) ++{ ++ return rtl8367c_getAsicRegBit(RTL8367C_REMARKING_CTRL_REG, RTL8367C_REMARKING_DSCP_ENABLE_OFFSET, pEnabled); ++} ++/* Function Name: ++ * rtl8367c_setAsicRemarkingDscpParameter ++ * Description: ++ * Set DSCP remarking parameter ++ * Input: ++ * priority - Priority value ++ * newDscp - New DSCP value ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_QOS_DSCP_VALUE - Invalid DSCP value ++ * RT_ERR_QOS_INT_PRIORITY - Invalid priority ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicRemarkingDscpParameter(rtk_uint32 priority, rtk_uint32 newDscp ) ++{ ++ if(priority > RTL8367C_PRIMAX ) ++ return RT_ERR_QOS_INT_PRIORITY; ++ ++ if(newDscp > RTL8367C_DSCPMAX) ++ return RT_ERR_QOS_DSCP_VALUE; ++ ++ return rtl8367c_setAsicRegBits(RTL8367C_QOS_DSCP_REMARK_REG(priority), RTL8367C_QOS_DSCP_REMARK_MASK(priority), newDscp); ++} ++/* Function Name: ++ * rtl8367c_getAsicRemarkingDscpParameter ++ * Description: ++ * Get DSCP remarking parameter ++ * Input: ++ * priority - Priority value ++ * pNewDscp - New DSCP value ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_QOS_INT_PRIORITY - Invalid priority ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicRemarkingDscpParameter(rtk_uint32 priority, rtk_uint32* pNewDscp ) ++{ ++ if(priority > RTL8367C_PRIMAX ) ++ return RT_ERR_QOS_INT_PRIORITY; ++ ++ return rtl8367c_getAsicRegBits(RTL8367C_QOS_DSCP_REMARK_REG(priority), RTL8367C_QOS_DSCP_REMARK_MASK(priority), pNewDscp); ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicRemarkingDscpSrc ++ * Description: ++ * Set remarking source of DSCP remarking. ++ * Input: ++ * type - remarking source ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_NOT_INIT - The module is not initial ++ * RT_ERR_PORT_ID - invalid port id ++ * RT_ERR_INPUT - invalid input parameter ++ ++ * Note: ++ * The API can configure DSCP remark functionality to map original DSCP value or internal ++ * priority to TX DSCP value. ++ */ ++ret_t rtl8367c_setAsicRemarkingDscpSrc(rtk_uint32 type) ++{ ++ ++ if(type >= DSCP_PRISEL_END ) ++ return RT_ERR_QOS_SEL_PRI_SOURCE; ++ ++ return rtl8367c_setAsicRegBits(RTL8367C_REG_RMK_CFG_SEL_CTRL, RTL8367C_RMK_DSCP_CFG_SEL_MASK, type); ++} ++ ++ ++/* Function Name: ++ * rtl8367c_getAsicRemarkingDscpSrc ++ * Description: ++ * Get remarking source of DSCP remarking. ++ * Output: ++ * pType - remarking source ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_NOT_INIT - The module is not initial ++ * RT_ERR_PORT_ID - invalid port id ++ * RT_ERR_INPUT - invalid input parameter ++ * RT_ERR_NULL_POINTER - input parameter may be null pointer ++ ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicRemarkingDscpSrc(rtk_uint32 *pType) ++{ ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_RMK_CFG_SEL_CTRL, RTL8367C_RMK_DSCP_CFG_SEL_MASK, pType); ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicRemarkingDscp2Dscp ++ * Description: ++ * Set DSCP to remarked DSCP mapping. ++ * Input: ++ * dscp - DSCP value ++ * rmkDscp - remarked DSCP value ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_UNIT_ID - Invalid unit id ++ * RT_ERR_QOS_DSCP_VALUE - Invalid dscp value ++ * Note: ++ * dscp parameter can be DSCP value or internal priority according to configuration of API ++ * dal_apollomp_qos_dscpRemarkSrcSel_set(), because DSCP remark functionality can map original DSCP ++ * value or internal priority to TX DSCP value. ++ */ ++ret_t rtl8367c_setAsicRemarkingDscp2Dscp(rtk_uint32 dscp, rtk_uint32 rmkDscp) ++{ ++ if((dscp > RTL8367C_DSCPMAX ) || (rmkDscp > RTL8367C_DSCPMAX)) ++ return RT_ERR_QOS_INT_PRIORITY; ++ ++ return rtl8367c_setAsicRegBits(RTL8367C_QOS_DSCP_TO_DSCP_REG(dscp), RTL8367C_QOS_DSCP_TO_DSCP_MASK(dscp), rmkDscp); ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicRemarkingDscp2Dscp ++ * Description: ++ * Get DSCP to remarked DSCP mapping. ++ * Input: ++ * dscp - DSCP value ++ * Output: ++ * pRmkDscp - remarked DSCP value ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_QOS_DSCP_VALUE - Invalid dscp value ++ * RT_ERR_NULL_POINTER - NULL pointer ++ * Note: ++ * None. ++ */ ++ret_t rtl8367c_getAsicRemarkingDscp2Dscp(rtk_uint32 dscp, rtk_uint32 *pRmkDscp) ++{ ++ if(dscp > RTL8367C_DSCPMAX) ++ return RT_ERR_QOS_DSCP_VALUE; ++ ++ return rtl8367c_getAsicRegBits(RTL8367C_QOS_DSCP_TO_DSCP_REG(dscp), RTL8367C_QOS_DSCP_TO_DSCP_MASK(dscp), pRmkDscp); ++ ++} ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_rldp.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_rldp.c +new file mode 100644 +index 000000000000..0309689d39b9 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_rldp.c +@@ -0,0 +1,674 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 42321 $ ++ * $Date: 2013-08-26 13:51:29 +0800 (週一, 26 八月 2013) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : RLDP related functions ++ * ++ */ ++ ++#include ++/* Function Name: ++ * rtl8367c_setAsicRldp ++ * Description: ++ * Set RLDP function enable/disable ++ * Input: ++ * enabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicRldp(rtk_uint32 enabled) ++{ ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_RLDP_CTRL0, RTL8367C_RLDP_ENABLE_OFFSET, enabled); ++} ++/* Function Name: ++ * rtl8367c_getAsicRldp ++ * Description: ++ * Get RLDP function enable/disable ++ * Input: ++ * pEnabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicRldp(rtk_uint32 *pEnabled) ++{ ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_RLDP_CTRL0, RTL8367C_RLDP_ENABLE_OFFSET, pEnabled); ++} ++/* Function Name: ++ * rtl8367c_setAsicRldpEnable8051 ++ * Description: ++ * Set RLDP function handled by ASIC or 8051 ++ * Input: ++ * enabled - 1: enabled 8051, 0: disabled 8051 (RLDP is handled by ASIC) ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicRldpEnable8051(rtk_uint32 enabled) ++{ ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_RLDP_CTRL0, RTL8367C_RLDP_8051_ENABLE_OFFSET, enabled); ++} ++/* Function Name: ++ * rtl8367c_setAsicRldrtl8367c_getAsicRldpEnable8051pEnable8051 ++ * Description: ++ * Get RLDP function handled by ASIC or 8051 ++ * Input: ++ * pEnabled - 1: enabled 8051, 0: disabled 8051 (RLDP is handled by ASIC) ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicRldpEnable8051(rtk_uint32 *pEnabled) ++{ ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_RLDP_CTRL0, RTL8367C_RLDP_8051_ENABLE_OFFSET, pEnabled); ++} ++/* Function Name: ++ * rtl8367c_setAsicRldpCompareRandomNumber ++ * Description: ++ * Set enable compare the random number field and seed field of RLDP frame ++ * Input: ++ * enabled - 1: enabled comparing random number, 0: disabled comparing random number ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicRldpCompareRandomNumber(rtk_uint32 enabled) ++{ ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_RLDP_CTRL0, RTL8367C_RLDP_COMP_ID_OFFSET, enabled); ++} ++/* Function Name: ++ * rtl8367c_getAsicRldpCompareRandomNumber ++ * Description: ++ * Get enable compare the random number field and seed field of RLDP frame ++ * Input: ++ * pEnabled - 1: enabled comparing random number, 0: disabled comparing random number ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicRldpCompareRandomNumber(rtk_uint32 *pEnabled) ++{ ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_RLDP_CTRL0, RTL8367C_RLDP_COMP_ID_OFFSET, pEnabled); ++} ++/* Function Name: ++ * rtl8367c_setAsicRldpIndicatorSource ++ * Description: ++ * Set buzzer and LED source when detecting a loop ++ * Input: ++ * src - 0: ASIC, 1: 8051 ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicRldpIndicatorSource(rtk_uint32 src) ++{ ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_RLDP_CTRL0, RTL8367C_RLDP_INDICATOR_SOURCE_OFFSET, src); ++} ++/* Function Name: ++ * rtl8367c_getAsicRldpIndicatorSource ++ * Description: ++ * Get buzzer and LED source when detecting a loop ++ * Input: ++ * pSrc - 0: ASIC, 1: 8051 ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicRldpIndicatorSource(rtk_uint32 *pSrc) ++{ ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_RLDP_CTRL0, RTL8367C_RLDP_INDICATOR_SOURCE_OFFSET, pSrc); ++} ++/* Function Name: ++ * rtl8367c_setAsicRldpCheckingStatePara ++ * Description: ++ * Set retry count and retry period of checking state ++ * Input: ++ * retryCount - 0~0xFF (times) ++ * retryPeriod - 0~0xFFFF (ms) ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - input parameter out of range ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicRldpCheckingStatePara(rtk_uint32 retryCount, rtk_uint32 retryPeriod) ++{ ++ ret_t retVal; ++ ++ if(retryCount > 0xFF) ++ return RT_ERR_OUT_OF_RANGE; ++ if(retryPeriod > RTL8367C_REGDATAMAX) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_RLDP_RETRY_COUNT_REG, RTL8367C_RLDP_RETRY_COUNT_CHKSTATE_MASK, retryCount); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ return rtl8367c_setAsicReg(RTL8367C_RLDP_RETRY_PERIOD_CHKSTATE_REG, retryPeriod); ++} ++/* Function Name: ++ * rtl8367c_getAsicRldpCheckingStatePara ++ * Description: ++ * Get retry count and retry period of checking state ++ * Input: ++ * pRetryCount - 0~0xFF (times) ++ * pRetryPeriod - 0~0xFFFF (ms) ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - input parameter out of range ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicRldpCheckingStatePara(rtk_uint32 *pRetryCount, rtk_uint32 *pRetryPeriod) ++{ ++ ret_t retVal; ++ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_RLDP_RETRY_COUNT_REG, RTL8367C_RLDP_RETRY_COUNT_CHKSTATE_MASK, pRetryCount); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ return rtl8367c_getAsicReg(RTL8367C_RLDP_RETRY_PERIOD_CHKSTATE_REG, pRetryPeriod); ++} ++/* Function Name: ++ * rtl8367c_setAsicRldpLoopStatePara ++ * Description: ++ * Set retry count and retry period of loop state ++ * Input: ++ * retryCount - 0~0xFF (times) ++ * retryPeriod - 0~0xFFFF (ms) ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - input parameter out of range ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicRldpLoopStatePara(rtk_uint32 retryCount, rtk_uint32 retryPeriod) ++{ ++ ret_t retVal; ++ ++ if(retryCount > 0xFF) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ if(retryPeriod > RTL8367C_REGDATAMAX) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_RLDP_RETRY_COUNT_REG, RTL8367C_RLDP_RETRY_COUNT_LOOPSTATE_MASK, retryCount); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ return rtl8367c_setAsicReg(RTL8367C_RLDP_RETRY_PERIOD_LOOPSTATE_REG, retryPeriod); ++} ++/* Function Name: ++ * rtl8367c_getAsicRldpLoopStatePara ++ * Description: ++ * Get retry count and retry period of loop state ++ * Input: ++ * pRetryCount - 0~0xFF (times) ++ * pRetryPeriod - 0~0xFFFF (ms) ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - input parameter out of range ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicRldpLoopStatePara(rtk_uint32 *pRetryCount, rtk_uint32 *pRetryPeriod) ++{ ++ ret_t retVal; ++ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_RLDP_RETRY_COUNT_REG, RTL8367C_RLDP_RETRY_COUNT_LOOPSTATE_MASK, pRetryCount); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ return rtl8367c_getAsicReg(RTL8367C_RLDP_RETRY_PERIOD_LOOPSTATE_REG, pRetryPeriod); ++} ++/* Function Name: ++ * rtl8367c_setAsicRldpTxPortmask ++ * Description: ++ * Set portmask that send/forward RLDP frame ++ * Input: ++ * portmask - 0~0xFF ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_MASK - Invalid portmask ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicRldpTxPortmask(rtk_uint32 portmask) ++{ ++ if(portmask > RTL8367C_PORTMASK) ++ return RT_ERR_PORT_MASK; ++ ++ return rtl8367c_setAsicReg(RTL8367C_RLDP_TX_PMSK_REG, portmask); ++} ++/* Function Name: ++ * rtl8367c_getAsicRldpTxPortmask ++ * Description: ++ * Get portmask that send/forward RLDP frame ++ * Input: ++ * pPortmask - 0~0xFF ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicRldpTxPortmask(rtk_uint32 *pPortmask) ++{ ++ return rtl8367c_getAsicReg(RTL8367C_RLDP_TX_PMSK_REG, pPortmask); ++} ++/* Function Name: ++ * rtl8367c_setAsicRldpMagicNum ++ * Description: ++ * Set Random seed of RLDP ++ * Input: ++ * seed - MAC ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicRldpMagicNum(ether_addr_t seed) ++{ ++ ret_t retVal; ++ rtk_uint32 regData; ++ rtk_uint16 *accessPtr; ++ rtk_uint32 i; ++ ++ accessPtr = (rtk_uint16*)&seed; ++ ++ for (i = 0; i < 3; i++) ++ { ++ regData = *accessPtr; ++ retVal = rtl8367c_setAsicReg(RTL8367C_RLDP_MAGIC_NUM_REG_BASE + i, regData); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ accessPtr++; ++ } ++ ++ return retVal; ++} ++/* Function Name: ++ * rtl8367c_getAsicRldpMagicNum ++ * Description: ++ * Get Random seed of RLDP ++ * Input: ++ * pSeed - MAC ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicRldpMagicNum(ether_addr_t *pSeed) ++{ ++ ret_t retVal; ++ rtk_uint32 regData; ++ rtk_uint16 *accessPtr; ++ rtk_uint32 i; ++ ++ accessPtr = (rtk_uint16*)pSeed; ++ ++ for(i = 0; i < 3; i++) ++ { ++ retVal = rtl8367c_getAsicReg(RTL8367C_RLDP_MAGIC_NUM_REG_BASE + i, ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ *accessPtr = regData; ++ accessPtr++; ++ } ++ ++ return retVal; ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicRldpLoopedPortmask ++ * Description: ++ * Get looped portmask ++ * Input: ++ * pPortmask - 0~0xFF ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicRldpLoopedPortmask(rtk_uint32 *pPortmask) ++{ ++ return rtl8367c_getAsicReg(RTL8367C_RLDP_LOOP_PMSK_REG, pPortmask); ++} ++/* Function Name: ++ * rtl8367c_getAsicRldpRandomNumber ++ * Description: ++ * Get Random number of RLDP ++ * Input: ++ * pRandNumber - MAC ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicRldpRandomNumber(ether_addr_t *pRandNumber) ++{ ++ ret_t retVal; ++ rtk_uint32 regData; ++ rtk_int16 accessPtr[3]; ++ rtk_uint32 i; ++ ++ for(i = 0; i < 3; i++) ++ { ++ retVal = rtl8367c_getAsicReg(RTL8367C_RLDP_RAND_NUM_REG_BASE+ i, ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ accessPtr[i] = regData; ++ } ++ ++ memcpy(pRandNumber, accessPtr, 6); ++ return retVal; ++} ++/* Function Name: ++ * rtl8367c_getAsicRldpLoopedPortmask ++ * Description: ++ * Get port number of looped pair ++ * Input: ++ * port - Physical port number (0~7) ++ * pLoopedPair - port (0~7) ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicRldpLoopedPortPair(rtk_uint32 port, rtk_uint32 *pLoopedPair) ++{ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ if(port < 8) ++ return rtl8367c_getAsicRegBits(RTL8367C_RLDP_LOOP_PORT_REG(port), RTL8367C_RLDP_LOOP_PORT_MASK(port), pLoopedPair); ++ else ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_RLDP_LOOP_PORT_REG4 + ((port - 8) >> 1), RTL8367C_RLDP_LOOP_PORT_MASK(port), pLoopedPair); ++} ++/* Function Name: ++ * rtl8367c_setAsicRlppTrap8051 ++ * Description: ++ * Set trap RLPP packet to 8051 ++ * Input: ++ * enabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicRlppTrap8051(rtk_uint32 enabled) ++{ ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_RLDP_CTRL0, RTL8367C_RLPP_8051_TRAP_OFFSET, enabled); ++} ++/* Function Name: ++ * rtl8367c_getAsicRlppTrap8051 ++ * Description: ++ * Get trap RLPP packet to 8051 ++ * Input: ++ * pEnabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicRlppTrap8051(rtk_uint32 *pEnabled) ++{ ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_RLDP_CTRL0, RTL8367C_RLPP_8051_TRAP_OFFSET, pEnabled); ++} ++/* Function Name: ++ * rtl8367c_setAsicRldpLeaveLoopedPortmask ++ * Description: ++ * Clear leaved looped portmask ++ * Input: ++ * portmask - 0~0xFF ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicRldpLeaveLoopedPortmask(rtk_uint32 portmask) ++{ ++ return rtl8367c_setAsicReg(RTL8367C_REG_RLDP_RELEASED_INDICATOR, portmask); ++} ++/* Function Name: ++ * rtl8367c_getAsicRldpLeaveLoopedPortmask ++ * Description: ++ * Get leaved looped portmask ++ * Input: ++ * pPortmask - 0~0xFF ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicRldpLeaveLoopedPortmask(rtk_uint32 *pPortmask) ++{ ++ return rtl8367c_getAsicReg(RTL8367C_REG_RLDP_RELEASED_INDICATOR, pPortmask); ++} ++/* Function Name: ++ * rtl8367c_setAsicRldpEnterLoopedPortmask ++ * Description: ++ * Clear enter loop portmask ++ * Input: ++ * portmask - 0~0xFF ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicRldpEnterLoopedPortmask(rtk_uint32 portmask) ++{ ++ return rtl8367c_setAsicReg(RTL8367C_REG_RLDP_LOOPED_INDICATOR, portmask); ++} ++/* Function Name: ++ * rtl8367c_getAsicRldpEnterLoopedPortmask ++ * Description: ++ * Get enter loop portmask ++ * Input: ++ * pPortmask - 0~0xFF ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicRldpEnterLoopedPortmask(rtk_uint32 *pPortmask) ++{ ++ return rtl8367c_getAsicReg(RTL8367C_REG_RLDP_LOOPED_INDICATOR, pPortmask); ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicRldpTriggerMode ++ * Description: ++ * Set trigger RLDP mode ++ * Input: ++ * mode - 1: Periodically, 0: SA moving ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicRldpTriggerMode(rtk_uint32 enabled) ++{ ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_RLDP_CTRL0, RTL8367C_RLDP_TRIGGER_MODE_OFFSET, enabled); ++} ++/* Function Name: ++ * rtl8367c_getAsicRldpTriggerMode ++ * Description: ++ * Get trigger RLDP mode ++ * Input: ++ * pMode - - 1: Periodically, 0: SA moving ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicRldpTriggerMode(rtk_uint32 *pEnabled) ++{ ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_RLDP_CTRL0, RTL8367C_RLDP_TRIGGER_MODE_OFFSET, pEnabled); ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicRldp8051Portmask ++ * Description: ++ * Set 8051/CPU configured looped portmask ++ * Input: ++ * portmask - 0~0xFF ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_MASK - Invalid portmask ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicRldp8051Portmask(rtk_uint32 portmask) ++{ ++ ret_t retVal; ++ if(portmask > RTL8367C_PORTMASK) ++ return RT_ERR_PORT_MASK; ++ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_RLDP_CTRL0_REG,RTL8367C_RLDP_8051_LOOP_PORTMSK_MASK,portmask & 0xff); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_RLDP_CTRL5,RTL8367C_RLDP_CTRL5_MASK,(portmask >> 8) & 7); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_getAsicRldp8051Portmask ++ * Description: ++ * Get 8051/CPU configured looped portmask ++ * Input: ++ * pPortmask - 0~0xFF ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicRldp8051Portmask(rtk_uint32 *pPortmask) ++{ ++ rtk_uint32 tmpPmsk; ++ ret_t retVal; ++ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_RLDP_CTRL0_REG,RTL8367C_RLDP_8051_LOOP_PORTMSK_MASK,&tmpPmsk); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ *pPortmask = tmpPmsk & 0xff; ++ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_RLDP_CTRL5,RTL8367C_RLDP_CTRL5_MASK,&tmpPmsk); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ *pPortmask |= (tmpPmsk & 7) <<8; ++ ++ return RT_ERR_OK; ++} ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_rma.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_rma.c +new file mode 100644 +index 000000000000..f297defa78ac +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_rma.c +@@ -0,0 +1,362 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 64716 $ ++ * $Date: 2015-12-31 16:31:55 +0800 (週四, 31 å二月 2015) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : RMA related functions ++ * ++ */ ++ ++#include ++/* Function Name: ++ * rtl8367c_setAsicRma ++ * Description: ++ * Set reserved multicast address for CPU trapping ++ * Input: ++ * index - reserved multicast LSB byte, 0x00~0x2F is available value ++ * pRmacfg - type of RMA for trapping frame type setting ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_RMA_ADDR - Invalid RMA address index ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicRma(rtk_uint32 index, rtl8367c_rma_t* pRmacfg) ++{ ++ rtk_uint32 regData = 0; ++ ret_t retVal; ++ ++ if(index > RTL8367C_RMAMAX) ++ return RT_ERR_RMA_ADDR; ++ ++ regData |= (pRmacfg->portiso_leaky & 0x0001); ++ regData |= ((pRmacfg->vlan_leaky & 0x0001) << 1); ++ regData |= ((pRmacfg->keep_format & 0x0001) << 2); ++ regData |= ((pRmacfg->trap_priority & 0x0007) << 3); ++ regData |= ((pRmacfg->discard_storm_filter & 0x0001) << 6); ++ regData |= ((pRmacfg->operation & 0x0003) << 7); ++ ++ if( (index >= 0x4 && index <= 0x7) || (index >= 0x9 && index <= 0x0C) || (0x0F == index)) ++ index = 0x04; ++ else if((index >= 0x13 && index <= 0x17) || (0x19 == index) || (index >= 0x1B && index <= 0x1f)) ++ index = 0x13; ++ else if(index >= 0x22 && index <= 0x2F) ++ index = 0x22; ++ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_RMA_CTRL00, RTL8367C_TRAP_PRIORITY_MASK, pRmacfg->trap_priority); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ return rtl8367c_setAsicReg(RTL8367C_REG_RMA_CTRL00+index, regData); ++} ++/* Function Name: ++ * rtl8367c_getAsicRma ++ * Description: ++ * Get reserved multicast address for CPU trapping ++ * Input: ++ * index - reserved multicast LSB byte, 0x00~0x2F is available value ++ * rmacfg - type of RMA for trapping frame type setting ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_RMA_ADDR - Invalid RMA address index ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicRma(rtk_uint32 index, rtl8367c_rma_t* pRmacfg) ++{ ++ ret_t retVal; ++ rtk_uint32 regData; ++ ++ if(index > RTL8367C_RMAMAX) ++ return RT_ERR_RMA_ADDR; ++ ++ if( (index >= 0x4 && index <= 0x7) || (index >= 0x9 && index <= 0x0C) || (0x0F == index)) ++ index = 0x04; ++ else if((index >= 0x13 && index <= 0x17) || (0x19 == index) || (index >= 0x1B && index <= 0x1f)) ++ index = 0x13; ++ else if(index >= 0x22 && index <= 0x2F) ++ index = 0x22; ++ ++ retVal = rtl8367c_getAsicReg(RTL8367C_REG_RMA_CTRL00+index, ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ pRmacfg->operation = ((regData >> 7) & 0x0003); ++ pRmacfg->discard_storm_filter = ((regData >> 6) & 0x0001); ++ pRmacfg->trap_priority = ((regData >> 3) & 0x0007); ++ pRmacfg->keep_format = ((regData >> 2) & 0x0001); ++ pRmacfg->vlan_leaky = ((regData >> 1) & 0x0001); ++ pRmacfg->portiso_leaky = (regData & 0x0001); ++ ++ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_RMA_CTRL00, RTL8367C_TRAP_PRIORITY_MASK, ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ pRmacfg->trap_priority = regData; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicRmaCdp ++ * Description: ++ * Set CDP(Cisco Discovery Protocol) for CPU trapping ++ * Input: ++ * pRmacfg - type of RMA for trapping frame type setting ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_RMA_ADDR - Invalid RMA address index ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicRmaCdp(rtl8367c_rma_t* pRmacfg) ++{ ++ rtk_uint32 regData = 0; ++ ret_t retVal; ++ ++ if(pRmacfg->operation >= RMAOP_END) ++ return RT_ERR_RMA_ACTION; ++ ++ if(pRmacfg->trap_priority > RTL8367C_PRIMAX) ++ return RT_ERR_QOS_INT_PRIORITY; ++ ++ regData |= (pRmacfg->portiso_leaky & 0x0001); ++ regData |= ((pRmacfg->vlan_leaky & 0x0001) << 1); ++ regData |= ((pRmacfg->keep_format & 0x0001) << 2); ++ regData |= ((pRmacfg->trap_priority & 0x0007) << 3); ++ regData |= ((pRmacfg->discard_storm_filter & 0x0001) << 6); ++ regData |= ((pRmacfg->operation & 0x0003) << 7); ++ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_RMA_CTRL00, RTL8367C_TRAP_PRIORITY_MASK, pRmacfg->trap_priority); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ return rtl8367c_setAsicReg(RTL8367C_REG_RMA_CTRL_CDP, regData); ++} ++/* Function Name: ++ * rtl8367c_getAsicRmaCdp ++ * Description: ++ * Get CDP(Cisco Discovery Protocol) for CPU trapping ++ * Input: ++ * None ++ * Output: ++ * pRmacfg - type of RMA for trapping frame type setting ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_RMA_ADDR - Invalid RMA address index ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicRmaCdp(rtl8367c_rma_t* pRmacfg) ++{ ++ ret_t retVal; ++ rtk_uint32 regData; ++ ++ retVal = rtl8367c_getAsicReg(RTL8367C_REG_RMA_CTRL_CDP, ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ pRmacfg->operation = ((regData >> 7) & 0x0003); ++ pRmacfg->discard_storm_filter = ((regData >> 6) & 0x0001); ++ pRmacfg->trap_priority = ((regData >> 3) & 0x0007); ++ pRmacfg->keep_format = ((regData >> 2) & 0x0001); ++ pRmacfg->vlan_leaky = ((regData >> 1) & 0x0001); ++ pRmacfg->portiso_leaky = (regData & 0x0001); ++ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_RMA_CTRL00, RTL8367C_TRAP_PRIORITY_MASK, ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ pRmacfg->trap_priority = regData; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicRmaCsstp ++ * Description: ++ * Set CSSTP(Cisco Shared Spanning Tree Protocol) for CPU trapping ++ * Input: ++ * pRmacfg - type of RMA for trapping frame type setting ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_RMA_ADDR - Invalid RMA address index ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicRmaCsstp(rtl8367c_rma_t* pRmacfg) ++{ ++ rtk_uint32 regData = 0; ++ ret_t retVal; ++ ++ if(pRmacfg->operation >= RMAOP_END) ++ return RT_ERR_RMA_ACTION; ++ ++ if(pRmacfg->trap_priority > RTL8367C_PRIMAX) ++ return RT_ERR_QOS_INT_PRIORITY; ++ ++ regData |= (pRmacfg->portiso_leaky & 0x0001); ++ regData |= ((pRmacfg->vlan_leaky & 0x0001) << 1); ++ regData |= ((pRmacfg->keep_format & 0x0001) << 2); ++ regData |= ((pRmacfg->trap_priority & 0x0007) << 3); ++ regData |= ((pRmacfg->discard_storm_filter & 0x0001) << 6); ++ regData |= ((pRmacfg->operation & 0x0003) << 7); ++ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_RMA_CTRL00, RTL8367C_TRAP_PRIORITY_MASK, pRmacfg->trap_priority); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ return rtl8367c_setAsicReg(RTL8367C_REG_RMA_CTRL_CSSTP, regData); ++} ++/* Function Name: ++ * rtl8367c_getAsicRmaCsstp ++ * Description: ++ * Get CSSTP(Cisco Shared Spanning Tree Protocol) for CPU trapping ++ * Input: ++ * None ++ * Output: ++ * pRmacfg - type of RMA for trapping frame type setting ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_RMA_ADDR - Invalid RMA address index ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicRmaCsstp(rtl8367c_rma_t* pRmacfg) ++{ ++ ret_t retVal; ++ rtk_uint32 regData; ++ ++ retVal = rtl8367c_getAsicReg(RTL8367C_REG_RMA_CTRL_CSSTP, ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ pRmacfg->operation = ((regData >> 7) & 0x0003); ++ pRmacfg->discard_storm_filter = ((regData >> 6) & 0x0001); ++ pRmacfg->trap_priority = ((regData >> 3) & 0x0007); ++ pRmacfg->keep_format = ((regData >> 2) & 0x0001); ++ pRmacfg->vlan_leaky = ((regData >> 1) & 0x0001); ++ pRmacfg->portiso_leaky = (regData & 0x0001); ++ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_RMA_CTRL00, RTL8367C_TRAP_PRIORITY_MASK, ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ pRmacfg->trap_priority = regData; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicRmaLldp ++ * Description: ++ * Set LLDP for CPU trapping ++ * Input: ++ * pRmacfg - type of RMA for trapping frame type setting ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_RMA_ADDR - Invalid RMA address index ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicRmaLldp(rtk_uint32 enabled, rtl8367c_rma_t* pRmacfg) ++{ ++ rtk_uint32 regData = 0; ++ ret_t retVal; ++ ++ if(enabled > 1) ++ return RT_ERR_ENABLE; ++ ++ if(pRmacfg->operation >= RMAOP_END) ++ return RT_ERR_RMA_ACTION; ++ ++ if(pRmacfg->trap_priority > RTL8367C_PRIMAX) ++ return RT_ERR_QOS_INT_PRIORITY; ++ ++ retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_RMA_LLDP_EN, RTL8367C_RMA_LLDP_EN_OFFSET,enabled); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ regData |= (pRmacfg->portiso_leaky & 0x0001); ++ regData |= ((pRmacfg->vlan_leaky & 0x0001) << 1); ++ regData |= ((pRmacfg->keep_format & 0x0001) << 2); ++ regData |= ((pRmacfg->trap_priority & 0x0007) << 3); ++ regData |= ((pRmacfg->discard_storm_filter & 0x0001) << 6); ++ regData |= ((pRmacfg->operation & 0x0003) << 7); ++ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_RMA_CTRL00, RTL8367C_TRAP_PRIORITY_MASK, pRmacfg->trap_priority); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ return rtl8367c_setAsicReg(RTL8367C_REG_RMA_CTRL_LLDP, regData); ++} ++/* Function Name: ++ * rtl8367c_getAsicRmaLldp ++ * Description: ++ * Get LLDP for CPU trapping ++ * Input: ++ * None ++ * Output: ++ * pRmacfg - type of RMA for trapping frame type setting ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_RMA_ADDR - Invalid RMA address index ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicRmaLldp(rtk_uint32 *pEnabled, rtl8367c_rma_t* pRmacfg) ++{ ++ ret_t retVal; ++ rtk_uint32 regData; ++ ++ retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_RMA_LLDP_EN, RTL8367C_RMA_LLDP_EN_OFFSET,pEnabled); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ retVal = rtl8367c_getAsicReg(RTL8367C_REG_RMA_CTRL_LLDP, ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ pRmacfg->operation = ((regData >> 7) & 0x0003); ++ pRmacfg->discard_storm_filter = ((regData >> 6) & 0x0001); ++ pRmacfg->trap_priority = ((regData >> 3) & 0x0007); ++ pRmacfg->keep_format = ((regData >> 2) & 0x0001); ++ pRmacfg->vlan_leaky = ((regData >> 1) & 0x0001); ++ pRmacfg->portiso_leaky = (regData & 0x0001); ++ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_RMA_CTRL00, RTL8367C_TRAP_PRIORITY_MASK, ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ pRmacfg->trap_priority = regData; ++ ++ return RT_ERR_OK; ++} ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_scheduling.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_scheduling.c +new file mode 100644 +index 000000000000..32d9b208408d +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_scheduling.c +@@ -0,0 +1,525 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : Packet Scheduling related functions ++ * ++ */ ++ ++#include ++/* Function Name: ++ * rtl8367c_setAsicLeakyBucketParameter ++ * Description: ++ * Set Leaky Bucket Parameters ++ * Input: ++ * tick - Tick is used for time slot size unit ++ * token - Token is used for adding budget in each time slot ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_TICK - Invalid TICK ++ * RT_ERR_TOKEN - Invalid TOKEN ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicLeakyBucketParameter(rtk_uint32 tick, rtk_uint32 token) ++{ ++ ret_t retVal; ++ ++ if(tick > 0xFF) ++ return RT_ERR_TICK; ++ ++ if(token > 0xFF) ++ return RT_ERR_TOKEN; ++ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_LEAKY_BUCKET_TICK_REG, RTL8367C_LEAKY_BUCKET_TICK_MASK, tick); ++ ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_LEAKY_BUCKET_TOKEN_REG, RTL8367C_LEAKY_BUCKET_TOKEN_MASK, token); ++ ++ return retVal; ++} ++/* Function Name: ++ * rtl8367c_getAsicLeakyBucketParameter ++ * Description: ++ * Get Leaky Bucket Parameters ++ * Input: ++ * tick - Tick is used for time slot size unit ++ * token - Token is used for adding budget in each time slot ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicLeakyBucketParameter(rtk_uint32 *tick, rtk_uint32 *token) ++{ ++ ret_t retVal; ++ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_LEAKY_BUCKET_TICK_REG, RTL8367C_LEAKY_BUCKET_TICK_MASK, tick); ++ ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_LEAKY_BUCKET_TOKEN_REG, RTL8367C_LEAKY_BUCKET_TOKEN_MASK, token); ++ ++ return retVal; ++} ++/* Function Name: ++ * rtl8367c_setAsicAprMeter ++ * Description: ++ * Set per-port per-queue APR shared meter index ++ * Input: ++ * port - Physical port number (0~10) ++ * qid - Queue id ++ * apridx - dedicated shared meter index for APR (0~7) ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * RT_ERR_QUEUE_ID - Invalid queue id ++ * RT_ERR_FILTER_METER_ID - Invalid meter ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicAprMeter(rtk_uint32 port, rtk_uint32 qid, rtk_uint32 apridx) ++{ ++ ret_t retVal; ++ rtk_uint32 regAddr; ++ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ if(qid > RTL8367C_QIDMAX) ++ return RT_ERR_QUEUE_ID; ++ ++ if(apridx > RTL8367C_PORT_QUEUE_METER_INDEX_MAX) ++ return RT_ERR_FILTER_METER_ID; ++ ++ if(port < 8) ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_SCHEDULE_PORT_APR_METER_REG(port, qid), RTL8367C_SCHEDULE_PORT_APR_METER_MASK(qid), apridx); ++ else { ++ regAddr = RTL8367C_REG_SCHEDULE_PORT8_APR_METER_CTRL0 + ((port-8) << 1) + (qid / 5); ++ retVal = rtl8367c_setAsicRegBits(regAddr, RTL8367C_SCHEDULE_PORT_APR_METER_MASK(qid), apridx); ++ } ++ ++ return retVal; ++} ++/* Function Name: ++ * rtl8367c_getAsicAprMeter ++ * Description: ++ * Get per-port per-queue APR shared meter index ++ * Input: ++ * port - Physical port number (0~10) ++ * qid - Queue id ++ * apridx - dedicated shared meter index for APR (0~7) ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * RT_ERR_QUEUE_ID - Invalid queue id ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicAprMeter(rtk_uint32 port, rtk_uint32 qid, rtk_uint32 *apridx) ++{ ++ ret_t retVal; ++ rtk_uint32 regAddr; ++ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ if(qid > RTL8367C_QIDMAX) ++ return RT_ERR_QUEUE_ID; ++ ++ if(port < 8) ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_SCHEDULE_PORT_APR_METER_REG(port, qid), RTL8367C_SCHEDULE_PORT_APR_METER_MASK(qid), apridx); ++ else { ++ regAddr = RTL8367C_REG_SCHEDULE_PORT8_APR_METER_CTRL0 + ((port-8) << 1) + (qid / 5); ++ retVal = rtl8367c_getAsicRegBits(regAddr, RTL8367C_SCHEDULE_PORT_APR_METER_MASK(qid), apridx); ++ } ++ ++ return retVal; ++} ++/* Function Name: ++ * rtl8367c_setAsicAprEnable ++ * Description: ++ * Set per-port APR enable ++ * Input: ++ * port - Physical port number (0~7) ++ * aprEnable - APR enable setting 1:enable 0:disable ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicAprEnable(rtk_uint32 port, rtk_uint32 aprEnable) ++{ ++ ret_t retVal; ++ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ retVal = rtl8367c_setAsicRegBit(RTL8367C_SCHEDULE_APR_CTRL_REG, RTL8367C_SCHEDULE_APR_CTRL_OFFSET(port), aprEnable); ++ ++ return retVal; ++} ++/* Function Name: ++ * rtl8367c_getAsicAprEnable ++ * Description: ++ * Get per-port APR enable ++ * Input: ++ * port - Physical port number (0~7) ++ * aprEnable - APR enable setting 1:enable 0:disable ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicAprEnable(rtk_uint32 port, rtk_uint32 *aprEnable) ++{ ++ ret_t retVal; ++ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ retVal = rtl8367c_getAsicRegBit(RTL8367C_SCHEDULE_APR_CTRL_REG, RTL8367C_SCHEDULE_APR_CTRL_OFFSET(port), aprEnable); ++ ++ return retVal; ++} ++/* Function Name: ++ * rtl8367c_setAsicWFQWeight ++ * Description: ++ * Set weight of a queue ++ * Input: ++ * port - Physical port number (0~10) ++ * qid - The queue ID wanted to set ++ * qWeight - The weight value wanted to set (valid:0~127) ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * RT_ERR_QUEUE_ID - Invalid queue id ++ * RT_ERR_QOS_QUEUE_WEIGHT - Invalid queue weight ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicWFQWeight(rtk_uint32 port, rtk_uint32 qid, rtk_uint32 qWeight) ++{ ++ ret_t retVal; ++ ++ /* Invalid input parameter */ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ if(qid > RTL8367C_QIDMAX) ++ return RT_ERR_QUEUE_ID; ++ ++ if(qWeight > RTL8367C_QWEIGHTMAX && qid > 0) ++ return RT_ERR_QOS_QUEUE_WEIGHT; ++ ++ retVal = rtl8367c_setAsicReg(RTL8367C_SCHEDULE_PORT_QUEUE_WFQ_WEIGHT_REG(port, qid), qWeight); ++ ++ return retVal; ++} ++/* Function Name: ++ * rtl8367c_getAsicWFQWeight ++ * Description: ++ * Get weight of a queue ++ * Input: ++ * port - Physical port number (0~10) ++ * qid - The queue ID wanted to set ++ * qWeight - The weight value wanted to set (valid:0~127) ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * RT_ERR_QUEUE_ID - Invalid queue id ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicWFQWeight(rtk_uint32 port, rtk_uint32 qid, rtk_uint32 *qWeight) ++{ ++ ret_t retVal; ++ ++ ++ /* Invalid input parameter */ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ if(qid > RTL8367C_QIDMAX) ++ return RT_ERR_QUEUE_ID; ++ ++ ++ retVal = rtl8367c_getAsicReg(RTL8367C_SCHEDULE_PORT_QUEUE_WFQ_WEIGHT_REG(port, qid), qWeight); ++ ++ return retVal; ++} ++/* Function Name: ++ * rtl8367c_setAsicWFQBurstSize ++ * Description: ++ * Set WFQ leaky bucket burst size ++ * Input: ++ * burstsize - Leaky bucket burst size, unit byte ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicWFQBurstSize(rtk_uint32 burstsize) ++{ ++ ret_t retVal; ++ ++ retVal = rtl8367c_setAsicReg(RTL8367C_SCHEDULE_WFQ_BURST_SIZE_REG, burstsize); ++ ++ return retVal; ++} ++/* Function Name: ++ * rtl8367c_getAsicWFQBurstSize ++ * Description: ++ * Get WFQ leaky bucket burst size ++ * Input: ++ * burstsize - Leaky bucket burst size, unit byte ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicWFQBurstSize(rtk_uint32 *burstsize) ++{ ++ ret_t retVal; ++ ++ retVal = rtl8367c_getAsicReg(RTL8367C_SCHEDULE_WFQ_BURST_SIZE_REG, burstsize); ++ ++ return retVal; ++} ++/* Function Name: ++ * rtl8367c_setAsicQueueType ++ * Description: ++ * Set type of a queue ++ * Input: ++ * port - Physical port number (0~10) ++ * qid - The queue ID wanted to set ++ * queueType - The specified queue type. 0b0: Strict priority, 0b1: WFQ ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * RT_ERR_QUEUE_ID - Invalid queue id ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicQueueType(rtk_uint32 port, rtk_uint32 qid, rtk_uint32 queueType) ++{ ++ ret_t retVal; ++ ++ /* Invalid input parameter */ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ if(qid > RTL8367C_QIDMAX) ++ return RT_ERR_QUEUE_ID; ++ ++ /* Set Related Registers */ ++ retVal = rtl8367c_setAsicRegBit(RTL8367C_SCHEDULE_QUEUE_TYPE_REG(port), RTL8367C_SCHEDULE_QUEUE_TYPE_OFFSET(port, qid),queueType); ++ ++ return retVal; ++} ++/* Function Name: ++ * rtl8367c_getAsicQueueType ++ * Description: ++ * Get type of a queue ++ * Input: ++ * port - Physical port number (0~7) ++ * qid - The queue ID wanted to set ++ * queueType - The specified queue type. 0b0: Strict priority, 0b1: WFQ ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * RT_ERR_QUEUE_ID - Invalid queue id ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicQueueType(rtk_uint32 port, rtk_uint32 qid, rtk_uint32 *queueType) ++{ ++ ret_t retVal; ++ ++ /* Invalid input parameter */ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ if(qid > RTL8367C_QIDMAX) ++ return RT_ERR_QUEUE_ID; ++ ++ retVal = rtl8367c_getAsicRegBit(RTL8367C_SCHEDULE_QUEUE_TYPE_REG(port), RTL8367C_SCHEDULE_QUEUE_TYPE_OFFSET(port, qid),queueType); ++ ++ return retVal; ++} ++/* Function Name: ++ * rtl8367c_setAsicPortEgressRate ++ * Description: ++ * Set per-port egress rate ++ * Input: ++ * port - Physical port number (0~10) ++ * rate - Egress rate ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * RT_ERR_QOS_EBW_RATE - Invalid bandwidth/rate ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicPortEgressRate(rtk_uint32 port, rtk_uint32 rate) ++{ ++ ret_t retVal; ++ rtk_uint32 regAddr, regData; ++ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ if(rate > RTL8367C_QOS_GRANULARTY_MAX) ++ return RT_ERR_QOS_EBW_RATE; ++ ++ regAddr = RTL8367C_PORT_EGRESSBW_LSB_REG(port); ++ regData = RTL8367C_QOS_GRANULARTY_LSB_MASK & rate; ++ ++ retVal = rtl8367c_setAsicReg(regAddr, regData); ++ ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ regAddr = RTL8367C_PORT_EGRESSBW_MSB_REG(port); ++ regData = (RTL8367C_QOS_GRANULARTY_MSB_MASK & rate) >> RTL8367C_QOS_GRANULARTY_MSB_OFFSET; ++ ++ retVal = rtl8367c_setAsicRegBits(regAddr, RTL8367C_PORT6_EGRESSBW_CTRL1_MASK, regData); ++ ++ return retVal; ++} ++/* Function Name: ++ * rtl8367c_getAsicPortEgressRate ++ * Description: ++ * Get per-port egress rate ++ * Input: ++ * port - Physical port number (0~10) ++ * rate - Egress rate ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicPortEgressRate(rtk_uint32 port, rtk_uint32 *rate) ++{ ++ ret_t retVal; ++ rtk_uint32 regAddr, regData,regData2; ++ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ regAddr = RTL8367C_PORT_EGRESSBW_LSB_REG(port); ++ ++ retVal = rtl8367c_getAsicReg(regAddr, ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ regAddr = RTL8367C_PORT_EGRESSBW_MSB_REG(port); ++ retVal = rtl8367c_getAsicRegBits(regAddr, RTL8367C_PORT6_EGRESSBW_CTRL1_MASK, ®Data2); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ *rate = regData | (regData2 << RTL8367C_QOS_GRANULARTY_MSB_OFFSET); ++ ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_setAsicPortEgressRateIfg ++ * Description: ++ * Set per-port egress rate calculate include/exclude IFG ++ * Input: ++ * ifg - 1:include IFG 0:exclude IFG ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicPortEgressRateIfg(rtk_uint32 ifg) ++{ ++ ret_t retVal; ++ ++ retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SCHEDULE_WFQ_CTRL, RTL8367C_SCHEDULE_WFQ_CTRL_OFFSET, ifg); ++ ++ return retVal; ++} ++/* Function Name: ++ * rtl8367c_getAsicPortEgressRateIfg ++ * Description: ++ * Get per-port egress rate calculate include/exclude IFG ++ * Input: ++ * ifg - 1:include IFG 0:exclude IFG ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicPortEgressRateIfg(rtk_uint32 *ifg) ++{ ++ ret_t retVal; ++ ++ retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_SCHEDULE_WFQ_CTRL, RTL8367C_SCHEDULE_WFQ_CTRL_OFFSET, ifg); ++ ++ return retVal; ++} +diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_storm.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_storm.c +new file mode 100644 +index 000000000000..a29f64769d65 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_storm.c +@@ -0,0 +1,851 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : Storm control filtering related functions ++ * ++ */ ++ ++#include ++/* Function Name: ++ * rtl8367c_setAsicStormFilterBroadcastEnable ++ * Description: ++ * Set per-port broadcast storm filter enable/disable ++ * Input: ++ * port - Physical port number (0~7) ++ * enabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicStormFilterBroadcastEnable(rtk_uint32 port, rtk_uint32 enabled) ++{ ++ if(port >= RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ return rtl8367c_setAsicRegBit(RTL8367C_STORM_BCAST_REG, port, enabled); ++} ++/* Function Name: ++ * rtl8367c_getAsicStormFilterBroadcastEnable ++ * Description: ++ * Get per-port broadcast storm filter enable/disable ++ * Input: ++ * port - Physical port number (0~7) ++ * pEnabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicStormFilterBroadcastEnable(rtk_uint32 port, rtk_uint32 *pEnabled) ++{ ++ if(port >= RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ return rtl8367c_getAsicRegBit(RTL8367C_STORM_BCAST_REG, port, pEnabled); ++} ++/* Function Name: ++ * rtl8367c_setAsicStormFilterBroadcastMeter ++ * Description: ++ * Set per-port broadcast storm filter meter ++ * Input: ++ * port - Physical port number (0~7) ++ * meter - meter index (0~31) ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * RT_ERR_FILTER_METER_ID - Invalid meter index ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicStormFilterBroadcastMeter(rtk_uint32 port, rtk_uint32 meter) ++{ ++ if(port >= RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ if(meter > RTL8367C_METERMAX) ++ return RT_ERR_FILTER_METER_ID; ++ ++ return rtl8367c_setAsicRegBits(RTL8367C_STORM_BCAST_METER_CTRL_REG(port), RTL8367C_STORM_BCAST_METER_CTRL_MASK(port), meter); ++} ++/* Function Name: ++ * rtl8367c_getAsicStormFilterBroadcastMeter ++ * Description: ++ * Get per-port broadcast storm filter meter ++ * Input: ++ * port - Physical port number (0~7) ++ * pMeter - meter index (0~31) ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicStormFilterBroadcastMeter(rtk_uint32 port, rtk_uint32 *pMeter) ++{ ++ if(port >= RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ return rtl8367c_getAsicRegBits(RTL8367C_STORM_BCAST_METER_CTRL_REG(port), RTL8367C_STORM_BCAST_METER_CTRL_MASK(port), pMeter); ++} ++/* Function Name: ++ * rtl8367c_setAsicStormFilterMulticastEnable ++ * Description: ++ * Set per-port multicast storm filter enable/disable ++ * Input: ++ * port - Physical port number (0~7) ++ * enabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicStormFilterMulticastEnable(rtk_uint32 port, rtk_uint32 enabled) ++{ ++ if(port >= RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ return rtl8367c_setAsicRegBit(RTL8367C_STORM_MCAST_REG, port, enabled); ++} ++/* Function Name: ++ * rtl8367c_getAsicStormFilterMulticastEnable ++ * Description: ++ * Get per-port multicast storm filter enable/disable ++ * Input: ++ * port - Physical port number (0~7) ++ * pEnabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicStormFilterMulticastEnable(rtk_uint32 port, rtk_uint32 *pEnabled) ++{ ++ if(port >= RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ return rtl8367c_getAsicRegBit(RTL8367C_STORM_MCAST_REG, port, pEnabled); ++} ++/* Function Name: ++ * rtl8367c_setAsicStormFilterMulticastMeter ++ * Description: ++ * Set per-port multicast storm filter meter ++ * Input: ++ * port - Physical port number (0~7) ++ * meter - meter index (0~31) ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * RT_ERR_FILTER_METER_ID - Invalid meter index ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicStormFilterMulticastMeter(rtk_uint32 port, rtk_uint32 meter) ++{ ++ if(port >= RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ if(meter > RTL8367C_METERMAX) ++ return RT_ERR_FILTER_METER_ID; ++ ++ return rtl8367c_setAsicRegBits(RTL8367C_STORM_MCAST_METER_CTRL_REG(port), RTL8367C_STORM_MCAST_METER_CTRL_MASK(port), meter); ++} ++/* Function Name: ++ * rtl8367c_getAsicStormFilterMulticastMeter ++ * Description: ++ * Get per-port multicast storm filter meter ++ * Input: ++ * port - Physical port number (0~7) ++ * pMeter - meter index (0~31) ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicStormFilterMulticastMeter(rtk_uint32 port, rtk_uint32 *pMeter) ++{ ++ if(port >= RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ return rtl8367c_getAsicRegBits(RTL8367C_STORM_MCAST_METER_CTRL_REG(port), RTL8367C_STORM_MCAST_METER_CTRL_MASK(port), pMeter); ++} ++/* Function Name: ++ * rtl8367c_setAsicStormFilterUnknownMulticastEnable ++ * Description: ++ * Set per-port unknown multicast storm filter enable/disable ++ * Input: ++ * port - Physical port number (0~7) ++ * enabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicStormFilterUnknownMulticastEnable(rtk_uint32 port, rtk_uint32 enabled) ++{ ++ if(port >= RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ return rtl8367c_setAsicRegBit(RTL8367C_STORM_UNKNOWN_MCAST_REG, port, enabled); ++} ++/* Function Name: ++ * rtl8367c_getAsicStormFilterUnknownMulticastEnable ++ * Description: ++ * Get per-port unknown multicast storm filter enable/disable ++ * Input: ++ * port - Physical port number (0~7) ++ * pEnabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicStormFilterUnknownMulticastEnable(rtk_uint32 port, rtk_uint32 *pEnabled) ++{ ++ if(port >= RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ return rtl8367c_getAsicRegBit(RTL8367C_STORM_UNKNOWN_MCAST_REG, port, pEnabled); ++} ++/* Function Name: ++ * rtl8367c_setAsicStormFilterUnknownMulticastMeter ++ * Description: ++ * Set per-port unknown multicast storm filter meter ++ * Input: ++ * port - Physical port number (0~7) ++ * meter - meter index (0~31) ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * RT_ERR_FILTER_METER_ID - Invalid meter index ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicStormFilterUnknownMulticastMeter(rtk_uint32 port, rtk_uint32 meter) ++{ ++ ret_t retVal; ++ ++ if(port >= RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ if(meter > RTL8367C_METERMAX) ++ return RT_ERR_FILTER_METER_ID; ++ ++ if(port < 8) ++ { ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_STORM_UNMC_METER_CTRL_REG(port), RTL8367C_STORM_UNMC_METER_CTRL_MASK(port), meter); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ { ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_STORM_UNMC_METER_CTRL4 + ((port - 8) >> 1), RTL8367C_STORM_UNMC_METER_CTRL_MASK(port), meter); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_getAsicStormFilterUnknownMulticastMeter ++ * Description: ++ * Get per-port unknown multicast storm filter meter ++ * Input: ++ * port - Physical port number (0~7) ++ * pMeter - meter index (0~31) ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicStormFilterUnknownMulticastMeter(rtk_uint32 port, rtk_uint32 *pMeter) ++{ ++ ret_t retVal; ++ ++ if(port >= RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ if(port < 8) ++ { ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_STORM_UNMC_METER_CTRL_REG(port), RTL8367C_STORM_UNMC_METER_CTRL_MASK(port), pMeter); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ { ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_STORM_UNMC_METER_CTRL4 + ((port - 8) >> 1), RTL8367C_STORM_UNMC_METER_CTRL_MASK(port), pMeter); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_setAsicStormFilterUnknownUnicastEnable ++ * Description: ++ * Set per-port unknown unicast storm filter enable/disable ++ * Input: ++ * port - Physical port number (0~7) ++ * enabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicStormFilterUnknownUnicastEnable(rtk_uint32 port, rtk_uint32 enabled) ++{ ++ if(port >= RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ return rtl8367c_setAsicRegBit(RTL8367C_STORM_UNKNOWN_UCAST_REG, port, enabled); ++} ++/* Function Name: ++ * rtl8367c_getAsicStormFilterUnknownUnicastEnable ++ * Description: ++ * get per-port unknown unicast storm filter enable/disable ++ * Input: ++ * port - Physical port number (0~7) ++ * pEnabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicStormFilterUnknownUnicastEnable(rtk_uint32 port, rtk_uint32 *pEnabled) ++{ ++ if(port >= RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ return rtl8367c_getAsicRegBit(RTL8367C_STORM_UNKNOWN_UCAST_REG, port, pEnabled); ++} ++/* Function Name: ++ * rtl8367c_setAsicStormFilterUnknownUnicastMeter ++ * Description: ++ * Set per-port unknown unicast storm filter meter ++ * Input: ++ * port - Physical port number (0~7) ++ * meter - meter index (0~31) ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * RT_ERR_FILTER_METER_ID - Invalid meter index ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicStormFilterUnknownUnicastMeter(rtk_uint32 port, rtk_uint32 meter) ++{ ++ if(port >= RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ if(meter > RTL8367C_METERMAX) ++ return RT_ERR_FILTER_METER_ID; ++ ++ return rtl8367c_setAsicRegBits(RTL8367C_STORM_UNDA_METER_CTRL_REG(port), RTL8367C_STORM_UNDA_METER_CTRL_MASK(port), meter); ++} ++/* Function Name: ++ * rtl8367c_getAsicStormFilterUnknownUnicastMeter ++ * Description: ++ * Get per-port unknown unicast storm filter meter ++ * Input: ++ * port - Physical port number (0~7) ++ * pMeter - meter index (0~31) ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicStormFilterUnknownUnicastMeter(rtk_uint32 port, rtk_uint32 *pMeter) ++{ ++ if(port >= RTL8367C_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ return rtl8367c_getAsicRegBits(RTL8367C_STORM_UNDA_METER_CTRL_REG(port), RTL8367C_STORM_UNDA_METER_CTRL_MASK(port), pMeter); ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicStormFilterExtBroadcastMeter ++ * Description: ++ * Set extension broadcast storm filter meter ++ * Input: ++ * meter - meter index (0~31) ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_FILTER_METER_ID - Invalid meter index ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicStormFilterExtBroadcastMeter(rtk_uint32 meter) ++{ ++ if(meter > RTL8367C_METERMAX) ++ return RT_ERR_FILTER_METER_ID; ++ ++ return rtl8367c_setAsicRegBits(RTL8367C_REG_STORM_EXT_MTRIDX_CFG0, RTL8367C_BC_STORM_EXT_METERIDX_MASK, meter); ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicStormFilterExtBroadcastMeter ++ * Description: ++ * get extension broadcast storm filter meter ++ * Input: ++ * None ++ * Output: ++ * pMeter - meter index (0~31) ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_NULL_POINTER - Invalid meter index ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicStormFilterExtBroadcastMeter(rtk_uint32 *pMeter) ++{ ++ if(NULL == pMeter) ++ return RT_ERR_NULL_POINTER; ++ ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_STORM_EXT_MTRIDX_CFG0, RTL8367C_BC_STORM_EXT_METERIDX_MASK, pMeter); ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicStormFilterExtMulticastMeter ++ * Description: ++ * Set extension multicast storm filter meter ++ * Input: ++ * meter - meter index (0~31) ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_FILTER_METER_ID - Invalid meter index ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicStormFilterExtMulticastMeter(rtk_uint32 meter) ++{ ++ if(meter > RTL8367C_METERMAX) ++ return RT_ERR_FILTER_METER_ID; ++ ++ return rtl8367c_setAsicRegBits(RTL8367C_REG_STORM_EXT_MTRIDX_CFG0, RTL8367C_MC_STORM_EXT_METERIDX_MASK, meter); ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicStormFilterExtMulticastMeter ++ * Description: ++ * get extension multicast storm filter meter ++ * Input: ++ * None ++ * Output: ++ * pMeter - meter index (0~31) ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_NULL_POINTER - Invalid meter index ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicStormFilterExtMulticastMeter(rtk_uint32 *pMeter) ++{ ++ if(NULL == pMeter) ++ return RT_ERR_NULL_POINTER; ++ ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_STORM_EXT_MTRIDX_CFG0, RTL8367C_MC_STORM_EXT_METERIDX_MASK, pMeter); ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicStormFilterExtUnknownMulticastMeter ++ * Description: ++ * Set extension unknown multicast storm filter meter ++ * Input: ++ * meter - meter index (0~31) ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_FILTER_METER_ID - Invalid meter index ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicStormFilterExtUnknownMulticastMeter(rtk_uint32 meter) ++{ ++ if(meter > RTL8367C_METERMAX) ++ return RT_ERR_FILTER_METER_ID; ++ ++ return rtl8367c_setAsicRegBits(RTL8367C_REG_STORM_EXT_MTRIDX_CFG1, RTL8367C_UNMC_STORM_EXT_METERIDX_MASK, meter); ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicStormFilterExtUnknownMulticastMeter ++ * Description: ++ * get extension unknown multicast storm filter meter ++ * Input: ++ * None ++ * Output: ++ * pMeter - meter index (0~31) ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_NULL_POINTER - Invalid meter index ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicStormFilterExtUnknownMulticastMeter(rtk_uint32 *pMeter) ++{ ++ if(NULL == pMeter) ++ return RT_ERR_NULL_POINTER; ++ ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_STORM_EXT_MTRIDX_CFG1, RTL8367C_UNMC_STORM_EXT_METERIDX_MASK, pMeter); ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicStormFilterExtUnknownUnicastMeter ++ * Description: ++ * Set extension unknown unicast storm filter meter ++ * Input: ++ * meter - meter index (0~31) ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_FILTER_METER_ID - Invalid meter index ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicStormFilterExtUnknownUnicastMeter(rtk_uint32 meter) ++{ ++ if(meter > RTL8367C_METERMAX) ++ return RT_ERR_FILTER_METER_ID; ++ ++ return rtl8367c_setAsicRegBits(RTL8367C_REG_STORM_EXT_MTRIDX_CFG1, RTL8367C_UNUC_STORM_EXT_METERIDX_MASK, meter); ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicStormFilterExtUnknownUnicastMeter ++ * Description: ++ * get extension unknown unicast storm filter meter ++ * Input: ++ * None ++ * Output: ++ * pMeter - meter index (0~31) ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_NULL_POINTER - Invalid meter index ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicStormFilterExtUnknownUnicastMeter(rtk_uint32 *pMeter) ++{ ++ if(NULL == pMeter) ++ return RT_ERR_NULL_POINTER; ++ ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_STORM_EXT_MTRIDX_CFG1, RTL8367C_UNUC_STORM_EXT_METERIDX_MASK, pMeter); ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicStormFilterExtBroadcastEnable ++ * Description: ++ * Set extension broadcast storm filter state ++ * Input: ++ * enabled - state ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicStormFilterExtBroadcastEnable(rtk_uint32 enabled) ++{ ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_STORM_EXT_CFG, RTL8367C_STORM_BCAST_EXT_EN_OFFSET, enabled); ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicStormFilterExtBroadcastEnable ++ * Description: ++ * Get extension broadcast storm filter state ++ * Input: ++ * None ++ * Output: ++ * pEnabled - state ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_NULL_POINTER - Null pointer ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicStormFilterExtBroadcastEnable(rtk_uint32 *pEnabled) ++{ ++ if(NULL == pEnabled) ++ return RT_ERR_NULL_POINTER; ++ ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_STORM_EXT_CFG, RTL8367C_STORM_BCAST_EXT_EN_OFFSET, pEnabled); ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicStormFilterExtMulticastEnable ++ * Description: ++ * Set extension multicast storm filter state ++ * Input: ++ * enabled - state ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicStormFilterExtMulticastEnable(rtk_uint32 enabled) ++{ ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_STORM_EXT_CFG, RTL8367C_STORM_MCAST_EXT_EN_OFFSET, enabled); ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicStormFilterExtMulticastEnable ++ * Description: ++ * Get extension multicast storm filter state ++ * Input: ++ * None ++ * Output: ++ * pEnabled - state ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_NULL_POINTER - Null pointer ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicStormFilterExtMulticastEnable(rtk_uint32 *pEnabled) ++{ ++ if(NULL == pEnabled) ++ return RT_ERR_NULL_POINTER; ++ ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_STORM_EXT_CFG, RTL8367C_STORM_MCAST_EXT_EN_OFFSET, pEnabled); ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicStormFilterExtUnknownMulticastEnable ++ * Description: ++ * Set extension unknown multicast storm filter state ++ * Input: ++ * enabled - state ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicStormFilterExtUnknownMulticastEnable(rtk_uint32 enabled) ++{ ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_STORM_EXT_CFG, RTL8367C_STORM_UNKNOWN_MCAST_EXT_EN_OFFSET, enabled); ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicStormFilterExtUnknownMulticastEnable ++ * Description: ++ * Get extension unknown multicast storm filter state ++ * Input: ++ * None ++ * Output: ++ * pEnabled - state ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_NULL_POINTER - Null pointer ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicStormFilterExtUnknownMulticastEnable(rtk_uint32 *pEnabled) ++{ ++ if(NULL == pEnabled) ++ return RT_ERR_NULL_POINTER; ++ ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_STORM_EXT_CFG, RTL8367C_STORM_UNKNOWN_MCAST_EXT_EN_OFFSET, pEnabled); ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicStormFilterExtUnknownUnicastEnable ++ * Description: ++ * Set extension unknown unicast storm filter state ++ * Input: ++ * enabled - state ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicStormFilterExtUnknownUnicastEnable(rtk_uint32 enabled) ++{ ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_STORM_EXT_CFG, RTL8367C_STORM_UNKNOWN_UCAST_EXT_EN_OFFSET, enabled); ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicStormFilterExtUnknownUnicastEnable ++ * Description: ++ * Get extension unknown unicast storm filter state ++ * Input: ++ * None ++ * Output: ++ * pEnabled - state ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_NULL_POINTER - Null pointer ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicStormFilterExtUnknownUnicastEnable(rtk_uint32 *pEnabled) ++{ ++ if(NULL == pEnabled) ++ return RT_ERR_NULL_POINTER; ++ ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_STORM_EXT_CFG, RTL8367C_STORM_UNKNOWN_UCAST_EXT_EN_OFFSET, pEnabled); ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicStormFilterExtEnablePortMask ++ * Description: ++ * Set extension storm filter port mask ++ * Input: ++ * portmask - port mask ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicStormFilterExtEnablePortMask(rtk_uint32 portmask) ++{ ++ ret_t retVal; ++ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_STORM_EXT_CFG, RTL8367C_STORM_EXT_EN_PORTMASK_MASK, portmask & 0x3FF); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_STORM_EXT_CFG, RTL8367C_STORM_EXT_EN_PORTMASK_EXT_MASK, (portmask >> 10)&1); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicStormFilterExtEnablePortMask ++ * Description: ++ * Get extension storm filter port mask ++ * Input: ++ * portmask - port mask ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_NULL_POINTER - Null pointer ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicStormFilterExtEnablePortMask(rtk_uint32 *pPortmask) ++{ ++ rtk_uint32 tmpPmsk; ++ ret_t retVal; ++ ++ if(NULL == pPortmask) ++ return RT_ERR_NULL_POINTER; ++ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_STORM_EXT_CFG, RTL8367C_STORM_EXT_EN_PORTMASK_MASK, &tmpPmsk); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ *pPortmask = tmpPmsk & 0x3ff; ++ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_STORM_EXT_CFG, RTL8367C_STORM_EXT_EN_PORTMASK_EXT_MASK, &tmpPmsk); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ *pPortmask |= (tmpPmsk & 1) << 10; ++ ++ return RT_ERR_OK; ++} ++ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_svlan.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_svlan.c +new file mode 100644 +index 000000000000..e199664b5e73 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_svlan.c +@@ -0,0 +1,1003 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : SVLAN related functions ++ * ++ */ ++#include ++ ++#include ++ ++static void _rtl8367c_svlanConfStUser2Smi( rtl8367c_svlan_memconf_t *pUserSt, rtk_uint16 *pSmiSt) ++{ ++ pSmiSt[0] |= (pUserSt->vs_member & 0x00FF); ++ pSmiSt[0] |= (pUserSt->vs_untag & 0x00FF) << 8; ++ ++ pSmiSt[1] |= (pUserSt->vs_fid_msti & 0x000F); ++ pSmiSt[1] |= (pUserSt->vs_priority & 0x0007) << 4; ++ pSmiSt[1] |= (pUserSt->vs_force_fid & 0x0001) << 7; ++ ++ pSmiSt[2] |= (pUserSt->vs_svid & 0x0FFF); ++ pSmiSt[2] |= (pUserSt->vs_efiden & 0x0001) << 12; ++ pSmiSt[2] |= (pUserSt->vs_efid & 0x0007) << 13; ++ ++ pSmiSt[3] |= ((pUserSt->vs_member & 0x0700) >> 8); ++ pSmiSt[3] |= ((pUserSt->vs_untag & 0x0700) >> 8) << 3; ++} ++ ++static void _rtl8367c_svlanConfStSmi2User( rtl8367c_svlan_memconf_t *pUserSt, rtk_uint16 *pSmiSt) ++{ ++ ++ pUserSt->vs_member = (pSmiSt[0] & 0x00FF) | ((pSmiSt[3] & 0x0007) << 8); ++ pUserSt->vs_untag = ((pSmiSt[0] & 0xFF00) >> 8) | (((pSmiSt[3] & 0x0038) >> 3) << 8); ++ ++ pUserSt->vs_fid_msti = (pSmiSt[1] & 0x000F); ++ pUserSt->vs_priority = (pSmiSt[1] & 0x0070) >> 4; ++ pUserSt->vs_force_fid = (pSmiSt[1] & 0x0080) >> 7; ++ ++ pUserSt->vs_svid = (pSmiSt[2] & 0x0FFF); ++ pUserSt->vs_efiden = (pSmiSt[2] & 0x1000) >> 12; ++ pUserSt->vs_efid = (pSmiSt[2] & 0xE000) >> 13; ++} ++ ++static void _rtl8367c_svlanMc2sStUser2Smi(rtl8367c_svlan_mc2s_t *pUserSt, rtk_uint16 *pSmiSt) ++{ ++ pSmiSt[0] |= (pUserSt->svidx & 0x003F); ++ pSmiSt[0] |= (pUserSt->format & 0x0001) << 6; ++ pSmiSt[0] |= (pUserSt->valid & 0x0001) << 7; ++ ++ pSmiSt[1] = (rtk_uint16)(pUserSt->smask & 0x0000FFFF); ++ pSmiSt[2] = (rtk_uint16)((pUserSt->smask & 0xFFFF0000) >> 16); ++ ++ pSmiSt[3] = (rtk_uint16)(pUserSt->sdata & 0x0000FFFF); ++ pSmiSt[4] = (rtk_uint16)((pUserSt->sdata & 0xFFFF0000) >> 16); ++} ++ ++static void _rtl8367c_svlanMc2sStSmi2User(rtl8367c_svlan_mc2s_t *pUserSt, rtk_uint16 *pSmiSt) ++{ ++ pUserSt->svidx = (pSmiSt[0] & 0x003F); ++ pUserSt->format = (pSmiSt[0] & 0x0040) >> 6; ++ pUserSt->valid = (pSmiSt[0] & 0x0080) >> 7; ++ ++ pUserSt->smask = pSmiSt[1] | (pSmiSt[2] << 16); ++ pUserSt->sdata = pSmiSt[3] | (pSmiSt[4] << 16); ++} ++ ++static void _rtl8367c_svlanSp2cStUser2Smi(rtl8367c_svlan_s2c_t *pUserSt, rtk_uint16 *pSmiSt) ++{ ++ pSmiSt[0] |= (pUserSt->dstport & 0x0007); ++ pSmiSt[0] |= (pUserSt->svidx & 0x003F) << 3; ++ pSmiSt[0] |= ((pUserSt->dstport & 0x0008) >> 3) << 9; ++ ++ pSmiSt[1] |= (pUserSt->vid & 0x0FFF); ++ pSmiSt[1] |= (pUserSt->valid & 0x0001) << 12; ++} ++ ++static void _rtl8367c_svlanSp2cStSmi2User(rtl8367c_svlan_s2c_t *pUserSt, rtk_uint16 *pSmiSt) ++{ ++ pUserSt->dstport = (((pSmiSt[0] & 0x0200) >> 9) << 3) | (pSmiSt[0] & 0x0007); ++ pUserSt->svidx = (pSmiSt[0] & 0x01F8) >> 3; ++ pUserSt->vid = (pSmiSt[1] & 0x0FFF); ++ pUserSt->valid = (pSmiSt[1] & 0x1000) >> 12; ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicSvlanUplinkPortMask ++ * Description: ++ * Set uplink ports mask ++ * Input: ++ * portMask - Uplink port mask setting ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicSvlanUplinkPortMask(rtk_uint32 portMask) ++{ ++ return rtl8367c_setAsicReg(RTL8367C_REG_SVLAN_UPLINK_PORTMASK, portMask); ++} ++/* Function Name: ++ * rtl8367c_getAsicSvlanUplinkPortMask ++ * Description: ++ * Get uplink ports mask ++ * Input: ++ * pPortmask - Uplink port mask setting ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicSvlanUplinkPortMask(rtk_uint32* pPortmask) ++{ ++ return rtl8367c_getAsicReg(RTL8367C_REG_SVLAN_UPLINK_PORTMASK, pPortmask); ++} ++/* Function Name: ++ * rtl8367c_setAsicSvlanTpid ++ * Description: ++ * Set accepted S-VLAN ether type. The default ether type of S-VLAN is 0x88a8 ++ * Input: ++ * protocolType - Ether type of S-tag frame parsing in uplink ports ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * Ether type of S-tag in 802.1ad is 0x88a8 and there are existed ether type 0x9100 and 0x9200 ++ * for Q-in-Q SLAN design. User can set matched ether type as service provider supported protocol ++ */ ++ret_t rtl8367c_setAsicSvlanTpid(rtk_uint32 protocolType) ++{ ++ return rtl8367c_setAsicReg(RTL8367C_REG_VS_TPID, protocolType); ++} ++/* Function Name: ++ * rtl8367c_getAsicReg ++ * Description: ++ * Get accepted S-VLAN ether type. The default ether type of S-VLAN is 0x88a8 ++ * Input: ++ * pProtocolType - Ether type of S-tag frame parsing in uplink ports ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicSvlanTpid(rtk_uint32* pProtocolType) ++{ ++ return rtl8367c_getAsicReg(RTL8367C_REG_VS_TPID, pProtocolType); ++} ++/* Function Name: ++ * rtl8367c_setAsicSvlanPrioritySel ++ * Description: ++ * Set SVLAN priority field setting ++ * Input: ++ * priSel - S-priority assignment method, 0:internal priority 1:C-tag priority 2:using Svlan member configuration ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameter ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicSvlanPrioritySel(rtk_uint32 priSel) ++{ ++ if(priSel >= SPRISEL_END) ++ return RT_ERR_QOS_INT_PRIORITY; ++ ++ return rtl8367c_setAsicRegBits(RTL8367C_REG_SVLAN_CFG, RTL8367C_VS_SPRISEL_MASK, priSel); ++} ++/* Function Name: ++ * rtl8367c_getAsicSvlanPrioritySel ++ * Description: ++ * Get SVLAN priority field setting ++ * Input: ++ * pPriSel - S-priority assignment method, 0:internal priority 1:C-tag priority 2:using Svlan member configuration ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicSvlanPrioritySel(rtk_uint32* pPriSel) ++{ ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_SVLAN_CFG, RTL8367C_VS_SPRISEL_MASK, pPriSel); ++} ++/* Function Name: ++ * rtl8367c_setAsicSvlanTrapPriority ++ * Description: ++ * Set trap to CPU priority assignment ++ * Input: ++ * priority - Priority assignment ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_QOS_INT_PRIORITY - Invalid priority ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicSvlanTrapPriority(rtk_uint32 priority) ++{ ++ if(priority > RTL8367C_PRIMAX) ++ return RT_ERR_QOS_INT_PRIORITY; ++ ++ return rtl8367c_setAsicRegBits(RTL8367C_REG_QOS_TRAP_PRIORITY0, RTL8367C_SVLAN_PRIOIRTY_MASK, priority); ++} ++/* Function Name: ++ * rtl8367c_getAsicSvlanTrapPriority ++ * Description: ++ * Get trap to CPU priority assignment ++ * Input: ++ * pPriority - Priority assignment ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicSvlanTrapPriority(rtk_uint32* pPriority) ++{ ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_QOS_TRAP_PRIORITY0, RTL8367C_SVLAN_PRIOIRTY_MASK, pPriority); ++} ++/* Function Name: ++ * rtl8367c_setAsicSvlanDefaultVlan ++ * Description: ++ * Set default egress SVLAN ++ * Input: ++ * port - Physical port number (0~10) ++ * index - index SVLAN member configuration ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * RT_ERR_SVLAN_ENTRY_INDEX - Invalid SVLAN index parameter ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicSvlanDefaultVlan(rtk_uint32 port, rtk_uint32 index) ++{ ++ ret_t retVal; ++ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ if(index > RTL8367C_SVIDXMAX) ++ return RT_ERR_SVLAN_ENTRY_INDEX; ++ ++ if(port < 8){ ++ if(port & 1) ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_SVLAN_PORTBASED_SVIDX_CTRL0 + (port >> 1), RTL8367C_VS_PORT1_SVIDX_MASK,index); ++ else ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_SVLAN_PORTBASED_SVIDX_CTRL0 + (port >> 1), RTL8367C_VS_PORT0_SVIDX_MASK,index); ++ }else{ ++ switch(port){ ++ case 8: ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_SVLAN_PORTBASED_SVIDX_CTRL4, RTL8367C_VS_PORT8_SVIDX_MASK,index); ++ break; ++ ++ case 9: ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_SVLAN_PORTBASED_SVIDX_CTRL4, RTL8367C_VS_PORT9_SVIDX_MASK,index); ++ break; ++ ++ case 10: ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_SVLAN_PORTBASED_SVIDX_CTRL5, RTL8367C_SVLAN_PORTBASED_SVIDX_CTRL5_MASK,index); ++ break; ++ } ++ } ++ ++ return retVal; ++} ++/* Function Name: ++ * rtl8367c_getAsicSvlanDefaultVlan ++ * Description: ++ * Get default egress SVLAN ++ * Input: ++ * port - Physical port number (0~7) ++ * pIndex - index SVLAN member configuration ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicSvlanDefaultVlan(rtk_uint32 port, rtk_uint32* pIndex) ++{ ++ ret_t retVal; ++ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ if(port < 8){ ++ if(port & 1) ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_SVLAN_PORTBASED_SVIDX_CTRL0 + (port >> 1), RTL8367C_VS_PORT1_SVIDX_MASK,pIndex); ++ else ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_SVLAN_PORTBASED_SVIDX_CTRL0 + (port >> 1), RTL8367C_VS_PORT0_SVIDX_MASK,pIndex); ++ }else{ ++ switch(port){ ++ case 8: ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_SVLAN_PORTBASED_SVIDX_CTRL4, RTL8367C_VS_PORT8_SVIDX_MASK,pIndex); ++ break; ++ ++ case 9: ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_SVLAN_PORTBASED_SVIDX_CTRL4, RTL8367C_VS_PORT9_SVIDX_MASK,pIndex); ++ break; ++ ++ case 10: ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_SVLAN_PORTBASED_SVIDX_CTRL5, RTL8367C_SVLAN_PORTBASED_SVIDX_CTRL5_MASK,pIndex); ++ break; ++ } ++ } ++ ++ return retVal; ++ ++} ++/* Function Name: ++ * rtl8367c_setAsicSvlanIngressUntag ++ * Description: ++ * Set action received un-Stag frame from uplink port ++ * Input: ++ * mode - 0:Drop 1:Trap 2:Assign SVLAN ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicSvlanIngressUntag(rtk_uint32 mode) ++{ ++ return rtl8367c_setAsicRegBits(RTL8367C_REG_SVLAN_CFG, RTL8367C_VS_UNTAG_MASK, mode); ++} ++/* Function Name: ++ * rtl8367c_getAsicSvlanIngressUntag ++ * Description: ++ * Get action received un-Stag frame from uplink port ++ * Input: ++ * pMode - 0:Drop 1:Trap 2:Assign SVLAN ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicSvlanIngressUntag(rtk_uint32* pMode) ++{ ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_SVLAN_CFG, RTL8367C_VS_UNTAG_MASK, pMode); ++} ++/* Function Name: ++ * rtl8367c_setAsicSvlanIngressUnmatch ++ * Description: ++ * Set action received unmatched Stag frame from uplink port ++ * Input: ++ * mode - 0:Drop 1:Trap 2:Assign SVLAN ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicSvlanIngressUnmatch(rtk_uint32 mode) ++{ ++ return rtl8367c_setAsicRegBits(RTL8367C_REG_SVLAN_CFG, RTL8367C_VS_UNMAT_MASK, mode); ++} ++/* Function Name: ++ * rtl8367c_getAsicSvlanIngressUnmatch ++ * Description: ++ * Get action received unmatched Stag frame from uplink port ++ * Input: ++ * pMode - 0:Drop 1:Trap 2:Assign SVLAN ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicSvlanIngressUnmatch(rtk_uint32* pMode) ++{ ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_SVLAN_CFG, RTL8367C_VS_UNMAT_MASK, pMode); ++ ++} ++/* Function Name: ++ * rtl8367c_setAsicSvlanEgressUnassign ++ * Description: ++ * Set uplink stream without egress SVID action ++ * Input: ++ * enabled - 1:Trap egress unassigned frames to CPU, 0: Use SVLAN setup in VS_CPSVIDX as egress SVID ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicSvlanEgressUnassign(rtk_uint32 enabled) ++{ ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_SVLAN_CFG, RTL8367C_VS_UIFSEG_OFFSET, enabled); ++} ++/* Function Name: ++ * rtl8367c_getAsicSvlanEgressUnassign ++ * Description: ++ * Get uplink stream without egress SVID action ++ * Input: ++ * pEnabled - 1:Trap egress unassigned frames to CPU, 0: Use SVLAN setup in VS_CPSVIDX as egress SVID ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicSvlanEgressUnassign(rtk_uint32* pEnabled) ++{ ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_SVLAN_CFG, RTL8367C_VS_UIFSEG_OFFSET, pEnabled); ++} ++ ++ ++/* Function Name: ++ * rtl8367c_setAsicSvlanMemberConfiguration ++ * Description: ++ * Set system 64 S-tag content ++ * Input: ++ * index - index of 64 s-tag configuration ++ * pSvlanMemCfg - SVLAN member configuration ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_SVLAN_ENTRY_INDEX - Invalid SVLAN index parameter ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicSvlanMemberConfiguration(rtk_uint32 index, rtl8367c_svlan_memconf_t* pSvlanMemCfg) ++{ ++ ret_t retVal; ++ rtk_uint32 regAddr, regData; ++ rtk_uint16 *accessPtr; ++ rtk_uint32 i; ++ rtk_uint16 smiSvlanMemConf[RTL8367C_SVLAN_MEMCONF_LEN]; ++ ++ if(index > RTL8367C_SVIDXMAX) ++ return RT_ERR_SVLAN_ENTRY_INDEX; ++ ++ memset(smiSvlanMemConf, 0x00, sizeof(rtk_uint16) * RTL8367C_SVLAN_MEMCONF_LEN); ++ _rtl8367c_svlanConfStUser2Smi(pSvlanMemCfg, smiSvlanMemConf); ++ ++ accessPtr = smiSvlanMemConf; ++ ++ regData = *accessPtr; ++ for(i = 0; i < 3; i++) ++ { ++ retVal = rtl8367c_setAsicReg(RTL8367C_SVLAN_MEMBERCFG_BASE_REG(index) + i, regData); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ accessPtr ++; ++ regData = *accessPtr; ++ } ++ ++ if(index < 63) ++ regAddr = RTL8367C_REG_SVLAN_MEMBERCFG0_CTRL4+index; ++ else if(index == 63) ++ regAddr = RTL8367C_REG_SVLAN_MEMBERCFG63_CTRL4; ++ ++ retVal = rtl8367c_setAsicReg(regAddr, regData); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++ ++} ++/* Function Name: ++ * rtl8367c_getAsicSvlanMemberConfiguration ++ * Description: ++ * Get system 64 S-tag content ++ * Input: ++ * index - index of 64 s-tag configuration ++ * pSvlanMemCfg - SVLAN member configuration ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_SVLAN_ENTRY_INDEX - Invalid SVLAN index parameter ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicSvlanMemberConfiguration(rtk_uint32 index,rtl8367c_svlan_memconf_t* pSvlanMemCfg) ++{ ++ ret_t retVal; ++ rtk_uint32 regAddr,regData; ++ rtk_uint16 *accessPtr; ++ rtk_uint32 i; ++ rtk_uint16 smiSvlanMemConf[RTL8367C_SVLAN_MEMCONF_LEN]; ++ ++ if(index > RTL8367C_SVIDXMAX) ++ return RT_ERR_SVLAN_ENTRY_INDEX; ++ ++ memset(smiSvlanMemConf, 0x00, sizeof(rtk_uint16) * RTL8367C_SVLAN_MEMCONF_LEN); ++ ++ accessPtr = smiSvlanMemConf; ++ ++ for(i = 0; i < 3; i++) ++ { ++ retVal = rtl8367c_getAsicReg(RTL8367C_SVLAN_MEMBERCFG_BASE_REG(index) + i, ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ *accessPtr = regData; ++ ++ accessPtr ++; ++ } ++ ++ if(index < 63) ++ regAddr = RTL8367C_REG_SVLAN_MEMBERCFG0_CTRL4+index; ++ else if(index == 63) ++ regAddr = RTL8367C_REG_SVLAN_MEMBERCFG63_CTRL4; ++ ++ retVal = rtl8367c_getAsicReg(regAddr, ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ *accessPtr = regData; ++ ++ _rtl8367c_svlanConfStSmi2User(pSvlanMemCfg, smiSvlanMemConf); ++ ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_setAsicSvlanC2SConf ++ * Description: ++ * Set SVLAN C2S table ++ * Input: ++ * index - index of 128 Svlan C2S configuration ++ * evid - Enhanced VID ++ * portmask - available c2s port mask ++ * svidx - index of 64 Svlan member configuration ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_ENTRY_INDEX - Invalid entry index ++ * Note: ++ * ASIC will check upstream's VID and assign related SVID to matched packet ++ */ ++ret_t rtl8367c_setAsicSvlanC2SConf(rtk_uint32 index, rtk_uint32 evid, rtk_uint32 portmask, rtk_uint32 svidx) ++{ ++ ret_t retVal; ++ ++ if(index > RTL8367C_C2SIDXMAX) ++ return RT_ERR_ENTRY_INDEX; ++ ++ retVal = rtl8367c_setAsicReg(RTL8367C_SVLAN_C2SCFG_BASE_REG(index), svidx); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ retVal = rtl8367c_setAsicReg(RTL8367C_SVLAN_C2SCFG_BASE_REG(index) + 1, portmask); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ retVal = rtl8367c_setAsicReg(RTL8367C_SVLAN_C2SCFG_BASE_REG(index) + 2, evid); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_getAsicSvlanC2SConf ++ * Description: ++ * Get SVLAN C2S table ++ * Input: ++ * index - index of 128 Svlan C2S configuration ++ * pEvid - Enhanced VID ++ * pPortmask - available c2s port mask ++ * pSvidx - index of 64 Svlan member configuration ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_ENTRY_INDEX - Invalid entry index ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicSvlanC2SConf(rtk_uint32 index, rtk_uint32* pEvid, rtk_uint32* pPortmask, rtk_uint32* pSvidx) ++{ ++ ret_t retVal; ++ ++ if(index > RTL8367C_C2SIDXMAX) ++ return RT_ERR_ENTRY_INDEX; ++ ++ retVal = rtl8367c_getAsicReg(RTL8367C_SVLAN_C2SCFG_BASE_REG(index), pSvidx); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ retVal = rtl8367c_getAsicReg(RTL8367C_SVLAN_C2SCFG_BASE_REG(index) + 1, pPortmask); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ retVal = rtl8367c_getAsicReg(RTL8367C_SVLAN_C2SCFG_BASE_REG(index) + 2, pEvid); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicSvlanMC2SConf ++ * Description: ++ * Set system MC2S content ++ * Input: ++ * index - index of 32 SVLAN 32 MC2S configuration ++ * pSvlanMc2sCfg - SVLAN Multicast to SVLAN member configuration ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_ENTRY_INDEX - Invalid entry index ++ * Note: ++ * If upstream packet is L2 multicast or IPv4 multicast packet and DMAC/DIP is matched MC2S ++ * configuration, ASIC will assign egress SVID to the packet ++ */ ++ret_t rtl8367c_setAsicSvlanMC2SConf(rtk_uint32 index,rtl8367c_svlan_mc2s_t* pSvlanMc2sCfg) ++{ ++ ret_t retVal; ++ rtk_uint32 regData; ++ rtk_uint16 *accessPtr; ++ rtk_uint32 i; ++ rtk_uint16 smiSvlanMC2S[RTL8367C_SVLAN_MC2S_LEN]; ++ ++ if(index > RTL8367C_MC2SIDXMAX) ++ return RT_ERR_ENTRY_INDEX; ++ ++ memset(smiSvlanMC2S, 0x00, sizeof(rtk_uint16) * RTL8367C_SVLAN_MC2S_LEN); ++ _rtl8367c_svlanMc2sStUser2Smi(pSvlanMc2sCfg, smiSvlanMC2S); ++ ++ accessPtr = smiSvlanMC2S; ++ ++ regData = *accessPtr; ++ for(i = 0; i < 5; i++) ++ { ++ retVal = rtl8367c_setAsicReg(RTL8367C_SVLAN_MCAST2S_ENTRY_BASE_REG(index) + i, regData); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ accessPtr ++; ++ regData = *accessPtr; ++ } ++ ++ return retVal; ++} ++/* Function Name: ++ * rtl8367c_getAsicSvlanMC2SConf ++ * Description: ++ * Get system MC2S content ++ * Input: ++ * index - index of 32 SVLAN 32 MC2S configuration ++ * pSvlanMc2sCfg - SVLAN Multicast to SVLAN member configuration ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_ENTRY_INDEX - Invalid entry index ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicSvlanMC2SConf(rtk_uint32 index, rtl8367c_svlan_mc2s_t* pSvlanMc2sCfg) ++{ ++ ret_t retVal; ++ rtk_uint32 regData; ++ rtk_uint16 *accessPtr; ++ rtk_uint32 i; ++ rtk_uint16 smiSvlanMC2S[RTL8367C_SVLAN_MC2S_LEN]; ++ ++ if(index > RTL8367C_MC2SIDXMAX) ++ return RT_ERR_ENTRY_INDEX; ++ ++ memset(smiSvlanMC2S, 0x00, sizeof(rtk_uint16) * RTL8367C_SVLAN_MC2S_LEN); ++ ++ accessPtr = smiSvlanMC2S; ++ ++ for(i = 0; i < 5; i++) ++ { ++ retVal = rtl8367c_getAsicReg(RTL8367C_SVLAN_MCAST2S_ENTRY_BASE_REG(index) + i, ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ *accessPtr = regData; ++ accessPtr ++; ++ } ++ ++ ++ _rtl8367c_svlanMc2sStSmi2User(pSvlanMc2sCfg, smiSvlanMC2S); ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicSvlanSP2CConf ++ * Description: ++ * Set system 128 SP2C content ++ * Input: ++ * index - index of 128 SVLAN & Port to CVLAN configuration ++ * pSvlanSp2cCfg - SVLAN & Port to CVLAN configuration ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_ENTRY_INDEX - Invalid entry index ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicSvlanSP2CConf(rtk_uint32 index, rtl8367c_svlan_s2c_t* pSvlanSp2cCfg) ++{ ++ ret_t retVal; ++ rtk_uint32 regData; ++ rtk_uint16 *accessPtr; ++ rtk_uint32 i; ++ rtk_uint16 smiSvlanSP2C[RTL8367C_SVLAN_SP2C_LEN]; ++ ++ if(index > RTL8367C_SP2CMAX) ++ return RT_ERR_ENTRY_INDEX; ++ ++ memset(smiSvlanSP2C, 0x00, sizeof(rtk_uint16) * RTL8367C_SVLAN_SP2C_LEN); ++ _rtl8367c_svlanSp2cStUser2Smi(pSvlanSp2cCfg,smiSvlanSP2C); ++ ++ accessPtr = smiSvlanSP2C; ++ ++ regData = *accessPtr; ++ for(i = 0; i < 2; i++) ++ { ++ retVal = rtl8367c_setAsicReg(RTL8367C_SVLAN_S2C_ENTRY_BASE_REG(index) + i, regData); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ accessPtr ++; ++ regData = *accessPtr; ++ } ++ ++ return retVal; ++} ++/* Function Name: ++ * rtl8367c_getAsicSvlanSP2CConf ++ * Description: ++ * Get system 128 SP2C content ++ * Input: ++ * index - index of 128 SVLAN & Port to CVLAN configuration ++ * pSvlanSp2cCfg - SVLAN & Port to CVLAN configuration ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_ENTRY_INDEX - Invalid entry index ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicSvlanSP2CConf(rtk_uint32 index,rtl8367c_svlan_s2c_t* pSvlanSp2cCfg) ++{ ++ ret_t retVal; ++ rtk_uint32 regData; ++ rtk_uint16 *accessPtr; ++ rtk_uint32 i; ++ rtk_uint16 smiSvlanSP2C[RTL8367C_SVLAN_SP2C_LEN]; ++ ++ if(index > RTL8367C_SP2CMAX) ++ return RT_ERR_ENTRY_INDEX; ++ ++ memset(smiSvlanSP2C, 0x00, sizeof(rtk_uint16) * RTL8367C_SVLAN_SP2C_LEN); ++ ++ accessPtr = smiSvlanSP2C; ++ ++ for(i = 0; i < 2; i++) ++ { ++ retVal = rtl8367c_getAsicReg(RTL8367C_SVLAN_S2C_ENTRY_BASE_REG(index) + i, ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ *accessPtr = regData; ++ ++ accessPtr ++; ++ } ++ ++ _rtl8367c_svlanSp2cStSmi2User(pSvlanSp2cCfg, smiSvlanSP2C); ++ ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_setAsicSvlanDmacCvidSel ++ * Description: ++ * Set downstream CVID decision by DMAC ++ * Input: ++ * port - Physical port number (0~7) ++ * enabled - 0:disabled, 1:enabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicSvlanDmacCvidSel(rtk_uint32 port, rtk_uint32 enabled) ++{ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ if(port < 8) ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_SVLAN_CFG, RTL8367C_VS_PORT0_DMACVIDSEL_OFFSET + port, enabled); ++ else ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_SVLAN_CFG_EXT, RTL8367C_VS_PORT8_DMACVIDSEL_OFFSET + (port-8), enabled); ++} ++/* Function Name: ++ * rtl8367c_getAsicSvlanDmacCvidSel ++ * Description: ++ * Get downstream CVID decision by DMAC ++ * Input: ++ * port - Physical port number (0~7) ++ * pEnabled - 0:disabled, 1:enabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicSvlanDmacCvidSel(rtk_uint32 port, rtk_uint32* pEnabled) ++{ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ if(port < 8) ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_SVLAN_CFG, RTL8367C_VS_PORT0_DMACVIDSEL_OFFSET + port, pEnabled); ++ else ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_SVLAN_CFG_EXT, RTL8367C_VS_PORT8_DMACVIDSEL_OFFSET + (port-8), pEnabled); ++} ++/* Function Name: ++ * rtl8367c_setAsicSvlanUntagVlan ++ * Description: ++ * Set default ingress untag SVLAN ++ * Input: ++ * index - index SVLAN member configuration ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_SVLAN_ENTRY_INDEX - Invalid SVLAN index parameter ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicSvlanUntagVlan(rtk_uint32 index) ++{ ++ if(index > RTL8367C_SVIDXMAX) ++ return RT_ERR_SVLAN_ENTRY_INDEX; ++ ++ return rtl8367c_setAsicRegBits(RTL8367C_REG_SVLAN_UNTAG_UNMAT_CFG, RTL8367C_VS_UNTAG_SVIDX_MASK, index); ++} ++/* Function Name: ++ * rtl8367c_getAsicSvlanUntagVlan ++ * Description: ++ * Get default ingress untag SVLAN ++ * Input: ++ * pIndex - index SVLAN member configuration ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicSvlanUntagVlan(rtk_uint32* pIndex) ++{ ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_SVLAN_UNTAG_UNMAT_CFG, RTL8367C_VS_UNTAG_SVIDX_MASK, pIndex); ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicSvlanUnmatchVlan ++ * Description: ++ * Set default ingress unmatch SVLAN ++ * Input: ++ * index - index SVLAN member configuration ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_SVLAN_ENTRY_INDEX - Invalid SVLAN index parameter ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicSvlanUnmatchVlan(rtk_uint32 index) ++{ ++ if(index > RTL8367C_SVIDXMAX) ++ return RT_ERR_SVLAN_ENTRY_INDEX; ++ ++ return rtl8367c_setAsicRegBits(RTL8367C_REG_SVLAN_UNTAG_UNMAT_CFG, RTL8367C_VS_UNMAT_SVIDX_MASK, index); ++} ++/* Function Name: ++ * rtl8367c_getAsicSvlanUnmatchVlan ++ * Description: ++ * Get default ingress unmatch SVLAN ++ * Input: ++ * pIndex - index SVLAN member configuration ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicSvlanUnmatchVlan(rtk_uint32* pIndex) ++{ ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_SVLAN_UNTAG_UNMAT_CFG, RTL8367C_VS_UNMAT_SVIDX_MASK, pIndex); ++} ++ ++ ++/* Function Name: ++ * rtl8367c_setAsicSvlanLookupType ++ * Description: ++ * Set svlan lookup table selection ++ * Input: ++ * type - lookup type ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicSvlanLookupType(rtk_uint32 type) ++{ ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_SVLAN_LOOKUP_TYPE, RTL8367C_SVLAN_LOOKUP_TYPE_OFFSET, type); ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicSvlanLookupType ++ * Description: ++ * Get svlan lookup table selection ++ * Input: ++ * pType - lookup type ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicSvlanLookupType(rtk_uint32* pType) ++{ ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_SVLAN_LOOKUP_TYPE, RTL8367C_SVLAN_LOOKUP_TYPE_OFFSET, pType); ++} ++ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_trunking.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_trunking.c +new file mode 100644 +index 000000000000..26d4c29b83b9 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_trunking.c +@@ -0,0 +1,356 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : Port trunking related functions ++ * ++ */ ++ ++#include ++/* Function Name: ++ * rtl8367c_setAsicTrunkingMode ++ * Description: ++ * Set port trunking mode ++ * Input: ++ * mode - 1:dumb 0:user defined ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicTrunkingMode(rtk_uint32 mode) ++{ ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_PORT_TRUNK_CTRL, RTL8367C_PORT_TRUNK_DUMB_OFFSET, mode); ++} ++/* Function Name: ++ * rtl8367c_getAsicTrunkingMode ++ * Description: ++ * Get port trunking mode ++ * Input: ++ * pMode - 1:dumb 0:user defined ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicTrunkingMode(rtk_uint32* pMode) ++{ ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_PORT_TRUNK_CTRL, RTL8367C_PORT_TRUNK_DUMB_OFFSET, pMode); ++} ++/* Function Name: ++ * rtl8367c_setAsicTrunkingFc ++ * Description: ++ * Set port trunking flow control ++ * Input: ++ * group - Trunk Group ID ++ * enabled - 0:disable, 1:enable ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicTrunkingFc(rtk_uint32 group, rtk_uint32 enabled) ++{ ++ ret_t retVal; ++ ++ if(group > RTL8367C_MAX_TRUNK_GID) ++ return RT_ERR_LA_TRUNK_ID; ++ ++ if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_PORT_TRUNK_DROP_CTRL, RTL8367C_PORT_TRUNK_DROP_CTRL_OFFSET, ENABLED)) != RT_ERR_OK) ++ return retVal; ++ ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_PORT_TRUNK_FLOWCTRL, (RTL8367C_EN_FLOWCTRL_TG0_OFFSET + group), enabled); ++} ++/* Function Name: ++ * rtl8367c_getAsicTrunkingFc ++ * Description: ++ * Get port trunking flow control ++ * Input: ++ * group - Trunk Group ID ++ * pEnabled - 0:disable, 1:enable ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicTrunkingFc(rtk_uint32 group, rtk_uint32* pEnabled) ++{ ++ if(group > RTL8367C_MAX_TRUNK_GID) ++ return RT_ERR_LA_TRUNK_ID; ++ ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_PORT_TRUNK_FLOWCTRL, (RTL8367C_EN_FLOWCTRL_TG0_OFFSET + group), pEnabled); ++} ++/* Function Name: ++ * rtl8367c_setAsicTrunkingGroup ++ * Description: ++ * Set trunking group available port mask ++ * Input: ++ * group - Trunk Group ID ++ * portmask - Logic trunking enable port mask, max 4 ports ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicTrunkingGroup(rtk_uint32 group, rtk_uint32 portmask) ++{ ++ if(group > RTL8367C_MAX_TRUNK_GID) ++ return RT_ERR_LA_TRUNK_ID; ++ return rtl8367c_setAsicRegBits(RTL8367C_REG_PORT_TRUNK_GROUP_MASK, RTL8367C_PORT_TRUNK_GROUP0_MASK_MASK << (group * 4), portmask); ++} ++/* Function Name: ++ * rtl8367c_getAsicTrunkingGroup ++ * Description: ++ * Get trunking group available port mask ++ * Input: ++ * group - Trunk Group ID ++ * Output: ++ * pPortmask - Logic trunking enable port mask, max 4 ports ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicTrunkingGroup(rtk_uint32 group, rtk_uint32* pPortmask) ++{ ++ if(group > RTL8367C_MAX_TRUNK_GID) ++ return RT_ERR_LA_TRUNK_ID; ++ ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_PORT_TRUNK_GROUP_MASK, RTL8367C_PORT_TRUNK_GROUP0_MASK_MASK << (group * 4), pPortmask); ++} ++/* Function Name: ++ * rtl8367c_setAsicTrunkingFlood ++ * Description: ++ * Set port trunking flood function ++ * Input: ++ * enabled - Port trunking flooding function 0:disable 1:enable ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicTrunkingFlood(rtk_uint32 enabled) ++{ ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_PORT_TRUNK_CTRL, RTL8367C_PORT_TRUNK_FLOOD_OFFSET, enabled); ++} ++/* Function Name: ++ * rtl8367c_getAsicTrunkingFlood ++ * Description: ++ * Get port trunking flood function ++ * Input: ++ * pEnabled - Port trunking flooding function 0:disable 1:enable ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicTrunkingFlood(rtk_uint32* pEnabled) ++{ ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_PORT_TRUNK_CTRL, RTL8367C_PORT_TRUNK_FLOOD_OFFSET, pEnabled); ++} ++/* Function Name: ++ * rtl8367c_setAsicTrunkingHashSelect ++ * Description: ++ * Set port trunking hash select sources ++ * Input: ++ * hashsel - hash sources mask ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * 7 bits mask for link aggregation group0 hash parameter selection {DIP, SIP, DMAC, SMAC, SPA} ++ * 0b0000001: SPA ++ * 0b0000010: SMAC ++ * 0b0000100: DMAC ++ * 0b0001000: SIP ++ * 0b0010000: DIP ++ * 0b0100000: TCP/UDP Source Port ++ * 0b1000000: TCP/UDP Destination Port ++ */ ++ret_t rtl8367c_setAsicTrunkingHashSelect(rtk_uint32 hashsel) ++{ ++ return rtl8367c_setAsicRegBits(RTL8367C_REG_PORT_TRUNK_CTRL, RTL8367C_PORT_TRUNK_HASH_MASK, hashsel); ++} ++/* Function Name: ++ * rtl8367c_getAsicTrunkingHashSelect ++ * Description: ++ * Get port trunking hash select sources ++ * Input: ++ * pHashsel - hash sources mask ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicTrunkingHashSelect(rtk_uint32* pHashsel) ++{ ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_PORT_TRUNK_CTRL, RTL8367C_PORT_TRUNK_HASH_MASK, pHashsel); ++} ++/* Function Name: ++ * rtl8367c_getAsicQeueuEmptyStatus ++ * Description: ++ * Get current output queue if empty status ++ * Input: ++ * portmask - queue empty port mask ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicQeueuEmptyStatus(rtk_uint32* portmask) ++{ ++ return rtl8367c_getAsicReg(RTL8367C_REG_PORT_QEMPTY, portmask); ++} ++/* Function Name: ++ * rtl8367c_setAsicTrunkingHashTable ++ * Description: ++ * Set port trunking hash value mapping table ++ * Input: ++ * hashval - hashing value 0-15 ++ * portId - trunking port id 0-3 ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * RT_ERR_OUT_OF_RANGE - Invalid hashing value (0-15) ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicTrunkingHashTable(rtk_uint32 hashval, rtk_uint32 portId) ++{ ++ if(hashval > RTL8367C_TRUNKING_HASHVALUE_MAX) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ if(portId >= RTL8367C_TRUNKING_PORTNO) ++ return RT_ERR_PORT_ID; ++ ++ if(hashval >= 8) ++ return rtl8367c_setAsicRegBits(RTL8367C_REG_PORT_TRUNK_HASH_MAPPING_CTRL1, RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL1_HASH8_MASK<<((hashval-8)*2), portId); ++ else ++ return rtl8367c_setAsicRegBits(RTL8367C_REG_PORT_TRUNK_HASH_MAPPING_CTRL0, RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL0_HASH0_MASK<<(hashval*2), portId); ++} ++/* Function Name: ++ * rtl8367c_getAsicTrunkingHashTable ++ * Description: ++ * Get port trunking hash value mapping table ++ * Input: ++ * hashval - hashing value 0-15 ++ * pPortId - trunking port id 0-3 ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - Invalid hashing value (0-15) ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicTrunkingHashTable(rtk_uint32 hashval, rtk_uint32* pPortId) ++{ ++ if(hashval > RTL8367C_TRUNKING_HASHVALUE_MAX) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ if(hashval >= 8) ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_PORT_TRUNK_HASH_MAPPING_CTRL1, RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL1_HASH8_MASK<<((hashval-8)*2), pPortId); ++ else ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_PORT_TRUNK_HASH_MAPPING_CTRL0, RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL0_HASH0_MASK<<(hashval*2), pPortId); ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicTrunkingHashTable1 ++ * Description: ++ * Set port trunking hash value mapping table ++ * Input: ++ * hashval - hashing value 0-15 ++ * portId - trunking port id 0-3 ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * RT_ERR_OUT_OF_RANGE - Invalid hashing value (0-15) ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicTrunkingHashTable1(rtk_uint32 hashval, rtk_uint32 portId) ++{ ++ if(hashval > RTL8367C_TRUNKING_HASHVALUE_MAX) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ if(portId >= RTL8367C_TRUNKING1_PORTN0) ++ return RT_ERR_PORT_ID; ++ ++ if(hashval >= 8) ++ return rtl8367c_setAsicRegBits(RTL8367C_REG_PORT_TRUNK_HASH_MAPPING_CTRL3, RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL3_HASH8_MASK<<((hashval-8)*2), portId); ++ else ++ return rtl8367c_setAsicRegBits(RTL8367C_REG_PORT_TRUNK_HASH_MAPPING_CTRL2, RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL2_HASH0_MASK<<(hashval*2), portId); ++} ++/* Function Name: ++ * rtl8367c_getAsicTrunkingHashTable1 ++ * Description: ++ * Get port trunking hash value mapping table ++ * Input: ++ * hashval - hashing value 0-15 ++ * pPortId - trunking port id 0-3 ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_OUT_OF_RANGE - Invalid hashing value (0-15) ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicTrunkingHashTable1(rtk_uint32 hashval, rtk_uint32* pPortId) ++{ ++ if(hashval > RTL8367C_TRUNKING_HASHVALUE_MAX) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ if(hashval >= 8) ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_PORT_TRUNK_HASH_MAPPING_CTRL3, RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL3_HASH8_MASK<<((hashval-8)*2), pPortId); ++ else ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_PORT_TRUNK_HASH_MAPPING_CTRL2, RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL2_HASH0_MASK<<(hashval*2), pPortId); ++} ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_unknownMulticast.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_unknownMulticast.c +new file mode 100644 +index 000000000000..a3455bbebdc6 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_unknownMulticast.c +@@ -0,0 +1,238 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : Unknown multicast related functions ++ * ++ */ ++ ++#include ++ ++/* Function Name: ++ * rtl8367c_setAsicUnknownL2MulticastBehavior ++ * Description: ++ * Set behavior of L2 multicast ++ * Input: ++ * port - Physical port number (0~7) ++ * behave - 0: flooding, 1: drop, 2: trap ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * RT_ERR_NOT_ALLOWED - Invalid operation ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicUnknownL2MulticastBehavior(rtk_uint32 port, rtk_uint32 behave) ++{ ++ ret_t retVal; ++ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ if(behave >= L2_UNKOWN_MULTICAST_END) ++ return RT_ERR_NOT_ALLOWED; ++ if(port < 8) ++ { ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_UNKNOWN_L2_MULTICAST_REG(port), RTL8367C_UNKNOWN_L2_MULTICAST_MASK(port), behave); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ { ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_UNKNOWN_L2_MULTICAST_CTRL1, 3 << ((port - 8) << 1), behave); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_getAsicUnknownL2MulticastBehavior ++ * Description: ++ * Get behavior of L2 multicast ++ * Input: ++ * port - Physical port number (0~7) ++ * pBehave - 0: flooding, 1: drop, 2: trap ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicUnknownL2MulticastBehavior(rtk_uint32 port, rtk_uint32 *pBehave) ++{ ++ ret_t retVal; ++ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ if(port < 8) ++ { ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_UNKNOWN_L2_MULTICAST_REG(port), RTL8367C_UNKNOWN_L2_MULTICAST_MASK(port), pBehave); ++ if (retVal != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ { ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_UNKNOWN_L2_MULTICAST_CTRL1, 3 << ((port - 8) << 1), pBehave); ++ if (retVal != RT_ERR_OK) ++ return retVal; ++ } ++ ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_setAsicUnknownIPv4MulticastBehavior ++ * Description: ++ * Set behavior of IPv4 multicast ++ * Input: ++ * port - Physical port number (0~7) ++ * behave - 0: flooding, 1: drop, 2: trap ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * RT_ERR_NOT_ALLOWED - Invalid operation ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicUnknownIPv4MulticastBehavior(rtk_uint32 port, rtk_uint32 behave) ++{ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ if(behave >= L3_UNKOWN_MULTICAST_END) ++ return RT_ERR_NOT_ALLOWED; ++ ++ return rtl8367c_setAsicRegBits(RTL8367C_UNKNOWN_IPV4_MULTICAST_REG(port), RTL8367C_UNKNOWN_IPV4_MULTICAST_MASK(port), behave); ++} ++/* Function Name: ++ * rtl8367c_getAsicUnknownIPv4MulticastBehavior ++ * Description: ++ * Get behavior of IPv4 multicast ++ * Input: ++ * port - Physical port number (0~7) ++ * pBehave - 0: flooding, 1: drop, 2: trap ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicUnknownIPv4MulticastBehavior(rtk_uint32 port, rtk_uint32 *pBehave) ++{ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ return rtl8367c_getAsicRegBits(RTL8367C_UNKNOWN_IPV4_MULTICAST_REG(port), RTL8367C_UNKNOWN_IPV4_MULTICAST_MASK(port), pBehave); ++} ++/* Function Name: ++ * rtl8367c_setAsicUnknownIPv6MulticastBehavior ++ * Description: ++ * Set behavior of IPv6 multicast ++ * Input: ++ * port - Physical port number (0~7) ++ * behave - 0: flooding, 1: drop, 2: trap ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * RT_ERR_NOT_ALLOWED - Invalid operation ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicUnknownIPv6MulticastBehavior(rtk_uint32 port, rtk_uint32 behave) ++{ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ if(behave >= L3_UNKOWN_MULTICAST_END) ++ return RT_ERR_NOT_ALLOWED; ++ ++ return rtl8367c_setAsicRegBits(RTL8367C_UNKNOWN_IPV6_MULTICAST_REG(port), RTL8367C_UNKNOWN_IPV6_MULTICAST_MASK(port), behave); ++} ++/* Function Name: ++ * rtl8367c_getAsicUnknownIPv6MulticastBehavior ++ * Description: ++ * Get behavior of IPv6 multicast ++ * Input: ++ * port - Physical port number (0~7) ++ * pBehave - 0: flooding, 1: drop, 2: trap ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicUnknownIPv6MulticastBehavior(rtk_uint32 port, rtk_uint32 *pBehave) ++{ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ return rtl8367c_getAsicRegBits(RTL8367C_UNKNOWN_IPV6_MULTICAST_REG(port), RTL8367C_UNKNOWN_IPV6_MULTICAST_MASK(port), pBehave); ++} ++/* Function Name: ++ * rtl8367c_setAsicUnknownMulticastTrapPriority ++ * Description: ++ * Set trap priority of unknown multicast frame ++ * Input: ++ * priority - priority (0~7) ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_QOS_INT_PRIORITY - Invalid priority ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicUnknownMulticastTrapPriority(rtk_uint32 priority) ++{ ++ if(priority > RTL8367C_PRIMAX) ++ return RT_ERR_QOS_INT_PRIORITY; ++ ++ return rtl8367c_setAsicRegBits(RTL8367C_QOS_TRAP_PRIORITY_CTRL0_REG, RTL8367C_UNKNOWN_MC_PRIORTY_MASK, priority); ++} ++/* Function Name: ++ * rtl8367c_getAsicUnknownMulticastTrapPriority ++ * Description: ++ * Get trap priority of unknown multicast frame ++ * Input: ++ * pPriority - priority (0~7) ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicUnknownMulticastTrapPriority(rtk_uint32 *pPriority) ++{ ++ return rtl8367c_getAsicRegBits(RTL8367C_QOS_TRAP_PRIORITY_CTRL0_REG, RTL8367C_UNKNOWN_MC_PRIORTY_MASK, pPriority); ++} +diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_vlan.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_vlan.c +new file mode 100644 +index 000000000000..1e283e7432c0 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_vlan.c +@@ -0,0 +1,1505 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ ++ * ++ * Purpose : RTL8367C switch high-level API for RTL8367C ++ * Feature : VLAN related functions ++ * ++ */ ++#include ++ ++#include ++ ++#if defined(CONFIG_RTL8367C_ASICDRV_TEST) ++rtl8367c_user_vlan4kentry Rtl8370sVirtualVlanTable[RTL8367C_VIDMAX + 1]; ++#endif ++ ++static void _rtl8367c_VlanMCStUser2Smi(rtl8367c_vlanconfiguser *pVlanCg, rtk_uint16 *pSmiVlanCfg) ++{ ++ pSmiVlanCfg[0] |= pVlanCg->mbr & 0x07FF; ++ ++ pSmiVlanCfg[1] |= pVlanCg->fid_msti & 0x000F; ++ ++ pSmiVlanCfg[2] |= pVlanCg->vbpen & 0x0001; ++ pSmiVlanCfg[2] |= (pVlanCg->vbpri & 0x0007) << 1; ++ pSmiVlanCfg[2] |= (pVlanCg->envlanpol & 0x0001) << 4; ++ pSmiVlanCfg[2] |= (pVlanCg->meteridx & 0x003F) << 5; ++ ++ pSmiVlanCfg[3] |= pVlanCg->evid & 0x1FFF; ++} ++ ++static void _rtl8367c_VlanMCStSmi2User(rtk_uint16 *pSmiVlanCfg, rtl8367c_vlanconfiguser *pVlanCg) ++{ ++ pVlanCg->mbr = pSmiVlanCfg[0] & 0x07FF; ++ pVlanCg->fid_msti = pSmiVlanCfg[1] & 0x000F; ++ pVlanCg->meteridx = (pSmiVlanCfg[2] >> 5) & 0x003F; ++ pVlanCg->envlanpol = (pSmiVlanCfg[2] >> 4) & 0x0001; ++ pVlanCg->vbpri = (pSmiVlanCfg[2] >> 1) & 0x0007; ++ pVlanCg->vbpen = pSmiVlanCfg[2] & 0x0001; ++ pVlanCg->evid = pSmiVlanCfg[3] & 0x1FFF; ++} ++ ++static void _rtl8367c_Vlan4kStUser2Smi(rtl8367c_user_vlan4kentry *pUserVlan4kEntry, rtk_uint16 *pSmiVlan4kEntry) ++{ ++ pSmiVlan4kEntry[0] |= (pUserVlan4kEntry->mbr & 0x00FF); ++ pSmiVlan4kEntry[0] |= (pUserVlan4kEntry->untag & 0x00FF) << 8; ++ ++ pSmiVlan4kEntry[1] |= (pUserVlan4kEntry->fid_msti & 0x000F); ++ pSmiVlan4kEntry[1] |= (pUserVlan4kEntry->vbpen & 0x0001) << 4; ++ pSmiVlan4kEntry[1] |= (pUserVlan4kEntry->vbpri & 0x0007) << 5; ++ pSmiVlan4kEntry[1] |= (pUserVlan4kEntry->envlanpol & 0x0001) << 8; ++ pSmiVlan4kEntry[1] |= (pUserVlan4kEntry->meteridx & 0x001F) << 9; ++ pSmiVlan4kEntry[1] |= (pUserVlan4kEntry->ivl_svl & 0x0001) << 14; ++ ++ pSmiVlan4kEntry[2] |= ((pUserVlan4kEntry->mbr & 0x0700) >> 8); ++ pSmiVlan4kEntry[2] |= ((pUserVlan4kEntry->untag & 0x0700) >> 8) << 3; ++ pSmiVlan4kEntry[2] |= ((pUserVlan4kEntry->meteridx & 0x0020) >> 5) << 6; ++} ++ ++ ++static void _rtl8367c_Vlan4kStSmi2User(rtk_uint16 *pSmiVlan4kEntry, rtl8367c_user_vlan4kentry *pUserVlan4kEntry) ++{ ++ pUserVlan4kEntry->mbr = (pSmiVlan4kEntry[0] & 0x00FF) | ((pSmiVlan4kEntry[2] & 0x0007) << 8); ++ pUserVlan4kEntry->untag = ((pSmiVlan4kEntry[0] & 0xFF00) >> 8) | (((pSmiVlan4kEntry[2] & 0x0038) >> 3) << 8); ++ pUserVlan4kEntry->fid_msti = pSmiVlan4kEntry[1] & 0x000F; ++ pUserVlan4kEntry->vbpen = (pSmiVlan4kEntry[1] & 0x0010) >> 4; ++ pUserVlan4kEntry->vbpri = (pSmiVlan4kEntry[1] & 0x00E0) >> 5; ++ pUserVlan4kEntry->envlanpol = (pSmiVlan4kEntry[1] & 0x0100) >> 8; ++ pUserVlan4kEntry->meteridx = ((pSmiVlan4kEntry[1] & 0x3E00) >> 9) | (((pSmiVlan4kEntry[2] & 0x0040) >> 6) << 5); ++ pUserVlan4kEntry->ivl_svl = (pSmiVlan4kEntry[1] & 0x4000) >> 14; ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicVlanMemberConfig ++ * Description: ++ * Set 32 VLAN member configurations ++ * Input: ++ * index - VLAN member configuration index (0~31) ++ * pVlanCg - VLAN member configuration ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameter ++ * RT_ERR_L2_FID - Invalid FID ++ * RT_ERR_PORT_MASK - Invalid portmask ++ * RT_ERR_FILTER_METER_ID - Invalid meter ++ * RT_ERR_QOS_INT_PRIORITY - Invalid priority ++ * RT_ERR_VLAN_ENTRY_NOT_FOUND - Invalid VLAN member configuration index ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicVlanMemberConfig(rtk_uint32 index, rtl8367c_vlanconfiguser *pVlanCg) ++{ ++ ret_t retVal; ++ rtk_uint32 regAddr; ++ rtk_uint32 regData; ++ rtk_uint16 *tableAddr; ++ rtk_uint32 page_idx; ++ rtk_uint16 smi_vlancfg[RTL8367C_VLAN_MBRCFG_LEN]; ++ ++ /* Error Checking */ ++ if(index > RTL8367C_CVIDXMAX) ++ return RT_ERR_VLAN_ENTRY_NOT_FOUND; ++ ++ if(pVlanCg->evid > RTL8367C_EVIDMAX) ++ return RT_ERR_INPUT; ++ ++ ++ if(pVlanCg->mbr > RTL8367C_PORTMASK) ++ return RT_ERR_PORT_MASK; ++ ++ if(pVlanCg->fid_msti > RTL8367C_FIDMAX) ++ return RT_ERR_L2_FID; ++ ++ if(pVlanCg->meteridx > RTL8367C_METERMAX) ++ return RT_ERR_FILTER_METER_ID; ++ ++ if(pVlanCg->vbpri > RTL8367C_PRIMAX) ++ return RT_ERR_QOS_INT_PRIORITY; ++ ++ memset(smi_vlancfg, 0x00, sizeof(rtk_uint16) * RTL8367C_VLAN_MBRCFG_LEN); ++ _rtl8367c_VlanMCStUser2Smi(pVlanCg, smi_vlancfg); ++ tableAddr = smi_vlancfg; ++ ++ for(page_idx = 0; page_idx < 4; page_idx++) /* 4 pages per VLAN Member Config */ ++ { ++ regAddr = RTL8367C_VLAN_MEMBER_CONFIGURATION_BASE + (index * 4) + page_idx; ++ regData = *tableAddr; ++ ++ retVal = rtl8367c_setAsicReg(regAddr, regData); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ tableAddr++; ++ } ++ ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_getAsicVlanMemberConfig ++ * Description: ++ * Get 32 VLAN member configurations ++ * Input: ++ * index - VLAN member configuration index (0~31) ++ * pVlanCg - VLAN member configuration ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameter ++ * RT_ERR_VLAN_ENTRY_NOT_FOUND - Invalid VLAN member configuration index ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicVlanMemberConfig(rtk_uint32 index, rtl8367c_vlanconfiguser *pVlanCg) ++{ ++ ret_t retVal; ++ rtk_uint32 page_idx; ++ rtk_uint32 regAddr; ++ rtk_uint32 regData; ++ rtk_uint16 *tableAddr; ++ rtk_uint16 smi_vlancfg[RTL8367C_VLAN_MBRCFG_LEN]; ++ ++ if(index > RTL8367C_CVIDXMAX) ++ return RT_ERR_VLAN_ENTRY_NOT_FOUND; ++ ++ memset(smi_vlancfg, 0x00, sizeof(rtk_uint16) * RTL8367C_VLAN_MBRCFG_LEN); ++ tableAddr = smi_vlancfg; ++ ++ for(page_idx = 0; page_idx < 4; page_idx++) /* 4 pages per VLAN Member Config */ ++ { ++ regAddr = RTL8367C_VLAN_MEMBER_CONFIGURATION_BASE + (index * 4) + page_idx; ++ ++ retVal = rtl8367c_getAsicReg(regAddr, ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ *tableAddr = (rtk_uint16)regData; ++ tableAddr++; ++ } ++ ++ _rtl8367c_VlanMCStSmi2User(smi_vlancfg, pVlanCg); ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_setAsicVlan4kEntry ++ * Description: ++ * Set VID mapped entry to 4K VLAN table ++ * Input: ++ * pVlan4kEntry - 4K VLAN configuration ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameter ++ * RT_ERR_L2_FID - Invalid FID ++ * RT_ERR_VLAN_VID - Invalid VID parameter (0~4095) ++ * RT_ERR_PORT_MASK - Invalid portmask ++ * RT_ERR_FILTER_METER_ID - Invalid meter ++ * RT_ERR_QOS_INT_PRIORITY - Invalid priority ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicVlan4kEntry(rtl8367c_user_vlan4kentry *pVlan4kEntry ) ++{ ++ rtk_uint16 vlan_4k_entry[RTL8367C_VLAN_4KTABLE_LEN]; ++ rtk_uint32 page_idx; ++ rtk_uint16 *tableAddr; ++ ret_t retVal; ++ rtk_uint32 regData; ++ ++ if(pVlan4kEntry->vid > RTL8367C_VIDMAX) ++ return RT_ERR_VLAN_VID; ++ ++ if(pVlan4kEntry->mbr > RTL8367C_PORTMASK) ++ return RT_ERR_PORT_MASK; ++ ++ if(pVlan4kEntry->untag > RTL8367C_PORTMASK) ++ return RT_ERR_PORT_MASK; ++ ++ if(pVlan4kEntry->fid_msti > RTL8367C_FIDMAX) ++ return RT_ERR_L2_FID; ++ ++ if(pVlan4kEntry->meteridx > RTL8367C_METERMAX) ++ return RT_ERR_FILTER_METER_ID; ++ ++ if(pVlan4kEntry->vbpri > RTL8367C_PRIMAX) ++ return RT_ERR_QOS_INT_PRIORITY; ++ ++ memset(vlan_4k_entry, 0x00, sizeof(rtk_uint16) * RTL8367C_VLAN_4KTABLE_LEN); ++ _rtl8367c_Vlan4kStUser2Smi(pVlan4kEntry, vlan_4k_entry); ++ ++ /* Prepare Data */ ++ tableAddr = vlan_4k_entry; ++ for(page_idx = 0; page_idx < RTL8367C_VLAN_4KTABLE_LEN; page_idx++) ++ { ++ regData = *tableAddr; ++ retVal = rtl8367c_setAsicReg(RTL8367C_TABLE_ACCESS_WRDATA_BASE + page_idx, regData); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ tableAddr++; ++ } ++ ++ /* Write Address (VLAN_ID) */ ++ regData = pVlan4kEntry->vid; ++ retVal = rtl8367c_setAsicReg(RTL8367C_TABLE_ACCESS_ADDR_REG, regData); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ /* Write Command */ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_TABLE_ACCESS_CTRL_REG, RTL8367C_TABLE_TYPE_MASK | RTL8367C_COMMAND_TYPE_MASK,RTL8367C_TABLE_ACCESS_REG_DATA(TB_OP_WRITE,TB_TARGET_CVLAN)); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++#if defined(CONFIG_RTL8367C_ASICDRV_TEST) ++ memcpy(&Rtl8370sVirtualVlanTable[pVlan4kEntry->vid], pVlan4kEntry, sizeof(rtl8367c_user_vlan4kentry)); ++#endif ++ ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_getAsicVlan4kEntry ++ * Description: ++ * Get VID mapped entry to 4K VLAN table ++ * Input: ++ * pVlan4kEntry - 4K VLAN configuration ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_VLAN_VID - Invalid VID parameter (0~4095) ++ * RT_ERR_BUSYWAIT_TIMEOUT - LUT is busy at retrieving ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicVlan4kEntry(rtl8367c_user_vlan4kentry *pVlan4kEntry ) ++{ ++ rtk_uint16 vlan_4k_entry[RTL8367C_VLAN_4KTABLE_LEN]; ++ rtk_uint32 page_idx; ++ rtk_uint16 *tableAddr; ++ ret_t retVal; ++ rtk_uint32 regData; ++ rtk_uint32 busyCounter; ++ ++ if(pVlan4kEntry->vid > RTL8367C_VIDMAX) ++ return RT_ERR_VLAN_VID; ++ ++ /* Polling status */ ++ busyCounter = RTL8367C_VLAN_BUSY_CHECK_NO; ++ while(busyCounter) ++ { ++ retVal = rtl8367c_getAsicRegBit(RTL8367C_TABLE_ACCESS_STATUS_REG, RTL8367C_TABLE_LUT_ADDR_BUSY_FLAG_OFFSET,®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ if(regData == 0) ++ break; ++ ++ busyCounter --; ++ if(busyCounter == 0) ++ return RT_ERR_BUSYWAIT_TIMEOUT; ++ } ++ ++ /* Write Address (VLAN_ID) */ ++ regData = pVlan4kEntry->vid; ++ retVal = rtl8367c_setAsicReg(RTL8367C_TABLE_ACCESS_ADDR_REG, regData); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ /* Read Command */ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_TABLE_ACCESS_CTRL_REG, RTL8367C_TABLE_TYPE_MASK | RTL8367C_COMMAND_TYPE_MASK, RTL8367C_TABLE_ACCESS_REG_DATA(TB_OP_READ,TB_TARGET_CVLAN)); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ /* Polling status */ ++ busyCounter = RTL8367C_VLAN_BUSY_CHECK_NO; ++ while(busyCounter) ++ { ++ retVal = rtl8367c_getAsicRegBit(RTL8367C_TABLE_ACCESS_STATUS_REG, RTL8367C_TABLE_LUT_ADDR_BUSY_FLAG_OFFSET,®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ if(regData == 0) ++ break; ++ ++ busyCounter --; ++ if(busyCounter == 0) ++ return RT_ERR_BUSYWAIT_TIMEOUT; ++ } ++ ++ /* Read VLAN data from register */ ++ tableAddr = vlan_4k_entry; ++ for(page_idx = 0; page_idx < RTL8367C_VLAN_4KTABLE_LEN; page_idx++) ++ { ++ retVal = rtl8367c_getAsicReg(RTL8367C_TABLE_ACCESS_RDDATA_BASE + page_idx, ®Data); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ *tableAddr = regData; ++ tableAddr++; ++ } ++ ++ _rtl8367c_Vlan4kStSmi2User(vlan_4k_entry, pVlan4kEntry); ++ ++#if defined(CONFIG_RTL8367C_ASICDRV_TEST) ++ memcpy(pVlan4kEntry, &Rtl8370sVirtualVlanTable[pVlan4kEntry->vid], sizeof(rtl8367c_user_vlan4kentry)); ++#endif ++ ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_setAsicVlanAccpetFrameType ++ * Description: ++ * Set per-port acceptable frame type ++ * Input: ++ * port - Physical port number (0~10) ++ * frameType - The acceptable frame type ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * RT_ERR_VLAN_ACCEPT_FRAME_TYPE - Invalid frame type ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicVlanAccpetFrameType(rtk_uint32 port, rtl8367c_accframetype frameType) ++{ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ if(frameType >= FRAME_TYPE_MAX_BOUND) ++ return RT_ERR_VLAN_ACCEPT_FRAME_TYPE; ++ ++ return rtl8367c_setAsicRegBits(RTL8367C_VLAN_ACCEPT_FRAME_TYPE_REG(port), RTL8367C_VLAN_ACCEPT_FRAME_TYPE_MASK(port), frameType); ++} ++/* Function Name: ++ * rtl8367c_getAsicVlanAccpetFrameType ++ * Description: ++ * Get per-port acceptable frame type ++ * Input: ++ * port - Physical port number (0~10) ++ * pFrameType - The acceptable frame type ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * RT_ERR_VLAN_ACCEPT_FRAME_TYPE - Invalid frame type ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicVlanAccpetFrameType(rtk_uint32 port, rtl8367c_accframetype *pFrameType) ++{ ++ rtk_uint32 regData; ++ ret_t retVal; ++ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ if((retVal = rtl8367c_getAsicRegBits(RTL8367C_VLAN_ACCEPT_FRAME_TYPE_REG(port), RTL8367C_VLAN_ACCEPT_FRAME_TYPE_MASK(port), ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ *pFrameType = (rtl8367c_accframetype)regData; ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_setAsicVlanIngressFilter ++ * Description: ++ * Set VLAN Ingress Filter ++ * Input: ++ * port - Physical port number (0~10) ++ * enabled - Enable or disable Ingress filter ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicVlanIngressFilter(rtk_uint32 port, rtk_uint32 enabled) ++{ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ return rtl8367c_setAsicRegBit(RTL8367C_VLAN_INGRESS_REG, port, enabled); ++} ++/* Function Name: ++ * rtl8367c_getAsicVlanIngressFilter ++ * Description: ++ * Get VLAN Ingress Filter ++ * Input: ++ * port - Physical port number (0~10) ++ * pEnable - Enable or disable Ingress filter ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicVlanIngressFilter(rtk_uint32 port, rtk_uint32 *pEnable) ++{ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ return rtl8367c_getAsicRegBit(RTL8367C_VLAN_INGRESS_REG, port, pEnable); ++} ++/* Function Name: ++ * rtl8367c_setAsicVlanEgressTagMode ++ * Description: ++ * Set CVLAN egress tag mode ++ * Input: ++ * port - Physical port number (0~10) ++ * tagMode - The egress tag mode. Including Original mode, Keep tag mode and Priority tag mode ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameter ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicVlanEgressTagMode(rtk_uint32 port, rtl8367c_egtagmode tagMode) ++{ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ if(tagMode >= EG_TAG_MODE_END) ++ return RT_ERR_INPUT; ++ ++ return rtl8367c_setAsicRegBits(RTL8367C_PORT_MISC_CFG_REG(port), RTL8367C_VLAN_EGRESS_MDOE_MASK, tagMode); ++} ++/* Function Name: ++ * rtl8367c_getAsicVlanEgressTagMode ++ * Description: ++ * Get CVLAN egress tag mode ++ * Input: ++ * port - Physical port number (0~10) ++ * pTagMode - The egress tag mode. Including Original mode, Keep tag mode and Priority tag mode ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicVlanEgressTagMode(rtk_uint32 port, rtl8367c_egtagmode *pTagMode) ++{ ++ rtk_uint32 regData; ++ ret_t retVal; ++ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ if((retVal = rtl8367c_getAsicRegBits(RTL8367C_PORT_MISC_CFG_REG(port), RTL8367C_VLAN_EGRESS_MDOE_MASK, ®Data)) != RT_ERR_OK) ++ return retVal; ++ ++ *pTagMode = (rtl8367c_egtagmode)regData; ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_setAsicVlanPortBasedVID ++ * Description: ++ * Set port based VID which is indexed to 32 VLAN member configurations ++ * Input: ++ * port - Physical port number (0~10) ++ * index - Index to VLAN member configuration ++ * pri - 1Q Port based VLAN priority ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * RT_ERR_QOS_INT_PRIORITY - Invalid priority ++ * RT_ERR_VLAN_ENTRY_NOT_FOUND - Invalid VLAN member configuration index ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicVlanPortBasedVID(rtk_uint32 port, rtk_uint32 index, rtk_uint32 pri) ++{ ++ rtk_uint32 regAddr, bit_mask; ++ ret_t retVal; ++ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ if(index > RTL8367C_CVIDXMAX) ++ return RT_ERR_VLAN_ENTRY_NOT_FOUND; ++ ++ if(pri > RTL8367C_PRIMAX) ++ return RT_ERR_QOS_INT_PRIORITY; ++ ++ regAddr = RTL8367C_VLAN_PVID_CTRL_REG(port); ++ bit_mask = RTL8367C_PORT_VIDX_MASK(port); ++ retVal = rtl8367c_setAsicRegBits(regAddr, bit_mask, index); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ regAddr = RTL8367C_VLAN_PORTBASED_PRIORITY_REG(port); ++ bit_mask = RTL8367C_VLAN_PORTBASED_PRIORITY_MASK(port); ++ retVal = rtl8367c_setAsicRegBits(regAddr, bit_mask, pri); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_getAsicVlanPortBasedVID ++ * Description: ++ * Get port based VID which is indexed to 32 VLAN member configurations ++ * Input: ++ * port - Physical port number (0~10) ++ * pIndex - Index to VLAN member configuration ++ * pPri - 1Q Port based VLAN priority ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicVlanPortBasedVID(rtk_uint32 port, rtk_uint32 *pIndex, rtk_uint32 *pPri) ++{ ++ rtk_uint32 regAddr,bit_mask; ++ ret_t retVal; ++ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ regAddr = RTL8367C_VLAN_PVID_CTRL_REG(port); ++ bit_mask = RTL8367C_PORT_VIDX_MASK(port); ++ retVal = rtl8367c_getAsicRegBits(regAddr, bit_mask, pIndex); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ regAddr = RTL8367C_VLAN_PORTBASED_PRIORITY_REG(port); ++ bit_mask = RTL8367C_VLAN_PORTBASED_PRIORITY_MASK(port); ++ retVal = rtl8367c_getAsicRegBits(regAddr, bit_mask, pPri); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_setAsicVlanProtocolBasedGroupData ++ * Description: ++ * Set protocol and port based group database ++ * Input: ++ * index - Index to VLAN member configuration ++ * pPbCfg - Protocol and port based group database entry ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameter ++ * RT_ERR_VLAN_PROTO_AND_PORT - Invalid protocol base group database index ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicVlanProtocolBasedGroupData(rtk_uint32 index, rtl8367c_protocolgdatacfg *pPbCfg) ++{ ++ rtk_uint32 frameType; ++ rtk_uint32 etherType; ++ ret_t retVal; ++ ++ /* Error Checking */ ++ if(index > RTL8367C_PROTOVLAN_GIDX_MAX) ++ return RT_ERR_VLAN_PROTO_AND_PORT; ++ ++ if(pPbCfg->frameType >= PPVLAN_FRAME_TYPE_END ) ++ return RT_ERR_INPUT; ++ ++ frameType = pPbCfg->frameType; ++ etherType = pPbCfg->etherType; ++ ++ /* Frame type */ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_VLAN_PPB_FRAMETYPE_REG(index), RTL8367C_VLAN_PPB_FRAMETYPE_MASK, frameType); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ /* Ether type */ ++ retVal = rtl8367c_setAsicReg(RTL8367C_VLAN_PPB_ETHERTYPR_REG(index), etherType); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_getAsicVlanProtocolBasedGroupData ++ * Description: ++ * Get protocol and port based group database ++ * Input: ++ * index - Index to VLAN member configuration ++ * pPbCfg - Protocol and port based group database entry ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameter ++ * RT_ERR_VLAN_PROTO_AND_PORT - Invalid protocol base group database index ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicVlanProtocolBasedGroupData(rtk_uint32 index, rtl8367c_protocolgdatacfg *pPbCfg) ++{ ++ rtk_uint32 frameType; ++ rtk_uint32 etherType; ++ ret_t retVal; ++ ++ /* Error Checking */ ++ if(index > RTL8367C_PROTOVLAN_GIDX_MAX) ++ return RT_ERR_VLAN_PROTO_AND_PORT; ++ ++ /* Read Frame type */ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_VLAN_PPB_FRAMETYPE_REG(index), RTL8367C_VLAN_PPB_FRAMETYPE_MASK, &frameType); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ /* Read Ether type */ ++ retVal = rtl8367c_getAsicReg(RTL8367C_VLAN_PPB_ETHERTYPR_REG(index), ðerType); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ ++ pPbCfg->frameType = frameType; ++ pPbCfg->etherType = etherType; ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_setAsicVlanPortAndProtocolBased ++ * Description: ++ * Set protocol and port based VLAN configuration ++ * Input: ++ * port - Physical port number (0~10) ++ * index - Index of protocol and port based database index ++ * pPpbCfg - Protocol and port based VLAN configuration ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameter ++ * RT_ERR_PORT_ID - Invalid port number ++ * RT_ERR_QOS_INT_PRIORITY - Invalid priority ++ * RT_ERR_VLAN_PROTO_AND_PORT - Invalid protocol base group database index ++ * RT_ERR_VLAN_ENTRY_NOT_FOUND - Invalid VLAN member configuration index ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicVlanPortAndProtocolBased(rtk_uint32 port, rtk_uint32 index, rtl8367c_protocolvlancfg *pPpbCfg) ++{ ++ rtk_uint32 reg_addr, bit_mask, bit_value; ++ ret_t retVal; ++ ++ /* Error Checking */ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ if(index > RTL8367C_PROTOVLAN_GIDX_MAX) ++ return RT_ERR_VLAN_PROTO_AND_PORT; ++ ++ if( (pPpbCfg->valid != FALSE) && (pPpbCfg->valid != TRUE) ) ++ return RT_ERR_INPUT; ++ ++ if(pPpbCfg->vlan_idx > RTL8367C_CVIDXMAX) ++ return RT_ERR_VLAN_ENTRY_NOT_FOUND; ++ ++ if(pPpbCfg->priority > RTL8367C_PRIMAX) ++ return RT_ERR_QOS_INT_PRIORITY; ++ ++ /* Valid bit */ ++ reg_addr = RTL8367C_VLAN_PPB_VALID_REG(index); ++ bit_mask = 0x0001 << port; ++ bit_value = ((TRUE == pPpbCfg->valid) ? 0x1 : 0x0); ++ retVal = rtl8367c_setAsicRegBits(reg_addr, bit_mask, bit_value); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ /* Calculate the actual register address for CVLAN index*/ ++ if(port < 8) ++ { ++ reg_addr = RTL8367C_VLAN_PPB_CTRL_REG(index, port); ++ bit_mask = RTL8367C_VLAN_PPB_CTRL_MASK(port); ++ } ++ else if(port == 8) ++ { ++ reg_addr = RTL8367C_REG_VLAN_PPB0_CTRL4; ++ bit_mask = RTL8367C_VLAN_PPB0_CTRL4_PORT8_INDEX_MASK; ++ } ++ else if(port == 9) ++ { ++ reg_addr = RTL8367C_REG_VLAN_PPB0_CTRL4; ++ bit_mask = RTL8367C_VLAN_PPB0_CTRL4_PORT9_INDEX_MASK; ++ } ++ else if(port == 10) ++ { ++ reg_addr = RTL8367C_REG_VLAN_PPB0_CTRL4; ++ bit_mask = RTL8367C_VLAN_PPB0_CTRL4_PORT10_INDEX_MASK; ++ } ++ ++ bit_value = pPpbCfg->vlan_idx; ++ retVal = rtl8367c_setAsicRegBits(reg_addr, bit_mask, bit_value); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ /* write priority */ ++ reg_addr = RTL8367C_VLAN_PPB_PRIORITY_ITEM_REG(port, index); ++ bit_mask = RTL8367C_VLAN_PPB_PRIORITY_ITEM_MASK(port); ++ bit_value = pPpbCfg->priority; ++ retVal = rtl8367c_setAsicRegBits(reg_addr, bit_mask, bit_value); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_getAsicVlanPortAndProtocolBased ++ * Description: ++ * Get protocol and port based VLAN configuration ++ * Input: ++ * port - Physical port number (0~7) ++ * index - Index of protocol and port based database index ++ * pPpbCfg - Protocol and port based VLAN configuration ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameter ++ * RT_ERR_PORT_ID - Invalid port number ++ * RT_ERR_VLAN_PROTO_AND_PORT - Invalid protocol base group database index ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicVlanPortAndProtocolBased(rtk_uint32 port, rtk_uint32 index, rtl8367c_protocolvlancfg *pPpbCfg) ++{ ++ rtk_uint32 reg_addr, bit_mask, bit_value; ++ ret_t retVal; ++ ++ /* Error Checking */ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ if(index > RTL8367C_PROTOVLAN_GIDX_MAX) ++ return RT_ERR_VLAN_PROTO_AND_PORT; ++ ++ if(pPpbCfg == NULL) ++ return RT_ERR_INPUT; ++ ++ /* Valid bit */ ++ reg_addr = RTL8367C_VLAN_PPB_VALID_REG(index); ++ bit_mask = 0x0001 << port; ++ retVal = rtl8367c_getAsicRegBits(reg_addr, bit_mask, &bit_value); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ pPpbCfg->valid = bit_value; ++ ++ /* CVLAN index */ ++ if(port < 8) ++ { ++ reg_addr = RTL8367C_VLAN_PPB_CTRL_REG(index, port); ++ bit_mask = RTL8367C_VLAN_PPB_CTRL_MASK(port); ++ } ++ else if(port == 8) ++ { ++ reg_addr = RTL8367C_REG_VLAN_PPB0_CTRL4; ++ bit_mask = RTL8367C_VLAN_PPB0_CTRL4_PORT8_INDEX_MASK; ++ } ++ else if(port == 9) ++ { ++ reg_addr = RTL8367C_REG_VLAN_PPB0_CTRL4; ++ bit_mask = RTL8367C_VLAN_PPB0_CTRL4_PORT9_INDEX_MASK; ++ } ++ else if(port == 10) ++ { ++ reg_addr = RTL8367C_REG_VLAN_PPB0_CTRL4; ++ bit_mask = RTL8367C_VLAN_PPB0_CTRL4_PORT10_INDEX_MASK; ++ } ++ ++ retVal = rtl8367c_getAsicRegBits(reg_addr, bit_mask, &bit_value); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ pPpbCfg->vlan_idx = bit_value; ++ ++ ++ /* priority */ ++ reg_addr = RTL8367C_VLAN_PPB_PRIORITY_ITEM_REG(port,index); ++ bit_mask = RTL8367C_VLAN_PPB_PRIORITY_ITEM_MASK(port); ++ retVal = rtl8367c_getAsicRegBits(reg_addr, bit_mask, &bit_value); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ pPpbCfg->priority = bit_value; ++ return RT_ERR_OK; ++} ++/* Function Name: ++ * rtl8367c_setAsicVlanFilter ++ * Description: ++ * Set enable CVLAN filtering function ++ * Input: ++ * enabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicVlanFilter(rtk_uint32 enabled) ++{ ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_VLAN_CTRL, RTL8367C_VLAN_CTRL_OFFSET, enabled); ++} ++/* Function Name: ++ * rtl8367c_getAsicVlanFilter ++ * Description: ++ * Get enable CVLAN filtering function ++ * Input: ++ * pEnabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicVlanFilter(rtk_uint32* pEnabled) ++{ ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_VLAN_CTRL, RTL8367C_VLAN_CTRL_OFFSET, pEnabled); ++} ++/* Function Name: ++ * rtl8367c_setAsicVlanUntagDscpPriorityEn ++ * Description: ++ * Set enable Dscp to untag 1Q priority ++ * Input: ++ * enabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicVlanUntagDscpPriorityEn(rtk_uint32 enabled) ++{ ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_UNTAG_DSCP_PRI_CFG, RTL8367C_UNTAG_DSCP_PRI_CFG_OFFSET, enabled); ++} ++/* Function Name: ++ * rtl8367c_getAsicVlanUntagDscpPriorityEn ++ * Description: ++ * Get enable Dscp to untag 1Q priority ++ * Input: ++ * enabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicVlanUntagDscpPriorityEn(rtk_uint32* enabled) ++{ ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_UNTAG_DSCP_PRI_CFG, RTL8367C_UNTAG_DSCP_PRI_CFG_OFFSET, enabled); ++} ++/* Function Name: ++ * rtl8367c_setAsicPortBasedFid ++ * Description: ++ * Set port based FID ++ * Input: ++ * port - Physical port number (0~10) ++ * fid - Port based fid ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_L2_FID - Invalid FID ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicPortBasedFid(rtk_uint32 port, rtk_uint32 fid) ++{ ++ rtk_uint32 reg_addr; ++ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ if(fid > RTL8367C_FIDMAX) ++ return RT_ERR_L2_FID; ++ ++ if(port < 8) ++ return rtl8367c_setAsicReg(RTL8367C_PORT_PBFID_REG(port),fid); ++ else { ++ reg_addr = RTL8367C_REG_PORT8_PBFID + port-8; ++ return rtl8367c_setAsicReg(reg_addr, fid); ++ } ++ ++} ++/* Function Name: ++ * rtl8367c_getAsicPortBasedFid ++ * Description: ++ * Get port based FID ++ * Input: ++ * port - Physical port number (0~7) ++ * pFid - Port based fid ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicPortBasedFid(rtk_uint32 port, rtk_uint32* pFid) ++{ ++ rtk_uint32 reg_addr; ++ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ if(port < 8) ++ return rtl8367c_getAsicReg(RTL8367C_PORT_PBFID_REG(port), pFid); ++ else{ ++ reg_addr = RTL8367C_REG_PORT8_PBFID + port-8; ++ return rtl8367c_getAsicReg(reg_addr, pFid); ++ } ++} ++/* Function Name: ++ * rtl8367c_setAsicPortBasedFidEn ++ * Description: ++ * Set port based FID selection enable ++ * Input: ++ * port - Physical port number (0~10) ++ * enabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicPortBasedFidEn(rtk_uint32 port, rtk_uint32 enabled) ++{ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ return rtl8367c_setAsicRegBit(RTL8367C_REG_PORT_PBFIDEN,port, enabled); ++} ++/* Function Name: ++ * rtl8367c_getAsicPortBasedFidEn ++ * Description: ++ * Get port based FID selection enable ++ * Input: ++ * port - Physical port number (0~10) ++ * pEnabled - 1: enabled, 0: disabled ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicPortBasedFidEn(rtk_uint32 port, rtk_uint32* pEnabled) ++{ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ return rtl8367c_getAsicRegBit(RTL8367C_REG_PORT_PBFIDEN,port, pEnabled); ++} ++/* Function Name: ++ * rtl8367c_setAsicSpanningTreeStatus ++ * Description: ++ * Set spanning tree state per each port ++ * Input: ++ * port - Physical port number (0~10) ++ * msti - Multiple spanning tree instance ++ * state - Spanning tree state for msti ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_MSTI - Invalid msti parameter ++ * RT_ERR_PORT_ID - Invalid port number ++ * RT_ERR_MSTP_STATE - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicSpanningTreeStatus(rtk_uint32 port, rtk_uint32 msti, rtk_uint32 state) ++{ ++ rtk_uint32 reg_addr,bits_msk; ++ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ if(msti > RTL8367C_MSTIMAX) ++ return RT_ERR_MSTI; ++ ++ if(state > STPST_FORWARDING) ++ return RT_ERR_MSTP_STATE; ++ ++ if(port < 8) ++ return rtl8367c_setAsicRegBits(RTL8367C_VLAN_MSTI_REG(msti,port), RTL8367C_VLAN_MSTI_MASK(port),state); ++ else{ ++ reg_addr = RTL8367C_VLAN_MSTI_REG(msti,port); ++ switch(port){ ++ case 8: bits_msk = RTL8367C_VLAN_MSTI0_CTRL1_PORT8_STATE_MASK;break; ++ case 9: bits_msk = RTL8367C_VLAN_MSTI0_CTRL1_PORT9_STATE_MASK;break; ++ case 10: bits_msk = RTL8367C_VLAN_MSTI0_CTRL1_PORT10_STATE_MASK;break; ++ } ++ return rtl8367c_setAsicRegBits(reg_addr, bits_msk,state); ++ } ++} ++/* Function Name: ++ * rtl8367c_getAsicSpanningTreeStatus ++ * Description: ++ * Set spanning tree state per each port ++ * Input: ++ * port - Physical port number (0~10) ++ * msti - Multiple spanning tree instance ++ * pState - Spanning tree state for msti ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_MSTI - Invalid msti parameter ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicSpanningTreeStatus(rtk_uint32 port, rtk_uint32 msti, rtk_uint32* pState) ++{ ++ rtk_uint32 reg_addr,bits_msk; ++ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ if(msti > RTL8367C_MSTIMAX) ++ return RT_ERR_MSTI; ++ ++ if(port < 8) ++ return rtl8367c_getAsicRegBits(RTL8367C_VLAN_MSTI_REG(msti,port), RTL8367C_VLAN_MSTI_MASK(port), pState); ++ else{ ++ reg_addr = RTL8367C_VLAN_MSTI_REG(msti,port); ++ switch(port){ ++ case 8: bits_msk = RTL8367C_VLAN_MSTI0_CTRL1_PORT8_STATE_MASK;break; ++ case 9: bits_msk = RTL8367C_VLAN_MSTI0_CTRL1_PORT9_STATE_MASK;break; ++ case 10: bits_msk = RTL8367C_VLAN_MSTI0_CTRL1_PORT10_STATE_MASK;break; ++ } ++ return rtl8367c_getAsicRegBits(reg_addr, bits_msk, pState); ++ } ++ ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicVlanTransparent ++ * Description: ++ * Set VLAN transparent ++ * Input: ++ * port - Physical port number (0~10) ++ * portmask - portmask(0~0xFF) ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_MASK - Invalid portmask ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicVlanTransparent(rtk_uint32 port, rtk_uint32 portmask) ++{ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ if(portmask > RTL8367C_PORTMASK) ++ return RT_ERR_PORT_MASK; ++ ++ return rtl8367c_setAsicRegBits(RTL8367C_REG_VLAN_EGRESS_TRANS_CTRL0 + port, RTL8367C_VLAN_EGRESS_TRANS_CTRL0_MASK, portmask); ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicVlanTransparent ++ * Description: ++ * Get VLAN transparent ++ * Input: ++ * port - Physical port number (0~10) ++ * Output: ++ * pPortmask - Ingress port mask ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_MASK - Invalid portmask ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicVlanTransparent(rtk_uint32 port, rtk_uint32 *pPortmask) ++{ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ return rtl8367c_getAsicRegBits(RTL8367C_REG_VLAN_EGRESS_TRANS_CTRL0 + port, RTL8367C_VLAN_EGRESS_TRANS_CTRL0_MASK, pPortmask); ++} ++ ++/* Function Name: ++ * rtl8367c_setAsicVlanEgressKeep ++ * Description: ++ * Set per egress port VLAN keep mode ++ * Input: ++ * port - Physical port number (0~10) ++ * portmask - portmask(0~0xFF) ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_MASK - Invalid portmask ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setAsicVlanEgressKeep(rtk_uint32 port, rtk_uint32 portmask) ++{ ++ rtk_uint32 regAddr, bit_mask; ++ ret_t retVal; ++ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ if(portmask > RTL8367C_PORTMASK) ++ return RT_ERR_PORT_MASK; ++ ++ if(port < 8){ ++ retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL0 + (port>>1),RTL8367C_PORT0_VLAN_KEEP_MASK_MASK<<((port&1)*8),portmask & 0xff); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ regAddr = RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL0_EXT + (port>>1); ++ bit_mask = RTL8367C_PORT0_VLAN_KEEP_MASK_EXT_MASK; ++ bit_mask <<= (port&1)*3; ++ retVal = rtl8367c_setAsicRegBits(regAddr, bit_mask, (portmask>>8)&0x7); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ } ++ else{ ++ switch(port){ ++ case 8: ++ regAddr = RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL4; ++ bit_mask = RTL8367C_PORT8_VLAN_KEEP_MASK_MASK; ++ retVal = rtl8367c_setAsicRegBits(regAddr, bit_mask, portmask & 0xff); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ regAddr = RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL4_EXT; ++ bit_mask = RTL8367C_PORT8_VLAN_KEEP_MASK_EXT_MASK; ++ retVal = rtl8367c_setAsicRegBits(regAddr, bit_mask, (portmask>>8)&0x7); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ break; ++ ++ case 9: ++ regAddr = RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL4; ++ bit_mask = RTL8367C_PORT9_VLAN_KEEP_MASK_MASK; ++ retVal = rtl8367c_setAsicRegBits(regAddr, bit_mask, portmask & 0xff); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ regAddr = RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL4_EXT; ++ bit_mask = RTL8367C_PORT9_VLAN_KEEP_MASK_EXT_MASK; ++ retVal = rtl8367c_setAsicRegBits(regAddr, bit_mask, (portmask>>8)&0x7); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ break; ++ ++ case 10: ++ regAddr = RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL5; ++ bit_mask = RTL8367C_VLAN_EGRESS_KEEP_CTRL5_MASK; ++ retVal = rtl8367c_setAsicRegBits(regAddr, bit_mask, portmask & 0xff); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ regAddr = RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL5_EXT; ++ bit_mask = RTL8367C_VLAN_EGRESS_KEEP_CTRL5_EXT_MASK; ++ retVal = rtl8367c_setAsicRegBits(regAddr, bit_mask, (portmask>>8)&0x7); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ break; ++ } ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_getAsicVlanEgressKeep ++ * Description: ++ * Get per egress port VLAN keep mode ++ * Input: ++ * port - Physical port number (0~7) ++ * pPortmask - portmask(0~0xFF) ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getAsicVlanEgressKeep(rtk_uint32 port, rtk_uint32* pPortmask) ++{ ++ rtk_uint32 regAddr, bit_mask, regval_l, regval_h; ++ ret_t retVal; ++ ++ if(port > RTL8367C_PORTIDMAX) ++ return RT_ERR_PORT_ID; ++ ++ if(port < 8){ ++ retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL0 + (port>>1),RTL8367C_PORT0_VLAN_KEEP_MASK_MASK<<((port&1)*8),®val_l); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ regAddr = RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL0_EXT + (port>>1); ++ bit_mask = RTL8367C_PORT0_VLAN_KEEP_MASK_EXT_MASK; ++ bit_mask <<= (port&1)*3; ++ retVal = rtl8367c_getAsicRegBits(regAddr, bit_mask, ®val_h); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ *pPortmask = (regval_h << 8) | regval_l; ++ } ++ else{ ++ switch(port){ ++ case 8: ++ regAddr = RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL4; ++ bit_mask = RTL8367C_PORT8_VLAN_KEEP_MASK_MASK; ++ retVal = rtl8367c_getAsicRegBits(regAddr, bit_mask, ®val_l); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ regAddr = RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL4_EXT; ++ bit_mask = RTL8367C_PORT8_VLAN_KEEP_MASK_EXT_MASK; ++ retVal = rtl8367c_getAsicRegBits(regAddr, bit_mask, ®val_h); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ *pPortmask = (regval_h << 8) | regval_l; ++ break; ++ ++ case 9: ++ regAddr = RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL4; ++ bit_mask = RTL8367C_PORT9_VLAN_KEEP_MASK_MASK; ++ retVal = rtl8367c_getAsicRegBits(regAddr, bit_mask, ®val_l); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ regAddr = RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL4_EXT; ++ bit_mask = RTL8367C_PORT9_VLAN_KEEP_MASK_EXT_MASK; ++ retVal = rtl8367c_getAsicRegBits(regAddr, bit_mask, ®val_h); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ *pPortmask = (regval_h << 8) | regval_l; ++ break; ++ ++ case 10: ++ regAddr = RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL5; ++ bit_mask = RTL8367C_VLAN_EGRESS_KEEP_CTRL5_MASK; ++ retVal = rtl8367c_getAsicRegBits(regAddr, bit_mask, ®val_l); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ regAddr = RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL5_EXT; ++ bit_mask = RTL8367C_VLAN_EGRESS_KEEP_CTRL5_EXT_MASK; ++ retVal = rtl8367c_getAsicRegBits(regAddr, bit_mask, ®val_h); ++ if(retVal != RT_ERR_OK) ++ return retVal; ++ ++ *pPortmask = (regval_h << 8) | regval_l; ++ break; ++ } ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_setReservedVidAction ++ * Description: ++ * Set reserved VID action ++ * Input: ++ * vid0Action - VID 0 action ++ * vid4095Action - VID 4095 action ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Error input ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setReservedVidAction(rtk_uint32 vid0Action, rtk_uint32 vid4095Action) ++{ ++ ret_t retVal; ++ ++ if(vid0Action >= RES_VID_ACT_END) ++ return RT_ERR_INPUT; ++ ++ if(vid4095Action >= RES_VID_ACT_END) ++ return RT_ERR_INPUT; ++ ++ if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_VLAN_EXT_CTRL, RTL8367C_VLAN_VID0_TYPE_OFFSET, vid0Action)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_VLAN_EXT_CTRL, RTL8367C_VLAN_VID4095_TYPE_OFFSET, vid4095Action)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_getReservedVidAction ++ * Description: ++ * Get reserved VID action ++ * Input: ++ * pVid0Action - VID 0 action ++ * pVid4095Action - VID 4095 action ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_NULL_POINTER - Null pointer ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getReservedVidAction(rtk_uint32 *pVid0Action, rtk_uint32 *pVid4095Action) ++{ ++ ret_t retVal; ++ ++ if(pVid0Action == NULL) ++ return RT_ERR_NULL_POINTER; ++ ++ if(pVid4095Action == NULL) ++ return RT_ERR_NULL_POINTER; ++ ++ if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_VLAN_EXT_CTRL, RTL8367C_VLAN_VID0_TYPE_OFFSET, pVid0Action)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_VLAN_EXT_CTRL, RTL8367C_VLAN_VID4095_TYPE_OFFSET, pVid4095Action)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++ ++} ++ ++/* Function Name: ++ * rtl8367c_setRealKeepRemarkEn ++ * Description: ++ * Set Real Keep Remark ++ * Input: ++ * enabled - 0: 1P remarking is forbidden at real keep packet, 1: 1P remarking is enabled at real keep packet ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Error input ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_setRealKeepRemarkEn(rtk_uint32 enabled) ++{ ++ ret_t retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_VLAN_EXT_CTRL, RTL8367C_VLAN_1P_REMARK_BYPASS_REALKEEP_OFFSET, enabled)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_getRealKeepRemarkEn ++ * Description: ++ * Get Real Keep Remark ++ * Input: ++ * None ++ * Output: ++ * pEnabled - 0: 1P remarking is forbidden at real keep packet, 1: 1P remarking is enabled at real keep packet ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Error input ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_getRealKeepRemarkEn(rtk_uint32 *pEnabled) ++{ ++ ret_t retVal; ++ ++ if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_VLAN_EXT_CTRL, RTL8367C_VLAN_1P_REMARK_BYPASS_REALKEEP_OFFSET, pEnabled)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtl8367c_resetVlan ++ * Description: ++ * Reset VLAN table ++ * Input: ++ * None. ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - Success ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * None ++ */ ++ret_t rtl8367c_resetVlan(void) ++{ ++ ret_t retVal; ++ ++ if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_VLAN_EXT_CTRL2, RTL8367C_VLAN_EXT_CTRL2_OFFSET, 1)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/smi.c b/drivers/net/phy/rtk/rtl8367c/smi.c +new file mode 100644 +index 000000000000..e707e4b9c583 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/smi.c +@@ -0,0 +1,442 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * Purpose : RTL8367C switch low-level function for access register ++ * Feature : SMI related functions ++ * ++ */ ++ ++ ++#include ++#include ++#include ++ ++#include "rtk_error.h" ++ ++ ++#if defined(MDC_MDIO_OPERATION) ++/*******************************************************************************/ ++/* MDC/MDIO porting */ ++/*******************************************************************************/ ++/* define the PHY ID currently used */ ++/* carlos */ ++#if 0 ++#define MDC_MDIO_PHY_ID 0 /* PHY ID 0 or 29 */ ++#else ++#define MDC_MDIO_PHY_ID 29 /* PHY ID 0 or 29 */ ++#endif ++ ++/* MDC/MDIO, redefine/implement the following Macro */ /*carlos*/ ++#if 0 ++#define MDC_MDIO_WRITE(preamableLength, phyID, regID, data) ++#define MDC_MDIO_READ(preamableLength, phyID, regID, pData) ++#else ++#define MDC_MDIO_WRITE(preamableLength, phyID, regID, data) mii_mgr_write(phyID, regID, data) ++#define MDC_MDIO_READ(preamableLength, phyID, regID, pData) mii_mgr_read(phyID, regID, pData) ++#endif ++ ++ ++ ++ ++ ++#elif defined(SPI_OPERATION) ++/*******************************************************************************/ ++/* SPI porting */ ++/*******************************************************************************/ ++/* SPI, redefine/implement the following Macro */ ++#define SPI_WRITE(data, length) ++#define SPI_READ(pData, length) ++ ++ ++ ++ ++ ++#else ++/*******************************************************************************/ ++/* I2C porting */ ++/*******************************************************************************/ ++/* Define the GPIO ID for SCK & SDA */ ++rtk_uint32 smi_SCK = 1; /* GPIO used for SMI Clock Generation */ ++rtk_uint32 smi_SDA = 2; /* GPIO used for SMI Data signal */ ++ ++/* I2C, redefine/implement the following Macro */ ++#define GPIO_DIRECTION_SET(gpioID, direction) ++#define GPIO_DATA_SET(gpioID, data) ++#define GPIO_DATA_GET(gpioID, pData) ++ ++ ++ ++ ++ ++#endif ++ ++static void rtlglue_drvMutexLock(void) ++{ ++ /* It is empty currently. Implement this function if Lock/Unlock function is needed */ ++ return; ++} ++ ++static void rtlglue_drvMutexUnlock(void) ++{ ++ /* It is empty currently. Implement this function if Lock/Unlock function is needed */ ++ return; ++} ++ ++ ++ ++#if defined(MDC_MDIO_OPERATION) || defined(SPI_OPERATION) ++ /* No local function in MDC/MDIO & SPI mode */ ++#else ++static void _smi_start(void) ++{ ++ ++ /* change GPIO pin to Output only */ ++ GPIO_DIRECTION_SET(smi_SCK, GPIO_DIR_OUT); ++ GPIO_DIRECTION_SET(smi_SDA, GPIO_DIR_OUT); ++ ++ /* Initial state: SCK: 0, SDA: 1 */ ++ GPIO_DATA_SET(smi_SCK, 0); ++ GPIO_DATA_SET(smi_SDA, 1); ++ CLK_DURATION(DELAY); ++ ++ /* CLK 1: 0 -> 1, 1 -> 0 */ ++ GPIO_DATA_SET(smi_SCK, 1); ++ CLK_DURATION(DELAY); ++ GPIO_DATA_SET(smi_SCK, 0); ++ CLK_DURATION(DELAY); ++ ++ /* CLK 2: */ ++ GPIO_DATA_SET(smi_SCK, 1); ++ CLK_DURATION(DELAY); ++ GPIO_DATA_SET(smi_SDA, 0); ++ CLK_DURATION(DELAY); ++ GPIO_DATA_SET(smi_SCK, 0); ++ CLK_DURATION(DELAY); ++ GPIO_DATA_SET(smi_SDA, 1); ++ ++} ++ ++ ++ ++static void _smi_writeBit(rtk_uint16 signal, rtk_uint32 bitLen) ++{ ++ for( ; bitLen > 0; bitLen--) ++ { ++ CLK_DURATION(DELAY); ++ ++ /* prepare data */ ++ if ( signal & (1<<(bitLen-1)) ) ++ { ++ GPIO_DATA_SET(smi_SDA, 1); ++ } ++ else ++ { ++ GPIO_DATA_SET(smi_SDA, 0); ++ } ++ CLK_DURATION(DELAY); ++ ++ /* clocking */ ++ GPIO_DATA_SET(smi_SCK, 1); ++ CLK_DURATION(DELAY); ++ GPIO_DATA_SET(smi_SCK, 0); ++ } ++} ++ ++ ++ ++static void _smi_readBit(rtk_uint32 bitLen, rtk_uint32 *rData) ++{ ++ rtk_uint32 u = 0; ++ ++ /* change GPIO pin to Input only */ ++ GPIO_DIRECTION_SET(smi_SDA, GPIO_DIR_IN); ++ ++ for (*rData = 0; bitLen > 0; bitLen--) ++ { ++ CLK_DURATION(DELAY); ++ ++ /* clocking */ ++ GPIO_DATA_SET(smi_SCK, 1); ++ CLK_DURATION(DELAY); ++ GPIO_DATA_GET(smi_SDA, &u); ++ GPIO_DATA_SET(smi_SCK, 0); ++ ++ *rData |= (u << (bitLen - 1)); ++ } ++ ++ /* change GPIO pin to Output only */ ++ GPIO_DIRECTION_SET(smi_SDA, GPIO_DIR_OUT); ++} ++ ++ ++ ++static void _smi_stop(void) ++{ ++ ++ CLK_DURATION(DELAY); ++ GPIO_DATA_SET(smi_SDA, 0); ++ GPIO_DATA_SET(smi_SCK, 1); ++ CLK_DURATION(DELAY); ++ GPIO_DATA_SET(smi_SDA, 1); ++ CLK_DURATION(DELAY); ++ GPIO_DATA_SET(smi_SCK, 1); ++ CLK_DURATION(DELAY); ++ GPIO_DATA_SET(smi_SCK, 0); ++ CLK_DURATION(DELAY); ++ GPIO_DATA_SET(smi_SCK, 1); ++ ++ /* add a click */ ++ CLK_DURATION(DELAY); ++ GPIO_DATA_SET(smi_SCK, 0); ++ CLK_DURATION(DELAY); ++ GPIO_DATA_SET(smi_SCK, 1); ++ ++ ++ /* change GPIO pin to Input only */ ++ GPIO_DIRECTION_SET(smi_SDA, GPIO_DIR_IN); ++ GPIO_DIRECTION_SET(smi_SCK, GPIO_DIR_IN); ++} ++ ++#endif /* End of #if defined(MDC_MDIO_OPERATION) || defined(SPI_OPERATION) */ ++ ++rtk_int32 smi_read(rtk_uint32 mAddrs, rtk_uint32 *rData) ++{ ++#if (!defined(MDC_MDIO_OPERATION) && !defined(SPI_OPERATION)) ++ rtk_uint32 rawData=0, ACK; ++ rtk_uint8 con; ++ rtk_uint32 ret = RT_ERR_OK; ++#endif ++ ++ if(mAddrs > 0xFFFF) ++ return RT_ERR_INPUT; ++ ++ if(rData == NULL) ++ return RT_ERR_NULL_POINTER; ++ ++#if defined(MDC_MDIO_OPERATION) ++ ++ /* Lock */ ++ rtlglue_drvMutexLock(); ++ ++ /* Write address control code to register 31 */ ++ MDC_MDIO_WRITE(MDC_MDIO_PREAMBLE_LEN, MDC_MDIO_PHY_ID, MDC_MDIO_CTRL0_REG, MDC_MDIO_ADDR_OP); ++ ++ /* Write address to register 23 */ ++ MDC_MDIO_WRITE(MDC_MDIO_PREAMBLE_LEN, MDC_MDIO_PHY_ID, MDC_MDIO_ADDRESS_REG, mAddrs); ++ ++ /* Write read control code to register 21 */ ++ MDC_MDIO_WRITE(MDC_MDIO_PREAMBLE_LEN, MDC_MDIO_PHY_ID, MDC_MDIO_CTRL1_REG, MDC_MDIO_READ_OP); ++ ++ /* Read data from register 25 */ ++ MDC_MDIO_READ(MDC_MDIO_PREAMBLE_LEN, MDC_MDIO_PHY_ID, MDC_MDIO_DATA_READ_REG, rData); ++ ++ /* Unlock */ ++ rtlglue_drvMutexUnlock(); ++ ++ return RT_ERR_OK; ++ ++#elif defined(SPI_OPERATION) ++ ++ /* Lock */ ++ rtlglue_drvMutexLock(); ++ ++ /* Write 8 bits READ OP_CODE */ ++ SPI_WRITE(SPI_READ_OP, SPI_READ_OP_LEN); ++ ++ /* Write 16 bits register address */ ++ SPI_WRITE(mAddrs, SPI_REG_LEN); ++ ++ /* Read 16 bits data */ ++ SPI_READ(rData, SPI_DATA_LEN); ++ ++ /* Unlock */ ++ rtlglue_drvMutexUnlock(); ++ ++ return RT_ERR_OK; ++ ++#else ++ ++ /*Disable CPU interrupt to ensure that the SMI operation is atomic. ++ The API is based on RTL865X, rewrite the API if porting to other platform.*/ ++ rtlglue_drvMutexLock(); ++ ++ _smi_start(); /* Start SMI */ ++ ++ _smi_writeBit(0x0b, 4); /* CTRL code: 4'b1011 for RTL8370 */ ++ ++ _smi_writeBit(0x4, 3); /* CTRL code: 3'b100 */ ++ ++ _smi_writeBit(0x1, 1); /* 1: issue READ command */ ++ ++ con = 0; ++ do { ++ con++; ++ _smi_readBit(1, &ACK); /* ACK for issuing READ command*/ ++ } while ((ACK != 0) && (con < ack_timer)); ++ ++ if (ACK != 0) ret = RT_ERR_FAILED; ++ ++ _smi_writeBit((mAddrs&0xff), 8); /* Set reg_addr[7:0] */ ++ ++ con = 0; ++ do { ++ con++; ++ _smi_readBit(1, &ACK); /* ACK for setting reg_addr[7:0] */ ++ } while ((ACK != 0) && (con < ack_timer)); ++ ++ if (ACK != 0) ret = RT_ERR_FAILED; ++ ++ _smi_writeBit((mAddrs>>8), 8); /* Set reg_addr[15:8] */ ++ ++ con = 0; ++ do { ++ con++; ++ _smi_readBit(1, &ACK); /* ACK by RTL8369 */ ++ } while ((ACK != 0) && (con < ack_timer)); ++ if (ACK != 0) ret = RT_ERR_FAILED; ++ ++ _smi_readBit(8, &rawData); /* Read DATA [7:0] */ ++ *rData = rawData&0xff; ++ ++ _smi_writeBit(0x00, 1); /* ACK by CPU */ ++ ++ _smi_readBit(8, &rawData); /* Read DATA [15: 8] */ ++ ++ _smi_writeBit(0x01, 1); /* ACK by CPU */ ++ *rData |= (rawData<<8); ++ ++ _smi_stop(); ++ ++ rtlglue_drvMutexUnlock();/*enable CPU interrupt*/ ++ ++ return ret; ++#endif /* end of #if defined(MDC_MDIO_OPERATION) */ ++} ++ ++ ++ ++rtk_int32 smi_write(rtk_uint32 mAddrs, rtk_uint32 rData) ++{ ++#if (!defined(MDC_MDIO_OPERATION) && !defined(SPI_OPERATION)) ++ rtk_int8 con; ++ rtk_uint32 ACK; ++ rtk_uint32 ret = RT_ERR_OK; ++#endif ++ ++ if(mAddrs > 0xFFFF) ++ return RT_ERR_INPUT; ++ ++ if(rData > 0xFFFF) ++ return RT_ERR_INPUT; ++ ++#if defined(MDC_MDIO_OPERATION) ++ ++ /* Lock */ ++ rtlglue_drvMutexLock(); ++ ++ /* Write address control code to register 31 */ ++ MDC_MDIO_WRITE(MDC_MDIO_PREAMBLE_LEN, MDC_MDIO_PHY_ID, MDC_MDIO_CTRL0_REG, MDC_MDIO_ADDR_OP); ++ ++ /* Write address to register 23 */ ++ MDC_MDIO_WRITE(MDC_MDIO_PREAMBLE_LEN, MDC_MDIO_PHY_ID, MDC_MDIO_ADDRESS_REG, mAddrs); ++ ++ /* Write data to register 24 */ ++ MDC_MDIO_WRITE(MDC_MDIO_PREAMBLE_LEN, MDC_MDIO_PHY_ID, MDC_MDIO_DATA_WRITE_REG, rData); ++ ++ /* Write data control code to register 21 */ ++ MDC_MDIO_WRITE(MDC_MDIO_PREAMBLE_LEN, MDC_MDIO_PHY_ID, MDC_MDIO_CTRL1_REG, MDC_MDIO_WRITE_OP); ++ ++ /* Unlock */ ++ rtlglue_drvMutexUnlock(); ++ ++ return RT_ERR_OK; ++ ++#elif defined(SPI_OPERATION) ++ ++ /* Lock */ ++ rtlglue_drvMutexLock(); ++ ++ /* Write 8 bits WRITE OP_CODE */ ++ SPI_WRITE(SPI_WRITE_OP, SPI_WRITE_OP_LEN); ++ ++ /* Write 16 bits register address */ ++ SPI_WRITE(mAddrs, SPI_REG_LEN); ++ ++ /* Write 16 bits data */ ++ SPI_WRITE(rData, SPI_DATA_LEN); ++ ++ /* Unlock */ ++ rtlglue_drvMutexUnlock(); ++ ++ return RT_ERR_OK; ++#else ++ ++ /*Disable CPU interrupt to ensure that the SMI operation is atomic. ++ The API is based on RTL865X, rewrite the API if porting to other platform.*/ ++ rtlglue_drvMutexLock(); ++ ++ _smi_start(); /* Start SMI */ ++ ++ _smi_writeBit(0x0b, 4); /* CTRL code: 4'b1011 for RTL8370*/ ++ ++ _smi_writeBit(0x4, 3); /* CTRL code: 3'b100 */ ++ ++ _smi_writeBit(0x0, 1); /* 0: issue WRITE command */ ++ ++ con = 0; ++ do { ++ con++; ++ _smi_readBit(1, &ACK); /* ACK for issuing WRITE command*/ ++ } while ((ACK != 0) && (con < ack_timer)); ++ if (ACK != 0) ret = RT_ERR_FAILED; ++ ++ _smi_writeBit((mAddrs&0xff), 8); /* Set reg_addr[7:0] */ ++ ++ con = 0; ++ do { ++ con++; ++ _smi_readBit(1, &ACK); /* ACK for setting reg_addr[7:0] */ ++ } while ((ACK != 0) && (con < ack_timer)); ++ if (ACK != 0) ret = RT_ERR_FAILED; ++ ++ _smi_writeBit((mAddrs>>8), 8); /* Set reg_addr[15:8] */ ++ ++ con = 0; ++ do { ++ con++; ++ _smi_readBit(1, &ACK); /* ACK for setting reg_addr[15:8] */ ++ } while ((ACK != 0) && (con < ack_timer)); ++ if (ACK != 0) ret = RT_ERR_FAILED; ++ ++ _smi_writeBit(rData&0xff, 8); /* Write Data [7:0] out */ ++ ++ con = 0; ++ do { ++ con++; ++ _smi_readBit(1, &ACK); /* ACK for writing data [7:0] */ ++ } while ((ACK != 0) && (con < ack_timer)); ++ if (ACK != 0) ret = RT_ERR_FAILED; ++ ++ _smi_writeBit(rData>>8, 8); /* Write Data [15:8] out */ ++ ++ con = 0; ++ do { ++ con++; ++ _smi_readBit(1, &ACK); /* ACK for writing data [15:8] */ ++ } while ((ACK != 0) && (con < ack_timer)); ++ if (ACK != 0) ret = RT_ERR_FAILED; ++ ++ _smi_stop(); ++ ++ rtlglue_drvMutexUnlock();/*enable CPU interrupt*/ ++ ++ return ret; ++#endif /* end of #if defined(MDC_MDIO_OPERATION) */ ++} ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/stat.c b/drivers/net/phy/rtk/rtl8367c/stat.c +new file mode 100644 +index 000000000000..3fd028a296e4 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/stat.c +@@ -0,0 +1,626 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ ++ * ++ * Purpose : RTK switch high-level API for RTL8367/RTL8367C ++ * Feature : Here is a list of all functions and variables in MIB module. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++/* Function Name: ++ * rtk_stat_global_reset ++ * Description: ++ * Reset global MIB counter. ++ * Input: ++ * None ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * Reset MIB counter of ports. API will use global reset while port mask is all-ports. ++ */ ++rtk_api_ret_t rtk_stat_global_reset(void) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if ((retVal = rtl8367c_setAsicMIBsCounterReset(TRUE,FALSE, 0)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_stat_port_reset ++ * Description: ++ * Reset per port MIB counter by port. ++ * Input: ++ * port - port id. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_stat_port_reset(rtk_port_t port) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check port valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if ((retVal = rtl8367c_setAsicMIBsCounterReset(FALSE,FALSE,1 << rtk_switch_port_L2P_get(port))) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_stat_queueManage_reset ++ * Description: ++ * Reset queue manage MIB counter. ++ * Input: ++ * None ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_stat_queueManage_reset(void) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if ((retVal = rtl8367c_setAsicMIBsCounterReset(FALSE,TRUE,0)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++ ++/* Function Name: ++ * rtk_stat_global_get ++ * Description: ++ * Get global MIB counter ++ * Input: ++ * cntr_idx - global counter index. ++ * Output: ++ * pCntr - global counter value. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * Get global MIB counter by index definition. ++ */ ++rtk_api_ret_t rtk_stat_global_get(rtk_stat_global_type_t cntr_idx, rtk_stat_counter_t *pCntr) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pCntr) ++ return RT_ERR_NULL_POINTER; ++ ++ if (cntr_idx!=DOT1D_TP_LEARNED_ENTRY_DISCARDS_INDEX) ++ return RT_ERR_STAT_INVALID_GLOBAL_CNTR; ++ ++ if ((retVal = rtl8367c_getAsicMIBsCounter(0, (RTL8367C_MIBCOUNTER)cntr_idx, pCntr)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_stat_global_getAll ++ * Description: ++ * Get all global MIB counter ++ * Input: ++ * None ++ * Output: ++ * pGlobal_cntrs - global counter structure. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * Get all global MIB counter by index definition. ++ */ ++rtk_api_ret_t rtk_stat_global_getAll(rtk_stat_global_cntr_t *pGlobal_cntrs) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pGlobal_cntrs) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicMIBsCounter(0, dot1dTpLearnedEntryDiscards, &pGlobal_cntrs->dot1dTpLearnedEntryDiscards)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++#define MIB_NOT_SUPPORT (0xFFFF) ++static rtk_api_ret_t _get_asic_mib_idx(rtk_stat_port_type_t cnt_idx, RTL8367C_MIBCOUNTER *pMib_idx) ++{ ++ RTL8367C_MIBCOUNTER mib_asic_idx[STAT_PORT_CNTR_END]= ++ { ++ ifInOctets, /* STAT_IfInOctets */ ++ dot3StatsFCSErrors, /* STAT_Dot3StatsFCSErrors */ ++ dot3StatsSymbolErrors, /* STAT_Dot3StatsSymbolErrors */ ++ dot3InPauseFrames, /* STAT_Dot3InPauseFrames */ ++ dot3ControlInUnknownOpcodes, /* STAT_Dot3ControlInUnknownOpcodes */ ++ etherStatsFragments, /* STAT_EtherStatsFragments */ ++ etherStatsJabbers, /* STAT_EtherStatsJabbers */ ++ ifInUcastPkts, /* STAT_IfInUcastPkts */ ++ etherStatsDropEvents, /* STAT_EtherStatsDropEvents */ ++ etherStatsOctets, /* STAT_EtherStatsOctets */ ++ etherStatsUnderSizePkts, /* STAT_EtherStatsUnderSizePkts */ ++ etherOversizeStats, /* STAT_EtherOversizeStats */ ++ etherStatsPkts64Octets, /* STAT_EtherStatsPkts64Octets */ ++ etherStatsPkts65to127Octets, /* STAT_EtherStatsPkts65to127Octets */ ++ etherStatsPkts128to255Octets, /* STAT_EtherStatsPkts128to255Octets */ ++ etherStatsPkts256to511Octets, /* STAT_EtherStatsPkts256to511Octets */ ++ etherStatsPkts512to1023Octets, /* STAT_EtherStatsPkts512to1023Octets */ ++ etherStatsPkts1024to1518Octets, /* STAT_EtherStatsPkts1024to1518Octets */ ++ ifInMulticastPkts, /* STAT_EtherStatsMulticastPkts */ ++ ifInBroadcastPkts, /* STAT_EtherStatsBroadcastPkts */ ++ ifOutOctets, /* STAT_IfOutOctets */ ++ dot3StatsSingleCollisionFrames, /* STAT_Dot3StatsSingleCollisionFrames */ ++ dot3StatMultipleCollisionFrames,/* STAT_Dot3StatsMultipleCollisionFrames */ ++ dot3sDeferredTransmissions, /* STAT_Dot3StatsDeferredTransmissions */ ++ dot3StatsLateCollisions, /* STAT_Dot3StatsLateCollisions */ ++ etherStatsCollisions, /* STAT_EtherStatsCollisions */ ++ dot3StatsExcessiveCollisions, /* STAT_Dot3StatsExcessiveCollisions */ ++ dot3OutPauseFrames, /* STAT_Dot3OutPauseFrames */ ++ MIB_NOT_SUPPORT, /* STAT_Dot1dBasePortDelayExceededDiscards */ ++ dot1dTpPortInDiscards, /* STAT_Dot1dTpPortInDiscards */ ++ ifOutUcastPkts, /* STAT_IfOutUcastPkts */ ++ ifOutMulticastPkts, /* STAT_IfOutMulticastPkts */ ++ ifOutBroadcastPkts, /* STAT_IfOutBroadcastPkts */ ++ outOampduPkts, /* STAT_OutOampduPkts */ ++ inOampduPkts, /* STAT_InOampduPkts */ ++ MIB_NOT_SUPPORT, /* STAT_PktgenPkts */ ++ inMldChecksumError, /* STAT_InMldChecksumError */ ++ inIgmpChecksumError, /* STAT_InIgmpChecksumError */ ++ inMldSpecificQuery, /* STAT_InMldSpecificQuery */ ++ inMldGeneralQuery, /* STAT_InMldGeneralQuery */ ++ inIgmpSpecificQuery, /* STAT_InIgmpSpecificQuery */ ++ inIgmpGeneralQuery, /* STAT_InIgmpGeneralQuery */ ++ inMldLeaves, /* STAT_InMldLeaves */ ++ inIgmpLeaves, /* STAT_InIgmpInterfaceLeaves */ ++ inIgmpJoinsSuccess, /* STAT_InIgmpJoinsSuccess */ ++ inIgmpJoinsFail, /* STAT_InIgmpJoinsFail */ ++ inMldJoinsSuccess, /* STAT_InMldJoinsSuccess */ ++ inMldJoinsFail, /* STAT_InMldJoinsFail */ ++ inReportSuppressionDrop, /* STAT_InReportSuppressionDrop */ ++ inLeaveSuppressionDrop, /* STAT_InLeaveSuppressionDrop */ ++ outIgmpReports, /* STAT_OutIgmpReports */ ++ outIgmpLeaves, /* STAT_OutIgmpLeaves */ ++ outIgmpGeneralQuery, /* STAT_OutIgmpGeneralQuery */ ++ outIgmpSpecificQuery, /* STAT_OutIgmpSpecificQuery */ ++ outMldReports, /* STAT_OutMldReports */ ++ outMldLeaves, /* STAT_OutMldLeaves */ ++ outMldGeneralQuery, /* STAT_OutMldGeneralQuery */ ++ outMldSpecificQuery, /* STAT_OutMldSpecificQuery */ ++ inKnownMulticastPkts, /* STAT_InKnownMulticastPkts */ ++ ifInMulticastPkts, /* STAT_IfInMulticastPkts */ ++ ifInBroadcastPkts, /* STAT_IfInBroadcastPkts */ ++ ifOutDiscards /* STAT_IfOutDiscards */ ++ }; ++ ++ if(cnt_idx >= STAT_PORT_CNTR_END) ++ return RT_ERR_STAT_INVALID_PORT_CNTR; ++ ++ if(mib_asic_idx[cnt_idx] == MIB_NOT_SUPPORT) ++ return RT_ERR_CHIP_NOT_SUPPORTED; ++ ++ *pMib_idx = mib_asic_idx[cnt_idx]; ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_stat_port_get ++ * Description: ++ * Get per port MIB counter by index ++ * Input: ++ * port - port id. ++ * cntr_idx - port counter index. ++ * Output: ++ * pCntr - MIB retrieved counter. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * Get per port MIB counter by index definition. ++ */ ++rtk_api_ret_t rtk_stat_port_get(rtk_port_t port, rtk_stat_port_type_t cntr_idx, rtk_stat_counter_t *pCntr) ++{ ++ rtk_api_ret_t retVal; ++ RTL8367C_MIBCOUNTER mib_idx; ++ rtk_stat_counter_t second_cnt; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pCntr) ++ return RT_ERR_NULL_POINTER; ++ ++ /* Check port valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if (cntr_idx>=STAT_PORT_CNTR_END) ++ return RT_ERR_STAT_INVALID_PORT_CNTR; ++ ++ if((retVal = _get_asic_mib_idx(cntr_idx, &mib_idx)) != RT_ERR_OK) ++ return retVal; ++ ++ if(mib_idx == MIB_NOT_SUPPORT) ++ return RT_ERR_CHIP_NOT_SUPPORTED; ++ ++ if ((retVal = rtl8367c_getAsicMIBsCounter(rtk_switch_port_L2P_get(port), mib_idx, pCntr)) != RT_ERR_OK) ++ return retVal; ++ ++ if(cntr_idx == STAT_EtherStatsMulticastPkts) ++ { ++ if((retVal = _get_asic_mib_idx(STAT_IfOutMulticastPkts, &mib_idx)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_getAsicMIBsCounter(rtk_switch_port_L2P_get(port), mib_idx, &second_cnt)) != RT_ERR_OK) ++ return retVal; ++ ++ *pCntr += second_cnt; ++ } ++ ++ if(cntr_idx == STAT_EtherStatsBroadcastPkts) ++ { ++ if((retVal = _get_asic_mib_idx(STAT_IfOutBroadcastPkts, &mib_idx)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_getAsicMIBsCounter(rtk_switch_port_L2P_get(port), mib_idx, &second_cnt)) != RT_ERR_OK) ++ return retVal; ++ ++ *pCntr += second_cnt; ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_stat_port_getAll ++ * Description: ++ * Get all counters of one specified port in the specified device. ++ * Input: ++ * port - port id. ++ * Output: ++ * pPort_cntrs - buffer pointer of counter value. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * Get all MIB counters of one port. ++ */ ++rtk_api_ret_t rtk_stat_port_getAll(rtk_port_t port, rtk_stat_port_cntr_t *pPort_cntrs) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 mibIndex; ++ rtk_uint64 mibCounter; ++ rtk_uint32 *accessPtr; ++ /* address offset to MIBs counter */ ++ CONST_T rtk_uint16 mibLength[STAT_PORT_CNTR_END]= { ++ 2,1,1,1,1,1,1,1,1, ++ 2,1,1,1,1,1,1,1,1,1,1, ++ 2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, ++ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pPort_cntrs) ++ return RT_ERR_NULL_POINTER; ++ ++ /* Check port valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ accessPtr = (rtk_uint32*)pPort_cntrs; ++ for (mibIndex=0;mibIndex RTL8367C_MIB_MAX_LOG_CNT_IDX) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ if((idx % 2) == 1) ++ return RT_ERR_INPUT; ++ ++ if(mode >= LOGGING_MODE_END) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ if(type >= LOGGING_TYPE_END) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ if((retVal = rtl8367c_setAsicMIBsLoggingType((idx / 2), (rtk_uint32)type)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicMIBsLoggingMode((idx / 2), (rtk_uint32)mode)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_stat_logging_counterCfg_get ++ * Description: ++ * Get the type and mode of Logging Counter ++ * Input: ++ * idx - The index of Logging Counter. Should be even number only.(0,2,4,6,8.....30) ++ * Output: ++ * pMode - 32 bits or 64 bits mode ++ * pType - Packet counter or byte counter ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_OUT_OF_RANGE - Out of range. ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_NULL_POINTER - NULL Pointer ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * Get the type and mode of Logging Counter. ++ */ ++rtk_api_ret_t rtk_stat_logging_counterCfg_get(rtk_uint32 idx, rtk_logging_counter_mode_t *pMode, rtk_logging_counter_type_t *pType) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 type, mode; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(idx > RTL8367C_MIB_MAX_LOG_CNT_IDX) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ if((idx % 2) == 1) ++ return RT_ERR_INPUT; ++ ++ if(pMode == NULL) ++ return RT_ERR_NULL_POINTER; ++ ++ if(pType == NULL) ++ return RT_ERR_NULL_POINTER; ++ ++ if((retVal = rtl8367c_getAsicMIBsLoggingType((idx / 2), &type)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_getAsicMIBsLoggingMode((idx / 2), &mode)) != RT_ERR_OK) ++ return retVal; ++ ++ *pMode = (rtk_logging_counter_mode_t)mode; ++ *pType = (rtk_logging_counter_type_t)type; ++ ++ return RT_ERR_OK; ++} ++ ++ ++/* Function Name: ++ * rtk_stat_logging_counter_reset ++ * Description: ++ * Reset Logging Counter ++ * Input: ++ * idx - The index of Logging Counter. (0~31) ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_OUT_OF_RANGE - Out of range. ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * Reset Logging Counter. ++ */ ++rtk_api_ret_t rtk_stat_logging_counter_reset(rtk_uint32 idx) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(idx > RTL8367C_MIB_MAX_LOG_CNT_IDX) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ if((retVal = rtl8367c_setAsicMIBsResetLoggingCounter(idx)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_stat_logging_counter_get ++ * Description: ++ * Get Logging Counter ++ * Input: ++ * idx - The index of Logging Counter. (0~31) ++ * Output: ++ * pCnt - Logging counter value ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_OUT_OF_RANGE - Out of range. ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * Get Logging Counter. ++ */ ++rtk_api_ret_t rtk_stat_logging_counter_get(rtk_uint32 idx, rtk_uint32 *pCnt) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pCnt) ++ return RT_ERR_NULL_POINTER; ++ ++ if(idx > RTL8367C_MIB_MAX_LOG_CNT_IDX) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ if((retVal = rtl8367c_getAsicMIBsLogCounter(idx, pCnt)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_stat_lengthMode_set ++ * Description: ++ * Set Legnth mode. ++ * Input: ++ * txMode - The length counting mode ++ * rxMode - The length counting mode ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_INPUT - Out of range. ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_stat_lengthMode_set(rtk_stat_lengthMode_t txMode, rtk_stat_lengthMode_t rxMode) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(txMode >= LENGTH_MODE_END) ++ return RT_ERR_INPUT; ++ ++ if(rxMode >= LENGTH_MODE_END) ++ return RT_ERR_INPUT; ++ ++ if((retVal = rtl8367c_setAsicMIBsLength((rtk_uint32)txMode, (rtk_uint32)rxMode)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_stat_lengthMode_get ++ * Description: ++ * Get Length mode. ++ * Input: ++ * None. ++ * Output: ++ * pTxMode - The length counting mode ++ * pRxMode - The length counting mode ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_INPUT - Out of range. ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ */ ++rtk_api_ret_t rtk_stat_lengthMode_get(rtk_stat_lengthMode_t *pTxMode, rtk_stat_lengthMode_t *pRxMode) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pTxMode) ++ return RT_ERR_NULL_POINTER; ++ ++ if(NULL == pRxMode) ++ return RT_ERR_NULL_POINTER; ++ ++ if((retVal = rtl8367c_getAsicMIBsLength((rtk_uint32 *)pTxMode, (rtk_uint32 *)pRxMode)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/storm.c b/drivers/net/phy/rtk/rtl8367c/storm.c +new file mode 100644 +index 000000000000..68063cdfa75f +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/storm.c +@@ -0,0 +1,816 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ ++ * ++ * Purpose : RTK switch high-level API for RTL8367/RTL8367C ++ * Feature : Here is a list of all functions and variables in Storm module. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Function Name: ++ * rtk_rate_stormControlMeterIdx_set ++ * Description: ++ * Set the storm control meter index. ++ * Input: ++ * port - port id ++ * storm_type - storm group type ++ * index - storm control meter index. ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_PORT_ID - Invalid port id ++ * RT_ERR_FILTER_METER_ID - Invalid meter ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_rate_stormControlMeterIdx_set(rtk_port_t port, rtk_rate_storm_group_t stormType, rtk_uint32 index) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if (stormType >= STORM_GROUP_END) ++ return RT_ERR_SFC_UNKNOWN_GROUP; ++ ++ if (index > RTK_MAX_METER_ID) ++ return RT_ERR_FILTER_METER_ID; ++ ++ switch (stormType) ++ { ++ case STORM_GROUP_UNKNOWN_UNICAST: ++ if ((retVal = rtl8367c_setAsicStormFilterUnknownUnicastMeter(rtk_switch_port_L2P_get(port), index))!=RT_ERR_OK) ++ return retVal; ++ break; ++ case STORM_GROUP_UNKNOWN_MULTICAST: ++ if ((retVal = rtl8367c_setAsicStormFilterUnknownMulticastMeter(rtk_switch_port_L2P_get(port), index))!=RT_ERR_OK) ++ return retVal; ++ break; ++ case STORM_GROUP_MULTICAST: ++ if ((retVal = rtl8367c_setAsicStormFilterMulticastMeter(rtk_switch_port_L2P_get(port), index))!=RT_ERR_OK) ++ return retVal; ++ break; ++ case STORM_GROUP_BROADCAST: ++ if ((retVal = rtl8367c_setAsicStormFilterBroadcastMeter(rtk_switch_port_L2P_get(port), index))!=RT_ERR_OK) ++ return retVal; ++ break; ++ default: ++ break; ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_rate_stormControlMeterIdx_get ++ * Description: ++ * Get the storm control meter index. ++ * Input: ++ * port - port id ++ * storm_type - storm group type ++ * Output: ++ * pIndex - storm control meter index. ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_PORT_ID - Invalid port id ++ * RT_ERR_FILTER_METER_ID - Invalid meter ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_rate_stormControlMeterIdx_get(rtk_port_t port, rtk_rate_storm_group_t stormType, rtk_uint32 *pIndex) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if (stormType >= STORM_GROUP_END) ++ return RT_ERR_SFC_UNKNOWN_GROUP; ++ ++ if (NULL == pIndex ) ++ return RT_ERR_NULL_POINTER; ++ ++ switch (stormType) ++ { ++ case STORM_GROUP_UNKNOWN_UNICAST: ++ if ((retVal = rtl8367c_getAsicStormFilterUnknownUnicastMeter(rtk_switch_port_L2P_get(port), pIndex))!=RT_ERR_OK) ++ return retVal; ++ break; ++ case STORM_GROUP_UNKNOWN_MULTICAST: ++ if ((retVal = rtl8367c_getAsicStormFilterUnknownMulticastMeter(rtk_switch_port_L2P_get(port), pIndex))!=RT_ERR_OK) ++ return retVal; ++ break; ++ case STORM_GROUP_MULTICAST: ++ if ((retVal = rtl8367c_getAsicStormFilterMulticastMeter(rtk_switch_port_L2P_get(port), pIndex))!=RT_ERR_OK) ++ return retVal; ++ break; ++ case STORM_GROUP_BROADCAST: ++ if ((retVal = rtl8367c_getAsicStormFilterBroadcastMeter(rtk_switch_port_L2P_get(port), pIndex))!=RT_ERR_OK) ++ return retVal; ++ break; ++ default: ++ break; ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_rate_stormControlPortEnable_set ++ * Description: ++ * Set enable status of storm control on specified port. ++ * Input: ++ * port - port id ++ * stormType - storm group type ++ * enable - enable status of storm control ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_NOT_INIT - The module is not initial ++ * RT_ERR_PORT_ID - invalid port id ++ * RT_ERR_INPUT - invalid input parameter ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_rate_stormControlPortEnable_set(rtk_port_t port, rtk_rate_storm_group_t stormType, rtk_enable_t enable) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if (stormType >= STORM_GROUP_END) ++ return RT_ERR_SFC_UNKNOWN_GROUP; ++ ++ if (enable >= RTK_ENABLE_END) ++ return RT_ERR_ENABLE; ++ ++ switch (stormType) ++ { ++ case STORM_GROUP_UNKNOWN_UNICAST: ++ if ((retVal = rtl8367c_setAsicStormFilterUnknownUnicastEnable(rtk_switch_port_L2P_get(port), enable)) != RT_ERR_OK) ++ return retVal; ++ break; ++ case STORM_GROUP_UNKNOWN_MULTICAST: ++ if ((retVal = rtl8367c_setAsicStormFilterUnknownMulticastEnable(rtk_switch_port_L2P_get(port), enable)) != RT_ERR_OK) ++ return retVal; ++ break; ++ case STORM_GROUP_MULTICAST: ++ if ((retVal = rtl8367c_setAsicStormFilterMulticastEnable(rtk_switch_port_L2P_get(port), enable)) != RT_ERR_OK) ++ return retVal; ++ break; ++ case STORM_GROUP_BROADCAST: ++ if ((retVal = rtl8367c_setAsicStormFilterBroadcastEnable(rtk_switch_port_L2P_get(port), enable)) != RT_ERR_OK) ++ return retVal; ++ break; ++ default: ++ break; ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_rate_stormControlPortEnable_set ++ * Description: ++ * Set enable status of storm control on specified port. ++ * Input: ++ * port - port id ++ * stormType - storm group type ++ * Output: ++ * pEnable - enable status of storm control ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_NOT_INIT - The module is not initial ++ * RT_ERR_PORT_ID - invalid port id ++ * RT_ERR_INPUT - invalid input parameter ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_rate_stormControlPortEnable_get(rtk_port_t port, rtk_rate_storm_group_t stormType, rtk_enable_t *pEnable) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if (stormType >= STORM_GROUP_END) ++ return RT_ERR_SFC_UNKNOWN_GROUP; ++ ++ if (NULL == pEnable) ++ return RT_ERR_ENABLE; ++ ++ switch (stormType) ++ { ++ case STORM_GROUP_UNKNOWN_UNICAST: ++ if ((retVal = rtl8367c_getAsicStormFilterUnknownUnicastEnable(rtk_switch_port_L2P_get(port), pEnable)) != RT_ERR_OK) ++ return retVal; ++ break; ++ case STORM_GROUP_UNKNOWN_MULTICAST: ++ if ((retVal = rtl8367c_getAsicStormFilterUnknownMulticastEnable(rtk_switch_port_L2P_get(port), pEnable)) != RT_ERR_OK) ++ return retVal; ++ break; ++ case STORM_GROUP_MULTICAST: ++ if ((retVal = rtl8367c_getAsicStormFilterMulticastEnable(rtk_switch_port_L2P_get(port), pEnable)) != RT_ERR_OK) ++ return retVal; ++ break; ++ case STORM_GROUP_BROADCAST: ++ if ((retVal = rtl8367c_getAsicStormFilterBroadcastEnable(rtk_switch_port_L2P_get(port), pEnable)) != RT_ERR_OK) ++ return retVal; ++ break; ++ default: ++ break; ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_storm_bypass_set ++ * Description: ++ * Set bypass storm filter control configuration. ++ * Input: ++ * type - Bypass storm filter control type. ++ * enable - Bypass status. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_ENABLE - Invalid IFG parameter ++ * Note: ++ * ++ * This API can set per-port bypass storm filter control frame type including RMA and IGMP. ++ * The bypass frame type is as following: ++ * - BYPASS_BRG_GROUP, ++ * - BYPASS_FD_PAUSE, ++ * - BYPASS_SP_MCAST, ++ * - BYPASS_1X_PAE, ++ * - BYPASS_UNDEF_BRG_04, ++ * - BYPASS_UNDEF_BRG_05, ++ * - BYPASS_UNDEF_BRG_06, ++ * - BYPASS_UNDEF_BRG_07, ++ * - BYPASS_PROVIDER_BRIDGE_GROUP_ADDRESS, ++ * - BYPASS_UNDEF_BRG_09, ++ * - BYPASS_UNDEF_BRG_0A, ++ * - BYPASS_UNDEF_BRG_0B, ++ * - BYPASS_UNDEF_BRG_0C, ++ * - BYPASS_PROVIDER_BRIDGE_GVRP_ADDRESS, ++ * - BYPASS_8021AB, ++ * - BYPASS_UNDEF_BRG_0F, ++ * - BYPASS_BRG_MNGEMENT, ++ * - BYPASS_UNDEFINED_11, ++ * - BYPASS_UNDEFINED_12, ++ * - BYPASS_UNDEFINED_13, ++ * - BYPASS_UNDEFINED_14, ++ * - BYPASS_UNDEFINED_15, ++ * - BYPASS_UNDEFINED_16, ++ * - BYPASS_UNDEFINED_17, ++ * - BYPASS_UNDEFINED_18, ++ * - BYPASS_UNDEFINED_19, ++ * - BYPASS_UNDEFINED_1A, ++ * - BYPASS_UNDEFINED_1B, ++ * - BYPASS_UNDEFINED_1C, ++ * - BYPASS_UNDEFINED_1D, ++ * - BYPASS_UNDEFINED_1E, ++ * - BYPASS_UNDEFINED_1F, ++ * - BYPASS_GMRP, ++ * - BYPASS_GVRP, ++ * - BYPASS_UNDEF_GARP_22, ++ * - BYPASS_UNDEF_GARP_23, ++ * - BYPASS_UNDEF_GARP_24, ++ * - BYPASS_UNDEF_GARP_25, ++ * - BYPASS_UNDEF_GARP_26, ++ * - BYPASS_UNDEF_GARP_27, ++ * - BYPASS_UNDEF_GARP_28, ++ * - BYPASS_UNDEF_GARP_29, ++ * - BYPASS_UNDEF_GARP_2A, ++ * - BYPASS_UNDEF_GARP_2B, ++ * - BYPASS_UNDEF_GARP_2C, ++ * - BYPASS_UNDEF_GARP_2D, ++ * - BYPASS_UNDEF_GARP_2E, ++ * - BYPASS_UNDEF_GARP_2F, ++ * - BYPASS_IGMP. ++ * - BYPASS_CDP. ++ * - BYPASS_CSSTP. ++ * - BYPASS_LLDP. ++ */ ++rtk_api_ret_t rtk_storm_bypass_set(rtk_storm_bypass_t type, rtk_enable_t enable) ++{ ++ rtk_api_ret_t retVal; ++ rtl8367c_rma_t rmacfg; ++ rtk_uint32 tmp; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (type >= BYPASS_END) ++ return RT_ERR_INPUT; ++ ++ if (enable >= RTK_ENABLE_END) ++ return RT_ERR_INPUT; ++ ++ if (type >= 0 && type <= BYPASS_UNDEF_GARP_2F) ++ { ++ if ((retVal = rtl8367c_getAsicRma(type, &rmacfg)) != RT_ERR_OK) ++ return retVal; ++ ++ rmacfg.discard_storm_filter = enable; ++ ++ if ((retVal = rtl8367c_setAsicRma(type, &rmacfg)) != RT_ERR_OK) ++ return retVal; ++ } ++ else if(type == BYPASS_IGMP) ++ { ++ if ((retVal = rtl8367c_setAsicIGMPBypassStormCTRL(enable)) != RT_ERR_OK) ++ return retVal; ++ } ++ else if (type == BYPASS_CDP) ++ { ++ if ((retVal = rtl8367c_getAsicRmaCdp(&rmacfg)) != RT_ERR_OK) ++ return retVal; ++ ++ rmacfg.discard_storm_filter = enable; ++ ++ if ((retVal = rtl8367c_setAsicRmaCdp(&rmacfg)) != RT_ERR_OK) ++ return retVal; ++ } ++ else if (type == BYPASS_CSSTP) ++ { ++ if ((retVal = rtl8367c_getAsicRmaCsstp(&rmacfg)) != RT_ERR_OK) ++ return retVal; ++ ++ rmacfg.discard_storm_filter = enable; ++ ++ if ((retVal = rtl8367c_setAsicRmaCsstp(&rmacfg)) != RT_ERR_OK) ++ return retVal; ++ } ++ else if (type == BYPASS_LLDP) ++ { ++ if ((retVal = rtl8367c_getAsicRmaLldp(&tmp, &rmacfg)) != RT_ERR_OK) ++ return retVal; ++ ++ rmacfg.discard_storm_filter = enable; ++ ++ if ((retVal = rtl8367c_setAsicRmaLldp(tmp, &rmacfg)) != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ return RT_ERR_INPUT; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_storm_bypass_get ++ * Description: ++ * Get bypass storm filter control configuration. ++ * Input: ++ * type - Bypass storm filter control type. ++ * Output: ++ * pEnable - Bypass status. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * This API can get per-port bypass storm filter control frame type including RMA and IGMP. ++ * The bypass frame type is as following: ++ * - BYPASS_BRG_GROUP, ++ * - BYPASS_FD_PAUSE, ++ * - BYPASS_SP_MCAST, ++ * - BYPASS_1X_PAE, ++ * - BYPASS_UNDEF_BRG_04, ++ * - BYPASS_UNDEF_BRG_05, ++ * - BYPASS_UNDEF_BRG_06, ++ * - BYPASS_UNDEF_BRG_07, ++ * - BYPASS_PROVIDER_BRIDGE_GROUP_ADDRESS, ++ * - BYPASS_UNDEF_BRG_09, ++ * - BYPASS_UNDEF_BRG_0A, ++ * - BYPASS_UNDEF_BRG_0B, ++ * - BYPASS_UNDEF_BRG_0C, ++ * - BYPASS_PROVIDER_BRIDGE_GVRP_ADDRESS, ++ * - BYPASS_8021AB, ++ * - BYPASS_UNDEF_BRG_0F, ++ * - BYPASS_BRG_MNGEMENT, ++ * - BYPASS_UNDEFINED_11, ++ * - BYPASS_UNDEFINED_12, ++ * - BYPASS_UNDEFINED_13, ++ * - BYPASS_UNDEFINED_14, ++ * - BYPASS_UNDEFINED_15, ++ * - BYPASS_UNDEFINED_16, ++ * - BYPASS_UNDEFINED_17, ++ * - BYPASS_UNDEFINED_18, ++ * - BYPASS_UNDEFINED_19, ++ * - BYPASS_UNDEFINED_1A, ++ * - BYPASS_UNDEFINED_1B, ++ * - BYPASS_UNDEFINED_1C, ++ * - BYPASS_UNDEFINED_1D, ++ * - BYPASS_UNDEFINED_1E, ++ * - BYPASS_UNDEFINED_1F, ++ * - BYPASS_GMRP, ++ * - BYPASS_GVRP, ++ * - BYPASS_UNDEF_GARP_22, ++ * - BYPASS_UNDEF_GARP_23, ++ * - BYPASS_UNDEF_GARP_24, ++ * - BYPASS_UNDEF_GARP_25, ++ * - BYPASS_UNDEF_GARP_26, ++ * - BYPASS_UNDEF_GARP_27, ++ * - BYPASS_UNDEF_GARP_28, ++ * - BYPASS_UNDEF_GARP_29, ++ * - BYPASS_UNDEF_GARP_2A, ++ * - BYPASS_UNDEF_GARP_2B, ++ * - BYPASS_UNDEF_GARP_2C, ++ * - BYPASS_UNDEF_GARP_2D, ++ * - BYPASS_UNDEF_GARP_2E, ++ * - BYPASS_UNDEF_GARP_2F, ++ * - BYPASS_IGMP. ++ * - BYPASS_CDP. ++ * - BYPASS_CSSTP. ++ * - BYPASS_LLDP. ++ */ ++rtk_api_ret_t rtk_storm_bypass_get(rtk_storm_bypass_t type, rtk_enable_t *pEnable) ++{ ++ rtk_api_ret_t retVal; ++ rtl8367c_rma_t rmacfg; ++ rtk_uint32 tmp; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (type >= BYPASS_END) ++ return RT_ERR_INPUT; ++ ++ if(NULL == pEnable) ++ return RT_ERR_NULL_POINTER; ++ ++ if (type >= 0 && type <= BYPASS_UNDEF_GARP_2F) ++ { ++ if ((retVal = rtl8367c_getAsicRma(type, &rmacfg)) != RT_ERR_OK) ++ return retVal; ++ ++ *pEnable = rmacfg.discard_storm_filter; ++ } ++ else if(type == BYPASS_IGMP) ++ { ++ if ((retVal = rtl8367c_getAsicIGMPBypassStormCTRL(pEnable)) != RT_ERR_OK) ++ return retVal; ++ } ++ else if (type == BYPASS_CDP) ++ { ++ if ((retVal = rtl8367c_getAsicRmaCdp(&rmacfg)) != RT_ERR_OK) ++ return retVal; ++ ++ *pEnable = rmacfg.discard_storm_filter; ++ } ++ else if (type == BYPASS_CSSTP) ++ { ++ if ((retVal = rtl8367c_getAsicRmaCsstp(&rmacfg)) != RT_ERR_OK) ++ return retVal; ++ ++ *pEnable = rmacfg.discard_storm_filter; ++ } ++ else if (type == BYPASS_LLDP) ++ { ++ if ((retVal = rtl8367c_getAsicRmaLldp(&tmp,&rmacfg)) != RT_ERR_OK) ++ return retVal; ++ ++ *pEnable = rmacfg.discard_storm_filter; ++ } ++ else ++ return RT_ERR_INPUT; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_rate_stormControlExtPortmask_set ++ * Description: ++ * Set extension storm control port mask ++ * Input: ++ * pPortmask - port mask ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_NOT_INIT - The module is not initial ++ * RT_ERR_INPUT - invalid input parameter ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_rate_stormControlExtPortmask_set(rtk_portmask_t *pPortmask) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 pmask; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pPortmask) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtk_switch_portmask_L2P_get(pPortmask, &pmask)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicStormFilterExtEnablePortMask(pmask)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_rate_stormControlExtPortmask_get ++ * Description: ++ * Set extension storm control port mask ++ * Input: ++ * None ++ * Output: ++ * pPortmask - port mask ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_NOT_INIT - The module is not initial ++ * RT_ERR_INPUT - invalid input parameter ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_rate_stormControlExtPortmask_get(rtk_portmask_t *pPortmask) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 pmask; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pPortmask) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicStormFilterExtEnablePortMask(&pmask)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtk_switch_portmask_P2L_get(pmask, pPortmask)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_rate_stormControlExtEnable_set ++ * Description: ++ * Set extension storm control state ++ * Input: ++ * stormType - storm group type ++ * enable - extension storm control state ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_NOT_INIT - The module is not initial ++ * RT_ERR_INPUT - invalid input parameter ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_rate_stormControlExtEnable_set(rtk_rate_storm_group_t stormType, rtk_enable_t enable) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (stormType >= STORM_GROUP_END) ++ return RT_ERR_SFC_UNKNOWN_GROUP; ++ ++ if (enable >= RTK_ENABLE_END) ++ return RT_ERR_ENABLE; ++ ++ switch (stormType) ++ { ++ case STORM_GROUP_UNKNOWN_UNICAST: ++ if ((retVal = rtl8367c_setAsicStormFilterExtUnknownUnicastEnable(enable)) != RT_ERR_OK) ++ return retVal; ++ break; ++ case STORM_GROUP_UNKNOWN_MULTICAST: ++ if ((retVal = rtl8367c_setAsicStormFilterExtUnknownMulticastEnable(enable)) != RT_ERR_OK) ++ return retVal; ++ break; ++ case STORM_GROUP_MULTICAST: ++ if ((retVal = rtl8367c_setAsicStormFilterExtMulticastEnable(enable)) != RT_ERR_OK) ++ return retVal; ++ break; ++ case STORM_GROUP_BROADCAST: ++ if ((retVal = rtl8367c_setAsicStormFilterExtBroadcastEnable(enable)) != RT_ERR_OK) ++ return retVal; ++ break; ++ default: ++ break; ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_rate_stormControlExtEnable_get ++ * Description: ++ * Get extension storm control state ++ * Input: ++ * stormType - storm group type ++ * Output: ++ * pEnable - extension storm control state ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_NOT_INIT - The module is not initial ++ * RT_ERR_INPUT - invalid input parameter ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_rate_stormControlExtEnable_get(rtk_rate_storm_group_t stormType, rtk_enable_t *pEnable) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (stormType >= STORM_GROUP_END) ++ return RT_ERR_SFC_UNKNOWN_GROUP; ++ ++ if (NULL == pEnable) ++ return RT_ERR_NULL_POINTER; ++ ++ switch (stormType) ++ { ++ case STORM_GROUP_UNKNOWN_UNICAST: ++ if ((retVal = rtl8367c_getAsicStormFilterExtUnknownUnicastEnable((rtk_uint32 *)pEnable)) != RT_ERR_OK) ++ return retVal; ++ break; ++ case STORM_GROUP_UNKNOWN_MULTICAST: ++ if ((retVal = rtl8367c_getAsicStormFilterExtUnknownMulticastEnable((rtk_uint32 *)pEnable)) != RT_ERR_OK) ++ return retVal; ++ break; ++ case STORM_GROUP_MULTICAST: ++ if ((retVal = rtl8367c_getAsicStormFilterExtMulticastEnable((rtk_uint32 *)pEnable)) != RT_ERR_OK) ++ return retVal; ++ break; ++ case STORM_GROUP_BROADCAST: ++ if ((retVal = rtl8367c_getAsicStormFilterExtBroadcastEnable((rtk_uint32 *)pEnable)) != RT_ERR_OK) ++ return retVal; ++ break; ++ default: ++ break; ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_rate_stormControlExtMeterIdx_set ++ * Description: ++ * Set extension storm control meter index ++ * Input: ++ * stormType - storm group type ++ * index - extension storm control state ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_NOT_INIT - The module is not initial ++ * RT_ERR_INPUT - invalid input parameter ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_rate_stormControlExtMeterIdx_set(rtk_rate_storm_group_t stormType, rtk_uint32 index) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (stormType >= STORM_GROUP_END) ++ return RT_ERR_SFC_UNKNOWN_GROUP; ++ ++ if (index > RTK_MAX_METER_ID) ++ return RT_ERR_FILTER_METER_ID; ++ ++ switch (stormType) ++ { ++ case STORM_GROUP_UNKNOWN_UNICAST: ++ if ((retVal = rtl8367c_setAsicStormFilterExtUnknownUnicastMeter(index))!=RT_ERR_OK) ++ return retVal; ++ break; ++ case STORM_GROUP_UNKNOWN_MULTICAST: ++ if ((retVal = rtl8367c_setAsicStormFilterExtUnknownMulticastMeter(index))!=RT_ERR_OK) ++ return retVal; ++ break; ++ case STORM_GROUP_MULTICAST: ++ if ((retVal = rtl8367c_setAsicStormFilterExtMulticastMeter(index))!=RT_ERR_OK) ++ return retVal; ++ break; ++ case STORM_GROUP_BROADCAST: ++ if ((retVal = rtl8367c_setAsicStormFilterExtBroadcastMeter(index))!=RT_ERR_OK) ++ return retVal; ++ break; ++ default: ++ break; ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_rate_stormControlExtMeterIdx_get ++ * Description: ++ * Get extension storm control meter index ++ * Input: ++ * stormType - storm group type ++ * pIndex - extension storm control state ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_NOT_INIT - The module is not initial ++ * RT_ERR_INPUT - invalid input parameter ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_rate_stormControlExtMeterIdx_get(rtk_rate_storm_group_t stormType, rtk_uint32 *pIndex) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (stormType >= STORM_GROUP_END) ++ return RT_ERR_SFC_UNKNOWN_GROUP; ++ ++ if(NULL == pIndex) ++ return RT_ERR_NULL_POINTER; ++ ++ switch (stormType) ++ { ++ case STORM_GROUP_UNKNOWN_UNICAST: ++ if ((retVal = rtl8367c_getAsicStormFilterExtUnknownUnicastMeter(pIndex))!=RT_ERR_OK) ++ return retVal; ++ break; ++ case STORM_GROUP_UNKNOWN_MULTICAST: ++ if ((retVal = rtl8367c_getAsicStormFilterExtUnknownMulticastMeter(pIndex))!=RT_ERR_OK) ++ return retVal; ++ break; ++ case STORM_GROUP_MULTICAST: ++ if ((retVal = rtl8367c_getAsicStormFilterExtMulticastMeter(pIndex))!=RT_ERR_OK) ++ return retVal; ++ break; ++ case STORM_GROUP_BROADCAST: ++ if ((retVal = rtl8367c_getAsicStormFilterExtBroadcastMeter(pIndex))!=RT_ERR_OK) ++ return retVal; ++ break; ++ default: ++ break; ++ } ++ ++ return RT_ERR_OK; ++} ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/svlan.c b/drivers/net/phy/rtk/rtl8367c/svlan.c +new file mode 100644 +index 000000000000..067291526ac8 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/svlan.c +@@ -0,0 +1,2415 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ ++ * ++ * Purpose : RTK switch high-level API for RTL8367/RTL8367C ++ * Feature : Here is a list of all functions and variables in SVLAN module. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++rtk_uint8 svlan_mbrCfgUsage[RTL8367C_SVIDXNO]; ++rtk_uint16 svlan_mbrCfgVid[RTL8367C_SVIDXNO]; ++rtk_svlan_lookupType_t svlan_lookupType; ++/* Function Name: ++ * rtk_svlan_init ++ * Description: ++ * Initialize SVLAN Configuration ++ * Input: ++ * None ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * Ether type of S-tag in 802.1ad is 0x88a8 and there are existed ether type 0x9100 and 0x9200 for Q-in-Q SLAN design. ++ * User can set matched ether type as service provider supported protocol. ++ */ ++rtk_api_ret_t rtk_svlan_init(void) ++{ ++ rtk_uint32 i; ++ rtk_api_ret_t retVal; ++ rtl8367c_svlan_memconf_t svlanMemConf; ++ rtl8367c_svlan_s2c_t svlanSP2CConf; ++ rtl8367c_svlan_mc2s_t svlanMC2SConf; ++ rtk_uint32 svidx; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /*default use C-priority*/ ++ if ((retVal = rtl8367c_setAsicSvlanPrioritySel(SPRISEL_CTAGPRI)) != RT_ERR_OK) ++ return retVal; ++ ++ /*Drop SVLAN untag frame*/ ++ if ((retVal = rtl8367c_setAsicSvlanIngressUntag(UNTAG_DROP)) != RT_ERR_OK) ++ return retVal; ++ ++ /*Drop SVLAN unmatch frame*/ ++ if ((retVal = rtl8367c_setAsicSvlanIngressUnmatch(UNMATCH_DROP)) != RT_ERR_OK) ++ return retVal; ++ ++ /*Set TPID to 0x88a8*/ ++ if ((retVal = rtl8367c_setAsicSvlanTpid(0x88a8)) != RT_ERR_OK) ++ return retVal; ++ ++ /*Clean Uplink Port Mask to none*/ ++ if ((retVal = rtl8367c_setAsicSvlanUplinkPortMask(0)) != RT_ERR_OK) ++ return retVal; ++ ++ /*Clean SVLAN Member Configuration*/ ++ for (i=0; i<= RTL8367C_SVIDXMAX; i++) ++ { ++ memset(&svlanMemConf, 0, sizeof(rtl8367c_svlan_memconf_t)); ++ if ((retVal = rtl8367c_setAsicSvlanMemberConfiguration(i, &svlanMemConf)) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ /*Clean C2S Configuration*/ ++ for (i=0; i<= RTL8367C_C2SIDXMAX; i++) ++ { ++ if ((retVal = rtl8367c_setAsicSvlanC2SConf(i, 0,0,0)) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ /*Clean SP2C Configuration*/ ++ for (i=0; i <= RTL8367C_SP2CMAX ; i++) ++ { ++ memset(&svlanSP2CConf, 0, sizeof(rtl8367c_svlan_s2c_t)); ++ if ((retVal = rtl8367c_setAsicSvlanSP2CConf(i, &svlanSP2CConf)) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ /*Clean MC2S Configuration*/ ++ for (i=0 ; i<= RTL8367C_MC2SIDXMAX; i++) ++ { ++ memset(&svlanMC2SConf, 0, sizeof(rtl8367c_svlan_mc2s_t)); ++ if ((retVal = rtl8367c_setAsicSvlanMC2SConf(i, &svlanMC2SConf)) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ ++ if ((retVal = rtk_svlan_lookupType_set(SVLAN_LOOKUP_S64MBRCGF)) != RT_ERR_OK) ++ return retVal; ++ ++ ++ for (svidx = 0; svidx <= RTL8367C_SVIDXMAX; svidx++) ++ { ++ svlan_mbrCfgUsage[svidx] = FALSE; ++ } ++ ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_svlan_servicePort_add ++ * Description: ++ * Add one service port in the specified device ++ * Input: ++ * port - Port id. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * This API is setting which port is connected to provider switch. All frames receiving from this port must ++ * contain accept SVID in S-tag field. ++ */ ++rtk_api_ret_t rtk_svlan_servicePort_add(rtk_port_t port) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 pmsk; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* check port valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if ((retVal = rtl8367c_getAsicSvlanUplinkPortMask(&pmsk)) != RT_ERR_OK) ++ return retVal; ++ ++ pmsk = pmsk | (1<RTK_MAX_NUM_OF_PROTO_TYPE) ++ return RT_ERR_INPUT; ++ ++ if ((retVal = rtl8367c_setAsicSvlanTpid(svlan_tag_id)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_svlan_tpidEntry_get ++ * Description: ++ * Get accepted S-VLAN ether type setting. ++ * Input: ++ * None ++ * Output: ++ * pSvlan_tag_id - Ether type of S-tag frame parsing in uplink ports. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * This API is setting which port is connected to provider switch. All frames receiving from this port must ++ * contain accept SVID in S-tag field. ++ */ ++rtk_api_ret_t rtk_svlan_tpidEntry_get(rtk_svlan_tpid_t *pSvlan_tag_id) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pSvlan_tag_id) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicSvlanTpid(pSvlan_tag_id)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_svlan_priorityRef_set ++ * Description: ++ * Set S-VLAN upstream priority reference setting. ++ * Input: ++ * ref - reference selection parameter. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameter. ++ * Note: ++ * The API can set the upstream SVLAN tag priority reference source. The related priority ++ * sources are as following: ++ * - REF_INTERNAL_PRI, ++ * - REF_CTAG_PRI, ++ * - REF_SVLAN_PRI, ++ * - REF_PB_PRI. ++ */ ++rtk_api_ret_t rtk_svlan_priorityRef_set(rtk_svlan_pri_ref_t ref) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (ref >= REF_PRI_END) ++ return RT_ERR_INPUT; ++ ++ if ((retVal = rtl8367c_setAsicSvlanPrioritySel(ref)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_svlan_priorityRef_get ++ * Description: ++ * Get S-VLAN upstream priority reference setting. ++ * Input: ++ * None ++ * Output: ++ * pRef - reference selection parameter. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * The API can get the upstream SVLAN tag priority reference source. The related priority ++ * sources are as following: ++ * - REF_INTERNAL_PRI, ++ * - REF_CTAG_PRI, ++ * - REF_SVLAN_PRI, ++ * - REF_PB_PRI ++ */ ++rtk_api_ret_t rtk_svlan_priorityRef_get(rtk_svlan_pri_ref_t *pRef) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pRef) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicSvlanPrioritySel(pRef)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_svlan_memberPortEntry_set ++ * Description: ++ * Configure system SVLAN member content ++ * Input: ++ * svid - SVLAN id ++ * psvlan_cfg - SVLAN member configuration ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameter. ++ * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. ++ * RT_ERR_PORT_MASK - Invalid portmask. ++ * RT_ERR_SVLAN_TABLE_FULL - SVLAN configuration is full. ++ * Note: ++ * The API can set system 64 accepted s-tag frame format. Only 64 SVID S-tag frame will be accepted ++ * to receiving from uplink ports. Other SVID S-tag frame or S-untagged frame will be dropped by default setup. ++ * - rtk_svlan_memberCfg_t->svid is SVID of SVLAN member configuration. ++ * - rtk_svlan_memberCfg_t->memberport is member port mask of SVLAN member configuration. ++ * - rtk_svlan_memberCfg_t->fid is filtering database of SVLAN member configuration. ++ * - rtk_svlan_memberCfg_t->priority is priority of SVLAN member configuration. ++ */ ++rtk_api_ret_t rtk_svlan_memberPortEntry_set(rtk_vlan_t svid, rtk_svlan_memberCfg_t *pSvlan_cfg) ++{ ++ rtk_api_ret_t retVal; ++ rtk_int32 i; ++ rtk_uint32 empty_idx; ++ rtl8367c_svlan_memconf_t svlanMemConf; ++ rtk_uint32 phyMbrPmask; ++ rtk_vlan_cfg_t vlanCfg; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pSvlan_cfg) ++ return RT_ERR_NULL_POINTER; ++ ++ if(svid > RTL8367C_VIDMAX) ++ return RT_ERR_SVLAN_VID; ++ ++ RTK_CHK_PORTMASK_VALID(&(pSvlan_cfg->memberport)); ++ ++ RTK_CHK_PORTMASK_VALID(&(pSvlan_cfg->untagport)); ++ ++ if (pSvlan_cfg->fiden > ENABLED) ++ return RT_ERR_ENABLE; ++ ++ if (pSvlan_cfg->fid > RTL8367C_FIDMAX) ++ return RT_ERR_L2_FID; ++ ++ if (pSvlan_cfg->priority > RTL8367C_PRIMAX) ++ return RT_ERR_VLAN_PRIORITY; ++ ++ if (pSvlan_cfg->efiden > ENABLED) ++ return RT_ERR_ENABLE; ++ ++ if (pSvlan_cfg->efid > RTL8367C_EFIDMAX) ++ return RT_ERR_L2_FID; ++ ++ if(SVLAN_LOOKUP_C4KVLAN == svlan_lookupType) ++ { ++ if ((retVal = rtk_vlan_get(svid, &vlanCfg)) != RT_ERR_OK) ++ return retVal; ++ ++ vlanCfg.mbr = pSvlan_cfg->memberport; ++ vlanCfg.untag = pSvlan_cfg->untagport; ++ ++ if ((retVal = rtk_vlan_set(svid, &vlanCfg)) != RT_ERR_OK) ++ return retVal; ++ ++ empty_idx = 0xFF; ++ ++ for (i = 0; i<= RTL8367C_SVIDXMAX; i++) ++ { ++ if (svid == svlan_mbrCfgVid[i] && TRUE == svlan_mbrCfgUsage[i]) ++ { ++ memset(&svlanMemConf, 0, sizeof(rtl8367c_svlan_memconf_t)); ++ svlanMemConf.vs_svid = svid; ++ svlanMemConf.vs_efiden = pSvlan_cfg->efiden; ++ svlanMemConf.vs_efid = pSvlan_cfg->efid; ++ svlanMemConf.vs_priority = pSvlan_cfg->priority; ++ ++ /*for create check*/ ++ if(0 == svlanMemConf.vs_efiden && 0 == svlanMemConf.vs_efid) ++ svlanMemConf.vs_efid = 1; ++ ++ if ((retVal = rtl8367c_setAsicSvlanMemberConfiguration(i, &svlanMemConf)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++ } ++ else if (FALSE == svlan_mbrCfgUsage[i] && 0xFF == empty_idx) ++ { ++ empty_idx = i; ++ } ++ } ++ ++ if (empty_idx != 0xFF) ++ { ++ svlan_mbrCfgUsage[empty_idx] = TRUE; ++ svlan_mbrCfgVid[empty_idx] = svid; ++ ++ memset(&svlanMemConf, 0, sizeof(rtl8367c_svlan_memconf_t)); ++ svlanMemConf.vs_svid = svid; ++ svlanMemConf.vs_efiden = pSvlan_cfg->efiden; ++ svlanMemConf.vs_efid = pSvlan_cfg->efid; ++ svlanMemConf.vs_priority = pSvlan_cfg->priority; ++ ++ /*for create check*/ ++ if(0 == svlanMemConf.vs_efiden && 0 == svlanMemConf.vs_efid) ++ svlanMemConf.vs_efid = 1; ++ ++ if ((retVal = rtl8367c_setAsicSvlanMemberConfiguration(empty_idx, &svlanMemConf)) != RT_ERR_OK) ++ return retVal; ++ ++ } ++ ++ return RT_ERR_OK; ++ } ++ ++ ++ empty_idx = 0xFF; ++ ++ for (i = 0; i<= RTL8367C_SVIDXMAX; i++) ++ { ++ /* ++ if ((retVal = rtl8367c_getAsicSvlanMemberConfiguration(i, &svlanMemConf)) != RT_ERR_OK) ++ return retVal; ++ */ ++ if (svid == svlan_mbrCfgVid[i] && TRUE == svlan_mbrCfgUsage[i]) ++ { ++ svlanMemConf.vs_svid = svid; ++ ++ if(rtk_switch_portmask_L2P_get(&(pSvlan_cfg->memberport), &phyMbrPmask) != RT_ERR_OK) ++ return RT_ERR_FAILED; ++ ++ svlanMemConf.vs_member = phyMbrPmask; ++ ++ if(rtk_switch_portmask_L2P_get(&(pSvlan_cfg->untagport), &phyMbrPmask) != RT_ERR_OK) ++ return RT_ERR_FAILED; ++ ++ svlanMemConf.vs_untag = phyMbrPmask; ++ ++ svlanMemConf.vs_force_fid = pSvlan_cfg->fiden; ++ svlanMemConf.vs_fid_msti = pSvlan_cfg->fid; ++ svlanMemConf.vs_priority = pSvlan_cfg->priority; ++ svlanMemConf.vs_efiden = pSvlan_cfg->efiden; ++ svlanMemConf.vs_efid = pSvlan_cfg->efid; ++ ++ /*all items are reset means deleting*/ ++ if( 0 == svlanMemConf.vs_member && ++ 0 == svlanMemConf.vs_untag && ++ 0 == svlanMemConf.vs_force_fid && ++ 0 == svlanMemConf.vs_fid_msti && ++ 0 == svlanMemConf.vs_priority && ++ 0 == svlanMemConf.vs_efiden && ++ 0 == svlanMemConf.vs_efid) ++ { ++ svlan_mbrCfgUsage[i] = FALSE; ++ svlan_mbrCfgVid[i] = 0; ++ ++ /* Clear SVID also */ ++ svlanMemConf.vs_svid = 0; ++ } ++ else ++ { ++ svlan_mbrCfgUsage[i] = TRUE; ++ svlan_mbrCfgVid[i] = svlanMemConf.vs_svid; ++ ++ if(0 == svlanMemConf.vs_svid) ++ { ++ /*for create check*/ ++ if(0 == svlanMemConf.vs_efiden && 0 == svlanMemConf.vs_efid) ++ { ++ svlanMemConf.vs_efid = 1; ++ } ++ } ++ } ++ ++ if ((retVal = rtl8367c_setAsicSvlanMemberConfiguration(i, &svlanMemConf)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++ } ++ else if (FALSE == svlan_mbrCfgUsage[i] && 0xFF == empty_idx) ++ { ++ empty_idx = i; ++ } ++ } ++ ++ if (empty_idx != 0xFF) ++ { ++ memset(&svlanMemConf, 0, sizeof(rtl8367c_svlan_memconf_t)); ++ svlanMemConf.vs_svid = svid; ++ ++ if(rtk_switch_portmask_L2P_get(&(pSvlan_cfg->memberport), &phyMbrPmask) != RT_ERR_OK) ++ return RT_ERR_FAILED; ++ ++ svlanMemConf.vs_member = phyMbrPmask; ++ ++ if(rtk_switch_portmask_L2P_get(&(pSvlan_cfg->untagport), &phyMbrPmask) != RT_ERR_OK) ++ return RT_ERR_FAILED; ++ ++ svlanMemConf.vs_untag = phyMbrPmask; ++ ++ svlanMemConf.vs_force_fid = pSvlan_cfg->fiden; ++ svlanMemConf.vs_fid_msti = pSvlan_cfg->fid; ++ svlanMemConf.vs_priority = pSvlan_cfg->priority; ++ ++ svlanMemConf.vs_efiden = pSvlan_cfg->efiden; ++ svlanMemConf.vs_efid = pSvlan_cfg->efid; ++ ++ /*change efid for empty svid 0*/ ++ if(0 == svlanMemConf.vs_svid) ++ { /*for create check*/ ++ if(0 == svlanMemConf.vs_efiden && 0 == svlanMemConf.vs_efid) ++ { ++ svlanMemConf.vs_efid = 1; ++ } ++ } ++ ++ svlan_mbrCfgUsage[empty_idx] = TRUE; ++ svlan_mbrCfgVid[empty_idx] = svlanMemConf.vs_svid; ++ ++ if ((retVal = rtl8367c_setAsicSvlanMemberConfiguration(empty_idx, &svlanMemConf)) != RT_ERR_OK) ++ { ++ return retVal; ++ } ++ ++ return RT_ERR_OK; ++ } ++ ++ return RT_ERR_SVLAN_TABLE_FULL; ++} ++ ++/* Function Name: ++ * rtk_svlan_memberPortEntry_get ++ * Description: ++ * Get SVLAN member Configure. ++ * Input: ++ * svid - SVLAN id ++ * Output: ++ * pSvlan_cfg - SVLAN member configuration ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_SVLAN_ENTRY_NOT_FOUND - specified svlan entry not found. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can get system 64 accepted s-tag frame format. Only 64 SVID S-tag frame will be accepted ++ * to receiving from uplink ports. Other SVID S-tag frame or S-untagged frame will be dropped. ++ */ ++rtk_api_ret_t rtk_svlan_memberPortEntry_get(rtk_vlan_t svid, rtk_svlan_memberCfg_t *pSvlan_cfg) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 i; ++ rtl8367c_svlan_memconf_t svlanMemConf; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pSvlan_cfg) ++ return RT_ERR_NULL_POINTER; ++ ++ if (svid > RTL8367C_VIDMAX) ++ return RT_ERR_SVLAN_VID; ++ ++ ++ for (i = 0; i<= RTL8367C_SVIDXMAX; i++) ++ { ++ if ((retVal = rtl8367c_getAsicSvlanMemberConfiguration(i, &svlanMemConf)) != RT_ERR_OK) ++ return retVal; ++ ++ if (svid == svlanMemConf.vs_svid) ++ { ++ pSvlan_cfg->svid = svlanMemConf.vs_svid; ++ ++ if(rtk_switch_portmask_P2L_get(svlanMemConf.vs_member,&(pSvlan_cfg->memberport)) != RT_ERR_OK) ++ return RT_ERR_FAILED; ++ ++ if(rtk_switch_portmask_P2L_get(svlanMemConf.vs_untag,&(pSvlan_cfg->untagport)) != RT_ERR_OK) ++ return RT_ERR_FAILED; ++ ++ pSvlan_cfg->fiden = svlanMemConf.vs_force_fid; ++ pSvlan_cfg->fid = svlanMemConf.vs_fid_msti; ++ pSvlan_cfg->priority = svlanMemConf.vs_priority; ++ pSvlan_cfg->efiden = svlanMemConf.vs_efiden; ++ pSvlan_cfg->efid = svlanMemConf.vs_efid; ++ ++ return RT_ERR_OK; ++ } ++ } ++ ++ return RT_ERR_SVLAN_ENTRY_NOT_FOUND; ++ ++} ++ ++/* Function Name: ++ * rtk_svlan_memberPortEntry_adv_set ++ * Description: ++ * Configure system SVLAN member by index ++ * Input: ++ * idx - Index (0 ~ 63) ++ * psvlan_cfg - SVLAN member configuration ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameter. ++ * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. ++ * RT_ERR_PORT_MASK - Invalid portmask. ++ * RT_ERR_SVLAN_TABLE_FULL - SVLAN configuration is full. ++ * Note: ++ * The API can set system 64 accepted s-tag frame format by index. ++ * - rtk_svlan_memberCfg_t->svid is SVID of SVLAN member configuration. ++ * - rtk_svlan_memberCfg_t->memberport is member port mask of SVLAN member configuration. ++ * - rtk_svlan_memberCfg_t->fid is filtering database of SVLAN member configuration. ++ * - rtk_svlan_memberCfg_t->priority is priority of SVLAN member configuration. ++ */ ++rtk_api_ret_t rtk_svlan_memberPortEntry_adv_set(rtk_uint32 idx, rtk_svlan_memberCfg_t *pSvlan_cfg) ++{ ++ rtk_api_ret_t retVal; ++ rtl8367c_svlan_memconf_t svlanMemConf; ++ rtk_uint32 phyMbrPmask; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pSvlan_cfg) ++ return RT_ERR_NULL_POINTER; ++ ++ if (idx > RTL8367C_SVIDXMAX) ++ return RT_ERR_SVLAN_ENTRY_INDEX; ++ ++ if (pSvlan_cfg->svid>RTL8367C_VIDMAX) ++ return RT_ERR_SVLAN_VID; ++ ++ RTK_CHK_PORTMASK_VALID(&(pSvlan_cfg->memberport)); ++ ++ RTK_CHK_PORTMASK_VALID(&(pSvlan_cfg->untagport)); ++ ++ if (pSvlan_cfg->fiden > ENABLED) ++ return RT_ERR_ENABLE; ++ ++ if (pSvlan_cfg->fid > RTL8367C_FIDMAX) ++ return RT_ERR_L2_FID; ++ ++ if (pSvlan_cfg->priority > RTL8367C_PRIMAX) ++ return RT_ERR_VLAN_PRIORITY; ++ ++ if (pSvlan_cfg->efiden > ENABLED) ++ return RT_ERR_ENABLE; ++ ++ if (pSvlan_cfg->efid > RTL8367C_EFIDMAX) ++ return RT_ERR_L2_FID; ++ ++ memset(&svlanMemConf, 0, sizeof(rtl8367c_svlan_memconf_t)); ++ svlanMemConf.vs_svid = pSvlan_cfg->svid; ++ if(rtk_switch_portmask_L2P_get(&(pSvlan_cfg->memberport), &phyMbrPmask) != RT_ERR_OK) ++ return RT_ERR_FAILED; ++ ++ svlanMemConf.vs_member = phyMbrPmask; ++ ++ if(rtk_switch_portmask_L2P_get(&(pSvlan_cfg->untagport), &phyMbrPmask) != RT_ERR_OK) ++ return RT_ERR_FAILED; ++ ++ svlanMemConf.vs_untag = phyMbrPmask; ++ ++ ++ svlanMemConf.vs_force_fid = pSvlan_cfg->fiden; ++ svlanMemConf.vs_fid_msti = pSvlan_cfg->fid; ++ svlanMemConf.vs_priority = pSvlan_cfg->priority; ++ svlanMemConf.vs_efiden = pSvlan_cfg->efiden; ++ svlanMemConf.vs_efid = pSvlan_cfg->efid; ++ ++ if(0 == svlanMemConf.vs_svid && ++ 0 == svlanMemConf.vs_member && ++ 0 == svlanMemConf.vs_untag && ++ 0 == svlanMemConf.vs_force_fid && ++ 0 == svlanMemConf.vs_fid_msti && ++ 0 == svlanMemConf.vs_priority && ++ 0 == svlanMemConf.vs_efiden && ++ 0 == svlanMemConf.vs_efid) ++ { ++ svlan_mbrCfgUsage[idx] = FALSE; ++ svlan_mbrCfgVid[idx] = 0; ++ } ++ else ++ { ++ svlan_mbrCfgUsage[idx] = TRUE; ++ svlan_mbrCfgVid[idx] = svlanMemConf.vs_svid; ++ } ++ ++ if ((retVal = rtl8367c_setAsicSvlanMemberConfiguration(idx, &svlanMemConf)) != RT_ERR_OK) ++ return retVal; ++ ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_svlan_memberPortEntry_adv_get ++ * Description: ++ * Get SVLAN member Configure by index. ++ * Input: ++ * idx - Index (0 ~ 63) ++ * Output: ++ * pSvlan_cfg - SVLAN member configuration ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_SVLAN_ENTRY_NOT_FOUND - specified svlan entry not found. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can get system 64 accepted s-tag frame format. Only 64 SVID S-tag frame will be accepted ++ * to receiving from uplink ports. Other SVID S-tag frame or S-untagged frame will be dropped. ++ */ ++rtk_api_ret_t rtk_svlan_memberPortEntry_adv_get(rtk_uint32 idx, rtk_svlan_memberCfg_t *pSvlan_cfg) ++{ ++ rtk_api_ret_t retVal; ++ rtl8367c_svlan_memconf_t svlanMemConf; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pSvlan_cfg) ++ return RT_ERR_NULL_POINTER; ++ ++ if (idx > RTL8367C_SVIDXMAX) ++ return RT_ERR_SVLAN_ENTRY_INDEX; ++ ++ if ((retVal = rtl8367c_getAsicSvlanMemberConfiguration(idx, &svlanMemConf)) != RT_ERR_OK) ++ return retVal; ++ ++ pSvlan_cfg->svid = svlanMemConf.vs_svid; ++ if(rtk_switch_portmask_P2L_get(svlanMemConf.vs_member,&(pSvlan_cfg->memberport)) != RT_ERR_OK) ++ return RT_ERR_FAILED; ++ ++ if(rtk_switch_portmask_P2L_get(svlanMemConf.vs_untag,&(pSvlan_cfg->untagport)) != RT_ERR_OK) ++ return RT_ERR_FAILED; ++ ++ pSvlan_cfg->fiden = svlanMemConf.vs_force_fid; ++ pSvlan_cfg->fid = svlanMemConf.vs_fid_msti; ++ pSvlan_cfg->priority = svlanMemConf.vs_priority; ++ pSvlan_cfg->efiden = svlanMemConf.vs_efiden; ++ pSvlan_cfg->efid = svlanMemConf.vs_efid; ++ ++ return RT_ERR_OK; ++ ++} ++ ++/* Function Name: ++ * rtk_svlan_defaultSvlan_set ++ * Description: ++ * Configure default egress SVLAN. ++ * Input: ++ * port - Source port ++ * svid - SVLAN id ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameter. ++ * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. ++ * RT_ERR_SVLAN_ENTRY_NOT_FOUND - specified svlan entry not found. ++ * Note: ++ * The API can set port n S-tag format index while receiving frame from port n ++ * is transmit through uplink port with s-tag field ++ */ ++rtk_api_ret_t rtk_svlan_defaultSvlan_set(rtk_port_t port, rtk_vlan_t svid) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 i; ++ rtl8367c_svlan_memconf_t svlanMemConf; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ /* svid must be 0~4095 */ ++ if (svid > RTL8367C_VIDMAX) ++ return RT_ERR_SVLAN_VID; ++ ++ for (i = 0; i < RTL8367C_SVIDXNO; i++) ++ { ++ if ((retVal = rtl8367c_getAsicSvlanMemberConfiguration(i, &svlanMemConf)) != RT_ERR_OK) ++ return retVal; ++ ++ if (svid == svlanMemConf.vs_svid) ++ { ++ if ((retVal = rtl8367c_setAsicSvlanDefaultVlan(rtk_switch_port_L2P_get(port), i)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++ } ++ } ++ ++ return RT_ERR_SVLAN_ENTRY_NOT_FOUND; ++} ++ ++/* Function Name: ++ * rtk_svlan_defaultSvlan_get ++ * Description: ++ * Get the configure default egress SVLAN. ++ * Input: ++ * port - Source port ++ * Output: ++ * pSvid - SVLAN VID ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can get port n S-tag format index while receiving frame from port n ++ * is transmit through uplink port with s-tag field ++ */ ++rtk_api_ret_t rtk_svlan_defaultSvlan_get(rtk_port_t port, rtk_vlan_t *pSvid) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 idx; ++ rtl8367c_svlan_memconf_t svlanMemConf; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pSvid) ++ return RT_ERR_NULL_POINTER; ++ ++ /* Check port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if ((retVal = rtl8367c_getAsicSvlanDefaultVlan(rtk_switch_port_L2P_get(port), &idx)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_getAsicSvlanMemberConfiguration(idx, &svlanMemConf)) != RT_ERR_OK) ++ return retVal; ++ ++ *pSvid = svlanMemConf.vs_svid; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_svlan_c2s_add ++ * Description: ++ * Configure SVLAN C2S table ++ * Input: ++ * vid - VLAN ID ++ * src_port - Ingress Port ++ * svid - SVLAN VID ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port ID. ++ * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. ++ * RT_ERR_VLAN_VID - Invalid VID parameter. ++ * RT_ERR_OUT_OF_RANGE - input out of range. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can set system C2S configuration. ASIC will check upstream's VID and assign related ++ * SVID to matched packet. There are 128 SVLAN C2S configurations. ++ */ ++rtk_api_ret_t rtk_svlan_c2s_add(rtk_vlan_t vid, rtk_port_t src_port, rtk_vlan_t svid) ++{ ++ rtk_api_ret_t retVal, i; ++ rtk_uint32 empty_idx; ++ rtk_uint32 evid, pmsk, svidx, c2s_svidx; ++ rtl8367c_svlan_memconf_t svlanMemConf; ++ rtk_port_t phyPort; ++ rtk_uint16 doneFlag; ++ ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ ++ if (vid > RTL8367C_VIDMAX) ++ return RT_ERR_VLAN_VID; ++ ++ if (svid > RTL8367C_VIDMAX) ++ return RT_ERR_SVLAN_VID; ++ ++ /* Check port Valid */ ++ RTK_CHK_PORT_VALID(src_port); ++ ++ phyPort = rtk_switch_port_L2P_get(src_port); ++ ++ empty_idx = 0xFFFF; ++ svidx = 0xFFFF; ++ doneFlag = FALSE; ++ ++ for (i = 0; i<= RTL8367C_SVIDXMAX; i++) ++ { ++ if ((retVal = rtl8367c_getAsicSvlanMemberConfiguration(i, &svlanMemConf)) != RT_ERR_OK) ++ return retVal; ++ ++ if (svid == svlanMemConf.vs_svid) ++ { ++ svidx = i; ++ break; ++ } ++ } ++ ++ if (0xFFFF == svidx) ++ return RT_ERR_SVLAN_VID; ++ ++ for (i=RTL8367C_C2SIDXMAX; i>=0; i--) ++ { ++ if ((retVal = rtl8367c_getAsicSvlanC2SConf(i, &evid, &pmsk, &c2s_svidx)) != RT_ERR_OK) ++ return retVal; ++ ++ if (evid == vid) ++ { ++ /* Check Src_port */ ++ if(pmsk & (1 << phyPort)) ++ { ++ /* Check SVIDX */ ++ if(c2s_svidx == svidx) ++ { ++ /* All the same, do nothing */ ++ } ++ else ++ { ++ /* New svidx, remove src_port and find a new slot to add a new entry */ ++ pmsk = pmsk & ~(1 << phyPort); ++ if(pmsk == 0) ++ c2s_svidx = 0; ++ ++ if ((retVal = rtl8367c_setAsicSvlanC2SConf(i, vid, pmsk, c2s_svidx)) != RT_ERR_OK) ++ return retVal; ++ } ++ } ++ else ++ { ++ if(c2s_svidx == svidx && doneFlag == FALSE) ++ { ++ pmsk = pmsk | (1 << phyPort); ++ if ((retVal = rtl8367c_setAsicSvlanC2SConf(i, vid, pmsk, svidx)) != RT_ERR_OK) ++ return retVal; ++ ++ doneFlag = TRUE; ++ } ++ } ++ } ++ else if (evid==0&&pmsk==0) ++ { ++ empty_idx = i; ++ } ++ } ++ ++ if (0xFFFF != empty_idx && doneFlag ==FALSE) ++ { ++ if ((retVal = rtl8367c_setAsicSvlanC2SConf(empty_idx, vid, (1< RTL8367C_EVIDMAX) ++ return RT_ERR_VLAN_VID; ++ ++ /* Check port Valid */ ++ RTK_CHK_PORT_VALID(src_port); ++ phyPort = rtk_switch_port_L2P_get(src_port); ++ ++ for (i = 0; i <= RTL8367C_C2SIDXMAX; i++) ++ { ++ if ((retVal = rtl8367c_getAsicSvlanC2SConf(i, &evid, &pmsk, &svidx)) != RT_ERR_OK) ++ return retVal; ++ ++ if (evid == vid) ++ { ++ if(pmsk & (1 << phyPort)) ++ { ++ pmsk = pmsk & ~(1 << phyPort); ++ if(pmsk == 0) ++ { ++ vid = 0; ++ svidx = 0; ++ } ++ ++ if ((retVal = rtl8367c_setAsicSvlanC2SConf(i, vid, pmsk, svidx)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++ } ++ } ++ } ++ ++ return RT_ERR_OUT_OF_RANGE; ++} ++ ++/* Function Name: ++ * rtk_svlan_c2s_get ++ * Description: ++ * Get configure SVLAN C2S table ++ * Input: ++ * vid - VLAN ID ++ * src_port - Ingress Port ++ * Output: ++ * pSvid - SVLAN ID ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_PORT_ID - Invalid port ID. ++ * RT_ERR_OUT_OF_RANGE - input out of range. ++ * Note: ++ * The API can get system C2S configuration. There are 128 SVLAN C2S configurations. ++ */ ++rtk_api_ret_t rtk_svlan_c2s_get(rtk_vlan_t vid, rtk_port_t src_port, rtk_vlan_t *pSvid) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 i; ++ rtk_uint32 evid, pmsk, svidx; ++ rtl8367c_svlan_memconf_t svlanMemConf; ++ rtk_port_t phyPort; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pSvid) ++ return RT_ERR_NULL_POINTER; ++ ++ if (vid > RTL8367C_VIDMAX) ++ return RT_ERR_VLAN_VID; ++ ++ /* Check port Valid */ ++ RTK_CHK_PORT_VALID(src_port); ++ phyPort = rtk_switch_port_L2P_get(src_port); ++ ++ for (i = 0; i <= RTL8367C_C2SIDXMAX; i++) ++ { ++ if ((retVal = rtl8367c_getAsicSvlanC2SConf(i, &evid, &pmsk, &svidx)) != RT_ERR_OK) ++ return retVal; ++ ++ if (evid == vid) ++ { ++ if(pmsk & (1 << phyPort)) ++ { ++ if ((retVal = rtl8367c_getAsicSvlanMemberConfiguration(svidx, &svlanMemConf)) != RT_ERR_OK) ++ return retVal; ++ ++ *pSvid = svlanMemConf.vs_svid; ++ return RT_ERR_OK; ++ } ++ } ++ } ++ ++ return RT_ERR_OUT_OF_RANGE; ++} ++ ++/* Function Name: ++ * rtk_svlan_untag_action_set ++ * Description: ++ * Configure Action of downstream UnStag packet ++ * Input: ++ * action - Action for UnStag ++ * svid - The SVID assigned to UnStag packet ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. ++ * RT_ERR_SVLAN_ENTRY_NOT_FOUND - specified svlan entry not found. ++ * RT_ERR_OUT_OF_RANGE - input out of range. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can configure action of downstream Un-Stag packet. A SVID assigned ++ * to the un-stag is also supported by this API. The parameter of svid is ++ * only referenced when the action is set to UNTAG_ASSIGN ++ */ ++rtk_api_ret_t rtk_svlan_untag_action_set(rtk_svlan_untag_action_t action, rtk_vlan_t svid) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 i; ++ rtl8367c_svlan_memconf_t svlanMemConf; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (action >= UNTAG_END) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ if(action == UNTAG_ASSIGN) ++ { ++ if (svid > RTL8367C_VIDMAX) ++ return RT_ERR_SVLAN_VID; ++ } ++ ++ if ((retVal = rtl8367c_setAsicSvlanIngressUntag((rtk_uint32)action)) != RT_ERR_OK) ++ return retVal; ++ ++ if(action == UNTAG_ASSIGN) ++ { ++ for (i = 0; i < RTL8367C_SVIDXNO; i++) ++ { ++ if ((retVal = rtl8367c_getAsicSvlanMemberConfiguration(i, &svlanMemConf)) != RT_ERR_OK) ++ return retVal; ++ ++ if (svid == svlanMemConf.vs_svid) ++ { ++ if ((retVal = rtl8367c_setAsicSvlanUntagVlan(i)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++ } ++ } ++ ++ return RT_ERR_SVLAN_ENTRY_NOT_FOUND; ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_svlan_untag_action_get ++ * Description: ++ * Get Action of downstream UnStag packet ++ * Input: ++ * None ++ * Output: ++ * pAction - Action for UnStag ++ * pSvid - The SVID assigned to UnStag packet ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. ++ * RT_ERR_SVLAN_ENTRY_NOT_FOUND - specified svlan entry not found. ++ * RT_ERR_OUT_OF_RANGE - input out of range. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can Get action of downstream Un-Stag packet. A SVID assigned ++ * to the un-stag is also retrieved by this API. The parameter pSvid is ++ * only referenced when the action is UNTAG_ASSIGN ++ */ ++rtk_api_ret_t rtk_svlan_untag_action_get(rtk_svlan_untag_action_t *pAction, rtk_vlan_t *pSvid) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 svidx; ++ rtl8367c_svlan_memconf_t svlanMemConf; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pAction || NULL == pSvid) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicSvlanIngressUntag(pAction)) != RT_ERR_OK) ++ return retVal; ++ ++ if(*pAction == UNTAG_ASSIGN) ++ { ++ if ((retVal = rtl8367c_getAsicSvlanUntagVlan(&svidx)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_getAsicSvlanMemberConfiguration(svidx, &svlanMemConf)) != RT_ERR_OK) ++ return retVal; ++ ++ *pSvid = svlanMemConf.vs_svid; ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_svlan_unmatch_action_set ++ * Description: ++ * Configure Action of downstream Unmatch packet ++ * Input: ++ * action - Action for Unmatch ++ * svid - The SVID assigned to Unmatch packet ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. ++ * RT_ERR_SVLAN_ENTRY_NOT_FOUND - specified svlan entry not found. ++ * RT_ERR_OUT_OF_RANGE - input out of range. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can configure action of downstream Un-match packet. A SVID assigned ++ * to the un-match is also supported by this API. The parameter of svid is ++ * only referenced when the action is set to UNMATCH_ASSIGN ++ */ ++rtk_api_ret_t rtk_svlan_unmatch_action_set(rtk_svlan_unmatch_action_t action, rtk_vlan_t svid) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 i; ++ rtl8367c_svlan_memconf_t svlanMemConf; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (action >= UNMATCH_END) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ if (action == UNMATCH_ASSIGN) ++ { ++ if (svid > RTL8367C_VIDMAX) ++ return RT_ERR_SVLAN_VID; ++ } ++ ++ if ((retVal = rtl8367c_setAsicSvlanIngressUnmatch((rtk_uint32)action)) != RT_ERR_OK) ++ return retVal; ++ ++ if(action == UNMATCH_ASSIGN) ++ { ++ for (i = 0; i < RTL8367C_SVIDXNO; i++) ++ { ++ if ((retVal = rtl8367c_getAsicSvlanMemberConfiguration(i, &svlanMemConf)) != RT_ERR_OK) ++ return retVal; ++ ++ if (svid == svlanMemConf.vs_svid) ++ { ++ if ((retVal = rtl8367c_setAsicSvlanUnmatchVlan(i)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++ } ++ } ++ ++ return RT_ERR_SVLAN_ENTRY_NOT_FOUND; ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_svlan_unmatch_action_get ++ * Description: ++ * Get Action of downstream Unmatch packet ++ * Input: ++ * None ++ * Output: ++ * pAction - Action for Unmatch ++ * pSvid - The SVID assigned to Unmatch packet ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. ++ * RT_ERR_SVLAN_ENTRY_NOT_FOUND - specified svlan entry not found. ++ * RT_ERR_OUT_OF_RANGE - input out of range. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can Get action of downstream Un-match packet. A SVID assigned ++ * to the un-match is also retrieved by this API. The parameter pSvid is ++ * only referenced when the action is UNMATCH_ASSIGN ++ */ ++rtk_api_ret_t rtk_svlan_unmatch_action_get(rtk_svlan_unmatch_action_t *pAction, rtk_vlan_t *pSvid) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 svidx; ++ rtl8367c_svlan_memconf_t svlanMemConf; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pAction || NULL == pSvid) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicSvlanIngressUnmatch(pAction)) != RT_ERR_OK) ++ return retVal; ++ ++ if(*pAction == UNMATCH_ASSIGN) ++ { ++ if ((retVal = rtl8367c_getAsicSvlanUnmatchVlan(&svidx)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_getAsicSvlanMemberConfiguration(svidx, &svlanMemConf)) != RT_ERR_OK) ++ return retVal; ++ ++ *pSvid = svlanMemConf.vs_svid; ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_svlan_unassign_action_set ++ * Description: ++ * Configure Action of upstream without svid assign action ++ * Input: ++ * action - Action for Un-assign ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_OUT_OF_RANGE - input out of range. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can configure action of upstream Un-assign svid packet. If action is not ++ * trap to CPU, the port-based SVID sure be assign as system need ++ */ ++rtk_api_ret_t rtk_svlan_unassign_action_set(rtk_svlan_unassign_action_t action) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (action >= UNASSIGN_END) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ retVal = rtl8367c_setAsicSvlanEgressUnassign((rtk_uint32)action); ++ ++ return retVal; ++} ++ ++/* Function Name: ++ * rtk_svlan_unassign_action_get ++ * Description: ++ * Get action of upstream without svid assignment ++ * Input: ++ * None ++ * Output: ++ * pAction - Action for Un-assign ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * Note: ++ * None ++ */ ++rtk_api_ret_t rtk_svlan_unassign_action_get(rtk_svlan_unassign_action_t *pAction) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pAction) ++ return RT_ERR_NULL_POINTER; ++ ++ retVal = rtl8367c_getAsicSvlanEgressUnassign(pAction); ++ ++ return retVal; ++} ++ ++/* Function Name: ++ * rtk_svlan_dmac_vidsel_set ++ * Description: ++ * Set DMAC CVID selection ++ * Input: ++ * port - Port ++ * enable - state of DMAC CVID Selection ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. ++ * RT_ERR_SVLAN_ENTRY_NOT_FOUND - specified svlan entry not found. ++ * RT_ERR_OUT_OF_RANGE - input out of range. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * This API can set DMAC CVID Selection state ++ */ ++rtk_api_ret_t rtk_svlan_dmac_vidsel_set(rtk_port_t port, rtk_enable_t enable) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if (enable >= RTK_ENABLE_END) ++ return RT_ERR_ENABLE; ++ ++ if ((retVal = rtl8367c_setAsicSvlanDmacCvidSel(rtk_switch_port_L2P_get(port), enable)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_svlan_dmac_vidsel_get ++ * Description: ++ * Get DMAC CVID selection ++ * Input: ++ * port - Port ++ * Output: ++ * pEnable - state of DMAC CVID Selection ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. ++ * RT_ERR_SVLAN_ENTRY_NOT_FOUND - specified svlan entry not found. ++ * RT_ERR_OUT_OF_RANGE - input out of range. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * This API can get DMAC CVID Selection state ++ */ ++rtk_api_ret_t rtk_svlan_dmac_vidsel_get(rtk_port_t port, rtk_enable_t *pEnable) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pEnable) ++ return RT_ERR_NULL_POINTER; ++ ++ /* Check port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if ((retVal = rtl8367c_getAsicSvlanDmacCvidSel(rtk_switch_port_L2P_get(port), pEnable)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_svlan_ipmc2s_add ++ * Description: ++ * add ip multicast address to SVLAN ++ * Input: ++ * svid - SVLAN VID ++ * ipmc - ip multicast address ++ * ipmcMsk - ip multicast mask ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. ++ * RT_ERR_SVLAN_ENTRY_NOT_FOUND - specified svlan entry not found. ++ * RT_ERR_OUT_OF_RANGE - input out of range. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can set IP multicast to SVID configuration. If upstream packet is IPv4 multicast ++ * packet and DIP is matched MC2S configuration, ASIC will assign egress SVID to the packet. ++ * There are 32 SVLAN multicast configurations for IP and L2 multicast. ++ */ ++rtk_api_ret_t rtk_svlan_ipmc2s_add(ipaddr_t ipmc, ipaddr_t ipmcMsk,rtk_vlan_t svid) ++{ ++ rtk_api_ret_t retVal, i; ++ rtk_uint32 empty_idx; ++ rtk_uint32 svidx; ++ rtl8367c_svlan_memconf_t svlanMemConf; ++ rtl8367c_svlan_mc2s_t svlanMC2SConf; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (svid > RTL8367C_VIDMAX) ++ return RT_ERR_SVLAN_VID; ++ ++ if ((ipmc&0xF0000000)!=0xE0000000) ++ return RT_ERR_INPUT; ++ ++ svidx = 0xFFFF; ++ ++ for (i = 0; i < RTL8367C_SVIDXNO; i++) ++ { ++ if ((retVal = rtl8367c_getAsicSvlanMemberConfiguration(i, &svlanMemConf)) != RT_ERR_OK) ++ return retVal; ++ ++ if (svid == svlanMemConf.vs_svid) ++ { ++ svidx = i; ++ break; ++ } ++ } ++ ++ if (0xFFFF == svidx) ++ return RT_ERR_SVLAN_ENTRY_NOT_FOUND; ++ ++ ++ empty_idx = 0xFFFF; ++ ++ for (i = RTL8367C_MC2SIDXMAX; i >= 0; i--) ++ { ++ if ((retVal = rtl8367c_getAsicSvlanMC2SConf(i, &svlanMC2SConf)) != RT_ERR_OK) ++ return retVal; ++ ++ if (TRUE == svlanMC2SConf.valid) ++ { ++ if (svlanMC2SConf.format == SVLAN_MC2S_MODE_IP && ++ svlanMC2SConf.sdata==ipmc&& ++ svlanMC2SConf.smask==ipmcMsk) ++ { ++ svlanMC2SConf.svidx = svidx; ++ if ((retVal = rtl8367c_setAsicSvlanMC2SConf(i, &svlanMC2SConf)) != RT_ERR_OK) ++ return retVal; ++ } ++ } ++ else ++ { ++ empty_idx = i; ++ } ++ } ++ ++ if (empty_idx!=0xFFFF) ++ { ++ svlanMC2SConf.valid = TRUE; ++ svlanMC2SConf.svidx = svidx; ++ svlanMC2SConf.format = SVLAN_MC2S_MODE_IP; ++ svlanMC2SConf.sdata = ipmc; ++ svlanMC2SConf.smask = ipmcMsk; ++ if ((retVal = rtl8367c_setAsicSvlanMC2SConf(empty_idx, &svlanMC2SConf)) != RT_ERR_OK) ++ return retVal; ++ return RT_ERR_OK; ++ } ++ ++ return RT_ERR_OUT_OF_RANGE; ++ ++} ++ ++/* Function Name: ++ * rtk_svlan_ipmc2s_del ++ * Description: ++ * delete ip multicast address to SVLAN ++ * Input: ++ * ipmc - ip multicast address ++ * ipmcMsk - ip multicast mask ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. ++ * RT_ERR_OUT_OF_RANGE - input out of range. ++ * Note: ++ * The API can delete IP multicast to SVID configuration. There are 32 SVLAN multicast configurations for IP and L2 multicast. ++ */ ++rtk_api_ret_t rtk_svlan_ipmc2s_del(ipaddr_t ipmc, ipaddr_t ipmcMsk) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 i; ++ rtl8367c_svlan_mc2s_t svlanMC2SConf; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if ((ipmc&0xF0000000)!=0xE0000000) ++ return RT_ERR_INPUT; ++ ++ for (i = 0; i <= RTL8367C_MC2SIDXMAX; i++) ++ { ++ if ((retVal = rtl8367c_getAsicSvlanMC2SConf(i, &svlanMC2SConf)) != RT_ERR_OK) ++ return retVal; ++ ++ if (TRUE == svlanMC2SConf.valid) ++ { ++ if (svlanMC2SConf.format == SVLAN_MC2S_MODE_IP && ++ svlanMC2SConf.sdata==ipmc&& ++ svlanMC2SConf.smask==ipmcMsk) ++ { ++ memset(&svlanMC2SConf, 0, sizeof(rtl8367c_svlan_mc2s_t)); ++ if ((retVal = rtl8367c_setAsicSvlanMC2SConf(i, &svlanMC2SConf)) != RT_ERR_OK) ++ return retVal; ++ return RT_ERR_OK; ++ } ++ } ++ } ++ ++ return RT_ERR_OUT_OF_RANGE; ++} ++ ++/* Function Name: ++ * rtk_svlan_ipmc2s_get ++ * Description: ++ * Get ip multicast address to SVLAN ++ * Input: ++ * ipmc - ip multicast address ++ * ipmcMsk - ip multicast mask ++ * Output: ++ * pSvid - SVLAN VID ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_OUT_OF_RANGE - input out of range. ++ * Note: ++ * The API can get IP multicast to SVID configuration. There are 32 SVLAN multicast configurations for IP and L2 multicast. ++ */ ++rtk_api_ret_t rtk_svlan_ipmc2s_get(ipaddr_t ipmc, ipaddr_t ipmcMsk, rtk_vlan_t *pSvid) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 i; ++ rtl8367c_svlan_memconf_t svlanMemConf; ++ rtl8367c_svlan_mc2s_t svlanMC2SConf; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pSvid) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((ipmc&0xF0000000)!=0xE0000000) ++ return RT_ERR_INPUT; ++ ++ for (i = 0; i <= RTL8367C_MC2SIDXMAX; i++) ++ { ++ if ((retVal = rtl8367c_getAsicSvlanMC2SConf(i, &svlanMC2SConf)) != RT_ERR_OK) ++ return retVal; ++ ++ if (TRUE == svlanMC2SConf.valid && ++ svlanMC2SConf.format == SVLAN_MC2S_MODE_IP && ++ svlanMC2SConf.sdata == ipmc && ++ svlanMC2SConf.smask == ipmcMsk) ++ { ++ if ((retVal = rtl8367c_getAsicSvlanMemberConfiguration(svlanMC2SConf.svidx, &svlanMemConf)) != RT_ERR_OK) ++ return retVal; ++ *pSvid = svlanMemConf.vs_svid; ++ return RT_ERR_OK; ++ } ++ } ++ ++ return RT_ERR_OUT_OF_RANGE; ++} ++ ++/* Function Name: ++ * rtk_svlan_l2mc2s_add ++ * Description: ++ * Add L2 multicast address to SVLAN ++ * Input: ++ * mac - L2 multicast address ++ * macMsk - L2 multicast address mask ++ * svid - SVLAN VID ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. ++ * RT_ERR_SVLAN_ENTRY_NOT_FOUND - specified svlan entry not found. ++ * RT_ERR_OUT_OF_RANGE - input out of range. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can set L2 Multicast to SVID configuration. If upstream packet is L2 multicast ++ * packet and DMAC is matched, ASIC will assign egress SVID to the packet. There are 32 ++ * SVLAN multicast configurations for IP and L2 multicast. ++ */ ++rtk_api_ret_t rtk_svlan_l2mc2s_add(rtk_mac_t mac, rtk_mac_t macMsk, rtk_vlan_t svid) ++{ ++ rtk_api_ret_t retVal, i; ++ rtk_uint32 empty_idx; ++ rtk_uint32 svidx, l2add, l2Mask; ++ rtl8367c_svlan_memconf_t svlanMemConf; ++ rtl8367c_svlan_mc2s_t svlanMC2SConf; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (svid > RTL8367C_VIDMAX) ++ return RT_ERR_SVLAN_VID; ++ ++ if (mac.octet[0]!= 1&&mac.octet[1]!=0) ++ return RT_ERR_INPUT; ++ ++ l2add = (mac.octet[2] << 24) | (mac.octet[3] << 16) | (mac.octet[4] << 8) | mac.octet[5]; ++ l2Mask = (macMsk.octet[2] << 24) | (macMsk.octet[3] << 16) | (macMsk.octet[4] << 8) | macMsk.octet[5]; ++ ++ svidx = 0xFFFF; ++ ++ for (i = 0; i < RTL8367C_SVIDXNO; i++) ++ { ++ if ((retVal = rtl8367c_getAsicSvlanMemberConfiguration(i, &svlanMemConf)) != RT_ERR_OK) ++ return retVal; ++ ++ if (svid == svlanMemConf.vs_svid) ++ { ++ svidx = i; ++ break; ++ } ++ } ++ ++ if (0xFFFF == svidx) ++ return RT_ERR_SVLAN_ENTRY_NOT_FOUND; ++ ++ empty_idx = 0xFFFF; ++ ++ for (i = RTL8367C_MC2SIDXMAX; i >=0; i--) ++ { ++ if ((retVal = rtl8367c_getAsicSvlanMC2SConf(i, &svlanMC2SConf)) != RT_ERR_OK) ++ return retVal; ++ ++ if (TRUE == svlanMC2SConf.valid) ++ { ++ if (svlanMC2SConf.format == SVLAN_MC2S_MODE_MAC && ++ svlanMC2SConf.sdata==l2add&& ++ svlanMC2SConf.smask==l2Mask) ++ { ++ svlanMC2SConf.svidx = svidx; ++ if ((retVal = rtl8367c_setAsicSvlanMC2SConf(i, &svlanMC2SConf)) != RT_ERR_OK) ++ return retVal; ++ } ++ } ++ else ++ { ++ empty_idx = i; ++ } ++ } ++ ++ if (empty_idx!=0xFFFF) ++ { ++ svlanMC2SConf.valid = TRUE; ++ svlanMC2SConf.svidx = svidx; ++ svlanMC2SConf.format = SVLAN_MC2S_MODE_MAC; ++ svlanMC2SConf.sdata = l2add; ++ svlanMC2SConf.smask = l2Mask; ++ ++ if ((retVal = rtl8367c_setAsicSvlanMC2SConf(empty_idx, &svlanMC2SConf)) != RT_ERR_OK) ++ return retVal; ++ return RT_ERR_OK; ++ } ++ ++ return RT_ERR_OUT_OF_RANGE; ++} ++ ++/* Function Name: ++ * rtk_svlan_l2mc2s_del ++ * Description: ++ * delete L2 multicast address to SVLAN ++ * Input: ++ * mac - L2 multicast address ++ * macMsk - L2 multicast address mask ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. ++ * RT_ERR_OUT_OF_RANGE - input out of range. ++ * Note: ++ * The API can delete Multicast to SVID configuration. There are 32 SVLAN multicast configurations for IP and L2 multicast. ++ */ ++rtk_api_ret_t rtk_svlan_l2mc2s_del(rtk_mac_t mac, rtk_mac_t macMsk) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 i; ++ rtk_uint32 l2add, l2Mask; ++ rtl8367c_svlan_mc2s_t svlanMC2SConf; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (mac.octet[0]!= 1&&mac.octet[1]!=0) ++ return RT_ERR_INPUT; ++ ++ l2add = (mac.octet[2] << 24) | (mac.octet[3] << 16) | (mac.octet[4] << 8) | mac.octet[5]; ++ l2Mask = (macMsk.octet[2] << 24) | (macMsk.octet[3] << 16) | (macMsk.octet[4] << 8) | macMsk.octet[5]; ++ ++ for (i = 0; i <= RTL8367C_MC2SIDXMAX; i++) ++ { ++ if ((retVal = rtl8367c_getAsicSvlanMC2SConf(i, &svlanMC2SConf)) != RT_ERR_OK) ++ return retVal; ++ ++ if (TRUE == svlanMC2SConf.valid) ++ { ++ if (svlanMC2SConf.format == SVLAN_MC2S_MODE_MAC && ++ svlanMC2SConf.sdata==l2add&& ++ svlanMC2SConf.smask==l2Mask) ++ { ++ memset(&svlanMC2SConf, 0, sizeof(rtl8367c_svlan_mc2s_t)); ++ if ((retVal = rtl8367c_setAsicSvlanMC2SConf(i, &svlanMC2SConf)) != RT_ERR_OK) ++ return retVal; ++ return RT_ERR_OK; ++ } ++ } ++ } ++ ++ return RT_ERR_OUT_OF_RANGE; ++} ++ ++/* Function Name: ++ * rtk_svlan_l2mc2s_get ++ * Description: ++ * Get L2 multicast address to SVLAN ++ * Input: ++ * mac - L2 multicast address ++ * macMsk - L2 multicast address mask ++ * Output: ++ * pSvid - SVLAN VID ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_OUT_OF_RANGE - input out of range. ++ * Note: ++ * The API can get L2 multicast to SVID configuration. There are 32 SVLAN multicast configurations for IP and L2 multicast. ++ */ ++rtk_api_ret_t rtk_svlan_l2mc2s_get(rtk_mac_t mac, rtk_mac_t macMsk, rtk_vlan_t *pSvid) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 i; ++ rtk_uint32 l2add,l2Mask; ++ rtl8367c_svlan_memconf_t svlanMemConf; ++ rtl8367c_svlan_mc2s_t svlanMC2SConf; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pSvid) ++ return RT_ERR_NULL_POINTER; ++ ++ if (mac.octet[0]!= 1&&mac.octet[1]!=0) ++ return RT_ERR_INPUT; ++ ++ l2add = (mac.octet[2] << 24) | (mac.octet[3] << 16) | (mac.octet[4] << 8) | mac.octet[5]; ++ l2Mask = (macMsk.octet[2] << 24) | (macMsk.octet[3] << 16) | (macMsk.octet[4] << 8) | macMsk.octet[5]; ++ ++ for (i = 0; i <= RTL8367C_MC2SIDXMAX; i++) ++ { ++ if ((retVal = rtl8367c_getAsicSvlanMC2SConf(i, &svlanMC2SConf)) != RT_ERR_OK) ++ return retVal; ++ ++ if (TRUE == svlanMC2SConf.valid) ++ { ++ if (svlanMC2SConf.format == SVLAN_MC2S_MODE_MAC && ++ svlanMC2SConf.sdata==l2add&& ++ svlanMC2SConf.smask==l2Mask) ++ { ++ if ((retVal = rtl8367c_getAsicSvlanMemberConfiguration(svlanMC2SConf.svidx, &svlanMemConf)) != RT_ERR_OK) ++ return retVal; ++ *pSvid = svlanMemConf.vs_svid; ++ ++ return RT_ERR_OK; ++ } ++ } ++ } ++ ++ return RT_ERR_OUT_OF_RANGE; ++} ++ ++/* Function Name: ++ * rtk_svlan_sp2c_add ++ * Description: ++ * Add system SP2C configuration ++ * Input: ++ * cvid - VLAN ID ++ * dst_port - Destination port of SVLAN to CVLAN configuration ++ * svid - SVLAN VID ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. ++ * RT_ERR_VLAN_VID - Invalid VID parameter. ++ * RT_ERR_OUT_OF_RANGE - input out of range. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * The API can add SVID & Destination Port to CVLAN configuration. The downstream frames with assigned ++ * SVID will be add C-tag with assigned CVID if the output port is the assigned destination port. ++ * There are 128 SP2C configurations. ++ */ ++rtk_api_ret_t rtk_svlan_sp2c_add(rtk_vlan_t svid, rtk_port_t dst_port, rtk_vlan_t cvid) ++{ ++ rtk_api_ret_t retVal, i; ++ rtk_uint32 empty_idx, svidx; ++ rtl8367c_svlan_memconf_t svlanMemConf; ++ rtl8367c_svlan_s2c_t svlanSP2CConf; ++ rtk_port_t port; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (svid > RTL8367C_VIDMAX) ++ return RT_ERR_SVLAN_VID; ++ ++ if (cvid > RTL8367C_VIDMAX) ++ return RT_ERR_VLAN_VID; ++ ++ /* Check port Valid */ ++ RTK_CHK_PORT_VALID(dst_port); ++ port = rtk_switch_port_L2P_get(dst_port); ++ ++ svidx = 0xFFFF; ++ ++ for (i = 0; i < RTL8367C_SVIDXNO; i++) ++ { ++ if ((retVal = rtl8367c_getAsicSvlanMemberConfiguration(i, &svlanMemConf)) != RT_ERR_OK) ++ return retVal; ++ ++ if (svid == svlanMemConf.vs_svid) ++ { ++ svidx = i; ++ break; ++ } ++ } ++ ++ if (0xFFFF == svidx) ++ return RT_ERR_SVLAN_ENTRY_NOT_FOUND; ++ ++ empty_idx = 0xFFFF; ++ ++ for (i=RTL8367C_SP2CMAX; i >=0 ; i--) ++ { ++ if ((retVal = rtl8367c_getAsicSvlanSP2CConf(i, &svlanSP2CConf)) != RT_ERR_OK) ++ return retVal; ++ ++ if ( (svlanSP2CConf.svidx == svidx) && (svlanSP2CConf.dstport == port) && (svlanSP2CConf.valid == 1)) ++ { ++ empty_idx = i; ++ break; ++ } ++ else if (svlanSP2CConf.valid == 0) ++ { ++ empty_idx = i; ++ } ++ } ++ ++ if (empty_idx!=0xFFFF) ++ { ++ svlanSP2CConf.valid = 1; ++ svlanSP2CConf.vid = cvid; ++ svlanSP2CConf.svidx = svidx; ++ svlanSP2CConf.dstport = port; ++ ++ if ((retVal = rtl8367c_setAsicSvlanSP2CConf(empty_idx, &svlanSP2CConf)) != RT_ERR_OK) ++ return retVal; ++ return RT_ERR_OK; ++ } ++ ++ return RT_ERR_OUT_OF_RANGE; ++ ++} ++ ++/* Function Name: ++ * rtk_svlan_sp2c_get ++ * Description: ++ * Get configure system SP2C content ++ * Input: ++ * svid - SVLAN VID ++ * dst_port - Destination port of SVLAN to CVLAN configuration ++ * Output: ++ * pCvid - VLAN ID ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_OUT_OF_RANGE - input out of range. ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. ++ * Note: ++ * The API can get SVID & Destination Port to CVLAN configuration. There are 128 SP2C configurations. ++ */ ++rtk_api_ret_t rtk_svlan_sp2c_get(rtk_vlan_t svid, rtk_port_t dst_port, rtk_vlan_t *pCvid) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 i, svidx; ++ rtl8367c_svlan_memconf_t svlanMemConf; ++ rtl8367c_svlan_s2c_t svlanSP2CConf; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pCvid) ++ return RT_ERR_NULL_POINTER; ++ ++ if (svid > RTL8367C_VIDMAX) ++ return RT_ERR_SVLAN_VID; ++ ++ /* Check port Valid */ ++ RTK_CHK_PORT_VALID(dst_port); ++ dst_port = rtk_switch_port_L2P_get(dst_port); ++ ++ svidx = 0xFFFF; ++ ++ for (i = 0; i < RTL8367C_SVIDXNO; i++) ++ { ++ if ((retVal = rtl8367c_getAsicSvlanMemberConfiguration(i, &svlanMemConf)) != RT_ERR_OK) ++ return retVal; ++ ++ if (svid == svlanMemConf.vs_svid) ++ { ++ svidx = i; ++ break; ++ } ++ } ++ ++ if (0xFFFF == svidx) ++ return RT_ERR_SVLAN_ENTRY_NOT_FOUND; ++ ++ for (i = 0; i <= RTL8367C_SP2CMAX; i++) ++ { ++ if ((retVal = rtl8367c_getAsicSvlanSP2CConf(i, &svlanSP2CConf)) != RT_ERR_OK) ++ return retVal; ++ ++ if ( (svlanSP2CConf.svidx == svidx) && (svlanSP2CConf.dstport == dst_port) && (svlanSP2CConf.valid == 1) ) ++ { ++ *pCvid = svlanSP2CConf.vid; ++ return RT_ERR_OK; ++ } ++ } ++ ++ return RT_ERR_OUT_OF_RANGE; ++} ++ ++/* Function Name: ++ * rtk_svlan_sp2c_del ++ * Description: ++ * Delete system SP2C configuration ++ * Input: ++ * svid - SVLAN VID ++ * dst_port - Destination port of SVLAN to CVLAN configuration ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. ++ * RT_ERR_OUT_OF_RANGE - input out of range. ++ * Note: ++ * The API can delete SVID & Destination Port to CVLAN configuration. There are 128 SP2C configurations. ++ */ ++rtk_api_ret_t rtk_svlan_sp2c_del(rtk_vlan_t svid, rtk_port_t dst_port) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 i, svidx; ++ rtl8367c_svlan_memconf_t svlanMemConf; ++ rtl8367c_svlan_s2c_t svlanSP2CConf; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (svid > RTL8367C_VIDMAX) ++ return RT_ERR_SVLAN_VID; ++ ++ /* Check port Valid */ ++ RTK_CHK_PORT_VALID(dst_port); ++ dst_port = rtk_switch_port_L2P_get(dst_port); ++ ++ svidx = 0xFFFF; ++ ++ for (i = 0; i < RTL8367C_SVIDXNO; i++) ++ { ++ if ((retVal = rtl8367c_getAsicSvlanMemberConfiguration(i, &svlanMemConf)) != RT_ERR_OK) ++ return retVal; ++ ++ if (svid == svlanMemConf.vs_svid) ++ { ++ svidx = i; ++ break; ++ } ++ } ++ ++ if (0xFFFF == svidx) ++ return RT_ERR_SVLAN_ENTRY_NOT_FOUND; ++ ++ for (i = 0; i <= RTL8367C_SP2CMAX; i++) ++ { ++ if ((retVal = rtl8367c_getAsicSvlanSP2CConf(i, &svlanSP2CConf)) != RT_ERR_OK) ++ return retVal; ++ ++ if ( (svlanSP2CConf.svidx == svidx) && (svlanSP2CConf.dstport == dst_port) && (svlanSP2CConf.valid == 1) ) ++ { ++ svlanSP2CConf.valid = 0; ++ svlanSP2CConf.vid = 0; ++ svlanSP2CConf.svidx = 0; ++ svlanSP2CConf.dstport = 0; ++ ++ if ((retVal = rtl8367c_setAsicSvlanSP2CConf(i, &svlanSP2CConf)) != RT_ERR_OK) ++ return retVal; ++ return RT_ERR_OK; ++ } ++ ++ } ++ ++ return RT_ERR_OUT_OF_RANGE; ++} ++ ++/* Function Name: ++ * rtk_svlan_lookupType_set ++ * Description: ++ * Set lookup type of SVLAN ++ * Input: ++ * type - lookup type ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * Note: ++ * none ++ */ ++rtk_api_ret_t rtk_svlan_lookupType_set(rtk_svlan_lookupType_t type) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (type >= SVLAN_LOOKUP_END) ++ return RT_ERR_CHIP_NOT_SUPPORTED; ++ ++ ++ svlan_lookupType = type; ++ ++ retVal = rtl8367c_setAsicSvlanLookupType((rtk_uint32)type); ++ ++ return retVal; ++} ++ ++/* Function Name: ++ * rtk_svlan_lookupType_get ++ * Description: ++ * Get lookup type of SVLAN ++ * Input: ++ * pType - lookup type ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * Note: ++ * none ++ */ ++rtk_api_ret_t rtk_svlan_lookupType_get(rtk_svlan_lookupType_t *pType) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pType) ++ return RT_ERR_NULL_POINTER; ++ ++ retVal = rtl8367c_getAsicSvlanLookupType(pType); ++ ++ svlan_lookupType = *pType; ++ ++ return retVal; ++} ++ ++/* Function Name: ++ * rtk_svlan_trapPri_set ++ * Description: ++ * Set svlan trap priority ++ * Input: ++ * priority - priority for trap packets ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_QOS_INT_PRIORITY ++ * Note: ++ * None ++ */ ++rtk_api_ret_t rtk_svlan_trapPri_set(rtk_pri_t priority) ++{ ++ rtk_api_ret_t retVal; ++ ++ RTK_CHK_INIT_STATE(); ++ ++ if(priority > RTL8367C_PRIMAX) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ retVal = rtl8367c_setAsicSvlanTrapPriority(priority); ++ ++ return retVal; ++} /* end of rtk_svlan_trapPri_set */ ++ ++/* Function Name: ++ * rtk_svlan_trapPri_get ++ * Description: ++ * Get svlan trap priority ++ * Input: ++ * None ++ * Output: ++ * pPriority - priority for trap packets ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_NULL_POINTER - input parameter may be null pointer ++ * Note: ++ * None ++ */ ++rtk_api_ret_t rtk_svlan_trapPri_get(rtk_pri_t *pPriority) ++{ ++ rtk_api_ret_t retVal; ++ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pPriority) ++ return RT_ERR_NULL_POINTER; ++ ++ retVal = rtl8367c_getAsicSvlanTrapPriority(pPriority); ++ ++ return retVal; ++} /* end of rtk_svlan_trapPri_get */ ++ ++ ++/* Function Name: ++ * rtk_svlan_checkAndCreateMbr ++ * Description: ++ * Check and create Member configuration and return index ++ * Input: ++ * vid - VLAN id. ++ * Output: ++ * pIndex - Member configuration index ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_VLAN_VID - Invalid VLAN ID. ++ * RT_ERR_TBL_FULL - Member Configuration table full ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_svlan_checkAndCreateMbr(rtk_vlan_t vid, rtk_uint32 *pIndex) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 svidx; ++ rtk_uint32 empty_idx = 0xFFFF; ++ rtl8367c_svlan_memconf_t svlan_cfg; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* vid must be 0~4095 */ ++ if (vid > RTL8367C_VIDMAX) ++ return RT_ERR_VLAN_VID; ++ ++ /* Null pointer check */ ++ if(NULL == pIndex) ++ return RT_ERR_NULL_POINTER; ++ ++ /* Search exist entry */ ++ for (svidx = 0; svidx <= RTL8367C_SVIDXMAX; svidx++) ++ { ++ if(svlan_mbrCfgUsage[svidx] == TRUE) ++ { ++ if(svlan_mbrCfgVid[svidx] == vid) ++ { ++ /* Found! return index */ ++ *pIndex = svidx; ++ return RT_ERR_OK; ++ } ++ } ++ else if(empty_idx == 0xFFFF) ++ { ++ empty_idx = svidx; ++ } ++ ++ } ++ ++ if(empty_idx == 0xFFFF) ++ { ++ /* No empty index */ ++ return RT_ERR_TBL_FULL; ++ } ++ ++ svlan_mbrCfgUsage[empty_idx] = TRUE; ++ svlan_mbrCfgVid[empty_idx] = vid; ++ ++ memset(&svlan_cfg, 0, sizeof(rtl8367c_svlan_memconf_t)); ++ ++ svlan_cfg.vs_svid = vid; ++ /*for create check*/ ++ if(vid == 0) ++ { ++ svlan_cfg.vs_efid = 1; ++ } ++ ++ if((retVal = rtl8367c_setAsicSvlanMemberConfiguration(empty_idx, &svlan_cfg)) != RT_ERR_OK) ++ return retVal; ++ ++ *pIndex = empty_idx; ++ return RT_ERR_OK; ++} ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/trap.c b/drivers/net/phy/rtk/rtl8367c/trap.c +new file mode 100644 +index 000000000000..af9661058b27 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/trap.c +@@ -0,0 +1,1229 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ ++ * ++ * Purpose : RTK switch high-level API for RTL8367/RTL8367C ++ * Feature : Here is a list of all functions and variables in Trap module. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Function Name: ++ * rtk_trap_unknownUnicastPktAction_set ++ * Description: ++ * Set unknown unicast packet action configuration. ++ * Input: ++ * port - ingress port ID for unknown unicast packet ++ * ucast_action - Unknown unicast action. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_NOT_ALLOWED - Invalid action. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * This API can set unknown unicast packet action configuration. ++ * The unknown unicast action is as following: ++ * - UCAST_ACTION_FORWARD_PMASK ++ * - UCAST_ACTION_DROP ++ * - UCAST_ACTION_TRAP2CPU ++ * - UCAST_ACTION_FLOODING ++ */ ++rtk_api_ret_t rtk_trap_unknownUnicastPktAction_set(rtk_port_t port, rtk_trap_ucast_action_t ucast_action) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* check port valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if (ucast_action >= UCAST_ACTION_END) ++ return RT_ERR_INPUT; ++ ++ if ((retVal = rtl8367c_setAsicPortUnknownDaBehavior(rtk_switch_port_L2P_get(port), ucast_action)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_trap_unknownUnicastPktAction_get ++ * Description: ++ * Get unknown unicast packet action configuration. ++ * Input: ++ * port - ingress port ID for unknown unicast packet ++ * Output: ++ * pUcast_action - Unknown unicast action. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_NOT_ALLOWED - Invalid action. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_NULL_POINTER - Null pointer ++ * Note: ++ * This API can get unknown unicast packet action configuration. ++ * The unknown unicast action is as following: ++ * - UCAST_ACTION_FORWARD_PMASK ++ * - UCAST_ACTION_DROP ++ * - UCAST_ACTION_TRAP2CPU ++ * - UCAST_ACTION_FLOODING ++ */ ++rtk_api_ret_t rtk_trap_unknownUnicastPktAction_get(rtk_port_t port, rtk_trap_ucast_action_t *pUcast_action) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* check port valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if (NULL == pUcast_action) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicPortUnknownDaBehavior(rtk_switch_port_L2P_get(port), pUcast_action)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_trap_unknownMacPktAction_set ++ * Description: ++ * Set unknown source MAC packet action configuration. ++ * Input: ++ * ucast_action - Unknown source MAC action. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_NOT_ALLOWED - Invalid action. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * This API can set unknown unicast packet action configuration. ++ * The unknown unicast action is as following: ++ * - UCAST_ACTION_FORWARD_PMASK ++ * - UCAST_ACTION_DROP ++ * - UCAST_ACTION_TRAP2CPU ++ */ ++rtk_api_ret_t rtk_trap_unknownMacPktAction_set(rtk_trap_ucast_action_t ucast_action) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (ucast_action >= UCAST_ACTION_FLOODING) ++ return RT_ERR_INPUT; ++ ++ if ((retVal = rtl8367c_setAsicPortUnknownSaBehavior(ucast_action)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_trap_unknownMacPktAction_get ++ * Description: ++ * Get unknown source MAC packet action configuration. ++ * Input: ++ * None. ++ * Output: ++ * pUcast_action - Unknown source MAC action. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_NULL_POINTER - Null Pointer. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_trap_unknownMacPktAction_get(rtk_trap_ucast_action_t *pUcast_action) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pUcast_action) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicPortUnknownSaBehavior(pUcast_action)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_trap_unmatchMacPktAction_set ++ * Description: ++ * Set unmatch source MAC packet action configuration. ++ * Input: ++ * ucast_action - Unknown source MAC action. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_NOT_ALLOWED - Invalid action. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * This API can set unknown unicast packet action configuration. ++ * The unknown unicast action is as following: ++ * - UCAST_ACTION_FORWARD_PMASK ++ * - UCAST_ACTION_DROP ++ * - UCAST_ACTION_TRAP2CPU ++ */ ++rtk_api_ret_t rtk_trap_unmatchMacPktAction_set(rtk_trap_ucast_action_t ucast_action) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (ucast_action >= UCAST_ACTION_FLOODING) ++ return RT_ERR_INPUT; ++ ++ if ((retVal = rtl8367c_setAsicPortUnmatchedSaBehavior(ucast_action)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_trap_unmatchMacPktAction_get ++ * Description: ++ * Get unmatch source MAC packet action configuration. ++ * Input: ++ * None. ++ * Output: ++ * pUcast_action - Unknown source MAC action. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_NOT_ALLOWED - Invalid action. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * This API can set unknown unicast packet action configuration. ++ * The unknown unicast action is as following: ++ * - UCAST_ACTION_FORWARD_PMASK ++ * - UCAST_ACTION_DROP ++ * - UCAST_ACTION_TRAP2CPU ++ */ ++rtk_api_ret_t rtk_trap_unmatchMacPktAction_get(rtk_trap_ucast_action_t *pUcast_action) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pUcast_action) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicPortUnmatchedSaBehavior(pUcast_action)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_trap_unmatchMacMoving_set ++ * Description: ++ * Set unmatch source MAC packet moving state. ++ * Input: ++ * port - Port ID. ++ * enable - ENABLED: allow SA moving, DISABLE: don't allow SA moving. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_NOT_ALLOWED - Invalid action. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ */ ++rtk_api_ret_t rtk_trap_unmatchMacMoving_set(rtk_port_t port, rtk_enable_t enable) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* check port valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if(enable >= RTK_ENABLE_END) ++ return RT_ERR_INPUT; ++ ++ if ((retVal = rtl8367c_setAsicPortUnmatchedSaMoving(rtk_switch_port_L2P_get(port), enable)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_trap_unmatchMacMoving_get ++ * Description: ++ * Set unmatch source MAC packet moving state. ++ * Input: ++ * port - Port ID. ++ * Output: ++ * pEnable - ENABLED: allow SA moving, DISABLE: don't allow SA moving. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_NOT_ALLOWED - Invalid action. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ */ ++rtk_api_ret_t rtk_trap_unmatchMacMoving_get(rtk_port_t port, rtk_enable_t *pEnable) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* check port valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if(NULL == pEnable) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicPortUnmatchedSaMoving(rtk_switch_port_L2P_get(port), pEnable)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_trap_unknownMcastPktAction_set ++ * Description: ++ * Set behavior of unknown multicast ++ * Input: ++ * port - Port id. ++ * type - unknown multicast packet type. ++ * mcast_action - unknown multicast action. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_NOT_ALLOWED - Invalid action. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * When receives an unknown multicast packet, switch may trap, drop or flood this packet ++ * (1) The unknown multicast packet type is as following: ++ * - MCAST_L2 ++ * - MCAST_IPV4 ++ * - MCAST_IPV6 ++ * (2) The unknown multicast action is as following: ++ * - MCAST_ACTION_FORWARD ++ * - MCAST_ACTION_DROP ++ * - MCAST_ACTION_TRAP2CPU ++ */ ++rtk_api_ret_t rtk_trap_unknownMcastPktAction_set(rtk_port_t port, rtk_mcast_type_t type, rtk_trap_mcast_action_t mcast_action) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 rawAction; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if (type >= MCAST_END) ++ return RT_ERR_INPUT; ++ ++ if (mcast_action >= MCAST_ACTION_END) ++ return RT_ERR_INPUT; ++ ++ ++ switch (type) ++ { ++ case MCAST_L2: ++ if (MCAST_ACTION_ROUTER_PORT == mcast_action) ++ return RT_ERR_INPUT; ++ else if(MCAST_ACTION_DROP_EX_RMA == mcast_action) ++ rawAction = L2_UNKOWN_MULTICAST_DROP_EXCLUDE_RMA; ++ else ++ rawAction = (rtk_uint32)mcast_action; ++ ++ if ((retVal = rtl8367c_setAsicUnknownL2MulticastBehavior(rtk_switch_port_L2P_get(port), rawAction)) != RT_ERR_OK) ++ return retVal; ++ ++ break; ++ case MCAST_IPV4: ++ if (MCAST_ACTION_DROP_EX_RMA == mcast_action) ++ return RT_ERR_INPUT; ++ else ++ rawAction = (rtk_uint32)mcast_action; ++ ++ if ((retVal = rtl8367c_setAsicUnknownIPv4MulticastBehavior(rtk_switch_port_L2P_get(port), rawAction)) != RT_ERR_OK) ++ return retVal; ++ ++ break; ++ case MCAST_IPV6: ++ if (MCAST_ACTION_DROP_EX_RMA == mcast_action) ++ return RT_ERR_INPUT; ++ else ++ rawAction = (rtk_uint32)mcast_action; ++ ++ if ((retVal = rtl8367c_setAsicUnknownIPv6MulticastBehavior(rtk_switch_port_L2P_get(port), rawAction)) != RT_ERR_OK) ++ return retVal; ++ ++ break; ++ default: ++ break; ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_trap_unknownMcastPktAction_get ++ * Description: ++ * Get behavior of unknown multicast ++ * Input: ++ * type - unknown multicast packet type. ++ * Output: ++ * pMcast_action - unknown multicast action. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_NOT_ALLOWED - Invalid operation. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * When receives an unknown multicast packet, switch may trap, drop or flood this packet ++ * (1) The unknown multicast packet type is as following: ++ * - MCAST_L2 ++ * - MCAST_IPV4 ++ * - MCAST_IPV6 ++ * (2) The unknown multicast action is as following: ++ * - MCAST_ACTION_FORWARD ++ * - MCAST_ACTION_DROP ++ * - MCAST_ACTION_TRAP2CPU ++ */ ++rtk_api_ret_t rtk_trap_unknownMcastPktAction_get(rtk_port_t port, rtk_mcast_type_t type, rtk_trap_mcast_action_t *pMcast_action) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 rawAction; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if (type >= MCAST_END) ++ return RT_ERR_INPUT; ++ ++ if(NULL == pMcast_action) ++ return RT_ERR_NULL_POINTER; ++ ++ switch (type) ++ { ++ case MCAST_L2: ++ if ((retVal = rtl8367c_getAsicUnknownL2MulticastBehavior(rtk_switch_port_L2P_get(port), &rawAction)) != RT_ERR_OK) ++ return retVal; ++ ++ if(L2_UNKOWN_MULTICAST_DROP_EXCLUDE_RMA == rawAction) ++ *pMcast_action = MCAST_ACTION_DROP_EX_RMA; ++ else ++ *pMcast_action = (rtk_trap_mcast_action_t)rawAction; ++ ++ break; ++ case MCAST_IPV4: ++ if ((retVal = rtl8367c_getAsicUnknownIPv4MulticastBehavior(rtk_switch_port_L2P_get(port), &rawAction)) != RT_ERR_OK) ++ return retVal; ++ ++ *pMcast_action = (rtk_trap_mcast_action_t)rawAction; ++ break; ++ case MCAST_IPV6: ++ if ((retVal = rtl8367c_getAsicUnknownIPv6MulticastBehavior(rtk_switch_port_L2P_get(port), &rawAction)) != RT_ERR_OK) ++ return retVal; ++ ++ *pMcast_action = (rtk_trap_mcast_action_t)rawAction; ++ break; ++ default: ++ break; ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_trap_lldpEnable_set ++ * Description: ++ * Set LLDP enable. ++ * Input: ++ * enabled - LLDP enable, 0: follow RMA, 1: use LLDP action. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_NOT_ALLOWED - Invalid action. ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * - DMAC Assignment ++ * - 01:80:c2:00:00:0e ethertype = 0x88CC LLDP ++ * - 01:80:c2:00:00:03 ethertype = 0x88CC ++ * - 01:80:c2:00:00:00 ethertype = 0x88CC ++ ++ */ ++rtk_api_ret_t rtk_trap_lldpEnable_set(rtk_enable_t enabled) ++{ ++ rtk_api_ret_t retVal; ++ rtl8367c_rma_t rmacfg; ++ rtk_enable_t tmp; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (enabled >= RTK_ENABLE_END) ++ return RT_ERR_ENABLE; ++ ++ if ((retVal = rtl8367c_getAsicRmaLldp(&tmp, &rmacfg)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicRmaLldp(enabled, &rmacfg)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_trap_lldpEnable_get ++ * Description: ++ * Get LLDP status. ++ * Input: ++ * None ++ * Output: ++ * pEnabled - LLDP enable, 0: follow RMA, 1: use LLDP action. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * LLDP is as following definition. ++ * - DMAC Assignment ++ * - 01:80:c2:00:00:0e ethertype = 0x88CC LLDP ++ * - 01:80:c2:00:00:03 ethertype = 0x88CC ++ * - 01:80:c2:00:00:00 ethertype = 0x88CC ++ */ ++rtk_api_ret_t rtk_trap_lldpEnable_get(rtk_enable_t *pEnabled) ++{ ++ rtk_api_ret_t retVal; ++ rtl8367c_rma_t rmacfg; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pEnabled) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicRmaLldp(pEnabled, &rmacfg)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_trap_reasonTrapToCpuPriority_set ++ * Description: ++ * Set priority value of a packet that trapped to CPU port according to specific reason. ++ * Input: ++ * type - reason that trap to CPU port. ++ * priority - internal priority that is going to be set for specific trap reason. ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_NOT_INIT - The module is not initial ++ * RT_ERR_INPUT - Invalid input parameter ++ * Note: ++ * Currently the trap reason that supported are listed as follows: ++ * - TRAP_REASON_RMA ++ * - TRAP_REASON_OAM ++ * - TRAP_REASON_1XUNAUTH ++ * - TRAP_REASON_VLANSTACK ++ * - TRAP_REASON_UNKNOWNMC ++ */ ++rtk_api_ret_t rtk_trap_reasonTrapToCpuPriority_set(rtk_trap_reason_type_t type, rtk_pri_t priority) ++{ ++ rtk_api_ret_t retVal; ++ rtl8367c_rma_t rmacfg; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (type >= TRAP_REASON_END) ++ return RT_ERR_INPUT; ++ ++ if (priority > RTL8367C_PRIMAX) ++ return RT_ERR_QOS_INT_PRIORITY; ++ ++ switch (type) ++ { ++ case TRAP_REASON_RMA: ++ if ((retVal = rtl8367c_getAsicRma(0, &rmacfg)) != RT_ERR_OK) ++ return retVal; ++ rmacfg.trap_priority= priority; ++ if ((retVal = rtl8367c_setAsicRma(0, &rmacfg)) != RT_ERR_OK) ++ return retVal; ++ ++ break; ++ case TRAP_REASON_OAM: ++ if ((retVal = rtl8367c_setAsicOamCpuPri(priority)) != RT_ERR_OK) ++ return retVal; ++ ++ break; ++ case TRAP_REASON_1XUNAUTH: ++ if ((retVal = rtl8367c_setAsic1xTrapPriority(priority)) != RT_ERR_OK) ++ return retVal; ++ ++ break; ++ case TRAP_REASON_VLANSTACK: ++ if ((retVal = rtl8367c_setAsicSvlanTrapPriority(priority)) != RT_ERR_OK) ++ return retVal; ++ ++ break; ++ case TRAP_REASON_UNKNOWNMC: ++ if ((retVal = rtl8367c_setAsicUnknownMulticastTrapPriority(priority)) != RT_ERR_OK) ++ return retVal; ++ ++ break; ++ default: ++ return RT_ERR_CHIP_NOT_SUPPORTED; ++ } ++ ++ ++ return RT_ERR_OK; ++} ++ ++ ++/* Function Name: ++ * rtk_trap_reasonTrapToCpuPriority_get ++ * Description: ++ * Get priority value of a packet that trapped to CPU port according to specific reason. ++ * Input: ++ * type - reason that trap to CPU port. ++ * Output: ++ * pPriority - configured internal priority for such reason. ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_NOT_INIT - The module is not initial ++ * RT_ERR_INPUT - Invalid input parameter ++ * RT_ERR_NULL_POINTER - NULL pointer ++ * Note: ++ * Currently the trap reason that supported are listed as follows: ++ * - TRAP_REASON_RMA ++ * - TRAP_REASON_OAM ++ * - TRAP_REASON_1XUNAUTH ++ * - TRAP_REASON_VLANSTACK ++ * - TRAP_REASON_UNKNOWNMC ++ */ ++rtk_api_ret_t rtk_trap_reasonTrapToCpuPriority_get(rtk_trap_reason_type_t type, rtk_pri_t *pPriority) ++{ ++ rtk_api_ret_t retVal; ++ rtl8367c_rma_t rmacfg; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (type >= TRAP_REASON_END) ++ return RT_ERR_INPUT; ++ ++ if(NULL == pPriority) ++ return RT_ERR_NULL_POINTER; ++ ++ switch (type) ++ { ++ case TRAP_REASON_RMA: ++ if ((retVal = rtl8367c_getAsicRma(0, &rmacfg)) != RT_ERR_OK) ++ return retVal; ++ *pPriority = rmacfg.trap_priority; ++ ++ break; ++ case TRAP_REASON_OAM: ++ if ((retVal = rtl8367c_getAsicOamCpuPri(pPriority)) != RT_ERR_OK) ++ return retVal; ++ ++ break; ++ case TRAP_REASON_1XUNAUTH: ++ if ((retVal = rtl8367c_getAsic1xTrapPriority(pPriority)) != RT_ERR_OK) ++ return retVal; ++ ++ break; ++ case TRAP_REASON_VLANSTACK: ++ if ((retVal = rtl8367c_getAsicSvlanTrapPriority(pPriority)) != RT_ERR_OK) ++ return retVal; ++ ++ break; ++ case TRAP_REASON_UNKNOWNMC: ++ if ((retVal = rtl8367c_getAsicUnknownMulticastTrapPriority(pPriority)) != RT_ERR_OK) ++ return retVal; ++ ++ break; ++ default: ++ return RT_ERR_CHIP_NOT_SUPPORTED; ++ ++ } ++ ++ return RT_ERR_OK; ++} ++ ++ ++ ++/* Function Name: ++ * rtk_trap_rmaAction_set ++ * Description: ++ * Set Reserved multicast address action configuration. ++ * Input: ++ * type - rma type. ++ * rma_action - RMA action. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * ++ * There are 48 types of Reserved Multicast Address frame for application usage. ++ * (1)They are as following definition. ++ * - TRAP_BRG_GROUP, ++ * - TRAP_FD_PAUSE, ++ * - TRAP_SP_MCAST, ++ * - TRAP_1X_PAE, ++ * - TRAP_UNDEF_BRG_04, ++ * - TRAP_UNDEF_BRG_05, ++ * - TRAP_UNDEF_BRG_06, ++ * - TRAP_UNDEF_BRG_07, ++ * - TRAP_PROVIDER_BRIDGE_GROUP_ADDRESS, ++ * - TRAP_UNDEF_BRG_09, ++ * - TRAP_UNDEF_BRG_0A, ++ * - TRAP_UNDEF_BRG_0B, ++ * - TRAP_UNDEF_BRG_0C, ++ * - TRAP_PROVIDER_BRIDGE_GVRP_ADDRESS, ++ * - TRAP_8021AB, ++ * - TRAP_UNDEF_BRG_0F, ++ * - TRAP_BRG_MNGEMENT, ++ * - TRAP_UNDEFINED_11, ++ * - TRAP_UNDEFINED_12, ++ * - TRAP_UNDEFINED_13, ++ * - TRAP_UNDEFINED_14, ++ * - TRAP_UNDEFINED_15, ++ * - TRAP_UNDEFINED_16, ++ * - TRAP_UNDEFINED_17, ++ * - TRAP_UNDEFINED_18, ++ * - TRAP_UNDEFINED_19, ++ * - TRAP_UNDEFINED_1A, ++ * - TRAP_UNDEFINED_1B, ++ * - TRAP_UNDEFINED_1C, ++ * - TRAP_UNDEFINED_1D, ++ * - TRAP_UNDEFINED_1E, ++ * - TRAP_UNDEFINED_1F, ++ * - TRAP_GMRP, ++ * - TRAP_GVRP, ++ * - TRAP_UNDEF_GARP_22, ++ * - TRAP_UNDEF_GARP_23, ++ * - TRAP_UNDEF_GARP_24, ++ * - TRAP_UNDEF_GARP_25, ++ * - TRAP_UNDEF_GARP_26, ++ * - TRAP_UNDEF_GARP_27, ++ * - TRAP_UNDEF_GARP_28, ++ * - TRAP_UNDEF_GARP_29, ++ * - TRAP_UNDEF_GARP_2A, ++ * - TRAP_UNDEF_GARP_2B, ++ * - TRAP_UNDEF_GARP_2C, ++ * - TRAP_UNDEF_GARP_2D, ++ * - TRAP_UNDEF_GARP_2E, ++ * - TRAP_UNDEF_GARP_2F, ++ * - TRAP_CDP. ++ * - TRAP_CSSTP. ++ * - TRAP_LLDP. ++ * (2) The RMA action is as following: ++ * - RMA_ACTION_FORWARD ++ * - RMA_ACTION_TRAP2CPU ++ * - RMA_ACTION_DROP ++ * - RMA_ACTION_FORWARD_EXCLUDE_CPU ++ */ ++rtk_api_ret_t rtk_trap_rmaAction_set(rtk_trap_type_t type, rtk_trap_rma_action_t rma_action) ++{ ++ rtk_api_ret_t retVal; ++ rtl8367c_rma_t rmacfg; ++ rtk_uint32 tmp; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (type >= TRAP_END) ++ return RT_ERR_INPUT; ++ ++ if (rma_action >= RMA_ACTION_END) ++ return RT_ERR_RMA_ACTION; ++ ++ if (type >= 0 && type <= TRAP_UNDEF_GARP_2F) ++ { ++ if ((retVal = rtl8367c_getAsicRma(type, &rmacfg)) != RT_ERR_OK) ++ return retVal; ++ ++ rmacfg.operation = rma_action; ++ ++ if ((retVal = rtl8367c_setAsicRma(type, &rmacfg)) != RT_ERR_OK) ++ return retVal; ++ } ++ else if (type == TRAP_CDP) ++ { ++ if ((retVal = rtl8367c_getAsicRmaCdp(&rmacfg)) != RT_ERR_OK) ++ return retVal; ++ ++ rmacfg.operation = rma_action; ++ ++ if ((retVal = rtl8367c_setAsicRmaCdp(&rmacfg)) != RT_ERR_OK) ++ return retVal; ++ } ++ else if (type == TRAP_CSSTP) ++ { ++ if ((retVal = rtl8367c_getAsicRmaCsstp(&rmacfg)) != RT_ERR_OK) ++ return retVal; ++ ++ rmacfg.operation = rma_action; ++ ++ if ((retVal = rtl8367c_setAsicRmaCsstp(&rmacfg)) != RT_ERR_OK) ++ return retVal; ++ } ++ else if (type == TRAP_LLDP) ++ { ++ if ((retVal = rtl8367c_getAsicRmaLldp(&tmp, &rmacfg)) != RT_ERR_OK) ++ return retVal; ++ ++ rmacfg.operation = rma_action; ++ ++ if ((retVal = rtl8367c_setAsicRmaLldp(tmp, &rmacfg)) != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ return RT_ERR_INPUT; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_trap_rmaAction_get ++ * Description: ++ * Get Reserved multicast address action configuration. ++ * Input: ++ * type - rma type. ++ * Output: ++ * pRma_action - RMA action. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * There are 48 types of Reserved Multicast Address frame for application usage. ++ * (1)They are as following definition. ++ * - TRAP_BRG_GROUP, ++ * - TRAP_FD_PAUSE, ++ * - TRAP_SP_MCAST, ++ * - TRAP_1X_PAE, ++ * - TRAP_UNDEF_BRG_04, ++ * - TRAP_UNDEF_BRG_05, ++ * - TRAP_UNDEF_BRG_06, ++ * - TRAP_UNDEF_BRG_07, ++ * - TRAP_PROVIDER_BRIDGE_GROUP_ADDRESS, ++ * - TRAP_UNDEF_BRG_09, ++ * - TRAP_UNDEF_BRG_0A, ++ * - TRAP_UNDEF_BRG_0B, ++ * - TRAP_UNDEF_BRG_0C, ++ * - TRAP_PROVIDER_BRIDGE_GVRP_ADDRESS, ++ * - TRAP_8021AB, ++ * - TRAP_UNDEF_BRG_0F, ++ * - TRAP_BRG_MNGEMENT, ++ * - TRAP_UNDEFINED_11, ++ * - TRAP_UNDEFINED_12, ++ * - TRAP_UNDEFINED_13, ++ * - TRAP_UNDEFINED_14, ++ * - TRAP_UNDEFINED_15, ++ * - TRAP_UNDEFINED_16, ++ * - TRAP_UNDEFINED_17, ++ * - TRAP_UNDEFINED_18, ++ * - TRAP_UNDEFINED_19, ++ * - TRAP_UNDEFINED_1A, ++ * - TRAP_UNDEFINED_1B, ++ * - TRAP_UNDEFINED_1C, ++ * - TRAP_UNDEFINED_1D, ++ * - TRAP_UNDEFINED_1E, ++ * - TRAP_UNDEFINED_1F, ++ * - TRAP_GMRP, ++ * - TRAP_GVRP, ++ * - TRAP_UNDEF_GARP_22, ++ * - TRAP_UNDEF_GARP_23, ++ * - TRAP_UNDEF_GARP_24, ++ * - TRAP_UNDEF_GARP_25, ++ * - TRAP_UNDEF_GARP_26, ++ * - TRAP_UNDEF_GARP_27, ++ * - TRAP_UNDEF_GARP_28, ++ * - TRAP_UNDEF_GARP_29, ++ * - TRAP_UNDEF_GARP_2A, ++ * - TRAP_UNDEF_GARP_2B, ++ * - TRAP_UNDEF_GARP_2C, ++ * - TRAP_UNDEF_GARP_2D, ++ * - TRAP_UNDEF_GARP_2E, ++ * - TRAP_UNDEF_GARP_2F, ++ * - TRAP_CDP. ++ * - TRAP_CSSTP. ++ * - TRAP_LLDP. ++ * (2) The RMA action is as following: ++ * - RMA_ACTION_FORWARD ++ * - RMA_ACTION_TRAP2CPU ++ * - RMA_ACTION_DROP ++ * - RMA_ACTION_FORWARD_EXCLUDE_CPU ++ */ ++rtk_api_ret_t rtk_trap_rmaAction_get(rtk_trap_type_t type, rtk_trap_rma_action_t *pRma_action) ++{ ++ rtk_api_ret_t retVal; ++ rtl8367c_rma_t rmacfg; ++ rtk_uint32 tmp; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (type >= TRAP_END) ++ return RT_ERR_INPUT; ++ ++ if(NULL == pRma_action) ++ return RT_ERR_NULL_POINTER; ++ ++ if (type >= 0 && type <= TRAP_UNDEF_GARP_2F) ++ { ++ if ((retVal = rtl8367c_getAsicRma(type, &rmacfg)) != RT_ERR_OK) ++ return retVal; ++ ++ *pRma_action = rmacfg.operation; ++ } ++ else if (type == TRAP_CDP) ++ { ++ if ((retVal = rtl8367c_getAsicRmaCdp(&rmacfg)) != RT_ERR_OK) ++ return retVal; ++ ++ *pRma_action = rmacfg.operation; ++ } ++ else if (type == TRAP_CSSTP) ++ { ++ if ((retVal = rtl8367c_getAsicRmaCsstp(&rmacfg)) != RT_ERR_OK) ++ return retVal; ++ ++ *pRma_action = rmacfg.operation; ++ } ++ else if (type == TRAP_LLDP) ++ { ++ if ((retVal = rtl8367c_getAsicRmaLldp(&tmp,&rmacfg)) != RT_ERR_OK) ++ return retVal; ++ ++ *pRma_action = rmacfg.operation; ++ } ++ else ++ return RT_ERR_INPUT; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_trap_rmaKeepFormat_set ++ * Description: ++ * Set Reserved multicast address keep format configuration. ++ * Input: ++ * type - rma type. ++ * enable - enable keep format. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_ENABLE - Invalid IFG parameter ++ * Note: ++ * ++ * There are 48 types of Reserved Multicast Address frame for application usage. ++ * They are as following definition. ++ * - TRAP_BRG_GROUP, ++ * - TRAP_FD_PAUSE, ++ * - TRAP_SP_MCAST, ++ * - TRAP_1X_PAE, ++ * - TRAP_UNDEF_BRG_04, ++ * - TRAP_UNDEF_BRG_05, ++ * - TRAP_UNDEF_BRG_06, ++ * - TRAP_UNDEF_BRG_07, ++ * - TRAP_PROVIDER_BRIDGE_GROUP_ADDRESS, ++ * - TRAP_UNDEF_BRG_09, ++ * - TRAP_UNDEF_BRG_0A, ++ * - TRAP_UNDEF_BRG_0B, ++ * - TRAP_UNDEF_BRG_0C, ++ * - TRAP_PROVIDER_BRIDGE_GVRP_ADDRESS, ++ * - TRAP_8021AB, ++ * - TRAP_UNDEF_BRG_0F, ++ * - TRAP_BRG_MNGEMENT, ++ * - TRAP_UNDEFINED_11, ++ * - TRAP_UNDEFINED_12, ++ * - TRAP_UNDEFINED_13, ++ * - TRAP_UNDEFINED_14, ++ * - TRAP_UNDEFINED_15, ++ * - TRAP_UNDEFINED_16, ++ * - TRAP_UNDEFINED_17, ++ * - TRAP_UNDEFINED_18, ++ * - TRAP_UNDEFINED_19, ++ * - TRAP_UNDEFINED_1A, ++ * - TRAP_UNDEFINED_1B, ++ * - TRAP_UNDEFINED_1C, ++ * - TRAP_UNDEFINED_1D, ++ * - TRAP_UNDEFINED_1E, ++ * - TRAP_UNDEFINED_1F, ++ * - TRAP_GMRP, ++ * - TRAP_GVRP, ++ * - TRAP_UNDEF_GARP_22, ++ * - TRAP_UNDEF_GARP_23, ++ * - TRAP_UNDEF_GARP_24, ++ * - TRAP_UNDEF_GARP_25, ++ * - TRAP_UNDEF_GARP_26, ++ * - TRAP_UNDEF_GARP_27, ++ * - TRAP_UNDEF_GARP_28, ++ * - TRAP_UNDEF_GARP_29, ++ * - TRAP_UNDEF_GARP_2A, ++ * - TRAP_UNDEF_GARP_2B, ++ * - TRAP_UNDEF_GARP_2C, ++ * - TRAP_UNDEF_GARP_2D, ++ * - TRAP_UNDEF_GARP_2E, ++ * - TRAP_UNDEF_GARP_2F, ++ * - TRAP_CDP. ++ * - TRAP_CSSTP. ++ * - TRAP_LLDP. ++ */ ++rtk_api_ret_t rtk_trap_rmaKeepFormat_set(rtk_trap_type_t type, rtk_enable_t enable) ++{ ++ rtk_api_ret_t retVal; ++ rtl8367c_rma_t rmacfg; ++ rtk_uint32 tmp; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (type >= TRAP_END) ++ return RT_ERR_INPUT; ++ ++ if (enable >= RTK_ENABLE_END) ++ return RT_ERR_INPUT; ++ ++ if (type >= 0 && type <= TRAP_UNDEF_GARP_2F) ++ { ++ if ((retVal = rtl8367c_getAsicRma(type, &rmacfg)) != RT_ERR_OK) ++ return retVal; ++ ++ rmacfg.keep_format = enable; ++ ++ if ((retVal = rtl8367c_setAsicRma(type, &rmacfg)) != RT_ERR_OK) ++ return retVal; ++ } ++ else if (type == TRAP_CDP) ++ { ++ if ((retVal = rtl8367c_getAsicRmaCdp(&rmacfg)) != RT_ERR_OK) ++ return retVal; ++ ++ rmacfg.keep_format = enable; ++ ++ if ((retVal = rtl8367c_setAsicRmaCdp(&rmacfg)) != RT_ERR_OK) ++ return retVal; ++ } ++ else if (type == TRAP_CSSTP) ++ { ++ if ((retVal = rtl8367c_getAsicRmaCsstp(&rmacfg)) != RT_ERR_OK) ++ return retVal; ++ ++ rmacfg.keep_format = enable; ++ ++ if ((retVal = rtl8367c_setAsicRmaCsstp(&rmacfg)) != RT_ERR_OK) ++ return retVal; ++ } ++ else if (type == TRAP_LLDP) ++ { ++ if ((retVal = rtl8367c_getAsicRmaLldp(&tmp, &rmacfg)) != RT_ERR_OK) ++ return retVal; ++ ++ rmacfg.keep_format = enable; ++ ++ if ((retVal = rtl8367c_setAsicRmaLldp(tmp, &rmacfg)) != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ return RT_ERR_INPUT; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_trap_rmaKeepFormat_get ++ * Description: ++ * Get Reserved multicast address action configuration. ++ * Input: ++ * type - rma type. ++ * Output: ++ * pEnable - keep format status. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * Note: ++ * There are 48 types of Reserved Multicast Address frame for application usage. ++ * They are as following definition. ++ * - TRAP_BRG_GROUP, ++ * - TRAP_FD_PAUSE, ++ * - TRAP_SP_MCAST, ++ * - TRAP_1X_PAE, ++ * - TRAP_UNDEF_BRG_04, ++ * - TRAP_UNDEF_BRG_05, ++ * - TRAP_UNDEF_BRG_06, ++ * - TRAP_UNDEF_BRG_07, ++ * - TRAP_PROVIDER_BRIDGE_GROUP_ADDRESS, ++ * - TRAP_UNDEF_BRG_09, ++ * - TRAP_UNDEF_BRG_0A, ++ * - TRAP_UNDEF_BRG_0B, ++ * - TRAP_UNDEF_BRG_0C, ++ * - TRAP_PROVIDER_BRIDGE_GVRP_ADDRESS, ++ * - TRAP_8021AB, ++ * - TRAP_UNDEF_BRG_0F, ++ * - TRAP_BRG_MNGEMENT, ++ * - TRAP_UNDEFINED_11, ++ * - TRAP_UNDEFINED_12, ++ * - TRAP_UNDEFINED_13, ++ * - TRAP_UNDEFINED_14, ++ * - TRAP_UNDEFINED_15, ++ * - TRAP_UNDEFINED_16, ++ * - TRAP_UNDEFINED_17, ++ * - TRAP_UNDEFINED_18, ++ * - TRAP_UNDEFINED_19, ++ * - TRAP_UNDEFINED_1A, ++ * - TRAP_UNDEFINED_1B, ++ * - TRAP_UNDEFINED_1C, ++ * - TRAP_UNDEFINED_1D, ++ * - TRAP_UNDEFINED_1E, ++ * - TRAP_UNDEFINED_1F, ++ * - TRAP_GMRP, ++ * - TRAP_GVRP, ++ * - TRAP_UNDEF_GARP_22, ++ * - TRAP_UNDEF_GARP_23, ++ * - TRAP_UNDEF_GARP_24, ++ * - TRAP_UNDEF_GARP_25, ++ * - TRAP_UNDEF_GARP_26, ++ * - TRAP_UNDEF_GARP_27, ++ * - TRAP_UNDEF_GARP_28, ++ * - TRAP_UNDEF_GARP_29, ++ * - TRAP_UNDEF_GARP_2A, ++ * - TRAP_UNDEF_GARP_2B, ++ * - TRAP_UNDEF_GARP_2C, ++ * - TRAP_UNDEF_GARP_2D, ++ * - TRAP_UNDEF_GARP_2E, ++ * - TRAP_UNDEF_GARP_2F, ++ * - TRAP_CDP. ++ * - TRAP_CSSTP. ++ * - TRAP_LLDP. ++ */ ++rtk_api_ret_t rtk_trap_rmaKeepFormat_get(rtk_trap_type_t type, rtk_enable_t *pEnable) ++{ ++ rtk_api_ret_t retVal; ++ rtl8367c_rma_t rmacfg; ++ rtk_uint32 tmp; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (type >= TRAP_END) ++ return RT_ERR_INPUT; ++ ++ if(NULL == pEnable) ++ return RT_ERR_NULL_POINTER; ++ ++ if (type >= 0 && type <= TRAP_UNDEF_GARP_2F) ++ { ++ if ((retVal = rtl8367c_getAsicRma(type, &rmacfg)) != RT_ERR_OK) ++ return retVal; ++ ++ *pEnable = rmacfg.keep_format; ++ } ++ else if (type == TRAP_CDP) ++ { ++ if ((retVal = rtl8367c_getAsicRmaCdp(&rmacfg)) != RT_ERR_OK) ++ return retVal; ++ ++ *pEnable = rmacfg.keep_format; ++ } ++ else if (type == TRAP_CSSTP) ++ { ++ if ((retVal = rtl8367c_getAsicRmaCsstp(&rmacfg)) != RT_ERR_OK) ++ return retVal; ++ ++ *pEnable = rmacfg.keep_format; ++ } ++ else if (type == TRAP_LLDP) ++ { ++ if ((retVal = rtl8367c_getAsicRmaLldp(&tmp,&rmacfg)) != RT_ERR_OK) ++ return retVal; ++ ++ *pEnable = rmacfg.keep_format; ++ } ++ else ++ return RT_ERR_INPUT; ++ ++ return RT_ERR_OK; ++} ++ ++ ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/trunk.c b/drivers/net/phy/rtk/rtl8367c/trunk.c +new file mode 100644 +index 000000000000..8a88dc5ff000 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/trunk.c +@@ -0,0 +1,605 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ ++ * ++ * Purpose : RTK switch high-level API for RTL8367/RTL8367C ++ * Feature : Here is a list of all functions and variables in Trunk module. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++/* Function Name: ++ * rtk_trunk_port_set ++ * Description: ++ * Set trunking group available port mask ++ * Input: ++ * trk_gid - trunk group id ++ * pTrunk_member_portmask - Logic trunking member port mask ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_LA_TRUNK_ID - Invalid trunking group ++ * RT_ERR_PORT_MASK - Invalid portmask. ++ * Note: ++ * The API can set port trunking group port mask. Each port trunking group has max 4 ports. ++ * If enabled port mask has less than 2 ports available setting, then this trunking group function is disabled. ++ */ ++rtk_api_ret_t rtk_trunk_port_set(rtk_trunk_group_t trk_gid, rtk_portmask_t *pTrunk_member_portmask) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 pmsk; ++ rtk_uint32 regValue, type, tmp; ++ ++ ++ if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0249)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_getAsicReg(0x1300, ®Value)) != RT_ERR_OK) ++ return retVal; ++ ++ if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0000)) != RT_ERR_OK) ++ return retVal; ++ ++ switch (regValue) ++ { ++ case 0x0276: ++ case 0x0597: ++ case 0x6367: ++ type = 0; ++ break; ++ case 0x0652: ++ case 0x6368: ++ type = 1; ++ break; ++ case 0x0801: ++ case 0x6511: ++ type = 2; ++ break; ++ default: ++ return RT_ERR_FAILED; ++ } ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Trunk Group Valid */ ++ RTK_CHK_TRUNK_GROUP_VALID(trk_gid); ++ ++ if(NULL == pTrunk_member_portmask) ++ return RT_ERR_NULL_POINTER; ++ ++ RTK_CHK_PORTMASK_VALID(pTrunk_member_portmask); ++ ++ if((retVal = rtk_switch_portmask_L2P_get(pTrunk_member_portmask, &pmsk)) != RT_ERR_OK) ++ return retVal; ++ ++ if((type == 0) || (type == 1)) ++ { ++ if ((pmsk | RTL8367C_PORT_TRUNK_GROUP_MASK_MASK(trk_gid)) != (rtk_uint32)RTL8367C_PORT_TRUNK_GROUP_MASK_MASK(trk_gid)) ++ return RT_ERR_PORT_MASK; ++ ++ pmsk = (pmsk & RTL8367C_PORT_TRUNK_GROUP_MASK_MASK(trk_gid)) >> RTL8367C_PORT_TRUNK_GROUP_MASK_OFFSET(trk_gid); ++ } ++ else if(type == 2) ++ { ++ tmp = 0; ++ ++ if(pmsk & 0x2) ++ tmp |= 1; ++ if(pmsk & 0x8) ++ tmp |=2; ++ if(pmsk & 0x80) ++ tmp |=8; ++ ++ pmsk = tmp; ++ } ++ ++ if ((retVal = rtl8367c_setAsicTrunkingGroup(trk_gid, pmsk)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_trunk_port_get ++ * Description: ++ * Get trunking group available port mask ++ * Input: ++ * trk_gid - trunk group id ++ * Output: ++ * pTrunk_member_portmask - Logic trunking member port mask ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_LA_TRUNK_ID - Invalid trunking group ++ * Note: ++ * The API can get 2 port trunking group. ++ */ ++rtk_api_ret_t rtk_trunk_port_get(rtk_trunk_group_t trk_gid, rtk_portmask_t *pTrunk_member_portmask) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 pmsk; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Trunk Group Valid */ ++ RTK_CHK_TRUNK_GROUP_VALID(trk_gid); ++ ++ if ((retVal = rtl8367c_getAsicTrunkingGroup(trk_gid, &pmsk)) != RT_ERR_OK) ++ return retVal; ++ ++ pmsk = pmsk << RTL8367C_PORT_TRUNK_GROUP_MASK_OFFSET(trk_gid); ++ ++ if((retVal = rtk_switch_portmask_P2L_get(pmsk, pTrunk_member_portmask)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_trunk_distributionAlgorithm_set ++ * Description: ++ * Set port trunking hash select sources ++ * Input: ++ * trk_gid - trunk group id ++ * algo_bitmask - Bitmask of the distribution algorithm ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_LA_TRUNK_ID - Invalid trunking group ++ * RT_ERR_LA_HASHMASK - Hash algorithm selection error. ++ * RT_ERR_PORT_MASK - Invalid portmask. ++ * Note: ++ * The API can set port trunking hash algorithm sources. ++ * 7 bits mask for link aggregation group0 hash parameter selection {DIP, SIP, DMAC, SMAC, SPA} ++ * - 0b0000001: SPA ++ * - 0b0000010: SMAC ++ * - 0b0000100: DMAC ++ * - 0b0001000: SIP ++ * - 0b0010000: DIP ++ * - 0b0100000: TCP/UDP Source Port ++ * - 0b1000000: TCP/UDP Destination Port ++ * Example: ++ * - 0b0000011: SMAC & SPA ++ * - Note that it could be an arbitrary combination or independent set ++ */ ++rtk_api_ret_t rtk_trunk_distributionAlgorithm_set(rtk_trunk_group_t trk_gid, rtk_uint32 algo_bitmask) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (trk_gid != RTK_WHOLE_SYSTEM) ++ return RT_ERR_LA_TRUNK_ID; ++ ++ if (algo_bitmask >= 128) ++ return RT_ERR_LA_HASHMASK; ++ ++ if ((retVal = rtl8367c_setAsicTrunkingHashSelect(algo_bitmask)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_trunk_distributionAlgorithm_get ++ * Description: ++ * Get port trunking hash select sources ++ * Input: ++ * trk_gid - trunk group id ++ * Output: ++ * pAlgo_bitmask - Bitmask of the distribution algorithm ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_LA_TRUNK_ID - Invalid trunking group ++ * Note: ++ * The API can get port trunking hash algorithm sources. ++ */ ++rtk_api_ret_t rtk_trunk_distributionAlgorithm_get(rtk_trunk_group_t trk_gid, rtk_uint32 *pAlgo_bitmask) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (trk_gid != RTK_WHOLE_SYSTEM) ++ return RT_ERR_LA_TRUNK_ID; ++ ++ if(NULL == pAlgo_bitmask) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicTrunkingHashSelect((rtk_uint32 *)pAlgo_bitmask)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_trunk_trafficSeparate_set ++ * Description: ++ * Set the traffic separation setting of a trunk group from the specified device. ++ * Input: ++ * trk_gid - trunk group id ++ * separateType - traffic separation setting ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_UNIT_ID - invalid unit id ++ * RT_ERR_LA_TRUNK_ID - invalid trunk ID ++ * RT_ERR_LA_HASHMASK - invalid hash mask ++ * Note: ++ * SEPARATE_NONE: disable traffic separation ++ * SEPARATE_FLOOD: trunk MSB link up port is dedicated to TX flooding (L2 lookup miss) traffic ++ */ ++rtk_api_ret_t rtk_trunk_trafficSeparate_set(rtk_trunk_group_t trk_gid, rtk_trunk_separateType_t separateType) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 enabled; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (trk_gid != RTK_WHOLE_SYSTEM) ++ return RT_ERR_LA_TRUNK_ID; ++ ++ if(separateType >= SEPARATE_END) ++ return RT_ERR_INPUT; ++ ++ enabled = (separateType == SEPARATE_FLOOD) ? ENABLED : DISABLED; ++ if ((retVal = rtl8367c_setAsicTrunkingFlood(enabled)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_trunk_trafficSeparate_get ++ * Description: ++ * Get the traffic separation setting of a trunk group from the specified device. ++ * Input: ++ * trk_gid - trunk group id ++ * Output: ++ * pSeparateType - pointer separated traffic type ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_UNIT_ID - invalid unit id ++ * RT_ERR_LA_TRUNK_ID - invalid trunk ID ++ * RT_ERR_NULL_POINTER - input parameter may be null pointer ++ * Note: ++ * SEPARATE_NONE: disable traffic separation ++ * SEPARATE_FLOOD: trunk MSB link up port is dedicated to TX flooding (L2 lookup miss) traffic ++ */ ++rtk_api_ret_t rtk_trunk_trafficSeparate_get(rtk_trunk_group_t trk_gid, rtk_trunk_separateType_t *pSeparateType) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 enabled; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if (trk_gid != RTK_WHOLE_SYSTEM) ++ return RT_ERR_LA_TRUNK_ID; ++ ++ if(NULL == pSeparateType) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicTrunkingFlood(&enabled)) != RT_ERR_OK) ++ return retVal; ++ ++ *pSeparateType = (enabled == ENABLED) ? SEPARATE_FLOOD : SEPARATE_NONE; ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_trunk_mode_set ++ * Description: ++ * Set the trunk mode to the specified device. ++ * Input: ++ * mode - trunk mode ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_INPUT - invalid input parameter ++ * Note: ++ * The enum of the trunk mode as following ++ * - TRUNK_MODE_NORMAL ++ * - TRUNK_MODE_DUMB ++ */ ++rtk_api_ret_t rtk_trunk_mode_set(rtk_trunk_mode_t mode) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(mode >= TRUNK_MODE_END) ++ return RT_ERR_INPUT; ++ ++ if ((retVal = rtl8367c_setAsicTrunkingMode((rtk_uint32)mode)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_trunk_mode_get ++ * Description: ++ * Get the trunk mode from the specified device. ++ * Input: ++ * None ++ * Output: ++ * pMode - pointer buffer of trunk mode ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_NULL_POINTER - input parameter may be null pointer ++ * Note: ++ * The enum of the trunk mode as following ++ * - TRUNK_MODE_NORMAL ++ * - TRUNK_MODE_DUMB ++ */ ++rtk_api_ret_t rtk_trunk_mode_get(rtk_trunk_mode_t *pMode) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pMode) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicTrunkingMode((rtk_uint32 *)pMode)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_trunk_trafficPause_set ++ * Description: ++ * Set the traffic pause setting of a trunk group. ++ * Input: ++ * trk_gid - trunk group id ++ * enable - traffic pause state ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_LA_TRUNK_ID - invalid trunk ID ++ * Note: ++ * None. ++ */ ++rtk_api_ret_t rtk_trunk_trafficPause_set(rtk_trunk_group_t trk_gid, rtk_enable_t enable) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Trunk Group Valid */ ++ RTK_CHK_TRUNK_GROUP_VALID(trk_gid); ++ ++ if(enable >= RTK_ENABLE_END) ++ return RT_ERR_INPUT; ++ ++ if ((retVal = rtl8367c_setAsicTrunkingFc((rtk_uint32)trk_gid, (rtk_uint32)enable)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_trunk_trafficPause_get ++ * Description: ++ * Get the traffic pause setting of a trunk group. ++ * Input: ++ * trk_gid - trunk group id ++ * Output: ++ * pEnable - pointer of traffic pause state. ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_LA_TRUNK_ID - invalid trunk ID ++ * RT_ERR_NULL_POINTER - input parameter may be null pointer ++ * Note: ++ * None. ++ */ ++rtk_api_ret_t rtk_trunk_trafficPause_get(rtk_trunk_group_t trk_gid, rtk_enable_t *pEnable) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Trunk Group Valid */ ++ RTK_CHK_TRUNK_GROUP_VALID(trk_gid); ++ ++ if(NULL == pEnable) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicTrunkingFc((rtk_uint32)trk_gid, (rtk_uint32 *)pEnable)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_trunk_hashMappingTable_set ++ * Description: ++ * Set hash value to port array in the trunk group id from the specified device. ++ * Input: ++ * trk_gid - trunk group id ++ * pHash2Port_array - ports associate with the hash value ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_UNIT_ID - invalid unit id ++ * RT_ERR_LA_TRUNK_ID - invalid trunk ID ++ * RT_ERR_NULL_POINTER - input parameter may be null pointer ++ * RT_ERR_LA_TRUNK_NOT_EXIST - the trunk doesn't exist ++ * RT_ERR_LA_NOT_MEMBER_PORT - the port is not a member port of the trunk ++ * RT_ERR_LA_CPUPORT - CPU port can not be aggregated port ++ * Note: ++ * Trunk group 0 & 1 shares the same hash mapping table. ++ * Trunk group 2 uses a independent table. ++ */ ++rtk_api_ret_t rtk_trunk_hashMappingTable_set(rtk_trunk_group_t trk_gid, rtk_trunk_hashVal2Port_t *pHash2Port_array) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 hashValue; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Trunk Group Valid */ ++ RTK_CHK_TRUNK_GROUP_VALID(trk_gid); ++ ++ if(NULL == pHash2Port_array) ++ return RT_ERR_NULL_POINTER; ++ ++ if(trk_gid <= TRUNK_GROUP1) ++ { ++ for(hashValue = 0; hashValue < RTK_MAX_NUM_OF_TRUNK_HASH_VAL; hashValue++) ++ { ++ if ((retVal = rtl8367c_setAsicTrunkingHashTable(hashValue, pHash2Port_array->value[hashValue])) != RT_ERR_OK) ++ return retVal; ++ } ++ } ++ else ++ { ++ for(hashValue = 0; hashValue < RTK_MAX_NUM_OF_TRUNK_HASH_VAL; hashValue++) ++ { ++ if ((retVal = rtl8367c_setAsicTrunkingHashTable1(hashValue, pHash2Port_array->value[hashValue])) != RT_ERR_OK) ++ return retVal; ++ } ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_trunk_hashMappingTable_get ++ * Description: ++ * Get hash value to port array in the trunk group id from the specified device. ++ * Input: ++ * trk_gid - trunk group id ++ * Output: ++ * pHash2Port_array - pointer buffer of ports associate with the hash value ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_UNIT_ID - invalid unit id ++ * RT_ERR_LA_TRUNK_ID - invalid trunk ID ++ * RT_ERR_NULL_POINTER - input parameter may be null pointer ++ * Note: ++ * Trunk group 0 & 1 shares the same hash mapping table. ++ * Trunk group 2 uses a independent table. ++ */ ++rtk_api_ret_t rtk_trunk_hashMappingTable_get(rtk_trunk_group_t trk_gid, rtk_trunk_hashVal2Port_t *pHash2Port_array) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 hashValue; ++ rtk_uint32 hashPort; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Trunk Group Valid */ ++ RTK_CHK_TRUNK_GROUP_VALID(trk_gid); ++ ++ if(NULL == pHash2Port_array) ++ return RT_ERR_NULL_POINTER; ++ ++ if(trk_gid <= TRUNK_GROUP1) ++ { ++ for(hashValue = 0; hashValue < RTK_MAX_NUM_OF_TRUNK_HASH_VAL; hashValue++) ++ { ++ if ((retVal = rtl8367c_getAsicTrunkingHashTable(hashValue, &hashPort)) != RT_ERR_OK) ++ return retVal; ++ ++ pHash2Port_array->value[hashValue] = hashPort; ++ } ++ } ++ else ++ { ++ for(hashValue = 0; hashValue < RTK_MAX_NUM_OF_TRUNK_HASH_VAL; hashValue++) ++ { ++ if ((retVal = rtl8367c_getAsicTrunkingHashTable1(hashValue, &hashPort)) != RT_ERR_OK) ++ return retVal; ++ ++ pHash2Port_array->value[hashValue] = hashPort; ++ } ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_trunk_portQueueEmpty_get ++ * Description: ++ * Get the port mask which all queues are empty. ++ * Input: ++ * None. ++ * Output: ++ * pEmpty_portmask - pointer empty port mask ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_NULL_POINTER - input parameter may be null pointer ++ * Note: ++ * None. ++ */ ++rtk_api_ret_t rtk_trunk_portQueueEmpty_get(rtk_portmask_t *pEmpty_portmask) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 pmask; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pEmpty_portmask) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicQeueuEmptyStatus(&pmask)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtk_switch_portmask_P2L_get(pmask, pEmpty_portmask)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ +diff --git a/drivers/net/phy/rtk/rtl8367c/vlan.c b/drivers/net/phy/rtk/rtl8367c/vlan.c +new file mode 100644 +index 000000000000..b407c3008cd0 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367c/vlan.c +@@ -0,0 +1,2124 @@ ++/* ++ * Copyright (C) 2013 Realtek Semiconductor Corp. ++ * All Rights Reserved. ++ * ++ * Unless you and Realtek execute a separate written software license ++ * agreement governing use of this software, this software is licensed ++ * to you under the terms of the GNU General Public License version 2, ++ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt ++ * ++ * $Revision: 76306 $ ++ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ ++ * ++ * Purpose : RTK switch high-level API for RTL8367/RTL8367C ++ * Feature : Here is a list of all functions and variables in VLAN module. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++typedef enum vlan_mbrCfgType_e ++{ ++ MBRCFG_UNUSED = 0, ++ MBRCFG_USED_BY_VLAN, ++ MBRCFG_END ++}vlan_mbrCfgType_t; ++ ++static rtk_vlan_t vlan_mbrCfgVid[RTL8367C_CVIDXNO]; ++static vlan_mbrCfgType_t vlan_mbrCfgUsage[RTL8367C_CVIDXNO]; ++ ++/* Function Name: ++ * rtk_vlan_init ++ * Description: ++ * Initialize VLAN. ++ * Input: ++ * None ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * Note: ++ * VLAN is disabled by default. User has to call this API to enable VLAN before ++ * using it. And It will set a default VLAN(vid 1) including all ports and set ++ * all ports PVID to the default VLAN. ++ */ ++rtk_api_ret_t rtk_vlan_init(void) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 i; ++ rtl8367c_user_vlan4kentry vlan4K; ++ rtl8367c_vlanconfiguser vlanMC; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Clean Database */ ++ memset(vlan_mbrCfgVid, 0x00, sizeof(rtk_vlan_t) * RTL8367C_CVIDXNO); ++ memset(vlan_mbrCfgUsage, 0x00, sizeof(vlan_mbrCfgType_t) * RTL8367C_CVIDXNO); ++ ++ /* clean 32 VLAN member configuration */ ++ for (i = 0; i <= RTL8367C_CVIDXMAX; i++) ++ { ++ vlanMC.evid = 0; ++ vlanMC.mbr = 0; ++ vlanMC.fid_msti = 0; ++ vlanMC.envlanpol = 0; ++ vlanMC.meteridx = 0; ++ vlanMC.vbpen = 0; ++ vlanMC.vbpri = 0; ++ if ((retVal = rtl8367c_setAsicVlanMemberConfig(i, &vlanMC)) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ /* Set a default VLAN with vid 1 to 4K table for all ports */ ++ memset(&vlan4K, 0, sizeof(rtl8367c_user_vlan4kentry)); ++ vlan4K.vid = 1; ++ vlan4K.mbr = RTK_PHY_PORTMASK_ALL; ++ vlan4K.untag = RTK_PHY_PORTMASK_ALL; ++ vlan4K.fid_msti = 0; ++ if ((retVal = rtl8367c_setAsicVlan4kEntry(&vlan4K)) != RT_ERR_OK) ++ return retVal; ++ ++ /* Also set the default VLAN to 32 member configuration index 0 */ ++ memset(&vlanMC, 0, sizeof(rtl8367c_vlanconfiguser)); ++ vlanMC.evid = 1; ++ vlanMC.mbr = RTK_PHY_PORTMASK_ALL; ++ vlanMC.fid_msti = 0; ++ if ((retVal = rtl8367c_setAsicVlanMemberConfig(0, &vlanMC)) != RT_ERR_OK) ++ return retVal; ++ ++ /* Set all ports PVID to default VLAN and tag-mode to original */ ++ RTK_SCAN_ALL_PHY_PORTMASK(i) ++ { ++ if ((retVal = rtl8367c_setAsicVlanPortBasedVID(i, 0, 0)) != RT_ERR_OK) ++ return retVal; ++ if ((retVal = rtl8367c_setAsicVlanEgressTagMode(i, EG_TAG_MODE_ORI)) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ /* Update Database */ ++ vlan_mbrCfgUsage[0] = MBRCFG_USED_BY_VLAN; ++ vlan_mbrCfgVid[0] = 1; ++ ++ /* Enable Ingress filter */ ++ RTK_SCAN_ALL_PHY_PORTMASK(i) ++ { ++ if ((retVal = rtl8367c_setAsicVlanIngressFilter(i, ENABLED)) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ /* enable VLAN */ ++ if ((retVal = rtl8367c_setAsicVlanFilter(ENABLED)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_vlan_set ++ * Description: ++ * Set a VLAN entry. ++ * Input: ++ * vid - VLAN ID to configure. ++ * pVlanCfg - VLAN Configuration ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_L2_FID - Invalid FID. ++ * RT_ERR_VLAN_PORT_MBR_EXIST - Invalid member port mask. ++ * RT_ERR_VLAN_VID - Invalid VID parameter. ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_vlan_set(rtk_vlan_t vid, rtk_vlan_cfg_t *pVlanCfg) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 phyMbrPmask; ++ rtk_uint32 phyUntagPmask; ++ rtl8367c_user_vlan4kentry vlan4K; ++ rtl8367c_vlanconfiguser vlanMC; ++ rtk_uint32 idx; ++ rtk_uint32 empty_index = 0xffff; ++ rtk_uint32 update_evid = 0; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* vid must be 0~8191 */ ++ if (vid > RTL8367C_EVIDMAX) ++ return RT_ERR_VLAN_VID; ++ ++ /* Null pointer check */ ++ if(NULL == pVlanCfg) ++ return RT_ERR_NULL_POINTER; ++ ++ /* Check port mask valid */ ++ RTK_CHK_PORTMASK_VALID(&(pVlanCfg->mbr)); ++ ++ if (vid <= RTL8367C_VIDMAX) ++ { ++ /* Check untag port mask valid */ ++ RTK_CHK_PORTMASK_VALID(&(pVlanCfg->untag)); ++ } ++ ++ /* IVL_EN */ ++ if(pVlanCfg->ivl_en >= RTK_ENABLE_END) ++ return RT_ERR_ENABLE; ++ ++ /* fid must be 0~15 */ ++ if(pVlanCfg->fid_msti > RTL8367C_FIDMAX) ++ return RT_ERR_L2_FID; ++ ++ /* Policing */ ++ if(pVlanCfg->envlanpol >= RTK_ENABLE_END) ++ return RT_ERR_ENABLE; ++ ++ /* Meter ID */ ++ if(pVlanCfg->meteridx > RTK_MAX_METER_ID) ++ return RT_ERR_INPUT; ++ ++ /* VLAN based priority */ ++ if(pVlanCfg->vbpen >= RTK_ENABLE_END) ++ return RT_ERR_ENABLE; ++ ++ /* Priority */ ++ if(pVlanCfg->vbpri > RTL8367C_PRIMAX) ++ return RT_ERR_INPUT; ++ ++ /* Get physical port mask */ ++ if(rtk_switch_portmask_L2P_get(&(pVlanCfg->mbr), &phyMbrPmask) != RT_ERR_OK) ++ return RT_ERR_FAILED; ++ ++ if(rtk_switch_portmask_L2P_get(&(pVlanCfg->untag), &phyUntagPmask) != RT_ERR_OK) ++ return RT_ERR_FAILED; ++ ++ if (vid <= RTL8367C_VIDMAX) ++ { ++ /* update 4K table */ ++ memset(&vlan4K, 0, sizeof(rtl8367c_user_vlan4kentry)); ++ vlan4K.vid = vid; ++ ++ vlan4K.mbr = (phyMbrPmask & 0xFFFF); ++ vlan4K.untag = (phyUntagPmask & 0xFFFF); ++ ++ vlan4K.ivl_svl = pVlanCfg->ivl_en; ++ vlan4K.fid_msti = pVlanCfg->fid_msti; ++ vlan4K.envlanpol = pVlanCfg->envlanpol; ++ vlan4K.meteridx = pVlanCfg->meteridx; ++ vlan4K.vbpen = pVlanCfg->vbpen; ++ vlan4K.vbpri = pVlanCfg->vbpri; ++ ++ if ((retVal = rtl8367c_setAsicVlan4kEntry(&vlan4K)) != RT_ERR_OK) ++ return retVal; ++ ++ /* Update Member configuration if exist */ ++ for (idx = 0; idx <= RTL8367C_CVIDXMAX; idx++) ++ { ++ if(vlan_mbrCfgUsage[idx] == MBRCFG_USED_BY_VLAN) ++ { ++ if(vlan_mbrCfgVid[idx] == vid) ++ { ++ /* Found! Update */ ++ if(phyMbrPmask == 0x00) ++ { ++ /* Member port = 0x00, delete this VLAN from Member Configuration */ ++ memset(&vlanMC, 0x00, sizeof(rtl8367c_vlanconfiguser)); ++ if ((retVal = rtl8367c_setAsicVlanMemberConfig(idx, &vlanMC)) != RT_ERR_OK) ++ return retVal; ++ ++ /* Clear Database */ ++ vlan_mbrCfgUsage[idx] = MBRCFG_UNUSED; ++ vlan_mbrCfgVid[idx] = 0; ++ } ++ else ++ { ++ /* Normal VLAN config, update to member configuration */ ++ vlanMC.evid = vid; ++ vlanMC.mbr = vlan4K.mbr; ++ vlanMC.fid_msti = vlan4K.fid_msti; ++ vlanMC.meteridx = vlan4K.meteridx; ++ vlanMC.envlanpol= vlan4K.envlanpol; ++ vlanMC.vbpen = vlan4K.vbpen; ++ vlanMC.vbpri = vlan4K.vbpri; ++ if ((retVal = rtl8367c_setAsicVlanMemberConfig(idx, &vlanMC)) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ break; ++ } ++ } ++ } ++ } ++ else ++ { ++ /* vid > 4095 */ ++ for (idx = 0; idx <= RTL8367C_CVIDXMAX; idx++) ++ { ++ if(vlan_mbrCfgUsage[idx] == MBRCFG_USED_BY_VLAN) ++ { ++ if(vlan_mbrCfgVid[idx] == vid) ++ { ++ /* Found! Update */ ++ if(phyMbrPmask == 0x00) ++ { ++ /* Member port = 0x00, delete this VLAN from Member Configuration */ ++ memset(&vlanMC, 0x00, sizeof(rtl8367c_vlanconfiguser)); ++ if ((retVal = rtl8367c_setAsicVlanMemberConfig(idx, &vlanMC)) != RT_ERR_OK) ++ return retVal; ++ ++ /* Clear Database */ ++ vlan_mbrCfgUsage[idx] = MBRCFG_UNUSED; ++ vlan_mbrCfgVid[idx] = 0; ++ } ++ else ++ { ++ /* Normal VLAN config, update to member configuration */ ++ vlanMC.evid = vid; ++ vlanMC.mbr = phyMbrPmask; ++ vlanMC.fid_msti = pVlanCfg->fid_msti; ++ vlanMC.meteridx = pVlanCfg->meteridx; ++ vlanMC.envlanpol= pVlanCfg->envlanpol; ++ vlanMC.vbpen = pVlanCfg->vbpen; ++ vlanMC.vbpri = pVlanCfg->vbpri; ++ if ((retVal = rtl8367c_setAsicVlanMemberConfig(idx, &vlanMC)) != RT_ERR_OK) ++ return retVal; ++ ++ break; ++ } ++ ++ update_evid = 1; ++ } ++ } ++ ++ if(vlan_mbrCfgUsage[idx] == MBRCFG_UNUSED) ++ { ++ if(0xffff == empty_index) ++ empty_index = idx; ++ } ++ } ++ ++ /* doesn't find out same EVID entry and there is empty index in member configuration */ ++ if( (phyMbrPmask != 0x00) && (update_evid == 0) && (empty_index != 0xFFFF) ) ++ { ++ vlanMC.evid = vid; ++ vlanMC.mbr = phyMbrPmask; ++ vlanMC.fid_msti = pVlanCfg->fid_msti; ++ vlanMC.meteridx = pVlanCfg->meteridx; ++ vlanMC.envlanpol= pVlanCfg->envlanpol; ++ vlanMC.vbpen = pVlanCfg->vbpen; ++ vlanMC.vbpri = pVlanCfg->vbpri; ++ if ((retVal = rtl8367c_setAsicVlanMemberConfig(empty_index, &vlanMC)) != RT_ERR_OK) ++ return retVal; ++ ++ vlan_mbrCfgUsage[empty_index] = MBRCFG_USED_BY_VLAN; ++ vlan_mbrCfgVid[empty_index] = vid; ++ ++ } ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_vlan_get ++ * Description: ++ * Get a VLAN entry. ++ * Input: ++ * vid - VLAN ID to configure. ++ * Output: ++ * pVlanCfg - VLAN Configuration ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_VLAN_VID - Invalid VID parameter. ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_vlan_get(rtk_vlan_t vid, rtk_vlan_cfg_t *pVlanCfg) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 phyMbrPmask; ++ rtk_uint32 phyUntagPmask; ++ rtl8367c_user_vlan4kentry vlan4K; ++ rtl8367c_vlanconfiguser vlanMC; ++ rtk_uint32 idx; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* vid must be 0~8191 */ ++ if (vid > RTL8367C_EVIDMAX) ++ return RT_ERR_VLAN_VID; ++ ++ /* Null pointer check */ ++ if(NULL == pVlanCfg) ++ return RT_ERR_NULL_POINTER; ++ ++ if (vid <= RTL8367C_VIDMAX) ++ { ++ vlan4K.vid = vid; ++ ++ if ((retVal = rtl8367c_getAsicVlan4kEntry(&vlan4K)) != RT_ERR_OK) ++ return retVal; ++ ++ phyMbrPmask = vlan4K.mbr; ++ phyUntagPmask = vlan4K.untag; ++ if(rtk_switch_portmask_P2L_get(phyMbrPmask, &(pVlanCfg->mbr)) != RT_ERR_OK) ++ return RT_ERR_FAILED; ++ ++ if(rtk_switch_portmask_P2L_get(phyUntagPmask, &(pVlanCfg->untag)) != RT_ERR_OK) ++ return RT_ERR_FAILED; ++ ++ pVlanCfg->ivl_en = vlan4K.ivl_svl; ++ pVlanCfg->fid_msti = vlan4K.fid_msti; ++ pVlanCfg->envlanpol = vlan4K.envlanpol; ++ pVlanCfg->meteridx = vlan4K.meteridx; ++ pVlanCfg->vbpen = vlan4K.vbpen; ++ pVlanCfg->vbpri = vlan4K.vbpri; ++ } ++ else ++ { ++ for (idx = 0; idx <= RTL8367C_CVIDXMAX; idx++) ++ { ++ if(vlan_mbrCfgUsage[idx] == MBRCFG_USED_BY_VLAN) ++ { ++ if(vlan_mbrCfgVid[idx] == vid) ++ { ++ if ((retVal = rtl8367c_getAsicVlanMemberConfig(idx, &vlanMC)) != RT_ERR_OK) ++ return retVal; ++ ++ phyMbrPmask = vlanMC.mbr; ++ if(rtk_switch_portmask_P2L_get(phyMbrPmask, &(pVlanCfg->mbr)) != RT_ERR_OK) ++ return RT_ERR_FAILED; ++ ++ pVlanCfg->untag.bits[0] = 0; ++ pVlanCfg->ivl_en = 0; ++ pVlanCfg->fid_msti = vlanMC.fid_msti; ++ pVlanCfg->envlanpol = vlanMC.envlanpol; ++ pVlanCfg->meteridx = vlanMC.meteridx; ++ pVlanCfg->vbpen = vlanMC.vbpen; ++ pVlanCfg->vbpri = vlanMC.vbpri; ++ } ++ } ++ } ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_vlan_egrFilterEnable_set ++ * Description: ++ * Set VLAN egress filter. ++ * Input: ++ * egrFilter - Egress filtering ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_ENABLE - Invalid input parameters. ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_vlan_egrFilterEnable_set(rtk_enable_t egrFilter) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(egrFilter >= RTK_ENABLE_END) ++ return RT_ERR_ENABLE; ++ ++ /* enable VLAN */ ++ if ((retVal = rtl8367c_setAsicVlanFilter((rtk_uint32)egrFilter)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_vlan_egrFilterEnable_get ++ * Description: ++ * Get VLAN egress filter. ++ * Input: ++ * pEgrFilter - Egress filtering ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_NULL_POINTER - NULL Pointer. ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_vlan_egrFilterEnable_get(rtk_enable_t *pEgrFilter) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 state; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pEgrFilter) ++ return RT_ERR_NULL_POINTER; ++ ++ /* enable VLAN */ ++ if ((retVal = rtl8367c_getAsicVlanFilter(&state)) != RT_ERR_OK) ++ return retVal; ++ ++ *pEgrFilter = (rtk_enable_t)state; ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_vlan_mbrCfg_set ++ * Description: ++ * Set a VLAN Member Configuration entry by index. ++ * Input: ++ * idx - Index of VLAN Member Configuration. ++ * pMbrcfg - VLAN member Configuration. ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_VLAN_VID - Invalid VID parameter. ++ * Note: ++ * Set a VLAN Member Configuration entry by index. ++ */ ++rtk_api_ret_t rtk_vlan_mbrCfg_set(rtk_uint32 idx, rtk_vlan_mbrcfg_t *pMbrcfg) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 phyMbrPmask; ++ rtl8367c_vlanconfiguser mbrCfg; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Error check */ ++ if(pMbrcfg == NULL) ++ return RT_ERR_NULL_POINTER; ++ ++ if(idx > RTL8367C_CVIDXMAX) ++ return RT_ERR_INPUT; ++ ++ if(pMbrcfg->evid > RTL8367C_EVIDMAX) ++ return RT_ERR_INPUT; ++ ++ if(pMbrcfg->fid_msti > RTL8367C_FIDMAX) ++ return RT_ERR_L2_FID; ++ ++ if(pMbrcfg->envlanpol >= RTK_ENABLE_END) ++ return RT_ERR_ENABLE; ++ ++ if(pMbrcfg->meteridx > RTK_MAX_METER_ID) ++ return RT_ERR_FILTER_METER_ID; ++ ++ if(pMbrcfg->vbpen >= RTK_ENABLE_END) ++ return RT_ERR_ENABLE; ++ ++ if(pMbrcfg->vbpri > RTL8367C_PRIMAX) ++ return RT_ERR_QOS_INT_PRIORITY; ++ ++ /* Check port mask valid */ ++ RTK_CHK_PORTMASK_VALID(&(pMbrcfg->mbr)); ++ ++ mbrCfg.evid = pMbrcfg->evid; ++ mbrCfg.fid_msti = pMbrcfg->fid_msti; ++ mbrCfg.envlanpol = pMbrcfg->envlanpol; ++ mbrCfg.meteridx = pMbrcfg->meteridx; ++ mbrCfg.vbpen = pMbrcfg->vbpen; ++ mbrCfg.vbpri = pMbrcfg->vbpri; ++ ++ if(rtk_switch_portmask_L2P_get(&(pMbrcfg->mbr), &phyMbrPmask) != RT_ERR_OK) ++ return RT_ERR_FAILED; ++ ++ mbrCfg.mbr = phyMbrPmask; ++ ++ if ((retVal = rtl8367c_setAsicVlanMemberConfig(idx, &mbrCfg)) != RT_ERR_OK) ++ return retVal; ++ ++ /* Update Database */ ++ if( (mbrCfg.evid == 0) && (mbrCfg.mbr == 0) ) ++ { ++ vlan_mbrCfgUsage[idx] = MBRCFG_UNUSED; ++ vlan_mbrCfgVid[idx] = 0; ++ } ++ else ++ { ++ vlan_mbrCfgUsage[idx] = MBRCFG_USED_BY_VLAN; ++ vlan_mbrCfgVid[idx] = mbrCfg.evid; ++ } ++ ++ return RT_ERR_OK; ++ ++} ++ ++/* Function Name: ++ * rtk_vlan_mbrCfg_get ++ * Description: ++ * Get a VLAN Member Configuration entry by index. ++ * Input: ++ * idx - Index of VLAN Member Configuration. ++ * Output: ++ * pMbrcfg - VLAN member Configuration. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_VLAN_VID - Invalid VID parameter. ++ * Note: ++ * Get a VLAN Member Configuration entry by index. ++ */ ++rtk_api_ret_t rtk_vlan_mbrCfg_get(rtk_uint32 idx, rtk_vlan_mbrcfg_t *pMbrcfg) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 phyMbrPmask; ++ rtl8367c_vlanconfiguser mbrCfg; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Error check */ ++ if(pMbrcfg == NULL) ++ return RT_ERR_NULL_POINTER; ++ ++ if(idx > RTL8367C_CVIDXMAX) ++ return RT_ERR_INPUT; ++ ++ memset(&mbrCfg, 0x00, sizeof(rtl8367c_vlanconfiguser)); ++ if ((retVal = rtl8367c_getAsicVlanMemberConfig(idx, &mbrCfg)) != RT_ERR_OK) ++ return retVal; ++ ++ pMbrcfg->evid = mbrCfg.evid; ++ pMbrcfg->fid_msti = mbrCfg.fid_msti; ++ pMbrcfg->envlanpol = mbrCfg.envlanpol; ++ pMbrcfg->meteridx = mbrCfg.meteridx; ++ pMbrcfg->vbpen = mbrCfg.vbpen; ++ pMbrcfg->vbpri = mbrCfg.vbpri; ++ ++ phyMbrPmask = mbrCfg.mbr; ++ if(rtk_switch_portmask_P2L_get(phyMbrPmask, &(pMbrcfg->mbr)) != RT_ERR_OK) ++ return RT_ERR_FAILED; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_vlan_portPvid_set ++ * Description: ++ * Set port to specified VLAN ID(PVID). ++ * Input: ++ * port - Port id. ++ * pvid - Specified VLAN ID. ++ * priority - 802.1p priority for the PVID. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_VLAN_PRIORITY - Invalid priority. ++ * RT_ERR_VLAN_ENTRY_NOT_FOUND - VLAN entry not found. ++ * RT_ERR_VLAN_VID - Invalid VID parameter. ++ * Note: ++ * The API is used for Port-based VLAN. The untagged frame received from the ++ * port will be classified to the specified VLAN and assigned to the specified priority. ++ */ ++rtk_api_ret_t rtk_vlan_portPvid_set(rtk_port_t port, rtk_vlan_t pvid, rtk_pri_t priority) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 index; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ /* vid must be 0~8191 */ ++ if (pvid > RTL8367C_EVIDMAX) ++ return RT_ERR_VLAN_VID; ++ ++ /* priority must be 0~7 */ ++ if (priority > RTL8367C_PRIMAX) ++ return RT_ERR_VLAN_PRIORITY; ++ ++ if((retVal = rtk_vlan_checkAndCreateMbr(pvid, &index)) != RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicVlanPortBasedVID(rtk_switch_port_L2P_get(port), index, priority)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_vlan_portPvid_get ++ * Description: ++ * Get VLAN ID(PVID) on specified port. ++ * Input: ++ * port - Port id. ++ * Output: ++ * pPvid - Specified VLAN ID. ++ * pPriority - 802.1p priority for the PVID. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * The API can get the PVID and 802.1p priority for the PVID of Port-based VLAN. ++ */ ++rtk_api_ret_t rtk_vlan_portPvid_get(rtk_port_t port, rtk_vlan_t *pPvid, rtk_pri_t *pPriority) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 index, pri; ++ rtl8367c_vlanconfiguser mbrCfg; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if(NULL == pPvid) ++ return RT_ERR_NULL_POINTER; ++ ++ if(NULL == pPriority) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicVlanPortBasedVID(rtk_switch_port_L2P_get(port), &index, &pri)) != RT_ERR_OK) ++ return retVal; ++ ++ memset(&mbrCfg, 0x00, sizeof(rtl8367c_vlanconfiguser)); ++ if ((retVal = rtl8367c_getAsicVlanMemberConfig(index, &mbrCfg)) != RT_ERR_OK) ++ return retVal; ++ ++ *pPvid = mbrCfg.evid; ++ *pPriority = pri; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_vlan_portIgrFilterEnable_set ++ * Description: ++ * Set VLAN ingress for each port. ++ * Input: ++ * port - Port id. ++ * igr_filter - VLAN ingress function enable status. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number ++ * RT_ERR_ENABLE - Invalid enable input ++ * Note: ++ * The status of vlan ingress filter is as following: ++ * - DISABLED ++ * - ENABLED ++ * While VLAN function is enabled, ASIC will decide VLAN ID for each received frame and get belonged member ++ * ports from VLAN table. If received port is not belonged to VLAN member ports, ASIC will drop received frame if VLAN ingress function is enabled. ++ */ ++rtk_api_ret_t rtk_vlan_portIgrFilterEnable_set(rtk_port_t port, rtk_enable_t igr_filter) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if (igr_filter >= RTK_ENABLE_END) ++ return RT_ERR_ENABLE; ++ ++ if ((retVal = rtl8367c_setAsicVlanIngressFilter(rtk_switch_port_L2P_get(port), igr_filter)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_vlan_portIgrFilterEnable_get ++ * Description: ++ * Get VLAN Ingress Filter ++ * Input: ++ * port - Port id. ++ * Output: ++ * pIgr_filter - VLAN ingress function enable status. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * The API can Get the VLAN ingress filter status. ++ * The status of vlan ingress filter is as following: ++ * - DISABLED ++ * - ENABLED ++ */ ++rtk_api_ret_t rtk_vlan_portIgrFilterEnable_get(rtk_port_t port, rtk_enable_t *pIgr_filter) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if(NULL == pIgr_filter) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicVlanIngressFilter(rtk_switch_port_L2P_get(port), pIgr_filter)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_vlan_portAcceptFrameType_set ++ * Description: ++ * Set VLAN accept_frame_type ++ * Input: ++ * port - Port id. ++ * accept_frame_type - accept frame type ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_VLAN_ACCEPT_FRAME_TYPE - Invalid frame type. ++ * Note: ++ * The API is used for checking 802.1Q tagged frames. ++ * The accept frame type as following: ++ * - ACCEPT_FRAME_TYPE_ALL ++ * - ACCEPT_FRAME_TYPE_TAG_ONLY ++ * - ACCEPT_FRAME_TYPE_UNTAG_ONLY ++ */ ++rtk_api_ret_t rtk_vlan_portAcceptFrameType_set(rtk_port_t port, rtk_vlan_acceptFrameType_t accept_frame_type) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if (accept_frame_type >= ACCEPT_FRAME_TYPE_END) ++ return RT_ERR_VLAN_ACCEPT_FRAME_TYPE; ++ ++ if ((retVal = rtl8367c_setAsicVlanAccpetFrameType(rtk_switch_port_L2P_get(port), (rtl8367c_accframetype)accept_frame_type)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_vlan_portAcceptFrameType_get ++ * Description: ++ * Get VLAN accept_frame_type ++ * Input: ++ * port - Port id. ++ * Output: ++ * pAccept_frame_type - accept frame type ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * The API can Get the VLAN ingress filter. ++ * The accept frame type as following: ++ * - ACCEPT_FRAME_TYPE_ALL ++ * - ACCEPT_FRAME_TYPE_TAG_ONLY ++ * - ACCEPT_FRAME_TYPE_UNTAG_ONLY ++ */ ++rtk_api_ret_t rtk_vlan_portAcceptFrameType_get(rtk_port_t port, rtk_vlan_acceptFrameType_t *pAccept_frame_type) ++{ ++ rtk_api_ret_t retVal; ++ rtl8367c_accframetype acc_frm_type; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if(NULL == pAccept_frame_type) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicVlanAccpetFrameType(rtk_switch_port_L2P_get(port), &acc_frm_type)) != RT_ERR_OK) ++ return retVal; ++ ++ *pAccept_frame_type = (rtk_vlan_acceptFrameType_t)acc_frm_type; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_vlan_protoAndPortBasedVlan_add ++ * Description: ++ * Add the protocol-and-port-based vlan to the specified port of device. ++ * Input: ++ * port - Port id. ++ * pInfo - Protocol and port based VLAN configuration information. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_VLAN_VID - Invalid VID parameter. ++ * RT_ERR_VLAN_PRIORITY - Invalid priority. ++ * RT_ERR_TBL_FULL - Table is full. ++ * RT_ERR_OUT_OF_RANGE - input out of range. ++ * Note: ++ * The incoming packet which match the protocol-and-port-based vlan will use the configure vid for ingress pipeline ++ * The frame type is shown in the following: ++ * - FRAME_TYPE_ETHERNET ++ * - FRAME_TYPE_RFC1042 ++ * - FRAME_TYPE_LLCOTHER ++ */ ++rtk_api_ret_t rtk_vlan_protoAndPortBasedVlan_add(rtk_port_t port, rtk_vlan_protoAndPortInfo_t *pInfo) ++{ ++ rtk_api_ret_t retVal, i; ++ rtk_uint32 exist, empty, used, index; ++ rtl8367c_protocolgdatacfg ppb_data_cfg; ++ rtl8367c_protocolvlancfg ppb_vlan_cfg; ++ rtl8367c_provlan_frametype tmp; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if(NULL == pInfo) ++ return RT_ERR_NULL_POINTER; ++ ++ if (pInfo->proto_type > RTK_MAX_NUM_OF_PROTO_TYPE) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ if (pInfo->frame_type >= FRAME_TYPE_END) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ if (pInfo->cvid > RTL8367C_VIDMAX) ++ return RT_ERR_VLAN_VID; ++ ++ if (pInfo->cpri > RTL8367C_PRIMAX) ++ return RT_ERR_VLAN_PRIORITY; ++ ++ exist = 0xFF; ++ empty = 0xFF; ++ for (i = RTL8367C_PROTOVLAN_GIDX_MAX; i >= 0; i--) ++ { ++ if ((retVal = rtl8367c_getAsicVlanProtocolBasedGroupData(i, &ppb_data_cfg)) != RT_ERR_OK) ++ return retVal; ++ tmp = (rtl8367c_provlan_frametype)pInfo->frame_type; ++ if (ppb_data_cfg.etherType == pInfo->proto_type && ppb_data_cfg.frameType == tmp) ++ { ++ /*Already exist*/ ++ exist = i; ++ break; ++ } ++ else if (ppb_data_cfg.etherType == 0 && ppb_data_cfg.frameType == 0) ++ { ++ /*find empty index*/ ++ empty = i; ++ } ++ } ++ ++ used = 0xFF; ++ /*No empty and exist index*/ ++ if (0xFF == exist && 0xFF == empty) ++ return RT_ERR_TBL_FULL; ++ else if (existframe_type; ++ ppb_data_cfg.etherType = pInfo->proto_type; ++ if ((retVal = rtl8367c_setAsicVlanProtocolBasedGroupData(empty, &ppb_data_cfg)) != RT_ERR_OK) ++ return retVal; ++ used = empty; ++ } ++ else ++ return RT_ERR_FAILED; ++ ++ if((retVal = rtk_vlan_checkAndCreateMbr(pInfo->cvid, &index)) != RT_ERR_OK) ++ return retVal; ++ ++ ppb_vlan_cfg.vlan_idx = index; ++ ppb_vlan_cfg.valid = TRUE; ++ ppb_vlan_cfg.priority = pInfo->cpri; ++ if ((retVal = rtl8367c_setAsicVlanPortAndProtocolBased(rtk_switch_port_L2P_get(port), used, &ppb_vlan_cfg)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_vlan_protoAndPortBasedVlan_get ++ * Description: ++ * Get the protocol-and-port-based vlan to the specified port of device. ++ * Input: ++ * port - Port id. ++ * proto_type - protocol-and-port-based vlan protocol type. ++ * frame_type - protocol-and-port-based vlan frame type. ++ * Output: ++ * pInfo - Protocol and port based VLAN configuration information. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_OUT_OF_RANGE - input out of range. ++ * RT_ERR_TBL_FULL - Table is full. ++ * Note: ++ * The incoming packet which match the protocol-and-port-based vlan will use the configure vid for ingress pipeline ++ * The frame type is shown in the following: ++ * - FRAME_TYPE_ETHERNET ++ * - FRAME_TYPE_RFC1042 ++ * - FRAME_TYPE_LLCOTHER ++ */ ++rtk_api_ret_t rtk_vlan_protoAndPortBasedVlan_get(rtk_port_t port, rtk_vlan_proto_type_t proto_type, rtk_vlan_protoVlan_frameType_t frame_type, rtk_vlan_protoAndPortInfo_t *pInfo) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 i; ++ rtk_uint32 ppb_idx; ++ rtl8367c_protocolgdatacfg ppb_data_cfg; ++ rtl8367c_protocolvlancfg ppb_vlan_cfg; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if (proto_type > RTK_MAX_NUM_OF_PROTO_TYPE) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ if (frame_type >= FRAME_TYPE_END) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ ppb_idx = 0; ++ ++ for (i = 0; i<= RTL8367C_PROTOVLAN_GIDX_MAX; i++) ++ { ++ if ((retVal = rtl8367c_getAsicVlanProtocolBasedGroupData(i, &ppb_data_cfg)) != RT_ERR_OK) ++ return retVal; ++ ++ if ( (ppb_data_cfg.frameType == (rtl8367c_provlan_frametype)frame_type) && (ppb_data_cfg.etherType == proto_type) ) ++ { ++ ppb_idx = i; ++ break; ++ } ++ else if (RTL8367C_PROTOVLAN_GIDX_MAX == i) ++ return RT_ERR_TBL_FULL; ++ } ++ ++ if ((retVal = rtl8367c_getAsicVlanPortAndProtocolBased(rtk_switch_port_L2P_get(port), ppb_idx, &ppb_vlan_cfg)) != RT_ERR_OK) ++ return retVal; ++ ++ if (FALSE == ppb_vlan_cfg.valid) ++ return RT_ERR_FAILED; ++ ++ pInfo->frame_type = frame_type; ++ pInfo->proto_type = proto_type; ++ pInfo->cvid = vlan_mbrCfgVid[ppb_vlan_cfg.vlan_idx]; ++ pInfo->cpri = ppb_vlan_cfg.priority; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_vlan_protoAndPortBasedVlan_del ++ * Description: ++ * Delete the protocol-and-port-based vlan from the specified port of device. ++ * Input: ++ * port - Port id. ++ * proto_type - protocol-and-port-based vlan protocol type. ++ * frame_type - protocol-and-port-based vlan frame type. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_OUT_OF_RANGE - input out of range. ++ * RT_ERR_TBL_FULL - Table is full. ++ * Note: ++ * The incoming packet which match the protocol-and-port-based vlan will use the configure vid for ingress pipeline ++ * The frame type is shown in the following: ++ * - FRAME_TYPE_ETHERNET ++ * - FRAME_TYPE_RFC1042 ++ * - FRAME_TYPE_LLCOTHER ++ */ ++rtk_api_ret_t rtk_vlan_protoAndPortBasedVlan_del(rtk_port_t port, rtk_vlan_proto_type_t proto_type, rtk_vlan_protoVlan_frameType_t frame_type) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 i, bUsed; ++ rtk_uint32 ppb_idx; ++ rtl8367c_protocolgdatacfg ppb_data_cfg; ++ rtl8367c_protocolvlancfg ppb_vlan_cfg; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if (proto_type > RTK_MAX_NUM_OF_PROTO_TYPE) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ if (frame_type >= FRAME_TYPE_END) ++ return RT_ERR_OUT_OF_RANGE; ++ ++ ppb_idx = 0; ++ ++ for (i = 0; i<= RTL8367C_PROTOVLAN_GIDX_MAX; i++) ++ { ++ if ((retVal = rtl8367c_getAsicVlanProtocolBasedGroupData(i, &ppb_data_cfg)) != RT_ERR_OK) ++ return retVal; ++ ++ if ( (ppb_data_cfg.frameType == (rtl8367c_provlan_frametype)frame_type) && (ppb_data_cfg.etherType == proto_type) ) ++ { ++ ppb_idx = i; ++ ppb_vlan_cfg.valid = FALSE; ++ ppb_vlan_cfg.vlan_idx = 0; ++ ppb_vlan_cfg.priority = 0; ++ if ((retVal = rtl8367c_setAsicVlanPortAndProtocolBased(rtk_switch_port_L2P_get(port), ppb_idx, &ppb_vlan_cfg)) != RT_ERR_OK) ++ return retVal; ++ } ++ } ++ ++ bUsed = FALSE; ++ RTK_SCAN_ALL_PHY_PORTMASK(i) ++ { ++ if ((retVal = rtl8367c_getAsicVlanPortAndProtocolBased(i, ppb_idx, &ppb_vlan_cfg)) != RT_ERR_OK) ++ return retVal; ++ ++ if (TRUE == ppb_vlan_cfg.valid) ++ { ++ bUsed = TRUE; ++ break; ++ } ++ } ++ ++ if (FALSE == bUsed) /*No Port use this PPB Index, Delete it*/ ++ { ++ ppb_data_cfg.etherType=0; ++ ppb_data_cfg.frameType=0; ++ if ((retVal = rtl8367c_setAsicVlanProtocolBasedGroupData(ppb_idx, &ppb_data_cfg)) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_vlan_protoAndPortBasedVlan_delAll ++ * Description: ++ * Delete all protocol-and-port-based vlans from the specified port of device. ++ * Input: ++ * port - Port id. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_OUT_OF_RANGE - input out of range. ++ * Note: ++ * The incoming packet which match the protocol-and-port-based vlan will use the configure vid for ingress pipeline ++ * Delete all flow table protocol-and-port-based vlan entries. ++ */ ++rtk_api_ret_t rtk_vlan_protoAndPortBasedVlan_delAll(rtk_port_t port) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 i, j, bUsed[4]; ++ rtl8367c_protocolgdatacfg ppb_data_cfg; ++ rtl8367c_protocolvlancfg ppb_vlan_cfg; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ for (i = 0; i<= RTL8367C_PROTOVLAN_GIDX_MAX; i++) ++ { ++ ppb_vlan_cfg.valid = FALSE; ++ ppb_vlan_cfg.vlan_idx = 0; ++ ppb_vlan_cfg.priority = 0; ++ if ((retVal = rtl8367c_setAsicVlanPortAndProtocolBased(rtk_switch_port_L2P_get(port), i, &ppb_vlan_cfg)) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ bUsed[0] = FALSE; ++ bUsed[1] = FALSE; ++ bUsed[2] = FALSE; ++ bUsed[3] = FALSE; ++ RTK_SCAN_ALL_PHY_PORTMASK(i) ++ { ++ for (j = 0; j <= RTL8367C_PROTOVLAN_GIDX_MAX; j++) ++ { ++ if ((retVal = rtl8367c_getAsicVlanPortAndProtocolBased(i,j, &ppb_vlan_cfg)) != RT_ERR_OK) ++ return retVal; ++ ++ if (TRUE == ppb_vlan_cfg.valid) ++ { ++ bUsed[j] = TRUE; ++ } ++ } ++ } ++ ++ for (i = 0; i<= RTL8367C_PROTOVLAN_GIDX_MAX; i++) ++ { ++ if (FALSE == bUsed[i]) /*No Port use this PPB Index, Delete it*/ ++ { ++ ppb_data_cfg.etherType=0; ++ ppb_data_cfg.frameType=0; ++ if ((retVal = rtl8367c_setAsicVlanProtocolBasedGroupData(i, &ppb_data_cfg)) != RT_ERR_OK) ++ return retVal; ++ } ++ } ++ ++ ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_vlan_tagMode_set ++ * Description: ++ * Set CVLAN egress tag mode ++ * Input: ++ * port - Port id. ++ * tag_mode - The egress tag mode. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_INPUT - Invalid input parameter. ++ * RT_ERR_ENABLE - Invalid enable input. ++ * Note: ++ * The API can set Egress tag mode. There are 4 mode for egress tag: ++ * - VLAN_TAG_MODE_ORIGINAL, ++ * - VLAN_TAG_MODE_KEEP_FORMAT, ++ * - VLAN_TAG_MODE_PRI. ++ * - VLAN_TAG_MODE_REAL_KEEP_FORMAT, ++ */ ++rtk_api_ret_t rtk_vlan_tagMode_set(rtk_port_t port, rtk_vlan_tagMode_t tag_mode) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if (tag_mode >= VLAN_TAG_MODE_END) ++ return RT_ERR_PORT_ID; ++ ++ if ((retVal = rtl8367c_setAsicVlanEgressTagMode(rtk_switch_port_L2P_get(port), (rtl8367c_egtagmode)tag_mode)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_vlan_tagMode_get ++ * Description: ++ * Get CVLAN egress tag mode ++ * Input: ++ * port - Port id. ++ * Output: ++ * pTag_mode - The egress tag mode. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * The API can get Egress tag mode. There are 4 mode for egress tag: ++ * - VLAN_TAG_MODE_ORIGINAL, ++ * - VLAN_TAG_MODE_KEEP_FORMAT, ++ * - VLAN_TAG_MODE_PRI. ++ * - VLAN_TAG_MODE_REAL_KEEP_FORMAT, ++ */ ++rtk_api_ret_t rtk_vlan_tagMode_get(rtk_port_t port, rtk_vlan_tagMode_t *pTag_mode) ++{ ++ rtk_api_ret_t retVal; ++ rtl8367c_egtagmode mode; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if(NULL == pTag_mode) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicVlanEgressTagMode(rtk_switch_port_L2P_get(port), &mode)) != RT_ERR_OK) ++ return retVal; ++ ++ *pTag_mode = (rtk_vlan_tagMode_t)mode; ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_vlan_transparent_set ++ * Description: ++ * Set VLAN transparent mode ++ * Input: ++ * egr_port - Egress Port id. ++ * pIgr_pmask - Ingress Port Mask. ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * None. ++ */ ++rtk_api_ret_t rtk_vlan_transparent_set(rtk_port_t egr_port, rtk_portmask_t *pIgr_pmask) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 pmask; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(egr_port); ++ ++ if(NULL == pIgr_pmask) ++ return RT_ERR_NULL_POINTER; ++ ++ RTK_CHK_PORTMASK_VALID(pIgr_pmask); ++ ++ if(rtk_switch_portmask_L2P_get(pIgr_pmask, &pmask) != RT_ERR_OK) ++ return RT_ERR_FAILED; ++ ++ if ((retVal = rtl8367c_setAsicVlanTransparent(rtk_switch_port_L2P_get(egr_port), pmask)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_vlan_transparent_get ++ * Description: ++ * Get VLAN transparent mode ++ * Input: ++ * egr_port - Egress Port id. ++ * Output: ++ * pIgr_pmask - Ingress Port Mask ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * None. ++ */ ++rtk_api_ret_t rtk_vlan_transparent_get(rtk_port_t egr_port, rtk_portmask_t *pIgr_pmask) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 pmask; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(egr_port); ++ ++ if(NULL == pIgr_pmask) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicVlanTransparent(rtk_switch_port_L2P_get(egr_port), &pmask)) != RT_ERR_OK) ++ return retVal; ++ ++ if(rtk_switch_portmask_P2L_get(pmask, pIgr_pmask) != RT_ERR_OK) ++ return RT_ERR_FAILED; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_vlan_keep_set ++ * Description: ++ * Set VLAN egress keep mode ++ * Input: ++ * egr_port - Egress Port id. ++ * pIgr_pmask - Ingress Port Mask. ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * None. ++ */ ++rtk_api_ret_t rtk_vlan_keep_set(rtk_port_t egr_port, rtk_portmask_t *pIgr_pmask) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 pmask; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(egr_port); ++ ++ if(NULL == pIgr_pmask) ++ return RT_ERR_NULL_POINTER; ++ ++ RTK_CHK_PORTMASK_VALID(pIgr_pmask); ++ ++ if(rtk_switch_portmask_L2P_get(pIgr_pmask, &pmask) != RT_ERR_OK) ++ return RT_ERR_FAILED; ++ ++ if ((retVal = rtl8367c_setAsicVlanEgressKeep(rtk_switch_port_L2P_get(egr_port), pmask)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_vlan_keep_get ++ * Description: ++ * Get VLAN egress keep mode ++ * Input: ++ * egr_port - Egress Port id. ++ * Output: ++ * pIgr_pmask - Ingress Port Mask ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_PORT_ID - Invalid port number. ++ * Note: ++ * None. ++ */ ++rtk_api_ret_t rtk_vlan_keep_get(rtk_port_t egr_port, rtk_portmask_t *pIgr_pmask) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 pmask; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(egr_port); ++ ++ if(NULL == pIgr_pmask) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicVlanEgressKeep(rtk_switch_port_L2P_get(egr_port), &pmask)) != RT_ERR_OK) ++ return retVal; ++ ++ if(rtk_switch_portmask_P2L_get(pmask, pIgr_pmask) != RT_ERR_OK) ++ return RT_ERR_FAILED; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_vlan_stg_set ++ * Description: ++ * Set spanning tree group instance of the vlan to the specified device ++ * Input: ++ * vid - Specified VLAN ID. ++ * stg - spanning tree group instance. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_MSTI - Invalid msti parameter ++ * RT_ERR_INPUT - Invalid input parameter. ++ * RT_ERR_VLAN_VID - Invalid VID parameter. ++ * Note: ++ * The API can set spanning tree group instance of the vlan to the specified device. ++ */ ++rtk_api_ret_t rtk_vlan_stg_set(rtk_vlan_t vid, rtk_stp_msti_id_t stg) ++{ ++ rtk_api_ret_t retVal; ++ rtl8367c_user_vlan4kentry vlan4K; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* vid must be 0~4095 */ ++ if (vid > RTL8367C_VIDMAX) ++ return RT_ERR_VLAN_VID; ++ ++ /* priority must be 0~15 */ ++ if (stg > RTL8367C_MSTIMAX) ++ return RT_ERR_MSTI; ++ ++ /* update 4K table */ ++ vlan4K.vid = vid; ++ if ((retVal = rtl8367c_getAsicVlan4kEntry(&vlan4K)) != RT_ERR_OK) ++ return retVal; ++ ++ vlan4K.fid_msti= stg; ++ if ((retVal = rtl8367c_setAsicVlan4kEntry(&vlan4K)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_vlan_stg_get ++ * Description: ++ * Get spanning tree group instance of the vlan to the specified device ++ * Input: ++ * vid - Specified VLAN ID. ++ * Output: ++ * pStg - spanning tree group instance. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_VLAN_VID - Invalid VID parameter. ++ * Note: ++ * The API can get spanning tree group instance of the vlan to the specified device. ++ */ ++rtk_api_ret_t rtk_vlan_stg_get(rtk_vlan_t vid, rtk_stp_msti_id_t *pStg) ++{ ++ rtk_api_ret_t retVal; ++ rtl8367c_user_vlan4kentry vlan4K; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* vid must be 0~4095 */ ++ if (vid > RTL8367C_VIDMAX) ++ return RT_ERR_VLAN_VID; ++ ++ if(NULL == pStg) ++ return RT_ERR_NULL_POINTER; ++ ++ /* update 4K table */ ++ vlan4K.vid = vid; ++ if ((retVal = rtl8367c_getAsicVlan4kEntry(&vlan4K)) != RT_ERR_OK) ++ return retVal; ++ ++ *pStg = vlan4K.fid_msti; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_vlan_portFid_set ++ * Description: ++ * Set port-based filtering database ++ * Input: ++ * port - Port id. ++ * enable - enable port-based FID ++ * fid - Specified filtering database. ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_L2_FID - Invalid fid. ++ * RT_ERR_INPUT - Invalid input parameter. ++ * RT_ERR_PORT_ID - Invalid port ID. ++ * Note: ++ * The API can set port-based filtering database. If the function is enabled, all input ++ * packets will be assigned to the port-based fid regardless vlan tag. ++ */ ++rtk_api_ret_t rtk_vlan_portFid_set(rtk_port_t port, rtk_enable_t enable, rtk_fid_t fid) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if (enable>=RTK_ENABLE_END) ++ return RT_ERR_ENABLE; ++ ++ /* fid must be 0~4095 */ ++ if (fid > RTK_FID_MAX) ++ return RT_ERR_L2_FID; ++ ++ if ((retVal = rtl8367c_setAsicPortBasedFidEn(rtk_switch_port_L2P_get(port), enable))!=RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_setAsicPortBasedFid(rtk_switch_port_L2P_get(port), fid))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_vlan_portFid_get ++ * Description: ++ * Get port-based filtering database ++ * Input: ++ * port - Port id. ++ * Output: ++ * pEnable - enable port-based FID ++ * pFid - Specified filtering database. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Invalid input parameters. ++ * RT_ERR_PORT_ID - Invalid port ID. ++ * Note: ++ * The API can get port-based filtering database status. If the function is enabled, all input ++ * packets will be assigned to the port-based fid regardless vlan tag. ++ */ ++rtk_api_ret_t rtk_vlan_portFid_get(rtk_port_t port, rtk_enable_t *pEnable, rtk_fid_t *pFid) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if(NULL == pEnable) ++ return RT_ERR_NULL_POINTER; ++ ++ if(NULL == pFid) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicPortBasedFidEn(rtk_switch_port_L2P_get(port), pEnable))!=RT_ERR_OK) ++ return retVal; ++ ++ if ((retVal = rtl8367c_getAsicPortBasedFid(rtk_switch_port_L2P_get(port), pFid))!=RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_vlan_UntagDscpPriorityEnable_set ++ * Description: ++ * Set Untag DSCP priority assign ++ * Input: ++ * enable - state of Untag DSCP priority assign ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_ENABLE - Invalid input parameters. ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_vlan_UntagDscpPriorityEnable_set(rtk_enable_t enable) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(enable >= RTK_ENABLE_END) ++ return RT_ERR_ENABLE; ++ ++ if ((retVal = rtl8367c_setAsicVlanUntagDscpPriorityEn((rtk_uint32)enable)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_vlan_UntagDscpPriorityEnable_get ++ * Description: ++ * Get Untag DSCP priority assign ++ * Input: ++ * None ++ * Output: ++ * pEnable - state of Untag DSCP priority assign ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_NULL_POINTER - Null pointer ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_vlan_UntagDscpPriorityEnable_get(rtk_enable_t *pEnable) ++{ ++ rtk_api_ret_t retVal; ++ rtk_uint32 value; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pEnable) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicVlanUntagDscpPriorityEn(&value)) != RT_ERR_OK) ++ return retVal; ++ ++ *pEnable = (rtk_enable_t)value; ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_stp_mstpState_set ++ * Description: ++ * Configure spanning tree state per each port. ++ * Input: ++ * port - Port id ++ * msti - Multiple spanning tree instance. ++ * stp_state - Spanning tree state for msti ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_MSTI - Invalid msti parameter. ++ * RT_ERR_MSTP_STATE - Invalid STP state. ++ * Note: ++ * System supports per-port multiple spanning tree state for each msti. ++ * There are four states supported by ASIC. ++ * - STP_STATE_DISABLED ++ * - STP_STATE_BLOCKING ++ * - STP_STATE_LEARNING ++ * - STP_STATE_FORWARDING ++ */ ++rtk_api_ret_t rtk_stp_mstpState_set(rtk_stp_msti_id_t msti, rtk_port_t port, rtk_stp_state_t stp_state) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if (msti > RTK_MAX_NUM_OF_MSTI) ++ return RT_ERR_MSTI; ++ ++ if (stp_state >= STP_STATE_END) ++ return RT_ERR_MSTP_STATE; ++ ++ if ((retVal = rtl8367c_setAsicSpanningTreeStatus(rtk_switch_port_L2P_get(port), msti, stp_state)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_stp_mstpState_get ++ * Description: ++ * Get spanning tree state per each port. ++ * Input: ++ * port - Port id. ++ * msti - Multiple spanning tree instance. ++ * Output: ++ * pStp_state - Spanning tree state for msti ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_PORT_ID - Invalid port number. ++ * RT_ERR_MSTI - Invalid msti parameter. ++ * Note: ++ * System supports per-port multiple spanning tree state for each msti. ++ * There are four states supported by ASIC. ++ * - STP_STATE_DISABLED ++ * - STP_STATE_BLOCKING ++ * - STP_STATE_LEARNING ++ * - STP_STATE_FORWARDING ++ */ ++rtk_api_ret_t rtk_stp_mstpState_get(rtk_stp_msti_id_t msti, rtk_port_t port, rtk_stp_state_t *pStp_state) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* Check Port Valid */ ++ RTK_CHK_PORT_VALID(port); ++ ++ if (msti > RTK_MAX_NUM_OF_MSTI) ++ return RT_ERR_MSTI; ++ ++ if(NULL == pStp_state) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getAsicSpanningTreeStatus(rtk_switch_port_L2P_get(port), msti, pStp_state)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_vlan_checkAndCreateMbr ++ * Description: ++ * Check and create Member configuration and return index ++ * Input: ++ * vid - VLAN id. ++ * Output: ++ * pIndex - Member configuration index ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_VLAN_VID - Invalid VLAN ID. ++ * RT_ERR_VLAN_ENTRY_NOT_FOUND - VLAN not found ++ * RT_ERR_TBL_FULL - Member Configuration table full ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_vlan_checkAndCreateMbr(rtk_vlan_t vid, rtk_uint32 *pIndex) ++{ ++ rtk_api_ret_t retVal; ++ rtl8367c_user_vlan4kentry vlan4K; ++ rtl8367c_vlanconfiguser vlanMC; ++ rtk_uint32 idx; ++ rtk_uint32 empty_idx = 0xFFFF; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ /* vid must be 0~8191 */ ++ if (vid > RTL8367C_EVIDMAX) ++ return RT_ERR_VLAN_VID; ++ ++ /* Null pointer check */ ++ if(NULL == pIndex) ++ return RT_ERR_NULL_POINTER; ++ ++ /* Get 4K VLAN */ ++ if (vid <= RTL8367C_VIDMAX) ++ { ++ memset(&vlan4K, 0x00, sizeof(rtl8367c_user_vlan4kentry)); ++ vlan4K.vid = vid; ++ if ((retVal = rtl8367c_getAsicVlan4kEntry(&vlan4K)) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ /* Search exist entry */ ++ for (idx = 0; idx <= RTL8367C_CVIDXMAX; idx++) ++ { ++ if(vlan_mbrCfgUsage[idx] == MBRCFG_USED_BY_VLAN) ++ { ++ if(vlan_mbrCfgVid[idx] == vid) ++ { ++ /* Found! return index */ ++ *pIndex = idx; ++ return RT_ERR_OK; ++ } ++ } ++ } ++ ++ /* Not found, Read H/W Member Configuration table to update database */ ++ for (idx = 0; idx <= RTL8367C_CVIDXMAX; idx++) ++ { ++ if ((retVal = rtl8367c_getAsicVlanMemberConfig(idx, &vlanMC)) != RT_ERR_OK) ++ return retVal; ++ ++ if( (vlanMC.evid == 0) && (vlanMC.mbr == 0x00)) ++ { ++ vlan_mbrCfgUsage[idx] = MBRCFG_UNUSED; ++ vlan_mbrCfgVid[idx] = 0; ++ } ++ else ++ { ++ vlan_mbrCfgUsage[idx] = MBRCFG_USED_BY_VLAN; ++ vlan_mbrCfgVid[idx] = vlanMC.evid; ++ } ++ } ++ ++ /* Search exist entry again */ ++ for (idx = 0; idx <= RTL8367C_CVIDXMAX; idx++) ++ { ++ if(vlan_mbrCfgUsage[idx] == MBRCFG_USED_BY_VLAN) ++ { ++ if(vlan_mbrCfgVid[idx] == vid) ++ { ++ /* Found! return index */ ++ *pIndex = idx; ++ return RT_ERR_OK; ++ } ++ } ++ } ++ ++ /* try to look up an empty index */ ++ for (idx = 0; idx <= RTL8367C_CVIDXMAX; idx++) ++ { ++ if(vlan_mbrCfgUsage[idx] == MBRCFG_UNUSED) ++ { ++ empty_idx = idx; ++ break; ++ } ++ } ++ ++ if(empty_idx == 0xFFFF) ++ { ++ /* No empty index */ ++ return RT_ERR_TBL_FULL; ++ } ++ ++ if (vid > RTL8367C_VIDMAX) ++ { ++ /* > 4K, there is no 4K entry, create on member configuration directly */ ++ memset(&vlanMC, 0x00, sizeof(rtl8367c_vlanconfiguser)); ++ vlanMC.evid = vid; ++ if ((retVal = rtl8367c_setAsicVlanMemberConfig(empty_idx, &vlanMC)) != RT_ERR_OK) ++ return retVal; ++ } ++ else ++ { ++ /* Copy from 4K table */ ++ vlanMC.evid = vid; ++ vlanMC.mbr = vlan4K.mbr; ++ vlanMC.fid_msti = vlan4K.fid_msti; ++ vlanMC.meteridx= vlan4K.meteridx; ++ vlanMC.envlanpol= vlan4K.envlanpol; ++ vlanMC.vbpen = vlan4K.vbpen; ++ vlanMC.vbpri = vlan4K.vbpri; ++ if ((retVal = rtl8367c_setAsicVlanMemberConfig(empty_idx, &vlanMC)) != RT_ERR_OK) ++ return retVal; ++ } ++ ++ /* Update Database */ ++ vlan_mbrCfgUsage[empty_idx] = MBRCFG_USED_BY_VLAN; ++ vlan_mbrCfgVid[empty_idx] = vid; ++ ++ *pIndex = empty_idx; ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_vlan_reservedVidAction_set ++ * Description: ++ * Set Action of VLAN ID = 0 & 4095 tagged packet ++ * Input: ++ * action_vid0 - Action for VID 0. ++ * action_vid4095 - Action for VID 4095. ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Error Input ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_vlan_reservedVidAction_set(rtk_vlan_resVidAction_t action_vid0, rtk_vlan_resVidAction_t action_vid4095) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(action_vid0 >= RESVID_ACTION_END) ++ return RT_ERR_INPUT; ++ ++ if(action_vid4095 >= RESVID_ACTION_END) ++ return RT_ERR_INPUT; ++ ++ if ((retVal = rtl8367c_setReservedVidAction((rtk_uint32)action_vid0, (rtk_uint32)action_vid4095)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_vlan_reservedVidAction_get ++ * Description: ++ * Get Action of VLAN ID = 0 & 4095 tagged packet ++ * Input: ++ * pAction_vid0 - Action for VID 0. ++ * pAction_vid4095 - Action for VID 4095. ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_NULL_POINTER - NULL Pointer ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_vlan_reservedVidAction_get(rtk_vlan_resVidAction_t *pAction_vid0, rtk_vlan_resVidAction_t *pAction_vid4095) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(pAction_vid0 == NULL) ++ return RT_ERR_NULL_POINTER; ++ ++ if(pAction_vid4095 == NULL) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getReservedVidAction((rtk_uint32 *)pAction_vid0, (rtk_uint32 *)pAction_vid4095)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_vlan_realKeepRemarkEnable_set ++ * Description: ++ * Set Real keep 1p remarking feature ++ * Input: ++ * enabled - State of 1p remarking at real keep packet ++ * Output: ++ * None. ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Error Input ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_vlan_realKeepRemarkEnable_set(rtk_enable_t enabled) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(enabled >= RTK_ENABLE_END) ++ return RT_ERR_INPUT; ++ ++ if ((retVal = rtl8367c_setRealKeepRemarkEn((rtk_uint32)enabled)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_vlan_realKeepRemarkEnable_get ++ * Description: ++ * Get Real keep 1p remarking feature ++ * Input: ++ * None. ++ * Output: ++ * pEnabled - State of 1p remarking at real keep packet ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Error Input ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_vlan_realKeepRemarkEnable_get(rtk_enable_t *pEnabled) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if(NULL == pEnabled) ++ return RT_ERR_NULL_POINTER; ++ ++ if ((retVal = rtl8367c_getRealKeepRemarkEn((rtk_uint32 *)pEnabled)) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ ++/* Function Name: ++ * rtk_vlan_reset ++ * Description: ++ * Reset VLAN ++ * Input: ++ * None. ++ * Output: ++ * pEnabled - State of 1p remarking at real keep packet ++ * Return: ++ * RT_ERR_OK - OK ++ * RT_ERR_FAILED - Failed ++ * RT_ERR_SMI - SMI access error ++ * RT_ERR_INPUT - Error Input ++ * Note: ++ * ++ */ ++rtk_api_ret_t rtk_vlan_reset(void) ++{ ++ rtk_api_ret_t retVal; ++ ++ /* Check initialization state */ ++ RTK_CHK_INIT_STATE(); ++ ++ if ((retVal = rtl8367c_resetVlan()) != RT_ERR_OK) ++ return retVal; ++ ++ return RT_ERR_OK; ++} ++ +diff --git a/drivers/net/phy/rtk/rtl8367s.c b/drivers/net/phy/rtk/rtl8367s.c +new file mode 100644 +index 000000000000..2988c8af56db +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367s.c +@@ -0,0 +1,580 @@ ++/* ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version 2 ++ * of the License, or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++//include from rtl8367c dir ++#include "./rtl8367c/include/rtk_switch.h" ++#include "./rtl8367c/include/vlan.h" ++#include "./rtl8367c/include/stat.h" ++#include "./rtl8367c/include/port.h" ++ ++#define RTL8367C_SW_CPU_PORT 6 ++ ++ //RTL8367C_PHY_PORT_NUM + ext0 + ext1 ++#define RTL8367C_NUM_PORTS 7 ++#define RTL8367C_NUM_VIDS 4096 ++ ++struct rtl8367_priv { ++ struct switch_dev swdev; ++ bool global_vlan_enable; ++}; ++ ++struct rtl8367_mib_counter { ++ const char *name; ++}; ++ ++struct rtl8367_vlan_info { ++ unsigned short vid; ++ unsigned int untag; ++ unsigned int member; ++ unsigned char fid; ++}; ++ ++struct rtl8367_priv rtl8367_priv_data; ++ ++unsigned int rtl8367c_port_id[RTL8367C_NUM_PORTS]={0,1,2,3,4,EXT_PORT1,EXT_PORT0}; ++ ++void (*rtl8367_switch_reset_func)(void)=NULL; ++ ++static struct rtl8367_mib_counter rtl8367c_mib_counters[] = { ++ {"ifInOctets"}, ++ {"dot3StatsFCSErrors"}, ++ {"dot3StatsSymbolErrors"}, ++ {"dot3InPauseFrames"}, ++ {"dot3ControlInUnknownOpcodes"}, ++ {"etherStatsFragments"}, ++ {"etherStatsJabbers"}, ++ {"ifInUcastPkts"}, ++ {"etherStatsDropEvents"}, ++ {"etherStatsOctets"}, ++ {"etherStatsUndersizePkts"}, ++ {"etherStatsOversizePkts"}, ++ {"etherStatsPkts64Octets"}, ++ {"etherStatsPkts65to127Octets"}, ++ {"etherStatsPkts128to255Octets"}, ++ {"etherStatsPkts256to511Octets"}, ++ {"etherStatsPkts512to1023Octets"}, ++ {"etherStatsPkts1024toMaxOctets"}, ++ {"etherStatsMcastPkts"}, ++ {"etherStatsBcastPkts"}, ++ {"ifOutOctets"}, ++ {"dot3StatsSingleCollisionFrames"}, ++ {"dot3StatsMultipleCollisionFrames"}, ++ {"dot3StatsDeferredTransmissions"}, ++ {"dot3StatsLateCollisions"}, ++ {"etherStatsCollisions"}, ++ {"dot3StatsExcessiveCollisions"}, ++ {"dot3OutPauseFrames"}, ++ {"dot1dBasePortDelayExceededDiscards"}, ++ {"dot1dTpPortInDiscards"}, ++ {"ifOutUcastPkts"}, ++ {"ifOutMulticastPkts"}, ++ {"ifOutBrocastPkts"}, ++ {"outOampduPkts"}, ++ {"inOampduPkts"}, ++ {"pktgenPkts"}, ++ {"inMldChecksumError"}, ++ {"inIgmpChecksumError"}, ++ {"inMldSpecificQuery"}, ++ {"inMldGeneralQuery"}, ++ {"inIgmpSpecificQuery"}, ++ {"inIgmpGeneralQuery"}, ++ {"inMldLeaves"}, ++ {"inIgmpLeaves"}, ++ {"inIgmpJoinsSuccess"}, ++ {"inIgmpJoinsFail"}, ++ {"inMldJoinsSuccess"}, ++ {"inMldJoinsFail"}, ++ {"inReportSuppressionDrop"}, ++ {"inLeaveSuppressionDrop"}, ++ {"outIgmpReports"}, ++ {"outIgmpLeaves"}, ++ {"outIgmpGeneralQuery"}, ++ {"outIgmpSpecificQuery"}, ++ {"outMldReports"}, ++ {"outMldLeaves"}, ++ {"outMldGeneralQuery"}, ++ {"outMldSpecificQuery"}, ++ {"inKnownMulticastPkts"}, ++ {"ifInMulticastPkts"}, ++ {"ifInBroadcastPkts"}, ++ {"ifOutDiscards"} ++}; ++ ++/*rtl8367c proprietary switch API wrapper */ ++static inline unsigned int rtl8367c_sw_to_phy_port(int port) ++{ ++ return rtl8367c_port_id[port]; ++} ++ ++static inline unsigned int rtl8367c_portmask_phy_to_sw(rtk_portmask_t phy_portmask) ++{ ++ int i; ++ for (i = 0; i < RTL8367C_NUM_PORTS; i++) { ++ if(RTK_PORTMASK_IS_PORT_SET(phy_portmask,rtl8367c_sw_to_phy_port(i))) { ++ RTK_PORTMASK_PORT_CLEAR(phy_portmask,rtl8367c_sw_to_phy_port(i)); ++ RTK_PORTMASK_PORT_SET(phy_portmask,i); ++ } ++ ++ } ++ return (unsigned int)phy_portmask.bits[0]; ++} ++ ++static int rtl8367c_reset_mibs(void) ++{ ++ return rtk_stat_global_reset(); ++} ++ ++static int rtl8367c_reset_port_mibs(int port) ++{ ++ ++ return rtk_stat_port_reset(rtl8367c_sw_to_phy_port(port)); ++} ++ ++static int rtl8367c_get_mibs_num(void) ++{ ++ return ARRAY_SIZE(rtl8367c_mib_counters); ++} ++ ++static const char *rtl8367c_get_mib_name(int idx) ++{ ++ ++ return rtl8367c_mib_counters[idx].name; ++} ++ ++static int rtl8367c_get_port_mib_counter(int idx, int port, unsigned long long *counter) ++{ ++ return rtk_stat_port_get(rtl8367c_sw_to_phy_port(port), idx, counter); ++} ++ ++static int rtl8367c_is_vlan_valid(unsigned int vlan) ++{ ++ unsigned max = RTL8367C_NUM_VIDS; ++ ++ if (vlan == 0 || vlan >= max) ++ return 0; ++ ++ return 1; ++} ++ ++static int rtl8367c_get_vlan( unsigned short vid, struct rtl8367_vlan_info *vlan) ++{ ++ rtk_vlan_cfg_t vlan_cfg; ++ ++ memset(vlan, '\0', sizeof(struct rtl8367_vlan_info)); ++ ++ if (vid >= RTL8367C_NUM_VIDS) ++ return -EINVAL; ++ ++ if(rtk_vlan_get(vid,&vlan_cfg)) ++ return -EINVAL; ++ ++ vlan->vid = vid; ++ vlan->member = rtl8367c_portmask_phy_to_sw(vlan_cfg.mbr); ++ vlan->untag = rtl8367c_portmask_phy_to_sw(vlan_cfg.untag); ++ vlan->fid = vlan_cfg.fid_msti; ++ ++ return 0; ++} ++ ++static int rtl8367c_set_vlan( unsigned short vid, u32 mbr, u32 untag, u8 fid) ++{ ++ rtk_vlan_cfg_t vlan_cfg; ++ int i; ++ ++ memset(&vlan_cfg, 0x00, sizeof(rtk_vlan_cfg_t)); ++ ++ for (i = 0; i < RTL8367C_NUM_PORTS; i++) { ++ if (mbr & (1 << i)) { ++ RTK_PORTMASK_PORT_SET(vlan_cfg.mbr, rtl8367c_sw_to_phy_port(i)); ++ if(untag & (1 << i)) ++ RTK_PORTMASK_PORT_SET(vlan_cfg.untag, rtl8367c_sw_to_phy_port(i)); ++ } ++ } ++ vlan_cfg.fid_msti=fid; ++ vlan_cfg.ivl_en = 1; ++ return rtk_vlan_set(vid, &vlan_cfg); ++} ++ ++ ++static int rtl8367c_get_pvid( int port, int *pvid) ++{ ++ u32 prio=0; ++ ++ if (port >= RTL8367C_NUM_PORTS) ++ return -EINVAL; ++ ++ return rtk_vlan_portPvid_get(rtl8367c_sw_to_phy_port(port),pvid,&prio); ++} ++ ++ ++static int rtl8367c_set_pvid( int port, int pvid) ++{ ++ u32 prio=0; ++ ++ if (port >= RTL8367C_NUM_PORTS) ++ return -EINVAL; ++ ++ return rtk_vlan_portPvid_set(rtl8367c_sw_to_phy_port(port),pvid,prio); ++} ++ ++static int rtl8367c_get_port_link(int port, int *link, int *speed, int *duplex) ++{ ++ ++ if(rtk_port_phyStatus_get(rtl8367c_sw_to_phy_port(port),(rtk_port_linkStatus_t *)link, ++ (rtk_port_speed_t *)speed,(rtk_port_duplex_t *)duplex)) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++/*common rtl8367 swconfig entry API*/ ++ ++static int ++rtl8367_sw_set_vlan_enable(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rtl8367_priv *priv = container_of(dev, struct rtl8367_priv, swdev); ++ ++ priv->global_vlan_enable = val->value.i ; ++ ++ return 0; ++} ++ ++static int ++rtl8367_sw_get_vlan_enable(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rtl8367_priv *priv = container_of(dev, struct rtl8367_priv, swdev); ++ ++ val->value.i = priv->global_vlan_enable; ++ ++ return 0; ++} ++ ++static int rtl8367_sw_reset_mibs(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ return rtl8367c_reset_mibs(); ++} ++ ++ ++static int rtl8367_sw_reset_port_mibs(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ int port; ++ ++ port = val->port_vlan; ++ if (port >= RTL8367C_NUM_PORTS) ++ return -EINVAL; ++ ++ return rtl8367c_reset_port_mibs(port); ++} ++ ++static int rtl8367_sw_get_port_mib(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ int i, len = 0; ++ unsigned long long counter = 0; ++ static char mib_buf[4096]; ++ ++ if (val->port_vlan >= RTL8367C_NUM_PORTS) ++ return -EINVAL; ++ ++ len += snprintf(mib_buf + len, sizeof(mib_buf) - len, ++ "Port %d MIB counters\n", ++ val->port_vlan); ++ ++ for (i = 0; i port_vlan, ++ &counter)) ++ len += snprintf(mib_buf + len, sizeof(mib_buf) - len, ++ "%llu\n", counter); ++ else ++ len += snprintf(mib_buf + len, sizeof(mib_buf) - len, ++ "%s\n", "N/A"); ++ } ++ ++ val->value.s = mib_buf; ++ val->len = len; ++ return 0; ++} ++ ++ ++static int rtl8367_sw_get_vlan_info(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ int i; ++ u32 len = 0; ++ struct rtl8367_vlan_info vlan; ++ static char vlan_buf[256]; ++ int err; ++ ++ if (!rtl8367c_is_vlan_valid(val->port_vlan)) ++ return -EINVAL; ++ ++ memset(vlan_buf, '\0', sizeof(vlan_buf)); ++ ++ err = rtl8367c_get_vlan(val->port_vlan, &vlan); ++ if (err) ++ return err; ++ ++ len += snprintf(vlan_buf + len, sizeof(vlan_buf) - len, ++ "VLAN %d: Ports: '", vlan.vid); ++ ++ for (i = 0; i value.s = vlan_buf; ++ val->len = len; ++ ++ return 0; ++} ++ ++ ++static int rtl8367_sw_get_vlan_ports(struct switch_dev *dev, struct switch_val *val) ++{ ++ struct switch_port *port; ++ struct rtl8367_vlan_info vlan; ++ int i; ++ ++ if (!rtl8367c_is_vlan_valid(val->port_vlan)) ++ return -EINVAL; ++ ++ if(rtl8367c_get_vlan(val->port_vlan, &vlan)) ++ return -EINVAL; ++ ++ port = &val->value.ports[0]; ++ val->len = 0; ++ for (i = 0; i id = i; ++ port->flags = (vlan.untag & BIT(i)) ? ++ 0 : BIT(SWITCH_PORT_FLAG_TAGGED); ++ val->len++; ++ port++; ++ } ++ return 0; ++} ++ ++ ++static int rtl8367_sw_set_vlan_ports(struct switch_dev *dev, struct switch_val *val) ++{ ++ struct switch_port *port; ++ u32 member = 0; ++ u32 untag = 0; ++ u8 fid=0; ++ int err; ++ int i; ++ ++ if (!rtl8367c_is_vlan_valid(val->port_vlan)) ++ return -EINVAL; ++ ++ port = &val->value.ports[0]; ++ for (i = 0; i < val->len; i++, port++) { ++ int pvid = 0; ++ member |= BIT(port->id); ++ ++ if (!(port->flags & BIT(SWITCH_PORT_FLAG_TAGGED))) ++ untag |= BIT(port->id); ++ ++ /* ++ * To ensure that we have a valid MC entry for this VLAN, ++ * initialize the port VLAN ID here. ++ */ ++ err = rtl8367c_get_pvid(port->id, &pvid); ++ if (err < 0) ++ return err; ++ if (pvid == 0) { ++ err = rtl8367c_set_pvid(port->id, val->port_vlan); ++ if (err < 0) ++ return err; ++ } ++ } ++ ++ //pr_info("[%s] vid=%d , mem=%x,untag=%x,fid=%d \n",__func__,val->port_vlan,member,untag,fid); ++ ++ return rtl8367c_set_vlan(val->port_vlan, member, untag, fid); ++ ++} ++ ++ ++static int rtl8367_sw_get_port_pvid(struct switch_dev *dev, int port, int *val) ++{ ++ return rtl8367c_get_pvid(port, val); ++} ++ ++ ++static int rtl8367_sw_set_port_pvid(struct switch_dev *dev, int port, int val) ++{ ++ return rtl8367c_set_pvid(port, val); ++} ++ ++ ++static int rtl8367_sw_reset_switch(struct switch_dev *dev) ++{ ++ if(rtl8367_switch_reset_func) ++ (*rtl8367_switch_reset_func)(); ++ else ++ printk("rest switch is not supported\n"); ++ ++ return 0; ++} ++ ++static int rtl8367_sw_get_port_link(struct switch_dev *dev, int port, ++ struct switch_port_link *link) ++{ ++ int speed; ++ ++ if (port >= RTL8367C_NUM_PORTS) ++ return -EINVAL; ++ ++ if(rtl8367c_get_port_link(port,(int *)&link->link,(int *)&speed,(int *)&link->duplex)) ++ return -EINVAL; ++ ++ if (!link->link) ++ return 0; ++ ++ switch (speed) { ++ case 0: ++ link->speed = SWITCH_PORT_SPEED_10; ++ break; ++ case 1: ++ link->speed = SWITCH_PORT_SPEED_100; ++ break; ++ case 2: ++ link->speed = SWITCH_PORT_SPEED_1000; ++ break; ++ default: ++ link->speed = SWITCH_PORT_SPEED_UNKNOWN; ++ break; ++ } ++ ++ return 0; ++} ++ ++ ++static struct switch_attr rtl8367_globals[] = { ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "enable_vlan", ++ .description = "Enable VLAN mode", ++ .set = rtl8367_sw_set_vlan_enable, ++ .get = rtl8367_sw_get_vlan_enable, ++ .max = 1, ++ }, { ++ .type = SWITCH_TYPE_NOVAL, ++ .name = "reset_mibs", ++ .description = "Reset all MIB counters", ++ .set = rtl8367_sw_reset_mibs, ++ } ++}; ++ ++static struct switch_attr rtl8367_port[] = { ++ { ++ .type = SWITCH_TYPE_NOVAL, ++ .name = "reset_mib", ++ .description = "Reset single port MIB counters", ++ .set = rtl8367_sw_reset_port_mibs, ++ }, { ++ .type = SWITCH_TYPE_STRING, ++ .name = "mib", ++ .description = "Get MIB counters for port", ++ //.max = 33, ++ .set = NULL, ++ .get = rtl8367_sw_get_port_mib, ++ }, ++}; ++ ++static struct switch_attr rtl8367_vlan[] = { ++ { ++ .type = SWITCH_TYPE_STRING, ++ .name = "info", ++ .description = "Get vlan information", ++ .max = 1, ++ .set = NULL, ++ .get = rtl8367_sw_get_vlan_info, ++ }, ++}; ++ ++static const struct switch_dev_ops rtl8367_sw_ops = { ++ .attr_global = { ++ .attr = rtl8367_globals, ++ .n_attr = ARRAY_SIZE(rtl8367_globals), ++ }, ++ .attr_port = { ++ .attr = rtl8367_port, ++ .n_attr = ARRAY_SIZE(rtl8367_port), ++ }, ++ .attr_vlan = { ++ .attr = rtl8367_vlan, ++ .n_attr = ARRAY_SIZE(rtl8367_vlan), ++ }, ++ ++ .get_vlan_ports = rtl8367_sw_get_vlan_ports, ++ .set_vlan_ports = rtl8367_sw_set_vlan_ports, ++ .get_port_pvid = rtl8367_sw_get_port_pvid, ++ .set_port_pvid = rtl8367_sw_set_port_pvid, ++ .reset_switch = rtl8367_sw_reset_switch, ++ .get_port_link = rtl8367_sw_get_port_link, ++}; ++ ++int rtl8367s_swconfig_init(void (*reset_func)(void)) ++{ ++ struct rtl8367_priv *priv = &rtl8367_priv_data; ++ struct switch_dev *dev=&priv->swdev; ++ int err=0; ++ ++ rtl8367_switch_reset_func = reset_func ; ++ ++ memset(priv, 0, sizeof(struct rtl8367_priv)); ++ priv->global_vlan_enable =0; ++ ++ dev->name = "RTL8367C"; ++ dev->cpu_port = RTL8367C_SW_CPU_PORT; ++ dev->ports = RTL8367C_NUM_PORTS; ++ dev->vlans = RTL8367C_NUM_VIDS; ++ dev->ops = &rtl8367_sw_ops; ++ dev->alias = "RTL8367C"; ++ err = register_switch(dev, NULL); ++ ++ pr_info("[%s]\n",__func__); ++ ++ return err; ++} +diff --git a/drivers/net/phy/rtk/rtl8367s_dbg.c b/drivers/net/phy/rtk/rtl8367s_dbg.c +new file mode 100644 +index 000000000000..6bc9cbbf0638 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367s_dbg.c +@@ -0,0 +1,648 @@ ++#include ++#include ++#include ++#include ++#include ++ ++#include "./rtl8367c/include/rtk_switch.h" ++#include "./rtl8367c/include/port.h" ++#include "./rtl8367c/include/vlan.h" ++#include "./rtl8367c/include/rtl8367c_asicdrv_port.h" ++#include "./rtl8367c/include/stat.h" ++#include "./rtl8367c/include/l2.h" ++#include "./rtl8367c/include/smi.h" ++#include "./rtl8367c/include/mirror.h" ++#include "./rtl8367c/include/igmp.h" ++#include "./rtl8367c/include/leaky.h" ++ ++static struct proc_dir_entry *proc_reg_dir; ++static struct proc_dir_entry *proc_esw_cnt; ++static struct proc_dir_entry *proc_vlan_cnt; ++static struct proc_dir_entry *proc_mac_tbl; ++static struct proc_dir_entry *proc_reg; ++static struct proc_dir_entry *proc_phyreg; ++static struct proc_dir_entry *proc_mirror; ++static struct proc_dir_entry *proc_igmp; ++ ++#define PROCREG_ESW_CNT "esw_cnt" ++#define PROCREG_VLAN "vlan" ++#define PROCREG_MAC_TBL "mac_tbl" ++#define PROCREG_REG "reg" ++#define PROCREG_PHYREG "phyreg" ++#define PROCREG_MIRROR "mirror" ++#define PROCREG_IGMP "igmp" ++#define PROCREG_DIR "rtk_gsw" ++ ++#define RTK_SW_VID_RANGE 16 ++ ++static void rtk_dump_mib_type(rtk_stat_port_type_t cntr_idx) ++{ ++ rtk_port_t port; ++ rtk_stat_counter_t Cntr; ++ ++ for (port = UTP_PORT0; port < (UTP_PORT0 + 5); port++) { ++ rtk_stat_port_get(port, cntr_idx, &Cntr); ++ printk("%8llu", Cntr); ++ } ++ ++ for (port = EXT_PORT0; port < (EXT_PORT0 + 2); port++) { ++ rtk_stat_port_get(port, cntr_idx, &Cntr); ++ printk("%8llu", Cntr); ++ } ++ ++ printk("\n"); ++} ++static void rtk_hal_dump_mib(void) ++{ ++ ++ printk("==================%8s%8s%8s%8s%8s%8s%8s\n", "Port0", "Port1", ++ "Port2", "Port3", "Port4", "Port16", "Port17"); ++ /* Get TX Unicast Pkts */ ++ printk("TX Unicast Pkts :"); ++ rtk_dump_mib_type(STAT_IfOutUcastPkts); ++ /* Get TX Multicast Pkts */ ++ printk("TX Multicast Pkts:"); ++ rtk_dump_mib_type(STAT_IfOutMulticastPkts); ++ /* Get TX BroadCast Pkts */ ++ printk("TX BroadCast Pkts:"); ++ rtk_dump_mib_type(STAT_IfOutBroadcastPkts); ++ /* Get TX Collisions */ ++ /* Get TX Puase Frames */ ++ printk("TX Pause Frames :"); ++ rtk_dump_mib_type(STAT_Dot3OutPauseFrames); ++ /* Get TX Drop Events */ ++ /* Get RX Unicast Pkts */ ++ printk("RX Unicast Pkts :"); ++ rtk_dump_mib_type(STAT_IfInUcastPkts); ++ /* Get RX Multicast Pkts */ ++ printk("RX Multicast Pkts:"); ++ rtk_dump_mib_type(STAT_IfInMulticastPkts); ++ /* Get RX Broadcast Pkts */ ++ printk("RX Broadcast Pkts:"); ++ rtk_dump_mib_type(STAT_IfInBroadcastPkts); ++ /* Get RX FCS Erros */ ++ printk("RX FCS Errors :"); ++ rtk_dump_mib_type(STAT_Dot3StatsFCSErrors); ++ /* Get RX Undersize Pkts */ ++ printk("RX Undersize Pkts:"); ++ rtk_dump_mib_type(STAT_EtherStatsUnderSizePkts); ++ /* Get RX Discard Pkts */ ++ printk("RX Discard Pkts :"); ++ rtk_dump_mib_type(STAT_Dot1dTpPortInDiscards); ++ /* Get RX Fragments */ ++ printk("RX Fragments :"); ++ rtk_dump_mib_type(STAT_EtherStatsFragments); ++ /* Get RX Oversize Pkts */ ++ printk("RX Oversize Pkts :"); ++ rtk_dump_mib_type(STAT_EtherOversizeStats); ++ /* Get RX Jabbers */ ++ printk("RX Jabbers :"); ++ rtk_dump_mib_type(STAT_EtherStatsJabbers); ++ /* Get RX Pause Frames */ ++ printk("RX Pause Frames :"); ++ rtk_dump_mib_type(STAT_Dot3InPauseFrames); ++ /* clear MIB */ ++ rtk_stat_global_reset(); ++ ++} ++ ++static int rtk_hal_dump_vlan(void) ++{ ++ rtk_vlan_cfg_t vlan; ++ int i; ++ ++ printk("vid portmap\n"); ++ for (i = 0; i < RTK_SW_VID_RANGE; i++) { ++ rtk_vlan_get(i, &vlan); ++ printk("%3d ", i); ++ printk("%c", ++ RTK_PORTMASK_IS_PORT_SET(vlan.mbr, ++ UTP_PORT0) ? '1' : '-'); ++ printk("%c", ++ RTK_PORTMASK_IS_PORT_SET(vlan.mbr, ++ UTP_PORT1) ? '1' : '-'); ++ printk("%c", ++ RTK_PORTMASK_IS_PORT_SET(vlan.mbr, ++ UTP_PORT2) ? '1' : '-'); ++ printk("%c", ++ RTK_PORTMASK_IS_PORT_SET(vlan.mbr, ++ UTP_PORT3) ? '1' : '-'); ++ printk("%c", ++ RTK_PORTMASK_IS_PORT_SET(vlan.mbr, ++ UTP_PORT4) ? '1' : '-'); ++ printk("%c", ++ RTK_PORTMASK_IS_PORT_SET(vlan.mbr, ++ EXT_PORT0) ? '1' : '-'); ++ printk("%c", ++ RTK_PORTMASK_IS_PORT_SET(vlan.mbr, ++ EXT_PORT1) ? '1' : '-'); ++ printk("\n"); ++ } ++ ++ return 0; ++} ++ ++static void rtk_hal_dump_table(void) ++{ ++ rtk_uint32 i; ++ rtk_uint32 address = 0; ++ rtk_l2_ucastAddr_t l2_data; ++ rtk_l2_ipMcastAddr_t ipMcastAddr; ++ rtk_l2_age_time_t age_timout; ++ ++ rtk_l2_aging_get(&age_timout); ++ printk("Mac table age timeout =%d\n",(unsigned int)age_timout); ++ ++ printk("hash port(0:17) fid vid mac-address\n"); ++ while (1) { ++ if (rtk_l2_addr_next_get(READMETHOD_NEXT_L2UC, UTP_PORT0, &address, &l2_data) != RT_ERR_OK) { ++ break; ++ } else { ++ printk("%03x ", l2_data.address); ++ for (i = 0; i < 5; i++) ++ if ( l2_data.port == i) ++ printk("1"); ++ else ++ printk("-"); ++ for (i = 16; i < 18; i++) ++ if ( l2_data.port == i) ++ printk("1"); ++ else ++ printk("-"); ++ ++ printk(" %2d", l2_data.fid); ++ printk(" %4d", l2_data.cvid); ++ printk(" %02x%02x%02x%02x%02x%02x\n", l2_data.mac.octet[0], ++ l2_data.mac.octet[1], l2_data.mac.octet[2], l2_data.mac.octet[3], ++ l2_data.mac.octet[4], l2_data.mac.octet[5]); ++ address ++; ++ } ++ } ++ ++ address = 0; ++ while (1) { ++ if (rtk_l2_ipMcastAddr_next_get(&address, &ipMcastAddr) != RT_ERR_OK) { ++ break; ++ } else { ++ printk("%03x ", ipMcastAddr.address); ++ for (i = 0; i < 5; i++) ++ printk("%c", RTK_PORTMASK_IS_PORT_SET(ipMcastAddr.portmask, i) ? '1' : '-'); ++ for (i = 16; i < 18; i++) ++ printk("%c", RTK_PORTMASK_IS_PORT_SET(ipMcastAddr.portmask, i) ? '1' : '-'); ++ printk(" "); ++ printk("01005E%06x\n", (ipMcastAddr.dip & 0xefffff)); ++ address ++; ++ } ++ } ++} ++ ++static void rtk_hal_clear_table(void) ++{ ++ rtk_api_ret_t ret; ++ ++ ret = rtk_l2_table_clear(); ++ if (ret != RT_ERR_OK) ++ printk("rtk_l2_table_clear failed\n"); ++} ++ ++static void rtk_hal_read_reg(unsigned int reg_addr) ++{ ++ ret_t retVal; ++ unsigned int reg_val; ++ ++ retVal = smi_read(reg_addr, ®_val); ++ ++ if(retVal != RT_ERR_OK) ++ printk("switch reg read failed\n"); ++ else ++ printk("reg0x%x = 0x%x\n", reg_addr, reg_val); ++} ++ ++static void rtk_hal_write_reg(unsigned int reg_addr , unsigned int reg_val) ++{ ++ ret_t retVal; ++ ++ retVal = smi_write(reg_addr, reg_val); ++ ++ if(retVal != RT_ERR_OK) ++ printk("switch reg write failed\n"); ++ else ++ printk("write switch reg0x%x 0x%x success\n", reg_addr, reg_val); ++} ++ ++static void rtk_hal_get_phy_reg(unsigned int port ,unsigned int reg_addr ) ++{ ++ ret_t retVal; ++ rtk_port_phy_data_t Data; ++ ++ retVal = rtk_port_phyReg_get(port, reg_addr, &Data); ++ if (retVal == RT_ERR_OK) ++ printk("Get: phy[%d].reg[%d] = 0x%04x\n", port, reg_addr, Data); ++ else ++ printk("read phy reg failed\n"); ++} ++ ++static void rtk_hal_set_phy_reg(unsigned int port ,unsigned int reg_addr,unsigned int reg_val) ++{ ++ ret_t retVal; ++ ++ retVal = rtk_port_phyReg_set(port, reg_addr, reg_val); ++ if (retVal == RT_ERR_OK) ++ printk("Set: phy[%d].reg[%d] = 0x%04x\n", port, reg_addr, reg_val); ++ else ++ printk("write phy reg failed\n"); ++} ++ ++static void rtk_hal_set_port_mirror(unsigned int port ,unsigned int rx_port_map,unsigned int tx_port_map) ++{ ++ rtk_portmask_t rx_portmask; ++ rtk_portmask_t tx_portmask; ++ rtk_api_ret_t ret; ++ int i; ++ ++ rtk_mirror_portIso_set(ENABLED); ++ RTK_PORTMASK_CLEAR(rx_portmask); ++ RTK_PORTMASK_CLEAR(tx_portmask); ++ ++ for (i = 0; i < 5; i++) ++ if (rx_port_map & (1 << i)) ++ RTK_PORTMASK_PORT_SET(rx_portmask, i); ++ ++ for (i = 0; i < 2; i++) ++ if (rx_port_map & (1 << (i + 5))) ++ RTK_PORTMASK_PORT_SET(rx_portmask, (i + EXT_PORT0)); ++ ++ RTK_PORTMASK_CLEAR(tx_portmask); ++ ++ for (i = 0; i < 5; i++) ++ if (tx_port_map & (1 << i)) ++ RTK_PORTMASK_PORT_SET(tx_portmask, i); ++ ++ for (i = 0; i < 2; i++) ++ if (tx_port_map & (1 << (i + 5))) ++ RTK_PORTMASK_PORT_SET(tx_portmask, (i + EXT_PORT0)); ++ ++ ret = rtk_mirror_portBased_set(port, &rx_portmask, &tx_portmask); ++ ++ if (!ret) ++ printk("rtk_mirror_portBased_set success\n"); ++ ++} ++ ++static void rtk_hal_enable_igmpsnoop(int hw_on) ++{ ++ rtk_api_ret_t ret; ++ rtk_portmask_t pmask; ++ ++ ret = rtk_igmp_init(); ++ if (hw_on == 1) { ++ RTK_PORTMASK_CLEAR(pmask); ++ RTK_PORTMASK_PORT_SET(pmask, EXT_PORT0); ++ ret |= rtk_igmp_static_router_port_set(&pmask); ++ ret |= rtk_igmp_protocol_set(UTP_PORT4, PROTOCOL_IGMPv1, IGMP_ACTION_FORWARD); ++ ret |= rtk_igmp_protocol_set(UTP_PORT4, PROTOCOL_IGMPv2, IGMP_ACTION_FORWARD); ++ ret |= rtk_igmp_protocol_set(UTP_PORT4, PROTOCOL_MLDv1, IGMP_ACTION_FORWARD); ++ ret |= rtk_igmp_protocol_set(EXT_PORT1, PROTOCOL_IGMPv1, IGMP_ACTION_FORWARD); ++ ret |= rtk_igmp_protocol_set(EXT_PORT1, PROTOCOL_IGMPv2, IGMP_ACTION_FORWARD); ++ ret |= rtk_igmp_protocol_set(EXT_PORT1, PROTOCOL_MLDv1, IGMP_ACTION_FORWARD); ++ ret |= rtk_igmp_protocol_set(UTP_PORT0, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC); ++ ret |= rtk_igmp_protocol_set(UTP_PORT1, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC); ++ ret |= rtk_igmp_protocol_set(UTP_PORT2, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC); ++ ret |= rtk_igmp_protocol_set(UTP_PORT3, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC); ++ ret |= rtk_igmp_protocol_set(EXT_PORT0, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC); ++ ++ ret |= rtk_leaky_vlan_set(LEAKY_IPMULTICAST, ENABLED); ++ ret |= rtk_l2_ipMcastForwardRouterPort_set(DISABLED); ++ /* drop unknown multicast packets*/ ++ /* ret |= rtk_trap_unknownMcastPktAction_set(UTP_PORT4, MCAST_IPV4, MCAST_ACTION_DROP);*/ ++ } else { ++ RTK_PORTMASK_CLEAR(pmask); ++ RTK_PORTMASK_PORT_SET(pmask, EXT_PORT0); ++ RTK_PORTMASK_PORT_SET(pmask, EXT_PORT1); ++ ret |= rtk_igmp_protocol_set(UTP_PORT0, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC); ++ ret |= rtk_igmp_protocol_set(UTP_PORT1, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC); ++ ret |= rtk_igmp_protocol_set(UTP_PORT2, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC); ++ ret |= rtk_igmp_protocol_set(UTP_PORT3, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC); ++ ret |= rtk_igmp_protocol_set(EXT_PORT0, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC); ++ ++ ret |= rtk_igmp_static_router_port_set(&pmask); ++ } ++ ++ if(ret != RT_ERR_OK) ++ printk("enable switch igmpsnoop failed\n"); ++ ++} ++ ++static void rtk_hal_disable_igmpsnoop(void) ++{ ++ if (rtk_igmp_state_set(DISABLED) != RT_ERR_OK) ++ printk("Disable IGMP SNOOPING failed\n"); ++} ++ ++static ssize_t mac_tbl_write(struct file *file, ++ const char __user *buffer, size_t count, ++ loff_t *data) ++{ ++ rtk_hal_clear_table(); ++ ++ return count; ++} ++ ++ ++static ssize_t phyreg_ops(struct file *file, ++ const char __user *buffer, size_t count, ++ loff_t *data) ++{ ++ char buf[64]; ++ unsigned int port; ++ unsigned int offset; ++ unsigned int val; ++ ++ memset(buf, 0, 64); ++ ++ if (copy_from_user(buf, buffer, count)) ++ return -EFAULT; ++ ++ ++ if(buf[0] == 'w') { ++ ++ if(sscanf(buf, "w %d %x %x", &port,&offset,&val) == -1) ++ return -EFAULT; ++ else ++ rtk_hal_set_phy_reg(port,offset,val); ++ ++ } else { ++ ++ if(sscanf(buf, "r %d %x",&port, &offset) == -1) ++ return -EFAULT; ++ else ++ rtk_hal_get_phy_reg(port,offset); ++ } ++ ++ return count; ++} ++ ++static ssize_t reg_ops(struct file *file, ++ const char __user *buffer, size_t count, ++ loff_t *data) ++{ ++ char buf[64]; ++ unsigned int offset; ++ unsigned int val; ++ ++ memset(buf, 0, 64); ++ ++ if (copy_from_user(buf, buffer, count)) ++ return -EFAULT; ++ ++ ++ if(buf[0] == 'w') { ++ ++ if(sscanf(buf, "w %x %x", &offset,&val) == -1) ++ return -EFAULT; ++ else ++ rtk_hal_write_reg(offset,val); ++ ++ } else { ++ ++ if(sscanf(buf, "r %x", &offset) == -1) ++ return -EFAULT; ++ else ++ rtk_hal_read_reg(offset); ++ } ++ ++ return count; ++} ++ ++static ssize_t mirror_ops(struct file *file, ++ const char __user *buffer, size_t count, ++ loff_t *data) ++{ ++ char buf[64]; ++ unsigned int port; ++ unsigned int tx_map,rx_map; ++ ++ memset(buf, 0, 64); ++ ++ if (copy_from_user(buf, buffer, count)) ++ return -EFAULT; ++ ++ if(sscanf(buf, "%d %x %x", &port,&rx_map,&tx_map) == -1) ++ return -EFAULT; ++ else ++ rtk_hal_set_port_mirror(port,rx_map,tx_map); ++ ++ return count; ++} ++ ++ ++static ssize_t igmp_ops(struct file *file, ++ const char __user *buffer, size_t count, ++ loff_t *data) ++{ ++ char buf[8]; ++ unsigned int ops; ++ ++ if (copy_from_user(buf, buffer, count)) ++ return -EFAULT; ++ ++ if(sscanf(buf, "%d", &ops) == -1) ++ return -EFAULT; ++ ++ if(ops == 0) ++ rtk_hal_disable_igmpsnoop(); ++ else if (ops == 1) ++ rtk_hal_enable_igmpsnoop(0); ++ else //hw igmp ++ rtk_hal_enable_igmpsnoop(1); ++ ++ return count; ++} ++ ++ ++static int esw_cnt_read(struct seq_file *seq, void *v) ++{ ++ rtk_hal_dump_mib(); ++ return 0; ++} ++ ++static int vlan_read(struct seq_file *seq, void *v) ++{ ++ rtk_hal_dump_vlan(); ++ return 0; ++} ++ ++static int mac_tbl_read(struct seq_file *seq, void *v) ++{ ++ rtk_hal_dump_table(); ++ return 0; ++} ++ ++static int reg_show(struct seq_file *seq, void *v) ++{ ++ return 0; ++} ++ ++static int phyreg_show(struct seq_file *seq, void *v) ++{ ++ return 0; ++} ++ ++static int mirror_show(struct seq_file *seq, void *v) ++{ ++ return 0; ++} ++ ++static int igmp_show(struct seq_file *seq, void *v) ++{ ++ return 0; ++} ++ ++static int switch_count_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, esw_cnt_read, 0); ++} ++ ++static int switch_vlan_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, vlan_read, 0); ++} ++ ++static int mac_tbl_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, mac_tbl_read, 0); ++} ++ ++static int reg_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, reg_show, 0); ++} ++ ++static int phyreg_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, phyreg_show, 0); ++} ++ ++static int mirror_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, mirror_show, 0); ++} ++ ++static int igmp_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, igmp_show, 0); ++} ++ ++ ++static const struct proc_ops switch_count_fops = { ++ .proc_open = switch_count_open, ++ .proc_read = seq_read, ++ .proc_lseek = seq_lseek, ++ .proc_release = single_release ++}; ++ ++static const struct proc_ops switch_vlan_fops = { ++ .proc_open = switch_vlan_open, ++ .proc_read = seq_read, ++ .proc_lseek = seq_lseek, ++ .proc_release = single_release ++}; ++ ++static const struct proc_ops mac_tbl_fops = { ++ .proc_open = mac_tbl_open, ++ .proc_read = seq_read, ++ .proc_lseek = seq_lseek, ++ .proc_write = mac_tbl_write, ++ .proc_release = single_release ++}; ++ ++static const struct proc_ops reg_fops = { ++ .proc_open = reg_open, ++ .proc_read = seq_read, ++ .proc_lseek = seq_lseek, ++ .proc_write = reg_ops, ++ .proc_release = single_release ++}; ++ ++static const struct proc_ops phyreg_fops = { ++ .proc_open = phyreg_open, ++ .proc_read = seq_read, ++ .proc_lseek = seq_lseek, ++ .proc_write = phyreg_ops, ++ .proc_release = single_release ++}; ++ ++static const struct proc_ops mirror_fops = { ++ .proc_open = mirror_open, ++ .proc_read = seq_read, ++ .proc_lseek = seq_lseek, ++ .proc_write = mirror_ops, ++ .proc_release = single_release ++}; ++ ++static const struct proc_ops igmp_fops = { ++ .proc_open = igmp_open, ++ .proc_read = seq_read, ++ .proc_lseek = seq_lseek, ++ .proc_write = igmp_ops, ++ .proc_release = single_release ++}; ++ ++int gsw_debug_proc_init(void) ++{ ++ ++ if (!proc_reg_dir) ++ proc_reg_dir = proc_mkdir(PROCREG_DIR, NULL); ++ ++ proc_esw_cnt = ++ proc_create(PROCREG_ESW_CNT, 0, proc_reg_dir, &switch_count_fops); ++ ++ if (!proc_esw_cnt) ++ pr_err("!! FAIL to create %s PROC !!\n", PROCREG_ESW_CNT); ++ ++ proc_vlan_cnt = ++ proc_create(PROCREG_VLAN, 0, proc_reg_dir, &switch_vlan_fops); ++ ++ if (!proc_vlan_cnt) ++ pr_err("!! FAIL to create %s PROC !!\n", PROCREG_VLAN); ++ ++ proc_mac_tbl = ++ proc_create(PROCREG_MAC_TBL, 0, proc_reg_dir, &mac_tbl_fops); ++ ++ if (!proc_mac_tbl) ++ pr_err("!! FAIL to create %s PROC !!\n", PROCREG_MAC_TBL); ++ ++ proc_reg = ++ proc_create(PROCREG_REG, 0, proc_reg_dir, ®_fops); ++ ++ if (!proc_reg) ++ pr_err("!! FAIL to create %s PROC !!\n", PROCREG_REG); ++ ++ proc_phyreg = ++ proc_create(PROCREG_PHYREG, 0, proc_reg_dir, &phyreg_fops); ++ ++ if (!proc_phyreg) ++ pr_err("!! FAIL to create %s PROC !!\n", PROCREG_PHYREG); ++ ++ proc_mirror = ++ proc_create(PROCREG_MIRROR, 0, proc_reg_dir, &mirror_fops); ++ ++ if (!proc_mirror) ++ pr_err("!! FAIL to create %s PROC !!\n", PROCREG_MIRROR); ++ ++ proc_igmp = ++ proc_create(PROCREG_IGMP, 0, proc_reg_dir, &igmp_fops); ++ ++ if (!proc_igmp) ++ pr_err("!! FAIL to create %s PROC !!\n", PROCREG_IGMP); ++ ++ return 0; ++} ++ ++void gsw_debug_proc_exit(void) ++{ ++ if (proc_esw_cnt) ++ remove_proc_entry(PROCREG_ESW_CNT, proc_reg_dir); ++} ++ ++ +diff --git a/drivers/net/phy/rtk/rtl8367s_mdio.c b/drivers/net/phy/rtk/rtl8367s_mdio.c +new file mode 100644 +index 000000000000..2f9dc0da6bc1 +--- /dev/null ++++ b/drivers/net/phy/rtk/rtl8367s_mdio.c +@@ -0,0 +1,301 @@ ++/* ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version 2 ++ * of the License, or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#include "./rtl8367c/include/rtk_switch.h" ++#include "./rtl8367c/include/port.h" ++#include "./rtl8367c/include/vlan.h" ++#include "./rtl8367c/include/rtl8367c_asicdrv_port.h" ++#include "./rtl8367c/include/rtl8367c_asicdrv_mii_mgr.h" ++ ++struct rtk_gsw { ++ struct device *dev; ++ struct mii_bus *bus; ++ int reset_pin; ++}; ++ ++static struct rtk_gsw *_gsw; ++ ++/*mii_mgr_read/mii_mgr_write is the callback API for rtl8367 driver*/ ++unsigned int mii_mgr_read(unsigned int phy_addr,unsigned int phy_register,unsigned int *read_data) ++{ ++ struct mii_bus *bus = _gsw->bus; ++ ++ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); ++ ++ *read_data = bus->read(bus, phy_addr, phy_register); ++ ++ mutex_unlock(&bus->mdio_lock); ++ ++ return 0; ++} ++ ++unsigned int mii_mgr_write(unsigned int phy_addr,unsigned int phy_register,unsigned int write_data) ++{ ++ struct mii_bus *bus = _gsw->bus; ++ ++ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); ++ ++ bus->write(bus, phy_addr, phy_register, write_data); ++ ++ mutex_unlock(&bus->mdio_lock); ++ ++ return 0; ++} ++ ++static int rtl8367s_hw_reset(void) ++{ ++ struct rtk_gsw *gsw = _gsw; ++ ++ if (gsw->reset_pin < 0) ++ return 0; ++ ++ gpio_direction_output(gsw->reset_pin, 0); ++ ++ usleep_range(1000, 1100); ++ ++ gpio_set_value(gsw->reset_pin, 1); ++ ++ mdelay(500); ++ ++ return 0; ++} ++ ++static int rtl8367s_vlan_config(int want_at_p0) ++{ ++ rtk_vlan_cfg_t vlan1, vlan2; ++ ++ /* Set LAN/WAN VLAN partition */ ++ memset(&vlan1, 0x00, sizeof(rtk_vlan_cfg_t)); ++ ++ RTK_PORTMASK_PORT_SET(vlan1.mbr, EXT_PORT0); ++ RTK_PORTMASK_PORT_SET(vlan1.mbr, UTP_PORT1); ++ RTK_PORTMASK_PORT_SET(vlan1.mbr, UTP_PORT2); ++ RTK_PORTMASK_PORT_SET(vlan1.mbr, UTP_PORT3); ++ RTK_PORTMASK_PORT_SET(vlan1.untag, EXT_PORT0); ++ RTK_PORTMASK_PORT_SET(vlan1.untag, UTP_PORT1); ++ RTK_PORTMASK_PORT_SET(vlan1.untag, UTP_PORT2); ++ RTK_PORTMASK_PORT_SET(vlan1.untag, UTP_PORT3); ++ ++ if (want_at_p0) { ++ RTK_PORTMASK_PORT_SET(vlan1.mbr, UTP_PORT4); ++ RTK_PORTMASK_PORT_SET(vlan1.untag, UTP_PORT4); ++ } else { ++ RTK_PORTMASK_PORT_SET(vlan1.mbr, UTP_PORT0); ++ RTK_PORTMASK_PORT_SET(vlan1.untag, UTP_PORT0); ++ } ++ ++ vlan1.ivl_en = 1; ++ ++ rtk_vlan_set(1, &vlan1); ++ ++ memset(&vlan2, 0x00, sizeof(rtk_vlan_cfg_t)); ++ ++ RTK_PORTMASK_PORT_SET(vlan2.mbr, EXT_PORT1); ++ RTK_PORTMASK_PORT_SET(vlan2.untag, EXT_PORT1); ++ ++ if (want_at_p0) { ++ RTK_PORTMASK_PORT_SET(vlan2.mbr, UTP_PORT0); ++ RTK_PORTMASK_PORT_SET(vlan2.untag, UTP_PORT0); ++ } else { ++ RTK_PORTMASK_PORT_SET(vlan2.mbr, UTP_PORT4); ++ RTK_PORTMASK_PORT_SET(vlan2.untag, UTP_PORT4); ++ } ++ ++ vlan2.ivl_en = 1; ++ rtk_vlan_set(2, &vlan2); ++ ++ rtk_vlan_portPvid_set(EXT_PORT0, 1, 0); ++ rtk_vlan_portPvid_set(UTP_PORT1, 1, 0); ++ rtk_vlan_portPvid_set(UTP_PORT2, 1, 0); ++ rtk_vlan_portPvid_set(UTP_PORT3, 1, 0); ++ rtk_vlan_portPvid_set(EXT_PORT1, 2, 0); ++ ++ if (want_at_p0) { ++ rtk_vlan_portPvid_set(UTP_PORT0, 2, 0); ++ rtk_vlan_portPvid_set(UTP_PORT4, 1, 0); ++ } else { ++ rtk_vlan_portPvid_set(UTP_PORT0, 1, 0); ++ rtk_vlan_portPvid_set(UTP_PORT4, 2, 0); ++ } ++ ++ return 0; ++} ++ ++static int rtl8367s_hw_init(void) ++{ ++ ++ rtl8367s_hw_reset(); ++ ++ if(rtk_switch_init()) ++ return -1; ++ ++ mdelay(500); ++ ++ if (rtk_vlan_reset()) ++ return -1; ++ ++ if (rtk_vlan_init()) ++ return -1; ++ ++ return 0; ++} ++ ++static void set_rtl8367s_sgmii(void) ++{ ++ rtk_port_mac_ability_t mac_cfg; ++ rtk_mode_ext_t mode; ++ ++ mode = MODE_EXT_HSGMII; ++ mac_cfg.forcemode = MAC_FORCE; ++ mac_cfg.speed = PORT_SPEED_2500M; ++ mac_cfg.duplex = PORT_FULL_DUPLEX; ++ mac_cfg.link = PORT_LINKUP; ++ mac_cfg.nway = DISABLED; ++ mac_cfg.txpause = ENABLED; ++ mac_cfg.rxpause = ENABLED; ++ rtk_port_macForceLinkExt_set(EXT_PORT0, mode, &mac_cfg); ++ rtk_port_sgmiiNway_set(EXT_PORT0, DISABLED); ++ rtk_port_phyEnableAll_set(ENABLED); ++ ++} ++ ++static void set_rtl8367s_rgmii(void) ++{ ++ rtk_port_mac_ability_t mac_cfg; ++ rtk_mode_ext_t mode; ++ ++ mode = MODE_EXT_RGMII; ++ mac_cfg.forcemode = MAC_FORCE; ++ mac_cfg.speed = PORT_SPEED_1000M; ++ mac_cfg.duplex = PORT_FULL_DUPLEX; ++ mac_cfg.link = PORT_LINKUP; ++ mac_cfg.nway = DISABLED; ++ mac_cfg.txpause = ENABLED; ++ mac_cfg.rxpause = ENABLED; ++ rtk_port_macForceLinkExt_set(EXT_PORT1, mode, &mac_cfg); ++ rtk_port_rgmiiDelayExt_set(EXT_PORT1, 1, 3); ++ rtk_port_phyEnableAll_set(ENABLED); ++ ++} ++ ++static void init_gsw(void) ++{ ++ rtl8367s_hw_init(); ++ set_rtl8367s_sgmii(); ++ set_rtl8367s_rgmii(); ++} ++ ++// below are platform driver ++static const struct of_device_id rtk_gsw_match[] = { ++ { .compatible = "mediatek,rtk-gsw" }, ++ {}, ++}; ++ ++MODULE_DEVICE_TABLE(of, rtk_gsw_match); ++ ++static int rtk_gsw_probe(struct platform_device *pdev) ++{ ++ struct device_node *np = pdev->dev.of_node; ++ struct device_node *mdio; ++ struct mii_bus *mdio_bus; ++ struct rtk_gsw *gsw; ++ const char *pm; ++ int ret; ++ ++ mdio = of_parse_phandle(np, "mediatek,mdio", 0); ++ ++ if (!mdio) ++ return -EINVAL; ++ ++ mdio_bus = of_mdio_find_bus(mdio); ++ ++ if (!mdio_bus) ++ return -EPROBE_DEFER; ++ ++ gsw = devm_kzalloc(&pdev->dev, sizeof(struct rtk_gsw), GFP_KERNEL); ++ ++ if (!gsw) ++ return -ENOMEM; ++ ++ gsw->dev = &pdev->dev; ++ ++ gsw->bus = mdio_bus; ++ ++ gsw->reset_pin = of_get_named_gpio(np, "mediatek,reset-pin", 0); ++ if (gsw->reset_pin >= 0) { ++ ret = devm_gpio_request(gsw->dev, gsw->reset_pin, "mediatek,reset-pin"); ++ if (ret) ++ printk("fail to devm_gpio_request\n"); ++ } ++ ++ _gsw = gsw; ++ ++ init_gsw(); ++ ++ //init default vlan or init swconfig ++ if(!of_property_read_string(pdev->dev.of_node, ++ "mediatek,port_map", &pm)) { ++ ++ if (!strcasecmp(pm, "wllll")) ++ rtl8367s_vlan_config(1); ++ else ++ rtl8367s_vlan_config(0); ++ ++ } else { ++#ifdef CONFIG_SWCONFIG ++ rtl8367s_swconfig_init(&init_gsw); ++#else ++ rtl8367s_vlan_config(0); ++#endif ++ } ++ ++ gsw_debug_proc_init(); ++ ++ platform_set_drvdata(pdev, gsw); ++ ++ return 0; ++ ++} ++ ++static void rtk_gsw_remove(struct platform_device *pdev) ++{ ++ platform_set_drvdata(pdev, NULL); ++ gsw_debug_proc_exit(); ++} ++ ++static struct platform_driver gsw_driver = { ++ .probe = rtk_gsw_probe, ++ .remove_new = rtk_gsw_remove, ++ .driver = { ++ .name = "rtk-gsw", ++ .of_match_table = rtk_gsw_match, ++ }, ++}; ++ ++module_platform_driver(gsw_driver); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Mark Lee "); ++MODULE_DESCRIPTION("rtl8367c switch driver for MT7622"); ++ +diff --git a/drivers/net/phy/rtl8261n/Kconfig b/drivers/net/phy/rtl8261n/Kconfig +new file mode 100644 +index 000000000000..cdb5cb74882a +--- /dev/null ++++ b/drivers/net/phy/rtl8261n/Kconfig +@@ -0,0 +1,5 @@ ++ ++config RTL8261N_PHY ++ tristate "Driver for Realtek RTL8261N PHYs" ++ help ++ Currently supports the RTL8261N,RTL8264B PHYs. +diff --git a/drivers/net/phy/rtl8261n/Makefile b/drivers/net/phy/rtl8261n/Makefile +new file mode 100644 +index 000000000000..fd4afb43b509 +--- /dev/null ++++ b/drivers/net/phy/rtl8261n/Makefile +@@ -0,0 +1,11 @@ ++ ++obj-$(CONFIG_RTL8261N_PHY) += rtl8261n.o ++ ++rtl8261n-objs += phy_patch.o ++rtl8261n-objs += phy_rtl826xb_patch.o ++rtl8261n-objs += rtk_osal.o ++rtl8261n-objs += rtk_phy.o ++rtl8261n-objs += rtk_phylib.o ++rtl8261n-objs += rtk_phylib_rtl826xb.o ++ ++ccflags-y += -Werror -DRTK_PHYDRV_IN_LINUX +diff --git a/drivers/net/phy/rtl8261n/construct/conf_rtl8261n_c.c b/drivers/net/phy/rtl8261n/construct/conf_rtl8261n_c.c +new file mode 100644 +index 000000000000..8e7c714fc401 +--- /dev/null ++++ b/drivers/net/phy/rtl8261n/construct/conf_rtl8261n_c.c +@@ -0,0 +1,1465 @@ ++/* ++ * SPDX-License-Identifier: GPL-2.0-only ++ * ++ * Copyright (c) 2023 Realtek Semiconductor Corp. All rights reserved. ++ */ ++ ++//Date: Tue Nov 15 19:53:03 2022 ++ ++rtk_hwpatch_t rtl8261n_c_top_conf[] = { ++ {RTK_PATCH_OP_TOP , 0xf , 2 , 20 , 15, 0 , 0x5 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_TOP , 0xf , 2 , 21 , 15, 0 , 0x0 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_TOP , 0xf , 2 , 22 , 15, 0 , 0x280 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_TOP , 0xf , 2 , 23 , 15, 0 , 0x0014, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_TOP , 0xf , 3 , 16 , 15, 0 , 0x0300, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_TOP , 0xf , 3 , 17 , 15, 0 , 0x01ff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_TOP , 0xf , 3 , 18 , 15, 0 , 0x000c, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_TOP , 0xf , 3 , 19 , 15, 0 , 0x01ff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_TOP , 0xf , 3 , 20 , 15, 0 , 0x0200, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_TOP , 0xf , 3 , 21 , 15, 0 , 0x0015, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_TOP , 0xf , 3 , 22 , 15, 0 , 0x0200, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_TOP , 0xf , 3 , 23 , 15, 0 , 0x0 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_TOP , 0xf , 4 , 16 , 15, 0 , 0x0 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_TOP , 0xf , 13 , 23 , 8 , 5 , 0x6 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_TOP , 0xf , 90 , 18 , 15, 0 , 0x5 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_TOP , 0xf , 90 , 19 , 15, 0 , 0x5 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_TOP , 0xf , 90 , 20 , 15, 8 , 0x01 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++}; ++ ++rtk_hwpatch_t rtl8261n_c_sds_conf[] = { ++ {RTK_PATCH_OP_TOP , 0xf , 24 , 18 , 15, 0 , 0x881F, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_TOP , 0xf , 24 , 19 , 15, 0 , 0x003F, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_TOP , 0xf , 24 , 20 , 15, 0 , 0x003F, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_TOP , 0xf , 24 , 21 , 15, 0 , 0x003F, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_TOP , 0xf , 24 , 22 , 15, 0 , 0x001F, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x06 , 0x0D , 15, 0 , 0x0F00, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x06 , 0x0E , 15, 0 , 0x3F5A, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x07 , 0x10 , 15, 12, 0x8 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x07 , 0x10 , 7 , 0 , 0x3 , RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x06 , 0x1D , 15, 0 , 0x0600, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x21 , 0x00 , 15, 0 , 0x4902, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x21 , 0x08 , 15, 0 , 0x0FC0, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x21 , 0x09 , 15, 0 , 0x33F0, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x21 , 0x0C , 15, 0 , 0x08BF, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x21 , 0x12 , 15, 0 , 0x8000, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x36 , 0x07 , 15, 0 , 0x04C0, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x36 , 0x08 , 15, 0 , 0x2000, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x2E , 0x0B , 15, 0 , 0x2390, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x2E , 0x0C , 15, 0 , 0xAA17, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x2E , 0x0D , 15, 0 , 0xFE40, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x2E , 0x0E , 15, 0 , 0x12F4, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x2E , 0x11 , 15, 0 , 0xF2AD, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x2E , 0x15 , 15, 0 , 0x7A41, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x2E , 0x16 , 15, 0 , 0x0041, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x2F , 0x00 , 15, 0 , 0x1F00, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x2F , 0x01 , 15, 0 , 0x2800, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x2F , 0x02 , 15, 0 , 0x0FC8, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x2F , 0x11 , 15, 0 , 0x3000, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x2F , 0x13 , 15, 0 , 0xF400, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x2F , 0x1E , 15, 0 , 0x0500, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x34 , 0x0B , 15, 0 , 0x2390, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x34 , 0x0C , 15, 0 , 0xA517, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x34 , 0x0D , 15, 0 , 0xFE41, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x34 , 0x0E , 15, 0 , 0x12F4, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x34 , 0x11 , 15, 0 , 0xF2AD, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x34 , 0x15 , 15, 0 , 0x7A41, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x34 , 0x16 , 15, 0 , 0x0041, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x35 , 0x00 , 15, 0 , 0x1F80, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x35 , 0x01 , 15, 0 , 0x0800, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x35 , 0x02 , 15, 0 , 0x0FC8, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x35 , 0x11 , 15, 0 , 0x3001, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x35 , 0x13 , 15, 0 , 0xF400, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x35 , 0x1E , 15, 0 , 0x0100, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x2C , 0x0B , 15, 0 , 0x2390, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x2C , 0x0C , 15, 0 , 0xA517, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x2C , 0x0D , 15, 0 , 0xFE41, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x2C , 0x0E , 15, 0 , 0x12F4, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x2C , 0x11 , 15, 0 , 0xF2AD, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x2C , 0x15 , 15, 0 , 0x7A61, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x2C , 0x16 , 15, 0 , 0x0041, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x2D , 0x00 , 15, 0 , 0x1F80, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x2D , 0x01 , 15, 0 , 0x0800, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x2D , 0x02 , 15, 0 , 0x0FC8, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x2D , 0x11 , 15, 0 , 0x3001, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x2D , 0x13 , 15, 0 , 0xF400, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x2D , 0x1E , 15, 0 , 0x0100, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x28 , 0x0B , 15, 0 , 0x2390, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x28 , 0x0C , 15, 0 , 0xA514, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x28 , 0x0D , 15, 0 , 0xFE43, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x28 , 0x0E , 15, 0 , 0x12F4, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x28 , 0x11 , 15, 0 , 0xF2AD, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x28 , 0x15 , 15, 0 , 0x7A61, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x28 , 0x16 , 15, 0 , 0x0041, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x29 , 0x00 , 15, 0 , 0x1F80, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x29 , 0x01 , 15, 0 , 0x0800, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x29 , 0x02 , 15, 0 , 0x0FC8, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x29 , 0x11 , 15, 0 , 0x3001, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x29 , 0x13 , 15, 0 , 0xF400, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x29 , 0x1E , 15, 0 , 0x0100, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x26 , 0x0B , 15, 0 , 0x2390, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x26 , 0x0C , 15, 0 , 0xA514, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x26 , 0x0D , 15, 0 , 0xFE43, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x26 , 0x0E , 15, 0 , 0x12F4, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x26 , 0x11 , 15, 0 , 0xF2AD, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x26 , 0x15 , 15, 0 , 0x7A41, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x26 , 0x16 , 15, 0 , 0x0041, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x27 , 0x00 , 15, 0 , 0x1F80, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x27 , 0x01 , 15, 0 , 0x0800, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x27 , 0x02 , 15, 0 , 0x0FC8, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x27 , 0x11 , 15, 0 , 0x3001, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x27 , 0x13 , 15, 0 , 0xF400, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x27 , 0x1E , 15, 0 , 0x0100, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x24 , 0x0B , 15, 0 , 0x2390, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x24 , 0x0C , 15, 0 , 0xA514, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x24 , 0x0D , 15, 0 , 0xFE43, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x24 , 0x0E , 15, 0 , 0x12F4, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x24 , 0x11 , 15, 0 , 0xF2AD, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x24 , 0x15 , 15, 0 , 0x7A41, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x24 , 0x16 , 15, 0 , 0x0041, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x25 , 0x00 , 15, 0 , 0x1F80, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x25 , 0x01 , 15, 0 , 0x0800, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x25 , 0x02 , 15, 0 , 0x0FC8, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x25 , 0x11 , 15, 0 , 0x3001, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x25 , 0x13 , 15, 0 , 0xF400, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x25 , 0x1E , 15, 0 , 0x0100, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_TOP , 0xf , 24 , 18 , 15, 0 , 0x880D, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_TOP , 0xf , 24 , 19 , 15, 0 , 0x0024, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_TOP , 0xf , 24 , 20 , 15, 0 , 0x0036, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_TOP , 0xf , 24 , 21 , 15, 0 , 0x0035, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_TOP , 0xf , 24 , 22 , 15, 0 , 0x001A, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x1F , 0x00 , 15, 0 , 0x001B, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x1F , 0x00 , 15, 0 , 0x0000, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_TOP , 0xf , 90 , 20 , 7 , 0 , 0x01 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++}; ++ ++rtk_hwpatch_t rtl8261n_c_afe_conf[] = { ++}; ++ ++rtk_hwpatch_t rtl8261n_c_uc_conf[] = { ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb820, 7 , 7 , 0x0 , RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xbd8a, 5 , 3 , 0x3 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xbd8c, 6 , 4 , 0x5 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x8060, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 12, 10, 0x3 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x8061, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 13, 0x5 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa466, 1 , 1 , 0x1 , RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x8491, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0x3D , RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++}; ++ ++rtk_hwpatch_t rtl8261n_c_uc2_conf[] = { ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb820, 7 , 7 , 0x1 , RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb87c, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8af6, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb87e, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xaf8b, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8af6}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0eaf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8af8}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8b41, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8afa}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xaf8b, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8afc}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4faf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8afe}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8b5b, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b00}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xaf8b, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b02}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xb4af, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b04}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8bc0, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b06}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xaf8b, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b08}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xdaaf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b0a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8bda, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b0c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf8ef, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b0e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x49f8, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b10}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf70, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b12}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3f02, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b14}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6772, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b16}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xad28, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b18}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13e1, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b1a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8a55, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b1c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xad28, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b1e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0502, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b20}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5ee2, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b22}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xae0e, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b24}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x025d, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b26}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8f02, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b28}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8bda, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b2a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xae06, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b2c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x025d, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b2e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x7002, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b30}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8c22, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b32}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xe087, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b34}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1ef6, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b36}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x27e4, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b38}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x871e, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b3a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xfcef, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b3c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x94fc, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b3e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x04a1, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b40}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0103, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b42}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x028b, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b44}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xfee0, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b46}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8a09, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b48}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xef23, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b4a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xaf5e, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b4c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5bac, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b4e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5003, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b50}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xaf62, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b52}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8a02, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b54}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8c22, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b56}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xaf62, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b58}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xb0bf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b5a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x68e0, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b5c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0267, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b5e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x72ef, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b60}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x31bf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b62}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x68dd, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b64}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0267, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b66}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x721e, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b68}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x31ac, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b6a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3819, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b6c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf68, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b6e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xe902, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b70}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6772, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b72}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xef31, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b74}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf68, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b76}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xe602, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b78}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6772, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b7a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1e31, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b7c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xac38, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b7e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0cee, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b80}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8933, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b82}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x02ae, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b84}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0aee, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b86}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8933, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b88}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x00ae, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b8a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x04ee, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b8c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8933, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b8e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x01bf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b90}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8ff9, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b92}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xe189, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b94}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x331a, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b96}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x91db, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b98}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf69, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b9a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4c02, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b9c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6772, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b9e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1f00, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ba0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1f22, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ba2}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1b45, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ba4}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xad27, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ba6}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x05e1, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ba8}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x870d, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8baa}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xae03, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bac}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xe187, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bae}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0eaf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bb0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x2d1a, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bb2}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0248, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bb4}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf702, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bb6}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8c46, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bb8}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0222, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bba}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4faf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bbc}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4176, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bbe}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf8c, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bc0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9002, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bc2}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x70eb, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bc4}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf8c, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bc6}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9f02, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bc8}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x70eb, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bca}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf8c, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bcc}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa502, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bce}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x70eb, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bd0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd300, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bd2}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0241, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bd4}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x7caf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bd6}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x46b2, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bd8}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf8ef, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bda}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x49f8, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bdc}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bde}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3a02, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8be0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6772, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8be2}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xac28, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8be4}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x12bf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8be6}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6d63, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8be8}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0267, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bea}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x72e5, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bec}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8ffc, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bee}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6d, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bf0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6f02, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bf2}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6772, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bf4}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xe58f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bf6}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xfdfc, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bf8}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xef94, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bfa}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xfc04, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bfc}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf8ef, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bfe}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x49f8, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c00}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c02}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3a02, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c04}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6772, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c06}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xac28, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c08}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x12e1, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c0a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8ffe, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c0c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6d, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c0e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6302, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c10}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6753, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c12}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xe18f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c14}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xffbf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c16}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6d6f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c18}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0267, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c1a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x53fc, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c1c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xef94, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c1e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xfc04, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c20}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf8ef, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c22}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x49f8, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c24}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c26}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3a02, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c28}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6772, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c2a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xac28, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c2c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x12e1, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c2e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8ffc, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c30}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6d, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c32}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6302, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c34}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6753, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c36}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xe18f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c38}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xfdbf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c3a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6d6f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c3c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0267, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c3e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x53fc, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c40}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xef94, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c42}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xfc04, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c44}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf8fa, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c46}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xef69, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c48}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c4a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3a02, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c4c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6772, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c4e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xad28, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c50}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0ebf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c52}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8c93, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c54}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0270, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c56}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf4bf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c58}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8c90, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c5a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0270, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c5c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf4ae, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c5e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x2ad1, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c60}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0fbf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c62}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8c96, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c64}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0267, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c66}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x53bf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c68}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8c99, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c6a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0270, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c6c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xebd1, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c6e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x00bf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c70}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8c9c, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c72}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0267, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c74}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x53bf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c76}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8c9f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c78}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0270, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c7a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf4d1, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c7c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x00bf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c7e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8ca2, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c80}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0267, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c82}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x53bf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c84}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8ca5, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c86}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0270, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c88}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf4ef, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c8a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x96fe, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c8c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xfc04, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c8e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x77bd, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c90}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6c66, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c92}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbd6c, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c94}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x30bd, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c96}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5444, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c98}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbd54, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c9a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x85bd, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c9c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5e55, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c9e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbd54, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ca0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa7bd, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ca2}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5cbb, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ca4}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbd5c, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ca6}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb85e, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x62ba, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb860, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5e56, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb862, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6287, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb864, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x2d07, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb886, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4170, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb888, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x46ad, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb88a, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xffff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb88c, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xffff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb838, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x003f, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb820, 7 , 7 , 0x0 , RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++}; ++ ++rtk_hwpatch_t rtl8261n_c_nctl0_conf[] = { ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb820, 7 , 7 , 0x1 , RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA016, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0000, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA012, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0000, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA014, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8010, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x801a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x4}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x801a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x6}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x801a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x8}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x801a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xa}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x801a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xb}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xc}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x801a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xd}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xe}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x801a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xf}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd719, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x10}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3bb7, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x11}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8014, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x12}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf003, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x13}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd704, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x14}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x406e, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x15}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x16}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x12db, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x17}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x18}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1301, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x19}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA026, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xffff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA024, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xffff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA022, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xffff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA020, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xffff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA006, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xffff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA004, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xffff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA002, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xffff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA000, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x12d7, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA008, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0100, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb820, 7 , 7 , 0x0 , RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++}; ++ ++rtk_hwpatch_t rtl8261n_c_nctl1_conf[] = { ++}; ++ ++rtk_hwpatch_t rtl8261n_c_nctl2_conf[] = { ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb820, 7 , 7 , 0x1 , RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA016, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0020, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA012, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0000, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA014, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8010, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8029, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x4}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8217, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x6}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x82d0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x8}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x82f9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xa}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8322, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xb}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xc}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8322, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xd}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xe}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8322, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xf}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x10}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x11}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xcb0a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x12}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0cc7, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x13}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x14}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x15}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x16}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4127, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x17}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x18}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x19}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c0f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b05, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c38, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0d28, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf008, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x20}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x21}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c0f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x22}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b0a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x23}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c38, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x24}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0d18, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x25}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x26}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x27}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0f73, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x28}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x29}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x37c9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8034, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x33a9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8031, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd1bf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd06d, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf006, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x30}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd1dd, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x31}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd06d, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x32}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf003, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x33}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd199, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x34}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd06e, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x35}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x36}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1418, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x37}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x38}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5fba, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x39}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x3a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd05a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x3b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x3c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x60cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x3d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x60f1, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x3e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6113, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x3f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6135, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x40}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6157, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x41}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x42}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x43}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x44}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x45}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf008, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x46}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x47}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf006, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x48}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x49}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf004, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x4a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x4b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf002, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x4c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x4d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x4e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x142d, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x4f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x50}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x51}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0ccf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x52}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b40, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x53}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c3f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x54}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c24, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x55}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x56}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa340, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x57}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x58}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x147c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x59}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa110, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x5a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x5b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1435, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x5c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8110, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x5d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x5e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1485, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x5f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa304, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x60}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa8c0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x61}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8810, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x62}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa00a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x63}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa120, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x64}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa310, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x65}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0cfc, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x66}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0224, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x67}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0ca0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x68}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0480, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x69}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x6a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x6b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa340, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x6c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x6d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd162, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x6e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd048, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x6f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x70}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1418, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x71}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x72}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5fba, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x73}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8840, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x74}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd1c4, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x75}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd045, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x76}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x77}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1418, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x78}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x79}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5fba, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x7a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd706, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x7b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6127, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x7c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x7d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f3b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x7e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x88c0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x7f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x800a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x80}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8120, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x81}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8350, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x82}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x84a0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x83}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xffb6, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x84}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xb920, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x85}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xcd33, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x86}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x87}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1418, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x88}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd71f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x89}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x7fb4, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x8a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9920, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x8b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x8c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1418, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x8d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd71f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x8e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6065, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x8f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f94, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x90}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xffee, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x91}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xb820, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x92}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x93}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1418, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x94}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd71f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x95}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x7fa5, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x96}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9820, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x97}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x800a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x98}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8120, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x99}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x9a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x147c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x9b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa108, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x9c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x9d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1435, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x9e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8108, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x9f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xa0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1485, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xa1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa2fc, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xa2}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa304, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xa3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8880, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xa4}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0cc0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xa5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0440, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xa6}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xcd34, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xa7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xa8}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xa9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0cc0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xaa}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b80, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xab}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xac3f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xac}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c38, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xad}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0d08, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xae}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xaf}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa810, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xb0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa00a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xb1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa120, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xb2}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa480, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xb3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa604, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xb4}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xb5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x37c9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xb6}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x80bb, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xb7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xb8}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd049, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xb9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf003, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xba}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd19f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xbb}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd049, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xbc}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xbd}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1418, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xbe}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd71f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xbf}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x63f4, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xc0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xc1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f7a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xc2}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd706, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xc3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4368, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xc4}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xc5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xc6}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0cc0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xc7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b40, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xc8}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8c3f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xc9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8d38, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xca}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xcb}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xcc}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x37c9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xcd}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x80d7, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xce}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x33a9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xcf}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x80d4, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xd0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd1f4, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xd1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xd2}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf006, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xd3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd1b7, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xd4}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xd5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf003, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xd6}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd1c6, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xd7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xd8}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xd9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1418, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xda}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd71f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xdb}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6074, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xdc}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xdd}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f7a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xde}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xdf}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1418, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xe0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd71f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xe1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4056, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xe2}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf004, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xe3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xe4}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x61fc, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xe5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xfff9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xe6}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd706, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xe7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6048, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xe8}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xe9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xea}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4070, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xeb}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xec}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x81a4, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xed}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xee}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xef}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xae80, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xf0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xf1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xf2}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x81a4, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xf3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xf4}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd05a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xf5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xf6}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x60cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xf7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x60f1, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xf8}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6113, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xf9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6135, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xfa}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6157, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xfb}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xfc}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xfd}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xfe}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xff}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf008, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x100}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x101}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf006, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x102}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x103}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf004, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x104}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x105}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf002, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x106}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x107}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x108}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x142d, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x109}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x10a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x10b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0ccf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x10c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b40, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x10d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c3f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x10e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c24, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x10f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x110}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa340, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x111}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x112}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x147c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x113}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa110, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x114}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x115}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1435, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x116}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8110, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x117}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x118}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1485, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x119}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa304, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x11a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa8c0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x11b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8810, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x11c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa00a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x11d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa120, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x11e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa310, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x11f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0cfc, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x120}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0224, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x121}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0ca0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x122}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0480, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x123}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8604, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x124}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xcd35, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x125}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd162, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x126}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd048, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x127}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x128}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1418, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x129}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x12a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5fba, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x12b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8840, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x12c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd1c4, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x12d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd045, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x12e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x12f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1418, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x130}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x131}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5fba, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x132}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd706, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x133}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6127, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x134}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x135}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f3b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x136}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x88c0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x137}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x800a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x138}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8120, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x139}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8350, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x13a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x84a0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x13b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xffb8, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x13c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbb80, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x13d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x13e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1418, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x13f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd71f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x140}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5fb4, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x141}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xb920, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x142}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xcd36, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x143}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x144}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1418, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x145}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd71f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x146}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x7fb4, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x147}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9920, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x148}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9b80, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x149}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x14a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1418, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x14b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd71f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x14c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6065, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x14d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f94, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x14e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xffe8, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x14f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xb820, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x150}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x151}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1418, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x152}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd71f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x153}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x7fa5, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x154}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9820, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x155}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x800a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x156}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8120, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x157}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x158}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x147c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x159}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa108, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x15a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x15b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1435, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x15c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8108, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x15d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x15e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1485, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x15f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa2fc, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x160}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa304, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x161}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8880, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x162}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0cc0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x163}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0440, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x164}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xcd37, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x165}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x166}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x167}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0cc0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x168}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b80, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x169}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xac3f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x16a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c38, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x16b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0d08, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x16c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x16d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa810, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x16e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa00a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x16f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa120, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x170}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa480, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x171}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa604, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x172}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x173}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x37c9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x174}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x817e, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x175}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x33a9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x176}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x817b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x177}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x178}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd048, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x179}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf006, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x17a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x17b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd048, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x17c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf003, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x17d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x17e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd048, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x17f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x180}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1418, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x181}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x182}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1463, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x183}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x184}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f7a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x185}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd706, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x186}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f28, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x187}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x188}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x189}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0cc0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x18a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b40, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x18b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8c3f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x18c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8d38, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x18d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x18e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x18f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x37c9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x190}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x819a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x191}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x33a9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x192}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8197, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x193}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd199, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x194}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x195}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf006, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x196}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x197}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x198}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf003, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x199}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd189, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x19a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x19b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x19c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1418, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x19d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x19e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1463, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x19f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1a0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f7a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1a1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd706, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1a2}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f28, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1a3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1a4}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1a5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c0f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1a6}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b05, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1a7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1a8}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1a9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x60cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1aa}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x60f1, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ab}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6113, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ac}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6135, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ad}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6157, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ae}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1af}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce08, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1b0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1b1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce08, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1b2}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf008, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1b3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce08, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1b4}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf006, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1b5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce08, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1b6}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf004, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1b7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce08, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1b8}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf002, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1b9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce08, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ba}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1bb}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x142d, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1bc}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa180, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1bd}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xcd38, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1be}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1bf}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x37c9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1c0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x81d4, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1c1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x33a9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1c2}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x81cc, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1c3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1c4}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1c5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1c6}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1c7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf013, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1c8}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd100, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1c9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd049, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ca}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf010, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1cb}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1cc}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1cd}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd1b7, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ce}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd049, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1cf}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1d0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd100, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1d1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd048, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1d2}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf008, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1d3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1d4}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1d5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1d6}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1d7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf003, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1d8}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd199, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1d9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1da}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd13b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1db}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd055, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1dc}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1dd}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1418, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1de}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1df}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1463, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1e0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1e1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f7b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1e2}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa302, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1e3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1e4}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1418, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1e5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1e6}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1463, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1e7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1e8}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f7a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1e9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd706, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ea}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f28, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1eb}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ec}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ed}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c3f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ee}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c12, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ef}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1f0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1f1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x37c9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1f2}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8206, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1f3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x33a9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1f4}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x81fe, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1f5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1f6}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1f7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd199, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1f8}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1f9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf013, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1fa}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd100, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1fb}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd048, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1fc}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf010, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1fd}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1fe}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ff}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x200}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x201}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x202}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd100, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x203}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd040, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x204}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf008, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x205}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x206}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x207}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd199, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x208}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x209}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf003, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x20a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd16b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x20b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x20c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x20d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1418, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x20e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x20f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1463, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x210}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x211}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f7a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x212}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd706, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x213}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f2a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x214}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x215}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x087a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x216}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x217}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x646d, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x218}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x37c9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x219}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8231, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x21a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x33a9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x21b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8227, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x21c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x21d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x40c7, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x21e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x21f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x220}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd100, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x221}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd049, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x222}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf01a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x223}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x224}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd049, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x225}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf017, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x226}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x227}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x40c7, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x228}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x229}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x22a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd100, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x22b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd049, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x22c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf010, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x22d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x22e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x22f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00d, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x230}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x231}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x40c7, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x232}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x233}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x234}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x235}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x236}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf006, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x237}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x238}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x239}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf003, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x23a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x23b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd048, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x23c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x23d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1418, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x23e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x23f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1463, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x240}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x241}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f7a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x242}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd706, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x243}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f29, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x244}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x245}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x60cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x246}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x60f1, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x247}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6113, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x248}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6135, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x249}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6157, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x24a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x24b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x24c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x24d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x24e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf008, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x24f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x250}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf006, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x251}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x252}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf004, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x253}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x254}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf002, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x255}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x256}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x257}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x142d, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x258}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x259}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x25a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8bc0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x25b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c3f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x25c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c09, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x25d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x25e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa120, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x25f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa310, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x260}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa420, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x261}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xcd3b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x262}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x263}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x65ad, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x264}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x43c7, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x265}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x266}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x37c9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x267}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x827b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x268}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x33a9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x269}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8273, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x26a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x26b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x26c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd199, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x26d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x26e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf024, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x26f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd15d, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x270}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x271}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf021, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x272}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x273}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x274}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd1c6, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x275}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x276}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf01c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x277}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd15d, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x278}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x279}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf019, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x27a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x27b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x27c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd199, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x27d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x27e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf014, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x27f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x280}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x281}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf011, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x282}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x283}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x37c9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x284}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x828e, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x285}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x33a9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x286}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x828b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x287}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd1e5, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x288}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x289}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf009, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x28a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd191, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x28b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04d, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x28c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf006, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x28d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x28e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04d, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x28f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf003, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x290}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd16b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x291}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x292}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x293}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1418, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x294}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x295}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1463, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x296}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x297}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f7a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x298}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd706, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x299}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f2c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x29a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x29b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x40e7, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x29c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x29d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x29e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c0f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x29f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b05, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2a0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2a1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf006, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2a2}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2a3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2a4}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c0f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2a5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b0a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2a6}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2a7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xcd3c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2a8}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2a9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x644d, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2aa}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x43c7, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2ab}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2ac}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x37c9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2ad}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x82c1, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2ae}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x33a9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2af}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x82b9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2b0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2b1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2b2}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2b3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2b4}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf019, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2b5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2b6}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd048, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2b7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf016, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2b8}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2b9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2ba}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2bb}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2bc}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf011, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2bd}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd13e, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2be}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd049, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2bf}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00e, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2c0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2c1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2c2}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2c3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2c4}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf009, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2c5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2c6}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd049, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2c7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf006, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2c8}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2c9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2ca}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf003, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2cb}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2cc}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd048, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2cd}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2ce}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0956, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2cf}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2d0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x2969, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2d1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x82f5, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2d2}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x37c9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2d3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x82eb, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2d4}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x33a9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2d5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x82e1, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2d6}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2d7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x40c7, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2d8}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2d9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2da}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd15c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2db}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2dc}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf01a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2dd}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd199, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2de}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2df}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf017, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2e0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2e1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x40c7, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2e2}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2e3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2e4}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd13e, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2e5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2e6}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf010, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2e7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd199, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2e8}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2e9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00d, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2ea}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2eb}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x40c7, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2ec}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2ed}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2ee}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2ef}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2f0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf006, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2f1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd199, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2f2}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2f3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf003, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2f4}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2f5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2f6}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2f7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x09a0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2f8}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2f9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x2969, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2fa}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x831e, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2fb}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x37c9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2fc}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8314, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2fd}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x33a9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2fe}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x830a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2ff}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x300}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x40c7, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x301}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x302}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x303}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd15d, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x304}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x305}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf01a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x306}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x307}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x308}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf017, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x309}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x30a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x40c7, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x30b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x30c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x30d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd16b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x30e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x30f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf010, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x310}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x311}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x312}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00d, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x313}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x314}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x40c7, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x315}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x316}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x317}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x318}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x319}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf006, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x31a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x31b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x31c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf003, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x31d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd1b7, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x31e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x31f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x320}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0a39, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x321}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA10E, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xffff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA10C, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xffff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA10A, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xffff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA108, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0a12, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA106, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0979, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA104, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x089f, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA102, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0692, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA100, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0f60, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA110, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x001f, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA016, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0020, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA012, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1ff8, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA014, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b0e, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ff8}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b0e, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ff9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b0e, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ffa}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ffb}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ffc}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ffd}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ffe}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1fff}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA164, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0baa, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA166, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c19, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA168, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1293, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA16A, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3fff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA16C, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3fff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA16E, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3fff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA170, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3fff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA172, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3fff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA162, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0007, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb820, 7 , 7 , 0x0 , RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++}; ++ ++rtk_hwpatch_t rtl8261n_c_algxg_conf[] = { ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8165, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x22 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8167, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x33 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x827E, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x68 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8013, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x39 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8ffb, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x14 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8ffa, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x1e , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8ff9, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x1e , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x82D9, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x20 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x82DA, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x00 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x816E, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0xab , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8159, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x58 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x815A, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x99 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8139, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x25 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8125, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x67 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8126, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x89 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x827D, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x42 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++}; ++ ++rtk_hwpatch_t rtl8261n_c_alg_giga_conf[] = { ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x8367, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0x5d , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++}; ++ ++rtk_hwpatch_t rtl8261n_c_normal_conf[] = { ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x817d, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0x07 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb516, 6 , 0 , 0x0 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8ffe, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x04 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8fff, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x05 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8132, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x77 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8134, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x88 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x80ca, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x77 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x80cc, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x88 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8062, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x77 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8064, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x88 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x801E, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0005, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++}; ++ ++rtk_hwpatch_t rtl8261n_c_dataram_conf[] = { ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb820, 7 , 7 , 0x0 , RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb896, 0 , 0 , 0x0 , RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb892, 15, 8 , 0x0 , RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC10B, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0xD5 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC10C, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0xD5 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC10D, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0xD5 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC10E, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0xD5 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC10F, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0xD5 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC110, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0xD5 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC149, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0x08 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC14A, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0x08 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC14B, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0x08 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC14C, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0x08 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC14D, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0x08 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC14E, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0x08 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC166, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0xEE , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC167, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0xEE , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC168, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0x07 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC169, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0x09 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC16A, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0x0B , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC16B, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0x0D , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC16C, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0x13 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC16D, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0x0E , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC16E, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0x11 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC16F, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0x14 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC170, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0x17 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC171, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0x15 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC172, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0x10 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC173, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0x0B , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC128, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0xF7 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC129, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0xF7 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC12A, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0xF8 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC12B, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0xF7 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC12C, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0xF6 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC12D, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0xF5 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC12E, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0xF2 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC12F, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0xF7 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC130, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0xF5 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC131, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0xF2 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC132, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0xF0 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC133, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0xF1 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC134, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0xF4 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC135, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0xF7 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb896, 0 , 0 , 0x1 , RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++}; ++ ++rtk_hwpatch_t rtl8261n_c_rtct_conf[] = { ++}; ++ +diff --git a/drivers/net/phy/rtl8261n/construct/conf_rtl8264b.c b/drivers/net/phy/rtl8261n/construct/conf_rtl8264b.c +new file mode 100644 +index 000000000000..d5cae3fd3bac +--- /dev/null ++++ b/drivers/net/phy/rtl8261n/construct/conf_rtl8264b.c +@@ -0,0 +1,2177 @@ ++/* ++ * SPDX-License-Identifier: GPL-2.0-only ++ * ++ * Copyright (c) 2023 Realtek Semiconductor Corp. All rights reserved. ++ */ ++ ++//Date: Thu Dec 15 16:01:01 2022 ++ ++rtk_hwpatch_t rtl8264b_top_conf[] = { ++ {RTK_PATCH_OP_TOP , 0xf , 2 , 20 , 15, 0 , 0x5 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_TOP , 0xf , 2 , 21 , 15, 0 , 0x0 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_TOP , 0xf , 2 , 22 , 15, 0 , 0x280 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_TOP , 0xf , 2 , 23 , 15, 0 , 0x0014, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_TOP , 0xf , 3 , 16 , 15, 0 , 0x0300, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_TOP , 0xf , 3 , 17 , 15, 0 , 0x01ff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_TOP , 0xf , 3 , 18 , 15, 0 , 0x000c, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_TOP , 0xf , 3 , 19 , 15, 0 , 0x01ff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_TOP , 0xf , 3 , 20 , 15, 0 , 0x0200, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_TOP , 0xf , 3 , 21 , 15, 0 , 0x0015, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_TOP , 0xf , 3 , 22 , 15, 0 , 0x0200, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_TOP , 0xf , 3 , 23 , 15, 0 , 0x0 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_TOP , 0xf , 4 , 16 , 15, 0 , 0x0 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_TOP , 0xf , 13 , 23 , 8 , 5 , 0x6 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_TOP , 0xf , 90 , 18 , 15, 0 , 0xc , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_TOP , 0xf , 90 , 19 , 15, 0 , 0xc , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_TOP , 0xf , 90 , 20 , 15, 8 , 0x01 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++}; ++ ++rtk_hwpatch_t rtl8264b_sds_conf[] = { ++ {RTK_PATCH_OP_TOP , 0xf , 24 , 18 , 15, 0 , 0x881F, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_TOP , 0xf , 24 , 19 , 15, 0 , 0x003F, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_TOP , 0xf , 24 , 20 , 15, 0 , 0x003F, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_TOP , 0xf , 24 , 21 , 15, 0 , 0x003F, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_TOP , 0xf , 24 , 22 , 15, 0 , 0x001F, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x06 , 0x0D , 15, 0 , 0x0F00, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x06 , 0x0E , 15, 0 , 0x3F5A, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x07 , 0x10 , 15, 12, 0x8 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x07 , 0x10 , 7 , 0 , 0x3 , RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x06 , 0x1D , 15, 0 , 0x0600, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x21 , 0x00 , 15, 0 , 0x4902, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x21 , 0x08 , 15, 0 , 0x0FC0, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x21 , 0x09 , 15, 0 , 0x33F0, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x21 , 0x0C , 15, 0 , 0x08BF, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x21 , 0x12 , 15, 0 , 0x8000, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x36 , 0x07 , 15, 0 , 0x04C0, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x36 , 0x08 , 15, 0 , 0x2000, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x2E , 0x0B , 15, 0 , 0x2390, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x2E , 0x0C , 15, 0 , 0xAA17, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x2E , 0x0D , 15, 0 , 0xFE40, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x2E , 0x0E , 15, 0 , 0x12F4, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x2E , 0x11 , 15, 0 , 0xF2AD, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x2E , 0x15 , 15, 0 , 0x7A41, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x2E , 0x16 , 15, 0 , 0x0041, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x2F , 0x00 , 15, 0 , 0x1F00, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x2F , 0x01 , 15, 0 , 0x2800, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x2F , 0x02 , 15, 0 , 0x0FC8, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x2F , 0x11 , 15, 0 , 0x3000, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x2F , 0x13 , 15, 0 , 0xF400, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x2F , 0x1E , 15, 0 , 0x0500, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x34 , 0x0B , 15, 0 , 0x2390, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x34 , 0x0C , 15, 0 , 0xA517, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x34 , 0x0D , 15, 0 , 0xFE41, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x34 , 0x0E , 15, 0 , 0x12F4, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x34 , 0x11 , 15, 0 , 0xF2AD, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x34 , 0x15 , 15, 0 , 0x7A41, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x34 , 0x16 , 15, 0 , 0x0041, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x35 , 0x00 , 15, 0 , 0x1F80, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x35 , 0x01 , 15, 0 , 0x0800, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x35 , 0x02 , 15, 0 , 0x0FC8, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x35 , 0x11 , 15, 0 , 0x3001, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x35 , 0x13 , 15, 0 , 0xF400, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x35 , 0x1E , 15, 0 , 0x0100, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x2C , 0x0B , 15, 0 , 0x2390, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x2C , 0x0C , 15, 0 , 0xA517, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x2C , 0x0D , 15, 0 , 0xFE41, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x2C , 0x0E , 15, 0 , 0x12F4, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x2C , 0x11 , 15, 0 , 0xF2AD, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x2C , 0x15 , 15, 0 , 0x7A61, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x2C , 0x16 , 15, 0 , 0x0041, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x2D , 0x00 , 15, 0 , 0x1F80, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x2D , 0x01 , 15, 0 , 0x0800, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x2D , 0x02 , 15, 0 , 0x0FC8, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x2D , 0x11 , 15, 0 , 0x3001, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x2D , 0x13 , 15, 0 , 0xF400, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x2D , 0x1E , 15, 0 , 0x0100, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x28 , 0x0B , 15, 0 , 0x2390, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x28 , 0x0C , 15, 0 , 0xA514, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x28 , 0x0D , 15, 0 , 0xFE43, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x28 , 0x0E , 15, 0 , 0x12F4, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x28 , 0x11 , 15, 0 , 0xF2AD, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x28 , 0x15 , 15, 0 , 0x7A61, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x28 , 0x16 , 15, 0 , 0x0041, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x29 , 0x00 , 15, 0 , 0x1F80, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x29 , 0x01 , 15, 0 , 0x0800, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x29 , 0x02 , 15, 0 , 0x0FC8, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x29 , 0x11 , 15, 0 , 0x3001, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x29 , 0x13 , 15, 0 , 0xF400, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x29 , 0x1E , 15, 0 , 0x0100, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x26 , 0x0B , 15, 0 , 0x2390, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x26 , 0x0C , 15, 0 , 0xA514, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x26 , 0x0D , 15, 0 , 0xFE43, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x26 , 0x0E , 15, 0 , 0x12F4, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x26 , 0x11 , 15, 0 , 0xF2AD, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x26 , 0x15 , 15, 0 , 0x7A41, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x26 , 0x16 , 15, 0 , 0x0041, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x27 , 0x00 , 15, 0 , 0x1F80, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x27 , 0x01 , 15, 0 , 0x0800, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x27 , 0x02 , 15, 0 , 0x0FC8, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x27 , 0x11 , 15, 0 , 0x3001, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x27 , 0x13 , 15, 0 , 0xF400, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x27 , 0x1E , 15, 0 , 0x0100, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x24 , 0x0B , 15, 0 , 0x2390, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x24 , 0x0C , 15, 0 , 0xA514, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x24 , 0x0D , 15, 0 , 0xFE43, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x24 , 0x0E , 15, 0 , 0x12F4, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x24 , 0x11 , 15, 0 , 0xF2AD, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x24 , 0x15 , 15, 0 , 0x7A41, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x24 , 0x16 , 15, 0 , 0x0041, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x25 , 0x00 , 15, 0 , 0x1F80, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x25 , 0x01 , 15, 0 , 0x0800, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x25 , 0x02 , 15, 0 , 0x0FC8, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x25 , 0x11 , 15, 0 , 0x3001, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x25 , 0x13 , 15, 0 , 0xF400, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x25 , 0x1E , 15, 0 , 0x0100, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_TOP , 0xf , 24 , 18 , 15, 0 , 0x880D, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_TOP , 0xf , 24 , 19 , 15, 0 , 0x0024, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_TOP , 0xf , 24 , 20 , 15, 0 , 0x0036, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_TOP , 0xf , 24 , 21 , 15, 0 , 0x0035, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_TOP , 0xf , 24 , 22 , 15, 0 , 0x001A, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x1F , 0x00 , 15, 0 , 0x001B, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xf , 0x1F , 0x00 , 15, 0 , 0x0000, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_TOP , 0xf , 90 , 20 , 7 , 0 , 0x03 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++}; ++ ++rtk_hwpatch_t rtl8264b_afe_conf[] = { ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xbf92, 15, 11, 0x1C , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xbfaa, 10, 8 , 0x5 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xbfae, 8 , 6 , 0x5 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xbfaa, 12, 11, 0x1 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xbf1c, 4 , 4 , 0x1 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xbf0e, 5 , 4 , 0x3 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xbf1c, 15, 13, 0x5 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xbf16, 12, 12, 0x0 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xbc24, 3 , 2 , 0x1 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xbc24, 1 , 0 , 0x1 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xbf08, 2 , 0 , 0x6 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xbf0c, 5 , 3 , 0x7 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xbf0c, 8 , 6 , 0x7 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xbf0c, 11, 9 , 0x7 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xbf0c, 14, 12, 0x7 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_TOP , 0xf , 90 , 21 , 15, 8 , 0x03 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++}; ++ ++rtk_hwpatch_t rtl8264b_uc_conf[] = { ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb820, 7 , 7 , 0x0 , RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xbd8a, 5 , 3 , 0x3 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xbd8c, 6 , 4 , 0x5 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x8060, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 12, 10, 0x3 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x8061, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 13, 0x5 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa466, 1 , 1 , 0x1 , RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x8491, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0x1D , RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x8018, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 12, 12, 0x1 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x85af, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xaf85, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85af}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xc7af, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85b1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x85df, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85b3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xaf86, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85b5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1baf, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85b7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8674, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85b9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xaf86, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85bb}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x7daf, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85bd}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x875b, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85bf}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xaf87, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85c1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x67af, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85c3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8774, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85c5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf85, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85c7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xdc02, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85c9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6957, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85cb}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xe48f, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85cd}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x2ce5, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85cf}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8f2d, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85d1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xe084, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85d3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x11e1, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85d5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8412, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85d7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xaf5d, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85d9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x73f6, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85db}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xb01a, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85dd}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xe08f, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85df}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x2ce1, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85e1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8f2d, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85e3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6d, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85e5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6802, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85e7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6938, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85e9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6d, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85eb}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6b02, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85ed}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6938, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85ef}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6d, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85f1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6e02, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85f3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6938, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85f5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6d, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85f7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x7102, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85f9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6938, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85fb}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6d, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85fd}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x7402, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85ff}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x70e5, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8601}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6d, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8603}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x7702, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8605}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x70e5, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8607}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6d, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8609}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x7a02, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x860b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x70e5, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x860d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6d, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x860f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x7d02, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8611}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x70e5, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8613}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd784, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8615}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa2af, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8617}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5eed, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8619}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0286, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x861b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x21af, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x861d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x07ad, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x861f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf8f9, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8621}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xfaef, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8623}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x69e0, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8625}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8018, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8627}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xad24, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8629}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x39d4, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x862b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x002e, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x862d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6e, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x862f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0402, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8631}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6938, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8633}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd480, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8635}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x03bf, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8637}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x866e, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8639}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0269, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x863b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x38d4, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x863d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x000f, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x863f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf86, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8641}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x7102, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8643}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6938, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8645}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf86, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8647}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x7102, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8649}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x70dc, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x864b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd480, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x864d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0bbf, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x864f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x866e, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8651}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0269, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8653}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x38d4, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8655}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x000f, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8657}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf86, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8659}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x7102, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x865b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6938, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x865d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf86, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x865f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x7102, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8661}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x70dc, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8663}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0208, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8665}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1eef, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8667}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x96fe, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8669}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xfdfc, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x866b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x04f0, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x866d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbd94, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x866f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x30bd, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8671}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9602, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8673}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8621, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8675}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0254, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8677}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xdcaf, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8679}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x03c1, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x867b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0286, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x867d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x2102, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x867f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8686, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8681}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xaf04, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8683}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x41f8, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8685}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xfbef, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8687}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x79e0, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8689}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8018, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x868b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xac20, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x868d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x03af, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x868f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8756, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8691}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6b, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8693}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3402, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8695}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x70dc, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8697}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6b, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8699}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3102, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x869b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x70e5, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x869d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6f, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x869f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4902, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86a1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x70dc, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86a3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6f, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86a5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4c02, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86a7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x70e5, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86a9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6f, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86ab}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4f02, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86ad}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x70e5, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86af}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6b, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86b1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3702, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86b3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x70dc, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86b5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6c, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86b7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c02, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86b9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x70dc, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86bb}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6b, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86bd}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3402, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86bf}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x70e5, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86c1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1f00, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86c3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xe183, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86c5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd4bf, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86c7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6bcd, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86c9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0269, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86cb}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x38bf, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86cd}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6bd0, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86cf}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0269, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86d1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x38bf, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86d3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6bd3, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86d5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0269, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86d7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x38bf, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86d9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6bd6, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86db}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0269, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86dd}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x38bf, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86df}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6bd9, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86e1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0270, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86e3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xe5bf, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86e5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6bdc, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86e7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0270, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86e9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xe5bf, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86eb}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6bdf, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86ed}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0270, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86ef}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xe5bf, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86f1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6be2, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86f3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0270, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86f5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xe5bf, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86f7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6f46, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86f9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0270, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86fb}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xdce1, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86fd}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x83d3, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86ff}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6f, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8701}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3a02, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8703}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6938, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8705}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0d14, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8707}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6f, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8709}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4002, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x870b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6938, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x870d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0d12, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x870f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6f, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8711}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3d02, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8713}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6938, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8715}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6f, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8717}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4302, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8719}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x70dc, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x871b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0238, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x871d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xb5bf, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x871f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6bd9, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8721}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0270, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8723}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xdcbf, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8725}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6bdc, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8727}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0270, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8729}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xdcbf, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x872b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6bdf, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x872d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0270, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x872f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xdcbf, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8731}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6be2, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8733}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0270, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8735}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xdcbf, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8737}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6b34, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8739}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0270, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x873b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xdcbf, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x873d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6b37, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x873f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0270, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8741}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xe5bf, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8743}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6f4f, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8745}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0270, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8747}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xdcbf, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8749}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6b31, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x874b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0270, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x874d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xdcbf, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x874f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6f4c, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8751}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0270, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8753}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xdcef, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8755}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x97ff, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8757}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xfc04, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8759}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xac2f, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x875b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x03af, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x875d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b2a, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x875f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x020e, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8761}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x95af, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8763}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b3f, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8765}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xee84, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8767}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3c00, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8769}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6c, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x876b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c02, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x876d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x70e5, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x876f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xaf01, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8771}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0300, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8773}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb818, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5d6d, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb81a, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5eea, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb81c, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x07aa, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb81e, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x03be, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb850, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x043e, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb852, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b26, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb878, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x00fd, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb884, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xffff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb832, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x007f, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++}; ++ ++rtk_hwpatch_t rtl8264b_uc2_conf[] = { ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb820, 7 , 7 , 0x1 , RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb87c, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8acf, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb87e, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xaf8a, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8acf}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xe7af, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ad1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8b40, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ad3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xaf8b, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ad5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4caf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ad7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8b6a, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ad9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xaf8b, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8adb}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xb5af, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8add}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8bd1, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8adf}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xaf8c, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ae1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x04af, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ae3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8c12, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ae5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf67, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ae7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6302, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ae9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x65f5, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8aeb}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xef31, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8aed}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf67, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8aef}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6002, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8af1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x65f5, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8af3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1e31, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8af5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xac38, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8af7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x19bf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8af9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x676c, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8afb}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0265, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8afd}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf5ef, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8aff}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x31bf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b01}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6769, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b03}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0265, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b05}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf51e, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b07}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x31ac, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b09}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x380c, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b0b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xee89, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b0d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x2c02, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b0f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xae0a, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b11}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xee89, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b13}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x2c00, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b15}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xae04, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b17}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xee89, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b19}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x2c01, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b1b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf8f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b1d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd5e1, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b1f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x892c, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b21}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1a91, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b23}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xdbbf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b25}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x67cf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b27}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0265, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b29}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf51f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b2b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x001f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b2d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x221b, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b2f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x45ad, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b31}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x2705, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b33}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xe187, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b35}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x06ae, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b37}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x03e1, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b39}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8707, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b3b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xaf2d, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b3d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1a02, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b3f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8c1e, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b41}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x028c, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b43}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x7b02, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b45}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x224f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b47}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xaf40, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b49}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xb8ac, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b4b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x2f0f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b4d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0210, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b4f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x62bf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b51}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6d36, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b53}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0265, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b55}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf5e5, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b57}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8fde, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b59}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xaf10, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b5b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4ae1, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b5d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8fde, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b5f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6d, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b61}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3602, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b63}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x65d6, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b65}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xaf10, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b67}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x59e1, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b69}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8fdd, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b6b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa100, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b6d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0dbf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b6f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6d36, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b71}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0265, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b73}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf5e5, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b75}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8fdc, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b77}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xee8f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b79}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xdd01, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b7b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6d, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b7d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3602, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b7f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6f77, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b81}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf86, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b83}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xc7e1, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b85}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x892c, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b87}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4903, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b89}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1a91, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b8b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xef69, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b8d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xdbbf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b8f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x67cf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b91}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0265, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b93}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf51f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b95}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x001f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b97}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x22ef, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b99}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x741b, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b9b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x45ad, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b9d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x2711, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b9f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf86, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ba1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd0d0, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ba3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x00e1, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ba5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8fdc, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ba7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6d, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ba9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3602, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bab}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x65d6, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bad}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xaf35, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8baf}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x46af, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bb1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3527, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bb3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x026f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bb5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6eee, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bb7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8fdd, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bb9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x00bf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bbb}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8d31, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bbd}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x026f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bbf}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6ebf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bc1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8d40, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bc3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x026f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bc5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6ebf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bc7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8d46, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bc9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x026f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bcb}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6eaf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bcd}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x36a9, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bcf}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf8ef, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bd1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x49f8, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bd3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6e, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bd5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xc202, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bd7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x65f5, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bd9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xad28, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bdb}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13e1, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bdd}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8a4e, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bdf}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xad28, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8be1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0502, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8be3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5d65, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8be5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xae0e, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8be7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x025c, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8be9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1202, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8beb}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8cc5, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bed}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xae06, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bef}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x025b, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bf1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf302, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bf3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8d0d, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bf5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xe087, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bf7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x17f6, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bf9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x27e4, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bfb}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8717, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bfd}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xfcef, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bff}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x94fc, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c01}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x04a1, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c03}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0103, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c05}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x028c, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c07}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xe9e0, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c09}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8a02, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c0b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xef23, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c0d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xaf5c, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c0f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xdeac, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c11}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5003, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c13}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xaf61, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c15}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0d02, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c17}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8d0d, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c19}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xaf61, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c1b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x33f8, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c1d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xfafb, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c1f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xef79, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c21}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xfbbf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c23}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6766, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c25}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0265, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c27}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf5ad, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c29}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x2810, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c2b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xad30, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c2d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x05d7, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c2f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0002, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c31}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xae16, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c33}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xad32, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c35}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x24d7, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c37}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0003, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c39}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xae0e, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c3b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xad31, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c3d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x05d7, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c3f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0000, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c41}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xae06, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c43}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xad33, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c45}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x14d7, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c47}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0001, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c49}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf8f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c4b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xdf4f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c4d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0008, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c4f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1a97, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c51}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd78c, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c53}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x63d6, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c55}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8c7b, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c57}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0265, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c59}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3bff, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c5b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xef97, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c5d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xfffe, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c5f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xfc04, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c61}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x206b, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c63}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0e20, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c65}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6b11, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c67}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x206b, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c69}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1420, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c6b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6b17, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c6d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x206b, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c6f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x2020, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c71}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6b23, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c73}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x206b, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c75}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x2600, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c77}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6b29, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c79}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf8fa, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c7b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xef69, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c7d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6d, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c7f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbd02, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c81}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x65f5, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c83}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xad28, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c85}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0ebf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c87}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8d34, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c89}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x026f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c8b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x77bf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c8d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8d31, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c8f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x026f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c91}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x77ae, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c93}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x2ad1, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c95}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0fbf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c97}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8d37, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c99}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0265, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c9b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd6bf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c9d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8d3a, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c9f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x026f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ca1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6ed1, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ca3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x00bf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ca5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8d3d, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ca7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0265, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ca9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd6bf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cab}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8d40, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cad}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x026f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8caf}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x77d1, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cb1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x00bf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cb3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8d43, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cb5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0265, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cb7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd6bf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cb9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8d46, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cbb}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x026f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cbd}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x77ef, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cbf}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x96fe, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cc1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xfc04, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cc3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf8ef, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cc5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x49f8, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cc7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6d, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cc9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbd02, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ccb}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x65f5, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ccd}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xac28, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ccf}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x12bf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cd1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6be6, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cd3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0265, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cd5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf5e5, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cd7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8fd8, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cd9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6b, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cdb}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf202, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cdd}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x65f5, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cdf}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xe58f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ce1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd9fc, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ce3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xef94, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ce5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xfc04, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ce7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf8ef, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ce9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x49f8, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ceb}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6d, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ced}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbd02, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cef}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x65f5, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cf1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xac28, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cf3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x12e1, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cf5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8fda, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cf7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6b, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cf9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xe602, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cfb}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x65d6, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cfd}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xe18f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cff}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xdbbf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d01}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6bf2, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d03}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0265, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d05}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd6fc, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d07}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xef94, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d09}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xfc04, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d0b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf8ef, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d0d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x49f8, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d0f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6d, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d11}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbd02, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d13}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x65f5, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d15}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xac28, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d17}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x12e1, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d19}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8fd8, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d1b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6b, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d1d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xe602, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d1f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x65d6, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d21}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xe18f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d23}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd9bf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d25}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6bf2, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d27}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0265, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d29}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd6fc, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d2b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xef94, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d2d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xfc04, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d2f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x77bd, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d31}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6c66, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d33}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbd6c, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d35}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x30bd, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d37}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5444, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d39}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbd54, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d3b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x85bd, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d3d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5e55, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d3f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbd54, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d41}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa7bd, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d43}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5cbb, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d45}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbd5c, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d47}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb85e, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x2d07, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb860, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x40b5, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb862, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1047, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb864, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3504, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb886, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x36A6, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb888, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x613d, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb88a, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5cd9, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb88c, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x610a, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb838, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x00ff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb820, 7 , 7 , 0x0 , RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++}; ++ ++rtk_hwpatch_t rtl8264b_nctl0_conf[] = { ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb820, 7 , 7 , 0x1 , RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA016, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0000, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA012, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0000, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA014, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8010, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8015, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x4}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8020, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x6}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x802a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x8}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8030, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xa}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8035, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xb}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xc}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8046, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xd}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xe}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x806b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xf}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd707, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x10}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x606f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x11}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x12}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x801a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x13}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x14}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd707, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x15}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x606f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x16}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x17}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x801a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x18}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x19}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce10, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xcf01, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd705, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4004, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xcf02, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd719, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x20}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3bb7, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x21}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8024, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x22}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf003, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x23}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd704, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x24}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x406e, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x25}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x26}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x12bd, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x27}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x28}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x12e3, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x29}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xab80, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd500, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xc402, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x004a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x30}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8b80, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x31}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd500, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x32}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x33}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0108, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x34}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c0f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x35}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x090f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x36}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c0f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x37}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0a03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x38}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd004, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x39}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd1c1, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x3a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x3b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x401c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x3c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce00, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x3d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd500, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x3e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x3f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x801a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x40}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd501, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x41}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce01, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x42}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x43}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x44}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0aa9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x45}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd500, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x46}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd706, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x47}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x2a69, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x48}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8056, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x49}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3f48, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x4a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8058, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x4b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3f4b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x4c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x805a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x4d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x618c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x4e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3f40, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x4f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x805c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x50}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3f43, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x51}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x805e, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x52}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x616b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x53}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6187, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x54}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x55}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xcc8f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x56}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x57}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xcc8d, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x58}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf008, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x59}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xcc8b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x5a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf006, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x5b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xcc89, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x5c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf004, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x5d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xcc87, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x5e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf002, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x5f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xcc91, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x60}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x61}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b9a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x62}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x63}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xca80, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x64}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x65}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0ba0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x66}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xca00, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x67}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd504, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x68}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x69}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1658, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x6a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa208, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x6b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x6c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0a88, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x6d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x6e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0d91, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x6f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA026, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0d90, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA024, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1657, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA022, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0aa1, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA020, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0047, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA006, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0049, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA004, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x12b9, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA002, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0be5, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA000, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1811, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA008, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xff00, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA016, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0000, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA012, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0ff8, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA014, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xc483, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x0ff8}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xc483, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xff9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xffa}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xffb}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xffc}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xffd}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xffe}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xfff}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA152, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1a83, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA154, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1d29, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA156, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3fff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA158, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3fff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA15A, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3fff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA15C, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3fff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA15E, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3fff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA160, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3fff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA150, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0003, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb820, 7 , 7 , 0x0 , RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++}; ++ ++rtk_hwpatch_t rtl8264b_nctl1_conf[] = { ++}; ++ ++rtk_hwpatch_t rtl8264b_nctl2_conf[] = { ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb820, 7 , 7 , 0x1 , RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA016, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0020, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA012, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0000, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA014, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8010, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8022, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x4}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8029, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x6}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8085, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x8}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x808c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xa}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8093, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xb}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xc}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8281, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xd}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xe}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x829a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xf}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x10}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x11}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8370, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x12}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x13}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd707, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x14}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x416f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x15}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x16}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd05a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x17}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa501, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x18}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x19}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd701, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5fbd, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8501, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0427, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x20}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x040b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x21}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8501, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x22}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd707, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x23}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x406f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x24}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x25}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x01d8, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x26}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x27}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x01cb, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x28}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd705, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x29}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3fa7, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8030, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd75f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x699c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1340, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd704, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x30}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4066, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x31}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x800a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x32}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf002, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x33}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa00a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x34}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd705, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x35}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x61b4, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x36}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd704, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x37}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x609f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x38}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6150, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x39}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x2d71, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x3a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8043, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x3b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x3c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x3d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0cf0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x3e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x05a0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x3f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x40}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x41}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13b1, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x42}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x43}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x44}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8220, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x45}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c30, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x46}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0410, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x47}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x48}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x800a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x49}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x81a0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x4a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8302, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x4b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8480, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x4c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8684, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x4d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x4e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x4f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8203, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x50}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8340, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x51}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x52}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xaa10, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x53}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8b07, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x54}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x55}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x60cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x56}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x60f1, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x57}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6113, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x58}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6135, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x59}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6157, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x5a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x5b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce0b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x5c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x5d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce0b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x5e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf008, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x5f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce0a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x60}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf006, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x61}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce0a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x62}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf004, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x63}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce09, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x64}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf002, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x65}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce09, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x66}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x67}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x68}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa204, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x69}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x6a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x6b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13e4, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x6c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xab08, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x6d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xcda0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x6e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd705, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x6f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x40de, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x70}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd162, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x71}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd045, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x72}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf10, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x73}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x74}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13b1, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x75}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9f10, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x76}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x77}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13b1, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x78}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x79}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x607a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x7a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x7b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13b1, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x7c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9f10, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x7d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x7e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x7f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8210, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x80}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa210, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x81}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x82}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x83}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1340, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x84}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x85}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x86}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8df8, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x87}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8370, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x88}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x89}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x8a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x01c1, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x8b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x8c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x8d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8df8, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x8e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8370, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x8f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x90}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x91}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x009e, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x92}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x93}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x37c9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x94}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x809e, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x95}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x33a9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x96}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x809b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x97}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd1bf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x98}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd06d, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x99}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf006, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x9a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd1dd, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x9b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd06d, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x9c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf003, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x9d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd199, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x9e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd06e, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x9f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xa0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xa1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xa2}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5fba, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xa3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xa4}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd05a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xa5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xa6}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x60cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xa7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x60f1, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xa8}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6113, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xa9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6135, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xaa}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6157, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xab}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xac}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xad}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xae}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xaf}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf008, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xb0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xb1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf006, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xb2}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xb3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf004, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xb4}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xb5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf002, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xb6}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xb7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xb8}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13e4, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xb9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xba}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xbb}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0ccf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xbc}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b40, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xbd}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c3f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xbe}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c24, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xbf}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xc0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa340, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xc1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xc2}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1433, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xc3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa110, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xc4}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xc5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13ec, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xc6}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8110, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xc7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xc8}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x143c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xc9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa304, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xca}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa8c0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xcb}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8810, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xcc}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa00a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xcd}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa120, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xce}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa310, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xcf}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0cfc, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xd0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0224, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xd1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0ca0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xd2}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0480, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xd3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xd4}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xd5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa340, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xd6}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xd7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd162, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xd8}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd048, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xd9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xda}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xdb}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xdc}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5fba, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xdd}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8840, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xde}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd1c4, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xdf}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd045, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xe0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xe1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xe2}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xe3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5fba, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xe4}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd706, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xe5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6127, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xe6}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xe7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f3b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xe8}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x88c0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xe9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x800a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xea}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8120, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xeb}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8350, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xec}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x84a0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xed}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xffb6, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xee}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xb920, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xef}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xcd33, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xf0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xf1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xf2}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd71f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xf3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x7fb4, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xf4}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9920, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xf5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xf6}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xf7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd71f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xf8}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6065, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xf9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f94, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xfa}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xffee, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xfb}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xb820, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xfc}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xfd}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xfe}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd71f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xff}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x7fa5, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x100}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9820, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x101}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x800a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x102}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8120, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x103}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x104}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1433, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x105}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa108, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x106}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x107}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13ec, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x108}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8108, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x109}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x10a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x143c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x10b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa2fc, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x10c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa304, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x10d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8880, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x10e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0cc0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x10f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0440, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x110}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xcd34, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x111}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x112}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x113}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0cc0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x114}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b80, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x115}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xac3f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x116}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c38, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x117}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0d08, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x118}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x119}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa810, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x11a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa00a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x11b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa120, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x11c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa480, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x11d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa604, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x11e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x11f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x37c9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x120}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8125, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x121}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x122}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd049, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x123}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf003, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x124}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd19f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x125}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd049, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x126}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x127}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x128}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd71f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x129}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x63f4, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x12a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x12b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f7a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x12c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd706, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x12d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4368, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x12e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x12f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x130}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0cc0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x131}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b40, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x132}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8c3f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x133}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8d38, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x134}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x135}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x136}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x37c9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x137}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8141, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x138}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x33a9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x139}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x813e, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x13a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd1f4, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x13b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x13c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf006, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x13d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd1b7, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x13e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x13f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf003, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x140}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd1c6, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x141}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x142}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x143}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x144}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd71f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x145}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6074, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x146}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x147}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f7a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x148}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x149}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x14a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd71f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x14b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4056, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x14c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf004, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x14d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x14e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x61fc, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x14f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xfff9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x150}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd706, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x151}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6048, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x152}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x153}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x154}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4070, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x155}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x156}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x820e, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x157}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x158}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x159}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xae80, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x15a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x15b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x15c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x820e, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x15d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x15e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd05a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x15f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x160}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x60cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x161}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x60f1, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x162}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6113, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x163}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6135, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x164}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6157, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x165}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x166}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x167}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x168}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x169}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf008, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x16a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x16b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf006, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x16c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x16d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf004, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x16e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x16f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf002, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x170}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x171}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x172}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13e4, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x173}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x174}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x175}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0ccf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x176}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b40, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x177}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c3f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x178}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c24, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x179}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x17a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa340, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x17b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x17c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1433, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x17d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa110, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x17e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x17f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13ec, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x180}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8110, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x181}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x182}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x143c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x183}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa304, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x184}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa8c0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x185}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8810, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x186}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa00a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x187}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa120, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x188}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa310, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x189}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0cfc, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x18a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0224, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x18b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0ca0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x18c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0480, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x18d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8604, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x18e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xcd35, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x18f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd162, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x190}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd048, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x191}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x192}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x193}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x194}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5fba, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x195}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8840, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x196}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd1c4, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x197}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd045, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x198}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x199}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x19a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x19b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5fba, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x19c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd706, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x19d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6127, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x19e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x19f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f3b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1a0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x88c0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1a1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x800a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1a2}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8120, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1a3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8350, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1a4}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x84a0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1a5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xffb8, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1a6}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbb80, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1a7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1a8}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1a9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd71f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1aa}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5fb4, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ab}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xb920, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ac}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xcd36, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ad}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ae}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1af}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd71f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1b0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x7fb4, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1b1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9920, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1b2}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9b80, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1b3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1b4}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1b5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd71f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1b6}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6065, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1b7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f94, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1b8}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xffe8, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1b9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xb820, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ba}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1bb}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1bc}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd71f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1bd}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x7fa5, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1be}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9820, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1bf}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x800a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1c0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8120, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1c1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1c2}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1433, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1c3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa108, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1c4}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1c5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13ec, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1c6}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8108, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1c7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1c8}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x143c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1c9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa2fc, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ca}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa304, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1cb}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8880, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1cc}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0cc0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1cd}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0440, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ce}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xcd37, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1cf}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1d0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1d1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0cc0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1d2}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b80, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1d3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xac3f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1d4}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c38, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1d5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0d08, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1d6}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1d7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa810, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1d8}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa00a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1d9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa120, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1da}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa480, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1db}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa604, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1dc}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1dd}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x37c9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1de}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x81e8, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1df}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x33a9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1e0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x81e5, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1e1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1e2}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd048, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1e3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf006, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1e4}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1e5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd048, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1e6}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf003, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1e7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1e8}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd048, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1e9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ea}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1eb}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ec}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x141a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ed}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ee}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f7a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ef}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd706, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1f0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f28, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1f1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1f2}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1f3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0cc0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1f4}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b40, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1f5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8c3f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1f6}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8d38, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1f7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1f8}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1f9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x37c9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1fa}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8204, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1fb}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x33a9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1fc}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8201, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1fd}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd199, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1fe}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ff}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf006, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x200}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x201}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x202}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf003, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x203}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd189, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x204}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x205}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x206}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x207}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x208}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x141a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x209}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x20a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f7a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x20b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd706, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x20c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f28, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x20d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x20e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x20f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c0f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x210}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b05, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x211}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x212}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x213}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x60cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x214}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x60f1, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x215}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6113, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x216}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6135, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x217}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6157, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x218}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x219}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce08, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x21a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x21b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce08, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x21c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf008, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x21d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce08, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x21e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf006, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x21f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce08, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x220}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf004, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x221}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce08, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x222}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf002, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x223}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce08, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x224}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x225}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13e4, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x226}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa180, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x227}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xcd38, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x228}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x229}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x37c9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x22a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x823e, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x22b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x33a9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x22c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8236, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x22d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x22e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x22f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x230}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x231}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf013, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x232}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd100, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x233}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd049, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x234}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf010, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x235}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x236}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x237}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd1b7, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x238}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd049, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x239}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x23a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd100, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x23b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd048, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x23c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf008, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x23d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x23e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x23f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x240}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x241}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf003, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x242}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd199, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x243}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x244}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd13b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x245}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd055, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x246}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x247}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x248}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x249}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x141a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x24a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x24b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f7b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x24c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa302, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x24d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x24e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x24f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x250}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x141a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x251}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x252}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f7a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x253}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd706, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x254}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f28, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x255}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x256}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x257}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c3f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x258}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c12, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x259}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x25a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x25b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x37c9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x25c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8270, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x25d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x33a9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x25e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8268, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x25f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x260}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x261}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd199, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x262}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x263}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf013, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x264}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd100, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x265}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd048, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x266}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf010, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x267}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x268}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x269}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x26a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x26b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x26c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd100, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x26d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd040, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x26e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf008, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x26f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x270}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x271}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd199, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x272}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x273}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf003, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x274}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd16b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x275}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x276}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x277}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x278}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x279}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x141a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x27a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x27b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f7a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x27c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd706, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x27d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f2a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x27e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x27f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x085e, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x280}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x281}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x282}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xcb0a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x283}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0cc7, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x284}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x285}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x286}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x287}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4127, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x288}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x289}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x28a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c0f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x28b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b05, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x28c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c38, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x28d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0d28, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x28e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x28f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf008, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x290}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x291}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x292}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c0f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x293}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b0a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x294}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c38, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x295}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0d18, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x296}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x297}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x298}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0f45, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x299}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x29a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x646d, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x29b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x37c9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x29c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x82b4, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x29d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x33a9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x29e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x82aa, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x29f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2a0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x40c7, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2a1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2a2}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2a3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd100, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2a4}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd049, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2a5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf01a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2a6}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2a7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd049, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2a8}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf017, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2a9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2aa}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x40c7, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2ab}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2ac}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2ad}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd100, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2ae}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd049, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2af}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf010, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2b0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2b1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2b2}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00d, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2b3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2b4}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x40c7, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2b5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2b6}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2b7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2b8}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2b9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf006, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2ba}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2bb}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2bc}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf003, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2bd}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2be}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd048, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2bf}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2c0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2c1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2c2}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x141a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2c3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2c4}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f7a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2c5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd706, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2c6}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f29, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2c7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2c8}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x60cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2c9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x60f1, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2ca}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6113, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2cb}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6135, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2cc}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6157, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2cd}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2ce}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2cf}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2d0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2d1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf008, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2d2}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2d3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf006, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2d4}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2d5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf004, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2d6}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2d7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf002, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2d8}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2d9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2da}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13e4, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2db}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2dc}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2dd}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8bc0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2de}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c3f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2df}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c09, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2e0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2e1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa120, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2e2}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa310, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2e3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa420, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2e4}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xcd3b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2e5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2e6}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x65ad, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2e7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x43c7, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2e8}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2e9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x37c9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2ea}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x82fe, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2eb}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x33a9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2ec}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x82f6, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2ed}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2ee}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2ef}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd199, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2f0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2f1}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf024, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2f2}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd15d, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2f3}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2f4}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf021, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2f5}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2f6}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2f7}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd1c6, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2f8}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2f9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf01c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2fa}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd15d, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2fb}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2fc}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf019, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2fd}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2fe}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2ff}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd199, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x300}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x301}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf014, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x302}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x303}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x304}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf011, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x305}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x306}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x37c9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x307}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8311, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x308}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x33a9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x309}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x830e, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x30a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd1e5, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x30b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x30c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf009, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x30d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd191, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x30e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04d, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x30f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf006, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x310}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x311}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04d, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x312}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf003, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x313}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd16b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x314}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x315}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x316}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x317}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x318}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x141a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x319}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x31a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f7a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x31b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd706, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x31c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f2c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x31d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x31e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x40e7, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x31f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x320}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x321}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c0f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x322}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b05, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x323}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x324}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf006, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x325}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x326}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x327}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c0f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x328}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b0a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x329}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x32a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xcd3c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x32b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x32c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x644d, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x32d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x43c7, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x32e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x32f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x37c9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x330}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8344, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x331}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x33a9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x332}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x833c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x333}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x334}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x335}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x336}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x337}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf019, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x338}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x339}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd048, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x33a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf016, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x33b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x33c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x33d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x33e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x33f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf011, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x340}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd13e, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x341}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd049, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x342}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00e, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x343}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x344}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x345}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x346}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x347}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf009, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x348}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x349}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd049, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x34a}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf006, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x34b}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x34c}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x34d}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf003, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x34e}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x34f}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd048, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x350}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x351}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x093a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x352}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA10E, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0883, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA10C, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0f32, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA10A, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0676, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA108, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x00fa, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA106, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x021d, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA104, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x12fe, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA102, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x01ca, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA100, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x047f, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA110, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x00ff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA016, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0020, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA012, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1ff8, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA014, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd13e, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ff8}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd15c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ff9}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd16b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ffa}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd15d, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ffb}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b0e, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ffc}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b0e, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ffd}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b0e, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ffe}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1fff}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA164, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0972, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA166, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0968, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA168, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0a0b, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA16A, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0a01, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA16C, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b8a, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA16E, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0bf9, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA170, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x125c, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA172, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3fff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA162, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x007F, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb820, 7 , 7 , 0x0 , RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++}; ++ ++rtk_hwpatch_t rtl8264b_algxg_conf[] = { ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x815B, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x75 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x80CD, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x25 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8065, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x15 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8175, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0xa2 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8176, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0xc5 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8077, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x40 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8078, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0xcc , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8969, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x0f , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8957, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x2C , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8959, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x15 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x895A, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x3E , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x895F, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x1E , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8165, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x22 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x827E, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x68 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8167, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x33 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8013, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x39 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8fd7, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x14 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8fd6, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x1e , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8fd5, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x1e , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x82D9, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x20 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x82DA, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x00 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x816E, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0xab , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8159, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x58 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x815A, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x99 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8139, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x25 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8125, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x67 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8126, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x89 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x827D, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x42 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++}; ++ ++rtk_hwpatch_t rtl8264b_alg_giga_conf[] = { ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80b8, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0x4d , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80b9, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0xcc , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80ba, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0x0 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80bb, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 13, 8 , 0x0 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80bc, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0x37 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80bd, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 12, 8 , 0x0c , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80be, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0xBB , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80bf, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0xca , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80c0, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0x45 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80c2, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0x3b , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80cc, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0x16 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80cd, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 10, 8 , 0x4 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80ce, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0x0 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80cf, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 13, 8 , 0x0 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80d0, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0x53 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80d1, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 12, 8 , 0x0a , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80d2, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0xB9 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80d3, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0xd0 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80d4, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0x4a , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80d6, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0x35 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80a4, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0x0d , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80a5, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0xa4 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80a6, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0x59 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80a7, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 13, 8 , 0x05 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80a8, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0xab , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80a9, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 12, 8 , 0x0b , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80aa, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0xef , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80ab, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0xae , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80ac, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0xdf , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80ae, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0x28 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x8367, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0x5d , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++}; ++ ++rtk_hwpatch_t rtl8264b_normal_conf[] = { ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xbd92, 15, 0 , 0x002e, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xbd94, 15, 0 , 0x8003, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xbd96, 3 , 0 , 0xf , RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xbd96, 3 , 0 , 0x0 , RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xbd94, 15, 0 , 0x800b, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xbd96, 3 , 0 , 0xf , RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xbd96, 3 , 0 , 0x0 , RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x817D, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0x07 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x8426, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0x46 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x8428, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0x46 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x84de, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0000, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x84e0, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x00fc, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x84e2, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf61a, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x84e4, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0x58 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x84e6, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0000, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x84e8, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x00fc, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x84ea, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf61a, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x84ec, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0x58 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x84ee, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0000, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x84f0, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x00fc, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x84f2, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf61a, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x84f4, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0x58 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xae32, 5 , 5 , 0x1 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x8018, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 12, 12, 0x1 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8fdf, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 0 , 0x0496, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8fe1, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 0 , 0x03a5, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8fe3, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 0 , 0x02e5, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8fe5, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 0 , 0x020d, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8fe7, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 0 , 0x0496, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8fe9, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 0 , 0x03a5, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8feb, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 0 , 0x02e5, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8fed, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 0 , 0x020d, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8fef, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 0 , 0x0496, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8ff1, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 0 , 0x03a5, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8ff3, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 0 , 0x02e5, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8ff5, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 0 , 0x020d, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8ff7, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 0 , 0x0496, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8ff9, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 0 , 0x03a5, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8ffb, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 0 , 0x02e5, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8ffd, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 0 , 0x020d, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb516, 6 , 0 , 0x0 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8fda, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x04 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8fdb, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x05 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8132, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x77 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8134, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x88 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x80ca, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x77 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x80cc, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x88 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8062, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x77 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8064, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x88 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x801E, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0012, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++}; ++ ++rtk_hwpatch_t rtl8264b_dataram_conf[] = { ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb820, 7 , 7 , 0x0 , RTK_PATCH_CMP_WS , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb896, 0 , 0 , 0x0 , RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb892, 15, 8 , 0x0 , RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC037, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0x33 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC038, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0x2A , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC039, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0x25 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC03A, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0x20 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC03B, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0x1C , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC03C, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0x17 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC03D, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0x13 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC075, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0xA1 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC076, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0xB1 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC077, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0x2E , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC078, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0x55 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC079, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0x19 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC07A, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0xDC , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC07B, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0xA0 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC10B, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0xD5 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC10C, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0xD5 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC10D, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0xD5 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC10E, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0xD5 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC10F, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0xD5 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC110, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0xD5 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC149, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0x08 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC14A, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0x08 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC14B, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0x08 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC14C, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0x08 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC14D, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0x08 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC14E, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0x08 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC166, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0xEE , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC167, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0xEE , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC168, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0x07 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC169, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0x09 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC16A, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0x0B , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC16B, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0x0D , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC16C, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0x13 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC16D, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0x0E , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC16E, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0x11 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC16F, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0x14 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC170, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0x17 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC171, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0x15 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC172, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0x10 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC173, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0x0B , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC128, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0xF7 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC129, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0xF7 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC12A, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0xF8 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC12B, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0xF7 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC12C, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0xF6 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC12D, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0xF5 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC12E, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0xF2 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC12F, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0xF7 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC130, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0xF5 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC131, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0xF2 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC132, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0xF0 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC133, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0xF1 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC134, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0xF4 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC135, RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0xF7 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb896, 0 , 0 , 0x1 , RTK_PATCH_CMP_W , 0, 0, 0, 0}, ++}; ++ ++rtk_hwpatch_t rtl8264b_rtct_conf[] = { ++}; ++ +diff --git a/drivers/net/phy/rtl8261n/error.h b/drivers/net/phy/rtl8261n/error.h +new file mode 100644 +index 000000000000..d99a996f8c05 +--- /dev/null ++++ b/drivers/net/phy/rtl8261n/error.h +@@ -0,0 +1,165 @@ ++/* ++ * SPDX-License-Identifier: GPL-2.0-only ++ * ++ * Copyright (c) 2023 Realtek Semiconductor Corp. All rights reserved. ++ */ ++ ++#ifndef __COMMON_ERROR_H__ ++#define __COMMON_ERROR_H__ ++ ++/* ++ * Include Files ++ */ ++#if defined(RTK_PHYDRV_IN_LINUX) ++ #include "type.h" ++#else ++ #include ++#endif ++/* ++ * Data Type Declaration ++ */ ++typedef enum rt_error_common_e ++{ ++ RT_ERR_FAILED = -1, /* General Error */ ++ ++ /* 0x0000xxxx for common error code */ ++ RT_ERR_OK = 0, /* 0x00000000, OK */ ++ RT_ERR_INPUT = 0xF001, /* 0x0000F001, invalid input parameter */ ++ RT_ERR_UNIT_ID, /* 0x0000F002, invalid unit id */ ++ RT_ERR_PORT_ID, /* 0x0000F003, invalid port id */ ++ RT_ERR_PORT_MASK, /* 0x0000F004, invalid port mask */ ++ RT_ERR_PORT_LINKDOWN, /* 0x0000F005, link down port status */ ++ RT_ERR_ENTRY_INDEX, /* 0x0000F006, invalid entry index */ ++ RT_ERR_NULL_POINTER, /* 0x0000F007, input parameter is null pointer */ ++ RT_ERR_QUEUE_ID, /* 0x0000F008, invalid queue id */ ++ RT_ERR_QUEUE_NUM, /* 0x0000F009, invalid queue number */ ++ RT_ERR_BUSYWAIT_TIMEOUT, /* 0x0000F00a, busy watting time out */ ++ RT_ERR_MAC, /* 0x0000F00b, invalid mac address */ ++ RT_ERR_OUT_OF_RANGE, /* 0x0000F00c, input parameter out of range */ ++ RT_ERR_CHIP_NOT_SUPPORTED, /* 0x0000F00d, functions not supported by this chip model */ ++ RT_ERR_SMI, /* 0x0000F00e, SMI error */ ++ RT_ERR_NOT_INIT, /* 0x0000F00f, The module is not initial */ ++ RT_ERR_CHIP_NOT_FOUND, /* 0x0000F010, The chip can not found */ ++ RT_ERR_NOT_ALLOWED, /* 0x0000F011, actions not allowed by the function */ ++ RT_ERR_DRIVER_NOT_FOUND, /* 0x0000F012, The driver can not found */ ++ RT_ERR_SEM_LOCK_FAILED, /* 0x0000F013, Failed to lock semaphore */ ++ RT_ERR_SEM_UNLOCK_FAILED, /* 0x0000F014, Failed to unlock semaphore */ ++ RT_ERR_THREAD_EXIST, /* 0x0000F015, Thread exist */ ++ RT_ERR_THREAD_CREATE_FAILED, /* 0x0000F016, Thread create fail */ ++ RT_ERR_FWD_ACTION, /* 0x0000F017, Invalid forwarding Action */ ++ RT_ERR_IPV4_ADDRESS, /* 0x0000F018, Invalid IPv4 address */ ++ RT_ERR_IPV6_ADDRESS, /* 0x0000F019, Invalid IPv6 address */ ++ RT_ERR_PRIORITY, /* 0x0000F01a, Invalid Priority value */ ++ RT_ERR_FID, /* 0x0000F01b, invalid fid */ ++ RT_ERR_ENTRY_NOTFOUND, /* 0x0000F01c, specified entry not found */ ++ RT_ERR_DROP_PRECEDENCE, /* 0x0000F01d, invalid drop precedence */ ++ RT_ERR_NOT_FINISH, /* 0x0000F01e, Action not finish, still need to wait */ ++ RT_ERR_TIMEOUT, /* 0x0000F01f, Time out */ ++ RT_ERR_REG_ARRAY_INDEX_1, /* 0x0000F020, invalid index 1 of register array */ ++ RT_ERR_REG_ARRAY_INDEX_2, /* 0x0000F021, invalid index 2 of register array */ ++ RT_ERR_ETHER_TYPE, /* 0x0000F022, invalid ether type */ ++ RT_ERR_MBUF_PKT_NOT_AVAILABLE, /* 0x0000F023, mbuf->packet is not available */ ++ RT_ERR_QOS_INVLD_RSN, /* 0x0000F024, invalid pkt to CPU reason */ ++ RT_ERR_CB_FUNCTION_EXIST, /* 0x0000F025, Callback function exist */ ++ RT_ERR_CB_FUNCTION_FULL, /* 0x0000F026, Callback function number is full */ ++ RT_ERR_CB_FUNCTION_NOT_FOUND, /* 0x0000F027, Callback function can not found */ ++ RT_ERR_TBL_FULL, /* 0x0000F028, The table is full */ ++ RT_ERR_TRUNK_ID, /* 0x0000F029, invalid trunk id */ ++ RT_ERR_TYPE, /* 0x0000F02a, invalid type */ ++ RT_ERR_ENTRY_EXIST, /* 0x0000F02b, entry exists */ ++ RT_ERR_CHIP_UNDEFINED_VALUE, /* 0x0000F02c, chip returned an undefined value */ ++ RT_ERR_EXCEEDS_CAPACITY, /* 0x0000F02d, exceeds the capacity of hardware */ ++ RT_ERR_ENTRY_REFERRED, /* 0x0000F02e, entry is still being referred */ ++ RT_ERR_OPER_DENIED, /* 0x0000F02f, operation denied */ ++ RT_ERR_PORT_NOT_SUPPORTED, /* 0x0000F030, functions not supported by this port */ ++ RT_ERR_SOCKET, /* 0x0000F031, socket error */ ++ RT_ERR_MEM_ALLOC, /* 0x0000F032, insufficient memory resource */ ++ RT_ERR_ABORT, /* 0x0000F033, operation aborted */ ++ RT_ERR_DEV_ID, /* 0x0000F034, invalid device id */ ++ RT_ERR_DRIVER_NOT_SUPPORTED, /* 0x0000F035, functions not supported by this driver */ ++ RT_ERR_NOT_SUPPORTED, /* 0x0000F036, functions not supported */ ++ RT_ERR_SER, /* 0x0000F037, ECC or parity error */ ++ RT_ERR_MEM_NOT_ALIGN, /* 0x0000F038, memory address is not aligned */ ++ RT_ERR_SEM_FAKELOCK_OK, /* 0x0000F039, attach thread lock a semaphore which was already locked */ ++ RT_ERR_CHECK_FAILED, /* 0x0000F03a, check result is failed */ ++ ++ RT_ERR_COMMON_END = 0xFFFF /* The symbol is the latest symbol of common error */ ++} rt_error_common_t; ++ ++/* ++ * Macro Definition ++ */ ++#define RT_PARAM_CHK(expr, errCode)\ ++do {\ ++ if ((int32)(expr)) {\ ++ return errCode; \ ++ }\ ++} while (0) ++ ++#define RT_PARAM_CHK_EHDL(expr, errCode, err_hdl)\ ++do {\ ++ if ((int32)(expr)) {\ ++ {err_hdl}\ ++ return errCode; \ ++ }\ ++} while (0) ++ ++#define RT_INIT_CHK(state)\ ++do {\ ++ if (INIT_COMPLETED != (state)) {\ ++ return RT_ERR_NOT_INIT;\ ++ }\ ++} while (0) ++ ++#define RT_INIT_REENTRY_CHK(state)\ ++do {\ ++ if (INIT_COMPLETED == (state)) {\ ++ osal_printf(" %s had already been initialized!\n", __FUNCTION__);\ ++ return RT_ERR_OK;\ ++ }\ ++} while (0) ++ ++#define RT_INIT_REENTRY_CHK_NO_WARNING(state)\ ++ do {\ ++ if (INIT_COMPLETED == (state)) {\ ++ return RT_ERR_OK;\ ++ }\ ++ } while (0) ++ ++#define RT_ERR_CHK(op, ret)\ ++do {\ ++ if ((ret = (op)) != RT_ERR_OK)\ ++ return ret;\ ++} while(0) ++ ++#define RT_ERR_HDL(op, errHandle, ret)\ ++do {\ ++ if ((ret = (op)) != RT_ERR_OK)\ ++ goto errHandle;\ ++} while(0) ++ ++#define RT_ERR_CHK_EHDL(op, ret, err_hdl)\ ++do {\ ++ if ((ret = (op)) != RT_ERR_OK)\ ++ {\ ++ {err_hdl}\ ++ return ret;\ ++ }\ ++} while(0) ++ ++#define RT_NULL_HDL(pointer, err_label)\ ++do {\ ++ if (NULL == (pointer)) {\ ++ goto err_label;\ ++ }\ ++} while (0) ++ ++#define RT_ERR_VOID_CHK(op, ret)\ ++do {\ ++ if ((ret = (op)) != RT_ERR_OK) {\ ++ osal_printf("Fail in %s %d, ret %x!\n", __FUNCTION__, __LINE__, ret);\ ++ return ;}\ ++} while(0) ++ ++#endif /* __COMMON_ERROR_H__ */ ++ +diff --git a/drivers/net/phy/rtl8261n/phy_patch.c b/drivers/net/phy/rtl8261n/phy_patch.c +new file mode 100644 +index 000000000000..7563f6705333 +--- /dev/null ++++ b/drivers/net/phy/rtl8261n/phy_patch.c +@@ -0,0 +1,188 @@ ++/* ++ * SPDX-License-Identifier: GPL-2.0-only ++ * ++ * Copyright (c) 2023 Realtek Semiconductor Corp. All rights reserved. ++ */ ++ ++/* ++ * Include Files ++ */ ++#if defined(RTK_PHYDRV_IN_LINUX) ++ #include "rtk_osal.h" ++#else ++ #include ++ #include ++ #include ++ #include ++ #include ++#endif ++ ++/* ++ * Function Declaration ++ */ ++uint8 phy_patch_op_translate(uint8 patch_mode, uint8 patch_op, uint8 compare_op) ++{ ++ if (patch_mode != PHY_PATCH_MODE_CMP) ++ { ++ return patch_op; ++ } ++ else ++ { ++ switch (compare_op) ++ { ++ case RTK_PATCH_CMP_WS: ++ return RTK_PATCH_OP_SKIP; ++ case RTK_PATCH_CMP_W: ++ case RTK_PATCH_CMP_WC: ++ case RTK_PATCH_CMP_SWC: ++ default: ++ return RTK_PATCH_OP_TO_CMP(patch_op, compare_op); ++ } ++ } ++} ++ ++int32 phy_patch_op(rt_phy_patch_db_t *pPhy_patchDb, uint32 unit, rtk_port_t port, uint8 portOffset, uint8 patch_op, uint16 portmask, uint16 pagemmd, uint16 addr, uint8 msb, uint8 lsb, uint16 data, uint8 patch_mode) ++{ ++ rtk_hwpatch_t op; ++ ++ op.patch_op = patch_op; ++ op.portmask = portmask; ++ op.pagemmd = pagemmd; ++ op.addr = addr; ++ op.msb = msb; ++ op.lsb = lsb; ++ op.data = data; ++ op.compare_op = RTK_PATCH_CMP_W; ++ ++ return pPhy_patchDb->fPatch_op(unit, port, portOffset, &op, patch_mode); ++} ++ ++static int32 _phy_patch_process(uint32 unit, rtk_port_t port, uint8 portOffset, rtk_hwpatch_t *pPatch, int32 size, uint8 patch_mode) ++{ ++ int32 i = 0; ++ int32 ret = 0; ++ int32 chk_ret = RT_ERR_OK; ++ int32 n; ++ rtk_hwpatch_t *patch = pPatch; ++ rt_phy_patch_db_t *pPatchDb = NULL; ++ ++ PHYPATCH_DB_GET(unit, port, pPatchDb); ++ ++ if (size <= 0) ++ { ++ return RT_ERR_OK; ++ } ++ n = size / sizeof(rtk_hwpatch_t); ++ ++ for (i = 0; i < n; i++) ++ { ++ ret = pPatchDb->fPatch_op(unit, port, portOffset, &patch[i], patch_mode); ++ if ((ret != RT_ERR_ABORT) && (ret != RT_ERR_OK)) ++ { ++ if ((ret == RT_ERR_CHECK_FAILED) && (patch_mode == PHY_PATCH_MODE_CMP)) ++ { ++ osal_printf("PATCH CHECK: Failed entry:%u|%u|0x%X|0x%X|%u|%u|0x%X\n", ++ i + 1, patch[i].patch_op, patch[i].pagemmd, patch[i].addr, patch[i].msb, patch[i].lsb, patch[i].data); ++ chk_ret = RT_ERR_CHECK_FAILED; ++ continue; ++ } ++ else ++ { ++ RT_LOG(LOG_MAJOR_ERR, (MOD_HAL | MOD_PHY), "U%u P%u %s failed! %u[%u][0x%X][0x%X][0x%X] ret=0x%X\n", unit, port, __FUNCTION__, ++ i+1, patch[i].patch_op, patch[i].pagemmd, patch[i].addr, patch[i].data, ret); ++ return ret; ++ } ++ } ++ ++ } ++ return (chk_ret == RT_ERR_CHECK_FAILED) ? chk_ret : RT_ERR_OK; ++} ++ ++rtk_hwpatch_t rtl826XB_patch_rtk_conf[] = { ++ {RTK_PATCH_OP_PSDS0 , 0xff , 0x07 , 0x10 , 15, 0, 0x80aa, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++ {RTK_PATCH_OP_PSDS0 , 0xff , 0x06 , 0x12 , 15, 0, 0x5078, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, ++}; ++ ++/* Function Name: ++ * phy_patch ++ * Description: ++ * apply initial patch data to PHY ++ * Input: ++ * unit - unit id ++ * port - port id ++ * portOffset - the index offset of port based the base port in the PHY chip ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_CHECK_FAILED ++ * RT_ERR_NOT_SUPPORTED ++ * Note: ++ * None ++ */ ++int32 phy_patch(uint32 unit, rtk_port_t port, uint8 portOffset, uint8 patch_mode) ++{ ++ int32 ret = RT_ERR_OK; ++ int32 chk_ret = RT_ERR_OK; ++ uint32 i = 0; ++ uint8 patch_type = 0; ++ rt_phy_patch_db_t *pPatchDb = NULL; ++ rtk_hwpatch_seq_t *table = NULL; ++ ++ PHYPATCH_DB_GET(unit, port, pPatchDb); ++ ++ if ((pPatchDb == NULL) || (pPatchDb->fPatch_op == NULL) || (pPatchDb->fPatch_flow == NULL)) ++ { ++ RT_LOG(LOG_MAJOR_ERR, (MOD_HAL | MOD_PHY), "U%u P%u phy_patch, db is NULL\n", unit, port); ++ return RT_ERR_DRIVER_NOT_SUPPORTED; ++ } ++ ++ if (patch_mode == PHY_PATCH_MODE_CMP) ++ { ++ table = pPatchDb->cmp_table; ++ } ++ else ++ { ++ table = pPatchDb->seq_table; ++ } ++ RT_LOG(LOG_INFO, (MOD_HAL | MOD_PHY), "phy_patch: U%u P%u portOffset:%u patch_mode:%u\n", unit, port, portOffset, patch_mode); ++ ++ for (i = 0; i < RTK_PATCH_SEQ_MAX; i++) ++ { ++ patch_type = table[i].patch_type; ++ RT_LOG(LOG_INFO, (MOD_HAL | MOD_PHY), "phy_patch: table[%u] patch_type:%u\n", i, patch_type); ++ ++ if (RTK_PATCH_TYPE_IS_DATA(patch_type)) ++ { ++ ret = _phy_patch_process(unit, port, portOffset, table[i].patch.data.conf, table[i].patch.data.size, patch_mode); ++ ++ if (ret == RT_ERR_CHECK_FAILED) ++ chk_ret = ret; ++ else if (ret != RT_ERR_OK) ++ { ++ RT_LOG(LOG_MAJOR_ERR, (MOD_HAL | MOD_PHY), "U%u P%u patch_mode:%u id:%u patch-%u failed. ret:0x%X\n", unit, port, patch_mode, i, patch_type, ret); ++ return ret; ++ } ++ } ++ else if (RTK_PATCH_TYPE_IS_FLOW(patch_type)) ++ { ++ RT_ERR_CHK_EHDL(pPatchDb->fPatch_flow(unit, port, portOffset, table[i].patch.flow_id, patch_mode), ++ ret, RT_LOG(LOG_MAJOR_ERR, (MOD_HAL | MOD_PHY), "U%u P%u patch_mode:%u id:%u patch-%u failed. ret:0x%X\n", unit, port, patch_mode, i, patch_type, ret);); ++ } ++ else ++ { ++ break; ++ } ++ } ++ ret = _phy_patch_process(unit, port, portOffset, rtl826XB_patch_rtk_conf, sizeof(rtl826XB_patch_rtk_conf), patch_mode); ++ if (ret == RT_ERR_CHECK_FAILED) ++ chk_ret = ret; ++ else if (ret != RT_ERR_OK) ++ { ++ RT_LOG(LOG_MAJOR_ERR, (MOD_HAL | MOD_PHY), "U%u P%u patch_mode:%u id:%u patch-%u failed. ret:0x%X\n", unit, port, patch_mode, i, patch_type, ret); ++ return ret; ++ } ++ ++ return (chk_ret == RT_ERR_CHECK_FAILED) ? chk_ret : RT_ERR_OK; ++} +diff --git a/drivers/net/phy/rtl8261n/phy_patch.h b/drivers/net/phy/rtl8261n/phy_patch.h +new file mode 100644 +index 000000000000..c2b7b1279c7e +--- /dev/null ++++ b/drivers/net/phy/rtl8261n/phy_patch.h +@@ -0,0 +1,174 @@ ++/* ++ * SPDX-License-Identifier: GPL-2.0-only ++ * ++ * Copyright (c) 2023 Realtek Semiconductor Corp. All rights reserved. ++ */ ++ ++#ifndef __HAL_PHY_PATCH_H__ ++#define __HAL_PHY_PATCH_H__ ++ ++/* ++ * Include Files ++ */ ++#if defined(RTK_PHYDRV_IN_LINUX) ++ #include "rtk_phylib_def.h" ++#else ++ #include ++ #include ++#endif ++ ++/* ++ * Symbol Definition ++ */ ++#define PHYPATCH_PHYCTRL_IN_HALCTRL 0 /* 3.6.x: 1 ,4.0.x: 1, 4.1.x+: 0 */ ++#define PHYPATCH_FMAILY_IN_HWP 0 /* 3.6.x: 1 ,4.0.x: 0, 4.1.x+: 0 */ ++#define PHY_PATCH_MODE_BCAST_DEFAULT PHY_PATCH_MODE_BCAST /* 3.6.x: PHY_PATCH_MODE_BCAST_BUS ,4.0.x+: PHY_PATCH_MODE_BCAST */ ++ ++#define PHY_PATCH_MODE_NORMAL 0 ++#define PHY_PATCH_MODE_CMP 1 ++#define PHY_PATCH_MODE_BCAST 2 ++#define PHY_PATCH_MODE_BCAST_BUS 3 ++ ++#define RTK_PATCH_CMP_W 0 /* write */ ++#define RTK_PATCH_CMP_WC 1 /* compare */ ++#define RTK_PATCH_CMP_SWC 2 /* sram compare */ ++#define RTK_PATCH_CMP_WS 3 /* skip */ ++ ++#define RTK_PATCH_OP_SECTION_SIZE 50 ++#define RTK_PATCH_OP_TO_CMP(_op, _cmp) (_op + (RTK_PATCH_OP_SECTION_SIZE * _cmp)) ++/* 0~49 normal op */ ++#define RTK_PATCH_OP_PHY 0 ++#define RTK_PATCH_OP_PHYOCP 1 ++#define RTK_PATCH_OP_TOP 2 ++#define RTK_PATCH_OP_TOPOCP 3 ++#define RTK_PATCH_OP_PSDS0 4 ++#define RTK_PATCH_OP_PSDS1 5 ++#define RTK_PATCH_OP_MSDS 6 ++#define RTK_PATCH_OP_MAC 7 ++ ++/* 50~99 normal op for compare */ ++#define RTK_PATCH_OP_CMP_PHY RTK_PATCH_OP_TO_CMP(RTK_PATCH_OP_PHY , RTK_PATCH_CMP_WC) ++#define RTK_PATCH_OP_CMP_PHYOCP RTK_PATCH_OP_TO_CMP(RTK_PATCH_OP_PHYOCP , RTK_PATCH_CMP_WC) ++#define RTK_PATCH_OP_CMP_TOP RTK_PATCH_OP_TO_CMP(RTK_PATCH_OP_TOP , RTK_PATCH_CMP_WC) ++#define RTK_PATCH_OP_CMP_TOPOCP RTK_PATCH_OP_TO_CMP(RTK_PATCH_OP_TOPOCP , RTK_PATCH_CMP_WC) ++#define RTK_PATCH_OP_CMP_PSDS0 RTK_PATCH_OP_TO_CMP(RTK_PATCH_OP_PSDS0 , RTK_PATCH_CMP_WC) ++#define RTK_PATCH_OP_CMP_PSDS1 RTK_PATCH_OP_TO_CMP(RTK_PATCH_OP_PSDS1 , RTK_PATCH_CMP_WC) ++#define RTK_PATCH_OP_CMP_MSDS RTK_PATCH_OP_TO_CMP(RTK_PATCH_OP_MSDS , RTK_PATCH_CMP_WC) ++#define RTK_PATCH_OP_CMP_MAC RTK_PATCH_OP_TO_CMP(RTK_PATCH_OP_MAC , RTK_PATCH_CMP_WC) ++ ++/* 100~149 normal op for sram compare */ ++#define RTK_PATCH_OP_CMP_SRAM_PHY RTK_PATCH_OP_TO_CMP(RTK_PATCH_OP_PHY , RTK_PATCH_CMP_SWC) ++#define RTK_PATCH_OP_CMP_SRAM_PHYOCP RTK_PATCH_OP_TO_CMP(RTK_PATCH_OP_PHYOCP , RTK_PATCH_CMP_SWC) ++#define RTK_PATCH_OP_CMP_SRAM_TOP RTK_PATCH_OP_TO_CMP(RTK_PATCH_OP_TOP , RTK_PATCH_CMP_SWC) ++#define RTK_PATCH_OP_CMP_SRAM_TOPOCP RTK_PATCH_OP_TO_CMP(RTK_PATCH_OP_TOPOCP , RTK_PATCH_CMP_SWC) ++#define RTK_PATCH_OP_CMP_SRAM_PSDS0 RTK_PATCH_OP_TO_CMP(RTK_PATCH_OP_PSDS0 , RTK_PATCH_CMP_SWC) ++#define RTK_PATCH_OP_CMP_SRAM_PSDS1 RTK_PATCH_OP_TO_CMP(RTK_PATCH_OP_PSDS1 , RTK_PATCH_CMP_SWC) ++#define RTK_PATCH_OP_CMP_SRAM_MSDS RTK_PATCH_OP_TO_CMP(RTK_PATCH_OP_MSDS , RTK_PATCH_CMP_SWC) ++#define RTK_PATCH_OP_CMP_SRAM_MAC RTK_PATCH_OP_TO_CMP(RTK_PATCH_OP_MAC , RTK_PATCH_CMP_SWC) ++ ++/* 200~255 control op */ ++#define RTK_PATCH_OP_DELAY_MS 200 ++#define RTK_PATCH_OP_SKIP 255 ++ ++ ++/* ++ patch type PHY_PATCH_TYPE_NONE => empty ++ patch type: PHY_PATCH_TYPE_TOP ~ (PHY_PATCH_TYPE_END-1) => data array ++ patch type: PHY_PATCH_TYPE_END ~ (PHY_PATCH_TYPE_END + RTK_PATCH_TYPE_FLOW_MAX) => flow ++*/ ++#define RTK_PATCH_TYPE_IS_DATA(_patch_type) (_patch_type > PHY_PATCH_TYPE_NONE && _patch_type < PHY_PATCH_TYPE_END) ++#define RTK_PATCH_TYPE_IS_FLOW(_patch_type) (_patch_type >= PHY_PATCH_TYPE_END && _patch_type <= (PHY_PATCH_TYPE_END + RTK_PATCH_TYPE_FLOWID_MAX)) ++ ++ ++/* ++ * Macro Definition ++ */ ++#if PHYPATCH_PHYCTRL_IN_HALCTRL ++ #define PHYPATCH_DB_GET(_unit, _port, _pPatchDb) \ ++ do {\ ++ hal_control_t *pHalCtrl = NULL;\ ++ if ((pHalCtrl = hal_ctrlInfo_get(_unit)) == NULL)\ ++ return RT_ERR_FAILED;\ ++ _pPatchDb = (pHalCtrl->pPhy_ctrl[_port]->pPhy_patchDb);\ ++ } while(0) ++#else ++ #if defined(RTK_PHYDRV_IN_LINUX) ++ #else ++ #include ++ #include ++ #endif ++ #define PHYPATCH_DB_GET(_unit, _port, _pPatchDb) \ ++ do {\ ++ rt_phyctrl_t *pPhyCtrl = NULL;\ ++ if ((pPhyCtrl = phy_phyctrl_get(_unit, _port)) == NULL)\ ++ return RT_ERR_FAILED;\ ++ _pPatchDb = (pPhyCtrl->pPhy_patchDb);\ ++ } while(0) ++#endif ++ ++#if PHYPATCH_FMAILY_IN_HWP ++ #define PHYPATCH_IS_RTKSDS(_unit) (HWP_9300_FAMILY_ID(_unit) || HWP_9310_FAMILY_ID(_unit)) ++#else ++ #define PHYPATCH_IS_RTKSDS(_unit) (RTK_9300_FAMILY_ID(_unit) || RTK_9310_FAMILY_ID(_unit) || RTK_9311B_FAMILY_ID(_unit) || RTK_9330_FAMILY_ID(_unit)) ++#endif ++ ++#define PHYPATCH_TABLE_ASSIGN(_pPatchDb, _table, _idx, _patch_type, _para) \ ++ do {\ ++ if (RTK_PATCH_TYPE_IS_DATA(_patch_type)) {\ ++ _pPatchDb->_table[_idx].patch_type = _patch_type;\ ++ _pPatchDb->_table[_idx].patch.data.conf = _para;\ ++ _pPatchDb->_table[_idx].patch.data.size = sizeof(_para);\ ++ }\ ++ else if (RTK_PATCH_TYPE_IS_FLOW(_patch_type)) {\ ++ _pPatchDb->_table[_idx].patch_type = _patch_type;\ ++ _pPatchDb->_table[_idx].patch.flow_id = _patch_type;\ ++ }\ ++ else {\ ++ _pPatchDb->_table[_idx].patch_type = PHY_PATCH_TYPE_NONE;\ ++ }\ ++ } while(0) ++#define PHYPATCH_SEQ_TABLE_ASSIGN(_pPatchDb, _idx, _patch_type, _para) PHYPATCH_TABLE_ASSIGN(_pPatchDb, seq_table, _idx, _patch_type, _para) ++#define PHYPATCH_CMP_TABLE_ASSIGN(_pPatchDb, _idx, _patch_type, _para) PHYPATCH_TABLE_ASSIGN(_pPatchDb, cmp_table, _idx, _patch_type, _para) ++ ++#define PHYPATCH_COMPARE(_mmdpage, _reg, _msb, _lsb, _exp, _real, _mask) \ ++ do {\ ++ uint32 _rData = REG32_FIELD_GET(_real, _lsb, _mask);\ ++ if (_exp != _rData) {\ ++ osal_printf("PATCH CHECK: %u(0x%X).%u(0x%X)[%u:%u] = 0x%X (!= 0x%X)\n", _mmdpage, _mmdpage, _reg, _reg, _msb, _lsb, _rData, _exp);\ ++ return RT_ERR_CHECK_FAILED;\ ++ }\ ++ } while (0) ++ ++/* ++ * Function Declaration ++ */ ++ ++extern uint8 phy_patch_op_translate(uint8 patch_mode, uint8 patch_op, uint8 compare_op); ++extern int32 phy_patch_op(rt_phy_patch_db_t *pPhy_patchDb, uint32 unit, rtk_port_t port, uint8 portOffset, ++ uint8 patch_op, uint16 portmask, uint16 pagemmd, uint16 addr, uint8 msb, uint8 lsb, uint16 data, ++ uint8 patch_mode); ++ ++ ++/* Function Name: ++ * phy_patch ++ * Description: ++ * apply initial patch data to PHY ++ * Input: ++ * unit - unit id ++ * port - port id ++ * portOffset - the index offset of port based the base port in the PHY chip ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_CHECK_FAILED ++ * RT_ERR_NOT_SUPPORTED ++ * Note: ++ * None ++ */ ++extern int32 phy_patch(uint32 unit, rtk_port_t port, uint8 portOffset, uint8 patch_mode); ++ ++ ++ ++#endif /* __HAL_PHY_PATCH_H__ */ +diff --git a/drivers/net/phy/rtl8261n/phy_rtl826xb_patch.c b/drivers/net/phy/rtl8261n/phy_rtl826xb_patch.c +new file mode 100644 +index 000000000000..0bfd93033f83 +--- /dev/null ++++ b/drivers/net/phy/rtl8261n/phy_rtl826xb_patch.c +@@ -0,0 +1,1031 @@ ++/* ++ * SPDX-License-Identifier: GPL-2.0-only ++ * ++ * Copyright (c) 2023 Realtek Semiconductor Corp. All rights reserved. ++ */ ++ ++/* ++ * Include Files ++ */ ++#if defined(RTK_PHYDRV_IN_LINUX) ++ #include "phy_rtl826xb_patch.h" ++ #include "construct/conf_rtl8264b.c" ++ #include "construct/conf_rtl8261n_c.c" ++#else ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ #if defined(CONFIG_SDK_RTL826XB) ++ #include ++ #include ++ #include ++ #endif ++#endif ++/* ++ * Symbol Definition ++ */ ++#define PHY_PATCH_WAIT_TIMEOUT 10000000 ++ ++#define PHY_PATCH_LOG LOG_INFO ++ ++/* ++ * Data Declaration ++ */ ++ ++/* ++ * Macro Declaration ++ */ ++ ++/* ++ * Function Declaration ++ */ ++static uint16 _phy_rtl826xb_mmd_convert(uint16 page, uint16 addr) ++{ ++ uint16 reg = 0; ++ if (addr < 16) ++ { ++ reg = 0xA400 + (page * 2); ++ } ++ else if (addr < 24) ++ { ++ reg = (16*page) + ((addr - 16) * 2); ++ } ++ else ++ { ++ reg = 0xA430 + ((addr - 24) * 2); ++ } ++ return reg; ++} ++ ++static int32 ++_phy_rtl826xb_patch_wait(uint32 unit, rtk_port_t port, uint32 mmdAddr, uint32 mmdReg, uint32 data, uint32 mask, uint8 patch_mode) ++{ ++ int32 ret = 0; ++ uint32 rData = 0; ++ uint32 cnt = 0; ++ WAIT_COMPLETE_VAR() ++ ++ rtk_port_t p = 0; ++ uint8 smiBus = HWP_PORT_SMI(unit, port); ++ uint32 phyChip = HWP_PHY_MODEL_BY_PORT(unit, port); ++ uint8 bcast_phyad = HWP_PHY_ADDR(unit, port);; ++ ++ ++ if (patch_mode == PHY_PATCH_MODE_BCAST_BUS) ++ { ++ if ((ret = phy_826xb_ctrl_set(unit, port, RTK_PHY_CTRL_MIIM_BCAST, 0)) != RT_ERR_OK) ++ { ++ RT_LOG(LOG_MAJOR_ERR, (MOD_HAL | MOD_PHY), "U%u P%u 826XB patch wait disable broadcast failed! 0x%X\n", unit, p, ret); ++ return ret; ++ } ++ ++ HWP_PORT_TRAVS_EXCEPT_CPU(unit, p) ++ { ++ if ((HWP_PORT_SMI(unit, p) == smiBus) && (HWP_PHY_MODEL_BY_PORT(unit, p) == phyChip)) ++ { ++ WAIT_COMPLETE(PHY_PATCH_WAIT_TIMEOUT) ++ { ++ if ((ret = phy_common_general_reg_mmd_get(unit, p, mmdAddr, mmdReg, &rData)) != RT_ERR_OK) ++ { ++ return ret; ++ } ++ ++cnt; ++ ++ if ((rData & mask) == data) ++ break; ++ ++ //osal_time_udelay(10); ++ } ++ ++ if (WAIT_COMPLETE_IS_TIMEOUT()) ++ { ++ RT_LOG(LOG_MAJOR_ERR, (MOD_HAL | MOD_PHY), "U%u P%u 826XB patch wait[%u,0x%X,0x%X,0x%X]:0x%X cnt:%u\n", unit, p, mmdAddr, mmdReg, data, mask, rData, cnt); ++ return RT_ERR_TIMEOUT; ++ } ++ } ++ } ++ ++ osal_time_mdelay(1); ++ //for port in same SMI bus, set mdio broadcast ENABLE ++ HWP_PORT_TRAVS_EXCEPT_CPU(unit, p) ++ { ++ if ((HWP_PORT_SMI(unit, p) == smiBus) && (HWP_PHY_MODEL_BY_PORT(unit, p) == phyChip)) ++ { ++ if ((ret = phy_826xb_ctrl_set(unit, p, RTK_PHY_CTRL_MIIM_BCAST_PHYAD, (uint32)bcast_phyad)) != RT_ERR_OK) ++ { ++ RT_LOG(LOG_MAJOR_ERR, (MOD_HAL | MOD_PHY), "U%u P%u 826XB patch wait set broadcast PHYAD failed! 0x%X\n", unit, p, ret); ++ return ret; ++ } ++ ++ if ((ret = phy_826xb_ctrl_set(unit, p, RTK_PHY_CTRL_MIIM_BCAST, 1)) != RT_ERR_OK) ++ { ++ RT_LOG(LOG_MAJOR_ERR, (MOD_HAL | MOD_PHY), "U%u P%u 826XB patch wait enable broadcast failed! 0x%X\n", unit, p, ret); ++ return ret; ++ } ++ } ++ } ++ } ++ else if (patch_mode == PHY_PATCH_MODE_BCAST) ++ { ++ if ((ret = phy_826xb_ctrl_set(unit, port, RTK_PHY_CTRL_MIIM_BCAST, 0)) != RT_ERR_OK) ++ { ++ RT_LOG(LOG_MAJOR_ERR, (MOD_HAL | MOD_PHY), "U%u P%u 826x patch wait disable broadcast failed! 0x%X\n", unit, p, ret); ++ return ret; ++ } ++ ++ HWP_PORT_TRAVS_EXCEPT_CPU(unit, p) ++ { ++ if (HWP_PHY_BASE_MACID(unit, p) == HWP_PHY_BASE_MACID(unit, port)) ++ { ++ WAIT_COMPLETE(PHY_PATCH_WAIT_TIMEOUT) ++ { ++ if ((ret = phy_common_general_reg_mmd_get(unit, p, mmdAddr, mmdReg, &rData)) != RT_ERR_OK) ++ { ++ return ret; ++ } ++ ++cnt; ++ ++ if ((rData & mask) == data) ++ break; ++ //osal_time_udelay(10); ++ } ++ ++ if (WAIT_COMPLETE_IS_TIMEOUT()) ++ { ++ RT_LOG(LOG_MAJOR_ERR, (MOD_HAL | MOD_PHY), "U%u P%u 826x patch wait[%u,0x%X,0x%X,0x%X]:0x%X cnt:%u\n", unit, p, mmdAddr, mmdReg, data, mask, rData, cnt); ++ return RT_ERR_TIMEOUT; ++ } ++ } ++ } ++ ++ osal_time_mdelay(1); ++ //for port in same PHY, set mdio broadcast ENABLE ++ HWP_PORT_TRAVS_EXCEPT_CPU(unit, p) ++ { ++ if (HWP_PHY_BASE_MACID(unit, p) == HWP_PHY_BASE_MACID(unit, port)) ++ { ++ if ((ret = phy_826xb_ctrl_set(unit, p, RTK_PHY_CTRL_MIIM_BCAST_PHYAD, (uint32)bcast_phyad)) != RT_ERR_OK) ++ { ++ RT_LOG(LOG_MAJOR_ERR, (MOD_HAL | MOD_PHY), "U%u P%u 826XB patch wait set broadcast PHYAD failed! 0x%X\n", unit, p, ret); ++ return ret; ++ } ++ ++ if ((ret = phy_826xb_ctrl_set(unit, p, RTK_PHY_CTRL_MIIM_BCAST, 1)) != RT_ERR_OK) ++ { ++ RT_LOG(LOG_MAJOR_ERR, (MOD_HAL | MOD_PHY), "U%u P%u 826XB patch wait enable broadcast failed! 0x%X\n", unit, p, ret); ++ return ret; ++ } ++ } ++ } ++ } ++ else ++ { ++ WAIT_COMPLETE(PHY_PATCH_WAIT_TIMEOUT) ++ { ++ if ((ret = phy_common_general_reg_mmd_get(unit, port, mmdAddr, mmdReg, &rData)) != RT_ERR_OK) ++ return ret; ++ ++ ++cnt; ++ if ((rData & mask) == data) ++ break; ++ ++ osal_time_mdelay(1); ++ } ++ ++ if (WAIT_COMPLETE_IS_TIMEOUT()) ++ { ++ RT_LOG(LOG_MAJOR_ERR, (MOD_HAL | MOD_PHY), "U%u P%u 826XB patch wait[%u,0x%X,0x%X,0x%X]:0x%X cnt:%u\n", unit, port, mmdAddr, mmdReg, data, mask, rData, cnt); ++ return RT_ERR_TIMEOUT; ++ } ++ } ++ ++ return RT_ERR_OK; ++} ++ ++static int32 ++_phy_rtl826xb_patch_wait_not_equal(uint32 unit, rtk_port_t port, uint32 mmdAddr, uint32 mmdReg, uint32 data, uint32 mask, uint8 patch_mode) ++{ ++ int32 ret = 0; ++ uint32 rData = 0; ++ uint32 cnt = 0; ++ WAIT_COMPLETE_VAR() ++ ++ rtk_port_t p = 0; ++ uint8 smiBus = HWP_PORT_SMI(unit, port); ++ uint32 phyChip = HWP_PHY_MODEL_BY_PORT(unit, port); ++ uint8 bcast_phyad = HWP_PHY_ADDR(unit, port); ++ ++ if (patch_mode == PHY_PATCH_MODE_BCAST_BUS) ++ { ++ if ((ret = phy_826xb_ctrl_set(unit, port, RTK_PHY_CTRL_MIIM_BCAST, 0)) != RT_ERR_OK) ++ { ++ RT_LOG(LOG_MAJOR_ERR, (MOD_HAL | MOD_PHY), "U%u P%u 826XB patch wait disable broadcast failed! 0x%X\n", unit, p, ret); ++ return ret; ++ } ++ ++ HWP_PORT_TRAVS_EXCEPT_CPU(unit, p) ++ { ++ if ((HWP_PORT_SMI(unit, p) == smiBus) && (HWP_PHY_MODEL_BY_PORT(unit, p) == phyChip)) ++ { ++ WAIT_COMPLETE(PHY_PATCH_WAIT_TIMEOUT) ++ { ++ if ((ret = phy_common_general_reg_mmd_get(unit, p, mmdAddr, mmdReg, &rData)) != RT_ERR_OK) ++ { ++ return ret; ++ } ++ ++cnt; ++ ++ if ((rData & mask) != data) ++ break; ++ ++ //osal_time_udelay(10); ++ } ++ if (WAIT_COMPLETE_IS_TIMEOUT()) ++ { ++ RT_LOG(LOG_MAJOR_ERR, (MOD_HAL | MOD_PHY), "U%u P%u 826XB patch wait[%u,0x%X,0x%X,0x%X]:0x%X cnt:%u\n", unit, p, mmdAddr, mmdReg, data, mask, rData, cnt); ++ return RT_ERR_TIMEOUT; ++ } ++ } ++ } ++ ++ osal_time_mdelay(1); ++ //for port in same SMI bus, set mdio broadcast ENABLE ++ HWP_PORT_TRAVS_EXCEPT_CPU(unit, p) ++ { ++ if ((HWP_PORT_SMI(unit, p) == smiBus) && (HWP_PHY_MODEL_BY_PORT(unit, p) == phyChip)) ++ { ++ if ((ret = phy_826xb_ctrl_set(unit, p, RTK_PHY_CTRL_MIIM_BCAST_PHYAD, (uint32)bcast_phyad)) != RT_ERR_OK) ++ { ++ RT_LOG(LOG_MAJOR_ERR, (MOD_HAL | MOD_PHY), "U%u P%u 826XB patch wait set broadcast PHYAD failed! 0x%X\n", unit, p, ret); ++ return ret; ++ } ++ ++ if ((ret = phy_826xb_ctrl_set(unit, p, RTK_PHY_CTRL_MIIM_BCAST, 1)) != RT_ERR_OK) ++ { ++ RT_LOG(LOG_MAJOR_ERR, (MOD_HAL | MOD_PHY), "U%u P%u 826XB patch wait enable broadcast failed! 0x%X\n", unit, p, ret); ++ return ret; ++ } ++ } ++ } ++ } ++ else if (patch_mode == PHY_PATCH_MODE_BCAST) ++ { ++ if ((ret = phy_826xb_ctrl_set(unit, port, RTK_PHY_CTRL_MIIM_BCAST, 0)) != RT_ERR_OK) ++ { ++ RT_LOG(LOG_MAJOR_ERR, (MOD_HAL | MOD_PHY), "U%u P%u 826x patch wait disable broadcast failed! 0x%X\n", unit, p, ret); ++ return ret; ++ } ++ ++ HWP_PORT_TRAVS_EXCEPT_CPU(unit, p) ++ { ++ if (HWP_PHY_BASE_MACID(unit, p) == HWP_PHY_BASE_MACID(unit, port)) ++ { ++ WAIT_COMPLETE(PHY_PATCH_WAIT_TIMEOUT) ++ { ++ if ((ret = phy_common_general_reg_mmd_get(unit, p, mmdAddr, mmdReg, &rData)) != RT_ERR_OK) ++ { ++ return ret; ++ } ++ ++cnt; ++ ++ if (((rData & mask) != data)) ++ break; ++ ++ //osal_time_udelay(10); ++ } ++ ++ if (WAIT_COMPLETE_IS_TIMEOUT()) ++ { ++ RT_LOG(LOG_MAJOR_ERR, (MOD_HAL | MOD_PHY), "U%u P%u 826XB patch wait[%u,0x%X,0x%X,0x%X]:0x%X cnt:%u\n", unit, p, mmdAddr, mmdReg, data, mask, rData, cnt); ++ return RT_ERR_TIMEOUT; ++ } ++ } ++ } ++ ++ osal_time_mdelay(1); ++ //for port in same PHY, set mdio broadcast ENABLE ++ HWP_PORT_TRAVS_EXCEPT_CPU(unit, p) ++ { ++ if (HWP_PHY_BASE_MACID(unit, p) == HWP_PHY_BASE_MACID(unit, port)) ++ { ++ if ((ret = phy_826xb_ctrl_set(unit, p, RTK_PHY_CTRL_MIIM_BCAST_PHYAD, (uint32)bcast_phyad)) != RT_ERR_OK) ++ { ++ RT_LOG(LOG_MAJOR_ERR, (MOD_HAL | MOD_PHY), "U%u P%u 826XB patch wait set broadcast PHYAD failed! 0x%X\n", unit, p, ret); ++ return ret; ++ } ++ ++ if ((ret = phy_826xb_ctrl_set(unit, p, RTK_PHY_CTRL_MIIM_BCAST, 1)) != RT_ERR_OK) ++ { ++ RT_LOG(LOG_MAJOR_ERR, (MOD_HAL | MOD_PHY), "U%u P%u 826XB patch wait enable broadcast failed! 0x%X\n", unit, p, ret); ++ return ret; ++ } ++ } ++ } ++ } ++ else ++ { ++ WAIT_COMPLETE(PHY_PATCH_WAIT_TIMEOUT) ++ { ++ if ((ret = phy_common_general_reg_mmd_get(unit, port, mmdAddr, mmdReg, &rData)) != RT_ERR_OK) ++ return ret; ++ ++ ++cnt; ++ if ((rData & mask) != data) ++ break; ++ ++ osal_time_mdelay(1); ++ } ++ if (WAIT_COMPLETE_IS_TIMEOUT()) ++ { ++ RT_LOG(LOG_MAJOR_ERR, (MOD_HAL | MOD_PHY), "U%u P%u 826xb patch wait[%u,0x%X,0x%X,0x%X]:0x%X cnt:%u\n", unit, port, mmdAddr, mmdReg, data, mask, rData, cnt); ++ return RT_ERR_TIMEOUT; ++ } ++ ++ } ++ ++ return RT_ERR_OK; ++} ++ ++static int32 ++_phy_rtl826xb_patch_top_get(uint32 unit, rtk_port_t port, uint32 topPage, uint32 topReg, uint32 *pData) ++{ ++ int32 ret = 0; ++ uint32 rData = 0; ++ uint32 topAddr = (topPage * 8) + (topReg - 16); ++ ++ if ((ret = phy_common_general_reg_mmd_get(unit, port, PHY_MMD_VEND1, topAddr, &rData)) != RT_ERR_OK) ++ return ret; ++ *pData = rData; ++ return RT_ERR_OK; ++} ++ ++static int32 ++_phy_rtl826xb_patch_top_set(uint32 unit, rtk_port_t port, uint32 topPage, uint32 topReg, uint32 wData) ++{ ++ int32 ret = 0; ++ uint32 topAddr = (topPage * 8) + (topReg - 16); ++ if ((ret = phy_common_general_reg_mmd_set(unit, port, PHY_MMD_VEND1, topAddr, wData)) != RT_ERR_OK) ++ return ret; ++ return RT_ERR_OK; ++} ++ ++static int32 ++_phy_rtl826xb_patch_sds_get(uint32 unit, rtk_port_t port, uint32 sdsPage, uint32 sdsReg, uint32 *pData) ++{ ++ int32 ret = 0; ++ uint32 rData = 0; ++ uint32 sdsAddr = 0x8000 + (sdsReg << 6) + sdsPage; ++ ++ if ((ret = _phy_rtl826xb_patch_top_set(unit, port, 40, 19, sdsAddr)) != RT_ERR_OK) ++ return ret; ++ if ((ret = _phy_rtl826xb_patch_top_get(unit, port, 40, 18, &rData)) != RT_ERR_OK) ++ return ret; ++ *pData = rData; ++ return _phy_rtl826xb_patch_wait(unit, port, PHY_MMD_VEND1, 0x143, 0, BIT_15, PHY_PATCH_MODE_NORMAL); ++} ++ ++static int32 ++_phy_rtl826xb_patch_sds_set(uint32 unit, rtk_port_t port, uint32 sdsPage, uint32 sdsReg, uint32 wData, uint8 patch_mode) ++{ ++ int32 ret = 0; ++ uint32 sdsAddr = 0x8800 + (sdsReg << 6) + sdsPage; ++ ++ if ((ret = _phy_rtl826xb_patch_top_set(unit, port, 40, 17, wData)) != RT_ERR_OK) ++ return ret; ++ if ((ret = _phy_rtl826xb_patch_top_set(unit, port, 40, 19, sdsAddr)) != RT_ERR_OK) ++ return ret; ++ return _phy_rtl826xb_patch_wait(unit, port, PHY_MMD_VEND1, 0x143, 0, BIT_15, patch_mode); ++} ++ ++static int32 _phy_rtl826xb_flow_r1(uint32 unit, rtk_port_t port, uint8 portOffset, uint8 patch_mode) ++{ ++ int32 ret = RT_ERR_OK; ++ rt_phy_patch_db_t *pPatchDb = NULL; ++ ++ PHYPATCH_DB_GET(unit, port, pPatchDb); ++ ++ //PHYReg_bit w $PHYID 0xb82 16 4 4 0x1 ++ RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xb82, 16, 4, 4, 0x1, patch_mode), ret); ++ //PHYReg_bit w $PHYID 0xb82 16 4 4 0x1 ++ RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xb82, 16, 4, 4, 0x1, patch_mode), ret); ++ ++ //set patch_rdy [PHYReg_bit r $PHYID 0xb80 16 6 6] ; Wait for patch ready = 1 ++ RT_ERR_CHK(_phy_rtl826xb_patch_wait(unit, port, 31, _phy_rtl826xb_mmd_convert(0xb80, 16), BIT_6, BIT_6, patch_mode), ret); ++ ++ //PHYReg w $PHYID 0xa43 27 $0x8023 ++ RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa43, 27, 15, 0, 0x8023, patch_mode), ret); ++ //PHYReg w $PHYID 0xa43 28 $0x3802 ++ RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa43, 28, 15, 0, 0x3802, patch_mode), ret); ++ //PHYReg w $PHYID 0xa43 27 0xB82E ++ RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa43, 27, 15, 0, 0xB82E, patch_mode), ret); ++ //PHYReg w $PHYID 0xa43 28 0x1 ++ RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa43, 28, 15, 0, 0x1, patch_mode), ret); ++ ++ return RT_ERR_OK; ++} ++ ++static int32 _phy_rtl826xb_flow_r12(uint32 unit, rtk_port_t port, uint8 portOffset, uint8 patch_mode) ++{ ++ int32 ret = RT_ERR_OK; ++ rt_phy_patch_db_t *pPatchDb = NULL; ++ ++ PHYPATCH_DB_GET(unit, port, pPatchDb); ++ ++ //PHYReg_bit w $PHYID 0xb82 16 4 4 0x1 ++ RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xb82, 16, 4, 4, 0x1, patch_mode), ret); ++ //PHYReg_bit w $PHYID 0xb82 16 4 4 0x1 ++ RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xb82, 16, 4, 4, 0x1, patch_mode), ret); ++ ++ //set patch_rdy [PHYReg_bit r $PHYID 0xb80 16 6 6] ; Wait for patch ready = 1 ++ RT_ERR_CHK(_phy_rtl826xb_patch_wait(unit, port, 31, _phy_rtl826xb_mmd_convert(0xb80, 16), BIT_6, BIT_6, patch_mode), ret); ++ ++ //PHYReg w $PHYID 0xa43 27 $0x8023 ++ RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa43, 27, 15, 0, 0x8023, patch_mode), ret); ++ //PHYReg w $PHYID 0xa43 28 $0x3800 ++ RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa43, 28, 15, 0, 0x3800, patch_mode), ret); ++ //PHYReg w $PHYID 0xa43 27 0xB82E ++ RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa43, 27, 15, 0, 0xB82E, patch_mode), ret); ++ //PHYReg w $PHYID 0xa43 28 0x1 ++ RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa43, 28, 15, 0, 0x1, patch_mode), ret); ++ ++ return RT_ERR_OK; ++} ++ ++ ++static int32 _phy_rtl826xb_flow_r2(uint32 unit, rtk_port_t port, uint8 portOffset, uint8 patch_mode) ++{ ++ int32 ret = RT_ERR_OK; ++ rt_phy_patch_db_t *pPatchDb = NULL; ++ ++ PHYPATCH_DB_GET(unit, port, pPatchDb); ++ ++ //PHYReg w $PHYID 0xa43 27 0x0000 ++ RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa43, 27, 15, 0, 0x0000, patch_mode), ret); ++ //PHYReg w $PHYID 0xa43 28 0x0000 ++ RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa43, 28, 15, 0, 0x0000, patch_mode), ret); ++ //PHYReg_bit w $PHYID 0xB82 23 0 0 0x0 ++ RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xB82, 23, 0, 0, 0x0, patch_mode), ret); ++ //PHYReg w $PHYID 0xa43 27 $0x8023 ++ RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa43, 27, 15, 0, 0x8023, patch_mode), ret); ++ //PHYReg w $PHYID 0xa43 28 0x0000 ++ RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa43, 28, 15, 0, 0x0000, patch_mode), ret); ++ ++ //PHYReg_bit w $PHYID 0xb82 16 4 4 0x0 ++ RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xb82, 16, 4, 4, 0x0, patch_mode), ret); ++ //set patch_rdy [PHYReg_bit r $PHYID 0xb80 16 6 6] ; Wait for patch ready != 1 ++ RT_ERR_CHK( _phy_rtl826xb_patch_wait_not_equal(unit, port, 31, _phy_rtl826xb_mmd_convert(0xb80, 16), BIT_6, BIT_6, patch_mode), ret); ++ ++ return RT_ERR_OK; ++} ++ ++static int32 _phy_rtl826xb_flow_l1(uint32 unit, rtk_port_t port, uint8 portOffset, uint8 patch_mode) ++{ ++ int32 ret = RT_ERR_OK; ++ rt_phy_patch_db_t *pPatchDb = NULL; ++ ++ PHYPATCH_DB_GET(unit, port, pPatchDb); ++ ++ //PHYReg_bit w $PHYID 0xa4a 16 10 10 0x1 ++ RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa4a, 16, 10, 10, 0x1, patch_mode), ret); ++ //PHYReg_bit w $PHYID 0xa4a 16 10 10 0x1 ++ RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa4a, 16, 10, 10, 0x1, patch_mode), ret); ++ ++ //set pcs_state [PHYReg_bit r $PHYID 0xa60 16 7 0] ; Wait for pcs state = 1 ++ RT_ERR_CHK( _phy_rtl826xb_patch_wait(unit, port, 31, _phy_rtl826xb_mmd_convert(0xa60, 16), 0x1, 0xFF, patch_mode), ret); ++ ++ return RT_ERR_OK; ++} ++ ++static int32 _phy_rtl826xb_flow_l2(uint32 unit, rtk_port_t port, uint8 portOffset, uint8 patch_mode) ++{ ++ int32 ret = RT_ERR_OK; ++ rt_phy_patch_db_t *pPatchDb = NULL; ++ ++ PHYPATCH_DB_GET(unit, port, pPatchDb); ++ ++ //PHYReg_bit w $PHYID 0xa4a 16 10 10 0x0 ++ RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa4a, 16, 10, 10, 0x0, patch_mode), ret); ++ ++ //set pcs_state [PHYReg_bit r $PHYID 0xa60 16 7 0] ; Wait for pcs state != 1 ++ RT_ERR_CHK( _phy_rtl826xb_patch_wait_not_equal(unit, port, 31, _phy_rtl826xb_mmd_convert(0xa60, 16), 0x1, 0xFF, patch_mode), ret); ++ ++ return RT_ERR_OK; ++} ++ ++static int32 _phy_rtl826xb_flow_pi(uint32 unit, rtk_port_t port, uint8 portOffset, uint8 patch_mode) ++{ ++ int32 ret = RT_ERR_OK; ++ rt_phy_patch_db_t *pPatchDb = NULL; ++ uint32 rData = 0, cnt = 0; ++ ++ PHYPATCH_DB_GET(unit, port, pPatchDb); ++ ++ _phy_rtl826xb_flow_l1(unit, port, portOffset, patch_mode); ++ ++ // PP_PHYReg_bit w $PHYID 0xbf86 9 9 0x1; #SS_EN_XG = 1 ++ RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHYOCP, 0xFF, 31, 0xbf86, 9, 9, 0x1, patch_mode), ret); ++ // PP_PHYReg_bit w $PHYID 0xbf86 8 8 0x0; ++ RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHYOCP, 0xFF, 31, 0xbf86, 8, 8, 0x0, patch_mode), ret); ++ // PP_PHYReg_bit w $PHYID 0xbf86 7 7 0x1; ++ RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHYOCP, 0xFF, 31, 0xbf86, 7, 7, 0x1, patch_mode), ret); ++ // PP_PHYReg_bit w $PHYID 0xbf86 6 6 0x1; ++ RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHYOCP, 0xFF, 31, 0xbf86, 6, 6, 0x1, patch_mode), ret); ++ // PP_PHYReg_bit w $PHYID 0xbf86 5 5 0x1; ++ RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHYOCP, 0xFF, 31, 0xbf86, 5, 5, 0x1, patch_mode), ret); ++ // PP_PHYReg_bit w $PHYID 0xbf86 4 4 0x1; ++ RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHYOCP, 0xFF, 31, 0xbf86, 4, 4, 0x1, patch_mode), ret); ++ // PP_PHYReg_bit w $PHYID 0xbf86 6 6 0x0; ++ RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHYOCP, 0xFF, 31, 0xbf86, 6, 6, 0x0, patch_mode), ret); ++ // PP_PHYReg_bit w $PHYID 0xbf86 9 9 0x0; ++ RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHYOCP, 0xFF, 31, 0xbf86, 9, 9, 0x0, patch_mode), ret); ++ // PP_PHYReg_bit w $PHYID 0xbf86 7 7 0x0; ++ RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHYOCP, 0xFF, 31, 0xbf86, 7, 7, 0x0, patch_mode), ret); ++ ++ //PP_PHYReg_bit r $PHYID 0xbc62 12 8 ++ if ((ret = phy_common_general_reg_mmd_get(unit, port, PHY_MMD_VEND2, 0xbc62, &rData)) != RT_ERR_OK) ++ return ret; ++ rData = REG32_FIELD_GET(rData, 8, 0x1F00); ++ for (cnt = 0; cnt <= rData; cnt++) ++ { ++ //PP_PHYReg_bit w $PHYID 0xbc62 12 8 $t ++ RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHYOCP, 0xFF, 31, 0xbc62, 12, 8, cnt, patch_mode), ret); ++ } ++ ++ // PP_PHYReg_bit w $PHYID 0xbc02 2 2 0x1 ++ RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHYOCP, 0xFF, 31, 0xbc02, 2, 2, 0x1, patch_mode), ret); ++ // PP_PHYReg_bit w $PHYID 0xbc02 3 3 0x1 ++ RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHYOCP, 0xFF, 31, 0xbc02, 3, 3, 0x1, patch_mode), ret); ++ // PP_PHYReg_bit w $PHYID 0xbf86 6 6 0x1 ++ RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHYOCP, 0xFF, 31, 0xbf86, 6, 6, 0x1, patch_mode), ret); ++ // PP_PHYReg_bit w $PHYID 0xbf86 9 9 0x1 ++ RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHYOCP, 0xFF, 31, 0xbf86, 9, 9, 0x1, patch_mode), ret); ++ // PP_PHYReg_bit w $PHYID 0xbf86 7 7 0x1 ++ RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHYOCP, 0xFF, 31, 0xbf86, 7, 7, 0x1, patch_mode), ret); ++ // PP_PHYReg_bit w $PHYID 0xbc04 9 2 0xff ++ RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHYOCP, 0xFF, 31, 0xbc04, 9, 2, 0xff, patch_mode), ret); ++ ++ _phy_rtl826xb_flow_l2(unit, port, portOffset, patch_mode); ++ return RT_ERR_OK; ++} ++ ++static int32 _phy_rtl826xb_flow_n01(uint32 unit, rtk_port_t port, uint8 portOffset, uint8 patch_mode) ++{ ++ int32 ret = RT_ERR_OK; ++ rt_phy_patch_db_t *pPatchDb = NULL; ++ ++ PHYPATCH_DB_GET(unit, port, pPatchDb); ++ ++ //PHYReg_bit w $PHYID 0xa01 21 15 0 0x1 ++ RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa01, 21, 15, 0, 0x1, patch_mode), ret); ++ //PHYReg_bit w $PHYID 0xa01 19 15 0 0x0000 ++ RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa01, 19, 15, 0, 0x0000, patch_mode), ret); ++ //# PHYReg_bit w $PHYID 0xa01 17 15 0 0x0000 ++ //RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa01, 17, 15, 0, 0x0000, patch_mode), ret); ++ ++ return RT_ERR_OK; ++} ++ ++static int32 _phy_rtl826xb_flow_n02(uint32 unit, rtk_port_t port, uint8 portOffset, uint8 patch_mode) ++{ ++ int32 ret = RT_ERR_OK; ++ rt_phy_patch_db_t *pPatchDb = NULL; ++ ++ PHYPATCH_DB_GET(unit, port, pPatchDb); ++ ++ //PHYReg_bit w $PHYID 0xa01 21 15 0 0x0 ++ RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa01, 21, 15, 0, 0x0, patch_mode), ret); ++ //PHYReg_bit w $PHYID 0xa01 19 15 0 0x0000 ++ RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa01, 19, 15, 0, 0x0000, patch_mode), ret); ++ //PHYReg_bit w $PHYID 0xa01 17 15 0 0x0000 ++ RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa01, 17, 15, 0, 0x0000, patch_mode), ret); ++ return RT_ERR_OK; ++} ++ ++static int32 _phy_rtl826xb_flow_n11(uint32 unit, rtk_port_t port, uint8 portOffset, uint8 patch_mode) ++{ ++ int32 ret = RT_ERR_OK; ++ rt_phy_patch_db_t *pPatchDb = NULL; ++ ++ PHYPATCH_DB_GET(unit, port, pPatchDb); ++ ++ //PHYReg_bit w $PHYID 0xa01 21 15 0 0x1 ++ RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa01, 21, 15, 0, 0x1, patch_mode), ret); ++ //PHYReg_bit w $PHYID 0xa01 19 15 0 0x0010 ++ RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa01, 19, 15, 0, 0x0010, patch_mode), ret); ++ //# PHYReg_bit w $PHYID 0xa01 17 15 0 0x0000 ++ //RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa01, 17, 15, 0, 0x0000, patch_mode), ret); ++ ++ return RT_ERR_OK; ++} ++ ++static int32 _phy_rtl826xb_flow_n12(uint32 unit, rtk_port_t port, uint8 portOffset, uint8 patch_mode) ++{ ++ int32 ret = RT_ERR_OK; ++ rt_phy_patch_db_t *pPatchDb = NULL; ++ ++ PHYPATCH_DB_GET(unit, port, pPatchDb); ++ ++ //PHYReg_bit w $PHYID 0xa01 21 15 0 0x0 ++ RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa01, 21, 15, 0, 0x0, patch_mode), ret); ++ //PHYReg_bit w $PHYID 0xa01 19 15 0 0x0010 ++ RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa01, 19, 15, 0, 0x0010, patch_mode), ret); ++ //PHYReg_bit w $PHYID 0xa01 17 15 0 0x0000 ++ RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa01, 17, 15, 0, 0x0000, patch_mode), ret); ++ ++ return RT_ERR_OK; ++} ++ ++static int32 _phy_rtl826xb_flow_n21(uint32 unit, rtk_port_t port, uint8 portOffset, uint8 patch_mode) ++{ ++ int32 ret = RT_ERR_OK; ++ rt_phy_patch_db_t *pPatchDb = NULL; ++ ++ PHYPATCH_DB_GET(unit, port, pPatchDb); ++ ++ //PHYReg_bit w $PHYID 0xa01 21 15 0 0x1 ++ RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa01, 21, 15, 0, 0x1, patch_mode), ret); ++ //PHYReg_bit w $PHYID 0xa01 19 15 0 0x0020 ++ RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa01, 19, 15, 0, 0x0020, patch_mode), ret); ++ //# PHYReg_bit w $PHYID 0xa01 17 15 0 0x0000 ++ //RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa01, 17, 15, 0, 0x0000, patch_mode), ret); ++ ++ return RT_ERR_OK; ++} ++ ++static int32 _phy_rtl826xb_flow_n22(uint32 unit, rtk_port_t port, uint8 portOffset, uint8 patch_mode) ++{ ++ int32 ret = RT_ERR_OK; ++ rt_phy_patch_db_t *pPatchDb = NULL; ++ ++ PHYPATCH_DB_GET(unit, port, pPatchDb); ++ ++ //PHYReg_bit w $PHYID 0xa01 21 15 0 0x0 ++ RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa01, 21, 15, 0, 0x0, patch_mode), ret); ++ //PHYReg_bit w $PHYID 0xa01 19 15 0 0x0020 ++ RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa01, 19, 15, 0, 0x0020, patch_mode), ret); ++ //PHYReg_bit w $PHYID 0xa01 17 15 0 0x0000 ++ RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa01, 17, 15, 0, 0x0000, patch_mode), ret); ++ ++ return RT_ERR_OK; ++} ++ ++static int32 _phy_rtl826xb_flow_s(uint32 unit, rtk_port_t port, uint8 portOffset, uint8 patch_mode) ++{ ++ int32 ret = RT_ERR_OK; ++ rt_phy_patch_db_t *pPatchDb = NULL; ++ ++ if (PHYPATCH_IS_RTKSDS(unit)) ++ { ++ PHYPATCH_DB_GET(unit, port, pPatchDb); ++ RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PSDS0, 0xff, 0x07, 0x10, 15, 0, 0x80aa, patch_mode), ret); ++ RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PSDS0, 0xff, 0x06, 0x12, 15, 0, 0x5078, patch_mode), ret); ++ } ++ ++ return RT_ERR_OK; ++} ++ ++static int32 phy_rtl826xb_patch_op(uint32 unit, rtk_port_t port, uint8 portOffset, rtk_hwpatch_t *pPatch_data, uint8 patch_mode) ++{ ++ int32 ret = RT_ERR_OK; ++ uint32 rData = 0, wData = 0; ++ uint16 reg = 0; ++ uint8 patch_op = 0; ++ uint32 mask = 0; ++ ++ if ((pPatch_data->portmask & (1 << portOffset)) == 0) ++ { ++ return RT_ERR_ABORT; ++ } ++ mask = UINT32_BITS_MASK(pPatch_data->msb, pPatch_data->lsb); ++ patch_op = phy_patch_op_translate(patch_mode, pPatch_data->patch_op, pPatch_data->compare_op); ++ ++ #if 0 ++ osal_printf("[%s,%d]u%up%u, patch_mode:%u/patch_op:%u/compare_op:%u => op: %u\n", __FUNCTION__, __LINE__, unit, port, ++ patch_mode, pPatch_data->patch_op, pPatch_data->compare_op, ++ patch_op); ++ #endif ++ ++ switch (patch_op) ++ { ++ case RTK_PATCH_OP_PHY: ++ reg = _phy_rtl826xb_mmd_convert(pPatch_data->pagemmd, pPatch_data->addr); ++ if ((pPatch_data->msb != 15) || (pPatch_data->lsb != 0)) ++ { ++ RT_ERR_CHK(phy_common_general_reg_mmd_get(unit, port, 31, reg, &rData), ret); ++ } ++ wData = REG32_FIELD_SET(rData, pPatch_data->data, pPatch_data->lsb, mask); ++ RT_ERR_CHK(phy_common_general_reg_mmd_set(unit, port, 31, reg, wData), ret); ++ break; ++ case RTK_PATCH_OP_CMP_PHY: ++ reg = _phy_rtl826xb_mmd_convert(pPatch_data->pagemmd, pPatch_data->addr); ++ RT_ERR_CHK(phy_common_general_reg_mmd_get(unit, port, 31, reg, &rData), ret); ++ PHYPATCH_COMPARE(pPatch_data->pagemmd, pPatch_data->addr, pPatch_data->msb, pPatch_data->lsb, pPatch_data->data, rData, mask); ++ break; ++ case RTK_PATCH_OP_CMP_SRAM_PHY: ++ reg = _phy_rtl826xb_mmd_convert(pPatch_data->sram_p, pPatch_data->sram_rw); ++ RT_ERR_CHK(phy_common_general_reg_mmd_set(unit, port, 31, reg, pPatch_data->sram_a), ret); ++ reg = _phy_rtl826xb_mmd_convert(pPatch_data->sram_p, pPatch_data->sram_rr); ++ RT_ERR_CHK(phy_common_general_reg_mmd_get(unit, port, 31, reg, &rData), ret); ++ PHYPATCH_COMPARE(pPatch_data->pagemmd, pPatch_data->addr, pPatch_data->msb, pPatch_data->lsb, pPatch_data->data, rData, mask); ++ break; ++ ++ case RTK_PATCH_OP_PHYOCP: ++ if ((pPatch_data->msb != 15) || (pPatch_data->lsb != 0)) ++ { ++ RT_ERR_CHK(phy_common_general_reg_mmd_get(unit, port, 31, pPatch_data->addr, &rData), ret); ++ } ++ wData = REG32_FIELD_SET(rData, pPatch_data->data, pPatch_data->lsb, mask); ++ RT_ERR_CHK(phy_common_general_reg_mmd_set(unit, port, 31, pPatch_data->addr, wData), ret); ++ break; ++ case RTK_PATCH_OP_CMP_PHYOCP: ++ RT_ERR_CHK(phy_common_general_reg_mmd_get(unit, port, 31, pPatch_data->addr, &rData), ret); ++ PHYPATCH_COMPARE(pPatch_data->pagemmd, pPatch_data->addr, pPatch_data->msb, pPatch_data->lsb, pPatch_data->data, rData, mask); ++ break; ++ case RTK_PATCH_OP_CMP_SRAM_PHYOCP: ++ RT_ERR_CHK(phy_common_general_reg_mmd_set(unit, port, 31, pPatch_data->sram_rw, pPatch_data->sram_a), ret); ++ RT_ERR_CHK(phy_common_general_reg_mmd_get(unit, port, 31, pPatch_data->sram_rr, &rData), ret); ++ PHYPATCH_COMPARE(pPatch_data->pagemmd, pPatch_data->addr, pPatch_data->msb, pPatch_data->lsb, pPatch_data->data, rData, mask); ++ break; ++ ++ case RTK_PATCH_OP_TOP: ++ if ((pPatch_data->msb != 15) || (pPatch_data->lsb != 0)) ++ { ++ RT_ERR_CHK(_phy_rtl826xb_patch_top_get(unit, port, pPatch_data->pagemmd, pPatch_data->addr, &rData), ret); ++ } ++ wData = REG32_FIELD_SET(rData, pPatch_data->data, pPatch_data->lsb, mask); ++ RT_ERR_CHK(_phy_rtl826xb_patch_top_set(unit, port, pPatch_data->pagemmd, pPatch_data->addr, wData), ret); ++ break; ++ case RTK_PATCH_OP_CMP_TOP: ++ RT_ERR_CHK(_phy_rtl826xb_patch_top_get(unit, port, pPatch_data->pagemmd, pPatch_data->addr, &rData), ret); ++ PHYPATCH_COMPARE(pPatch_data->pagemmd, pPatch_data->addr, pPatch_data->msb, pPatch_data->lsb, pPatch_data->data, rData, mask); ++ break; ++ case RTK_PATCH_OP_CMP_SRAM_TOP: ++ RT_ERR_CHK(_phy_rtl826xb_patch_top_set(unit, port, pPatch_data->sram_p, pPatch_data->sram_rw, pPatch_data->sram_a), ret); ++ RT_ERR_CHK(_phy_rtl826xb_patch_top_get(unit, port, pPatch_data->sram_p, pPatch_data->sram_rr, &rData), ret); ++ PHYPATCH_COMPARE(pPatch_data->pagemmd, pPatch_data->addr, pPatch_data->msb, pPatch_data->lsb, pPatch_data->data, rData, mask); ++ break; ++ ++ case RTK_PATCH_OP_PSDS0: ++ if ((pPatch_data->msb != 15) || (pPatch_data->lsb != 0)) ++ { ++ RT_ERR_CHK(_phy_rtl826xb_patch_sds_get(unit, port, pPatch_data->pagemmd, pPatch_data->addr, &rData), ret); ++ } ++ wData = REG32_FIELD_SET(rData, pPatch_data->data, pPatch_data->lsb, mask); ++ RT_ERR_CHK(_phy_rtl826xb_patch_sds_set(unit, port, pPatch_data->pagemmd, pPatch_data->addr, wData, patch_mode), ret); ++ break; ++ case RTK_PATCH_OP_CMP_PSDS0: ++ RT_ERR_CHK(_phy_rtl826xb_patch_sds_get(unit, port, pPatch_data->pagemmd, pPatch_data->addr, &rData), ret); ++ PHYPATCH_COMPARE(pPatch_data->pagemmd, pPatch_data->addr, pPatch_data->msb, pPatch_data->lsb, pPatch_data->data, rData, mask); ++ break; ++ case RTK_PATCH_OP_CMP_SRAM_PSDS0: ++ RT_ERR_CHK(_phy_rtl826xb_patch_sds_set(unit, port, pPatch_data->sram_p, pPatch_data->sram_rw, pPatch_data->sram_a, patch_mode), ret); ++ RT_ERR_CHK(_phy_rtl826xb_patch_sds_get(unit, port, pPatch_data->sram_p, pPatch_data->sram_rr, &rData), ret); ++ PHYPATCH_COMPARE(pPatch_data->pagemmd, pPatch_data->addr, pPatch_data->msb, pPatch_data->lsb, pPatch_data->data, rData, mask); ++ break; ++ ++ case RTK_PATCH_OP_SKIP: ++ return RT_ERR_ABORT; ++ ++ default: ++ RT_LOG(LOG_MAJOR_ERR, (MOD_HAL | MOD_PHY), "U%u P%u patch_op:%u not implemented yet!\n", unit, port, pPatch_data->patch_op); ++ return RT_ERR_DRIVER_NOT_SUPPORTED; ++ } ++ ++ return ret; ++} ++ ++static int32 phy_rtl826xb_patch_flow(uint32 unit, rtk_port_t port, uint8 portOffset, uint8 patch_flow, uint8 patch_mode) ++{ ++ int32 ret = RT_ERR_OK; ++ ++ RT_LOG(LOG_INFO, (MOD_HAL | MOD_PHY), "[%s]U%u,P%u,flow%u\n", __FUNCTION__, unit, port, (patch_flow - PHY_PATCH_TYPE_END)); ++ switch (patch_flow) ++ { ++ case RTK_PATCH_TYPE_FLOW(0): ++ RT_ERR_CHK(_phy_rtl826xb_flow_r1(unit, port, portOffset, patch_mode), ret); ++ break; ++ case RTK_PATCH_TYPE_FLOW(1): ++ RT_ERR_CHK(_phy_rtl826xb_flow_r2(unit, port, portOffset, patch_mode), ret); ++ break; ++ ++ case RTK_PATCH_TYPE_FLOW(2): ++ RT_ERR_CHK(_phy_rtl826xb_flow_l1(unit, port, portOffset, patch_mode), ret); ++ break; ++ case RTK_PATCH_TYPE_FLOW(3): ++ RT_ERR_CHK(_phy_rtl826xb_flow_l2(unit, port, portOffset, patch_mode), ret); ++ break; ++ ++ case RTK_PATCH_TYPE_FLOW(4): ++ RT_ERR_CHK(_phy_rtl826xb_flow_n01(unit, port, portOffset, patch_mode), ret); ++ break; ++ case RTK_PATCH_TYPE_FLOW(5): ++ RT_ERR_CHK(_phy_rtl826xb_flow_n02(unit, port, portOffset, patch_mode), ret); ++ break; ++ ++ case RTK_PATCH_TYPE_FLOW(6): ++ RT_ERR_CHK(_phy_rtl826xb_flow_n11(unit, port, portOffset, patch_mode), ret); ++ break; ++ case RTK_PATCH_TYPE_FLOW(7): ++ RT_ERR_CHK(_phy_rtl826xb_flow_n12(unit, port, portOffset, patch_mode), ret); ++ break; ++ ++ case RTK_PATCH_TYPE_FLOW(8): ++ RT_ERR_CHK(_phy_rtl826xb_flow_n21(unit, port, portOffset, patch_mode), ret); ++ break; ++ case RTK_PATCH_TYPE_FLOW(9): ++ RT_ERR_CHK(_phy_rtl826xb_flow_n22(unit, port, portOffset, patch_mode), ret); ++ break; ++ ++ case RTK_PATCH_TYPE_FLOW(10): ++ RT_ERR_CHK(_phy_rtl826xb_flow_s(unit, port, portOffset, patch_mode), ret); ++ break; ++ ++ case RTK_PATCH_TYPE_FLOW(11): ++ RT_ERR_CHK(_phy_rtl826xb_flow_pi(unit, port, portOffset, patch_mode), ret); ++ break; ++ case RTK_PATCH_TYPE_FLOW(12): ++ RT_ERR_CHK(_phy_rtl826xb_flow_r12(unit, port, portOffset, patch_mode), ret); ++ break; ++ ++ default: ++ return RT_ERR_INPUT; ++ } ++ return RT_ERR_OK; ++} ++ ++int32 phy_rtl826xb_patch_db_init(uint32 unit, rtk_port_t port, rt_phy_patch_db_t **pPhy_patchDb) ++{ ++ int32 ret = RT_ERR_OK; ++ rt_phy_patch_db_t *patch_db = NULL; ++ uint32 rData = 0; ++ ++ patch_db = osal_alloc(sizeof(rt_phy_patch_db_t)); ++ RT_PARAM_CHK(NULL == patch_db, RT_ERR_MEM_ALLOC); ++ osal_memset(patch_db, 0x0, sizeof(rt_phy_patch_db_t)); ++ ++ /* patch callback */ ++ patch_db->fPatch_op = phy_rtl826xb_patch_op; ++ patch_db->fPatch_flow = phy_rtl826xb_patch_flow; ++ ++ /* patch table */ ++ RT_ERR_CHK(phy_common_general_reg_mmd_get(unit, port, 30, 0x104, &rData), ret); ++ if ((rData & 0x7) == 0x0) ++ { ++ /* patch */ ++ PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 0, RTK_PATCH_TYPE_FLOW(12), NULL); ++ PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 1, PHY_PATCH_TYPE_NCTL0, rtl8264b_nctl0_conf); ++ PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 2, PHY_PATCH_TYPE_NCTL1, rtl8264b_nctl1_conf); ++ PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 3, PHY_PATCH_TYPE_NCTL2, rtl8264b_nctl2_conf); ++ PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 4, PHY_PATCH_TYPE_UC2, rtl8264b_uc2_conf); ++ PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 5, PHY_PATCH_TYPE_UC, rtl8264b_uc_conf); ++ PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 6, PHY_PATCH_TYPE_DATARAM, rtl8264b_dataram_conf); ++ PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 7, RTK_PATCH_TYPE_FLOW(1), NULL); ++ PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 8, RTK_PATCH_TYPE_FLOW(2), NULL); ++ PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 9, PHY_PATCH_TYPE_ALGXG, rtl8264b_algxg_conf); ++ PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 10, PHY_PATCH_TYPE_ALG1G, rtl8264b_alg_giga_conf); ++ PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 11, PHY_PATCH_TYPE_NORMAL, rtl8264b_normal_conf); ++ PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 12, PHY_PATCH_TYPE_TOP, rtl8264b_top_conf); ++ PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 13, PHY_PATCH_TYPE_SDS, rtl8264b_sds_conf); ++ PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 14, PHY_PATCH_TYPE_AFE, rtl8264b_afe_conf); ++ PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 15, PHY_PATCH_TYPE_RTCT, rtl8264b_rtct_conf); ++ PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 16, RTK_PATCH_TYPE_FLOW(3), NULL); ++ PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 17, RTK_PATCH_TYPE_FLOW(11), NULL); ++ PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 18, RTK_PATCH_TYPE_FLOW(10), NULL); ++ ++ /* compare */ ++ PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 0, PHY_PATCH_TYPE_TOP, rtl8264b_top_conf); ++ PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 1, PHY_PATCH_TYPE_SDS, rtl8264b_sds_conf); ++ PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 2, PHY_PATCH_TYPE_AFE, rtl8264b_afe_conf); ++ PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 3, RTK_PATCH_TYPE_FLOW(4), NULL); ++ PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 4, PHY_PATCH_TYPE_NCTL0, rtl8264b_nctl0_conf); ++ PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 5, RTK_PATCH_TYPE_FLOW(5), NULL); ++ PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 6, RTK_PATCH_TYPE_FLOW(6), NULL); ++ PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 7, PHY_PATCH_TYPE_NCTL1, rtl8264b_nctl1_conf); ++ PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 8, RTK_PATCH_TYPE_FLOW(7), NULL); ++ PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 9, RTK_PATCH_TYPE_FLOW(8), NULL); ++ PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 10, PHY_PATCH_TYPE_NCTL2, rtl8264b_nctl2_conf); ++ PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 11, RTK_PATCH_TYPE_FLOW(9), NULL); ++ PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 12, PHY_PATCH_TYPE_UC, rtl8264b_uc_conf); ++ PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 13, PHY_PATCH_TYPE_UC2, rtl8264b_uc2_conf); ++ PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 14, RTK_PATCH_TYPE_FLOW(12), NULL); ++ PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 15, PHY_PATCH_TYPE_DATARAM, rtl8264b_dataram_conf); ++ PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 16, RTK_PATCH_TYPE_FLOW(1), NULL); ++ PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 17, PHY_PATCH_TYPE_ALGXG, rtl8264b_algxg_conf); ++ PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 18, PHY_PATCH_TYPE_ALG1G, rtl8264b_alg_giga_conf); ++ PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 19, PHY_PATCH_TYPE_NORMAL, rtl8264b_normal_conf); ++ PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 20, PHY_PATCH_TYPE_RTCT, rtl8264b_rtct_conf); ++ } ++ else ++ { ++ /* patch */ ++ PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 0, RTK_PATCH_TYPE_FLOW(0), NULL); ++ PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 1, PHY_PATCH_TYPE_NCTL0, rtl8261n_c_nctl0_conf); ++ PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 2, PHY_PATCH_TYPE_NCTL1, rtl8261n_c_nctl1_conf); ++ PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 3, PHY_PATCH_TYPE_NCTL2, rtl8261n_c_nctl2_conf); ++ PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 4, PHY_PATCH_TYPE_UC2, rtl8261n_c_uc2_conf); ++ PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 5, PHY_PATCH_TYPE_UC, rtl8261n_c_uc_conf); ++ PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 6, PHY_PATCH_TYPE_DATARAM, rtl8261n_c_dataram_conf); ++ PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 7, RTK_PATCH_TYPE_FLOW(1), NULL); ++ PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 8, RTK_PATCH_TYPE_FLOW(2), NULL); ++ PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 9, PHY_PATCH_TYPE_ALGXG, rtl8261n_c_algxg_conf); ++ PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 10, PHY_PATCH_TYPE_ALG1G, rtl8261n_c_alg_giga_conf); ++ PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 11, PHY_PATCH_TYPE_NORMAL, rtl8261n_c_normal_conf); ++ PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 12, PHY_PATCH_TYPE_TOP, rtl8261n_c_top_conf); ++ PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 13, PHY_PATCH_TYPE_SDS, rtl8261n_c_sds_conf); ++ PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 14, PHY_PATCH_TYPE_AFE, rtl8261n_c_afe_conf); ++ PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 15, PHY_PATCH_TYPE_RTCT, rtl8261n_c_rtct_conf); ++ PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 16, RTK_PATCH_TYPE_FLOW(3), NULL); ++ PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 17, RTK_PATCH_TYPE_FLOW(10), NULL); ++ ++ /* compare */ ++ PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 0, PHY_PATCH_TYPE_TOP, rtl8261n_c_top_conf); ++ PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 1, PHY_PATCH_TYPE_SDS, rtl8261n_c_sds_conf); ++ PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 2, PHY_PATCH_TYPE_AFE, rtl8261n_c_afe_conf); ++ PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 3, RTK_PATCH_TYPE_FLOW(4), NULL); ++ PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 4, PHY_PATCH_TYPE_NCTL0, rtl8261n_c_nctl0_conf); ++ PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 5, RTK_PATCH_TYPE_FLOW(5), NULL); ++ PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 6, RTK_PATCH_TYPE_FLOW(6), NULL); ++ PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 7, PHY_PATCH_TYPE_NCTL1, rtl8261n_c_nctl1_conf); ++ PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 8, RTK_PATCH_TYPE_FLOW(7), NULL); ++ PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 9, RTK_PATCH_TYPE_FLOW(8), NULL); ++ PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 10, PHY_PATCH_TYPE_NCTL2, rtl8261n_c_nctl2_conf); ++ PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 11, RTK_PATCH_TYPE_FLOW(9), NULL); ++ PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 12, PHY_PATCH_TYPE_UC, rtl8261n_c_uc_conf); ++ PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 13, PHY_PATCH_TYPE_UC2, rtl8261n_c_uc2_conf); ++ PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 14, RTK_PATCH_TYPE_FLOW(0), NULL); ++ PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 15, PHY_PATCH_TYPE_DATARAM, rtl8261n_c_dataram_conf); ++ PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 16, RTK_PATCH_TYPE_FLOW(1), NULL); ++ PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 17, PHY_PATCH_TYPE_ALGXG, rtl8261n_c_algxg_conf); ++ PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 18, PHY_PATCH_TYPE_ALG1G, rtl8261n_c_alg_giga_conf); ++ PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 19, PHY_PATCH_TYPE_NORMAL, rtl8261n_c_normal_conf); ++ PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 20, PHY_PATCH_TYPE_RTCT, rtl8261n_c_rtct_conf); ++ } ++ *pPhy_patchDb = patch_db; ++ return ret; ++} ++ ++/* Function Name: ++ * phy_rtl826xb_patch ++ * Description: ++ * apply initial patch data to PHY ++ * Input: ++ * unit - unit id ++ * baseport - base port id on the PHY chip ++ * portOffset - the index offset base on baseport for the port to patch ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_NOT_SUPPORTED ++ * RT_ERR_ABORT ++ * Note: ++ * None ++ */ ++int32 phy_rtl826xb_patch(uint32 unit, rtk_port_t port, uint8 portOffset) ++{ ++ return phy_patch( unit, port, portOffset, PHY_PATCH_MODE_NORMAL); ++} ++ ++/* Function Name: ++ * phy_rtl826xb_broadcast_patch ++ * Description: ++ * apply patch data to PHY ++ * Input: ++ * unit - unit id ++ * baseport - base port id on the PHY chip ++ * portOffset - the index offset base on baseport for the port to patch ++ * perChip - 1 for per-chip mode, 0 for per-bus mode ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_NOT_SUPPORTED ++ * RT_ERR_ABORT ++ * Note: ++ * None ++ */ ++int32 phy_rtl826xb_broadcast_patch(uint32 unit, rtk_port_t port, uint8 portOffset, uint8 perChip) ++{ ++ int32 ret = 0; ++ if (perChip == 0) ++ { ++ ret = phy_patch(unit, port, portOffset, PHY_PATCH_MODE_BCAST_BUS); ++ } ++ else ++ { ++ ret = phy_patch(unit, port, portOffset, PHY_PATCH_MODE_BCAST); ++ } ++ return ret; ++} ++ +diff --git a/drivers/net/phy/rtl8261n/phy_rtl826xb_patch.h b/drivers/net/phy/rtl8261n/phy_rtl826xb_patch.h +new file mode 100644 +index 000000000000..c2311ef2bf46 +--- /dev/null ++++ b/drivers/net/phy/rtl8261n/phy_rtl826xb_patch.h +@@ -0,0 +1,63 @@ ++/* ++ * SPDX-License-Identifier: GPL-2.0-only ++ * ++ * Copyright (c) 2023 Realtek Semiconductor Corp. All rights reserved. ++ */ ++ ++#ifndef __HAL_PHY_PHY_RTL826XB_PATCH_H__ ++#define __HAL_PHY_PHY_RTL826XB_PATCH_H__ ++ ++/* ++ * Include Files ++ */ ++#if defined(RTK_PHYDRV_IN_LINUX) ++ #include "rtk_osal.h" ++ #include "rtk_phylib_def.h" ++#else ++ #include ++ #include ++#endif ++ ++/* Function Name: ++ * phy_rtl826xb_patch ++ * Description: ++ * apply patch data to PHY ++ * Input: ++ * unit - unit id ++ * baseport - base port id on the PHY chip ++ * portOffset - the index offset base on baseport for the port to patch ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_NOT_SUPPORTED ++ * RT_ERR_ABORT ++ * Note: ++ * None ++ */ ++extern int32 phy_rtl826xb_patch(uint32 unit, rtk_port_t baseport, uint8 portOffset); ++ ++/* Function Name: ++ * phy_rtl826xb_broadcast_patch ++ * Description: ++ * apply patch data to PHY ++ * Input: ++ * unit - unit id ++ * baseport - base port id on the PHY chip ++ * portOffset - the index offset base on baseport for the port to patch ++ * perChip - 1 for per-chip mode, 0 for per-bus mode ++ * Output: ++ * None ++ * Return: ++ * RT_ERR_OK ++ * RT_ERR_FAILED ++ * RT_ERR_NOT_SUPPORTED ++ * RT_ERR_ABORT ++ * Note: ++ * None ++ */ ++extern int32 phy_rtl826xb_broadcast_patch(uint32 unit, rtk_port_t port, uint8 portOffset, uint8 perChip); ++ ++extern int32 phy_rtl826xb_patch_db_init(uint32 unit, rtk_port_t port, rt_phy_patch_db_t **pPhy_patchDb); ++#endif /* __HAL_PHY_PHY_RTL826XB_PATCH_H__ */ +diff --git a/drivers/net/phy/rtl8261n/rtk_osal.c b/drivers/net/phy/rtl8261n/rtk_osal.c +new file mode 100644 +index 000000000000..35339400d01b +--- /dev/null ++++ b/drivers/net/phy/rtl8261n/rtk_osal.c +@@ -0,0 +1,57 @@ ++/* ++ * SPDX-License-Identifier: GPL-2.0-only ++ * ++ * Copyright (c) 2023 Realtek Semiconductor Corp. All rights reserved. ++ */ ++ ++#include "type.h" ++#include "error.h" ++#include "rtk_phylib_def.h" ++#include "rtk_osal.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++int32 ++osal_time_usecs_get(osal_usecs_t *pUsec) ++{ ++ struct timespec64 ts; ++ ++ RT_PARAM_CHK((NULL == pUsec), RT_ERR_NULL_POINTER); ++ ++ ktime_get_ts64(&ts); ++ *pUsec = (osal_usecs_t)((ts.tv_sec * USEC_PER_SEC) + (ts.tv_nsec / NSEC_PER_USEC)); ++ return RT_ERR_OK; ++} ++ ++void * ++osal_alloc(uint32 size) ++{ ++ void *p; ++ p = kmalloc((size_t)size, GFP_ATOMIC); ++ return p; ++} ++ ++int32 ++phy_common_general_reg_mmd_get(uint32 unit, rtk_port_t port, uint32 mmdAddr, uint32 mmdReg, uint32 *pData) ++{ ++ int32 rData = 0; ++ rData = phy_read_mmd(port, mmdAddr, mmdReg); ++ if (rData < 0) ++ return RT_ERR_FAILED; ++ *pData = (uint32)rData; ++ return RT_ERR_OK; ++} ++ ++int32 ++phy_common_general_reg_mmd_set(uint32 unit, rtk_port_t port, uint32 mmdAddr, uint32 mmdReg, uint32 data) ++{ ++ int ret = phy_write_mmd(port, mmdAddr, mmdReg, data); ++ return (ret < 0) ? RT_ERR_FAILED : RT_ERR_OK; ++} +diff --git a/drivers/net/phy/rtl8261n/rtk_osal.h b/drivers/net/phy/rtl8261n/rtk_osal.h +new file mode 100644 +index 000000000000..edf674611efd +--- /dev/null ++++ b/drivers/net/phy/rtl8261n/rtk_osal.h +@@ -0,0 +1,99 @@ ++/* ++ * SPDX-License-Identifier: GPL-2.0-only ++ * ++ * Copyright (c) 2023 Realtek Semiconductor Corp. All rights reserved. ++ */ ++ ++#ifndef __RTK_PHY_OSAL_H ++#define __RTK_PHY_OSAL_H ++ ++#include ++#include ++#include "type.h" ++#include "error.h" ++#include "phy_patch.h" ++#include "rtk_phylib.h" ++ ++#ifdef PHYPATCH_DB_GET ++ #undef PHYPATCH_DB_GET ++#endif ++ ++#define PHYPATCH_DB_GET(_unit, _pPhy_device, _pPatchDb) \ ++ do { \ ++ struct rtk_phy_priv *_pPriv = (_pPhy_device)->priv; \ ++ rt_phy_patch_db_t *_pDb = _pPriv->patch; _pPatchDb = _pDb; \ ++ /*printk("[PHYPATCH_DB_GET] ? [%s]\n", (_pDb != NULL) ? "E":"N");*/ \ ++ } while(0) ++ ++#define HWP_9300_FAMILY_ID(_unit) 0 ++#define HWP_9310_FAMILY_ID(_unit) 0 ++#define RTK_9300_FAMILY_ID(_unit) 0 ++#define RTK_9310_FAMILY_ID(_unit) 0 ++#define RTK_9311B_FAMILY_ID(_unit) 0 ++#define RTK_9330_FAMILY_ID(_unit) 0 ++ ++#ifndef WAIT_COMPLETE_VAR ++#define WAIT_COMPLETE_VAR() \ ++ osal_usecs_t _t, _now, _t_wait=0, _timeout; \ ++ int32 _chkCnt=0; ++ ++#define WAIT_COMPLETE(_timeout_us) \ ++ _timeout = _timeout_us; \ ++ for(osal_time_usecs_get(&_t),osal_time_usecs_get(&_now),_t_wait=0,_chkCnt=0 ; \ ++ (_t_wait <= _timeout); \ ++ osal_time_usecs_get(&_now), _chkCnt++, _t_wait += ((_now >= _t) ? (_now - _t) : (0xFFFFFFFF - _t + _now)),_t = _now \ ++ ) ++ ++#define WAIT_COMPLETE_IS_TIMEOUT() (_t_wait > _timeout) ++#endif ++ ++/* OSAL */ ++#include ++int32 osal_time_usecs_get(osal_usecs_t *pUsec); ++void *osal_alloc(uint32 size); ++#define osal_time_mdelay mdelay ++ ++#include /* for Kernel Space */ ++#include ++#include ++#define osal_strlen strlen ++#define osal_strcmp strcmp ++#define osal_strcpy strcpy ++#define osal_strncpy strncpy ++#define osal_strcat strcat ++#define osal_strchr strchr ++#define osal_memset memset ++#define osal_memcpy memcpy ++#define osal_memcmp memcmp ++#define osal_strdup strdup ++#define osal_strncmp strncmp ++#define osal_strstr strstr ++#define osal_strtok strtok ++#define osal_strtok_r strtok_r ++#define osal_toupper toupper ++ ++#define osal_printf printk ++ ++/* HWP */ ++#define HWP_PORT_SMI(unit, port) 0 ++#define HWP_PHY_MODEL_BY_PORT(unit, port) 0 ++#define HWP_PHY_ADDR(unit, port) 0 ++#define HWP_PHY_BASE_MACID(unit, p) 0 ++#define HWP_PORT_TRAVS_EXCEPT_CPU(unit, p) if (bcast_phyad < 0x1F && p != NULL) ++ ++ ++/* RT_LOG */ ++//#define RT_LOG(level, module, fmt, args...) do { printk("RT_LOG:"fmt, ## args); } while(0) ++#define RT_LOG(level, module, fmt, args...) do {} while(0) ++#define RT_ERR(error_code, module, fmt, args...) do {} while(0) ++#define RT_INIT_ERR(error_code, module, fmt, args...) do {} while(0) ++#define RT_INIT_MSG(fmt, args...) do {} while(0) ++ ++#define phy_826xb_ctrl_set(unit, p, RTK_PHY_CTRL_MIIM_BCAST_PHYAD, bcast_phyad) 0 ++ ++/* reg access */ ++int32 phy_common_general_reg_mmd_get(uint32 unit, rtk_port_t port, uint32 mmdAddr, uint32 mmdReg, uint32 *pData); ++int32 phy_common_general_reg_mmd_set(uint32 unit, rtk_port_t port, uint32 mmdAddr, uint32 mmdReg, uint32 data); ++ ++ ++#endif /* __RTK_PHY_OSAL_H */ +diff --git a/drivers/net/phy/rtl8261n/rtk_phy.c b/drivers/net/phy/rtl8261n/rtk_phy.c +new file mode 100644 +index 000000000000..a1eb2c16149c +--- /dev/null ++++ b/drivers/net/phy/rtl8261n/rtk_phy.c +@@ -0,0 +1,324 @@ ++/* ++ * SPDX-License-Identifier: GPL-2.0-only ++ * ++ * Copyright (c) 2023 Realtek Semiconductor Corp. All rights reserved. ++ */ ++ ++#include ++#include ++#include ++ ++#include "phy_rtl826xb_patch.h" ++#include "rtk_phylib_rtl826xb.h" ++#include "rtk_phylib.h" ++ ++#define REALTEK_PHY_ID_RTL8261N 0x001CCAF3 ++#define REALTEK_PHY_ID_RTL8264B 0x001CC813 ++#define REALTEK_PHY_ID_RTL8264 0x001CCAF2 ++ ++#define REALTEK_SERDES_GLOBAL_CFG 0xC1 ++#define REALTEK_HSO_INV BIT(7) ++#define REALTEK_HSI_INV BIT(6) ++ ++static int rtl826xb_get_features(struct phy_device *phydev) ++{ ++ int ret; ++ ret = genphy_c45_pma_read_abilities(phydev); ++ if (ret) ++ return ret; ++ ++ linkmode_or(phydev->supported, phydev->supported, PHY_BASIC_FEATURES); ++ ++ ++ linkmode_set_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, ++ phydev->supported); ++ linkmode_set_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT, ++ phydev->supported); ++ ++ /* not support 10M modes */ ++ linkmode_clear_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT, ++ phydev->supported); ++ linkmode_clear_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, ++ phydev->supported); ++ ++ return 0; ++} ++ ++static int rtl826xb_probe(struct phy_device *phydev) ++{ ++ struct device *dev = &phydev->mdio.dev; ++ struct rtk_phy_priv *priv = NULL; ++ ++ priv = devm_kzalloc(&phydev->mdio.dev, sizeof(struct rtk_phy_priv), GFP_KERNEL); ++ if (!priv) ++ { ++ return -ENOMEM; ++ } ++ memset(priv, 0, sizeof(struct rtk_phy_priv)); ++ ++ if (phy_rtl826xb_patch_db_init(0, phydev, &(priv->patch)) != RT_ERR_OK) ++ return -ENOMEM; ++ ++ priv->phytype = (phydev->drv->phy_id == REALTEK_PHY_ID_RTL8261N) ? (RTK_PHYLIB_RTL8261N) : (RTK_PHYLIB_RTL8264B); ++ priv->isBasePort = (phydev->drv->phy_id == REALTEK_PHY_ID_RTL8261N) ? (1) : (((phydev->mdio.addr % 4) == 0) ? (1) : (0)); ++ priv->pnswap_rx = device_property_read_bool(dev, "realtek,pnswap-rx"); ++ priv->pnswap_tx = device_property_read_bool(dev, "realtek,pnswap-tx"); ++ phydev->priv = priv; ++ ++ return 0; ++} ++ ++static int rtkphy_config_init(struct phy_device *phydev) ++{ ++ struct rtk_phy_priv *priv = phydev->priv; ++ int ret = 0; ++ switch (phydev->drv->phy_id) ++ { ++ case REALTEK_PHY_ID_RTL8261N: ++ case REALTEK_PHY_ID_RTL8264B: ++ case REALTEK_PHY_ID_RTL8264: ++ phydev_info(phydev, "%s:%u [RTL8261N/RTL8264/RTL826XB] phy_id: 0x%X PHYAD:%d\n", __FUNCTION__, __LINE__, phydev->drv->phy_id, phydev->mdio.addr); ++#ifdef CONFIG_MACH_REALTEK_RTL ++ return 0; ++#endif ++ ++ #if 1 /* toggle reset */ ++ phy_modify_mmd_changed(phydev, 30, 0x145, BIT(0) , 1); ++ phy_modify_mmd_changed(phydev, 30, 0x145, BIT(0) , 0); ++ mdelay(30); ++ #endif ++ ++ ret = phy_patch(0, phydev, 0, PHY_PATCH_MODE_NORMAL); ++ if (ret) ++ { ++ phydev_err(phydev, "%s:%u [RTL8261N/RTL826XB] patch failed!! 0x%X\n", __FUNCTION__, __LINE__, ret); ++ return ret; ++ } ++ #if 0 /* Debug: patch check */ ++ ret = phy_patch(0, phydev, 0, PHY_PATCH_MODE_CMP); ++ if (ret) ++ { ++ phydev_err(phydev, "%s:%u [RTL8261N/RTL826XB] phy_patch failed!! 0x%X\n", __FUNCTION__, __LINE__, ret); ++ return ret; ++ } ++ printk("[%s,%u] patch chk %s\n", __FUNCTION__, __LINE__, (ret == 0) ? "PASS" : "FAIL"); ++ #endif ++ #if 0 /* Debug: USXGMII*/ ++ { ++ uint32 data = 0; ++ rtk_phylib_826xb_sds_read(phydev, 0x07, 0x10, 15, 0, &data); ++ printk("[%s,%u] SDS 0x07, 0x10 : 0x%X\n", __FUNCTION__, __LINE__, data); ++ rtk_phylib_826xb_sds_read(phydev, 0x06, 0x12, 15, 0, &data); ++ printk("[%s,%u] SDS 0x06, 0x12 : 0x%X\n", __FUNCTION__, __LINE__, data); ++ } ++ { ++ u16 sdspage = 0x5, sdsreg = 0x0; ++ u16 regData = (sdspage & 0x3f) | ((sdsreg & 0x1f) << 6) | BIT(15); ++ u16 readData = 0; ++ phy_write_mmd(phydev, 30, 323, regData); ++ do ++ { ++ udelay(10); ++ readData = phy_read_mmd(phydev, 30, 323); ++ } while ((readData & BIT(15)) != 0); ++ readData = phy_read_mmd(phydev, 30, 322); ++ printk("[%s,%d] sds link [%s] (0x%X)\n", __FUNCTION__, __LINE__, (readData & BIT(12)) ? "UP" : "DOWN", readData); ++ } ++ #endif ++ ++ if (priv->pnswap_rx) ++ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, ++ REALTEK_SERDES_GLOBAL_CFG, ++ REALTEK_HSI_INV); ++ ++ if (priv->pnswap_tx) ++ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, ++ REALTEK_SERDES_GLOBAL_CFG, ++ REALTEK_HSO_INV); ++ ++ break; ++ default: ++ phydev_err(phydev, "%s:%u Unknow phy_id: 0x%X\n", __FUNCTION__, __LINE__, phydev->drv->phy_id); ++ return -EPERM; ++ } ++ ++ return ret; ++} ++ ++static int rtkphy_c45_suspend(struct phy_device *phydev) ++{ ++ int ret = 0; ++ ++#ifndef CONFIG_MACH_REALTEK_RTL ++ ret = rtk_phylib_c45_power_low(phydev); ++#endif ++ ++ phydev->speed = SPEED_UNKNOWN; ++ phydev->duplex = DUPLEX_UNKNOWN; ++ phydev->pause = 0; ++ phydev->asym_pause = 0; ++ ++ return ret; ++} ++ ++static int rtkphy_c45_resume(struct phy_device *phydev) ++{ ++#ifndef CONFIG_MACH_REALTEK_RTL ++ return rtk_phylib_c45_power_normal(phydev); ++#else ++ return 0; ++#endif ++} ++ ++static int rtkphy_c45_config_aneg(struct phy_device *phydev) ++{ ++ bool changed = false; ++ u16 reg = 0; ++ int ret = 0; ++ ++ phydev->mdix_ctrl = ETH_TP_MDI_AUTO; ++ if (phydev->autoneg == AUTONEG_DISABLE) ++ return genphy_c45_pma_setup_forced(phydev); ++ ++ ret = genphy_c45_an_config_aneg(phydev); ++ if (ret < 0) ++ return ret; ++ if (ret > 0) ++ changed = true; ++ ++ reg = 0; ++ if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, ++ phydev->advertising)) ++ reg |= BIT(9); ++ ++ if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, ++ phydev->advertising)) ++ reg |= BIT(8); ++ ++ ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, 0xA412, ++ BIT(9) | BIT(8) , reg); ++ if (ret < 0) ++ return ret; ++ if (ret > 0) ++ changed = true; ++ ++ return genphy_c45_check_and_restart_aneg(phydev, changed); ++} ++ ++static int rtkphy_c45_aneg_done(struct phy_device *phydev) ++{ ++ return genphy_c45_aneg_done(phydev); ++} ++ ++static int rtkphy_c45_read_status(struct phy_device *phydev) ++{ ++ int ret = 0, status = 0; ++ phydev->speed = SPEED_UNKNOWN; ++ phydev->duplex = DUPLEX_UNKNOWN; ++ phydev->pause = 0; ++ phydev->asym_pause = 0; ++ ++ ret = genphy_c45_read_link(phydev); ++ if (ret) ++ return ret; ++ ++ if (phydev->autoneg == AUTONEG_ENABLE) ++ { ++ linkmode_clear_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, ++ phydev->lp_advertising); ++ ++ ret = genphy_c45_read_lpa(phydev); ++ if (ret) ++ return ret; ++ ++ status = phy_read_mmd(phydev, 31, 0xA414); ++ if (status < 0) ++ return status; ++ linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, ++ phydev->lp_advertising, status & BIT(11)); ++ ++ phy_resolve_aneg_linkmode(phydev); ++ } ++ else ++ { ++ ret = genphy_c45_read_pma(phydev); ++ } ++ ++ /* mdix*/ ++ status = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBT_SWAPPOL); ++ if (status < 0) ++ return status; ++ ++ switch (status & 0x3) ++ { ++ case MDIO_PMA_10GBT_SWAPPOL_ABNX | MDIO_PMA_10GBT_SWAPPOL_CDNX: ++ phydev->mdix = ETH_TP_MDI; ++ break; ++ ++ case 0: ++ phydev->mdix = ETH_TP_MDI_X; ++ break; ++ ++ default: ++ phydev->mdix = ETH_TP_MDI_INVALID; ++ break; ++ } ++ ++ return ret; ++} ++ ++ ++static struct phy_driver rtk_phy_drivers[] = { ++ { ++ PHY_ID_MATCH_EXACT(REALTEK_PHY_ID_RTL8261N), ++ .name = "Realtek RTL8261N", ++ .get_features = rtl826xb_get_features, ++ .config_init = rtkphy_config_init, ++ .probe = rtl826xb_probe, ++ .suspend = rtkphy_c45_suspend, ++ .resume = rtkphy_c45_resume, ++ .config_aneg = rtkphy_c45_config_aneg, ++ .aneg_done = rtkphy_c45_aneg_done, ++ .read_status = rtkphy_c45_read_status, ++ }, ++ { ++ PHY_ID_MATCH_EXACT(REALTEK_PHY_ID_RTL8264B), ++ .name = "Realtek RTL8264B", ++ .get_features = rtl826xb_get_features, ++ .config_init = rtkphy_config_init, ++ .probe = rtl826xb_probe, ++ .suspend = rtkphy_c45_suspend, ++ .resume = rtkphy_c45_resume, ++ .config_aneg = rtkphy_c45_config_aneg, ++ .aneg_done = rtkphy_c45_aneg_done, ++ .read_status = rtkphy_c45_read_status, ++ }, ++ { ++ PHY_ID_MATCH_EXACT(REALTEK_PHY_ID_RTL8264), ++ .name = "Realtek RTL8264", ++ .get_features = rtl826xb_get_features, ++ .config_init = rtkphy_config_init, ++ .probe = rtl826xb_probe, ++ .suspend = rtkphy_c45_suspend, ++ .resume = rtkphy_c45_resume, ++ .config_aneg = rtkphy_c45_config_aneg, ++ .aneg_done = rtkphy_c45_aneg_done, ++ .read_status = rtkphy_c45_read_status, ++ }, ++}; ++ ++module_phy_driver(rtk_phy_drivers); ++ ++ ++static struct mdio_device_id __maybe_unused rtk_phy_tbl[] = { ++ { PHY_ID_MATCH_EXACT(REALTEK_PHY_ID_RTL8261N) }, ++ { PHY_ID_MATCH_EXACT(REALTEK_PHY_ID_RTL8264B) }, ++ { PHY_ID_MATCH_EXACT(REALTEK_PHY_ID_RTL8264) }, ++ { }, ++}; ++ ++MODULE_DEVICE_TABLE(mdio, rtk_phy_tbl); ++ ++MODULE_AUTHOR("Realtek"); ++MODULE_DESCRIPTION("Realtek PHY drivers"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/net/phy/rtl8261n/rtk_phylib.c b/drivers/net/phy/rtl8261n/rtk_phylib.c +new file mode 100644 +index 000000000000..7dd593ce72df +--- /dev/null ++++ b/drivers/net/phy/rtl8261n/rtk_phylib.c +@@ -0,0 +1,108 @@ ++/* ++ * SPDX-License-Identifier: GPL-2.0-only ++ * ++ * Copyright (c) 2023 Realtek Semiconductor Corp. All rights reserved. ++ */ ++ ++#include "rtk_phylib.h" ++#include ++ ++ ++/* OSAL */ ++ ++void rtk_phylib_mdelay(uint32 msec) ++{ ++#if defined(RTK_PHYDRV_IN_LINUX) ++ mdelay(msec); ++#else ++ osal_time_mdelay(msec); ++#endif ++} ++ ++ ++void rtk_phylib_udelay(uint32 usec) ++{ ++#if defined(RTK_PHYDRV_IN_LINUX) ++ if (1000 <= usec) ++ { ++ mdelay(usec/1000); ++ usec = usec % 1000; ++ } ++ udelay(usec); ++#else ++ osal_time_udelay(usec); ++#endif ++} ++ ++ ++/* Register Access APIs */ ++int32 rtk_phylib_mmd_write(rtk_phydev *phydev, uint32 mmd, uint32 reg, uint8 msb, uint8 lsb, uint32 data) ++{ ++ int32 ret = 0; ++ uint32 mask = 0; ++ mask = UINT32_BITS_MASK(msb,lsb); ++ ++#if defined(RTK_PHYDRV_IN_LINUX) ++ ret = phy_modify_mmd(phydev, mmd, reg, mask, data); ++#else ++ { ++ uint32 rData = 0, wData = 0; ++ if ((msb != 15) || (lsb != 0)) ++ { ++ if ((ret = phy_common_general_reg_mmd_get(phydev->unit, phydev->port, page, reg, &rData)) != RT_ERR_OK) ++ return ret; ++ } ++ wData = REG32_FIELD_SET(rData, data, lsb, mask); ++ ret = phy_common_general_reg_mmd_set(phydev->unit, phydev->port, page, reg, wData); ++ } ++#endif ++ ++ return ret; ++} ++ ++int32 rtk_phylib_mmd_read(rtk_phydev *phydev, uint32 mmd, uint32 reg, uint8 msb, uint8 lsb, uint32 *pData) ++{ ++ int32 ret = 0; ++ uint32 rData = 0; ++ uint32 mask = 0; ++ mask = UINT32_BITS_MASK(msb,lsb); ++ ++#if defined(RTK_PHYDRV_IN_LINUX) ++ rData = phy_read_mmd(phydev, mmd, reg); ++#else ++ { ++ ret = phy_common_general_reg_mmd_get(phydev->unit, phydev->port, page, reg, &rData); ++ } ++#endif ++ ++ *pData = REG32_FIELD_GET(rData, lsb, mask); ++ return ret; ++} ++ ++/* Function Driver */ ++ ++int32 rtk_phylib_c45_power_normal(rtk_phydev *phydev) ++{ ++ int32 ret = 0; ++ RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 1, 0, 11, 11, 0)); ++ ++ return 0; ++} ++ ++int32 rtk_phylib_c45_power_low(rtk_phydev *phydev) ++{ ++ int32 ret = 0; ++ RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 1, 0, 11, 11, 1)); ++ ++ return 0; ++} ++ ++int32 rtk_phylib_c45_pcs_loopback(rtk_phydev *phydev, uint32 enable) ++{ ++ int32 ret = 0; ++ RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 3, 0, 14, 14, (enable == 0) ? 0 : 1)); ++ ++ return 0; ++} ++ ++ +diff --git a/drivers/net/phy/rtl8261n/rtk_phylib.h b/drivers/net/phy/rtl8261n/rtk_phylib.h +new file mode 100644 +index 000000000000..c1253b1ec975 +--- /dev/null ++++ b/drivers/net/phy/rtl8261n/rtk_phylib.h +@@ -0,0 +1,106 @@ ++/* ++ * SPDX-License-Identifier: GPL-2.0-only ++ * ++ * Copyright (c) 2023 Realtek Semiconductor Corp. All rights reserved. ++ */ ++ ++#ifndef __RTK_PHYLIB_H ++#define __RTK_PHYLIB_H ++ ++#if defined(RTK_PHYDRV_IN_LINUX) ++ #include ++ ++ #include "type.h" ++ #include "rtk_phylib_def.h" ++#else ++ //#include SDK headers ++#endif ++ ++#if defined(RTK_PHYDRV_IN_LINUX) ++ #define PR_INFO(_fmt, _args...) pr_info(_fmt, ##_args) ++ #define PR_DBG(_fmt, _args...) pr_debug(_fmt, ##_args) ++ #define PR_ERR(_fmt, _args...) pr_err("ERROR: "_fmt, ##_args) ++ ++ #define RTK_PHYLIB_ERR_FAILED (-EPERM) ++ #define RTK_PHYLIB_ERR_INPUT (-EINVAL) ++ #define RTK_PHYLIB_ERR_EXCEEDS_CAPACITY (-ENOSPC) ++ #define RTK_PHYLIB_ERR_TIMEOUT (-ETIME) ++ #define RTK_PHYLIB_ERR_ENTRY_NOTFOUND (-ENODATA) ++#else ++ #define PR_INFO(_fmt, _args...) RT_LOG(LOG_INFO, (MOD_HAL|MOD_PHY), _fmt, ##_args) ++ #define PR_DBG(_fmt, _args...) RT_LOG(LOG_DEBUG, (MOD_HAL|MOD_PHY), _fmt, ##_args) ++ #define PR_ERR(_fmt, _args...) RT_LOG(LOG_MAJOR_ERR, (MOD_HAL|MOD_PHY), _fmt, ##_args) ++ ++ #define RTK_PHYLIB_ERR_FAILED (RT_ERR_FAILED) ++ #define RTK_PHYLIB_ERR_INPUT (RT_ERR_INPUT) ++ #define RTK_PHYLIB_ERR_EXCEEDS_CAPACITY (RT_ERR_EXCEEDS_CAPACITY) ++ #define RTK_PHYLIB_ERR_TIMEOUT (RT_ERR_BUSYWAIT_TIMEOUT) ++ #define RTK_PHYLIB_ERR_ENTRY_NOTFOUND (RT_ERR_ENTRY_NOTFOUND) ++#endif ++ ++typedef enum rtk_phylib_phy_e ++{ ++ RTK_PHYLIB_NONE, ++ RTK_PHYLIB_RTL8261N, ++ RTK_PHYLIB_RTL8264B, ++ RTK_PHYLIB_END ++} rtk_phylib_phy_t; ++ ++struct rtk_phy_priv { ++ rtk_phylib_phy_t phytype; ++ uint8 isBasePort; ++ rt_phy_patch_db_t *patch; ++ ++ bool pnswap_rx; ++ bool pnswap_tx; ++}; ++ ++#if defined(RTK_PHYDRV_IN_LINUX) ++ typedef struct phy_device rtk_phydev; ++#else ++ struct rtk_phy_dev_s ++ { ++ uint32 unit; ++ rtk_port_t port; ++ ++ struct rtk_phy_priv *priv; ++ }; ++ typedef struct rtk_phy_dev_s rtk_phydev; ++#endif ++ ++#define RTK_PHYLIB_ERR_CHK(op)\ ++do {\ ++ if ((ret = (op)) != 0)\ ++ return ret;\ ++} while(0) ++ ++#define RTK_PHYLIB_VAL_TO_BYTE_ARRAY(_val, _valbytes, _array, _start, _bytes)\ ++do{\ ++ uint32 _i = 0;\ ++ for (_i = 0; _i < _bytes; _i++)\ ++ _array[_start+_i] = (_val >> (8* (_valbytes - _i - 1)));\ ++}while(0) ++ ++#define RTK_PHYLIB_BYTE_ARRAY_TO_VAL(_val, _array, _start, _bytes)\ ++do{\ ++ uint32 _i = 0;\ ++ for (_i = 0; _i < _bytes; _i++)\ ++ _val = (_val << 8) | _array[_start + _i];\ ++}while(0) ++ ++ ++/* OSAL */ ++void rtk_phylib_mdelay(uint32 msec); ++void rtk_phylib_udelay(uint32 usec); ++ ++/* Register Access APIs */ ++int32 rtk_phylib_mmd_write(rtk_phydev *phydev, uint32 mmd, uint32 reg, uint8 msb, uint8 lsb, uint32 data); ++int32 rtk_phylib_mmd_read(rtk_phydev *phydev, uint32 mmd, uint32 reg, uint8 msb, uint8 lsb, uint32 *pData); ++ ++/* Function Driver */ ++int32 rtk_phylib_c45_power_normal(rtk_phydev *phydev); ++int32 rtk_phylib_c45_power_low(rtk_phydev *phydev); ++int32 rtk_phylib_c45_pcs_loopback(rtk_phydev *phydev, uint32 enable); ++ ++ ++#endif /* __RTK_PHYLIB_H */ +diff --git a/drivers/net/phy/rtl8261n/rtk_phylib_def.h b/drivers/net/phy/rtl8261n/rtk_phylib_def.h +new file mode 100644 +index 000000000000..f49f0b547cc3 +--- /dev/null ++++ b/drivers/net/phy/rtl8261n/rtk_phylib_def.h +@@ -0,0 +1,166 @@ ++/* ++ * SPDX-License-Identifier: GPL-2.0-only ++ * ++ * Copyright (c) 2023 Realtek Semiconductor Corp. All rights reserved. ++ */ ++#ifndef __RTK_PHYLIB_DEF_H ++#define __RTK_PHYLIB_DEF_H ++ ++#include "type.h" ++ ++//#define PHY_C22_MMD_PAGE 0 ++#define PHY_C22_MMD_PAGE 0x0A41 ++#define PHY_C22_MMD_DEV_REG 13 ++#define PHY_C22_MMD_ADD_REG 14 ++ ++/* MDIO Manageable Device(MDD) address*/ ++#define PHY_MMD_PMAPMD 1 ++#define PHY_MMD_PCS 3 ++#define PHY_MMD_AN 7 ++#define PHY_MMD_VEND1 30 /* Vendor specific 1 */ ++#define PHY_MMD_VEND2 31 /* Vendor specific 2 */ ++ ++#define BIT_0 0x00000001U ++#define BIT_1 0x00000002U ++#define BIT_2 0x00000004U ++#define BIT_3 0x00000008U ++#define BIT_4 0x00000010U ++#define BIT_5 0x00000020U ++#define BIT_6 0x00000040U ++#define BIT_7 0x00000080U ++#define BIT_8 0x00000100U ++#define BIT_9 0x00000200U ++#define BIT_10 0x00000400U ++#define BIT_11 0x00000800U ++#define BIT_12 0x00001000U ++#define BIT_13 0x00002000U ++#define BIT_14 0x00004000U ++#define BIT_15 0x00008000U ++#define BIT_16 0x00010000U ++#define BIT_17 0x00020000U ++#define BIT_18 0x00040000U ++#define BIT_19 0x00080000U ++#define BIT_20 0x00100000U ++#define BIT_21 0x00200000U ++#define BIT_22 0x00400000U ++#define BIT_23 0x00800000U ++#define BIT_24 0x01000000U ++#define BIT_25 0x02000000U ++#define BIT_26 0x04000000U ++#define BIT_27 0x08000000U ++#define BIT_28 0x10000000U ++#define BIT_29 0x20000000U ++#define BIT_30 0x40000000U ++#define BIT_31 0x80000000U ++ ++#define MASK_1_BITS (BIT_1 - 1) ++#define MASK_2_BITS (BIT_2 - 1) ++#define MASK_3_BITS (BIT_3 - 1) ++#define MASK_4_BITS (BIT_4 - 1) ++#define MASK_5_BITS (BIT_5 - 1) ++#define MASK_6_BITS (BIT_6 - 1) ++#define MASK_7_BITS (BIT_7 - 1) ++#define MASK_8_BITS (BIT_8 - 1) ++#define MASK_9_BITS (BIT_9 - 1) ++#define MASK_10_BITS (BIT_10 - 1) ++#define MASK_11_BITS (BIT_11 - 1) ++#define MASK_12_BITS (BIT_12 - 1) ++#define MASK_13_BITS (BIT_13 - 1) ++#define MASK_14_BITS (BIT_14 - 1) ++#define MASK_15_BITS (BIT_15 - 1) ++#define MASK_16_BITS (BIT_16 - 1) ++#define MASK_17_BITS (BIT_17 - 1) ++#define MASK_18_BITS (BIT_18 - 1) ++#define MASK_19_BITS (BIT_19 - 1) ++#define MASK_20_BITS (BIT_20 - 1) ++#define MASK_21_BITS (BIT_21 - 1) ++#define MASK_22_BITS (BIT_22 - 1) ++#define MASK_23_BITS (BIT_23 - 1) ++#define MASK_24_BITS (BIT_24 - 1) ++#define MASK_25_BITS (BIT_25 - 1) ++#define MASK_26_BITS (BIT_26 - 1) ++#define MASK_27_BITS (BIT_27 - 1) ++#define MASK_28_BITS (BIT_28 - 1) ++#define MASK_29_BITS (BIT_29 - 1) ++#define MASK_30_BITS (BIT_30 - 1) ++#define MASK_31_BITS (BIT_31 - 1) ++ ++#define REG32_FIELD_SET(_data, _val, _fOffset, _fMask) ((_data & ~(_fMask)) | ((_val << (_fOffset)) & (_fMask))) ++#define REG32_FIELD_GET(_data, _fOffset, _fMask) ((_data & (_fMask)) >> (_fOffset)) ++#define UINT32_BITS_MASK(_mBit, _lBit) ((0xFFFFFFFF >> (31 - _mBit)) ^ ((1 << _lBit) - 1)) ++ ++typedef struct phy_device * rtk_port_t; ++ ++#if 1 /* ss\sdk\include\hal\phy\phydef.h */ ++/* unified patch format */ ++typedef enum rtk_phypatch_type_e ++{ ++ PHY_PATCH_TYPE_NONE = 0, ++ PHY_PATCH_TYPE_TOP = 1, ++ PHY_PATCH_TYPE_SDS, ++ PHY_PATCH_TYPE_AFE, ++ PHY_PATCH_TYPE_UC, ++ PHY_PATCH_TYPE_UC2, ++ PHY_PATCH_TYPE_NCTL0, ++ PHY_PATCH_TYPE_NCTL1, ++ PHY_PATCH_TYPE_NCTL2, ++ PHY_PATCH_TYPE_ALGXG, ++ PHY_PATCH_TYPE_ALG1G, ++ PHY_PATCH_TYPE_NORMAL, ++ PHY_PATCH_TYPE_DATARAM, ++ PHY_PATCH_TYPE_RTCT, ++ PHY_PATCH_TYPE_END ++} rtk_phypatch_type_t; ++ ++#define RTK_PATCH_TYPE_FLOW(_id) (PHY_PATCH_TYPE_END + _id) ++#define RTK_PATCH_TYPE_FLOWID_MAX PHY_PATCH_TYPE_END ++#define RTK_PATCH_SEQ_MAX ( PHY_PATCH_TYPE_END + RTK_PATCH_TYPE_FLOWID_MAX -1) ++ ++typedef struct rtk_hwpatch_s ++{ ++ uint8 patch_op; ++ uint8 portmask; ++ uint16 pagemmd; ++ uint16 addr; ++ uint8 msb; ++ uint8 lsb; ++ uint16 data; ++ uint8 compare_op; ++ uint16 sram_p; ++ uint16 sram_rr; ++ uint16 sram_rw; ++ uint16 sram_a; ++} rtk_hwpatch_t; ++ ++typedef struct rtk_hwpatch_data_s ++{ ++ rtk_hwpatch_t *conf; ++ uint32 size; ++} rtk_hwpatch_data_t; ++ ++typedef struct rtk_hwpatch_seq_s ++{ ++ uint8 patch_type; ++ union ++ { ++ rtk_hwpatch_data_t data; ++ uint8 flow_id; ++ } patch; ++} rtk_hwpatch_seq_t; ++ ++typedef struct rt_phy_patch_db_s ++{ ++ /* patch operation */ ++ int32 (*fPatch_op)(uint32 unit, rtk_port_t port, uint8 portOffset, rtk_hwpatch_t *pPatch_data, uint8 patch_mode); ++ int32 (*fPatch_flow)(uint32 unit, rtk_port_t port, uint8 portOffset, uint8 patch_flow, uint8 patch_mode); ++ ++ /* patch data */ ++ rtk_hwpatch_seq_t seq_table[RTK_PATCH_SEQ_MAX]; ++ rtk_hwpatch_seq_t cmp_table[RTK_PATCH_SEQ_MAX]; ++ ++} rt_phy_patch_db_t; ++#endif ++ ++ ++ ++#endif /* __RTK_PHYLIB_DEF_H */ +diff --git a/drivers/net/phy/rtl8261n/rtk_phylib_rtl826xb.c b/drivers/net/phy/rtl8261n/rtk_phylib_rtl826xb.c +new file mode 100644 +index 000000000000..1c33846a70fc +--- /dev/null ++++ b/drivers/net/phy/rtl8261n/rtk_phylib_rtl826xb.c +@@ -0,0 +1,57 @@ ++/* ++ * SPDX-License-Identifier: GPL-2.0-only ++ * ++ * Copyright (c) 2023 Realtek Semiconductor Corp. All rights reserved. ++ */ ++ ++#include "rtk_phylib_rtl826xb.h" ++ ++/* Indirect Register Access APIs */ ++int rtk_phylib_826xb_sds_read(rtk_phydev *phydev, uint32 page, uint32 reg, uint8 msb, uint8 lsb, uint32 *pData) ++{ ++ int32 ret = 0; ++ uint32 rData = 0; ++ uint32 op = (page & 0x3f) | ((reg & 0x1f) << 6) | (0x8000); ++ uint32 i = 0; ++ uint32 mask = 0; ++ mask = UINT32_BITS_MASK(msb,lsb); ++ ++ RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 30, 323, 15, 0, op)); ++ ++ for (i = 0; i < 10; i++) ++ { ++ RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_read(phydev, 30, 323, 15, 15, &rData)); ++ if (rData == 0) ++ { ++ break; ++ } ++ rtk_phylib_udelay(10); ++ } ++ if (i == 10) ++ { ++ return -1; ++ } ++ ++ RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_read(phydev, 30, 322, 15, 0, &rData)); ++ *pData = REG32_FIELD_GET(rData, lsb, mask); ++ ++ return ret; ++} ++ ++int rtk_phylib_826xb_sds_write(rtk_phydev *phydev, uint32 page, uint32 reg, uint8 msb, uint8 lsb, uint32 data) ++{ ++ int32 ret = 0; ++ uint32 wData = 0, rData = 0; ++ uint32 op = (page & 0x3f) | ((reg & 0x1f) << 6) | (0x8800); ++ uint32 mask = 0; ++ mask = UINT32_BITS_MASK(msb,lsb); ++ ++ RTK_PHYLIB_ERR_CHK(rtk_phylib_826xb_sds_read(phydev, page, reg, 15, 0, &rData)); ++ ++ wData = REG32_FIELD_SET(rData, data, lsb, mask); ++ ++ RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 30, 321, 15, 0, wData)); ++ RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 30, 323, 15, 0, op)); ++ ++ return ret; ++} +diff --git a/drivers/net/phy/rtl8261n/rtk_phylib_rtl826xb.h b/drivers/net/phy/rtl8261n/rtk_phylib_rtl826xb.h +new file mode 100644 +index 000000000000..9f827d4ba254 +--- /dev/null ++++ b/drivers/net/phy/rtl8261n/rtk_phylib_rtl826xb.h +@@ -0,0 +1,19 @@ ++/* ++ * SPDX-License-Identifier: GPL-2.0-only ++ * ++ * Copyright (c) 2023 Realtek Semiconductor Corp. All rights reserved. ++ */ ++ ++#ifndef __RTK_PHYLIB_RTL826XB_H ++#define __RTK_PHYLIB_RTL826XB_H ++ ++#if defined(RTK_PHYDRV_IN_LINUX) ++ #include "rtk_phylib.h" ++#else ++ //#include SDK headers ++#endif ++ ++int rtk_phylib_826xb_sds_read(rtk_phydev *phydev, uint32 page, uint32 reg, uint8 msb, uint8 lsb, uint32 *pData); ++int rtk_phylib_826xb_sds_write(rtk_phydev *phydev, uint32 page, uint32 reg, uint8 msb, uint8 lsb, uint32 data); ++ ++#endif /* __RTK_PHYLIB_RTL826XB_H */ +diff --git a/drivers/net/phy/rtl8261n/type.h b/drivers/net/phy/rtl8261n/type.h +new file mode 100644 +index 000000000000..98d7e15e1e4b +--- /dev/null ++++ b/drivers/net/phy/rtl8261n/type.h +@@ -0,0 +1,117 @@ ++/* ++ * SPDX-License-Identifier: GPL-2.0-only ++ * ++ * Copyright (c) 2023 Realtek Semiconductor Corp. All rights reserved. ++ */ ++ ++#ifndef __COMMON_TYPE_H__ ++#define __COMMON_TYPE_H__ ++ ++/* ++ * Symbol Definition ++ */ ++ ++#define USING_RTSTK_PKT_AS_RAIL ++ ++ ++#ifndef NULL ++#define NULL 0 ++#endif ++ ++#ifndef TRUE ++#define TRUE 1 ++#endif ++ ++#ifndef FALSE ++#define FALSE 0 ++#endif ++ ++#ifndef ETHER_ADDR_LEN ++#define ETHER_ADDR_LEN 6 ++#endif ++ ++#ifndef IP6_ADDR_LEN ++#define IP6_ADDR_LEN 16 ++#endif ++ ++ ++/* ++ * Data Type Declaration ++ */ ++#ifndef uint64 ++typedef unsigned long long uint64; ++#endif ++ ++#ifndef int64 ++typedef signed long long int64; ++#endif ++ ++#ifndef uint32 ++typedef unsigned int uint32; ++#endif ++ ++#ifndef int32 ++typedef signed int int32; ++#endif ++ ++#ifndef uint16 ++typedef unsigned short uint16; ++#endif ++ ++#ifndef int16 ++typedef signed short int16; ++#endif ++ ++#ifndef uint8 ++typedef unsigned char uint8; ++#endif ++ ++#ifndef int8 ++typedef signed char int8; ++#endif ++ ++//#define CONFIG_SDK_WORDSIZE_64 /* not ready */ ++#ifdef CONFIG_SDK_WORDSIZE_64 ++ typedef long int intptr; ++ typedef unsigned long int uintptr; ++#else ++ typedef int intptr; ++ typedef unsigned int uintptr; ++#endif ++ ++ ++#ifndef ipaddr_t ++typedef uint32 ipaddr_t; /* ipv4 address type */ ++#endif ++ ++/* configuration mode type */ ++typedef enum rtk_enable_e ++{ ++ DISABLED = 0, ++ ENABLED, ++ RTK_ENABLE_END ++} rtk_enable_t; ++ ++/* initial state of module */ ++typedef enum init_state_e ++{ ++ INIT_NOT_COMPLETED = 0, ++ INIT_COMPLETED, ++ INIT_STATE_END ++} init_state_t; ++ ++/* ethernet address type */ ++typedef struct rtk_mac_s ++{ ++ uint8 octet[ETHER_ADDR_LEN]; ++} rtk_mac_t; ++ ++typedef uint32 osal_time_t; ++typedef uint32 osal_usecs_t; ++ ++/* ++ * Macro Definition ++ */ ++ ++#endif /* __COMMON_TYPE_H__ */ ++ +diff --git a/drivers/net/phy/rtl8306.c b/drivers/net/phy/rtl8306.c +new file mode 100644 +index 000000000000..9bd1735f67b7 +--- /dev/null ++++ b/drivers/net/phy/rtl8306.c +@@ -0,0 +1,1063 @@ ++/* ++ * rtl8306.c: RTL8306S switch driver ++ * ++ * Copyright (C) 2009 Felix Fietkau ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * version 2 as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++//#define DEBUG 1 ++ ++/* Global (PHY0) */ ++#define RTL8306_REG_PAGE 16 ++#define RTL8306_REG_PAGE_LO (1 << 15) ++#define RTL8306_REG_PAGE_HI (1 << 1) /* inverted */ ++ ++#define RTL8306_NUM_VLANS 16 ++#define RTL8306_NUM_PORTS 6 ++#define RTL8306_PORT_CPU 5 ++#define RTL8306_NUM_PAGES 4 ++#define RTL8306_NUM_REGS 32 ++ ++#define RTL_NAME_S "RTL8306S" ++#define RTL_NAME_SD "RTL8306SD" ++#define RTL_NAME_SDM "RTL8306SDM" ++#define RTL_NAME_UNKNOWN "RTL8306(unknown)" ++ ++#define RTL8306_MAGIC 0x8306 ++ ++static LIST_HEAD(phydevs); ++ ++struct rtl_priv { ++ struct list_head list; ++ struct switch_dev dev; ++ int page; ++ int type; ++ int do_cpu; ++ struct mii_bus *bus; ++ char hwname[sizeof(RTL_NAME_UNKNOWN)]; ++ bool fixup; ++}; ++ ++struct rtl_phyregs { ++ int nway; ++ int speed; ++ int duplex; ++}; ++ ++#define to_rtl(_dev) container_of(_dev, struct rtl_priv, dev) ++ ++enum { ++ RTL_TYPE_S, ++ RTL_TYPE_SD, ++ RTL_TYPE_SDM, ++}; ++ ++struct rtl_reg { ++ int page; ++ int phy; ++ int reg; ++ int bits; ++ int shift; ++ int inverted; ++}; ++ ++#define RTL_VLAN_REGOFS(name) \ ++ (RTL_REG_VLAN1_##name - RTL_REG_VLAN0_##name) ++ ++#define RTL_PORT_REGOFS(name) \ ++ (RTL_REG_PORT1_##name - RTL_REG_PORT0_##name) ++ ++#define RTL_PORT_REG(id, reg) \ ++ (RTL_REG_PORT0_##reg + (id * RTL_PORT_REGOFS(reg))) ++ ++#define RTL_VLAN_REG(id, reg) \ ++ (RTL_REG_VLAN0_##reg + (id * RTL_VLAN_REGOFS(reg))) ++ ++#define RTL_GLOBAL_REGATTR(reg) \ ++ .id = RTL_REG_##reg, \ ++ .type = SWITCH_TYPE_INT, \ ++ .ofs = 0, \ ++ .set = rtl_attr_set_int, \ ++ .get = rtl_attr_get_int ++ ++#define RTL_PORT_REGATTR(reg) \ ++ .id = RTL_REG_PORT0_##reg, \ ++ .type = SWITCH_TYPE_INT, \ ++ .ofs = RTL_PORT_REGOFS(reg), \ ++ .set = rtl_attr_set_port_int, \ ++ .get = rtl_attr_get_port_int ++ ++#define RTL_VLAN_REGATTR(reg) \ ++ .id = RTL_REG_VLAN0_##reg, \ ++ .type = SWITCH_TYPE_INT, \ ++ .ofs = RTL_VLAN_REGOFS(reg), \ ++ .set = rtl_attr_set_vlan_int, \ ++ .get = rtl_attr_get_vlan_int ++ ++enum rtl_regidx { ++ RTL_REG_CHIPID, ++ RTL_REG_CHIPVER, ++ RTL_REG_CHIPTYPE, ++ RTL_REG_CPUPORT, ++ ++ RTL_REG_EN_CPUPORT, ++ RTL_REG_EN_TAG_OUT, ++ RTL_REG_EN_TAG_CLR, ++ RTL_REG_EN_TAG_IN, ++ RTL_REG_TRAP_CPU, ++ RTL_REG_CPU_LINKUP, ++ RTL_REG_TRUNK_PORTSEL, ++ RTL_REG_EN_TRUNK, ++ RTL_REG_RESET, ++ ++ RTL_REG_VLAN_ENABLE, ++ RTL_REG_VLAN_FILTER, ++ RTL_REG_VLAN_TAG_ONLY, ++ RTL_REG_VLAN_TAG_AWARE, ++#define RTL_VLAN_ENUM(id) \ ++ RTL_REG_VLAN##id##_VID, \ ++ RTL_REG_VLAN##id##_PORTMASK ++ RTL_VLAN_ENUM(0), ++ RTL_VLAN_ENUM(1), ++ RTL_VLAN_ENUM(2), ++ RTL_VLAN_ENUM(3), ++ RTL_VLAN_ENUM(4), ++ RTL_VLAN_ENUM(5), ++ RTL_VLAN_ENUM(6), ++ RTL_VLAN_ENUM(7), ++ RTL_VLAN_ENUM(8), ++ RTL_VLAN_ENUM(9), ++ RTL_VLAN_ENUM(10), ++ RTL_VLAN_ENUM(11), ++ RTL_VLAN_ENUM(12), ++ RTL_VLAN_ENUM(13), ++ RTL_VLAN_ENUM(14), ++ RTL_VLAN_ENUM(15), ++#define RTL_PORT_ENUM(id) \ ++ RTL_REG_PORT##id##_PVID, \ ++ RTL_REG_PORT##id##_NULL_VID_REPLACE, \ ++ RTL_REG_PORT##id##_NON_PVID_DISCARD, \ ++ RTL_REG_PORT##id##_VID_INSERT, \ ++ RTL_REG_PORT##id##_TAG_INSERT, \ ++ RTL_REG_PORT##id##_LINK, \ ++ RTL_REG_PORT##id##_SPEED, \ ++ RTL_REG_PORT##id##_NWAY, \ ++ RTL_REG_PORT##id##_NRESTART, \ ++ RTL_REG_PORT##id##_DUPLEX, \ ++ RTL_REG_PORT##id##_RXEN, \ ++ RTL_REG_PORT##id##_TXEN ++ RTL_PORT_ENUM(0), ++ RTL_PORT_ENUM(1), ++ RTL_PORT_ENUM(2), ++ RTL_PORT_ENUM(3), ++ RTL_PORT_ENUM(4), ++ RTL_PORT_ENUM(5), ++}; ++ ++static const struct rtl_reg rtl_regs[] = { ++ [RTL_REG_CHIPID] = { 0, 4, 30, 16, 0, 0 }, ++ [RTL_REG_CHIPVER] = { 0, 4, 31, 8, 0, 0 }, ++ [RTL_REG_CHIPTYPE] = { 0, 4, 31, 2, 8, 0 }, ++ ++ /* CPU port number */ ++ [RTL_REG_CPUPORT] = { 2, 4, 21, 3, 0, 0 }, ++ /* Enable CPU port function */ ++ [RTL_REG_EN_CPUPORT] = { 3, 2, 21, 1, 15, 1 }, ++ /* Enable CPU port tag insertion */ ++ [RTL_REG_EN_TAG_OUT] = { 3, 2, 21, 1, 12, 0 }, ++ /* Enable CPU port tag removal */ ++ [RTL_REG_EN_TAG_CLR] = { 3, 2, 21, 1, 11, 0 }, ++ /* Enable CPU port tag checking */ ++ [RTL_REG_EN_TAG_IN] = { 0, 4, 21, 1, 7, 0 }, ++ [RTL_REG_EN_TRUNK] = { 0, 0, 19, 1, 11, 1 }, ++ [RTL_REG_TRUNK_PORTSEL] = { 0, 0, 16, 1, 6, 1 }, ++ [RTL_REG_RESET] = { 0, 0, 16, 1, 12, 0 }, ++ ++ [RTL_REG_TRAP_CPU] = { 3, 2, 22, 1, 6, 0 }, ++ [RTL_REG_CPU_LINKUP] = { 0, 6, 22, 1, 15, 0 }, ++ ++ [RTL_REG_VLAN_TAG_ONLY] = { 0, 0, 16, 1, 8, 1 }, ++ [RTL_REG_VLAN_FILTER] = { 0, 0, 16, 1, 9, 1 }, ++ [RTL_REG_VLAN_TAG_AWARE] = { 0, 0, 16, 1, 10, 1 }, ++ [RTL_REG_VLAN_ENABLE] = { 0, 0, 18, 1, 8, 1 }, ++ ++#define RTL_VLAN_REGS(id, phy, page, regofs) \ ++ [RTL_REG_VLAN##id##_VID] = { page, phy, 25 + regofs, 12, 0, 0 }, \ ++ [RTL_REG_VLAN##id##_PORTMASK] = { page, phy, 24 + regofs, 6, 0, 0 } ++ RTL_VLAN_REGS( 0, 0, 0, 0), ++ RTL_VLAN_REGS( 1, 1, 0, 0), ++ RTL_VLAN_REGS( 2, 2, 0, 0), ++ RTL_VLAN_REGS( 3, 3, 0, 0), ++ RTL_VLAN_REGS( 4, 4, 0, 0), ++ RTL_VLAN_REGS( 5, 0, 1, 2), ++ RTL_VLAN_REGS( 6, 1, 1, 2), ++ RTL_VLAN_REGS( 7, 2, 1, 2), ++ RTL_VLAN_REGS( 8, 3, 1, 2), ++ RTL_VLAN_REGS( 9, 4, 1, 2), ++ RTL_VLAN_REGS(10, 0, 1, 4), ++ RTL_VLAN_REGS(11, 1, 1, 4), ++ RTL_VLAN_REGS(12, 2, 1, 4), ++ RTL_VLAN_REGS(13, 3, 1, 4), ++ RTL_VLAN_REGS(14, 4, 1, 4), ++ RTL_VLAN_REGS(15, 0, 1, 6), ++ ++#define REG_PORT_SETTING(port, phy) \ ++ [RTL_REG_PORT##port##_SPEED] = { 0, phy, 0, 1, 13, 0 }, \ ++ [RTL_REG_PORT##port##_NWAY] = { 0, phy, 0, 1, 12, 0 }, \ ++ [RTL_REG_PORT##port##_NRESTART] = { 0, phy, 0, 1, 9, 0 }, \ ++ [RTL_REG_PORT##port##_DUPLEX] = { 0, phy, 0, 1, 8, 0 }, \ ++ [RTL_REG_PORT##port##_TXEN] = { 0, phy, 24, 1, 11, 0 }, \ ++ [RTL_REG_PORT##port##_RXEN] = { 0, phy, 24, 1, 10, 0 }, \ ++ [RTL_REG_PORT##port##_LINK] = { 0, phy, 1, 1, 2, 0 }, \ ++ [RTL_REG_PORT##port##_NULL_VID_REPLACE] = { 0, phy, 22, 1, 12, 0 }, \ ++ [RTL_REG_PORT##port##_NON_PVID_DISCARD] = { 0, phy, 22, 1, 11, 0 }, \ ++ [RTL_REG_PORT##port##_VID_INSERT] = { 0, phy, 22, 2, 9, 0 }, \ ++ [RTL_REG_PORT##port##_TAG_INSERT] = { 0, phy, 22, 2, 0, 0 } ++ ++ REG_PORT_SETTING(0, 0), ++ REG_PORT_SETTING(1, 1), ++ REG_PORT_SETTING(2, 2), ++ REG_PORT_SETTING(3, 3), ++ REG_PORT_SETTING(4, 4), ++ REG_PORT_SETTING(5, 6), ++ ++#define REG_PORT_PVID(phy, page, regofs) \ ++ { page, phy, 24 + regofs, 4, 12, 0 } ++ [RTL_REG_PORT0_PVID] = REG_PORT_PVID(0, 0, 0), ++ [RTL_REG_PORT1_PVID] = REG_PORT_PVID(1, 0, 0), ++ [RTL_REG_PORT2_PVID] = REG_PORT_PVID(2, 0, 0), ++ [RTL_REG_PORT3_PVID] = REG_PORT_PVID(3, 0, 0), ++ [RTL_REG_PORT4_PVID] = REG_PORT_PVID(4, 0, 0), ++ [RTL_REG_PORT5_PVID] = REG_PORT_PVID(0, 1, 2), ++}; ++ ++ ++static inline void ++rtl_set_page(struct rtl_priv *priv, unsigned int page) ++{ ++ struct mii_bus *bus = priv->bus; ++ u16 pgsel; ++ ++ if (priv->fixup) ++ return; ++ ++ if (priv->page == page) ++ return; ++ ++ BUG_ON(page > RTL8306_NUM_PAGES); ++ pgsel = bus->read(bus, 0, RTL8306_REG_PAGE); ++ pgsel &= ~(RTL8306_REG_PAGE_LO | RTL8306_REG_PAGE_HI); ++ if (page & (1 << 0)) ++ pgsel |= RTL8306_REG_PAGE_LO; ++ if (!(page & (1 << 1))) /* bit is inverted */ ++ pgsel |= RTL8306_REG_PAGE_HI; ++ bus->write(bus, 0, RTL8306_REG_PAGE, pgsel); ++} ++ ++static inline int ++rtl_w16(struct switch_dev *dev, unsigned int page, unsigned int phy, unsigned int reg, u16 val) ++{ ++ struct rtl_priv *priv = to_rtl(dev); ++ struct mii_bus *bus = priv->bus; ++ ++ rtl_set_page(priv, page); ++ bus->write(bus, phy, reg, val); ++ bus->read(bus, phy, reg); /* flush */ ++ return 0; ++} ++ ++static inline int ++rtl_r16(struct switch_dev *dev, unsigned int page, unsigned int phy, unsigned int reg) ++{ ++ struct rtl_priv *priv = to_rtl(dev); ++ struct mii_bus *bus = priv->bus; ++ ++ rtl_set_page(priv, page); ++ return bus->read(bus, phy, reg); ++} ++ ++static inline u16 ++rtl_rmw(struct switch_dev *dev, unsigned int page, unsigned int phy, unsigned int reg, u16 mask, u16 val) ++{ ++ struct rtl_priv *priv = to_rtl(dev); ++ struct mii_bus *bus = priv->bus; ++ u16 r; ++ ++ rtl_set_page(priv, page); ++ r = bus->read(bus, phy, reg); ++ r &= ~mask; ++ r |= val; ++ bus->write(bus, phy, reg, r); ++ return bus->read(bus, phy, reg); /* flush */ ++} ++ ++ ++static inline int ++rtl_get(struct switch_dev *dev, enum rtl_regidx s) ++{ ++ const struct rtl_reg *r = &rtl_regs[s]; ++ u16 val; ++ ++ BUG_ON(s >= ARRAY_SIZE(rtl_regs)); ++ if (r->bits == 0) /* unimplemented */ ++ return 0; ++ ++ val = rtl_r16(dev, r->page, r->phy, r->reg); ++ ++ if (r->shift > 0) ++ val >>= r->shift; ++ ++ if (r->inverted) ++ val = ~val; ++ ++ val &= (1 << r->bits) - 1; ++ ++ return val; ++} ++ ++static int ++rtl_set(struct switch_dev *dev, enum rtl_regidx s, unsigned int val) ++{ ++ const struct rtl_reg *r = &rtl_regs[s]; ++ u16 mask = 0xffff; ++ ++ BUG_ON(s >= ARRAY_SIZE(rtl_regs)); ++ ++ if (r->bits == 0) /* unimplemented */ ++ return 0; ++ ++ if (r->shift > 0) ++ val <<= r->shift; ++ ++ if (r->inverted) ++ val = ~val; ++ ++ if (r->bits != 16) { ++ mask = (1 << r->bits) - 1; ++ mask <<= r->shift; ++ } ++ val &= mask; ++ return rtl_rmw(dev, r->page, r->phy, r->reg, mask, val); ++} ++ ++static void ++rtl_phy_save(struct switch_dev *dev, int port, struct rtl_phyregs *regs) ++{ ++ regs->nway = rtl_get(dev, RTL_PORT_REG(port, NWAY)); ++ regs->speed = rtl_get(dev, RTL_PORT_REG(port, SPEED)); ++ regs->duplex = rtl_get(dev, RTL_PORT_REG(port, DUPLEX)); ++} ++ ++static void ++rtl_phy_restore(struct switch_dev *dev, int port, struct rtl_phyregs *regs) ++{ ++ rtl_set(dev, RTL_PORT_REG(port, NWAY), regs->nway); ++ rtl_set(dev, RTL_PORT_REG(port, SPEED), regs->speed); ++ rtl_set(dev, RTL_PORT_REG(port, DUPLEX), regs->duplex); ++} ++ ++static void ++rtl_port_set_enable(struct switch_dev *dev, int port, int enabled) ++{ ++ rtl_set(dev, RTL_PORT_REG(port, RXEN), enabled); ++ rtl_set(dev, RTL_PORT_REG(port, TXEN), enabled); ++ ++ if ((port >= 5) || !enabled) ++ return; ++ ++ /* restart autonegotiation if enabled */ ++ rtl_set(dev, RTL_PORT_REG(port, NRESTART), 1); ++} ++ ++static int ++rtl_hw_apply(struct switch_dev *dev) ++{ ++ int i; ++ int trunk_en, trunk_psel; ++ struct rtl_phyregs port5; ++ ++ rtl_phy_save(dev, 5, &port5); ++ ++ /* disable rx/tx from PHYs */ ++ for (i = 0; i < RTL8306_NUM_PORTS - 1; i++) { ++ rtl_port_set_enable(dev, i, 0); ++ } ++ ++ /* save trunking status */ ++ trunk_en = rtl_get(dev, RTL_REG_EN_TRUNK); ++ trunk_psel = rtl_get(dev, RTL_REG_TRUNK_PORTSEL); ++ ++ /* trunk port 3 and 4 ++ * XXX: Big WTF, but RealTek seems to do it */ ++ rtl_set(dev, RTL_REG_EN_TRUNK, 1); ++ rtl_set(dev, RTL_REG_TRUNK_PORTSEL, 1); ++ ++ /* execute the software reset */ ++ rtl_set(dev, RTL_REG_RESET, 1); ++ ++ /* wait for the reset to complete, ++ * but don't wait for too long */ ++ for (i = 0; i < 10; i++) { ++ if (rtl_get(dev, RTL_REG_RESET) == 0) ++ break; ++ ++ msleep(1); ++ } ++ ++ /* enable rx/tx from PHYs */ ++ for (i = 0; i < RTL8306_NUM_PORTS - 1; i++) { ++ rtl_port_set_enable(dev, i, 1); ++ } ++ ++ /* restore trunking settings */ ++ rtl_set(dev, RTL_REG_EN_TRUNK, trunk_en); ++ rtl_set(dev, RTL_REG_TRUNK_PORTSEL, trunk_psel); ++ rtl_phy_restore(dev, 5, &port5); ++ ++ rtl_set(dev, RTL_REG_CPU_LINKUP, 1); ++ ++ return 0; ++} ++ ++static void ++rtl_hw_init(struct switch_dev *dev) ++{ ++ struct rtl_priv *priv = to_rtl(dev); ++ int cpu_mask = 1 << dev->cpu_port; ++ int i; ++ ++ rtl_set(dev, RTL_REG_VLAN_ENABLE, 0); ++ rtl_set(dev, RTL_REG_VLAN_FILTER, 0); ++ rtl_set(dev, RTL_REG_EN_TRUNK, 0); ++ rtl_set(dev, RTL_REG_TRUNK_PORTSEL, 0); ++ ++ /* initialize cpu port settings */ ++ if (priv->do_cpu) { ++ rtl_set(dev, RTL_REG_CPUPORT, dev->cpu_port); ++ rtl_set(dev, RTL_REG_EN_CPUPORT, 1); ++ } else { ++ rtl_set(dev, RTL_REG_CPUPORT, 7); ++ rtl_set(dev, RTL_REG_EN_CPUPORT, 0); ++ } ++ rtl_set(dev, RTL_REG_EN_TAG_OUT, 0); ++ rtl_set(dev, RTL_REG_EN_TAG_IN, 0); ++ rtl_set(dev, RTL_REG_EN_TAG_CLR, 0); ++ ++ /* reset all vlans */ ++ for (i = 0; i < RTL8306_NUM_VLANS; i++) { ++ rtl_set(dev, RTL_VLAN_REG(i, VID), i); ++ rtl_set(dev, RTL_VLAN_REG(i, PORTMASK), 0); ++ } ++ ++ /* default to port isolation */ ++ for (i = 0; i < RTL8306_NUM_PORTS; i++) { ++ unsigned long mask; ++ ++ if ((1 << i) == cpu_mask) ++ mask = ((1 << RTL8306_NUM_PORTS) - 1) & ~cpu_mask; /* all bits set */ ++ else ++ mask = cpu_mask | (1 << i); ++ ++ rtl_set(dev, RTL_VLAN_REG(i, PORTMASK), mask); ++ rtl_set(dev, RTL_PORT_REG(i, PVID), i); ++ rtl_set(dev, RTL_PORT_REG(i, NULL_VID_REPLACE), 1); ++ rtl_set(dev, RTL_PORT_REG(i, VID_INSERT), 1); ++ rtl_set(dev, RTL_PORT_REG(i, TAG_INSERT), 3); ++ } ++ rtl_hw_apply(dev); ++} ++ ++#ifdef DEBUG ++static int ++rtl_set_use_cpuport(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) ++{ ++ struct rtl_priv *priv = to_rtl(dev); ++ priv->do_cpu = val->value.i; ++ rtl_hw_init(dev); ++ return 0; ++} ++ ++static int ++rtl_get_use_cpuport(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) ++{ ++ struct rtl_priv *priv = to_rtl(dev); ++ val->value.i = priv->do_cpu; ++ return 0; ++} ++ ++static int ++rtl_set_cpuport(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) ++{ ++ dev->cpu_port = val->value.i; ++ rtl_hw_init(dev); ++ return 0; ++} ++ ++static int ++rtl_get_cpuport(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) ++{ ++ val->value.i = dev->cpu_port; ++ return 0; ++} ++#endif ++ ++static int ++rtl_reset(struct switch_dev *dev) ++{ ++ rtl_hw_init(dev); ++ return 0; ++} ++ ++static int ++rtl_attr_set_int(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) ++{ ++ int idx = attr->id + (val->port_vlan * attr->ofs); ++ struct rtl_phyregs port; ++ ++ if (attr->id >= ARRAY_SIZE(rtl_regs)) ++ return -EINVAL; ++ ++ if ((attr->max > 0) && (val->value.i > attr->max)) ++ return -EINVAL; ++ ++ /* access to phy register 22 on port 4/5 ++ * needs phy status save/restore */ ++ if ((val->port_vlan > 3) && ++ (rtl_regs[idx].reg == 22) && ++ (rtl_regs[idx].page == 0)) { ++ ++ rtl_phy_save(dev, val->port_vlan, &port); ++ rtl_set(dev, idx, val->value.i); ++ rtl_phy_restore(dev, val->port_vlan, &port); ++ } else { ++ rtl_set(dev, idx, val->value.i); ++ } ++ ++ return 0; ++} ++ ++static int ++rtl_attr_get_int(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) ++{ ++ int idx = attr->id + (val->port_vlan * attr->ofs); ++ ++ if (idx >= ARRAY_SIZE(rtl_regs)) ++ return -EINVAL; ++ ++ val->value.i = rtl_get(dev, idx); ++ return 0; ++} ++ ++static int ++rtl_attr_set_port_int(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) ++{ ++ if (val->port_vlan >= RTL8306_NUM_PORTS) ++ return -EINVAL; ++ ++ return rtl_attr_set_int(dev, attr, val); ++} ++ ++static int ++rtl_attr_get_port_int(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) ++{ ++ if (val->port_vlan >= RTL8306_NUM_PORTS) ++ return -EINVAL; ++ return rtl_attr_get_int(dev, attr, val); ++} ++ ++static int ++rtl_get_port_link(struct switch_dev *dev, int port, struct switch_port_link *link) ++{ ++ if (port >= RTL8306_NUM_PORTS) ++ return -EINVAL; ++ ++ /* in case the link changes from down to up, the register is only updated on read */ ++ link->link = rtl_get(dev, RTL_PORT_REG(port, LINK)); ++ if (!link->link) ++ link->link = rtl_get(dev, RTL_PORT_REG(port, LINK)); ++ ++ if (!link->link) ++ return 0; ++ ++ link->duplex = rtl_get(dev, RTL_PORT_REG(port, DUPLEX)); ++ link->aneg = rtl_get(dev, RTL_PORT_REG(port, NWAY)); ++ ++ if (rtl_get(dev, RTL_PORT_REG(port, SPEED))) ++ link->speed = SWITCH_PORT_SPEED_100; ++ else ++ link->speed = SWITCH_PORT_SPEED_10; ++ ++ return 0; ++} ++ ++static int ++rtl_attr_set_vlan_int(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) ++{ ++ if (val->port_vlan >= dev->vlans) ++ return -EINVAL; ++ ++ return rtl_attr_set_int(dev, attr, val); ++} ++ ++static int ++rtl_attr_get_vlan_int(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) ++{ ++ if (val->port_vlan >= dev->vlans) ++ return -EINVAL; ++ ++ return rtl_attr_get_int(dev, attr, val); ++} ++ ++static int ++rtl_get_ports(struct switch_dev *dev, struct switch_val *val) ++{ ++ unsigned int i, mask; ++ ++ mask = rtl_get(dev, RTL_VLAN_REG(val->port_vlan, PORTMASK)); ++ for (i = 0; i < RTL8306_NUM_PORTS; i++) { ++ struct switch_port *port; ++ ++ if (!(mask & (1 << i))) ++ continue; ++ ++ port = &val->value.ports[val->len]; ++ port->id = i; ++ if (rtl_get(dev, RTL_PORT_REG(i, TAG_INSERT)) == 2 || i == dev->cpu_port) ++ port->flags = (1 << SWITCH_PORT_FLAG_TAGGED); ++ val->len++; ++ } ++ ++ return 0; ++} ++ ++static int ++rtl_set_vlan(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) ++{ ++ struct rtl_priv *priv = to_rtl(dev); ++ struct rtl_phyregs port; ++ int en = val->value.i; ++ int i; ++ ++ rtl_set(dev, RTL_REG_EN_TAG_OUT, en && priv->do_cpu); ++ rtl_set(dev, RTL_REG_EN_TAG_IN, en && priv->do_cpu); ++ rtl_set(dev, RTL_REG_EN_TAG_CLR, en && priv->do_cpu); ++ rtl_set(dev, RTL_REG_VLAN_TAG_AWARE, en); ++ if (en) ++ rtl_set(dev, RTL_REG_VLAN_FILTER, en); ++ ++ for (i = 0; i < RTL8306_NUM_PORTS; i++) { ++ if (i > 3) ++ rtl_phy_save(dev, val->port_vlan, &port); ++ rtl_set(dev, RTL_PORT_REG(i, NULL_VID_REPLACE), 1); ++ rtl_set(dev, RTL_PORT_REG(i, VID_INSERT), (en ? (i == dev->cpu_port ? 0 : 1) : 1)); ++ rtl_set(dev, RTL_PORT_REG(i, TAG_INSERT), (en ? (i == dev->cpu_port ? 2 : 1) : 3)); ++ if (i > 3) ++ rtl_phy_restore(dev, val->port_vlan, &port); ++ } ++ rtl_set(dev, RTL_REG_VLAN_ENABLE, en); ++ ++ return 0; ++} ++ ++static int ++rtl_get_vlan(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) ++{ ++ val->value.i = rtl_get(dev, RTL_REG_VLAN_ENABLE); ++ return 0; ++} ++ ++static int ++rtl_set_ports(struct switch_dev *dev, struct switch_val *val) ++{ ++ unsigned int mask = 0; ++ unsigned int oldmask; ++ int i; ++ ++ for(i = 0; i < val->len; i++) ++ { ++ struct switch_port *port = &val->value.ports[i]; ++ bool tagged = false; ++ ++ mask |= (1 << port->id); ++ ++ if (port->id == dev->cpu_port) ++ continue; ++ ++ if ((i == dev->cpu_port) || ++ (port->flags & (1 << SWITCH_PORT_FLAG_TAGGED))) ++ tagged = true; ++ ++ /* fix up PVIDs for added ports */ ++ if (!tagged) ++ rtl_set(dev, RTL_PORT_REG(port->id, PVID), val->port_vlan); ++ ++ rtl_set(dev, RTL_PORT_REG(port->id, NON_PVID_DISCARD), (tagged ? 0 : 1)); ++ rtl_set(dev, RTL_PORT_REG(port->id, VID_INSERT), (tagged ? 0 : 1)); ++ rtl_set(dev, RTL_PORT_REG(port->id, TAG_INSERT), (tagged ? 2 : 1)); ++ } ++ ++ oldmask = rtl_get(dev, RTL_VLAN_REG(val->port_vlan, PORTMASK)); ++ rtl_set(dev, RTL_VLAN_REG(val->port_vlan, PORTMASK), mask); ++ ++ /* fix up PVIDs for removed ports, default to last vlan */ ++ oldmask &= ~mask; ++ for (i = 0; i < RTL8306_NUM_PORTS; i++) { ++ if (!(oldmask & (1 << i))) ++ continue; ++ ++ if (i == dev->cpu_port) ++ continue; ++ ++ if (rtl_get(dev, RTL_PORT_REG(i, PVID)) == val->port_vlan) ++ rtl_set(dev, RTL_PORT_REG(i, PVID), dev->vlans - 1); ++ } ++ ++ return 0; ++} ++ ++static struct switch_attr rtl_globals[] = { ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "enable_vlan", ++ .description = "Enable VLAN mode", ++ .max = 1, ++ .set = rtl_set_vlan, ++ .get = rtl_get_vlan, ++ }, ++ { ++ RTL_GLOBAL_REGATTR(EN_TRUNK), ++ .name = "trunk", ++ .description = "Enable port trunking", ++ .max = 1, ++ }, ++ { ++ RTL_GLOBAL_REGATTR(TRUNK_PORTSEL), ++ .name = "trunk_sel", ++ .description = "Select ports for trunking (0: 0,1 - 1: 3,4)", ++ .max = 1, ++ }, ++#ifdef DEBUG ++ { ++ RTL_GLOBAL_REGATTR(VLAN_FILTER), ++ .name = "vlan_filter", ++ .description = "Filter incoming packets for allowed VLANS", ++ .max = 1, ++ }, ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "cpuport", ++ .description = "CPU Port", ++ .set = rtl_set_cpuport, ++ .get = rtl_get_cpuport, ++ .max = RTL8306_NUM_PORTS, ++ }, ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "use_cpuport", ++ .description = "CPU Port handling flag", ++ .set = rtl_set_use_cpuport, ++ .get = rtl_get_use_cpuport, ++ .max = RTL8306_NUM_PORTS, ++ }, ++ { ++ RTL_GLOBAL_REGATTR(TRAP_CPU), ++ .name = "trap_cpu", ++ .description = "VLAN trap to CPU", ++ .max = 1, ++ }, ++ { ++ RTL_GLOBAL_REGATTR(VLAN_TAG_AWARE), ++ .name = "vlan_tag_aware", ++ .description = "Enable VLAN tag awareness", ++ .max = 1, ++ }, ++ { ++ RTL_GLOBAL_REGATTR(VLAN_TAG_ONLY), ++ .name = "tag_only", ++ .description = "Only accept tagged packets", ++ .max = 1, ++ }, ++#endif ++}; ++static struct switch_attr rtl_port[] = { ++ { ++ RTL_PORT_REGATTR(PVID), ++ .name = "pvid", ++ .description = "Port VLAN ID", ++ .max = RTL8306_NUM_VLANS - 1, ++ }, ++#ifdef DEBUG ++ { ++ RTL_PORT_REGATTR(NULL_VID_REPLACE), ++ .name = "null_vid", ++ .description = "NULL VID gets replaced by port default vid", ++ .max = 1, ++ }, ++ { ++ RTL_PORT_REGATTR(NON_PVID_DISCARD), ++ .name = "non_pvid_discard", ++ .description = "discard packets with VID != PVID", ++ .max = 1, ++ }, ++ { ++ RTL_PORT_REGATTR(VID_INSERT), ++ .name = "vid_insert_remove", ++ .description = "how should the switch insert and remove vids ?", ++ .max = 3, ++ }, ++ { ++ RTL_PORT_REGATTR(TAG_INSERT), ++ .name = "tag_insert", ++ .description = "tag insertion handling", ++ .max = 3, ++ }, ++#endif ++}; ++ ++static struct switch_attr rtl_vlan[] = { ++ { ++ RTL_VLAN_REGATTR(VID), ++ .name = "vid", ++ .description = "VLAN ID (1-4095)", ++ .max = 4095, ++ }, ++}; ++ ++static const struct switch_dev_ops rtl8306_ops = { ++ .attr_global = { ++ .attr = rtl_globals, ++ .n_attr = ARRAY_SIZE(rtl_globals), ++ }, ++ .attr_port = { ++ .attr = rtl_port, ++ .n_attr = ARRAY_SIZE(rtl_port), ++ }, ++ .attr_vlan = { ++ .attr = rtl_vlan, ++ .n_attr = ARRAY_SIZE(rtl_vlan), ++ }, ++ ++ .get_vlan_ports = rtl_get_ports, ++ .set_vlan_ports = rtl_set_ports, ++ .apply_config = rtl_hw_apply, ++ .reset_switch = rtl_reset, ++ .get_port_link = rtl_get_port_link, ++}; ++ ++static int ++rtl8306_config_init(struct phy_device *pdev) ++{ ++ struct net_device *netdev = pdev->attached_dev; ++ struct rtl_priv *priv = pdev->priv; ++ struct switch_dev *dev = &priv->dev; ++ struct switch_val val; ++ unsigned int chipid, chipver, chiptype; ++ int err; ++ ++ /* Only init the switch for the primary PHY */ ++ if (pdev->mdio.addr != 0) ++ return 0; ++ ++ val.value.i = 1; ++ priv->dev.cpu_port = RTL8306_PORT_CPU; ++ priv->dev.ports = RTL8306_NUM_PORTS; ++ priv->dev.vlans = RTL8306_NUM_VLANS; ++ priv->dev.ops = &rtl8306_ops; ++ priv->do_cpu = 0; ++ priv->page = -1; ++ priv->bus = pdev->mdio.bus; ++ ++ chipid = rtl_get(dev, RTL_REG_CHIPID); ++ chipver = rtl_get(dev, RTL_REG_CHIPVER); ++ chiptype = rtl_get(dev, RTL_REG_CHIPTYPE); ++ switch(chiptype) { ++ case 0: ++ case 2: ++ strncpy(priv->hwname, RTL_NAME_S, sizeof(priv->hwname)); ++ priv->type = RTL_TYPE_S; ++ break; ++ case 1: ++ strncpy(priv->hwname, RTL_NAME_SD, sizeof(priv->hwname)); ++ priv->type = RTL_TYPE_SD; ++ break; ++ case 3: ++ strncpy(priv->hwname, RTL_NAME_SDM, sizeof(priv->hwname)); ++ priv->type = RTL_TYPE_SDM; ++ break; ++ default: ++ strncpy(priv->hwname, RTL_NAME_UNKNOWN, sizeof(priv->hwname)); ++ break; ++ } ++ ++ dev->name = priv->hwname; ++ rtl_hw_init(dev); ++ ++ printk(KERN_INFO "Registering %s switch with Chip ID: 0x%04x, version: 0x%04x\n", priv->hwname, chipid, chipver); ++ ++ err = register_switch(dev, netdev); ++ if (err < 0) { ++ kfree(priv); ++ return err; ++ } ++ ++ return 0; ++} ++ ++ ++static int ++rtl8306_fixup(struct phy_device *pdev) ++{ ++ struct rtl_priv priv; ++ u16 chipid; ++ ++ /* Attach to primary LAN port and WAN port */ ++ if (pdev->mdio.addr != 0 && pdev->mdio.addr != 4) ++ return 0; ++ ++ memset(&priv, 0, sizeof(priv)); ++ priv.fixup = true; ++ priv.page = -1; ++ priv.bus = pdev->mdio.bus; ++ chipid = rtl_get(&priv.dev, RTL_REG_CHIPID); ++ if (chipid == 0x5988) ++ pdev->phy_id = RTL8306_MAGIC; ++ ++ return 0; ++} ++ ++static int ++rtl8306_probe(struct phy_device *pdev) ++{ ++ struct rtl_priv *priv; ++ ++ list_for_each_entry(priv, &phydevs, list) { ++ /* ++ * share one rtl_priv instance between virtual phy ++ * devices on the same bus ++ */ ++ if (priv->bus == pdev->mdio.bus) ++ goto found; ++ } ++ priv = kzalloc(sizeof(struct rtl_priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ priv->bus = pdev->mdio.bus; ++ ++found: ++ pdev->priv = priv; ++ return 0; ++} ++ ++static void ++rtl8306_remove(struct phy_device *pdev) ++{ ++ struct rtl_priv *priv = pdev->priv; ++ unregister_switch(&priv->dev); ++ kfree(priv); ++} ++ ++static int ++rtl8306_config_aneg(struct phy_device *pdev) ++{ ++ struct rtl_priv *priv = pdev->priv; ++ ++ /* Only for WAN */ ++ if (pdev->mdio.addr == 0) ++ return 0; ++ ++ /* Restart autonegotiation */ ++ rtl_set(&priv->dev, RTL_PORT_REG(4, NWAY), 1); ++ rtl_set(&priv->dev, RTL_PORT_REG(4, NRESTART), 1); ++ ++ return 0; ++} ++ ++static int ++rtl8306_read_status(struct phy_device *pdev) ++{ ++ struct rtl_priv *priv = pdev->priv; ++ struct switch_dev *dev = &priv->dev; ++ ++ if (pdev->mdio.addr == 4) { ++ /* WAN */ ++ pdev->speed = rtl_get(dev, RTL_PORT_REG(4, SPEED)) ? SPEED_100 : SPEED_10; ++ pdev->duplex = rtl_get(dev, RTL_PORT_REG(4, DUPLEX)) ? DUPLEX_FULL : DUPLEX_HALF; ++ pdev->link = !!rtl_get(dev, RTL_PORT_REG(4, LINK)); ++ } else { ++ /* LAN */ ++ pdev->speed = SPEED_100; ++ pdev->duplex = DUPLEX_FULL; ++ pdev->link = 1; ++ } ++ ++ /* ++ * Bypass generic PHY status read, ++ * it doesn't work with this switch ++ */ ++ if (pdev->link) { ++ pdev->state = PHY_RUNNING; ++ netif_carrier_on(pdev->attached_dev); ++ pdev->adjust_link(pdev->attached_dev); ++ } else { ++ pdev->state = PHY_NOLINK; ++ netif_carrier_off(pdev->attached_dev); ++ pdev->adjust_link(pdev->attached_dev); ++ } ++ ++ return 0; ++} ++ ++ ++static struct phy_driver rtl8306_driver = { ++ .name = "Realtek RTL8306S", ++ .phy_id = RTL8306_MAGIC, ++ .phy_id_mask = 0xffffffff, ++ .features = PHY_BASIC_FEATURES, ++ .probe = &rtl8306_probe, ++ .remove = &rtl8306_remove, ++ .config_init = &rtl8306_config_init, ++ .config_aneg = &rtl8306_config_aneg, ++ .read_status = &rtl8306_read_status, ++}; ++ ++ ++static int __init ++rtl_init(void) ++{ ++ phy_register_fixup_for_id(PHY_ANY_ID, rtl8306_fixup); ++ return phy_driver_register(&rtl8306_driver, THIS_MODULE); ++} ++ ++static void __exit ++rtl_exit(void) ++{ ++ phy_driver_unregister(&rtl8306_driver); ++} ++ ++module_init(rtl_init); ++module_exit(rtl_exit); ++MODULE_LICENSE("GPL"); ++ +diff --git a/drivers/net/phy/rtl8366_smi.c b/drivers/net/phy/rtl8366_smi.c +new file mode 100644 +index 000000000000..89fc04fa64d7 +--- /dev/null ++++ b/drivers/net/phy/rtl8366_smi.c +@@ -0,0 +1,1625 @@ ++/* ++ * Realtek RTL8366 SMI interface driver ++ * ++ * Copyright (C) 2009-2010 Gabor Juhos ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef CONFIG_RTL8366_SMI_DEBUG_FS ++#include ++#endif ++ ++#include "rtl8366_smi.h" ++ ++#define RTL8366_SMI_ACK_RETRY_COUNT 5 ++ ++#define RTL8366_SMI_HW_STOP_DELAY 25 /* msecs */ ++#define RTL8366_SMI_HW_START_DELAY 100 /* msecs */ ++ ++static inline void rtl8366_smi_clk_delay(struct rtl8366_smi *smi) ++{ ++ ndelay(smi->clk_delay); ++} ++ ++static void rtl8366_smi_start(struct rtl8366_smi *smi) ++{ ++ unsigned int sda = smi->gpio_sda; ++ unsigned int sck = smi->gpio_sck; ++ ++ /* ++ * Set GPIO pins to output mode, with initial state: ++ * SCK = 0, SDA = 1 ++ */ ++ gpio_direction_output(sck, 0); ++ gpio_direction_output(sda, 1); ++ rtl8366_smi_clk_delay(smi); ++ ++ /* CLK 1: 0 -> 1, 1 -> 0 */ ++ gpio_set_value(sck, 1); ++ rtl8366_smi_clk_delay(smi); ++ gpio_set_value(sck, 0); ++ rtl8366_smi_clk_delay(smi); ++ ++ /* CLK 2: */ ++ gpio_set_value(sck, 1); ++ rtl8366_smi_clk_delay(smi); ++ gpio_set_value(sda, 0); ++ rtl8366_smi_clk_delay(smi); ++ gpio_set_value(sck, 0); ++ rtl8366_smi_clk_delay(smi); ++ gpio_set_value(sda, 1); ++} ++ ++static void rtl8366_smi_stop(struct rtl8366_smi *smi) ++{ ++ unsigned int sda = smi->gpio_sda; ++ unsigned int sck = smi->gpio_sck; ++ ++ rtl8366_smi_clk_delay(smi); ++ gpio_set_value(sda, 0); ++ gpio_set_value(sck, 1); ++ rtl8366_smi_clk_delay(smi); ++ gpio_set_value(sda, 1); ++ rtl8366_smi_clk_delay(smi); ++ gpio_set_value(sck, 1); ++ rtl8366_smi_clk_delay(smi); ++ gpio_set_value(sck, 0); ++ rtl8366_smi_clk_delay(smi); ++ gpio_set_value(sck, 1); ++ ++ /* add a click */ ++ rtl8366_smi_clk_delay(smi); ++ gpio_set_value(sck, 0); ++ rtl8366_smi_clk_delay(smi); ++ gpio_set_value(sck, 1); ++ ++ /* set GPIO pins to input mode */ ++ gpio_direction_input(sda); ++ gpio_direction_input(sck); ++} ++ ++static void rtl8366_smi_write_bits(struct rtl8366_smi *smi, u32 data, u32 len) ++{ ++ unsigned int sda = smi->gpio_sda; ++ unsigned int sck = smi->gpio_sck; ++ ++ for (; len > 0; len--) { ++ rtl8366_smi_clk_delay(smi); ++ ++ /* prepare data */ ++ gpio_set_value(sda, !!(data & ( 1 << (len - 1)))); ++ rtl8366_smi_clk_delay(smi); ++ ++ /* clocking */ ++ gpio_set_value(sck, 1); ++ rtl8366_smi_clk_delay(smi); ++ gpio_set_value(sck, 0); ++ } ++} ++ ++static void rtl8366_smi_read_bits(struct rtl8366_smi *smi, u32 len, u32 *data) ++{ ++ unsigned int sda = smi->gpio_sda; ++ unsigned int sck = smi->gpio_sck; ++ ++ gpio_direction_input(sda); ++ ++ for (*data = 0; len > 0; len--) { ++ u32 u; ++ ++ rtl8366_smi_clk_delay(smi); ++ ++ /* clocking */ ++ gpio_set_value(sck, 1); ++ rtl8366_smi_clk_delay(smi); ++ u = !!gpio_get_value(sda); ++ gpio_set_value(sck, 0); ++ ++ *data |= (u << (len - 1)); ++ } ++ ++ gpio_direction_output(sda, 0); ++} ++ ++static int rtl8366_smi_wait_for_ack(struct rtl8366_smi *smi) ++{ ++ int retry_cnt; ++ ++ retry_cnt = 0; ++ do { ++ u32 ack; ++ ++ rtl8366_smi_read_bits(smi, 1, &ack); ++ if (ack == 0) ++ break; ++ ++ if (++retry_cnt > RTL8366_SMI_ACK_RETRY_COUNT) { ++ dev_err(smi->parent, "ACK timeout\n"); ++ return -ETIMEDOUT; ++ } ++ } while (1); ++ ++ return 0; ++} ++ ++static int rtl8366_smi_write_byte(struct rtl8366_smi *smi, u8 data) ++{ ++ rtl8366_smi_write_bits(smi, data, 8); ++ return rtl8366_smi_wait_for_ack(smi); ++} ++ ++static int rtl8366_smi_write_byte_noack(struct rtl8366_smi *smi, u8 data) ++{ ++ rtl8366_smi_write_bits(smi, data, 8); ++ return 0; ++} ++ ++static int rtl8366_smi_read_byte0(struct rtl8366_smi *smi, u8 *data) ++{ ++ u32 t; ++ ++ /* read data */ ++ rtl8366_smi_read_bits(smi, 8, &t); ++ *data = (t & 0xff); ++ ++ /* send an ACK */ ++ rtl8366_smi_write_bits(smi, 0x00, 1); ++ ++ return 0; ++} ++ ++static int rtl8366_smi_read_byte1(struct rtl8366_smi *smi, u8 *data) ++{ ++ u32 t; ++ ++ /* read data */ ++ rtl8366_smi_read_bits(smi, 8, &t); ++ *data = (t & 0xff); ++ ++ /* send an ACK */ ++ rtl8366_smi_write_bits(smi, 0x01, 1); ++ ++ return 0; ++} ++ ++static int __rtl8366_smi_read_reg(struct rtl8366_smi *smi, u32 addr, u32 *data) ++{ ++ unsigned long flags; ++ u8 lo = 0; ++ u8 hi = 0; ++ int ret; ++ ++ spin_lock_irqsave(&smi->lock, flags); ++ ++ rtl8366_smi_start(smi); ++ ++ /* send READ command */ ++ ret = rtl8366_smi_write_byte(smi, smi->cmd_read); ++ if (ret) ++ goto out; ++ ++ /* set ADDR[7:0] */ ++ ret = rtl8366_smi_write_byte(smi, addr & 0xff); ++ if (ret) ++ goto out; ++ ++ /* set ADDR[15:8] */ ++ ret = rtl8366_smi_write_byte(smi, addr >> 8); ++ if (ret) ++ goto out; ++ ++ /* read DATA[7:0] */ ++ rtl8366_smi_read_byte0(smi, &lo); ++ /* read DATA[15:8] */ ++ rtl8366_smi_read_byte1(smi, &hi); ++ ++ *data = ((u32) lo) | (((u32) hi) << 8); ++ ++ ret = 0; ++ ++ out: ++ rtl8366_smi_stop(smi); ++ spin_unlock_irqrestore(&smi->lock, flags); ++ ++ return ret; ++} ++/* Read/write via mdiobus */ ++#define MDC_MDIO_CTRL0_REG 31 ++#define MDC_MDIO_START_REG 29 ++#define MDC_MDIO_CTRL1_REG 21 ++#define MDC_MDIO_ADDRESS_REG 23 ++#define MDC_MDIO_DATA_WRITE_REG 24 ++#define MDC_MDIO_DATA_READ_REG 25 ++ ++#define MDC_MDIO_START_OP 0xFFFF ++#define MDC_MDIO_ADDR_OP 0x000E ++#define MDC_MDIO_READ_OP 0x0001 ++#define MDC_MDIO_WRITE_OP 0x0003 ++#define MDC_REALTEK_PHY_ADDR 0x0 ++ ++static int __rtl8366_mdio_read_reg(struct rtl8366_smi *smi, u32 addr, u32 *data) ++{ ++ u32 phy_id = smi->phy_id; ++ struct mii_bus *mbus = smi->ext_mbus; ++ ++ BUG_ON(in_interrupt()); ++ ++ mutex_lock(&mbus->mdio_lock); ++ /* Write Start command to register 29 */ ++ mbus->write(mbus, phy_id, MDC_MDIO_START_REG, MDC_MDIO_START_OP); ++ ++ /* Write address control code to register 31 */ ++ mbus->write(mbus, phy_id, MDC_MDIO_CTRL0_REG, MDC_MDIO_ADDR_OP); ++ ++ /* Write Start command to register 29 */ ++ mbus->write(mbus, phy_id, MDC_MDIO_START_REG, MDC_MDIO_START_OP); ++ ++ /* Write address to register 23 */ ++ mbus->write(mbus, phy_id, MDC_MDIO_ADDRESS_REG, addr); ++ ++ /* Write Start command to register 29 */ ++ mbus->write(mbus, phy_id, MDC_MDIO_START_REG, MDC_MDIO_START_OP); ++ ++ /* Write read control code to register 21 */ ++ mbus->write(mbus, phy_id, MDC_MDIO_CTRL1_REG, MDC_MDIO_READ_OP); ++ ++ /* Write Start command to register 29 */ ++ mbus->write(smi->ext_mbus, phy_id, MDC_MDIO_START_REG, MDC_MDIO_START_OP); ++ ++ /* Read data from register 25 */ ++ *data = mbus->read(mbus, phy_id, MDC_MDIO_DATA_READ_REG); ++ ++ mutex_unlock(&mbus->mdio_lock); ++ ++ return 0; ++} ++ ++static int __rtl8366_mdio_write_reg(struct rtl8366_smi *smi, u32 addr, u32 data) ++{ ++ u32 phy_id = smi->phy_id; ++ struct mii_bus *mbus = smi->ext_mbus; ++ ++ BUG_ON(in_interrupt()); ++ ++ mutex_lock(&mbus->mdio_lock); ++ ++ /* Write Start command to register 29 */ ++ mbus->write(mbus, phy_id, MDC_MDIO_START_REG, MDC_MDIO_START_OP); ++ ++ /* Write address control code to register 31 */ ++ mbus->write(mbus, phy_id, MDC_MDIO_CTRL0_REG, MDC_MDIO_ADDR_OP); ++ ++ /* Write Start command to register 29 */ ++ mbus->write(mbus, phy_id, MDC_MDIO_START_REG, MDC_MDIO_START_OP); ++ ++ /* Write address to register 23 */ ++ mbus->write(mbus, phy_id, MDC_MDIO_ADDRESS_REG, addr); ++ ++ /* Write Start command to register 29 */ ++ mbus->write(mbus, phy_id, MDC_MDIO_START_REG, MDC_MDIO_START_OP); ++ ++ /* Write data to register 24 */ ++ mbus->write(mbus, phy_id, MDC_MDIO_DATA_WRITE_REG, data); ++ ++ /* Write Start command to register 29 */ ++ mbus->write(mbus, phy_id, MDC_MDIO_START_REG, MDC_MDIO_START_OP); ++ ++ /* Write data control code to register 21 */ ++ mbus->write(mbus, phy_id, MDC_MDIO_CTRL1_REG, MDC_MDIO_WRITE_OP); ++ ++ mutex_unlock(&mbus->mdio_lock); ++ return 0; ++} ++ ++int rtl8366_smi_read_reg(struct rtl8366_smi *smi, u32 addr, u32 *data) ++{ ++ if (smi->ext_mbus) ++ return __rtl8366_mdio_read_reg(smi, addr, data); ++ else ++ return __rtl8366_smi_read_reg(smi, addr, data); ++} ++EXPORT_SYMBOL_GPL(rtl8366_smi_read_reg); ++ ++static int __rtl8366_smi_write_reg(struct rtl8366_smi *smi, ++ u32 addr, u32 data, bool ack) ++{ ++ unsigned long flags; ++ int ret; ++ ++ spin_lock_irqsave(&smi->lock, flags); ++ ++ rtl8366_smi_start(smi); ++ ++ /* send WRITE command */ ++ ret = rtl8366_smi_write_byte(smi, smi->cmd_write); ++ if (ret) ++ goto out; ++ ++ /* set ADDR[7:0] */ ++ ret = rtl8366_smi_write_byte(smi, addr & 0xff); ++ if (ret) ++ goto out; ++ ++ /* set ADDR[15:8] */ ++ ret = rtl8366_smi_write_byte(smi, addr >> 8); ++ if (ret) ++ goto out; ++ ++ /* write DATA[7:0] */ ++ ret = rtl8366_smi_write_byte(smi, data & 0xff); ++ if (ret) ++ goto out; ++ ++ /* write DATA[15:8] */ ++ if (ack) ++ ret = rtl8366_smi_write_byte(smi, data >> 8); ++ else ++ ret = rtl8366_smi_write_byte_noack(smi, data >> 8); ++ if (ret) ++ goto out; ++ ++ ret = 0; ++ ++ out: ++ rtl8366_smi_stop(smi); ++ spin_unlock_irqrestore(&smi->lock, flags); ++ ++ return ret; ++} ++ ++int rtl8366_smi_write_reg(struct rtl8366_smi *smi, u32 addr, u32 data) ++{ ++ if (smi->ext_mbus) ++ return __rtl8366_mdio_write_reg(smi, addr, data); ++ else ++ return __rtl8366_smi_write_reg(smi, addr, data, true); ++} ++EXPORT_SYMBOL_GPL(rtl8366_smi_write_reg); ++ ++int rtl8366_smi_write_reg_noack(struct rtl8366_smi *smi, u32 addr, u32 data) ++{ ++ return __rtl8366_smi_write_reg(smi, addr, data, false); ++} ++EXPORT_SYMBOL_GPL(rtl8366_smi_write_reg_noack); ++ ++int rtl8366_smi_rmwr(struct rtl8366_smi *smi, u32 addr, u32 mask, u32 data) ++{ ++ u32 t; ++ int err; ++ ++ err = rtl8366_smi_read_reg(smi, addr, &t); ++ if (err) ++ return err; ++ ++ err = rtl8366_smi_write_reg(smi, addr, (t & ~mask) | data); ++ return err; ++ ++} ++EXPORT_SYMBOL_GPL(rtl8366_smi_rmwr); ++ ++static int rtl8366_reset(struct rtl8366_smi *smi) ++{ ++ if (smi->hw_reset) { ++ smi->hw_reset(smi, true); ++ msleep(RTL8366_SMI_HW_STOP_DELAY); ++ smi->hw_reset(smi, false); ++ msleep(RTL8366_SMI_HW_START_DELAY); ++ return 0; ++ } ++ ++ return smi->ops->reset_chip(smi); ++} ++ ++static int rtl8366_mc_is_used(struct rtl8366_smi *smi, int mc_index, int *used) ++{ ++ int err; ++ int i; ++ ++ *used = 0; ++ for (i = 0; i < smi->num_ports; i++) { ++ int index = 0; ++ ++ err = smi->ops->get_mc_index(smi, i, &index); ++ if (err) ++ return err; ++ ++ if (mc_index == index) { ++ *used = 1; ++ break; ++ } ++ } ++ ++ return 0; ++} ++ ++static int rtl8366_set_vlan(struct rtl8366_smi *smi, int vid, u32 member, ++ u32 untag, u32 fid) ++{ ++ struct rtl8366_vlan_4k vlan4k; ++ int err; ++ int i; ++ ++ /* Update the 4K table */ ++ err = smi->ops->get_vlan_4k(smi, vid, &vlan4k); ++ if (err) ++ return err; ++ ++ vlan4k.member = member; ++ vlan4k.untag = untag; ++ vlan4k.fid = fid; ++ err = smi->ops->set_vlan_4k(smi, &vlan4k); ++ if (err) ++ return err; ++ ++ /* Try to find an existing MC entry for this VID */ ++ for (i = 0; i < smi->num_vlan_mc; i++) { ++ struct rtl8366_vlan_mc vlanmc; ++ ++ err = smi->ops->get_vlan_mc(smi, i, &vlanmc); ++ if (err) ++ return err; ++ ++ if (vid == vlanmc.vid) { ++ /* update the MC entry */ ++ vlanmc.member = member; ++ vlanmc.untag = untag; ++ vlanmc.fid = fid; ++ ++ err = smi->ops->set_vlan_mc(smi, i, &vlanmc); ++ break; ++ } ++ } ++ ++ return err; ++} ++ ++static int rtl8366_get_pvid(struct rtl8366_smi *smi, int port, int *val) ++{ ++ struct rtl8366_vlan_mc vlanmc; ++ int err; ++ int index; ++ ++ err = smi->ops->get_mc_index(smi, port, &index); ++ if (err) ++ return err; ++ ++ err = smi->ops->get_vlan_mc(smi, index, &vlanmc); ++ if (err) ++ return err; ++ ++ *val = vlanmc.vid; ++ return 0; ++} ++ ++static int rtl8366_set_pvid(struct rtl8366_smi *smi, unsigned port, ++ unsigned vid) ++{ ++ struct rtl8366_vlan_mc vlanmc; ++ struct rtl8366_vlan_4k vlan4k; ++ int err; ++ int i; ++ ++ /* Try to find an existing MC entry for this VID */ ++ for (i = 0; i < smi->num_vlan_mc; i++) { ++ err = smi->ops->get_vlan_mc(smi, i, &vlanmc); ++ if (err) ++ return err; ++ ++ if (vid == vlanmc.vid) { ++ err = smi->ops->set_vlan_mc(smi, i, &vlanmc); ++ if (err) ++ return err; ++ ++ err = smi->ops->set_mc_index(smi, port, i); ++ return err; ++ } ++ } ++ ++ /* We have no MC entry for this VID, try to find an empty one */ ++ for (i = 0; i < smi->num_vlan_mc; i++) { ++ err = smi->ops->get_vlan_mc(smi, i, &vlanmc); ++ if (err) ++ return err; ++ ++ if (vlanmc.vid == 0 && vlanmc.member == 0) { ++ /* Update the entry from the 4K table */ ++ err = smi->ops->get_vlan_4k(smi, vid, &vlan4k); ++ if (err) ++ return err; ++ ++ vlanmc.vid = vid; ++ vlanmc.member = vlan4k.member; ++ vlanmc.untag = vlan4k.untag; ++ vlanmc.fid = vlan4k.fid; ++ err = smi->ops->set_vlan_mc(smi, i, &vlanmc); ++ if (err) ++ return err; ++ ++ err = smi->ops->set_mc_index(smi, port, i); ++ return err; ++ } ++ } ++ ++ /* MC table is full, try to find an unused entry and replace it */ ++ for (i = 0; i < smi->num_vlan_mc; i++) { ++ int used; ++ ++ err = rtl8366_mc_is_used(smi, i, &used); ++ if (err) ++ return err; ++ ++ if (!used) { ++ /* Update the entry from the 4K table */ ++ err = smi->ops->get_vlan_4k(smi, vid, &vlan4k); ++ if (err) ++ return err; ++ ++ vlanmc.vid = vid; ++ vlanmc.member = vlan4k.member; ++ vlanmc.untag = vlan4k.untag; ++ vlanmc.fid = vlan4k.fid; ++ err = smi->ops->set_vlan_mc(smi, i, &vlanmc); ++ if (err) ++ return err; ++ ++ err = smi->ops->set_mc_index(smi, port, i); ++ return err; ++ } ++ } ++ ++ dev_err(smi->parent, ++ "all VLAN member configurations are in use\n"); ++ ++ return -ENOSPC; ++} ++ ++static int rtl8366_smi_enable_vlan(struct rtl8366_smi *smi, int enable) ++{ ++ int err; ++ ++ err = smi->ops->enable_vlan(smi, enable); ++ if (err) ++ return err; ++ ++ smi->vlan_enabled = enable; ++ ++ if (!enable) { ++ smi->vlan4k_enabled = 0; ++ err = smi->ops->enable_vlan4k(smi, enable); ++ } ++ ++ return err; ++} ++ ++static int rtl8366_smi_enable_vlan4k(struct rtl8366_smi *smi, int enable) ++{ ++ int err; ++ ++ if (enable) { ++ err = smi->ops->enable_vlan(smi, enable); ++ if (err) ++ return err; ++ ++ smi->vlan_enabled = enable; ++ } ++ ++ err = smi->ops->enable_vlan4k(smi, enable); ++ if (err) ++ return err; ++ ++ smi->vlan4k_enabled = enable; ++ return 0; ++} ++ ++static int rtl8366_smi_enable_all_ports(struct rtl8366_smi *smi, int enable) ++{ ++ int port; ++ int err; ++ ++ for (port = 0; port < smi->num_ports; port++) { ++ err = smi->ops->enable_port(smi, port, enable); ++ if (err) ++ return err; ++ } ++ ++ return 0; ++} ++ ++static int rtl8366_smi_reset_vlan(struct rtl8366_smi *smi) ++{ ++ struct rtl8366_vlan_mc vlanmc; ++ int err; ++ int i; ++ ++ rtl8366_smi_enable_vlan(smi, 0); ++ rtl8366_smi_enable_vlan4k(smi, 0); ++ ++ /* clear VLAN member configurations */ ++ vlanmc.vid = 0; ++ vlanmc.priority = 0; ++ vlanmc.member = 0; ++ vlanmc.untag = 0; ++ vlanmc.fid = 0; ++ for (i = 0; i < smi->num_vlan_mc; i++) { ++ err = smi->ops->set_vlan_mc(smi, i, &vlanmc); ++ if (err) ++ return err; ++ } ++ ++ return 0; ++} ++ ++static int rtl8366_init_vlan(struct rtl8366_smi *smi) ++{ ++ int port; ++ int err; ++ ++ err = rtl8366_smi_reset_vlan(smi); ++ if (err) ++ return err; ++ ++ for (port = 0; port < smi->num_ports; port++) { ++ u32 mask; ++ ++ if (port == smi->cpu_port) ++ mask = (1 << smi->num_ports) - 1; ++ else ++ mask = (1 << port) | (1 << smi->cpu_port); ++ ++ err = rtl8366_set_vlan(smi, (port + 1), mask, mask, 0); ++ if (err) ++ return err; ++ ++ err = rtl8366_set_pvid(smi, port, (port + 1)); ++ if (err) ++ return err; ++ } ++ ++ return rtl8366_smi_enable_vlan(smi, 1); ++} ++ ++#ifdef CONFIG_RTL8366_SMI_DEBUG_FS ++int rtl8366_debugfs_open(struct inode *inode, struct file *file) ++{ ++ file->private_data = inode->i_private; ++ return 0; ++} ++EXPORT_SYMBOL_GPL(rtl8366_debugfs_open); ++ ++static ssize_t rtl8366_read_debugfs_vlan_mc(struct file *file, ++ char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct rtl8366_smi *smi = (struct rtl8366_smi *)file->private_data; ++ int i, len = 0; ++ char *buf = smi->buf; ++ ++ len += snprintf(buf + len, sizeof(smi->buf) - len, ++ "%2s %6s %4s %6s %6s %3s\n", ++ "id", "vid","prio", "member", "untag", "fid"); ++ ++ for (i = 0; i < smi->num_vlan_mc; ++i) { ++ struct rtl8366_vlan_mc vlanmc; ++ ++ smi->ops->get_vlan_mc(smi, i, &vlanmc); ++ ++ len += snprintf(buf + len, sizeof(smi->buf) - len, ++ "%2d %6d %4d 0x%04x 0x%04x %3d\n", ++ i, vlanmc.vid, vlanmc.priority, ++ vlanmc.member, vlanmc.untag, vlanmc.fid); ++ } ++ ++ return simple_read_from_buffer(user_buf, count, ppos, buf, len); ++} ++ ++#define RTL8366_VLAN4K_PAGE_SIZE 64 ++#define RTL8366_VLAN4K_NUM_PAGES (4096 / RTL8366_VLAN4K_PAGE_SIZE) ++ ++static ssize_t rtl8366_read_debugfs_vlan_4k(struct file *file, ++ char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct rtl8366_smi *smi = (struct rtl8366_smi *)file->private_data; ++ int i, len = 0; ++ int offset; ++ char *buf = smi->buf; ++ ++ if (smi->dbg_vlan_4k_page >= RTL8366_VLAN4K_NUM_PAGES) { ++ len += snprintf(buf + len, sizeof(smi->buf) - len, ++ "invalid page: %u\n", smi->dbg_vlan_4k_page); ++ return simple_read_from_buffer(user_buf, count, ppos, buf, len); ++ } ++ ++ len += snprintf(buf + len, sizeof(smi->buf) - len, ++ "%4s %6s %6s %3s\n", ++ "vid", "member", "untag", "fid"); ++ ++ offset = RTL8366_VLAN4K_PAGE_SIZE * smi->dbg_vlan_4k_page; ++ for (i = 0; i < RTL8366_VLAN4K_PAGE_SIZE; i++) { ++ struct rtl8366_vlan_4k vlan4k; ++ ++ smi->ops->get_vlan_4k(smi, offset + i, &vlan4k); ++ ++ len += snprintf(buf + len, sizeof(smi->buf) - len, ++ "%4d 0x%04x 0x%04x %3d\n", ++ vlan4k.vid, vlan4k.member, ++ vlan4k.untag, vlan4k.fid); ++ } ++ ++ return simple_read_from_buffer(user_buf, count, ppos, buf, len); ++} ++ ++static ssize_t rtl8366_read_debugfs_pvid(struct file *file, ++ char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct rtl8366_smi *smi = (struct rtl8366_smi *)file->private_data; ++ char *buf = smi->buf; ++ int len = 0; ++ int i; ++ ++ len += snprintf(buf + len, sizeof(smi->buf) - len, "%4s %4s\n", ++ "port", "pvid"); ++ ++ for (i = 0; i < smi->num_ports; i++) { ++ int pvid; ++ int err; ++ ++ err = rtl8366_get_pvid(smi, i, &pvid); ++ if (err) ++ len += snprintf(buf + len, sizeof(smi->buf) - len, ++ "%4d error\n", i); ++ else ++ len += snprintf(buf + len, sizeof(smi->buf) - len, ++ "%4d %4d\n", i, pvid); ++ } ++ ++ return simple_read_from_buffer(user_buf, count, ppos, buf, len); ++} ++ ++static ssize_t rtl8366_read_debugfs_reg(struct file *file, ++ char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct rtl8366_smi *smi = (struct rtl8366_smi *)file->private_data; ++ u32 t, reg = smi->dbg_reg; ++ int err, len = 0; ++ char *buf = smi->buf; ++ ++ memset(buf, '\0', sizeof(smi->buf)); ++ ++ err = rtl8366_smi_read_reg(smi, reg, &t); ++ if (err) { ++ len += snprintf(buf, sizeof(smi->buf), ++ "Read failed (reg: 0x%04x)\n", reg); ++ return simple_read_from_buffer(user_buf, count, ppos, buf, len); ++ } ++ ++ len += snprintf(buf, sizeof(smi->buf), "reg = 0x%04x, val = 0x%04x\n", ++ reg, t); ++ ++ return simple_read_from_buffer(user_buf, count, ppos, buf, len); ++} ++ ++static ssize_t rtl8366_write_debugfs_reg(struct file *file, ++ const char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct rtl8366_smi *smi = (struct rtl8366_smi *)file->private_data; ++ unsigned long data; ++ u32 reg = smi->dbg_reg; ++ int err; ++ size_t len; ++ char *buf = smi->buf; ++ ++ len = min(count, sizeof(smi->buf) - 1); ++ if (copy_from_user(buf, user_buf, len)) { ++ dev_err(smi->parent, "copy from user failed\n"); ++ return -EFAULT; ++ } ++ ++ buf[len] = '\0'; ++ if (len > 0 && buf[len - 1] == '\n') ++ buf[len - 1] = '\0'; ++ ++ ++ if (kstrtoul(buf, 16, &data)) { ++ dev_err(smi->parent, "Invalid reg value %s\n", buf); ++ } else { ++ err = rtl8366_smi_write_reg(smi, reg, data); ++ if (err) { ++ dev_err(smi->parent, ++ "writing reg 0x%04x val 0x%04lx failed\n", ++ reg, data); ++ } ++ } ++ ++ return count; ++} ++ ++static ssize_t rtl8366_read_debugfs_mibs(struct file *file, ++ char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct rtl8366_smi *smi = file->private_data; ++ int i, j, len = 0; ++ char *buf = smi->buf; ++ ++ len += snprintf(buf + len, sizeof(smi->buf) - len, "%-36s", ++ "Counter"); ++ ++ for (i = 0; i < smi->num_ports; i++) { ++ char port_buf[10]; ++ ++ snprintf(port_buf, sizeof(port_buf), "Port %d", i); ++ len += snprintf(buf + len, sizeof(smi->buf) - len, " %12s", ++ port_buf); ++ } ++ len += snprintf(buf + len, sizeof(smi->buf) - len, "\n"); ++ ++ for (i = 0; i < smi->num_mib_counters; i++) { ++ len += snprintf(buf + len, sizeof(smi->buf) - len, "%-36s ", ++ smi->mib_counters[i].name); ++ for (j = 0; j < smi->num_ports; j++) { ++ unsigned long long counter = 0; ++ ++ if (!smi->ops->get_mib_counter(smi, i, j, &counter)) ++ len += snprintf(buf + len, ++ sizeof(smi->buf) - len, ++ "%12llu ", counter); ++ else ++ len += snprintf(buf + len, ++ sizeof(smi->buf) - len, ++ "%12s ", "error"); ++ } ++ len += snprintf(buf + len, sizeof(smi->buf) - len, "\n"); ++ } ++ ++ return simple_read_from_buffer(user_buf, count, ppos, buf, len); ++} ++ ++static const struct file_operations fops_rtl8366_regs = { ++ .read = rtl8366_read_debugfs_reg, ++ .write = rtl8366_write_debugfs_reg, ++ .open = rtl8366_debugfs_open, ++ .owner = THIS_MODULE ++}; ++ ++static const struct file_operations fops_rtl8366_vlan_mc = { ++ .read = rtl8366_read_debugfs_vlan_mc, ++ .open = rtl8366_debugfs_open, ++ .owner = THIS_MODULE ++}; ++ ++static const struct file_operations fops_rtl8366_vlan_4k = { ++ .read = rtl8366_read_debugfs_vlan_4k, ++ .open = rtl8366_debugfs_open, ++ .owner = THIS_MODULE ++}; ++ ++static const struct file_operations fops_rtl8366_pvid = { ++ .read = rtl8366_read_debugfs_pvid, ++ .open = rtl8366_debugfs_open, ++ .owner = THIS_MODULE ++}; ++ ++static const struct file_operations fops_rtl8366_mibs = { ++ .read = rtl8366_read_debugfs_mibs, ++ .open = rtl8366_debugfs_open, ++ .owner = THIS_MODULE ++}; ++ ++static void rtl8366_debugfs_init(struct rtl8366_smi *smi) ++{ ++ struct dentry *node; ++ struct dentry *root; ++ ++ if (!smi->debugfs_root) ++ smi->debugfs_root = debugfs_create_dir(dev_name(smi->parent), ++ NULL); ++ ++ if (!smi->debugfs_root) { ++ dev_err(smi->parent, "Unable to create debugfs dir\n"); ++ return; ++ } ++ root = smi->debugfs_root; ++ ++ node = debugfs_create_x16("reg", S_IRUGO | S_IWUSR, root, ++ &smi->dbg_reg); ++ if (!node) { ++ dev_err(smi->parent, "Creating debugfs file '%s' failed\n", ++ "reg"); ++ return; ++ } ++ ++ node = debugfs_create_file("val", S_IRUGO | S_IWUSR, root, smi, ++ &fops_rtl8366_regs); ++ if (!node) { ++ dev_err(smi->parent, "Creating debugfs file '%s' failed\n", ++ "val"); ++ return; ++ } ++ ++ node = debugfs_create_file("vlan_mc", S_IRUSR, root, smi, ++ &fops_rtl8366_vlan_mc); ++ if (!node) { ++ dev_err(smi->parent, "Creating debugfs file '%s' failed\n", ++ "vlan_mc"); ++ return; ++ } ++ ++ node = debugfs_create_u8("vlan_4k_page", S_IRUGO | S_IWUSR, root, ++ &smi->dbg_vlan_4k_page); ++ if (!node) { ++ dev_err(smi->parent, "Creating debugfs file '%s' failed\n", ++ "vlan_4k_page"); ++ return; ++ } ++ ++ node = debugfs_create_file("vlan_4k", S_IRUSR, root, smi, ++ &fops_rtl8366_vlan_4k); ++ if (!node) { ++ dev_err(smi->parent, "Creating debugfs file '%s' failed\n", ++ "vlan_4k"); ++ return; ++ } ++ ++ node = debugfs_create_file("pvid", S_IRUSR, root, smi, ++ &fops_rtl8366_pvid); ++ if (!node) { ++ dev_err(smi->parent, "Creating debugfs file '%s' failed\n", ++ "pvid"); ++ return; ++ } ++ ++ node = debugfs_create_file("mibs", S_IRUSR, smi->debugfs_root, smi, ++ &fops_rtl8366_mibs); ++ if (!node) ++ dev_err(smi->parent, "Creating debugfs file '%s' failed\n", ++ "mibs"); ++} ++ ++static void rtl8366_debugfs_remove(struct rtl8366_smi *smi) ++{ ++ if (smi->debugfs_root) { ++ debugfs_remove_recursive(smi->debugfs_root); ++ smi->debugfs_root = NULL; ++ } ++} ++#else ++static inline void rtl8366_debugfs_init(struct rtl8366_smi *smi) {} ++static inline void rtl8366_debugfs_remove(struct rtl8366_smi *smi) {} ++#endif /* CONFIG_RTL8366_SMI_DEBUG_FS */ ++ ++static int rtl8366_smi_mii_init(struct rtl8366_smi *smi) ++{ ++ int ret; ++ ++#ifdef CONFIG_OF ++ struct device_node *np = NULL; ++ ++ np = of_get_child_by_name(smi->parent->of_node, "mdio-bus"); ++#endif ++ ++ smi->mii_bus = mdiobus_alloc(); ++ if (smi->mii_bus == NULL) { ++ ret = -ENOMEM; ++ goto err; ++ } ++ ++ smi->mii_bus->priv = (void *) smi; ++ smi->mii_bus->name = dev_name(smi->parent); ++ smi->mii_bus->read = smi->ops->mii_read; ++ smi->mii_bus->write = smi->ops->mii_write; ++ snprintf(smi->mii_bus->id, MII_BUS_ID_SIZE, "%s", ++ dev_name(smi->parent)); ++ smi->mii_bus->parent = smi->parent; ++ smi->mii_bus->phy_mask = ~(0x1f); ++ ++#ifdef CONFIG_OF ++ if (np) ++ ret = of_mdiobus_register(smi->mii_bus, np); ++ else ++#endif ++ ret = mdiobus_register(smi->mii_bus); ++ ++ if (ret) ++ goto err_free; ++ ++ return 0; ++ ++ err_free: ++ mdiobus_free(smi->mii_bus); ++ err: ++ return ret; ++} ++ ++static void rtl8366_smi_mii_cleanup(struct rtl8366_smi *smi) ++{ ++ mdiobus_unregister(smi->mii_bus); ++ mdiobus_free(smi->mii_bus); ++} ++ ++int rtl8366_sw_reset_switch(struct switch_dev *dev) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ int err; ++ ++ err = rtl8366_reset(smi); ++ if (err) ++ return err; ++ ++ err = smi->ops->setup(smi); ++ if (err) ++ return err; ++ ++ err = rtl8366_smi_reset_vlan(smi); ++ if (err) ++ return err; ++ ++ err = rtl8366_smi_enable_vlan(smi, 1); ++ if (err) ++ return err; ++ ++ return rtl8366_smi_enable_all_ports(smi, 1); ++} ++EXPORT_SYMBOL_GPL(rtl8366_sw_reset_switch); ++ ++int rtl8366_sw_get_port_pvid(struct switch_dev *dev, int port, int *val) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ return rtl8366_get_pvid(smi, port, val); ++} ++EXPORT_SYMBOL_GPL(rtl8366_sw_get_port_pvid); ++ ++int rtl8366_sw_set_port_pvid(struct switch_dev *dev, int port, int val) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ return rtl8366_set_pvid(smi, port, val); ++} ++EXPORT_SYMBOL_GPL(rtl8366_sw_set_port_pvid); ++ ++int rtl8366_sw_get_port_mib(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ int i, len = 0; ++ unsigned long long counter = 0; ++ char *buf = smi->buf; ++ ++ if (val->port_vlan >= smi->num_ports) ++ return -EINVAL; ++ ++ len += snprintf(buf + len, sizeof(smi->buf) - len, ++ "Port %d MIB counters\n", ++ val->port_vlan); ++ ++ for (i = 0; i < smi->num_mib_counters; ++i) { ++ len += snprintf(buf + len, sizeof(smi->buf) - len, ++ "%-36s: ", smi->mib_counters[i].name); ++ if (!smi->ops->get_mib_counter(smi, i, val->port_vlan, ++ &counter)) ++ len += snprintf(buf + len, sizeof(smi->buf) - len, ++ "%llu\n", counter); ++ else ++ len += snprintf(buf + len, sizeof(smi->buf) - len, ++ "%s\n", "error"); ++ } ++ ++ val->value.s = buf; ++ val->len = len; ++ return 0; ++} ++EXPORT_SYMBOL_GPL(rtl8366_sw_get_port_mib); ++ ++int rtl8366_sw_get_port_stats(struct switch_dev *dev, int port, ++ struct switch_port_stats *stats, ++ int txb_id, int rxb_id) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ unsigned long long counter = 0; ++ int ret; ++ ++ if (port >= smi->num_ports) ++ return -EINVAL; ++ ++ ret = smi->ops->get_mib_counter(smi, txb_id, port, &counter); ++ if (ret) ++ return ret; ++ ++ stats->tx_bytes = counter; ++ ++ ret = smi->ops->get_mib_counter(smi, rxb_id, port, &counter); ++ if (ret) ++ return ret; ++ ++ stats->rx_bytes = counter; ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(rtl8366_sw_get_port_stats); ++ ++int rtl8366_sw_get_vlan_info(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ int i; ++ u32 len = 0; ++ struct rtl8366_vlan_4k vlan4k; ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ char *buf = smi->buf; ++ int err; ++ ++ if (!smi->ops->is_vlan_valid(smi, val->port_vlan)) ++ return -EINVAL; ++ ++ memset(buf, '\0', sizeof(smi->buf)); ++ ++ err = smi->ops->get_vlan_4k(smi, val->port_vlan, &vlan4k); ++ if (err) ++ return err; ++ ++ len += snprintf(buf + len, sizeof(smi->buf) - len, ++ "VLAN %d: Ports: '", vlan4k.vid); ++ ++ for (i = 0; i < smi->num_ports; i++) { ++ if (!(vlan4k.member & (1 << i))) ++ continue; ++ ++ len += snprintf(buf + len, sizeof(smi->buf) - len, "%d%s", i, ++ (vlan4k.untag & (1 << i)) ? "" : "t"); ++ } ++ ++ len += snprintf(buf + len, sizeof(smi->buf) - len, ++ "', members=%04x, untag=%04x, fid=%u", ++ vlan4k.member, vlan4k.untag, vlan4k.fid); ++ ++ val->value.s = buf; ++ val->len = len; ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(rtl8366_sw_get_vlan_info); ++ ++int rtl8366_sw_get_vlan_ports(struct switch_dev *dev, struct switch_val *val) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ struct switch_port *port; ++ struct rtl8366_vlan_4k vlan4k; ++ int i; ++ ++ if (!smi->ops->is_vlan_valid(smi, val->port_vlan)) ++ return -EINVAL; ++ ++ smi->ops->get_vlan_4k(smi, val->port_vlan, &vlan4k); ++ ++ port = &val->value.ports[0]; ++ val->len = 0; ++ for (i = 0; i < smi->num_ports; i++) { ++ if (!(vlan4k.member & BIT(i))) ++ continue; ++ ++ port->id = i; ++ port->flags = (vlan4k.untag & BIT(i)) ? ++ 0 : BIT(SWITCH_PORT_FLAG_TAGGED); ++ val->len++; ++ port++; ++ } ++ return 0; ++} ++EXPORT_SYMBOL_GPL(rtl8366_sw_get_vlan_ports); ++ ++int rtl8366_sw_set_vlan_ports(struct switch_dev *dev, struct switch_val *val) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ struct switch_port *port; ++ u32 member = 0; ++ u32 untag = 0; ++ int err; ++ int i; ++ ++ if (!smi->ops->is_vlan_valid(smi, val->port_vlan)) ++ return -EINVAL; ++ ++ port = &val->value.ports[0]; ++ for (i = 0; i < val->len; i++, port++) { ++ int pvid = 0; ++ member |= BIT(port->id); ++ ++ if (!(port->flags & BIT(SWITCH_PORT_FLAG_TAGGED))) ++ untag |= BIT(port->id); ++ ++ /* ++ * To ensure that we have a valid MC entry for this VLAN, ++ * initialize the port VLAN ID here. ++ */ ++ err = rtl8366_get_pvid(smi, port->id, &pvid); ++ if (err < 0) ++ return err; ++ if (pvid == 0) { ++ err = rtl8366_set_pvid(smi, port->id, val->port_vlan); ++ if (err < 0) ++ return err; ++ } ++ } ++ ++ return rtl8366_set_vlan(smi, val->port_vlan, member, untag, 0); ++} ++EXPORT_SYMBOL_GPL(rtl8366_sw_set_vlan_ports); ++ ++int rtl8366_sw_get_vlan_fid(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rtl8366_vlan_4k vlan4k; ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ int err; ++ ++ if (!smi->ops->is_vlan_valid(smi, val->port_vlan)) ++ return -EINVAL; ++ ++ err = smi->ops->get_vlan_4k(smi, val->port_vlan, &vlan4k); ++ if (err) ++ return err; ++ ++ val->value.i = vlan4k.fid; ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(rtl8366_sw_get_vlan_fid); ++ ++int rtl8366_sw_set_vlan_fid(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rtl8366_vlan_4k vlan4k; ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ int err; ++ ++ if (!smi->ops->is_vlan_valid(smi, val->port_vlan)) ++ return -EINVAL; ++ ++ if (val->value.i < 0 || val->value.i > attr->max) ++ return -EINVAL; ++ ++ err = smi->ops->get_vlan_4k(smi, val->port_vlan, &vlan4k); ++ if (err) ++ return err; ++ ++ return rtl8366_set_vlan(smi, val->port_vlan, ++ vlan4k.member, ++ vlan4k.untag, ++ val->value.i); ++} ++EXPORT_SYMBOL_GPL(rtl8366_sw_set_vlan_fid); ++ ++int rtl8366_sw_get_vlan_enable(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ ++ if (attr->ofs > 2) ++ return -EINVAL; ++ ++ if (attr->ofs == 1) ++ val->value.i = smi->vlan_enabled; ++ else ++ val->value.i = smi->vlan4k_enabled; ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(rtl8366_sw_get_vlan_enable); ++ ++int rtl8366_sw_set_vlan_enable(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ int err; ++ ++ if (attr->ofs > 2) ++ return -EINVAL; ++ ++ if (attr->ofs == 1) ++ err = rtl8366_smi_enable_vlan(smi, val->value.i); ++ else ++ err = rtl8366_smi_enable_vlan4k(smi, val->value.i); ++ ++ return err; ++} ++EXPORT_SYMBOL_GPL(rtl8366_sw_set_vlan_enable); ++ ++struct rtl8366_smi *rtl8366_smi_alloc(struct device *parent) ++{ ++ struct rtl8366_smi *smi; ++ ++ BUG_ON(!parent); ++ ++ smi = kzalloc(sizeof(*smi), GFP_KERNEL); ++ if (!smi) { ++ dev_err(parent, "no memory for private data\n"); ++ return NULL; ++ } ++ ++ smi->parent = parent; ++ return smi; ++} ++EXPORT_SYMBOL_GPL(rtl8366_smi_alloc); ++ ++static int __rtl8366_smi_init(struct rtl8366_smi *smi, const char *name) ++{ ++ int err; ++ ++ if (!smi->ext_mbus) { ++ err = gpio_request(smi->gpio_sda, name); ++ if (err) { ++ printk(KERN_ERR "rtl8366_smi: gpio_request failed for %u, err=%d\n", ++ smi->gpio_sda, err); ++ goto err_out; ++ } ++ ++ err = gpio_request(smi->gpio_sck, name); ++ if (err) { ++ printk(KERN_ERR "rtl8366_smi: gpio_request failed for %u, err=%d\n", ++ smi->gpio_sck, err); ++ goto err_free_sda; ++ } ++ } ++ ++ spin_lock_init(&smi->lock); ++ ++ /* start the switch */ ++ if (smi->hw_reset) { ++ smi->hw_reset(smi, false); ++ msleep(RTL8366_SMI_HW_START_DELAY); ++ } ++ ++ return 0; ++ ++ err_free_sda: ++ gpio_free(smi->gpio_sda); ++ err_out: ++ return err; ++} ++ ++static void __rtl8366_smi_cleanup(struct rtl8366_smi *smi) ++{ ++ if (smi->hw_reset) ++ smi->hw_reset(smi, true); ++ ++ if (!smi->ext_mbus) { ++ gpio_free(smi->gpio_sck); ++ gpio_free(smi->gpio_sda); ++ } ++} ++ ++enum rtl8366_type rtl8366_smi_detect(struct rtl8366_platform_data *pdata) ++{ ++ static struct rtl8366_smi smi; ++ enum rtl8366_type type = RTL8366_TYPE_UNKNOWN; ++ u32 reg = 0; ++ ++ memset(&smi, 0, sizeof(smi)); ++ smi.gpio_sda = pdata->gpio_sda; ++ smi.gpio_sck = pdata->gpio_sck; ++ smi.clk_delay = 10; ++ smi.cmd_read = 0xa9; ++ smi.cmd_write = 0xa8; ++ ++ if (__rtl8366_smi_init(&smi, "rtl8366")) ++ goto out; ++ ++ if (rtl8366_smi_read_reg(&smi, 0x5c, ®)) ++ goto cleanup; ++ ++ switch(reg) { ++ case 0x6027: ++ printk("Found an RTL8366S switch\n"); ++ type = RTL8366_TYPE_S; ++ break; ++ case 0x5937: ++ printk("Found an RTL8366RB switch\n"); ++ type = RTL8366_TYPE_RB; ++ break; ++ default: ++ printk("Found an Unknown RTL8366 switch (id=0x%04x)\n", reg); ++ break; ++ } ++ ++cleanup: ++ __rtl8366_smi_cleanup(&smi); ++out: ++ return type; ++} ++ ++int rtl8366_smi_init(struct rtl8366_smi *smi) ++{ ++ int err; ++ ++ if (!smi->ops) ++ return -EINVAL; ++ ++ err = __rtl8366_smi_init(smi, dev_name(smi->parent)); ++ if (err) ++ goto err_out; ++ ++ if (!smi->ext_mbus) ++ dev_info(smi->parent, "using GPIO pins %u (SDA) and %u (SCK)\n", ++ smi->gpio_sda, smi->gpio_sck); ++ else ++ dev_info(smi->parent, "using MDIO bus '%s'\n", smi->ext_mbus->name); ++ ++ err = smi->ops->detect(smi); ++ if (err) { ++ dev_err(smi->parent, "chip detection failed, err=%d\n", err); ++ goto err_free_sck; ++ } ++ ++ err = rtl8366_reset(smi); ++ if (err) ++ goto err_free_sck; ++ ++ err = smi->ops->setup(smi); ++ if (err) { ++ dev_err(smi->parent, "chip setup failed, err=%d\n", err); ++ goto err_free_sck; ++ } ++ ++ err = rtl8366_init_vlan(smi); ++ if (err) { ++ dev_err(smi->parent, "VLAN initialization failed, err=%d\n", ++ err); ++ goto err_free_sck; ++ } ++ ++ err = rtl8366_smi_enable_all_ports(smi, 1); ++ if (err) ++ goto err_free_sck; ++ ++ err = rtl8366_smi_mii_init(smi); ++ if (err) ++ goto err_free_sck; ++ ++ rtl8366_debugfs_init(smi); ++ ++ return 0; ++ ++ err_free_sck: ++ __rtl8366_smi_cleanup(smi); ++ err_out: ++ return err; ++} ++EXPORT_SYMBOL_GPL(rtl8366_smi_init); ++ ++void rtl8366_smi_cleanup(struct rtl8366_smi *smi) ++{ ++ rtl8366_debugfs_remove(smi); ++ rtl8366_smi_mii_cleanup(smi); ++ __rtl8366_smi_cleanup(smi); ++} ++EXPORT_SYMBOL_GPL(rtl8366_smi_cleanup); ++ ++#ifdef CONFIG_OF ++static void rtl8366_smi_reset(struct rtl8366_smi *smi, bool active) ++{ ++ if (active) ++ reset_control_assert(smi->reset); ++ else ++ reset_control_deassert(smi->reset); ++} ++ ++static int rtl8366_smi_probe_of(struct platform_device *pdev, struct rtl8366_smi *smi) ++{ ++ int sck = of_get_named_gpio(pdev->dev.of_node, "gpio-sck", 0); ++ int sda = of_get_named_gpio(pdev->dev.of_node, "gpio-sda", 0); ++ struct device_node *np = pdev->dev.of_node; ++ struct device_node *mdio_node; ++ ++ mdio_node = of_parse_phandle(np, "mii-bus", 0); ++ if (!mdio_node) { ++ dev_err(&pdev->dev, "cannot find mdio node phandle"); ++ goto try_gpio; ++ } ++ ++ smi->ext_mbus = of_mdio_find_bus(mdio_node); ++ if (!smi->ext_mbus) { ++ dev_info(&pdev->dev, ++ "cannot find mdio bus from bus handle (yet)"); ++ goto try_gpio; ++ } ++ ++ if (of_property_read_u32(np, "phy-id", &smi->phy_id)) ++ smi->phy_id = MDC_REALTEK_PHY_ADDR; ++ ++ return 0; ++ ++try_gpio: ++ if (!gpio_is_valid(sck) || !gpio_is_valid(sda)) { ++ if (!mdio_node) { ++ dev_err(&pdev->dev, "gpios missing in devictree\n"); ++ return -EINVAL; ++ } else { ++ return -EPROBE_DEFER; ++ } ++ } ++ ++ smi->gpio_sda = sda; ++ smi->gpio_sck = sck; ++ smi->reset = devm_reset_control_get(&pdev->dev, "switch"); ++ if (!IS_ERR(smi->reset)) ++ smi->hw_reset = rtl8366_smi_reset; ++ ++ return 0; ++} ++#else ++static inline int rtl8366_smi_probe_of(struct platform_device *pdev, struct rtl8366_smi *smi) ++{ ++ return -ENODEV; ++} ++#endif ++ ++static int rtl8366_smi_probe_plat(struct platform_device *pdev, struct rtl8366_smi *smi) ++{ ++ struct rtl8366_platform_data *pdata = pdev->dev.platform_data; ++ ++ if (!pdev->dev.platform_data) { ++ dev_err(&pdev->dev, "no platform data specified\n"); ++ return -EINVAL; ++ } ++ ++ smi->gpio_sda = pdata->gpio_sda; ++ smi->gpio_sck = pdata->gpio_sck; ++ smi->hw_reset = pdata->hw_reset; ++ smi->phy_id = MDC_REALTEK_PHY_ADDR; ++ ++ return 0; ++} ++ ++ ++struct rtl8366_smi *rtl8366_smi_probe(struct platform_device *pdev) ++{ ++ struct rtl8366_smi *smi; ++ int err; ++ ++ smi = rtl8366_smi_alloc(&pdev->dev); ++ if (!smi) ++ return NULL; ++ ++ if (pdev->dev.of_node) ++ err = rtl8366_smi_probe_of(pdev, smi); ++ else ++ err = rtl8366_smi_probe_plat(pdev, smi); ++ ++ if (err) ++ goto free_smi; ++ ++ return smi; ++ ++free_smi: ++ kfree(smi); ++ return ERR_PTR(err); ++} ++EXPORT_SYMBOL_GPL(rtl8366_smi_probe); ++ ++MODULE_DESCRIPTION("Realtek RTL8366 SMI interface driver"); ++MODULE_AUTHOR("Gabor Juhos "); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/net/phy/rtl8366_smi.h b/drivers/net/phy/rtl8366_smi.h +new file mode 100644 +index 000000000000..2608240bb083 +--- /dev/null ++++ b/drivers/net/phy/rtl8366_smi.h +@@ -0,0 +1,171 @@ ++/* ++ * Realtek RTL8366 SMI interface driver defines ++ * ++ * Copyright (C) 2009-2010 Gabor Juhos ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation. ++ */ ++ ++#ifndef _RTL8366_SMI_H ++#define _RTL8366_SMI_H ++ ++#include ++#include ++#include ++#include ++ ++struct rtl8366_smi_ops; ++struct rtl8366_vlan_ops; ++struct mii_bus; ++struct dentry; ++struct inode; ++struct file; ++ ++typedef enum rtl8367b_chip_e { ++ RTL8367B_CHIP_UNKNOWN, ++ /* Family B */ ++ RTL8367B_CHIP_RTL8367RB, ++ RTL8367B_CHIP_RTL8367R_VB, /* chip with exception in extif assignment */ ++/* Family C */ ++ RTL8367B_CHIP_RTL8367RB_VB, ++ RTL8367B_CHIP_RTL8367S, ++/* Family D */ ++ RTL8367B_CHIP_RTL8367S_VB /* chip with exception in extif assignment */ ++} rtl8367b_chip_t; ++ ++struct rtl8366_mib_counter { ++ unsigned base; ++ unsigned offset; ++ unsigned length; ++ const char *name; ++}; ++ ++struct rtl8366_smi { ++ struct device *parent; ++ unsigned int gpio_sda; ++ unsigned int gpio_sck; ++ void (*hw_reset)(struct rtl8366_smi *smi, bool active); ++ unsigned int clk_delay; /* ns */ ++ u8 cmd_read; ++ u8 cmd_write; ++ spinlock_t lock; ++ struct mii_bus *mii_bus; ++ int mii_irq[PHY_MAX_ADDR]; ++ struct switch_dev sw_dev; ++ ++ unsigned int cpu_port; ++ unsigned int num_ports; ++ unsigned int num_vlan_mc; ++ unsigned int num_mib_counters; ++ struct rtl8366_mib_counter *mib_counters; ++ ++ struct rtl8366_smi_ops *ops; ++ ++ int vlan_enabled; ++ int vlan4k_enabled; ++ ++ char buf[4096]; ++ ++ struct reset_control *reset; ++ ++#ifdef CONFIG_RTL8366_SMI_DEBUG_FS ++ struct dentry *debugfs_root; ++ u16 dbg_reg; ++ u8 dbg_vlan_4k_page; ++#endif ++ u32 phy_id; ++ rtl8367b_chip_t rtl8367b_chip; ++ struct mii_bus *ext_mbus; ++ struct rtl8366_vlan_mc *emu_vlanmc; ++}; ++ ++struct rtl8366_vlan_mc { ++ u16 vid; ++ u16 untag; ++ u16 member; ++ u8 fid; ++ u8 priority; ++}; ++ ++struct rtl8366_vlan_4k { ++ u16 vid; ++ u16 untag; ++ u16 member; ++ u8 fid; ++}; ++ ++struct rtl8366_smi_ops { ++ int (*detect)(struct rtl8366_smi *smi); ++ int (*reset_chip)(struct rtl8366_smi *smi); ++ int (*setup)(struct rtl8366_smi *smi); ++ ++ int (*mii_read)(struct mii_bus *bus, int addr, int reg); ++ int (*mii_write)(struct mii_bus *bus, int addr, int reg, u16 val); ++ ++ int (*get_vlan_mc)(struct rtl8366_smi *smi, u32 index, ++ struct rtl8366_vlan_mc *vlanmc); ++ int (*set_vlan_mc)(struct rtl8366_smi *smi, u32 index, ++ const struct rtl8366_vlan_mc *vlanmc); ++ int (*get_vlan_4k)(struct rtl8366_smi *smi, u32 vid, ++ struct rtl8366_vlan_4k *vlan4k); ++ int (*set_vlan_4k)(struct rtl8366_smi *smi, ++ const struct rtl8366_vlan_4k *vlan4k); ++ int (*get_mc_index)(struct rtl8366_smi *smi, int port, int *val); ++ int (*set_mc_index)(struct rtl8366_smi *smi, int port, int index); ++ int (*get_mib_counter)(struct rtl8366_smi *smi, int counter, ++ int port, unsigned long long *val); ++ int (*is_vlan_valid)(struct rtl8366_smi *smi, unsigned vlan); ++ int (*enable_vlan)(struct rtl8366_smi *smi, int enable); ++ int (*enable_vlan4k)(struct rtl8366_smi *smi, int enable); ++ int (*enable_port)(struct rtl8366_smi *smi, int port, int enable); ++}; ++ ++struct rtl8366_smi *rtl8366_smi_alloc(struct device *parent); ++int rtl8366_smi_init(struct rtl8366_smi *smi); ++void rtl8366_smi_cleanup(struct rtl8366_smi *smi); ++int rtl8366_smi_write_reg(struct rtl8366_smi *smi, u32 addr, u32 data); ++int rtl8366_smi_write_reg_noack(struct rtl8366_smi *smi, u32 addr, u32 data); ++int rtl8366_smi_read_reg(struct rtl8366_smi *smi, u32 addr, u32 *data); ++int rtl8366_smi_rmwr(struct rtl8366_smi *smi, u32 addr, u32 mask, u32 data); ++ ++#ifdef CONFIG_RTL8366_SMI_DEBUG_FS ++int rtl8366_debugfs_open(struct inode *inode, struct file *file); ++#endif ++ ++static inline struct rtl8366_smi *sw_to_rtl8366_smi(struct switch_dev *sw) ++{ ++ return container_of(sw, struct rtl8366_smi, sw_dev); ++} ++ ++int rtl8366_sw_reset_switch(struct switch_dev *dev); ++int rtl8366_sw_get_port_pvid(struct switch_dev *dev, int port, int *val); ++int rtl8366_sw_set_port_pvid(struct switch_dev *dev, int port, int val); ++int rtl8366_sw_get_port_mib(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val); ++int rtl8366_sw_get_vlan_info(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val); ++int rtl8366_sw_get_vlan_fid(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val); ++int rtl8366_sw_set_vlan_fid(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val); ++int rtl8366_sw_get_vlan_ports(struct switch_dev *dev, struct switch_val *val); ++int rtl8366_sw_set_vlan_ports(struct switch_dev *dev, struct switch_val *val); ++int rtl8366_sw_get_vlan_enable(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val); ++int rtl8366_sw_set_vlan_enable(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val); ++int rtl8366_sw_get_port_stats(struct switch_dev *dev, int port, ++ struct switch_port_stats *stats, ++ int txb_id, int rxb_id); ++ ++struct rtl8366_smi* rtl8366_smi_probe(struct platform_device *pdev); ++ ++#endif /* _RTL8366_SMI_H */ +diff --git a/drivers/net/phy/rtl8366rb.c b/drivers/net/phy/rtl8366rb.c +new file mode 100644 +index 000000000000..7057b252526d +--- /dev/null ++++ b/drivers/net/phy/rtl8366rb.c +@@ -0,0 +1,1529 @@ ++/* ++ * Platform driver for the Realtek RTL8366RB ethernet switch ++ * ++ * Copyright (C) 2009-2010 Gabor Juhos ++ * Copyright (C) 2010 Antti Seppälä ++ * Copyright (C) 2010 Roman Yeryomin ++ * Copyright (C) 2011 Colin Leitner ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "rtl8366_smi.h" ++ ++#define RTL8366RB_DRIVER_DESC "Realtek RTL8366RB ethernet switch driver" ++#define RTL8366RB_DRIVER_VER "0.2.4" ++ ++#define RTL8366RB_PHY_NO_MAX 4 ++#define RTL8366RB_PHY_PAGE_MAX 7 ++#define RTL8366RB_PHY_ADDR_MAX 31 ++ ++/* Switch Global Configuration register */ ++#define RTL8366RB_SGCR 0x0000 ++#define RTL8366RB_SGCR_EN_BC_STORM_CTRL BIT(0) ++#define RTL8366RB_SGCR_MAX_LENGTH(_x) (_x << 4) ++#define RTL8366RB_SGCR_MAX_LENGTH_MASK RTL8366RB_SGCR_MAX_LENGTH(0x3) ++#define RTL8366RB_SGCR_MAX_LENGTH_1522 RTL8366RB_SGCR_MAX_LENGTH(0x0) ++#define RTL8366RB_SGCR_MAX_LENGTH_1536 RTL8366RB_SGCR_MAX_LENGTH(0x1) ++#define RTL8366RB_SGCR_MAX_LENGTH_1552 RTL8366RB_SGCR_MAX_LENGTH(0x2) ++#define RTL8366RB_SGCR_MAX_LENGTH_9216 RTL8366RB_SGCR_MAX_LENGTH(0x3) ++#define RTL8366RB_SGCR_EN_VLAN BIT(13) ++#define RTL8366RB_SGCR_EN_VLAN_4KTB BIT(14) ++ ++/* Port Enable Control register */ ++#define RTL8366RB_PECR 0x0001 ++ ++/* Port Mirror Control Register */ ++#define RTL8366RB_PMCR 0x0007 ++#define RTL8366RB_PMCR_SOURCE_PORT(_x) (_x) ++#define RTL8366RB_PMCR_SOURCE_PORT_MASK 0x000f ++#define RTL8366RB_PMCR_MONITOR_PORT(_x) ((_x) << 4) ++#define RTL8366RB_PMCR_MONITOR_PORT_MASK 0x00f0 ++#define RTL8366RB_PMCR_MIRROR_RX BIT(8) ++#define RTL8366RB_PMCR_MIRROR_TX BIT(9) ++#define RTL8366RB_PMCR_MIRROR_SPC BIT(10) ++#define RTL8366RB_PMCR_MIRROR_ISO BIT(11) ++ ++/* Switch Security Control registers */ ++#define RTL8366RB_SSCR0 0x0002 ++#define RTL8366RB_SSCR1 0x0003 ++#define RTL8366RB_SSCR2 0x0004 ++#define RTL8366RB_SSCR2_DROP_UNKNOWN_DA BIT(0) ++ ++#define RTL8366RB_RESET_CTRL_REG 0x0100 ++#define RTL8366RB_CHIP_CTRL_RESET_HW 1 ++#define RTL8366RB_CHIP_CTRL_RESET_SW (1 << 1) ++ ++#define RTL8366RB_CHIP_VERSION_CTRL_REG 0x050A ++#define RTL8366RB_CHIP_VERSION_MASK 0xf ++#define RTL8366RB_CHIP_ID_REG 0x0509 ++#define RTL8366RB_CHIP_ID_8366 0x5937 ++ ++/* PHY registers control */ ++#define RTL8366RB_PHY_ACCESS_CTRL_REG 0x8000 ++#define RTL8366RB_PHY_ACCESS_DATA_REG 0x8002 ++ ++#define RTL8366RB_PHY_CTRL_READ 1 ++#define RTL8366RB_PHY_CTRL_WRITE 0 ++ ++#define RTL8366RB_PHY_REG_MASK 0x1f ++#define RTL8366RB_PHY_PAGE_OFFSET 5 ++#define RTL8366RB_PHY_PAGE_MASK (0xf << 5) ++#define RTL8366RB_PHY_NO_OFFSET 9 ++#define RTL8366RB_PHY_NO_MASK (0x1f << 9) ++ ++#define RTL8366RB_VLAN_INGRESS_CTRL2_REG 0x037f ++ ++/* LED control registers */ ++#define RTL8366RB_LED_BLINKRATE_REG 0x0430 ++#define RTL8366RB_LED_BLINKRATE_BIT 0 ++#define RTL8366RB_LED_BLINKRATE_MASK 0x0007 ++ ++#define RTL8366RB_LED_CTRL_REG 0x0431 ++#define RTL8366RB_LED_0_1_CTRL_REG 0x0432 ++#define RTL8366RB_LED_2_3_CTRL_REG 0x0433 ++ ++#define RTL8366RB_MIB_COUNT 33 ++#define RTL8366RB_GLOBAL_MIB_COUNT 1 ++#define RTL8366RB_MIB_COUNTER_PORT_OFFSET 0x0050 ++#define RTL8366RB_MIB_COUNTER_BASE 0x1000 ++#define RTL8366RB_MIB_CTRL_REG 0x13F0 ++#define RTL8366RB_MIB_CTRL_USER_MASK 0x0FFC ++#define RTL8366RB_MIB_CTRL_BUSY_MASK BIT(0) ++#define RTL8366RB_MIB_CTRL_RESET_MASK BIT(1) ++#define RTL8366RB_MIB_CTRL_PORT_RESET(_p) BIT(2 + (_p)) ++#define RTL8366RB_MIB_CTRL_GLOBAL_RESET BIT(11) ++ ++#define RTL8366RB_PORT_VLAN_CTRL_BASE 0x0063 ++#define RTL8366RB_PORT_VLAN_CTRL_REG(_p) \ ++ (RTL8366RB_PORT_VLAN_CTRL_BASE + (_p) / 4) ++#define RTL8366RB_PORT_VLAN_CTRL_MASK 0xf ++#define RTL8366RB_PORT_VLAN_CTRL_SHIFT(_p) (4 * ((_p) % 4)) ++ ++ ++#define RTL8366RB_VLAN_TABLE_READ_BASE 0x018C ++#define RTL8366RB_VLAN_TABLE_WRITE_BASE 0x0185 ++ ++ ++#define RTL8366RB_TABLE_ACCESS_CTRL_REG 0x0180 ++#define RTL8366RB_TABLE_VLAN_READ_CTRL 0x0E01 ++#define RTL8366RB_TABLE_VLAN_WRITE_CTRL 0x0F01 ++ ++#define RTL8366RB_VLAN_MC_BASE(_x) (0x0020 + (_x) * 3) ++ ++ ++#define RTL8366RB_PORT_LINK_STATUS_BASE 0x0014 ++#define RTL8366RB_PORT_STATUS_SPEED_MASK 0x0003 ++#define RTL8366RB_PORT_STATUS_DUPLEX_MASK 0x0004 ++#define RTL8366RB_PORT_STATUS_LINK_MASK 0x0010 ++#define RTL8366RB_PORT_STATUS_TXPAUSE_MASK 0x0020 ++#define RTL8366RB_PORT_STATUS_RXPAUSE_MASK 0x0040 ++#define RTL8366RB_PORT_STATUS_AN_MASK 0x0080 ++ ++ ++#define RTL8366RB_PORT_NUM_CPU 5 ++#define RTL8366RB_NUM_PORTS 6 ++#define RTL8366RB_NUM_VLANS 16 ++#define RTL8366RB_NUM_LEDGROUPS 4 ++#define RTL8366RB_NUM_VIDS 4096 ++#define RTL8366RB_PRIORITYMAX 7 ++#define RTL8366RB_FIDMAX 7 ++ ++ ++#define RTL8366RB_PORT_1 (1 << 0) /* In userspace port 0 */ ++#define RTL8366RB_PORT_2 (1 << 1) /* In userspace port 1 */ ++#define RTL8366RB_PORT_3 (1 << 2) /* In userspace port 2 */ ++#define RTL8366RB_PORT_4 (1 << 3) /* In userspace port 3 */ ++#define RTL8366RB_PORT_5 (1 << 4) /* In userspace port 4 */ ++ ++#define RTL8366RB_PORT_CPU (1 << 5) /* CPU port */ ++ ++#define RTL8366RB_PORT_ALL (RTL8366RB_PORT_1 | \ ++ RTL8366RB_PORT_2 | \ ++ RTL8366RB_PORT_3 | \ ++ RTL8366RB_PORT_4 | \ ++ RTL8366RB_PORT_5 | \ ++ RTL8366RB_PORT_CPU) ++ ++#define RTL8366RB_PORT_ALL_BUT_CPU (RTL8366RB_PORT_1 | \ ++ RTL8366RB_PORT_2 | \ ++ RTL8366RB_PORT_3 | \ ++ RTL8366RB_PORT_4 | \ ++ RTL8366RB_PORT_5) ++ ++#define RTL8366RB_PORT_ALL_EXTERNAL (RTL8366RB_PORT_1 | \ ++ RTL8366RB_PORT_2 | \ ++ RTL8366RB_PORT_3 | \ ++ RTL8366RB_PORT_4) ++ ++#define RTL8366RB_PORT_ALL_INTERNAL RTL8366RB_PORT_CPU ++ ++#define RTL8366RB_VLAN_VID_MASK 0xfff ++#define RTL8366RB_VLAN_PRIORITY_SHIFT 12 ++#define RTL8366RB_VLAN_PRIORITY_MASK 0x7 ++#define RTL8366RB_VLAN_UNTAG_SHIFT 8 ++#define RTL8366RB_VLAN_UNTAG_MASK 0xff ++#define RTL8366RB_VLAN_MEMBER_MASK 0xff ++#define RTL8366RB_VLAN_FID_MASK 0x7 ++ ++ ++/* Port ingress bandwidth control */ ++#define RTL8366RB_IB_BASE 0x0200 ++#define RTL8366RB_IB_REG(pnum) (RTL8366RB_IB_BASE + pnum) ++#define RTL8366RB_IB_BDTH_MASK 0x3fff ++#define RTL8366RB_IB_PREIFG_OFFSET 14 ++#define RTL8366RB_IB_PREIFG_MASK (1 << RTL8366RB_IB_PREIFG_OFFSET) ++ ++/* Port egress bandwidth control */ ++#define RTL8366RB_EB_BASE 0x02d1 ++#define RTL8366RB_EB_REG(pnum) (RTL8366RB_EB_BASE + pnum) ++#define RTL8366RB_EB_BDTH_MASK 0x3fff ++#define RTL8366RB_EB_PREIFG_REG 0x02f8 ++#define RTL8366RB_EB_PREIFG_OFFSET 9 ++#define RTL8366RB_EB_PREIFG_MASK (1 << RTL8366RB_EB_PREIFG_OFFSET) ++ ++#define RTL8366RB_BDTH_SW_MAX 1048512 ++#define RTL8366RB_BDTH_UNIT 64 ++#define RTL8366RB_BDTH_REG_DEFAULT 16383 ++ ++/* QOS */ ++#define RTL8366RB_QOS_BIT 15 ++#define RTL8366RB_QOS_MASK (1 << RTL8366RB_QOS_BIT) ++/* Include/Exclude Preamble and IFG (20 bytes). 0:Exclude, 1:Include. */ ++#define RTL8366RB_QOS_DEFAULT_PREIFG 1 ++ ++ ++#define RTL8366RB_MIB_RXB_ID 0 /* IfInOctets */ ++#define RTL8366RB_MIB_TXB_ID 20 /* IfOutOctets */ ++ ++static struct rtl8366_mib_counter rtl8366rb_mib_counters[] = { ++ { 0, 0, 4, "IfInOctets" }, ++ { 0, 4, 4, "EtherStatsOctets" }, ++ { 0, 8, 2, "EtherStatsUnderSizePkts" }, ++ { 0, 10, 2, "EtherFragments" }, ++ { 0, 12, 2, "EtherStatsPkts64Octets" }, ++ { 0, 14, 2, "EtherStatsPkts65to127Octets" }, ++ { 0, 16, 2, "EtherStatsPkts128to255Octets" }, ++ { 0, 18, 2, "EtherStatsPkts256to511Octets" }, ++ { 0, 20, 2, "EtherStatsPkts512to1023Octets" }, ++ { 0, 22, 2, "EtherStatsPkts1024to1518Octets" }, ++ { 0, 24, 2, "EtherOversizeStats" }, ++ { 0, 26, 2, "EtherStatsJabbers" }, ++ { 0, 28, 2, "IfInUcastPkts" }, ++ { 0, 30, 2, "EtherStatsMulticastPkts" }, ++ { 0, 32, 2, "EtherStatsBroadcastPkts" }, ++ { 0, 34, 2, "EtherStatsDropEvents" }, ++ { 0, 36, 2, "Dot3StatsFCSErrors" }, ++ { 0, 38, 2, "Dot3StatsSymbolErrors" }, ++ { 0, 40, 2, "Dot3InPauseFrames" }, ++ { 0, 42, 2, "Dot3ControlInUnknownOpcodes" }, ++ { 0, 44, 4, "IfOutOctets" }, ++ { 0, 48, 2, "Dot3StatsSingleCollisionFrames" }, ++ { 0, 50, 2, "Dot3StatMultipleCollisionFrames" }, ++ { 0, 52, 2, "Dot3sDeferredTransmissions" }, ++ { 0, 54, 2, "Dot3StatsLateCollisions" }, ++ { 0, 56, 2, "EtherStatsCollisions" }, ++ { 0, 58, 2, "Dot3StatsExcessiveCollisions" }, ++ { 0, 60, 2, "Dot3OutPauseFrames" }, ++ { 0, 62, 2, "Dot1dBasePortDelayExceededDiscards" }, ++ { 0, 64, 2, "Dot1dTpPortInDiscards" }, ++ { 0, 66, 2, "IfOutUcastPkts" }, ++ { 0, 68, 2, "IfOutMulticastPkts" }, ++ { 0, 70, 2, "IfOutBroadcastPkts" }, ++}; ++ ++#define REG_WR(_smi, _reg, _val) \ ++ do { \ ++ err = rtl8366_smi_write_reg(_smi, _reg, _val); \ ++ if (err) \ ++ return err; \ ++ } while (0) ++ ++#define REG_RMW(_smi, _reg, _mask, _val) \ ++ do { \ ++ err = rtl8366_smi_rmwr(_smi, _reg, _mask, _val); \ ++ if (err) \ ++ return err; \ ++ } while (0) ++ ++static int rtl8366rb_reset_chip(struct rtl8366_smi *smi) ++{ ++ int timeout = 10; ++ u32 data; ++ ++ rtl8366_smi_write_reg_noack(smi, RTL8366RB_RESET_CTRL_REG, ++ RTL8366RB_CHIP_CTRL_RESET_HW); ++ do { ++ msleep(1); ++ if (rtl8366_smi_read_reg(smi, RTL8366RB_RESET_CTRL_REG, &data)) ++ return -EIO; ++ ++ if (!(data & RTL8366RB_CHIP_CTRL_RESET_HW)) ++ break; ++ } while (--timeout); ++ ++ if (!timeout) { ++ printk("Timeout waiting for the switch to reset\n"); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++static int rtl8366rb_setup(struct rtl8366_smi *smi) ++{ ++ int err; ++#ifdef CONFIG_OF ++ unsigned i; ++ struct device_node *np; ++ unsigned num_initvals; ++ const __be32 *paddr; ++ ++ np = smi->parent->of_node; ++ ++ paddr = of_get_property(np, "realtek,initvals", &num_initvals); ++ if (paddr) { ++ dev_info(smi->parent, "applying initvals from DTS\n"); ++ ++ if (num_initvals < (2 * sizeof(*paddr))) ++ return -EINVAL; ++ ++ num_initvals /= sizeof(*paddr); ++ ++ for (i = 0; i < num_initvals - 1; i += 2) { ++ u32 reg = be32_to_cpup(paddr + i); ++ u32 val = be32_to_cpup(paddr + i + 1); ++ ++ REG_WR(smi, reg, val); ++ } ++ } ++#endif ++ ++ /* set maximum packet length to 1536 bytes */ ++ REG_RMW(smi, RTL8366RB_SGCR, RTL8366RB_SGCR_MAX_LENGTH_MASK, ++ RTL8366RB_SGCR_MAX_LENGTH_1536); ++ ++ /* enable learning for all ports */ ++ REG_WR(smi, RTL8366RB_SSCR0, 0); ++ ++ /* enable auto ageing for all ports */ ++ REG_WR(smi, RTL8366RB_SSCR1, 0); ++ ++ /* ++ * discard VLAN tagged packets if the port is not a member of ++ * the VLAN with which the packets is associated. ++ */ ++ REG_WR(smi, RTL8366RB_VLAN_INGRESS_CTRL2_REG, RTL8366RB_PORT_ALL); ++ ++ /* don't drop packets whose DA has not been learned */ ++ REG_RMW(smi, RTL8366RB_SSCR2, RTL8366RB_SSCR2_DROP_UNKNOWN_DA, 0); ++ ++ return 0; ++} ++ ++static int rtl8366rb_read_phy_reg(struct rtl8366_smi *smi, ++ u32 phy_no, u32 page, u32 addr, u32 *data) ++{ ++ u32 reg; ++ int ret; ++ ++ if (phy_no > RTL8366RB_PHY_NO_MAX) ++ return -EINVAL; ++ ++ if (page > RTL8366RB_PHY_PAGE_MAX) ++ return -EINVAL; ++ ++ if (addr > RTL8366RB_PHY_ADDR_MAX) ++ return -EINVAL; ++ ++ ret = rtl8366_smi_write_reg(smi, RTL8366RB_PHY_ACCESS_CTRL_REG, ++ RTL8366RB_PHY_CTRL_READ); ++ if (ret) ++ return ret; ++ ++ reg = 0x8000 | (1 << (phy_no + RTL8366RB_PHY_NO_OFFSET)) | ++ ((page << RTL8366RB_PHY_PAGE_OFFSET) & RTL8366RB_PHY_PAGE_MASK) | ++ (addr & RTL8366RB_PHY_REG_MASK); ++ ++ ret = rtl8366_smi_write_reg(smi, reg, 0); ++ if (ret) ++ return ret; ++ ++ ret = rtl8366_smi_read_reg(smi, RTL8366RB_PHY_ACCESS_DATA_REG, data); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static int rtl8366rb_write_phy_reg(struct rtl8366_smi *smi, ++ u32 phy_no, u32 page, u32 addr, u32 data) ++{ ++ u32 reg; ++ int ret; ++ ++ if (phy_no > RTL8366RB_PHY_NO_MAX) ++ return -EINVAL; ++ ++ if (page > RTL8366RB_PHY_PAGE_MAX) ++ return -EINVAL; ++ ++ if (addr > RTL8366RB_PHY_ADDR_MAX) ++ return -EINVAL; ++ ++ ret = rtl8366_smi_write_reg(smi, RTL8366RB_PHY_ACCESS_CTRL_REG, ++ RTL8366RB_PHY_CTRL_WRITE); ++ if (ret) ++ return ret; ++ ++ reg = 0x8000 | (1 << (phy_no + RTL8366RB_PHY_NO_OFFSET)) | ++ ((page << RTL8366RB_PHY_PAGE_OFFSET) & RTL8366RB_PHY_PAGE_MASK) | ++ (addr & RTL8366RB_PHY_REG_MASK); ++ ++ ret = rtl8366_smi_write_reg(smi, reg, data); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static int rtl8366rb_get_mib_counter(struct rtl8366_smi *smi, int counter, ++ int port, unsigned long long *val) ++{ ++ int i; ++ int err; ++ u32 addr, data; ++ u64 mibvalue; ++ ++ if (port > RTL8366RB_NUM_PORTS || counter >= RTL8366RB_MIB_COUNT) ++ return -EINVAL; ++ ++ addr = RTL8366RB_MIB_COUNTER_BASE + ++ RTL8366RB_MIB_COUNTER_PORT_OFFSET * (port) + ++ rtl8366rb_mib_counters[counter].offset; ++ ++ /* ++ * Writing access counter address first ++ * then ASIC will prepare 64bits counter wait for being retrived ++ */ ++ data = 0; /* writing data will be discard by ASIC */ ++ err = rtl8366_smi_write_reg(smi, addr, data); ++ if (err) ++ return err; ++ ++ /* read MIB control register */ ++ err = rtl8366_smi_read_reg(smi, RTL8366RB_MIB_CTRL_REG, &data); ++ if (err) ++ return err; ++ ++ if (data & RTL8366RB_MIB_CTRL_BUSY_MASK) ++ return -EBUSY; ++ ++ if (data & RTL8366RB_MIB_CTRL_RESET_MASK) ++ return -EIO; ++ ++ mibvalue = 0; ++ for (i = rtl8366rb_mib_counters[counter].length; i > 0; i--) { ++ err = rtl8366_smi_read_reg(smi, addr + (i - 1), &data); ++ if (err) ++ return err; ++ ++ mibvalue = (mibvalue << 16) | (data & 0xFFFF); ++ } ++ ++ *val = mibvalue; ++ return 0; ++} ++ ++static int rtl8366rb_get_vlan_4k(struct rtl8366_smi *smi, u32 vid, ++ struct rtl8366_vlan_4k *vlan4k) ++{ ++ u32 data[3]; ++ int err; ++ int i; ++ ++ memset(vlan4k, '\0', sizeof(struct rtl8366_vlan_4k)); ++ ++ if (vid >= RTL8366RB_NUM_VIDS) ++ return -EINVAL; ++ ++ /* write VID */ ++ err = rtl8366_smi_write_reg(smi, RTL8366RB_VLAN_TABLE_WRITE_BASE, ++ vid & RTL8366RB_VLAN_VID_MASK); ++ if (err) ++ return err; ++ ++ /* write table access control word */ ++ err = rtl8366_smi_write_reg(smi, RTL8366RB_TABLE_ACCESS_CTRL_REG, ++ RTL8366RB_TABLE_VLAN_READ_CTRL); ++ if (err) ++ return err; ++ ++ for (i = 0; i < 3; i++) { ++ err = rtl8366_smi_read_reg(smi, ++ RTL8366RB_VLAN_TABLE_READ_BASE + i, ++ &data[i]); ++ if (err) ++ return err; ++ } ++ ++ vlan4k->vid = vid; ++ vlan4k->untag = (data[1] >> RTL8366RB_VLAN_UNTAG_SHIFT) & ++ RTL8366RB_VLAN_UNTAG_MASK; ++ vlan4k->member = data[1] & RTL8366RB_VLAN_MEMBER_MASK; ++ vlan4k->fid = data[2] & RTL8366RB_VLAN_FID_MASK; ++ ++ return 0; ++} ++ ++static int rtl8366rb_set_vlan_4k(struct rtl8366_smi *smi, ++ const struct rtl8366_vlan_4k *vlan4k) ++{ ++ u32 data[3]; ++ int err; ++ int i; ++ ++ if (vlan4k->vid >= RTL8366RB_NUM_VIDS || ++ vlan4k->member > RTL8366RB_VLAN_MEMBER_MASK || ++ vlan4k->untag > RTL8366RB_VLAN_UNTAG_MASK || ++ vlan4k->fid > RTL8366RB_FIDMAX) ++ return -EINVAL; ++ ++ data[0] = vlan4k->vid & RTL8366RB_VLAN_VID_MASK; ++ data[1] = (vlan4k->member & RTL8366RB_VLAN_MEMBER_MASK) | ++ ((vlan4k->untag & RTL8366RB_VLAN_UNTAG_MASK) << ++ RTL8366RB_VLAN_UNTAG_SHIFT); ++ data[2] = vlan4k->fid & RTL8366RB_VLAN_FID_MASK; ++ ++ for (i = 0; i < 3; i++) { ++ err = rtl8366_smi_write_reg(smi, ++ RTL8366RB_VLAN_TABLE_WRITE_BASE + i, ++ data[i]); ++ if (err) ++ return err; ++ } ++ ++ /* write table access control word */ ++ err = rtl8366_smi_write_reg(smi, RTL8366RB_TABLE_ACCESS_CTRL_REG, ++ RTL8366RB_TABLE_VLAN_WRITE_CTRL); ++ ++ return err; ++} ++ ++static int rtl8366rb_get_vlan_mc(struct rtl8366_smi *smi, u32 index, ++ struct rtl8366_vlan_mc *vlanmc) ++{ ++ u32 data[3]; ++ int err; ++ int i; ++ ++ memset(vlanmc, '\0', sizeof(struct rtl8366_vlan_mc)); ++ ++ if (index >= RTL8366RB_NUM_VLANS) ++ return -EINVAL; ++ ++ for (i = 0; i < 3; i++) { ++ err = rtl8366_smi_read_reg(smi, ++ RTL8366RB_VLAN_MC_BASE(index) + i, ++ &data[i]); ++ if (err) ++ return err; ++ } ++ ++ vlanmc->vid = data[0] & RTL8366RB_VLAN_VID_MASK; ++ vlanmc->priority = (data[0] >> RTL8366RB_VLAN_PRIORITY_SHIFT) & ++ RTL8366RB_VLAN_PRIORITY_MASK; ++ vlanmc->untag = (data[1] >> RTL8366RB_VLAN_UNTAG_SHIFT) & ++ RTL8366RB_VLAN_UNTAG_MASK; ++ vlanmc->member = data[1] & RTL8366RB_VLAN_MEMBER_MASK; ++ vlanmc->fid = data[2] & RTL8366RB_VLAN_FID_MASK; ++ ++ return 0; ++} ++ ++static int rtl8366rb_set_vlan_mc(struct rtl8366_smi *smi, u32 index, ++ const struct rtl8366_vlan_mc *vlanmc) ++{ ++ u32 data[3]; ++ int err; ++ int i; ++ ++ if (index >= RTL8366RB_NUM_VLANS || ++ vlanmc->vid >= RTL8366RB_NUM_VIDS || ++ vlanmc->priority > RTL8366RB_PRIORITYMAX || ++ vlanmc->member > RTL8366RB_VLAN_MEMBER_MASK || ++ vlanmc->untag > RTL8366RB_VLAN_UNTAG_MASK || ++ vlanmc->fid > RTL8366RB_FIDMAX) ++ return -EINVAL; ++ ++ data[0] = (vlanmc->vid & RTL8366RB_VLAN_VID_MASK) | ++ ((vlanmc->priority & RTL8366RB_VLAN_PRIORITY_MASK) << ++ RTL8366RB_VLAN_PRIORITY_SHIFT); ++ data[1] = (vlanmc->member & RTL8366RB_VLAN_MEMBER_MASK) | ++ ((vlanmc->untag & RTL8366RB_VLAN_UNTAG_MASK) << ++ RTL8366RB_VLAN_UNTAG_SHIFT); ++ data[2] = vlanmc->fid & RTL8366RB_VLAN_FID_MASK; ++ ++ for (i = 0; i < 3; i++) { ++ err = rtl8366_smi_write_reg(smi, ++ RTL8366RB_VLAN_MC_BASE(index) + i, ++ data[i]); ++ if (err) ++ return err; ++ } ++ ++ return 0; ++} ++ ++static int rtl8366rb_get_mc_index(struct rtl8366_smi *smi, int port, int *val) ++{ ++ u32 data; ++ int err; ++ ++ if (port >= RTL8366RB_NUM_PORTS) ++ return -EINVAL; ++ ++ err = rtl8366_smi_read_reg(smi, RTL8366RB_PORT_VLAN_CTRL_REG(port), ++ &data); ++ if (err) ++ return err; ++ ++ *val = (data >> RTL8366RB_PORT_VLAN_CTRL_SHIFT(port)) & ++ RTL8366RB_PORT_VLAN_CTRL_MASK; ++ ++ return 0; ++ ++} ++ ++static int rtl8366rb_set_mc_index(struct rtl8366_smi *smi, int port, int index) ++{ ++ if (port >= RTL8366RB_NUM_PORTS || index >= RTL8366RB_NUM_VLANS) ++ return -EINVAL; ++ ++ return rtl8366_smi_rmwr(smi, RTL8366RB_PORT_VLAN_CTRL_REG(port), ++ RTL8366RB_PORT_VLAN_CTRL_MASK << ++ RTL8366RB_PORT_VLAN_CTRL_SHIFT(port), ++ (index & RTL8366RB_PORT_VLAN_CTRL_MASK) << ++ RTL8366RB_PORT_VLAN_CTRL_SHIFT(port)); ++} ++ ++static int rtl8366rb_is_vlan_valid(struct rtl8366_smi *smi, unsigned vlan) ++{ ++ unsigned max = RTL8366RB_NUM_VLANS; ++ ++ if (smi->vlan4k_enabled) ++ max = RTL8366RB_NUM_VIDS - 1; ++ ++ if (vlan == 0 || vlan >= max) ++ return 0; ++ ++ return 1; ++} ++ ++static int rtl8366rb_enable_vlan(struct rtl8366_smi *smi, int enable) ++{ ++ return rtl8366_smi_rmwr(smi, RTL8366RB_SGCR, RTL8366RB_SGCR_EN_VLAN, ++ (enable) ? RTL8366RB_SGCR_EN_VLAN : 0); ++} ++ ++static int rtl8366rb_enable_vlan4k(struct rtl8366_smi *smi, int enable) ++{ ++ return rtl8366_smi_rmwr(smi, RTL8366RB_SGCR, ++ RTL8366RB_SGCR_EN_VLAN_4KTB, ++ (enable) ? RTL8366RB_SGCR_EN_VLAN_4KTB : 0); ++} ++ ++static int rtl8366rb_enable_port(struct rtl8366_smi *smi, int port, int enable) ++{ ++ return rtl8366_smi_rmwr(smi, RTL8366RB_PECR, (1 << port), ++ (enable) ? 0 : (1 << port)); ++} ++ ++static int rtl8366rb_sw_reset_mibs(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ ++ return rtl8366_smi_rmwr(smi, RTL8366RB_MIB_CTRL_REG, 0, ++ RTL8366RB_MIB_CTRL_GLOBAL_RESET); ++} ++ ++static int rtl8366rb_sw_get_blinkrate(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ u32 data; ++ ++ rtl8366_smi_read_reg(smi, RTL8366RB_LED_BLINKRATE_REG, &data); ++ ++ val->value.i = (data & (RTL8366RB_LED_BLINKRATE_MASK)); ++ ++ return 0; ++} ++ ++static int rtl8366rb_sw_set_blinkrate(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ ++ if (val->value.i >= 6) ++ return -EINVAL; ++ ++ return rtl8366_smi_rmwr(smi, RTL8366RB_LED_BLINKRATE_REG, ++ RTL8366RB_LED_BLINKRATE_MASK, ++ val->value.i); ++} ++ ++static int rtl8366rb_sw_get_learning_enable(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ u32 data; ++ ++ rtl8366_smi_read_reg(smi, RTL8366RB_SSCR0, &data); ++ val->value.i = !data; ++ ++ return 0; ++} ++ ++ ++static int rtl8366rb_sw_set_learning_enable(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ u32 portmask = 0; ++ int err = 0; ++ ++ if (!val->value.i) ++ portmask = RTL8366RB_PORT_ALL; ++ ++ /* set learning for all ports */ ++ REG_WR(smi, RTL8366RB_SSCR0, portmask); ++ ++ /* set auto ageing for all ports */ ++ REG_WR(smi, RTL8366RB_SSCR1, portmask); ++ ++ return 0; ++} ++ ++static int rtl8366rb_sw_get_port_link(struct switch_dev *dev, ++ int port, ++ struct switch_port_link *link) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ u32 data = 0; ++ u32 speed; ++ ++ if (port >= RTL8366RB_NUM_PORTS) ++ return -EINVAL; ++ ++ rtl8366_smi_read_reg(smi, RTL8366RB_PORT_LINK_STATUS_BASE + (port / 2), ++ &data); ++ ++ if (port % 2) ++ data = data >> 8; ++ ++ link->link = !!(data & RTL8366RB_PORT_STATUS_LINK_MASK); ++ if (!link->link) ++ return 0; ++ ++ link->duplex = !!(data & RTL8366RB_PORT_STATUS_DUPLEX_MASK); ++ link->rx_flow = !!(data & RTL8366RB_PORT_STATUS_RXPAUSE_MASK); ++ link->tx_flow = !!(data & RTL8366RB_PORT_STATUS_TXPAUSE_MASK); ++ link->aneg = !!(data & RTL8366RB_PORT_STATUS_AN_MASK); ++ ++ speed = (data & RTL8366RB_PORT_STATUS_SPEED_MASK); ++ switch (speed) { ++ case 0: ++ link->speed = SWITCH_PORT_SPEED_10; ++ break; ++ case 1: ++ link->speed = SWITCH_PORT_SPEED_100; ++ break; ++ case 2: ++ link->speed = SWITCH_PORT_SPEED_1000; ++ break; ++ default: ++ link->speed = SWITCH_PORT_SPEED_UNKNOWN; ++ break; ++ } ++ ++ return 0; ++} ++ ++static int rtl8366rb_sw_set_port_led(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ u32 data; ++ u32 mask; ++ u32 reg; ++ ++ if (val->port_vlan >= RTL8366RB_NUM_PORTS) ++ return -EINVAL; ++ ++ if (val->port_vlan == RTL8366RB_PORT_NUM_CPU) { ++ reg = RTL8366RB_LED_BLINKRATE_REG; ++ mask = 0xF << 4; ++ data = val->value.i << 4; ++ } else { ++ reg = RTL8366RB_LED_CTRL_REG; ++ mask = 0xF << (val->port_vlan * 4), ++ data = val->value.i << (val->port_vlan * 4); ++ } ++ ++ return rtl8366_smi_rmwr(smi, reg, mask, data); ++} ++ ++static int rtl8366rb_sw_get_port_led(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ u32 data = 0; ++ ++ if (val->port_vlan >= RTL8366RB_NUM_LEDGROUPS) ++ return -EINVAL; ++ ++ rtl8366_smi_read_reg(smi, RTL8366RB_LED_CTRL_REG, &data); ++ val->value.i = (data >> (val->port_vlan * 4)) & 0x000F; ++ ++ return 0; ++} ++ ++static int rtl8366rb_sw_set_port_disable(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ u32 mask, data; ++ ++ if (val->port_vlan >= RTL8366RB_NUM_PORTS) ++ return -EINVAL; ++ ++ mask = 1 << val->port_vlan ; ++ if (val->value.i) ++ data = mask; ++ else ++ data = 0; ++ ++ return rtl8366_smi_rmwr(smi, RTL8366RB_PECR, mask, data); ++} ++ ++static int rtl8366rb_sw_get_port_disable(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ u32 data; ++ ++ if (val->port_vlan >= RTL8366RB_NUM_PORTS) ++ return -EINVAL; ++ ++ rtl8366_smi_read_reg(smi, RTL8366RB_PECR, &data); ++ if (data & (1 << val->port_vlan)) ++ val->value.i = 1; ++ else ++ val->value.i = 0; ++ ++ return 0; ++} ++ ++static int rtl8366rb_sw_set_port_rate_in(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ ++ if (val->port_vlan >= RTL8366RB_NUM_PORTS) ++ return -EINVAL; ++ ++ if (val->value.i > 0 && val->value.i < RTL8366RB_BDTH_SW_MAX) ++ val->value.i = (val->value.i - 1) / RTL8366RB_BDTH_UNIT; ++ else ++ val->value.i = RTL8366RB_BDTH_REG_DEFAULT; ++ ++ return rtl8366_smi_rmwr(smi, RTL8366RB_IB_REG(val->port_vlan), ++ RTL8366RB_IB_BDTH_MASK | RTL8366RB_IB_PREIFG_MASK, ++ val->value.i | ++ (RTL8366RB_QOS_DEFAULT_PREIFG << RTL8366RB_IB_PREIFG_OFFSET)); ++ ++} ++ ++static int rtl8366rb_sw_get_port_rate_in(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ u32 data; ++ ++ if (val->port_vlan >= RTL8366RB_NUM_PORTS) ++ return -EINVAL; ++ ++ rtl8366_smi_read_reg(smi, RTL8366RB_IB_REG(val->port_vlan), &data); ++ data &= RTL8366RB_IB_BDTH_MASK; ++ if (data < RTL8366RB_IB_BDTH_MASK) ++ data += 1; ++ ++ val->value.i = (int)data * RTL8366RB_BDTH_UNIT; ++ ++ return 0; ++} ++ ++static int rtl8366rb_sw_set_port_rate_out(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ ++ if (val->port_vlan >= RTL8366RB_NUM_PORTS) ++ return -EINVAL; ++ ++ rtl8366_smi_rmwr(smi, RTL8366RB_EB_PREIFG_REG, ++ RTL8366RB_EB_PREIFG_MASK, ++ (RTL8366RB_QOS_DEFAULT_PREIFG << RTL8366RB_EB_PREIFG_OFFSET)); ++ ++ if (val->value.i > 0 && val->value.i < RTL8366RB_BDTH_SW_MAX) ++ val->value.i = (val->value.i - 1) / RTL8366RB_BDTH_UNIT; ++ else ++ val->value.i = RTL8366RB_BDTH_REG_DEFAULT; ++ ++ return rtl8366_smi_rmwr(smi, RTL8366RB_EB_REG(val->port_vlan), ++ RTL8366RB_EB_BDTH_MASK, val->value.i ); ++ ++} ++ ++static int rtl8366rb_sw_get_port_rate_out(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ u32 data; ++ ++ if (val->port_vlan >= RTL8366RB_NUM_PORTS) ++ return -EINVAL; ++ ++ rtl8366_smi_read_reg(smi, RTL8366RB_EB_REG(val->port_vlan), &data); ++ data &= RTL8366RB_EB_BDTH_MASK; ++ if (data < RTL8366RB_EB_BDTH_MASK) ++ data += 1; ++ ++ val->value.i = (int)data * RTL8366RB_BDTH_UNIT; ++ ++ return 0; ++} ++ ++static int rtl8366rb_sw_set_qos_enable(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ u32 data; ++ ++ if (val->value.i) ++ data = RTL8366RB_QOS_MASK; ++ else ++ data = 0; ++ ++ return rtl8366_smi_rmwr(smi, RTL8366RB_SGCR, RTL8366RB_QOS_MASK, data); ++} ++ ++static int rtl8366rb_sw_get_qos_enable(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ u32 data; ++ ++ rtl8366_smi_read_reg(smi, RTL8366RB_SGCR, &data); ++ if (data & RTL8366RB_QOS_MASK) ++ val->value.i = 1; ++ else ++ val->value.i = 0; ++ ++ return 0; ++} ++ ++static int rtl8366rb_sw_set_mirror_rx_enable(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ u32 data; ++ ++ if (val->value.i) ++ data = RTL8366RB_PMCR_MIRROR_RX; ++ else ++ data = 0; ++ ++ return rtl8366_smi_rmwr(smi, RTL8366RB_PMCR, RTL8366RB_PMCR_MIRROR_RX, data); ++} ++ ++static int rtl8366rb_sw_get_mirror_rx_enable(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ u32 data; ++ ++ rtl8366_smi_read_reg(smi, RTL8366RB_PMCR, &data); ++ if (data & RTL8366RB_PMCR_MIRROR_RX) ++ val->value.i = 1; ++ else ++ val->value.i = 0; ++ ++ return 0; ++} ++ ++static int rtl8366rb_sw_set_mirror_tx_enable(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ u32 data; ++ ++ if (val->value.i) ++ data = RTL8366RB_PMCR_MIRROR_TX; ++ else ++ data = 0; ++ ++ return rtl8366_smi_rmwr(smi, RTL8366RB_PMCR, RTL8366RB_PMCR_MIRROR_TX, data); ++} ++ ++static int rtl8366rb_sw_get_mirror_tx_enable(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ u32 data; ++ ++ rtl8366_smi_read_reg(smi, RTL8366RB_PMCR, &data); ++ if (data & RTL8366RB_PMCR_MIRROR_TX) ++ val->value.i = 1; ++ else ++ val->value.i = 0; ++ ++ return 0; ++} ++ ++static int rtl8366rb_sw_set_monitor_isolation_enable(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ u32 data; ++ ++ if (val->value.i) ++ data = RTL8366RB_PMCR_MIRROR_ISO; ++ else ++ data = 0; ++ ++ return rtl8366_smi_rmwr(smi, RTL8366RB_PMCR, RTL8366RB_PMCR_MIRROR_ISO, data); ++} ++ ++static int rtl8366rb_sw_get_monitor_isolation_enable(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ u32 data; ++ ++ rtl8366_smi_read_reg(smi, RTL8366RB_PMCR, &data); ++ if (data & RTL8366RB_PMCR_MIRROR_ISO) ++ val->value.i = 1; ++ else ++ val->value.i = 0; ++ ++ return 0; ++} ++ ++static int rtl8366rb_sw_set_mirror_pause_frames_enable(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ u32 data; ++ ++ if (val->value.i) ++ data = RTL8366RB_PMCR_MIRROR_SPC; ++ else ++ data = 0; ++ ++ return rtl8366_smi_rmwr(smi, RTL8366RB_PMCR, RTL8366RB_PMCR_MIRROR_SPC, data); ++} ++ ++static int rtl8366rb_sw_get_mirror_pause_frames_enable(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ u32 data; ++ ++ rtl8366_smi_read_reg(smi, RTL8366RB_PMCR, &data); ++ if (data & RTL8366RB_PMCR_MIRROR_SPC) ++ val->value.i = 1; ++ else ++ val->value.i = 0; ++ ++ return 0; ++} ++ ++static int rtl8366rb_sw_set_mirror_monitor_port(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ u32 data; ++ ++ data = RTL8366RB_PMCR_MONITOR_PORT(val->value.i); ++ ++ return rtl8366_smi_rmwr(smi, RTL8366RB_PMCR, RTL8366RB_PMCR_MONITOR_PORT_MASK, data); ++} ++ ++static int rtl8366rb_sw_get_mirror_monitor_port(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ u32 data; ++ ++ rtl8366_smi_read_reg(smi, RTL8366RB_PMCR, &data); ++ val->value.i = (data & RTL8366RB_PMCR_MONITOR_PORT_MASK) >> 4; ++ ++ return 0; ++} ++ ++static int rtl8366rb_sw_set_mirror_source_port(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ u32 data; ++ ++ data = RTL8366RB_PMCR_SOURCE_PORT(val->value.i); ++ ++ return rtl8366_smi_rmwr(smi, RTL8366RB_PMCR, RTL8366RB_PMCR_SOURCE_PORT_MASK, data); ++} ++ ++static int rtl8366rb_sw_get_mirror_source_port(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ u32 data; ++ ++ rtl8366_smi_read_reg(smi, RTL8366RB_PMCR, &data); ++ val->value.i = data & RTL8366RB_PMCR_SOURCE_PORT_MASK; ++ ++ return 0; ++} ++ ++static int rtl8366rb_sw_reset_port_mibs(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ ++ if (val->port_vlan >= RTL8366RB_NUM_PORTS) ++ return -EINVAL; ++ ++ return rtl8366_smi_rmwr(smi, RTL8366RB_MIB_CTRL_REG, 0, ++ RTL8366RB_MIB_CTRL_PORT_RESET(val->port_vlan)); ++} ++ ++static int rtl8366rb_sw_get_port_stats(struct switch_dev *dev, int port, ++ struct switch_port_stats *stats) ++{ ++ return (rtl8366_sw_get_port_stats(dev, port, stats, ++ RTL8366RB_MIB_TXB_ID, RTL8366RB_MIB_RXB_ID)); ++} ++ ++static struct switch_attr rtl8366rb_globals[] = { ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "enable_learning", ++ .description = "Enable learning, enable aging", ++ .set = rtl8366rb_sw_set_learning_enable, ++ .get = rtl8366rb_sw_get_learning_enable, ++ .max = 1 ++ }, { ++ .type = SWITCH_TYPE_INT, ++ .name = "enable_vlan", ++ .description = "Enable VLAN mode", ++ .set = rtl8366_sw_set_vlan_enable, ++ .get = rtl8366_sw_get_vlan_enable, ++ .max = 1, ++ .ofs = 1 ++ }, { ++ .type = SWITCH_TYPE_INT, ++ .name = "enable_vlan4k", ++ .description = "Enable VLAN 4K mode", ++ .set = rtl8366_sw_set_vlan_enable, ++ .get = rtl8366_sw_get_vlan_enable, ++ .max = 1, ++ .ofs = 2 ++ }, { ++ .type = SWITCH_TYPE_NOVAL, ++ .name = "reset_mibs", ++ .description = "Reset all MIB counters", ++ .set = rtl8366rb_sw_reset_mibs, ++ }, { ++ .type = SWITCH_TYPE_INT, ++ .name = "blinkrate", ++ .description = "Get/Set LED blinking rate (0 = 43ms, 1 = 84ms," ++ " 2 = 120ms, 3 = 170ms, 4 = 340ms, 5 = 670ms)", ++ .set = rtl8366rb_sw_set_blinkrate, ++ .get = rtl8366rb_sw_get_blinkrate, ++ .max = 5 ++ }, { ++ .type = SWITCH_TYPE_INT, ++ .name = "enable_qos", ++ .description = "Enable QOS", ++ .set = rtl8366rb_sw_set_qos_enable, ++ .get = rtl8366rb_sw_get_qos_enable, ++ .max = 1 ++ }, { ++ .type = SWITCH_TYPE_INT, ++ .name = "enable_mirror_rx", ++ .description = "Enable mirroring of RX packets", ++ .set = rtl8366rb_sw_set_mirror_rx_enable, ++ .get = rtl8366rb_sw_get_mirror_rx_enable, ++ .max = 1 ++ }, { ++ .type = SWITCH_TYPE_INT, ++ .name = "enable_mirror_tx", ++ .description = "Enable mirroring of TX packets", ++ .set = rtl8366rb_sw_set_mirror_tx_enable, ++ .get = rtl8366rb_sw_get_mirror_tx_enable, ++ .max = 1 ++ }, { ++ .type = SWITCH_TYPE_INT, ++ .name = "enable_monitor_isolation", ++ .description = "Enable isolation of monitor port (TX packets will be dropped)", ++ .set = rtl8366rb_sw_set_monitor_isolation_enable, ++ .get = rtl8366rb_sw_get_monitor_isolation_enable, ++ .max = 1 ++ }, { ++ .type = SWITCH_TYPE_INT, ++ .name = "enable_mirror_pause_frames", ++ .description = "Enable mirroring of RX pause frames", ++ .set = rtl8366rb_sw_set_mirror_pause_frames_enable, ++ .get = rtl8366rb_sw_get_mirror_pause_frames_enable, ++ .max = 1 ++ }, { ++ .type = SWITCH_TYPE_INT, ++ .name = "mirror_monitor_port", ++ .description = "Mirror monitor port", ++ .set = rtl8366rb_sw_set_mirror_monitor_port, ++ .get = rtl8366rb_sw_get_mirror_monitor_port, ++ .max = 5 ++ }, { ++ .type = SWITCH_TYPE_INT, ++ .name = "mirror_source_port", ++ .description = "Mirror source port", ++ .set = rtl8366rb_sw_set_mirror_source_port, ++ .get = rtl8366rb_sw_get_mirror_source_port, ++ .max = 5 ++ }, ++}; ++ ++static struct switch_attr rtl8366rb_port[] = { ++ { ++ .type = SWITCH_TYPE_NOVAL, ++ .name = "reset_mib", ++ .description = "Reset single port MIB counters", ++ .set = rtl8366rb_sw_reset_port_mibs, ++ }, { ++ .type = SWITCH_TYPE_STRING, ++ .name = "mib", ++ .description = "Get MIB counters for port", ++ .max = 33, ++ .set = NULL, ++ .get = rtl8366_sw_get_port_mib, ++ }, { ++ .type = SWITCH_TYPE_INT, ++ .name = "led", ++ .description = "Get/Set port group (0 - 3) led mode (0 - 15)", ++ .max = 15, ++ .set = rtl8366rb_sw_set_port_led, ++ .get = rtl8366rb_sw_get_port_led, ++ }, { ++ .type = SWITCH_TYPE_INT, ++ .name = "disable", ++ .description = "Get/Set port state (enabled or disabled)", ++ .max = 1, ++ .set = rtl8366rb_sw_set_port_disable, ++ .get = rtl8366rb_sw_get_port_disable, ++ }, { ++ .type = SWITCH_TYPE_INT, ++ .name = "rate_in", ++ .description = "Get/Set port ingress (incoming) bandwidth limit in kbps", ++ .max = RTL8366RB_BDTH_SW_MAX, ++ .set = rtl8366rb_sw_set_port_rate_in, ++ .get = rtl8366rb_sw_get_port_rate_in, ++ }, { ++ .type = SWITCH_TYPE_INT, ++ .name = "rate_out", ++ .description = "Get/Set port egress (outgoing) bandwidth limit in kbps", ++ .max = RTL8366RB_BDTH_SW_MAX, ++ .set = rtl8366rb_sw_set_port_rate_out, ++ .get = rtl8366rb_sw_get_port_rate_out, ++ }, ++}; ++ ++static struct switch_attr rtl8366rb_vlan[] = { ++ { ++ .type = SWITCH_TYPE_STRING, ++ .name = "info", ++ .description = "Get vlan information", ++ .max = 1, ++ .set = NULL, ++ .get = rtl8366_sw_get_vlan_info, ++ }, { ++ .type = SWITCH_TYPE_INT, ++ .name = "fid", ++ .description = "Get/Set vlan FID", ++ .max = RTL8366RB_FIDMAX, ++ .set = rtl8366_sw_set_vlan_fid, ++ .get = rtl8366_sw_get_vlan_fid, ++ }, ++}; ++ ++static const struct switch_dev_ops rtl8366_ops = { ++ .attr_global = { ++ .attr = rtl8366rb_globals, ++ .n_attr = ARRAY_SIZE(rtl8366rb_globals), ++ }, ++ .attr_port = { ++ .attr = rtl8366rb_port, ++ .n_attr = ARRAY_SIZE(rtl8366rb_port), ++ }, ++ .attr_vlan = { ++ .attr = rtl8366rb_vlan, ++ .n_attr = ARRAY_SIZE(rtl8366rb_vlan), ++ }, ++ ++ .get_vlan_ports = rtl8366_sw_get_vlan_ports, ++ .set_vlan_ports = rtl8366_sw_set_vlan_ports, ++ .get_port_pvid = rtl8366_sw_get_port_pvid, ++ .set_port_pvid = rtl8366_sw_set_port_pvid, ++ .reset_switch = rtl8366_sw_reset_switch, ++ .get_port_link = rtl8366rb_sw_get_port_link, ++ .get_port_stats = rtl8366rb_sw_get_port_stats, ++}; ++ ++static int rtl8366rb_switch_init(struct rtl8366_smi *smi) ++{ ++ struct switch_dev *dev = &smi->sw_dev; ++ int err; ++ ++ dev->name = "RTL8366RB"; ++ dev->cpu_port = RTL8366RB_PORT_NUM_CPU; ++ dev->ports = RTL8366RB_NUM_PORTS; ++ dev->vlans = RTL8366RB_NUM_VIDS; ++ dev->ops = &rtl8366_ops; ++ dev->alias = dev_name(smi->parent); ++ ++ err = register_switch(dev, NULL); ++ if (err) ++ dev_err(smi->parent, "switch registration failed\n"); ++ ++ return err; ++} ++ ++static void rtl8366rb_switch_cleanup(struct rtl8366_smi *smi) ++{ ++ unregister_switch(&smi->sw_dev); ++} ++ ++static int rtl8366rb_mii_read(struct mii_bus *bus, int addr, int reg) ++{ ++ struct rtl8366_smi *smi = bus->priv; ++ u32 val = 0; ++ int err; ++ ++ err = rtl8366rb_read_phy_reg(smi, addr, 0, reg, &val); ++ if (err) ++ return 0xffff; ++ ++ return val; ++} ++ ++static int rtl8366rb_mii_write(struct mii_bus *bus, int addr, int reg, u16 val) ++{ ++ struct rtl8366_smi *smi = bus->priv; ++ u32 t; ++ int err; ++ ++ err = rtl8366rb_write_phy_reg(smi, addr, 0, reg, val); ++ /* flush write */ ++ (void) rtl8366rb_read_phy_reg(smi, addr, 0, reg, &t); ++ ++ return err; ++} ++ ++static int rtl8366rb_detect(struct rtl8366_smi *smi) ++{ ++ u32 chip_id = 0; ++ u32 chip_ver = 0; ++ int ret; ++ ++ ret = rtl8366_smi_read_reg(smi, RTL8366RB_CHIP_ID_REG, &chip_id); ++ if (ret) { ++ dev_err(smi->parent, "unable to read chip id\n"); ++ return ret; ++ } ++ ++ switch (chip_id) { ++ case RTL8366RB_CHIP_ID_8366: ++ break; ++ default: ++ dev_err(smi->parent, "unknown chip id (%04x)\n", chip_id); ++ return -ENODEV; ++ } ++ ++ ret = rtl8366_smi_read_reg(smi, RTL8366RB_CHIP_VERSION_CTRL_REG, ++ &chip_ver); ++ if (ret) { ++ dev_err(smi->parent, "unable to read chip version\n"); ++ return ret; ++ } ++ ++ dev_info(smi->parent, "RTL%04x ver. %u chip found\n", ++ chip_id, chip_ver & RTL8366RB_CHIP_VERSION_MASK); ++ ++ return 0; ++} ++ ++static struct rtl8366_smi_ops rtl8366rb_smi_ops = { ++ .detect = rtl8366rb_detect, ++ .reset_chip = rtl8366rb_reset_chip, ++ .setup = rtl8366rb_setup, ++ ++ .mii_read = rtl8366rb_mii_read, ++ .mii_write = rtl8366rb_mii_write, ++ ++ .get_vlan_mc = rtl8366rb_get_vlan_mc, ++ .set_vlan_mc = rtl8366rb_set_vlan_mc, ++ .get_vlan_4k = rtl8366rb_get_vlan_4k, ++ .set_vlan_4k = rtl8366rb_set_vlan_4k, ++ .get_mc_index = rtl8366rb_get_mc_index, ++ .set_mc_index = rtl8366rb_set_mc_index, ++ .get_mib_counter = rtl8366rb_get_mib_counter, ++ .is_vlan_valid = rtl8366rb_is_vlan_valid, ++ .enable_vlan = rtl8366rb_enable_vlan, ++ .enable_vlan4k = rtl8366rb_enable_vlan4k, ++ .enable_port = rtl8366rb_enable_port, ++}; ++ ++static int rtl8366rb_probe(struct platform_device *pdev) ++{ ++ static int rtl8366_smi_version_printed; ++ struct rtl8366_smi *smi; ++ int err; ++ ++ if (!rtl8366_smi_version_printed++) ++ printk(KERN_NOTICE RTL8366RB_DRIVER_DESC ++ " version " RTL8366RB_DRIVER_VER"\n"); ++ ++ smi = rtl8366_smi_probe(pdev); ++ if (IS_ERR(smi)) ++ return PTR_ERR(smi); ++ ++ smi->clk_delay = 10; ++ smi->cmd_read = 0xa9; ++ smi->cmd_write = 0xa8; ++ smi->ops = &rtl8366rb_smi_ops; ++ smi->cpu_port = RTL8366RB_PORT_NUM_CPU; ++ smi->num_ports = RTL8366RB_NUM_PORTS; ++ smi->num_vlan_mc = RTL8366RB_NUM_VLANS; ++ smi->mib_counters = rtl8366rb_mib_counters; ++ smi->num_mib_counters = ARRAY_SIZE(rtl8366rb_mib_counters); ++ ++ err = rtl8366_smi_init(smi); ++ if (err) ++ goto err_free_smi; ++ ++ platform_set_drvdata(pdev, smi); ++ ++ err = rtl8366rb_switch_init(smi); ++ if (err) ++ goto err_clear_drvdata; ++ ++ return 0; ++ ++ err_clear_drvdata: ++ platform_set_drvdata(pdev, NULL); ++ rtl8366_smi_cleanup(smi); ++ err_free_smi: ++ kfree(smi); ++ return err; ++} ++ ++static void rtl8366rb_remove(struct platform_device *pdev) ++{ ++ struct rtl8366_smi *smi = platform_get_drvdata(pdev); ++ ++ if (smi) { ++ rtl8366rb_switch_cleanup(smi); ++ platform_set_drvdata(pdev, NULL); ++ rtl8366_smi_cleanup(smi); ++ kfree(smi); ++ } ++} ++ ++#ifdef CONFIG_OF ++static const struct of_device_id rtl8366rb_match[] = { ++ { .compatible = "realtek,rtl8366rb" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, rtl8366rb_match); ++#endif ++ ++static struct platform_driver rtl8366rb_driver = { ++ .driver = { ++ .name = RTL8366RB_DRIVER_NAME, ++ .of_match_table = of_match_ptr(rtl8366rb_match), ++ }, ++ .probe = rtl8366rb_probe, ++ .remove_new = rtl8366rb_remove, ++}; ++ ++static int __init rtl8366rb_module_init(void) ++{ ++ return platform_driver_register(&rtl8366rb_driver); ++} ++module_init(rtl8366rb_module_init); ++ ++static void __exit rtl8366rb_module_exit(void) ++{ ++ platform_driver_unregister(&rtl8366rb_driver); ++} ++module_exit(rtl8366rb_module_exit); ++ ++MODULE_DESCRIPTION(RTL8366RB_DRIVER_DESC); ++MODULE_VERSION(RTL8366RB_DRIVER_VER); ++MODULE_AUTHOR("Gabor Juhos "); ++MODULE_AUTHOR("Antti Seppälä "); ++MODULE_AUTHOR("Roman Yeryomin "); ++MODULE_AUTHOR("Colin Leitner "); ++MODULE_LICENSE("GPL v2"); ++MODULE_ALIAS("platform:" RTL8366RB_DRIVER_NAME); +diff --git a/drivers/net/phy/rtl8366s.c b/drivers/net/phy/rtl8366s.c +new file mode 100644 +index 000000000000..5458c5048728 +--- /dev/null ++++ b/drivers/net/phy/rtl8366s.c +@@ -0,0 +1,1317 @@ ++/* ++ * Platform driver for the Realtek RTL8366S ethernet switch ++ * ++ * Copyright (C) 2009-2010 Gabor Juhos ++ * Copyright (C) 2010 Antti Seppälä ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "rtl8366_smi.h" ++ ++#define RTL8366S_DRIVER_DESC "Realtek RTL8366S ethernet switch driver" ++#define RTL8366S_DRIVER_VER "0.2.2" ++ ++#define RTL8366S_PHY_NO_MAX 4 ++#define RTL8366S_PHY_PAGE_MAX 7 ++#define RTL8366S_PHY_ADDR_MAX 31 ++ ++/* Switch Global Configuration register */ ++#define RTL8366S_SGCR 0x0000 ++#define RTL8366S_SGCR_EN_BC_STORM_CTRL BIT(0) ++#define RTL8366S_SGCR_MAX_LENGTH(_x) (_x << 4) ++#define RTL8366S_SGCR_MAX_LENGTH_MASK RTL8366S_SGCR_MAX_LENGTH(0x3) ++#define RTL8366S_SGCR_MAX_LENGTH_1522 RTL8366S_SGCR_MAX_LENGTH(0x0) ++#define RTL8366S_SGCR_MAX_LENGTH_1536 RTL8366S_SGCR_MAX_LENGTH(0x1) ++#define RTL8366S_SGCR_MAX_LENGTH_1552 RTL8366S_SGCR_MAX_LENGTH(0x2) ++#define RTL8366S_SGCR_MAX_LENGTH_16000 RTL8366S_SGCR_MAX_LENGTH(0x3) ++#define RTL8366S_SGCR_EN_VLAN BIT(13) ++ ++/* Port Enable Control register */ ++#define RTL8366S_PECR 0x0001 ++ ++/* Green Ethernet Feature (based on GPL_BELKIN_F5D8235-4_v1000 v1.01.24) */ ++#define RTL8366S_GREEN_ETHERNET_CTRL_REG 0x000a ++#define RTL8366S_GREEN_ETHERNET_CTRL_MASK 0x0018 ++#define RTL8366S_GREEN_ETHERNET_TX_BIT (1 << 3) ++#define RTL8366S_GREEN_ETHERNET_RX_BIT (1 << 4) ++ ++/* Switch Security Control registers */ ++#define RTL8366S_SSCR0 0x0002 ++#define RTL8366S_SSCR1 0x0003 ++#define RTL8366S_SSCR2 0x0004 ++#define RTL8366S_SSCR2_DROP_UNKNOWN_DA BIT(0) ++ ++#define RTL8366S_RESET_CTRL_REG 0x0100 ++#define RTL8366S_CHIP_CTRL_RESET_HW 1 ++#define RTL8366S_CHIP_CTRL_RESET_SW (1 << 1) ++ ++#define RTL8366S_CHIP_VERSION_CTRL_REG 0x0104 ++#define RTL8366S_CHIP_VERSION_MASK 0xf ++#define RTL8366S_CHIP_ID_REG 0x0105 ++#define RTL8366S_CHIP_ID_8366 0x8366 ++ ++/* PHY registers control */ ++#define RTL8366S_PHY_ACCESS_CTRL_REG 0x8028 ++#define RTL8366S_PHY_ACCESS_DATA_REG 0x8029 ++ ++#define RTL8366S_PHY_CTRL_READ 1 ++#define RTL8366S_PHY_CTRL_WRITE 0 ++ ++#define RTL8366S_PHY_REG_MASK 0x1f ++#define RTL8366S_PHY_PAGE_OFFSET 5 ++#define RTL8366S_PHY_PAGE_MASK (0x7 << 5) ++#define RTL8366S_PHY_NO_OFFSET 9 ++#define RTL8366S_PHY_NO_MASK (0x1f << 9) ++ ++/* Green Ethernet Feature for PHY ports */ ++#define RTL8366S_PHY_POWER_SAVING_CTRL_REG 12 ++#define RTL8366S_PHY_POWER_SAVING_MASK 0x1000 ++ ++/* LED control registers */ ++#define RTL8366S_LED_BLINKRATE_REG 0x0420 ++#define RTL8366S_LED_BLINKRATE_BIT 0 ++#define RTL8366S_LED_BLINKRATE_MASK 0x0007 ++ ++#define RTL8366S_LED_CTRL_REG 0x0421 ++#define RTL8366S_LED_0_1_CTRL_REG 0x0422 ++#define RTL8366S_LED_2_3_CTRL_REG 0x0423 ++ ++#define RTL8366S_MIB_COUNT 33 ++#define RTL8366S_GLOBAL_MIB_COUNT 1 ++#define RTL8366S_MIB_COUNTER_PORT_OFFSET 0x0040 ++#define RTL8366S_MIB_COUNTER_BASE 0x1000 ++#define RTL8366S_MIB_COUNTER_PORT_OFFSET2 0x0008 ++#define RTL8366S_MIB_COUNTER_BASE2 0x1180 ++#define RTL8366S_MIB_CTRL_REG 0x11F0 ++#define RTL8366S_MIB_CTRL_USER_MASK 0x01FF ++#define RTL8366S_MIB_CTRL_BUSY_MASK 0x0001 ++#define RTL8366S_MIB_CTRL_RESET_MASK 0x0002 ++ ++#define RTL8366S_MIB_CTRL_GLOBAL_RESET_MASK 0x0004 ++#define RTL8366S_MIB_CTRL_PORT_RESET_BIT 0x0003 ++#define RTL8366S_MIB_CTRL_PORT_RESET_MASK 0x01FC ++ ++ ++#define RTL8366S_PORT_VLAN_CTRL_BASE 0x0058 ++#define RTL8366S_PORT_VLAN_CTRL_REG(_p) \ ++ (RTL8366S_PORT_VLAN_CTRL_BASE + (_p) / 4) ++#define RTL8366S_PORT_VLAN_CTRL_MASK 0xf ++#define RTL8366S_PORT_VLAN_CTRL_SHIFT(_p) (4 * ((_p) % 4)) ++ ++ ++#define RTL8366S_VLAN_TABLE_READ_BASE 0x018B ++#define RTL8366S_VLAN_TABLE_WRITE_BASE 0x0185 ++ ++#define RTL8366S_VLAN_TB_CTRL_REG 0x010F ++ ++#define RTL8366S_TABLE_ACCESS_CTRL_REG 0x0180 ++#define RTL8366S_TABLE_VLAN_READ_CTRL 0x0E01 ++#define RTL8366S_TABLE_VLAN_WRITE_CTRL 0x0F01 ++ ++#define RTL8366S_VLAN_MC_BASE(_x) (0x0016 + (_x) * 2) ++ ++#define RTL8366S_VLAN_MEMBERINGRESS_REG 0x0379 ++ ++#define RTL8366S_PORT_LINK_STATUS_BASE 0x0060 ++#define RTL8366S_PORT_STATUS_SPEED_MASK 0x0003 ++#define RTL8366S_PORT_STATUS_DUPLEX_MASK 0x0004 ++#define RTL8366S_PORT_STATUS_LINK_MASK 0x0010 ++#define RTL8366S_PORT_STATUS_TXPAUSE_MASK 0x0020 ++#define RTL8366S_PORT_STATUS_RXPAUSE_MASK 0x0040 ++#define RTL8366S_PORT_STATUS_AN_MASK 0x0080 ++ ++ ++#define RTL8366S_PORT_NUM_CPU 5 ++#define RTL8366S_NUM_PORTS 6 ++#define RTL8366S_NUM_VLANS 16 ++#define RTL8366S_NUM_LEDGROUPS 4 ++#define RTL8366S_NUM_VIDS 4096 ++#define RTL8366S_PRIORITYMAX 7 ++#define RTL8366S_FIDMAX 7 ++ ++ ++#define RTL8366S_PORT_1 (1 << 0) /* In userspace port 0 */ ++#define RTL8366S_PORT_2 (1 << 1) /* In userspace port 1 */ ++#define RTL8366S_PORT_3 (1 << 2) /* In userspace port 2 */ ++#define RTL8366S_PORT_4 (1 << 3) /* In userspace port 3 */ ++ ++#define RTL8366S_PORT_UNKNOWN (1 << 4) /* No known connection */ ++#define RTL8366S_PORT_CPU (1 << 5) /* CPU port */ ++ ++#define RTL8366S_PORT_ALL (RTL8366S_PORT_1 | \ ++ RTL8366S_PORT_2 | \ ++ RTL8366S_PORT_3 | \ ++ RTL8366S_PORT_4 | \ ++ RTL8366S_PORT_UNKNOWN | \ ++ RTL8366S_PORT_CPU) ++ ++#define RTL8366S_PORT_ALL_BUT_CPU (RTL8366S_PORT_1 | \ ++ RTL8366S_PORT_2 | \ ++ RTL8366S_PORT_3 | \ ++ RTL8366S_PORT_4 | \ ++ RTL8366S_PORT_UNKNOWN) ++ ++#define RTL8366S_PORT_ALL_EXTERNAL (RTL8366S_PORT_1 | \ ++ RTL8366S_PORT_2 | \ ++ RTL8366S_PORT_3 | \ ++ RTL8366S_PORT_4) ++ ++#define RTL8366S_PORT_ALL_INTERNAL (RTL8366S_PORT_UNKNOWN | \ ++ RTL8366S_PORT_CPU) ++ ++#define RTL8366S_VLAN_VID_MASK 0xfff ++#define RTL8366S_VLAN_PRIORITY_SHIFT 12 ++#define RTL8366S_VLAN_PRIORITY_MASK 0x7 ++#define RTL8366S_VLAN_MEMBER_MASK 0x3f ++#define RTL8366S_VLAN_UNTAG_SHIFT 6 ++#define RTL8366S_VLAN_UNTAG_MASK 0x3f ++#define RTL8366S_VLAN_FID_SHIFT 12 ++#define RTL8366S_VLAN_FID_MASK 0x7 ++ ++#define RTL8366S_MIB_RXB_ID 0 /* IfInOctets */ ++#define RTL8366S_MIB_TXB_ID 20 /* IfOutOctets */ ++ ++static struct rtl8366_mib_counter rtl8366s_mib_counters[] = { ++ { 0, 0, 4, "IfInOctets" }, ++ { 0, 4, 4, "EtherStatsOctets" }, ++ { 0, 8, 2, "EtherStatsUnderSizePkts" }, ++ { 0, 10, 2, "EtherFragments" }, ++ { 0, 12, 2, "EtherStatsPkts64Octets" }, ++ { 0, 14, 2, "EtherStatsPkts65to127Octets" }, ++ { 0, 16, 2, "EtherStatsPkts128to255Octets" }, ++ { 0, 18, 2, "EtherStatsPkts256to511Octets" }, ++ { 0, 20, 2, "EtherStatsPkts512to1023Octets" }, ++ { 0, 22, 2, "EtherStatsPkts1024to1518Octets" }, ++ { 0, 24, 2, "EtherOversizeStats" }, ++ { 0, 26, 2, "EtherStatsJabbers" }, ++ { 0, 28, 2, "IfInUcastPkts" }, ++ { 0, 30, 2, "EtherStatsMulticastPkts" }, ++ { 0, 32, 2, "EtherStatsBroadcastPkts" }, ++ { 0, 34, 2, "EtherStatsDropEvents" }, ++ { 0, 36, 2, "Dot3StatsFCSErrors" }, ++ { 0, 38, 2, "Dot3StatsSymbolErrors" }, ++ { 0, 40, 2, "Dot3InPauseFrames" }, ++ { 0, 42, 2, "Dot3ControlInUnknownOpcodes" }, ++ { 0, 44, 4, "IfOutOctets" }, ++ { 0, 48, 2, "Dot3StatsSingleCollisionFrames" }, ++ { 0, 50, 2, "Dot3StatMultipleCollisionFrames" }, ++ { 0, 52, 2, "Dot3sDeferredTransmissions" }, ++ { 0, 54, 2, "Dot3StatsLateCollisions" }, ++ { 0, 56, 2, "EtherStatsCollisions" }, ++ { 0, 58, 2, "Dot3StatsExcessiveCollisions" }, ++ { 0, 60, 2, "Dot3OutPauseFrames" }, ++ { 0, 62, 2, "Dot1dBasePortDelayExceededDiscards" }, ++ ++ /* ++ * The following counters are accessible at a different ++ * base address. ++ */ ++ { 1, 0, 2, "Dot1dTpPortInDiscards" }, ++ { 1, 2, 2, "IfOutUcastPkts" }, ++ { 1, 4, 2, "IfOutMulticastPkts" }, ++ { 1, 6, 2, "IfOutBroadcastPkts" }, ++}; ++ ++#define REG_WR(_smi, _reg, _val) \ ++ do { \ ++ err = rtl8366_smi_write_reg(_smi, _reg, _val); \ ++ if (err) \ ++ return err; \ ++ } while (0) ++ ++#define REG_RMW(_smi, _reg, _mask, _val) \ ++ do { \ ++ err = rtl8366_smi_rmwr(_smi, _reg, _mask, _val); \ ++ if (err) \ ++ return err; \ ++ } while (0) ++ ++static int rtl8366s_reset_chip(struct rtl8366_smi *smi) ++{ ++ int timeout = 10; ++ u32 data; ++ ++ rtl8366_smi_write_reg_noack(smi, RTL8366S_RESET_CTRL_REG, ++ RTL8366S_CHIP_CTRL_RESET_HW); ++ do { ++ msleep(1); ++ if (rtl8366_smi_read_reg(smi, RTL8366S_RESET_CTRL_REG, &data)) ++ return -EIO; ++ ++ if (!(data & RTL8366S_CHIP_CTRL_RESET_HW)) ++ break; ++ } while (--timeout); ++ ++ if (!timeout) { ++ printk("Timeout waiting for the switch to reset\n"); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++static int rtl8366s_read_phy_reg(struct rtl8366_smi *smi, ++ u32 phy_no, u32 page, u32 addr, u32 *data) ++{ ++ u32 reg; ++ int ret; ++ ++ if (phy_no > RTL8366S_PHY_NO_MAX) ++ return -EINVAL; ++ ++ if (page > RTL8366S_PHY_PAGE_MAX) ++ return -EINVAL; ++ ++ if (addr > RTL8366S_PHY_ADDR_MAX) ++ return -EINVAL; ++ ++ ret = rtl8366_smi_write_reg(smi, RTL8366S_PHY_ACCESS_CTRL_REG, ++ RTL8366S_PHY_CTRL_READ); ++ if (ret) ++ return ret; ++ ++ reg = 0x8000 | (1 << (phy_no + RTL8366S_PHY_NO_OFFSET)) | ++ ((page << RTL8366S_PHY_PAGE_OFFSET) & RTL8366S_PHY_PAGE_MASK) | ++ (addr & RTL8366S_PHY_REG_MASK); ++ ++ ret = rtl8366_smi_write_reg(smi, reg, 0); ++ if (ret) ++ return ret; ++ ++ ret = rtl8366_smi_read_reg(smi, RTL8366S_PHY_ACCESS_DATA_REG, data); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static int rtl8366s_write_phy_reg(struct rtl8366_smi *smi, ++ u32 phy_no, u32 page, u32 addr, u32 data) ++{ ++ u32 reg; ++ int ret; ++ ++ if (phy_no > RTL8366S_PHY_NO_MAX) ++ return -EINVAL; ++ ++ if (page > RTL8366S_PHY_PAGE_MAX) ++ return -EINVAL; ++ ++ if (addr > RTL8366S_PHY_ADDR_MAX) ++ return -EINVAL; ++ ++ ret = rtl8366_smi_write_reg(smi, RTL8366S_PHY_ACCESS_CTRL_REG, ++ RTL8366S_PHY_CTRL_WRITE); ++ if (ret) ++ return ret; ++ ++ reg = 0x8000 | (1 << (phy_no + RTL8366S_PHY_NO_OFFSET)) | ++ ((page << RTL8366S_PHY_PAGE_OFFSET) & RTL8366S_PHY_PAGE_MASK) | ++ (addr & RTL8366S_PHY_REG_MASK); ++ ++ ret = rtl8366_smi_write_reg(smi, reg, data); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static int rtl8366s_set_green_port(struct rtl8366_smi *smi, int port, int enable) ++{ ++ int err; ++ u32 phyData; ++ ++ if (port >= RTL8366S_NUM_PORTS) ++ return -EINVAL; ++ ++ err = rtl8366s_read_phy_reg(smi, port, 0, RTL8366S_PHY_POWER_SAVING_CTRL_REG, &phyData); ++ if (err) ++ return err; ++ ++ if (enable) ++ phyData |= RTL8366S_PHY_POWER_SAVING_MASK; ++ else ++ phyData &= ~RTL8366S_PHY_POWER_SAVING_MASK; ++ ++ err = rtl8366s_write_phy_reg(smi, port, 0, RTL8366S_PHY_POWER_SAVING_CTRL_REG, phyData); ++ if (err) ++ return err; ++ ++ return 0; ++} ++ ++static int rtl8366s_set_green(struct rtl8366_smi *smi, int enable) ++{ ++ int err; ++ unsigned i; ++ u32 data = 0; ++ ++ if (!enable) { ++ for (i = 0; i <= RTL8366S_PHY_NO_MAX; i++) { ++ rtl8366s_set_green_port(smi, i, 0); ++ } ++ } ++ ++ if (enable) ++ data = (RTL8366S_GREEN_ETHERNET_TX_BIT | RTL8366S_GREEN_ETHERNET_RX_BIT); ++ ++ REG_RMW(smi, RTL8366S_GREEN_ETHERNET_CTRL_REG, RTL8366S_GREEN_ETHERNET_CTRL_MASK, data); ++ ++ return 0; ++} ++ ++static int rtl8366s_setup(struct rtl8366_smi *smi) ++{ ++ struct rtl8366_platform_data *pdata; ++ int err; ++ unsigned i; ++#ifdef CONFIG_OF ++ struct device_node *np; ++ unsigned num_initvals; ++ const __be32 *paddr; ++#endif ++ ++ pdata = smi->parent->platform_data; ++ if (pdata && pdata->num_initvals && pdata->initvals) { ++ dev_info(smi->parent, "applying initvals\n"); ++ for (i = 0; i < pdata->num_initvals; i++) ++ REG_WR(smi, pdata->initvals[i].reg, ++ pdata->initvals[i].val); ++ } ++ ++#ifdef CONFIG_OF ++ np = smi->parent->of_node; ++ ++ paddr = of_get_property(np, "realtek,initvals", &num_initvals); ++ if (paddr) { ++ dev_info(smi->parent, "applying initvals from DTS\n"); ++ ++ if (num_initvals < (2 * sizeof(*paddr))) ++ return -EINVAL; ++ ++ num_initvals /= sizeof(*paddr); ++ ++ for (i = 0; i < num_initvals - 1; i += 2) { ++ u32 reg = be32_to_cpup(paddr + i); ++ u32 val = be32_to_cpup(paddr + i + 1); ++ ++ REG_WR(smi, reg, val); ++ } ++ } ++ ++ if (of_property_read_bool(np, "realtek,green-ethernet-features")) { ++ dev_info(smi->parent, "activating Green Ethernet features\n"); ++ ++ err = rtl8366s_set_green(smi, 1); ++ if (err) ++ return err; ++ ++ for (i = 0; i <= RTL8366S_PHY_NO_MAX; i++) { ++ err = rtl8366s_set_green_port(smi, i, 1); ++ if (err) ++ return err; ++ } ++ } ++#endif ++ ++ /* set maximum packet length to 1536 bytes */ ++ REG_RMW(smi, RTL8366S_SGCR, RTL8366S_SGCR_MAX_LENGTH_MASK, ++ RTL8366S_SGCR_MAX_LENGTH_1536); ++ ++ /* enable learning for all ports */ ++ REG_WR(smi, RTL8366S_SSCR0, 0); ++ ++ /* enable auto ageing for all ports */ ++ REG_WR(smi, RTL8366S_SSCR1, 0); ++ ++ /* ++ * discard VLAN tagged packets if the port is not a member of ++ * the VLAN with which the packets is associated. ++ */ ++ REG_WR(smi, RTL8366S_VLAN_MEMBERINGRESS_REG, RTL8366S_PORT_ALL); ++ ++ /* don't drop packets whose DA has not been learned */ ++ REG_RMW(smi, RTL8366S_SSCR2, RTL8366S_SSCR2_DROP_UNKNOWN_DA, 0); ++ ++ return 0; ++} ++ ++static int rtl8366_get_mib_counter(struct rtl8366_smi *smi, int counter, ++ int port, unsigned long long *val) ++{ ++ int i; ++ int err; ++ u32 addr, data; ++ u64 mibvalue; ++ ++ if (port > RTL8366S_NUM_PORTS || counter >= RTL8366S_MIB_COUNT) ++ return -EINVAL; ++ ++ switch (rtl8366s_mib_counters[counter].base) { ++ case 0: ++ addr = RTL8366S_MIB_COUNTER_BASE + ++ RTL8366S_MIB_COUNTER_PORT_OFFSET * port; ++ break; ++ ++ case 1: ++ addr = RTL8366S_MIB_COUNTER_BASE2 + ++ RTL8366S_MIB_COUNTER_PORT_OFFSET2 * port; ++ break; ++ ++ default: ++ return -EINVAL; ++ } ++ ++ addr += rtl8366s_mib_counters[counter].offset; ++ ++ /* ++ * Writing access counter address first ++ * then ASIC will prepare 64bits counter wait for being retrived ++ */ ++ data = 0; /* writing data will be discard by ASIC */ ++ err = rtl8366_smi_write_reg(smi, addr, data); ++ if (err) ++ return err; ++ ++ /* read MIB control register */ ++ err = rtl8366_smi_read_reg(smi, RTL8366S_MIB_CTRL_REG, &data); ++ if (err) ++ return err; ++ ++ if (data & RTL8366S_MIB_CTRL_BUSY_MASK) ++ return -EBUSY; ++ ++ if (data & RTL8366S_MIB_CTRL_RESET_MASK) ++ return -EIO; ++ ++ mibvalue = 0; ++ for (i = rtl8366s_mib_counters[counter].length; i > 0; i--) { ++ err = rtl8366_smi_read_reg(smi, addr + (i - 1), &data); ++ if (err) ++ return err; ++ ++ mibvalue = (mibvalue << 16) | (data & 0xFFFF); ++ } ++ ++ *val = mibvalue; ++ return 0; ++} ++ ++static int rtl8366s_get_vlan_4k(struct rtl8366_smi *smi, u32 vid, ++ struct rtl8366_vlan_4k *vlan4k) ++{ ++ u32 data[2]; ++ int err; ++ int i; ++ ++ memset(vlan4k, '\0', sizeof(struct rtl8366_vlan_4k)); ++ ++ if (vid >= RTL8366S_NUM_VIDS) ++ return -EINVAL; ++ ++ /* write VID */ ++ err = rtl8366_smi_write_reg(smi, RTL8366S_VLAN_TABLE_WRITE_BASE, ++ vid & RTL8366S_VLAN_VID_MASK); ++ if (err) ++ return err; ++ ++ /* write table access control word */ ++ err = rtl8366_smi_write_reg(smi, RTL8366S_TABLE_ACCESS_CTRL_REG, ++ RTL8366S_TABLE_VLAN_READ_CTRL); ++ if (err) ++ return err; ++ ++ for (i = 0; i < 2; i++) { ++ err = rtl8366_smi_read_reg(smi, ++ RTL8366S_VLAN_TABLE_READ_BASE + i, ++ &data[i]); ++ if (err) ++ return err; ++ } ++ ++ vlan4k->vid = vid; ++ vlan4k->untag = (data[1] >> RTL8366S_VLAN_UNTAG_SHIFT) & ++ RTL8366S_VLAN_UNTAG_MASK; ++ vlan4k->member = data[1] & RTL8366S_VLAN_MEMBER_MASK; ++ vlan4k->fid = (data[1] >> RTL8366S_VLAN_FID_SHIFT) & ++ RTL8366S_VLAN_FID_MASK; ++ ++ return 0; ++} ++ ++static int rtl8366s_set_vlan_4k(struct rtl8366_smi *smi, ++ const struct rtl8366_vlan_4k *vlan4k) ++{ ++ u32 data[2]; ++ int err; ++ int i; ++ ++ if (vlan4k->vid >= RTL8366S_NUM_VIDS || ++ vlan4k->member > RTL8366S_VLAN_MEMBER_MASK || ++ vlan4k->untag > RTL8366S_VLAN_UNTAG_MASK || ++ vlan4k->fid > RTL8366S_FIDMAX) ++ return -EINVAL; ++ ++ data[0] = vlan4k->vid & RTL8366S_VLAN_VID_MASK; ++ data[1] = (vlan4k->member & RTL8366S_VLAN_MEMBER_MASK) | ++ ((vlan4k->untag & RTL8366S_VLAN_UNTAG_MASK) << ++ RTL8366S_VLAN_UNTAG_SHIFT) | ++ ((vlan4k->fid & RTL8366S_VLAN_FID_MASK) << ++ RTL8366S_VLAN_FID_SHIFT); ++ ++ for (i = 0; i < 2; i++) { ++ err = rtl8366_smi_write_reg(smi, ++ RTL8366S_VLAN_TABLE_WRITE_BASE + i, ++ data[i]); ++ if (err) ++ return err; ++ } ++ ++ /* write table access control word */ ++ err = rtl8366_smi_write_reg(smi, RTL8366S_TABLE_ACCESS_CTRL_REG, ++ RTL8366S_TABLE_VLAN_WRITE_CTRL); ++ ++ return err; ++} ++ ++static int rtl8366s_get_vlan_mc(struct rtl8366_smi *smi, u32 index, ++ struct rtl8366_vlan_mc *vlanmc) ++{ ++ u32 data[2]; ++ int err; ++ int i; ++ ++ memset(vlanmc, '\0', sizeof(struct rtl8366_vlan_mc)); ++ ++ if (index >= RTL8366S_NUM_VLANS) ++ return -EINVAL; ++ ++ for (i = 0; i < 2; i++) { ++ err = rtl8366_smi_read_reg(smi, ++ RTL8366S_VLAN_MC_BASE(index) + i, ++ &data[i]); ++ if (err) ++ return err; ++ } ++ ++ vlanmc->vid = data[0] & RTL8366S_VLAN_VID_MASK; ++ vlanmc->priority = (data[0] >> RTL8366S_VLAN_PRIORITY_SHIFT) & ++ RTL8366S_VLAN_PRIORITY_MASK; ++ vlanmc->untag = (data[1] >> RTL8366S_VLAN_UNTAG_SHIFT) & ++ RTL8366S_VLAN_UNTAG_MASK; ++ vlanmc->member = data[1] & RTL8366S_VLAN_MEMBER_MASK; ++ vlanmc->fid = (data[1] >> RTL8366S_VLAN_FID_SHIFT) & ++ RTL8366S_VLAN_FID_MASK; ++ ++ return 0; ++} ++ ++static int rtl8366s_set_vlan_mc(struct rtl8366_smi *smi, u32 index, ++ const struct rtl8366_vlan_mc *vlanmc) ++{ ++ u32 data[2]; ++ int err; ++ int i; ++ ++ if (index >= RTL8366S_NUM_VLANS || ++ vlanmc->vid >= RTL8366S_NUM_VIDS || ++ vlanmc->priority > RTL8366S_PRIORITYMAX || ++ vlanmc->member > RTL8366S_VLAN_MEMBER_MASK || ++ vlanmc->untag > RTL8366S_VLAN_UNTAG_MASK || ++ vlanmc->fid > RTL8366S_FIDMAX) ++ return -EINVAL; ++ ++ data[0] = (vlanmc->vid & RTL8366S_VLAN_VID_MASK) | ++ ((vlanmc->priority & RTL8366S_VLAN_PRIORITY_MASK) << ++ RTL8366S_VLAN_PRIORITY_SHIFT); ++ data[1] = (vlanmc->member & RTL8366S_VLAN_MEMBER_MASK) | ++ ((vlanmc->untag & RTL8366S_VLAN_UNTAG_MASK) << ++ RTL8366S_VLAN_UNTAG_SHIFT) | ++ ((vlanmc->fid & RTL8366S_VLAN_FID_MASK) << ++ RTL8366S_VLAN_FID_SHIFT); ++ ++ for (i = 0; i < 2; i++) { ++ err = rtl8366_smi_write_reg(smi, ++ RTL8366S_VLAN_MC_BASE(index) + i, ++ data[i]); ++ if (err) ++ return err; ++ } ++ ++ return 0; ++} ++ ++static int rtl8366s_get_mc_index(struct rtl8366_smi *smi, int port, int *val) ++{ ++ u32 data; ++ int err; ++ ++ if (port >= RTL8366S_NUM_PORTS) ++ return -EINVAL; ++ ++ err = rtl8366_smi_read_reg(smi, RTL8366S_PORT_VLAN_CTRL_REG(port), ++ &data); ++ if (err) ++ return err; ++ ++ *val = (data >> RTL8366S_PORT_VLAN_CTRL_SHIFT(port)) & ++ RTL8366S_PORT_VLAN_CTRL_MASK; ++ ++ return 0; ++} ++ ++static int rtl8366s_set_mc_index(struct rtl8366_smi *smi, int port, int index) ++{ ++ if (port >= RTL8366S_NUM_PORTS || index >= RTL8366S_NUM_VLANS) ++ return -EINVAL; ++ ++ return rtl8366_smi_rmwr(smi, RTL8366S_PORT_VLAN_CTRL_REG(port), ++ RTL8366S_PORT_VLAN_CTRL_MASK << ++ RTL8366S_PORT_VLAN_CTRL_SHIFT(port), ++ (index & RTL8366S_PORT_VLAN_CTRL_MASK) << ++ RTL8366S_PORT_VLAN_CTRL_SHIFT(port)); ++} ++ ++static int rtl8366s_enable_vlan(struct rtl8366_smi *smi, int enable) ++{ ++ return rtl8366_smi_rmwr(smi, RTL8366S_SGCR, RTL8366S_SGCR_EN_VLAN, ++ (enable) ? RTL8366S_SGCR_EN_VLAN : 0); ++} ++ ++static int rtl8366s_enable_vlan4k(struct rtl8366_smi *smi, int enable) ++{ ++ return rtl8366_smi_rmwr(smi, RTL8366S_VLAN_TB_CTRL_REG, ++ 1, (enable) ? 1 : 0); ++} ++ ++static int rtl8366s_is_vlan_valid(struct rtl8366_smi *smi, unsigned vlan) ++{ ++ unsigned max = RTL8366S_NUM_VLANS; ++ ++ if (smi->vlan4k_enabled) ++ max = RTL8366S_NUM_VIDS - 1; ++ ++ if (vlan == 0 || vlan >= max) ++ return 0; ++ ++ return 1; ++} ++ ++static int rtl8366s_enable_port(struct rtl8366_smi *smi, int port, int enable) ++{ ++ return rtl8366_smi_rmwr(smi, RTL8366S_PECR, (1 << port), ++ (enable) ? 0 : (1 << port)); ++} ++ ++static int rtl8366s_sw_reset_mibs(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ ++ return rtl8366_smi_rmwr(smi, RTL8366S_MIB_CTRL_REG, 0, (1 << 2)); ++} ++ ++static int rtl8366s_sw_get_blinkrate(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ u32 data; ++ ++ rtl8366_smi_read_reg(smi, RTL8366S_LED_BLINKRATE_REG, &data); ++ ++ val->value.i = (data & (RTL8366S_LED_BLINKRATE_MASK)); ++ ++ return 0; ++} ++ ++static int rtl8366s_sw_set_blinkrate(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ ++ if (val->value.i >= 6) ++ return -EINVAL; ++ ++ return rtl8366_smi_rmwr(smi, RTL8366S_LED_BLINKRATE_REG, ++ RTL8366S_LED_BLINKRATE_MASK, ++ val->value.i); ++} ++ ++static int rtl8366s_sw_get_max_length(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ u32 data; ++ ++ rtl8366_smi_read_reg(smi, RTL8366S_SGCR, &data); ++ ++ val->value.i = ((data & (RTL8366S_SGCR_MAX_LENGTH_MASK)) >> 4); ++ ++ return 0; ++} ++ ++static int rtl8366s_sw_set_max_length(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ char length_code; ++ ++ switch (val->value.i) { ++ case 0: ++ length_code = RTL8366S_SGCR_MAX_LENGTH_1522; ++ break; ++ case 1: ++ length_code = RTL8366S_SGCR_MAX_LENGTH_1536; ++ break; ++ case 2: ++ length_code = RTL8366S_SGCR_MAX_LENGTH_1552; ++ break; ++ case 3: ++ length_code = RTL8366S_SGCR_MAX_LENGTH_16000; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return rtl8366_smi_rmwr(smi, RTL8366S_SGCR, ++ RTL8366S_SGCR_MAX_LENGTH_MASK, ++ length_code); ++} ++ ++static int rtl8366s_sw_get_learning_enable(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ u32 data; ++ ++ rtl8366_smi_read_reg(smi,RTL8366S_SSCR0, &data); ++ val->value.i = !data; ++ ++ return 0; ++} ++ ++ ++static int rtl8366s_sw_set_learning_enable(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ u32 portmask = 0; ++ int err = 0; ++ ++ if (!val->value.i) ++ portmask = RTL8366S_PORT_ALL; ++ ++ /* set learning for all ports */ ++ REG_WR(smi, RTL8366S_SSCR0, portmask); ++ ++ /* set auto ageing for all ports */ ++ REG_WR(smi, RTL8366S_SSCR1, portmask); ++ ++ return 0; ++} ++ ++static int rtl8366s_sw_get_green(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ u32 data; ++ int err; ++ ++ err = rtl8366_smi_read_reg(smi, RTL8366S_GREEN_ETHERNET_CTRL_REG, &data); ++ if (err) ++ return err; ++ ++ val->value.i = ((data & (RTL8366S_GREEN_ETHERNET_TX_BIT | RTL8366S_GREEN_ETHERNET_RX_BIT)) != 0) ? 1 : 0; ++ ++ return 0; ++} ++ ++static int rtl8366s_sw_set_green(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ ++ return rtl8366s_set_green(smi, val->value.i); ++} ++ ++static int rtl8366s_sw_get_port_link(struct switch_dev *dev, ++ int port, ++ struct switch_port_link *link) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ u32 data = 0; ++ u32 speed; ++ ++ if (port >= RTL8366S_NUM_PORTS) ++ return -EINVAL; ++ ++ rtl8366_smi_read_reg(smi, RTL8366S_PORT_LINK_STATUS_BASE + (port / 2), ++ &data); ++ ++ if (port % 2) ++ data = data >> 8; ++ ++ link->link = !!(data & RTL8366S_PORT_STATUS_LINK_MASK); ++ if (!link->link) ++ return 0; ++ ++ link->duplex = !!(data & RTL8366S_PORT_STATUS_DUPLEX_MASK); ++ link->rx_flow = !!(data & RTL8366S_PORT_STATUS_RXPAUSE_MASK); ++ link->tx_flow = !!(data & RTL8366S_PORT_STATUS_TXPAUSE_MASK); ++ link->aneg = !!(data & RTL8366S_PORT_STATUS_AN_MASK); ++ ++ speed = (data & RTL8366S_PORT_STATUS_SPEED_MASK); ++ switch (speed) { ++ case 0: ++ link->speed = SWITCH_PORT_SPEED_10; ++ break; ++ case 1: ++ link->speed = SWITCH_PORT_SPEED_100; ++ break; ++ case 2: ++ link->speed = SWITCH_PORT_SPEED_1000; ++ break; ++ default: ++ link->speed = SWITCH_PORT_SPEED_UNKNOWN; ++ break; ++ } ++ ++ return 0; ++} ++ ++static int rtl8366s_sw_set_port_led(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ u32 data; ++ u32 mask; ++ u32 reg; ++ ++ if (val->port_vlan >= RTL8366S_NUM_PORTS || ++ (1 << val->port_vlan) == RTL8366S_PORT_UNKNOWN) ++ return -EINVAL; ++ ++ if (val->port_vlan == RTL8366S_PORT_NUM_CPU) { ++ reg = RTL8366S_LED_BLINKRATE_REG; ++ mask = 0xF << 4; ++ data = val->value.i << 4; ++ } else { ++ reg = RTL8366S_LED_CTRL_REG; ++ mask = 0xF << (val->port_vlan * 4), ++ data = val->value.i << (val->port_vlan * 4); ++ } ++ ++ return rtl8366_smi_rmwr(smi, reg, mask, data); ++} ++ ++static int rtl8366s_sw_get_port_led(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ u32 data = 0; ++ ++ if (val->port_vlan >= RTL8366S_NUM_LEDGROUPS) ++ return -EINVAL; ++ ++ rtl8366_smi_read_reg(smi, RTL8366S_LED_CTRL_REG, &data); ++ val->value.i = (data >> (val->port_vlan * 4)) & 0x000F; ++ ++ return 0; ++} ++ ++static int rtl8366s_sw_get_green_port(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ int err; ++ u32 phyData; ++ ++ if (val->port_vlan >= RTL8366S_NUM_PORTS) ++ return -EINVAL; ++ ++ err = rtl8366s_read_phy_reg(smi, val->port_vlan, 0, RTL8366S_PHY_POWER_SAVING_CTRL_REG, &phyData); ++ if (err) ++ return err; ++ ++ val->value.i = ((phyData & RTL8366S_PHY_POWER_SAVING_MASK) != 0) ? 1 : 0; ++ ++ return 0; ++} ++ ++static int rtl8366s_sw_set_green_port(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ return rtl8366s_set_green_port(smi, val->port_vlan, val->value.i); ++} ++ ++static int rtl8366s_sw_reset_port_mibs(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ ++ if (val->port_vlan >= RTL8366S_NUM_PORTS) ++ return -EINVAL; ++ ++ ++ return rtl8366_smi_rmwr(smi, RTL8366S_MIB_CTRL_REG, ++ 0, (1 << (val->port_vlan + 3))); ++} ++ ++static int rtl8366s_sw_get_port_stats(struct switch_dev *dev, int port, ++ struct switch_port_stats *stats) ++{ ++ return (rtl8366_sw_get_port_stats(dev, port, stats, ++ RTL8366S_MIB_TXB_ID, RTL8366S_MIB_RXB_ID)); ++} ++ ++static struct switch_attr rtl8366s_globals[] = { ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "enable_learning", ++ .description = "Enable learning, enable aging", ++ .set = rtl8366s_sw_set_learning_enable, ++ .get = rtl8366s_sw_get_learning_enable, ++ .max = 1, ++ }, { ++ .type = SWITCH_TYPE_INT, ++ .name = "enable_vlan", ++ .description = "Enable VLAN mode", ++ .set = rtl8366_sw_set_vlan_enable, ++ .get = rtl8366_sw_get_vlan_enable, ++ .max = 1, ++ .ofs = 1 ++ }, { ++ .type = SWITCH_TYPE_INT, ++ .name = "enable_vlan4k", ++ .description = "Enable VLAN 4K mode", ++ .set = rtl8366_sw_set_vlan_enable, ++ .get = rtl8366_sw_get_vlan_enable, ++ .max = 1, ++ .ofs = 2 ++ }, { ++ .type = SWITCH_TYPE_NOVAL, ++ .name = "reset_mibs", ++ .description = "Reset all MIB counters", ++ .set = rtl8366s_sw_reset_mibs, ++ }, { ++ .type = SWITCH_TYPE_INT, ++ .name = "blinkrate", ++ .description = "Get/Set LED blinking rate (0 = 43ms, 1 = 84ms," ++ " 2 = 120ms, 3 = 170ms, 4 = 340ms, 5 = 670ms)", ++ .set = rtl8366s_sw_set_blinkrate, ++ .get = rtl8366s_sw_get_blinkrate, ++ .max = 5 ++ }, { ++ .type = SWITCH_TYPE_INT, ++ .name = "max_length", ++ .description = "Get/Set the maximum length of valid packets" ++ " (0 = 1522, 1 = 1536, 2 = 1552, 3 = 16000 (9216?))", ++ .set = rtl8366s_sw_set_max_length, ++ .get = rtl8366s_sw_get_max_length, ++ .max = 3, ++ }, { ++ .type = SWITCH_TYPE_INT, ++ .name = "green_mode", ++ .description = "Get/Set the router green feature", ++ .set = rtl8366s_sw_set_green, ++ .get = rtl8366s_sw_get_green, ++ .max = 1, ++ }, ++}; ++ ++static struct switch_attr rtl8366s_port[] = { ++ { ++ .type = SWITCH_TYPE_NOVAL, ++ .name = "reset_mib", ++ .description = "Reset single port MIB counters", ++ .set = rtl8366s_sw_reset_port_mibs, ++ }, { ++ .type = SWITCH_TYPE_STRING, ++ .name = "mib", ++ .description = "Get MIB counters for port", ++ .max = 33, ++ .set = NULL, ++ .get = rtl8366_sw_get_port_mib, ++ }, { ++ .type = SWITCH_TYPE_INT, ++ .name = "led", ++ .description = "Get/Set port group (0 - 3) led mode (0 - 15)", ++ .max = 15, ++ .set = rtl8366s_sw_set_port_led, ++ .get = rtl8366s_sw_get_port_led, ++ }, { ++ .type = SWITCH_TYPE_INT, ++ .name = "green_port", ++ .description = "Get/Set port green feature (0 - 1)", ++ .max = 1, ++ .set = rtl8366s_sw_set_green_port, ++ .get = rtl8366s_sw_get_green_port, ++ }, ++}; ++ ++static struct switch_attr rtl8366s_vlan[] = { ++ { ++ .type = SWITCH_TYPE_STRING, ++ .name = "info", ++ .description = "Get vlan information", ++ .max = 1, ++ .set = NULL, ++ .get = rtl8366_sw_get_vlan_info, ++ }, { ++ .type = SWITCH_TYPE_INT, ++ .name = "fid", ++ .description = "Get/Set vlan FID", ++ .max = RTL8366S_FIDMAX, ++ .set = rtl8366_sw_set_vlan_fid, ++ .get = rtl8366_sw_get_vlan_fid, ++ }, ++}; ++ ++static const struct switch_dev_ops rtl8366_ops = { ++ .attr_global = { ++ .attr = rtl8366s_globals, ++ .n_attr = ARRAY_SIZE(rtl8366s_globals), ++ }, ++ .attr_port = { ++ .attr = rtl8366s_port, ++ .n_attr = ARRAY_SIZE(rtl8366s_port), ++ }, ++ .attr_vlan = { ++ .attr = rtl8366s_vlan, ++ .n_attr = ARRAY_SIZE(rtl8366s_vlan), ++ }, ++ ++ .get_vlan_ports = rtl8366_sw_get_vlan_ports, ++ .set_vlan_ports = rtl8366_sw_set_vlan_ports, ++ .get_port_pvid = rtl8366_sw_get_port_pvid, ++ .set_port_pvid = rtl8366_sw_set_port_pvid, ++ .reset_switch = rtl8366_sw_reset_switch, ++ .get_port_link = rtl8366s_sw_get_port_link, ++ .get_port_stats = rtl8366s_sw_get_port_stats, ++}; ++ ++static int rtl8366s_switch_init(struct rtl8366_smi *smi) ++{ ++ struct switch_dev *dev = &smi->sw_dev; ++ int err; ++ ++ dev->name = "RTL8366S"; ++ dev->cpu_port = RTL8366S_PORT_NUM_CPU; ++ dev->ports = RTL8366S_NUM_PORTS; ++ dev->vlans = RTL8366S_NUM_VIDS; ++ dev->ops = &rtl8366_ops; ++ dev->alias = dev_name(smi->parent); ++ ++ err = register_switch(dev, NULL); ++ if (err) ++ dev_err(smi->parent, "switch registration failed\n"); ++ ++ return err; ++} ++ ++static void rtl8366s_switch_cleanup(struct rtl8366_smi *smi) ++{ ++ unregister_switch(&smi->sw_dev); ++} ++ ++static int rtl8366s_mii_read(struct mii_bus *bus, int addr, int reg) ++{ ++ struct rtl8366_smi *smi = bus->priv; ++ u32 val = 0; ++ int err; ++ ++ err = rtl8366s_read_phy_reg(smi, addr, 0, reg, &val); ++ if (err) ++ return 0xffff; ++ ++ return val; ++} ++ ++static int rtl8366s_mii_write(struct mii_bus *bus, int addr, int reg, u16 val) ++{ ++ struct rtl8366_smi *smi = bus->priv; ++ u32 t; ++ int err; ++ ++ err = rtl8366s_write_phy_reg(smi, addr, 0, reg, val); ++ /* flush write */ ++ (void) rtl8366s_read_phy_reg(smi, addr, 0, reg, &t); ++ ++ return err; ++} ++ ++static int rtl8366s_detect(struct rtl8366_smi *smi) ++{ ++ u32 chip_id = 0; ++ u32 chip_ver = 0; ++ int ret; ++ ++ ret = rtl8366_smi_read_reg(smi, RTL8366S_CHIP_ID_REG, &chip_id); ++ if (ret) { ++ dev_err(smi->parent, "unable to read chip id\n"); ++ return ret; ++ } ++ ++ switch (chip_id) { ++ case RTL8366S_CHIP_ID_8366: ++ break; ++ default: ++ dev_err(smi->parent, "unknown chip id (%04x)\n", chip_id); ++ return -ENODEV; ++ } ++ ++ ret = rtl8366_smi_read_reg(smi, RTL8366S_CHIP_VERSION_CTRL_REG, ++ &chip_ver); ++ if (ret) { ++ dev_err(smi->parent, "unable to read chip version\n"); ++ return ret; ++ } ++ ++ dev_info(smi->parent, "RTL%04x ver. %u chip found\n", ++ chip_id, chip_ver & RTL8366S_CHIP_VERSION_MASK); ++ ++ return 0; ++} ++ ++static struct rtl8366_smi_ops rtl8366s_smi_ops = { ++ .detect = rtl8366s_detect, ++ .reset_chip = rtl8366s_reset_chip, ++ .setup = rtl8366s_setup, ++ ++ .mii_read = rtl8366s_mii_read, ++ .mii_write = rtl8366s_mii_write, ++ ++ .get_vlan_mc = rtl8366s_get_vlan_mc, ++ .set_vlan_mc = rtl8366s_set_vlan_mc, ++ .get_vlan_4k = rtl8366s_get_vlan_4k, ++ .set_vlan_4k = rtl8366s_set_vlan_4k, ++ .get_mc_index = rtl8366s_get_mc_index, ++ .set_mc_index = rtl8366s_set_mc_index, ++ .get_mib_counter = rtl8366_get_mib_counter, ++ .is_vlan_valid = rtl8366s_is_vlan_valid, ++ .enable_vlan = rtl8366s_enable_vlan, ++ .enable_vlan4k = rtl8366s_enable_vlan4k, ++ .enable_port = rtl8366s_enable_port, ++}; ++ ++static int rtl8366s_probe(struct platform_device *pdev) ++{ ++ static int rtl8366_smi_version_printed; ++ struct rtl8366_smi *smi; ++ int err; ++ ++ if (!rtl8366_smi_version_printed++) ++ printk(KERN_NOTICE RTL8366S_DRIVER_DESC ++ " version " RTL8366S_DRIVER_VER"\n"); ++ ++ smi = rtl8366_smi_probe(pdev); ++ if (IS_ERR(smi)) ++ return PTR_ERR(smi); ++ ++ smi->clk_delay = 10; ++ smi->cmd_read = 0xa9; ++ smi->cmd_write = 0xa8; ++ smi->ops = &rtl8366s_smi_ops; ++ smi->cpu_port = RTL8366S_PORT_NUM_CPU; ++ smi->num_ports = RTL8366S_NUM_PORTS; ++ smi->num_vlan_mc = RTL8366S_NUM_VLANS; ++ smi->mib_counters = rtl8366s_mib_counters; ++ smi->num_mib_counters = ARRAY_SIZE(rtl8366s_mib_counters); ++ ++ err = rtl8366_smi_init(smi); ++ if (err) ++ goto err_free_smi; ++ ++ platform_set_drvdata(pdev, smi); ++ ++ err = rtl8366s_switch_init(smi); ++ if (err) ++ goto err_clear_drvdata; ++ ++ return 0; ++ ++ err_clear_drvdata: ++ platform_set_drvdata(pdev, NULL); ++ rtl8366_smi_cleanup(smi); ++ err_free_smi: ++ kfree(smi); ++ return err; ++} ++ ++static void rtl8366s_remove(struct platform_device *pdev) ++{ ++ struct rtl8366_smi *smi = platform_get_drvdata(pdev); ++ ++ if (smi) { ++ rtl8366s_switch_cleanup(smi); ++ platform_set_drvdata(pdev, NULL); ++ rtl8366_smi_cleanup(smi); ++ kfree(smi); ++ } ++} ++ ++#ifdef CONFIG_OF ++static const struct of_device_id rtl8366s_match[] = { ++ { .compatible = "realtek,rtl8366s" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, rtl8366s_match); ++#endif ++ ++static struct platform_driver rtl8366s_driver = { ++ .driver = { ++ .name = RTL8366S_DRIVER_NAME, ++#ifdef CONFIG_OF ++ .of_match_table = of_match_ptr(rtl8366s_match), ++#endif ++ }, ++ .probe = rtl8366s_probe, ++ .remove_new = rtl8366s_remove, ++}; ++ ++static int __init rtl8366s_module_init(void) ++{ ++ return platform_driver_register(&rtl8366s_driver); ++} ++module_init(rtl8366s_module_init); ++ ++static void __exit rtl8366s_module_exit(void) ++{ ++ platform_driver_unregister(&rtl8366s_driver); ++} ++module_exit(rtl8366s_module_exit); ++ ++MODULE_DESCRIPTION(RTL8366S_DRIVER_DESC); ++MODULE_VERSION(RTL8366S_DRIVER_VER); ++MODULE_AUTHOR("Gabor Juhos "); ++MODULE_AUTHOR("Antti Seppälä "); ++MODULE_LICENSE("GPL v2"); ++MODULE_ALIAS("platform:" RTL8366S_DRIVER_NAME); +diff --git a/drivers/net/phy/rtl8367.c b/drivers/net/phy/rtl8367.c +new file mode 100644 +index 000000000000..1b996019a614 +--- /dev/null ++++ b/drivers/net/phy/rtl8367.c +@@ -0,0 +1,1859 @@ ++/* ++ * Platform driver for the Realtek RTL8367R/M ethernet switches ++ * ++ * Copyright (C) 2011 Gabor Juhos ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "rtl8366_smi.h" ++ ++#define RTL8367_RESET_DELAY 1000 /* msecs*/ ++ ++#define RTL8367_PHY_ADDR_MAX 8 ++#define RTL8367_PHY_REG_MAX 31 ++ ++#define RTL8367_VID_MASK 0xffff ++#define RTL8367_FID_MASK 0xfff ++#define RTL8367_UNTAG_MASK 0xffff ++#define RTL8367_MEMBER_MASK 0xffff ++ ++#define RTL8367_PORT_CFG_REG(_p) (0x000e + 0x20 * (_p)) ++#define RTL8367_PORT_CFG_EGRESS_MODE_SHIFT 4 ++#define RTL8367_PORT_CFG_EGRESS_MODE_MASK 0x3 ++#define RTL8367_PORT_CFG_EGRESS_MODE_ORIGINAL 0 ++#define RTL8367_PORT_CFG_EGRESS_MODE_KEEP 1 ++#define RTL8367_PORT_CFG_EGRESS_MODE_PRI 2 ++#define RTL8367_PORT_CFG_EGRESS_MODE_REAL 3 ++ ++#define RTL8367_BYPASS_LINE_RATE_REG 0x03f7 ++ ++#define RTL8367_TA_CTRL_REG 0x0500 ++#define RTL8367_TA_CTRL_STATUS BIT(12) ++#define RTL8367_TA_CTRL_METHOD BIT(5) ++#define RTL8367_TA_CTRL_CMD_SHIFT 4 ++#define RTL8367_TA_CTRL_CMD_READ 0 ++#define RTL8367_TA_CTRL_CMD_WRITE 1 ++#define RTL8367_TA_CTRL_TABLE_SHIFT 0 ++#define RTL8367_TA_CTRL_TABLE_ACLRULE 1 ++#define RTL8367_TA_CTRL_TABLE_ACLACT 2 ++#define RTL8367_TA_CTRL_TABLE_CVLAN 3 ++#define RTL8367_TA_CTRL_TABLE_L2 4 ++#define RTL8367_TA_CTRL_CVLAN_READ \ ++ ((RTL8367_TA_CTRL_CMD_READ << RTL8367_TA_CTRL_CMD_SHIFT) | \ ++ RTL8367_TA_CTRL_TABLE_CVLAN) ++#define RTL8367_TA_CTRL_CVLAN_WRITE \ ++ ((RTL8367_TA_CTRL_CMD_WRITE << RTL8367_TA_CTRL_CMD_SHIFT) | \ ++ RTL8367_TA_CTRL_TABLE_CVLAN) ++ ++#define RTL8367_TA_ADDR_REG 0x0501 ++#define RTL8367_TA_ADDR_MASK 0x3fff ++ ++#define RTL8367_TA_DATA_REG(_x) (0x0503 + (_x)) ++#define RTL8367_TA_VLAN_DATA_SIZE 4 ++#define RTL8367_TA_VLAN_VID_MASK RTL8367_VID_MASK ++#define RTL8367_TA_VLAN_MEMBER_SHIFT 0 ++#define RTL8367_TA_VLAN_MEMBER_MASK RTL8367_MEMBER_MASK ++#define RTL8367_TA_VLAN_FID_SHIFT 0 ++#define RTL8367_TA_VLAN_FID_MASK RTL8367_FID_MASK ++#define RTL8367_TA_VLAN_UNTAG1_SHIFT 14 ++#define RTL8367_TA_VLAN_UNTAG1_MASK 0x3 ++#define RTL8367_TA_VLAN_UNTAG2_SHIFT 0 ++#define RTL8367_TA_VLAN_UNTAG2_MASK 0x3fff ++ ++#define RTL8367_VLAN_PVID_CTRL_REG(_p) (0x0700 + (_p) / 2) ++#define RTL8367_VLAN_PVID_CTRL_MASK 0x1f ++#define RTL8367_VLAN_PVID_CTRL_SHIFT(_p) (8 * ((_p) % 2)) ++ ++#define RTL8367_VLAN_MC_BASE(_x) (0x0728 + (_x) * 4) ++#define RTL8367_VLAN_MC_DATA_SIZE 4 ++#define RTL8367_VLAN_MC_MEMBER_SHIFT 0 ++#define RTL8367_VLAN_MC_MEMBER_MASK RTL8367_MEMBER_MASK ++#define RTL8367_VLAN_MC_FID_SHIFT 0 ++#define RTL8367_VLAN_MC_FID_MASK RTL8367_FID_MASK ++#define RTL8367_VLAN_MC_EVID_SHIFT 0 ++#define RTL8367_VLAN_MC_EVID_MASK RTL8367_VID_MASK ++ ++#define RTL8367_VLAN_CTRL_REG 0x07a8 ++#define RTL8367_VLAN_CTRL_ENABLE BIT(0) ++ ++#define RTL8367_VLAN_INGRESS_REG 0x07a9 ++ ++#define RTL8367_PORT_ISOLATION_REG(_p) (0x08a2 + (_p)) ++ ++#define RTL8367_MIB_COUNTER_REG(_x) (0x1000 + (_x)) ++ ++#define RTL8367_MIB_ADDRESS_REG 0x1004 ++ ++#define RTL8367_MIB_CTRL_REG(_x) (0x1005 + (_x)) ++#define RTL8367_MIB_CTRL_GLOBAL_RESET_MASK BIT(11) ++#define RTL8367_MIB_CTRL_QM_RESET_MASK BIT(10) ++#define RTL8367_MIB_CTRL_PORT_RESET_MASK(_p) BIT(2 + (_p)) ++#define RTL8367_MIB_CTRL_RESET_MASK BIT(1) ++#define RTL8367_MIB_CTRL_BUSY_MASK BIT(0) ++ ++#define RTL8367_MIB_COUNT 36 ++#define RTL8367_MIB_COUNTER_PORT_OFFSET 0x0050 ++ ++#define RTL8367_SWC0_REG 0x1200 ++#define RTL8367_SWC0_MAX_LENGTH_SHIFT 13 ++#define RTL8367_SWC0_MAX_LENGTH(_x) ((_x) << 13) ++#define RTL8367_SWC0_MAX_LENGTH_MASK RTL8367_SWC0_MAX_LENGTH(0x3) ++#define RTL8367_SWC0_MAX_LENGTH_1522 RTL8367_SWC0_MAX_LENGTH(0) ++#define RTL8367_SWC0_MAX_LENGTH_1536 RTL8367_SWC0_MAX_LENGTH(1) ++#define RTL8367_SWC0_MAX_LENGTH_1552 RTL8367_SWC0_MAX_LENGTH(2) ++#define RTL8367_SWC0_MAX_LENGTH_16000 RTL8367_SWC0_MAX_LENGTH(3) ++ ++#define RTL8367_CHIP_NUMBER_REG 0x1300 ++ ++#define RTL8367_CHIP_VER_REG 0x1301 ++#define RTL8367_CHIP_VER_RLVID_SHIFT 12 ++#define RTL8367_CHIP_VER_RLVID_MASK 0xf ++#define RTL8367_CHIP_VER_MCID_SHIFT 8 ++#define RTL8367_CHIP_VER_MCID_MASK 0xf ++#define RTL8367_CHIP_VER_BOID_SHIFT 4 ++#define RTL8367_CHIP_VER_BOID_MASK 0xf ++ ++#define RTL8367_CHIP_MODE_REG 0x1302 ++#define RTL8367_CHIP_MODE_MASK 0x7 ++ ++#define RTL8367_CHIP_DEBUG0_REG 0x1303 ++#define RTL8367_CHIP_DEBUG0_DUMMY0(_x) BIT(8 + (_x)) ++ ++#define RTL8367_CHIP_DEBUG1_REG 0x1304 ++ ++#define RTL8367_DIS_REG 0x1305 ++#define RTL8367_DIS_SKIP_MII_RXER(_x) BIT(12 + (_x)) ++#define RTL8367_DIS_RGMII_SHIFT(_x) (4 * (_x)) ++#define RTL8367_DIS_RGMII_MASK 0x7 ++ ++#define RTL8367_EXT_RGMXF_REG(_x) (0x1306 + (_x)) ++#define RTL8367_EXT_RGMXF_DUMMY0_SHIFT 5 ++#define RTL8367_EXT_RGMXF_DUMMY0_MASK 0x7ff ++#define RTL8367_EXT_RGMXF_TXDELAY_SHIFT 3 ++#define RTL8367_EXT_RGMXF_TXDELAY_MASK 1 ++#define RTL8367_EXT_RGMXF_RXDELAY_MASK 0x7 ++ ++#define RTL8367_DI_FORCE_REG(_x) (0x1310 + (_x)) ++#define RTL8367_DI_FORCE_MODE BIT(12) ++#define RTL8367_DI_FORCE_NWAY BIT(7) ++#define RTL8367_DI_FORCE_TXPAUSE BIT(6) ++#define RTL8367_DI_FORCE_RXPAUSE BIT(5) ++#define RTL8367_DI_FORCE_LINK BIT(4) ++#define RTL8367_DI_FORCE_DUPLEX BIT(2) ++#define RTL8367_DI_FORCE_SPEED_MASK 3 ++#define RTL8367_DI_FORCE_SPEED_10 0 ++#define RTL8367_DI_FORCE_SPEED_100 1 ++#define RTL8367_DI_FORCE_SPEED_1000 2 ++ ++#define RTL8367_MAC_FORCE_REG(_x) (0x1312 + (_x)) ++ ++#define RTL8367_CHIP_RESET_REG 0x1322 ++#define RTL8367_CHIP_RESET_SW BIT(1) ++#define RTL8367_CHIP_RESET_HW BIT(0) ++ ++#define RTL8367_PORT_STATUS_REG(_p) (0x1352 + (_p)) ++#define RTL8367_PORT_STATUS_NWAY BIT(7) ++#define RTL8367_PORT_STATUS_TXPAUSE BIT(6) ++#define RTL8367_PORT_STATUS_RXPAUSE BIT(5) ++#define RTL8367_PORT_STATUS_LINK BIT(4) ++#define RTL8367_PORT_STATUS_DUPLEX BIT(2) ++#define RTL8367_PORT_STATUS_SPEED_MASK 0x0003 ++#define RTL8367_PORT_STATUS_SPEED_10 0 ++#define RTL8367_PORT_STATUS_SPEED_100 1 ++#define RTL8367_PORT_STATUS_SPEED_1000 2 ++ ++#define RTL8367_RTL_NO_REG 0x13c0 ++#define RTL8367_RTL_NO_8367R 0x3670 ++#define RTL8367_RTL_NO_8367M 0x3671 ++ ++#define RTL8367_RTL_VER_REG 0x13c1 ++#define RTL8367_RTL_VER_MASK 0xf ++ ++#define RTL8367_RTL_MAGIC_ID_REG 0x13c2 ++#define RTL8367_RTL_MAGIC_ID_VAL 0x0249 ++ ++#define RTL8367_LED_SYS_CONFIG_REG 0x1b00 ++#define RTL8367_LED_MODE_REG 0x1b02 ++#define RTL8367_LED_MODE_RATE_M 0x7 ++#define RTL8367_LED_MODE_RATE_S 1 ++ ++#define RTL8367_LED_CONFIG_REG 0x1b03 ++#define RTL8367_LED_CONFIG_DATA_S 12 ++#define RTL8367_LED_CONFIG_DATA_M 0x3 ++#define RTL8367_LED_CONFIG_SEL BIT(14) ++#define RTL8367_LED_CONFIG_LED_CFG_M 0xf ++ ++#define RTL8367_PARA_LED_IO_EN1_REG 0x1b24 ++#define RTL8367_PARA_LED_IO_EN2_REG 0x1b25 ++#define RTL8367_PARA_LED_IO_EN_PMASK 0xff ++ ++#define RTL8367_IA_CTRL_REG 0x1f00 ++#define RTL8367_IA_CTRL_RW(_x) ((_x) << 1) ++#define RTL8367_IA_CTRL_RW_READ RTL8367_IA_CTRL_RW(0) ++#define RTL8367_IA_CTRL_RW_WRITE RTL8367_IA_CTRL_RW(1) ++#define RTL8367_IA_CTRL_CMD_MASK BIT(0) ++ ++#define RTL8367_IA_STATUS_REG 0x1f01 ++#define RTL8367_IA_STATUS_PHY_BUSY BIT(2) ++#define RTL8367_IA_STATUS_SDS_BUSY BIT(1) ++#define RTL8367_IA_STATUS_MDX_BUSY BIT(0) ++ ++#define RTL8367_IA_ADDRESS_REG 0x1f02 ++ ++#define RTL8367_IA_WRITE_DATA_REG 0x1f03 ++#define RTL8367_IA_READ_DATA_REG 0x1f04 ++ ++#define RTL8367_INTERNAL_PHY_REG(_a, _r) (0x2000 + 32 * (_a) + (_r)) ++ ++#define RTL8367_CPU_PORT_NUM 9 ++#define RTL8367_NUM_PORTS 10 ++#define RTL8367_NUM_VLANS 32 ++#define RTL8367_NUM_LEDGROUPS 4 ++#define RTL8367_NUM_VIDS 4096 ++#define RTL8367_PRIORITYMAX 7 ++#define RTL8367_FIDMAX 7 ++ ++#define RTL8367_PORT_0 BIT(0) ++#define RTL8367_PORT_1 BIT(1) ++#define RTL8367_PORT_2 BIT(2) ++#define RTL8367_PORT_3 BIT(3) ++#define RTL8367_PORT_4 BIT(4) ++#define RTL8367_PORT_5 BIT(5) ++#define RTL8367_PORT_6 BIT(6) ++#define RTL8367_PORT_7 BIT(7) ++#define RTL8367_PORT_E1 BIT(8) /* external port 1 */ ++#define RTL8367_PORT_E0 BIT(9) /* external port 0 */ ++ ++#define RTL8367_PORTS_ALL \ ++ (RTL8367_PORT_0 | RTL8367_PORT_1 | RTL8367_PORT_2 | \ ++ RTL8367_PORT_3 | RTL8367_PORT_4 | RTL8367_PORT_5 | \ ++ RTL8367_PORT_6 | RTL8367_PORT_7 | RTL8367_PORT_E1 | \ ++ RTL8367_PORT_E0) ++ ++#define RTL8367_PORTS_ALL_BUT_CPU \ ++ (RTL8367_PORT_0 | RTL8367_PORT_1 | RTL8367_PORT_2 | \ ++ RTL8367_PORT_3 | RTL8367_PORT_4 | RTL8367_PORT_5 | \ ++ RTL8367_PORT_6 | RTL8367_PORT_7 | RTL8367_PORT_E1) ++ ++struct rtl8367_initval { ++ u16 reg; ++ u16 val; ++}; ++ ++#define RTL8367_MIB_RXB_ID 0 /* IfInOctets */ ++#define RTL8367_MIB_TXB_ID 20 /* IfOutOctets */ ++ ++static struct rtl8366_mib_counter rtl8367_mib_counters[] = { ++ { 0, 0, 4, "IfInOctets" }, ++ { 0, 4, 2, "Dot3StatsFCSErrors" }, ++ { 0, 6, 2, "Dot3StatsSymbolErrors" }, ++ { 0, 8, 2, "Dot3InPauseFrames" }, ++ { 0, 10, 2, "Dot3ControlInUnknownOpcodes" }, ++ { 0, 12, 2, "EtherStatsFragments" }, ++ { 0, 14, 2, "EtherStatsJabbers" }, ++ { 0, 16, 2, "IfInUcastPkts" }, ++ { 0, 18, 2, "EtherStatsDropEvents" }, ++ { 0, 20, 4, "EtherStatsOctets" }, ++ ++ { 0, 24, 2, "EtherStatsUnderSizePkts" }, ++ { 0, 26, 2, "EtherOversizeStats" }, ++ { 0, 28, 2, "EtherStatsPkts64Octets" }, ++ { 0, 30, 2, "EtherStatsPkts65to127Octets" }, ++ { 0, 32, 2, "EtherStatsPkts128to255Octets" }, ++ { 0, 34, 2, "EtherStatsPkts256to511Octets" }, ++ { 0, 36, 2, "EtherStatsPkts512to1023Octets" }, ++ { 0, 38, 2, "EtherStatsPkts1024to1518Octets" }, ++ { 0, 40, 2, "EtherStatsMulticastPkts" }, ++ { 0, 42, 2, "EtherStatsBroadcastPkts" }, ++ ++ { 0, 44, 4, "IfOutOctets" }, ++ ++ { 0, 48, 2, "Dot3StatsSingleCollisionFrames" }, ++ { 0, 50, 2, "Dot3StatMultipleCollisionFrames" }, ++ { 0, 52, 2, "Dot3sDeferredTransmissions" }, ++ { 0, 54, 2, "Dot3StatsLateCollisions" }, ++ { 0, 56, 2, "EtherStatsCollisions" }, ++ { 0, 58, 2, "Dot3StatsExcessiveCollisions" }, ++ { 0, 60, 2, "Dot3OutPauseFrames" }, ++ { 0, 62, 2, "Dot1dBasePortDelayExceededDiscards" }, ++ { 0, 64, 2, "Dot1dTpPortInDiscards" }, ++ { 0, 66, 2, "IfOutUcastPkts" }, ++ { 0, 68, 2, "IfOutMulticastPkts" }, ++ { 0, 70, 2, "IfOutBroadcastPkts" }, ++ { 0, 72, 2, "OutOampduPkts" }, ++ { 0, 74, 2, "InOampduPkts" }, ++ { 0, 76, 2, "PktgenPkts" }, ++}; ++ ++#define REG_RD(_smi, _reg, _val) \ ++ do { \ ++ err = rtl8366_smi_read_reg(_smi, _reg, _val); \ ++ if (err) \ ++ return err; \ ++ } while (0) ++ ++#define REG_WR(_smi, _reg, _val) \ ++ do { \ ++ err = rtl8366_smi_write_reg(_smi, _reg, _val); \ ++ if (err) \ ++ return err; \ ++ } while (0) ++ ++#define REG_RMW(_smi, _reg, _mask, _val) \ ++ do { \ ++ err = rtl8366_smi_rmwr(_smi, _reg, _mask, _val); \ ++ if (err) \ ++ return err; \ ++ } while (0) ++ ++static const struct rtl8367_initval rtl8367_initvals_0_0[] = { ++ {0x133f, 0x0030}, {0x133e, 0x000e}, {0x221f, 0x0000}, {0x2215, 0x1006}, ++ {0x221f, 0x0005}, {0x2200, 0x00c6}, {0x221f, 0x0007}, {0x221e, 0x0048}, ++ {0x2215, 0x6412}, {0x2216, 0x6412}, {0x2217, 0x6412}, {0x2218, 0x6412}, ++ {0x2219, 0x6412}, {0x221A, 0x6412}, {0x221f, 0x0001}, {0x220c, 0xdbf0}, ++ {0x2209, 0x2576}, {0x2207, 0x287E}, {0x220A, 0x68E5}, {0x221D, 0x3DA4}, ++ {0x221C, 0xE7F7}, {0x2214, 0x7F52}, {0x2218, 0x7FCE}, {0x2208, 0x04B7}, ++ {0x2206, 0x4072}, {0x2210, 0xF05E}, {0x221B, 0xB414}, {0x221F, 0x0003}, ++ {0x221A, 0x06A6}, {0x2210, 0xF05E}, {0x2213, 0x06EB}, {0x2212, 0xF4D2}, ++ {0x220E, 0xE120}, {0x2200, 0x7C00}, {0x2202, 0x5FD0}, {0x220D, 0x0207}, ++ {0x221f, 0x0002}, {0x2205, 0x0978}, {0x2202, 0x8C01}, {0x2207, 0x3620}, ++ {0x221C, 0x0001}, {0x2203, 0x0420}, {0x2204, 0x80C8}, {0x133e, 0x0ede}, ++ {0x221f, 0x0002}, {0x220c, 0x0073}, {0x220d, 0xEB65}, {0x220e, 0x51d1}, ++ {0x220f, 0x5dcb}, {0x2210, 0x3044}, {0x2211, 0x1800}, {0x2212, 0x7E00}, ++ {0x2213, 0x0000}, {0x133f, 0x0010}, {0x133e, 0x0ffe}, {0x207f, 0x0002}, ++ {0x2074, 0x3D22}, {0x2075, 0x2000}, {0x2076, 0x6040}, {0x2077, 0x0000}, ++ {0x2078, 0x0f0a}, {0x2079, 0x50AB}, {0x207a, 0x0000}, {0x207b, 0x0f0f}, ++ {0x205f, 0x0002}, {0x2054, 0xFF00}, {0x2055, 0x000A}, {0x2056, 0x000A}, ++ {0x2057, 0x0005}, {0x2058, 0x0005}, {0x2059, 0x0000}, {0x205A, 0x0005}, ++ {0x205B, 0x0005}, {0x205C, 0x0005}, {0x209f, 0x0002}, {0x2094, 0x00AA}, ++ {0x2095, 0x00AA}, {0x2096, 0x00AA}, {0x2097, 0x00AA}, {0x2098, 0x0055}, ++ {0x2099, 0x00AA}, {0x209A, 0x00AA}, {0x209B, 0x00AA}, {0x1363, 0x8354}, ++ {0x1270, 0x3333}, {0x1271, 0x3333}, {0x1272, 0x3333}, {0x1330, 0x00DB}, ++ {0x1203, 0xff00}, {0x1200, 0x7fc4}, {0x121d, 0x1006}, {0x121e, 0x03e8}, ++ {0x121f, 0x02b3}, {0x1220, 0x028f}, {0x1221, 0x029b}, {0x1222, 0x0277}, ++ {0x1223, 0x02b3}, {0x1224, 0x028f}, {0x1225, 0x029b}, {0x1226, 0x0277}, ++ {0x1227, 0x00c0}, {0x1228, 0x00b4}, {0x122f, 0x00c0}, {0x1230, 0x00b4}, ++ {0x1229, 0x0020}, {0x122a, 0x000c}, {0x1231, 0x0030}, {0x1232, 0x0024}, ++ {0x0219, 0x0032}, {0x0200, 0x03e8}, {0x0201, 0x03e8}, {0x0202, 0x03e8}, ++ {0x0203, 0x03e8}, {0x0204, 0x03e8}, {0x0205, 0x03e8}, {0x0206, 0x03e8}, ++ {0x0207, 0x03e8}, {0x0218, 0x0032}, {0x0208, 0x029b}, {0x0209, 0x029b}, ++ {0x020a, 0x029b}, {0x020b, 0x029b}, {0x020c, 0x029b}, {0x020d, 0x029b}, ++ {0x020e, 0x029b}, {0x020f, 0x029b}, {0x0210, 0x029b}, {0x0211, 0x029b}, ++ {0x0212, 0x029b}, {0x0213, 0x029b}, {0x0214, 0x029b}, {0x0215, 0x029b}, ++ {0x0216, 0x029b}, {0x0217, 0x029b}, {0x0900, 0x0000}, {0x0901, 0x0000}, ++ {0x0902, 0x0000}, {0x0903, 0x0000}, {0x0865, 0x3210}, {0x087b, 0x0000}, ++ {0x087c, 0xff00}, {0x087d, 0x0000}, {0x087e, 0x0000}, {0x0801, 0x0100}, ++ {0x0802, 0x0100}, {0x1700, 0x014C}, {0x0301, 0x00FF}, {0x12AA, 0x0096}, ++ {0x133f, 0x0030}, {0x133e, 0x000e}, {0x221f, 0x0005}, {0x2200, 0x00C4}, ++ {0x221f, 0x0000}, {0x2210, 0x05EF}, {0x2204, 0x05E1}, {0x2200, 0x1340}, ++ {0x133f, 0x0010}, {0x20A0, 0x1940}, {0x20C0, 0x1940}, {0x20E0, 0x1940}, ++}; ++ ++static const struct rtl8367_initval rtl8367_initvals_0_1[] = { ++ {0x133f, 0x0030}, {0x133e, 0x000e}, {0x221f, 0x0000}, {0x2215, 0x1006}, ++ {0x221f, 0x0005}, {0x2200, 0x00c6}, {0x221f, 0x0007}, {0x221e, 0x0048}, ++ {0x2215, 0x6412}, {0x2216, 0x6412}, {0x2217, 0x6412}, {0x2218, 0x6412}, ++ {0x2219, 0x6412}, {0x221A, 0x6412}, {0x221f, 0x0001}, {0x220c, 0xdbf0}, ++ {0x2209, 0x2576}, {0x2207, 0x287E}, {0x220A, 0x68E5}, {0x221D, 0x3DA4}, ++ {0x221C, 0xE7F7}, {0x2214, 0x7F52}, {0x2218, 0x7FCE}, {0x2208, 0x04B7}, ++ {0x2206, 0x4072}, {0x2210, 0xF05E}, {0x221B, 0xB414}, {0x221F, 0x0003}, ++ {0x221A, 0x06A6}, {0x2210, 0xF05E}, {0x2213, 0x06EB}, {0x2212, 0xF4D2}, ++ {0x220E, 0xE120}, {0x2200, 0x7C00}, {0x2202, 0x5FD0}, {0x220D, 0x0207}, ++ {0x221f, 0x0002}, {0x2205, 0x0978}, {0x2202, 0x8C01}, {0x2207, 0x3620}, ++ {0x221C, 0x0001}, {0x2203, 0x0420}, {0x2204, 0x80C8}, {0x133e, 0x0ede}, ++ {0x221f, 0x0002}, {0x220c, 0x0073}, {0x220d, 0xEB65}, {0x220e, 0x51d1}, ++ {0x220f, 0x5dcb}, {0x2210, 0x3044}, {0x2211, 0x1800}, {0x2212, 0x7E00}, ++ {0x2213, 0x0000}, {0x133f, 0x0010}, {0x133e, 0x0ffe}, {0x207f, 0x0002}, ++ {0x2074, 0x3D22}, {0x2075, 0x2000}, {0x2076, 0x6040}, {0x2077, 0x0000}, ++ {0x2078, 0x0f0a}, {0x2079, 0x50AB}, {0x207a, 0x0000}, {0x207b, 0x0f0f}, ++ {0x205f, 0x0002}, {0x2054, 0xFF00}, {0x2055, 0x000A}, {0x2056, 0x000A}, ++ {0x2057, 0x0005}, {0x2058, 0x0005}, {0x2059, 0x0000}, {0x205A, 0x0005}, ++ {0x205B, 0x0005}, {0x205C, 0x0005}, {0x209f, 0x0002}, {0x2094, 0x00AA}, ++ {0x2095, 0x00AA}, {0x2096, 0x00AA}, {0x2097, 0x00AA}, {0x2098, 0x0055}, ++ {0x2099, 0x00AA}, {0x209A, 0x00AA}, {0x209B, 0x00AA}, {0x1363, 0x8354}, ++ {0x1270, 0x3333}, {0x1271, 0x3333}, {0x1272, 0x3333}, {0x1330, 0x00DB}, ++ {0x1203, 0xff00}, {0x1200, 0x7fc4}, {0x121d, 0x1b06}, {0x121e, 0x07f0}, ++ {0x121f, 0x0438}, {0x1220, 0x040f}, {0x1221, 0x040f}, {0x1222, 0x03eb}, ++ {0x1223, 0x0438}, {0x1224, 0x040f}, {0x1225, 0x040f}, {0x1226, 0x03eb}, ++ {0x1227, 0x0144}, {0x1228, 0x0138}, {0x122f, 0x0144}, {0x1230, 0x0138}, ++ {0x1229, 0x0020}, {0x122a, 0x000c}, {0x1231, 0x0030}, {0x1232, 0x0024}, ++ {0x0219, 0x0032}, {0x0200, 0x07d0}, {0x0201, 0x07d0}, {0x0202, 0x07d0}, ++ {0x0203, 0x07d0}, {0x0204, 0x07d0}, {0x0205, 0x07d0}, {0x0206, 0x07d0}, ++ {0x0207, 0x07d0}, {0x0218, 0x0032}, {0x0208, 0x0190}, {0x0209, 0x0190}, ++ {0x020a, 0x0190}, {0x020b, 0x0190}, {0x020c, 0x0190}, {0x020d, 0x0190}, ++ {0x020e, 0x0190}, {0x020f, 0x0190}, {0x0210, 0x0190}, {0x0211, 0x0190}, ++ {0x0212, 0x0190}, {0x0213, 0x0190}, {0x0214, 0x0190}, {0x0215, 0x0190}, ++ {0x0216, 0x0190}, {0x0217, 0x0190}, {0x0900, 0x0000}, {0x0901, 0x0000}, ++ {0x0902, 0x0000}, {0x0903, 0x0000}, {0x0865, 0x3210}, {0x087b, 0x0000}, ++ {0x087c, 0xff00}, {0x087d, 0x0000}, {0x087e, 0x0000}, {0x0801, 0x0100}, ++ {0x0802, 0x0100}, {0x1700, 0x0125}, {0x0301, 0x00FF}, {0x12AA, 0x0096}, ++ {0x133f, 0x0030}, {0x133e, 0x000e}, {0x221f, 0x0005}, {0x2200, 0x00C4}, ++ {0x221f, 0x0000}, {0x2210, 0x05EF}, {0x2204, 0x05E1}, {0x2200, 0x1340}, ++ {0x133f, 0x0010}, ++}; ++ ++static const struct rtl8367_initval rtl8367_initvals_1_0[] = { ++ {0x1B24, 0x0000}, {0x1B25, 0x0000}, {0x1B26, 0x0000}, {0x1B27, 0x0000}, ++ {0x207F, 0x0002}, {0x2079, 0x0200}, {0x207F, 0x0000}, {0x133F, 0x0030}, ++ {0x133E, 0x000E}, {0x221F, 0x0005}, {0x2201, 0x0700}, {0x2205, 0x8B82}, ++ {0x2206, 0x05CB}, {0x221F, 0x0002}, {0x2204, 0x80C2}, {0x2205, 0x0938}, ++ {0x221F, 0x0003}, {0x2212, 0xC4D2}, {0x220D, 0x0207}, {0x221F, 0x0001}, ++ {0x2207, 0x267E}, {0x221C, 0xE5F7}, {0x221B, 0x0424}, {0x221F, 0x0007}, ++ {0x221E, 0x0040}, {0x2218, 0x0000}, {0x221F, 0x0007}, {0x221E, 0x002C}, ++ {0x2218, 0x008B}, {0x221F, 0x0005}, {0x2205, 0xFFF6}, {0x2206, 0x0080}, ++ {0x2205, 0x8000}, {0x2206, 0xF8E0}, {0x2206, 0xE000}, {0x2206, 0xE1E0}, ++ {0x2206, 0x01AC}, {0x2206, 0x2408}, {0x2206, 0xE08B}, {0x2206, 0x84F7}, ++ {0x2206, 0x20E4}, {0x2206, 0x8B84}, {0x2206, 0xFC05}, {0x2206, 0xF8FA}, ++ {0x2206, 0xEF69}, {0x2206, 0xE08B}, {0x2206, 0x86AC}, {0x2206, 0x201A}, ++ {0x2206, 0xBF80}, {0x2206, 0x59D0}, {0x2206, 0x2402}, {0x2206, 0x803D}, ++ {0x2206, 0xE0E0}, {0x2206, 0xE4E1}, {0x2206, 0xE0E5}, {0x2206, 0x5806}, ++ {0x2206, 0x68C0}, {0x2206, 0xD1D2}, {0x2206, 0xE4E0}, {0x2206, 0xE4E5}, ++ {0x2206, 0xE0E5}, {0x2206, 0xEF96}, {0x2206, 0xFEFC}, {0x2206, 0x05FB}, ++ {0x2206, 0x0BFB}, {0x2206, 0x58FF}, {0x2206, 0x9E11}, {0x2206, 0x06F0}, ++ {0x2206, 0x0C81}, {0x2206, 0x8AE0}, {0x2206, 0x0019}, {0x2206, 0x1B89}, ++ {0x2206, 0xCFEB}, {0x2206, 0x19EB}, {0x2206, 0x19B0}, {0x2206, 0xEFFF}, ++ {0x2206, 0x0BFF}, {0x2206, 0x0425}, {0x2206, 0x0807}, {0x2206, 0x2640}, ++ {0x2206, 0x7227}, {0x2206, 0x267E}, {0x2206, 0x2804}, {0x2206, 0xB729}, ++ {0x2206, 0x2576}, {0x2206, 0x2A68}, {0x2206, 0xE52B}, {0x2206, 0xAD00}, ++ {0x2206, 0x2CDB}, {0x2206, 0xF02D}, {0x2206, 0x67BB}, {0x2206, 0x2E7B}, ++ {0x2206, 0x0F2F}, {0x2206, 0x7365}, {0x2206, 0x31AC}, {0x2206, 0xCC32}, ++ {0x2206, 0x2300}, {0x2206, 0x332D}, {0x2206, 0x1734}, {0x2206, 0x7F52}, ++ {0x2206, 0x3510}, {0x2206, 0x0036}, {0x2206, 0x0600}, {0x2206, 0x370C}, ++ {0x2206, 0xC038}, {0x2206, 0x7FCE}, {0x2206, 0x3CE5}, {0x2206, 0xF73D}, ++ {0x2206, 0x3DA4}, {0x2206, 0x6530}, {0x2206, 0x3E67}, {0x2206, 0x0053}, ++ {0x2206, 0x69D2}, {0x2206, 0x0F6A}, {0x2206, 0x012C}, {0x2206, 0x6C2B}, ++ {0x2206, 0x136E}, {0x2206, 0xE100}, {0x2206, 0x6F12}, {0x2206, 0xF771}, ++ {0x2206, 0x006B}, {0x2206, 0x7306}, {0x2206, 0xEB74}, {0x2206, 0x94C7}, ++ {0x2206, 0x7698}, {0x2206, 0x0A77}, {0x2206, 0x5000}, {0x2206, 0x788A}, ++ {0x2206, 0x1579}, {0x2206, 0x7F6F}, {0x2206, 0x7A06}, {0x2206, 0xA600}, ++ {0x2205, 0x8B90}, {0x2206, 0x8000}, {0x2205, 0x8B92}, {0x2206, 0x8000}, ++ {0x2205, 0x8B94}, {0x2206, 0x8014}, {0x2208, 0xFFFA}, {0x2202, 0x3C65}, ++ {0x2205, 0xFFF6}, {0x2206, 0x00F7}, {0x221F, 0x0000}, {0x221F, 0x0007}, ++ {0x221E, 0x0042}, {0x2218, 0x0000}, {0x221E, 0x002D}, {0x2218, 0xF010}, ++ {0x221E, 0x0020}, {0x2215, 0x0000}, {0x221E, 0x0023}, {0x2216, 0x8000}, ++ {0x221F, 0x0000}, {0x133F, 0x0010}, {0x133E, 0x0FFE}, {0x1362, 0x0115}, ++ {0x1363, 0x0002}, {0x1363, 0x0000}, {0x1306, 0x000C}, {0x1307, 0x000C}, ++ {0x1303, 0x0067}, {0x1304, 0x4444}, {0x1203, 0xFF00}, {0x1200, 0x7FC4}, ++ {0x121D, 0x7D16}, {0x121E, 0x03E8}, {0x121F, 0x024E}, {0x1220, 0x0230}, ++ {0x1221, 0x0244}, {0x1222, 0x0226}, {0x1223, 0x024E}, {0x1224, 0x0230}, ++ {0x1225, 0x0244}, {0x1226, 0x0226}, {0x1227, 0x00C0}, {0x1228, 0x00B4}, ++ {0x122F, 0x00C0}, {0x1230, 0x00B4}, {0x0208, 0x03E8}, {0x0209, 0x03E8}, ++ {0x020A, 0x03E8}, {0x020B, 0x03E8}, {0x020C, 0x03E8}, {0x020D, 0x03E8}, ++ {0x020E, 0x03E8}, {0x020F, 0x03E8}, {0x0210, 0x03E8}, {0x0211, 0x03E8}, ++ {0x0212, 0x03E8}, {0x0213, 0x03E8}, {0x0214, 0x03E8}, {0x0215, 0x03E8}, ++ {0x0216, 0x03E8}, {0x0217, 0x03E8}, {0x0900, 0x0000}, {0x0901, 0x0000}, ++ {0x0902, 0x0000}, {0x0903, 0x0000}, {0x0865, 0x3210}, {0x087B, 0x0000}, ++ {0x087C, 0xFF00}, {0x087D, 0x0000}, {0x087E, 0x0000}, {0x0801, 0x0100}, ++ {0x0802, 0x0100}, {0x0A20, 0x2040}, {0x0A21, 0x2040}, {0x0A22, 0x2040}, ++ {0x0A23, 0x2040}, {0x0A24, 0x2040}, {0x0A28, 0x2040}, {0x0A29, 0x2040}, ++ {0x133F, 0x0030}, {0x133E, 0x000E}, {0x221F, 0x0000}, {0x2200, 0x1340}, ++ {0x221F, 0x0000}, {0x133F, 0x0010}, {0x133E, 0x0FFE}, {0x20A0, 0x1940}, ++ {0x20C0, 0x1940}, {0x20E0, 0x1940}, {0x130c, 0x0050}, ++}; ++ ++static const struct rtl8367_initval rtl8367_initvals_1_1[] = { ++ {0x1B24, 0x0000}, {0x1B25, 0x0000}, {0x1B26, 0x0000}, {0x1B27, 0x0000}, ++ {0x207F, 0x0002}, {0x2079, 0x0200}, {0x207F, 0x0000}, {0x133F, 0x0030}, ++ {0x133E, 0x000E}, {0x221F, 0x0005}, {0x2201, 0x0700}, {0x2205, 0x8B82}, ++ {0x2206, 0x05CB}, {0x221F, 0x0002}, {0x2204, 0x80C2}, {0x2205, 0x0938}, ++ {0x221F, 0x0003}, {0x2212, 0xC4D2}, {0x220D, 0x0207}, {0x221F, 0x0001}, ++ {0x2207, 0x267E}, {0x221C, 0xE5F7}, {0x221B, 0x0424}, {0x221F, 0x0007}, ++ {0x221E, 0x0040}, {0x2218, 0x0000}, {0x221F, 0x0007}, {0x221E, 0x002C}, ++ {0x2218, 0x008B}, {0x221F, 0x0005}, {0x2205, 0xFFF6}, {0x2206, 0x0080}, ++ {0x2205, 0x8000}, {0x2206, 0xF8E0}, {0x2206, 0xE000}, {0x2206, 0xE1E0}, ++ {0x2206, 0x01AC}, {0x2206, 0x2408}, {0x2206, 0xE08B}, {0x2206, 0x84F7}, ++ {0x2206, 0x20E4}, {0x2206, 0x8B84}, {0x2206, 0xFC05}, {0x2206, 0xF8FA}, ++ {0x2206, 0xEF69}, {0x2206, 0xE08B}, {0x2206, 0x86AC}, {0x2206, 0x201A}, ++ {0x2206, 0xBF80}, {0x2206, 0x59D0}, {0x2206, 0x2402}, {0x2206, 0x803D}, ++ {0x2206, 0xE0E0}, {0x2206, 0xE4E1}, {0x2206, 0xE0E5}, {0x2206, 0x5806}, ++ {0x2206, 0x68C0}, {0x2206, 0xD1D2}, {0x2206, 0xE4E0}, {0x2206, 0xE4E5}, ++ {0x2206, 0xE0E5}, {0x2206, 0xEF96}, {0x2206, 0xFEFC}, {0x2206, 0x05FB}, ++ {0x2206, 0x0BFB}, {0x2206, 0x58FF}, {0x2206, 0x9E11}, {0x2206, 0x06F0}, ++ {0x2206, 0x0C81}, {0x2206, 0x8AE0}, {0x2206, 0x0019}, {0x2206, 0x1B89}, ++ {0x2206, 0xCFEB}, {0x2206, 0x19EB}, {0x2206, 0x19B0}, {0x2206, 0xEFFF}, ++ {0x2206, 0x0BFF}, {0x2206, 0x0425}, {0x2206, 0x0807}, {0x2206, 0x2640}, ++ {0x2206, 0x7227}, {0x2206, 0x267E}, {0x2206, 0x2804}, {0x2206, 0xB729}, ++ {0x2206, 0x2576}, {0x2206, 0x2A68}, {0x2206, 0xE52B}, {0x2206, 0xAD00}, ++ {0x2206, 0x2CDB}, {0x2206, 0xF02D}, {0x2206, 0x67BB}, {0x2206, 0x2E7B}, ++ {0x2206, 0x0F2F}, {0x2206, 0x7365}, {0x2206, 0x31AC}, {0x2206, 0xCC32}, ++ {0x2206, 0x2300}, {0x2206, 0x332D}, {0x2206, 0x1734}, {0x2206, 0x7F52}, ++ {0x2206, 0x3510}, {0x2206, 0x0036}, {0x2206, 0x0600}, {0x2206, 0x370C}, ++ {0x2206, 0xC038}, {0x2206, 0x7FCE}, {0x2206, 0x3CE5}, {0x2206, 0xF73D}, ++ {0x2206, 0x3DA4}, {0x2206, 0x6530}, {0x2206, 0x3E67}, {0x2206, 0x0053}, ++ {0x2206, 0x69D2}, {0x2206, 0x0F6A}, {0x2206, 0x012C}, {0x2206, 0x6C2B}, ++ {0x2206, 0x136E}, {0x2206, 0xE100}, {0x2206, 0x6F12}, {0x2206, 0xF771}, ++ {0x2206, 0x006B}, {0x2206, 0x7306}, {0x2206, 0xEB74}, {0x2206, 0x94C7}, ++ {0x2206, 0x7698}, {0x2206, 0x0A77}, {0x2206, 0x5000}, {0x2206, 0x788A}, ++ {0x2206, 0x1579}, {0x2206, 0x7F6F}, {0x2206, 0x7A06}, {0x2206, 0xA600}, ++ {0x2205, 0x8B90}, {0x2206, 0x8000}, {0x2205, 0x8B92}, {0x2206, 0x8000}, ++ {0x2205, 0x8B94}, {0x2206, 0x8014}, {0x2208, 0xFFFA}, {0x2202, 0x3C65}, ++ {0x2205, 0xFFF6}, {0x2206, 0x00F7}, {0x221F, 0x0000}, {0x221F, 0x0007}, ++ {0x221E, 0x0042}, {0x2218, 0x0000}, {0x221E, 0x002D}, {0x2218, 0xF010}, ++ {0x221E, 0x0020}, {0x2215, 0x0000}, {0x221E, 0x0023}, {0x2216, 0x8000}, ++ {0x221F, 0x0000}, {0x133F, 0x0010}, {0x133E, 0x0FFE}, {0x1362, 0x0115}, ++ {0x1363, 0x0002}, {0x1363, 0x0000}, {0x1306, 0x000C}, {0x1307, 0x000C}, ++ {0x1303, 0x0067}, {0x1304, 0x4444}, {0x1203, 0xFF00}, {0x1200, 0x7FC4}, ++ {0x0900, 0x0000}, {0x0901, 0x0000}, {0x0902, 0x0000}, {0x0903, 0x0000}, ++ {0x0865, 0x3210}, {0x087B, 0x0000}, {0x087C, 0xFF00}, {0x087D, 0x0000}, ++ {0x087E, 0x0000}, {0x0801, 0x0100}, {0x0802, 0x0100}, {0x0A20, 0x2040}, ++ {0x0A21, 0x2040}, {0x0A22, 0x2040}, {0x0A23, 0x2040}, {0x0A24, 0x2040}, ++ {0x0A25, 0x2040}, {0x0A26, 0x2040}, {0x0A27, 0x2040}, {0x0A28, 0x2040}, ++ {0x0A29, 0x2040}, {0x133F, 0x0030}, {0x133E, 0x000E}, {0x221F, 0x0000}, ++ {0x2200, 0x1340}, {0x221F, 0x0000}, {0x133F, 0x0010}, {0x133E, 0x0FFE}, ++ {0x1B03, 0x0876}, ++}; ++ ++static const struct rtl8367_initval rtl8367_initvals_2_0[] = { ++ {0x1b24, 0x0000}, {0x1b25, 0x0000}, {0x1b26, 0x0000}, {0x1b27, 0x0000}, ++ {0x133f, 0x0030}, {0x133e, 0x000e}, {0x221f, 0x0007}, {0x221e, 0x0048}, ++ {0x2219, 0x4012}, {0x221f, 0x0003}, {0x2201, 0x3554}, {0x2202, 0x63e8}, ++ {0x2203, 0x99c2}, {0x2204, 0x0113}, {0x2205, 0x303e}, {0x220d, 0x0207}, ++ {0x220e, 0xe100}, {0x221f, 0x0007}, {0x221e, 0x0040}, {0x2218, 0x0000}, ++ {0x221f, 0x0007}, {0x221e, 0x002c}, {0x2218, 0x008b}, {0x221f, 0x0005}, ++ {0x2205, 0xfff6}, {0x2206, 0x0080}, {0x221f, 0x0005}, {0x2205, 0x8000}, ++ {0x2206, 0x0280}, {0x2206, 0x2bf7}, {0x2206, 0x00e0}, {0x2206, 0xfff7}, ++ {0x2206, 0xa080}, {0x2206, 0x02ae}, {0x2206, 0xf602}, {0x2206, 0x804e}, ++ {0x2206, 0x0201}, {0x2206, 0x5002}, {0x2206, 0x0163}, {0x2206, 0x0201}, ++ {0x2206, 0x79e0}, {0x2206, 0x8b8c}, {0x2206, 0xe18b}, {0x2206, 0x8d1e}, ++ {0x2206, 0x01e1}, {0x2206, 0x8b8e}, {0x2206, 0x1e01}, {0x2206, 0xa000}, ++ {0x2206, 0xe4ae}, {0x2206, 0xd8bf}, {0x2206, 0x8b88}, {0x2206, 0xec00}, ++ {0x2206, 0x19a9}, {0x2206, 0x8b90}, {0x2206, 0xf9ee}, {0x2206, 0xfff6}, ++ {0x2206, 0x00ee}, {0x2206, 0xfff7}, {0x2206, 0xfce0}, {0x2206, 0xe140}, ++ {0x2206, 0xe1e1}, {0x2206, 0x41f7}, {0x2206, 0x2ff6}, {0x2206, 0x28e4}, ++ {0x2206, 0xe140}, {0x2206, 0xe5e1}, {0x2206, 0x4104}, {0x2206, 0xf8fa}, ++ {0x2206, 0xef69}, {0x2206, 0xe08b}, {0x2206, 0x86ac}, {0x2206, 0x201a}, ++ {0x2206, 0xbf80}, {0x2206, 0x77d0}, {0x2206, 0x6c02}, {0x2206, 0x2978}, ++ {0x2206, 0xe0e0}, {0x2206, 0xe4e1}, {0x2206, 0xe0e5}, {0x2206, 0x5806}, ++ {0x2206, 0x68c0}, {0x2206, 0xd1d2}, {0x2206, 0xe4e0}, {0x2206, 0xe4e5}, ++ {0x2206, 0xe0e5}, {0x2206, 0xef96}, {0x2206, 0xfefc}, {0x2206, 0x0425}, ++ {0x2206, 0x0807}, {0x2206, 0x2640}, {0x2206, 0x7227}, {0x2206, 0x267e}, ++ {0x2206, 0x2804}, {0x2206, 0xb729}, {0x2206, 0x2576}, {0x2206, 0x2a68}, ++ {0x2206, 0xe52b}, {0x2206, 0xad00}, {0x2206, 0x2cdb}, {0x2206, 0xf02d}, ++ {0x2206, 0x67bb}, {0x2206, 0x2e7b}, {0x2206, 0x0f2f}, {0x2206, 0x7365}, ++ {0x2206, 0x31ac}, {0x2206, 0xcc32}, {0x2206, 0x2300}, {0x2206, 0x332d}, ++ {0x2206, 0x1734}, {0x2206, 0x7f52}, {0x2206, 0x3510}, {0x2206, 0x0036}, ++ {0x2206, 0x0600}, {0x2206, 0x370c}, {0x2206, 0xc038}, {0x2206, 0x7fce}, ++ {0x2206, 0x3ce5}, {0x2206, 0xf73d}, {0x2206, 0x3da4}, {0x2206, 0x6530}, ++ {0x2206, 0x3e67}, {0x2206, 0x0053}, {0x2206, 0x69d2}, {0x2206, 0x0f6a}, ++ {0x2206, 0x012c}, {0x2206, 0x6c2b}, {0x2206, 0x136e}, {0x2206, 0xe100}, ++ {0x2206, 0x6f12}, {0x2206, 0xf771}, {0x2206, 0x006b}, {0x2206, 0x7306}, ++ {0x2206, 0xeb74}, {0x2206, 0x94c7}, {0x2206, 0x7698}, {0x2206, 0x0a77}, ++ {0x2206, 0x5000}, {0x2206, 0x788a}, {0x2206, 0x1579}, {0x2206, 0x7f6f}, ++ {0x2206, 0x7a06}, {0x2206, 0xa600}, {0x2201, 0x0701}, {0x2200, 0x0405}, ++ {0x221f, 0x0000}, {0x2200, 0x1340}, {0x221f, 0x0000}, {0x133f, 0x0010}, ++ {0x133e, 0x0ffe}, {0x1203, 0xff00}, {0x1200, 0x7fc4}, {0x121d, 0x7D16}, ++ {0x121e, 0x03e8}, {0x121f, 0x024e}, {0x1220, 0x0230}, {0x1221, 0x0244}, ++ {0x1222, 0x0226}, {0x1223, 0x024e}, {0x1224, 0x0230}, {0x1225, 0x0244}, ++ {0x1226, 0x0226}, {0x1227, 0x00c0}, {0x1228, 0x00b4}, {0x122f, 0x00c0}, ++ {0x1230, 0x00b4}, {0x0208, 0x03e8}, {0x0209, 0x03e8}, {0x020a, 0x03e8}, ++ {0x020b, 0x03e8}, {0x020c, 0x03e8}, {0x020d, 0x03e8}, {0x020e, 0x03e8}, ++ {0x020f, 0x03e8}, {0x0210, 0x03e8}, {0x0211, 0x03e8}, {0x0212, 0x03e8}, ++ {0x0213, 0x03e8}, {0x0214, 0x03e8}, {0x0215, 0x03e8}, {0x0216, 0x03e8}, ++ {0x0217, 0x03e8}, {0x0900, 0x0000}, {0x0901, 0x0000}, {0x0902, 0x0000}, ++ {0x0903, 0x0000}, {0x0865, 0x3210}, {0x087b, 0x0000}, {0x087c, 0xff00}, ++ {0x087d, 0x0000}, {0x087e, 0x0000}, {0x0801, 0x0100}, {0x0802, 0x0100}, ++ {0x0A20, 0x2040}, {0x0A21, 0x2040}, {0x0A22, 0x2040}, {0x0A23, 0x2040}, ++ {0x0A24, 0x2040}, {0x0A28, 0x2040}, {0x0A29, 0x2040}, {0x20A0, 0x1940}, ++ {0x20C0, 0x1940}, {0x20E0, 0x1940}, {0x130c, 0x0050}, ++}; ++ ++static const struct rtl8367_initval rtl8367_initvals_2_1[] = { ++ {0x1b24, 0x0000}, {0x1b25, 0x0000}, {0x1b26, 0x0000}, {0x1b27, 0x0000}, ++ {0x133f, 0x0030}, {0x133e, 0x000e}, {0x221f, 0x0007}, {0x221e, 0x0048}, ++ {0x2219, 0x4012}, {0x221f, 0x0003}, {0x2201, 0x3554}, {0x2202, 0x63e8}, ++ {0x2203, 0x99c2}, {0x2204, 0x0113}, {0x2205, 0x303e}, {0x220d, 0x0207}, ++ {0x220e, 0xe100}, {0x221f, 0x0007}, {0x221e, 0x0040}, {0x2218, 0x0000}, ++ {0x221f, 0x0007}, {0x221e, 0x002c}, {0x2218, 0x008b}, {0x221f, 0x0005}, ++ {0x2205, 0xfff6}, {0x2206, 0x0080}, {0x221f, 0x0005}, {0x2205, 0x8000}, ++ {0x2206, 0x0280}, {0x2206, 0x2bf7}, {0x2206, 0x00e0}, {0x2206, 0xfff7}, ++ {0x2206, 0xa080}, {0x2206, 0x02ae}, {0x2206, 0xf602}, {0x2206, 0x804e}, ++ {0x2206, 0x0201}, {0x2206, 0x5002}, {0x2206, 0x0163}, {0x2206, 0x0201}, ++ {0x2206, 0x79e0}, {0x2206, 0x8b8c}, {0x2206, 0xe18b}, {0x2206, 0x8d1e}, ++ {0x2206, 0x01e1}, {0x2206, 0x8b8e}, {0x2206, 0x1e01}, {0x2206, 0xa000}, ++ {0x2206, 0xe4ae}, {0x2206, 0xd8bf}, {0x2206, 0x8b88}, {0x2206, 0xec00}, ++ {0x2206, 0x19a9}, {0x2206, 0x8b90}, {0x2206, 0xf9ee}, {0x2206, 0xfff6}, ++ {0x2206, 0x00ee}, {0x2206, 0xfff7}, {0x2206, 0xfce0}, {0x2206, 0xe140}, ++ {0x2206, 0xe1e1}, {0x2206, 0x41f7}, {0x2206, 0x2ff6}, {0x2206, 0x28e4}, ++ {0x2206, 0xe140}, {0x2206, 0xe5e1}, {0x2206, 0x4104}, {0x2206, 0xf8fa}, ++ {0x2206, 0xef69}, {0x2206, 0xe08b}, {0x2206, 0x86ac}, {0x2206, 0x201a}, ++ {0x2206, 0xbf80}, {0x2206, 0x77d0}, {0x2206, 0x6c02}, {0x2206, 0x2978}, ++ {0x2206, 0xe0e0}, {0x2206, 0xe4e1}, {0x2206, 0xe0e5}, {0x2206, 0x5806}, ++ {0x2206, 0x68c0}, {0x2206, 0xd1d2}, {0x2206, 0xe4e0}, {0x2206, 0xe4e5}, ++ {0x2206, 0xe0e5}, {0x2206, 0xef96}, {0x2206, 0xfefc}, {0x2206, 0x0425}, ++ {0x2206, 0x0807}, {0x2206, 0x2640}, {0x2206, 0x7227}, {0x2206, 0x267e}, ++ {0x2206, 0x2804}, {0x2206, 0xb729}, {0x2206, 0x2576}, {0x2206, 0x2a68}, ++ {0x2206, 0xe52b}, {0x2206, 0xad00}, {0x2206, 0x2cdb}, {0x2206, 0xf02d}, ++ {0x2206, 0x67bb}, {0x2206, 0x2e7b}, {0x2206, 0x0f2f}, {0x2206, 0x7365}, ++ {0x2206, 0x31ac}, {0x2206, 0xcc32}, {0x2206, 0x2300}, {0x2206, 0x332d}, ++ {0x2206, 0x1734}, {0x2206, 0x7f52}, {0x2206, 0x3510}, {0x2206, 0x0036}, ++ {0x2206, 0x0600}, {0x2206, 0x370c}, {0x2206, 0xc038}, {0x2206, 0x7fce}, ++ {0x2206, 0x3ce5}, {0x2206, 0xf73d}, {0x2206, 0x3da4}, {0x2206, 0x6530}, ++ {0x2206, 0x3e67}, {0x2206, 0x0053}, {0x2206, 0x69d2}, {0x2206, 0x0f6a}, ++ {0x2206, 0x012c}, {0x2206, 0x6c2b}, {0x2206, 0x136e}, {0x2206, 0xe100}, ++ {0x2206, 0x6f12}, {0x2206, 0xf771}, {0x2206, 0x006b}, {0x2206, 0x7306}, ++ {0x2206, 0xeb74}, {0x2206, 0x94c7}, {0x2206, 0x7698}, {0x2206, 0x0a77}, ++ {0x2206, 0x5000}, {0x2206, 0x788a}, {0x2206, 0x1579}, {0x2206, 0x7f6f}, ++ {0x2206, 0x7a06}, {0x2206, 0xa600}, {0x2201, 0x0701}, {0x2200, 0x0405}, ++ {0x221f, 0x0000}, {0x2200, 0x1340}, {0x221f, 0x0000}, {0x133f, 0x0010}, ++ {0x133e, 0x0ffe}, {0x1203, 0xff00}, {0x1200, 0x7fc4}, {0x0900, 0x0000}, ++ {0x0901, 0x0000}, {0x0902, 0x0000}, {0x0903, 0x0000}, {0x0865, 0x3210}, ++ {0x087b, 0x0000}, {0x087c, 0xff00}, {0x087d, 0x0000}, {0x087e, 0x0000}, ++ {0x0801, 0x0100}, {0x0802, 0x0100}, {0x0A20, 0x2040}, {0x0A21, 0x2040}, ++ {0x0A22, 0x2040}, {0x0A23, 0x2040}, {0x0A24, 0x2040}, {0x0A25, 0x2040}, ++ {0x0A26, 0x2040}, {0x0A27, 0x2040}, {0x0A28, 0x2040}, {0x0A29, 0x2040}, ++ {0x130c, 0x0050}, ++}; ++ ++static int rtl8367_write_initvals(struct rtl8366_smi *smi, ++ const struct rtl8367_initval *initvals, ++ int count) ++{ ++ int err; ++ int i; ++ ++ for (i = 0; i < count; i++) ++ REG_WR(smi, initvals[i].reg, initvals[i].val); ++ ++ return 0; ++} ++ ++static int rtl8367_read_phy_reg(struct rtl8366_smi *smi, ++ u32 phy_addr, u32 phy_reg, u32 *val) ++{ ++ int timeout; ++ u32 data; ++ int err; ++ ++ if (phy_addr > RTL8367_PHY_ADDR_MAX) ++ return -EINVAL; ++ ++ if (phy_reg > RTL8367_PHY_REG_MAX) ++ return -EINVAL; ++ ++ REG_RD(smi, RTL8367_IA_STATUS_REG, &data); ++ if (data & RTL8367_IA_STATUS_PHY_BUSY) ++ return -ETIMEDOUT; ++ ++ /* prepare address */ ++ REG_WR(smi, RTL8367_IA_ADDRESS_REG, ++ RTL8367_INTERNAL_PHY_REG(phy_addr, phy_reg)); ++ ++ /* send read command */ ++ REG_WR(smi, RTL8367_IA_CTRL_REG, ++ RTL8367_IA_CTRL_CMD_MASK | RTL8367_IA_CTRL_RW_READ); ++ ++ timeout = 5; ++ do { ++ REG_RD(smi, RTL8367_IA_STATUS_REG, &data); ++ if ((data & RTL8367_IA_STATUS_PHY_BUSY) == 0) ++ break; ++ ++ if (timeout--) { ++ dev_err(smi->parent, "phy read timed out\n"); ++ return -ETIMEDOUT; ++ } ++ ++ udelay(1); ++ } while (1); ++ ++ /* read data */ ++ REG_RD(smi, RTL8367_IA_READ_DATA_REG, val); ++ ++ dev_dbg(smi->parent, "phy_read: addr:%02x, reg:%02x, val:%04x\n", ++ phy_addr, phy_reg, *val); ++ return 0; ++} ++ ++static int rtl8367_write_phy_reg(struct rtl8366_smi *smi, ++ u32 phy_addr, u32 phy_reg, u32 val) ++{ ++ int timeout; ++ u32 data; ++ int err; ++ ++ dev_dbg(smi->parent, "phy_write: addr:%02x, reg:%02x, val:%04x\n", ++ phy_addr, phy_reg, val); ++ ++ if (phy_addr > RTL8367_PHY_ADDR_MAX) ++ return -EINVAL; ++ ++ if (phy_reg > RTL8367_PHY_REG_MAX) ++ return -EINVAL; ++ ++ REG_RD(smi, RTL8367_IA_STATUS_REG, &data); ++ if (data & RTL8367_IA_STATUS_PHY_BUSY) ++ return -ETIMEDOUT; ++ ++ /* preapre data */ ++ REG_WR(smi, RTL8367_IA_WRITE_DATA_REG, val); ++ ++ /* prepare address */ ++ REG_WR(smi, RTL8367_IA_ADDRESS_REG, ++ RTL8367_INTERNAL_PHY_REG(phy_addr, phy_reg)); ++ ++ /* send write command */ ++ REG_WR(smi, RTL8367_IA_CTRL_REG, ++ RTL8367_IA_CTRL_CMD_MASK | RTL8367_IA_CTRL_RW_WRITE); ++ ++ timeout = 5; ++ do { ++ REG_RD(smi, RTL8367_IA_STATUS_REG, &data); ++ if ((data & RTL8367_IA_STATUS_PHY_BUSY) == 0) ++ break; ++ ++ if (timeout--) { ++ dev_err(smi->parent, "phy write timed out\n"); ++ return -ETIMEDOUT; ++ } ++ ++ udelay(1); ++ } while (1); ++ ++ return 0; ++} ++ ++static int rtl8367_init_regs0(struct rtl8366_smi *smi, unsigned mode) ++{ ++ const struct rtl8367_initval *initvals; ++ int count; ++ int err; ++ ++ switch (mode) { ++ case 0: ++ initvals = rtl8367_initvals_0_0; ++ count = ARRAY_SIZE(rtl8367_initvals_0_0); ++ break; ++ ++ case 1: ++ case 2: ++ initvals = rtl8367_initvals_0_1; ++ count = ARRAY_SIZE(rtl8367_initvals_0_1); ++ break; ++ ++ default: ++ dev_err(smi->parent, "%s: unknow mode %u\n", __func__, mode); ++ return -ENODEV; ++ } ++ ++ err = rtl8367_write_initvals(smi, initvals, count); ++ if (err) ++ return err; ++ ++ /* TODO: complete this */ ++ ++ return 0; ++} ++ ++static int rtl8367_init_regs1(struct rtl8366_smi *smi, unsigned mode) ++{ ++ const struct rtl8367_initval *initvals; ++ int count; ++ ++ switch (mode) { ++ case 0: ++ initvals = rtl8367_initvals_1_0; ++ count = ARRAY_SIZE(rtl8367_initvals_1_0); ++ break; ++ ++ case 1: ++ case 2: ++ initvals = rtl8367_initvals_1_1; ++ count = ARRAY_SIZE(rtl8367_initvals_1_1); ++ break; ++ ++ default: ++ dev_err(smi->parent, "%s: unknow mode %u\n", __func__, mode); ++ return -ENODEV; ++ } ++ ++ return rtl8367_write_initvals(smi, initvals, count); ++} ++ ++static int rtl8367_init_regs2(struct rtl8366_smi *smi, unsigned mode) ++{ ++ const struct rtl8367_initval *initvals; ++ int count; ++ ++ switch (mode) { ++ case 0: ++ initvals = rtl8367_initvals_2_0; ++ count = ARRAY_SIZE(rtl8367_initvals_2_0); ++ break; ++ ++ case 1: ++ case 2: ++ initvals = rtl8367_initvals_2_1; ++ count = ARRAY_SIZE(rtl8367_initvals_2_1); ++ break; ++ ++ default: ++ dev_err(smi->parent, "%s: unknow mode %u\n", __func__, mode); ++ return -ENODEV; ++ } ++ ++ return rtl8367_write_initvals(smi, initvals, count); ++} ++ ++static int rtl8367_init_regs(struct rtl8366_smi *smi) ++{ ++ u32 data; ++ u32 rlvid; ++ u32 mode; ++ int err; ++ ++ REG_WR(smi, RTL8367_RTL_MAGIC_ID_REG, RTL8367_RTL_MAGIC_ID_VAL); ++ ++ REG_RD(smi, RTL8367_CHIP_VER_REG, &data); ++ rlvid = (data >> RTL8367_CHIP_VER_RLVID_SHIFT) & ++ RTL8367_CHIP_VER_RLVID_MASK; ++ ++ REG_RD(smi, RTL8367_CHIP_MODE_REG, &data); ++ mode = data & RTL8367_CHIP_MODE_MASK; ++ ++ switch (rlvid) { ++ case 0: ++ err = rtl8367_init_regs0(smi, mode); ++ break; ++ ++ case 1: ++ err = rtl8367_write_phy_reg(smi, 0, 31, 5); ++ if (err) ++ break; ++ ++ err = rtl8367_write_phy_reg(smi, 0, 5, 0x3ffe); ++ if (err) ++ break; ++ ++ err = rtl8367_read_phy_reg(smi, 0, 6, &data); ++ if (err) ++ break; ++ ++ if (data == 0x94eb) { ++ err = rtl8367_init_regs1(smi, mode); ++ } else if (data == 0x2104) { ++ err = rtl8367_init_regs2(smi, mode); ++ } else { ++ dev_err(smi->parent, "unknow phy data %04x\n", data); ++ return -ENODEV; ++ } ++ ++ break; ++ ++ default: ++ dev_err(smi->parent, "unknow rlvid %u\n", rlvid); ++ err = -ENODEV; ++ break; ++ } ++ ++ return err; ++} ++ ++static int rtl8367_reset_chip(struct rtl8366_smi *smi) ++{ ++ int timeout = 10; ++ int err; ++ u32 data; ++ ++ REG_WR(smi, RTL8367_CHIP_RESET_REG, RTL8367_CHIP_RESET_HW); ++ msleep(RTL8367_RESET_DELAY); ++ ++ do { ++ REG_RD(smi, RTL8367_CHIP_RESET_REG, &data); ++ if (!(data & RTL8367_CHIP_RESET_HW)) ++ break; ++ ++ msleep(1); ++ } while (--timeout); ++ ++ if (!timeout) { ++ dev_err(smi->parent, "chip reset timed out\n"); ++ return -ETIMEDOUT; ++ } ++ ++ return 0; ++} ++ ++static int rtl8367_extif_set_mode(struct rtl8366_smi *smi, int id, ++ enum rtl8367_extif_mode mode) ++{ ++ int err; ++ ++ /* set port mode */ ++ switch (mode) { ++ case RTL8367_EXTIF_MODE_RGMII: ++ case RTL8367_EXTIF_MODE_RGMII_33V: ++ REG_WR(smi, RTL8367_CHIP_DEBUG0_REG, 0x0367); ++ REG_WR(smi, RTL8367_CHIP_DEBUG1_REG, 0x7777); ++ break; ++ ++ case RTL8367_EXTIF_MODE_TMII_MAC: ++ case RTL8367_EXTIF_MODE_TMII_PHY: ++ REG_RMW(smi, RTL8367_BYPASS_LINE_RATE_REG, ++ BIT((id + 1) % 2), BIT((id + 1) % 2)); ++ break; ++ ++ case RTL8367_EXTIF_MODE_GMII: ++ REG_RMW(smi, RTL8367_CHIP_DEBUG0_REG, ++ RTL8367_CHIP_DEBUG0_DUMMY0(id), ++ RTL8367_CHIP_DEBUG0_DUMMY0(id)); ++ REG_RMW(smi, RTL8367_EXT_RGMXF_REG(id), BIT(6), BIT(6)); ++ break; ++ ++ case RTL8367_EXTIF_MODE_MII_MAC: ++ case RTL8367_EXTIF_MODE_MII_PHY: ++ case RTL8367_EXTIF_MODE_DISABLED: ++ REG_RMW(smi, RTL8367_BYPASS_LINE_RATE_REG, ++ BIT((id + 1) % 2), 0); ++ REG_RMW(smi, RTL8367_EXT_RGMXF_REG(id), BIT(6), 0); ++ break; ++ ++ default: ++ dev_err(smi->parent, ++ "invalid mode for external interface %d\n", id); ++ return -EINVAL; ++ } ++ ++ REG_RMW(smi, RTL8367_DIS_REG, ++ RTL8367_DIS_RGMII_MASK << RTL8367_DIS_RGMII_SHIFT(id), ++ mode << RTL8367_DIS_RGMII_SHIFT(id)); ++ ++ return 0; ++} ++ ++static int rtl8367_extif_set_force(struct rtl8366_smi *smi, int id, ++ struct rtl8367_port_ability *pa) ++{ ++ u32 mask; ++ u32 val; ++ int err; ++ ++ mask = (RTL8367_DI_FORCE_MODE | ++ RTL8367_DI_FORCE_NWAY | ++ RTL8367_DI_FORCE_TXPAUSE | ++ RTL8367_DI_FORCE_RXPAUSE | ++ RTL8367_DI_FORCE_LINK | ++ RTL8367_DI_FORCE_DUPLEX | ++ RTL8367_DI_FORCE_SPEED_MASK); ++ ++ val = pa->speed; ++ val |= pa->force_mode ? RTL8367_DI_FORCE_MODE : 0; ++ val |= pa->nway ? RTL8367_DI_FORCE_NWAY : 0; ++ val |= pa->txpause ? RTL8367_DI_FORCE_TXPAUSE : 0; ++ val |= pa->rxpause ? RTL8367_DI_FORCE_RXPAUSE : 0; ++ val |= pa->link ? RTL8367_DI_FORCE_LINK : 0; ++ val |= pa->duplex ? RTL8367_DI_FORCE_DUPLEX : 0; ++ ++ REG_RMW(smi, RTL8367_DI_FORCE_REG(id), mask, val); ++ ++ return 0; ++} ++ ++static int rtl8367_extif_set_rgmii_delay(struct rtl8366_smi *smi, int id, ++ unsigned txdelay, unsigned rxdelay) ++{ ++ u32 mask; ++ u32 val; ++ int err; ++ ++ mask = (RTL8367_EXT_RGMXF_RXDELAY_MASK | ++ (RTL8367_EXT_RGMXF_TXDELAY_MASK << ++ RTL8367_EXT_RGMXF_TXDELAY_SHIFT)); ++ ++ val = rxdelay; ++ val |= txdelay << RTL8367_EXT_RGMXF_TXDELAY_SHIFT; ++ ++ REG_RMW(smi, RTL8367_EXT_RGMXF_REG(id), mask, val); ++ ++ return 0; ++} ++ ++static int rtl8367_extif_init(struct rtl8366_smi *smi, int id, ++ struct rtl8367_extif_config *cfg) ++{ ++ enum rtl8367_extif_mode mode; ++ int err; ++ ++ mode = (cfg) ? cfg->mode : RTL8367_EXTIF_MODE_DISABLED; ++ ++ err = rtl8367_extif_set_mode(smi, id, mode); ++ if (err) ++ return err; ++ ++ if (mode != RTL8367_EXTIF_MODE_DISABLED) { ++ err = rtl8367_extif_set_force(smi, id, &cfg->ability); ++ if (err) ++ return err; ++ ++ err = rtl8367_extif_set_rgmii_delay(smi, id, cfg->txdelay, ++ cfg->rxdelay); ++ if (err) ++ return err; ++ } ++ ++ return 0; ++} ++ ++static int rtl8367_led_group_set_ports(struct rtl8366_smi *smi, ++ unsigned int group, u16 port_mask) ++{ ++ u32 reg; ++ u32 s; ++ int err; ++ ++ port_mask &= RTL8367_PARA_LED_IO_EN_PMASK; ++ s = (group % 2) * 8; ++ reg = RTL8367_PARA_LED_IO_EN1_REG + (group / 2); ++ ++ REG_RMW(smi, reg, (RTL8367_PARA_LED_IO_EN_PMASK << s), port_mask << s); ++ ++ return 0; ++} ++ ++static int rtl8367_led_group_set_mode(struct rtl8366_smi *smi, ++ unsigned int mode) ++{ ++ u16 mask; ++ u16 set; ++ int err; ++ ++ mode &= RTL8367_LED_CONFIG_DATA_M; ++ ++ mask = (RTL8367_LED_CONFIG_DATA_M << RTL8367_LED_CONFIG_DATA_S) | ++ RTL8367_LED_CONFIG_SEL; ++ set = (mode << RTL8367_LED_CONFIG_DATA_S) | RTL8367_LED_CONFIG_SEL; ++ ++ REG_RMW(smi, RTL8367_LED_CONFIG_REG, mask, set); ++ ++ return 0; ++} ++ ++static int rtl8367_led_group_set_config(struct rtl8366_smi *smi, ++ unsigned int led, unsigned int cfg) ++{ ++ u16 mask; ++ u16 set; ++ int err; ++ ++ mask = (RTL8367_LED_CONFIG_LED_CFG_M << (led * 4)) | ++ RTL8367_LED_CONFIG_SEL; ++ set = (cfg & RTL8367_LED_CONFIG_LED_CFG_M) << (led * 4); ++ ++ REG_RMW(smi, RTL8367_LED_CONFIG_REG, mask, set); ++ return 0; ++} ++ ++static int rtl8367_led_op_select_parallel(struct rtl8366_smi *smi) ++{ ++ int err; ++ ++ REG_WR(smi, RTL8367_LED_SYS_CONFIG_REG, 0x1472); ++ return 0; ++} ++ ++static int rtl8367_led_blinkrate_set(struct rtl8366_smi *smi, unsigned int rate) ++{ ++ u16 mask; ++ u16 set; ++ int err; ++ ++ mask = RTL8367_LED_MODE_RATE_M << RTL8367_LED_MODE_RATE_S; ++ set = (rate & RTL8367_LED_MODE_RATE_M) << RTL8367_LED_MODE_RATE_S; ++ REG_RMW(smi, RTL8367_LED_MODE_REG, mask, set); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_OF ++static int rtl8367_extif_init_of(struct rtl8366_smi *smi, ++ const char *name) ++{ ++ struct rtl8367_extif_config *cfg; ++ const __be32 *prop; ++ int size; ++ int err; ++ unsigned cpu_port; ++ unsigned id = UINT_MAX; ++ ++ prop = of_get_property(smi->parent->of_node, name, &size); ++ if (!prop || (size != (10 * sizeof(*prop)))) { ++ dev_err(smi->parent, "%s property is not defined or invalid\n", name); ++ err = -EINVAL; ++ goto err_init; ++ } ++ ++ cpu_port = be32_to_cpup(prop++); ++ switch (cpu_port) { ++ case RTL8367_CPU_PORT_NUM - 1: ++ case RTL8367_CPU_PORT_NUM: ++ id = RTL8367_CPU_PORT_NUM - cpu_port; ++ if (smi->cpu_port == UINT_MAX) { ++ dev_info(smi->parent, "cpu_port:%u, assigned to extif%u\n", cpu_port, id); ++ smi->cpu_port = cpu_port; ++ } ++ break; ++ default: ++ dev_err(smi->parent, "wrong cpu_port %u in %s property\n", cpu_port, name); ++ err = -EINVAL; ++ goto err_init; ++ } ++ ++ cfg = kzalloc(sizeof(struct rtl8367_extif_config), GFP_KERNEL); ++ if (!cfg) ++ return -ENOMEM; ++ ++ cfg->txdelay = be32_to_cpup(prop++); ++ cfg->rxdelay = be32_to_cpup(prop++); ++ cfg->mode = be32_to_cpup(prop++); ++ cfg->ability.force_mode = be32_to_cpup(prop++); ++ cfg->ability.txpause = be32_to_cpup(prop++); ++ cfg->ability.rxpause = be32_to_cpup(prop++); ++ cfg->ability.link = be32_to_cpup(prop++); ++ cfg->ability.duplex = be32_to_cpup(prop++); ++ cfg->ability.speed = be32_to_cpup(prop++); ++ ++ err = rtl8367_extif_init(smi, id, cfg); ++ kfree(cfg); ++ ++err_init: ++ if (id != 0) rtl8367_extif_init(smi, 0, NULL); ++ if (id != 1) rtl8367_extif_init(smi, 1, NULL); ++ ++ return err; ++} ++#else ++static int rtl8367_extif_init_of(struct rtl8366_smi *smi, ++ const char *name) ++{ ++ return -EINVAL; ++} ++#endif ++ ++static int rtl8367_setup(struct rtl8366_smi *smi) ++{ ++ struct rtl8367_platform_data *pdata; ++ int err; ++ int i; ++ ++ pdata = smi->parent->platform_data; ++ ++ err = rtl8367_init_regs(smi); ++ if (err) ++ return err; ++ ++ /* initialize external interfaces */ ++ if (smi->parent->of_node) { ++ err = rtl8367_extif_init_of(smi, "realtek,extif"); ++ if (err) ++ return err; ++ } else { ++ err = rtl8367_extif_init(smi, 0, pdata->extif0_cfg); ++ if (err) ++ return err; ++ ++ err = rtl8367_extif_init(smi, 1, pdata->extif1_cfg); ++ if (err) ++ return err; ++ } ++ ++ /* set maximum packet length to 1536 bytes */ ++ REG_RMW(smi, RTL8367_SWC0_REG, RTL8367_SWC0_MAX_LENGTH_MASK, ++ RTL8367_SWC0_MAX_LENGTH_1536); ++ ++ /* ++ * discard VLAN tagged packets if the port is not a member of ++ * the VLAN with which the packets is associated. ++ */ ++ REG_WR(smi, RTL8367_VLAN_INGRESS_REG, RTL8367_PORTS_ALL); ++ ++ /* ++ * Setup egress tag mode for each port. ++ */ ++ for (i = 0; i < RTL8367_NUM_PORTS; i++) ++ REG_RMW(smi, ++ RTL8367_PORT_CFG_REG(i), ++ RTL8367_PORT_CFG_EGRESS_MODE_MASK << ++ RTL8367_PORT_CFG_EGRESS_MODE_SHIFT, ++ RTL8367_PORT_CFG_EGRESS_MODE_ORIGINAL << ++ RTL8367_PORT_CFG_EGRESS_MODE_SHIFT); ++ ++ /* setup LEDs */ ++ err = rtl8367_led_group_set_ports(smi, 0, RTL8367_PORTS_ALL); ++ if (err) ++ return err; ++ ++ err = rtl8367_led_group_set_mode(smi, 0); ++ if (err) ++ return err; ++ ++ err = rtl8367_led_op_select_parallel(smi); ++ if (err) ++ return err; ++ ++ err = rtl8367_led_blinkrate_set(smi, 1); ++ if (err) ++ return err; ++ ++ err = rtl8367_led_group_set_config(smi, 0, 2); ++ if (err) ++ return err; ++ ++ return 0; ++} ++ ++static int rtl8367_get_mib_counter(struct rtl8366_smi *smi, int counter, ++ int port, unsigned long long *val) ++{ ++ struct rtl8366_mib_counter *mib; ++ int offset; ++ int i; ++ int err; ++ u32 addr, data; ++ u64 mibvalue; ++ ++ if (port > RTL8367_NUM_PORTS || counter >= RTL8367_MIB_COUNT) ++ return -EINVAL; ++ ++ mib = &rtl8367_mib_counters[counter]; ++ addr = RTL8367_MIB_COUNTER_PORT_OFFSET * port + mib->offset; ++ ++ /* ++ * Writing access counter address first ++ * then ASIC will prepare 64bits counter wait for being retrived ++ */ ++ REG_WR(smi, RTL8367_MIB_ADDRESS_REG, addr >> 2); ++ ++ /* read MIB control register */ ++ REG_RD(smi, RTL8367_MIB_CTRL_REG(0), &data); ++ ++ if (data & RTL8367_MIB_CTRL_BUSY_MASK) ++ return -EBUSY; ++ ++ if (data & RTL8367_MIB_CTRL_RESET_MASK) ++ return -EIO; ++ ++ if (mib->length == 4) ++ offset = 3; ++ else ++ offset = (mib->offset + 1) % 4; ++ ++ mibvalue = 0; ++ for (i = 0; i < mib->length; i++) { ++ REG_RD(smi, RTL8367_MIB_COUNTER_REG(offset - i), &data); ++ mibvalue = (mibvalue << 16) | (data & 0xFFFF); ++ } ++ ++ *val = mibvalue; ++ return 0; ++} ++ ++static int rtl8367_get_vlan_4k(struct rtl8366_smi *smi, u32 vid, ++ struct rtl8366_vlan_4k *vlan4k) ++{ ++ u32 data[RTL8367_TA_VLAN_DATA_SIZE]; ++ int err; ++ int i; ++ ++ memset(vlan4k, '\0', sizeof(struct rtl8366_vlan_4k)); ++ ++ if (vid >= RTL8367_NUM_VIDS) ++ return -EINVAL; ++ ++ /* write VID */ ++ REG_WR(smi, RTL8367_TA_ADDR_REG, vid); ++ ++ /* write table access control word */ ++ REG_WR(smi, RTL8367_TA_CTRL_REG, RTL8367_TA_CTRL_CVLAN_READ); ++ ++ for (i = 0; i < ARRAY_SIZE(data); i++) ++ REG_RD(smi, RTL8367_TA_DATA_REG(i), &data[i]); ++ ++ vlan4k->vid = vid; ++ vlan4k->member = (data[0] >> RTL8367_TA_VLAN_MEMBER_SHIFT) & ++ RTL8367_TA_VLAN_MEMBER_MASK; ++ vlan4k->fid = (data[1] >> RTL8367_TA_VLAN_FID_SHIFT) & ++ RTL8367_TA_VLAN_FID_MASK; ++ vlan4k->untag = (data[2] >> RTL8367_TA_VLAN_UNTAG1_SHIFT) & ++ RTL8367_TA_VLAN_UNTAG1_MASK; ++ vlan4k->untag |= ((data[3] >> RTL8367_TA_VLAN_UNTAG2_SHIFT) & ++ RTL8367_TA_VLAN_UNTAG2_MASK) << 2; ++ ++ return 0; ++} ++ ++static int rtl8367_set_vlan_4k(struct rtl8366_smi *smi, ++ const struct rtl8366_vlan_4k *vlan4k) ++{ ++ u32 data[RTL8367_TA_VLAN_DATA_SIZE]; ++ int err; ++ int i; ++ ++ if (vlan4k->vid >= RTL8367_NUM_VIDS || ++ vlan4k->member > RTL8367_TA_VLAN_MEMBER_MASK || ++ vlan4k->untag > RTL8367_UNTAG_MASK || ++ vlan4k->fid > RTL8367_FIDMAX) ++ return -EINVAL; ++ ++ data[0] = (vlan4k->member & RTL8367_TA_VLAN_MEMBER_MASK) << ++ RTL8367_TA_VLAN_MEMBER_SHIFT; ++ data[1] = (vlan4k->fid & RTL8367_TA_VLAN_FID_MASK) << ++ RTL8367_TA_VLAN_FID_SHIFT; ++ data[2] = (vlan4k->untag & RTL8367_TA_VLAN_UNTAG1_MASK) << ++ RTL8367_TA_VLAN_UNTAG1_SHIFT; ++ data[3] = ((vlan4k->untag >> 2) & RTL8367_TA_VLAN_UNTAG2_MASK) << ++ RTL8367_TA_VLAN_UNTAG2_SHIFT; ++ ++ for (i = 0; i < ARRAY_SIZE(data); i++) ++ REG_WR(smi, RTL8367_TA_DATA_REG(i), data[i]); ++ ++ /* write VID */ ++ REG_WR(smi, RTL8367_TA_ADDR_REG, ++ vlan4k->vid & RTL8367_TA_VLAN_VID_MASK); ++ ++ /* write table access control word */ ++ REG_WR(smi, RTL8367_TA_CTRL_REG, RTL8367_TA_CTRL_CVLAN_WRITE); ++ ++ return 0; ++} ++ ++static int rtl8367_get_vlan_mc(struct rtl8366_smi *smi, u32 index, ++ struct rtl8366_vlan_mc *vlanmc) ++{ ++ u32 data[RTL8367_VLAN_MC_DATA_SIZE]; ++ int err; ++ int i; ++ ++ memset(vlanmc, '\0', sizeof(struct rtl8366_vlan_mc)); ++ ++ if (index >= RTL8367_NUM_VLANS) ++ return -EINVAL; ++ ++ for (i = 0; i < ARRAY_SIZE(data); i++) ++ REG_RD(smi, RTL8367_VLAN_MC_BASE(index) + i, &data[i]); ++ ++ vlanmc->member = (data[0] >> RTL8367_VLAN_MC_MEMBER_SHIFT) & ++ RTL8367_VLAN_MC_MEMBER_MASK; ++ vlanmc->fid = (data[1] >> RTL8367_VLAN_MC_FID_SHIFT) & ++ RTL8367_VLAN_MC_FID_MASK; ++ vlanmc->vid = (data[3] >> RTL8367_VLAN_MC_EVID_SHIFT) & ++ RTL8367_VLAN_MC_EVID_MASK; ++ ++ return 0; ++} ++ ++static int rtl8367_set_vlan_mc(struct rtl8366_smi *smi, u32 index, ++ const struct rtl8366_vlan_mc *vlanmc) ++{ ++ u32 data[RTL8367_VLAN_MC_DATA_SIZE]; ++ int err; ++ int i; ++ ++ if (index >= RTL8367_NUM_VLANS || ++ vlanmc->vid >= RTL8367_NUM_VIDS || ++ vlanmc->priority > RTL8367_PRIORITYMAX || ++ vlanmc->member > RTL8367_VLAN_MC_MEMBER_MASK || ++ vlanmc->untag > RTL8367_UNTAG_MASK || ++ vlanmc->fid > RTL8367_FIDMAX) ++ return -EINVAL; ++ ++ data[0] = (vlanmc->member & RTL8367_VLAN_MC_MEMBER_MASK) << ++ RTL8367_VLAN_MC_MEMBER_SHIFT; ++ data[1] = (vlanmc->fid & RTL8367_VLAN_MC_FID_MASK) << ++ RTL8367_VLAN_MC_FID_SHIFT; ++ data[2] = 0; ++ data[3] = (vlanmc->vid & RTL8367_VLAN_MC_EVID_MASK) << ++ RTL8367_VLAN_MC_EVID_SHIFT; ++ ++ for (i = 0; i < ARRAY_SIZE(data); i++) ++ REG_WR(smi, RTL8367_VLAN_MC_BASE(index) + i, data[i]); ++ ++ return 0; ++} ++ ++static int rtl8367_get_mc_index(struct rtl8366_smi *smi, int port, int *val) ++{ ++ u32 data; ++ int err; ++ ++ if (port >= RTL8367_NUM_PORTS) ++ return -EINVAL; ++ ++ REG_RD(smi, RTL8367_VLAN_PVID_CTRL_REG(port), &data); ++ ++ *val = (data >> RTL8367_VLAN_PVID_CTRL_SHIFT(port)) & ++ RTL8367_VLAN_PVID_CTRL_MASK; ++ ++ return 0; ++} ++ ++static int rtl8367_set_mc_index(struct rtl8366_smi *smi, int port, int index) ++{ ++ if (port >= RTL8367_NUM_PORTS || index >= RTL8367_NUM_VLANS) ++ return -EINVAL; ++ ++ return rtl8366_smi_rmwr(smi, RTL8367_VLAN_PVID_CTRL_REG(port), ++ RTL8367_VLAN_PVID_CTRL_MASK << ++ RTL8367_VLAN_PVID_CTRL_SHIFT(port), ++ (index & RTL8367_VLAN_PVID_CTRL_MASK) << ++ RTL8367_VLAN_PVID_CTRL_SHIFT(port)); ++} ++ ++static int rtl8367_enable_vlan(struct rtl8366_smi *smi, int enable) ++{ ++ return rtl8366_smi_rmwr(smi, RTL8367_VLAN_CTRL_REG, ++ RTL8367_VLAN_CTRL_ENABLE, ++ (enable) ? RTL8367_VLAN_CTRL_ENABLE : 0); ++} ++ ++static int rtl8367_enable_vlan4k(struct rtl8366_smi *smi, int enable) ++{ ++ return 0; ++} ++ ++static int rtl8367_is_vlan_valid(struct rtl8366_smi *smi, unsigned vlan) ++{ ++ unsigned max = RTL8367_NUM_VLANS; ++ ++ if (smi->vlan4k_enabled) ++ max = RTL8367_NUM_VIDS - 1; ++ ++ if (vlan == 0 || vlan >= max) ++ return 0; ++ ++ return 1; ++} ++ ++static int rtl8367_enable_port(struct rtl8366_smi *smi, int port, int enable) ++{ ++ int err; ++ ++ REG_WR(smi, RTL8367_PORT_ISOLATION_REG(port), ++ (enable) ? RTL8367_PORTS_ALL : 0); ++ ++ return 0; ++} ++ ++static int rtl8367_sw_reset_mibs(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ ++ return rtl8366_smi_rmwr(smi, RTL8367_MIB_CTRL_REG(0), 0, ++ RTL8367_MIB_CTRL_GLOBAL_RESET_MASK); ++} ++ ++static int rtl8367_sw_get_port_link(struct switch_dev *dev, ++ int port, ++ struct switch_port_link *link) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ u32 data = 0; ++ u32 speed; ++ ++ if (port >= RTL8367_NUM_PORTS) ++ return -EINVAL; ++ ++ rtl8366_smi_read_reg(smi, RTL8367_PORT_STATUS_REG(port), &data); ++ ++ link->link = !!(data & RTL8367_PORT_STATUS_LINK); ++ if (!link->link) ++ return 0; ++ ++ link->duplex = !!(data & RTL8367_PORT_STATUS_DUPLEX); ++ link->rx_flow = !!(data & RTL8367_PORT_STATUS_RXPAUSE); ++ link->tx_flow = !!(data & RTL8367_PORT_STATUS_TXPAUSE); ++ link->aneg = !!(data & RTL8367_PORT_STATUS_NWAY); ++ ++ speed = (data & RTL8367_PORT_STATUS_SPEED_MASK); ++ switch (speed) { ++ case 0: ++ link->speed = SWITCH_PORT_SPEED_10; ++ break; ++ case 1: ++ link->speed = SWITCH_PORT_SPEED_100; ++ break; ++ case 2: ++ link->speed = SWITCH_PORT_SPEED_1000; ++ break; ++ default: ++ link->speed = SWITCH_PORT_SPEED_UNKNOWN; ++ break; ++ } ++ ++ return 0; ++} ++ ++static int rtl8367_sw_get_max_length(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ u32 data; ++ ++ rtl8366_smi_read_reg(smi, RTL8367_SWC0_REG, &data); ++ val->value.i = (data & RTL8367_SWC0_MAX_LENGTH_MASK) >> ++ RTL8367_SWC0_MAX_LENGTH_SHIFT; ++ ++ return 0; ++} ++ ++static int rtl8367_sw_set_max_length(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ u32 max_len; ++ ++ switch (val->value.i) { ++ case 0: ++ max_len = RTL8367_SWC0_MAX_LENGTH_1522; ++ break; ++ case 1: ++ max_len = RTL8367_SWC0_MAX_LENGTH_1536; ++ break; ++ case 2: ++ max_len = RTL8367_SWC0_MAX_LENGTH_1552; ++ break; ++ case 3: ++ max_len = RTL8367_SWC0_MAX_LENGTH_16000; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return rtl8366_smi_rmwr(smi, RTL8367_SWC0_REG, ++ RTL8367_SWC0_MAX_LENGTH_MASK, max_len); ++} ++ ++ ++static int rtl8367_sw_reset_port_mibs(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ int port; ++ ++ port = val->port_vlan; ++ if (port >= RTL8367_NUM_PORTS) ++ return -EINVAL; ++ ++ return rtl8366_smi_rmwr(smi, RTL8367_MIB_CTRL_REG(port / 8), 0, ++ RTL8367_MIB_CTRL_PORT_RESET_MASK(port % 8)); ++} ++ ++static int rtl8367_sw_get_port_stats(struct switch_dev *dev, int port, ++ struct switch_port_stats *stats) ++{ ++ return (rtl8366_sw_get_port_stats(dev, port, stats, ++ RTL8367_MIB_TXB_ID, RTL8367_MIB_RXB_ID)); ++} ++ ++static struct switch_attr rtl8367_globals[] = { ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "enable_vlan", ++ .description = "Enable VLAN mode", ++ .set = rtl8366_sw_set_vlan_enable, ++ .get = rtl8366_sw_get_vlan_enable, ++ .max = 1, ++ .ofs = 1 ++ }, { ++ .type = SWITCH_TYPE_INT, ++ .name = "enable_vlan4k", ++ .description = "Enable VLAN 4K mode", ++ .set = rtl8366_sw_set_vlan_enable, ++ .get = rtl8366_sw_get_vlan_enable, ++ .max = 1, ++ .ofs = 2 ++ }, { ++ .type = SWITCH_TYPE_NOVAL, ++ .name = "reset_mibs", ++ .description = "Reset all MIB counters", ++ .set = rtl8367_sw_reset_mibs, ++ }, { ++ .type = SWITCH_TYPE_INT, ++ .name = "max_length", ++ .description = "Get/Set the maximum length of valid packets" ++ "(0:1522, 1:1536, 2:1552, 3:16000)", ++ .set = rtl8367_sw_set_max_length, ++ .get = rtl8367_sw_get_max_length, ++ .max = 3, ++ } ++}; ++ ++static struct switch_attr rtl8367_port[] = { ++ { ++ .type = SWITCH_TYPE_NOVAL, ++ .name = "reset_mib", ++ .description = "Reset single port MIB counters", ++ .set = rtl8367_sw_reset_port_mibs, ++ }, { ++ .type = SWITCH_TYPE_STRING, ++ .name = "mib", ++ .description = "Get MIB counters for port", ++ .max = 33, ++ .set = NULL, ++ .get = rtl8366_sw_get_port_mib, ++ }, ++}; ++ ++static struct switch_attr rtl8367_vlan[] = { ++ { ++ .type = SWITCH_TYPE_STRING, ++ .name = "info", ++ .description = "Get vlan information", ++ .max = 1, ++ .set = NULL, ++ .get = rtl8366_sw_get_vlan_info, ++ }, { ++ .type = SWITCH_TYPE_INT, ++ .name = "fid", ++ .description = "Get/Set vlan FID", ++ .max = RTL8367_FIDMAX, ++ .set = rtl8366_sw_set_vlan_fid, ++ .get = rtl8366_sw_get_vlan_fid, ++ }, ++}; ++ ++static const struct switch_dev_ops rtl8367_sw_ops = { ++ .attr_global = { ++ .attr = rtl8367_globals, ++ .n_attr = ARRAY_SIZE(rtl8367_globals), ++ }, ++ .attr_port = { ++ .attr = rtl8367_port, ++ .n_attr = ARRAY_SIZE(rtl8367_port), ++ }, ++ .attr_vlan = { ++ .attr = rtl8367_vlan, ++ .n_attr = ARRAY_SIZE(rtl8367_vlan), ++ }, ++ ++ .get_vlan_ports = rtl8366_sw_get_vlan_ports, ++ .set_vlan_ports = rtl8366_sw_set_vlan_ports, ++ .get_port_pvid = rtl8366_sw_get_port_pvid, ++ .set_port_pvid = rtl8366_sw_set_port_pvid, ++ .reset_switch = rtl8366_sw_reset_switch, ++ .get_port_link = rtl8367_sw_get_port_link, ++ .get_port_stats = rtl8367_sw_get_port_stats, ++}; ++ ++static int rtl8367_switch_init(struct rtl8366_smi *smi) ++{ ++ struct switch_dev *dev = &smi->sw_dev; ++ int err; ++ ++ dev->name = "RTL8367"; ++ dev->cpu_port = smi->cpu_port; ++ dev->ports = RTL8367_NUM_PORTS; ++ dev->vlans = RTL8367_NUM_VIDS; ++ dev->ops = &rtl8367_sw_ops; ++ dev->alias = dev_name(smi->parent); ++ ++ err = register_switch(dev, NULL); ++ if (err) ++ dev_err(smi->parent, "switch registration failed\n"); ++ ++ return err; ++} ++ ++static void rtl8367_switch_cleanup(struct rtl8366_smi *smi) ++{ ++ unregister_switch(&smi->sw_dev); ++} ++ ++static int rtl8367_mii_read(struct mii_bus *bus, int addr, int reg) ++{ ++ struct rtl8366_smi *smi = bus->priv; ++ u32 val = 0; ++ int err; ++ ++ err = rtl8367_read_phy_reg(smi, addr, reg, &val); ++ if (err) ++ return 0xffff; ++ ++ return val; ++} ++ ++static int rtl8367_mii_write(struct mii_bus *bus, int addr, int reg, u16 val) ++{ ++ struct rtl8366_smi *smi = bus->priv; ++ u32 t; ++ int err; ++ ++ err = rtl8367_write_phy_reg(smi, addr, reg, val); ++ if (err) ++ return err; ++ ++ /* flush write */ ++ (void) rtl8367_read_phy_reg(smi, addr, reg, &t); ++ ++ return err; ++} ++ ++static int rtl8367_detect(struct rtl8366_smi *smi) ++{ ++ u32 rtl_no = 0; ++ u32 rtl_ver = 0; ++ char *chip_name; ++ int ret; ++ ++ ret = rtl8366_smi_read_reg(smi, RTL8367_RTL_NO_REG, &rtl_no); ++ if (ret) { ++ dev_err(smi->parent, "unable to read chip number\n"); ++ return ret; ++ } ++ ++ switch (rtl_no) { ++ case RTL8367_RTL_NO_8367R: ++ chip_name = "8367R"; ++ break; ++ case RTL8367_RTL_NO_8367M: ++ chip_name = "8367M"; ++ break; ++ default: ++ dev_err(smi->parent, "unknown chip number (%04x)\n", rtl_no); ++ return -ENODEV; ++ } ++ ++ ret = rtl8366_smi_read_reg(smi, RTL8367_RTL_VER_REG, &rtl_ver); ++ if (ret) { ++ dev_err(smi->parent, "unable to read chip version\n"); ++ return ret; ++ } ++ ++ dev_info(smi->parent, "RTL%s ver. %u chip found\n", ++ chip_name, rtl_ver & RTL8367_RTL_VER_MASK); ++ ++ return 0; ++} ++ ++static struct rtl8366_smi_ops rtl8367_smi_ops = { ++ .detect = rtl8367_detect, ++ .reset_chip = rtl8367_reset_chip, ++ .setup = rtl8367_setup, ++ ++ .mii_read = rtl8367_mii_read, ++ .mii_write = rtl8367_mii_write, ++ ++ .get_vlan_mc = rtl8367_get_vlan_mc, ++ .set_vlan_mc = rtl8367_set_vlan_mc, ++ .get_vlan_4k = rtl8367_get_vlan_4k, ++ .set_vlan_4k = rtl8367_set_vlan_4k, ++ .get_mc_index = rtl8367_get_mc_index, ++ .set_mc_index = rtl8367_set_mc_index, ++ .get_mib_counter = rtl8367_get_mib_counter, ++ .is_vlan_valid = rtl8367_is_vlan_valid, ++ .enable_vlan = rtl8367_enable_vlan, ++ .enable_vlan4k = rtl8367_enable_vlan4k, ++ .enable_port = rtl8367_enable_port, ++}; ++ ++static int rtl8367_probe(struct platform_device *pdev) ++{ ++ struct rtl8366_smi *smi; ++ int err; ++ ++ smi = rtl8366_smi_probe(pdev); ++ if (IS_ERR(smi)) ++ return PTR_ERR(smi); ++ ++ smi->clk_delay = 1500; ++ smi->cmd_read = 0xb9; ++ smi->cmd_write = 0xb8; ++ smi->ops = &rtl8367_smi_ops; ++ smi->cpu_port = UINT_MAX; /* not defined yet */ ++ smi->num_ports = RTL8367_NUM_PORTS; ++ smi->num_vlan_mc = RTL8367_NUM_VLANS; ++ smi->mib_counters = rtl8367_mib_counters; ++ smi->num_mib_counters = ARRAY_SIZE(rtl8367_mib_counters); ++ ++ err = rtl8366_smi_init(smi); ++ if (err) ++ goto err_free_smi; ++ ++ platform_set_drvdata(pdev, smi); ++ ++ err = rtl8367_switch_init(smi); ++ if (err) ++ goto err_clear_drvdata; ++ ++ return 0; ++ ++ err_clear_drvdata: ++ platform_set_drvdata(pdev, NULL); ++ rtl8366_smi_cleanup(smi); ++ err_free_smi: ++ kfree(smi); ++ return err; ++} ++ ++static void rtl8367_remove(struct platform_device *pdev) ++{ ++ struct rtl8366_smi *smi = platform_get_drvdata(pdev); ++ ++ if (smi) { ++ rtl8367_switch_cleanup(smi); ++ platform_set_drvdata(pdev, NULL); ++ rtl8366_smi_cleanup(smi); ++ kfree(smi); ++ } ++} ++ ++static void rtl8367_shutdown(struct platform_device *pdev) ++{ ++ struct rtl8366_smi *smi = platform_get_drvdata(pdev); ++ ++ if (smi) ++ rtl8367_reset_chip(smi); ++} ++ ++#ifdef CONFIG_OF ++static const struct of_device_id rtl8367_match[] = { ++ { .compatible = "realtek,rtl8367" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, rtl8367_match); ++#endif ++ ++static struct platform_driver rtl8367_driver = { ++ .driver = { ++ .name = RTL8367_DRIVER_NAME, ++#ifdef CONFIG_OF ++ .of_match_table = of_match_ptr(rtl8367_match), ++#endif ++ }, ++ .probe = rtl8367_probe, ++ .remove_new = rtl8367_remove, ++ .shutdown = rtl8367_shutdown, ++}; ++ ++static int __init rtl8367_module_init(void) ++{ ++ return platform_driver_register(&rtl8367_driver); ++} ++module_init(rtl8367_module_init); ++ ++static void __exit rtl8367_module_exit(void) ++{ ++ platform_driver_unregister(&rtl8367_driver); ++} ++module_exit(rtl8367_module_exit); ++ ++MODULE_DESCRIPTION("Realtek RTL8367 ethernet switch driver"); ++MODULE_AUTHOR("Gabor Juhos "); ++MODULE_LICENSE("GPL v2"); ++MODULE_ALIAS("platform:" RTL8367_DRIVER_NAME); +diff --git a/drivers/net/phy/rtl8367b.c b/drivers/net/phy/rtl8367b.c +new file mode 100644 +index 000000000000..5adcf00f0cac +--- /dev/null ++++ b/drivers/net/phy/rtl8367b.c +@@ -0,0 +1,1649 @@ ++/* ++ * Platform driver for Realtek RTL8367B family chips, i.e. RTL8367RB and RTL8367R-VB ++ * extended with support for RTL8367C family chips, i.e. RTL8367RB-VB and RTL8367S ++ * extended with support for RTL8367D family chips, i.e. RTL8367S-VB ++ * ++ * Copyright (C) 2012 Gabor Juhos ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "rtl8366_smi.h" ++ ++#define RTL8367B_RESET_DELAY 1000 /* msecs*/ ++ ++#define RTL8367B_PHY_ADDR_MAX 8 ++#define RTL8367B_PHY_REG_MAX 31 ++ ++#define RTL8367B_VID_MASK 0x3fff ++#define RTL8367B_FID_MASK 0xf ++#define RTL8367B_UNTAG_MASK 0xff ++#define RTL8367B_MEMBER_MASK 0xff ++ ++#define RTL8367B_PORT_MISC_CFG_REG(_p) (0x000e + 0x20 * (_p)) ++#define RTL8367B_PORT_MISC_CFG_EGRESS_MODE_SHIFT 4 ++#define RTL8367B_PORT_MISC_CFG_EGRESS_MODE_MASK 0x3 ++#define RTL8367B_PORT_MISC_CFG_EGRESS_MODE_ORIGINAL 0 ++#define RTL8367B_PORT_MISC_CFG_EGRESS_MODE_KEEP 1 ++#define RTL8367B_PORT_MISC_CFG_EGRESS_MODE_PRI 2 ++#define RTL8367B_PORT_MISC_CFG_EGRESS_MODE_REAL 3 ++ ++#define RTL8367B_BYPASS_LINE_RATE_REG 0x03f7 ++ ++#define RTL8367B_TA_CTRL_REG 0x0500 /*GOOD*/ ++#define RTL8367B_TA_CTRL_SPA_SHIFT 8 ++#define RTL8367B_TA_CTRL_SPA_MASK 0x7 ++#define RTL8367B_TA_CTRL_METHOD BIT(4)/*GOOD*/ ++#define RTL8367B_TA_CTRL_CMD_SHIFT 3 ++#define RTL8367B_TA_CTRL_CMD_READ 0 ++#define RTL8367B_TA_CTRL_CMD_WRITE 1 ++#define RTL8367B_TA_CTRL_TABLE_SHIFT 0 /*GOOD*/ ++#define RTL8367B_TA_CTRL_TABLE_ACLRULE 1 ++#define RTL8367B_TA_CTRL_TABLE_ACLACT 2 ++#define RTL8367B_TA_CTRL_TABLE_CVLAN 3 ++#define RTL8367B_TA_CTRL_TABLE_L2 4 ++#define RTL8367B_TA_CTRL_CVLAN_READ \ ++ ((RTL8367B_TA_CTRL_CMD_READ << RTL8367B_TA_CTRL_CMD_SHIFT) | \ ++ RTL8367B_TA_CTRL_TABLE_CVLAN) ++#define RTL8367B_TA_CTRL_CVLAN_WRITE \ ++ ((RTL8367B_TA_CTRL_CMD_WRITE << RTL8367B_TA_CTRL_CMD_SHIFT) | \ ++ RTL8367B_TA_CTRL_TABLE_CVLAN) ++ ++#define RTL8367B_TA_ADDR_REG 0x0501/*GOOD*/ ++#define RTL8367B_TA_ADDR_MASK 0x3fff/*GOOD*/ ++ ++#define RTL8367B_TA_LUT_REG 0x0502/*GOOD*/ ++ ++#define RTL8367B_TA_WRDATA_REG(_x) (0x0510 + (_x))/*GOOD*/ ++#define RTL8367B_TA_VLAN_NUM_WORDS 2 ++#define RTL8367B_TA_VLAN_VID_MASK RTL8367B_VID_MASK ++#define RTL8367B_TA_VLAN0_MEMBER_SHIFT 0 ++#define RTL8367B_TA_VLAN0_MEMBER_MASK RTL8367B_MEMBER_MASK ++#define RTL8367B_TA_VLAN0_UNTAG_SHIFT 8 ++#define RTL8367B_TA_VLAN0_UNTAG_MASK RTL8367B_MEMBER_MASK ++#define RTL8367B_TA_VLAN1_FID_SHIFT 0 ++#define RTL8367B_TA_VLAN1_FID_MASK RTL8367B_FID_MASK ++ ++#define RTL8367B_TA_RDDATA_REG(_x) (0x0520 + (_x))/*GOOD*/ ++ ++#define RTL8367B_VLAN_PVID_CTRL_REG(_p) (0x0700 + (_p) / 2) /*GOOD*/ ++#define RTL8367B_VLAN_PVID_CTRL_MASK 0x1f /*GOOD*/ ++#define RTL8367B_VLAN_PVID_CTRL_SHIFT(_p) (8 * ((_p) % 2)) /*GOOD*/ ++ ++#define RTL8367B_VLAN_MC_BASE(_x) (0x0728 + (_x) * 4) /*GOOD*/ ++#define RTL8367B_VLAN_MC_NUM_WORDS 4 /*GOOD*/ ++#define RTL8367B_VLAN_MC0_MEMBER_SHIFT 0/*GOOD*/ ++#define RTL8367B_VLAN_MC0_MEMBER_MASK RTL8367B_MEMBER_MASK/*GOOD*/ ++#define RTL8367B_VLAN_MC1_FID_SHIFT 0/*GOOD*/ ++#define RTL8367B_VLAN_MC1_FID_MASK RTL8367B_FID_MASK/*GOOD*/ ++#define RTL8367B_VLAN_MC3_EVID_SHIFT 0/*GOOD*/ ++#define RTL8367B_VLAN_MC3_EVID_MASK RTL8367B_VID_MASK/*GOOD*/ ++ ++#define RTL8367B_VLAN_CTRL_REG 0x07a8 /*GOOD*/ ++#define RTL8367B_VLAN_CTRL_ENABLE BIT(0) ++ ++#define RTL8367B_VLAN_INGRESS_REG 0x07a9 /*GOOD*/ ++ ++#define RTL8367B_PORT_ISOLATION_REG(_p) (0x08a2 + (_p)) /*GOOD*/ ++ ++#define RTL8367B_MIB_COUNTER_REG(_x) (0x1000 + (_x)) /*GOOD*/ ++#define RTL8367B_MIB_COUNTER_PORT_OFFSET 0x007c /*GOOD*/ ++ ++#define RTL8367B_MIB_ADDRESS_REG 0x1004 /*GOOD*/ ++ ++#define RTL8367B_MIB_CTRL0_REG(_x) (0x1005 + (_x)) /*GOOD*/ ++#define RTL8367B_MIB_CTRL0_GLOBAL_RESET_MASK BIT(11) /*GOOD*/ ++#define RTL8367B_MIB_CTRL0_QM_RESET_MASK BIT(10) /*GOOD*/ ++#define RTL8367B_MIB_CTRL0_PORT_RESET_MASK(_p) BIT(2 + (_p)) /*GOOD*/ ++#define RTL8367B_MIB_CTRL0_RESET_MASK BIT(1) /*GOOD*/ ++#define RTL8367B_MIB_CTRL0_BUSY_MASK BIT(0) /*GOOD*/ ++ ++#define RTL8367B_SWC0_REG 0x1200/*GOOD*/ ++#define RTL8367B_SWC0_MAX_LENGTH_SHIFT 13/*GOOD*/ ++#define RTL8367B_SWC0_MAX_LENGTH(_x) ((_x) << 13) /*GOOD*/ ++#define RTL8367B_SWC0_MAX_LENGTH_MASK RTL8367B_SWC0_MAX_LENGTH(0x3) ++#define RTL8367B_SWC0_MAX_LENGTH_1522 RTL8367B_SWC0_MAX_LENGTH(0) ++#define RTL8367B_SWC0_MAX_LENGTH_1536 RTL8367B_SWC0_MAX_LENGTH(1) ++#define RTL8367B_SWC0_MAX_LENGTH_1552 RTL8367B_SWC0_MAX_LENGTH(2) ++#define RTL8367B_SWC0_MAX_LENGTH_16000 RTL8367B_SWC0_MAX_LENGTH(3) ++ ++#define RTL8367B_CHIP_NUMBER_REG 0x1300/*GOOD*/ ++ ++#define RTL8367B_CHIP_VER_REG 0x1301/*GOOD*/ ++#define RTL8367B_CHIP_VER_RLVID_SHIFT 12/*GOOD*/ ++#define RTL8367B_CHIP_VER_RLVID_MASK 0xf/*GOOD*/ ++#define RTL8367B_CHIP_VER_MCID_SHIFT 8/*GOOD*/ ++#define RTL8367B_CHIP_VER_MCID_MASK 0xf/*GOOD*/ ++#define RTL8367B_CHIP_VER_BOID_SHIFT 4/*GOOD*/ ++#define RTL8367B_CHIP_VER_BOID_MASK 0xf/*GOOD*/ ++#define RTL8367B_CHIP_VER_AFE_SHIFT 0/*GOOD*/ ++#define RTL8367B_CHIP_VER_AFE_MASK 0x1/*GOOD*/ ++ ++#define RTL8367B_CHIP_MODE_REG 0x1302 ++#define RTL8367B_CHIP_MODE_MASK 0x7 ++ ++#define RTL8367B_CHIP_DEBUG0_REG 0x1303 ++#define RTL8367B_DEBUG0_SEL33(_x) BIT(8 + (_x)) ++#define RTL8367B_DEBUG0_DRI_OTHER BIT(7) ++#define RTL8367B_DEBUG0_DRI_RG(_x) BIT(5 + (_x)) ++#define RTL8367B_DEBUG0_DRI(_x) BIT(3 + (_x)) ++#define RTL8367B_DEBUG0_SLR_OTHER BIT(2) ++#define RTL8367B_DEBUG0_SLR(_x) BIT(_x) ++ ++#define RTL8367B_CHIP_DEBUG1_REG 0x1304 ++#define RTL8367B_DEBUG1_DN_MASK(_x) \ ++ GENMASK(6 + (_x)*8, 4 + (_x)*8) ++#define RTL8367B_DEBUG1_DN_SHIFT(_x) (4 + (_x) * 8) ++#define RTL8367B_DEBUG1_DP_MASK(_x) \ ++ GENMASK(2 + (_x) * 8, (_x) * 8) ++#define RTL8367B_DEBUG1_DP_SHIFT(_x) ((_x) * 8) ++ ++#define RTL8367B_CHIP_DEBUG2_REG 0x13e2 ++#define RTL8367B_DEBUG2_RG2_DN_MASK GENMASK(8, 6) ++#define RTL8367B_DEBUG2_RG2_DN_SHIFT 6 ++#define RTL8367B_DEBUG2_RG2_DP_MASK GENMASK(5, 3) ++#define RTL8367B_DEBUG2_RG2_DP_SHIFT 3 ++#define RTL8367B_DEBUG2_DRI_EXT2_RG BIT(2) ++#define RTL8367B_DEBUG2_DRI_EXT2 BIT(1) ++#define RTL8367B_DEBUG2_SLR_EXT2 BIT(0) ++ ++#define RTL8367B_DIS_REG 0x1305 ++#define RTL8367B_DIS_SKIP_MII_RXER(_x) BIT(12 + (_x)) ++#define RTL8367B_DIS_RGMII_SHIFT(_x) (4 * (_x)) ++#define RTL8367B_DIS_RGMII_MASK 0x7 ++ ++#define RTL8367B_DIS2_REG 0x13c3 ++#define RTL8367B_DIS2_SKIP_MII_RXER_SHIFT 4 ++#define RTL8367B_DIS2_SKIP_MII_RXER 0x10 ++#define RTL8367B_DIS2_RGMII_SHIFT 0 ++#define RTL8367B_DIS2_RGMII_MASK 0xf ++ ++#define RTL8367B_EXT_RGMXF_REG(_x) \ ++ ((_x) == 2 ? 0x13c5 : 0x1306 + (_x)) ++#define RTL8367B_EXT_RGMXF_DUMMY0_SHIFT 5 ++#define RTL8367B_EXT_RGMXF_DUMMY0_MASK 0x7ff ++#define RTL8367B_EXT_RGMXF_TXDELAY_SHIFT 3 ++#define RTL8367B_EXT_RGMXF_TXDELAY_MASK 1 ++#define RTL8367B_EXT_RGMXF_RXDELAY_MASK 0x7 ++ ++#define RTL8367B_DI_FORCE_REG(_x) \ ++ ((_x) == 2 ? 0x13c4 : 0x1310 + (_x)) ++#define RTL8367B_DI_FORCE_MODE BIT(12) ++#define RTL8367B_DI_FORCE_NWAY BIT(7) ++#define RTL8367B_DI_FORCE_TXPAUSE BIT(6) ++#define RTL8367B_DI_FORCE_RXPAUSE BIT(5) ++#define RTL8367B_DI_FORCE_LINK BIT(4) ++#define RTL8367B_DI_FORCE_DUPLEX BIT(2) ++#define RTL8367B_DI_FORCE_SPEED_MASK 3 ++#define RTL8367B_DI_FORCE_SPEED_10 0 ++#define RTL8367B_DI_FORCE_SPEED_100 1 ++#define RTL8367B_DI_FORCE_SPEED_1000 2 ++ ++#define RTL8367B_MAC_FORCE_REG(_x) (0x1312 + (_x)) ++ ++#define RTL8367B_CHIP_RESET_REG 0x1322 /*GOOD*/ ++#define RTL8367B_CHIP_RESET_SW BIT(1) /*GOOD*/ ++#define RTL8367B_CHIP_RESET_HW BIT(0) /*GOOD*/ ++ ++#define RTL8367B_PORT_STATUS_REG(_p) (0x1352 + (_p)) /*GOOD*/ ++#define RTL8367B_PORT_STATUS_EN_1000_SPI BIT(11) /*GOOD*/ ++#define RTL8367B_PORT_STATUS_EN_100_SPI BIT(10)/*GOOD*/ ++#define RTL8367B_PORT_STATUS_NWAY_FAULT BIT(9)/*GOOD*/ ++#define RTL8367B_PORT_STATUS_LINK_MASTER BIT(8)/*GOOD*/ ++#define RTL8367B_PORT_STATUS_NWAY BIT(7)/*GOOD*/ ++#define RTL8367B_PORT_STATUS_TXPAUSE BIT(6)/*GOOD*/ ++#define RTL8367B_PORT_STATUS_RXPAUSE BIT(5)/*GOOD*/ ++#define RTL8367B_PORT_STATUS_LINK BIT(4)/*GOOD*/ ++#define RTL8367B_PORT_STATUS_DUPLEX BIT(2)/*GOOD*/ ++#define RTL8367B_PORT_STATUS_SPEED_MASK 0x0003/*GOOD*/ ++#define RTL8367B_PORT_STATUS_SPEED_10 0/*GOOD*/ ++#define RTL8367B_PORT_STATUS_SPEED_100 1/*GOOD*/ ++#define RTL8367B_PORT_STATUS_SPEED_1000 2/*GOOD*/ ++ ++#define RTL8367B_RTL_MAGIC_ID_REG 0x13c2 ++#define RTL8367B_RTL_MAGIC_ID_VAL 0x0249 ++ ++#define RTL8367B_IA_CTRL_REG 0x1f00 ++#define RTL8367B_IA_CTRL_RW(_x) ((_x) << 1) ++#define RTL8367B_IA_CTRL_RW_READ RTL8367B_IA_CTRL_RW(0) ++#define RTL8367B_IA_CTRL_RW_WRITE RTL8367B_IA_CTRL_RW(1) ++#define RTL8367B_IA_CTRL_CMD_MASK BIT(0) ++ ++#define RTL8367B_IA_STATUS_REG 0x1f01 ++#define RTL8367B_IA_STATUS_PHY_BUSY BIT(2) ++#define RTL8367B_IA_STATUS_SDS_BUSY BIT(1) ++#define RTL8367B_IA_STATUS_MDX_BUSY BIT(0) ++ ++#define RTL8367B_IA_ADDRESS_REG 0x1f02 ++#define RTL8367B_IA_WRITE_DATA_REG 0x1f03 ++#define RTL8367B_IA_READ_DATA_REG 0x1f04 ++ ++#define RTL8367B_INTERNAL_PHY_REG(_a, _r) (0x2000 + 32 * (_a) + (_r)) ++ ++#define RTL8367B_NUM_MIB_COUNTERS 58 ++ ++#define RTL8367B_CPU_PORT_NUM 5 ++#define RTL8367B_NUM_PORTS 8 ++#define RTL8367B_NUM_VLANS 32 ++#define RTL8367B_NUM_VIDS 4096 ++#define RTL8367B_PRIORITYMAX 7 ++#define RTL8367B_FIDMAX 7 ++ ++#define RTL8367B_PORT_0 BIT(0) ++#define RTL8367B_PORT_1 BIT(1) ++#define RTL8367B_PORT_2 BIT(2) ++#define RTL8367B_PORT_3 BIT(3) ++#define RTL8367B_PORT_4 BIT(4) ++#define RTL8367B_PORT_E0 BIT(5) /* External port 0 */ ++#define RTL8367B_PORT_E1 BIT(6) /* External port 1 */ ++#define RTL8367B_PORT_E2 BIT(7) /* External port 2 */ ++ ++#define RTL8367B_PORTS_ALL \ ++ (RTL8367B_PORT_0 | RTL8367B_PORT_1 | RTL8367B_PORT_2 | \ ++ RTL8367B_PORT_3 | RTL8367B_PORT_4 | RTL8367B_PORT_E0 | \ ++ RTL8367B_PORT_E1 | RTL8367B_PORT_E2) ++ ++#define RTL8367B_PORTS_ALL_BUT_CPU \ ++ (RTL8367B_PORT_0 | RTL8367B_PORT_1 | RTL8367B_PORT_2 | \ ++ RTL8367B_PORT_3 | RTL8367B_PORT_4 | RTL8367B_PORT_E1 | \ ++ RTL8367B_PORT_E2) ++ ++struct rtl8367b_initval { ++ u16 reg; ++ u16 val; ++}; ++ ++#define RTL8367B_MIB_RXB_ID 0 /* IfInOctets */ ++#define RTL8367B_MIB_TXB_ID 28 /* IfOutOctets */ ++ ++#define RTL8367D_PORT_STATUS_REG(_p) (0x12d0 + (_p)) ++ ++#define RTL8367D_PORT_STATUS_SPEED1_MASK 0x3000 ++#define RTL8367D_PORT_STATUS_SPEED1_SHIFT 10 /*12-2*/ ++ ++#define RTL8367D_REG_MAC0_FORCE_SELECT 0x12c0 ++#define RTL8367D_REG_MAC0_FORCE_SELECT_EN 0x12c8 ++ ++#define RTL8367D_VLAN_PVID_CTRL_REG(_p) (0x0700 + (_p)) ++#define RTL8367D_VLAN_PVID_CTRL_MASK 0xfff ++#define RTL8367D_VLAN_PVID_CTRL_SHIFT(_p) 0 ++ ++#define RTL8367D_FIDMAX 3 ++#define RTL8367D_FID_MASK 3 ++#define RTL8367D_TA_VLAN1_FID_SHIFT 0 ++#define RTL8367D_TA_VLAN1_FID_MASK RTL8367D_FID_MASK ++ ++#define RTL8367D_VID_MASK 0xfff ++#define RTL8367D_TA_VLAN_VID_MASK RTL8367D_VID_MASK ++ ++#define RTL8367D_REG_EXT_TXC_DLY 0x13f9 ++#define RTL8367D_EXT1_RGMII_TX_DLY_MASK 0x38 ++ ++#define RTL8367D_REG_TOP_CON0 0x1d70 ++#define RTL8367D_MAC7_SEL_EXT1_MASK 0x2000 ++#define RTL8367D_MAC4_SEL_EXT1_MASK 0x1000 ++ ++#define RTL8367D_REG_SDS1_MISC0 0x1d78 ++#define RTL8367D_SDS1_MODE_MASK 0x1f ++#define RTL8367D_PORT_SDS_MODE_DISABLE 0x1f ++ ++static struct rtl8366_mib_counter ++rtl8367b_mib_counters[RTL8367B_NUM_MIB_COUNTERS] = { ++ {0, 0, 4, "ifInOctets" }, ++ {0, 4, 2, "dot3StatsFCSErrors" }, ++ {0, 6, 2, "dot3StatsSymbolErrors" }, ++ {0, 8, 2, "dot3InPauseFrames" }, ++ {0, 10, 2, "dot3ControlInUnknownOpcodes" }, ++ {0, 12, 2, "etherStatsFragments" }, ++ {0, 14, 2, "etherStatsJabbers" }, ++ {0, 16, 2, "ifInUcastPkts" }, ++ {0, 18, 2, "etherStatsDropEvents" }, ++ {0, 20, 2, "ifInMulticastPkts" }, ++ {0, 22, 2, "ifInBroadcastPkts" }, ++ {0, 24, 2, "inMldChecksumError" }, ++ {0, 26, 2, "inIgmpChecksumError" }, ++ {0, 28, 2, "inMldSpecificQuery" }, ++ {0, 30, 2, "inMldGeneralQuery" }, ++ {0, 32, 2, "inIgmpSpecificQuery" }, ++ {0, 34, 2, "inIgmpGeneralQuery" }, ++ {0, 36, 2, "inMldLeaves" }, ++ {0, 38, 2, "inIgmpLeaves" }, ++ ++ {0, 40, 4, "etherStatsOctets" }, ++ {0, 44, 2, "etherStatsUnderSizePkts" }, ++ {0, 46, 2, "etherOversizeStats" }, ++ {0, 48, 2, "etherStatsPkts64Octets" }, ++ {0, 50, 2, "etherStatsPkts65to127Octets" }, ++ {0, 52, 2, "etherStatsPkts128to255Octets" }, ++ {0, 54, 2, "etherStatsPkts256to511Octets" }, ++ {0, 56, 2, "etherStatsPkts512to1023Octets" }, ++ {0, 58, 2, "etherStatsPkts1024to1518Octets" }, ++ ++ {0, 60, 4, "ifOutOctets" }, ++ {0, 64, 2, "dot3StatsSingleCollisionFrames" }, ++ {0, 66, 2, "dot3StatMultipleCollisionFrames" }, ++ {0, 68, 2, "dot3sDeferredTransmissions" }, ++ {0, 70, 2, "dot3StatsLateCollisions" }, ++ {0, 72, 2, "etherStatsCollisions" }, ++ {0, 74, 2, "dot3StatsExcessiveCollisions" }, ++ {0, 76, 2, "dot3OutPauseFrames" }, ++ {0, 78, 2, "ifOutDiscards" }, ++ {0, 80, 2, "dot1dTpPortInDiscards" }, ++ {0, 82, 2, "ifOutUcastPkts" }, ++ {0, 84, 2, "ifOutMulticastPkts" }, ++ {0, 86, 2, "ifOutBroadcastPkts" }, ++ {0, 88, 2, "outOampduPkts" }, ++ {0, 90, 2, "inOampduPkts" }, ++ {0, 92, 2, "inIgmpJoinsSuccess" }, ++ {0, 94, 2, "inIgmpJoinsFail" }, ++ {0, 96, 2, "inMldJoinsSuccess" }, ++ {0, 98, 2, "inMldJoinsFail" }, ++ {0, 100, 2, "inReportSuppressionDrop" }, ++ {0, 102, 2, "inLeaveSuppressionDrop" }, ++ {0, 104, 2, "outIgmpReports" }, ++ {0, 106, 2, "outIgmpLeaves" }, ++ {0, 108, 2, "outIgmpGeneralQuery" }, ++ {0, 110, 2, "outIgmpSpecificQuery" }, ++ {0, 112, 2, "outMldReports" }, ++ {0, 114, 2, "outMldLeaves" }, ++ {0, 116, 2, "outMldGeneralQuery" }, ++ {0, 118, 2, "outMldSpecificQuery" }, ++ {0, 120, 2, "inKnownMulticastPkts" }, ++}; ++ ++#define REG_RD(_smi, _reg, _val) \ ++ do { \ ++ err = rtl8366_smi_read_reg(_smi, _reg, _val); \ ++ if (err) \ ++ return err; \ ++ } while (0) ++ ++#define REG_WR(_smi, _reg, _val) \ ++ do { \ ++ err = rtl8366_smi_write_reg(_smi, _reg, _val); \ ++ if (err) \ ++ return err; \ ++ } while (0) ++ ++#define REG_RMW(_smi, _reg, _mask, _val) \ ++ do { \ ++ err = rtl8366_smi_rmwr(_smi, _reg, _mask, _val); \ ++ if (err) \ ++ return err; \ ++ } while (0) ++ ++static const struct rtl8367b_initval rtl8367b_initvals[] = { ++ {0x1B03, 0x0876}, {0x1200, 0x7FC4}, {0x1305, 0xC000}, {0x121E, 0x03CA}, ++ {0x1233, 0x0352}, {0x1234, 0x0064}, {0x1237, 0x0096}, {0x1238, 0x0078}, ++ {0x1239, 0x0084}, {0x123A, 0x0030}, {0x205F, 0x0002}, {0x2059, 0x1A00}, ++ {0x205F, 0x0000}, {0x207F, 0x0002}, {0x2077, 0x0000}, {0x2078, 0x0000}, ++ {0x2079, 0x0000}, {0x207A, 0x0000}, {0x207B, 0x0000}, {0x207F, 0x0000}, ++ {0x205F, 0x0002}, {0x2053, 0x0000}, {0x2054, 0x0000}, {0x2055, 0x0000}, ++ {0x2056, 0x0000}, {0x2057, 0x0000}, {0x205F, 0x0000}, {0x133F, 0x0030}, ++ {0x133E, 0x000E}, {0x221F, 0x0005}, {0x2205, 0x8B86}, {0x2206, 0x800E}, ++ {0x221F, 0x0000}, {0x133F, 0x0010}, {0x12A3, 0x2200}, {0x6107, 0xE58B}, ++ {0x6103, 0xA970}, {0x0018, 0x0F00}, {0x0038, 0x0F00}, {0x0058, 0x0F00}, ++ {0x0078, 0x0F00}, {0x0098, 0x0F00}, {0x133F, 0x0030}, {0x133E, 0x000E}, ++ {0x221F, 0x0005}, {0x2205, 0x8B6E}, {0x2206, 0x0000}, {0x220F, 0x0100}, ++ {0x2205, 0xFFF6}, {0x2206, 0x0080}, {0x2205, 0x8000}, {0x2206, 0x0280}, ++ {0x2206, 0x2BF7}, {0x2206, 0x00E0}, {0x2206, 0xFFF7}, {0x2206, 0xA080}, ++ {0x2206, 0x02AE}, {0x2206, 0xF602}, {0x2206, 0x0153}, {0x2206, 0x0201}, ++ {0x2206, 0x6602}, {0x2206, 0x8044}, {0x2206, 0x0201}, {0x2206, 0x7CE0}, ++ {0x2206, 0x8B8C}, {0x2206, 0xE18B}, {0x2206, 0x8D1E}, {0x2206, 0x01E1}, ++ {0x2206, 0x8B8E}, {0x2206, 0x1E01}, {0x2206, 0xA000}, {0x2206, 0xE4AE}, ++ {0x2206, 0xD8EE}, {0x2206, 0x85C0}, {0x2206, 0x00EE}, {0x2206, 0x85C1}, ++ {0x2206, 0x00EE}, {0x2206, 0x8AFC}, {0x2206, 0x07EE}, {0x2206, 0x8AFD}, ++ {0x2206, 0x73EE}, {0x2206, 0xFFF6}, {0x2206, 0x00EE}, {0x2206, 0xFFF7}, ++ {0x2206, 0xFC04}, {0x2206, 0xF8E0}, {0x2206, 0x8B8E}, {0x2206, 0xAD20}, ++ {0x2206, 0x0302}, {0x2206, 0x8050}, {0x2206, 0xFC04}, {0x2206, 0xF8F9}, ++ {0x2206, 0xE08B}, {0x2206, 0x85AD}, {0x2206, 0x2548}, {0x2206, 0xE08A}, ++ {0x2206, 0xE4E1}, {0x2206, 0x8AE5}, {0x2206, 0x7C00}, {0x2206, 0x009E}, ++ {0x2206, 0x35EE}, {0x2206, 0x8AE4}, {0x2206, 0x00EE}, {0x2206, 0x8AE5}, ++ {0x2206, 0x00E0}, {0x2206, 0x8AFC}, {0x2206, 0xE18A}, {0x2206, 0xFDE2}, ++ {0x2206, 0x85C0}, {0x2206, 0xE385}, {0x2206, 0xC102}, {0x2206, 0x2DAC}, ++ {0x2206, 0xAD20}, {0x2206, 0x12EE}, {0x2206, 0x8AE4}, {0x2206, 0x03EE}, ++ {0x2206, 0x8AE5}, {0x2206, 0xB7EE}, {0x2206, 0x85C0}, {0x2206, 0x00EE}, ++ {0x2206, 0x85C1}, {0x2206, 0x00AE}, {0x2206, 0x1115}, {0x2206, 0xE685}, ++ {0x2206, 0xC0E7}, {0x2206, 0x85C1}, {0x2206, 0xAE08}, {0x2206, 0xEE85}, ++ {0x2206, 0xC000}, {0x2206, 0xEE85}, {0x2206, 0xC100}, {0x2206, 0xFDFC}, ++ {0x2206, 0x0400}, {0x2205, 0xE142}, {0x2206, 0x0701}, {0x2205, 0xE140}, ++ {0x2206, 0x0405}, {0x220F, 0x0000}, {0x221F, 0x0000}, {0x133E, 0x000E}, ++ {0x133F, 0x0010}, {0x13EB, 0x11BB}, {0x207F, 0x0002}, {0x2073, 0x1D22}, ++ {0x207F, 0x0000}, {0x133F, 0x0030}, {0x133E, 0x000E}, {0x2200, 0x1340}, ++ {0x133E, 0x000E}, {0x133F, 0x0010}, ++}; ++ ++static const struct rtl8367b_initval rtl8367c_initvals[] = { ++ {0x13c2, 0x0000}, {0x0018, 0x0f00}, {0x0038, 0x0f00}, {0x0058, 0x0f00}, ++ {0x0078, 0x0f00}, {0x0098, 0x0f00}, {0x1d15, 0x0a69}, {0x2000, 0x1340}, ++ {0x2020, 0x1340}, {0x2040, 0x1340}, {0x2060, 0x1340}, {0x2080, 0x1340}, ++ {0x13eb, 0x15bb}, {0x1303, 0x06d6}, {0x1304, 0x0700}, {0x13E2, 0x003F}, ++ {0x13F9, 0x0090}, {0x121e, 0x03CA}, {0x1233, 0x0352}, {0x1237, 0x00a0}, ++ {0x123a, 0x0030}, {0x1239, 0x0084}, {0x0301, 0x1000}, {0x1349, 0x001F}, ++ {0x18e0, 0x4004}, {0x122b, 0x641c}, {0x1305, 0xc000}, {0x1200, 0x7fcb}, ++ {0x0884, 0x0003}, {0x06eb, 0x0001}, {0x00cf, 0xffff}, {0x00d0, 0x0007}, ++ {0x00ce, 0x48b0}, {0x00ce, 0x48b0}, {0x0398, 0xffff}, {0x0399, 0x0007}, ++ {0x0300, 0x0001}, {0x03fa, 0x0007}, {0x08c8, 0x00c0}, {0x0a30, 0x020e}, ++ {0x0800, 0x0000}, {0x0802, 0x0000}, {0x09da, 0x0017}, {0x1d32, 0x0002}, ++}; ++ ++static int rtl8367b_write_initvals(struct rtl8366_smi *smi, ++ const struct rtl8367b_initval *initvals, ++ int count) ++{ ++ int err; ++ int i; ++ ++ for (i = 0; i < count; i++) ++ REG_WR(smi, initvals[i].reg, initvals[i].val); ++ ++ return 0; ++} ++ ++static int rtl8367b_read_phy_reg(struct rtl8366_smi *smi, ++ u32 phy_addr, u32 phy_reg, u32 *val) ++{ ++ int timeout; ++ u32 data; ++ int err; ++ ++ if (phy_addr > RTL8367B_PHY_ADDR_MAX) ++ return -EINVAL; ++ ++ if (phy_reg > RTL8367B_PHY_REG_MAX) ++ return -EINVAL; ++ ++ REG_RD(smi, RTL8367B_IA_STATUS_REG, &data); ++ if (data & RTL8367B_IA_STATUS_PHY_BUSY) ++ return -ETIMEDOUT; ++ ++ /* prepare address */ ++ REG_WR(smi, RTL8367B_IA_ADDRESS_REG, ++ RTL8367B_INTERNAL_PHY_REG(phy_addr, phy_reg)); ++ ++ /* send read command */ ++ REG_WR(smi, RTL8367B_IA_CTRL_REG, ++ RTL8367B_IA_CTRL_CMD_MASK | RTL8367B_IA_CTRL_RW_READ); ++ ++ timeout = 5; ++ do { ++ REG_RD(smi, RTL8367B_IA_STATUS_REG, &data); ++ if ((data & RTL8367B_IA_STATUS_PHY_BUSY) == 0) ++ break; ++ ++ if (timeout--) { ++ dev_err(smi->parent, "phy read timed out\n"); ++ return -ETIMEDOUT; ++ } ++ ++ udelay(1); ++ } while (1); ++ ++ /* read data */ ++ REG_RD(smi, RTL8367B_IA_READ_DATA_REG, val); ++ ++ dev_dbg(smi->parent, "phy_read: addr:%02x, reg:%02x, val:%04x\n", ++ phy_addr, phy_reg, *val); ++ return 0; ++} ++ ++static int rtl8367b_write_phy_reg(struct rtl8366_smi *smi, ++ u32 phy_addr, u32 phy_reg, u32 val) ++{ ++ int timeout; ++ u32 data; ++ int err; ++ ++ dev_dbg(smi->parent, "phy_write: addr:%02x, reg:%02x, val:%04x\n", ++ phy_addr, phy_reg, val); ++ ++ if (phy_addr > RTL8367B_PHY_ADDR_MAX) ++ return -EINVAL; ++ ++ if (phy_reg > RTL8367B_PHY_REG_MAX) ++ return -EINVAL; ++ ++ REG_RD(smi, RTL8367B_IA_STATUS_REG, &data); ++ if (data & RTL8367B_IA_STATUS_PHY_BUSY) ++ return -ETIMEDOUT; ++ ++ /* preapre data */ ++ REG_WR(smi, RTL8367B_IA_WRITE_DATA_REG, val); ++ ++ /* prepare address */ ++ REG_WR(smi, RTL8367B_IA_ADDRESS_REG, ++ RTL8367B_INTERNAL_PHY_REG(phy_addr, phy_reg)); ++ ++ /* send write command */ ++ REG_WR(smi, RTL8367B_IA_CTRL_REG, ++ RTL8367B_IA_CTRL_CMD_MASK | RTL8367B_IA_CTRL_RW_WRITE); ++ ++ timeout = 5; ++ do { ++ REG_RD(smi, RTL8367B_IA_STATUS_REG, &data); ++ if ((data & RTL8367B_IA_STATUS_PHY_BUSY) == 0) ++ break; ++ ++ if (timeout--) { ++ dev_err(smi->parent, "phy write timed out\n"); ++ return -ETIMEDOUT; ++ } ++ ++ udelay(1); ++ } while (1); ++ ++ return 0; ++} ++ ++static int rtl8367b_init_regs(struct rtl8366_smi *smi) ++{ ++ const struct rtl8367b_initval *initvals; ++ int count; ++ ++ switch (smi->rtl8367b_chip) { ++ case RTL8367B_CHIP_RTL8367RB: ++ case RTL8367B_CHIP_RTL8367R_VB: ++ initvals = rtl8367b_initvals; ++ count = ARRAY_SIZE(rtl8367b_initvals); ++ break; ++ case RTL8367B_CHIP_RTL8367RB_VB: ++ case RTL8367B_CHIP_RTL8367S: ++ case RTL8367B_CHIP_RTL8367S_VB: ++ initvals = rtl8367c_initvals; ++ count = ARRAY_SIZE(rtl8367c_initvals); ++ if ((smi->rtl8367b_chip == RTL8367B_CHIP_RTL8367S_VB) && (smi->emu_vlanmc == NULL)) { ++ smi->emu_vlanmc = kzalloc(sizeof(struct rtl8366_vlan_mc) * smi->num_vlan_mc, GFP_KERNEL); ++ dev_info(smi->parent, "alloc vlan mc emulator"); ++ } ++ break; ++ default: ++ return -ENODEV; ++ } ++ ++ return rtl8367b_write_initvals(smi, initvals, count); ++} ++ ++static int rtl8367b_reset_chip(struct rtl8366_smi *smi) ++{ ++ int timeout = 10; ++ int err; ++ u32 data; ++ ++ REG_WR(smi, RTL8367B_CHIP_RESET_REG, RTL8367B_CHIP_RESET_HW); ++ msleep(RTL8367B_RESET_DELAY); ++ ++ do { ++ REG_RD(smi, RTL8367B_CHIP_RESET_REG, &data); ++ if (!(data & RTL8367B_CHIP_RESET_HW)) ++ break; ++ ++ msleep(1); ++ } while (--timeout); ++ ++ if (!timeout) { ++ dev_err(smi->parent, "chip reset timed out\n"); ++ return -ETIMEDOUT; ++ } ++ ++ return 0; ++} ++ ++static int rtl8367b_extif_set_mode(struct rtl8366_smi *smi, int id, ++ enum rtl8367_extif_mode mode) ++{ ++ int err; ++ u32 data; ++ ++ /* set port mode */ ++ switch (mode) { ++ case RTL8367_EXTIF_MODE_RGMII: ++ REG_RMW(smi, RTL8367B_CHIP_DEBUG0_REG, ++ RTL8367B_DEBUG0_SEL33(id), ++ RTL8367B_DEBUG0_SEL33(id)); ++ if (id <= 1) { ++ REG_RMW(smi, RTL8367B_CHIP_DEBUG0_REG, ++ RTL8367B_DEBUG0_DRI(id) | ++ RTL8367B_DEBUG0_DRI_RG(id) | ++ RTL8367B_DEBUG0_SLR(id), ++ RTL8367B_DEBUG0_DRI_RG(id) | ++ RTL8367B_DEBUG0_SLR(id)); ++ REG_RMW(smi, RTL8367B_CHIP_DEBUG1_REG, ++ RTL8367B_DEBUG1_DN_MASK(id) | ++ RTL8367B_DEBUG1_DP_MASK(id), ++ (7 << RTL8367B_DEBUG1_DN_SHIFT(id)) | ++ (7 << RTL8367B_DEBUG1_DP_SHIFT(id))); ++ if ((smi->rtl8367b_chip == RTL8367B_CHIP_RTL8367S_VB) && (id == 1)) { ++ REG_RMW(smi, RTL8367D_REG_EXT_TXC_DLY, RTL8367D_EXT1_RGMII_TX_DLY_MASK, 0); ++ /* Configure RGMII/MII mux to port 7 if UTP_PORT4 is not RGMII mode */ ++ REG_RD(smi, RTL8367D_REG_TOP_CON0, &data); ++ data &= RTL8367D_MAC4_SEL_EXT1_MASK; ++ if (data == 0) ++ REG_RMW(smi, RTL8367D_REG_TOP_CON0, RTL8367D_MAC7_SEL_EXT1_MASK, RTL8367D_MAC7_SEL_EXT1_MASK); ++ REG_RMW(smi, RTL8367D_REG_SDS1_MISC0, RTL8367D_SDS1_MODE_MASK, RTL8367D_PORT_SDS_MODE_DISABLE); ++ } ++ } else { ++ REG_RMW(smi, RTL8367B_CHIP_DEBUG2_REG, ++ RTL8367B_DEBUG2_DRI_EXT2 | ++ RTL8367B_DEBUG2_DRI_EXT2_RG | ++ RTL8367B_DEBUG2_SLR_EXT2 | ++ RTL8367B_DEBUG2_RG2_DN_MASK | ++ RTL8367B_DEBUG2_RG2_DP_MASK, ++ RTL8367B_DEBUG2_DRI_EXT2_RG | ++ RTL8367B_DEBUG2_SLR_EXT2 | ++ (7 << RTL8367B_DEBUG2_RG2_DN_SHIFT) | ++ (7 << RTL8367B_DEBUG2_RG2_DP_SHIFT)); ++ } ++ break; ++ ++ case RTL8367_EXTIF_MODE_TMII_MAC: ++ case RTL8367_EXTIF_MODE_TMII_PHY: ++ REG_RMW(smi, RTL8367B_BYPASS_LINE_RATE_REG, BIT(id), BIT(id)); ++ break; ++ ++ case RTL8367_EXTIF_MODE_GMII: ++ REG_RMW(smi, RTL8367B_CHIP_DEBUG0_REG, ++ RTL8367B_DEBUG0_SEL33(id), ++ RTL8367B_DEBUG0_SEL33(id)); ++ REG_RMW(smi, RTL8367B_EXT_RGMXF_REG(id), BIT(6), BIT(6)); ++ break; ++ ++ case RTL8367_EXTIF_MODE_MII_MAC: ++ case RTL8367_EXTIF_MODE_MII_PHY: ++ case RTL8367_EXTIF_MODE_DISABLED: ++ REG_RMW(smi, RTL8367B_BYPASS_LINE_RATE_REG, BIT(id), 0); ++ REG_RMW(smi, RTL8367B_EXT_RGMXF_REG(id), BIT(6), 0); ++ break; ++ ++ default: ++ dev_err(smi->parent, ++ "invalid mode for external interface %d\n", id); ++ return -EINVAL; ++ } ++ ++ if (id <= 1) ++ REG_RMW(smi, RTL8367B_DIS_REG, ++ RTL8367B_DIS_RGMII_MASK << RTL8367B_DIS_RGMII_SHIFT(id), ++ mode << RTL8367B_DIS_RGMII_SHIFT(id)); ++ else ++ REG_RMW(smi, RTL8367B_DIS2_REG, ++ RTL8367B_DIS2_RGMII_MASK << RTL8367B_DIS2_RGMII_SHIFT, ++ mode << RTL8367B_DIS2_RGMII_SHIFT); ++ ++ return 0; ++} ++ ++static int rtl8367b_extif_set_force(struct rtl8366_smi *smi, int id, ++ struct rtl8367_port_ability *pa) ++{ ++ u32 mask; ++ u32 val; ++ int err; ++ ++ val = pa->speed & RTL8367B_DI_FORCE_SPEED_MASK; ++ val |= pa->nway ? RTL8367B_DI_FORCE_NWAY : 0; ++ val |= pa->txpause ? RTL8367B_DI_FORCE_TXPAUSE : 0; ++ val |= pa->rxpause ? RTL8367B_DI_FORCE_RXPAUSE : 0; ++ val |= pa->link ? RTL8367B_DI_FORCE_LINK : 0; ++ val |= pa->duplex ? RTL8367B_DI_FORCE_DUPLEX : 0; ++ ++ if (smi->rtl8367b_chip >= RTL8367B_CHIP_RTL8367S_VB) { /* Family D */ ++ val |= (pa->speed << RTL8367D_PORT_STATUS_SPEED1_SHIFT) & RTL8367D_PORT_STATUS_SPEED1_MASK; ++ if (smi->cpu_port != UINT_MAX) { ++ REG_WR(smi, RTL8367D_REG_MAC0_FORCE_SELECT + smi->cpu_port, val); ++ REG_WR(smi, RTL8367D_REG_MAC0_FORCE_SELECT_EN + smi->cpu_port, pa->force_mode ? 0xffff : 0x0000); ++ } ++ } else { ++ val |= pa->force_mode ? RTL8367B_DI_FORCE_MODE : 0; ++ mask = (RTL8367B_DI_FORCE_MODE | ++ RTL8367B_DI_FORCE_NWAY | ++ RTL8367B_DI_FORCE_TXPAUSE | ++ RTL8367B_DI_FORCE_RXPAUSE | ++ RTL8367B_DI_FORCE_LINK | ++ RTL8367B_DI_FORCE_DUPLEX | ++ RTL8367B_DI_FORCE_SPEED_MASK); ++ ++ REG_RMW(smi, RTL8367B_DI_FORCE_REG(id), mask, val); ++ } ++ ++ return 0; ++} ++ ++static int rtl8367b_extif_set_rgmii_delay(struct rtl8366_smi *smi, int id, ++ unsigned txdelay, unsigned rxdelay) ++{ ++ u32 mask; ++ u32 val; ++ int err; ++ ++ mask = (RTL8367B_EXT_RGMXF_RXDELAY_MASK | ++ (RTL8367B_EXT_RGMXF_TXDELAY_MASK << ++ RTL8367B_EXT_RGMXF_TXDELAY_SHIFT)); ++ ++ val = rxdelay; ++ val |= txdelay << RTL8367B_EXT_RGMXF_TXDELAY_SHIFT; ++ ++ REG_RMW(smi, RTL8367B_EXT_RGMXF_REG(id), mask, val); ++ ++ return 0; ++} ++ ++static int rtl8367b_extif_init(struct rtl8366_smi *smi, int id, ++ struct rtl8367_extif_config *cfg) ++{ ++ enum rtl8367_extif_mode mode; ++ int err; ++ ++ mode = (cfg) ? cfg->mode : RTL8367_EXTIF_MODE_DISABLED; ++ ++ err = rtl8367b_extif_set_mode(smi, id, mode); ++ if (err) ++ return err; ++ ++ if (mode != RTL8367_EXTIF_MODE_DISABLED) { ++ err = rtl8367b_extif_set_force(smi, id, &cfg->ability); ++ if (err) ++ return err; ++ ++ err = rtl8367b_extif_set_rgmii_delay(smi, id, cfg->txdelay, ++ cfg->rxdelay); ++ if (err) ++ return err; ++ } ++ ++ return 0; ++} ++ ++#ifdef CONFIG_OF ++static int rtl8367b_extif_init_of(struct rtl8366_smi *smi, ++ const char *name) ++{ ++ struct rtl8367_extif_config *cfg; ++ const __be32 *prop; ++ int size; ++ int err; ++ unsigned cpu_port; ++ unsigned id = UINT_MAX; ++ ++ prop = of_get_property(smi->parent->of_node, name, &size); ++ if (!prop || (size != (10 * sizeof(*prop)))) { ++ dev_err(smi->parent, "%s property is not defined or invalid\n", name); ++ err = -EINVAL; ++ goto err_init; ++ } ++ ++ cpu_port = be32_to_cpup(prop++); ++ switch (cpu_port) { ++ case RTL8367B_CPU_PORT_NUM: ++ case RTL8367B_CPU_PORT_NUM + 1: ++ case RTL8367B_CPU_PORT_NUM + 2: ++ if (smi->rtl8367b_chip == RTL8367B_CHIP_RTL8367R_VB) { /* for the RTL8367R-VB chip, cpu_port 5 corresponds to extif1 */ ++ if (cpu_port == RTL8367B_CPU_PORT_NUM) ++ id = 1; ++ else { ++ dev_err(smi->parent, "wrong cpu_port %u in %s property\n", cpu_port, name); ++ err = -EINVAL; ++ goto err_init; ++ } ++ } else if (smi->rtl8367b_chip == RTL8367B_CHIP_RTL8367S_VB) { /* for the RTL8367S-VB chip, cpu_port 7 corresponds to extif1, cpu_port 6 corresponds to extif0 */ ++ if (cpu_port != RTL8367B_CPU_PORT_NUM) { ++ id = cpu_port - RTL8367B_CPU_PORT_NUM - 1; ++ } else { ++ dev_err(smi->parent, "wrong cpu_port %u in %s property\n", cpu_port, name); ++ err = -EINVAL; ++ goto err_init; ++ } ++ } else { ++ id = cpu_port - RTL8367B_CPU_PORT_NUM; ++ } ++ if (smi->cpu_port == UINT_MAX) { ++ dev_info(smi->parent, "cpu_port:%u, assigned to extif%u\n", cpu_port, id); ++ smi->cpu_port = cpu_port; ++ } ++ break; ++ default: ++ dev_err(smi->parent, "wrong cpu_port %u in %s property\n", cpu_port, name); ++ err = -EINVAL; ++ goto err_init; ++ } ++ ++ cfg = kzalloc(sizeof(struct rtl8367_extif_config), GFP_KERNEL); ++ if (!cfg) ++ return -ENOMEM; ++ ++ cfg->txdelay = be32_to_cpup(prop++); ++ cfg->rxdelay = be32_to_cpup(prop++); ++ cfg->mode = be32_to_cpup(prop++); ++ cfg->ability.force_mode = be32_to_cpup(prop++); ++ cfg->ability.txpause = be32_to_cpup(prop++); ++ cfg->ability.rxpause = be32_to_cpup(prop++); ++ cfg->ability.link = be32_to_cpup(prop++); ++ cfg->ability.duplex = be32_to_cpup(prop++); ++ cfg->ability.speed = be32_to_cpup(prop++); ++ ++ err = rtl8367b_extif_init(smi, id, cfg); ++ kfree(cfg); ++ ++err_init: ++ if (id != 0) rtl8367b_extif_init(smi, 0, NULL); ++ if (id != 1) rtl8367b_extif_init(smi, 1, NULL); ++ if (id != 2) rtl8367b_extif_init(smi, 2, NULL); ++ ++ return err; ++} ++#else ++static int rtl8367b_extif_init_of(struct rtl8366_smi *smi, ++ const char *name) ++{ ++ return -EINVAL; ++} ++#endif ++ ++static int rtl8367b_setup(struct rtl8366_smi *smi) ++{ ++ struct rtl8367_platform_data *pdata; ++ int err; ++ int i; ++ ++ pdata = smi->parent->platform_data; ++ ++ err = rtl8367b_init_regs(smi); ++ if (err) ++ return err; ++ ++ /* initialize external interfaces */ ++ if (smi->parent->of_node) { ++ err = rtl8367b_extif_init_of(smi, "realtek,extif"); ++ if (err) ++ return err; ++ } else { ++ err = rtl8367b_extif_init(smi, 0, pdata->extif0_cfg); ++ if (err) ++ return err; ++ ++ err = rtl8367b_extif_init(smi, 1, pdata->extif1_cfg); ++ if (err) ++ return err; ++ } ++ ++ /* set maximum packet length to 1536 bytes */ ++ REG_RMW(smi, RTL8367B_SWC0_REG, RTL8367B_SWC0_MAX_LENGTH_MASK, ++ RTL8367B_SWC0_MAX_LENGTH_1536); ++ ++ /* ++ * discard VLAN tagged packets if the port is not a member of ++ * the VLAN with which the packets is associated. ++ */ ++ REG_WR(smi, RTL8367B_VLAN_INGRESS_REG, RTL8367B_PORTS_ALL); ++ ++ /* ++ * Setup egress tag mode for each port. ++ */ ++ for (i = 0; i < RTL8367B_NUM_PORTS; i++) ++ REG_RMW(smi, ++ RTL8367B_PORT_MISC_CFG_REG(i), ++ RTL8367B_PORT_MISC_CFG_EGRESS_MODE_MASK << ++ RTL8367B_PORT_MISC_CFG_EGRESS_MODE_SHIFT, ++ RTL8367B_PORT_MISC_CFG_EGRESS_MODE_ORIGINAL << ++ RTL8367B_PORT_MISC_CFG_EGRESS_MODE_SHIFT); ++ ++ return 0; ++} ++ ++static int rtl8367b_get_mib_counter(struct rtl8366_smi *smi, int counter, ++ int port, unsigned long long *val) ++{ ++ struct rtl8366_mib_counter *mib; ++ int offset; ++ int i; ++ int err; ++ u32 addr, data; ++ u64 mibvalue; ++ ++ if (port > RTL8367B_NUM_PORTS || ++ counter >= RTL8367B_NUM_MIB_COUNTERS) ++ return -EINVAL; ++ ++ mib = &rtl8367b_mib_counters[counter]; ++ addr = RTL8367B_MIB_COUNTER_PORT_OFFSET * port + mib->offset; ++ ++ /* ++ * Writing access counter address first ++ * then ASIC will prepare 64bits counter wait for being retrived ++ */ ++ REG_WR(smi, RTL8367B_MIB_ADDRESS_REG, addr >> 2); ++ ++ /* read MIB control register */ ++ REG_RD(smi, RTL8367B_MIB_CTRL0_REG(0), &data); ++ ++ if (data & RTL8367B_MIB_CTRL0_BUSY_MASK) ++ return -EBUSY; ++ ++ if (data & RTL8367B_MIB_CTRL0_RESET_MASK) ++ return -EIO; ++ ++ if (mib->length == 4) ++ offset = 3; ++ else ++ offset = (mib->offset + 1) % 4; ++ ++ mibvalue = 0; ++ for (i = 0; i < mib->length; i++) { ++ REG_RD(smi, RTL8367B_MIB_COUNTER_REG(offset - i), &data); ++ mibvalue = (mibvalue << 16) | (data & 0xFFFF); ++ } ++ ++ *val = mibvalue; ++ return 0; ++} ++ ++static int rtl8367b_get_vlan_4k(struct rtl8366_smi *smi, u32 vid, ++ struct rtl8366_vlan_4k *vlan4k) ++{ ++ u32 data[RTL8367B_TA_VLAN_NUM_WORDS]; ++ int err; ++ int i; ++ ++ memset(vlan4k, '\0', sizeof(struct rtl8366_vlan_4k)); ++ ++ if (vid >= RTL8367B_NUM_VIDS) ++ return -EINVAL; ++ ++ /* write VID */ ++ REG_WR(smi, RTL8367B_TA_ADDR_REG, vid); ++ ++ /* write table access control word */ ++ REG_WR(smi, RTL8367B_TA_CTRL_REG, RTL8367B_TA_CTRL_CVLAN_READ); ++ ++ for (i = 0; i < ARRAY_SIZE(data); i++) ++ REG_RD(smi, RTL8367B_TA_RDDATA_REG(i), &data[i]); ++ ++ vlan4k->vid = vid; ++ vlan4k->member = (data[0] >> RTL8367B_TA_VLAN0_MEMBER_SHIFT) & ++ RTL8367B_TA_VLAN0_MEMBER_MASK; ++ vlan4k->untag = (data[0] >> RTL8367B_TA_VLAN0_UNTAG_SHIFT) & ++ RTL8367B_TA_VLAN0_UNTAG_MASK; ++ if (smi->rtl8367b_chip >= RTL8367B_CHIP_RTL8367S_VB) /* Family D */ ++ vlan4k->fid = (data[1] >> RTL8367D_TA_VLAN1_FID_SHIFT) & ++ RTL8367D_TA_VLAN1_FID_MASK; ++ else ++ vlan4k->fid = (data[1] >> RTL8367B_TA_VLAN1_FID_SHIFT) & ++ RTL8367B_TA_VLAN1_FID_MASK; ++ ++ return 0; ++} ++ ++static int rtl8367b_set_vlan_4k(struct rtl8366_smi *smi, ++ const struct rtl8366_vlan_4k *vlan4k) ++{ ++ u32 data[RTL8367B_TA_VLAN_NUM_WORDS]; ++ int err; ++ int i; ++ ++ if (vlan4k->vid >= RTL8367B_NUM_VIDS || ++ vlan4k->member > RTL8367B_TA_VLAN0_MEMBER_MASK || ++ vlan4k->untag > RTL8367B_UNTAG_MASK || ++ vlan4k->fid > ((smi->rtl8367b_chip >= RTL8367B_CHIP_RTL8367S_VB) ? RTL8367D_FIDMAX : RTL8367B_FIDMAX)) ++ return -EINVAL; ++ ++ memset(data, 0, sizeof(data)); ++ ++ data[0] = (vlan4k->member & RTL8367B_TA_VLAN0_MEMBER_MASK) << ++ RTL8367B_TA_VLAN0_MEMBER_SHIFT; ++ data[0] |= (vlan4k->untag & RTL8367B_TA_VLAN0_UNTAG_MASK) << ++ RTL8367B_TA_VLAN0_UNTAG_SHIFT; ++ ++ if (smi->rtl8367b_chip >= RTL8367B_CHIP_RTL8367S_VB) /* Family D */ ++ data[1] = ((vlan4k->fid & RTL8367D_TA_VLAN1_FID_MASK) << ++ RTL8367D_TA_VLAN1_FID_SHIFT) | 12; /* ivl_svl - BIT(3), svlan_chek_ivl_svl - BIT(2) */ ++ else ++ data[1] = (vlan4k->fid & RTL8367B_TA_VLAN1_FID_MASK) << ++ RTL8367B_TA_VLAN1_FID_SHIFT; ++ ++ for (i = 0; i < ARRAY_SIZE(data); i++) ++ REG_WR(smi, RTL8367B_TA_WRDATA_REG(i), data[i]); ++ ++ /* write VID */ ++ if (smi->rtl8367b_chip >= RTL8367B_CHIP_RTL8367S_VB) /* Family D */ ++ REG_WR(smi, RTL8367B_TA_ADDR_REG, ++ vlan4k->vid & RTL8367D_TA_VLAN_VID_MASK); ++ else ++ REG_WR(smi, RTL8367B_TA_ADDR_REG, ++ vlan4k->vid & RTL8367B_TA_VLAN_VID_MASK); ++ ++ /* write table access control word */ ++ REG_WR(smi, RTL8367B_TA_CTRL_REG, RTL8367B_TA_CTRL_CVLAN_WRITE); ++ ++ return 0; ++} ++ ++static int rtl8367b_get_vlan_mc(struct rtl8366_smi *smi, u32 index, ++ struct rtl8366_vlan_mc *vlanmc) ++{ ++ u32 data[RTL8367B_VLAN_MC_NUM_WORDS]; ++ int err; ++ int i; ++ ++ memset(vlanmc, '\0', sizeof(struct rtl8366_vlan_mc)); ++ ++ if (index >= RTL8367B_NUM_VLANS) ++ return -EINVAL; ++ ++ if (smi->emu_vlanmc) { /* use vlan mc emulation */ ++ vlanmc->vid = smi->emu_vlanmc[index].vid; ++ vlanmc->member = smi->emu_vlanmc[index].member; ++ vlanmc->fid = smi->emu_vlanmc[index].fid; ++ vlanmc->untag = smi->emu_vlanmc[index].untag; ++ return 0; ++ } ++ ++ for (i = 0; i < ARRAY_SIZE(data); i++) ++ REG_RD(smi, RTL8367B_VLAN_MC_BASE(index) + i, &data[i]); ++ ++ vlanmc->member = (data[0] >> RTL8367B_VLAN_MC0_MEMBER_SHIFT) & ++ RTL8367B_VLAN_MC0_MEMBER_MASK; ++ vlanmc->fid = (data[1] >> RTL8367B_VLAN_MC1_FID_SHIFT) & ++ RTL8367B_VLAN_MC1_FID_MASK; ++ vlanmc->vid = (data[3] >> RTL8367B_VLAN_MC3_EVID_SHIFT) & ++ RTL8367B_VLAN_MC3_EVID_MASK; ++ ++ return 0; ++} ++ ++static int rtl8367b_set_vlan_mc(struct rtl8366_smi *smi, u32 index, ++ const struct rtl8366_vlan_mc *vlanmc) ++{ ++ u32 data[RTL8367B_VLAN_MC_NUM_WORDS]; ++ int err; ++ int i; ++ ++ if (index >= RTL8367B_NUM_VLANS || ++ vlanmc->vid >= RTL8367B_NUM_VIDS || ++ vlanmc->priority > RTL8367B_PRIORITYMAX || ++ vlanmc->member > RTL8367B_VLAN_MC0_MEMBER_MASK || ++ vlanmc->untag > RTL8367B_UNTAG_MASK || ++ vlanmc->fid > ((smi->rtl8367b_chip >= RTL8367B_CHIP_RTL8367S_VB) ? RTL8367D_FIDMAX : RTL8367B_FIDMAX)) ++ return -EINVAL; ++ ++ if (smi->emu_vlanmc) { /* use vlanmc emulation */ ++ smi->emu_vlanmc[index].vid = vlanmc->vid; ++ smi->emu_vlanmc[index].member = vlanmc->member; ++ smi->emu_vlanmc[index].fid = vlanmc->fid; ++ smi->emu_vlanmc[index].untag = vlanmc->untag; ++ return 0; ++ } ++ ++ data[0] = (vlanmc->member & RTL8367B_VLAN_MC0_MEMBER_MASK) << ++ RTL8367B_VLAN_MC0_MEMBER_SHIFT; ++ data[1] = (vlanmc->fid & RTL8367B_VLAN_MC1_FID_MASK) << ++ RTL8367B_VLAN_MC1_FID_SHIFT; ++ data[2] = 0; ++ data[3] = (vlanmc->vid & RTL8367B_VLAN_MC3_EVID_MASK) << ++ RTL8367B_VLAN_MC3_EVID_SHIFT; ++ ++ for (i = 0; i < ARRAY_SIZE(data); i++) ++ REG_WR(smi, RTL8367B_VLAN_MC_BASE(index) + i, data[i]); ++ ++ return 0; ++} ++ ++static int rtl8367b_get_mc_index(struct rtl8366_smi *smi, int port, int *val) ++{ ++ u32 data; ++ int err; ++ ++ if (port >= RTL8367B_NUM_PORTS) ++ return -EINVAL; ++ ++ if (smi->rtl8367b_chip >= RTL8367B_CHIP_RTL8367S_VB) { /* Family D */ ++ int i; ++ struct rtl8366_vlan_mc vlanmc; ++ ++ err = rtl8366_smi_read_reg(smi, RTL8367D_VLAN_PVID_CTRL_REG(port), &data); ++ ++ if (err) { ++ dev_err(smi->parent, "read pvid register 0x%04x fail", RTL8367D_VLAN_PVID_CTRL_REG(port)); ++ return err; ++ } ++ ++ data &= RTL8367D_VLAN_PVID_CTRL_MASK; ++ for (i = 0; i < smi->num_vlan_mc; i++) { ++ err = rtl8367b_get_vlan_mc(smi, i, &vlanmc); ++ ++ if (err) { ++ dev_err(smi->parent, "get vlan mc index %d fail", i); ++ return err; ++ } ++ ++ if (data == vlanmc.vid) break; ++ } ++ ++ if (i < smi->num_vlan_mc) { ++ *val = i; ++ } else { ++ dev_err(smi->parent, "vlan mc index for pvid %d not found", data); ++ return -EINVAL; ++ } ++ } else { ++ REG_RD(smi, RTL8367B_VLAN_PVID_CTRL_REG(port), &data); ++ ++ *val = (data >> RTL8367B_VLAN_PVID_CTRL_SHIFT(port)) & ++ RTL8367B_VLAN_PVID_CTRL_MASK; ++ } ++ ++ return 0; ++} ++ ++static int rtl8367b_set_mc_index(struct rtl8366_smi *smi, int port, int index) ++{ ++ if (port >= RTL8367B_NUM_PORTS || index >= RTL8367B_NUM_VLANS) ++ return -EINVAL; ++ ++ if (smi->rtl8367b_chip >= RTL8367B_CHIP_RTL8367S_VB) { /* Family D */ ++ int pvid, err; ++ struct rtl8366_vlan_mc vlanmc; ++ ++ err = rtl8367b_get_vlan_mc(smi, index, &vlanmc); ++ ++ if (err) { ++ dev_err(smi->parent, "get vlan mc index %d fail", index); ++ return err; ++ } ++ ++ pvid = vlanmc.vid & RTL8367D_VLAN_PVID_CTRL_MASK; ++ err = rtl8366_smi_write_reg(smi, RTL8367D_VLAN_PVID_CTRL_REG(port), pvid); ++ ++ if (err) { ++ dev_err(smi->parent, "set port %d pvid %d fail", port, pvid); ++ return err; ++ } ++ ++ return 0; ++ } else ++ return rtl8366_smi_rmwr(smi, RTL8367B_VLAN_PVID_CTRL_REG(port), ++ RTL8367B_VLAN_PVID_CTRL_MASK << ++ RTL8367B_VLAN_PVID_CTRL_SHIFT(port), ++ (index & RTL8367B_VLAN_PVID_CTRL_MASK) << ++ RTL8367B_VLAN_PVID_CTRL_SHIFT(port)); ++} ++ ++static int rtl8367b_enable_vlan(struct rtl8366_smi *smi, int enable) ++{ ++ return rtl8366_smi_rmwr(smi, RTL8367B_VLAN_CTRL_REG, ++ RTL8367B_VLAN_CTRL_ENABLE, ++ (enable) ? RTL8367B_VLAN_CTRL_ENABLE : 0); ++} ++ ++static int rtl8367b_enable_vlan4k(struct rtl8366_smi *smi, int enable) ++{ ++ return 0; ++} ++ ++static int rtl8367b_is_vlan_valid(struct rtl8366_smi *smi, unsigned vlan) ++{ ++ unsigned max = RTL8367B_NUM_VLANS; ++ ++ if (smi->vlan4k_enabled) ++ max = RTL8367B_NUM_VIDS - 1; ++ ++ if (vlan == 0 || vlan >= max) ++ return 0; ++ ++ return 1; ++} ++ ++static int rtl8367b_enable_port(struct rtl8366_smi *smi, int port, int enable) ++{ ++ int err; ++ ++ REG_WR(smi, RTL8367B_PORT_ISOLATION_REG(port), ++ (enable) ? RTL8367B_PORTS_ALL : 0); ++ ++ return 0; ++} ++ ++static int rtl8367b_sw_reset_mibs(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ ++ return rtl8366_smi_rmwr(smi, RTL8367B_MIB_CTRL0_REG(0), 0, ++ RTL8367B_MIB_CTRL0_GLOBAL_RESET_MASK); ++} ++ ++static int rtl8367b_sw_get_port_link(struct switch_dev *dev, ++ int port, ++ struct switch_port_link *link) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ u32 data = 0; ++ u32 speed; ++ ++ if (port >= RTL8367B_NUM_PORTS) ++ return -EINVAL; ++ ++ if (smi->rtl8367b_chip >= RTL8367B_CHIP_RTL8367S_VB) /* Family D */ ++ rtl8366_smi_read_reg(smi, RTL8367D_PORT_STATUS_REG(port), &data); ++ else ++ rtl8366_smi_read_reg(smi, RTL8367B_PORT_STATUS_REG(port), &data); ++ ++ link->link = !!(data & RTL8367B_PORT_STATUS_LINK); ++ if (!link->link) ++ return 0; ++ ++ link->duplex = !!(data & RTL8367B_PORT_STATUS_DUPLEX); ++ link->rx_flow = !!(data & RTL8367B_PORT_STATUS_RXPAUSE); ++ link->tx_flow = !!(data & RTL8367B_PORT_STATUS_TXPAUSE); ++ link->aneg = !!(data & RTL8367B_PORT_STATUS_NWAY); ++ ++ if (smi->rtl8367b_chip >= RTL8367B_CHIP_RTL8367S_VB) /* Family D */ ++ speed = (data & RTL8367B_PORT_STATUS_SPEED_MASK) | ((data & RTL8367D_PORT_STATUS_SPEED1_MASK) >> RTL8367D_PORT_STATUS_SPEED1_SHIFT); ++ else ++ speed = (data & RTL8367B_PORT_STATUS_SPEED_MASK); ++ switch (speed) { ++ case RTL8367B_PORT_STATUS_SPEED_10: ++ link->speed = SWITCH_PORT_SPEED_10; ++ break; ++ case RTL8367B_PORT_STATUS_SPEED_100: ++ link->speed = SWITCH_PORT_SPEED_100; ++ break; ++ case RTL8367B_PORT_STATUS_SPEED_1000: ++ link->speed = SWITCH_PORT_SPEED_1000; ++ break; ++ default: ++ link->speed = SWITCH_PORT_SPEED_UNKNOWN; ++ break; ++ } ++ ++ return 0; ++} ++ ++static int rtl8367b_sw_get_max_length(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ u32 data; ++ ++ rtl8366_smi_read_reg(smi, RTL8367B_SWC0_REG, &data); ++ val->value.i = (data & RTL8367B_SWC0_MAX_LENGTH_MASK) >> ++ RTL8367B_SWC0_MAX_LENGTH_SHIFT; ++ ++ return 0; ++} ++ ++static int rtl8367b_sw_set_max_length(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ u32 max_len; ++ ++ switch (val->value.i) { ++ case 0: ++ max_len = RTL8367B_SWC0_MAX_LENGTH_1522; ++ break; ++ case 1: ++ max_len = RTL8367B_SWC0_MAX_LENGTH_1536; ++ break; ++ case 2: ++ max_len = RTL8367B_SWC0_MAX_LENGTH_1552; ++ break; ++ case 3: ++ max_len = RTL8367B_SWC0_MAX_LENGTH_16000; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return rtl8366_smi_rmwr(smi, RTL8367B_SWC0_REG, ++ RTL8367B_SWC0_MAX_LENGTH_MASK, max_len); ++} ++ ++ ++static int rtl8367b_sw_reset_port_mibs(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); ++ int port; ++ ++ port = val->port_vlan; ++ if (port >= RTL8367B_NUM_PORTS) ++ return -EINVAL; ++ ++ return rtl8366_smi_rmwr(smi, RTL8367B_MIB_CTRL0_REG(port / 8), 0, ++ RTL8367B_MIB_CTRL0_PORT_RESET_MASK(port % 8)); ++} ++ ++static int rtl8367b_sw_get_port_stats(struct switch_dev *dev, int port, ++ struct switch_port_stats *stats) ++{ ++ return (rtl8366_sw_get_port_stats(dev, port, stats, ++ RTL8367B_MIB_TXB_ID, RTL8367B_MIB_RXB_ID)); ++} ++ ++static struct switch_attr rtl8367b_globals[] = { ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "enable_vlan", ++ .description = "Enable VLAN mode", ++ .set = rtl8366_sw_set_vlan_enable, ++ .get = rtl8366_sw_get_vlan_enable, ++ .max = 1, ++ .ofs = 1 ++ }, { ++ .type = SWITCH_TYPE_INT, ++ .name = "enable_vlan4k", ++ .description = "Enable VLAN 4K mode", ++ .set = rtl8366_sw_set_vlan_enable, ++ .get = rtl8366_sw_get_vlan_enable, ++ .max = 1, ++ .ofs = 2 ++ }, { ++ .type = SWITCH_TYPE_NOVAL, ++ .name = "reset_mibs", ++ .description = "Reset all MIB counters", ++ .set = rtl8367b_sw_reset_mibs, ++ }, { ++ .type = SWITCH_TYPE_INT, ++ .name = "max_length", ++ .description = "Get/Set the maximum length of valid packets" ++ "(0:1522, 1:1536, 2:1552, 3:16000)", ++ .set = rtl8367b_sw_set_max_length, ++ .get = rtl8367b_sw_get_max_length, ++ .max = 3, ++ } ++}; ++ ++static struct switch_attr rtl8367b_port[] = { ++ { ++ .type = SWITCH_TYPE_NOVAL, ++ .name = "reset_mib", ++ .description = "Reset single port MIB counters", ++ .set = rtl8367b_sw_reset_port_mibs, ++ }, { ++ .type = SWITCH_TYPE_STRING, ++ .name = "mib", ++ .description = "Get MIB counters for port", ++ .max = 33, ++ .set = NULL, ++ .get = rtl8366_sw_get_port_mib, ++ }, ++}; ++ ++static struct switch_attr rtl8367b_vlan[] = { ++ { ++ .type = SWITCH_TYPE_STRING, ++ .name = "info", ++ .description = "Get vlan information", ++ .max = 1, ++ .set = NULL, ++ .get = rtl8366_sw_get_vlan_info, ++ }, ++}; ++ ++static const struct switch_dev_ops rtl8367b_sw_ops = { ++ .attr_global = { ++ .attr = rtl8367b_globals, ++ .n_attr = ARRAY_SIZE(rtl8367b_globals), ++ }, ++ .attr_port = { ++ .attr = rtl8367b_port, ++ .n_attr = ARRAY_SIZE(rtl8367b_port), ++ }, ++ .attr_vlan = { ++ .attr = rtl8367b_vlan, ++ .n_attr = ARRAY_SIZE(rtl8367b_vlan), ++ }, ++ ++ .get_vlan_ports = rtl8366_sw_get_vlan_ports, ++ .set_vlan_ports = rtl8366_sw_set_vlan_ports, ++ .get_port_pvid = rtl8366_sw_get_port_pvid, ++ .set_port_pvid = rtl8366_sw_set_port_pvid, ++ .reset_switch = rtl8366_sw_reset_switch, ++ .get_port_link = rtl8367b_sw_get_port_link, ++ .get_port_stats = rtl8367b_sw_get_port_stats, ++}; ++ ++static int rtl8367b_switch_init(struct rtl8366_smi *smi) ++{ ++ struct switch_dev *dev = &smi->sw_dev; ++ int err; ++ ++ dev->name = "RTL8367B"; ++ dev->cpu_port = smi->cpu_port; ++ dev->ports = RTL8367B_NUM_PORTS; ++ dev->vlans = RTL8367B_NUM_VIDS; ++ dev->ops = &rtl8367b_sw_ops; ++ dev->alias = dev_name(smi->parent); ++ ++ err = register_switch(dev, NULL); ++ if (err) ++ dev_err(smi->parent, "switch registration failed\n"); ++ ++ return err; ++} ++ ++static void rtl8367b_switch_cleanup(struct rtl8366_smi *smi) ++{ ++ unregister_switch(&smi->sw_dev); ++} ++ ++static int rtl8367b_mii_read(struct mii_bus *bus, int addr, int reg) ++{ ++ struct rtl8366_smi *smi = bus->priv; ++ u32 val = 0; ++ int err; ++ ++ err = rtl8367b_read_phy_reg(smi, addr, reg, &val); ++ if (err) ++ return 0xffff; ++ ++ return val; ++} ++ ++static int rtl8367b_mii_write(struct mii_bus *bus, int addr, int reg, u16 val) ++{ ++ struct rtl8366_smi *smi = bus->priv; ++ u32 t; ++ int err; ++ ++ err = rtl8367b_write_phy_reg(smi, addr, reg, val); ++ if (err) ++ return err; ++ ++ /* flush write */ ++ (void) rtl8367b_read_phy_reg(smi, addr, reg, &t); ++ ++ return err; ++} ++ ++static int rtl8367b_detect(struct rtl8366_smi *smi) ++{ ++ const char *chip_name = NULL; ++ u32 chip_num; ++ u32 chip_ver; ++ int ret; ++ ++ smi->emu_vlanmc = NULL; ++ smi->rtl8367b_chip = RTL8367B_CHIP_UNKNOWN; ++ ++ rtl8366_smi_write_reg(smi, RTL8367B_RTL_MAGIC_ID_REG, ++ RTL8367B_RTL_MAGIC_ID_VAL); ++ ++ ret = rtl8366_smi_read_reg(smi, RTL8367B_CHIP_NUMBER_REG, &chip_num); ++ if (ret) { ++ dev_err(smi->parent, "unable to read %s register\n", ++ "chip number"); ++ return ret; ++ } ++ ++ ret = rtl8366_smi_read_reg(smi, RTL8367B_CHIP_VER_REG, &chip_ver); ++ if (ret) { ++ dev_err(smi->parent, "unable to read %s register\n", ++ "chip version"); ++ return ret; ++ } ++ ++ switch (chip_ver) { ++ case 0x0010: ++ if (chip_num == 0x6642) { ++ chip_name = "8367S-VB"; ++ smi->rtl8367b_chip = RTL8367B_CHIP_RTL8367S_VB; ++ } ++ break; ++ case 0x0020: ++ if (chip_num == 0x6367) { ++ chip_name = "8367RB-VB"; ++ smi->rtl8367b_chip = RTL8367B_CHIP_RTL8367RB_VB; ++ } ++ break; ++ case 0x00A0: ++ if (chip_num == 0x6367) { ++ chip_name = "8367S"; ++ smi->rtl8367b_chip = RTL8367B_CHIP_RTL8367S; ++ } ++ break; ++ case 0x1000: ++ chip_name = "8367RB"; ++ smi->rtl8367b_chip = RTL8367B_CHIP_RTL8367RB; ++ break; ++ case 0x1010: ++ chip_name = "8367R-VB"; ++ smi->rtl8367b_chip = RTL8367B_CHIP_RTL8367R_VB; ++ } ++ ++ if (!chip_name) { ++ dev_err(smi->parent, ++ "unknown chip (num:%04x ver:%04x)\n", ++ chip_num, chip_ver); ++ return -ENODEV; ++ } ++ ++ dev_info(smi->parent, "RTL%s chip found (num:%04x ver:%04x)\n", chip_name, chip_num, chip_ver); ++ ++ return 0; ++} ++ ++static struct rtl8366_smi_ops rtl8367b_smi_ops = { ++ .detect = rtl8367b_detect, ++ .reset_chip = rtl8367b_reset_chip, ++ .setup = rtl8367b_setup, ++ ++ .mii_read = rtl8367b_mii_read, ++ .mii_write = rtl8367b_mii_write, ++ ++ .get_vlan_mc = rtl8367b_get_vlan_mc, ++ .set_vlan_mc = rtl8367b_set_vlan_mc, ++ .get_vlan_4k = rtl8367b_get_vlan_4k, ++ .set_vlan_4k = rtl8367b_set_vlan_4k, ++ .get_mc_index = rtl8367b_get_mc_index, ++ .set_mc_index = rtl8367b_set_mc_index, ++ .get_mib_counter = rtl8367b_get_mib_counter, ++ .is_vlan_valid = rtl8367b_is_vlan_valid, ++ .enable_vlan = rtl8367b_enable_vlan, ++ .enable_vlan4k = rtl8367b_enable_vlan4k, ++ .enable_port = rtl8367b_enable_port, ++}; ++ ++static int rtl8367b_probe(struct platform_device *pdev) ++{ ++ struct rtl8366_smi *smi; ++ int err; ++ ++ smi = rtl8366_smi_probe(pdev); ++ if (IS_ERR(smi)) ++ return PTR_ERR(smi); ++ ++ smi->clk_delay = 1500; ++ smi->cmd_read = 0xb9; ++ smi->cmd_write = 0xb8; ++ smi->ops = &rtl8367b_smi_ops; ++ smi->num_ports = RTL8367B_NUM_PORTS; ++ smi->cpu_port = UINT_MAX; /* not defined yet */ ++ smi->num_vlan_mc = RTL8367B_NUM_VLANS; ++ smi->mib_counters = rtl8367b_mib_counters; ++ smi->num_mib_counters = ARRAY_SIZE(rtl8367b_mib_counters); ++ ++ err = rtl8366_smi_init(smi); ++ if (err) ++ goto err_free_smi; ++ ++ platform_set_drvdata(pdev, smi); ++ ++ err = rtl8367b_switch_init(smi); ++ if (err) ++ goto err_clear_drvdata; ++ ++ return 0; ++ ++ err_clear_drvdata: ++ platform_set_drvdata(pdev, NULL); ++ rtl8366_smi_cleanup(smi); ++ err_free_smi: ++ if (smi->emu_vlanmc) ++ kfree(smi->emu_vlanmc); ++ kfree(smi); ++ return err; ++} ++ ++static void rtl8367b_remove(struct platform_device *pdev) ++{ ++ struct rtl8366_smi *smi = platform_get_drvdata(pdev); ++ ++ if (smi) { ++ rtl8367b_switch_cleanup(smi); ++ platform_set_drvdata(pdev, NULL); ++ rtl8366_smi_cleanup(smi); ++ kfree(smi); ++ } ++} ++ ++static void rtl8367b_shutdown(struct platform_device *pdev) ++{ ++ struct rtl8366_smi *smi = platform_get_drvdata(pdev); ++ ++ if (smi) ++ rtl8367b_reset_chip(smi); ++} ++ ++#ifdef CONFIG_OF ++static const struct of_device_id rtl8367b_match[] = { ++ { .compatible = "realtek,rtl8367b" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, rtl8367b_match); ++#endif ++ ++static struct platform_driver rtl8367b_driver = { ++ .driver = { ++ .name = RTL8367B_DRIVER_NAME, ++#ifdef CONFIG_OF ++ .of_match_table = of_match_ptr(rtl8367b_match), ++#endif ++ }, ++ .probe = rtl8367b_probe, ++ .remove_new = rtl8367b_remove, ++ .shutdown = rtl8367b_shutdown, ++}; ++ ++module_platform_driver(rtl8367b_driver); ++ ++MODULE_DESCRIPTION("Realtek RTL8367B ethernet switch driver"); ++MODULE_AUTHOR("Gabor Juhos "); ++MODULE_LICENSE("GPL v2"); ++MODULE_ALIAS("platform:" RTL8367B_DRIVER_NAME); ++ +diff --git a/drivers/net/phy/swconfig.c b/drivers/net/phy/swconfig.c +new file mode 100644 +index 000000000000..71dd5b31f541 +--- /dev/null ++++ b/drivers/net/phy/swconfig.c +@@ -0,0 +1,1242 @@ ++/* ++ * swconfig.c: Switch configuration API ++ * ++ * Copyright (C) 2008 Felix Fietkau ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version 2 ++ * of the License, or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define SWCONFIG_DEVNAME "switch%d" ++ ++#include "swconfig_leds.c" ++ ++MODULE_AUTHOR("Felix Fietkau "); ++MODULE_LICENSE("GPL"); ++ ++static int swdev_id; ++static struct list_head swdevs; ++static DEFINE_MUTEX(swdevs_lock); ++struct swconfig_callback; ++ ++struct swconfig_callback { ++ struct sk_buff *msg; ++ struct genlmsghdr *hdr; ++ struct genl_info *info; ++ int cmd; ++ ++ /* callback for filling in the message data */ ++ int (*fill)(struct swconfig_callback *cb, void *arg); ++ ++ /* callback for closing the message before sending it */ ++ int (*close)(struct swconfig_callback *cb, void *arg); ++ ++ struct nlattr *nest[4]; ++ int args[4]; ++}; ++ ++/* defaults */ ++ ++static int ++swconfig_get_vlan_ports(struct switch_dev *dev, const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ int ret; ++ if (val->port_vlan >= dev->vlans) ++ return -EINVAL; ++ ++ if (!dev->ops->get_vlan_ports) ++ return -EOPNOTSUPP; ++ ++ ret = dev->ops->get_vlan_ports(dev, val); ++ return ret; ++} ++ ++static int ++swconfig_set_vlan_ports(struct switch_dev *dev, const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct switch_port *ports = val->value.ports; ++ const struct switch_dev_ops *ops = dev->ops; ++ int i; ++ ++ if (val->port_vlan >= dev->vlans) ++ return -EINVAL; ++ ++ /* validate ports */ ++ if (val->len > dev->ports) ++ return -EINVAL; ++ ++ if (!ops->set_vlan_ports) ++ return -EOPNOTSUPP; ++ ++ for (i = 0; i < val->len; i++) { ++ if (ports[i].id >= dev->ports) ++ return -EINVAL; ++ ++ if (ops->set_port_pvid && ++ !(ports[i].flags & (1 << SWITCH_PORT_FLAG_TAGGED))) ++ ops->set_port_pvid(dev, ports[i].id, val->port_vlan); ++ } ++ ++ return ops->set_vlan_ports(dev, val); ++} ++ ++static int ++swconfig_set_pvid(struct switch_dev *dev, const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ if (val->port_vlan >= dev->ports) ++ return -EINVAL; ++ ++ if (!dev->ops->set_port_pvid) ++ return -EOPNOTSUPP; ++ ++ return dev->ops->set_port_pvid(dev, val->port_vlan, val->value.i); ++} ++ ++static int ++swconfig_get_pvid(struct switch_dev *dev, const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ if (val->port_vlan >= dev->ports) ++ return -EINVAL; ++ ++ if (!dev->ops->get_port_pvid) ++ return -EOPNOTSUPP; ++ ++ return dev->ops->get_port_pvid(dev, val->port_vlan, &val->value.i); ++} ++ ++static int ++swconfig_set_link(struct switch_dev *dev, const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ if (!dev->ops->set_port_link) ++ return -EOPNOTSUPP; ++ ++ return dev->ops->set_port_link(dev, val->port_vlan, val->value.link); ++} ++ ++static int ++swconfig_get_link(struct switch_dev *dev, const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct switch_port_link *link = val->value.link; ++ ++ if (val->port_vlan >= dev->ports) ++ return -EINVAL; ++ ++ if (!dev->ops->get_port_link) ++ return -EOPNOTSUPP; ++ ++ memset(link, 0, sizeof(*link)); ++ return dev->ops->get_port_link(dev, val->port_vlan, link); ++} ++ ++static int ++swconfig_apply_config(struct switch_dev *dev, const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ /* don't complain if not supported by the switch driver */ ++ if (!dev->ops->apply_config) ++ return 0; ++ ++ return dev->ops->apply_config(dev); ++} ++ ++static int ++swconfig_reset_switch(struct switch_dev *dev, const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ /* don't complain if not supported by the switch driver */ ++ if (!dev->ops->reset_switch) ++ return 0; ++ ++ return dev->ops->reset_switch(dev); ++} ++ ++enum global_defaults { ++ GLOBAL_APPLY, ++ GLOBAL_RESET, ++}; ++ ++enum vlan_defaults { ++ VLAN_PORTS, ++}; ++ ++enum port_defaults { ++ PORT_PVID, ++ PORT_LINK, ++}; ++ ++static struct switch_attr default_global[] = { ++ [GLOBAL_APPLY] = { ++ .type = SWITCH_TYPE_NOVAL, ++ .name = "apply", ++ .description = "Activate changes in the hardware", ++ .set = swconfig_apply_config, ++ }, ++ [GLOBAL_RESET] = { ++ .type = SWITCH_TYPE_NOVAL, ++ .name = "reset", ++ .description = "Reset the switch", ++ .set = swconfig_reset_switch, ++ } ++}; ++ ++static struct switch_attr default_port[] = { ++ [PORT_PVID] = { ++ .type = SWITCH_TYPE_INT, ++ .name = "pvid", ++ .description = "Primary VLAN ID", ++ .set = swconfig_set_pvid, ++ .get = swconfig_get_pvid, ++ }, ++ [PORT_LINK] = { ++ .type = SWITCH_TYPE_LINK, ++ .name = "link", ++ .description = "Get port link information", ++ .set = swconfig_set_link, ++ .get = swconfig_get_link, ++ } ++}; ++ ++static struct switch_attr default_vlan[] = { ++ [VLAN_PORTS] = { ++ .type = SWITCH_TYPE_PORTS, ++ .name = "ports", ++ .description = "VLAN port mapping", ++ .set = swconfig_set_vlan_ports, ++ .get = swconfig_get_vlan_ports, ++ }, ++}; ++ ++static const struct switch_attr * ++swconfig_find_attr_by_name(const struct switch_attrlist *alist, ++ const char *name) ++{ ++ int i; ++ ++ for (i = 0; i < alist->n_attr; i++) ++ if (strcmp(name, alist->attr[i].name) == 0) ++ return &alist->attr[i]; ++ ++ return NULL; ++} ++ ++static void swconfig_defaults_init(struct switch_dev *dev) ++{ ++ const struct switch_dev_ops *ops = dev->ops; ++ ++ dev->def_global = 0; ++ dev->def_vlan = 0; ++ dev->def_port = 0; ++ ++ if (ops->get_vlan_ports || ops->set_vlan_ports) ++ set_bit(VLAN_PORTS, &dev->def_vlan); ++ ++ if (ops->get_port_pvid || ops->set_port_pvid) ++ set_bit(PORT_PVID, &dev->def_port); ++ ++ if (ops->get_port_link && ++ !swconfig_find_attr_by_name(&ops->attr_port, "link")) ++ set_bit(PORT_LINK, &dev->def_port); ++ ++ /* always present, can be no-op */ ++ set_bit(GLOBAL_APPLY, &dev->def_global); ++ set_bit(GLOBAL_RESET, &dev->def_global); ++} ++ ++ ++static struct genl_family switch_fam; ++ ++static const struct nla_policy switch_policy[SWITCH_ATTR_MAX+1] = { ++ [SWITCH_ATTR_ID] = { .type = NLA_U32 }, ++ [SWITCH_ATTR_OP_ID] = { .type = NLA_U32 }, ++ [SWITCH_ATTR_OP_PORT] = { .type = NLA_U32 }, ++ [SWITCH_ATTR_OP_VLAN] = { .type = NLA_U32 }, ++ [SWITCH_ATTR_OP_VALUE_INT] = { .type = NLA_U32 }, ++ [SWITCH_ATTR_OP_VALUE_STR] = { .type = NLA_NUL_STRING }, ++ [SWITCH_ATTR_OP_VALUE_PORTS] = { .type = NLA_NESTED }, ++ [SWITCH_ATTR_TYPE] = { .type = NLA_U32 }, ++}; ++ ++static const struct nla_policy port_policy[SWITCH_PORT_ATTR_MAX+1] = { ++ [SWITCH_PORT_ID] = { .type = NLA_U32 }, ++ [SWITCH_PORT_FLAG_TAGGED] = { .type = NLA_FLAG }, ++}; ++ ++static struct nla_policy link_policy[SWITCH_LINK_ATTR_MAX] = { ++ [SWITCH_LINK_FLAG_DUPLEX] = { .type = NLA_FLAG }, ++ [SWITCH_LINK_FLAG_ANEG] = { .type = NLA_FLAG }, ++ [SWITCH_LINK_SPEED] = { .type = NLA_U32 }, ++}; ++ ++static inline void ++swconfig_lock(void) ++{ ++ mutex_lock(&swdevs_lock); ++} ++ ++static inline void ++swconfig_unlock(void) ++{ ++ mutex_unlock(&swdevs_lock); ++} ++ ++static struct switch_dev * ++swconfig_get_dev(struct genl_info *info) ++{ ++ struct switch_dev *dev = NULL; ++ struct switch_dev *p; ++ int id; ++ ++ if (!info->attrs[SWITCH_ATTR_ID]) ++ goto done; ++ ++ id = nla_get_u32(info->attrs[SWITCH_ATTR_ID]); ++ swconfig_lock(); ++ list_for_each_entry(p, &swdevs, dev_list) { ++ if (id != p->id) ++ continue; ++ ++ dev = p; ++ break; ++ } ++ if (dev) ++ mutex_lock(&dev->sw_mutex); ++ else ++ pr_debug("device %d not found\n", id); ++ swconfig_unlock(); ++done: ++ return dev; ++} ++ ++static inline void ++swconfig_put_dev(struct switch_dev *dev) ++{ ++ mutex_unlock(&dev->sw_mutex); ++} ++ ++static int ++swconfig_dump_attr(struct swconfig_callback *cb, void *arg) ++{ ++ struct switch_attr *op = arg; ++ struct genl_info *info = cb->info; ++ struct sk_buff *msg = cb->msg; ++ int id = cb->args[0]; ++ void *hdr; ++ ++ hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq, &switch_fam, ++ NLM_F_MULTI, SWITCH_CMD_NEW_ATTR); ++ if (IS_ERR(hdr)) ++ return -1; ++ ++ if (nla_put_u32(msg, SWITCH_ATTR_OP_ID, id)) ++ goto nla_put_failure; ++ if (nla_put_u32(msg, SWITCH_ATTR_OP_TYPE, op->type)) ++ goto nla_put_failure; ++ if (nla_put_string(msg, SWITCH_ATTR_OP_NAME, op->name)) ++ goto nla_put_failure; ++ if (op->description) ++ if (nla_put_string(msg, SWITCH_ATTR_OP_DESCRIPTION, ++ op->description)) ++ goto nla_put_failure; ++ ++ genlmsg_end(msg, hdr); ++ return msg->len; ++nla_put_failure: ++ genlmsg_cancel(msg, hdr); ++ return -EMSGSIZE; ++} ++ ++/* spread multipart messages across multiple message buffers */ ++static int ++swconfig_send_multipart(struct swconfig_callback *cb, void *arg) ++{ ++ struct genl_info *info = cb->info; ++ int restart = 0; ++ int err; ++ ++ do { ++ if (!cb->msg) { ++ cb->msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); ++ if (cb->msg == NULL) ++ goto error; ++ } ++ ++ if (!(cb->fill(cb, arg) < 0)) ++ break; ++ ++ /* fill failed, check if this was already the second attempt */ ++ if (restart) ++ goto error; ++ ++ /* try again in a new message, send the current one */ ++ restart = 1; ++ if (cb->close) { ++ if (cb->close(cb, arg) < 0) ++ goto error; ++ } ++ err = genlmsg_reply(cb->msg, info); ++ cb->msg = NULL; ++ if (err < 0) ++ goto error; ++ ++ } while (restart); ++ ++ return 0; ++ ++error: ++ if (cb->msg) ++ nlmsg_free(cb->msg); ++ return -1; ++} ++ ++static int ++swconfig_list_attrs(struct sk_buff *skb, struct genl_info *info) ++{ ++ struct genlmsghdr *hdr = nlmsg_data(info->nlhdr); ++ const struct switch_attrlist *alist; ++ struct switch_dev *dev; ++ struct swconfig_callback cb; ++ int err = -EINVAL; ++ int i; ++ ++ /* defaults */ ++ struct switch_attr *def_list; ++ unsigned long *def_active; ++ int n_def; ++ ++ dev = swconfig_get_dev(info); ++ if (!dev) ++ return -EINVAL; ++ ++ switch (hdr->cmd) { ++ case SWITCH_CMD_LIST_GLOBAL: ++ alist = &dev->ops->attr_global; ++ def_list = default_global; ++ def_active = &dev->def_global; ++ n_def = ARRAY_SIZE(default_global); ++ break; ++ case SWITCH_CMD_LIST_VLAN: ++ alist = &dev->ops->attr_vlan; ++ def_list = default_vlan; ++ def_active = &dev->def_vlan; ++ n_def = ARRAY_SIZE(default_vlan); ++ break; ++ case SWITCH_CMD_LIST_PORT: ++ alist = &dev->ops->attr_port; ++ def_list = default_port; ++ def_active = &dev->def_port; ++ n_def = ARRAY_SIZE(default_port); ++ break; ++ default: ++ WARN_ON(1); ++ goto out; ++ } ++ ++ memset(&cb, 0, sizeof(cb)); ++ cb.info = info; ++ cb.fill = swconfig_dump_attr; ++ for (i = 0; i < alist->n_attr; i++) { ++ if (alist->attr[i].disabled) ++ continue; ++ cb.args[0] = i; ++ err = swconfig_send_multipart(&cb, (void *) &alist->attr[i]); ++ if (err < 0) ++ goto error; ++ } ++ ++ /* defaults */ ++ for (i = 0; i < n_def; i++) { ++ if (!test_bit(i, def_active)) ++ continue; ++ cb.args[0] = SWITCH_ATTR_DEFAULTS_OFFSET + i; ++ err = swconfig_send_multipart(&cb, (void *) &def_list[i]); ++ if (err < 0) ++ goto error; ++ } ++ swconfig_put_dev(dev); ++ ++ if (!cb.msg) ++ return 0; ++ ++ return genlmsg_reply(cb.msg, info); ++ ++error: ++ if (cb.msg) ++ nlmsg_free(cb.msg); ++out: ++ swconfig_put_dev(dev); ++ return err; ++} ++ ++static const struct switch_attr * ++swconfig_lookup_attr(struct switch_dev *dev, struct genl_info *info, ++ struct switch_val *val) ++{ ++ struct genlmsghdr *hdr = nlmsg_data(info->nlhdr); ++ const struct switch_attrlist *alist; ++ const struct switch_attr *attr = NULL; ++ unsigned int attr_id; ++ ++ /* defaults */ ++ struct switch_attr *def_list; ++ unsigned long *def_active; ++ int n_def; ++ ++ if (!info->attrs[SWITCH_ATTR_OP_ID]) ++ goto done; ++ ++ switch (hdr->cmd) { ++ case SWITCH_CMD_SET_GLOBAL: ++ case SWITCH_CMD_GET_GLOBAL: ++ alist = &dev->ops->attr_global; ++ def_list = default_global; ++ def_active = &dev->def_global; ++ n_def = ARRAY_SIZE(default_global); ++ break; ++ case SWITCH_CMD_SET_VLAN: ++ case SWITCH_CMD_GET_VLAN: ++ alist = &dev->ops->attr_vlan; ++ def_list = default_vlan; ++ def_active = &dev->def_vlan; ++ n_def = ARRAY_SIZE(default_vlan); ++ if (!info->attrs[SWITCH_ATTR_OP_VLAN]) ++ goto done; ++ val->port_vlan = nla_get_u32(info->attrs[SWITCH_ATTR_OP_VLAN]); ++ if (val->port_vlan >= dev->vlans) ++ goto done; ++ break; ++ case SWITCH_CMD_SET_PORT: ++ case SWITCH_CMD_GET_PORT: ++ alist = &dev->ops->attr_port; ++ def_list = default_port; ++ def_active = &dev->def_port; ++ n_def = ARRAY_SIZE(default_port); ++ if (!info->attrs[SWITCH_ATTR_OP_PORT]) ++ goto done; ++ val->port_vlan = nla_get_u32(info->attrs[SWITCH_ATTR_OP_PORT]); ++ if (val->port_vlan >= dev->ports) ++ goto done; ++ break; ++ default: ++ WARN_ON(1); ++ goto done; ++ } ++ ++ if (!alist) ++ goto done; ++ ++ attr_id = nla_get_u32(info->attrs[SWITCH_ATTR_OP_ID]); ++ if (attr_id >= SWITCH_ATTR_DEFAULTS_OFFSET) { ++ attr_id -= SWITCH_ATTR_DEFAULTS_OFFSET; ++ if (attr_id >= n_def) ++ goto done; ++ if (!test_bit(attr_id, def_active)) ++ goto done; ++ attr = &def_list[attr_id]; ++ } else { ++ if (attr_id >= alist->n_attr) ++ goto done; ++ attr = &alist->attr[attr_id]; ++ } ++ ++ if (attr->disabled) ++ attr = NULL; ++ ++done: ++ if (!attr) ++ pr_debug("attribute lookup failed\n"); ++ val->attr = attr; ++ return attr; ++} ++ ++static int ++swconfig_parse_ports(struct sk_buff *msg, struct nlattr *head, ++ struct switch_val *val, int max) ++{ ++ struct nlattr *nla; ++ int rem; ++ ++ val->len = 0; ++ nla_for_each_nested(nla, head, rem) { ++ struct nlattr *tb[SWITCH_PORT_ATTR_MAX+1]; ++ struct switch_port *port; ++ ++ if (val->len >= max) ++ return -EINVAL; ++ ++ port = &val->value.ports[val->len]; ++ ++ if (nla_parse_nested_deprecated(tb, SWITCH_PORT_ATTR_MAX, nla, ++ port_policy, NULL)) ++ return -EINVAL; ++ ++ if (!tb[SWITCH_PORT_ID]) ++ return -EINVAL; ++ ++ port->id = nla_get_u32(tb[SWITCH_PORT_ID]); ++ if (tb[SWITCH_PORT_FLAG_TAGGED]) ++ port->flags |= (1 << SWITCH_PORT_FLAG_TAGGED); ++ val->len++; ++ } ++ ++ return 0; ++} ++ ++static int ++swconfig_parse_link(struct sk_buff *msg, struct nlattr *nla, ++ struct switch_port_link *link) ++{ ++ struct nlattr *tb[SWITCH_LINK_ATTR_MAX + 1]; ++ ++ if (nla_parse_nested_deprecated(tb, SWITCH_LINK_ATTR_MAX, nla, link_policy, NULL)) ++ return -EINVAL; ++ ++ link->duplex = !!tb[SWITCH_LINK_FLAG_DUPLEX]; ++ link->aneg = !!tb[SWITCH_LINK_FLAG_ANEG]; ++ link->speed = nla_get_u32(tb[SWITCH_LINK_SPEED]); ++ ++ return 0; ++} ++ ++static int ++swconfig_set_attr(struct sk_buff *skb, struct genl_info *info) ++{ ++ const struct switch_attr *attr; ++ struct switch_dev *dev; ++ struct switch_val val; ++ int err = -EINVAL; ++ ++ if (!capable(CAP_NET_ADMIN)) ++ return -EPERM; ++ ++ dev = swconfig_get_dev(info); ++ if (!dev) ++ return -EINVAL; ++ ++ memset(&val, 0, sizeof(val)); ++ attr = swconfig_lookup_attr(dev, info, &val); ++ if (!attr || !attr->set) ++ goto error; ++ ++ val.attr = attr; ++ switch (attr->type) { ++ case SWITCH_TYPE_NOVAL: ++ break; ++ case SWITCH_TYPE_INT: ++ if (!info->attrs[SWITCH_ATTR_OP_VALUE_INT]) ++ goto error; ++ val.value.i = ++ nla_get_u32(info->attrs[SWITCH_ATTR_OP_VALUE_INT]); ++ break; ++ case SWITCH_TYPE_STRING: ++ if (!info->attrs[SWITCH_ATTR_OP_VALUE_STR]) ++ goto error; ++ val.value.s = ++ nla_data(info->attrs[SWITCH_ATTR_OP_VALUE_STR]); ++ break; ++ case SWITCH_TYPE_PORTS: ++ val.value.ports = dev->portbuf; ++ memset(dev->portbuf, 0, ++ sizeof(struct switch_port) * dev->ports); ++ ++ /* TODO: implement multipart? */ ++ if (info->attrs[SWITCH_ATTR_OP_VALUE_PORTS]) { ++ err = swconfig_parse_ports(skb, ++ info->attrs[SWITCH_ATTR_OP_VALUE_PORTS], ++ &val, dev->ports); ++ if (err < 0) ++ goto error; ++ } else { ++ val.len = 0; ++ err = 0; ++ } ++ break; ++ case SWITCH_TYPE_LINK: ++ val.value.link = &dev->linkbuf; ++ memset(&dev->linkbuf, 0, sizeof(struct switch_port_link)); ++ ++ if (info->attrs[SWITCH_ATTR_OP_VALUE_LINK]) { ++ err = swconfig_parse_link(skb, ++ info->attrs[SWITCH_ATTR_OP_VALUE_LINK], ++ val.value.link); ++ if (err < 0) ++ goto error; ++ } else { ++ val.len = 0; ++ err = 0; ++ } ++ break; ++ default: ++ goto error; ++ } ++ ++ err = attr->set(dev, attr, &val); ++error: ++ swconfig_put_dev(dev); ++ return err; ++} ++ ++static int ++swconfig_close_portlist(struct swconfig_callback *cb, void *arg) ++{ ++ if (cb->nest[0]) ++ nla_nest_end(cb->msg, cb->nest[0]); ++ return 0; ++} ++ ++static int ++swconfig_send_port(struct swconfig_callback *cb, void *arg) ++{ ++ const struct switch_port *port = arg; ++ struct nlattr *p = NULL; ++ ++ if (!cb->nest[0]) { ++ cb->nest[0] = nla_nest_start(cb->msg, cb->cmd); ++ if (!cb->nest[0]) ++ return -1; ++ } ++ ++ p = nla_nest_start(cb->msg, SWITCH_ATTR_PORT); ++ if (!p) ++ goto error; ++ ++ if (nla_put_u32(cb->msg, SWITCH_PORT_ID, port->id)) ++ goto nla_put_failure; ++ if (port->flags & (1 << SWITCH_PORT_FLAG_TAGGED)) { ++ if (nla_put_flag(cb->msg, SWITCH_PORT_FLAG_TAGGED)) ++ goto nla_put_failure; ++ } ++ ++ nla_nest_end(cb->msg, p); ++ return 0; ++ ++nla_put_failure: ++ nla_nest_cancel(cb->msg, p); ++error: ++ nla_nest_cancel(cb->msg, cb->nest[0]); ++ return -1; ++} ++ ++static int ++swconfig_send_ports(struct sk_buff **msg, struct genl_info *info, int attr, ++ const struct switch_val *val) ++{ ++ struct swconfig_callback cb; ++ int err = 0; ++ int i; ++ ++ if (!val->value.ports) ++ return -EINVAL; ++ ++ memset(&cb, 0, sizeof(cb)); ++ cb.cmd = attr; ++ cb.msg = *msg; ++ cb.info = info; ++ cb.fill = swconfig_send_port; ++ cb.close = swconfig_close_portlist; ++ ++ cb.nest[0] = nla_nest_start(cb.msg, cb.cmd); ++ for (i = 0; i < val->len; i++) { ++ err = swconfig_send_multipart(&cb, &val->value.ports[i]); ++ if (err) ++ goto done; ++ } ++ err = val->len; ++ swconfig_close_portlist(&cb, NULL); ++ *msg = cb.msg; ++ ++done: ++ return err; ++} ++ ++static int ++swconfig_send_link(struct sk_buff *msg, struct genl_info *info, int attr, ++ const struct switch_port_link *link) ++{ ++ struct nlattr *p = NULL; ++ int err = 0; ++ ++ p = nla_nest_start(msg, attr); ++ if (link->link) { ++ if (nla_put_flag(msg, SWITCH_LINK_FLAG_LINK)) ++ goto nla_put_failure; ++ } ++ if (link->duplex) { ++ if (nla_put_flag(msg, SWITCH_LINK_FLAG_DUPLEX)) ++ goto nla_put_failure; ++ } ++ if (link->aneg) { ++ if (nla_put_flag(msg, SWITCH_LINK_FLAG_ANEG)) ++ goto nla_put_failure; ++ } ++ if (link->tx_flow) { ++ if (nla_put_flag(msg, SWITCH_LINK_FLAG_TX_FLOW)) ++ goto nla_put_failure; ++ } ++ if (link->rx_flow) { ++ if (nla_put_flag(msg, SWITCH_LINK_FLAG_RX_FLOW)) ++ goto nla_put_failure; ++ } ++ if (nla_put_u32(msg, SWITCH_LINK_SPEED, link->speed)) ++ goto nla_put_failure; ++ if (link->eee & ADVERTISED_100baseT_Full) { ++ if (nla_put_flag(msg, SWITCH_LINK_FLAG_EEE_100BASET)) ++ goto nla_put_failure; ++ } ++ if (link->eee & ADVERTISED_1000baseT_Full) { ++ if (nla_put_flag(msg, SWITCH_LINK_FLAG_EEE_1000BASET)) ++ goto nla_put_failure; ++ } ++ nla_nest_end(msg, p); ++ ++ return err; ++ ++nla_put_failure: ++ nla_nest_cancel(msg, p); ++ return -1; ++} ++ ++static int ++swconfig_get_attr(struct sk_buff *skb, struct genl_info *info) ++{ ++ struct genlmsghdr *hdr = nlmsg_data(info->nlhdr); ++ const struct switch_attr *attr; ++ struct switch_dev *dev; ++ struct sk_buff *msg = NULL; ++ struct switch_val val; ++ int err = -EINVAL; ++ int cmd = hdr->cmd; ++ ++ dev = swconfig_get_dev(info); ++ if (!dev) ++ return -EINVAL; ++ ++ memset(&val, 0, sizeof(val)); ++ attr = swconfig_lookup_attr(dev, info, &val); ++ if (!attr || !attr->get) ++ goto error; ++ ++ if (attr->type == SWITCH_TYPE_PORTS) { ++ val.value.ports = dev->portbuf; ++ memset(dev->portbuf, 0, ++ sizeof(struct switch_port) * dev->ports); ++ } else if (attr->type == SWITCH_TYPE_LINK) { ++ val.value.link = &dev->linkbuf; ++ memset(&dev->linkbuf, 0, sizeof(struct switch_port_link)); ++ } ++ ++ err = attr->get(dev, attr, &val); ++ if (err) ++ goto error; ++ ++ msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); ++ if (!msg) ++ goto error; ++ ++ hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq, &switch_fam, ++ 0, cmd); ++ if (IS_ERR(hdr)) ++ goto nla_put_failure; ++ ++ switch (attr->type) { ++ case SWITCH_TYPE_INT: ++ if (nla_put_u32(msg, SWITCH_ATTR_OP_VALUE_INT, val.value.i)) ++ goto nla_put_failure; ++ break; ++ case SWITCH_TYPE_STRING: ++ if (nla_put_string(msg, SWITCH_ATTR_OP_VALUE_STR, val.value.s)) ++ goto nla_put_failure; ++ break; ++ case SWITCH_TYPE_PORTS: ++ err = swconfig_send_ports(&msg, info, ++ SWITCH_ATTR_OP_VALUE_PORTS, &val); ++ if (err < 0) ++ goto nla_put_failure; ++ break; ++ case SWITCH_TYPE_LINK: ++ err = swconfig_send_link(msg, info, ++ SWITCH_ATTR_OP_VALUE_LINK, val.value.link); ++ if (err < 0) ++ goto nla_put_failure; ++ break; ++ default: ++ pr_debug("invalid type in attribute\n"); ++ err = -EINVAL; ++ goto nla_put_failure; ++ } ++ genlmsg_end(msg, hdr); ++ err = msg->len; ++ if (err < 0) ++ goto nla_put_failure; ++ ++ swconfig_put_dev(dev); ++ return genlmsg_reply(msg, info); ++ ++nla_put_failure: ++ if (msg) ++ nlmsg_free(msg); ++error: ++ swconfig_put_dev(dev); ++ if (!err) ++ err = -ENOMEM; ++ return err; ++} ++ ++static int ++swconfig_send_switch(struct sk_buff *msg, u32 pid, u32 seq, int flags, ++ const struct switch_dev *dev) ++{ ++ struct nlattr *p = NULL, *m = NULL; ++ void *hdr; ++ int i; ++ ++ hdr = genlmsg_put(msg, pid, seq, &switch_fam, flags, ++ SWITCH_CMD_NEW_ATTR); ++ if (IS_ERR(hdr)) ++ return -1; ++ ++ if (nla_put_u32(msg, SWITCH_ATTR_ID, dev->id)) ++ goto nla_put_failure; ++ if (nla_put_string(msg, SWITCH_ATTR_DEV_NAME, dev->devname)) ++ goto nla_put_failure; ++ if (nla_put_string(msg, SWITCH_ATTR_ALIAS, dev->alias)) ++ goto nla_put_failure; ++ if (nla_put_string(msg, SWITCH_ATTR_NAME, dev->name)) ++ goto nla_put_failure; ++ if (nla_put_u32(msg, SWITCH_ATTR_VLANS, dev->vlans)) ++ goto nla_put_failure; ++ if (nla_put_u32(msg, SWITCH_ATTR_PORTS, dev->ports)) ++ goto nla_put_failure; ++ if (nla_put_u32(msg, SWITCH_ATTR_CPU_PORT, dev->cpu_port)) ++ goto nla_put_failure; ++ ++ m = nla_nest_start(msg, SWITCH_ATTR_PORTMAP); ++ if (!m) ++ goto nla_put_failure; ++ for (i = 0; i < dev->ports; i++) { ++ p = nla_nest_start(msg, SWITCH_ATTR_PORTS); ++ if (!p) ++ continue; ++ if (dev->portmap[i].s) { ++ if (nla_put_string(msg, SWITCH_PORTMAP_SEGMENT, ++ dev->portmap[i].s)) ++ goto nla_put_failure; ++ if (nla_put_u32(msg, SWITCH_PORTMAP_VIRT, ++ dev->portmap[i].virt)) ++ goto nla_put_failure; ++ } ++ nla_nest_end(msg, p); ++ } ++ nla_nest_end(msg, m); ++ genlmsg_end(msg, hdr); ++ return msg->len; ++nla_put_failure: ++ genlmsg_cancel(msg, hdr); ++ return -EMSGSIZE; ++} ++ ++static int swconfig_dump_switches(struct sk_buff *skb, ++ struct netlink_callback *cb) ++{ ++ struct switch_dev *dev; ++ int start = cb->args[0]; ++ int idx = 0; ++ ++ swconfig_lock(); ++ list_for_each_entry(dev, &swdevs, dev_list) { ++ if (++idx <= start) ++ continue; ++ if (swconfig_send_switch(skb, NETLINK_CB(cb->skb).portid, ++ cb->nlh->nlmsg_seq, NLM_F_MULTI, ++ dev) < 0) ++ break; ++ } ++ swconfig_unlock(); ++ cb->args[0] = idx; ++ ++ return skb->len; ++} ++ ++static int ++swconfig_done(struct netlink_callback *cb) ++{ ++ return 0; ++} ++ ++static struct genl_ops swconfig_ops[] = { ++ { ++ .cmd = SWITCH_CMD_LIST_GLOBAL, ++ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, ++ .doit = swconfig_list_attrs, ++ }, ++ { ++ .cmd = SWITCH_CMD_LIST_VLAN, ++ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, ++ .doit = swconfig_list_attrs, ++ }, ++ { ++ .cmd = SWITCH_CMD_LIST_PORT, ++ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, ++ .doit = swconfig_list_attrs, ++ }, ++ { ++ .cmd = SWITCH_CMD_GET_GLOBAL, ++ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, ++ .doit = swconfig_get_attr, ++ }, ++ { ++ .cmd = SWITCH_CMD_GET_VLAN, ++ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, ++ .doit = swconfig_get_attr, ++ }, ++ { ++ .cmd = SWITCH_CMD_GET_PORT, ++ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, ++ .doit = swconfig_get_attr, ++ }, ++ { ++ .cmd = SWITCH_CMD_SET_GLOBAL, ++ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, ++ .flags = GENL_ADMIN_PERM, ++ .doit = swconfig_set_attr, ++ }, ++ { ++ .cmd = SWITCH_CMD_SET_VLAN, ++ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, ++ .flags = GENL_ADMIN_PERM, ++ .doit = swconfig_set_attr, ++ }, ++ { ++ .cmd = SWITCH_CMD_SET_PORT, ++ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, ++ .flags = GENL_ADMIN_PERM, ++ .doit = swconfig_set_attr, ++ }, ++ { ++ .cmd = SWITCH_CMD_GET_SWITCH, ++ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, ++ .dumpit = swconfig_dump_switches, ++ .done = swconfig_done, ++ } ++}; ++ ++static struct genl_family switch_fam = { ++ .name = "switch", ++ .hdrsize = 0, ++ .version = 1, ++ .maxattr = SWITCH_ATTR_MAX, ++ .policy = switch_policy, ++ .module = THIS_MODULE, ++ .ops = swconfig_ops, ++ .n_ops = ARRAY_SIZE(swconfig_ops), ++ .resv_start_op = SWITCH_CMD_SET_VLAN + 1, ++}; ++ ++#ifdef CONFIG_OF ++static void ++of_switch_load_portmap(struct switch_dev *dev) ++{ ++ struct device_node *port; ++ ++ if (!dev->of_node) ++ return; ++ ++ for_each_child_of_node(dev->of_node, port) { ++ const __be32 *prop; ++ const char *segment; ++ int size, phys; ++ ++ if (!of_device_is_compatible(port, "swconfig,port")) ++ continue; ++ ++ if (of_property_read_string(port, "swconfig,segment", &segment)) ++ continue; ++ ++ prop = of_get_property(port, "swconfig,portmap", &size); ++ if (!prop) ++ continue; ++ ++ if (size != (2 * sizeof(*prop))) { ++ pr_err("%s: failed to parse port mapping\n", ++ port->name); ++ continue; ++ } ++ ++ phys = be32_to_cpup(prop++); ++ if ((phys < 0) | (phys >= dev->ports)) { ++ pr_err("%s: physical port index out of range\n", ++ port->name); ++ continue; ++ } ++ ++ dev->portmap[phys].s = kstrdup(segment, GFP_KERNEL); ++ dev->portmap[phys].virt = be32_to_cpup(prop); ++ pr_debug("Found port: %s, physical: %d, virtual: %d\n", ++ segment, phys, dev->portmap[phys].virt); ++ } ++} ++#endif ++ ++int ++register_switch(struct switch_dev *dev, struct net_device *netdev) ++{ ++ struct switch_dev *sdev; ++ const int max_switches = 8 * sizeof(unsigned long); ++ unsigned long in_use = 0; ++ int err; ++ int i; ++ ++ INIT_LIST_HEAD(&dev->dev_list); ++ if (netdev) { ++ dev->netdev = netdev; ++ if (!dev->alias) ++ dev->alias = netdev->name; ++ } ++ BUG_ON(!dev->alias); ++ ++ /* Make sure swdev_id doesn't overflow */ ++ if (swdev_id == INT_MAX) { ++ return -ENOMEM; ++ } ++ ++ if (dev->ports > 0) { ++ dev->portbuf = kzalloc(sizeof(struct switch_port) * ++ dev->ports, GFP_KERNEL); ++ if (!dev->portbuf) ++ return -ENOMEM; ++ dev->portmap = kzalloc(sizeof(struct switch_portmap) * ++ dev->ports, GFP_KERNEL); ++ if (!dev->portmap) { ++ kfree(dev->portbuf); ++ return -ENOMEM; ++ } ++ } ++ swconfig_defaults_init(dev); ++ mutex_init(&dev->sw_mutex); ++ swconfig_lock(); ++ dev->id = ++swdev_id; ++ ++ list_for_each_entry(sdev, &swdevs, dev_list) { ++ if (!sscanf(sdev->devname, SWCONFIG_DEVNAME, &i)) ++ continue; ++ if (i < 0 || i > max_switches) ++ continue; ++ ++ set_bit(i, &in_use); ++ } ++ i = find_first_zero_bit(&in_use, max_switches); ++ ++ if (i == max_switches) { ++ swconfig_unlock(); ++ return -ENFILE; ++ } ++ ++#ifdef CONFIG_OF ++ if (dev->ports) ++ of_switch_load_portmap(dev); ++#endif ++ ++ /* fill device name */ ++ snprintf(dev->devname, IFNAMSIZ, SWCONFIG_DEVNAME, i); ++ ++ list_add_tail(&dev->dev_list, &swdevs); ++ swconfig_unlock(); ++ ++ err = swconfig_create_led_trigger(dev); ++ if (err) ++ return err; ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(register_switch); ++ ++void ++unregister_switch(struct switch_dev *dev) ++{ ++ swconfig_destroy_led_trigger(dev); ++ kfree(dev->portbuf); ++ mutex_lock(&dev->sw_mutex); ++ swconfig_lock(); ++ list_del(&dev->dev_list); ++ swconfig_unlock(); ++ mutex_unlock(&dev->sw_mutex); ++} ++EXPORT_SYMBOL_GPL(unregister_switch); ++ ++int ++switch_generic_set_link(struct switch_dev *dev, int port, ++ struct switch_port_link *link) ++{ ++ if (WARN_ON(!dev->ops->phy_write16)) ++ return -ENOTSUPP; ++ ++ /* Generic implementation */ ++ if (link->aneg) { ++ dev->ops->phy_write16(dev, port, MII_BMCR, 0x0000); ++ dev->ops->phy_write16(dev, port, MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART); ++ } else { ++ u16 bmcr = 0; ++ ++ if (link->duplex) ++ bmcr |= BMCR_FULLDPLX; ++ ++ switch (link->speed) { ++ case SWITCH_PORT_SPEED_10: ++ break; ++ case SWITCH_PORT_SPEED_100: ++ bmcr |= BMCR_SPEED100; ++ break; ++ case SWITCH_PORT_SPEED_1000: ++ bmcr |= BMCR_SPEED1000; ++ break; ++ default: ++ return -ENOTSUPP; ++ } ++ ++ dev->ops->phy_write16(dev, port, MII_BMCR, bmcr); ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(switch_generic_set_link); ++ ++static int __init ++swconfig_init(void) ++{ ++ INIT_LIST_HEAD(&swdevs); ++ ++ return genl_register_family(&switch_fam); ++} ++ ++static void __exit ++swconfig_exit(void) ++{ ++ genl_unregister_family(&switch_fam); ++} ++ ++module_init(swconfig_init); ++module_exit(swconfig_exit); +diff --git a/drivers/net/phy/swconfig_leds.c b/drivers/net/phy/swconfig_leds.c +new file mode 100644 +index 000000000000..1fcd4432b54e +--- /dev/null ++++ b/drivers/net/phy/swconfig_leds.c +@@ -0,0 +1,555 @@ ++/* ++ * swconfig_led.c: LED trigger support for the switch configuration API ++ * ++ * Copyright (C) 2011 Gabor Juhos ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version 2 ++ * of the License, or (at your option) any later version. ++ * ++ */ ++ ++#ifdef CONFIG_SWCONFIG_LEDS ++ ++#include ++#include ++#include ++#include ++ ++#define SWCONFIG_LED_TIMER_INTERVAL (HZ / 10) ++#define SWCONFIG_LED_NUM_PORTS 32 ++ ++#define SWCONFIG_LED_PORT_SPEED_NA 0x01 /* unknown speed */ ++#define SWCONFIG_LED_PORT_SPEED_10 0x02 /* 10 Mbps */ ++#define SWCONFIG_LED_PORT_SPEED_100 0x04 /* 100 Mbps */ ++#define SWCONFIG_LED_PORT_SPEED_1000 0x08 /* 1000 Mbps */ ++#define SWCONFIG_LED_PORT_SPEED_ALL (SWCONFIG_LED_PORT_SPEED_NA | \ ++ SWCONFIG_LED_PORT_SPEED_10 | \ ++ SWCONFIG_LED_PORT_SPEED_100 | \ ++ SWCONFIG_LED_PORT_SPEED_1000) ++ ++#define SWCONFIG_LED_MODE_LINK 0x01 ++#define SWCONFIG_LED_MODE_TX 0x02 ++#define SWCONFIG_LED_MODE_RX 0x04 ++#define SWCONFIG_LED_MODE_TXRX (SWCONFIG_LED_MODE_TX | \ ++ SWCONFIG_LED_MODE_RX) ++#define SWCONFIG_LED_MODE_ALL (SWCONFIG_LED_MODE_LINK | \ ++ SWCONFIG_LED_MODE_TX | \ ++ SWCONFIG_LED_MODE_RX) ++ ++struct switch_led_trigger { ++ struct led_trigger trig; ++ struct switch_dev *swdev; ++ ++ struct delayed_work sw_led_work; ++ u32 port_mask; ++ u32 port_link; ++ unsigned long long port_tx_traffic[SWCONFIG_LED_NUM_PORTS]; ++ unsigned long long port_rx_traffic[SWCONFIG_LED_NUM_PORTS]; ++ u8 link_speed[SWCONFIG_LED_NUM_PORTS]; ++}; ++ ++struct swconfig_trig_data { ++ struct led_classdev *led_cdev; ++ struct switch_dev *swdev; ++ ++ rwlock_t lock; ++ u32 port_mask; ++ ++ bool prev_link; ++ unsigned long prev_traffic; ++ enum led_brightness prev_brightness; ++ u8 mode; ++ u8 speed_mask; ++}; ++ ++static void ++swconfig_trig_set_brightness(struct swconfig_trig_data *trig_data, ++ enum led_brightness brightness) ++{ ++ led_set_brightness(trig_data->led_cdev, brightness); ++ trig_data->prev_brightness = brightness; ++} ++ ++static void ++swconfig_trig_update_port_mask(struct led_trigger *trigger) ++{ ++ struct list_head *entry; ++ struct switch_led_trigger *sw_trig; ++ u32 port_mask; ++ ++ if (!trigger) ++ return; ++ ++ sw_trig = (void *) trigger; ++ ++ port_mask = 0; ++ spin_lock(&trigger->leddev_list_lock); ++ list_for_each(entry, &trigger->led_cdevs) { ++ struct led_classdev *led_cdev; ++ struct swconfig_trig_data *trig_data; ++ ++ led_cdev = list_entry(entry, struct led_classdev, trig_list); ++ trig_data = led_cdev->trigger_data; ++ if (trig_data) { ++ read_lock(&trig_data->lock); ++ port_mask |= trig_data->port_mask; ++ read_unlock(&trig_data->lock); ++ } ++ } ++ spin_unlock(&trigger->leddev_list_lock); ++ ++ sw_trig->port_mask = port_mask; ++ ++ if (port_mask) ++ schedule_delayed_work(&sw_trig->sw_led_work, ++ SWCONFIG_LED_TIMER_INTERVAL); ++ else ++ cancel_delayed_work_sync(&sw_trig->sw_led_work); ++} ++ ++static ssize_t ++swconfig_trig_port_mask_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t size) ++{ ++ struct led_classdev *led_cdev = dev_get_drvdata(dev); ++ struct swconfig_trig_data *trig_data = led_cdev->trigger_data; ++ unsigned long port_mask; ++ int ret; ++ bool changed; ++ ++ ret = kstrtoul(buf, 0, &port_mask); ++ if (ret) ++ return ret; ++ ++ write_lock(&trig_data->lock); ++ changed = (trig_data->port_mask != port_mask); ++ trig_data->port_mask = port_mask; ++ write_unlock(&trig_data->lock); ++ ++ if (changed) { ++ if (port_mask == 0) ++ swconfig_trig_set_brightness(trig_data, LED_OFF); ++ ++ swconfig_trig_update_port_mask(led_cdev->trigger); ++ } ++ ++ return size; ++} ++ ++static ssize_t ++swconfig_trig_port_mask_show(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct led_classdev *led_cdev = dev_get_drvdata(dev); ++ struct swconfig_trig_data *trig_data = led_cdev->trigger_data; ++ u32 port_mask; ++ ++ read_lock(&trig_data->lock); ++ port_mask = trig_data->port_mask; ++ read_unlock(&trig_data->lock); ++ ++ sprintf(buf, "%#x\n", port_mask); ++ ++ return strlen(buf) + 1; ++} ++ ++static DEVICE_ATTR(port_mask, 0644, swconfig_trig_port_mask_show, ++ swconfig_trig_port_mask_store); ++ ++/* speed_mask file handler - display value */ ++static ssize_t swconfig_trig_speed_mask_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct led_classdev *led_cdev = dev_get_drvdata(dev); ++ struct swconfig_trig_data *trig_data = led_cdev->trigger_data; ++ u8 speed_mask; ++ ++ read_lock(&trig_data->lock); ++ speed_mask = trig_data->speed_mask; ++ read_unlock(&trig_data->lock); ++ ++ sprintf(buf, "%#x\n", speed_mask); ++ ++ return strlen(buf) + 1; ++} ++ ++/* speed_mask file handler - store value */ ++static ssize_t swconfig_trig_speed_mask_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t size) ++{ ++ struct led_classdev *led_cdev = dev_get_drvdata(dev); ++ struct swconfig_trig_data *trig_data = led_cdev->trigger_data; ++ u8 speed_mask; ++ int ret; ++ ++ ret = kstrtou8(buf, 0, &speed_mask); ++ if (ret) ++ return ret; ++ ++ write_lock(&trig_data->lock); ++ trig_data->speed_mask = speed_mask & SWCONFIG_LED_PORT_SPEED_ALL; ++ write_unlock(&trig_data->lock); ++ ++ return size; ++} ++ ++/* speed_mask special file */ ++static DEVICE_ATTR(speed_mask, 0644, swconfig_trig_speed_mask_show, ++ swconfig_trig_speed_mask_store); ++ ++static ssize_t swconfig_trig_mode_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct led_classdev *led_cdev = dev_get_drvdata(dev); ++ struct swconfig_trig_data *trig_data = led_cdev->trigger_data; ++ u8 mode; ++ ++ read_lock(&trig_data->lock); ++ mode = trig_data->mode; ++ read_unlock(&trig_data->lock); ++ ++ if (mode == 0) { ++ strcpy(buf, "none\n"); ++ } else { ++ if (mode & SWCONFIG_LED_MODE_LINK) ++ strcat(buf, "link "); ++ if (mode & SWCONFIG_LED_MODE_TX) ++ strcat(buf, "tx "); ++ if (mode & SWCONFIG_LED_MODE_RX) ++ strcat(buf, "rx "); ++ strcat(buf, "\n"); ++ } ++ ++ return strlen(buf)+1; ++} ++ ++static ssize_t swconfig_trig_mode_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t size) ++{ ++ struct led_classdev *led_cdev = dev_get_drvdata(dev); ++ struct swconfig_trig_data *trig_data = led_cdev->trigger_data; ++ char copybuf[128]; ++ int new_mode = -1; ++ char *p, *token; ++ ++ /* take a copy since we don't want to trash the inbound buffer when using strsep */ ++ strncpy(copybuf, buf, sizeof(copybuf)); ++ copybuf[sizeof(copybuf) - 1] = 0; ++ p = copybuf; ++ ++ while ((token = strsep(&p, " \t\n")) != NULL) { ++ if (!*token) ++ continue; ++ ++ if (new_mode < 0) ++ new_mode = 0; ++ ++ if (!strcmp(token, "none")) ++ new_mode = 0; ++ else if (!strcmp(token, "tx")) ++ new_mode |= SWCONFIG_LED_MODE_TX; ++ else if (!strcmp(token, "rx")) ++ new_mode |= SWCONFIG_LED_MODE_RX; ++ else if (!strcmp(token, "link")) ++ new_mode |= SWCONFIG_LED_MODE_LINK; ++ else ++ return -EINVAL; ++ } ++ ++ if (new_mode < 0) ++ return -EINVAL; ++ ++ write_lock(&trig_data->lock); ++ trig_data->mode = (u8)new_mode; ++ write_unlock(&trig_data->lock); ++ ++ return size; ++} ++ ++/* mode special file */ ++static DEVICE_ATTR(mode, 0644, swconfig_trig_mode_show, ++ swconfig_trig_mode_store); ++ ++static int ++swconfig_trig_activate(struct led_classdev *led_cdev) ++{ ++ struct switch_led_trigger *sw_trig; ++ struct swconfig_trig_data *trig_data; ++ int err; ++ ++ trig_data = kzalloc(sizeof(struct swconfig_trig_data), GFP_KERNEL); ++ if (!trig_data) ++ return -ENOMEM; ++ ++ sw_trig = (void *) led_cdev->trigger; ++ ++ rwlock_init(&trig_data->lock); ++ trig_data->led_cdev = led_cdev; ++ trig_data->swdev = sw_trig->swdev; ++ trig_data->speed_mask = SWCONFIG_LED_PORT_SPEED_ALL; ++ trig_data->mode = SWCONFIG_LED_MODE_ALL; ++ led_cdev->trigger_data = trig_data; ++ ++ err = device_create_file(led_cdev->dev, &dev_attr_port_mask); ++ if (err) ++ goto err_free; ++ ++ err = device_create_file(led_cdev->dev, &dev_attr_speed_mask); ++ if (err) ++ goto err_dev_free; ++ ++ err = device_create_file(led_cdev->dev, &dev_attr_mode); ++ if (err) ++ goto err_mode_free; ++ ++ return 0; ++ ++err_mode_free: ++ device_remove_file(led_cdev->dev, &dev_attr_speed_mask); ++ ++err_dev_free: ++ device_remove_file(led_cdev->dev, &dev_attr_port_mask); ++ ++err_free: ++ led_cdev->trigger_data = NULL; ++ kfree(trig_data); ++ ++ return err; ++} ++ ++static void ++swconfig_trig_deactivate(struct led_classdev *led_cdev) ++{ ++ struct swconfig_trig_data *trig_data; ++ ++ swconfig_trig_update_port_mask(led_cdev->trigger); ++ ++ trig_data = (void *) led_cdev->trigger_data; ++ if (trig_data) { ++ device_remove_file(led_cdev->dev, &dev_attr_port_mask); ++ device_remove_file(led_cdev->dev, &dev_attr_speed_mask); ++ device_remove_file(led_cdev->dev, &dev_attr_mode); ++ kfree(trig_data); ++ } ++} ++ ++/* ++ * link off -> led off (can't be any other reason to turn it on) ++ * link on: ++ * mode link: led on by default only if speed matches, else off ++ * mode txrx: blink only if speed matches, else off ++ */ ++static void ++swconfig_trig_led_event(struct switch_led_trigger *sw_trig, ++ struct led_classdev *led_cdev) ++{ ++ struct swconfig_trig_data *trig_data; ++ u32 port_mask; ++ bool link; ++ u8 speed_mask, mode; ++ enum led_brightness led_base, led_blink; ++ ++ trig_data = led_cdev->trigger_data; ++ if (!trig_data) ++ return; ++ ++ read_lock(&trig_data->lock); ++ port_mask = trig_data->port_mask; ++ speed_mask = trig_data->speed_mask; ++ mode = trig_data->mode; ++ read_unlock(&trig_data->lock); ++ ++ link = !!(sw_trig->port_link & port_mask); ++ if (!link) { ++ if (trig_data->prev_brightness != LED_OFF) ++ swconfig_trig_set_brightness(trig_data, LED_OFF); /* and stop */ ++ } ++ else { ++ unsigned long traffic; ++ int speedok; /* link speed flag */ ++ int i; ++ ++ led_base = LED_FULL; ++ led_blink = LED_OFF; ++ traffic = 0; ++ speedok = 0; ++ for (i = 0; i < SWCONFIG_LED_NUM_PORTS; i++) { ++ if (port_mask & (1 << i)) { ++ if (sw_trig->link_speed[i] & speed_mask) { ++ traffic += ((mode & SWCONFIG_LED_MODE_TX) ? ++ sw_trig->port_tx_traffic[i] : 0) + ++ ((mode & SWCONFIG_LED_MODE_RX) ? ++ sw_trig->port_rx_traffic[i] : 0); ++ speedok = 1; ++ } ++ } ++ } ++ ++ if (speedok) { ++ /* At least one port speed matches speed_mask */ ++ if (!(mode & SWCONFIG_LED_MODE_LINK)) { ++ led_base = LED_OFF; ++ led_blink = LED_FULL; ++ } ++ ++ if (trig_data->prev_brightness != led_base) ++ swconfig_trig_set_brightness(trig_data, ++ led_base); ++ else if (traffic != trig_data->prev_traffic) ++ swconfig_trig_set_brightness(trig_data, ++ led_blink); ++ } else if (trig_data->prev_brightness != LED_OFF) ++ swconfig_trig_set_brightness(trig_data, LED_OFF); ++ ++ trig_data->prev_traffic = traffic; ++ } ++ ++ trig_data->prev_link = link; ++} ++ ++static void ++swconfig_trig_update_leds(struct switch_led_trigger *sw_trig) ++{ ++ struct list_head *entry; ++ struct led_trigger *trigger; ++ ++ trigger = &sw_trig->trig; ++ spin_lock(&trigger->leddev_list_lock); ++ list_for_each(entry, &trigger->led_cdevs) { ++ struct led_classdev *led_cdev; ++ ++ led_cdev = list_entry(entry, struct led_classdev, trig_list); ++ swconfig_trig_led_event(sw_trig, led_cdev); ++ } ++ spin_unlock(&trigger->leddev_list_lock); ++} ++ ++static void ++swconfig_led_work_func(struct work_struct *work) ++{ ++ struct switch_led_trigger *sw_trig; ++ struct switch_dev *swdev; ++ u32 port_mask; ++ u32 link; ++ int i; ++ ++ sw_trig = container_of(work, struct switch_led_trigger, ++ sw_led_work.work); ++ ++ port_mask = sw_trig->port_mask; ++ swdev = sw_trig->swdev; ++ ++ link = 0; ++ for (i = 0; i < SWCONFIG_LED_NUM_PORTS; i++) { ++ u32 port_bit; ++ ++ sw_trig->link_speed[i] = 0; ++ ++ port_bit = BIT(i); ++ if ((port_mask & port_bit) == 0) ++ continue; ++ ++ if (swdev->ops->get_port_link) { ++ struct switch_port_link port_link; ++ ++ memset(&port_link, '\0', sizeof(port_link)); ++ swdev->ops->get_port_link(swdev, i, &port_link); ++ ++ if (port_link.link) { ++ link |= port_bit; ++ switch (port_link.speed) { ++ case SWITCH_PORT_SPEED_UNKNOWN: ++ sw_trig->link_speed[i] = ++ SWCONFIG_LED_PORT_SPEED_NA; ++ break; ++ case SWITCH_PORT_SPEED_10: ++ sw_trig->link_speed[i] = ++ SWCONFIG_LED_PORT_SPEED_10; ++ break; ++ case SWITCH_PORT_SPEED_100: ++ sw_trig->link_speed[i] = ++ SWCONFIG_LED_PORT_SPEED_100; ++ break; ++ case SWITCH_PORT_SPEED_1000: ++ sw_trig->link_speed[i] = ++ SWCONFIG_LED_PORT_SPEED_1000; ++ break; ++ } ++ } ++ } ++ ++ if (swdev->ops->get_port_stats) { ++ struct switch_port_stats port_stats; ++ ++ memset(&port_stats, '\0', sizeof(port_stats)); ++ swdev->ops->get_port_stats(swdev, i, &port_stats); ++ sw_trig->port_tx_traffic[i] = port_stats.tx_bytes; ++ sw_trig->port_rx_traffic[i] = port_stats.rx_bytes; ++ } ++ } ++ ++ sw_trig->port_link = link; ++ ++ swconfig_trig_update_leds(sw_trig); ++ ++ schedule_delayed_work(&sw_trig->sw_led_work, ++ SWCONFIG_LED_TIMER_INTERVAL); ++} ++ ++static int ++swconfig_create_led_trigger(struct switch_dev *swdev) ++{ ++ struct switch_led_trigger *sw_trig; ++ int err; ++ ++ if (!swdev->ops->get_port_link) ++ return 0; ++ ++ sw_trig = kzalloc(sizeof(struct switch_led_trigger), GFP_KERNEL); ++ if (!sw_trig) ++ return -ENOMEM; ++ ++ sw_trig->swdev = swdev; ++ sw_trig->trig.name = swdev->devname; ++ sw_trig->trig.activate = swconfig_trig_activate; ++ sw_trig->trig.deactivate = swconfig_trig_deactivate; ++ ++ INIT_DELAYED_WORK(&sw_trig->sw_led_work, swconfig_led_work_func); ++ ++ err = led_trigger_register(&sw_trig->trig); ++ if (err) ++ goto err_free; ++ ++ swdev->led_trigger = sw_trig; ++ ++ return 0; ++ ++err_free: ++ kfree(sw_trig); ++ return err; ++} ++ ++static void ++swconfig_destroy_led_trigger(struct switch_dev *swdev) ++{ ++ struct switch_led_trigger *sw_trig; ++ ++ sw_trig = swdev->led_trigger; ++ if (sw_trig) { ++ cancel_delayed_work_sync(&sw_trig->sw_led_work); ++ led_trigger_unregister(&sw_trig->trig); ++ kfree(sw_trig); ++ } ++} ++ ++#else /* SWCONFIG_LEDS */ ++static inline int ++swconfig_create_led_trigger(struct switch_dev *swdev) { return 0; } ++ ++static inline void ++swconfig_destroy_led_trigger(struct switch_dev *swdev) { } ++#endif /* CONFIG_SWCONFIG_LEDS */ +diff --git a/drivers/nvmem/an8855-efuse.c b/drivers/nvmem/an8855-efuse.c +new file mode 100644 +index 000000000000..7940453d6e58 +--- /dev/null ++++ b/drivers/nvmem/an8855-efuse.c +@@ -0,0 +1,63 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Airoha AN8855 Switch EFUSE Driver ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#define AN8855_EFUSE_CELL 50 ++ ++#define AN8855_EFUSE_DATA0 0x1000a500 ++#define AN8855_EFUSE_R50O GENMASK(30, 24) ++ ++static int an8855_efuse_read(void *context, unsigned int offset, ++ void *val, size_t bytes) ++{ ++ struct regmap *regmap = context; ++ ++ return regmap_bulk_read(regmap, AN8855_EFUSE_DATA0 + offset, ++ val, bytes / sizeof(u32)); ++} ++ ++static int an8855_efuse_probe(struct platform_device *pdev) ++{ ++ struct nvmem_config an8855_nvmem_config = { ++ .name = "an8855-efuse", ++ .size = AN8855_EFUSE_CELL * sizeof(u32), ++ .stride = sizeof(u32), ++ .word_size = sizeof(u32), ++ .reg_read = an8855_efuse_read, ++ }; ++ struct device *dev = &pdev->dev; ++ struct nvmem_device *nvmem; ++ ++ /* Assign NVMEM priv to MFD regmap */ ++ an8855_nvmem_config.priv = dev_get_regmap(dev->parent, NULL); ++ an8855_nvmem_config.dev = dev; ++ nvmem = devm_nvmem_register(dev, &an8855_nvmem_config); ++ ++ return PTR_ERR_OR_ZERO(nvmem); ++} ++ ++static const struct of_device_id an8855_efuse_of_match[] = { ++ { .compatible = "airoha,an8855-efuse", }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, an8855_efuse_of_match); ++ ++static struct platform_driver an8855_efuse_driver = { ++ .probe = an8855_efuse_probe, ++ .driver = { ++ .name = "an8855-efuse", ++ .of_match_table = an8855_efuse_of_match, ++ }, ++}; ++module_platform_driver(an8855_efuse_driver); ++ ++MODULE_AUTHOR("Christian Marangi "); ++MODULE_DESCRIPTION("Driver for AN8855 Switch EFUSE"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/platform/mikrotik/Kconfig b/drivers/platform/mikrotik/Kconfig +new file mode 100644 +index 000000000000..85fe7b20503c +--- /dev/null ++++ b/drivers/platform/mikrotik/Kconfig +@@ -0,0 +1,31 @@ ++menuconfig MIKROTIK ++ bool "Platform support for MikroTik RouterBoard virtual devices" ++ help ++ Say Y here to get to see options for the MikroTik RouterBoard platform. ++ This option alone does not add any kernel code. ++ ++ ++if MIKROTIK ++ ++config MIKROTIK_RB_SYSFS ++ tristate "RouterBoot sysfs support" ++ depends on MTD ++ select LZO_DECOMPRESS ++ select CRC32 ++ help ++ This driver exposes RouterBoot configuration in sysfs. ++ ++config NVMEM_LAYOUT_MIKROTIK ++ tristate "RouterBoot NVMEM layout support" ++ depends on NVMEM_LAYOUTS ++ help ++ This driver exposes MikroTik hard_config via NVMEM layout. ++ ++config MIKROTIK_WLAN_DECOMPRESS_LZ77 ++ tristate "Mikrotik factory Wi-Fi caldata LZ77 decompression support" ++ depends on MIKROTIK_RB_SYSFS ++ help ++ Allow Mikrotik LZ77 factory flashed Wi-Fi calibration data to be ++ decompressed ++ ++endif # MIKROTIK +diff --git a/drivers/platform/mikrotik/Makefile b/drivers/platform/mikrotik/Makefile +new file mode 100644 +index 000000000000..9ffb355c1e3d +--- /dev/null ++++ b/drivers/platform/mikrotik/Makefile +@@ -0,0 +1,6 @@ ++# ++# Makefile for MikroTik RouterBoard platform specific drivers ++# ++obj-$(CONFIG_MIKROTIK_RB_SYSFS) += routerboot.o rb_hardconfig.o rb_softconfig.o ++obj-$(CONFIG_NVMEM_LAYOUT_MIKROTIK) += rb_nvmem.o ++obj-$(CONFIG_MIKROTIK_WLAN_DECOMPRESS_LZ77) += rb_lz77.o +diff --git a/drivers/platform/mikrotik/rb_hardconfig.c b/drivers/platform/mikrotik/rb_hardconfig.c +new file mode 100644 +index 000000000000..4c1edad08178 +--- /dev/null ++++ b/drivers/platform/mikrotik/rb_hardconfig.c +@@ -0,0 +1,844 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Driver for MikroTik RouterBoot hard config. ++ * ++ * Copyright (C) 2020 Thibaut VARÈNE ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation. ++ * ++ * This driver exposes the data encoded in the "hard_config" flash segment of ++ * MikroTik RouterBOARDs devices. It presents the data in a sysfs folder ++ * named "hard_config". The WLAN calibration data is available on demand via ++ * the 'wlan_data' sysfs file in that folder. ++ * ++ * This driver permanently allocates a chunk of RAM as large as the hard_config ++ * MTD partition, although it is technically possible to operate entirely from ++ * the MTD device without using a local buffer (except when requesting WLAN ++ * calibration data), at the cost of a performance penalty. ++ * ++ * Note: PAGE_SIZE is assumed to be >= 4K, hence the device attribute show ++ * routines need not check for output overflow. ++ * ++ * Some constant defines extracted from routerboot.{c,h} by Gabor Juhos ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "rb_hardconfig.h" ++#include "routerboot.h" ++#include "rb_lz77.h" ++ ++#define RB_HARDCONFIG_VER "0.08" ++#define RB_HC_PR_PFX "[rb_hardconfig] " ++ ++/* Bit definitions for hardware options */ ++#define RB_HW_OPT_NO_UART BIT(0) ++#define RB_HW_OPT_HAS_VOLTAGE BIT(1) ++#define RB_HW_OPT_HAS_USB BIT(2) ++#define RB_HW_OPT_HAS_ATTINY BIT(3) ++#define RB_HW_OPT_PULSE_DUTY_CYCLE BIT(9) ++#define RB_HW_OPT_NO_NAND BIT(14) ++#define RB_HW_OPT_HAS_LCD BIT(15) ++#define RB_HW_OPT_HAS_POE_OUT BIT(16) ++#define RB_HW_OPT_HAS_uSD BIT(17) ++#define RB_HW_OPT_HAS_SIM BIT(18) ++#define RB_HW_OPT_HAS_SFP BIT(20) ++#define RB_HW_OPT_HAS_WIFI BIT(21) ++#define RB_HW_OPT_HAS_TS_FOR_ADC BIT(22) ++#define RB_HW_OPT_HAS_PLC BIT(29) ++ ++/* ++ * Tag ID values for ERD data. ++ * Mikrotik used to pack all calibration data under a single tag id 0x1, but ++ * recently switched to a new scheme where each radio calibration gets a ++ * separate tag. The new scheme has tag id bit 15 always set and seems to be ++ * mutually exclusive with the old scheme. ++ */ ++#define RB_WLAN_ERD_ID_SOLO 0x0001 ++#define RB_WLAN_ERD_ID_MULTI_8001 0x8001 ++#define RB_WLAN_ERD_ID_MULTI_8201 0x8201 ++ ++static struct kobject *hc_kobj; ++static u8 *hc_buf; // ro buffer after init(): no locking required ++static size_t hc_buflen; ++ ++/* ++ * For LZOR style WLAN data unpacking. ++ * This binary blob is prepended to the data encoded on some devices as ++ * RB_ID_WLAN_DATA, the result is then first decompressed with LZO, and then ++ * finally RLE-decoded. ++ * This binary blob has been extracted from RouterOS by ++ * https://forum.openwrt.org/u/ius ++ */ ++static const u8 hc_lzor_prefix[] = { ++ 0x00, 0x05, 0x4c, 0x4c, 0x44, 0x00, 0x34, 0xfe, ++ 0xfe, 0x34, 0x11, 0x3c, 0x1e, 0x3c, 0x2e, 0x3c, ++ 0x4c, 0x34, 0x00, 0x52, 0x62, 0x92, 0xa2, 0xb2, ++ 0xc3, 0x2a, 0x14, 0x00, 0x00, 0x05, 0xfe, 0x6a, ++ 0x3c, 0x16, 0x32, 0x16, 0x11, 0x1e, 0x12, 0x46, ++ 0x32, 0x46, 0x11, 0x4e, 0x12, 0x36, 0x32, 0x36, ++ 0x11, 0x3e, 0x12, 0x5a, 0x9a, 0x64, 0x00, 0x04, ++ 0xfe, 0x10, 0x3c, 0x00, 0x01, 0x00, 0x00, 0x28, ++ 0x0c, 0x00, 0x0f, 0xfe, 0x14, 0x00, 0x24, 0x24, ++ 0x23, 0x24, 0x24, 0x23, 0x25, 0x22, 0x21, 0x21, ++ 0x23, 0x22, 0x21, 0x22, 0x21, 0x2d, 0x38, 0x00, ++ 0x0c, 0x25, 0x25, 0x24, 0x25, 0x25, 0x24, 0x23, ++ 0x22, 0x21, 0x20, 0x23, 0x21, 0x21, 0x22, 0x21, ++ 0x2d, 0x38, 0x00, 0x28, 0xb0, 0x00, 0x00, 0x22, ++ 0x00, 0x00, 0xc0, 0xfe, 0x03, 0x00, 0xc0, 0x00, ++ 0x62, 0xff, 0x62, 0xff, 0xfe, 0x06, 0x00, 0xbb, ++ 0xff, 0xba, 0xff, 0xfe, 0x08, 0x00, 0x9e, 0xff, ++ 0xfe, 0x0a, 0x00, 0x53, 0xff, 0xfe, 0x02, 0x00, ++ 0x20, 0xff, 0xb1, 0xfe, 0xfe, 0xb2, 0xfe, 0xfe, ++ 0xed, 0xfe, 0xfe, 0xfe, 0x04, 0x00, 0x3a, 0xff, ++ 0x3a, 0xff, 0xde, 0xfd, 0x5f, 0x04, 0x33, 0xff, ++ 0x4c, 0x74, 0x03, 0x05, 0x05, 0xff, 0x6d, 0xfe, ++ 0xfe, 0x6d, 0xfe, 0xfe, 0xaf, 0x08, 0x63, 0xff, ++ 0x64, 0x6f, 0x08, 0xac, 0xff, 0xbf, 0x6d, 0x08, ++ 0x7a, 0x6d, 0x08, 0x96, 0x74, 0x04, 0x00, 0x08, ++ 0x79, 0xff, 0xda, 0xfe, 0xfe, 0xdb, 0xfe, 0xfe, ++ 0x56, 0xff, 0xfe, 0x04, 0x00, 0x5e, 0xff, 0x5e, ++ 0xff, 0x6c, 0xfe, 0xfe, 0xfe, 0x06, 0x00, 0x41, ++ 0xff, 0x7f, 0x74, 0x03, 0x00, 0x11, 0x44, 0xff, ++ 0xa9, 0xfe, 0xfe, 0xa9, 0xfe, 0xfe, 0xa5, 0x8f, ++ 0x01, 0x00, 0x08, 0x01, 0x01, 0x02, 0x04, 0x08, ++ 0x02, 0x04, 0x08, 0x08, 0x01, 0x01, 0xfe, 0x22, ++ 0x00, 0x4c, 0x60, 0x64, 0x8c, 0x90, 0xd0, 0xd4, ++ 0xd8, 0x5c, 0x10, 0x09, 0xd8, 0xff, 0xb0, 0xff, ++ 0x00, 0x00, 0xba, 0xff, 0x14, 0x00, 0xba, 0xff, ++ 0x64, 0x00, 0x00, 0x08, 0xfe, 0x06, 0x00, 0x74, ++ 0xff, 0x42, 0xff, 0xce, 0xff, 0x60, 0xff, 0x0a, ++ 0x00, 0xb4, 0x00, 0xa0, 0x00, 0xa0, 0xfe, 0x07, ++ 0x00, 0x0a, 0x00, 0xb0, 0xff, 0x96, 0x4d, 0x00, ++ 0x56, 0x57, 0x18, 0xa6, 0xff, 0x92, 0x70, 0x11, ++ 0x00, 0x12, 0x90, 0x90, 0x76, 0x5a, 0x54, 0x54, ++ 0x4c, 0x46, 0x38, 0x00, 0x10, 0x10, 0x08, 0xfe, ++ 0x05, 0x00, 0x38, 0x29, 0x25, 0x23, 0x22, 0x22, ++ 0x1f, 0x00, 0x00, 0x00, 0xf6, 0xe1, 0xdd, 0xf8, ++ 0xfe, 0x00, 0xfe, 0x15, 0x00, 0x00, 0xd0, 0x02, ++ 0x74, 0x02, 0x08, 0xf8, 0xe5, 0xde, 0x02, 0x04, ++ 0x04, 0xfd, 0x00, 0x00, 0x00, 0x07, 0x50, 0x2d, ++ 0x01, 0x90, 0x90, 0x76, 0x60, 0xb0, 0x07, 0x07, ++ 0x0c, 0x0c, 0x04, 0xfe, 0x05, 0x00, 0x66, 0x66, ++ 0x5a, 0x56, 0xbc, 0x01, 0x06, 0xfc, 0xfc, 0xf1, ++ 0xfe, 0x07, 0x00, 0x24, 0x95, 0x70, 0x64, 0x18, ++ 0x06, 0x2c, 0xff, 0xb5, 0xfe, 0xfe, 0xb5, 0xfe, ++ 0xfe, 0xe2, 0x8c, 0x24, 0x02, 0x2f, 0xff, 0x2f, ++ 0xff, 0xb4, 0x78, 0x02, 0x05, 0x73, 0xff, 0xed, ++ 0xfe, 0xfe, 0x4f, 0xff, 0x36, 0x74, 0x1e, 0x09, ++ 0x4f, 0xff, 0x50, 0xff, 0xfe, 0x16, 0x00, 0x70, ++ 0xac, 0x70, 0x8e, 0xac, 0x40, 0x0e, 0x01, 0x70, ++ 0x7f, 0x8e, 0xac, 0x6c, 0x00, 0x0b, 0xfe, 0x02, ++ 0x00, 0xfe, 0x0a, 0x2c, 0x2a, 0x2a, 0x28, 0x26, ++ 0x1e, 0x1e, 0xfe, 0x02, 0x20, 0x65, 0x20, 0x00, ++ 0x00, 0x05, 0x12, 0x00, 0x11, 0x1e, 0x11, 0x11, ++ 0x41, 0x1e, 0x41, 0x11, 0x31, 0x1e, 0x31, 0x11, ++ 0x70, 0x75, 0x7a, 0x7f, 0x84, 0x89, 0x8e, 0x93, ++ 0x98, 0x30, 0x20, 0x00, 0x02, 0x00, 0xfe, 0x06, ++ 0x3c, 0xbc, 0x32, 0x0c, 0x00, 0x00, 0x2a, 0x12, ++ 0x1e, 0x12, 0x2e, 0x12, 0xcc, 0x12, 0x11, 0x1a, ++ 0x1e, 0x1a, 0x2e, 0x1a, 0x4c, 0x10, 0x1e, 0x10, ++ 0x11, 0x18, 0x1e, 0x42, 0x1e, 0x42, 0x2e, 0x42, ++ 0xcc, 0x42, 0x11, 0x4a, 0x1e, 0x4a, 0x2e, 0x4a, ++ 0x4c, 0x40, 0x1e, 0x40, 0x11, 0x48, 0x1e, 0x32, ++ 0x1e, 0x32, 0x2e, 0x32, 0xcc, 0x32, 0x11, 0x3a, ++ 0x1e, 0x3a, 0x2e, 0x3a, 0x4c, 0x30, 0x1e, 0x30, ++ 0x11, 0x38, 0x1e, 0x27, 0x9a, 0x01, 0x9d, 0xa2, ++ 0x2f, 0x28, 0x00, 0x00, 0x46, 0xde, 0xc4, 0xbf, ++ 0xa6, 0x9d, 0x81, 0x7b, 0x5c, 0x61, 0x40, 0xc7, ++ 0xc0, 0xae, 0xa9, 0x8c, 0x83, 0x6a, 0x62, 0x50, ++ 0x3e, 0xce, 0xc2, 0xae, 0xa3, 0x8c, 0x7b, 0x6a, ++ 0x5a, 0x50, 0x35, 0xd7, 0xc2, 0xb7, 0xa4, 0x95, ++ 0x7e, 0x72, 0x5a, 0x59, 0x37, 0xfe, 0x02, 0xf8, ++ 0x8c, 0x95, 0x90, 0x8f, 0x00, 0xd7, 0xc0, 0xb7, ++ 0xa2, 0x95, 0x7b, 0x72, 0x56, 0x59, 0x32, 0xc7, ++ 0xc3, 0xae, 0xad, 0x8c, 0x85, 0x6a, 0x63, 0x50, ++ 0x3e, 0xce, 0xc3, 0xae, 0xa4, 0x8c, 0x7c, 0x6a, ++ 0x59, 0x50, 0x34, 0xd7, 0xc2, 0xb7, 0xa5, 0x95, ++ 0x7e, 0x72, 0x59, 0x59, 0x36, 0xfc, 0x05, 0x00, ++ 0x02, 0xce, 0xc5, 0xae, 0xa5, 0x95, 0x83, 0x72, ++ 0x5c, 0x59, 0x36, 0xbf, 0xc6, 0xa5, 0xab, 0x8c, ++ 0x8c, 0x6a, 0x67, 0x50, 0x41, 0x64, 0x07, 0x00, ++ 0x02, 0x95, 0x8c, 0x72, 0x65, 0x59, 0x3f, 0xce, ++ 0xc7, 0xae, 0xa8, 0x95, 0x86, 0x72, 0x5f, 0x59, ++ 0x39, 0xfe, 0x02, 0xf8, 0x8b, 0x7c, 0x0b, 0x09, ++ 0xb7, 0xc2, 0x9d, 0xa4, 0x83, 0x85, 0x6a, 0x6b, ++ 0x50, 0x44, 0xb7, 0xc1, 0x64, 0x01, 0x00, 0x06, ++ 0x61, 0x5d, 0x48, 0x3d, 0xae, 0xc4, 0x9d, 0xad, ++ 0x7b, 0x85, 0x61, 0x66, 0x48, 0x46, 0xae, 0xc3, ++ 0x95, 0xa3, 0x72, 0x7c, 0x59, 0x56, 0x38, 0x31, ++ 0x7c, 0x0b, 0x00, 0x0c, 0x96, 0x91, 0x8f, 0x00, ++ 0xb7, 0xc0, 0xa5, 0xab, 0x8c, 0x8a, 0x6a, 0x64, ++ 0x50, 0x3c, 0xb7, 0xc0, 0x9d, 0xa0, 0x83, 0x80, ++ 0x6a, 0x64, 0x50, 0x3d, 0xb7, 0xc5, 0x9d, 0xa5, ++ 0x83, 0x87, 0x6c, 0x08, 0x07, 0xae, 0xc0, 0x9d, ++ 0xa8, 0x83, 0x88, 0x6a, 0x6d, 0x50, 0x46, 0xfc, ++ 0x05, 0x00, 0x16, 0xbf, 0xc0, 0xa5, 0xa2, 0x8c, ++ 0x7f, 0x6a, 0x57, 0x50, 0x2f, 0xb7, 0xc7, 0xa5, ++ 0xb1, 0x8c, 0x8e, 0x72, 0x6d, 0x59, 0x45, 0xbf, ++ 0xc6, 0xa5, 0xa8, 0x8c, 0x87, 0x6a, 0x5f, 0x50, ++ 0x37, 0xbf, 0xc2, 0xa5, 0xa4, 0x8c, 0x83, 0x6a, ++ 0x5c, 0x50, 0x34, 0xbc, 0x05, 0x00, 0x0e, 0x90, ++ 0x00, 0xc7, 0xc2, 0xae, 0xaa, 0x95, 0x82, 0x7b, ++ 0x60, 0x61, 0x3f, 0xb7, 0xc6, 0xa5, 0xb1, 0x8c, ++ 0x8d, 0x72, 0x6b, 0x61, 0x51, 0xbf, 0xc4, 0xa5, ++ 0xa5, 0x8c, 0x82, 0x72, 0x61, 0x59, 0x39, 0x6c, ++ 0x26, 0x03, 0x95, 0x82, 0x7b, 0x61, 0x61, 0x40, ++ 0xfc, 0x05, 0x00, 0x00, 0x7e, 0xd7, 0xc3, 0xb7, ++ 0xa8, 0x9d, 0x80, 0x83, 0x5d, 0x6a, 0x3f, 0xbf, ++ 0xc7, 0xa5, 0xa8, 0x8c, 0x84, 0x72, 0x60, 0x61, ++ 0x46, 0xbf, 0xc2, 0xae, 0xb0, 0x9d, 0x92, 0x83, ++ 0x6f, 0x6a, 0x50, 0xd7, 0xc3, 0xb7, 0xa7, 0x9d, ++ 0x80, 0x83, 0x5e, 0x6a, 0x40, 0xfe, 0x02, 0xf8, ++ 0x8d, 0x96, 0x90, 0x90, 0xfe, 0x05, 0x00, 0x8a, ++ 0xc4, 0x63, 0xb8, 0x3c, 0xa6, 0x29, 0x97, 0x16, ++ 0x81, 0x84, 0xb7, 0x5b, 0xa9, 0x33, 0x94, 0x1e, ++ 0x83, 0x11, 0x70, 0xb8, 0xc2, 0x70, 0xb1, 0x4d, ++ 0xa3, 0x2a, 0x8d, 0x1b, 0x7b, 0xa8, 0xbc, 0x68, ++ 0xab, 0x47, 0x9d, 0x27, 0x87, 0x18, 0x75, 0xae, ++ 0xc6, 0x7d, 0xbb, 0x4d, 0xaa, 0x1c, 0x84, 0x11, ++ 0x72, 0xa3, 0xbb, 0x6e, 0xad, 0x3c, 0x97, 0x24, ++ 0x85, 0x16, 0x71, 0x80, 0xb2, 0x57, 0xa4, 0x30, ++ 0x8e, 0x1c, 0x7c, 0x10, 0x68, 0xbb, 0xbd, 0x75, ++ 0xac, 0x4f, 0x9e, 0x2b, 0x87, 0x1a, 0x76, 0x96, ++ 0xc5, 0x5e, 0xb5, 0x3e, 0xa5, 0x1f, 0x8c, 0x12, ++ 0x7a, 0xc1, 0xc6, 0x42, 0x9f, 0x27, 0x8c, 0x16, ++ 0x77, 0x0f, 0x67, 0x9d, 0xbc, 0x68, 0xad, 0x36, ++ 0x95, 0x20, 0x83, 0x11, 0x6d, 0x9b, 0xb8, 0x67, ++ 0xa8, 0x34, 0x90, 0x1f, 0x7c, 0x10, 0x67, 0x9e, ++ 0xc9, 0x6a, 0xbb, 0x37, 0xa4, 0x20, 0x90, 0x11, ++ 0x7b, 0xc6, 0xc8, 0x47, 0xa4, 0x2a, 0x90, 0x18, ++ 0x7b, 0x10, 0x6c, 0xae, 0xc4, 0x5d, 0xad, 0x37, ++ 0x9a, 0x1f, 0x85, 0x13, 0x75, 0x70, 0xad, 0x42, ++ 0x99, 0x25, 0x84, 0x17, 0x74, 0x0b, 0x56, 0x87, ++ 0xc8, 0x57, 0xb8, 0x2b, 0x9e, 0x19, 0x8a, 0x0d, ++ 0x74, 0xa7, 0xc8, 0x6e, 0xb9, 0x36, 0xa0, 0x1f, ++ 0x8b, 0x11, 0x75, 0x94, 0xbe, 0x4b, 0xa5, 0x2a, ++ 0x92, 0x18, 0x7c, 0x0f, 0x6b, 0xaf, 0xc0, 0x58, ++ 0xa8, 0x34, 0x94, 0x1d, 0x7d, 0x12, 0x6d, 0x82, ++ 0xc0, 0x52, 0xb0, 0x25, 0x94, 0x14, 0x7f, 0x0c, ++ 0x68, 0x84, 0xbf, 0x3e, 0xa4, 0x22, 0x8e, 0x10, ++ 0x76, 0x0b, 0x65, 0x88, 0xb6, 0x42, 0x9b, 0x26, ++ 0x87, 0x14, 0x70, 0x0c, 0x5f, 0xc5, 0xc2, 0x3e, ++ 0x97, 0x23, 0x83, 0x13, 0x6c, 0x0c, 0x5c, 0xb1, ++ 0xc9, 0x76, 0xbc, 0x4a, 0xaa, 0x20, 0x8d, 0x12, ++ 0x78, 0x93, 0xbf, 0x46, 0xa3, 0x26, 0x8d, 0x14, ++ 0x74, 0x0c, 0x62, 0xc8, 0xc4, 0x3b, 0x97, 0x21, ++ 0x82, 0x11, 0x6a, 0x0a, 0x59, 0xa3, 0xb9, 0x68, ++ 0xa9, 0x30, 0x8d, 0x1a, 0x78, 0x0f, 0x61, 0xa0, ++ 0xc9, 0x73, 0xbe, 0x50, 0xb1, 0x30, 0x9f, 0x14, ++ 0x80, 0x83, 0xb7, 0x3c, 0x9a, 0x20, 0x84, 0x0e, ++ 0x6a, 0x0a, 0x57, 0xac, 0xc2, 0x68, 0xb0, 0x2e, ++ 0x92, 0x19, 0x7c, 0x0d, 0x63, 0x93, 0xbe, 0x62, ++ 0xb0, 0x3c, 0x9e, 0x1a, 0x80, 0x0e, 0x6b, 0xbb, ++ 0x02, 0xa0, 0x02, 0xa0, 0x02, 0x6f, 0x00, 0x75, ++ 0x00, 0x75, 0x00, 0x00, 0x00, 0xad, 0x02, 0xb3, ++ 0x02, 0x6f, 0x00, 0x87, 0x00, 0x85, 0xfe, 0x03, ++ 0x00, 0xc2, 0x02, 0x82, 0x4d, 0x92, 0x6e, 0x4d, ++ 0xb1, 0xa8, 0x84, 0x01, 0x00, 0x07, 0x7e, 0x00, ++ 0xa8, 0x02, 0xa4, 0x02, 0xa4, 0x02, 0xa2, 0x00, ++ 0xa6, 0x00, 0xa6, 0x00, 0x00, 0x00, 0xb4, 0x02, ++ 0xb4, 0x02, 0x92, 0x00, 0x96, 0x00, 0x96, 0x46, ++ 0x04, 0xb0, 0x02, 0x64, 0x02, 0x0a, 0x8c, 0x00, ++ 0x90, 0x02, 0x98, 0x02, 0x98, 0x02, 0x0e, 0x01, ++ 0x11, 0x01, 0x11, 0x50, 0xc3, 0x08, 0x88, 0x02, ++ 0x88, 0x02, 0x19, 0x01, 0x02, 0x01, 0x02, 0x01, ++ 0xf3, 0x2d, 0x00, 0x00 ++}; ++ ++/* Array of known hw_options bits with human-friendly parsing */ ++static struct hc_hwopt { ++ const u32 bit; ++ const char *str; ++} const hc_hwopts[] = { ++ { ++ .bit = RB_HW_OPT_NO_UART, ++ .str = "no UART\t\t", ++ }, { ++ .bit = RB_HW_OPT_HAS_VOLTAGE, ++ .str = "has Vreg\t", ++ }, { ++ .bit = RB_HW_OPT_HAS_USB, ++ .str = "has usb\t\t", ++ }, { ++ .bit = RB_HW_OPT_HAS_ATTINY, ++ .str = "has ATtiny\t", ++ }, { ++ .bit = RB_HW_OPT_NO_NAND, ++ .str = "no NAND\t\t", ++ }, { ++ .bit = RB_HW_OPT_HAS_LCD, ++ .str = "has LCD\t\t", ++ }, { ++ .bit = RB_HW_OPT_HAS_POE_OUT, ++ .str = "has POE out\t", ++ }, { ++ .bit = RB_HW_OPT_HAS_uSD, ++ .str = "has MicroSD\t", ++ }, { ++ .bit = RB_HW_OPT_HAS_SIM, ++ .str = "has SIM\t\t", ++ }, { ++ .bit = RB_HW_OPT_HAS_SFP, ++ .str = "has SFP\t\t", ++ }, { ++ .bit = RB_HW_OPT_HAS_WIFI, ++ .str = "has WiFi\t", ++ }, { ++ .bit = RB_HW_OPT_HAS_TS_FOR_ADC, ++ .str = "has TS ADC\t", ++ }, { ++ .bit = RB_HW_OPT_HAS_PLC, ++ .str = "has PLC\t\t", ++ }, ++}; ++ ++/* ++ * The MAC is stored network-endian on all devices, in 2 32-bit segments: ++ * . Kernel print has us covered. ++ */ ++static ssize_t hc_tag_show_mac(const u8 *pld, u16 pld_len, char *buf) ++{ ++ if (8 != pld_len) ++ return -EINVAL; ++ ++ return sprintf(buf, "%pM\n", pld); ++} ++ ++/* ++ * Print HW options in a human readable way: ++ * The raw number and in decoded form ++ */ ++static ssize_t hc_tag_show_hwoptions(const u8 *pld, u16 pld_len, char *buf) ++{ ++ char *out = buf; ++ u32 data; // cpu-endian ++ int i; ++ ++ if (sizeof(data) != pld_len) ++ return -EINVAL; ++ ++ data = *(u32 *)pld; ++ out += sprintf(out, "raw\t\t: 0x%08x\n\n", data); ++ ++ for (i = 0; i < ARRAY_SIZE(hc_hwopts); i++) ++ out += sprintf(out, "%s: %s\n", hc_hwopts[i].str, ++ (data & hc_hwopts[i].bit) ? "true" : "false"); ++ ++ return out - buf; ++} ++ ++static ssize_t hc_wlan_data_bin_read(struct file *filp, struct kobject *kobj, ++ struct bin_attribute *attr, char *buf, ++ loff_t off, size_t count); ++ ++static struct hc_wlan_attr { ++ const u16 erd_tag_id; ++ struct bin_attribute battr; ++ u16 pld_ofs; ++ u16 pld_len; ++} hc_wd_multi_battrs[] = { ++ { ++ .erd_tag_id = RB_WLAN_ERD_ID_MULTI_8001, ++ .battr = __BIN_ATTR(data_0, S_IRUSR, hc_wlan_data_bin_read, NULL, 0), ++ }, { ++ .erd_tag_id = RB_WLAN_ERD_ID_MULTI_8201, ++ .battr = __BIN_ATTR(data_2, S_IRUSR, hc_wlan_data_bin_read, NULL, 0), ++ } ++}; ++ ++static struct hc_wlan_attr hc_wd_solo_battr = { ++ .erd_tag_id = RB_WLAN_ERD_ID_SOLO, ++ .battr = __BIN_ATTR(wlan_data, S_IRUSR, hc_wlan_data_bin_read, NULL, 0), ++}; ++ ++static ssize_t hc_attr_show(struct kobject *kobj, struct kobj_attribute *attr, ++ char *buf); ++ ++/* Array of known tags to publish in sysfs */ ++static struct hc_attr { ++ const u16 tag_id; ++ ssize_t (* const tshow)(const u8 *pld, u16 pld_len, char *buf); ++ struct kobj_attribute kattr; ++ u16 pld_ofs; ++ u16 pld_len; ++} hc_attrs[] = { ++ { ++ .tag_id = RB_ID_FLASH_INFO, ++ .tshow = routerboot_tag_show_u32s, ++ .kattr = __ATTR(flash_info, S_IRUSR, hc_attr_show, NULL), ++ }, { ++ .tag_id = RB_ID_MAC_ADDRESS_PACK, ++ .tshow = hc_tag_show_mac, ++ .kattr = __ATTR(mac_base, S_IRUSR, hc_attr_show, NULL), ++ }, { ++ .tag_id = RB_ID_BOARD_PRODUCT_CODE, ++ .tshow = routerboot_tag_show_string, ++ .kattr = __ATTR(board_product_code, S_IRUSR, hc_attr_show, NULL), ++ }, { ++ .tag_id = RB_ID_BIOS_VERSION, ++ .tshow = routerboot_tag_show_string, ++ .kattr = __ATTR(booter_version, S_IRUSR, hc_attr_show, NULL), ++ }, { ++ .tag_id = RB_ID_SERIAL_NUMBER, ++ .tshow = routerboot_tag_show_string, ++ .kattr = __ATTR(board_serial, S_IRUSR, hc_attr_show, NULL), ++ }, { ++ .tag_id = RB_ID_MEMORY_SIZE, ++ .tshow = routerboot_tag_show_u32s, ++ .kattr = __ATTR(mem_size, S_IRUSR, hc_attr_show, NULL), ++ }, { ++ .tag_id = RB_ID_MAC_ADDRESS_COUNT, ++ .tshow = routerboot_tag_show_u32s, ++ .kattr = __ATTR(mac_count, S_IRUSR, hc_attr_show, NULL), ++ }, { ++ .tag_id = RB_ID_HW_OPTIONS, ++ .tshow = hc_tag_show_hwoptions, ++ .kattr = __ATTR(hw_options, S_IRUSR, hc_attr_show, NULL), ++ }, { ++ .tag_id = RB_ID_WLAN_DATA, ++ .tshow = NULL, ++ }, { ++ .tag_id = RB_ID_BOARD_IDENTIFIER, ++ .tshow = routerboot_tag_show_string, ++ .kattr = __ATTR(board_identifier, S_IRUSR, hc_attr_show, NULL), ++ }, { ++ .tag_id = RB_ID_PRODUCT_NAME, ++ .tshow = routerboot_tag_show_string, ++ .kattr = __ATTR(product_name, S_IRUSR, hc_attr_show, NULL), ++ }, { ++ .tag_id = RB_ID_DEFCONF, ++ .tshow = routerboot_tag_show_string, ++ .kattr = __ATTR(defconf, S_IRUSR, hc_attr_show, NULL), ++ }, { ++ .tag_id = RB_ID_BOARD_REVISION, ++ .tshow = routerboot_tag_show_string, ++ .kattr = __ATTR(board_revision, S_IRUSR, hc_attr_show, NULL), ++ } ++}; ++ ++/* ++ * If the RB_ID_WLAN_DATA payload starts with RB_MAGIC_ERD, then past ++ * that magic number the payload itself contains a routerboot tag node ++ * locating the LZO-compressed calibration data. So far this scheme is only ++ * known to use a single tag at id 0x1. ++ */ ++static int hc_wlan_data_unpack_erd(const u16 tag_id, const u8 *inbuf, size_t inlen, ++ void *outbuf, size_t *outlen) ++{ ++ u16 lzo_ofs, lzo_len; ++ int ret; ++ ++ /* Find embedded tag */ ++ ret = routerboot_tag_find(inbuf, inlen, tag_id, &lzo_ofs, &lzo_len); ++ if (ret) { ++ pr_debug(RB_HC_PR_PFX "no ERD data for id 0x%04x\n", tag_id); ++ goto fail; ++ } ++ ++ if (lzo_len > inlen) { ++ pr_debug(RB_HC_PR_PFX "Invalid ERD data length\n"); ++ ret = -EINVAL; ++ goto fail; ++ } ++ ++ ret = lzo1x_decompress_safe(inbuf+lzo_ofs, lzo_len, outbuf, outlen); ++ if (ret) ++ pr_debug(RB_HC_PR_PFX "LZO decompression error (%d)\n", ret); ++ ++fail: ++ return ret; ++} ++ ++/* ++ * If the RB_ID_WLAN_DATA payload starts with RB_MAGIC_LZOR, then past ++ * that magic number is a payload that must be appended to the hc_lzor_prefix, ++ * the resulting blob is LZO-compressed. ++ * If payload starts with RB_MAGIC_LZ77, a separate (bit level LZ77) ++ * decompression function needs to be used. In the decompressed result, ++ * the RB_MAGIC_ERD magic number (aligned) must be located. Following that ++ * magic, there is one or more routerboot tag node(s) locating the RLE-encoded ++ * calibration data payload. ++ */ ++static int hc_wlan_data_unpack_lzor_lz77(const u16 tag_id, const u8 *inbuf, size_t inlen, ++ void *outbuf, size_t *outlen, u32 magic) ++{ ++ u16 rle_ofs, rle_len; ++ const u32 *needle; ++ u8 *tempbuf; ++ size_t templen, lzo_len; ++ int ret; ++ const char lzor[] = "LZOR"; ++ const char lz77[] = "LZ77"; ++ const char *lz_type; ++ ++ /* Temporary buffer same size as the outbuf */ ++ templen = *outlen; ++ tempbuf = kmalloc(templen, GFP_KERNEL); ++ if (!tempbuf) ++ return -ENOMEM; ++ ++ lzo_len = inlen; ++ if (magic == RB_MAGIC_LZOR) ++ lzo_len += sizeof(hc_lzor_prefix); ++ if (lzo_len > *outlen) ++ return -EFBIG; ++ ++ switch (magic) { ++ case RB_MAGIC_LZOR: ++ lz_type = lzor; ++ ++ /* Concatenate into the outbuf */ ++ memcpy(outbuf, hc_lzor_prefix, sizeof(hc_lzor_prefix)); ++ memcpy(outbuf + sizeof(hc_lzor_prefix), inbuf, inlen); ++ ++ /* LZO-decompress lzo_len bytes of outbuf into the tempbuf */ ++ ret = lzo1x_decompress_safe(outbuf, lzo_len, tempbuf, &templen); ++ if (ret) { ++ if (LZO_E_INPUT_NOT_CONSUMED == ret) { ++ /* ++ * The tag length is always aligned thus the LZO payload may be padded, ++ * which can trigger a spurious error which we ignore here. ++ */ ++ pr_debug(RB_HC_PR_PFX "LZOR: LZO EOF before buffer end - this may be harmless\n"); ++ } else { ++ pr_debug(RB_HC_PR_PFX "LZOR: LZO decompression error (%d)\n", ret); ++ goto fail; ++ } ++ } ++ break; ++ case RB_MAGIC_LZ77: ++ lz_type = lz77; ++ /* LZO-decompress lzo_len bytes of inbuf into the tempbuf */ ++ ret = rb_lz77_decompress(inbuf, inlen, tempbuf, &templen); ++ if (ret) { ++ pr_err(RB_HC_PR_PFX "LZ77: LZ77 decompress error %d\n", ret); ++ goto fail; ++ } ++ ++ pr_debug(RB_HC_PR_PFX "LZ77: decompressed from %zu to %zu\n", ++ inlen, templen); ++ break; ++ default: ++ return -EINVAL; ++ break; ++ } ++ ++ /* ++ * Post decompression we have a blob (possibly byproduct of the lzo ++ * dictionary). We need to find RB_MAGIC_ERD. The magic number seems to ++ * be 32bit-aligned in the decompression output. ++ */ ++ needle = (const u32 *)tempbuf; ++ while (RB_MAGIC_ERD != *needle++) { ++ if ((u8 *)needle >= tempbuf+templen) { ++ pr_warn(RB_HC_PR_PFX "%s: ERD magic not found. Decompressed first word: 0x%08x\n", lz_type, *(u32 *)tempbuf); ++ ret = -ENODATA; ++ goto fail; ++ } ++ }; ++ templen -= (u8 *)needle - tempbuf; ++ ++ /* Past magic. Look for tag node */ ++ ret = routerboot_tag_find((u8 *)needle, templen, tag_id, &rle_ofs, &rle_len); ++ if (ret) { ++ pr_debug(RB_HC_PR_PFX "%s: no RLE data for id 0x%04x\n", lz_type, tag_id); ++ goto fail; ++ } ++ ++ if (rle_len > templen) { ++ pr_debug(RB_HC_PR_PFX "%s: Invalid RLE data length\n", lz_type); ++ ret = -EINVAL; ++ goto fail; ++ } ++ ++ /* RLE-decode tempbuf from needle back into the outbuf */ ++ ret = routerboot_rle_decode((u8 *)needle+rle_ofs, rle_len, outbuf, outlen); ++ if (ret) ++ pr_debug(RB_HC_PR_PFX "%s: RLE decoding error (%d)\n", lz_type, ret); ++ ++fail: ++ kfree(tempbuf); ++ return ret; ++} ++ ++static int hc_wlan_data_unpack(const u16 tag_id, const size_t tofs, size_t tlen, ++ void *outbuf, size_t *outlen) ++{ ++ const u8 *lbuf; ++ u32 magic; ++ int ret; ++ ++ /* Caller ensure tlen > 0. tofs is aligned */ ++ if ((tofs + tlen) > hc_buflen) ++ return -EIO; ++ ++ lbuf = hc_buf + tofs; ++ magic = *(u32 *)lbuf; ++ ++ ret = -ENODATA; ++ switch (magic) { ++ case RB_MAGIC_LZ77: ++ /* no known instances of lz77 without 8001/8201 data, skip SOLO */ ++ if (tag_id == RB_WLAN_ERD_ID_SOLO) { ++ pr_debug(RB_HC_PR_PFX "skipped LZ77 decompress in search for SOLO tag\n"); ++ break; ++ } ++ fallthrough; ++ case RB_MAGIC_LZOR: ++ /* Skip magic */ ++ lbuf += sizeof(magic); ++ tlen -= sizeof(magic); ++ ret = hc_wlan_data_unpack_lzor_lz77(tag_id, lbuf, tlen, outbuf, outlen, magic); ++ break; ++ case RB_MAGIC_ERD: ++ /* Skip magic */ ++ lbuf += sizeof(magic); ++ tlen -= sizeof(magic); ++ ret = hc_wlan_data_unpack_erd(tag_id, lbuf, tlen, outbuf, outlen); ++ break; ++ default: ++ /* ++ * If the RB_ID_WLAN_DATA payload doesn't start with a ++ * magic number, the payload itself is the raw RLE-encoded ++ * calibration data. Only RB_WLAN_ERD_ID_SOLO makes sense here. ++ */ ++ if (RB_WLAN_ERD_ID_SOLO == tag_id) { ++ ret = routerboot_rle_decode(lbuf, tlen, outbuf, outlen); ++ if (ret) ++ pr_debug(RB_HC_PR_PFX "RLE decoding error (%d)\n", ret); ++ } ++ break; ++ } ++ ++ return ret; ++} ++ ++static ssize_t hc_attr_show(struct kobject *kobj, struct kobj_attribute *attr, ++ char *buf) ++{ ++ const struct hc_attr *hc_attr; ++ const u8 *pld; ++ u16 pld_len; ++ ++ hc_attr = container_of(attr, typeof(*hc_attr), kattr); ++ ++ if (!hc_attr->pld_len) ++ return -ENOENT; ++ ++ pld = hc_buf + hc_attr->pld_ofs; ++ pld_len = hc_attr->pld_len; ++ ++ return hc_attr->tshow(pld, pld_len, buf); ++} ++ ++/* ++ * This function will allocate and free memory every time it is called. This ++ * is not the fastest way to do this, but since the data is rarely read (mainly ++ * at boot time to load wlan caldata), this makes it possible to save memory for ++ * the system. ++ */ ++static ssize_t hc_wlan_data_bin_read(struct file *filp, struct kobject *kobj, ++ struct bin_attribute *attr, char *buf, ++ loff_t off, size_t count) ++{ ++ struct hc_wlan_attr *hc_wattr; ++ size_t outlen; ++ void *outbuf; ++ int ret; ++ ++ hc_wattr = container_of(attr, typeof(*hc_wattr), battr); ++ ++ if (!hc_wattr->pld_len) ++ return -ENOENT; ++ ++ outlen = RB_ART_SIZE; ++ ++ /* Don't bother unpacking if the source is already too large */ ++ if (hc_wattr->pld_len > outlen) ++ return -EFBIG; ++ ++ outbuf = kmalloc(outlen, GFP_KERNEL); ++ if (!outbuf) ++ return -ENOMEM; ++ ++ ret = hc_wlan_data_unpack(hc_wattr->erd_tag_id, hc_wattr->pld_ofs, hc_wattr->pld_len, outbuf, &outlen); ++ if (ret) { ++ kfree(outbuf); ++ return ret; ++ } ++ ++ if (off >= outlen) { ++ kfree(outbuf); ++ return 0; ++ } ++ ++ if (off + count > outlen) ++ count = outlen - off; ++ ++ memcpy(buf, outbuf + off, count); ++ ++ kfree(outbuf); ++ return count; ++} ++ ++int rb_hardconfig_init(struct kobject *rb_kobj, struct mtd_info *mtd) ++{ ++ struct kobject *hc_wlan_kobj; ++ size_t bytes_read, buflen, outlen; ++ const u8 *buf; ++ void *outbuf; ++ int i, j, ret; ++ u32 magic; ++ ++ hc_buf = NULL; ++ hc_kobj = NULL; ++ hc_wlan_kobj = NULL; ++ ++ ret = __get_mtd_device(mtd); ++ if (ret) ++ return -ENODEV; ++ ++ hc_buflen = mtd->size; ++ hc_buf = kmalloc(hc_buflen, GFP_KERNEL); ++ if (!hc_buf) { ++ __put_mtd_device(mtd); ++ return -ENOMEM; ++ } ++ ++ ret = mtd_read(mtd, 0, hc_buflen, &bytes_read, hc_buf); ++ __put_mtd_device(mtd); ++ ++ if (ret) ++ goto fail; ++ ++ if (bytes_read != hc_buflen) { ++ ret = -EIO; ++ goto fail; ++ } ++ ++ /* Check we have what we expect */ ++ magic = *(const u32 *)hc_buf; ++ if (RB_MAGIC_HARD != magic) { ++ ret = -EINVAL; ++ goto fail; ++ } ++ ++ /* Skip magic */ ++ buf = hc_buf + sizeof(magic); ++ buflen = hc_buflen - sizeof(magic); ++ ++ /* Populate sysfs */ ++ ret = -ENOMEM; ++ hc_kobj = kobject_create_and_add(RB_MTD_HARD_CONFIG, rb_kobj); ++ if (!hc_kobj) ++ goto fail; ++ ++ /* Locate and publish all known tags */ ++ for (i = 0; i < ARRAY_SIZE(hc_attrs); i++) { ++ ret = routerboot_tag_find(buf, buflen, hc_attrs[i].tag_id, ++ &hc_attrs[i].pld_ofs, &hc_attrs[i].pld_len); ++ if (ret) { ++ hc_attrs[i].pld_ofs = hc_attrs[i].pld_len = 0; ++ continue; ++ } ++ ++ /* Account for skipped magic */ ++ hc_attrs[i].pld_ofs += sizeof(magic); ++ ++ /* ++ * Special case RB_ID_WLAN_DATA to prep and create the binary attribute. ++ * We first check if the data is "old style" within a single tag (or no tag at all): ++ * If it is we publish this single blob as a binary attribute child of hc_kobj to ++ * preserve backward compatibility. ++ * If it isn't and instead uses multiple ERD tags, we create a subfolder and ++ * publish the known ones there. ++ */ ++ if ((RB_ID_WLAN_DATA == hc_attrs[i].tag_id) && hc_attrs[i].pld_len) { ++ outlen = RB_ART_SIZE; ++ outbuf = kmalloc(outlen, GFP_KERNEL); ++ if (!outbuf) { ++ pr_warn(RB_HC_PR_PFX "Out of memory parsing WLAN tag\n"); ++ continue; ++ } ++ ++ /* Test ID_SOLO first, if found: done */ ++ ret = hc_wlan_data_unpack(RB_WLAN_ERD_ID_SOLO, hc_attrs[i].pld_ofs, hc_attrs[i].pld_len, outbuf, &outlen); ++ if (!ret) { ++ hc_wd_solo_battr.pld_ofs = hc_attrs[i].pld_ofs; ++ hc_wd_solo_battr.pld_len = hc_attrs[i].pld_len; ++ ++ ret = sysfs_create_bin_file(hc_kobj, &hc_wd_solo_battr.battr); ++ if (ret) ++ pr_warn(RB_HC_PR_PFX "Could not create %s sysfs entry (%d)\n", ++ hc_wd_solo_battr.battr.attr.name, ret); ++ } ++ /* Otherwise, create "wlan_data" subtree and publish known data */ ++ else { ++ hc_wlan_kobj = kobject_create_and_add("wlan_data", hc_kobj); ++ if (!hc_wlan_kobj) { ++ kfree(outbuf); ++ pr_warn(RB_HC_PR_PFX "Could not create wlan_data sysfs folder\n"); ++ continue; ++ } ++ ++ for (j = 0; j < ARRAY_SIZE(hc_wd_multi_battrs); j++) { ++ outlen = RB_ART_SIZE; ++ ret = hc_wlan_data_unpack(hc_wd_multi_battrs[j].erd_tag_id, ++ hc_attrs[i].pld_ofs, hc_attrs[i].pld_len, outbuf, &outlen); ++ if (ret) { ++ hc_wd_multi_battrs[j].pld_ofs = hc_wd_multi_battrs[j].pld_len = 0; ++ continue; ++ } ++ ++ hc_wd_multi_battrs[j].pld_ofs = hc_attrs[i].pld_ofs; ++ hc_wd_multi_battrs[j].pld_len = hc_attrs[i].pld_len; ++ ++ ret = sysfs_create_bin_file(hc_wlan_kobj, &hc_wd_multi_battrs[j].battr); ++ if (ret) ++ pr_warn(RB_HC_PR_PFX "Could not create wlan_data/%s sysfs entry (%d)\n", ++ hc_wd_multi_battrs[j].battr.attr.name, ret); ++ } ++ } ++ ++ kfree(outbuf); ++ } ++ /* All other tags are published via standard attributes */ ++ else { ++ ret = sysfs_create_file(hc_kobj, &hc_attrs[i].kattr.attr); ++ if (ret) ++ pr_warn(RB_HC_PR_PFX "Could not create %s sysfs entry (%d)\n", ++ hc_attrs[i].kattr.attr.name, ret); ++ } ++ } ++ ++ pr_info("MikroTik RouterBOARD hardware configuration sysfs driver v" RB_HARDCONFIG_VER "\n"); ++ ++ return 0; ++ ++fail: ++ kfree(hc_buf); ++ hc_buf = NULL; ++ return ret; ++} ++ ++void rb_hardconfig_exit(void) ++{ ++ kobject_put(hc_kobj); ++ hc_kobj = NULL; ++ kfree(hc_buf); ++ hc_buf = NULL; ++} +diff --git a/drivers/platform/mikrotik/rb_hardconfig.h b/drivers/platform/mikrotik/rb_hardconfig.h +new file mode 100644 +index 000000000000..328f4fe3c32a +--- /dev/null ++++ b/drivers/platform/mikrotik/rb_hardconfig.h +@@ -0,0 +1,32 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Common definitions for MikroTik RouterBoot hard config data. ++ * ++ * Copyright (C) 2020 Thibaut VARÈNE ++ * ++ * Some constant defines extracted from routerboot.{c,h} by Gabor Juhos ++ * ++ */ ++ ++#ifndef _ROUTERBOOT_HARD_CONFIG_H_ ++#define _ROUTERBOOT_HARD_CONFIG_H_ ++ ++/* ID values for hardware settings */ ++#define RB_ID_FLASH_INFO 0x03 ++#define RB_ID_MAC_ADDRESS_PACK 0x04 ++#define RB_ID_BOARD_PRODUCT_CODE 0x05 ++#define RB_ID_BIOS_VERSION 0x06 ++#define RB_ID_SDRAM_TIMINGS 0x08 ++#define RB_ID_DEVICE_TIMINGS 0x09 ++#define RB_ID_SOFTWARE_ID 0x0A ++#define RB_ID_SERIAL_NUMBER 0x0B ++#define RB_ID_MEMORY_SIZE 0x0D ++#define RB_ID_MAC_ADDRESS_COUNT 0x0E ++#define RB_ID_HW_OPTIONS 0x15 ++#define RB_ID_WLAN_DATA 0x16 ++#define RB_ID_BOARD_IDENTIFIER 0x17 ++#define RB_ID_PRODUCT_NAME 0x21 ++#define RB_ID_DEFCONF 0x26 ++#define RB_ID_BOARD_REVISION 0x27 ++ ++#endif /* _ROUTERBOOT_HARD_CONFIG_H_ */ +diff --git a/drivers/platform/mikrotik/rb_lz77.c b/drivers/platform/mikrotik/rb_lz77.c +new file mode 100644 +index 000000000000..d443adb128ee +--- /dev/null ++++ b/drivers/platform/mikrotik/rb_lz77.c +@@ -0,0 +1,446 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (C) 2023 John Thomson ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "rb_lz77.h" ++ ++#define MIKRO_LZ77 "[rb lz77] " ++ ++/* ++ * The maximum number of bits used in a counter. ++ * For the look behind window, long instruction match offsets ++ * up to 6449 have been seen in provided compressed caldata blobs ++ * (that would need 21 counter bits: 4 to 12 + 11 to 0). ++ * conservative value here: 27 provides offset up to 0x8000 bytes ++ * uses a u8 in this code ++ */ ++#define MIKRO_LZ77_MAX_COUNT_BIT_LEN 27 ++ ++enum rb_lz77_instruction { ++ INSTR_ERROR = -1, ++ INSTR_LITERAL_BYTE = 0, ++ /* a (non aligned) byte follows this instruction, ++ * which is directly copied into output ++ */ ++ INSTR_PREVIOUS_OFFSET = 1, ++ /* this group is a match, with a bytes length defined by ++ * following counter bits, starting at bitshift 0, ++ * less the built-in count of 1 ++ * using the previous offset as source ++ */ ++ INSTR_LONG = 2 ++ /* this group has two counters, ++ * the first counter starts at bitshift 4, ++ * if this counter == 0, this is a non-matching group ++ * the second counter (bytes length) starts at bitshift 4, ++ * less the built-in count of 11+1. ++ * The final match group has this count 0, ++ * and following bits which pad to byte-alignment. ++ * ++ * if this counter > 0, this is a matching group ++ * this first count is the match offset (in bytes) ++ * the second count is the match length (in bytes), ++ * less the built-in count of 2 ++ * these groups can source bytes that are part of this group ++ */ ++}; ++ ++struct rb_lz77_instr_opcodes { ++ /* group instruction */ ++ enum rb_lz77_instruction instruction; ++ /* if >0, a match group, ++ * which starts at byte output_position - 1*offset ++ */ ++ size_t offset; ++ /* how long the match group is, ++ * or how long the (following counter) non-match group is ++ */ ++ size_t length; ++ /* how many bits were used for this instruction + op code(s) */ ++ size_t bits_used; ++ /* input char */ ++ u8 *in; ++ /* offset where this instruction started */ ++ size_t in_pos; ++}; ++ ++/** ++ * rb_lz77_get_bit ++ * ++ * @in: compressed data ptr ++ * @in_offset_bit: bit offset to extract ++ * ++ * convert the bit offset to byte offset, ++ * shift to modulo of bits per bytes, so that wanted bit is lsb ++ * and to extract only that bit. ++ * Caller is responsible for ensuring that in_offset_bit/8 ++ * does not exceed input length ++ */ ++static inline u8 rb_lz77_get_bit(const u8 *in, const size_t in_offset_bit) ++{ ++ return ((in[in_offset_bit / BITS_PER_BYTE] >> ++ (in_offset_bit % BITS_PER_BYTE)) & ++ 1); ++} ++ ++/** ++ * rb_lz77_get_byte ++ * ++ * @in: compressed data ++ * @in_offset_bit: bit offset to extract byte ++ */ ++static inline u8 rb_lz77_get_byte(const u8 *in, const size_t in_offset_bit) ++{ ++ u8 buf = 0; ++ int i; ++ ++ /* built a reversed byte from (likely) unaligned bits */ ++ for (i = 0; i <= 7; ++i) ++ buf += rb_lz77_get_bit(in, in_offset_bit + i) << (7 - i); ++ return buf; ++} ++ ++/** ++ * rb_lz77_decode_count - decode bits at given offset as a count ++ * ++ * @in: compressed data ++ * @in_len: length of compressed data ++ * @in_offset_bit: bit offset where count starts ++ * @shift: left shift operand value of first count bit ++ * @count: initial count ++ * @bits_used: how many bits were consumed by this count ++ * @max_bits: maximum bit count for this counter ++ * ++ * Returns the decoded count ++ */ ++static int rb_lz77_decode_count(const u8 *in, const size_t in_len, ++ const size_t in_offset_bit, u8 shift, ++ size_t count, u8 *bits_used, const u8 max_bits) ++{ ++ size_t pos = in_offset_bit; ++ const size_t max_pos = min(pos + max_bits, in_len * BITS_PER_BYTE); ++ bool up = true; ++ ++ *bits_used = 0; ++ pr_debug(MIKRO_LZ77 ++ "decode_count inbit: %zu, start shift:%u, initial count:%zu\n", ++ in_offset_bit, shift, count); ++ ++ while (true) { ++ /* check the input offset bit does not overflow the minimum of ++ * a reasonable length for this encoded count, and ++ * the end of the input */ ++ if (unlikely(pos >= max_pos)) { ++ pr_err(MIKRO_LZ77 ++ "max bit index reached before count completed\n"); ++ return -EFBIG; ++ } ++ ++ /* if the bit value at offset is set */ ++ if (rb_lz77_get_bit(in, pos)) ++ count += (1 << shift); ++ ++ /* shift increases until we find an unsed bit */ ++ else if (up) ++ up = false; ++ ++ if (up) ++ ++shift; ++ else { ++ if (!shift) { ++ *bits_used = pos - in_offset_bit + 1; ++ return count; ++ } ++ --shift; ++ } ++ ++ ++pos; ++ } ++ ++ return -EINVAL; ++} ++ ++/** ++ * rb_lz77_decode_instruction ++ * ++ * @in: compressed data ++ * @in_offset_bit: bit offset where instruction starts ++ * @bits_used: how many bits were consumed by this count ++ * ++ * Returns the decoded instruction ++ */ ++static enum rb_lz77_instruction ++rb_lz77_decode_instruction(const u8 *in, size_t in_offset_bit, u8 *bits_used) ++{ ++ if (rb_lz77_get_bit(in, in_offset_bit)) { ++ *bits_used = 2; ++ if (rb_lz77_get_bit(in, ++in_offset_bit)) ++ return INSTR_LONG; ++ else ++ return INSTR_PREVIOUS_OFFSET; ++ } else { ++ *bits_used = 1; ++ return INSTR_LITERAL_BYTE; ++ } ++ return INSTR_ERROR; ++} ++ ++/** ++ * rb_lz77_decode_instruction_operators ++ * ++ * @in: compressed data ++ * @in_len: length of compressed data ++ * @in_offset_bit: bit offset where instruction starts ++ * @previous_offset: last used match offset ++ * @opcode: struct to hold instruction & operators ++ * ++ * Returns error code ++ */ ++static int rb_lz77_decode_instruction_operators( ++ const u8 *in, const size_t in_len, const size_t in_offset_bit, ++ const size_t previous_offset, struct rb_lz77_instr_opcodes *opcode) ++{ ++ enum rb_lz77_instruction instruction; ++ u8 bit_count = 0; ++ u8 bits_used = 0; ++ int offset = 0; ++ int length = 0; ++ ++ instruction = rb_lz77_decode_instruction(in, in_offset_bit, &bit_count); ++ ++ /* skip bits used by instruction */ ++ bits_used += bit_count; ++ ++ switch (instruction) { ++ case INSTR_LITERAL_BYTE: ++ /* non-matching char */ ++ offset = 0; ++ length = 1; ++ break; ++ ++ case INSTR_PREVIOUS_OFFSET: ++ /* matching group uses previous offset */ ++ offset = previous_offset; ++ ++ length = rb_lz77_decode_count(in, in_len, ++ in_offset_bit + bits_used, 0, 1, ++ &bit_count, ++ MIKRO_LZ77_MAX_COUNT_BIT_LEN); ++ if (unlikely(length < 0)) ++ return length; ++ /* skip bits used by count */ ++ bits_used += bit_count; ++ break; ++ ++ case INSTR_LONG: ++ offset = rb_lz77_decode_count(in, in_len, ++ in_offset_bit + bits_used, 4, 0, ++ &bit_count, ++ MIKRO_LZ77_MAX_COUNT_BIT_LEN); ++ if (unlikely(offset < 0)) ++ return offset; ++ ++ /* skip bits used by offset count */ ++ bits_used += bit_count; ++ ++ if (offset == 0) { ++ /* non-matching long group */ ++ length = rb_lz77_decode_count( ++ in, in_len, in_offset_bit + bits_used, 4, 12, ++ &bit_count, MIKRO_LZ77_MAX_COUNT_BIT_LEN); ++ if (unlikely(length < 0)) ++ return length; ++ /* skip bits used by length count */ ++ bits_used += bit_count; ++ } else { ++ /* matching group */ ++ length = rb_lz77_decode_count( ++ in, in_len, in_offset_bit + bits_used, 0, 2, ++ &bit_count, MIKRO_LZ77_MAX_COUNT_BIT_LEN); ++ if (unlikely(length < 0)) ++ return length; ++ /* skip bits used by length count */ ++ bits_used += bit_count; ++ } ++ ++ break; ++ ++ case INSTR_ERROR: ++ return -EINVAL; ++ } ++ ++ opcode->instruction = instruction; ++ opcode->offset = offset; ++ opcode->length = length; ++ opcode->bits_used = bits_used; ++ opcode->in = (u8 *)in; ++ opcode->in_pos = in_offset_bit; ++ return 0; ++} ++ ++/** ++ * rb_lz77_decompress ++ * ++ * @in: compressed data ptr ++ * @in_len: length of compressed data ++ * @out: buffer ptr to decompress into ++ * @out_len: length of decompressed buffer in input, ++ * length of decompressed data in success ++ * ++ * Returns 0 on success, or negative error ++ */ ++int rb_lz77_decompress(const u8 *in, const size_t in_len, u8 *out, ++ size_t *out_len) ++{ ++ u8 *output_ptr; ++ size_t input_bit = 0; ++ const u8 *output_end = out + *out_len; ++ struct rb_lz77_instr_opcodes *opcode; ++ size_t match_offset = 0; ++ int rc = 0; ++ size_t match_length, partial_count, i; ++ ++ output_ptr = out; ++ ++ if (unlikely((in_len * BITS_PER_BYTE) > SIZE_MAX)) { ++ pr_err(MIKRO_LZ77 "input longer than expected\n"); ++ return -EFBIG; ++ } ++ ++ opcode = kmalloc(sizeof(*opcode), GFP_KERNEL); ++ if (!opcode) ++ return -ENOMEM; ++ ++ while (true) { ++ if (unlikely(output_ptr > output_end)) { ++ pr_err(MIKRO_LZ77 "output overrun\n"); ++ rc = -EOVERFLOW; ++ goto free_lz77_struct; ++ } ++ if (unlikely(input_bit > in_len * BITS_PER_BYTE)) { ++ pr_err(MIKRO_LZ77 "input overrun\n"); ++ rc = -ENODATA; ++ goto free_lz77_struct; ++ } ++ ++ rc = rb_lz77_decode_instruction_operators(in, in_len, input_bit, ++ match_offset, opcode); ++ if (unlikely(rc < 0)) { ++ pr_err(MIKRO_LZ77 ++ "instruction operands decode error\n"); ++ goto free_lz77_struct; ++ } ++ ++ pr_debug(MIKRO_LZ77 "inbit:0x%zx->outbyte:0x%zx", input_bit, ++ output_ptr - out); ++ ++ input_bit += opcode->bits_used; ++ switch (opcode->instruction) { ++ case INSTR_LITERAL_BYTE: ++ pr_debug(" short"); ++ fallthrough; ++ case INSTR_LONG: ++ if (opcode->offset == 0) { ++ /* this is a non-matching group */ ++ pr_debug(" non-match, len: 0x%zx\n", ++ opcode->length); ++ /* test end marker */ ++ if (opcode->length == 0xc && ++ ((input_bit + ++ opcode->length * BITS_PER_BYTE) > ++ in_len)) { ++ *out_len = output_ptr - out; ++ pr_debug( ++ MIKRO_LZ77 ++ "lz77 decompressed from %zu to %zu\n", ++ in_len, *out_len); ++ rc = 0; ++ goto free_lz77_struct; ++ } ++ for (i = opcode->length; i > 0; --i) { ++ *output_ptr = ++ rb_lz77_get_byte(in, input_bit); ++ ++output_ptr; ++ input_bit += BITS_PER_BYTE; ++ } ++ /* do no fallthrough if a non-match group */ ++ break; ++ } ++ match_offset = opcode->offset; ++ fallthrough; ++ case INSTR_PREVIOUS_OFFSET: ++ match_length = opcode->length; ++ partial_count = 0; ++ ++ pr_debug(" match, offset: 0x%zx, len: 0x%zx", ++ opcode->offset, match_length); ++ ++ if (unlikely(opcode->offset == 0)) { ++ pr_err(MIKRO_LZ77 ++ "match group missing opcode->offset\n"); ++ rc = -EBADMSG; ++ goto free_lz77_struct; ++ } ++ ++ /* overflow */ ++ if (unlikely((output_ptr + match_length) > ++ output_end)) { ++ pr_err(MIKRO_LZ77 ++ "match group output overflow\n"); ++ rc = -ENOBUFS; ++ goto free_lz77_struct; ++ } ++ ++ /* underflow */ ++ if (unlikely((output_ptr - opcode->offset) < out)) { ++ pr_err(MIKRO_LZ77 ++ "match group offset underflow\n"); ++ rc = -ESPIPE; ++ goto free_lz77_struct; ++ } ++ ++ /* there are cases where the match (length) includes ++ * data that is a part of the same match ++ */ ++ while (opcode->offset < match_length) { ++ ++partial_count; ++ memcpy(output_ptr, output_ptr - opcode->offset, ++ opcode->offset); ++ output_ptr += opcode->offset; ++ match_length -= opcode->offset; ++ } ++ memcpy(output_ptr, output_ptr - opcode->offset, ++ match_length); ++ output_ptr += match_length; ++ if (partial_count) ++ pr_debug(" (%zu partial memcpy)", ++ partial_count); ++ pr_debug("\n"); ++ ++ break; ++ ++ case INSTR_ERROR: ++ rc = -EINVAL; ++ goto free_lz77_struct; ++ } ++ } ++ ++ pr_err(MIKRO_LZ77 "decode loop broken\n"); ++ rc = -EINVAL; ++ ++free_lz77_struct: ++ kfree(opcode); ++ return rc; ++} ++EXPORT_SYMBOL_GPL(rb_lz77_decompress); ++ ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("Mikrotik Wi-Fi caldata LZ77 decompressor"); ++MODULE_AUTHOR("John Thomson"); +diff --git a/drivers/platform/mikrotik/rb_lz77.h b/drivers/platform/mikrotik/rb_lz77.h +new file mode 100644 +index 000000000000..55179fcbc8e0 +--- /dev/null ++++ b/drivers/platform/mikrotik/rb_lz77.h +@@ -0,0 +1,35 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (C) 2024 John Thomson ++ */ ++ ++#ifndef __MIKROTIK_WLAN_LZ77_H__ ++#define __MIKROTIK_WLAN_LZ77_H__ ++ ++#include ++ ++#ifdef CONFIG_MIKROTIK_WLAN_DECOMPRESS_LZ77 ++/** ++ * rb_lz77_decompress ++ * ++ * @in: compressed data ptr ++ * @in_len: length of compressed data ++ * @out: buffer ptr to decompress into ++ * @out_len: length of decompressed buffer in input, ++ * length of decompressed data in success ++ * ++ * Returns 0 on success, or negative error ++ */ ++int rb_lz77_decompress(const u8 *in, const size_t in_len, u8 *out, ++ size_t *out_len); ++ ++#else /* CONFIG_MIKROTIK_WLAN_DECOMPRESS_LZ77 */ ++ ++static inline int rb_lz77_decompress(const u8 *in, const size_t in_len, u8 *out, ++ size_t *out_len) ++{ ++ return -EOPNOTSUPP; ++} ++ ++#endif /* CONFIG_MIKROTIK_WLAN_DECOMPRESS_LZ77 */ ++#endif /* __MIKROTIK_WLAN_LZ77_H__ */ +diff --git a/drivers/platform/mikrotik/rb_nvmem.c b/drivers/platform/mikrotik/rb_nvmem.c +new file mode 100644 +index 000000000000..6f785ce7d14d +--- /dev/null ++++ b/drivers/platform/mikrotik/rb_nvmem.c +@@ -0,0 +1,230 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * NVMEM layout driver for MikroTik Routerboard hard config cells ++ * ++ * Copyright (C) 2024 Robert Marko ++ * Based on the sysfs hard config driver by Thibaut VARÈNE ++ * Comments documenting the format carried over from routerboot.c ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "rb_hardconfig.h" ++#include "routerboot.h" ++ ++#define TLV_TAG_MASK GENMASK(15, 0) ++#define TLV_LEN_MASK GENMASK(31, 16) ++ ++static const char *rb_tlv_cell_name(u16 tag) ++{ ++ switch (tag) { ++ case RB_ID_FLASH_INFO: ++ return "flash-info"; ++ case RB_ID_MAC_ADDRESS_PACK: ++ return "base-mac-address"; ++ case RB_ID_BOARD_PRODUCT_CODE: ++ return "board-product-code"; ++ case RB_ID_BIOS_VERSION: ++ return "booter-version"; ++ case RB_ID_SERIAL_NUMBER: ++ return "board-serial"; ++ case RB_ID_MEMORY_SIZE: ++ return "mem-size"; ++ case RB_ID_MAC_ADDRESS_COUNT: ++ return "mac-count"; ++ case RB_ID_HW_OPTIONS: ++ return "hw-options"; ++ case RB_ID_WLAN_DATA: ++ return "wlan-data"; ++ case RB_ID_BOARD_IDENTIFIER: ++ return "board-identifier"; ++ case RB_ID_PRODUCT_NAME: ++ return "product-name"; ++ case RB_ID_DEFCONF: ++ return "defconf"; ++ case RB_ID_BOARD_REVISION: ++ return "board-revision"; ++ default: ++ break; ++ } ++ ++ return NULL; ++} ++ ++static int rb_tlv_mac_read_cb(void *priv, const char *id, int index, ++ unsigned int offset, void *buf, ++ size_t bytes) ++{ ++ if (index < 0) ++ return -EINVAL; ++ ++ if (!is_valid_ether_addr(buf)) ++ return -EINVAL; ++ ++ eth_addr_add(buf, index); ++ ++ return 0; ++} ++ ++static nvmem_cell_post_process_t rb_tlv_read_cb(u16 tag) ++{ ++ switch (tag) { ++ case RB_ID_MAC_ADDRESS_PACK: ++ return &rb_tlv_mac_read_cb; ++ default: ++ break; ++ } ++ ++ return NULL; ++} ++ ++static int rb_add_cells(struct device *dev, struct nvmem_device *nvmem, ++ const size_t data_len, u8 *data) ++{ ++ u32 node, offset = sizeof(RB_MAGIC_HARD); ++ struct nvmem_cell_info cell = {}; ++ struct device_node *layout; ++ u16 tlv_tag, tlv_len; ++ int ret; ++ ++ layout = of_nvmem_layout_get_container(nvmem); ++ if (!layout) ++ return -ENOENT; ++ ++ /* ++ * Routerboot tag nodes are u32 values: ++ * - The low nibble is the tag identification number, ++ * - The high nibble is the tag payload length (node excluded) in bytes. ++ * Tag nodes are CPU-endian. ++ * Tag nodes are 32bit-aligned. ++ * ++ * The payload immediately follows the tag node. ++ * Payload offset will always be aligned. while length may not end on 32bit ++ * boundary (the only known case is when parsing ERD data). ++ * The payload is CPU-endian when applicable. ++ * Tag nodes are not ordered (by ID) on flash. ++ */ ++ while ((offset + sizeof(node)) <= data_len) { ++ node = *((const u32 *) (data + offset)); ++ /* Tag list ends with null node */ ++ if (!node) ++ break; ++ ++ tlv_tag = FIELD_GET(TLV_TAG_MASK, node); ++ tlv_len = FIELD_GET(TLV_LEN_MASK, node); ++ ++ offset += sizeof(node); ++ if (offset + tlv_len > data_len) { ++ dev_err(dev, "Out of bounds field (0x%x bytes at 0x%x)\n", ++ tlv_len, offset); ++ break; ++ } ++ ++ cell.name = rb_tlv_cell_name(tlv_tag); ++ if (!cell.name) ++ goto skip; ++ ++ cell.offset = offset; ++ /* ++ * MikroTik stores MAC-s with length of 8 bytes, ++ * but kernel expects it to be ETH_ALEN (6 bytes), ++ * so we need to make sure that is the case. ++ */ ++ if (tlv_tag == RB_ID_MAC_ADDRESS_PACK) ++ cell.bytes = ETH_ALEN; ++ else ++ cell.bytes = tlv_len; ++ cell.np = of_get_child_by_name(layout, cell.name); ++ cell.read_post_process = rb_tlv_read_cb(tlv_tag); ++ ++ ret = nvmem_add_one_cell(nvmem, &cell); ++ if (ret) { ++ of_node_put(layout); ++ return ret; ++ } ++ ++ /* ++ * The only known situation where len may not end on 32bit ++ * boundary is within ERD data. Since we're only extracting ++ * one tag (the first and only one) from that data, we should ++ * never need to forcefully ALIGN(). Do it anyway, this is not a ++ * performance path. ++ */ ++skip: ++ offset += ALIGN(tlv_len, sizeof(offset)); ++ } ++ ++ of_node_put(layout); ++ ++ return 0; ++} ++ ++static int rb_parse_table(struct nvmem_layout *layout) ++{ ++ struct nvmem_device *nvmem = layout->nvmem; ++ struct device *dev = &layout->dev; ++ size_t mtd_size; ++ u8 *data; ++ u32 hdr; ++ int ret; ++ ++ ret = nvmem_device_read(nvmem, 0, sizeof(hdr), &hdr); ++ if (ret < 0) ++ return ret; ++ ++ if (hdr != RB_MAGIC_HARD) { ++ dev_err(dev, "Invalid header\n"); ++ return -EINVAL; ++ } ++ ++ mtd_size = nvmem_dev_size(nvmem); ++ ++ data = devm_kmalloc(dev, mtd_size, GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; ++ ++ ret = nvmem_device_read(nvmem, 0, mtd_size, data); ++ if (ret != mtd_size) ++ return ret; ++ ++ return rb_add_cells(dev, nvmem, mtd_size, data); ++} ++ ++static int rb_nvmem_probe(struct nvmem_layout *layout) ++{ ++ layout->add_cells = rb_parse_table; ++ ++ return nvmem_layout_register(layout); ++} ++ ++static void rb_nvmem_remove(struct nvmem_layout *layout) ++{ ++ nvmem_layout_unregister(layout); ++} ++ ++static const struct of_device_id rb_nvmem_of_match_table[] = { ++ { .compatible = "mikrotik,routerboot-nvmem", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, rb_nvmem_of_match_table); ++ ++static struct nvmem_layout_driver rb_nvmem_layout = { ++ .probe = rb_nvmem_probe, ++ .remove = rb_nvmem_remove, ++ .driver = { ++ .owner = THIS_MODULE, ++ .name = "rb_nvmem", ++ .of_match_table = rb_nvmem_of_match_table, ++ }, ++}; ++module_nvmem_layout_driver(rb_nvmem_layout); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Robert Marko "); ++MODULE_DESCRIPTION("NVMEM layout driver for MikroTik Routerboard hard config cells"); +diff --git a/drivers/platform/mikrotik/rb_softconfig.c b/drivers/platform/mikrotik/rb_softconfig.c +new file mode 100644 +index 000000000000..5acff6aa9184 +--- /dev/null ++++ b/drivers/platform/mikrotik/rb_softconfig.c +@@ -0,0 +1,795 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Driver for MikroTik RouterBoot soft config. ++ * ++ * Copyright (C) 2020 Thibaut VARÈNE ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation. ++ * ++ * This driver exposes the data encoded in the "soft_config" flash segment of ++ * MikroTik RouterBOARDs devices. It presents the data in a sysfs folder ++ * named "soft_config". The data is presented in a user/machine-friendly way ++ * with just as much parsing as can be generalized across mikrotik platforms ++ * (as inferred from reverse-engineering). ++ * ++ * The known soft_config tags are presented in the "soft_config" sysfs folder, ++ * with the addition of one specific file named "commit", which is only ++ * available if the driver supports writes to the mtd device: no modifications ++ * made to any of the other attributes are actually written back to flash media ++ * until a true value is input into this file (e.g. [Yy1]). This is to avoid ++ * unnecessary flash wear, and to permit to revert all changes by issuing a ++ * false value ([Nn0]). Reading the content of this file shows the current ++ * status of the driver: if the data in sysfs matches the content of the ++ * soft_config partition, the file will read "clean". Otherwise, it will read ++ * "dirty". ++ * ++ * The writeable sysfs files presented by this driver will accept only inputs ++ * which are in a valid range for the given tag. As a design choice, the driver ++ * will not assess whether the inputs are identical to the existing data. ++ * ++ * Note: PAGE_SIZE is assumed to be >= 4K, hence the device attribute show ++ * routines need not check for output overflow. ++ * ++ * Some constant defines extracted from rbcfg.h by Gabor Juhos ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef CONFIG_ATH79 ++ #include ++#endif ++ ++#include "routerboot.h" ++ ++#define RB_SOFTCONFIG_VER "0.05" ++#define RB_SC_PR_PFX "[rb_softconfig] " ++ ++#define RB_SC_HAS_WRITE_SUPPORT true ++#define RB_SC_WMODE S_IWUSR ++#define RB_SC_RMODE S_IRUSR ++ ++/* ID values for software settings */ ++#define RB_SCID_UART_SPEED 0x01 // u32*1 ++#define RB_SCID_BOOT_DELAY 0x02 // u32*1 ++#define RB_SCID_BOOT_DEVICE 0x03 // u32*1 ++#define RB_SCID_BOOT_KEY 0x04 // u32*1 ++#define RB_SCID_CPU_MODE 0x05 // u32*1 ++#define RB_SCID_BIOS_VERSION 0x06 // str ++#define RB_SCID_BOOT_PROTOCOL 0x09 // u32*1 ++#define RB_SCID_CPU_FREQ_IDX 0x0C // u32*1 ++#define RB_SCID_BOOTER 0x0D // u32*1 ++#define RB_SCID_SILENT_BOOT 0x0F // u32*1 ++/* ++ * protected_routerboot seems to use tag 0x1F. It only works in combination with ++ * RouterOS, resulting in a wiped board otherwise, so it's not implemented here. ++ * The tag values are as follows: ++ * - off: 0x0 ++ * - on: the lower halfword encodes the max value in s for the reset feature, ++ * the higher halfword encodes the min value in s for the reset feature. ++ * Default value when on: 0x00140258: 0x14 = 20s / 0x258= 600s ++ * See details here: https://wiki.mikrotik.com/wiki/Manual:RouterBOARD_settings#Protected_bootloader ++ */ ++ ++/* Tag values */ ++ ++#define RB_UART_SPEED_115200 0 ++#define RB_UART_SPEED_57600 1 ++#define RB_UART_SPEED_38400 2 ++#define RB_UART_SPEED_19200 3 ++#define RB_UART_SPEED_9600 4 ++#define RB_UART_SPEED_4800 5 ++#define RB_UART_SPEED_2400 6 ++#define RB_UART_SPEED_1200 7 ++#define RB_UART_SPEED_OFF 8 ++ ++/* valid boot delay: 1 - 9s in 1s increment */ ++#define RB_BOOT_DELAY_MIN 1 ++#define RB_BOOT_DELAY_MAX 9 ++ ++#define RB_BOOT_DEVICE_ETHER 0 // "boot over Ethernet" ++#define RB_BOOT_DEVICE_NANDETH 1 // "boot from NAND, if fail then Ethernet" ++#define RB_BOOT_DEVICE_CFCARD 2 // (not available in rbcfg) ++#define RB_BOOT_DEVICE_ETHONCE 3 // "boot Ethernet once, then NAND" ++#define RB_BOOT_DEVICE_NANDONLY 5 // "boot from NAND only" ++#define RB_BOOT_DEVICE_FLASHCFG 7 // "boot in flash configuration mode" ++#define RB_BOOT_DEVICE_FLSHONCE 8 // "boot in flash configuration mode once, then NAND" ++ ++/* ++ * ATH79 9xxx CPU frequency indices. ++ * It is unknown if they apply to all ATH79 RBs, and some do not seem to feature ++ * the upper levels (QCA955x), while F is presumably AR9344-only. ++ */ ++#define RB_CPU_FREQ_IDX_ATH79_9X_A (0 << 3) ++#define RB_CPU_FREQ_IDX_ATH79_9X_B (1 << 3) // 0x8 ++#define RB_CPU_FREQ_IDX_ATH79_9X_C (2 << 3) // 0x10 - factory freq for many devices ++#define RB_CPU_FREQ_IDX_ATH79_9X_D (3 << 3) // 0x18 ++#define RB_CPU_FREQ_IDX_ATH79_9X_E (4 << 3) // 0x20 ++#define RB_CPU_FREQ_IDX_ATH79_9X_F (5 << 3) // 0x28 ++ ++#define RB_CPU_FREQ_IDX_ATH79_9X_MIN 0 // all devices support lowest setting ++#define RB_CPU_FREQ_IDX_ATH79_9X_AR9334_MAX 5 // stops at F ++#define RB_CPU_FREQ_IDX_ATH79_9X_QCA953X_MAX 4 // stops at E ++#define RB_CPU_FREQ_IDX_ATH79_9X_QCA9556_MAX 2 // stops at C ++#define RB_CPU_FREQ_IDX_ATH79_9X_QCA9558_MAX 3 // stops at D ++ ++/* ATH79 7xxx CPU frequency indices. */ ++#define RB_CPU_FREQ_IDX_ATH79_7X_A ((0 * 9) << 4) ++#define RB_CPU_FREQ_IDX_ATH79_7X_B ((1 * 9) << 4) ++#define RB_CPU_FREQ_IDX_ATH79_7X_C ((2 * 9) << 4) ++#define RB_CPU_FREQ_IDX_ATH79_7X_D ((3 * 9) << 4) ++#define RB_CPU_FREQ_IDX_ATH79_7X_E ((4 * 9) << 4) ++#define RB_CPU_FREQ_IDX_ATH79_7X_F ((5 * 9) << 4) ++#define RB_CPU_FREQ_IDX_ATH79_7X_G ((6 * 9) << 4) ++#define RB_CPU_FREQ_IDX_ATH79_7X_H ((7 * 9) << 4) ++ ++#define RB_CPU_FREQ_IDX_ATH79_7X_MIN 0 // all devices support lowest setting ++#define RB_CPU_FREQ_IDX_ATH79_7X_AR724X_MAX 3 // stops at D ++#define RB_CPU_FREQ_IDX_ATH79_7X_AR7161_MAX 7 // stops at H - check if applies to all AR71xx devices ++ ++#define RB_SC_CRC32_OFFSET 4 // located right after magic ++ ++static struct kobject *sc_kobj; ++static u8 *sc_buf; ++static size_t sc_buflen; ++static rwlock_t sc_bufrwl; // rw lock to sc_buf ++ ++/* MUST be used with lock held */ ++#define RB_SC_CLRCRC() *(u32 *)(sc_buf + RB_SC_CRC32_OFFSET) = 0 ++#define RB_SC_GETCRC() *(u32 *)(sc_buf + RB_SC_CRC32_OFFSET) ++#define RB_SC_SETCRC(_crc) *(u32 *)(sc_buf + RB_SC_CRC32_OFFSET) = (_crc) ++ ++struct sc_u32tvs { ++ const u32 val; ++ const char *str; ++}; ++ ++#define RB_SC_TVS(_val, _str) { \ ++ .val = (_val), \ ++ .str = (_str), \ ++} ++ ++static ssize_t sc_tag_show_u32tvs(const u8 *pld, u16 pld_len, char *buf, ++ const struct sc_u32tvs tvs[], const int tvselmts) ++{ ++ const char *fmt; ++ char *out = buf; ++ u32 data; // cpu-endian ++ int i; ++ ++ // fallback to raw hex output if we can't handle the input ++ if (tvselmts < 0) ++ return routerboot_tag_show_u32s(pld, pld_len, buf); ++ ++ if (sizeof(data) != pld_len) ++ return -EINVAL; ++ ++ read_lock(&sc_bufrwl); ++ data = *(u32 *)pld; // pld aliases sc_buf ++ read_unlock(&sc_bufrwl); ++ ++ for (i = 0; i < tvselmts; i++) { ++ fmt = (tvs[i].val == data) ? "[%s] " : "%s "; ++ out += sprintf(out, fmt, tvs[i].str); ++ } ++ ++ out += sprintf(out, "\n"); ++ return out - buf; ++} ++ ++static ssize_t sc_tag_store_u32tvs(const u8 *pld, u16 pld_len, const char *buf, size_t count, ++ const struct sc_u32tvs tvs[], const int tvselmts) ++{ ++ int i; ++ ++ if (tvselmts < 0) ++ return tvselmts; ++ ++ if (sizeof(u32) != pld_len) ++ return -EINVAL; ++ ++ for (i = 0; i < tvselmts; i++) { ++ if (sysfs_streq(buf, tvs[i].str)) { ++ write_lock(&sc_bufrwl); ++ *(u32 *)pld = tvs[i].val; // pld aliases sc_buf ++ RB_SC_CLRCRC(); ++ write_unlock(&sc_bufrwl); ++ return count; ++ } ++ } ++ ++ return -EINVAL; ++} ++ ++struct sc_boolts { ++ const char *strfalse; ++ const char *strtrue; ++}; ++ ++static ssize_t sc_tag_show_boolts(const u8 *pld, u16 pld_len, char *buf, ++ const struct sc_boolts *bts) ++{ ++ const char *fmt; ++ char *out = buf; ++ u32 data; // cpu-endian ++ ++ if (sizeof(data) != pld_len) ++ return -EINVAL; ++ ++ read_lock(&sc_bufrwl); ++ data = *(u32 *)pld; // pld aliases sc_buf ++ read_unlock(&sc_bufrwl); ++ ++ fmt = (data) ? "%s [%s]\n" : "[%s] %s\n"; ++ out += sprintf(out, fmt, bts->strfalse, bts->strtrue); ++ ++ return out - buf; ++} ++ ++static ssize_t sc_tag_store_boolts(const u8 *pld, u16 pld_len, const char *buf, size_t count, ++ const struct sc_boolts *bts) ++{ ++ u32 data; // cpu-endian ++ ++ if (sizeof(data) != pld_len) ++ return -EINVAL; ++ ++ if (sysfs_streq(buf, bts->strfalse)) ++ data = 0; ++ else if (sysfs_streq(buf, bts->strtrue)) ++ data = 1; ++ else ++ return -EINVAL; ++ ++ write_lock(&sc_bufrwl); ++ *(u32 *)pld = data; // pld aliases sc_buf ++ RB_SC_CLRCRC(); ++ write_unlock(&sc_bufrwl); ++ ++ return count; ++} ++static struct sc_u32tvs const sc_uartspeeds[] = { ++ RB_SC_TVS(RB_UART_SPEED_OFF, "off"), ++ RB_SC_TVS(RB_UART_SPEED_1200, "1200"), ++ RB_SC_TVS(RB_UART_SPEED_2400, "2400"), ++ RB_SC_TVS(RB_UART_SPEED_4800, "4800"), ++ RB_SC_TVS(RB_UART_SPEED_9600, "9600"), ++ RB_SC_TVS(RB_UART_SPEED_19200, "19200"), ++ RB_SC_TVS(RB_UART_SPEED_38400, "38400"), ++ RB_SC_TVS(RB_UART_SPEED_57600, "57600"), ++ RB_SC_TVS(RB_UART_SPEED_115200, "115200"), ++}; ++ ++/* ++ * While the defines are carried over from rbcfg, use strings that more clearly ++ * show the actual setting purpose (especially since the NAND* settings apply ++ * to both nand- and nor-based devices). "cfcard" was disabled in rbcfg: disable ++ * it here too. ++ */ ++static struct sc_u32tvs const sc_bootdevices[] = { ++ RB_SC_TVS(RB_BOOT_DEVICE_ETHER, "eth"), ++ RB_SC_TVS(RB_BOOT_DEVICE_NANDETH, "flasheth"), ++ //RB_SC_TVS(RB_BOOT_DEVICE_CFCARD, "cfcard"), ++ RB_SC_TVS(RB_BOOT_DEVICE_ETHONCE, "ethonce"), ++ RB_SC_TVS(RB_BOOT_DEVICE_NANDONLY, "flash"), ++ RB_SC_TVS(RB_BOOT_DEVICE_FLASHCFG, "cfg"), ++ RB_SC_TVS(RB_BOOT_DEVICE_FLSHONCE, "cfgonce"), ++}; ++ ++static struct sc_boolts const sc_bootkey = { ++ .strfalse = "any", ++ .strtrue = "del", ++}; ++ ++static struct sc_boolts const sc_cpumode = { ++ .strfalse = "powersave", ++ .strtrue = "regular", ++}; ++ ++static struct sc_boolts const sc_bootproto = { ++ .strfalse = "bootp", ++ .strtrue = "dhcp", ++}; ++ ++static struct sc_boolts const sc_booter = { ++ .strfalse = "regular", ++ .strtrue = "backup", ++}; ++ ++static struct sc_boolts const sc_silent_boot = { ++ .strfalse = "off", ++ .strtrue = "on", ++}; ++ ++#define SC_TAG_SHOW_STORE_U32TVS_FUNCS(_name) \ ++static ssize_t sc_tag_show_##_name(const u8 *pld, u16 pld_len, char *buf) \ ++{ \ ++ return sc_tag_show_u32tvs(pld, pld_len, buf, sc_##_name, ARRAY_SIZE(sc_##_name)); \ ++} \ ++static ssize_t sc_tag_store_##_name(const u8 *pld, u16 pld_len, const char *buf, size_t count) \ ++{ \ ++ return sc_tag_store_u32tvs(pld, pld_len, buf, count, sc_##_name, ARRAY_SIZE(sc_##_name)); \ ++} ++ ++#define SC_TAG_SHOW_STORE_BOOLTS_FUNCS(_name) \ ++static ssize_t sc_tag_show_##_name(const u8 *pld, u16 pld_len, char *buf) \ ++{ \ ++ return sc_tag_show_boolts(pld, pld_len, buf, &sc_##_name); \ ++} \ ++static ssize_t sc_tag_store_##_name(const u8 *pld, u16 pld_len, const char *buf, size_t count) \ ++{ \ ++ return sc_tag_store_boolts(pld, pld_len, buf, count, &sc_##_name); \ ++} ++ ++SC_TAG_SHOW_STORE_U32TVS_FUNCS(uartspeeds) ++SC_TAG_SHOW_STORE_U32TVS_FUNCS(bootdevices) ++SC_TAG_SHOW_STORE_BOOLTS_FUNCS(bootkey) ++SC_TAG_SHOW_STORE_BOOLTS_FUNCS(cpumode) ++SC_TAG_SHOW_STORE_BOOLTS_FUNCS(bootproto) ++SC_TAG_SHOW_STORE_BOOLTS_FUNCS(booter) ++SC_TAG_SHOW_STORE_BOOLTS_FUNCS(silent_boot) ++ ++static ssize_t sc_tag_show_bootdelays(const u8 *pld, u16 pld_len, char *buf) ++{ ++ const char *fmt; ++ char *out = buf; ++ u32 data; // cpu-endian ++ int i; ++ ++ if (sizeof(data) != pld_len) ++ return -EINVAL; ++ ++ read_lock(&sc_bufrwl); ++ data = *(u32 *)pld; // pld aliases sc_buf ++ read_unlock(&sc_bufrwl); ++ ++ for (i = RB_BOOT_DELAY_MIN; i <= RB_BOOT_DELAY_MAX; i++) { ++ fmt = (i == data) ? "[%d] " : "%d "; ++ out += sprintf(out, fmt, i); ++ } ++ ++ out += sprintf(out, "\n"); ++ return out - buf; ++} ++ ++static ssize_t sc_tag_store_bootdelays(const u8 *pld, u16 pld_len, const char *buf, size_t count) ++{ ++ u32 data; // cpu-endian ++ int ret; ++ ++ if (sizeof(data) != pld_len) ++ return -EINVAL; ++ ++ ret = kstrtou32(buf, 10, &data); ++ if (ret) ++ return ret; ++ ++ if ((data < RB_BOOT_DELAY_MIN) || (RB_BOOT_DELAY_MAX < data)) ++ return -EINVAL; ++ ++ write_lock(&sc_bufrwl); ++ *(u32 *)pld = data; // pld aliases sc_buf ++ RB_SC_CLRCRC(); ++ write_unlock(&sc_bufrwl); ++ ++ return count; ++} ++ ++/* Support CPU frequency accessors only when the tag format has been asserted */ ++#if defined(CONFIG_ATH79) ++/* Use the same letter-based nomenclature as RouterBOOT */ ++static struct sc_u32tvs const sc_cpufreq_indexes_ath79_9x[] = { ++ RB_SC_TVS(RB_CPU_FREQ_IDX_ATH79_9X_A, "a"), ++ RB_SC_TVS(RB_CPU_FREQ_IDX_ATH79_9X_B, "b"), ++ RB_SC_TVS(RB_CPU_FREQ_IDX_ATH79_9X_C, "c"), ++ RB_SC_TVS(RB_CPU_FREQ_IDX_ATH79_9X_D, "d"), ++ RB_SC_TVS(RB_CPU_FREQ_IDX_ATH79_9X_E, "e"), ++ RB_SC_TVS(RB_CPU_FREQ_IDX_ATH79_9X_F, "f"), ++}; ++ ++static struct sc_u32tvs const sc_cpufreq_indexes_ath79_7x[] = { ++ RB_SC_TVS(RB_CPU_FREQ_IDX_ATH79_7X_A, "a"), ++ RB_SC_TVS(RB_CPU_FREQ_IDX_ATH79_7X_B, "b"), ++ RB_SC_TVS(RB_CPU_FREQ_IDX_ATH79_7X_C, "c"), ++ RB_SC_TVS(RB_CPU_FREQ_IDX_ATH79_7X_D, "d"), ++ RB_SC_TVS(RB_CPU_FREQ_IDX_ATH79_7X_E, "e"), ++ RB_SC_TVS(RB_CPU_FREQ_IDX_ATH79_7X_F, "f"), ++ RB_SC_TVS(RB_CPU_FREQ_IDX_ATH79_7X_G, "g"), ++ RB_SC_TVS(RB_CPU_FREQ_IDX_ATH79_7X_H, "h"), ++}; ++ ++static int sc_tag_cpufreq_ath79_arraysize(void) ++{ ++ int idx_max; ++ ++ if (ATH79_SOC_AR7161 == ath79_soc) ++ idx_max = RB_CPU_FREQ_IDX_ATH79_7X_AR7161_MAX+1; ++ else if (soc_is_ar724x()) ++ idx_max = RB_CPU_FREQ_IDX_ATH79_7X_AR724X_MAX+1; ++ else if (soc_is_ar9344()) ++ idx_max = RB_CPU_FREQ_IDX_ATH79_9X_AR9334_MAX+1; ++ else if (soc_is_qca953x()) ++ idx_max = RB_CPU_FREQ_IDX_ATH79_9X_QCA953X_MAX+1; ++ else if (soc_is_qca9556()) ++ idx_max = RB_CPU_FREQ_IDX_ATH79_9X_QCA9556_MAX+1; ++ else if (soc_is_qca9558()) ++ idx_max = RB_CPU_FREQ_IDX_ATH79_9X_QCA9558_MAX+1; ++ else ++ idx_max = -EOPNOTSUPP; ++ ++ return idx_max; ++} ++ ++static ssize_t sc_tag_show_cpufreq_indexes(const u8 *pld, u16 pld_len, char *buf) ++{ ++ const struct sc_u32tvs *tvs; ++ ++ if (soc_is_ar71xx() || soc_is_ar724x()) ++ tvs = sc_cpufreq_indexes_ath79_7x; ++ else ++ tvs = sc_cpufreq_indexes_ath79_9x; ++ ++ return sc_tag_show_u32tvs(pld, pld_len, buf, tvs, sc_tag_cpufreq_ath79_arraysize()); ++} ++ ++static ssize_t sc_tag_store_cpufreq_indexes(const u8 *pld, u16 pld_len, const char *buf, size_t count) ++{ ++ const struct sc_u32tvs *tvs; ++ ++ if (soc_is_ar71xx() || soc_is_ar724x()) ++ tvs = sc_cpufreq_indexes_ath79_7x; ++ else ++ tvs = sc_cpufreq_indexes_ath79_9x; ++ ++ return sc_tag_store_u32tvs(pld, pld_len, buf, count, tvs, sc_tag_cpufreq_ath79_arraysize()); ++} ++#else ++ /* By default we only show the raw value to help with reverse-engineering */ ++ #define sc_tag_show_cpufreq_indexes routerboot_tag_show_u32s ++ #define sc_tag_store_cpufreq_indexes NULL ++#endif ++ ++static ssize_t sc_attr_show(struct kobject *kobj, struct kobj_attribute *attr, ++ char *buf); ++static ssize_t sc_attr_store(struct kobject *kobj, struct kobj_attribute *attr, ++ const char *buf, size_t count); ++ ++/* Array of known tags to publish in sysfs */ ++static struct sc_attr { ++ const u16 tag_id; ++ /* sysfs tag show attribute. Must lock sc_buf when dereferencing pld */ ++ ssize_t (* const tshow)(const u8 *pld, u16 pld_len, char *buf); ++ /* sysfs tag store attribute. Must lock sc_buf when dereferencing pld */ ++ ssize_t (* const tstore)(const u8 *pld, u16 pld_len, const char *buf, size_t count); ++ struct kobj_attribute kattr; ++ u16 pld_ofs; ++ u16 pld_len; ++} sc_attrs[] = { ++ { ++ .tag_id = RB_SCID_UART_SPEED, ++ .tshow = sc_tag_show_uartspeeds, ++ .tstore = sc_tag_store_uartspeeds, ++ .kattr = __ATTR(uart_speed, RB_SC_RMODE|RB_SC_WMODE, sc_attr_show, sc_attr_store), ++ }, { ++ .tag_id = RB_SCID_BOOT_DELAY, ++ .tshow = sc_tag_show_bootdelays, ++ .tstore = sc_tag_store_bootdelays, ++ .kattr = __ATTR(boot_delay, RB_SC_RMODE|RB_SC_WMODE, sc_attr_show, sc_attr_store), ++ }, { ++ .tag_id = RB_SCID_BOOT_DEVICE, ++ .tshow = sc_tag_show_bootdevices, ++ .tstore = sc_tag_store_bootdevices, ++ .kattr = __ATTR(boot_device, RB_SC_RMODE|RB_SC_WMODE, sc_attr_show, sc_attr_store), ++ }, { ++ .tag_id = RB_SCID_BOOT_KEY, ++ .tshow = sc_tag_show_bootkey, ++ .tstore = sc_tag_store_bootkey, ++ .kattr = __ATTR(boot_key, RB_SC_RMODE|RB_SC_WMODE, sc_attr_show, sc_attr_store), ++ }, { ++ .tag_id = RB_SCID_CPU_MODE, ++ .tshow = sc_tag_show_cpumode, ++ .tstore = sc_tag_store_cpumode, ++ .kattr = __ATTR(cpu_mode, RB_SC_RMODE|RB_SC_WMODE, sc_attr_show, sc_attr_store), ++ }, { ++ .tag_id = RB_SCID_BIOS_VERSION, ++ .tshow = routerboot_tag_show_string, ++ .tstore = NULL, ++ .kattr = __ATTR(bios_version, RB_SC_RMODE, sc_attr_show, NULL), ++ }, { ++ .tag_id = RB_SCID_BOOT_PROTOCOL, ++ .tshow = sc_tag_show_bootproto, ++ .tstore = sc_tag_store_bootproto, ++ .kattr = __ATTR(boot_proto, RB_SC_RMODE|RB_SC_WMODE, sc_attr_show, sc_attr_store), ++ }, { ++ .tag_id = RB_SCID_CPU_FREQ_IDX, ++ .tshow = sc_tag_show_cpufreq_indexes, ++ .tstore = sc_tag_store_cpufreq_indexes, ++ .kattr = __ATTR(cpufreq_index, RB_SC_RMODE|RB_SC_WMODE, sc_attr_show, sc_attr_store), ++ }, { ++ .tag_id = RB_SCID_BOOTER, ++ .tshow = sc_tag_show_booter, ++ .tstore = sc_tag_store_booter, ++ .kattr = __ATTR(booter, RB_SC_RMODE|RB_SC_WMODE, sc_attr_show, sc_attr_store), ++ }, { ++ .tag_id = RB_SCID_SILENT_BOOT, ++ .tshow = sc_tag_show_silent_boot, ++ .tstore = sc_tag_store_silent_boot, ++ .kattr = __ATTR(silent_boot, RB_SC_RMODE|RB_SC_WMODE, sc_attr_show, sc_attr_store), ++ }, ++}; ++ ++static ssize_t sc_attr_show(struct kobject *kobj, struct kobj_attribute *attr, ++ char *buf) ++{ ++ const struct sc_attr *sc_attr; ++ const u8 *pld; ++ u16 pld_len; ++ ++ sc_attr = container_of(attr, typeof(*sc_attr), kattr); ++ ++ if (!sc_attr->pld_len) ++ return -ENOENT; ++ ++ pld = sc_buf + sc_attr->pld_ofs; // pld aliases sc_buf -> lock! ++ pld_len = sc_attr->pld_len; ++ ++ return sc_attr->tshow(pld, pld_len, buf); ++} ++ ++static ssize_t sc_attr_store(struct kobject *kobj, struct kobj_attribute *attr, ++ const char *buf, size_t count) ++{ ++ const struct sc_attr *sc_attr; ++ const u8 *pld; ++ u16 pld_len; ++ ++ if (!RB_SC_HAS_WRITE_SUPPORT) ++ return -EOPNOTSUPP; ++ ++ if (!capable(CAP_SYS_ADMIN)) ++ return -EACCES; ++ ++ sc_attr = container_of(attr, typeof(*sc_attr), kattr); ++ ++ if (!sc_attr->tstore) ++ return -EOPNOTSUPP; ++ ++ if (!sc_attr->pld_len) ++ return -ENOENT; ++ ++ pld = sc_buf + sc_attr->pld_ofs; // pld aliases sc_buf -> lock! ++ pld_len = sc_attr->pld_len; ++ ++ return sc_attr->tstore(pld, pld_len, buf, count); ++} ++ ++/* ++ * Shows the current buffer status: ++ * "clean": the buffer is in sync with the mtd data ++ * "dirty": the buffer is out of sync with the mtd data ++ */ ++static ssize_t sc_commit_show(struct kobject *kobj, struct kobj_attribute *attr, ++ char *buf) ++{ ++ const char *str; ++ char *out = buf; ++ u32 crc; ++ ++ read_lock(&sc_bufrwl); ++ crc = RB_SC_GETCRC(); ++ read_unlock(&sc_bufrwl); ++ ++ str = (crc) ? "clean" : "dirty"; ++ out += sprintf(out, "%s\n", str); ++ ++ return out - buf; ++} ++ ++/* ++ * Performs buffer flushing: ++ * This routine expects an input compatible with kstrtobool(). ++ * - a "false" input discards the current changes and reads data back from mtd. ++ * - a "true" input commits the current changes to mtd. ++ * If there is no pending changes, this routine is a no-op. ++ * Handling failures is left as an exercise to userspace. ++ */ ++static ssize_t sc_commit_store(struct kobject *kobj, struct kobj_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct mtd_info *mtd; ++ struct erase_info ei; ++ size_t bytes_rw, ret = count; ++ bool flush; ++ u32 crc; ++ ++ if (!RB_SC_HAS_WRITE_SUPPORT) ++ return -EOPNOTSUPP; ++ ++ read_lock(&sc_bufrwl); ++ crc = RB_SC_GETCRC(); ++ read_unlock(&sc_bufrwl); ++ ++ if (crc) ++ return count; // NO-OP ++ ++ ret = kstrtobool(buf, &flush); ++ if (ret) ++ return ret; ++ ++ mtd = get_mtd_device_nm(RB_MTD_SOFT_CONFIG); // TODO allow override ++ if (IS_ERR(mtd)) ++ return -ENODEV; ++ ++ write_lock(&sc_bufrwl); ++ if (!flush) // reread ++ ret = mtd_read(mtd, 0, mtd->size, &bytes_rw, sc_buf); ++ else { // crc32 + commit ++ /* ++ * CRC32 is computed on the entire buffer, excluding the CRC ++ * value itself. CRC is already null when we reach this point, ++ * so we can compute the CRC32 on the buffer as is. ++ * The expected CRC32 is Ethernet FCS style, meaning the seed is ++ * ~0 and the final result is also bitflipped. ++ */ ++ ++ crc = ~crc32(~0, sc_buf, sc_buflen); ++ RB_SC_SETCRC(crc); ++ ++ /* ++ * The soft_config partition is assumed to be entirely contained ++ * in a single eraseblock. ++ */ ++ ++ ei.addr = 0; ++ ei.len = mtd->size; ++ ret = mtd_erase(mtd, &ei); ++ if (!ret) ++ ret = mtd_write(mtd, 0, mtd->size, &bytes_rw, sc_buf); ++ ++ /* ++ * Handling mtd_write() failure here is a tricky situation. The ++ * proposed approach is to let userspace deal with retrying, ++ * with the caveat that it must try to flush the buffer again as ++ * rereading the mtd contents could potentially read garbage. ++ * The rationale is: even if we keep a shadow buffer of the ++ * original content, there is no guarantee that we will ever be ++ * able to write it anyway. ++ * Regardless, it appears that RouterBOOT will ignore an invalid ++ * soft_config (including a completely wiped segment) and will ++ * write back factory defaults when it happens. ++ */ ++ } ++ write_unlock(&sc_bufrwl); ++ ++ put_mtd_device(mtd); ++ ++ if (ret) ++ goto mtdfail; ++ ++ if (bytes_rw != sc_buflen) { ++ ret = -EIO; ++ goto mtdfail; ++ } ++ ++ return count; ++ ++mtdfail: ++ RB_SC_CLRCRC(); // mark buffer content as dirty/invalid ++ return ret; ++} ++ ++static struct kobj_attribute sc_kattrcommit = __ATTR(commit, RB_SC_RMODE|RB_SC_WMODE, sc_commit_show, sc_commit_store); ++ ++int rb_softconfig_init(struct kobject *rb_kobj, struct mtd_info *mtd) ++{ ++ size_t bytes_read, buflen; ++ const u8 *buf; ++ int i, ret; ++ u32 magic; ++ ++ sc_buf = NULL; ++ sc_kobj = NULL; ++ ++ ret = __get_mtd_device(mtd); ++ if (ret) ++ return -ENODEV; ++ ++ sc_buflen = mtd->size; ++ sc_buf = kmalloc(sc_buflen, GFP_KERNEL); ++ if (!sc_buf) { ++ __put_mtd_device(mtd); ++ return -ENOMEM; ++ } ++ ++ ret = mtd_read(mtd, 0, sc_buflen, &bytes_read, sc_buf); ++ __put_mtd_device(mtd); ++ ++ if (ret) ++ goto fail; ++ ++ if (bytes_read != sc_buflen) { ++ ret = -EIO; ++ goto fail; ++ } ++ ++ /* Check we have what we expect */ ++ magic = *(const u32 *)sc_buf; ++ if (RB_MAGIC_SOFT != magic) { ++ ret = -EINVAL; ++ goto fail; ++ } ++ ++ /* Skip magic and 32bit CRC located immediately after */ ++ buf = sc_buf + (sizeof(magic) + sizeof(u32)); ++ buflen = sc_buflen - (sizeof(magic) + sizeof(u32)); ++ ++ /* Populate sysfs */ ++ ret = -ENOMEM; ++ sc_kobj = kobject_create_and_add(RB_MTD_SOFT_CONFIG, rb_kobj); ++ if (!sc_kobj) ++ goto fail; ++ ++ rwlock_init(&sc_bufrwl); ++ ++ /* Locate and publish all known tags */ ++ for (i = 0; i < ARRAY_SIZE(sc_attrs); i++) { ++ ret = routerboot_tag_find(buf, buflen, sc_attrs[i].tag_id, ++ &sc_attrs[i].pld_ofs, &sc_attrs[i].pld_len); ++ if (ret) { ++ sc_attrs[i].pld_ofs = sc_attrs[i].pld_len = 0; ++ continue; ++ } ++ ++ /* Account for skipped magic and crc32 */ ++ sc_attrs[i].pld_ofs += sizeof(magic) + sizeof(u32); ++ ++ ret = sysfs_create_file(sc_kobj, &sc_attrs[i].kattr.attr); ++ if (ret) ++ pr_warn(RB_SC_PR_PFX "Could not create %s sysfs entry (%d)\n", ++ sc_attrs[i].kattr.attr.name, ret); ++ } ++ ++ /* Finally add the 'commit' attribute */ ++ if (RB_SC_HAS_WRITE_SUPPORT) { ++ ret = sysfs_create_file(sc_kobj, &sc_kattrcommit.attr); ++ if (ret) { ++ pr_err(RB_SC_PR_PFX "Could not create %s sysfs entry (%d), aborting!\n", ++ sc_kattrcommit.attr.name, ret); ++ goto sysfsfail; // required attribute ++ } ++ } ++ ++ pr_info("MikroTik RouterBOARD software configuration sysfs driver v" RB_SOFTCONFIG_VER "\n"); ++ ++ return 0; ++ ++sysfsfail: ++ kobject_put(sc_kobj); ++ sc_kobj = NULL; ++fail: ++ kfree(sc_buf); ++ sc_buf = NULL; ++ return ret; ++} ++ ++void rb_softconfig_exit(void) ++{ ++ kobject_put(sc_kobj); ++ sc_kobj = NULL; ++ kfree(sc_buf); ++ sc_buf = NULL; ++} +diff --git a/drivers/platform/mikrotik/routerboot.c b/drivers/platform/mikrotik/routerboot.c +new file mode 100644 +index 000000000000..96f24609161b +--- /dev/null ++++ b/drivers/platform/mikrotik/routerboot.c +@@ -0,0 +1,251 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Driver for MikroTik RouterBoot flash data. Common routines. ++ * ++ * Copyright (C) 2020 Thibaut VARÈNE ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "routerboot.h" ++ ++static struct kobject *rb_kobj; ++ ++/** ++ * routerboot_tag_find() - Locate a given tag in routerboot config data. ++ * @bufhead: the buffer to look into. Must start with a tag node. ++ * @buflen: size of bufhead ++ * @tag_id: the tag identifier to look for ++ * @pld_ofs: will be updated with tag payload offset in bufhead, if tag found ++ * @pld_len: will be updated with tag payload size, if tag found ++ * ++ * This incarnation of tag_find() does only that: it finds a specific routerboot ++ * tag node in the input buffer. Routerboot tag nodes are u32 values: ++ * - The low nibble is the tag identification number, ++ * - The high nibble is the tag payload length (node excluded) in bytes. ++ * The payload immediately follows the tag node. Tag nodes are 32bit-aligned. ++ * The returned pld_ofs will always be aligned. pld_len may not end on 32bit ++ * boundary (the only known case is when parsing ERD data). ++ * The nodes are cpu-endian on the flash media. The payload is cpu-endian when ++ * applicable. Tag nodes are not ordered (by ID) on flash. ++ * ++ * Return: 0 on success (tag found) or errno ++ */ ++int routerboot_tag_find(const u8 *bufhead, const size_t buflen, const u16 tag_id, ++ u16 *pld_ofs, u16 *pld_len) ++{ ++ const u32 *datum, *bufend; ++ u32 node; ++ u16 id, len; ++ int ret; ++ ++ if (!bufhead || !tag_id) ++ return -EINVAL; ++ ++ ret = -ENOENT; ++ datum = (const u32 *)bufhead; ++ bufend = (const u32 *)(bufhead + buflen); ++ ++ while (datum < bufend) { ++ node = *datum++; ++ ++ /* Tag list ends with null node */ ++ if (!node) ++ break; ++ ++ id = node & 0xFFFF; ++ len = node >> 16; ++ ++ if (tag_id == id) { ++ if (datum >= bufend) ++ break; ++ ++ if (pld_ofs) ++ *pld_ofs = (u16)((u8 *)datum - bufhead); ++ if (pld_len) ++ *pld_len = len; ++ ++ ret = 0; ++ break; ++ } ++ ++ /* ++ * The only known situation where len may not end on 32bit ++ * boundary is within ERD data. Since we're only extracting ++ * one tag (the first and only one) from that data, we should ++ * never need to forcefully ALIGN(). Do it anyway, this is not a ++ * performance path. ++ */ ++ len = ALIGN(len, sizeof(*datum)); ++ datum += len / sizeof(*datum); ++ } ++ ++ return ret; ++} ++ ++/** ++ * routerboot_rle_decode() - Simple RLE (MikroTik variant) decoding routine. ++ * @in: input buffer to decode ++ * @inlen: size of in ++ * @out: output buffer to write decoded data to ++ * @outlen: pointer to out size when function is called, will be updated with ++ * size of decoded output on return ++ * ++ * MikroTik's variant of RLE operates as follows, considering a signed run byte: ++ * - positive run => classic RLE ++ * - negative run => the next - bytes must be copied verbatim ++ * The API is matched to the lzo1x routines for convenience. ++ * ++ * NB: The output buffer cannot overlap with the input buffer. ++ * ++ * Return: 0 on success or errno ++ */ ++int routerboot_rle_decode(const u8 *in, size_t inlen, u8 *out, size_t *outlen) ++{ ++ int ret, run, nbytes; // use native types for speed ++ u8 byte; ++ ++ if (!in || (inlen < 2) || !out) ++ return -EINVAL; ++ ++ ret = -ENOSPC; ++ nbytes = 0; ++ while (inlen >= 2) { ++ run = *in++; ++ inlen--; ++ ++ /* Verbatim copies */ ++ if (run & 0x80) { ++ /* Invert run byte sign */ ++ run = ~run & 0xFF; ++ run++; ++ ++ if (run > inlen) ++ goto fail; ++ ++ inlen -= run; ++ ++ nbytes += run; ++ if (nbytes > *outlen) ++ goto fail; ++ ++ /* Basic memcpy */ ++ while (run-- > 0) ++ *out++ = *in++; ++ } ++ /* Stream of half-words RLE: . run == 0 is ignored */ ++ else { ++ byte = *in++; ++ inlen--; ++ ++ nbytes += run; ++ if (nbytes > *outlen) ++ goto fail; ++ ++ while (run-- > 0) ++ *out++ = byte; ++ } ++ } ++ ++ ret = 0; ++fail: ++ *outlen = nbytes; ++ return ret; ++} ++ ++static void routerboot_mtd_notifier_add(struct mtd_info *mtd) ++{ ++ /* Currently routerboot is only known to live on NOR flash */ ++ if (mtd->type != MTD_NORFLASH) ++ return; ++ ++ /* ++ * We ignore the following return values and always register. ++ * These init() routines are designed so that their failed state is ++ * always manageable by the corresponding exit() calls. ++ * Notifier is called with MTD mutex held: use __get/__put variants. ++ * TODO: allow partition names override ++ */ ++ if (!strcmp(mtd->name, RB_MTD_HARD_CONFIG)) ++ rb_hardconfig_init(rb_kobj, mtd); ++ else if (!strcmp(mtd->name, RB_MTD_SOFT_CONFIG)) ++ rb_softconfig_init(rb_kobj, mtd); ++} ++ ++static void routerboot_mtd_notifier_remove(struct mtd_info *mtd) ++{ ++ if (mtd->type != MTD_NORFLASH) ++ return; ++ ++ if (!strcmp(mtd->name, RB_MTD_HARD_CONFIG)) ++ rb_hardconfig_exit(); ++ else if (!strcmp(mtd->name, RB_MTD_SOFT_CONFIG)) ++ rb_softconfig_exit(); ++} ++ ++/* Note: using a notifier prevents qualifying init()/exit() functions with __init/__exit */ ++static struct mtd_notifier routerboot_mtd_notifier = { ++ .add = routerboot_mtd_notifier_add, ++ .remove = routerboot_mtd_notifier_remove, ++}; ++ ++static int __init routerboot_init(void) ++{ ++ rb_kobj = kobject_create_and_add("mikrotik", firmware_kobj); ++ if (!rb_kobj) ++ return -ENOMEM; ++ ++ register_mtd_user(&routerboot_mtd_notifier); ++ ++ return 0; ++} ++ ++static void __exit routerboot_exit(void) ++{ ++ unregister_mtd_user(&routerboot_mtd_notifier); ++ /* Exit routines are idempotent */ ++ rb_softconfig_exit(); ++ rb_hardconfig_exit(); ++ kobject_put(rb_kobj); // recursive afaict ++} ++ ++/* Common routines */ ++ ++ssize_t routerboot_tag_show_string(const u8 *pld, u16 pld_len, char *buf) ++{ ++ return scnprintf(buf, pld_len+1, "%s\n", pld); ++} ++ ++ssize_t routerboot_tag_show_u32s(const u8 *pld, u16 pld_len, char *buf) ++{ ++ char *out = buf; ++ u32 *data; // cpu-endian ++ ++ /* Caller ensures pld_len > 0 */ ++ if (pld_len % sizeof(*data)) ++ return -EINVAL; ++ ++ data = (u32 *)pld; ++ ++ do { ++ out += sprintf(out, "0x%08x\n", *data); ++ data++; ++ } while ((pld_len -= sizeof(*data))); ++ ++ return out - buf; ++} ++ ++module_init(routerboot_init); ++module_exit(routerboot_exit); ++ ++MODULE_LICENSE("GPL v2"); ++MODULE_DESCRIPTION("MikroTik RouterBoot sysfs support"); ++MODULE_AUTHOR("Thibaut VARENE"); +diff --git a/drivers/platform/mikrotik/routerboot.h b/drivers/platform/mikrotik/routerboot.h +new file mode 100644 +index 000000000000..723f993eebe2 +--- /dev/null ++++ b/drivers/platform/mikrotik/routerboot.h +@@ -0,0 +1,38 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Common definitions for MikroTik RouterBoot data. ++ * ++ * Copyright (C) 2020 Thibaut VARÈNE ++ */ ++ ++ ++#ifndef _ROUTERBOOT_H_ ++#define _ROUTERBOOT_H_ ++ ++#include ++ ++// these magic values are stored in cpu-endianness on flash ++#define RB_MAGIC_HARD (('H') | ('a' << 8) | ('r' << 16) | ('d' << 24)) ++#define RB_MAGIC_SOFT (('S') | ('o' << 8) | ('f' << 16) | ('t' << 24)) ++#define RB_MAGIC_LZOR (('L') | ('Z' << 8) | ('O' << 16) | ('R' << 24)) ++#define RB_MAGIC_LZ77 (('L' << 24) | ('Z' << 16) | ('7' << 8) | ('7')) ++#define RB_MAGIC_ERD (('E' << 16) | ('R' << 8) | ('D')) ++ ++#define RB_ART_SIZE 0x10000 ++ ++#define RB_MTD_HARD_CONFIG "hard_config" ++#define RB_MTD_SOFT_CONFIG "soft_config" ++ ++int routerboot_tag_find(const u8 *bufhead, const size_t buflen, const u16 tag_id, u16 *pld_ofs, u16 *pld_len); ++int routerboot_rle_decode(const u8 *in, size_t inlen, u8 *out, size_t *outlen); ++ ++int rb_hardconfig_init(struct kobject *rb_kobj, struct mtd_info *mtd); ++void rb_hardconfig_exit(void); ++ ++int rb_softconfig_init(struct kobject *rb_kobj, struct mtd_info *mtd); ++void rb_softconfig_exit(void); ++ ++ssize_t routerboot_tag_show_string(const u8 *pld, u16 pld_len, char *buf); ++ssize_t routerboot_tag_show_u32s(const u8 *pld, u16 pld_len, char *buf); ++ ++#endif /* _ROUTERBOOT_H_ */ +diff --git a/drivers/ssb/fallback-sprom.c b/drivers/ssb/fallback-sprom.c +new file mode 100644 +index 000000000000..9c2511febe18 +--- /dev/null ++++ b/drivers/ssb/fallback-sprom.c +@@ -0,0 +1,745 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * SSB Fallback SPROM Driver ++ * ++ * Copyright (C) 2020 Ãlvaro Fernández Rojas ++ * Copyright (C) 2014 Jonas Gorski ++ * Copyright (C) 2008 Maxime Bizon ++ * Copyright (C) 2008 Florian Fainelli ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "fallback-sprom.h" ++ ++#define SSB_FBS_MAX_SIZE 440 ++ ++/* Get the word-offset for a SSB_SPROM_XXX define. */ ++#define SPOFF(offset) ((offset) / sizeof(u16)) ++/* Helper to extract some _offset, which is one of the SSB_SPROM_XXX defines. */ ++#define SPEX16(_outvar, _offset, _mask, _shift) \ ++ out->_outvar = ((in[SPOFF(_offset)] & (_mask)) >> (_shift)) ++#define SPEX32(_outvar, _offset, _mask, _shift) \ ++ out->_outvar = ((((u32)in[SPOFF((_offset)+2)] << 16 | \ ++ in[SPOFF(_offset)]) & (_mask)) >> (_shift)) ++#define SPEX(_outvar, _offset, _mask, _shift) \ ++ SPEX16(_outvar, _offset, _mask, _shift) ++ ++#define SPEX_ARRAY8(_field, _offset, _mask, _shift) \ ++ do { \ ++ SPEX(_field[0], _offset + 0, _mask, _shift); \ ++ SPEX(_field[1], _offset + 2, _mask, _shift); \ ++ SPEX(_field[2], _offset + 4, _mask, _shift); \ ++ SPEX(_field[3], _offset + 6, _mask, _shift); \ ++ SPEX(_field[4], _offset + 8, _mask, _shift); \ ++ SPEX(_field[5], _offset + 10, _mask, _shift); \ ++ SPEX(_field[6], _offset + 12, _mask, _shift); \ ++ SPEX(_field[7], _offset + 14, _mask, _shift); \ ++ } while (0) ++ ++struct ssb_fbs { ++ struct device *dev; ++ struct list_head list; ++ struct ssb_sprom sprom; ++ u32 pci_bus; ++ u32 pci_dev; ++ bool devid_override; ++}; ++ ++static DEFINE_SPINLOCK(ssb_fbs_lock); ++static struct list_head ssb_fbs_list = LIST_HEAD_INIT(ssb_fbs_list); ++ ++int ssb_get_fallback_sprom(struct ssb_bus *bus, struct ssb_sprom *out) ++{ ++ struct ssb_fbs *pos; ++ u32 pci_bus, pci_dev; ++ ++ if (bus->bustype != SSB_BUSTYPE_PCI) ++ return -ENOENT; ++ ++ pci_bus = bus->host_pci->bus->number; ++ pci_dev = PCI_SLOT(bus->host_pci->devfn); ++ ++ list_for_each_entry(pos, &ssb_fbs_list, list) { ++ if (pos->pci_bus != pci_bus || ++ pos->pci_dev != pci_dev) ++ continue; ++ ++ if (pos->devid_override) ++ bus->host_pci->device = pos->sprom.dev_id; ++ ++ memcpy(out, &pos->sprom, sizeof(struct ssb_sprom)); ++ dev_info(pos->dev, "requested by [%x:%x]", ++ pos->pci_bus, pos->pci_dev); ++ ++ return 0; ++ } ++ ++ pr_err("unable to fill SPROM for [%x:%x]\n", pci_bus, pci_dev); ++ ++ return -EINVAL; ++} ++ ++static s8 sprom_extract_antgain(u8 sprom_revision, const u16 *in, u16 offset, ++ u16 mask, u16 shift) ++{ ++ u16 v; ++ u8 gain; ++ ++ v = in[SPOFF(offset)]; ++ gain = (v & mask) >> shift; ++ if (gain == 0xFF) ++ gain = 2; /* If unset use 2dBm */ ++ if (sprom_revision == 1) { ++ /* Convert to Q5.2 */ ++ gain <<= 2; ++ } else { ++ /* Q5.2 Fractional part is stored in 0xC0 */ ++ gain = ((gain & 0xC0) >> 6) | ((gain & 0x3F) << 2); ++ } ++ ++ return (s8)gain; ++} ++ ++static void sprom_extract_r23(struct ssb_sprom *out, const u16 *in) ++{ ++ SPEX(boardflags_hi, SSB_SPROM2_BFLHI, 0xFFFF, 0); ++ SPEX(opo, SSB_SPROM2_OPO, SSB_SPROM2_OPO_VALUE, 0); ++ SPEX(pa1lob0, SSB_SPROM2_PA1LOB0, 0xFFFF, 0); ++ SPEX(pa1lob1, SSB_SPROM2_PA1LOB1, 0xFFFF, 0); ++ SPEX(pa1lob2, SSB_SPROM2_PA1LOB2, 0xFFFF, 0); ++ SPEX(pa1hib0, SSB_SPROM2_PA1HIB0, 0xFFFF, 0); ++ SPEX(pa1hib1, SSB_SPROM2_PA1HIB1, 0xFFFF, 0); ++ SPEX(pa1hib2, SSB_SPROM2_PA1HIB2, 0xFFFF, 0); ++ SPEX(maxpwr_ah, SSB_SPROM2_MAXP_A, SSB_SPROM2_MAXP_A_HI, 0); ++ SPEX(maxpwr_al, SSB_SPROM2_MAXP_A, SSB_SPROM2_MAXP_A_LO, ++ SSB_SPROM2_MAXP_A_LO_SHIFT); ++} ++ ++static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in) ++{ ++ SPEX(et0phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0A, 0); ++ SPEX(et1phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1A, ++ SSB_SPROM1_ETHPHY_ET1A_SHIFT); ++ SPEX(et0mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0M, 14); ++ SPEX(et1mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1M, 15); ++ SPEX(board_rev, SSB_SPROM1_BINF, SSB_SPROM1_BINF_BREV, 0); ++ SPEX(board_type, SSB_SPROM1_SPID, 0xFFFF, 0); ++ if (out->revision == 1) ++ SPEX(country_code, SSB_SPROM1_BINF, SSB_SPROM1_BINF_CCODE, ++ SSB_SPROM1_BINF_CCODE_SHIFT); ++ SPEX(ant_available_a, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTA, ++ SSB_SPROM1_BINF_ANTA_SHIFT); ++ SPEX(ant_available_bg, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTBG, ++ SSB_SPROM1_BINF_ANTBG_SHIFT); ++ SPEX(pa0b0, SSB_SPROM1_PA0B0, 0xFFFF, 0); ++ SPEX(pa0b1, SSB_SPROM1_PA0B1, 0xFFFF, 0); ++ SPEX(pa0b2, SSB_SPROM1_PA0B2, 0xFFFF, 0); ++ SPEX(pa1b0, SSB_SPROM1_PA1B0, 0xFFFF, 0); ++ SPEX(pa1b1, SSB_SPROM1_PA1B1, 0xFFFF, 0); ++ SPEX(pa1b2, SSB_SPROM1_PA1B2, 0xFFFF, 0); ++ SPEX(gpio0, SSB_SPROM1_GPIOA, SSB_SPROM1_GPIOA_P0, 0); ++ SPEX(gpio1, SSB_SPROM1_GPIOA, SSB_SPROM1_GPIOA_P1, ++ SSB_SPROM1_GPIOA_P1_SHIFT); ++ SPEX(gpio2, SSB_SPROM1_GPIOB, SSB_SPROM1_GPIOB_P2, 0); ++ SPEX(gpio3, SSB_SPROM1_GPIOB, SSB_SPROM1_GPIOB_P3, ++ SSB_SPROM1_GPIOB_P3_SHIFT); ++ SPEX(maxpwr_a, SSB_SPROM1_MAXPWR, SSB_SPROM1_MAXPWR_A, ++ SSB_SPROM1_MAXPWR_A_SHIFT); ++ SPEX(maxpwr_bg, SSB_SPROM1_MAXPWR, SSB_SPROM1_MAXPWR_BG, 0); ++ SPEX(itssi_a, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_A, ++ SSB_SPROM1_ITSSI_A_SHIFT); ++ SPEX(itssi_bg, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_BG, 0); ++ SPEX(boardflags_lo, SSB_SPROM1_BFLLO, 0xFFFF, 0); ++ ++ SPEX(alpha2[0], SSB_SPROM1_CCODE, 0xff00, 8); ++ SPEX(alpha2[1], SSB_SPROM1_CCODE, 0x00ff, 0); ++ ++ /* Extract the antenna gain values. */ ++ out->antenna_gain.a0 = sprom_extract_antgain(out->revision, in, ++ SSB_SPROM1_AGAIN, ++ SSB_SPROM1_AGAIN_BG, ++ SSB_SPROM1_AGAIN_BG_SHIFT); ++ out->antenna_gain.a1 = sprom_extract_antgain(out->revision, in, ++ SSB_SPROM1_AGAIN, ++ SSB_SPROM1_AGAIN_A, ++ SSB_SPROM1_AGAIN_A_SHIFT); ++ if (out->revision >= 2) ++ sprom_extract_r23(out, in); ++} ++ ++/* Revs 4 5 and 8 have partially shared layout */ ++static void sprom_extract_r458(struct ssb_sprom *out, const u16 *in) ++{ ++ SPEX(txpid2g[0], SSB_SPROM4_TXPID2G01, ++ SSB_SPROM4_TXPID2G0, SSB_SPROM4_TXPID2G0_SHIFT); ++ SPEX(txpid2g[1], SSB_SPROM4_TXPID2G01, ++ SSB_SPROM4_TXPID2G1, SSB_SPROM4_TXPID2G1_SHIFT); ++ SPEX(txpid2g[2], SSB_SPROM4_TXPID2G23, ++ SSB_SPROM4_TXPID2G2, SSB_SPROM4_TXPID2G2_SHIFT); ++ SPEX(txpid2g[3], SSB_SPROM4_TXPID2G23, ++ SSB_SPROM4_TXPID2G3, SSB_SPROM4_TXPID2G3_SHIFT); ++ ++ SPEX(txpid5gl[0], SSB_SPROM4_TXPID5GL01, ++ SSB_SPROM4_TXPID5GL0, SSB_SPROM4_TXPID5GL0_SHIFT); ++ SPEX(txpid5gl[1], SSB_SPROM4_TXPID5GL01, ++ SSB_SPROM4_TXPID5GL1, SSB_SPROM4_TXPID5GL1_SHIFT); ++ SPEX(txpid5gl[2], SSB_SPROM4_TXPID5GL23, ++ SSB_SPROM4_TXPID5GL2, SSB_SPROM4_TXPID5GL2_SHIFT); ++ SPEX(txpid5gl[3], SSB_SPROM4_TXPID5GL23, ++ SSB_SPROM4_TXPID5GL3, SSB_SPROM4_TXPID5GL3_SHIFT); ++ ++ SPEX(txpid5g[0], SSB_SPROM4_TXPID5G01, ++ SSB_SPROM4_TXPID5G0, SSB_SPROM4_TXPID5G0_SHIFT); ++ SPEX(txpid5g[1], SSB_SPROM4_TXPID5G01, ++ SSB_SPROM4_TXPID5G1, SSB_SPROM4_TXPID5G1_SHIFT); ++ SPEX(txpid5g[2], SSB_SPROM4_TXPID5G23, ++ SSB_SPROM4_TXPID5G2, SSB_SPROM4_TXPID5G2_SHIFT); ++ SPEX(txpid5g[3], SSB_SPROM4_TXPID5G23, ++ SSB_SPROM4_TXPID5G3, SSB_SPROM4_TXPID5G3_SHIFT); ++ ++ SPEX(txpid5gh[0], SSB_SPROM4_TXPID5GH01, ++ SSB_SPROM4_TXPID5GH0, SSB_SPROM4_TXPID5GH0_SHIFT); ++ SPEX(txpid5gh[1], SSB_SPROM4_TXPID5GH01, ++ SSB_SPROM4_TXPID5GH1, SSB_SPROM4_TXPID5GH1_SHIFT); ++ SPEX(txpid5gh[2], SSB_SPROM4_TXPID5GH23, ++ SSB_SPROM4_TXPID5GH2, SSB_SPROM4_TXPID5GH2_SHIFT); ++ SPEX(txpid5gh[3], SSB_SPROM4_TXPID5GH23, ++ SSB_SPROM4_TXPID5GH3, SSB_SPROM4_TXPID5GH3_SHIFT); ++} ++ ++static void sprom_extract_r45(struct ssb_sprom *out, const u16 *in) ++{ ++ static const u16 pwr_info_offset[] = { ++ SSB_SPROM4_PWR_INFO_CORE0, SSB_SPROM4_PWR_INFO_CORE1, ++ SSB_SPROM4_PWR_INFO_CORE2, SSB_SPROM4_PWR_INFO_CORE3 ++ }; ++ int i; ++ ++ BUILD_BUG_ON(ARRAY_SIZE(pwr_info_offset) != ++ ARRAY_SIZE(out->core_pwr_info)); ++ ++ SPEX(et0phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET0A, 0); ++ SPEX(et1phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET1A, ++ SSB_SPROM4_ETHPHY_ET1A_SHIFT); ++ SPEX(board_rev, SSB_SPROM4_BOARDREV, 0xFFFF, 0); ++ SPEX(board_type, SSB_SPROM1_SPID, 0xFFFF, 0); ++ if (out->revision == 4) { ++ SPEX(alpha2[0], SSB_SPROM4_CCODE, 0xff00, 8); ++ SPEX(alpha2[1], SSB_SPROM4_CCODE, 0x00ff, 0); ++ SPEX(boardflags_lo, SSB_SPROM4_BFLLO, 0xFFFF, 0); ++ SPEX(boardflags_hi, SSB_SPROM4_BFLHI, 0xFFFF, 0); ++ SPEX(boardflags2_lo, SSB_SPROM4_BFL2LO, 0xFFFF, 0); ++ SPEX(boardflags2_hi, SSB_SPROM4_BFL2HI, 0xFFFF, 0); ++ } else { ++ SPEX(alpha2[0], SSB_SPROM5_CCODE, 0xff00, 8); ++ SPEX(alpha2[1], SSB_SPROM5_CCODE, 0x00ff, 0); ++ SPEX(boardflags_lo, SSB_SPROM5_BFLLO, 0xFFFF, 0); ++ SPEX(boardflags_hi, SSB_SPROM5_BFLHI, 0xFFFF, 0); ++ SPEX(boardflags2_lo, SSB_SPROM5_BFL2LO, 0xFFFF, 0); ++ SPEX(boardflags2_hi, SSB_SPROM5_BFL2HI, 0xFFFF, 0); ++ } ++ SPEX(ant_available_a, SSB_SPROM4_ANTAVAIL, SSB_SPROM4_ANTAVAIL_A, ++ SSB_SPROM4_ANTAVAIL_A_SHIFT); ++ SPEX(ant_available_bg, SSB_SPROM4_ANTAVAIL, SSB_SPROM4_ANTAVAIL_BG, ++ SSB_SPROM4_ANTAVAIL_BG_SHIFT); ++ SPEX(maxpwr_bg, SSB_SPROM4_MAXP_BG, SSB_SPROM4_MAXP_BG_MASK, 0); ++ SPEX(itssi_bg, SSB_SPROM4_MAXP_BG, SSB_SPROM4_ITSSI_BG, ++ SSB_SPROM4_ITSSI_BG_SHIFT); ++ SPEX(maxpwr_a, SSB_SPROM4_MAXP_A, SSB_SPROM4_MAXP_A_MASK, 0); ++ SPEX(itssi_a, SSB_SPROM4_MAXP_A, SSB_SPROM4_ITSSI_A, ++ SSB_SPROM4_ITSSI_A_SHIFT); ++ if (out->revision == 4) { ++ SPEX(gpio0, SSB_SPROM4_GPIOA, SSB_SPROM4_GPIOA_P0, 0); ++ SPEX(gpio1, SSB_SPROM4_GPIOA, SSB_SPROM4_GPIOA_P1, ++ SSB_SPROM4_GPIOA_P1_SHIFT); ++ SPEX(gpio2, SSB_SPROM4_GPIOB, SSB_SPROM4_GPIOB_P2, 0); ++ SPEX(gpio3, SSB_SPROM4_GPIOB, SSB_SPROM4_GPIOB_P3, ++ SSB_SPROM4_GPIOB_P3_SHIFT); ++ } else { ++ SPEX(gpio0, SSB_SPROM5_GPIOA, SSB_SPROM5_GPIOA_P0, 0); ++ SPEX(gpio1, SSB_SPROM5_GPIOA, SSB_SPROM5_GPIOA_P1, ++ SSB_SPROM5_GPIOA_P1_SHIFT); ++ SPEX(gpio2, SSB_SPROM5_GPIOB, SSB_SPROM5_GPIOB_P2, 0); ++ SPEX(gpio3, SSB_SPROM5_GPIOB, SSB_SPROM5_GPIOB_P3, ++ SSB_SPROM5_GPIOB_P3_SHIFT); ++ } ++ ++ /* Extract the antenna gain values. */ ++ out->antenna_gain.a0 = sprom_extract_antgain(out->revision, in, ++ SSB_SPROM4_AGAIN01, ++ SSB_SPROM4_AGAIN0, ++ SSB_SPROM4_AGAIN0_SHIFT); ++ out->antenna_gain.a1 = sprom_extract_antgain(out->revision, in, ++ SSB_SPROM4_AGAIN01, ++ SSB_SPROM4_AGAIN1, ++ SSB_SPROM4_AGAIN1_SHIFT); ++ out->antenna_gain.a2 = sprom_extract_antgain(out->revision, in, ++ SSB_SPROM4_AGAIN23, ++ SSB_SPROM4_AGAIN2, ++ SSB_SPROM4_AGAIN2_SHIFT); ++ out->antenna_gain.a3 = sprom_extract_antgain(out->revision, in, ++ SSB_SPROM4_AGAIN23, ++ SSB_SPROM4_AGAIN3, ++ SSB_SPROM4_AGAIN3_SHIFT); ++ ++ /* Extract cores power info info */ ++ for (i = 0; i < ARRAY_SIZE(pwr_info_offset); i++) { ++ u16 o = pwr_info_offset[i]; ++ ++ SPEX(core_pwr_info[i].itssi_2g, o + SSB_SPROM4_2G_MAXP_ITSSI, ++ SSB_SPROM4_2G_ITSSI, SSB_SPROM4_2G_ITSSI_SHIFT); ++ SPEX(core_pwr_info[i].maxpwr_2g, o + SSB_SPROM4_2G_MAXP_ITSSI, ++ SSB_SPROM4_2G_MAXP, 0); ++ ++ SPEX(core_pwr_info[i].pa_2g[0], o + SSB_SPROM4_2G_PA_0, ~0, 0); ++ SPEX(core_pwr_info[i].pa_2g[1], o + SSB_SPROM4_2G_PA_1, ~0, 0); ++ SPEX(core_pwr_info[i].pa_2g[2], o + SSB_SPROM4_2G_PA_2, ~0, 0); ++ SPEX(core_pwr_info[i].pa_2g[3], o + SSB_SPROM4_2G_PA_3, ~0, 0); ++ ++ SPEX(core_pwr_info[i].itssi_5g, o + SSB_SPROM4_5G_MAXP_ITSSI, ++ SSB_SPROM4_5G_ITSSI, SSB_SPROM4_5G_ITSSI_SHIFT); ++ SPEX(core_pwr_info[i].maxpwr_5g, o + SSB_SPROM4_5G_MAXP_ITSSI, ++ SSB_SPROM4_5G_MAXP, 0); ++ SPEX(core_pwr_info[i].maxpwr_5gh, o + SSB_SPROM4_5GHL_MAXP, ++ SSB_SPROM4_5GH_MAXP, 0); ++ SPEX(core_pwr_info[i].maxpwr_5gl, o + SSB_SPROM4_5GHL_MAXP, ++ SSB_SPROM4_5GL_MAXP, SSB_SPROM4_5GL_MAXP_SHIFT); ++ ++ SPEX(core_pwr_info[i].pa_5gl[0], o + SSB_SPROM4_5GL_PA_0, ~0, 0); ++ SPEX(core_pwr_info[i].pa_5gl[1], o + SSB_SPROM4_5GL_PA_1, ~0, 0); ++ SPEX(core_pwr_info[i].pa_5gl[2], o + SSB_SPROM4_5GL_PA_2, ~0, 0); ++ SPEX(core_pwr_info[i].pa_5gl[3], o + SSB_SPROM4_5GL_PA_3, ~0, 0); ++ SPEX(core_pwr_info[i].pa_5g[0], o + SSB_SPROM4_5G_PA_0, ~0, 0); ++ SPEX(core_pwr_info[i].pa_5g[1], o + SSB_SPROM4_5G_PA_1, ~0, 0); ++ SPEX(core_pwr_info[i].pa_5g[2], o + SSB_SPROM4_5G_PA_2, ~0, 0); ++ SPEX(core_pwr_info[i].pa_5g[3], o + SSB_SPROM4_5G_PA_3, ~0, 0); ++ SPEX(core_pwr_info[i].pa_5gh[0], o + SSB_SPROM4_5GH_PA_0, ~0, 0); ++ SPEX(core_pwr_info[i].pa_5gh[1], o + SSB_SPROM4_5GH_PA_1, ~0, 0); ++ SPEX(core_pwr_info[i].pa_5gh[2], o + SSB_SPROM4_5GH_PA_2, ~0, 0); ++ SPEX(core_pwr_info[i].pa_5gh[3], o + SSB_SPROM4_5GH_PA_3, ~0, 0); ++ } ++ ++ sprom_extract_r458(out, in); ++ ++ /* TODO - get remaining rev 4 stuff needed */ ++} ++ ++static void sprom_extract_r8(struct ssb_sprom *out, const u16 *in) ++{ ++ int i; ++ u16 o; ++ static const u16 pwr_info_offset[] = { ++ SSB_SROM8_PWR_INFO_CORE0, SSB_SROM8_PWR_INFO_CORE1, ++ SSB_SROM8_PWR_INFO_CORE2, SSB_SROM8_PWR_INFO_CORE3 ++ }; ++ BUILD_BUG_ON(ARRAY_SIZE(pwr_info_offset) != ++ ARRAY_SIZE(out->core_pwr_info)); ++ ++ SPEX(board_rev, SSB_SPROM8_BOARDREV, 0xFFFF, 0); ++ SPEX(board_type, SSB_SPROM1_SPID, 0xFFFF, 0); ++ SPEX(alpha2[0], SSB_SPROM8_CCODE, 0xff00, 8); ++ SPEX(alpha2[1], SSB_SPROM8_CCODE, 0x00ff, 0); ++ SPEX(boardflags_lo, SSB_SPROM8_BFLLO, 0xFFFF, 0); ++ SPEX(boardflags_hi, SSB_SPROM8_BFLHI, 0xFFFF, 0); ++ SPEX(boardflags2_lo, SSB_SPROM8_BFL2LO, 0xFFFF, 0); ++ SPEX(boardflags2_hi, SSB_SPROM8_BFL2HI, 0xFFFF, 0); ++ SPEX(ant_available_a, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_A, ++ SSB_SPROM8_ANTAVAIL_A_SHIFT); ++ SPEX(ant_available_bg, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_BG, ++ SSB_SPROM8_ANTAVAIL_BG_SHIFT); ++ SPEX(maxpwr_bg, SSB_SPROM8_MAXP_BG, SSB_SPROM8_MAXP_BG_MASK, 0); ++ SPEX(itssi_bg, SSB_SPROM8_MAXP_BG, SSB_SPROM8_ITSSI_BG, ++ SSB_SPROM8_ITSSI_BG_SHIFT); ++ SPEX(maxpwr_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_MAXP_A_MASK, 0); ++ SPEX(itssi_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_ITSSI_A, ++ SSB_SPROM8_ITSSI_A_SHIFT); ++ SPEX(maxpwr_ah, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AH_MASK, 0); ++ SPEX(maxpwr_al, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AL_MASK, ++ SSB_SPROM8_MAXP_AL_SHIFT); ++ SPEX(gpio0, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P0, 0); ++ SPEX(gpio1, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P1, ++ SSB_SPROM8_GPIOA_P1_SHIFT); ++ SPEX(gpio2, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P2, 0); ++ SPEX(gpio3, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P3, ++ SSB_SPROM8_GPIOB_P3_SHIFT); ++ SPEX(tri2g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI2G, 0); ++ SPEX(tri5g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI5G, ++ SSB_SPROM8_TRI5G_SHIFT); ++ SPEX(tri5gl, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GL, 0); ++ SPEX(tri5gh, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GH, ++ SSB_SPROM8_TRI5GH_SHIFT); ++ SPEX(rxpo2g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO2G, 0); ++ SPEX(rxpo5g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO5G, ++ SSB_SPROM8_RXPO5G_SHIFT); ++ SPEX(rssismf2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMF2G, 0); ++ SPEX(rssismc2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMC2G, ++ SSB_SPROM8_RSSISMC2G_SHIFT); ++ SPEX(rssisav2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISAV2G, ++ SSB_SPROM8_RSSISAV2G_SHIFT); ++ SPEX(bxa2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_BXA2G, ++ SSB_SPROM8_BXA2G_SHIFT); ++ SPEX(rssismf5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMF5G, 0); ++ SPEX(rssismc5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMC5G, ++ SSB_SPROM8_RSSISMC5G_SHIFT); ++ SPEX(rssisav5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISAV5G, ++ SSB_SPROM8_RSSISAV5G_SHIFT); ++ SPEX(bxa5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_BXA5G, ++ SSB_SPROM8_BXA5G_SHIFT); ++ SPEX(pa0b0, SSB_SPROM8_PA0B0, 0xFFFF, 0); ++ SPEX(pa0b1, SSB_SPROM8_PA0B1, 0xFFFF, 0); ++ SPEX(pa0b2, SSB_SPROM8_PA0B2, 0xFFFF, 0); ++ SPEX(pa1b0, SSB_SPROM8_PA1B0, 0xFFFF, 0); ++ SPEX(pa1b1, SSB_SPROM8_PA1B1, 0xFFFF, 0); ++ SPEX(pa1b2, SSB_SPROM8_PA1B2, 0xFFFF, 0); ++ SPEX(pa1lob0, SSB_SPROM8_PA1LOB0, 0xFFFF, 0); ++ SPEX(pa1lob1, SSB_SPROM8_PA1LOB1, 0xFFFF, 0); ++ SPEX(pa1lob2, SSB_SPROM8_PA1LOB2, 0xFFFF, 0); ++ SPEX(pa1hib0, SSB_SPROM8_PA1HIB0, 0xFFFF, 0); ++ SPEX(pa1hib1, SSB_SPROM8_PA1HIB1, 0xFFFF, 0); ++ SPEX(pa1hib2, SSB_SPROM8_PA1HIB2, 0xFFFF, 0); ++ SPEX(cck2gpo, SSB_SPROM8_CCK2GPO, 0xFFFF, 0); ++ SPEX32(ofdm2gpo, SSB_SPROM8_OFDM2GPO, 0xFFFFFFFF, 0); ++ SPEX32(ofdm5glpo, SSB_SPROM8_OFDM5GLPO, 0xFFFFFFFF, 0); ++ SPEX32(ofdm5gpo, SSB_SPROM8_OFDM5GPO, 0xFFFFFFFF, 0); ++ SPEX32(ofdm5ghpo, SSB_SPROM8_OFDM5GHPO, 0xFFFFFFFF, 0); ++ ++ /* Extract the antenna gain values. */ ++ out->antenna_gain.a0 = sprom_extract_antgain(out->revision, in, ++ SSB_SPROM8_AGAIN01, ++ SSB_SPROM8_AGAIN0, ++ SSB_SPROM8_AGAIN0_SHIFT); ++ out->antenna_gain.a1 = sprom_extract_antgain(out->revision, in, ++ SSB_SPROM8_AGAIN01, ++ SSB_SPROM8_AGAIN1, ++ SSB_SPROM8_AGAIN1_SHIFT); ++ out->antenna_gain.a2 = sprom_extract_antgain(out->revision, in, ++ SSB_SPROM8_AGAIN23, ++ SSB_SPROM8_AGAIN2, ++ SSB_SPROM8_AGAIN2_SHIFT); ++ out->antenna_gain.a3 = sprom_extract_antgain(out->revision, in, ++ SSB_SPROM8_AGAIN23, ++ SSB_SPROM8_AGAIN3, ++ SSB_SPROM8_AGAIN3_SHIFT); ++ ++ /* Extract cores power info info */ ++ for (i = 0; i < ARRAY_SIZE(pwr_info_offset); i++) { ++ o = pwr_info_offset[i]; ++ SPEX(core_pwr_info[i].itssi_2g, o + SSB_SROM8_2G_MAXP_ITSSI, ++ SSB_SPROM8_2G_ITSSI, SSB_SPROM8_2G_ITSSI_SHIFT); ++ SPEX(core_pwr_info[i].maxpwr_2g, o + SSB_SROM8_2G_MAXP_ITSSI, ++ SSB_SPROM8_2G_MAXP, 0); ++ ++ SPEX(core_pwr_info[i].pa_2g[0], o + SSB_SROM8_2G_PA_0, ~0, 0); ++ SPEX(core_pwr_info[i].pa_2g[1], o + SSB_SROM8_2G_PA_1, ~0, 0); ++ SPEX(core_pwr_info[i].pa_2g[2], o + SSB_SROM8_2G_PA_2, ~0, 0); ++ ++ SPEX(core_pwr_info[i].itssi_5g, o + SSB_SROM8_5G_MAXP_ITSSI, ++ SSB_SPROM8_5G_ITSSI, SSB_SPROM8_5G_ITSSI_SHIFT); ++ SPEX(core_pwr_info[i].maxpwr_5g, o + SSB_SROM8_5G_MAXP_ITSSI, ++ SSB_SPROM8_5G_MAXP, 0); ++ SPEX(core_pwr_info[i].maxpwr_5gh, o + SSB_SPROM8_5GHL_MAXP, ++ SSB_SPROM8_5GH_MAXP, 0); ++ SPEX(core_pwr_info[i].maxpwr_5gl, o + SSB_SPROM8_5GHL_MAXP, ++ SSB_SPROM8_5GL_MAXP, SSB_SPROM8_5GL_MAXP_SHIFT); ++ ++ SPEX(core_pwr_info[i].pa_5gl[0], o + SSB_SROM8_5GL_PA_0, ~0, 0); ++ SPEX(core_pwr_info[i].pa_5gl[1], o + SSB_SROM8_5GL_PA_1, ~0, 0); ++ SPEX(core_pwr_info[i].pa_5gl[2], o + SSB_SROM8_5GL_PA_2, ~0, 0); ++ SPEX(core_pwr_info[i].pa_5g[0], o + SSB_SROM8_5G_PA_0, ~0, 0); ++ SPEX(core_pwr_info[i].pa_5g[1], o + SSB_SROM8_5G_PA_1, ~0, 0); ++ SPEX(core_pwr_info[i].pa_5g[2], o + SSB_SROM8_5G_PA_2, ~0, 0); ++ SPEX(core_pwr_info[i].pa_5gh[0], o + SSB_SROM8_5GH_PA_0, ~0, 0); ++ SPEX(core_pwr_info[i].pa_5gh[1], o + SSB_SROM8_5GH_PA_1, ~0, 0); ++ SPEX(core_pwr_info[i].pa_5gh[2], o + SSB_SROM8_5GH_PA_2, ~0, 0); ++ } ++ ++ /* Extract FEM info */ ++ SPEX(fem.ghz2.tssipos, SSB_SPROM8_FEM2G, ++ SSB_SROM8_FEM_TSSIPOS, SSB_SROM8_FEM_TSSIPOS_SHIFT); ++ SPEX(fem.ghz2.extpa_gain, SSB_SPROM8_FEM2G, ++ SSB_SROM8_FEM_EXTPA_GAIN, SSB_SROM8_FEM_EXTPA_GAIN_SHIFT); ++ SPEX(fem.ghz2.pdet_range, SSB_SPROM8_FEM2G, ++ SSB_SROM8_FEM_PDET_RANGE, SSB_SROM8_FEM_PDET_RANGE_SHIFT); ++ SPEX(fem.ghz2.tr_iso, SSB_SPROM8_FEM2G, ++ SSB_SROM8_FEM_TR_ISO, SSB_SROM8_FEM_TR_ISO_SHIFT); ++ SPEX(fem.ghz2.antswlut, SSB_SPROM8_FEM2G, ++ SSB_SROM8_FEM_ANTSWLUT, SSB_SROM8_FEM_ANTSWLUT_SHIFT); ++ ++ SPEX(fem.ghz5.tssipos, SSB_SPROM8_FEM5G, ++ SSB_SROM8_FEM_TSSIPOS, SSB_SROM8_FEM_TSSIPOS_SHIFT); ++ SPEX(fem.ghz5.extpa_gain, SSB_SPROM8_FEM5G, ++ SSB_SROM8_FEM_EXTPA_GAIN, SSB_SROM8_FEM_EXTPA_GAIN_SHIFT); ++ SPEX(fem.ghz5.pdet_range, SSB_SPROM8_FEM5G, ++ SSB_SROM8_FEM_PDET_RANGE, SSB_SROM8_FEM_PDET_RANGE_SHIFT); ++ SPEX(fem.ghz5.tr_iso, SSB_SPROM8_FEM5G, ++ SSB_SROM8_FEM_TR_ISO, SSB_SROM8_FEM_TR_ISO_SHIFT); ++ SPEX(fem.ghz5.antswlut, SSB_SPROM8_FEM5G, ++ SSB_SROM8_FEM_ANTSWLUT, SSB_SROM8_FEM_ANTSWLUT_SHIFT); ++ ++ SPEX(leddc_on_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_ON, ++ SSB_SPROM8_LEDDC_ON_SHIFT); ++ SPEX(leddc_off_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_OFF, ++ SSB_SPROM8_LEDDC_OFF_SHIFT); ++ ++ SPEX(txchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_TXCHAIN, ++ SSB_SPROM8_TXRXC_TXCHAIN_SHIFT); ++ SPEX(rxchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_RXCHAIN, ++ SSB_SPROM8_TXRXC_RXCHAIN_SHIFT); ++ SPEX(antswitch, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_SWITCH, ++ SSB_SPROM8_TXRXC_SWITCH_SHIFT); ++ ++ SPEX(opo, SSB_SPROM8_OFDM2GPO, 0x00ff, 0); ++ ++ SPEX_ARRAY8(mcs2gpo, SSB_SPROM8_2G_MCSPO, ~0, 0); ++ SPEX_ARRAY8(mcs5gpo, SSB_SPROM8_5G_MCSPO, ~0, 0); ++ SPEX_ARRAY8(mcs5glpo, SSB_SPROM8_5GL_MCSPO, ~0, 0); ++ SPEX_ARRAY8(mcs5ghpo, SSB_SPROM8_5GH_MCSPO, ~0, 0); ++ ++ SPEX(rawtempsense, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_RAWTEMP, ++ SSB_SPROM8_RAWTS_RAWTEMP_SHIFT); ++ SPEX(measpower, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_MEASPOWER, ++ SSB_SPROM8_RAWTS_MEASPOWER_SHIFT); ++ SPEX(tempsense_slope, SSB_SPROM8_OPT_CORRX, ++ SSB_SPROM8_OPT_CORRX_TEMP_SLOPE, ++ SSB_SPROM8_OPT_CORRX_TEMP_SLOPE_SHIFT); ++ SPEX(tempcorrx, SSB_SPROM8_OPT_CORRX, SSB_SPROM8_OPT_CORRX_TEMPCORRX, ++ SSB_SPROM8_OPT_CORRX_TEMPCORRX_SHIFT); ++ SPEX(tempsense_option, SSB_SPROM8_OPT_CORRX, ++ SSB_SPROM8_OPT_CORRX_TEMP_OPTION, ++ SSB_SPROM8_OPT_CORRX_TEMP_OPTION_SHIFT); ++ SPEX(freqoffset_corr, SSB_SPROM8_HWIQ_IQSWP, ++ SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR, ++ SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR_SHIFT); ++ SPEX(iqcal_swp_dis, SSB_SPROM8_HWIQ_IQSWP, ++ SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP, ++ SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP_SHIFT); ++ SPEX(hw_iqcal_en, SSB_SPROM8_HWIQ_IQSWP, SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL, ++ SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL_SHIFT); ++ ++ SPEX(bw40po, SSB_SPROM8_BW40PO, ~0, 0); ++ SPEX(cddpo, SSB_SPROM8_CDDPO, ~0, 0); ++ SPEX(stbcpo, SSB_SPROM8_STBCPO, ~0, 0); ++ SPEX(bwduppo, SSB_SPROM8_BWDUPPO, ~0, 0); ++ ++ SPEX(tempthresh, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_TRESH, ++ SSB_SPROM8_THERMAL_TRESH_SHIFT); ++ SPEX(tempoffset, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_OFFSET, ++ SSB_SPROM8_THERMAL_OFFSET_SHIFT); ++ SPEX(phycal_tempdelta, SSB_SPROM8_TEMPDELTA, ++ SSB_SPROM8_TEMPDELTA_PHYCAL, ++ SSB_SPROM8_TEMPDELTA_PHYCAL_SHIFT); ++ SPEX(temps_period, SSB_SPROM8_TEMPDELTA, SSB_SPROM8_TEMPDELTA_PERIOD, ++ SSB_SPROM8_TEMPDELTA_PERIOD_SHIFT); ++ SPEX(temps_hysteresis, SSB_SPROM8_TEMPDELTA, ++ SSB_SPROM8_TEMPDELTA_HYSTERESIS, ++ SSB_SPROM8_TEMPDELTA_HYSTERESIS_SHIFT); ++ sprom_extract_r458(out, in); ++ ++ /* TODO - get remaining rev 8 stuff needed */ ++} ++ ++static int sprom_extract(struct ssb_fbs *priv, const u16 *in, u16 size) ++{ ++ struct ssb_sprom *out = &priv->sprom; ++ ++ memset(out, 0, sizeof(*out)); ++ ++ out->revision = in[size - 1] & 0x00FF; ++ ++ switch (out->revision) { ++ case 1: ++ case 2: ++ case 3: ++ sprom_extract_r123(out, in); ++ break; ++ case 4: ++ case 5: ++ sprom_extract_r45(out, in); ++ break; ++ case 8: ++ sprom_extract_r8(out, in); ++ break; ++ default: ++ dev_warn(priv->dev, ++ "Unsupported SPROM revision %d detected." ++ " Will extract v1\n", ++ out->revision); ++ out->revision = 1; ++ sprom_extract_r123(out, in); ++ } ++ ++ if (out->boardflags_lo == 0xFFFF) ++ out->boardflags_lo = 0; /* per specs */ ++ if (out->boardflags_hi == 0xFFFF) ++ out->boardflags_hi = 0; /* per specs */ ++ ++ return 0; ++} ++ ++static void ssb_fbs_fixup(struct ssb_fbs *priv, u16 *sprom) ++{ ++ struct device_node *node = priv->dev->of_node; ++ u32 fixups, off, val; ++ int i = 0; ++ ++ if (!of_get_property(node, "brcm,sprom-fixups", &fixups)) ++ return; ++ ++ fixups /= sizeof(u32); ++ ++ dev_info(priv->dev, "patching SPROM with %u fixups...\n", fixups >> 1); ++ ++ while (i < fixups) { ++ if (of_property_read_u32_index(node, "brcm,sprom-fixups", ++ i++, &off)) { ++ dev_err(priv->dev, "error reading fixup[%u] offset\n", ++ i - 1); ++ return; ++ } ++ ++ if (of_property_read_u32_index(node, "brcm,sprom-fixups", ++ i++, &val)) { ++ dev_err(priv->dev, "error reading fixup[%u] value\n", ++ i - 1); ++ return; ++ } ++ ++ dev_dbg(priv->dev, "fixup[%d]=0x%04x\n", off, val); ++ ++ sprom[off] = val; ++ } ++} ++ ++static bool sprom_override_devid(struct ssb_fbs *priv, struct ssb_sprom *out, ++ const u16 *in) ++{ ++ SPEX(dev_id, SSB_SPROM1_PID, 0xFFFF, 0); ++ return !!out->dev_id; ++} ++ ++static int ssb_fbs_set(struct ssb_fbs *priv, struct device_node *node) ++{ ++ struct ssb_sprom *sprom = &priv->sprom; ++ const struct firmware *fw; ++ const char *sprom_name; ++ int err; ++ ++ if (of_property_read_string(node, "brcm,sprom", &sprom_name)) ++ sprom_name = NULL; ++ ++ if (sprom_name) { ++ err = request_firmware_direct(&fw, sprom_name, priv->dev); ++ if (err) ++ dev_err(priv->dev, "%s load error\n", sprom_name); ++ } else { ++ err = -ENOENT; ++ } ++ ++ if (err) { ++ sprom->revision = 0x02; ++ sprom->board_rev = 0x0017; ++ sprom->country_code = 0x00; ++ sprom->ant_available_bg = 0x03; ++ sprom->pa0b0 = 0x15ae; ++ sprom->pa0b1 = 0xfa85; ++ sprom->pa0b2 = 0xfe8d; ++ sprom->pa1b0 = 0xffff; ++ sprom->pa1b1 = 0xffff; ++ sprom->pa1b2 = 0xffff; ++ sprom->gpio0 = 0xff; ++ sprom->gpio1 = 0xff; ++ sprom->gpio2 = 0xff; ++ sprom->gpio3 = 0xff; ++ sprom->maxpwr_bg = 0x4c; ++ sprom->itssi_bg = 0x00; ++ sprom->boardflags_lo = 0x2848; ++ sprom->boardflags_hi = 0x0000; ++ priv->devid_override = false; ++ ++ dev_warn(priv->dev, "using basic SPROM\n"); ++ } else { ++ size_t size = min(fw->size, (size_t) SSB_FBS_MAX_SIZE); ++ u16 tmp_sprom[SSB_FBS_MAX_SIZE >> 1]; ++ u32 i, j; ++ ++ for (i = 0, j = 0; i < size; i += 2, j++) ++ tmp_sprom[j] = (fw->data[i] << 8) | fw->data[i + 1]; ++ ++ release_firmware(fw); ++ ssb_fbs_fixup(priv, tmp_sprom); ++ sprom_extract(priv, tmp_sprom, size >> 1); ++ ++ priv->devid_override = sprom_override_devid(priv, sprom, ++ tmp_sprom); ++ } ++ ++ return 0; ++} ++ ++static int ssb_fbs_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct device_node *node = dev->of_node; ++ struct ssb_fbs *priv; ++ unsigned long flags; ++ u8 mac[ETH_ALEN]; ++ ++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ priv->dev = dev; ++ ++ ssb_fbs_set(priv, node); ++ ++ of_property_read_u32(node, "pci-bus", &priv->pci_bus); ++ of_property_read_u32(node, "pci-dev", &priv->pci_dev); ++ ++ of_get_mac_address(node, mac); ++ if (is_valid_ether_addr(mac)) { ++ dev_info(dev, "mtd mac %pM\n", mac); ++ } else { ++ eth_random_addr(mac); ++ dev_info(dev, "random mac %pM\n", mac); ++ } ++ ++ memcpy(priv->sprom.il0mac, mac, ETH_ALEN); ++ memcpy(priv->sprom.et0mac, mac, ETH_ALEN); ++ memcpy(priv->sprom.et1mac, mac, ETH_ALEN); ++ memcpy(priv->sprom.et2mac, mac, ETH_ALEN); ++ ++ spin_lock_irqsave(&ssb_fbs_lock, flags); ++ list_add(&priv->list, &ssb_fbs_list); ++ spin_unlock_irqrestore(&ssb_fbs_lock, flags); ++ ++ dev_info(dev, "registered SPROM for [%x:%x]\n", ++ priv->pci_bus, priv->pci_dev); ++ ++ return 0; ++} ++ ++static const struct of_device_id ssb_fbs_of_match[] = { ++ { .compatible = "brcm,ssb-sprom", }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, ssb_fbs_of_match); ++ ++static struct platform_driver ssb_fbs_driver = { ++ .probe = ssb_fbs_probe, ++ .driver = { ++ .name = "ssb-sprom", ++ .of_match_table = ssb_fbs_of_match, ++ }, ++}; ++ ++int __init ssb_fbs_register(void) ++{ ++ return platform_driver_register(&ssb_fbs_driver); ++} +diff --git a/drivers/ssb/fallback-sprom.h b/drivers/ssb/fallback-sprom.h +new file mode 100644 +index 000000000000..3966a18b86de +--- /dev/null ++++ b/drivers/ssb/fallback-sprom.h +@@ -0,0 +1,7 @@ ++#ifndef _FALLBACK_SPROM_H ++#define _FALLBACK_SPROM_H ++ ++int __init ssb_fbs_register(void); ++int ssb_get_fallback_sprom(struct ssb_bus *dev, struct ssb_sprom *out); ++ ++#endif /* _FALLBACK_SPROM_H */ +diff --git a/include/dt-bindings/mtd/partitions/uimage.h b/include/dt-bindings/mtd/partitions/uimage.h +new file mode 100644 +index 000000000000..43d5f7b5da87 +--- /dev/null ++++ b/include/dt-bindings/mtd/partitions/uimage.h +@@ -0,0 +1,198 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* ++ * *** IMPORTANT *** ++ * This file is not only included from C-code but also from devicetree source ++ * files. As such this file MUST only contain comments and defines. ++ * ++ * Based on image.h from U-Boot which is ++ * (C) Copyright 2008 Semihalf ++ * (C) Copyright 2000-2005 Wolfgang Denk, DENX Software Engineering, wd@denx.de. ++ */ ++ ++#ifndef __UIMAGE_H__ ++#define __UIMAGE_H__ ++ ++/* ++ * Operating System Codes ++ * ++ * The following are exposed to uImage header. ++ * New IDs *MUST* be appended at the end of the list and *NEVER* ++ * inserted for backward compatibility. ++ */ ++#define IH_OS_INVALID 0 /* Invalid OS */ ++#define IH_OS_OPENBSD 1 /* OpenBSD */ ++#define IH_OS_NETBSD 2 /* NetBSD */ ++#define IH_OS_FREEBSD 3 /* FreeBSD */ ++#define IH_OS_4_4BSD 4 /* 4.4BSD */ ++#define IH_OS_LINUX 5 /* Linux */ ++#define IH_OS_SVR4 6 /* SVR4 */ ++#define IH_OS_ESIX 7 /* Esix */ ++#define IH_OS_SOLARIS 8 /* Solaris */ ++#define IH_OS_IRIX 9 /* Irix */ ++#define IH_OS_SCO 10 /* SCO */ ++#define IH_OS_DELL 11 /* Dell */ ++#define IH_OS_NCR 12 /* NCR */ ++#define IH_OS_LYNXOS 13 /* LynxOS */ ++#define IH_OS_VXWORKS 14 /* VxWorks */ ++#define IH_OS_PSOS 15 /* pSOS */ ++#define IH_OS_QNX 16 /* QNX */ ++#define IH_OS_U_BOOT 17 /* Firmware */ ++#define IH_OS_RTEMS 18 /* RTEMS */ ++#define IH_OS_ARTOS 19 /* ARTOS */ ++#define IH_OS_UNITY 20 /* Unity OS */ ++#define IH_OS_INTEGRITY 21 /* INTEGRITY */ ++#define IH_OS_OSE 22 /* OSE */ ++#define IH_OS_PLAN9 23 /* Plan 9 */ ++#define IH_OS_OPENRTOS 24 /* OpenRTOS */ ++#define IH_OS_ARM_TRUSTED_FIRMWARE 25 /* ARM Trusted Firmware */ ++#define IH_OS_TEE 26 /* Trusted Execution Environment */ ++#define IH_OS_OPENSBI 27 /* RISC-V OpenSBI */ ++#define IH_OS_EFI 28 /* EFI Firmware (e.g. GRUB2) */ ++ ++/* ++ * CPU Architecture Codes (supported by Linux) ++ * ++ * The following are exposed to uImage header. ++ * New IDs *MUST* be appended at the end of the list and *NEVER* ++ * inserted for backward compatibility. ++ */ ++#define IH_ARCH_INVALID 0 /* Invalid CPU */ ++#define IH_ARCH_ALPHA 1 /* Alpha */ ++#define IH_ARCH_ARM 2 /* ARM */ ++#define IH_ARCH_I386 3 /* Intel x86 */ ++#define IH_ARCH_IA64 4 /* IA64 */ ++#define IH_ARCH_MIPS 5 /* MIPS */ ++#define IH_ARCH_MIPS64 6 /* MIPS 64 Bit */ ++#define IH_ARCH_PPC 7 /* PowerPC */ ++#define IH_ARCH_S390 8 /* IBM S390 */ ++#define IH_ARCH_SH 9 /* SuperH */ ++#define IH_ARCH_SPARC 10 /* Sparc */ ++#define IH_ARCH_SPARC64 11 /* Sparc 64 Bit */ ++#define IH_ARCH_M68K 12 /* M68K */ ++#define IH_ARCH_NIOS 13 /* Nios-32 */ ++#define IH_ARCH_MICROBLAZE 14 /* MicroBlaze */ ++#define IH_ARCH_NIOS2 15 /* Nios-II */ ++#define IH_ARCH_BLACKFIN 16 /* Blackfin */ ++#define IH_ARCH_AVR32 17 /* AVR32 */ ++#define IH_ARCH_ST200 18 /* STMicroelectronics ST200 */ ++#define IH_ARCH_SANDBOX 19 /* Sandbox architecture (test only) */ ++#define IH_ARCH_NDS32 20 /* ANDES Technology - NDS32 */ ++#define IH_ARCH_OPENRISC 21 /* OpenRISC 1000 */ ++#define IH_ARCH_ARM64 22 /* ARM64 */ ++#define IH_ARCH_ARC 23 /* Synopsys DesignWare ARC */ ++#define IH_ARCH_X86_64 24 /* AMD x86_64, Intel and Via */ ++#define IH_ARCH_XTENSA 25 /* Xtensa */ ++#define IH_ARCH_RISCV 26 /* RISC-V */ ++ ++/* ++ * Image Types ++ * ++ * "Standalone Programs" are directly runnable in the environment ++ * provided by U-Boot; it is expected that (if they behave ++ * well) you can continue to work in U-Boot after return from ++ * the Standalone Program. ++ * "OS Kernel Images" are usually images of some Embedded OS which ++ * will take over control completely. Usually these programs ++ * will install their own set of exception handlers, device ++ * drivers, set up the MMU, etc. - this means, that you cannot ++ * expect to re-enter U-Boot except by resetting the CPU. ++ * "RAMDisk Images" are more or less just data blocks, and their ++ * parameters (address, size) are passed to an OS kernel that is ++ * being started. ++ * "Multi-File Images" contain several images, typically an OS ++ * (Linux) kernel image and one or more data images like ++ * RAMDisks. This construct is useful for instance when you want ++ * to boot over the network using BOOTP etc., where the boot ++ * server provides just a single image file, but you want to get ++ * for instance an OS kernel and a RAMDisk image. ++ * ++ * "Multi-File Images" start with a list of image sizes, each ++ * image size (in bytes) specified by an "uint32_t" in network ++ * byte order. This list is terminated by an "(uint32_t)0". ++ * Immediately after the terminating 0 follow the images, one by ++ * one, all aligned on "uint32_t" boundaries (size rounded up to ++ * a multiple of 4 bytes - except for the last file). ++ * ++ * "Firmware Images" are binary images containing firmware (like ++ * U-Boot or FPGA images) which usually will be programmed to ++ * flash memory. ++ * ++ * "Script files" are command sequences that will be executed by ++ * U-Boot's command interpreter; this feature is especially ++ * useful when you configure U-Boot to use a real shell (hush) ++ * as command interpreter (=> Shell Scripts). ++ * ++ * The following are exposed to uImage header. ++ * New IDs *MUST* be appended at the end of the list and *NEVER* ++ * inserted for backward compatibility. ++ */ ++#define IH_TYPE_INVALID 0 /* Invalid Image */ ++#define IH_TYPE_STANDALONE 1 /* Standalone Program */ ++#define IH_TYPE_KERNEL 2 /* OS Kernel Image */ ++#define IH_TYPE_RAMDISK 3 /* RAMDisk Image */ ++#define IH_TYPE_MULTI 4 /* Multi-File Image */ ++#define IH_TYPE_FIRMWARE 5 /* Firmware Image */ ++#define IH_TYPE_SCRIPT 6 /* Script file */ ++#define IH_TYPE_FILESYSTEM 7 /* Filesystem Image (any type) */ ++#define IH_TYPE_FLATDT 8 /* Binary Flat Device Tree Blob */ ++#define IH_TYPE_KWBIMAGE 9 /* Kirkwood Boot Image */ ++#define IH_TYPE_IMXIMAGE 10 /* Freescale IMXBoot Image */ ++#define IH_TYPE_UBLIMAGE 11 /* Davinci UBL Image */ ++#define IH_TYPE_OMAPIMAGE 12 /* TI OMAP Config Header Image */ ++#define IH_TYPE_AISIMAGE 13 /* TI Davinci AIS Image */ ++ /* OS Kernel Image, can run from any load address */ ++#define IH_TYPE_KERNEL_NOLOAD 14 ++#define IH_TYPE_PBLIMAGE 15 /* Freescale PBL Boot Image */ ++#define IH_TYPE_MXSIMAGE 16 /* Freescale MXSBoot Image */ ++#define IH_TYPE_GPIMAGE 17 /* TI Keystone GPHeader Image */ ++#define IH_TYPE_ATMELIMAGE 18 /* ATMEL ROM bootable Image */ ++#define IH_TYPE_SOCFPGAIMAGE 19 /* Altera SOCFPGA CV/AV Preloader */ ++#define IH_TYPE_X86_SETUP 20 /* x86 setup.bin Image */ ++#define IH_TYPE_LPC32XXIMAGE 21 /* x86 setup.bin Image */ ++#define IH_TYPE_LOADABLE 22 /* A list of typeless images */ ++#define IH_TYPE_RKIMAGE 23 /* Rockchip Boot Image */ ++#define IH_TYPE_RKSD 24 /* Rockchip SD card */ ++#define IH_TYPE_RKSPI 25 /* Rockchip SPI image */ ++#define IH_TYPE_ZYNQIMAGE 26 /* Xilinx Zynq Boot Image */ ++#define IH_TYPE_ZYNQMPIMAGE 27 /* Xilinx ZynqMP Boot Image */ ++#define IH_TYPE_ZYNQMPBIF 28 /* Xilinx ZynqMP Boot Image (bif) */ ++#define IH_TYPE_FPGA 29 /* FPGA Image */ ++#define IH_TYPE_VYBRIDIMAGE 30 /* VYBRID .vyb Image */ ++#define IH_TYPE_TEE 31 /* Trusted Execution Environment OS Image */ ++#define IH_TYPE_FIRMWARE_IVT 32 /* Firmware Image with HABv4 IVT */ ++#define IH_TYPE_PMMC 33 /* TI Power Management Micro-Controller Firmware */ ++#define IH_TYPE_STM32IMAGE 34 /* STMicroelectronics STM32 Image */ ++#define IH_TYPE_SOCFPGAIMAGE_V1 35 /* Altera SOCFPGA A10 Preloader */ ++#define IH_TYPE_MTKIMAGE 36 /* MediaTek BootROM loadable Image */ ++#define IH_TYPE_IMX8MIMAGE 37 /* Freescale IMX8MBoot Image */ ++#define IH_TYPE_IMX8IMAGE 38 /* Freescale IMX8Boot Image */ ++#define IH_TYPE_COPRO 39 /* Coprocessor Image for remoteproc*/ ++ ++ ++/* ++ * Compression Types ++ * ++ * The following are exposed to uImage header. ++ * New IDs *MUST* be appended at the end of the list and *NEVER* ++ * inserted for backward compatibility. ++ */ ++#define IH_COMP_NONE 0 /* No Compression Used */ ++#define IH_COMP_GZIP 1 /* gzip Compression Used */ ++#define IH_COMP_BZIP2 2 /* bzip2 Compression Used */ ++#define IH_COMP_LZMA 3 /* lzma Compression Used */ ++#define IH_COMP_LZO 4 /* lzo Compression Used */ ++#define IH_COMP_LZ4 5 /* lz4 Compression Used */ ++ ++ ++#define LZ4F_MAGIC 0x184D2204 /* LZ4 Magic Number */ ++#define IH_MAGIC 0x27051956 /* Image Magic Number */ ++#define IH_NMLEN 32 /* Image Name Length */ ++ ++/* ++ * Magic values specific to "openwrt,uimage" partitions ++ */ ++#define IH_MAGIC_OKLI 0x4f4b4c49 /* 'OKLI' */ ++#define FW_EDIMAX_OFFSET 20 /* Edimax Firmware Offset */ ++#define FW_MAGIC_EDIMAX 0x43535953 /* Edimax Firmware Magic Number */ ++ ++#endif /* __UIMAGE_H__ */ +diff --git a/include/linux/ar8216_platform.h b/include/linux/ar8216_platform.h +new file mode 100644 +index 000000000000..fff05ffb5c16 +--- /dev/null ++++ b/include/linux/ar8216_platform.h +@@ -0,0 +1,134 @@ ++/* ++ * AR8216 switch driver platform data ++ * ++ * Copyright (C) 2012 Gabor Juhos ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version 2 ++ * of the License, or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#ifndef AR8216_PLATFORM_H ++#define AR8216_PLATFORM_H ++ ++enum ar8327_pad_mode { ++ AR8327_PAD_NC = 0, ++ AR8327_PAD_MAC2MAC_MII, ++ AR8327_PAD_MAC2MAC_GMII, ++ AR8327_PAD_MAC_SGMII, ++ AR8327_PAD_MAC2PHY_MII, ++ AR8327_PAD_MAC2PHY_GMII, ++ AR8327_PAD_MAC_RGMII, ++ AR8327_PAD_PHY_GMII, ++ AR8327_PAD_PHY_RGMII, ++ AR8327_PAD_PHY_MII, ++}; ++ ++enum ar8327_clk_delay_sel { ++ AR8327_CLK_DELAY_SEL0 = 0, ++ AR8327_CLK_DELAY_SEL1, ++ AR8327_CLK_DELAY_SEL2, ++ AR8327_CLK_DELAY_SEL3, ++}; ++ ++struct ar8327_pad_cfg { ++ enum ar8327_pad_mode mode; ++ bool rxclk_sel; ++ bool txclk_sel; ++ bool pipe_rxclk_sel; ++ bool txclk_delay_en; ++ bool rxclk_delay_en; ++ bool sgmii_delay_en; ++ enum ar8327_clk_delay_sel txclk_delay_sel; ++ enum ar8327_clk_delay_sel rxclk_delay_sel; ++ bool mac06_exchange_dis; ++}; ++ ++enum ar8327_port_speed { ++ AR8327_PORT_SPEED_10 = 0, ++ AR8327_PORT_SPEED_100, ++ AR8327_PORT_SPEED_1000, ++}; ++ ++struct ar8327_port_cfg { ++ int force_link:1; ++ enum ar8327_port_speed speed; ++ int txpause:1; ++ int rxpause:1; ++ int duplex:1; ++}; ++ ++struct ar8327_sgmii_cfg { ++ u32 sgmii_ctrl; ++ bool serdes_aen; ++}; ++ ++struct ar8327_led_cfg { ++ u32 led_ctrl0; ++ u32 led_ctrl1; ++ u32 led_ctrl2; ++ u32 led_ctrl3; ++ bool open_drain; ++}; ++ ++enum ar8327_led_num { ++ AR8327_LED_PHY0_0 = 0, ++ AR8327_LED_PHY0_1, ++ AR8327_LED_PHY0_2, ++ AR8327_LED_PHY1_0, ++ AR8327_LED_PHY1_1, ++ AR8327_LED_PHY1_2, ++ AR8327_LED_PHY2_0, ++ AR8327_LED_PHY2_1, ++ AR8327_LED_PHY2_2, ++ AR8327_LED_PHY3_0, ++ AR8327_LED_PHY3_1, ++ AR8327_LED_PHY3_2, ++ AR8327_LED_PHY4_0, ++ AR8327_LED_PHY4_1, ++ AR8327_LED_PHY4_2, ++}; ++ ++enum ar8327_led_mode { ++ AR8327_LED_MODE_HW = 0, ++ AR8327_LED_MODE_SW, ++}; ++ ++struct ar8327_led_info { ++ const char *name; ++ const char *default_trigger; ++ bool active_low; ++ enum ar8327_led_num led_num; ++ enum ar8327_led_mode mode; ++ struct fwnode_handle *fwnode; ++}; ++ ++#define AR8327_LED_INFO(_led, _mode, _name) { \ ++ .name = (_name), \ ++ .led_num = AR8327_LED_ ## _led, \ ++ .mode = AR8327_LED_MODE_ ## _mode \ ++} ++ ++struct ar8327_platform_data { ++ struct ar8327_pad_cfg *pad0_cfg; ++ struct ar8327_pad_cfg *pad5_cfg; ++ struct ar8327_pad_cfg *pad6_cfg; ++ struct ar8327_sgmii_cfg *sgmii_cfg; ++ struct ar8327_port_cfg port0_cfg; ++ struct ar8327_port_cfg port6_cfg; ++ struct ar8327_led_cfg *led_cfg; ++ ++ int (*get_port_link)(unsigned port); ++ ++ unsigned num_leds; ++ const struct ar8327_led_info *leds; ++}; ++ ++#endif /* AR8216_PLATFORM_H */ ++ +diff --git a/include/linux/ath5k_platform.h b/include/linux/ath5k_platform.h +new file mode 100644 +index 000000000000..ec8522452879 +--- /dev/null ++++ b/include/linux/ath5k_platform.h +@@ -0,0 +1,30 @@ ++/* ++ * Copyright (c) 2008 Atheros Communications Inc. ++ * Copyright (c) 2009 Gabor Juhos ++ * Copyright (c) 2009 Imre Kaloz ++ * Copyright (c) 2010 Daniel Golle ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#ifndef _LINUX_ATH5K_PLATFORM_H ++#define _LINUX_ATH5K_PLATFORM_H ++ ++#define ATH5K_PLAT_EEP_MAX_WORDS 2048 ++ ++struct ath5k_platform_data { ++ u16 *eeprom_data; ++ u8 *macaddr; ++}; ++ ++#endif /* _LINUX_ATH5K_PLATFORM_H */ +diff --git a/include/linux/mfd/airoha-an8855-mfd.h b/include/linux/mfd/airoha-an8855-mfd.h +new file mode 100644 +index 000000000000..56061566a079 +--- /dev/null ++++ b/include/linux/mfd/airoha-an8855-mfd.h +@@ -0,0 +1,41 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* ++ * MFD driver for Airoha AN8855 Switch ++ */ ++#ifndef _LINUX_INCLUDE_MFD_AIROHA_AN8855_MFD_H ++#define _LINUX_INCLUDE_MFD_AIROHA_AN8855_MFD_H ++ ++#include ++ ++/* MII Registers */ ++#define AN8855_PHY_SELECT_PAGE 0x1f ++#define AN8855_PHY_PAGE GENMASK(2, 0) ++#define AN8855_PHY_PAGE_STANDARD FIELD_PREP_CONST(AN8855_PHY_PAGE, 0x0) ++#define AN8855_PHY_PAGE_EXTENDED_1 FIELD_PREP_CONST(AN8855_PHY_PAGE, 0x1) ++#define AN8855_PHY_PAGE_EXTENDED_4 FIELD_PREP_CONST(AN8855_PHY_PAGE, 0x4) ++ ++/* MII Registers Page 4 */ ++#define AN8855_PBUS_MODE 0x10 ++#define AN8855_PBUS_MODE_ADDR_FIXED 0x0 ++#define AN8855_PBUS_MODE_ADDR_INCR BIT(15) ++#define AN8855_PBUS_WR_ADDR_HIGH 0x11 ++#define AN8855_PBUS_WR_ADDR_LOW 0x12 ++#define AN8855_PBUS_WR_DATA_HIGH 0x13 ++#define AN8855_PBUS_WR_DATA_LOW 0x14 ++#define AN8855_PBUS_RD_ADDR_HIGH 0x15 ++#define AN8855_PBUS_RD_ADDR_LOW 0x16 ++#define AN8855_PBUS_RD_DATA_HIGH 0x17 ++#define AN8855_PBUS_RD_DATA_LOW 0x18 ++ ++struct an8855_mfd_priv { ++ struct device *dev; ++ struct mii_bus *bus; ++ ++ unsigned int switch_addr; ++ u16 current_page; ++}; ++ ++int an8855_mii_set_page(struct an8855_mfd_priv *priv, u8 phy_id, ++ u8 page); ++ ++#endif +diff --git a/include/linux/mtd/mtk_bmt.h b/include/linux/mtd/mtk_bmt.h +new file mode 100644 +index 000000000000..cbb6d04d8952 +--- /dev/null ++++ b/include/linux/mtd/mtk_bmt.h +@@ -0,0 +1,18 @@ ++#ifndef __MTK_BMT_H ++#define __MTK_BMT_H ++ ++#ifdef CONFIG_MTD_NAND_MTK_BMT ++int mtk_bmt_attach(struct mtd_info *mtd); ++void mtk_bmt_detach(struct mtd_info *mtd); ++#else ++static inline int mtk_bmt_attach(struct mtd_info *mtd) ++{ ++ return 0; ++} ++ ++static inline void mtk_bmt_detach(struct mtd_info *mtd) ++{ ++} ++#endif ++ ++#endif +diff --git a/include/linux/myloader.h b/include/linux/myloader.h +new file mode 100644 +index 000000000000..d89e415fba6c +--- /dev/null ++++ b/include/linux/myloader.h +@@ -0,0 +1,121 @@ ++/* ++ * Compex's MyLoader specific definitions ++ * ++ * Copyright (C) 2006-2008 Gabor Juhos ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation. ++ * ++ */ ++ ++#ifndef _MYLOADER_H_ ++#define _MYLOADER_H_ ++ ++/* Myloader specific magic numbers */ ++#define MYLO_MAGIC_SYS_PARAMS 0x20021107 ++#define MYLO_MAGIC_PARTITIONS 0x20021103 ++#define MYLO_MAGIC_BOARD_PARAMS 0x20021103 ++ ++/* Vendor ID's (seems to be same as the PCI vendor ID's) */ ++#define VENID_COMPEX 0x11F6 ++ ++/* Devices based on the ADM5120 */ ++#define DEVID_COMPEX_NP27G 0x0078 ++#define DEVID_COMPEX_NP28G 0x044C ++#define DEVID_COMPEX_NP28GHS 0x044E ++#define DEVID_COMPEX_WP54Gv1C 0x0514 ++#define DEVID_COMPEX_WP54G 0x0515 ++#define DEVID_COMPEX_WP54AG 0x0546 ++#define DEVID_COMPEX_WPP54AG 0x0550 ++#define DEVID_COMPEX_WPP54G 0x0555 ++ ++/* Devices based on the Atheros AR2317 */ ++#define DEVID_COMPEX_NP25G 0x05E6 ++#define DEVID_COMPEX_WPE53G 0x05DC ++ ++/* Devices based on the Atheros AR71xx */ ++#define DEVID_COMPEX_WP543 0x0640 ++#define DEVID_COMPEX_WPE72 0x0672 ++ ++/* Devices based on the IXP422 */ ++#define DEVID_COMPEX_WP18 0x047E ++#define DEVID_COMPEX_NP18A 0x0489 ++ ++/* Other devices */ ++#define DEVID_COMPEX_NP26G8M 0x03E8 ++#define DEVID_COMPEX_NP26G16M 0x03E9 ++ ++struct mylo_partition { ++ uint16_t flags; /* partition flags */ ++ uint16_t type; /* type of the partition */ ++ uint32_t addr; /* relative address of the partition from the ++ flash start */ ++ uint32_t size; /* size of the partition in bytes */ ++ uint32_t param; /* if this is the active partition, the ++ MyLoader load code to this address */ ++}; ++ ++#define PARTITION_FLAG_ACTIVE 0x8000 /* this is the active partition, ++ * MyLoader loads firmware from here */ ++#define PARTITION_FLAG_ISRAM 0x2000 /* FIXME: this is a RAM partition? */ ++#define PARTIIION_FLAG_RAMLOAD 0x1000 /* FIXME: load this partition into the RAM? */ ++#define PARTITION_FLAG_PRELOAD 0x0800 /* the partition data preloaded to RAM ++ * before decompression */ ++#define PARTITION_FLAG_LZMA 0x0100 /* partition data compressed by LZMA */ ++#define PARTITION_FLAG_HAVEHDR 0x0002 /* the partition data have a header */ ++ ++#define PARTITION_TYPE_FREE 0 ++#define PARTITION_TYPE_USED 1 ++ ++#define MYLO_MAX_PARTITIONS 8 /* maximum number of partitions in the ++ partition table */ ++ ++struct mylo_partition_table { ++ uint32_t magic; /* must be MYLO_MAGIC_PARTITIONS */ ++ uint32_t res0; /* unknown/unused */ ++ uint32_t res1; /* unknown/unused */ ++ uint32_t res2; /* unknown/unused */ ++ struct mylo_partition partitions[MYLO_MAX_PARTITIONS]; ++}; ++ ++struct mylo_partition_header { ++ uint32_t len; /* length of the partition data */ ++ uint32_t crc; /* CRC value of the partition data */ ++}; ++ ++struct mylo_system_params { ++ uint32_t magic; /* must be MYLO_MAGIC_SYS_PARAMS */ ++ uint32_t res0; ++ uint32_t res1; ++ uint32_t mylo_ver; ++ uint16_t vid; /* Vendor ID */ ++ uint16_t did; /* Device ID */ ++ uint16_t svid; /* Sub Vendor ID */ ++ uint16_t sdid; /* Sub Device ID */ ++ uint32_t rev; /* device revision */ ++ uint32_t fwhi; ++ uint32_t fwlo; ++ uint32_t tftp_addr; ++ uint32_t prog_start; ++ uint32_t flash_size; /* size of boot FLASH in bytes */ ++ uint32_t dram_size; /* size of onboard RAM in bytes */ ++}; ++ ++struct mylo_eth_addr { ++ uint8_t mac[6]; ++ uint8_t csum[2]; ++}; ++ ++#define MYLO_ETHADDR_COUNT 8 /* maximum number of ethernet address ++ in the board parameters */ ++ ++struct mylo_board_params { ++ uint32_t magic; /* must be MYLO_MAGIC_BOARD_PARAMS */ ++ uint32_t res0; ++ uint32_t res1; ++ uint32_t res2; ++ struct mylo_eth_addr addr[MYLO_ETHADDR_COUNT]; ++}; ++ ++#endif /* _MYLOADER_H_*/ +diff --git a/include/linux/platform_data/adm6996-gpio.h b/include/linux/platform_data/adm6996-gpio.h +new file mode 100644 +index 000000000000..d5af9bbf6e55 +--- /dev/null ++++ b/include/linux/platform_data/adm6996-gpio.h +@@ -0,0 +1,29 @@ ++/* ++ * ADM6996 GPIO platform data ++ * ++ * Copyright (C) 2013 Hauke Mehrtens ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License v2 as published by the ++ * Free Software Foundation ++ */ ++ ++#ifndef __PLATFORM_ADM6996_GPIO_H ++#define __PLATFORM_ADM6996_GPIO_H ++ ++#include ++ ++enum adm6996_model { ++ ADM6996FC = 1, ++ ADM6996M = 2, ++ ADM6996L = 3, ++}; ++ ++struct adm6996_gpio_platform_data { ++ u8 eecs; ++ u8 eesk; ++ u8 eedi; ++ enum adm6996_model model; ++}; ++ ++#endif +diff --git a/include/linux/routerboot.h b/include/linux/routerboot.h +new file mode 100644 +index 000000000000..3cda858cf9c2 +--- /dev/null ++++ b/include/linux/routerboot.h +@@ -0,0 +1,106 @@ ++/* ++ * Mikrotik's RouterBOOT definitions ++ * ++ * Copyright (C) 2007-2008 Gabor Juhos ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation. ++ * ++ */ ++ ++#ifndef _ROUTERBOOT_H ++#define _ROUTERBOOT_H ++ ++#define RB_MAC_SIZE 6 ++ ++/* ++ * Magic numbers ++ */ ++#define RB_MAGIC_HARD 0x64726148 /* "Hard" */ ++#define RB_MAGIC_SOFT 0x74666F53 /* "Soft" */ ++#define RB_MAGIC_DAWN 0x6E776144 /* "Dawn" */ ++ ++#define RB_ID_TERMINATOR 0 ++ ++/* ++ * ID values for Hardware settings ++ */ ++#define RB_ID_HARD_01 1 ++#define RB_ID_HARD_02 2 ++#define RB_ID_FLASH_INFO 3 ++#define RB_ID_MAC_ADDRESS_PACK 4 ++#define RB_ID_BOARD_NAME 5 ++#define RB_ID_BIOS_VERSION 6 ++#define RB_ID_HARD_07 7 ++#define RB_ID_SDRAM_TIMINGS 8 ++#define RB_ID_DEVICE_TIMINGS 9 ++#define RB_ID_SOFTWARE_ID 10 ++#define RB_ID_SERIAL_NUMBER 11 ++#define RB_ID_HARD_12 12 ++#define RB_ID_MEMORY_SIZE 13 ++#define RB_ID_MAC_ADDRESS_COUNT 14 ++#define RB_ID_HW_OPTIONS 21 ++#define RB_ID_WLAN_DATA 22 ++ ++/* ++ * ID values for Software settings ++ */ ++#define RB_ID_UART_SPEED 1 ++#define RB_ID_BOOT_DELAY 2 ++#define RB_ID_BOOT_DEVICE 3 ++#define RB_ID_BOOT_KEY 4 ++#define RB_ID_CPU_MODE 5 ++#define RB_ID_FW_VERSION 6 ++#define RB_ID_SOFT_07 7 ++#define RB_ID_SOFT_08 8 ++#define RB_ID_BOOT_PROTOCOL 9 ++#define RB_ID_SOFT_10 10 ++#define RB_ID_SOFT_11 11 ++ ++/* ++ * UART_SPEED values ++ */ ++#define RB_UART_SPEED_115200 0 ++#define RB_UART_SPEED_57600 1 ++#define RB_UART_SPEED_38400 2 ++#define RB_UART_SPEED_19200 3 ++#define RB_UART_SPEED_9600 4 ++#define RB_UART_SPEED_4800 5 ++#define RB_UART_SPEED_2400 6 ++#define RB_UART_SPEED_1200 7 ++ ++/* ++ * BOOT_DELAY values ++ */ ++#define RB_BOOT_DELAY_0SEC 0 ++#define RB_BOOT_DELAY_1SEC 1 ++#define RB_BOOT_DELAY_2SEC 2 ++ ++/* ++ * BOOT_DEVICE values ++ */ ++#define RB_BOOT_DEVICE_ETHER 0 ++#define RB_BOOT_DEVICE_NANDETH 1 ++#define RB_BOOT_DEVICE_ETHONCE 2 ++#define RB_BOOT_DEVICE_NANDONLY 3 ++ ++/* ++ * BOOT_KEY values ++ */ ++#define RB_BOOT_KEY_ANY 0 ++#define RB_BOOT_KEY_DEL 1 ++ ++/* ++ * CPU_MODE values ++ */ ++#define RB_CPU_MODE_POWERSAVE 0 ++#define RB_CPU_MODE_REGULAR 1 ++ ++/* ++ * BOOT_PROTOCOL values ++ */ ++#define RB_BOOT_PROTOCOL_BOOTP 0 ++#define RB_BOOT_PROTOCOL_DHCP 1 ++ ++#endif /* _ROUTERBOOT_H */ +diff --git a/include/linux/rtl8366.h b/include/linux/rtl8366.h +new file mode 100644 +index 000000000000..e3ce8f5361eb +--- /dev/null ++++ b/include/linux/rtl8366.h +@@ -0,0 +1,42 @@ ++/* ++ * Platform data definition for the Realtek RTL8366RB/S ethernet switch driver ++ * ++ * Copyright (C) 2009-2010 Gabor Juhos ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation. ++ */ ++ ++#ifndef _RTL8366_H ++#define _RTL8366_H ++ ++#define RTL8366_DRIVER_NAME "rtl8366" ++#define RTL8366S_DRIVER_NAME "rtl8366s" ++#define RTL8366RB_DRIVER_NAME "rtl8366rb" ++ ++struct rtl8366_smi; ++ ++enum rtl8366_type { ++ RTL8366_TYPE_UNKNOWN, ++ RTL8366_TYPE_S, ++ RTL8366_TYPE_RB, ++}; ++ ++struct rtl8366_initval { ++ unsigned reg; ++ u16 val; ++}; ++ ++struct rtl8366_platform_data { ++ unsigned gpio_sda; ++ unsigned gpio_sck; ++ void (*hw_reset)(struct rtl8366_smi *smi, bool active); ++ ++ unsigned num_initvals; ++ struct rtl8366_initval *initvals; ++}; ++ ++enum rtl8366_type rtl8366_smi_detect(struct rtl8366_platform_data *pdata); ++ ++#endif /* _RTL8366_H */ +diff --git a/include/linux/rtl8367.h b/include/linux/rtl8367.h +new file mode 100644 +index 000000000000..14150393e280 +--- /dev/null ++++ b/include/linux/rtl8367.h +@@ -0,0 +1,63 @@ ++/* ++ * Platform data definition for the Realtek RTL8367 ethernet switch driver ++ * ++ * Copyright (C) 2011 Gabor Juhos ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation. ++ */ ++ ++#ifndef _RTL8367_H ++#define _RTL8367_H ++ ++#define RTL8367_DRIVER_NAME "rtl8367" ++#define RTL8367B_DRIVER_NAME "rtl8367b" ++ ++enum rtl8367_port_speed { ++ RTL8367_PORT_SPEED_10 = 0, ++ RTL8367_PORT_SPEED_100, ++ RTL8367_PORT_SPEED_1000, ++}; ++ ++struct rtl8367_port_ability { ++ int force_mode; ++ int nway; ++ int txpause; ++ int rxpause; ++ int link; ++ int duplex; ++ enum rtl8367_port_speed speed; ++}; ++ ++enum rtl8367_extif_mode { ++ RTL8367_EXTIF_MODE_DISABLED = 0, ++ RTL8367_EXTIF_MODE_RGMII, ++ RTL8367_EXTIF_MODE_MII_MAC, ++ RTL8367_EXTIF_MODE_MII_PHY, ++ RTL8367_EXTIF_MODE_TMII_MAC, ++ RTL8367_EXTIF_MODE_TMII_PHY, ++ RTL8367_EXTIF_MODE_GMII, ++ RTL8367_EXTIF_MODE_RGMII_33V, ++ RTL8367B_EXTIF_MODE_RMII_MAC = 7, ++ RTL8367B_EXTIF_MODE_RMII_PHY, ++ RTL8367B_EXTIF_MODE_RGMII_33V, ++}; ++ ++struct rtl8367_extif_config { ++ unsigned int txdelay; ++ unsigned int rxdelay; ++ enum rtl8367_extif_mode mode; ++ struct rtl8367_port_ability ability; ++}; ++ ++struct rtl8367_platform_data { ++ unsigned gpio_sda; ++ unsigned gpio_sck; ++ void (*hw_reset)(bool active); ++ ++ struct rtl8367_extif_config *extif0_cfg; ++ struct rtl8367_extif_config *extif1_cfg; ++}; ++ ++#endif /* _RTL8367_H */ +diff --git a/include/linux/switch.h b/include/linux/switch.h +new file mode 100644 +index 000000000000..4e6238470d30 +--- /dev/null ++++ b/include/linux/switch.h +@@ -0,0 +1,179 @@ ++/* ++ * switch.h: Switch configuration API ++ * ++ * Copyright (C) 2008 Felix Fietkau ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version 2 ++ * of the License, or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++#ifndef _LINUX_SWITCH_H ++#define _LINUX_SWITCH_H ++ ++#include ++#include ++ ++struct switch_dev; ++struct switch_op; ++struct switch_val; ++struct switch_attr; ++struct switch_attrlist; ++struct switch_led_trigger; ++ ++int register_switch(struct switch_dev *dev, struct net_device *netdev); ++void unregister_switch(struct switch_dev *dev); ++ ++/** ++ * struct switch_attrlist - attribute list ++ * ++ * @n_attr: number of attributes ++ * @attr: pointer to the attributes array ++ */ ++struct switch_attrlist { ++ int n_attr; ++ const struct switch_attr *attr; ++}; ++ ++enum switch_port_speed { ++ SWITCH_PORT_SPEED_UNKNOWN = 0, ++ SWITCH_PORT_SPEED_10 = 10, ++ SWITCH_PORT_SPEED_100 = 100, ++ SWITCH_PORT_SPEED_1000 = 1000, ++}; ++ ++struct switch_port_link { ++ bool link; ++ bool duplex; ++ bool aneg; ++ bool tx_flow; ++ bool rx_flow; ++ enum switch_port_speed speed; ++ /* in ethtool adv_t format */ ++ u32 eee; ++}; ++ ++struct switch_port_stats { ++ unsigned long long tx_bytes; ++ unsigned long long rx_bytes; ++}; ++ ++/** ++ * struct switch_dev_ops - switch driver operations ++ * ++ * @attr_global: global switch attribute list ++ * @attr_port: port attribute list ++ * @attr_vlan: vlan attribute list ++ * ++ * Callbacks: ++ * ++ * @get_vlan_ports: read the port list of a VLAN ++ * @set_vlan_ports: set the port list of a VLAN ++ * ++ * @get_port_pvid: get the primary VLAN ID of a port ++ * @set_port_pvid: set the primary VLAN ID of a port ++ * ++ * @apply_config: apply all changed settings to the switch ++ * @reset_switch: resetting the switch ++ */ ++struct switch_dev_ops { ++ struct switch_attrlist attr_global, attr_port, attr_vlan; ++ ++ int (*get_vlan_ports)(struct switch_dev *dev, struct switch_val *val); ++ int (*set_vlan_ports)(struct switch_dev *dev, struct switch_val *val); ++ ++ int (*get_port_pvid)(struct switch_dev *dev, int port, int *val); ++ int (*set_port_pvid)(struct switch_dev *dev, int port, int val); ++ ++ int (*apply_config)(struct switch_dev *dev); ++ int (*reset_switch)(struct switch_dev *dev); ++ ++ int (*get_port_link)(struct switch_dev *dev, int port, ++ struct switch_port_link *link); ++ int (*set_port_link)(struct switch_dev *dev, int port, ++ struct switch_port_link *link); ++ int (*get_port_stats)(struct switch_dev *dev, int port, ++ struct switch_port_stats *stats); ++ ++ int (*phy_read16)(struct switch_dev *dev, int addr, u8 reg, u16 *value); ++ int (*phy_write16)(struct switch_dev *dev, int addr, u8 reg, u16 value); ++}; ++ ++struct switch_dev { ++ struct device_node *of_node; ++ const struct switch_dev_ops *ops; ++ /* will be automatically filled */ ++ char devname[IFNAMSIZ]; ++ ++ const char *name; ++ /* NB: either alias or netdev must be set */ ++ const char *alias; ++ struct net_device *netdev; ++ ++ unsigned int ports; ++ unsigned int vlans; ++ unsigned int cpu_port; ++ ++ /* the following fields are internal for swconfig */ ++ unsigned int id; ++ struct list_head dev_list; ++ unsigned long def_global, def_port, def_vlan; ++ ++ struct mutex sw_mutex; ++ struct switch_port *portbuf; ++ struct switch_portmap *portmap; ++ struct switch_port_link linkbuf; ++ ++ char buf[128]; ++ ++#ifdef CONFIG_SWCONFIG_LEDS ++ struct switch_led_trigger *led_trigger; ++#endif ++}; ++ ++struct switch_port { ++ u32 id; ++ u32 flags; ++}; ++ ++struct switch_portmap { ++ u32 virt; ++ const char *s; ++}; ++ ++struct switch_val { ++ const struct switch_attr *attr; ++ unsigned int port_vlan; ++ unsigned int len; ++ union { ++ const char *s; ++ u32 i; ++ struct switch_port *ports; ++ struct switch_port_link *link; ++ } value; ++}; ++ ++struct switch_attr { ++ int disabled; ++ int type; ++ const char *name; ++ const char *description; ++ ++ int (*set)(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val); ++ int (*get)(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val); ++ ++ /* for driver internal use */ ++ int id; ++ int ofs; ++ int max; ++}; ++ ++int switch_generic_set_link(struct switch_dev *dev, int port, ++ struct switch_port_link *link); ++ ++#endif /* _LINUX_SWITCH_H */ +diff --git a/include/uapi/linux/switch.h b/include/uapi/linux/switch.h +new file mode 100644 +index 000000000000..ea449653fafa +--- /dev/null ++++ b/include/uapi/linux/switch.h +@@ -0,0 +1,119 @@ ++/* ++ * switch.h: Switch configuration API ++ * ++ * Copyright (C) 2008 Felix Fietkau ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version 2 ++ * of the License, or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#ifndef _UAPI_LINUX_SWITCH_H ++#define _UAPI_LINUX_SWITCH_H ++ ++#include ++#include ++#include ++#include ++#ifndef __KERNEL__ ++#include ++#include ++#include ++#endif ++ ++/* main attributes */ ++enum { ++ SWITCH_ATTR_UNSPEC, ++ /* global */ ++ SWITCH_ATTR_TYPE, ++ /* device */ ++ SWITCH_ATTR_ID, ++ SWITCH_ATTR_DEV_NAME, ++ SWITCH_ATTR_ALIAS, ++ SWITCH_ATTR_NAME, ++ SWITCH_ATTR_VLANS, ++ SWITCH_ATTR_PORTS, ++ SWITCH_ATTR_PORTMAP, ++ SWITCH_ATTR_CPU_PORT, ++ /* attributes */ ++ SWITCH_ATTR_OP_ID, ++ SWITCH_ATTR_OP_TYPE, ++ SWITCH_ATTR_OP_NAME, ++ SWITCH_ATTR_OP_PORT, ++ SWITCH_ATTR_OP_VLAN, ++ SWITCH_ATTR_OP_VALUE_INT, ++ SWITCH_ATTR_OP_VALUE_STR, ++ SWITCH_ATTR_OP_VALUE_PORTS, ++ SWITCH_ATTR_OP_VALUE_LINK, ++ SWITCH_ATTR_OP_DESCRIPTION, ++ /* port lists */ ++ SWITCH_ATTR_PORT, ++ SWITCH_ATTR_MAX ++}; ++ ++enum { ++ /* port map */ ++ SWITCH_PORTMAP_PORTS, ++ SWITCH_PORTMAP_SEGMENT, ++ SWITCH_PORTMAP_VIRT, ++ SWITCH_PORTMAP_MAX ++}; ++ ++/* commands */ ++enum { ++ SWITCH_CMD_UNSPEC, ++ SWITCH_CMD_GET_SWITCH, ++ SWITCH_CMD_NEW_ATTR, ++ SWITCH_CMD_LIST_GLOBAL, ++ SWITCH_CMD_GET_GLOBAL, ++ SWITCH_CMD_SET_GLOBAL, ++ SWITCH_CMD_LIST_PORT, ++ SWITCH_CMD_GET_PORT, ++ SWITCH_CMD_SET_PORT, ++ SWITCH_CMD_LIST_VLAN, ++ SWITCH_CMD_GET_VLAN, ++ SWITCH_CMD_SET_VLAN ++}; ++ ++/* data types */ ++enum switch_val_type { ++ SWITCH_TYPE_UNSPEC, ++ SWITCH_TYPE_INT, ++ SWITCH_TYPE_STRING, ++ SWITCH_TYPE_PORTS, ++ SWITCH_TYPE_LINK, ++ SWITCH_TYPE_NOVAL, ++}; ++ ++/* port nested attributes */ ++enum { ++ SWITCH_PORT_UNSPEC, ++ SWITCH_PORT_ID, ++ SWITCH_PORT_FLAG_TAGGED, ++ SWITCH_PORT_ATTR_MAX ++}; ++ ++/* link nested attributes */ ++enum { ++ SWITCH_LINK_UNSPEC, ++ SWITCH_LINK_FLAG_LINK, ++ SWITCH_LINK_FLAG_DUPLEX, ++ SWITCH_LINK_FLAG_ANEG, ++ SWITCH_LINK_FLAG_TX_FLOW, ++ SWITCH_LINK_FLAG_RX_FLOW, ++ SWITCH_LINK_SPEED, ++ SWITCH_LINK_FLAG_EEE_100BASET, ++ SWITCH_LINK_FLAG_EEE_1000BASET, ++ SWITCH_LINK_ATTR_MAX, ++}; ++ ++#define SWITCH_ATTR_DEFAULTS_OFFSET 0x1000 ++ ++ ++#endif /* _UAPI_LINUX_SWITCH_H */ +-- +2.51.0 + + +From 99a7ee0f062c7ea20d18a364a824e63cd95c637a Mon Sep 17 00:00:00 2001 +From: Easwar Hariharan +Date: Wed, 30 Oct 2024 17:47:35 +0000 +Subject: [PATCH 002/517] jiffies: Define secs_to_jiffies() + +secs_to_jiffies() is defined in hci_event.c and cannot be reused by +other call sites. Hoist it into the core code to allow conversion of the +~1150 usages of msecs_to_jiffies() that either: + + - use a multiplier value of 1000 or equivalently MSEC_PER_SEC, or + - have timeouts that are denominated in seconds (i.e. end in 000) + +It's implemented as a macro to allow usage in static initializers. + +This will also allow conversion of yet more sites that use (sec * HZ) +directly, and improve their readability. + +Suggested-by: Michael Kelley +Signed-off-by: Easwar Hariharan +Signed-off-by: Thomas Gleixner +Reviewed-by: Luiz Augusto von Dentz +Link: https://lore.kernel.org/all/20241030-open-coded-timeouts-v3-1-9ba123facf88@linux.microsoft.com +--- + include/linux/jiffies.h | 13 +++++++++++++ + net/bluetooth/hci_event.c | 2 -- + 2 files changed, 13 insertions(+), 2 deletions(-) + +diff --git a/include/linux/jiffies.h b/include/linux/jiffies.h +index 5d21dacd62bc..ed945f42e064 100644 +--- a/include/linux/jiffies.h ++++ b/include/linux/jiffies.h +@@ -526,6 +526,19 @@ static __always_inline unsigned long msecs_to_jiffies(const unsigned int m) + } + } + ++/** ++ * secs_to_jiffies: - convert seconds to jiffies ++ * @_secs: time in seconds ++ * ++ * Conversion is done by simple multiplication with HZ ++ * ++ * secs_to_jiffies() is defined as a macro rather than a static inline ++ * function so it can be used in static initializers. ++ * ++ * Return: jiffies value ++ */ ++#define secs_to_jiffies(_secs) ((_secs) * HZ) ++ + extern unsigned long __usecs_to_jiffies(const unsigned int u); + #if !(USEC_PER_SEC % HZ) + static inline unsigned long _usecs_to_jiffies(const unsigned int u) +diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c +index 1e537ed83ba4..fdaaaf541cac 100644 +--- a/net/bluetooth/hci_event.c ++++ b/net/bluetooth/hci_event.c +@@ -42,8 +42,6 @@ + #define ZERO_KEY "\x00\x00\x00\x00\x00\x00\x00\x00" \ + "\x00\x00\x00\x00\x00\x00\x00\x00" + +-#define secs_to_jiffies(_secs) msecs_to_jiffies((_secs) * 1000) +- + /* Handle HCI Event packets */ + + static void *hci_ev_skb_pull(struct hci_dev *hdev, struct sk_buff *skb, +-- +2.51.0 + + +From 53a192c572edbbdfc84567d1e5d6c9b443186755 Mon Sep 17 00:00:00 2001 +From: Easwar Hariharan +Date: Thu, 30 Jan 2025 19:26:58 +0000 +Subject: [PATCH 003/517] jiffies: Cast to unsigned long in secs_to_jiffies() + conversion + +While converting users of msecs_to_jiffies(), lkp reported that some range +checks would always be true because of the mismatch between the implied int +value of secs_to_jiffies() vs the unsigned long return value of the +msecs_to_jiffies() calls it was replacing. + +Fix this by casting the secs_to_jiffies() input value to unsigned long. + +Fixes: b35108a51cf7ba ("jiffies: Define secs_to_jiffies()") +Reported-by: kernel test robot +Signed-off-by: Easwar Hariharan +Signed-off-by: Thomas Gleixner +Cc: stable@vger.kernel.org +Link: https://lore.kernel.org/all/20250130192701.99626-1-eahariha@linux.microsoft.com +Closes: https://lore.kernel.org/oe-kbuild-all/202501301334.NB6NszQR-lkp@intel.com/ +--- + include/linux/jiffies.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/include/linux/jiffies.h b/include/linux/jiffies.h +index ed945f42e064..0ea8c9887429 100644 +--- a/include/linux/jiffies.h ++++ b/include/linux/jiffies.h +@@ -537,7 +537,7 @@ static __always_inline unsigned long msecs_to_jiffies(const unsigned int m) + * + * Return: jiffies value + */ +-#define secs_to_jiffies(_secs) ((_secs) * HZ) ++#define secs_to_jiffies(_secs) (unsigned long)((_secs) * HZ) + + extern unsigned long __usecs_to_jiffies(const unsigned int u); + #if !(USEC_PER_SEC % HZ) +-- +2.51.0 + + +From 49b181f4b38d468ce212fe2926334a12260893d9 Mon Sep 17 00:00:00 2001 +From: Kuninori Morimoto +Date: Thu, 24 Oct 2024 02:20:02 +0000 +Subject: [PATCH 004/517] of: property: add of_graph_get_next_port() + +We have endpoint base functions + - of_graph_get_next_endpoint() + - of_graph_get_endpoint_count() + - for_each_endpoint_of_node() + +Here, for_each_endpoint_of_node() loop finds each endpoints + + ports { + port@0 { +(1) endpoint {...}; + }; + port@1 { +(2) endpoint {...}; + }; + ... + }; + +In above case, it finds endpoint as (1) -> (2) -> ... + +Basically, user/driver knows which port is used for what, but not in +all cases. For example on flexible/generic driver case, how many ports +are used is not fixed. + +For example Sound Generic Card driver which is very flexible/generic and +used from many venders can't know how many ports are used, and used for +what, because it depends on each vender SoC and/or its used board. + +And more, the port can have multi endpoints. For example Generic Sound +Card case, it supports many type of connection between CPU / Codec, and +some of them uses multi endpoint in one port. see below. + + ports { +(A) port@0 { +(1) endpoint@0 {...}; +(2) endpoint@1 {...}; + }; +(B) port@1 { +(3) endpoint {...}; + }; + ... + }; + +Generic Sound Card want to handle each connection via "port" base instead +of "endpoint" base. But, it is very difficult to handle each "port" via +existing for_each_endpoint_of_node(). Because getting each "port" via +of_get_parent() from each "endpoint" doesn't work. For example in above +case, both (1) (2) endpoint has same "port" (= A). + +Add "port" base functions. + +Signed-off-by: Kuninori Morimoto +Link: https://lore.kernel.org/r/87ldyeb5t9.wl-kuninori.morimoto.gx@renesas.com +Signed-off-by: Rob Herring (Arm) +--- + drivers/of/property.c | 54 ++++++++++++++++++++++++++++++++++++++++ + include/linux/of_graph.h | 28 +++++++++++++++++++++ + 2 files changed, 82 insertions(+) + +diff --git a/drivers/of/property.c b/drivers/of/property.c +index 906a33ae717f..7c8fb5dd4cb1 100644 +--- a/drivers/of/property.c ++++ b/drivers/of/property.c +@@ -630,6 +630,43 @@ struct device_node *of_graph_get_port_by_id(struct device_node *parent, u32 id) + } + EXPORT_SYMBOL(of_graph_get_port_by_id); + ++/** ++ * of_graph_get_next_port() - get next port node. ++ * @parent: pointer to the parent device node, or parent ports node ++ * @prev: previous port node, or NULL to get first ++ * ++ * Parent device node can be used as @parent whether device node has ports node ++ * or not. It will work same as ports@0 node. ++ * ++ * Return: A 'port' node pointer with refcount incremented. Refcount ++ * of the passed @prev node is decremented. ++ */ ++struct device_node *of_graph_get_next_port(const struct device_node *parent, ++ struct device_node *prev) ++{ ++ if (!parent) ++ return NULL; ++ ++ if (!prev) { ++ struct device_node *node __free(device_node) = ++ of_get_child_by_name(parent, "ports"); ++ ++ if (node) ++ parent = node; ++ ++ return of_get_child_by_name(parent, "port"); ++ } ++ ++ do { ++ prev = of_get_next_child(parent, prev); ++ if (!prev) ++ break; ++ } while (!of_node_name_eq(prev, "port")); ++ ++ return prev; ++} ++EXPORT_SYMBOL(of_graph_get_next_port); ++ + /** + * of_graph_get_next_endpoint() - get next endpoint node + * @parent: pointer to the parent device node +@@ -823,6 +860,23 @@ unsigned int of_graph_get_endpoint_count(const struct device_node *np) + } + EXPORT_SYMBOL(of_graph_get_endpoint_count); + ++/** ++ * of_graph_get_port_count() - get the number of port in a device or ports node ++ * @np: pointer to the device or ports node ++ * ++ * Return: count of port of this device or ports node ++ */ ++unsigned int of_graph_get_port_count(struct device_node *np) ++{ ++ unsigned int num = 0; ++ ++ for_each_of_graph_port(np, port) ++ num++; ++ ++ return num; ++} ++EXPORT_SYMBOL(of_graph_get_port_count); ++ + /** + * of_graph_get_remote_node() - get remote parent device_node for given port/endpoint + * @node: pointer to parent device_node containing graph port/endpoint +diff --git a/include/linux/of_graph.h b/include/linux/of_graph.h +index a4bea62bfa29..44518f3583a4 100644 +--- a/include/linux/of_graph.h ++++ b/include/linux/of_graph.h +@@ -11,6 +11,7 @@ + #ifndef __LINUX_OF_GRAPH_H + #define __LINUX_OF_GRAPH_H + ++#include + #include + #include + +@@ -37,14 +38,29 @@ struct of_endpoint { + for (child = of_graph_get_next_endpoint(parent, NULL); child != NULL; \ + child = of_graph_get_next_endpoint(parent, child)) + ++/** ++ * for_each_of_graph_port - iterate over every port in a device or ports node ++ * @parent: parent device or ports node containing port ++ * @child: loop variable pointing to the current port node ++ * ++ * When breaking out of the loop, and continue to use the @child, you need to ++ * use return_ptr(@child) or no_free_ptr(@child) not to call __free() for it. ++ */ ++#define for_each_of_graph_port(parent, child) \ ++ for (struct device_node *child __free(device_node) = of_graph_get_next_port(parent, NULL);\ ++ child != NULL; child = of_graph_get_next_port(parent, child)) ++ + #ifdef CONFIG_OF + bool of_graph_is_present(const struct device_node *node); + int of_graph_parse_endpoint(const struct device_node *node, + struct of_endpoint *endpoint); + unsigned int of_graph_get_endpoint_count(const struct device_node *np); ++unsigned int of_graph_get_port_count(struct device_node *np); + struct device_node *of_graph_get_port_by_id(struct device_node *node, u32 id); + struct device_node *of_graph_get_next_endpoint(const struct device_node *parent, + struct device_node *previous); ++struct device_node *of_graph_get_next_port(const struct device_node *parent, ++ struct device_node *port); + struct device_node *of_graph_get_endpoint_by_regs( + const struct device_node *parent, int port_reg, int reg); + struct device_node *of_graph_get_remote_endpoint( +@@ -73,6 +89,11 @@ static inline unsigned int of_graph_get_endpoint_count(const struct device_node + return 0; + } + ++static inline unsigned int of_graph_get_port_count(struct device_node *np) ++{ ++ return 0; ++} ++ + static inline struct device_node *of_graph_get_port_by_id( + struct device_node *node, u32 id) + { +@@ -86,6 +107,13 @@ static inline struct device_node *of_graph_get_next_endpoint( + return NULL; + } + ++static inline struct device_node *of_graph_get_next_port( ++ const struct device_node *parent, ++ struct device_node *previous) ++{ ++ return NULL; ++} ++ + static inline struct device_node *of_graph_get_endpoint_by_regs( + const struct device_node *parent, int port_reg, int reg) + { +-- +2.51.0 + + +From 380cec7c796666f368f79a4059b3b7533bc5afd9 Mon Sep 17 00:00:00 2001 +From: Cristian Ciocaltea +Date: Sat, 19 Oct 2024 14:16:00 +0300 +Subject: [PATCH 005/517] clk: Provide devm_clk_bulk_get_all_enabled() helper + +Commit 265b07df758a ("clk: Provide managed helper to get and enable bulk +clocks") added devm_clk_bulk_get_all_enable() function, but missed to +return the number of clocks stored in the clk_bulk_data table referenced +by the clks argument. Without knowing the number, it's not possible to +iterate these clocks when needed, hence the argument is useless and +could have been simply removed. + +Introduce devm_clk_bulk_get_all_enabled() variant, which is consistent +with devm_clk_bulk_get_all() in terms of the returned value: + + > 0 if one or more clocks have been stored + = 0 if there are no clocks + < 0 if an error occurred + +Moreover, the naming is consistent with devm_clk_get_enabled(), i.e. use +the past form of 'enable'. + +To reduce code duplication and improve patch readability, make +devm_clk_bulk_get_all_enable() use the new helper, as suggested by +Stephen Boyd. + +Reviewed-by: AngeloGioacchino Del Regno +Reviewed-by: Manivannan Sadhasivam +Signed-off-by: Cristian Ciocaltea +Link: https://lore.kernel.org/r/20241019-clk_bulk_ena_fix-v4-1-57f108f64e70@collabora.com +Signed-off-by: Stephen Boyd +--- + drivers/clk/clk-devres.c | 9 +++++---- + include/linux/clk.h | 21 ++++++++++++++++----- + 2 files changed, 21 insertions(+), 9 deletions(-) + +diff --git a/drivers/clk/clk-devres.c b/drivers/clk/clk-devres.c +index 82ae1f26e634..5368d92d9b39 100644 +--- a/drivers/clk/clk-devres.c ++++ b/drivers/clk/clk-devres.c +@@ -218,8 +218,8 @@ static void devm_clk_bulk_release_all_enable(struct device *dev, void *res) + clk_bulk_put_all(devres->num_clks, devres->clks); + } + +-int __must_check devm_clk_bulk_get_all_enable(struct device *dev, +- struct clk_bulk_data **clks) ++int __must_check devm_clk_bulk_get_all_enabled(struct device *dev, ++ struct clk_bulk_data **clks) + { + struct clk_bulk_devres *devres; + int ret; +@@ -244,11 +244,12 @@ int __must_check devm_clk_bulk_get_all_enable(struct device *dev, + } else { + clk_bulk_put_all(devres->num_clks, devres->clks); + devres_free(devres); ++ return ret; + } + +- return ret; ++ return devres->num_clks; + } +-EXPORT_SYMBOL_GPL(devm_clk_bulk_get_all_enable); ++EXPORT_SYMBOL_GPL(devm_clk_bulk_get_all_enabled); + + static int devm_clk_match(struct device *dev, void *res, void *data) + { +diff --git a/include/linux/clk.h b/include/linux/clk.h +index 851a0f2cf42c..1dcee6d701e4 100644 +--- a/include/linux/clk.h ++++ b/include/linux/clk.h +@@ -496,11 +496,13 @@ int __must_check devm_clk_bulk_get_all(struct device *dev, + struct clk_bulk_data **clks); + + /** +- * devm_clk_bulk_get_all_enable - Get and enable all clocks of the consumer (managed) ++ * devm_clk_bulk_get_all_enabled - Get and enable all clocks of the consumer (managed) + * @dev: device for clock "consumer" + * @clks: pointer to the clk_bulk_data table of consumer + * +- * Returns success (0) or negative errno. ++ * Returns a positive value for the number of clocks obtained while the ++ * clock references are stored in the clk_bulk_data table in @clks field. ++ * Returns 0 if there're none and a negative value if something failed. + * + * This helper function allows drivers to get all clocks of the + * consumer and enables them in one operation with management. +@@ -508,8 +510,8 @@ int __must_check devm_clk_bulk_get_all(struct device *dev, + * is unbound. + */ + +-int __must_check devm_clk_bulk_get_all_enable(struct device *dev, +- struct clk_bulk_data **clks); ++int __must_check devm_clk_bulk_get_all_enabled(struct device *dev, ++ struct clk_bulk_data **clks); + + /** + * devm_clk_get - lookup and obtain a managed reference to a clock producer. +@@ -1034,7 +1036,7 @@ static inline int __must_check devm_clk_bulk_get_all(struct device *dev, + return 0; + } + +-static inline int __must_check devm_clk_bulk_get_all_enable(struct device *dev, ++static inline int __must_check devm_clk_bulk_get_all_enabled(struct device *dev, + struct clk_bulk_data **clks) + { + return 0; +@@ -1136,6 +1138,15 @@ static inline void clk_restore_context(void) {} + + #endif + ++/* Deprecated. Use devm_clk_bulk_get_all_enabled() */ ++static inline int __must_check ++devm_clk_bulk_get_all_enable(struct device *dev, struct clk_bulk_data **clks) ++{ ++ int ret = devm_clk_bulk_get_all_enabled(dev, clks); ++ ++ return ret > 0 ? 0 : ret; ++} ++ + /* clk_prepare_enable helps cases using clk_enable in non-atomic context. */ + static inline int clk_prepare_enable(struct clk *clk) + { +-- +2.51.0 + + +From 15d25ea31ecbcaa422e8a49831e06e0b78af0037 Mon Sep 17 00:00:00 2001 +From: Kees Cook +Date: Thu, 12 Dec 2024 17:28:06 -0800 +Subject: [PATCH 006/517] fortify: Hide run-time copy size from value range + tracking +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +GCC performs value range tracking for variables as a way to provide better +diagnostics. One place this is regularly seen is with warnings associated +with bounds-checking, e.g. -Wstringop-overflow, -Wstringop-overread, +-Warray-bounds, etc. In order to keep the signal-to-noise ratio high, +warnings aren't emitted when a value range spans the entire value range +representable by a given variable. For example: + + unsigned int len; + char dst[8]; + ... + memcpy(dst, src, len); + +If len's value is unknown, it has the full "unsigned int" range of [0, +UINT_MAX], and GCC's compile-time bounds checks against memcpy() will +be ignored. However, when a code path has been able to narrow the range: + + if (len > 16) + return; + memcpy(dst, src, len); + +Then the range will be updated for the execution path. Above, len is +now [0, 16] when reading memcpy(), so depending on other optimizations, +we might see a -Wstringop-overflow warning like: + + error: '__builtin_memcpy' writing between 9 and 16 bytes into region of size 8 [-Werror=stringop-overflow] + +When building with CONFIG_FORTIFY_SOURCE, the fortified run-time bounds +checking can appear to narrow value ranges of lengths for memcpy(), +depending on how the compiler constructs the execution paths during +optimization passes, due to the checks against the field sizes. For +example: + + if (p_size_field != SIZE_MAX && + p_size != p_size_field && p_size_field < size) + +As intentionally designed, these checks only affect the kernel warnings +emitted at run-time and do not block the potentially overflowing memcpy(), +so GCC thinks it needs to produce a warning about the resulting value +range that might be reaching the memcpy(). + +We have seen this manifest a few times now, with the most recent being +with cpumasks: + +In function ‘bitmap_copy’, + inlined from ‘cpumask_copy’ at ./include/linux/cpumask.h:839:2, + inlined from ‘__padata_set_cpumasks’ at kernel/padata.c:730:2: +./include/linux/fortify-string.h:114:33: error: ‘__builtin_memcpy’ reading between 257 and 536870904 bytes from a region of size 256 [-Werror=stringop-overread] + 114 | #define __underlying_memcpy __builtin_memcpy + | ^ +./include/linux/fortify-string.h:633:9: note: in expansion of macro ‘__underlying_memcpy’ + 633 | __underlying_##op(p, q, __fortify_size); \ + | ^~~~~~~~~~~~~ +./include/linux/fortify-string.h:678:26: note: in expansion of macro ‘__fortify_memcpy_chk’ + 678 | #define memcpy(p, q, s) __fortify_memcpy_chk(p, q, s, \ + | ^~~~~~~~~~~~~~~~~~~~ +./include/linux/bitmap.h:259:17: note: in expansion of macro ‘memcpy’ + 259 | memcpy(dst, src, len); + | ^~~~~~ +kernel/padata.c: In function ‘__padata_set_cpumasks’: +kernel/padata.c:713:48: note: source object ‘pcpumask’ of size [0, 256] + 713 | cpumask_var_t pcpumask, + | ~~~~~~~~~~~~~~^~~~~~~~ + +This warning is _not_ emitted when CONFIG_FORTIFY_SOURCE is disabled, +and with the recent -fdiagnostics-details we can confirm the origin of +the warning is due to FORTIFY's bounds checking: + +../include/linux/bitmap.h:259:17: note: in expansion of macro 'memcpy' + 259 | memcpy(dst, src, len); + | ^~~~~~ + '__padata_set_cpumasks': events 1-2 +../include/linux/fortify-string.h:613:36: + 612 | if (p_size_field != SIZE_MAX && + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + 613 | p_size != p_size_field && p_size_field < size) + | ~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~ + | | + | (1) when the condition is evaluated to false + | (2) when the condition is evaluated to true + '__padata_set_cpumasks': event 3 + 114 | #define __underlying_memcpy __builtin_memcpy + | ^ + | | + | (3) out of array bounds here + +Note that the cpumask warning started appearing since bitmap functions +were recently marked __always_inline in commit ed8cd2b3bd9f ("bitmap: +Switch from inline to __always_inline"), which allowed GCC to gain +visibility into the variables as they passed through the FORTIFY +implementation. + +In order to silence these false positives but keep otherwise deterministic +compile-time warnings intact, hide the length variable from GCC with +OPTIMIZE_HIDE_VAR() before calling the builtin memcpy. + +Additionally add a comment about why all the macro args have copies with +const storage. + +Reported-by: "Thomas Weißschuh" +Closes: https://lore.kernel.org/all/db7190c8-d17f-4a0d-bc2f-5903c79f36c2@t-8ch.de/ +Reported-by: Nilay Shroff +Closes: https://lore.kernel.org/all/20241112124127.1666300-1-nilay@linux.ibm.com/ +Tested-by: Nilay Shroff +Acked-by: Yury Norov +Acked-by: Greg Kroah-Hartman +Signed-off-by: Kees Cook +--- + include/linux/fortify-string.h | 14 +++++++++++++- + 1 file changed, 13 insertions(+), 1 deletion(-) + +diff --git a/include/linux/fortify-string.h b/include/linux/fortify-string.h +index 71f9dcf56128..b3b53f8c1b28 100644 +--- a/include/linux/fortify-string.h ++++ b/include/linux/fortify-string.h +@@ -616,6 +616,12 @@ __FORTIFY_INLINE bool fortify_memcpy_chk(__kernel_size_t size, + return false; + } + ++/* ++ * To work around what seems to be an optimizer bug, the macro arguments ++ * need to have const copies or the values end up changed by the time they ++ * reach fortify_warn_once(). See commit 6f7630b1b5bc ("fortify: Capture ++ * __bos() results in const temp vars") for more details. ++ */ + #define __fortify_memcpy_chk(p, q, size, p_size, q_size, \ + p_size_field, q_size_field, op) ({ \ + const size_t __fortify_size = (size_t)(size); \ +@@ -623,6 +629,8 @@ __FORTIFY_INLINE bool fortify_memcpy_chk(__kernel_size_t size, + const size_t __q_size = (q_size); \ + const size_t __p_size_field = (p_size_field); \ + const size_t __q_size_field = (q_size_field); \ ++ /* Keep a mutable version of the size for the final copy. */ \ ++ size_t __copy_size = __fortify_size; \ + fortify_warn_once(fortify_memcpy_chk(__fortify_size, __p_size, \ + __q_size, __p_size_field, \ + __q_size_field, FORTIFY_FUNC_ ##op), \ +@@ -630,7 +638,11 @@ __FORTIFY_INLINE bool fortify_memcpy_chk(__kernel_size_t size, + __fortify_size, \ + "field \"" #p "\" at " FILE_LINE, \ + __p_size_field); \ +- __underlying_##op(p, q, __fortify_size); \ ++ /* Hide only the run-time size from value range tracking to */ \ ++ /* silence compile-time false positive bounds warnings. */ \ ++ if (!__builtin_constant_p(__copy_size)) \ ++ OPTIMIZER_HIDE_VAR(__copy_size); \ ++ __underlying_##op(p, q, __copy_size); \ + }) + + /* +-- +2.51.0 + + +From 377e4603cc60869e907fd2e5c1a16d6749cf0cc0 Mon Sep 17 00:00:00 2001 +From: Bohdan Chubuk +Date: Sun, 10 Nov 2024 22:50:47 +0200 +Subject: [PATCH 007/517] mtd: spinand: add support for FORESEE F35SQA001G + +Add support for FORESEE F35SQA001G SPI NAND. + +Similar to F35SQA002G, but differs in capacity. +Datasheet: + - https://cdn.ozdisan.com/ETicaret_Dosya/704795_871495.pdf + +Tested on Xiaomi AX3000T flashed with OpenWRT. + +Signed-off-by: Bohdan Chubuk +Signed-off-by: Miquel Raynal +--- + drivers/mtd/nand/spi/foresee.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/drivers/mtd/nand/spi/foresee.c b/drivers/mtd/nand/spi/foresee.c +index e0d2d9257045..8a01582c0f53 100644 +--- a/drivers/mtd/nand/spi/foresee.c ++++ b/drivers/mtd/nand/spi/foresee.c +@@ -81,6 +81,16 @@ static const struct spinand_info foresee_spinand_table[] = { + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&f35sqa002g_ooblayout, + f35sqa002g_ecc_get_status)), ++ SPINAND_INFO("F35SQA001G", ++ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x71, 0x71), ++ NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), ++ NAND_ECCREQ(1, 512), ++ SPINAND_INFO_OP_VARIANTS(&read_cache_variants, ++ &write_cache_variants, ++ &update_cache_variants), ++ SPINAND_HAS_QE_BIT, ++ SPINAND_ECCINFO(&f35sqa002g_ooblayout, ++ f35sqa002g_ecc_get_status)), + }; + + static const struct spinand_manufacturer_ops foresee_spinand_manuf_ops = { +-- +2.51.0 + + +From 747b700acdaf801e23257c4de2457df42706bbdb Mon Sep 17 00:00:00 2001 +From: Tianling Shen +Date: Mon, 25 Aug 2025 01:00:13 +0800 +Subject: [PATCH 008/517] mtd: spinand: add support for FudanMicro FM25S01A + +Add support for FudanMicro FM25S01A SPI NAND. +Datasheet: http://eng.fmsh.com/nvm/FM25S01A_ds_eng.pdf + +Signed-off-by: Tianling Shen +Signed-off-by: Miquel Raynal +Link: https://lore.kernel.org/linux-mtd/20250824170013.3328777-1-cnsztl@gmail.com +--- + drivers/mtd/nand/spi/Makefile | 2 +- + drivers/mtd/nand/spi/core.c | 1 + + drivers/mtd/nand/spi/fmsh.c | 74 +++++++++++++++++++++++++++++++++++ + include/linux/mtd/spinand.h | 1 + + 4 files changed, 77 insertions(+), 1 deletion(-) + create mode 100644 drivers/mtd/nand/spi/fmsh.c + +diff --git a/drivers/mtd/nand/spi/Makefile b/drivers/mtd/nand/spi/Makefile +index 19cc77288ebb..32a696055d9f 100644 +--- a/drivers/mtd/nand/spi/Makefile ++++ b/drivers/mtd/nand/spi/Makefile +@@ -1,4 +1,4 @@ + # SPDX-License-Identifier: GPL-2.0 +-spinand-objs := core.o alliancememory.o ato.o esmt.o foresee.o gigadevice.o macronix.o ++spinand-objs := core.o alliancememory.o ato.o esmt.o fmsh.o foresee.o gigadevice.o macronix.o + spinand-objs += micron.o paragon.o toshiba.o winbond.o xtx.o + obj-$(CONFIG_MTD_SPI_NAND) += spinand.o +diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c +index c523a1a22c2b..8e4c825b9789 100644 +--- a/drivers/mtd/nand/spi/core.c ++++ b/drivers/mtd/nand/spi/core.c +@@ -1115,6 +1115,7 @@ static const struct spinand_manufacturer *spinand_manufacturers[] = { + &alliancememory_spinand_manufacturer, + &ato_spinand_manufacturer, + &esmt_c8_spinand_manufacturer, ++ &fmsh_spinand_manufacturer, + &foresee_spinand_manufacturer, + &gigadevice_spinand_manufacturer, + ¯onix_spinand_manufacturer, +diff --git a/drivers/mtd/nand/spi/fmsh.c b/drivers/mtd/nand/spi/fmsh.c +new file mode 100644 +index 000000000000..71922d94f218 +--- /dev/null ++++ b/drivers/mtd/nand/spi/fmsh.c +@@ -0,0 +1,74 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (c) 2020-2021 Rockchip Electronics Co., Ltd. ++ * ++ * Author: Dingqiang Lin ++ */ ++ ++#include ++#include ++#include ++ ++#define SPINAND_MFR_FMSH 0xA1 ++ ++static SPINAND_OP_VARIANTS(read_cache_variants, ++ SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0)); ++ ++static SPINAND_OP_VARIANTS(write_cache_variants, ++ SPINAND_PROG_LOAD_X4(true, 0, NULL, 0), ++ SPINAND_PROG_LOAD(true, 0, NULL, 0)); ++ ++static SPINAND_OP_VARIANTS(update_cache_variants, ++ SPINAND_PROG_LOAD_X4(false, 0, NULL, 0), ++ SPINAND_PROG_LOAD(false, 0, NULL, 0)); ++ ++static int fm25s01a_ooblayout_ecc(struct mtd_info *mtd, int section, ++ struct mtd_oob_region *region) ++{ ++ return -ERANGE; ++} ++ ++static int fm25s01a_ooblayout_free(struct mtd_info *mtd, int section, ++ struct mtd_oob_region *region) ++{ ++ if (section) ++ return -ERANGE; ++ ++ region->offset = 2; ++ region->length = 62; ++ ++ return 0; ++} ++ ++static const struct mtd_ooblayout_ops fm25s01a_ooblayout = { ++ .ecc = fm25s01a_ooblayout_ecc, ++ .free = fm25s01a_ooblayout_free, ++}; ++ ++static const struct spinand_info fmsh_spinand_table[] = { ++ SPINAND_INFO("FM25S01A", ++ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xE4), ++ NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), ++ NAND_ECCREQ(1, 512), ++ SPINAND_INFO_OP_VARIANTS(&read_cache_variants, ++ &write_cache_variants, ++ &update_cache_variants), ++ SPINAND_HAS_QE_BIT, ++ SPINAND_ECCINFO(&fm25s01a_ooblayout, NULL)), ++}; ++ ++static const struct spinand_manufacturer_ops fmsh_spinand_manuf_ops = { ++}; ++ ++const struct spinand_manufacturer fmsh_spinand_manufacturer = { ++ .id = SPINAND_MFR_FMSH, ++ .name = "Fudan Micro", ++ .chips = fmsh_spinand_table, ++ .nchips = ARRAY_SIZE(fmsh_spinand_table), ++ .ops = &fmsh_spinand_manuf_ops, ++}; +diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h +index 702e5fb13dae..ba7b73c9675e 100644 +--- a/include/linux/mtd/spinand.h ++++ b/include/linux/mtd/spinand.h +@@ -263,6 +263,7 @@ struct spinand_manufacturer { + extern const struct spinand_manufacturer alliancememory_spinand_manufacturer; + extern const struct spinand_manufacturer ato_spinand_manufacturer; + extern const struct spinand_manufacturer esmt_c8_spinand_manufacturer; ++extern const struct spinand_manufacturer fmsh_spinand_manufacturer; + extern const struct spinand_manufacturer foresee_spinand_manufacturer; + extern const struct spinand_manufacturer gigadevice_spinand_manufacturer; + extern const struct spinand_manufacturer macronix_spinand_manufacturer; +-- +2.51.0 + + +From ac22dde59c9dc55647118463603931a1ac92c942 Mon Sep 17 00:00:00 2001 +From: Markus Stockhausen +Date: Wed, 10 Sep 2025 14:32:58 -0400 +Subject: [PATCH 009/517] mtd: nand: move nand_check_erased_ecc_chunk() to + nand/core + +The check function for bitflips in erased blocks will be needed +by the Realtek ECC engine driver (which is currently under +development). Right now it is located in raw/nand_base.c. +While this is sufficient for the current usecases, there is +no real dependency for an ECC engine on the raw nand library. + +Move the function over to a more generic place in core library. + +Suggested-by: Miquel Raynal +Signed-off-by: Markus Stockhausen +Signed-off-by: Miquel Raynal +--- + drivers/mtd/nand/core.c | 131 +++++++++++++++++++++++++++++++ + drivers/mtd/nand/raw/nand_base.c | 131 ------------------------------- + include/linux/mtd/nand.h | 5 ++ + include/linux/mtd/rawnand.h | 5 -- + 4 files changed, 136 insertions(+), 136 deletions(-) + +diff --git a/drivers/mtd/nand/core.c b/drivers/mtd/nand/core.c +index 7737b1a4a177..3e76d127715f 100644 +--- a/drivers/mtd/nand/core.c ++++ b/drivers/mtd/nand/core.c +@@ -12,6 +12,137 @@ + #include + #include + ++/** ++ * nand_check_erased_buf - check if a buffer contains (almost) only 0xff data ++ * @buf: buffer to test ++ * @len: buffer length ++ * @bitflips_threshold: maximum number of bitflips ++ * ++ * Check if a buffer contains only 0xff, which means the underlying region ++ * has been erased and is ready to be programmed. ++ * The bitflips_threshold specify the maximum number of bitflips before ++ * considering the region is not erased. ++ * Note: The logic of this function has been extracted from the memweight ++ * implementation, except that nand_check_erased_buf function exit before ++ * testing the whole buffer if the number of bitflips exceed the ++ * bitflips_threshold value. ++ * ++ * Returns a positive number of bitflips less than or equal to ++ * bitflips_threshold, or -ERROR_CODE for bitflips in excess of the ++ * threshold. ++ */ ++static int nand_check_erased_buf(void *buf, int len, int bitflips_threshold) ++{ ++ const unsigned char *bitmap = buf; ++ int bitflips = 0; ++ int weight; ++ ++ for (; len && ((uintptr_t)bitmap) % sizeof(long); ++ len--, bitmap++) { ++ weight = hweight8(*bitmap); ++ bitflips += BITS_PER_BYTE - weight; ++ if (unlikely(bitflips > bitflips_threshold)) ++ return -EBADMSG; ++ } ++ ++ for (; len >= sizeof(long); ++ len -= sizeof(long), bitmap += sizeof(long)) { ++ unsigned long d = *((unsigned long *)bitmap); ++ if (d == ~0UL) ++ continue; ++ weight = hweight_long(d); ++ bitflips += BITS_PER_LONG - weight; ++ if (unlikely(bitflips > bitflips_threshold)) ++ return -EBADMSG; ++ } ++ ++ for (; len > 0; len--, bitmap++) { ++ weight = hweight8(*bitmap); ++ bitflips += BITS_PER_BYTE - weight; ++ if (unlikely(bitflips > bitflips_threshold)) ++ return -EBADMSG; ++ } ++ ++ return bitflips; ++} ++ ++/** ++ * nand_check_erased_ecc_chunk - check if an ECC chunk contains (almost) only ++ * 0xff data ++ * @data: data buffer to test ++ * @datalen: data length ++ * @ecc: ECC buffer ++ * @ecclen: ECC length ++ * @extraoob: extra OOB buffer ++ * @extraooblen: extra OOB length ++ * @bitflips_threshold: maximum number of bitflips ++ * ++ * Check if a data buffer and its associated ECC and OOB data contains only ++ * 0xff pattern, which means the underlying region has been erased and is ++ * ready to be programmed. ++ * The bitflips_threshold specify the maximum number of bitflips before ++ * considering the region as not erased. ++ * ++ * Note: ++ * 1/ ECC algorithms are working on pre-defined block sizes which are usually ++ * different from the NAND page size. When fixing bitflips, ECC engines will ++ * report the number of errors per chunk, and the NAND core infrastructure ++ * expect you to return the maximum number of bitflips for the whole page. ++ * This is why you should always use this function on a single chunk and ++ * not on the whole page. After checking each chunk you should update your ++ * max_bitflips value accordingly. ++ * 2/ When checking for bitflips in erased pages you should not only check ++ * the payload data but also their associated ECC data, because a user might ++ * have programmed almost all bits to 1 but a few. In this case, we ++ * shouldn't consider the chunk as erased, and checking ECC bytes prevent ++ * this case. ++ * 3/ The extraoob argument is optional, and should be used if some of your OOB ++ * data are protected by the ECC engine. ++ * It could also be used if you support subpages and want to attach some ++ * extra OOB data to an ECC chunk. ++ * ++ * Returns a positive number of bitflips less than or equal to ++ * bitflips_threshold, or -ERROR_CODE for bitflips in excess of the ++ * threshold. In case of success, the passed buffers are filled with 0xff. ++ */ ++int nand_check_erased_ecc_chunk(void *data, int datalen, ++ void *ecc, int ecclen, ++ void *extraoob, int extraooblen, ++ int bitflips_threshold) ++{ ++ int data_bitflips = 0, ecc_bitflips = 0, extraoob_bitflips = 0; ++ ++ data_bitflips = nand_check_erased_buf(data, datalen, ++ bitflips_threshold); ++ if (data_bitflips < 0) ++ return data_bitflips; ++ ++ bitflips_threshold -= data_bitflips; ++ ++ ecc_bitflips = nand_check_erased_buf(ecc, ecclen, bitflips_threshold); ++ if (ecc_bitflips < 0) ++ return ecc_bitflips; ++ ++ bitflips_threshold -= ecc_bitflips; ++ ++ extraoob_bitflips = nand_check_erased_buf(extraoob, extraooblen, ++ bitflips_threshold); ++ if (extraoob_bitflips < 0) ++ return extraoob_bitflips; ++ ++ if (data_bitflips) ++ memset(data, 0xff, datalen); ++ ++ if (ecc_bitflips) ++ memset(ecc, 0xff, ecclen); ++ ++ if (extraoob_bitflips) ++ memset(extraoob, 0xff, extraooblen); ++ ++ return data_bitflips + ecc_bitflips + extraoob_bitflips; ++} ++EXPORT_SYMBOL(nand_check_erased_ecc_chunk); ++ + /** + * nanddev_isbad() - Check if a block is bad + * @nand: NAND device +diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c +index 53e16d39af4b..c1f785a8b7e5 100644 +--- a/drivers/mtd/nand/raw/nand_base.c ++++ b/drivers/mtd/nand/raw/nand_base.c +@@ -2783,137 +2783,6 @@ int nand_set_features(struct nand_chip *chip, int addr, + return nand_set_features_op(chip, addr, subfeature_param); + } + +-/** +- * nand_check_erased_buf - check if a buffer contains (almost) only 0xff data +- * @buf: buffer to test +- * @len: buffer length +- * @bitflips_threshold: maximum number of bitflips +- * +- * Check if a buffer contains only 0xff, which means the underlying region +- * has been erased and is ready to be programmed. +- * The bitflips_threshold specify the maximum number of bitflips before +- * considering the region is not erased. +- * Note: The logic of this function has been extracted from the memweight +- * implementation, except that nand_check_erased_buf function exit before +- * testing the whole buffer if the number of bitflips exceed the +- * bitflips_threshold value. +- * +- * Returns a positive number of bitflips less than or equal to +- * bitflips_threshold, or -ERROR_CODE for bitflips in excess of the +- * threshold. +- */ +-static int nand_check_erased_buf(void *buf, int len, int bitflips_threshold) +-{ +- const unsigned char *bitmap = buf; +- int bitflips = 0; +- int weight; +- +- for (; len && ((uintptr_t)bitmap) % sizeof(long); +- len--, bitmap++) { +- weight = hweight8(*bitmap); +- bitflips += BITS_PER_BYTE - weight; +- if (unlikely(bitflips > bitflips_threshold)) +- return -EBADMSG; +- } +- +- for (; len >= sizeof(long); +- len -= sizeof(long), bitmap += sizeof(long)) { +- unsigned long d = *((unsigned long *)bitmap); +- if (d == ~0UL) +- continue; +- weight = hweight_long(d); +- bitflips += BITS_PER_LONG - weight; +- if (unlikely(bitflips > bitflips_threshold)) +- return -EBADMSG; +- } +- +- for (; len > 0; len--, bitmap++) { +- weight = hweight8(*bitmap); +- bitflips += BITS_PER_BYTE - weight; +- if (unlikely(bitflips > bitflips_threshold)) +- return -EBADMSG; +- } +- +- return bitflips; +-} +- +-/** +- * nand_check_erased_ecc_chunk - check if an ECC chunk contains (almost) only +- * 0xff data +- * @data: data buffer to test +- * @datalen: data length +- * @ecc: ECC buffer +- * @ecclen: ECC length +- * @extraoob: extra OOB buffer +- * @extraooblen: extra OOB length +- * @bitflips_threshold: maximum number of bitflips +- * +- * Check if a data buffer and its associated ECC and OOB data contains only +- * 0xff pattern, which means the underlying region has been erased and is +- * ready to be programmed. +- * The bitflips_threshold specify the maximum number of bitflips before +- * considering the region as not erased. +- * +- * Note: +- * 1/ ECC algorithms are working on pre-defined block sizes which are usually +- * different from the NAND page size. When fixing bitflips, ECC engines will +- * report the number of errors per chunk, and the NAND core infrastructure +- * expect you to return the maximum number of bitflips for the whole page. +- * This is why you should always use this function on a single chunk and +- * not on the whole page. After checking each chunk you should update your +- * max_bitflips value accordingly. +- * 2/ When checking for bitflips in erased pages you should not only check +- * the payload data but also their associated ECC data, because a user might +- * have programmed almost all bits to 1 but a few. In this case, we +- * shouldn't consider the chunk as erased, and checking ECC bytes prevent +- * this case. +- * 3/ The extraoob argument is optional, and should be used if some of your OOB +- * data are protected by the ECC engine. +- * It could also be used if you support subpages and want to attach some +- * extra OOB data to an ECC chunk. +- * +- * Returns a positive number of bitflips less than or equal to +- * bitflips_threshold, or -ERROR_CODE for bitflips in excess of the +- * threshold. In case of success, the passed buffers are filled with 0xff. +- */ +-int nand_check_erased_ecc_chunk(void *data, int datalen, +- void *ecc, int ecclen, +- void *extraoob, int extraooblen, +- int bitflips_threshold) +-{ +- int data_bitflips = 0, ecc_bitflips = 0, extraoob_bitflips = 0; +- +- data_bitflips = nand_check_erased_buf(data, datalen, +- bitflips_threshold); +- if (data_bitflips < 0) +- return data_bitflips; +- +- bitflips_threshold -= data_bitflips; +- +- ecc_bitflips = nand_check_erased_buf(ecc, ecclen, bitflips_threshold); +- if (ecc_bitflips < 0) +- return ecc_bitflips; +- +- bitflips_threshold -= ecc_bitflips; +- +- extraoob_bitflips = nand_check_erased_buf(extraoob, extraooblen, +- bitflips_threshold); +- if (extraoob_bitflips < 0) +- return extraoob_bitflips; +- +- if (data_bitflips) +- memset(data, 0xff, datalen); +- +- if (ecc_bitflips) +- memset(ecc, 0xff, ecclen); +- +- if (extraoob_bitflips) +- memset(extraoob, 0xff, extraooblen); +- +- return data_bitflips + ecc_bitflips + extraoob_bitflips; +-} +-EXPORT_SYMBOL(nand_check_erased_ecc_chunk); +- + /** + * nand_read_page_raw_notsupp - dummy read raw page function + * @chip: nand chip info structure +diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h +index 1e4208040956..f4ee1e4bc18f 100644 +--- a/include/linux/mtd/nand.h ++++ b/include/linux/mtd/nand.h +@@ -1136,4 +1136,9 @@ static inline bool nanddev_bbt_is_initialized(struct nand_device *nand) + int nanddev_mtd_erase(struct mtd_info *mtd, struct erase_info *einfo); + int nanddev_mtd_max_bad_blocks(struct mtd_info *mtd, loff_t offs, size_t len); + ++int nand_check_erased_ecc_chunk(void *data, int datalen, ++ void *ecc, int ecclen, ++ void *extraoob, int extraooblen, ++ int threshold); ++ + #endif /* __LINUX_MTD_NAND_H */ +diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h +index e84522e31301..d30bdc3fcfd7 100644 +--- a/include/linux/mtd/rawnand.h ++++ b/include/linux/mtd/rawnand.h +@@ -1519,11 +1519,6 @@ int rawnand_sw_bch_correct(struct nand_chip *chip, unsigned char *buf, + unsigned char *read_ecc, unsigned char *calc_ecc); + void rawnand_sw_bch_cleanup(struct nand_chip *chip); + +-int nand_check_erased_ecc_chunk(void *data, int datalen, +- void *ecc, int ecclen, +- void *extraoob, int extraooblen, +- int threshold); +- + int nand_ecc_choose_conf(struct nand_chip *chip, + const struct nand_ecc_caps *caps, int oobavail); + +-- +2.51.0 + + +From 7b26769b0e737b7f7ecb5b0201a0cbf5a72ed150 Mon Sep 17 00:00:00 2001 +From: Md Sadre Alam +Date: Wed, 20 Nov 2024 14:45:00 +0530 +Subject: [PATCH 010/517] mtd: rawnand: qcom: cleanup qcom_nandc driver + +Perform a global cleanup of the Qualcomm NAND +controller driver with the following improvements: + +- Remove register value indirection API + +- Remove set_reg() API + +- Convert read_loc_first & read_loc_last macro to functions + +- Rename multiple variables + +Signed-off-by: Md Sadre Alam +Signed-off-by: Miquel Raynal +--- + drivers/mtd/nand/raw/qcom_nandc.c | 520 ++++++++++++++---------------- + 1 file changed, 236 insertions(+), 284 deletions(-) + +diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c +index 275d34119acd..94a57a0de067 100644 +--- a/drivers/mtd/nand/raw/qcom_nandc.c ++++ b/drivers/mtd/nand/raw/qcom_nandc.c +@@ -189,17 +189,6 @@ + #define ECC_BCH_4BIT BIT(2) + #define ECC_BCH_8BIT BIT(3) + +-#define nandc_set_read_loc_first(chip, reg, cw_offset, read_size, is_last_read_loc) \ +-nandc_set_reg(chip, reg, \ +- ((cw_offset) << READ_LOCATION_OFFSET) | \ +- ((read_size) << READ_LOCATION_SIZE) | \ +- ((is_last_read_loc) << READ_LOCATION_LAST)) +- +-#define nandc_set_read_loc_last(chip, reg, cw_offset, read_size, is_last_read_loc) \ +-nandc_set_reg(chip, reg, \ +- ((cw_offset) << READ_LOCATION_OFFSET) | \ +- ((read_size) << READ_LOCATION_SIZE) | \ +- ((is_last_read_loc) << READ_LOCATION_LAST)) + /* + * Returns the actual register address for all NAND_DEV_ registers + * (i.e. NAND_DEV_CMD0, NAND_DEV_CMD1, NAND_DEV_CMD2 and NAND_DEV_CMD_VLD) +@@ -257,8 +246,6 @@ nandc_set_reg(chip, reg, \ + * @tx_sgl_start - start index in data sgl for tx. + * @rx_sgl_pos - current index in data sgl for rx. + * @rx_sgl_start - start index in data sgl for rx. +- * @wait_second_completion - wait for second DMA desc completion before making +- * the NAND transfer completion. + */ + struct bam_transaction { + struct bam_cmd_element *bam_ce; +@@ -275,7 +262,6 @@ struct bam_transaction { + u32 tx_sgl_start; + u32 rx_sgl_pos; + u32 rx_sgl_start; +- bool wait_second_completion; + }; + + /* +@@ -471,9 +457,9 @@ struct qcom_op { + unsigned int data_instr_idx; + unsigned int rdy_timeout_ms; + unsigned int rdy_delay_ns; +- u32 addr1_reg; +- u32 addr2_reg; +- u32 cmd_reg; ++ __le32 addr1_reg; ++ __le32 addr2_reg; ++ __le32 cmd_reg; + u8 flag; + }; + +@@ -549,17 +535,17 @@ struct qcom_nand_host { + * among different NAND controllers. + * @ecc_modes - ecc mode for NAND + * @dev_cmd_reg_start - NAND_DEV_CMD_* registers starting offset +- * @is_bam - whether NAND controller is using BAM +- * @is_qpic - whether NAND CTRL is part of qpic IP +- * @qpic_v2 - flag to indicate QPIC IP version 2 ++ * @supports_bam - whether NAND controller is using Bus Access Manager (BAM) ++ * @nandc_part_of_qpic - whether NAND controller is part of qpic IP ++ * @qpic_version2 - flag to indicate QPIC IP version 2 + * @use_codeword_fixup - whether NAND has different layout for boot partitions + */ + struct qcom_nandc_props { + u32 ecc_modes; + u32 dev_cmd_reg_start; +- bool is_bam; +- bool is_qpic; +- bool qpic_v2; ++ bool supports_bam; ++ bool nandc_part_of_qpic; ++ bool qpic_version2; + bool use_codeword_fixup; + }; + +@@ -613,19 +599,11 @@ static void clear_bam_transaction(struct qcom_nand_controller *nandc) + { + struct bam_transaction *bam_txn = nandc->bam_txn; + +- if (!nandc->props->is_bam) ++ if (!nandc->props->supports_bam) + return; + +- bam_txn->bam_ce_pos = 0; +- bam_txn->bam_ce_start = 0; +- bam_txn->cmd_sgl_pos = 0; +- bam_txn->cmd_sgl_start = 0; +- bam_txn->tx_sgl_pos = 0; +- bam_txn->tx_sgl_start = 0; +- bam_txn->rx_sgl_pos = 0; +- bam_txn->rx_sgl_start = 0; ++ memset(&bam_txn->bam_ce_pos, 0, sizeof(u32) * 8); + bam_txn->last_data_desc = NULL; +- bam_txn->wait_second_completion = false; + + sg_init_table(bam_txn->cmd_sgl, nandc->max_cwperpage * + QPIC_PER_CW_CMD_SGL); +@@ -640,46 +618,35 @@ static void qpic_bam_dma_done(void *data) + { + struct bam_transaction *bam_txn = data; + +- /* +- * In case of data transfer with NAND, 2 callbacks will be generated. +- * One for command channel and another one for data channel. +- * If current transaction has data descriptors +- * (i.e. wait_second_completion is true), then set this to false +- * and wait for second DMA descriptor completion. +- */ +- if (bam_txn->wait_second_completion) +- bam_txn->wait_second_completion = false; +- else +- complete(&bam_txn->txn_done); ++ complete(&bam_txn->txn_done); + } + +-static inline struct qcom_nand_host *to_qcom_nand_host(struct nand_chip *chip) ++static struct qcom_nand_host *to_qcom_nand_host(struct nand_chip *chip) + { + return container_of(chip, struct qcom_nand_host, chip); + } + +-static inline struct qcom_nand_controller * ++static struct qcom_nand_controller * + get_qcom_nand_controller(struct nand_chip *chip) + { + return container_of(chip->controller, struct qcom_nand_controller, + controller); + } + +-static inline u32 nandc_read(struct qcom_nand_controller *nandc, int offset) ++static u32 nandc_read(struct qcom_nand_controller *nandc, int offset) + { + return ioread32(nandc->base + offset); + } + +-static inline void nandc_write(struct qcom_nand_controller *nandc, int offset, +- u32 val) ++static void nandc_write(struct qcom_nand_controller *nandc, int offset, ++ u32 val) + { + iowrite32(val, nandc->base + offset); + } + +-static inline void nandc_read_buffer_sync(struct qcom_nand_controller *nandc, +- bool is_cpu) ++static void nandc_dev_to_mem(struct qcom_nand_controller *nandc, bool is_cpu) + { +- if (!nandc->props->is_bam) ++ if (!nandc->props->supports_bam) + return; + + if (is_cpu) +@@ -694,93 +661,90 @@ static inline void nandc_read_buffer_sync(struct qcom_nand_controller *nandc, + DMA_FROM_DEVICE); + } + +-static __le32 *offset_to_nandc_reg(struct nandc_regs *regs, int offset) +-{ +- switch (offset) { +- case NAND_FLASH_CMD: +- return ®s->cmd; +- case NAND_ADDR0: +- return ®s->addr0; +- case NAND_ADDR1: +- return ®s->addr1; +- case NAND_FLASH_CHIP_SELECT: +- return ®s->chip_sel; +- case NAND_EXEC_CMD: +- return ®s->exec; +- case NAND_FLASH_STATUS: +- return ®s->clrflashstatus; +- case NAND_DEV0_CFG0: +- return ®s->cfg0; +- case NAND_DEV0_CFG1: +- return ®s->cfg1; +- case NAND_DEV0_ECC_CFG: +- return ®s->ecc_bch_cfg; +- case NAND_READ_STATUS: +- return ®s->clrreadstatus; +- case NAND_DEV_CMD1: +- return ®s->cmd1; +- case NAND_DEV_CMD1_RESTORE: +- return ®s->orig_cmd1; +- case NAND_DEV_CMD_VLD: +- return ®s->vld; +- case NAND_DEV_CMD_VLD_RESTORE: +- return ®s->orig_vld; +- case NAND_EBI2_ECC_BUF_CFG: +- return ®s->ecc_buf_cfg; +- case NAND_READ_LOCATION_0: +- return ®s->read_location0; +- case NAND_READ_LOCATION_1: +- return ®s->read_location1; +- case NAND_READ_LOCATION_2: +- return ®s->read_location2; +- case NAND_READ_LOCATION_3: +- return ®s->read_location3; +- case NAND_READ_LOCATION_LAST_CW_0: +- return ®s->read_location_last0; +- case NAND_READ_LOCATION_LAST_CW_1: +- return ®s->read_location_last1; +- case NAND_READ_LOCATION_LAST_CW_2: +- return ®s->read_location_last2; +- case NAND_READ_LOCATION_LAST_CW_3: +- return ®s->read_location_last3; +- default: +- return NULL; +- } ++/* Helper to check whether this is the last CW or not */ ++static bool qcom_nandc_is_last_cw(struct nand_ecc_ctrl *ecc, int cw) ++{ ++ return cw == (ecc->steps - 1); + } + +-static void nandc_set_reg(struct nand_chip *chip, int offset, +- u32 val) ++/** ++ * nandc_set_read_loc_first() - to set read location first register ++ * @chip: NAND Private Flash Chip Data ++ * @reg_base: location register base ++ * @cw_offset: code word offset ++ * @read_size: code word read length ++ * @is_last_read_loc: is this the last read location ++ * ++ * This function will set location register value ++ */ ++static void nandc_set_read_loc_first(struct nand_chip *chip, ++ int reg_base, u32 cw_offset, ++ u32 read_size, u32 is_last_read_loc) + { + struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); +- struct nandc_regs *regs = nandc->regs; +- __le32 *reg; +- +- reg = offset_to_nandc_reg(regs, offset); ++ __le32 locreg_val; ++ u32 val = (((cw_offset) << READ_LOCATION_OFFSET) | ++ ((read_size) << READ_LOCATION_SIZE) | ++ ((is_last_read_loc) << READ_LOCATION_LAST)); ++ ++ locreg_val = cpu_to_le32(val); ++ ++ if (reg_base == NAND_READ_LOCATION_0) ++ nandc->regs->read_location0 = locreg_val; ++ else if (reg_base == NAND_READ_LOCATION_1) ++ nandc->regs->read_location1 = locreg_val; ++ else if (reg_base == NAND_READ_LOCATION_2) ++ nandc->regs->read_location2 = locreg_val; ++ else if (reg_base == NAND_READ_LOCATION_3) ++ nandc->regs->read_location3 = locreg_val; ++} ++ ++/** ++ * nandc_set_read_loc_last - to set read location last register ++ * @chip: NAND Private Flash Chip Data ++ * @reg_base: location register base ++ * @cw_offset: code word offset ++ * @read_size: code word read length ++ * @is_last_read_loc: is this the last read location ++ * ++ * This function will set location last register value ++ */ ++static void nandc_set_read_loc_last(struct nand_chip *chip, ++ int reg_base, u32 cw_offset, ++ u32 read_size, u32 is_last_read_loc) ++{ ++ struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); ++ __le32 locreg_val; ++ u32 val = (((cw_offset) << READ_LOCATION_OFFSET) | ++ ((read_size) << READ_LOCATION_SIZE) | ++ ((is_last_read_loc) << READ_LOCATION_LAST)); + +- if (reg) +- *reg = cpu_to_le32(val); +-} ++ locreg_val = cpu_to_le32(val); + +-/* Helper to check the code word, whether it is last cw or not */ +-static bool qcom_nandc_is_last_cw(struct nand_ecc_ctrl *ecc, int cw) +-{ +- return cw == (ecc->steps - 1); ++ if (reg_base == NAND_READ_LOCATION_LAST_CW_0) ++ nandc->regs->read_location_last0 = locreg_val; ++ else if (reg_base == NAND_READ_LOCATION_LAST_CW_1) ++ nandc->regs->read_location_last1 = locreg_val; ++ else if (reg_base == NAND_READ_LOCATION_LAST_CW_2) ++ nandc->regs->read_location_last2 = locreg_val; ++ else if (reg_base == NAND_READ_LOCATION_LAST_CW_3) ++ nandc->regs->read_location_last3 = locreg_val; + } + + /* helper to configure location register values */ + static void nandc_set_read_loc(struct nand_chip *chip, int cw, int reg, +- int cw_offset, int read_size, int is_last_read_loc) ++ u32 cw_offset, u32 read_size, u32 is_last_read_loc) + { + struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); + struct nand_ecc_ctrl *ecc = &chip->ecc; + int reg_base = NAND_READ_LOCATION_0; + +- if (nandc->props->qpic_v2 && qcom_nandc_is_last_cw(ecc, cw)) ++ if (nandc->props->qpic_version2 && qcom_nandc_is_last_cw(ecc, cw)) + reg_base = NAND_READ_LOCATION_LAST_CW_0; + + reg_base += reg * 4; + +- if (nandc->props->qpic_v2 && qcom_nandc_is_last_cw(ecc, cw)) ++ if (nandc->props->qpic_version2 && qcom_nandc_is_last_cw(ecc, cw)) + return nandc_set_read_loc_last(chip, reg_base, cw_offset, + read_size, is_last_read_loc); + else +@@ -792,12 +756,13 @@ static void nandc_set_read_loc(struct nand_chip *chip, int cw, int reg, + static void set_address(struct qcom_nand_host *host, u16 column, int page) + { + struct nand_chip *chip = &host->chip; ++ struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); + + if (chip->options & NAND_BUSWIDTH_16) + column >>= 1; + +- nandc_set_reg(chip, NAND_ADDR0, page << 16 | column); +- nandc_set_reg(chip, NAND_ADDR1, page >> 16 & 0xff); ++ nandc->regs->addr0 = cpu_to_le32(page << 16 | column); ++ nandc->regs->addr1 = cpu_to_le32(page >> 16 & 0xff); + } + + /* +@@ -811,41 +776,43 @@ static void set_address(struct qcom_nand_host *host, u16 column, int page) + static void update_rw_regs(struct qcom_nand_host *host, int num_cw, bool read, int cw) + { + struct nand_chip *chip = &host->chip; +- u32 cmd, cfg0, cfg1, ecc_bch_cfg; ++ __le32 cmd, cfg0, cfg1, ecc_bch_cfg; + struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); + + if (read) { + if (host->use_ecc) +- cmd = OP_PAGE_READ_WITH_ECC | PAGE_ACC | LAST_PAGE; ++ cmd = cpu_to_le32(OP_PAGE_READ_WITH_ECC | PAGE_ACC | LAST_PAGE); + else +- cmd = OP_PAGE_READ | PAGE_ACC | LAST_PAGE; ++ cmd = cpu_to_le32(OP_PAGE_READ | PAGE_ACC | LAST_PAGE); + } else { +- cmd = OP_PROGRAM_PAGE | PAGE_ACC | LAST_PAGE; ++ cmd = cpu_to_le32(OP_PROGRAM_PAGE | PAGE_ACC | LAST_PAGE); + } + + if (host->use_ecc) { +- cfg0 = (host->cfg0 & ~(7U << CW_PER_PAGE)) | +- (num_cw - 1) << CW_PER_PAGE; ++ cfg0 = cpu_to_le32((host->cfg0 & ~(7U << CW_PER_PAGE)) | ++ (num_cw - 1) << CW_PER_PAGE); + +- cfg1 = host->cfg1; +- ecc_bch_cfg = host->ecc_bch_cfg; ++ cfg1 = cpu_to_le32(host->cfg1); ++ ecc_bch_cfg = cpu_to_le32(host->ecc_bch_cfg); + } else { +- cfg0 = (host->cfg0_raw & ~(7U << CW_PER_PAGE)) | +- (num_cw - 1) << CW_PER_PAGE; ++ cfg0 = cpu_to_le32((host->cfg0_raw & ~(7U << CW_PER_PAGE)) | ++ (num_cw - 1) << CW_PER_PAGE); + +- cfg1 = host->cfg1_raw; +- ecc_bch_cfg = 1 << ECC_CFG_ECC_DISABLE; ++ cfg1 = cpu_to_le32(host->cfg1_raw); ++ ecc_bch_cfg = cpu_to_le32(1 << ECC_CFG_ECC_DISABLE); + } + +- nandc_set_reg(chip, NAND_FLASH_CMD, cmd); +- nandc_set_reg(chip, NAND_DEV0_CFG0, cfg0); +- nandc_set_reg(chip, NAND_DEV0_CFG1, cfg1); +- nandc_set_reg(chip, NAND_DEV0_ECC_CFG, ecc_bch_cfg); +- if (!nandc->props->qpic_v2) +- nandc_set_reg(chip, NAND_EBI2_ECC_BUF_CFG, host->ecc_buf_cfg); +- nandc_set_reg(chip, NAND_FLASH_STATUS, host->clrflashstatus); +- nandc_set_reg(chip, NAND_READ_STATUS, host->clrreadstatus); +- nandc_set_reg(chip, NAND_EXEC_CMD, 1); ++ nandc->regs->cmd = cmd; ++ nandc->regs->cfg0 = cfg0; ++ nandc->regs->cfg1 = cfg1; ++ nandc->regs->ecc_bch_cfg = ecc_bch_cfg; ++ ++ if (!nandc->props->qpic_version2) ++ nandc->regs->ecc_buf_cfg = cpu_to_le32(host->ecc_buf_cfg); ++ ++ nandc->regs->clrflashstatus = cpu_to_le32(host->clrflashstatus); ++ nandc->regs->clrreadstatus = cpu_to_le32(host->clrreadstatus); ++ nandc->regs->exec = cpu_to_le32(1); + + if (read) + nandc_set_read_loc(chip, cw, 0, 0, host->use_ecc ? +@@ -1121,7 +1088,7 @@ static int read_reg_dma(struct qcom_nand_controller *nandc, int first, + if (first == NAND_DEV_CMD_VLD || first == NAND_DEV_CMD1) + first = dev_cmd_reg_addr(nandc, first); + +- if (nandc->props->is_bam) ++ if (nandc->props->supports_bam) + return prep_bam_dma_desc_cmd(nandc, true, first, vaddr, + num_regs, flags); + +@@ -1136,25 +1103,16 @@ static int read_reg_dma(struct qcom_nand_controller *nandc, int first, + * write_reg_dma: prepares a descriptor to write a given number of + * contiguous registers + * ++ * @vaddr: contiguous memory from where register value will ++ * be written + * @first: offset of the first register in the contiguous block + * @num_regs: number of registers to write + * @flags: flags to control DMA descriptor preparation + */ +-static int write_reg_dma(struct qcom_nand_controller *nandc, int first, +- int num_regs, unsigned int flags) ++static int write_reg_dma(struct qcom_nand_controller *nandc, __le32 *vaddr, ++ int first, int num_regs, unsigned int flags) + { + bool flow_control = false; +- struct nandc_regs *regs = nandc->regs; +- void *vaddr; +- +- vaddr = offset_to_nandc_reg(regs, first); +- +- if (first == NAND_ERASED_CW_DETECT_CFG) { +- if (flags & NAND_ERASED_CW_SET) +- vaddr = ®s->erased_cw_detect_cfg_set; +- else +- vaddr = ®s->erased_cw_detect_cfg_clr; +- } + + if (first == NAND_EXEC_CMD) + flags |= NAND_BAM_NWD; +@@ -1165,7 +1123,7 @@ static int write_reg_dma(struct qcom_nand_controller *nandc, int first, + if (first == NAND_DEV_CMD_VLD_RESTORE || first == NAND_DEV_CMD_VLD) + first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD); + +- if (nandc->props->is_bam) ++ if (nandc->props->supports_bam) + return prep_bam_dma_desc_cmd(nandc, false, first, vaddr, + num_regs, flags); + +@@ -1188,7 +1146,7 @@ static int write_reg_dma(struct qcom_nand_controller *nandc, int first, + static int read_data_dma(struct qcom_nand_controller *nandc, int reg_off, + const u8 *vaddr, int size, unsigned int flags) + { +- if (nandc->props->is_bam) ++ if (nandc->props->supports_bam) + return prep_bam_dma_desc_data(nandc, true, vaddr, size, flags); + + return prep_adm_dma_desc(nandc, true, reg_off, vaddr, size, false); +@@ -1206,7 +1164,7 @@ static int read_data_dma(struct qcom_nand_controller *nandc, int reg_off, + static int write_data_dma(struct qcom_nand_controller *nandc, int reg_off, + const u8 *vaddr, int size, unsigned int flags) + { +- if (nandc->props->is_bam) ++ if (nandc->props->supports_bam) + return prep_bam_dma_desc_data(nandc, false, vaddr, size, flags); + + return prep_adm_dma_desc(nandc, false, reg_off, vaddr, size, false); +@@ -1220,13 +1178,14 @@ static void config_nand_page_read(struct nand_chip *chip) + { + struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); + +- write_reg_dma(nandc, NAND_ADDR0, 2, 0); +- write_reg_dma(nandc, NAND_DEV0_CFG0, 3, 0); +- if (!nandc->props->qpic_v2) +- write_reg_dma(nandc, NAND_EBI2_ECC_BUF_CFG, 1, 0); +- write_reg_dma(nandc, NAND_ERASED_CW_DETECT_CFG, 1, 0); +- write_reg_dma(nandc, NAND_ERASED_CW_DETECT_CFG, 1, +- NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL); ++ write_reg_dma(nandc, &nandc->regs->addr0, NAND_ADDR0, 2, 0); ++ write_reg_dma(nandc, &nandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0); ++ if (!nandc->props->qpic_version2) ++ write_reg_dma(nandc, &nandc->regs->ecc_buf_cfg, NAND_EBI2_ECC_BUF_CFG, 1, 0); ++ write_reg_dma(nandc, &nandc->regs->erased_cw_detect_cfg_clr, ++ NAND_ERASED_CW_DETECT_CFG, 1, 0); ++ write_reg_dma(nandc, &nandc->regs->erased_cw_detect_cfg_set, ++ NAND_ERASED_CW_DETECT_CFG, 1, NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL); + } + + /* +@@ -1239,16 +1198,16 @@ config_nand_cw_read(struct nand_chip *chip, bool use_ecc, int cw) + struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); + struct nand_ecc_ctrl *ecc = &chip->ecc; + +- int reg = NAND_READ_LOCATION_0; ++ __le32 *reg = &nandc->regs->read_location0; + +- if (nandc->props->qpic_v2 && qcom_nandc_is_last_cw(ecc, cw)) +- reg = NAND_READ_LOCATION_LAST_CW_0; ++ if (nandc->props->qpic_version2 && qcom_nandc_is_last_cw(ecc, cw)) ++ reg = &nandc->regs->read_location_last0; + +- if (nandc->props->is_bam) +- write_reg_dma(nandc, reg, 4, NAND_BAM_NEXT_SGL); ++ if (nandc->props->supports_bam) ++ write_reg_dma(nandc, reg, NAND_READ_LOCATION_0, 4, NAND_BAM_NEXT_SGL); + +- write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL); +- write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); ++ write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL); ++ write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); + + if (use_ecc) { + read_reg_dma(nandc, NAND_FLASH_STATUS, 2, 0); +@@ -1279,10 +1238,10 @@ static void config_nand_page_write(struct nand_chip *chip) + { + struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); + +- write_reg_dma(nandc, NAND_ADDR0, 2, 0); +- write_reg_dma(nandc, NAND_DEV0_CFG0, 3, 0); +- if (!nandc->props->qpic_v2) +- write_reg_dma(nandc, NAND_EBI2_ECC_BUF_CFG, 1, ++ write_reg_dma(nandc, &nandc->regs->addr0, NAND_ADDR0, 2, 0); ++ write_reg_dma(nandc, &nandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0); ++ if (!nandc->props->qpic_version2) ++ write_reg_dma(nandc, &nandc->regs->ecc_buf_cfg, NAND_EBI2_ECC_BUF_CFG, 1, + NAND_BAM_NEXT_SGL); + } + +@@ -1294,13 +1253,13 @@ static void config_nand_cw_write(struct nand_chip *chip) + { + struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); + +- write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL); +- write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); ++ write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL); ++ write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); + + read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL); + +- write_reg_dma(nandc, NAND_FLASH_STATUS, 1, 0); +- write_reg_dma(nandc, NAND_READ_STATUS, 1, NAND_BAM_NEXT_SGL); ++ write_reg_dma(nandc, &nandc->regs->clrflashstatus, NAND_FLASH_STATUS, 1, 0); ++ write_reg_dma(nandc, &nandc->regs->clrreadstatus, NAND_READ_STATUS, 1, NAND_BAM_NEXT_SGL); + } + + /* helpers to submit/free our list of dma descriptors */ +@@ -1311,7 +1270,7 @@ static int submit_descs(struct qcom_nand_controller *nandc) + struct bam_transaction *bam_txn = nandc->bam_txn; + int ret = 0; + +- if (nandc->props->is_bam) { ++ if (nandc->props->supports_bam) { + if (bam_txn->rx_sgl_pos > bam_txn->rx_sgl_start) { + ret = prepare_bam_async_desc(nandc, nandc->rx_chan, 0); + if (ret) +@@ -1336,14 +1295,9 @@ static int submit_descs(struct qcom_nand_controller *nandc) + list_for_each_entry(desc, &nandc->desc_list, node) + cookie = dmaengine_submit(desc->dma_desc); + +- if (nandc->props->is_bam) { ++ if (nandc->props->supports_bam) { + bam_txn->last_cmd_desc->callback = qpic_bam_dma_done; + bam_txn->last_cmd_desc->callback_param = bam_txn; +- if (bam_txn->last_data_desc) { +- bam_txn->last_data_desc->callback = qpic_bam_dma_done; +- bam_txn->last_data_desc->callback_param = bam_txn; +- bam_txn->wait_second_completion = true; +- } + + dma_async_issue_pending(nandc->tx_chan); + dma_async_issue_pending(nandc->rx_chan); +@@ -1365,7 +1319,7 @@ static int submit_descs(struct qcom_nand_controller *nandc) + list_for_each_entry_safe(desc, n, &nandc->desc_list, node) { + list_del(&desc->node); + +- if (nandc->props->is_bam) ++ if (nandc->props->supports_bam) + dma_unmap_sg(nandc->dev, desc->bam_sgl, + desc->sgl_cnt, desc->dir); + else +@@ -1382,7 +1336,7 @@ static int submit_descs(struct qcom_nand_controller *nandc) + static void clear_read_regs(struct qcom_nand_controller *nandc) + { + nandc->reg_read_pos = 0; +- nandc_read_buffer_sync(nandc, false); ++ nandc_dev_to_mem(nandc, false); + } + + /* +@@ -1446,7 +1400,7 @@ static int check_flash_errors(struct qcom_nand_host *host, int cw_cnt) + struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); + int i; + +- nandc_read_buffer_sync(nandc, true); ++ nandc_dev_to_mem(nandc, true); + + for (i = 0; i < cw_cnt; i++) { + u32 flash = le32_to_cpu(nandc->reg_read_buf[i]); +@@ -1476,7 +1430,7 @@ qcom_nandc_read_cw_raw(struct mtd_info *mtd, struct nand_chip *chip, + clear_read_regs(nandc); + host->use_ecc = false; + +- if (nandc->props->qpic_v2) ++ if (nandc->props->qpic_version2) + raw_cw = ecc->steps - 1; + + clear_bam_transaction(nandc); +@@ -1497,7 +1451,7 @@ qcom_nandc_read_cw_raw(struct mtd_info *mtd, struct nand_chip *chip, + oob_size2 = host->ecc_bytes_hw + host->spare_bytes; + } + +- if (nandc->props->is_bam) { ++ if (nandc->props->supports_bam) { + nandc_set_read_loc(chip, cw, 0, read_loc, data_size1, 0); + read_loc += data_size1; + +@@ -1621,7 +1575,7 @@ static int parse_read_errors(struct qcom_nand_host *host, u8 *data_buf, + u8 *data_buf_start = data_buf, *oob_buf_start = oob_buf; + + buf = (struct read_stats *)nandc->reg_read_buf; +- nandc_read_buffer_sync(nandc, true); ++ nandc_dev_to_mem(nandc, true); + + for (i = 0; i < ecc->steps; i++, buf++) { + u32 flash, buffer, erased_cw; +@@ -1734,7 +1688,7 @@ static int read_page_ecc(struct qcom_nand_host *host, u8 *data_buf, + oob_size = host->ecc_bytes_hw + host->spare_bytes; + } + +- if (nandc->props->is_bam) { ++ if (nandc->props->supports_bam) { + if (data_buf && oob_buf) { + nandc_set_read_loc(chip, i, 0, 0, data_size, 0); + nandc_set_read_loc(chip, i, 1, data_size, +@@ -2455,14 +2409,14 @@ static int qcom_nand_attach_chip(struct nand_chip *chip) + + mtd_set_ooblayout(mtd, &qcom_nand_ooblayout_ops); + /* Free the initially allocated BAM transaction for reading the ONFI params */ +- if (nandc->props->is_bam) ++ if (nandc->props->supports_bam) + free_bam_transaction(nandc); + + nandc->max_cwperpage = max_t(unsigned int, nandc->max_cwperpage, + cwperpage); + + /* Now allocate the BAM transaction based on updated max_cwperpage */ +- if (nandc->props->is_bam) { ++ if (nandc->props->supports_bam) { + nandc->bam_txn = alloc_bam_transaction(nandc); + if (!nandc->bam_txn) { + dev_err(nandc->dev, +@@ -2522,7 +2476,7 @@ static int qcom_nand_attach_chip(struct nand_chip *chip) + | ecc_mode << ECC_MODE + | host->ecc_bytes_hw << ECC_PARITY_SIZE_BYTES_BCH; + +- if (!nandc->props->qpic_v2) ++ if (!nandc->props->qpic_version2) + host->ecc_buf_cfg = 0x203 << NUM_STEPS; + + host->clrflashstatus = FS_READY_BSY_N; +@@ -2556,7 +2510,7 @@ static int qcom_op_cmd_mapping(struct nand_chip *chip, u8 opcode, + cmd = OP_FETCH_ID; + break; + case NAND_CMD_PARAM: +- if (nandc->props->qpic_v2) ++ if (nandc->props->qpic_version2) + cmd = OP_PAGE_READ_ONFI_READ; + else + cmd = OP_PAGE_READ; +@@ -2609,7 +2563,7 @@ static int qcom_parse_instructions(struct nand_chip *chip, + if (ret < 0) + return ret; + +- q_op->cmd_reg = ret; ++ q_op->cmd_reg = cpu_to_le32(ret); + q_op->rdy_delay_ns = instr->delay_ns; + break; + +@@ -2619,10 +2573,10 @@ static int qcom_parse_instructions(struct nand_chip *chip, + addrs = &instr->ctx.addr.addrs[offset]; + + for (i = 0; i < min_t(unsigned int, 4, naddrs); i++) +- q_op->addr1_reg |= addrs[i] << (i * 8); ++ q_op->addr1_reg |= cpu_to_le32(addrs[i] << (i * 8)); + + if (naddrs > 4) +- q_op->addr2_reg |= addrs[4]; ++ q_op->addr2_reg |= cpu_to_le32(addrs[4]); + + q_op->rdy_delay_ns = instr->delay_ns; + break; +@@ -2663,7 +2617,7 @@ static int qcom_wait_rdy_poll(struct nand_chip *chip, unsigned int time_ms) + unsigned long start = jiffies + msecs_to_jiffies(time_ms); + u32 flash; + +- nandc_read_buffer_sync(nandc, true); ++ nandc_dev_to_mem(nandc, true); + + do { + flash = le32_to_cpu(nandc->reg_read_buf[0]); +@@ -2706,11 +2660,11 @@ static int qcom_read_status_exec(struct nand_chip *chip, + clear_read_regs(nandc); + clear_bam_transaction(nandc); + +- nandc_set_reg(chip, NAND_FLASH_CMD, q_op.cmd_reg); +- nandc_set_reg(chip, NAND_EXEC_CMD, 1); ++ nandc->regs->cmd = q_op.cmd_reg; ++ nandc->regs->exec = cpu_to_le32(1); + +- write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL); +- write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); ++ write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL); ++ write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); + read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL); + + ret = submit_descs(nandc); +@@ -2719,7 +2673,7 @@ static int qcom_read_status_exec(struct nand_chip *chip, + goto err_out; + } + +- nandc_read_buffer_sync(nandc, true); ++ nandc_dev_to_mem(nandc, true); + + for (i = 0; i < num_cw; i++) { + flash_status = le32_to_cpu(nandc->reg_read_buf[i]); +@@ -2763,16 +2717,14 @@ static int qcom_read_id_type_exec(struct nand_chip *chip, const struct nand_subo + clear_read_regs(nandc); + clear_bam_transaction(nandc); + +- nandc_set_reg(chip, NAND_FLASH_CMD, q_op.cmd_reg); +- nandc_set_reg(chip, NAND_ADDR0, q_op.addr1_reg); +- nandc_set_reg(chip, NAND_ADDR1, q_op.addr2_reg); +- nandc_set_reg(chip, NAND_FLASH_CHIP_SELECT, +- nandc->props->is_bam ? 0 : DM_EN); +- +- nandc_set_reg(chip, NAND_EXEC_CMD, 1); ++ nandc->regs->cmd = q_op.cmd_reg; ++ nandc->regs->addr0 = q_op.addr1_reg; ++ nandc->regs->addr1 = q_op.addr2_reg; ++ nandc->regs->chip_sel = cpu_to_le32(nandc->props->supports_bam ? 0 : DM_EN); ++ nandc->regs->exec = cpu_to_le32(1); + +- write_reg_dma(nandc, NAND_FLASH_CMD, 4, NAND_BAM_NEXT_SGL); +- write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); ++ write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 4, NAND_BAM_NEXT_SGL); ++ write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); + + read_reg_dma(nandc, NAND_READ_ID, 1, NAND_BAM_NEXT_SGL); + +@@ -2786,7 +2738,7 @@ static int qcom_read_id_type_exec(struct nand_chip *chip, const struct nand_subo + op_id = q_op.data_instr_idx; + len = nand_subop_get_data_len(subop, op_id); + +- nandc_read_buffer_sync(nandc, true); ++ nandc_dev_to_mem(nandc, true); + memcpy(instr->ctx.data.buf.in, nandc->reg_read_buf, len); + + err_out: +@@ -2807,15 +2759,14 @@ static int qcom_misc_cmd_type_exec(struct nand_chip *chip, const struct nand_sub + + if (q_op.flag == OP_PROGRAM_PAGE) { + goto wait_rdy; +- } else if (q_op.cmd_reg == OP_BLOCK_ERASE) { +- q_op.cmd_reg |= PAGE_ACC | LAST_PAGE; +- nandc_set_reg(chip, NAND_ADDR0, q_op.addr1_reg); +- nandc_set_reg(chip, NAND_ADDR1, q_op.addr2_reg); +- nandc_set_reg(chip, NAND_DEV0_CFG0, +- host->cfg0_raw & ~(7 << CW_PER_PAGE)); +- nandc_set_reg(chip, NAND_DEV0_CFG1, host->cfg1_raw); ++ } else if (q_op.cmd_reg == cpu_to_le32(OP_BLOCK_ERASE)) { ++ q_op.cmd_reg |= cpu_to_le32(PAGE_ACC | LAST_PAGE); ++ nandc->regs->addr0 = q_op.addr1_reg; ++ nandc->regs->addr1 = q_op.addr2_reg; ++ nandc->regs->cfg0 = cpu_to_le32(host->cfg0_raw & ~(7 << CW_PER_PAGE)); ++ nandc->regs->cfg1 = cpu_to_le32(host->cfg1_raw); + instrs = 3; +- } else if (q_op.cmd_reg != OP_RESET_DEVICE) { ++ } else if (q_op.cmd_reg != cpu_to_le32(OP_RESET_DEVICE)) { + return 0; + } + +@@ -2826,14 +2777,14 @@ static int qcom_misc_cmd_type_exec(struct nand_chip *chip, const struct nand_sub + clear_read_regs(nandc); + clear_bam_transaction(nandc); + +- nandc_set_reg(chip, NAND_FLASH_CMD, q_op.cmd_reg); +- nandc_set_reg(chip, NAND_EXEC_CMD, 1); ++ nandc->regs->cmd = q_op.cmd_reg; ++ nandc->regs->exec = cpu_to_le32(1); + +- write_reg_dma(nandc, NAND_FLASH_CMD, instrs, NAND_BAM_NEXT_SGL); +- if (q_op.cmd_reg == OP_BLOCK_ERASE) +- write_reg_dma(nandc, NAND_DEV0_CFG0, 2, NAND_BAM_NEXT_SGL); ++ write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, instrs, NAND_BAM_NEXT_SGL); ++ if (q_op.cmd_reg == cpu_to_le32(OP_BLOCK_ERASE)) ++ write_reg_dma(nandc, &nandc->regs->cfg0, NAND_DEV0_CFG0, 2, NAND_BAM_NEXT_SGL); + +- write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); ++ write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); + read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL); + + ret = submit_descs(nandc); +@@ -2862,14 +2813,14 @@ static int qcom_param_page_type_exec(struct nand_chip *chip, const struct nand_ + + reg_base = NAND_READ_LOCATION_0; + +- if (nandc->props->qpic_v2) ++ if (nandc->props->qpic_version2) + reg_base = NAND_READ_LOCATION_LAST_CW_0; + + ret = qcom_parse_instructions(chip, subop, &q_op); + if (ret) + return ret; + +- q_op.cmd_reg |= PAGE_ACC | LAST_PAGE; ++ q_op.cmd_reg |= cpu_to_le32(PAGE_ACC | LAST_PAGE); + + nandc->buf_count = 0; + nandc->buf_start = 0; +@@ -2877,52 +2828,52 @@ static int qcom_param_page_type_exec(struct nand_chip *chip, const struct nand_ + clear_read_regs(nandc); + clear_bam_transaction(nandc); + +- nandc_set_reg(chip, NAND_FLASH_CMD, q_op.cmd_reg); +- +- nandc_set_reg(chip, NAND_ADDR0, 0); +- nandc_set_reg(chip, NAND_ADDR1, 0); +- nandc_set_reg(chip, NAND_DEV0_CFG0, 0 << CW_PER_PAGE +- | 512 << UD_SIZE_BYTES +- | 5 << NUM_ADDR_CYCLES +- | 0 << SPARE_SIZE_BYTES); +- nandc_set_reg(chip, NAND_DEV0_CFG1, 7 << NAND_RECOVERY_CYCLES +- | 0 << CS_ACTIVE_BSY +- | 17 << BAD_BLOCK_BYTE_NUM +- | 1 << BAD_BLOCK_IN_SPARE_AREA +- | 2 << WR_RD_BSY_GAP +- | 0 << WIDE_FLASH +- | 1 << DEV0_CFG1_ECC_DISABLE); +- if (!nandc->props->qpic_v2) +- nandc_set_reg(chip, NAND_EBI2_ECC_BUF_CFG, 1 << ECC_CFG_ECC_DISABLE); ++ nandc->regs->cmd = q_op.cmd_reg; ++ nandc->regs->addr0 = 0; ++ nandc->regs->addr1 = 0; ++ ++ nandc->regs->cfg0 = cpu_to_le32(0 << CW_PER_PAGE | ++ 512 << UD_SIZE_BYTES | ++ 5 << NUM_ADDR_CYCLES | ++ 0 << SPARE_SIZE_BYTES); ++ ++ nandc->regs->cfg1 = cpu_to_le32(7 << NAND_RECOVERY_CYCLES | ++ 0 << CS_ACTIVE_BSY | ++ 17 << BAD_BLOCK_BYTE_NUM | ++ 1 << BAD_BLOCK_IN_SPARE_AREA | ++ 2 << WR_RD_BSY_GAP | ++ 0 << WIDE_FLASH | ++ 1 << DEV0_CFG1_ECC_DISABLE); ++ ++ if (!nandc->props->qpic_version2) ++ nandc->regs->ecc_buf_cfg = cpu_to_le32(1 << ECC_CFG_ECC_DISABLE); + + /* configure CMD1 and VLD for ONFI param probing in QPIC v1 */ +- if (!nandc->props->qpic_v2) { +- nandc_set_reg(chip, NAND_DEV_CMD_VLD, +- (nandc->vld & ~READ_START_VLD)); +- nandc_set_reg(chip, NAND_DEV_CMD1, +- (nandc->cmd1 & ~(0xFF << READ_ADDR)) +- | NAND_CMD_PARAM << READ_ADDR); ++ if (!nandc->props->qpic_version2) { ++ nandc->regs->vld = cpu_to_le32((nandc->vld & ~READ_START_VLD)); ++ nandc->regs->cmd1 = cpu_to_le32((nandc->cmd1 & ~(0xFF << READ_ADDR)) ++ | NAND_CMD_PARAM << READ_ADDR); + } + +- nandc_set_reg(chip, NAND_EXEC_CMD, 1); ++ nandc->regs->exec = cpu_to_le32(1); + +- if (!nandc->props->qpic_v2) { +- nandc_set_reg(chip, NAND_DEV_CMD1_RESTORE, nandc->cmd1); +- nandc_set_reg(chip, NAND_DEV_CMD_VLD_RESTORE, nandc->vld); ++ if (!nandc->props->qpic_version2) { ++ nandc->regs->orig_cmd1 = cpu_to_le32(nandc->cmd1); ++ nandc->regs->orig_vld = cpu_to_le32(nandc->vld); + } + + instr = q_op.data_instr; + op_id = q_op.data_instr_idx; + len = nand_subop_get_data_len(subop, op_id); + +- if (nandc->props->qpic_v2) ++ if (nandc->props->qpic_version2) + nandc_set_read_loc_last(chip, reg_base, 0, len, 1); + else + nandc_set_read_loc_first(chip, reg_base, 0, len, 1); + +- if (!nandc->props->qpic_v2) { +- write_reg_dma(nandc, NAND_DEV_CMD_VLD, 1, 0); +- write_reg_dma(nandc, NAND_DEV_CMD1, 1, NAND_BAM_NEXT_SGL); ++ if (!nandc->props->qpic_version2) { ++ write_reg_dma(nandc, &nandc->regs->vld, NAND_DEV_CMD_VLD, 1, 0); ++ write_reg_dma(nandc, &nandc->regs->cmd1, NAND_DEV_CMD1, 1, NAND_BAM_NEXT_SGL); + } + + nandc->buf_count = 512; +@@ -2934,9 +2885,10 @@ static int qcom_param_page_type_exec(struct nand_chip *chip, const struct nand_ + nandc->buf_count, 0); + + /* restore CMD1 and VLD regs */ +- if (!nandc->props->qpic_v2) { +- write_reg_dma(nandc, NAND_DEV_CMD1_RESTORE, 1, 0); +- write_reg_dma(nandc, NAND_DEV_CMD_VLD_RESTORE, 1, NAND_BAM_NEXT_SGL); ++ if (!nandc->props->qpic_version2) { ++ write_reg_dma(nandc, &nandc->regs->orig_cmd1, NAND_DEV_CMD1_RESTORE, 1, 0); ++ write_reg_dma(nandc, &nandc->regs->orig_vld, NAND_DEV_CMD_VLD_RESTORE, 1, ++ NAND_BAM_NEXT_SGL); + } + + ret = submit_descs(nandc); +@@ -3025,7 +2977,7 @@ static const struct nand_controller_ops qcom_nandc_ops = { + + static void qcom_nandc_unalloc(struct qcom_nand_controller *nandc) + { +- if (nandc->props->is_bam) { ++ if (nandc->props->supports_bam) { + if (!dma_mapping_error(nandc->dev, nandc->reg_read_dma)) + dma_unmap_single(nandc->dev, nandc->reg_read_dma, + MAX_REG_RD * +@@ -3078,7 +3030,7 @@ static int qcom_nandc_alloc(struct qcom_nand_controller *nandc) + if (!nandc->reg_read_buf) + return -ENOMEM; + +- if (nandc->props->is_bam) { ++ if (nandc->props->supports_bam) { + nandc->reg_read_dma = + dma_map_single(nandc->dev, nandc->reg_read_buf, + MAX_REG_RD * +@@ -3159,15 +3111,15 @@ static int qcom_nandc_setup(struct qcom_nand_controller *nandc) + u32 nand_ctrl; + + /* kill onenand */ +- if (!nandc->props->is_qpic) ++ if (!nandc->props->nandc_part_of_qpic) + nandc_write(nandc, SFLASHC_BURST_CFG, 0); + +- if (!nandc->props->qpic_v2) ++ if (!nandc->props->qpic_version2) + nandc_write(nandc, dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD), + NAND_DEV_CMD_VLD_VAL); + + /* enable ADM or BAM DMA */ +- if (nandc->props->is_bam) { ++ if (nandc->props->supports_bam) { + nand_ctrl = nandc_read(nandc, NAND_CTRL); + + /* +@@ -3184,7 +3136,7 @@ static int qcom_nandc_setup(struct qcom_nand_controller *nandc) + } + + /* save the original values of these registers */ +- if (!nandc->props->qpic_v2) { ++ if (!nandc->props->qpic_version2) { + nandc->cmd1 = nandc_read(nandc, dev_cmd_reg_addr(nandc, NAND_DEV_CMD1)); + nandc->vld = NAND_DEV_CMD_VLD_VAL; + } +@@ -3357,7 +3309,7 @@ static int qcom_nandc_parse_dt(struct platform_device *pdev) + struct device_node *np = nandc->dev->of_node; + int ret; + +- if (!nandc->props->is_bam) { ++ if (!nandc->props->supports_bam) { + ret = of_property_read_u32(np, "qcom,cmd-crci", + &nandc->cmd_crci); + if (ret) { +@@ -3482,30 +3434,30 @@ static void qcom_nandc_remove(struct platform_device *pdev) + + static const struct qcom_nandc_props ipq806x_nandc_props = { + .ecc_modes = (ECC_RS_4BIT | ECC_BCH_8BIT), +- .is_bam = false, ++ .supports_bam = false, + .use_codeword_fixup = true, + .dev_cmd_reg_start = 0x0, + }; + + static const struct qcom_nandc_props ipq4019_nandc_props = { + .ecc_modes = (ECC_BCH_4BIT | ECC_BCH_8BIT), +- .is_bam = true, +- .is_qpic = true, ++ .supports_bam = true, ++ .nandc_part_of_qpic = true, + .dev_cmd_reg_start = 0x0, + }; + + static const struct qcom_nandc_props ipq8074_nandc_props = { + .ecc_modes = (ECC_BCH_4BIT | ECC_BCH_8BIT), +- .is_bam = true, +- .is_qpic = true, ++ .supports_bam = true, ++ .nandc_part_of_qpic = true, + .dev_cmd_reg_start = 0x7000, + }; + + static const struct qcom_nandc_props sdx55_nandc_props = { + .ecc_modes = (ECC_BCH_4BIT | ECC_BCH_8BIT), +- .is_bam = true, +- .is_qpic = true, +- .qpic_v2 = true, ++ .supports_bam = true, ++ .nandc_part_of_qpic = true, ++ .qpic_version2 = true, + .dev_cmd_reg_start = 0x7000, + }; + +-- +2.51.0 + + +From 3eb84d95e970b09e7ceeff3bcae17bd351aeabe0 Mon Sep 17 00:00:00 2001 +From: Md Sadre Alam +Date: Wed, 20 Nov 2024 14:45:01 +0530 +Subject: [PATCH 011/517] mtd: rawnand: qcom: Add qcom prefix to common api + +Add qcom prefix to all the api which will be commonly +used by spi nand driver and raw nand driver. + +Reviewed-by: Konrad Dybcio +Signed-off-by: Md Sadre Alam +Signed-off-by: Miquel Raynal +--- + drivers/mtd/nand/raw/qcom_nandc.c | 320 +++++++++++++++--------------- + 1 file changed, 160 insertions(+), 160 deletions(-) + +diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c +index 94a57a0de067..ee73876f7244 100644 +--- a/drivers/mtd/nand/raw/qcom_nandc.c ++++ b/drivers/mtd/nand/raw/qcom_nandc.c +@@ -53,7 +53,7 @@ + #define NAND_READ_LOCATION_LAST_CW_2 0xf48 + #define NAND_READ_LOCATION_LAST_CW_3 0xf4c + +-/* dummy register offsets, used by write_reg_dma */ ++/* dummy register offsets, used by qcom_write_reg_dma */ + #define NAND_DEV_CMD1_RESTORE 0xdead + #define NAND_DEV_CMD_VLD_RESTORE 0xbeef + +@@ -211,7 +211,7 @@ + + /* + * Flags used in DMA descriptor preparation helper functions +- * (i.e. read_reg_dma/write_reg_dma/read_data_dma/write_data_dma) ++ * (i.e. qcom_read_reg_dma/qcom_write_reg_dma/qcom_read_data_dma/qcom_write_data_dma) + */ + /* Don't set the EOT in current tx BAM sgl */ + #define NAND_BAM_NO_EOT BIT(0) +@@ -550,7 +550,7 @@ struct qcom_nandc_props { + }; + + /* Frees the BAM transaction memory */ +-static void free_bam_transaction(struct qcom_nand_controller *nandc) ++static void qcom_free_bam_transaction(struct qcom_nand_controller *nandc) + { + struct bam_transaction *bam_txn = nandc->bam_txn; + +@@ -559,7 +559,7 @@ static void free_bam_transaction(struct qcom_nand_controller *nandc) + + /* Allocates and Initializes the BAM transaction */ + static struct bam_transaction * +-alloc_bam_transaction(struct qcom_nand_controller *nandc) ++qcom_alloc_bam_transaction(struct qcom_nand_controller *nandc) + { + struct bam_transaction *bam_txn; + size_t bam_txn_size; +@@ -595,7 +595,7 @@ alloc_bam_transaction(struct qcom_nand_controller *nandc) + } + + /* Clears the BAM transaction indexes */ +-static void clear_bam_transaction(struct qcom_nand_controller *nandc) ++static void qcom_clear_bam_transaction(struct qcom_nand_controller *nandc) + { + struct bam_transaction *bam_txn = nandc->bam_txn; + +@@ -614,7 +614,7 @@ static void clear_bam_transaction(struct qcom_nand_controller *nandc) + } + + /* Callback for DMA descriptor completion */ +-static void qpic_bam_dma_done(void *data) ++static void qcom_qpic_bam_dma_done(void *data) + { + struct bam_transaction *bam_txn = data; + +@@ -644,7 +644,7 @@ static void nandc_write(struct qcom_nand_controller *nandc, int offset, + iowrite32(val, nandc->base + offset); + } + +-static void nandc_dev_to_mem(struct qcom_nand_controller *nandc, bool is_cpu) ++static void qcom_nandc_dev_to_mem(struct qcom_nand_controller *nandc, bool is_cpu) + { + if (!nandc->props->supports_bam) + return; +@@ -824,9 +824,9 @@ static void update_rw_regs(struct qcom_nand_host *host, int num_cw, bool read, i + * for BAM. This descriptor will be added in the NAND DMA descriptor queue + * which will be submitted to DMA engine. + */ +-static int prepare_bam_async_desc(struct qcom_nand_controller *nandc, +- struct dma_chan *chan, +- unsigned long flags) ++static int qcom_prepare_bam_async_desc(struct qcom_nand_controller *nandc, ++ struct dma_chan *chan, ++ unsigned long flags) + { + struct desc_info *desc; + struct scatterlist *sgl; +@@ -903,9 +903,9 @@ static int prepare_bam_async_desc(struct qcom_nand_controller *nandc, + * NAND_BAM_NEXT_SGL will be used for starting the separate SGL + * after the current command element. + */ +-static int prep_bam_dma_desc_cmd(struct qcom_nand_controller *nandc, bool read, +- int reg_off, const void *vaddr, +- int size, unsigned int flags) ++static int qcom_prep_bam_dma_desc_cmd(struct qcom_nand_controller *nandc, bool read, ++ int reg_off, const void *vaddr, ++ int size, unsigned int flags) + { + int bam_ce_size; + int i, ret; +@@ -943,9 +943,9 @@ static int prep_bam_dma_desc_cmd(struct qcom_nand_controller *nandc, bool read, + bam_txn->bam_ce_start = bam_txn->bam_ce_pos; + + if (flags & NAND_BAM_NWD) { +- ret = prepare_bam_async_desc(nandc, nandc->cmd_chan, +- DMA_PREP_FENCE | +- DMA_PREP_CMD); ++ ret = qcom_prepare_bam_async_desc(nandc, nandc->cmd_chan, ++ DMA_PREP_FENCE | ++ DMA_PREP_CMD); + if (ret) + return ret; + } +@@ -958,9 +958,8 @@ static int prep_bam_dma_desc_cmd(struct qcom_nand_controller *nandc, bool read, + * Prepares the data descriptor for BAM DMA which will be used for NAND + * data reads and writes. + */ +-static int prep_bam_dma_desc_data(struct qcom_nand_controller *nandc, bool read, +- const void *vaddr, +- int size, unsigned int flags) ++static int qcom_prep_bam_dma_desc_data(struct qcom_nand_controller *nandc, bool read, ++ const void *vaddr, int size, unsigned int flags) + { + int ret; + struct bam_transaction *bam_txn = nandc->bam_txn; +@@ -979,8 +978,8 @@ static int prep_bam_dma_desc_data(struct qcom_nand_controller *nandc, bool read, + * is not set, form the DMA descriptor + */ + if (!(flags & NAND_BAM_NO_EOT)) { +- ret = prepare_bam_async_desc(nandc, nandc->tx_chan, +- DMA_PREP_INTERRUPT); ++ ret = qcom_prepare_bam_async_desc(nandc, nandc->tx_chan, ++ DMA_PREP_INTERRUPT); + if (ret) + return ret; + } +@@ -989,9 +988,9 @@ static int prep_bam_dma_desc_data(struct qcom_nand_controller *nandc, bool read, + return 0; + } + +-static int prep_adm_dma_desc(struct qcom_nand_controller *nandc, bool read, +- int reg_off, const void *vaddr, int size, +- bool flow_control) ++static int qcom_prep_adm_dma_desc(struct qcom_nand_controller *nandc, bool read, ++ int reg_off, const void *vaddr, int size, ++ bool flow_control) + { + struct desc_info *desc; + struct dma_async_tx_descriptor *dma_desc; +@@ -1069,15 +1068,15 @@ static int prep_adm_dma_desc(struct qcom_nand_controller *nandc, bool read, + } + + /* +- * read_reg_dma: prepares a descriptor to read a given number of ++ * qcom_read_reg_dma: prepares a descriptor to read a given number of + * contiguous registers to the reg_read_buf pointer + * + * @first: offset of the first register in the contiguous block + * @num_regs: number of registers to read + * @flags: flags to control DMA descriptor preparation + */ +-static int read_reg_dma(struct qcom_nand_controller *nandc, int first, +- int num_regs, unsigned int flags) ++static int qcom_read_reg_dma(struct qcom_nand_controller *nandc, int first, ++ int num_regs, unsigned int flags) + { + bool flow_control = false; + void *vaddr; +@@ -1089,18 +1088,18 @@ static int read_reg_dma(struct qcom_nand_controller *nandc, int first, + first = dev_cmd_reg_addr(nandc, first); + + if (nandc->props->supports_bam) +- return prep_bam_dma_desc_cmd(nandc, true, first, vaddr, ++ return qcom_prep_bam_dma_desc_cmd(nandc, true, first, vaddr, + num_regs, flags); + + if (first == NAND_READ_ID || first == NAND_FLASH_STATUS) + flow_control = true; + +- return prep_adm_dma_desc(nandc, true, first, vaddr, ++ return qcom_prep_adm_dma_desc(nandc, true, first, vaddr, + num_regs * sizeof(u32), flow_control); + } + + /* +- * write_reg_dma: prepares a descriptor to write a given number of ++ * qcom_write_reg_dma: prepares a descriptor to write a given number of + * contiguous registers + * + * @vaddr: contiguous memory from where register value will +@@ -1109,8 +1108,8 @@ static int read_reg_dma(struct qcom_nand_controller *nandc, int first, + * @num_regs: number of registers to write + * @flags: flags to control DMA descriptor preparation + */ +-static int write_reg_dma(struct qcom_nand_controller *nandc, __le32 *vaddr, +- int first, int num_regs, unsigned int flags) ++static int qcom_write_reg_dma(struct qcom_nand_controller *nandc, __le32 *vaddr, ++ int first, int num_regs, unsigned int flags) + { + bool flow_control = false; + +@@ -1124,18 +1123,18 @@ static int write_reg_dma(struct qcom_nand_controller *nandc, __le32 *vaddr, + first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD); + + if (nandc->props->supports_bam) +- return prep_bam_dma_desc_cmd(nandc, false, first, vaddr, ++ return qcom_prep_bam_dma_desc_cmd(nandc, false, first, vaddr, + num_regs, flags); + + if (first == NAND_FLASH_CMD) + flow_control = true; + +- return prep_adm_dma_desc(nandc, false, first, vaddr, ++ return qcom_prep_adm_dma_desc(nandc, false, first, vaddr, + num_regs * sizeof(u32), flow_control); + } + + /* +- * read_data_dma: prepares a DMA descriptor to transfer data from the ++ * qcom_read_data_dma: prepares a DMA descriptor to transfer data from the + * controller's internal buffer to the buffer 'vaddr' + * + * @reg_off: offset within the controller's data buffer +@@ -1143,17 +1142,17 @@ static int write_reg_dma(struct qcom_nand_controller *nandc, __le32 *vaddr, + * @size: DMA transaction size in bytes + * @flags: flags to control DMA descriptor preparation + */ +-static int read_data_dma(struct qcom_nand_controller *nandc, int reg_off, +- const u8 *vaddr, int size, unsigned int flags) ++static int qcom_read_data_dma(struct qcom_nand_controller *nandc, int reg_off, ++ const u8 *vaddr, int size, unsigned int flags) + { + if (nandc->props->supports_bam) +- return prep_bam_dma_desc_data(nandc, true, vaddr, size, flags); ++ return qcom_prep_bam_dma_desc_data(nandc, true, vaddr, size, flags); + +- return prep_adm_dma_desc(nandc, true, reg_off, vaddr, size, false); ++ return qcom_prep_adm_dma_desc(nandc, true, reg_off, vaddr, size, false); + } + + /* +- * write_data_dma: prepares a DMA descriptor to transfer data from ++ * qcom_write_data_dma: prepares a DMA descriptor to transfer data from + * 'vaddr' to the controller's internal buffer + * + * @reg_off: offset within the controller's data buffer +@@ -1161,13 +1160,13 @@ static int read_data_dma(struct qcom_nand_controller *nandc, int reg_off, + * @size: DMA transaction size in bytes + * @flags: flags to control DMA descriptor preparation + */ +-static int write_data_dma(struct qcom_nand_controller *nandc, int reg_off, +- const u8 *vaddr, int size, unsigned int flags) ++static int qcom_write_data_dma(struct qcom_nand_controller *nandc, int reg_off, ++ const u8 *vaddr, int size, unsigned int flags) + { + if (nandc->props->supports_bam) +- return prep_bam_dma_desc_data(nandc, false, vaddr, size, flags); ++ return qcom_prep_bam_dma_desc_data(nandc, false, vaddr, size, flags); + +- return prep_adm_dma_desc(nandc, false, reg_off, vaddr, size, false); ++ return qcom_prep_adm_dma_desc(nandc, false, reg_off, vaddr, size, false); + } + + /* +@@ -1178,14 +1177,14 @@ static void config_nand_page_read(struct nand_chip *chip) + { + struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); + +- write_reg_dma(nandc, &nandc->regs->addr0, NAND_ADDR0, 2, 0); +- write_reg_dma(nandc, &nandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0); ++ qcom_write_reg_dma(nandc, &nandc->regs->addr0, NAND_ADDR0, 2, 0); ++ qcom_write_reg_dma(nandc, &nandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0); + if (!nandc->props->qpic_version2) +- write_reg_dma(nandc, &nandc->regs->ecc_buf_cfg, NAND_EBI2_ECC_BUF_CFG, 1, 0); +- write_reg_dma(nandc, &nandc->regs->erased_cw_detect_cfg_clr, +- NAND_ERASED_CW_DETECT_CFG, 1, 0); +- write_reg_dma(nandc, &nandc->regs->erased_cw_detect_cfg_set, +- NAND_ERASED_CW_DETECT_CFG, 1, NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL); ++ qcom_write_reg_dma(nandc, &nandc->regs->ecc_buf_cfg, NAND_EBI2_ECC_BUF_CFG, 1, 0); ++ qcom_write_reg_dma(nandc, &nandc->regs->erased_cw_detect_cfg_clr, ++ NAND_ERASED_CW_DETECT_CFG, 1, 0); ++ qcom_write_reg_dma(nandc, &nandc->regs->erased_cw_detect_cfg_set, ++ NAND_ERASED_CW_DETECT_CFG, 1, NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL); + } + + /* +@@ -1204,17 +1203,17 @@ config_nand_cw_read(struct nand_chip *chip, bool use_ecc, int cw) + reg = &nandc->regs->read_location_last0; + + if (nandc->props->supports_bam) +- write_reg_dma(nandc, reg, NAND_READ_LOCATION_0, 4, NAND_BAM_NEXT_SGL); ++ qcom_write_reg_dma(nandc, reg, NAND_READ_LOCATION_0, 4, NAND_BAM_NEXT_SGL); + +- write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL); +- write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); ++ qcom_write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL); ++ qcom_write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); + + if (use_ecc) { +- read_reg_dma(nandc, NAND_FLASH_STATUS, 2, 0); +- read_reg_dma(nandc, NAND_ERASED_CW_DETECT_STATUS, 1, +- NAND_BAM_NEXT_SGL); ++ qcom_read_reg_dma(nandc, NAND_FLASH_STATUS, 2, 0); ++ qcom_read_reg_dma(nandc, NAND_ERASED_CW_DETECT_STATUS, 1, ++ NAND_BAM_NEXT_SGL); + } else { +- read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL); ++ qcom_read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL); + } + } + +@@ -1238,11 +1237,11 @@ static void config_nand_page_write(struct nand_chip *chip) + { + struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); + +- write_reg_dma(nandc, &nandc->regs->addr0, NAND_ADDR0, 2, 0); +- write_reg_dma(nandc, &nandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0); ++ qcom_write_reg_dma(nandc, &nandc->regs->addr0, NAND_ADDR0, 2, 0); ++ qcom_write_reg_dma(nandc, &nandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0); + if (!nandc->props->qpic_version2) +- write_reg_dma(nandc, &nandc->regs->ecc_buf_cfg, NAND_EBI2_ECC_BUF_CFG, 1, +- NAND_BAM_NEXT_SGL); ++ qcom_write_reg_dma(nandc, &nandc->regs->ecc_buf_cfg, NAND_EBI2_ECC_BUF_CFG, 1, ++ NAND_BAM_NEXT_SGL); + } + + /* +@@ -1253,17 +1252,18 @@ static void config_nand_cw_write(struct nand_chip *chip) + { + struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); + +- write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL); +- write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); ++ qcom_write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL); ++ qcom_write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); + +- read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL); ++ qcom_read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL); + +- write_reg_dma(nandc, &nandc->regs->clrflashstatus, NAND_FLASH_STATUS, 1, 0); +- write_reg_dma(nandc, &nandc->regs->clrreadstatus, NAND_READ_STATUS, 1, NAND_BAM_NEXT_SGL); ++ qcom_write_reg_dma(nandc, &nandc->regs->clrflashstatus, NAND_FLASH_STATUS, 1, 0); ++ qcom_write_reg_dma(nandc, &nandc->regs->clrreadstatus, NAND_READ_STATUS, 1, ++ NAND_BAM_NEXT_SGL); + } + + /* helpers to submit/free our list of dma descriptors */ +-static int submit_descs(struct qcom_nand_controller *nandc) ++static int qcom_submit_descs(struct qcom_nand_controller *nandc) + { + struct desc_info *desc, *n; + dma_cookie_t cookie = 0; +@@ -1272,21 +1272,21 @@ static int submit_descs(struct qcom_nand_controller *nandc) + + if (nandc->props->supports_bam) { + if (bam_txn->rx_sgl_pos > bam_txn->rx_sgl_start) { +- ret = prepare_bam_async_desc(nandc, nandc->rx_chan, 0); ++ ret = qcom_prepare_bam_async_desc(nandc, nandc->rx_chan, 0); + if (ret) + goto err_unmap_free_desc; + } + + if (bam_txn->tx_sgl_pos > bam_txn->tx_sgl_start) { +- ret = prepare_bam_async_desc(nandc, nandc->tx_chan, +- DMA_PREP_INTERRUPT); ++ ret = qcom_prepare_bam_async_desc(nandc, nandc->tx_chan, ++ DMA_PREP_INTERRUPT); + if (ret) + goto err_unmap_free_desc; + } + + if (bam_txn->cmd_sgl_pos > bam_txn->cmd_sgl_start) { +- ret = prepare_bam_async_desc(nandc, nandc->cmd_chan, +- DMA_PREP_CMD); ++ ret = qcom_prepare_bam_async_desc(nandc, nandc->cmd_chan, ++ DMA_PREP_CMD); + if (ret) + goto err_unmap_free_desc; + } +@@ -1296,7 +1296,7 @@ static int submit_descs(struct qcom_nand_controller *nandc) + cookie = dmaengine_submit(desc->dma_desc); + + if (nandc->props->supports_bam) { +- bam_txn->last_cmd_desc->callback = qpic_bam_dma_done; ++ bam_txn->last_cmd_desc->callback = qcom_qpic_bam_dma_done; + bam_txn->last_cmd_desc->callback_param = bam_txn; + + dma_async_issue_pending(nandc->tx_chan); +@@ -1314,7 +1314,7 @@ static int submit_descs(struct qcom_nand_controller *nandc) + err_unmap_free_desc: + /* + * Unmap the dma sg_list and free the desc allocated by both +- * prepare_bam_async_desc() and prep_adm_dma_desc() functions. ++ * qcom_prepare_bam_async_desc() and qcom_prep_adm_dma_desc() functions. + */ + list_for_each_entry_safe(desc, n, &nandc->desc_list, node) { + list_del(&desc->node); +@@ -1333,10 +1333,10 @@ static int submit_descs(struct qcom_nand_controller *nandc) + } + + /* reset the register read buffer for next NAND operation */ +-static void clear_read_regs(struct qcom_nand_controller *nandc) ++static void qcom_clear_read_regs(struct qcom_nand_controller *nandc) + { + nandc->reg_read_pos = 0; +- nandc_dev_to_mem(nandc, false); ++ qcom_nandc_dev_to_mem(nandc, false); + } + + /* +@@ -1400,7 +1400,7 @@ static int check_flash_errors(struct qcom_nand_host *host, int cw_cnt) + struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); + int i; + +- nandc_dev_to_mem(nandc, true); ++ qcom_nandc_dev_to_mem(nandc, true); + + for (i = 0; i < cw_cnt; i++) { + u32 flash = le32_to_cpu(nandc->reg_read_buf[i]); +@@ -1427,13 +1427,13 @@ qcom_nandc_read_cw_raw(struct mtd_info *mtd, struct nand_chip *chip, + nand_read_page_op(chip, page, 0, NULL, 0); + nandc->buf_count = 0; + nandc->buf_start = 0; +- clear_read_regs(nandc); ++ qcom_clear_read_regs(nandc); + host->use_ecc = false; + + if (nandc->props->qpic_version2) + raw_cw = ecc->steps - 1; + +- clear_bam_transaction(nandc); ++ qcom_clear_bam_transaction(nandc); + set_address(host, host->cw_size * cw, page); + update_rw_regs(host, 1, true, raw_cw); + config_nand_page_read(chip); +@@ -1466,18 +1466,18 @@ qcom_nandc_read_cw_raw(struct mtd_info *mtd, struct nand_chip *chip, + + config_nand_cw_read(chip, false, raw_cw); + +- read_data_dma(nandc, reg_off, data_buf, data_size1, 0); ++ qcom_read_data_dma(nandc, reg_off, data_buf, data_size1, 0); + reg_off += data_size1; + +- read_data_dma(nandc, reg_off, oob_buf, oob_size1, 0); ++ qcom_read_data_dma(nandc, reg_off, oob_buf, oob_size1, 0); + reg_off += oob_size1; + +- read_data_dma(nandc, reg_off, data_buf + data_size1, data_size2, 0); ++ qcom_read_data_dma(nandc, reg_off, data_buf + data_size1, data_size2, 0); + reg_off += data_size2; + +- read_data_dma(nandc, reg_off, oob_buf + oob_size1, oob_size2, 0); ++ qcom_read_data_dma(nandc, reg_off, oob_buf + oob_size1, oob_size2, 0); + +- ret = submit_descs(nandc); ++ ret = qcom_submit_descs(nandc); + if (ret) { + dev_err(nandc->dev, "failure to read raw cw %d\n", cw); + return ret; +@@ -1575,7 +1575,7 @@ static int parse_read_errors(struct qcom_nand_host *host, u8 *data_buf, + u8 *data_buf_start = data_buf, *oob_buf_start = oob_buf; + + buf = (struct read_stats *)nandc->reg_read_buf; +- nandc_dev_to_mem(nandc, true); ++ qcom_nandc_dev_to_mem(nandc, true); + + for (i = 0; i < ecc->steps; i++, buf++) { + u32 flash, buffer, erased_cw; +@@ -1704,8 +1704,8 @@ static int read_page_ecc(struct qcom_nand_host *host, u8 *data_buf, + config_nand_cw_read(chip, true, i); + + if (data_buf) +- read_data_dma(nandc, FLASH_BUF_ACC, data_buf, +- data_size, 0); ++ qcom_read_data_dma(nandc, FLASH_BUF_ACC, data_buf, ++ data_size, 0); + + /* + * when ecc is enabled, the controller doesn't read the real +@@ -1720,8 +1720,8 @@ static int read_page_ecc(struct qcom_nand_host *host, u8 *data_buf, + for (j = 0; j < host->bbm_size; j++) + *oob_buf++ = 0xff; + +- read_data_dma(nandc, FLASH_BUF_ACC + data_size, +- oob_buf, oob_size, 0); ++ qcom_read_data_dma(nandc, FLASH_BUF_ACC + data_size, ++ oob_buf, oob_size, 0); + } + + if (data_buf) +@@ -1730,7 +1730,7 @@ static int read_page_ecc(struct qcom_nand_host *host, u8 *data_buf, + oob_buf += oob_size; + } + +- ret = submit_descs(nandc); ++ ret = qcom_submit_descs(nandc); + if (ret) { + dev_err(nandc->dev, "failure to read page/oob\n"); + return ret; +@@ -1751,7 +1751,7 @@ static int copy_last_cw(struct qcom_nand_host *host, int page) + int size; + int ret; + +- clear_read_regs(nandc); ++ qcom_clear_read_regs(nandc); + + size = host->use_ecc ? host->cw_data : host->cw_size; + +@@ -1763,9 +1763,9 @@ static int copy_last_cw(struct qcom_nand_host *host, int page) + + config_nand_single_cw_page_read(chip, host->use_ecc, ecc->steps - 1); + +- read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer, size, 0); ++ qcom_read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer, size, 0); + +- ret = submit_descs(nandc); ++ ret = qcom_submit_descs(nandc); + if (ret) + dev_err(nandc->dev, "failed to copy last codeword\n"); + +@@ -1851,14 +1851,14 @@ static int qcom_nandc_read_page(struct nand_chip *chip, u8 *buf, + nandc->buf_count = 0; + nandc->buf_start = 0; + host->use_ecc = true; +- clear_read_regs(nandc); ++ qcom_clear_read_regs(nandc); + set_address(host, 0, page); + update_rw_regs(host, ecc->steps, true, 0); + + data_buf = buf; + oob_buf = oob_required ? chip->oob_poi : NULL; + +- clear_bam_transaction(nandc); ++ qcom_clear_bam_transaction(nandc); + + return read_page_ecc(host, data_buf, oob_buf, page); + } +@@ -1899,8 +1899,8 @@ static int qcom_nandc_read_oob(struct nand_chip *chip, int page) + if (host->nr_boot_partitions) + qcom_nandc_codeword_fixup(host, page); + +- clear_read_regs(nandc); +- clear_bam_transaction(nandc); ++ qcom_clear_read_regs(nandc); ++ qcom_clear_bam_transaction(nandc); + + host->use_ecc = true; + set_address(host, 0, page); +@@ -1927,8 +1927,8 @@ static int qcom_nandc_write_page(struct nand_chip *chip, const u8 *buf, + set_address(host, 0, page); + nandc->buf_count = 0; + nandc->buf_start = 0; +- clear_read_regs(nandc); +- clear_bam_transaction(nandc); ++ qcom_clear_read_regs(nandc); ++ qcom_clear_bam_transaction(nandc); + + data_buf = (u8 *)buf; + oob_buf = chip->oob_poi; +@@ -1949,8 +1949,8 @@ static int qcom_nandc_write_page(struct nand_chip *chip, const u8 *buf, + oob_size = ecc->bytes; + } + +- write_data_dma(nandc, FLASH_BUF_ACC, data_buf, data_size, +- i == (ecc->steps - 1) ? NAND_BAM_NO_EOT : 0); ++ qcom_write_data_dma(nandc, FLASH_BUF_ACC, data_buf, data_size, ++ i == (ecc->steps - 1) ? NAND_BAM_NO_EOT : 0); + + /* + * when ECC is enabled, we don't really need to write anything +@@ -1962,8 +1962,8 @@ static int qcom_nandc_write_page(struct nand_chip *chip, const u8 *buf, + if (qcom_nandc_is_last_cw(ecc, i)) { + oob_buf += host->bbm_size; + +- write_data_dma(nandc, FLASH_BUF_ACC + data_size, +- oob_buf, oob_size, 0); ++ qcom_write_data_dma(nandc, FLASH_BUF_ACC + data_size, ++ oob_buf, oob_size, 0); + } + + config_nand_cw_write(chip); +@@ -1972,7 +1972,7 @@ static int qcom_nandc_write_page(struct nand_chip *chip, const u8 *buf, + oob_buf += oob_size; + } + +- ret = submit_descs(nandc); ++ ret = qcom_submit_descs(nandc); + if (ret) { + dev_err(nandc->dev, "failure to write page\n"); + return ret; +@@ -1997,8 +1997,8 @@ static int qcom_nandc_write_page_raw(struct nand_chip *chip, + qcom_nandc_codeword_fixup(host, page); + + nand_prog_page_begin_op(chip, page, 0, NULL, 0); +- clear_read_regs(nandc); +- clear_bam_transaction(nandc); ++ qcom_clear_read_regs(nandc); ++ qcom_clear_bam_transaction(nandc); + + data_buf = (u8 *)buf; + oob_buf = chip->oob_poi; +@@ -2024,28 +2024,28 @@ static int qcom_nandc_write_page_raw(struct nand_chip *chip, + oob_size2 = host->ecc_bytes_hw + host->spare_bytes; + } + +- write_data_dma(nandc, reg_off, data_buf, data_size1, +- NAND_BAM_NO_EOT); ++ qcom_write_data_dma(nandc, reg_off, data_buf, data_size1, ++ NAND_BAM_NO_EOT); + reg_off += data_size1; + data_buf += data_size1; + +- write_data_dma(nandc, reg_off, oob_buf, oob_size1, +- NAND_BAM_NO_EOT); ++ qcom_write_data_dma(nandc, reg_off, oob_buf, oob_size1, ++ NAND_BAM_NO_EOT); + reg_off += oob_size1; + oob_buf += oob_size1; + +- write_data_dma(nandc, reg_off, data_buf, data_size2, +- NAND_BAM_NO_EOT); ++ qcom_write_data_dma(nandc, reg_off, data_buf, data_size2, ++ NAND_BAM_NO_EOT); + reg_off += data_size2; + data_buf += data_size2; + +- write_data_dma(nandc, reg_off, oob_buf, oob_size2, 0); ++ qcom_write_data_dma(nandc, reg_off, oob_buf, oob_size2, 0); + oob_buf += oob_size2; + + config_nand_cw_write(chip); + } + +- ret = submit_descs(nandc); ++ ret = qcom_submit_descs(nandc); + if (ret) { + dev_err(nandc->dev, "failure to write raw page\n"); + return ret; +@@ -2075,7 +2075,7 @@ static int qcom_nandc_write_oob(struct nand_chip *chip, int page) + qcom_nandc_codeword_fixup(host, page); + + host->use_ecc = true; +- clear_bam_transaction(nandc); ++ qcom_clear_bam_transaction(nandc); + + /* calculate the data and oob size for the last codeword/step */ + data_size = ecc->size - ((ecc->steps - 1) << 2); +@@ -2090,11 +2090,11 @@ static int qcom_nandc_write_oob(struct nand_chip *chip, int page) + update_rw_regs(host, 1, false, 0); + + config_nand_page_write(chip); +- write_data_dma(nandc, FLASH_BUF_ACC, +- nandc->data_buffer, data_size + oob_size, 0); ++ qcom_write_data_dma(nandc, FLASH_BUF_ACC, ++ nandc->data_buffer, data_size + oob_size, 0); + config_nand_cw_write(chip); + +- ret = submit_descs(nandc); ++ ret = qcom_submit_descs(nandc); + if (ret) { + dev_err(nandc->dev, "failure to write oob\n"); + return ret; +@@ -2121,7 +2121,7 @@ static int qcom_nandc_block_bad(struct nand_chip *chip, loff_t ofs) + */ + host->use_ecc = false; + +- clear_bam_transaction(nandc); ++ qcom_clear_bam_transaction(nandc); + ret = copy_last_cw(host, page); + if (ret) + goto err; +@@ -2148,8 +2148,8 @@ static int qcom_nandc_block_markbad(struct nand_chip *chip, loff_t ofs) + struct nand_ecc_ctrl *ecc = &chip->ecc; + int page, ret; + +- clear_read_regs(nandc); +- clear_bam_transaction(nandc); ++ qcom_clear_read_regs(nandc); ++ qcom_clear_bam_transaction(nandc); + + /* + * to mark the BBM as bad, we flash the entire last codeword with 0s. +@@ -2166,11 +2166,11 @@ static int qcom_nandc_block_markbad(struct nand_chip *chip, loff_t ofs) + update_rw_regs(host, 1, false, ecc->steps - 1); + + config_nand_page_write(chip); +- write_data_dma(nandc, FLASH_BUF_ACC, +- nandc->data_buffer, host->cw_size, 0); ++ qcom_write_data_dma(nandc, FLASH_BUF_ACC, ++ nandc->data_buffer, host->cw_size, 0); + config_nand_cw_write(chip); + +- ret = submit_descs(nandc); ++ ret = qcom_submit_descs(nandc); + if (ret) { + dev_err(nandc->dev, "failure to update BBM\n"); + return ret; +@@ -2410,14 +2410,14 @@ static int qcom_nand_attach_chip(struct nand_chip *chip) + mtd_set_ooblayout(mtd, &qcom_nand_ooblayout_ops); + /* Free the initially allocated BAM transaction for reading the ONFI params */ + if (nandc->props->supports_bam) +- free_bam_transaction(nandc); ++ qcom_free_bam_transaction(nandc); + + nandc->max_cwperpage = max_t(unsigned int, nandc->max_cwperpage, + cwperpage); + + /* Now allocate the BAM transaction based on updated max_cwperpage */ + if (nandc->props->supports_bam) { +- nandc->bam_txn = alloc_bam_transaction(nandc); ++ nandc->bam_txn = qcom_alloc_bam_transaction(nandc); + if (!nandc->bam_txn) { + dev_err(nandc->dev, + "failed to allocate bam transaction\n"); +@@ -2617,7 +2617,7 @@ static int qcom_wait_rdy_poll(struct nand_chip *chip, unsigned int time_ms) + unsigned long start = jiffies + msecs_to_jiffies(time_ms); + u32 flash; + +- nandc_dev_to_mem(nandc, true); ++ qcom_nandc_dev_to_mem(nandc, true); + + do { + flash = le32_to_cpu(nandc->reg_read_buf[0]); +@@ -2657,23 +2657,23 @@ static int qcom_read_status_exec(struct nand_chip *chip, + nandc->buf_start = 0; + host->use_ecc = false; + +- clear_read_regs(nandc); +- clear_bam_transaction(nandc); ++ qcom_clear_read_regs(nandc); ++ qcom_clear_bam_transaction(nandc); + + nandc->regs->cmd = q_op.cmd_reg; + nandc->regs->exec = cpu_to_le32(1); + +- write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL); +- write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); +- read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL); ++ qcom_write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL); ++ qcom_write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); ++ qcom_read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL); + +- ret = submit_descs(nandc); ++ ret = qcom_submit_descs(nandc); + if (ret) { + dev_err(nandc->dev, "failure in submitting status descriptor\n"); + goto err_out; + } + +- nandc_dev_to_mem(nandc, true); ++ qcom_nandc_dev_to_mem(nandc, true); + + for (i = 0; i < num_cw; i++) { + flash_status = le32_to_cpu(nandc->reg_read_buf[i]); +@@ -2714,8 +2714,8 @@ static int qcom_read_id_type_exec(struct nand_chip *chip, const struct nand_subo + nandc->buf_start = 0; + host->use_ecc = false; + +- clear_read_regs(nandc); +- clear_bam_transaction(nandc); ++ qcom_clear_read_regs(nandc); ++ qcom_clear_bam_transaction(nandc); + + nandc->regs->cmd = q_op.cmd_reg; + nandc->regs->addr0 = q_op.addr1_reg; +@@ -2723,12 +2723,12 @@ static int qcom_read_id_type_exec(struct nand_chip *chip, const struct nand_subo + nandc->regs->chip_sel = cpu_to_le32(nandc->props->supports_bam ? 0 : DM_EN); + nandc->regs->exec = cpu_to_le32(1); + +- write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 4, NAND_BAM_NEXT_SGL); +- write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); ++ qcom_write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 4, NAND_BAM_NEXT_SGL); ++ qcom_write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); + +- read_reg_dma(nandc, NAND_READ_ID, 1, NAND_BAM_NEXT_SGL); ++ qcom_read_reg_dma(nandc, NAND_READ_ID, 1, NAND_BAM_NEXT_SGL); + +- ret = submit_descs(nandc); ++ ret = qcom_submit_descs(nandc); + if (ret) { + dev_err(nandc->dev, "failure in submitting read id descriptor\n"); + goto err_out; +@@ -2738,7 +2738,7 @@ static int qcom_read_id_type_exec(struct nand_chip *chip, const struct nand_subo + op_id = q_op.data_instr_idx; + len = nand_subop_get_data_len(subop, op_id); + +- nandc_dev_to_mem(nandc, true); ++ qcom_nandc_dev_to_mem(nandc, true); + memcpy(instr->ctx.data.buf.in, nandc->reg_read_buf, len); + + err_out: +@@ -2774,20 +2774,20 @@ static int qcom_misc_cmd_type_exec(struct nand_chip *chip, const struct nand_sub + nandc->buf_start = 0; + host->use_ecc = false; + +- clear_read_regs(nandc); +- clear_bam_transaction(nandc); ++ qcom_clear_read_regs(nandc); ++ qcom_clear_bam_transaction(nandc); + + nandc->regs->cmd = q_op.cmd_reg; + nandc->regs->exec = cpu_to_le32(1); + +- write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, instrs, NAND_BAM_NEXT_SGL); ++ qcom_write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, instrs, NAND_BAM_NEXT_SGL); + if (q_op.cmd_reg == cpu_to_le32(OP_BLOCK_ERASE)) +- write_reg_dma(nandc, &nandc->regs->cfg0, NAND_DEV0_CFG0, 2, NAND_BAM_NEXT_SGL); ++ qcom_write_reg_dma(nandc, &nandc->regs->cfg0, NAND_DEV0_CFG0, 2, NAND_BAM_NEXT_SGL); + +- write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); +- read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL); ++ qcom_write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); ++ qcom_read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL); + +- ret = submit_descs(nandc); ++ ret = qcom_submit_descs(nandc); + if (ret) { + dev_err(nandc->dev, "failure in submitting misc descriptor\n"); + goto err_out; +@@ -2825,8 +2825,8 @@ static int qcom_param_page_type_exec(struct nand_chip *chip, const struct nand_ + nandc->buf_count = 0; + nandc->buf_start = 0; + host->use_ecc = false; +- clear_read_regs(nandc); +- clear_bam_transaction(nandc); ++ qcom_clear_read_regs(nandc); ++ qcom_clear_bam_transaction(nandc); + + nandc->regs->cmd = q_op.cmd_reg; + nandc->regs->addr0 = 0; +@@ -2872,8 +2872,8 @@ static int qcom_param_page_type_exec(struct nand_chip *chip, const struct nand_ + nandc_set_read_loc_first(chip, reg_base, 0, len, 1); + + if (!nandc->props->qpic_version2) { +- write_reg_dma(nandc, &nandc->regs->vld, NAND_DEV_CMD_VLD, 1, 0); +- write_reg_dma(nandc, &nandc->regs->cmd1, NAND_DEV_CMD1, 1, NAND_BAM_NEXT_SGL); ++ qcom_write_reg_dma(nandc, &nandc->regs->vld, NAND_DEV_CMD_VLD, 1, 0); ++ qcom_write_reg_dma(nandc, &nandc->regs->cmd1, NAND_DEV_CMD1, 1, NAND_BAM_NEXT_SGL); + } + + nandc->buf_count = 512; +@@ -2881,17 +2881,17 @@ static int qcom_param_page_type_exec(struct nand_chip *chip, const struct nand_ + + config_nand_single_cw_page_read(chip, false, 0); + +- read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer, +- nandc->buf_count, 0); ++ qcom_read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer, ++ nandc->buf_count, 0); + + /* restore CMD1 and VLD regs */ + if (!nandc->props->qpic_version2) { +- write_reg_dma(nandc, &nandc->regs->orig_cmd1, NAND_DEV_CMD1_RESTORE, 1, 0); +- write_reg_dma(nandc, &nandc->regs->orig_vld, NAND_DEV_CMD_VLD_RESTORE, 1, +- NAND_BAM_NEXT_SGL); ++ qcom_write_reg_dma(nandc, &nandc->regs->orig_cmd1, NAND_DEV_CMD1_RESTORE, 1, 0); ++ qcom_write_reg_dma(nandc, &nandc->regs->orig_vld, NAND_DEV_CMD_VLD_RESTORE, 1, ++ NAND_BAM_NEXT_SGL); + } + +- ret = submit_descs(nandc); ++ ret = qcom_submit_descs(nandc); + if (ret) { + dev_err(nandc->dev, "failure in submitting param page descriptor\n"); + goto err_out; +@@ -3075,7 +3075,7 @@ static int qcom_nandc_alloc(struct qcom_nand_controller *nandc) + * maximum codeword size + */ + nandc->max_cwperpage = 1; +- nandc->bam_txn = alloc_bam_transaction(nandc); ++ nandc->bam_txn = qcom_alloc_bam_transaction(nandc); + if (!nandc->bam_txn) { + dev_err(nandc->dev, + "failed to allocate bam transaction\n"); +-- +2.51.0 + + +From 6c04b5738159ccfc2447219245c49e71c7428db0 Mon Sep 17 00:00:00 2001 +From: Md Sadre Alam +Date: Wed, 20 Nov 2024 14:45:02 +0530 +Subject: [PATCH 012/517] mtd: nand: Add qpic_common API file + +Add qpic_common.c file which hold all the common +qpic APIs which will be used by both qpic raw nand +driver and qpic spi nand driver. + +Signed-off-by: Md Sadre Alam +Signed-off-by: Miquel Raynal +--- + drivers/mtd/nand/Makefile | 2 +- + drivers/mtd/nand/qpic_common.c | 759 ++++++++++++++++++ + drivers/mtd/nand/raw/qcom_nandc.c | 1092 +------------------------- + include/linux/mtd/nand-qpic-common.h | 468 +++++++++++ + 4 files changed, 1240 insertions(+), 1081 deletions(-) + create mode 100644 drivers/mtd/nand/qpic_common.c + create mode 100644 include/linux/mtd/nand-qpic-common.h + +diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile +index 19e1291ac4d5..da1586a36574 100644 +--- a/drivers/mtd/nand/Makefile ++++ b/drivers/mtd/nand/Makefile +@@ -3,7 +3,7 @@ + nandcore-objs := core.o bbt.o + obj-$(CONFIG_MTD_NAND_CORE) += nandcore.o + obj-$(CONFIG_MTD_NAND_ECC_MEDIATEK) += ecc-mtk.o +- ++obj-$(CONFIG_MTD_NAND_QCOM) += qpic_common.o + obj-y += onenand/ + obj-y += raw/ + obj-y += spi/ +diff --git a/drivers/mtd/nand/qpic_common.c b/drivers/mtd/nand/qpic_common.c +new file mode 100644 +index 000000000000..8abbb960a7ce +--- /dev/null ++++ b/drivers/mtd/nand/qpic_common.c +@@ -0,0 +1,759 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Copyright (c) 2016, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/** ++ * qcom_free_bam_transaction() - Frees the BAM transaction memory ++ * @nandc: qpic nand controller ++ * ++ * This function frees the bam transaction memory ++ */ ++void qcom_free_bam_transaction(struct qcom_nand_controller *nandc) ++{ ++ struct bam_transaction *bam_txn = nandc->bam_txn; ++ ++ kfree(bam_txn); ++} ++EXPORT_SYMBOL(qcom_free_bam_transaction); ++ ++/** ++ * qcom_alloc_bam_transaction() - allocate BAM transaction ++ * @nandc: qpic nand controller ++ * ++ * This function will allocate and initialize the BAM transaction structure ++ */ ++struct bam_transaction * ++qcom_alloc_bam_transaction(struct qcom_nand_controller *nandc) ++{ ++ struct bam_transaction *bam_txn; ++ size_t bam_txn_size; ++ unsigned int num_cw = nandc->max_cwperpage; ++ void *bam_txn_buf; ++ ++ bam_txn_size = ++ sizeof(*bam_txn) + num_cw * ++ ((sizeof(*bam_txn->bam_ce) * QPIC_PER_CW_CMD_ELEMENTS) + ++ (sizeof(*bam_txn->cmd_sgl) * QPIC_PER_CW_CMD_SGL) + ++ (sizeof(*bam_txn->data_sgl) * QPIC_PER_CW_DATA_SGL)); ++ ++ bam_txn_buf = kzalloc(bam_txn_size, GFP_KERNEL); ++ if (!bam_txn_buf) ++ return NULL; ++ ++ bam_txn = bam_txn_buf; ++ bam_txn_buf += sizeof(*bam_txn); ++ ++ bam_txn->bam_ce = bam_txn_buf; ++ bam_txn_buf += ++ sizeof(*bam_txn->bam_ce) * QPIC_PER_CW_CMD_ELEMENTS * num_cw; ++ ++ bam_txn->cmd_sgl = bam_txn_buf; ++ bam_txn_buf += ++ sizeof(*bam_txn->cmd_sgl) * QPIC_PER_CW_CMD_SGL * num_cw; ++ ++ bam_txn->data_sgl = bam_txn_buf; ++ ++ init_completion(&bam_txn->txn_done); ++ ++ return bam_txn; ++} ++EXPORT_SYMBOL(qcom_alloc_bam_transaction); ++ ++/** ++ * qcom_clear_bam_transaction() - Clears the BAM transaction ++ * @nandc: qpic nand controller ++ * ++ * This function will clear the BAM transaction indexes. ++ */ ++void qcom_clear_bam_transaction(struct qcom_nand_controller *nandc) ++{ ++ struct bam_transaction *bam_txn = nandc->bam_txn; ++ ++ if (!nandc->props->supports_bam) ++ return; ++ ++ memset(&bam_txn->bam_ce_pos, 0, sizeof(u32) * 8); ++ bam_txn->last_data_desc = NULL; ++ ++ sg_init_table(bam_txn->cmd_sgl, nandc->max_cwperpage * ++ QPIC_PER_CW_CMD_SGL); ++ sg_init_table(bam_txn->data_sgl, nandc->max_cwperpage * ++ QPIC_PER_CW_DATA_SGL); ++ ++ reinit_completion(&bam_txn->txn_done); ++} ++EXPORT_SYMBOL(qcom_clear_bam_transaction); ++ ++/** ++ * qcom_qpic_bam_dma_done() - Callback for DMA descriptor completion ++ * @data: data pointer ++ * ++ * This function is a callback for DMA descriptor completion ++ */ ++void qcom_qpic_bam_dma_done(void *data) ++{ ++ struct bam_transaction *bam_txn = data; ++ ++ complete(&bam_txn->txn_done); ++} ++EXPORT_SYMBOL(qcom_qpic_bam_dma_done); ++ ++/** ++ * qcom_nandc_dev_to_mem() - Check for dma sync for cpu or device ++ * @nandc: qpic nand controller ++ * @is_cpu: cpu or Device ++ * ++ * This function will check for dma sync for cpu or device ++ */ ++inline void qcom_nandc_dev_to_mem(struct qcom_nand_controller *nandc, bool is_cpu) ++{ ++ if (!nandc->props->supports_bam) ++ return; ++ ++ if (is_cpu) ++ dma_sync_single_for_cpu(nandc->dev, nandc->reg_read_dma, ++ MAX_REG_RD * ++ sizeof(*nandc->reg_read_buf), ++ DMA_FROM_DEVICE); ++ else ++ dma_sync_single_for_device(nandc->dev, nandc->reg_read_dma, ++ MAX_REG_RD * ++ sizeof(*nandc->reg_read_buf), ++ DMA_FROM_DEVICE); ++} ++EXPORT_SYMBOL(qcom_nandc_dev_to_mem); ++ ++/** ++ * qcom_prepare_bam_async_desc() - Prepare DMA descriptor ++ * @nandc: qpic nand controller ++ * @chan: dma channel ++ * @flags: flags to control DMA descriptor preparation ++ * ++ * This function maps the scatter gather list for DMA transfer and forms the ++ * DMA descriptor for BAM.This descriptor will be added in the NAND DMA ++ * descriptor queue which will be submitted to DMA engine. ++ */ ++int qcom_prepare_bam_async_desc(struct qcom_nand_controller *nandc, ++ struct dma_chan *chan, unsigned long flags) ++{ ++ struct desc_info *desc; ++ struct scatterlist *sgl; ++ unsigned int sgl_cnt; ++ int ret; ++ struct bam_transaction *bam_txn = nandc->bam_txn; ++ enum dma_transfer_direction dir_eng; ++ struct dma_async_tx_descriptor *dma_desc; ++ ++ desc = kzalloc(sizeof(*desc), GFP_KERNEL); ++ if (!desc) ++ return -ENOMEM; ++ ++ if (chan == nandc->cmd_chan) { ++ sgl = &bam_txn->cmd_sgl[bam_txn->cmd_sgl_start]; ++ sgl_cnt = bam_txn->cmd_sgl_pos - bam_txn->cmd_sgl_start; ++ bam_txn->cmd_sgl_start = bam_txn->cmd_sgl_pos; ++ dir_eng = DMA_MEM_TO_DEV; ++ desc->dir = DMA_TO_DEVICE; ++ } else if (chan == nandc->tx_chan) { ++ sgl = &bam_txn->data_sgl[bam_txn->tx_sgl_start]; ++ sgl_cnt = bam_txn->tx_sgl_pos - bam_txn->tx_sgl_start; ++ bam_txn->tx_sgl_start = bam_txn->tx_sgl_pos; ++ dir_eng = DMA_MEM_TO_DEV; ++ desc->dir = DMA_TO_DEVICE; ++ } else { ++ sgl = &bam_txn->data_sgl[bam_txn->rx_sgl_start]; ++ sgl_cnt = bam_txn->rx_sgl_pos - bam_txn->rx_sgl_start; ++ bam_txn->rx_sgl_start = bam_txn->rx_sgl_pos; ++ dir_eng = DMA_DEV_TO_MEM; ++ desc->dir = DMA_FROM_DEVICE; ++ } ++ ++ sg_mark_end(sgl + sgl_cnt - 1); ++ ret = dma_map_sg(nandc->dev, sgl, sgl_cnt, desc->dir); ++ if (ret == 0) { ++ dev_err(nandc->dev, "failure in mapping desc\n"); ++ kfree(desc); ++ return -ENOMEM; ++ } ++ ++ desc->sgl_cnt = sgl_cnt; ++ desc->bam_sgl = sgl; ++ ++ dma_desc = dmaengine_prep_slave_sg(chan, sgl, sgl_cnt, dir_eng, ++ flags); ++ ++ if (!dma_desc) { ++ dev_err(nandc->dev, "failure in prep desc\n"); ++ dma_unmap_sg(nandc->dev, sgl, sgl_cnt, desc->dir); ++ kfree(desc); ++ return -EINVAL; ++ } ++ ++ desc->dma_desc = dma_desc; ++ ++ /* update last data/command descriptor */ ++ if (chan == nandc->cmd_chan) ++ bam_txn->last_cmd_desc = dma_desc; ++ else ++ bam_txn->last_data_desc = dma_desc; ++ ++ list_add_tail(&desc->node, &nandc->desc_list); ++ ++ return 0; ++} ++EXPORT_SYMBOL(qcom_prepare_bam_async_desc); ++ ++/** ++ * qcom_prep_bam_dma_desc_cmd() - Prepares the command descriptor for BAM DMA ++ * @nandc: qpic nand controller ++ * @read: read or write type ++ * @reg_off: offset within the controller's data buffer ++ * @vaddr: virtual address of the buffer we want to write to ++ * @size: DMA transaction size in bytes ++ * @flags: flags to control DMA descriptor preparation ++ * ++ * This function will prepares the command descriptor for BAM DMA ++ * which will be used for NAND register reads and writes. ++ */ ++int qcom_prep_bam_dma_desc_cmd(struct qcom_nand_controller *nandc, bool read, ++ int reg_off, const void *vaddr, ++ int size, unsigned int flags) ++{ ++ int bam_ce_size; ++ int i, ret; ++ struct bam_cmd_element *bam_ce_buffer; ++ struct bam_transaction *bam_txn = nandc->bam_txn; ++ ++ bam_ce_buffer = &bam_txn->bam_ce[bam_txn->bam_ce_pos]; ++ ++ /* fill the command desc */ ++ for (i = 0; i < size; i++) { ++ if (read) ++ bam_prep_ce(&bam_ce_buffer[i], ++ nandc_reg_phys(nandc, reg_off + 4 * i), ++ BAM_READ_COMMAND, ++ reg_buf_dma_addr(nandc, ++ (__le32 *)vaddr + i)); ++ else ++ bam_prep_ce_le32(&bam_ce_buffer[i], ++ nandc_reg_phys(nandc, reg_off + 4 * i), ++ BAM_WRITE_COMMAND, ++ *((__le32 *)vaddr + i)); ++ } ++ ++ bam_txn->bam_ce_pos += size; ++ ++ /* use the separate sgl after this command */ ++ if (flags & NAND_BAM_NEXT_SGL) { ++ bam_ce_buffer = &bam_txn->bam_ce[bam_txn->bam_ce_start]; ++ bam_ce_size = (bam_txn->bam_ce_pos - ++ bam_txn->bam_ce_start) * ++ sizeof(struct bam_cmd_element); ++ sg_set_buf(&bam_txn->cmd_sgl[bam_txn->cmd_sgl_pos], ++ bam_ce_buffer, bam_ce_size); ++ bam_txn->cmd_sgl_pos++; ++ bam_txn->bam_ce_start = bam_txn->bam_ce_pos; ++ ++ if (flags & NAND_BAM_NWD) { ++ ret = qcom_prepare_bam_async_desc(nandc, nandc->cmd_chan, ++ DMA_PREP_FENCE | DMA_PREP_CMD); ++ if (ret) ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(qcom_prep_bam_dma_desc_cmd); ++ ++/** ++ * qcom_prep_bam_dma_desc_data() - Prepares the data descriptor for BAM DMA ++ * @nandc: qpic nand controller ++ * @read: read or write type ++ * @vaddr: virtual address of the buffer we want to write to ++ * @size: DMA transaction size in bytes ++ * @flags: flags to control DMA descriptor preparation ++ * ++ * This function will prepares the data descriptor for BAM DMA which ++ * will be used for NAND data reads and writes. ++ */ ++int qcom_prep_bam_dma_desc_data(struct qcom_nand_controller *nandc, bool read, ++ const void *vaddr, int size, unsigned int flags) ++{ ++ int ret; ++ struct bam_transaction *bam_txn = nandc->bam_txn; ++ ++ if (read) { ++ sg_set_buf(&bam_txn->data_sgl[bam_txn->rx_sgl_pos], ++ vaddr, size); ++ bam_txn->rx_sgl_pos++; ++ } else { ++ sg_set_buf(&bam_txn->data_sgl[bam_txn->tx_sgl_pos], ++ vaddr, size); ++ bam_txn->tx_sgl_pos++; ++ ++ /* ++ * BAM will only set EOT for DMA_PREP_INTERRUPT so if this flag ++ * is not set, form the DMA descriptor ++ */ ++ if (!(flags & NAND_BAM_NO_EOT)) { ++ ret = qcom_prepare_bam_async_desc(nandc, nandc->tx_chan, ++ DMA_PREP_INTERRUPT); ++ if (ret) ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(qcom_prep_bam_dma_desc_data); ++ ++/** ++ * qcom_prep_adm_dma_desc() - Prepare descriptor for adma ++ * @nandc: qpic nand controller ++ * @read: read or write type ++ * @reg_off: offset within the controller's data buffer ++ * @vaddr: virtual address of the buffer we want to write to ++ * @size: adm dma transaction size in bytes ++ * @flow_control: flow controller ++ * ++ * This function will prepare descriptor for adma ++ */ ++int qcom_prep_adm_dma_desc(struct qcom_nand_controller *nandc, bool read, ++ int reg_off, const void *vaddr, int size, ++ bool flow_control) ++{ ++ struct qcom_adm_peripheral_config periph_conf = {}; ++ struct dma_async_tx_descriptor *dma_desc; ++ struct dma_slave_config slave_conf = {0}; ++ enum dma_transfer_direction dir_eng; ++ struct desc_info *desc; ++ struct scatterlist *sgl; ++ int ret; ++ ++ desc = kzalloc(sizeof(*desc), GFP_KERNEL); ++ if (!desc) ++ return -ENOMEM; ++ ++ sgl = &desc->adm_sgl; ++ ++ sg_init_one(sgl, vaddr, size); ++ ++ if (read) { ++ dir_eng = DMA_DEV_TO_MEM; ++ desc->dir = DMA_FROM_DEVICE; ++ } else { ++ dir_eng = DMA_MEM_TO_DEV; ++ desc->dir = DMA_TO_DEVICE; ++ } ++ ++ ret = dma_map_sg(nandc->dev, sgl, 1, desc->dir); ++ if (!ret) { ++ ret = -ENOMEM; ++ goto err; ++ } ++ ++ slave_conf.device_fc = flow_control; ++ if (read) { ++ slave_conf.src_maxburst = 16; ++ slave_conf.src_addr = nandc->base_dma + reg_off; ++ if (nandc->data_crci) { ++ periph_conf.crci = nandc->data_crci; ++ slave_conf.peripheral_config = &periph_conf; ++ slave_conf.peripheral_size = sizeof(periph_conf); ++ } ++ } else { ++ slave_conf.dst_maxburst = 16; ++ slave_conf.dst_addr = nandc->base_dma + reg_off; ++ if (nandc->cmd_crci) { ++ periph_conf.crci = nandc->cmd_crci; ++ slave_conf.peripheral_config = &periph_conf; ++ slave_conf.peripheral_size = sizeof(periph_conf); ++ } ++ } ++ ++ ret = dmaengine_slave_config(nandc->chan, &slave_conf); ++ if (ret) { ++ dev_err(nandc->dev, "failed to configure dma channel\n"); ++ goto err; ++ } ++ ++ dma_desc = dmaengine_prep_slave_sg(nandc->chan, sgl, 1, dir_eng, 0); ++ if (!dma_desc) { ++ dev_err(nandc->dev, "failed to prepare desc\n"); ++ ret = -EINVAL; ++ goto err; ++ } ++ ++ desc->dma_desc = dma_desc; ++ ++ list_add_tail(&desc->node, &nandc->desc_list); ++ ++ return 0; ++err: ++ kfree(desc); ++ ++ return ret; ++} ++EXPORT_SYMBOL(qcom_prep_adm_dma_desc); ++ ++/** ++ * qcom_read_reg_dma() - read a given number of registers to the reg_read_buf pointer ++ * @nandc: qpic nand controller ++ * @first: offset of the first register in the contiguous block ++ * @num_regs: number of registers to read ++ * @flags: flags to control DMA descriptor preparation ++ * ++ * This function will prepares a descriptor to read a given number of ++ * contiguous registers to the reg_read_buf pointer. ++ */ ++int qcom_read_reg_dma(struct qcom_nand_controller *nandc, int first, ++ int num_regs, unsigned int flags) ++{ ++ bool flow_control = false; ++ void *vaddr; ++ ++ vaddr = nandc->reg_read_buf + nandc->reg_read_pos; ++ nandc->reg_read_pos += num_regs; ++ ++ if (first == NAND_DEV_CMD_VLD || first == NAND_DEV_CMD1) ++ first = dev_cmd_reg_addr(nandc, first); ++ ++ if (nandc->props->supports_bam) ++ return qcom_prep_bam_dma_desc_cmd(nandc, true, first, vaddr, ++ num_regs, flags); ++ ++ if (first == NAND_READ_ID || first == NAND_FLASH_STATUS) ++ flow_control = true; ++ ++ return qcom_prep_adm_dma_desc(nandc, true, first, vaddr, ++ num_regs * sizeof(u32), flow_control); ++} ++EXPORT_SYMBOL(qcom_read_reg_dma); ++ ++/** ++ * qcom_write_reg_dma() - write a given number of registers ++ * @nandc: qpic nand controller ++ * @vaddr: contiguous memory from where register value will ++ * be written ++ * @first: offset of the first register in the contiguous block ++ * @num_regs: number of registers to write ++ * @flags: flags to control DMA descriptor preparation ++ * ++ * This function will prepares a descriptor to write a given number of ++ * contiguous registers ++ */ ++int qcom_write_reg_dma(struct qcom_nand_controller *nandc, __le32 *vaddr, ++ int first, int num_regs, unsigned int flags) ++{ ++ bool flow_control = false; ++ ++ if (first == NAND_EXEC_CMD) ++ flags |= NAND_BAM_NWD; ++ ++ if (first == NAND_DEV_CMD1_RESTORE || first == NAND_DEV_CMD1) ++ first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD1); ++ ++ if (first == NAND_DEV_CMD_VLD_RESTORE || first == NAND_DEV_CMD_VLD) ++ first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD); ++ ++ if (nandc->props->supports_bam) ++ return qcom_prep_bam_dma_desc_cmd(nandc, false, first, vaddr, ++ num_regs, flags); ++ ++ if (first == NAND_FLASH_CMD) ++ flow_control = true; ++ ++ return qcom_prep_adm_dma_desc(nandc, false, first, vaddr, ++ num_regs * sizeof(u32), flow_control); ++} ++EXPORT_SYMBOL(qcom_write_reg_dma); ++ ++/** ++ * qcom_read_data_dma() - transfer data ++ * @nandc: qpic nand controller ++ * @reg_off: offset within the controller's data buffer ++ * @vaddr: virtual address of the buffer we want to write to ++ * @size: DMA transaction size in bytes ++ * @flags: flags to control DMA descriptor preparation ++ * ++ * This function will prepares a DMA descriptor to transfer data from the ++ * controller's internal buffer to the buffer 'vaddr' ++ */ ++int qcom_read_data_dma(struct qcom_nand_controller *nandc, int reg_off, ++ const u8 *vaddr, int size, unsigned int flags) ++{ ++ if (nandc->props->supports_bam) ++ return qcom_prep_bam_dma_desc_data(nandc, true, vaddr, size, flags); ++ ++ return qcom_prep_adm_dma_desc(nandc, true, reg_off, vaddr, size, false); ++} ++EXPORT_SYMBOL(qcom_read_data_dma); ++ ++/** ++ * qcom_write_data_dma() - transfer data ++ * @nandc: qpic nand controller ++ * @reg_off: offset within the controller's data buffer ++ * @vaddr: virtual address of the buffer we want to read from ++ * @size: DMA transaction size in bytes ++ * @flags: flags to control DMA descriptor preparation ++ * ++ * This function will prepares a DMA descriptor to transfer data from ++ * 'vaddr' to the controller's internal buffer ++ */ ++int qcom_write_data_dma(struct qcom_nand_controller *nandc, int reg_off, ++ const u8 *vaddr, int size, unsigned int flags) ++{ ++ if (nandc->props->supports_bam) ++ return qcom_prep_bam_dma_desc_data(nandc, false, vaddr, size, flags); ++ ++ return qcom_prep_adm_dma_desc(nandc, false, reg_off, vaddr, size, false); ++} ++EXPORT_SYMBOL(qcom_write_data_dma); ++ ++/** ++ * qcom_submit_descs() - submit dma descriptor ++ * @nandc: qpic nand controller ++ * ++ * This function will submit all the prepared dma descriptor ++ * cmd or data descriptor ++ */ ++int qcom_submit_descs(struct qcom_nand_controller *nandc) ++{ ++ struct desc_info *desc, *n; ++ dma_cookie_t cookie = 0; ++ struct bam_transaction *bam_txn = nandc->bam_txn; ++ int ret = 0; ++ ++ if (nandc->props->supports_bam) { ++ if (bam_txn->rx_sgl_pos > bam_txn->rx_sgl_start) { ++ ret = qcom_prepare_bam_async_desc(nandc, nandc->rx_chan, 0); ++ if (ret) ++ goto err_unmap_free_desc; ++ } ++ ++ if (bam_txn->tx_sgl_pos > bam_txn->tx_sgl_start) { ++ ret = qcom_prepare_bam_async_desc(nandc, nandc->tx_chan, ++ DMA_PREP_INTERRUPT); ++ if (ret) ++ goto err_unmap_free_desc; ++ } ++ ++ if (bam_txn->cmd_sgl_pos > bam_txn->cmd_sgl_start) { ++ ret = qcom_prepare_bam_async_desc(nandc, nandc->cmd_chan, ++ DMA_PREP_CMD); ++ if (ret) ++ goto err_unmap_free_desc; ++ } ++ } ++ ++ list_for_each_entry(desc, &nandc->desc_list, node) ++ cookie = dmaengine_submit(desc->dma_desc); ++ ++ if (nandc->props->supports_bam) { ++ bam_txn->last_cmd_desc->callback = qcom_qpic_bam_dma_done; ++ bam_txn->last_cmd_desc->callback_param = bam_txn; ++ ++ dma_async_issue_pending(nandc->tx_chan); ++ dma_async_issue_pending(nandc->rx_chan); ++ dma_async_issue_pending(nandc->cmd_chan); ++ ++ if (!wait_for_completion_timeout(&bam_txn->txn_done, ++ QPIC_NAND_COMPLETION_TIMEOUT)) ++ ret = -ETIMEDOUT; ++ } else { ++ if (dma_sync_wait(nandc->chan, cookie) != DMA_COMPLETE) ++ ret = -ETIMEDOUT; ++ } ++ ++err_unmap_free_desc: ++ /* ++ * Unmap the dma sg_list and free the desc allocated by both ++ * qcom_prepare_bam_async_desc() and qcom_prep_adm_dma_desc() functions. ++ */ ++ list_for_each_entry_safe(desc, n, &nandc->desc_list, node) { ++ list_del(&desc->node); ++ ++ if (nandc->props->supports_bam) ++ dma_unmap_sg(nandc->dev, desc->bam_sgl, ++ desc->sgl_cnt, desc->dir); ++ else ++ dma_unmap_sg(nandc->dev, &desc->adm_sgl, 1, ++ desc->dir); ++ ++ kfree(desc); ++ } ++ ++ return ret; ++} ++EXPORT_SYMBOL(qcom_submit_descs); ++ ++/** ++ * qcom_clear_read_regs() - reset the read register buffer ++ * @nandc: qpic nand controller ++ * ++ * This function reset the register read buffer for next NAND operation ++ */ ++void qcom_clear_read_regs(struct qcom_nand_controller *nandc) ++{ ++ nandc->reg_read_pos = 0; ++ qcom_nandc_dev_to_mem(nandc, false); ++} ++EXPORT_SYMBOL(qcom_clear_read_regs); ++ ++/** ++ * qcom_nandc_unalloc() - unallocate qpic nand controller ++ * @nandc: qpic nand controller ++ * ++ * This function will unallocate memory alloacted for qpic nand controller ++ */ ++void qcom_nandc_unalloc(struct qcom_nand_controller *nandc) ++{ ++ if (nandc->props->supports_bam) { ++ if (!dma_mapping_error(nandc->dev, nandc->reg_read_dma)) ++ dma_unmap_single(nandc->dev, nandc->reg_read_dma, ++ MAX_REG_RD * ++ sizeof(*nandc->reg_read_buf), ++ DMA_FROM_DEVICE); ++ ++ if (nandc->tx_chan) ++ dma_release_channel(nandc->tx_chan); ++ ++ if (nandc->rx_chan) ++ dma_release_channel(nandc->rx_chan); ++ ++ if (nandc->cmd_chan) ++ dma_release_channel(nandc->cmd_chan); ++ } else { ++ if (nandc->chan) ++ dma_release_channel(nandc->chan); ++ } ++} ++EXPORT_SYMBOL(qcom_nandc_unalloc); ++ ++/** ++ * qcom_nandc_alloc() - Allocate qpic nand controller ++ * @nandc: qpic nand controller ++ * ++ * This function will allocate memory for qpic nand controller ++ */ ++int qcom_nandc_alloc(struct qcom_nand_controller *nandc) ++{ ++ int ret; ++ ++ ret = dma_set_coherent_mask(nandc->dev, DMA_BIT_MASK(32)); ++ if (ret) { ++ dev_err(nandc->dev, "failed to set DMA mask\n"); ++ return ret; ++ } ++ ++ /* ++ * we use the internal buffer for reading ONFI params, reading small ++ * data like ID and status, and preforming read-copy-write operations ++ * when writing to a codeword partially. 532 is the maximum possible ++ * size of a codeword for our nand controller ++ */ ++ nandc->buf_size = 532; ++ ++ nandc->data_buffer = devm_kzalloc(nandc->dev, nandc->buf_size, GFP_KERNEL); ++ if (!nandc->data_buffer) ++ return -ENOMEM; ++ ++ nandc->regs = devm_kzalloc(nandc->dev, sizeof(*nandc->regs), GFP_KERNEL); ++ if (!nandc->regs) ++ return -ENOMEM; ++ ++ nandc->reg_read_buf = devm_kcalloc(nandc->dev, MAX_REG_RD, ++ sizeof(*nandc->reg_read_buf), ++ GFP_KERNEL); ++ if (!nandc->reg_read_buf) ++ return -ENOMEM; ++ ++ if (nandc->props->supports_bam) { ++ nandc->reg_read_dma = ++ dma_map_single(nandc->dev, nandc->reg_read_buf, ++ MAX_REG_RD * ++ sizeof(*nandc->reg_read_buf), ++ DMA_FROM_DEVICE); ++ if (dma_mapping_error(nandc->dev, nandc->reg_read_dma)) { ++ dev_err(nandc->dev, "failed to DMA MAP reg buffer\n"); ++ return -EIO; ++ } ++ ++ nandc->tx_chan = dma_request_chan(nandc->dev, "tx"); ++ if (IS_ERR(nandc->tx_chan)) { ++ ret = PTR_ERR(nandc->tx_chan); ++ nandc->tx_chan = NULL; ++ dev_err_probe(nandc->dev, ret, ++ "tx DMA channel request failed\n"); ++ goto unalloc; ++ } ++ ++ nandc->rx_chan = dma_request_chan(nandc->dev, "rx"); ++ if (IS_ERR(nandc->rx_chan)) { ++ ret = PTR_ERR(nandc->rx_chan); ++ nandc->rx_chan = NULL; ++ dev_err_probe(nandc->dev, ret, ++ "rx DMA channel request failed\n"); ++ goto unalloc; ++ } ++ ++ nandc->cmd_chan = dma_request_chan(nandc->dev, "cmd"); ++ if (IS_ERR(nandc->cmd_chan)) { ++ ret = PTR_ERR(nandc->cmd_chan); ++ nandc->cmd_chan = NULL; ++ dev_err_probe(nandc->dev, ret, ++ "cmd DMA channel request failed\n"); ++ goto unalloc; ++ } ++ ++ /* ++ * Initially allocate BAM transaction to read ONFI param page. ++ * After detecting all the devices, this BAM transaction will ++ * be freed and the next BAM transaction will be allocated with ++ * maximum codeword size ++ */ ++ nandc->max_cwperpage = 1; ++ nandc->bam_txn = qcom_alloc_bam_transaction(nandc); ++ if (!nandc->bam_txn) { ++ dev_err(nandc->dev, ++ "failed to allocate bam transaction\n"); ++ ret = -ENOMEM; ++ goto unalloc; ++ } ++ } else { ++ nandc->chan = dma_request_chan(nandc->dev, "rxtx"); ++ if (IS_ERR(nandc->chan)) { ++ ret = PTR_ERR(nandc->chan); ++ nandc->chan = NULL; ++ dev_err_probe(nandc->dev, ret, ++ "rxtx DMA channel request failed\n"); ++ return ret; ++ } ++ } ++ ++ INIT_LIST_HEAD(&nandc->desc_list); ++ INIT_LIST_HEAD(&nandc->host_list); ++ ++ return 0; ++unalloc: ++ qcom_nandc_unalloc(nandc); ++ return ret; ++} ++EXPORT_SYMBOL(qcom_nandc_alloc); ++ ++MODULE_DESCRIPTION("QPIC controller common api"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c +index ee73876f7244..f07871532ef0 100644 +--- a/drivers/mtd/nand/raw/qcom_nandc.c ++++ b/drivers/mtd/nand/raw/qcom_nandc.c +@@ -15,417 +15,7 @@ + #include + #include + #include +- +-/* NANDc reg offsets */ +-#define NAND_FLASH_CMD 0x00 +-#define NAND_ADDR0 0x04 +-#define NAND_ADDR1 0x08 +-#define NAND_FLASH_CHIP_SELECT 0x0c +-#define NAND_EXEC_CMD 0x10 +-#define NAND_FLASH_STATUS 0x14 +-#define NAND_BUFFER_STATUS 0x18 +-#define NAND_DEV0_CFG0 0x20 +-#define NAND_DEV0_CFG1 0x24 +-#define NAND_DEV0_ECC_CFG 0x28 +-#define NAND_AUTO_STATUS_EN 0x2c +-#define NAND_DEV1_CFG0 0x30 +-#define NAND_DEV1_CFG1 0x34 +-#define NAND_READ_ID 0x40 +-#define NAND_READ_STATUS 0x44 +-#define NAND_DEV_CMD0 0xa0 +-#define NAND_DEV_CMD1 0xa4 +-#define NAND_DEV_CMD2 0xa8 +-#define NAND_DEV_CMD_VLD 0xac +-#define SFLASHC_BURST_CFG 0xe0 +-#define NAND_ERASED_CW_DETECT_CFG 0xe8 +-#define NAND_ERASED_CW_DETECT_STATUS 0xec +-#define NAND_EBI2_ECC_BUF_CFG 0xf0 +-#define FLASH_BUF_ACC 0x100 +- +-#define NAND_CTRL 0xf00 +-#define NAND_VERSION 0xf08 +-#define NAND_READ_LOCATION_0 0xf20 +-#define NAND_READ_LOCATION_1 0xf24 +-#define NAND_READ_LOCATION_2 0xf28 +-#define NAND_READ_LOCATION_3 0xf2c +-#define NAND_READ_LOCATION_LAST_CW_0 0xf40 +-#define NAND_READ_LOCATION_LAST_CW_1 0xf44 +-#define NAND_READ_LOCATION_LAST_CW_2 0xf48 +-#define NAND_READ_LOCATION_LAST_CW_3 0xf4c +- +-/* dummy register offsets, used by qcom_write_reg_dma */ +-#define NAND_DEV_CMD1_RESTORE 0xdead +-#define NAND_DEV_CMD_VLD_RESTORE 0xbeef +- +-/* NAND_FLASH_CMD bits */ +-#define PAGE_ACC BIT(4) +-#define LAST_PAGE BIT(5) +- +-/* NAND_FLASH_CHIP_SELECT bits */ +-#define NAND_DEV_SEL 0 +-#define DM_EN BIT(2) +- +-/* NAND_FLASH_STATUS bits */ +-#define FS_OP_ERR BIT(4) +-#define FS_READY_BSY_N BIT(5) +-#define FS_MPU_ERR BIT(8) +-#define FS_DEVICE_STS_ERR BIT(16) +-#define FS_DEVICE_WP BIT(23) +- +-/* NAND_BUFFER_STATUS bits */ +-#define BS_UNCORRECTABLE_BIT BIT(8) +-#define BS_CORRECTABLE_ERR_MSK 0x1f +- +-/* NAND_DEVn_CFG0 bits */ +-#define DISABLE_STATUS_AFTER_WRITE 4 +-#define CW_PER_PAGE 6 +-#define UD_SIZE_BYTES 9 +-#define UD_SIZE_BYTES_MASK GENMASK(18, 9) +-#define ECC_PARITY_SIZE_BYTES_RS 19 +-#define SPARE_SIZE_BYTES 23 +-#define SPARE_SIZE_BYTES_MASK GENMASK(26, 23) +-#define NUM_ADDR_CYCLES 27 +-#define STATUS_BFR_READ 30 +-#define SET_RD_MODE_AFTER_STATUS 31 +- +-/* NAND_DEVn_CFG0 bits */ +-#define DEV0_CFG1_ECC_DISABLE 0 +-#define WIDE_FLASH 1 +-#define NAND_RECOVERY_CYCLES 2 +-#define CS_ACTIVE_BSY 5 +-#define BAD_BLOCK_BYTE_NUM 6 +-#define BAD_BLOCK_IN_SPARE_AREA 16 +-#define WR_RD_BSY_GAP 17 +-#define ENABLE_BCH_ECC 27 +- +-/* NAND_DEV0_ECC_CFG bits */ +-#define ECC_CFG_ECC_DISABLE 0 +-#define ECC_SW_RESET 1 +-#define ECC_MODE 4 +-#define ECC_PARITY_SIZE_BYTES_BCH 8 +-#define ECC_NUM_DATA_BYTES 16 +-#define ECC_NUM_DATA_BYTES_MASK GENMASK(25, 16) +-#define ECC_FORCE_CLK_OPEN 30 +- +-/* NAND_DEV_CMD1 bits */ +-#define READ_ADDR 0 +- +-/* NAND_DEV_CMD_VLD bits */ +-#define READ_START_VLD BIT(0) +-#define READ_STOP_VLD BIT(1) +-#define WRITE_START_VLD BIT(2) +-#define ERASE_START_VLD BIT(3) +-#define SEQ_READ_START_VLD BIT(4) +- +-/* NAND_EBI2_ECC_BUF_CFG bits */ +-#define NUM_STEPS 0 +- +-/* NAND_ERASED_CW_DETECT_CFG bits */ +-#define ERASED_CW_ECC_MASK 1 +-#define AUTO_DETECT_RES 0 +-#define MASK_ECC BIT(ERASED_CW_ECC_MASK) +-#define RESET_ERASED_DET BIT(AUTO_DETECT_RES) +-#define ACTIVE_ERASED_DET (0 << AUTO_DETECT_RES) +-#define CLR_ERASED_PAGE_DET (RESET_ERASED_DET | MASK_ECC) +-#define SET_ERASED_PAGE_DET (ACTIVE_ERASED_DET | MASK_ECC) +- +-/* NAND_ERASED_CW_DETECT_STATUS bits */ +-#define PAGE_ALL_ERASED BIT(7) +-#define CODEWORD_ALL_ERASED BIT(6) +-#define PAGE_ERASED BIT(5) +-#define CODEWORD_ERASED BIT(4) +-#define ERASED_PAGE (PAGE_ALL_ERASED | PAGE_ERASED) +-#define ERASED_CW (CODEWORD_ALL_ERASED | CODEWORD_ERASED) +- +-/* NAND_READ_LOCATION_n bits */ +-#define READ_LOCATION_OFFSET 0 +-#define READ_LOCATION_SIZE 16 +-#define READ_LOCATION_LAST 31 +- +-/* Version Mask */ +-#define NAND_VERSION_MAJOR_MASK 0xf0000000 +-#define NAND_VERSION_MAJOR_SHIFT 28 +-#define NAND_VERSION_MINOR_MASK 0x0fff0000 +-#define NAND_VERSION_MINOR_SHIFT 16 +- +-/* NAND OP_CMDs */ +-#define OP_PAGE_READ 0x2 +-#define OP_PAGE_READ_WITH_ECC 0x3 +-#define OP_PAGE_READ_WITH_ECC_SPARE 0x4 +-#define OP_PAGE_READ_ONFI_READ 0x5 +-#define OP_PROGRAM_PAGE 0x6 +-#define OP_PAGE_PROGRAM_WITH_ECC 0x7 +-#define OP_PROGRAM_PAGE_SPARE 0x9 +-#define OP_BLOCK_ERASE 0xa +-#define OP_CHECK_STATUS 0xc +-#define OP_FETCH_ID 0xb +-#define OP_RESET_DEVICE 0xd +- +-/* Default Value for NAND_DEV_CMD_VLD */ +-#define NAND_DEV_CMD_VLD_VAL (READ_START_VLD | WRITE_START_VLD | \ +- ERASE_START_VLD | SEQ_READ_START_VLD) +- +-/* NAND_CTRL bits */ +-#define BAM_MODE_EN BIT(0) +- +-/* +- * the NAND controller performs reads/writes with ECC in 516 byte chunks. +- * the driver calls the chunks 'step' or 'codeword' interchangeably +- */ +-#define NANDC_STEP_SIZE 512 +- +-/* +- * the largest page size we support is 8K, this will have 16 steps/codewords +- * of 512 bytes each +- */ +-#define MAX_NUM_STEPS (SZ_8K / NANDC_STEP_SIZE) +- +-/* we read at most 3 registers per codeword scan */ +-#define MAX_REG_RD (3 * MAX_NUM_STEPS) +- +-/* ECC modes supported by the controller */ +-#define ECC_NONE BIT(0) +-#define ECC_RS_4BIT BIT(1) +-#define ECC_BCH_4BIT BIT(2) +-#define ECC_BCH_8BIT BIT(3) +- +-/* +- * Returns the actual register address for all NAND_DEV_ registers +- * (i.e. NAND_DEV_CMD0, NAND_DEV_CMD1, NAND_DEV_CMD2 and NAND_DEV_CMD_VLD) +- */ +-#define dev_cmd_reg_addr(nandc, reg) ((nandc)->props->dev_cmd_reg_start + (reg)) +- +-/* Returns the NAND register physical address */ +-#define nandc_reg_phys(chip, offset) ((chip)->base_phys + (offset)) +- +-/* Returns the dma address for reg read buffer */ +-#define reg_buf_dma_addr(chip, vaddr) \ +- ((chip)->reg_read_dma + \ +- ((u8 *)(vaddr) - (u8 *)(chip)->reg_read_buf)) +- +-#define QPIC_PER_CW_CMD_ELEMENTS 32 +-#define QPIC_PER_CW_CMD_SGL 32 +-#define QPIC_PER_CW_DATA_SGL 8 +- +-#define QPIC_NAND_COMPLETION_TIMEOUT msecs_to_jiffies(2000) +- +-/* +- * Flags used in DMA descriptor preparation helper functions +- * (i.e. qcom_read_reg_dma/qcom_write_reg_dma/qcom_read_data_dma/qcom_write_data_dma) +- */ +-/* Don't set the EOT in current tx BAM sgl */ +-#define NAND_BAM_NO_EOT BIT(0) +-/* Set the NWD flag in current BAM sgl */ +-#define NAND_BAM_NWD BIT(1) +-/* Finish writing in the current BAM sgl and start writing in another BAM sgl */ +-#define NAND_BAM_NEXT_SGL BIT(2) +-/* +- * Erased codeword status is being used two times in single transfer so this +- * flag will determine the current value of erased codeword status register +- */ +-#define NAND_ERASED_CW_SET BIT(4) +- +-#define MAX_ADDRESS_CYCLE 5 +- +-/* +- * This data type corresponds to the BAM transaction which will be used for all +- * NAND transfers. +- * @bam_ce - the array of BAM command elements +- * @cmd_sgl - sgl for NAND BAM command pipe +- * @data_sgl - sgl for NAND BAM consumer/producer pipe +- * @last_data_desc - last DMA desc in data channel (tx/rx). +- * @last_cmd_desc - last DMA desc in command channel. +- * @txn_done - completion for NAND transfer. +- * @bam_ce_pos - the index in bam_ce which is available for next sgl +- * @bam_ce_start - the index in bam_ce which marks the start position ce +- * for current sgl. It will be used for size calculation +- * for current sgl +- * @cmd_sgl_pos - current index in command sgl. +- * @cmd_sgl_start - start index in command sgl. +- * @tx_sgl_pos - current index in data sgl for tx. +- * @tx_sgl_start - start index in data sgl for tx. +- * @rx_sgl_pos - current index in data sgl for rx. +- * @rx_sgl_start - start index in data sgl for rx. +- */ +-struct bam_transaction { +- struct bam_cmd_element *bam_ce; +- struct scatterlist *cmd_sgl; +- struct scatterlist *data_sgl; +- struct dma_async_tx_descriptor *last_data_desc; +- struct dma_async_tx_descriptor *last_cmd_desc; +- struct completion txn_done; +- u32 bam_ce_pos; +- u32 bam_ce_start; +- u32 cmd_sgl_pos; +- u32 cmd_sgl_start; +- u32 tx_sgl_pos; +- u32 tx_sgl_start; +- u32 rx_sgl_pos; +- u32 rx_sgl_start; +-}; +- +-/* +- * This data type corresponds to the nand dma descriptor +- * @dma_desc - low level DMA engine descriptor +- * @list - list for desc_info +- * +- * @adm_sgl - sgl which will be used for single sgl dma descriptor. Only used by +- * ADM +- * @bam_sgl - sgl which will be used for dma descriptor. Only used by BAM +- * @sgl_cnt - number of SGL in bam_sgl. Only used by BAM +- * @dir - DMA transfer direction +- */ +-struct desc_info { +- struct dma_async_tx_descriptor *dma_desc; +- struct list_head node; +- +- union { +- struct scatterlist adm_sgl; +- struct { +- struct scatterlist *bam_sgl; +- int sgl_cnt; +- }; +- }; +- enum dma_data_direction dir; +-}; +- +-/* +- * holds the current register values that we want to write. acts as a contiguous +- * chunk of memory which we use to write the controller registers through DMA. +- */ +-struct nandc_regs { +- __le32 cmd; +- __le32 addr0; +- __le32 addr1; +- __le32 chip_sel; +- __le32 exec; +- +- __le32 cfg0; +- __le32 cfg1; +- __le32 ecc_bch_cfg; +- +- __le32 clrflashstatus; +- __le32 clrreadstatus; +- +- __le32 cmd1; +- __le32 vld; +- +- __le32 orig_cmd1; +- __le32 orig_vld; +- +- __le32 ecc_buf_cfg; +- __le32 read_location0; +- __le32 read_location1; +- __le32 read_location2; +- __le32 read_location3; +- __le32 read_location_last0; +- __le32 read_location_last1; +- __le32 read_location_last2; +- __le32 read_location_last3; +- +- __le32 erased_cw_detect_cfg_clr; +- __le32 erased_cw_detect_cfg_set; +-}; +- +-/* +- * NAND controller data struct +- * +- * @dev: parent device +- * +- * @base: MMIO base +- * +- * @core_clk: controller clock +- * @aon_clk: another controller clock +- * +- * @regs: a contiguous chunk of memory for DMA register +- * writes. contains the register values to be +- * written to controller +- * +- * @props: properties of current NAND controller, +- * initialized via DT match data +- * +- * @controller: base controller structure +- * @host_list: list containing all the chips attached to the +- * controller +- * +- * @chan: dma channel +- * @cmd_crci: ADM DMA CRCI for command flow control +- * @data_crci: ADM DMA CRCI for data flow control +- * +- * @desc_list: DMA descriptor list (list of desc_infos) +- * +- * @data_buffer: our local DMA buffer for page read/writes, +- * used when we can't use the buffer provided +- * by upper layers directly +- * @reg_read_buf: local buffer for reading back registers via DMA +- * +- * @base_phys: physical base address of controller registers +- * @base_dma: dma base address of controller registers +- * @reg_read_dma: contains dma address for register read buffer +- * +- * @buf_size/count/start: markers for chip->legacy.read_buf/write_buf +- * functions +- * @max_cwperpage: maximum QPIC codewords required. calculated +- * from all connected NAND devices pagesize +- * +- * @reg_read_pos: marker for data read in reg_read_buf +- * +- * @cmd1/vld: some fixed controller register values +- * +- * @exec_opwrite: flag to select correct number of code word +- * while reading status +- */ +-struct qcom_nand_controller { +- struct device *dev; +- +- void __iomem *base; +- +- struct clk *core_clk; +- struct clk *aon_clk; +- +- struct nandc_regs *regs; +- struct bam_transaction *bam_txn; +- +- const struct qcom_nandc_props *props; +- +- struct nand_controller controller; +- struct list_head host_list; +- +- union { +- /* will be used only by QPIC for BAM DMA */ +- struct { +- struct dma_chan *tx_chan; +- struct dma_chan *rx_chan; +- struct dma_chan *cmd_chan; +- }; +- +- /* will be used only by EBI2 for ADM DMA */ +- struct { +- struct dma_chan *chan; +- unsigned int cmd_crci; +- unsigned int data_crci; +- }; +- }; +- +- struct list_head desc_list; +- +- u8 *data_buffer; +- __le32 *reg_read_buf; +- +- phys_addr_t base_phys; +- dma_addr_t base_dma; +- dma_addr_t reg_read_dma; +- +- int buf_size; +- int buf_count; +- int buf_start; +- unsigned int max_cwperpage; +- +- int reg_read_pos; +- +- u32 cmd1, vld; +- bool exec_opwrite; +-}; ++#include + + /* + * NAND special boot partitions +@@ -530,97 +120,6 @@ struct qcom_nand_host { + bool bch_enabled; + }; + +-/* +- * This data type corresponds to the NAND controller properties which varies +- * among different NAND controllers. +- * @ecc_modes - ecc mode for NAND +- * @dev_cmd_reg_start - NAND_DEV_CMD_* registers starting offset +- * @supports_bam - whether NAND controller is using Bus Access Manager (BAM) +- * @nandc_part_of_qpic - whether NAND controller is part of qpic IP +- * @qpic_version2 - flag to indicate QPIC IP version 2 +- * @use_codeword_fixup - whether NAND has different layout for boot partitions +- */ +-struct qcom_nandc_props { +- u32 ecc_modes; +- u32 dev_cmd_reg_start; +- bool supports_bam; +- bool nandc_part_of_qpic; +- bool qpic_version2; +- bool use_codeword_fixup; +-}; +- +-/* Frees the BAM transaction memory */ +-static void qcom_free_bam_transaction(struct qcom_nand_controller *nandc) +-{ +- struct bam_transaction *bam_txn = nandc->bam_txn; +- +- devm_kfree(nandc->dev, bam_txn); +-} +- +-/* Allocates and Initializes the BAM transaction */ +-static struct bam_transaction * +-qcom_alloc_bam_transaction(struct qcom_nand_controller *nandc) +-{ +- struct bam_transaction *bam_txn; +- size_t bam_txn_size; +- unsigned int num_cw = nandc->max_cwperpage; +- void *bam_txn_buf; +- +- bam_txn_size = +- sizeof(*bam_txn) + num_cw * +- ((sizeof(*bam_txn->bam_ce) * QPIC_PER_CW_CMD_ELEMENTS) + +- (sizeof(*bam_txn->cmd_sgl) * QPIC_PER_CW_CMD_SGL) + +- (sizeof(*bam_txn->data_sgl) * QPIC_PER_CW_DATA_SGL)); +- +- bam_txn_buf = devm_kzalloc(nandc->dev, bam_txn_size, GFP_KERNEL); +- if (!bam_txn_buf) +- return NULL; +- +- bam_txn = bam_txn_buf; +- bam_txn_buf += sizeof(*bam_txn); +- +- bam_txn->bam_ce = bam_txn_buf; +- bam_txn_buf += +- sizeof(*bam_txn->bam_ce) * QPIC_PER_CW_CMD_ELEMENTS * num_cw; +- +- bam_txn->cmd_sgl = bam_txn_buf; +- bam_txn_buf += +- sizeof(*bam_txn->cmd_sgl) * QPIC_PER_CW_CMD_SGL * num_cw; +- +- bam_txn->data_sgl = bam_txn_buf; +- +- init_completion(&bam_txn->txn_done); +- +- return bam_txn; +-} +- +-/* Clears the BAM transaction indexes */ +-static void qcom_clear_bam_transaction(struct qcom_nand_controller *nandc) +-{ +- struct bam_transaction *bam_txn = nandc->bam_txn; +- +- if (!nandc->props->supports_bam) +- return; +- +- memset(&bam_txn->bam_ce_pos, 0, sizeof(u32) * 8); +- bam_txn->last_data_desc = NULL; +- +- sg_init_table(bam_txn->cmd_sgl, nandc->max_cwperpage * +- QPIC_PER_CW_CMD_SGL); +- sg_init_table(bam_txn->data_sgl, nandc->max_cwperpage * +- QPIC_PER_CW_DATA_SGL); +- +- reinit_completion(&bam_txn->txn_done); +-} +- +-/* Callback for DMA descriptor completion */ +-static void qcom_qpic_bam_dma_done(void *data) +-{ +- struct bam_transaction *bam_txn = data; +- +- complete(&bam_txn->txn_done); +-} +- + static struct qcom_nand_host *to_qcom_nand_host(struct nand_chip *chip) + { + return container_of(chip, struct qcom_nand_host, chip); +@@ -629,8 +128,8 @@ static struct qcom_nand_host *to_qcom_nand_host(struct nand_chip *chip) + static struct qcom_nand_controller * + get_qcom_nand_controller(struct nand_chip *chip) + { +- return container_of(chip->controller, struct qcom_nand_controller, +- controller); ++ return (struct qcom_nand_controller *) ++ ((u8 *)chip->controller - sizeof(struct qcom_nand_controller)); + } + + static u32 nandc_read(struct qcom_nand_controller *nandc, int offset) +@@ -644,23 +143,6 @@ static void nandc_write(struct qcom_nand_controller *nandc, int offset, + iowrite32(val, nandc->base + offset); + } + +-static void qcom_nandc_dev_to_mem(struct qcom_nand_controller *nandc, bool is_cpu) +-{ +- if (!nandc->props->supports_bam) +- return; +- +- if (is_cpu) +- dma_sync_single_for_cpu(nandc->dev, nandc->reg_read_dma, +- MAX_REG_RD * +- sizeof(*nandc->reg_read_buf), +- DMA_FROM_DEVICE); +- else +- dma_sync_single_for_device(nandc->dev, nandc->reg_read_dma, +- MAX_REG_RD * +- sizeof(*nandc->reg_read_buf), +- DMA_FROM_DEVICE); +-} +- + /* Helper to check whether this is the last CW or not */ + static bool qcom_nandc_is_last_cw(struct nand_ecc_ctrl *ecc, int cw) + { +@@ -819,356 +301,6 @@ static void update_rw_regs(struct qcom_nand_host *host, int num_cw, bool read, i + host->cw_data : host->cw_size, 1); + } + +-/* +- * Maps the scatter gather list for DMA transfer and forms the DMA descriptor +- * for BAM. This descriptor will be added in the NAND DMA descriptor queue +- * which will be submitted to DMA engine. +- */ +-static int qcom_prepare_bam_async_desc(struct qcom_nand_controller *nandc, +- struct dma_chan *chan, +- unsigned long flags) +-{ +- struct desc_info *desc; +- struct scatterlist *sgl; +- unsigned int sgl_cnt; +- int ret; +- struct bam_transaction *bam_txn = nandc->bam_txn; +- enum dma_transfer_direction dir_eng; +- struct dma_async_tx_descriptor *dma_desc; +- +- desc = kzalloc(sizeof(*desc), GFP_KERNEL); +- if (!desc) +- return -ENOMEM; +- +- if (chan == nandc->cmd_chan) { +- sgl = &bam_txn->cmd_sgl[bam_txn->cmd_sgl_start]; +- sgl_cnt = bam_txn->cmd_sgl_pos - bam_txn->cmd_sgl_start; +- bam_txn->cmd_sgl_start = bam_txn->cmd_sgl_pos; +- dir_eng = DMA_MEM_TO_DEV; +- desc->dir = DMA_TO_DEVICE; +- } else if (chan == nandc->tx_chan) { +- sgl = &bam_txn->data_sgl[bam_txn->tx_sgl_start]; +- sgl_cnt = bam_txn->tx_sgl_pos - bam_txn->tx_sgl_start; +- bam_txn->tx_sgl_start = bam_txn->tx_sgl_pos; +- dir_eng = DMA_MEM_TO_DEV; +- desc->dir = DMA_TO_DEVICE; +- } else { +- sgl = &bam_txn->data_sgl[bam_txn->rx_sgl_start]; +- sgl_cnt = bam_txn->rx_sgl_pos - bam_txn->rx_sgl_start; +- bam_txn->rx_sgl_start = bam_txn->rx_sgl_pos; +- dir_eng = DMA_DEV_TO_MEM; +- desc->dir = DMA_FROM_DEVICE; +- } +- +- sg_mark_end(sgl + sgl_cnt - 1); +- ret = dma_map_sg(nandc->dev, sgl, sgl_cnt, desc->dir); +- if (ret == 0) { +- dev_err(nandc->dev, "failure in mapping desc\n"); +- kfree(desc); +- return -ENOMEM; +- } +- +- desc->sgl_cnt = sgl_cnt; +- desc->bam_sgl = sgl; +- +- dma_desc = dmaengine_prep_slave_sg(chan, sgl, sgl_cnt, dir_eng, +- flags); +- +- if (!dma_desc) { +- dev_err(nandc->dev, "failure in prep desc\n"); +- dma_unmap_sg(nandc->dev, sgl, sgl_cnt, desc->dir); +- kfree(desc); +- return -EINVAL; +- } +- +- desc->dma_desc = dma_desc; +- +- /* update last data/command descriptor */ +- if (chan == nandc->cmd_chan) +- bam_txn->last_cmd_desc = dma_desc; +- else +- bam_txn->last_data_desc = dma_desc; +- +- list_add_tail(&desc->node, &nandc->desc_list); +- +- return 0; +-} +- +-/* +- * Prepares the command descriptor for BAM DMA which will be used for NAND +- * register reads and writes. The command descriptor requires the command +- * to be formed in command element type so this function uses the command +- * element from bam transaction ce array and fills the same with required +- * data. A single SGL can contain multiple command elements so +- * NAND_BAM_NEXT_SGL will be used for starting the separate SGL +- * after the current command element. +- */ +-static int qcom_prep_bam_dma_desc_cmd(struct qcom_nand_controller *nandc, bool read, +- int reg_off, const void *vaddr, +- int size, unsigned int flags) +-{ +- int bam_ce_size; +- int i, ret; +- struct bam_cmd_element *bam_ce_buffer; +- struct bam_transaction *bam_txn = nandc->bam_txn; +- +- bam_ce_buffer = &bam_txn->bam_ce[bam_txn->bam_ce_pos]; +- +- /* fill the command desc */ +- for (i = 0; i < size; i++) { +- if (read) +- bam_prep_ce(&bam_ce_buffer[i], +- nandc_reg_phys(nandc, reg_off + 4 * i), +- BAM_READ_COMMAND, +- reg_buf_dma_addr(nandc, +- (__le32 *)vaddr + i)); +- else +- bam_prep_ce_le32(&bam_ce_buffer[i], +- nandc_reg_phys(nandc, reg_off + 4 * i), +- BAM_WRITE_COMMAND, +- *((__le32 *)vaddr + i)); +- } +- +- bam_txn->bam_ce_pos += size; +- +- /* use the separate sgl after this command */ +- if (flags & NAND_BAM_NEXT_SGL) { +- bam_ce_buffer = &bam_txn->bam_ce[bam_txn->bam_ce_start]; +- bam_ce_size = (bam_txn->bam_ce_pos - +- bam_txn->bam_ce_start) * +- sizeof(struct bam_cmd_element); +- sg_set_buf(&bam_txn->cmd_sgl[bam_txn->cmd_sgl_pos], +- bam_ce_buffer, bam_ce_size); +- bam_txn->cmd_sgl_pos++; +- bam_txn->bam_ce_start = bam_txn->bam_ce_pos; +- +- if (flags & NAND_BAM_NWD) { +- ret = qcom_prepare_bam_async_desc(nandc, nandc->cmd_chan, +- DMA_PREP_FENCE | +- DMA_PREP_CMD); +- if (ret) +- return ret; +- } +- } +- +- return 0; +-} +- +-/* +- * Prepares the data descriptor for BAM DMA which will be used for NAND +- * data reads and writes. +- */ +-static int qcom_prep_bam_dma_desc_data(struct qcom_nand_controller *nandc, bool read, +- const void *vaddr, int size, unsigned int flags) +-{ +- int ret; +- struct bam_transaction *bam_txn = nandc->bam_txn; +- +- if (read) { +- sg_set_buf(&bam_txn->data_sgl[bam_txn->rx_sgl_pos], +- vaddr, size); +- bam_txn->rx_sgl_pos++; +- } else { +- sg_set_buf(&bam_txn->data_sgl[bam_txn->tx_sgl_pos], +- vaddr, size); +- bam_txn->tx_sgl_pos++; +- +- /* +- * BAM will only set EOT for DMA_PREP_INTERRUPT so if this flag +- * is not set, form the DMA descriptor +- */ +- if (!(flags & NAND_BAM_NO_EOT)) { +- ret = qcom_prepare_bam_async_desc(nandc, nandc->tx_chan, +- DMA_PREP_INTERRUPT); +- if (ret) +- return ret; +- } +- } +- +- return 0; +-} +- +-static int qcom_prep_adm_dma_desc(struct qcom_nand_controller *nandc, bool read, +- int reg_off, const void *vaddr, int size, +- bool flow_control) +-{ +- struct desc_info *desc; +- struct dma_async_tx_descriptor *dma_desc; +- struct scatterlist *sgl; +- struct dma_slave_config slave_conf; +- struct qcom_adm_peripheral_config periph_conf = {}; +- enum dma_transfer_direction dir_eng; +- int ret; +- +- desc = kzalloc(sizeof(*desc), GFP_KERNEL); +- if (!desc) +- return -ENOMEM; +- +- sgl = &desc->adm_sgl; +- +- sg_init_one(sgl, vaddr, size); +- +- if (read) { +- dir_eng = DMA_DEV_TO_MEM; +- desc->dir = DMA_FROM_DEVICE; +- } else { +- dir_eng = DMA_MEM_TO_DEV; +- desc->dir = DMA_TO_DEVICE; +- } +- +- ret = dma_map_sg(nandc->dev, sgl, 1, desc->dir); +- if (ret == 0) { +- ret = -ENOMEM; +- goto err; +- } +- +- memset(&slave_conf, 0x00, sizeof(slave_conf)); +- +- slave_conf.device_fc = flow_control; +- if (read) { +- slave_conf.src_maxburst = 16; +- slave_conf.src_addr = nandc->base_dma + reg_off; +- if (nandc->data_crci) { +- periph_conf.crci = nandc->data_crci; +- slave_conf.peripheral_config = &periph_conf; +- slave_conf.peripheral_size = sizeof(periph_conf); +- } +- } else { +- slave_conf.dst_maxburst = 16; +- slave_conf.dst_addr = nandc->base_dma + reg_off; +- if (nandc->cmd_crci) { +- periph_conf.crci = nandc->cmd_crci; +- slave_conf.peripheral_config = &periph_conf; +- slave_conf.peripheral_size = sizeof(periph_conf); +- } +- } +- +- ret = dmaengine_slave_config(nandc->chan, &slave_conf); +- if (ret) { +- dev_err(nandc->dev, "failed to configure dma channel\n"); +- goto err; +- } +- +- dma_desc = dmaengine_prep_slave_sg(nandc->chan, sgl, 1, dir_eng, 0); +- if (!dma_desc) { +- dev_err(nandc->dev, "failed to prepare desc\n"); +- ret = -EINVAL; +- goto err; +- } +- +- desc->dma_desc = dma_desc; +- +- list_add_tail(&desc->node, &nandc->desc_list); +- +- return 0; +-err: +- kfree(desc); +- +- return ret; +-} +- +-/* +- * qcom_read_reg_dma: prepares a descriptor to read a given number of +- * contiguous registers to the reg_read_buf pointer +- * +- * @first: offset of the first register in the contiguous block +- * @num_regs: number of registers to read +- * @flags: flags to control DMA descriptor preparation +- */ +-static int qcom_read_reg_dma(struct qcom_nand_controller *nandc, int first, +- int num_regs, unsigned int flags) +-{ +- bool flow_control = false; +- void *vaddr; +- +- vaddr = nandc->reg_read_buf + nandc->reg_read_pos; +- nandc->reg_read_pos += num_regs; +- +- if (first == NAND_DEV_CMD_VLD || first == NAND_DEV_CMD1) +- first = dev_cmd_reg_addr(nandc, first); +- +- if (nandc->props->supports_bam) +- return qcom_prep_bam_dma_desc_cmd(nandc, true, first, vaddr, +- num_regs, flags); +- +- if (first == NAND_READ_ID || first == NAND_FLASH_STATUS) +- flow_control = true; +- +- return qcom_prep_adm_dma_desc(nandc, true, first, vaddr, +- num_regs * sizeof(u32), flow_control); +-} +- +-/* +- * qcom_write_reg_dma: prepares a descriptor to write a given number of +- * contiguous registers +- * +- * @vaddr: contiguous memory from where register value will +- * be written +- * @first: offset of the first register in the contiguous block +- * @num_regs: number of registers to write +- * @flags: flags to control DMA descriptor preparation +- */ +-static int qcom_write_reg_dma(struct qcom_nand_controller *nandc, __le32 *vaddr, +- int first, int num_regs, unsigned int flags) +-{ +- bool flow_control = false; +- +- if (first == NAND_EXEC_CMD) +- flags |= NAND_BAM_NWD; +- +- if (first == NAND_DEV_CMD1_RESTORE || first == NAND_DEV_CMD1) +- first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD1); +- +- if (first == NAND_DEV_CMD_VLD_RESTORE || first == NAND_DEV_CMD_VLD) +- first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD); +- +- if (nandc->props->supports_bam) +- return qcom_prep_bam_dma_desc_cmd(nandc, false, first, vaddr, +- num_regs, flags); +- +- if (first == NAND_FLASH_CMD) +- flow_control = true; +- +- return qcom_prep_adm_dma_desc(nandc, false, first, vaddr, +- num_regs * sizeof(u32), flow_control); +-} +- +-/* +- * qcom_read_data_dma: prepares a DMA descriptor to transfer data from the +- * controller's internal buffer to the buffer 'vaddr' +- * +- * @reg_off: offset within the controller's data buffer +- * @vaddr: virtual address of the buffer we want to write to +- * @size: DMA transaction size in bytes +- * @flags: flags to control DMA descriptor preparation +- */ +-static int qcom_read_data_dma(struct qcom_nand_controller *nandc, int reg_off, +- const u8 *vaddr, int size, unsigned int flags) +-{ +- if (nandc->props->supports_bam) +- return qcom_prep_bam_dma_desc_data(nandc, true, vaddr, size, flags); +- +- return qcom_prep_adm_dma_desc(nandc, true, reg_off, vaddr, size, false); +-} +- +-/* +- * qcom_write_data_dma: prepares a DMA descriptor to transfer data from +- * 'vaddr' to the controller's internal buffer +- * +- * @reg_off: offset within the controller's data buffer +- * @vaddr: virtual address of the buffer we want to read from +- * @size: DMA transaction size in bytes +- * @flags: flags to control DMA descriptor preparation +- */ +-static int qcom_write_data_dma(struct qcom_nand_controller *nandc, int reg_off, +- const u8 *vaddr, int size, unsigned int flags) +-{ +- if (nandc->props->supports_bam) +- return qcom_prep_bam_dma_desc_data(nandc, false, vaddr, size, flags); +- +- return qcom_prep_adm_dma_desc(nandc, false, reg_off, vaddr, size, false); +-} +- + /* + * Helper to prepare DMA descriptors for configuring registers + * before reading a NAND page. +@@ -1262,83 +394,6 @@ static void config_nand_cw_write(struct nand_chip *chip) + NAND_BAM_NEXT_SGL); + } + +-/* helpers to submit/free our list of dma descriptors */ +-static int qcom_submit_descs(struct qcom_nand_controller *nandc) +-{ +- struct desc_info *desc, *n; +- dma_cookie_t cookie = 0; +- struct bam_transaction *bam_txn = nandc->bam_txn; +- int ret = 0; +- +- if (nandc->props->supports_bam) { +- if (bam_txn->rx_sgl_pos > bam_txn->rx_sgl_start) { +- ret = qcom_prepare_bam_async_desc(nandc, nandc->rx_chan, 0); +- if (ret) +- goto err_unmap_free_desc; +- } +- +- if (bam_txn->tx_sgl_pos > bam_txn->tx_sgl_start) { +- ret = qcom_prepare_bam_async_desc(nandc, nandc->tx_chan, +- DMA_PREP_INTERRUPT); +- if (ret) +- goto err_unmap_free_desc; +- } +- +- if (bam_txn->cmd_sgl_pos > bam_txn->cmd_sgl_start) { +- ret = qcom_prepare_bam_async_desc(nandc, nandc->cmd_chan, +- DMA_PREP_CMD); +- if (ret) +- goto err_unmap_free_desc; +- } +- } +- +- list_for_each_entry(desc, &nandc->desc_list, node) +- cookie = dmaengine_submit(desc->dma_desc); +- +- if (nandc->props->supports_bam) { +- bam_txn->last_cmd_desc->callback = qcom_qpic_bam_dma_done; +- bam_txn->last_cmd_desc->callback_param = bam_txn; +- +- dma_async_issue_pending(nandc->tx_chan); +- dma_async_issue_pending(nandc->rx_chan); +- dma_async_issue_pending(nandc->cmd_chan); +- +- if (!wait_for_completion_timeout(&bam_txn->txn_done, +- QPIC_NAND_COMPLETION_TIMEOUT)) +- ret = -ETIMEDOUT; +- } else { +- if (dma_sync_wait(nandc->chan, cookie) != DMA_COMPLETE) +- ret = -ETIMEDOUT; +- } +- +-err_unmap_free_desc: +- /* +- * Unmap the dma sg_list and free the desc allocated by both +- * qcom_prepare_bam_async_desc() and qcom_prep_adm_dma_desc() functions. +- */ +- list_for_each_entry_safe(desc, n, &nandc->desc_list, node) { +- list_del(&desc->node); +- +- if (nandc->props->supports_bam) +- dma_unmap_sg(nandc->dev, desc->bam_sgl, +- desc->sgl_cnt, desc->dir); +- else +- dma_unmap_sg(nandc->dev, &desc->adm_sgl, 1, +- desc->dir); +- +- kfree(desc); +- } +- +- return ret; +-} +- +-/* reset the register read buffer for next NAND operation */ +-static void qcom_clear_read_regs(struct qcom_nand_controller *nandc) +-{ +- nandc->reg_read_pos = 0; +- qcom_nandc_dev_to_mem(nandc, false); +-} +- + /* + * when using BCH ECC, the HW flags an error in NAND_FLASH_STATUS if it read + * an erased CW, and reports an erased CW in NAND_ERASED_CW_DETECT_STATUS. +@@ -2975,141 +2030,14 @@ static const struct nand_controller_ops qcom_nandc_ops = { + .exec_op = qcom_nand_exec_op, + }; + +-static void qcom_nandc_unalloc(struct qcom_nand_controller *nandc) +-{ +- if (nandc->props->supports_bam) { +- if (!dma_mapping_error(nandc->dev, nandc->reg_read_dma)) +- dma_unmap_single(nandc->dev, nandc->reg_read_dma, +- MAX_REG_RD * +- sizeof(*nandc->reg_read_buf), +- DMA_FROM_DEVICE); +- +- if (nandc->tx_chan) +- dma_release_channel(nandc->tx_chan); +- +- if (nandc->rx_chan) +- dma_release_channel(nandc->rx_chan); +- +- if (nandc->cmd_chan) +- dma_release_channel(nandc->cmd_chan); +- } else { +- if (nandc->chan) +- dma_release_channel(nandc->chan); +- } +-} +- +-static int qcom_nandc_alloc(struct qcom_nand_controller *nandc) +-{ +- int ret; +- +- ret = dma_set_coherent_mask(nandc->dev, DMA_BIT_MASK(32)); +- if (ret) { +- dev_err(nandc->dev, "failed to set DMA mask\n"); +- return ret; +- } +- +- /* +- * we use the internal buffer for reading ONFI params, reading small +- * data like ID and status, and preforming read-copy-write operations +- * when writing to a codeword partially. 532 is the maximum possible +- * size of a codeword for our nand controller +- */ +- nandc->buf_size = 532; +- +- nandc->data_buffer = devm_kzalloc(nandc->dev, nandc->buf_size, GFP_KERNEL); +- if (!nandc->data_buffer) +- return -ENOMEM; +- +- nandc->regs = devm_kzalloc(nandc->dev, sizeof(*nandc->regs), GFP_KERNEL); +- if (!nandc->regs) +- return -ENOMEM; +- +- nandc->reg_read_buf = devm_kcalloc(nandc->dev, MAX_REG_RD, +- sizeof(*nandc->reg_read_buf), +- GFP_KERNEL); +- if (!nandc->reg_read_buf) +- return -ENOMEM; +- +- if (nandc->props->supports_bam) { +- nandc->reg_read_dma = +- dma_map_single(nandc->dev, nandc->reg_read_buf, +- MAX_REG_RD * +- sizeof(*nandc->reg_read_buf), +- DMA_FROM_DEVICE); +- if (dma_mapping_error(nandc->dev, nandc->reg_read_dma)) { +- dev_err(nandc->dev, "failed to DMA MAP reg buffer\n"); +- return -EIO; +- } +- +- nandc->tx_chan = dma_request_chan(nandc->dev, "tx"); +- if (IS_ERR(nandc->tx_chan)) { +- ret = PTR_ERR(nandc->tx_chan); +- nandc->tx_chan = NULL; +- dev_err_probe(nandc->dev, ret, +- "tx DMA channel request failed\n"); +- goto unalloc; +- } +- +- nandc->rx_chan = dma_request_chan(nandc->dev, "rx"); +- if (IS_ERR(nandc->rx_chan)) { +- ret = PTR_ERR(nandc->rx_chan); +- nandc->rx_chan = NULL; +- dev_err_probe(nandc->dev, ret, +- "rx DMA channel request failed\n"); +- goto unalloc; +- } +- +- nandc->cmd_chan = dma_request_chan(nandc->dev, "cmd"); +- if (IS_ERR(nandc->cmd_chan)) { +- ret = PTR_ERR(nandc->cmd_chan); +- nandc->cmd_chan = NULL; +- dev_err_probe(nandc->dev, ret, +- "cmd DMA channel request failed\n"); +- goto unalloc; +- } +- +- /* +- * Initially allocate BAM transaction to read ONFI param page. +- * After detecting all the devices, this BAM transaction will +- * be freed and the next BAM transaction will be allocated with +- * maximum codeword size +- */ +- nandc->max_cwperpage = 1; +- nandc->bam_txn = qcom_alloc_bam_transaction(nandc); +- if (!nandc->bam_txn) { +- dev_err(nandc->dev, +- "failed to allocate bam transaction\n"); +- ret = -ENOMEM; +- goto unalloc; +- } +- } else { +- nandc->chan = dma_request_chan(nandc->dev, "rxtx"); +- if (IS_ERR(nandc->chan)) { +- ret = PTR_ERR(nandc->chan); +- nandc->chan = NULL; +- dev_err_probe(nandc->dev, ret, +- "rxtx DMA channel request failed\n"); +- return ret; +- } +- } +- +- INIT_LIST_HEAD(&nandc->desc_list); +- INIT_LIST_HEAD(&nandc->host_list); +- +- nand_controller_init(&nandc->controller); +- nandc->controller.ops = &qcom_nandc_ops; +- +- return 0; +-unalloc: +- qcom_nandc_unalloc(nandc); +- return ret; +-} +- + /* one time setup of a few nand controller registers */ + static int qcom_nandc_setup(struct qcom_nand_controller *nandc) + { + u32 nand_ctrl; + ++ nand_controller_init(nandc->controller); ++ nandc->controller->ops = &qcom_nandc_ops; ++ + /* kill onenand */ + if (!nandc->props->nandc_part_of_qpic) + nandc_write(nandc, SFLASHC_BURST_CFG, 0); +@@ -3248,7 +2176,7 @@ static int qcom_nand_host_init_and_register(struct qcom_nand_controller *nandc, + chip->legacy.block_bad = qcom_nandc_block_bad; + chip->legacy.block_markbad = qcom_nandc_block_markbad; + +- chip->controller = &nandc->controller; ++ chip->controller = nandc->controller; + chip->options |= NAND_NO_SUBPAGE_WRITE | NAND_USES_DMA | + NAND_SKIP_BBTSCAN; + +@@ -3331,17 +2259,21 @@ static int qcom_nandc_parse_dt(struct platform_device *pdev) + static int qcom_nandc_probe(struct platform_device *pdev) + { + struct qcom_nand_controller *nandc; ++ struct nand_controller *controller; + const void *dev_data; + struct device *dev = &pdev->dev; + struct resource *res; + int ret; + +- nandc = devm_kzalloc(&pdev->dev, sizeof(*nandc), GFP_KERNEL); ++ nandc = devm_kzalloc(&pdev->dev, sizeof(*nandc) + sizeof(*controller), ++ GFP_KERNEL); + if (!nandc) + return -ENOMEM; ++ controller = (struct nand_controller *)&nandc[1]; + + platform_set_drvdata(pdev, nandc); + nandc->dev = dev; ++ nandc->controller = controller; + + dev_data = of_device_get_match_data(dev); + if (!dev_data) { +diff --git a/include/linux/mtd/nand-qpic-common.h b/include/linux/mtd/nand-qpic-common.h +new file mode 100644 +index 000000000000..425994429387 +--- /dev/null ++++ b/include/linux/mtd/nand-qpic-common.h +@@ -0,0 +1,468 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * QCOM QPIC common APIs header file ++ * ++ * Copyright (c) 2023 Qualcomm Inc. ++ * Authors: Md sadre Alam ++ * ++ */ ++#ifndef __MTD_NAND_QPIC_COMMON_H__ ++#define __MTD_NAND_QPIC_COMMON_H__ ++ ++/* NANDc reg offsets */ ++#define NAND_FLASH_CMD 0x00 ++#define NAND_ADDR0 0x04 ++#define NAND_ADDR1 0x08 ++#define NAND_FLASH_CHIP_SELECT 0x0c ++#define NAND_EXEC_CMD 0x10 ++#define NAND_FLASH_STATUS 0x14 ++#define NAND_BUFFER_STATUS 0x18 ++#define NAND_DEV0_CFG0 0x20 ++#define NAND_DEV0_CFG1 0x24 ++#define NAND_DEV0_ECC_CFG 0x28 ++#define NAND_AUTO_STATUS_EN 0x2c ++#define NAND_DEV1_CFG0 0x30 ++#define NAND_DEV1_CFG1 0x34 ++#define NAND_READ_ID 0x40 ++#define NAND_READ_STATUS 0x44 ++#define NAND_DEV_CMD0 0xa0 ++#define NAND_DEV_CMD1 0xa4 ++#define NAND_DEV_CMD2 0xa8 ++#define NAND_DEV_CMD_VLD 0xac ++#define SFLASHC_BURST_CFG 0xe0 ++#define NAND_ERASED_CW_DETECT_CFG 0xe8 ++#define NAND_ERASED_CW_DETECT_STATUS 0xec ++#define NAND_EBI2_ECC_BUF_CFG 0xf0 ++#define FLASH_BUF_ACC 0x100 ++ ++#define NAND_CTRL 0xf00 ++#define NAND_VERSION 0xf08 ++#define NAND_READ_LOCATION_0 0xf20 ++#define NAND_READ_LOCATION_1 0xf24 ++#define NAND_READ_LOCATION_2 0xf28 ++#define NAND_READ_LOCATION_3 0xf2c ++#define NAND_READ_LOCATION_LAST_CW_0 0xf40 ++#define NAND_READ_LOCATION_LAST_CW_1 0xf44 ++#define NAND_READ_LOCATION_LAST_CW_2 0xf48 ++#define NAND_READ_LOCATION_LAST_CW_3 0xf4c ++ ++/* dummy register offsets, used by qcom_write_reg_dma */ ++#define NAND_DEV_CMD1_RESTORE 0xdead ++#define NAND_DEV_CMD_VLD_RESTORE 0xbeef ++ ++/* NAND_FLASH_CMD bits */ ++#define PAGE_ACC BIT(4) ++#define LAST_PAGE BIT(5) ++ ++/* NAND_FLASH_CHIP_SELECT bits */ ++#define NAND_DEV_SEL 0 ++#define DM_EN BIT(2) ++ ++/* NAND_FLASH_STATUS bits */ ++#define FS_OP_ERR BIT(4) ++#define FS_READY_BSY_N BIT(5) ++#define FS_MPU_ERR BIT(8) ++#define FS_DEVICE_STS_ERR BIT(16) ++#define FS_DEVICE_WP BIT(23) ++ ++/* NAND_BUFFER_STATUS bits */ ++#define BS_UNCORRECTABLE_BIT BIT(8) ++#define BS_CORRECTABLE_ERR_MSK 0x1f ++ ++/* NAND_DEVn_CFG0 bits */ ++#define DISABLE_STATUS_AFTER_WRITE 4 ++#define CW_PER_PAGE 6 ++#define UD_SIZE_BYTES 9 ++#define UD_SIZE_BYTES_MASK GENMASK(18, 9) ++#define ECC_PARITY_SIZE_BYTES_RS 19 ++#define SPARE_SIZE_BYTES 23 ++#define SPARE_SIZE_BYTES_MASK GENMASK(26, 23) ++#define NUM_ADDR_CYCLES 27 ++#define STATUS_BFR_READ 30 ++#define SET_RD_MODE_AFTER_STATUS 31 ++ ++/* NAND_DEVn_CFG0 bits */ ++#define DEV0_CFG1_ECC_DISABLE 0 ++#define WIDE_FLASH 1 ++#define NAND_RECOVERY_CYCLES 2 ++#define CS_ACTIVE_BSY 5 ++#define BAD_BLOCK_BYTE_NUM 6 ++#define BAD_BLOCK_IN_SPARE_AREA 16 ++#define WR_RD_BSY_GAP 17 ++#define ENABLE_BCH_ECC 27 ++ ++/* NAND_DEV0_ECC_CFG bits */ ++#define ECC_CFG_ECC_DISABLE 0 ++#define ECC_SW_RESET 1 ++#define ECC_MODE 4 ++#define ECC_PARITY_SIZE_BYTES_BCH 8 ++#define ECC_NUM_DATA_BYTES 16 ++#define ECC_NUM_DATA_BYTES_MASK GENMASK(25, 16) ++#define ECC_FORCE_CLK_OPEN 30 ++ ++/* NAND_DEV_CMD1 bits */ ++#define READ_ADDR 0 ++ ++/* NAND_DEV_CMD_VLD bits */ ++#define READ_START_VLD BIT(0) ++#define READ_STOP_VLD BIT(1) ++#define WRITE_START_VLD BIT(2) ++#define ERASE_START_VLD BIT(3) ++#define SEQ_READ_START_VLD BIT(4) ++ ++/* NAND_EBI2_ECC_BUF_CFG bits */ ++#define NUM_STEPS 0 ++ ++/* NAND_ERASED_CW_DETECT_CFG bits */ ++#define ERASED_CW_ECC_MASK 1 ++#define AUTO_DETECT_RES 0 ++#define MASK_ECC BIT(ERASED_CW_ECC_MASK) ++#define RESET_ERASED_DET BIT(AUTO_DETECT_RES) ++#define ACTIVE_ERASED_DET (0 << AUTO_DETECT_RES) ++#define CLR_ERASED_PAGE_DET (RESET_ERASED_DET | MASK_ECC) ++#define SET_ERASED_PAGE_DET (ACTIVE_ERASED_DET | MASK_ECC) ++ ++/* NAND_ERASED_CW_DETECT_STATUS bits */ ++#define PAGE_ALL_ERASED BIT(7) ++#define CODEWORD_ALL_ERASED BIT(6) ++#define PAGE_ERASED BIT(5) ++#define CODEWORD_ERASED BIT(4) ++#define ERASED_PAGE (PAGE_ALL_ERASED | PAGE_ERASED) ++#define ERASED_CW (CODEWORD_ALL_ERASED | CODEWORD_ERASED) ++ ++/* NAND_READ_LOCATION_n bits */ ++#define READ_LOCATION_OFFSET 0 ++#define READ_LOCATION_SIZE 16 ++#define READ_LOCATION_LAST 31 ++ ++/* Version Mask */ ++#define NAND_VERSION_MAJOR_MASK 0xf0000000 ++#define NAND_VERSION_MAJOR_SHIFT 28 ++#define NAND_VERSION_MINOR_MASK 0x0fff0000 ++#define NAND_VERSION_MINOR_SHIFT 16 ++ ++/* NAND OP_CMDs */ ++#define OP_PAGE_READ 0x2 ++#define OP_PAGE_READ_WITH_ECC 0x3 ++#define OP_PAGE_READ_WITH_ECC_SPARE 0x4 ++#define OP_PAGE_READ_ONFI_READ 0x5 ++#define OP_PROGRAM_PAGE 0x6 ++#define OP_PAGE_PROGRAM_WITH_ECC 0x7 ++#define OP_PROGRAM_PAGE_SPARE 0x9 ++#define OP_BLOCK_ERASE 0xa ++#define OP_CHECK_STATUS 0xc ++#define OP_FETCH_ID 0xb ++#define OP_RESET_DEVICE 0xd ++ ++/* Default Value for NAND_DEV_CMD_VLD */ ++#define NAND_DEV_CMD_VLD_VAL (READ_START_VLD | WRITE_START_VLD | \ ++ ERASE_START_VLD | SEQ_READ_START_VLD) ++ ++/* NAND_CTRL bits */ ++#define BAM_MODE_EN BIT(0) ++ ++/* ++ * the NAND controller performs reads/writes with ECC in 516 byte chunks. ++ * the driver calls the chunks 'step' or 'codeword' interchangeably ++ */ ++#define NANDC_STEP_SIZE 512 ++ ++/* ++ * the largest page size we support is 8K, this will have 16 steps/codewords ++ * of 512 bytes each ++ */ ++#define MAX_NUM_STEPS (SZ_8K / NANDC_STEP_SIZE) ++ ++/* we read at most 3 registers per codeword scan */ ++#define MAX_REG_RD (3 * MAX_NUM_STEPS) ++ ++/* ECC modes supported by the controller */ ++#define ECC_NONE BIT(0) ++#define ECC_RS_4BIT BIT(1) ++#define ECC_BCH_4BIT BIT(2) ++#define ECC_BCH_8BIT BIT(3) ++ ++/* ++ * Returns the actual register address for all NAND_DEV_ registers ++ * (i.e. NAND_DEV_CMD0, NAND_DEV_CMD1, NAND_DEV_CMD2 and NAND_DEV_CMD_VLD) ++ */ ++#define dev_cmd_reg_addr(nandc, reg) ((nandc)->props->dev_cmd_reg_start + (reg)) ++ ++/* Returns the NAND register physical address */ ++#define nandc_reg_phys(chip, offset) ((chip)->base_phys + (offset)) ++ ++/* Returns the dma address for reg read buffer */ ++#define reg_buf_dma_addr(chip, vaddr) \ ++ ((chip)->reg_read_dma + \ ++ ((u8 *)(vaddr) - (u8 *)(chip)->reg_read_buf)) ++ ++#define QPIC_PER_CW_CMD_ELEMENTS 32 ++#define QPIC_PER_CW_CMD_SGL 32 ++#define QPIC_PER_CW_DATA_SGL 8 ++ ++#define QPIC_NAND_COMPLETION_TIMEOUT msecs_to_jiffies(2000) ++ ++/* ++ * Flags used in DMA descriptor preparation helper functions ++ * (i.e. qcom_read_reg_dma/qcom_write_reg_dma/qcom_read_data_dma/qcom_write_data_dma) ++ */ ++/* Don't set the EOT in current tx BAM sgl */ ++#define NAND_BAM_NO_EOT BIT(0) ++/* Set the NWD flag in current BAM sgl */ ++#define NAND_BAM_NWD BIT(1) ++/* Finish writing in the current BAM sgl and start writing in another BAM sgl */ ++#define NAND_BAM_NEXT_SGL BIT(2) ++/* ++ * Erased codeword status is being used two times in single transfer so this ++ * flag will determine the current value of erased codeword status register ++ */ ++#define NAND_ERASED_CW_SET BIT(4) ++ ++#define MAX_ADDRESS_CYCLE 5 ++ ++/* ++ * This data type corresponds to the BAM transaction which will be used for all ++ * NAND transfers. ++ * @bam_ce - the array of BAM command elements ++ * @cmd_sgl - sgl for NAND BAM command pipe ++ * @data_sgl - sgl for NAND BAM consumer/producer pipe ++ * @last_data_desc - last DMA desc in data channel (tx/rx). ++ * @last_cmd_desc - last DMA desc in command channel. ++ * @txn_done - completion for NAND transfer. ++ * @bam_ce_pos - the index in bam_ce which is available for next sgl ++ * @bam_ce_start - the index in bam_ce which marks the start position ce ++ * for current sgl. It will be used for size calculation ++ * for current sgl ++ * @cmd_sgl_pos - current index in command sgl. ++ * @cmd_sgl_start - start index in command sgl. ++ * @tx_sgl_pos - current index in data sgl for tx. ++ * @tx_sgl_start - start index in data sgl for tx. ++ * @rx_sgl_pos - current index in data sgl for rx. ++ * @rx_sgl_start - start index in data sgl for rx. ++ */ ++struct bam_transaction { ++ struct bam_cmd_element *bam_ce; ++ struct scatterlist *cmd_sgl; ++ struct scatterlist *data_sgl; ++ struct dma_async_tx_descriptor *last_data_desc; ++ struct dma_async_tx_descriptor *last_cmd_desc; ++ struct completion txn_done; ++ u32 bam_ce_pos; ++ u32 bam_ce_start; ++ u32 cmd_sgl_pos; ++ u32 cmd_sgl_start; ++ u32 tx_sgl_pos; ++ u32 tx_sgl_start; ++ u32 rx_sgl_pos; ++ u32 rx_sgl_start; ++}; ++ ++/* ++ * This data type corresponds to the nand dma descriptor ++ * @dma_desc - low level DMA engine descriptor ++ * @list - list for desc_info ++ * ++ * @adm_sgl - sgl which will be used for single sgl dma descriptor. Only used by ++ * ADM ++ * @bam_sgl - sgl which will be used for dma descriptor. Only used by BAM ++ * @sgl_cnt - number of SGL in bam_sgl. Only used by BAM ++ * @dir - DMA transfer direction ++ */ ++struct desc_info { ++ struct dma_async_tx_descriptor *dma_desc; ++ struct list_head node; ++ ++ union { ++ struct scatterlist adm_sgl; ++ struct { ++ struct scatterlist *bam_sgl; ++ int sgl_cnt; ++ }; ++ }; ++ enum dma_data_direction dir; ++}; ++ ++/* ++ * holds the current register values that we want to write. acts as a contiguous ++ * chunk of memory which we use to write the controller registers through DMA. ++ */ ++struct nandc_regs { ++ __le32 cmd; ++ __le32 addr0; ++ __le32 addr1; ++ __le32 chip_sel; ++ __le32 exec; ++ ++ __le32 cfg0; ++ __le32 cfg1; ++ __le32 ecc_bch_cfg; ++ ++ __le32 clrflashstatus; ++ __le32 clrreadstatus; ++ ++ __le32 cmd1; ++ __le32 vld; ++ ++ __le32 orig_cmd1; ++ __le32 orig_vld; ++ ++ __le32 ecc_buf_cfg; ++ __le32 read_location0; ++ __le32 read_location1; ++ __le32 read_location2; ++ __le32 read_location3; ++ __le32 read_location_last0; ++ __le32 read_location_last1; ++ __le32 read_location_last2; ++ __le32 read_location_last3; ++ ++ __le32 erased_cw_detect_cfg_clr; ++ __le32 erased_cw_detect_cfg_set; ++}; ++ ++/* ++ * NAND controller data struct ++ * ++ * @dev: parent device ++ * ++ * @base: MMIO base ++ * ++ * @core_clk: controller clock ++ * @aon_clk: another controller clock ++ * ++ * @regs: a contiguous chunk of memory for DMA register ++ * writes. contains the register values to be ++ * written to controller ++ * ++ * @props: properties of current NAND controller, ++ * initialized via DT match data ++ * ++ * @controller: base controller structure ++ * @host_list: list containing all the chips attached to the ++ * controller ++ * ++ * @chan: dma channel ++ * @cmd_crci: ADM DMA CRCI for command flow control ++ * @data_crci: ADM DMA CRCI for data flow control ++ * ++ * @desc_list: DMA descriptor list (list of desc_infos) ++ * ++ * @data_buffer: our local DMA buffer for page read/writes, ++ * used when we can't use the buffer provided ++ * by upper layers directly ++ * @reg_read_buf: local buffer for reading back registers via DMA ++ * ++ * @base_phys: physical base address of controller registers ++ * @base_dma: dma base address of controller registers ++ * @reg_read_dma: contains dma address for register read buffer ++ * ++ * @buf_size/count/start: markers for chip->legacy.read_buf/write_buf ++ * functions ++ * @max_cwperpage: maximum QPIC codewords required. calculated ++ * from all connected NAND devices pagesize ++ * ++ * @reg_read_pos: marker for data read in reg_read_buf ++ * ++ * @cmd1/vld: some fixed controller register values ++ * ++ * @exec_opwrite: flag to select correct number of code word ++ * while reading status ++ */ ++struct qcom_nand_controller { ++ struct device *dev; ++ ++ void __iomem *base; ++ ++ struct clk *core_clk; ++ struct clk *aon_clk; ++ ++ struct nandc_regs *regs; ++ struct bam_transaction *bam_txn; ++ ++ const struct qcom_nandc_props *props; ++ ++ struct nand_controller *controller; ++ struct list_head host_list; ++ ++ union { ++ /* will be used only by QPIC for BAM DMA */ ++ struct { ++ struct dma_chan *tx_chan; ++ struct dma_chan *rx_chan; ++ struct dma_chan *cmd_chan; ++ }; ++ ++ /* will be used only by EBI2 for ADM DMA */ ++ struct { ++ struct dma_chan *chan; ++ unsigned int cmd_crci; ++ unsigned int data_crci; ++ }; ++ }; ++ ++ struct list_head desc_list; ++ ++ u8 *data_buffer; ++ __le32 *reg_read_buf; ++ ++ phys_addr_t base_phys; ++ dma_addr_t base_dma; ++ dma_addr_t reg_read_dma; ++ ++ int buf_size; ++ int buf_count; ++ int buf_start; ++ unsigned int max_cwperpage; ++ ++ int reg_read_pos; ++ ++ u32 cmd1, vld; ++ bool exec_opwrite; ++}; ++ ++/* ++ * This data type corresponds to the NAND controller properties which varies ++ * among different NAND controllers. ++ * @ecc_modes - ecc mode for NAND ++ * @dev_cmd_reg_start - NAND_DEV_CMD_* registers starting offset ++ * @supports_bam - whether NAND controller is using BAM ++ * @nandc_part_of_qpic - whether NAND controller is part of qpic IP ++ * @qpic_version2 - flag to indicate QPIC IP version 2 ++ * @use_codeword_fixup - whether NAND has different layout for boot partitions ++ */ ++struct qcom_nandc_props { ++ u32 ecc_modes; ++ u32 dev_cmd_reg_start; ++ bool supports_bam; ++ bool nandc_part_of_qpic; ++ bool qpic_version2; ++ bool use_codeword_fixup; ++}; ++ ++void qcom_free_bam_transaction(struct qcom_nand_controller *nandc); ++struct bam_transaction *qcom_alloc_bam_transaction(struct qcom_nand_controller *nandc); ++void qcom_clear_bam_transaction(struct qcom_nand_controller *nandc); ++void qcom_qpic_bam_dma_done(void *data); ++void qcom_nandc_dev_to_mem(struct qcom_nand_controller *nandc, bool is_cpu); ++int qcom_prepare_bam_async_desc(struct qcom_nand_controller *nandc, ++ struct dma_chan *chan, unsigned long flags); ++int qcom_prep_bam_dma_desc_cmd(struct qcom_nand_controller *nandc, bool read, ++ int reg_off, const void *vaddr, int size, unsigned int flags); ++int qcom_prep_bam_dma_desc_data(struct qcom_nand_controller *nandc, bool read, ++ const void *vaddr, int size, unsigned int flags); ++int qcom_prep_adm_dma_desc(struct qcom_nand_controller *nandc, bool read, int reg_off, ++ const void *vaddr, int size, bool flow_control); ++int qcom_read_reg_dma(struct qcom_nand_controller *nandc, int first, int num_regs, ++ unsigned int flags); ++int qcom_write_reg_dma(struct qcom_nand_controller *nandc, __le32 *vaddr, int first, ++ int num_regs, unsigned int flags); ++int qcom_read_data_dma(struct qcom_nand_controller *nandc, int reg_off, const u8 *vaddr, ++ int size, unsigned int flags); ++int qcom_write_data_dma(struct qcom_nand_controller *nandc, int reg_off, const u8 *vaddr, ++ int size, unsigned int flags); ++int qcom_submit_descs(struct qcom_nand_controller *nandc); ++void qcom_clear_read_regs(struct qcom_nand_controller *nandc); ++void qcom_nandc_unalloc(struct qcom_nand_controller *nandc); ++int qcom_nandc_alloc(struct qcom_nand_controller *nandc); ++#endif ++ +-- +2.51.0 + + +From 70800832162a019d19111fdac370e50ae4afad08 Mon Sep 17 00:00:00 2001 +From: Md Sadre Alam +Date: Wed, 20 Nov 2024 14:45:03 +0530 +Subject: [PATCH 013/517] mtd: rawnand: qcom: use FIELD_PREP and GENMASK + +Use the bitfield macro FIELD_PREP, and GENMASK to +do the shift and mask in one go. This makes the code +more readable. + +Reviewed-by: Konrad Dybcio +Signed-off-by: Md Sadre Alam +Signed-off-by: Miquel Raynal +--- + drivers/mtd/nand/raw/qcom_nandc.c | 97 ++++++++++++++-------------- + include/linux/mtd/nand-qpic-common.h | 31 +++++---- + 2 files changed, 67 insertions(+), 61 deletions(-) + +diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c +index f07871532ef0..086cb139adf1 100644 +--- a/drivers/mtd/nand/raw/qcom_nandc.c ++++ b/drivers/mtd/nand/raw/qcom_nandc.c +@@ -281,7 +281,7 @@ static void update_rw_regs(struct qcom_nand_host *host, int num_cw, bool read, i + (num_cw - 1) << CW_PER_PAGE); + + cfg1 = cpu_to_le32(host->cfg1_raw); +- ecc_bch_cfg = cpu_to_le32(1 << ECC_CFG_ECC_DISABLE); ++ ecc_bch_cfg = cpu_to_le32(ECC_CFG_ECC_DISABLE); + } + + nandc->regs->cmd = cmd; +@@ -1494,42 +1494,41 @@ static int qcom_nand_attach_chip(struct nand_chip *chip) + host->cw_size = host->cw_data + ecc->bytes; + bad_block_byte = mtd->writesize - host->cw_size * (cwperpage - 1) + 1; + +- host->cfg0 = (cwperpage - 1) << CW_PER_PAGE +- | host->cw_data << UD_SIZE_BYTES +- | 0 << DISABLE_STATUS_AFTER_WRITE +- | 5 << NUM_ADDR_CYCLES +- | host->ecc_bytes_hw << ECC_PARITY_SIZE_BYTES_RS +- | 0 << STATUS_BFR_READ +- | 1 << SET_RD_MODE_AFTER_STATUS +- | host->spare_bytes << SPARE_SIZE_BYTES; +- +- host->cfg1 = 7 << NAND_RECOVERY_CYCLES +- | 0 << CS_ACTIVE_BSY +- | bad_block_byte << BAD_BLOCK_BYTE_NUM +- | 0 << BAD_BLOCK_IN_SPARE_AREA +- | 2 << WR_RD_BSY_GAP +- | wide_bus << WIDE_FLASH +- | host->bch_enabled << ENABLE_BCH_ECC; +- +- host->cfg0_raw = (cwperpage - 1) << CW_PER_PAGE +- | host->cw_size << UD_SIZE_BYTES +- | 5 << NUM_ADDR_CYCLES +- | 0 << SPARE_SIZE_BYTES; +- +- host->cfg1_raw = 7 << NAND_RECOVERY_CYCLES +- | 0 << CS_ACTIVE_BSY +- | 17 << BAD_BLOCK_BYTE_NUM +- | 1 << BAD_BLOCK_IN_SPARE_AREA +- | 2 << WR_RD_BSY_GAP +- | wide_bus << WIDE_FLASH +- | 1 << DEV0_CFG1_ECC_DISABLE; +- +- host->ecc_bch_cfg = !host->bch_enabled << ECC_CFG_ECC_DISABLE +- | 0 << ECC_SW_RESET +- | host->cw_data << ECC_NUM_DATA_BYTES +- | 1 << ECC_FORCE_CLK_OPEN +- | ecc_mode << ECC_MODE +- | host->ecc_bytes_hw << ECC_PARITY_SIZE_BYTES_BCH; ++ host->cfg0 = FIELD_PREP(CW_PER_PAGE_MASK, (cwperpage - 1)) | ++ FIELD_PREP(UD_SIZE_BYTES_MASK, host->cw_data) | ++ FIELD_PREP(DISABLE_STATUS_AFTER_WRITE, 0) | ++ FIELD_PREP(NUM_ADDR_CYCLES_MASK, 5) | ++ FIELD_PREP(ECC_PARITY_SIZE_BYTES_RS, host->ecc_bytes_hw) | ++ FIELD_PREP(STATUS_BFR_READ, 0) | ++ FIELD_PREP(SET_RD_MODE_AFTER_STATUS, 1) | ++ FIELD_PREP(SPARE_SIZE_BYTES_MASK, host->spare_bytes); ++ ++ host->cfg1 = FIELD_PREP(NAND_RECOVERY_CYCLES_MASK, 7) | ++ FIELD_PREP(BAD_BLOCK_BYTE_NUM_MASK, bad_block_byte) | ++ FIELD_PREP(BAD_BLOCK_IN_SPARE_AREA, 0) | ++ FIELD_PREP(WR_RD_BSY_GAP_MASK, 2) | ++ FIELD_PREP(WIDE_FLASH, wide_bus) | ++ FIELD_PREP(ENABLE_BCH_ECC, host->bch_enabled); ++ ++ host->cfg0_raw = FIELD_PREP(CW_PER_PAGE_MASK, (cwperpage - 1)) | ++ FIELD_PREP(UD_SIZE_BYTES_MASK, host->cw_size) | ++ FIELD_PREP(NUM_ADDR_CYCLES_MASK, 5) | ++ FIELD_PREP(SPARE_SIZE_BYTES_MASK, 0); ++ ++ host->cfg1_raw = FIELD_PREP(NAND_RECOVERY_CYCLES_MASK, 7) | ++ FIELD_PREP(CS_ACTIVE_BSY, 0) | ++ FIELD_PREP(BAD_BLOCK_BYTE_NUM_MASK, 17) | ++ FIELD_PREP(BAD_BLOCK_IN_SPARE_AREA, 1) | ++ FIELD_PREP(WR_RD_BSY_GAP_MASK, 2) | ++ FIELD_PREP(WIDE_FLASH, wide_bus) | ++ FIELD_PREP(DEV0_CFG1_ECC_DISABLE, 1); ++ ++ host->ecc_bch_cfg = FIELD_PREP(ECC_CFG_ECC_DISABLE, !host->bch_enabled) | ++ FIELD_PREP(ECC_SW_RESET, 0) | ++ FIELD_PREP(ECC_NUM_DATA_BYTES_MASK, host->cw_data) | ++ FIELD_PREP(ECC_FORCE_CLK_OPEN, 1) | ++ FIELD_PREP(ECC_MODE_MASK, ecc_mode) | ++ FIELD_PREP(ECC_PARITY_SIZE_BYTES_BCH_MASK, host->ecc_bytes_hw); + + if (!nandc->props->qpic_version2) + host->ecc_buf_cfg = 0x203 << NUM_STEPS; +@@ -1887,21 +1886,21 @@ static int qcom_param_page_type_exec(struct nand_chip *chip, const struct nand_ + nandc->regs->addr0 = 0; + nandc->regs->addr1 = 0; + +- nandc->regs->cfg0 = cpu_to_le32(0 << CW_PER_PAGE | +- 512 << UD_SIZE_BYTES | +- 5 << NUM_ADDR_CYCLES | +- 0 << SPARE_SIZE_BYTES); ++ host->cfg0 = FIELD_PREP(CW_PER_PAGE_MASK, 0) | ++ FIELD_PREP(UD_SIZE_BYTES_MASK, 512) | ++ FIELD_PREP(NUM_ADDR_CYCLES_MASK, 5) | ++ FIELD_PREP(SPARE_SIZE_BYTES_MASK, 0); + +- nandc->regs->cfg1 = cpu_to_le32(7 << NAND_RECOVERY_CYCLES | +- 0 << CS_ACTIVE_BSY | +- 17 << BAD_BLOCK_BYTE_NUM | +- 1 << BAD_BLOCK_IN_SPARE_AREA | +- 2 << WR_RD_BSY_GAP | +- 0 << WIDE_FLASH | +- 1 << DEV0_CFG1_ECC_DISABLE); ++ host->cfg1 = FIELD_PREP(NAND_RECOVERY_CYCLES_MASK, 7) | ++ FIELD_PREP(BAD_BLOCK_BYTE_NUM_MASK, 17) | ++ FIELD_PREP(CS_ACTIVE_BSY, 0) | ++ FIELD_PREP(BAD_BLOCK_IN_SPARE_AREA, 1) | ++ FIELD_PREP(WR_RD_BSY_GAP_MASK, 2) | ++ FIELD_PREP(WIDE_FLASH, 0) | ++ FIELD_PREP(DEV0_CFG1_ECC_DISABLE, 1); + + if (!nandc->props->qpic_version2) +- nandc->regs->ecc_buf_cfg = cpu_to_le32(1 << ECC_CFG_ECC_DISABLE); ++ nandc->regs->ecc_buf_cfg = cpu_to_le32(ECC_CFG_ECC_DISABLE); + + /* configure CMD1 and VLD for ONFI param probing in QPIC v1 */ + if (!nandc->props->qpic_version2) { +diff --git a/include/linux/mtd/nand-qpic-common.h b/include/linux/mtd/nand-qpic-common.h +index 425994429387..e79c79775eb8 100644 +--- a/include/linux/mtd/nand-qpic-common.h ++++ b/include/linux/mtd/nand-qpic-common.h +@@ -70,35 +70,42 @@ + #define BS_CORRECTABLE_ERR_MSK 0x1f + + /* NAND_DEVn_CFG0 bits */ +-#define DISABLE_STATUS_AFTER_WRITE 4 ++#define DISABLE_STATUS_AFTER_WRITE BIT(4) + #define CW_PER_PAGE 6 ++#define CW_PER_PAGE_MASK GENMASK(8, 6) + #define UD_SIZE_BYTES 9 + #define UD_SIZE_BYTES_MASK GENMASK(18, 9) +-#define ECC_PARITY_SIZE_BYTES_RS 19 ++#define ECC_PARITY_SIZE_BYTES_RS GENMASK(22, 19) + #define SPARE_SIZE_BYTES 23 + #define SPARE_SIZE_BYTES_MASK GENMASK(26, 23) + #define NUM_ADDR_CYCLES 27 +-#define STATUS_BFR_READ 30 +-#define SET_RD_MODE_AFTER_STATUS 31 ++#define NUM_ADDR_CYCLES_MASK GENMASK(29, 27) ++#define STATUS_BFR_READ BIT(30) ++#define SET_RD_MODE_AFTER_STATUS BIT(31) + + /* NAND_DEVn_CFG0 bits */ +-#define DEV0_CFG1_ECC_DISABLE 0 +-#define WIDE_FLASH 1 ++#define DEV0_CFG1_ECC_DISABLE BIT(0) ++#define WIDE_FLASH BIT(1) + #define NAND_RECOVERY_CYCLES 2 +-#define CS_ACTIVE_BSY 5 ++#define NAND_RECOVERY_CYCLES_MASK GENMASK(4, 2) ++#define CS_ACTIVE_BSY BIT(5) + #define BAD_BLOCK_BYTE_NUM 6 +-#define BAD_BLOCK_IN_SPARE_AREA 16 ++#define BAD_BLOCK_BYTE_NUM_MASK GENMASK(15, 6) ++#define BAD_BLOCK_IN_SPARE_AREA BIT(16) + #define WR_RD_BSY_GAP 17 +-#define ENABLE_BCH_ECC 27 ++#define WR_RD_BSY_GAP_MASK GENMASK(22, 17) ++#define ENABLE_BCH_ECC BIT(27) + + /* NAND_DEV0_ECC_CFG bits */ +-#define ECC_CFG_ECC_DISABLE 0 +-#define ECC_SW_RESET 1 ++#define ECC_CFG_ECC_DISABLE BIT(0) ++#define ECC_SW_RESET BIT(1) + #define ECC_MODE 4 ++#define ECC_MODE_MASK GENMASK(5, 4) + #define ECC_PARITY_SIZE_BYTES_BCH 8 ++#define ECC_PARITY_SIZE_BYTES_BCH_MASK GENMASK(12, 8) + #define ECC_NUM_DATA_BYTES 16 + #define ECC_NUM_DATA_BYTES_MASK GENMASK(25, 16) +-#define ECC_FORCE_CLK_OPEN 30 ++#define ECC_FORCE_CLK_OPEN BIT(30) + + /* NAND_DEV_CMD1 bits */ + #define READ_ADDR 0 +-- +2.51.0 + + +From 7f26e2256fd3b07d0d72101cd313fbe8adc0b6c5 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Fri, 7 Feb 2025 20:42:38 +0100 +Subject: [PATCH 014/517] mtd: rawnand: qcom: fix broken config in + qcom_param_page_type_exec + +Fix broken config in qcom_param_page_type_exec caused by copy-paste error +from commit 0c08080fd71c ("mtd: rawnand: qcom: use FIELD_PREP and GENMASK") + +In qcom_param_page_type_exec the value needs to be set to +nandc->regs->cfg0 instead of host->cfg0. This wrong configuration caused +the Qcom NANDC driver to malfunction on any device that makes use of it +(IPQ806x, IPQ40xx, IPQ807x, IPQ60xx) with the following error: + +[ 0.885369] nand: device found, Manufacturer ID: 0x2c, Chip ID: 0xaa +[ 0.885909] nand: Micron NAND 256MiB 1,8V 8-bit +[ 0.892499] nand: 256 MiB, SLC, erase size: 128 KiB, page size: 2048, OOB size: 64 +[ 0.896823] nand: ECC (step, strength) = (512, 8) does not fit in OOB +[ 0.896836] qcom-nandc 79b0000.nand-controller: No valid ECC settings possible +[ 0.910996] bam-dma-engine 7984000.dma-controller: Cannot free busy channel +[ 0.918070] qcom-nandc: probe of 79b0000.nand-controller failed with error -28 + +Restore original configuration fix the problem and makes the driver work +again. + +Cc: stable@vger.kernel.org +Fixes: 0c08080fd71c ("mtd: rawnand: qcom: use FIELD_PREP and GENMASK") +Signed-off-by: Christian Marangi +--- + drivers/mtd/nand/raw/qcom_nandc.c | 24 ++++++++++++------------ + 1 file changed, 12 insertions(+), 12 deletions(-) + +diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c +index 086cb139adf1..c3b26fee55a8 100644 +--- a/drivers/mtd/nand/raw/qcom_nandc.c ++++ b/drivers/mtd/nand/raw/qcom_nandc.c +@@ -1886,18 +1886,18 @@ static int qcom_param_page_type_exec(struct nand_chip *chip, const struct nand_ + nandc->regs->addr0 = 0; + nandc->regs->addr1 = 0; + +- host->cfg0 = FIELD_PREP(CW_PER_PAGE_MASK, 0) | +- FIELD_PREP(UD_SIZE_BYTES_MASK, 512) | +- FIELD_PREP(NUM_ADDR_CYCLES_MASK, 5) | +- FIELD_PREP(SPARE_SIZE_BYTES_MASK, 0); +- +- host->cfg1 = FIELD_PREP(NAND_RECOVERY_CYCLES_MASK, 7) | +- FIELD_PREP(BAD_BLOCK_BYTE_NUM_MASK, 17) | +- FIELD_PREP(CS_ACTIVE_BSY, 0) | +- FIELD_PREP(BAD_BLOCK_IN_SPARE_AREA, 1) | +- FIELD_PREP(WR_RD_BSY_GAP_MASK, 2) | +- FIELD_PREP(WIDE_FLASH, 0) | +- FIELD_PREP(DEV0_CFG1_ECC_DISABLE, 1); ++ nandc->regs->cfg0 = FIELD_PREP(CW_PER_PAGE_MASK, 0) | ++ FIELD_PREP(UD_SIZE_BYTES_MASK, 512) | ++ FIELD_PREP(NUM_ADDR_CYCLES_MASK, 5) | ++ FIELD_PREP(SPARE_SIZE_BYTES_MASK, 0); ++ ++ nandc->regs->cfg1 = FIELD_PREP(NAND_RECOVERY_CYCLES_MASK, 7) | ++ FIELD_PREP(BAD_BLOCK_BYTE_NUM_MASK, 17) | ++ FIELD_PREP(CS_ACTIVE_BSY, 0) | ++ FIELD_PREP(BAD_BLOCK_IN_SPARE_AREA, 1) | ++ FIELD_PREP(WR_RD_BSY_GAP_MASK, 2) | ++ FIELD_PREP(WIDE_FLASH, 0) | ++ FIELD_PREP(DEV0_CFG1_ECC_DISABLE, 1); + + if (!nandc->props->qpic_version2) + nandc->regs->ecc_buf_cfg = cpu_to_le32(ECC_CFG_ECC_DISABLE); +-- +2.51.0 + + +From 49f737acfea2251c082d8669fe62fabb1f13f626 Mon Sep 17 00:00:00 2001 +From: Md Sadre Alam +Date: Mon, 6 Jan 2025 18:45:58 +0530 +Subject: [PATCH 015/517] mtd: rawnand: qcom: Fix build issue on x86 + architecture +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Fix a buffer overflow issue in qcom_clear_bam_transaction by using +struct_group to group related fields and avoid FORTIFY_SOURCE warnings. + +On x86 architecture, the following error occurs due to warnings being +treated as errors: + +In function ‘fortify_memset_chk’, + inlined from ‘qcom_clear_bam_transaction’ at +drivers/mtd/nand/qpic_common.c:88:2: +./include/linux/fortify-string.h:480:25: error: call to ‘__write_overflow_field’ +declared with attribute warning: detected write beyond size of field +(1st parameter); maybe use struct_group()? [-Werror=attribute-warning] + 480 | __write_overflow_field(p_size_field, size); + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + LD [M] drivers/mtd/nand/nandcore.o + CC [M] drivers/w1/masters/mxc_w1.o +cc1: all warnings being treated as errors + +This patch addresses the issue by grouping the related fields in +struct bam_transaction using struct_group and updating the memset call +accordingly. + +Fixes: 8c52932da5e6 ("mtd: rawnand: qcom: cleanup qcom_nandc driver") +Signed-off-by: Md Sadre Alam +Signed-off-by: Miquel Raynal +--- + drivers/mtd/nand/qpic_common.c | 2 +- + include/linux/mtd/nand-qpic-common.h | 19 +++++++++++-------- + 2 files changed, 12 insertions(+), 9 deletions(-) + +diff --git a/drivers/mtd/nand/qpic_common.c b/drivers/mtd/nand/qpic_common.c +index 8abbb960a7ce..e0ed25b5afea 100644 +--- a/drivers/mtd/nand/qpic_common.c ++++ b/drivers/mtd/nand/qpic_common.c +@@ -85,7 +85,7 @@ void qcom_clear_bam_transaction(struct qcom_nand_controller *nandc) + if (!nandc->props->supports_bam) + return; + +- memset(&bam_txn->bam_ce_pos, 0, sizeof(u32) * 8); ++ memset(&bam_txn->bam_positions, 0, sizeof(bam_txn->bam_positions)); + bam_txn->last_data_desc = NULL; + + sg_init_table(bam_txn->cmd_sgl, nandc->max_cwperpage * +diff --git a/include/linux/mtd/nand-qpic-common.h b/include/linux/mtd/nand-qpic-common.h +index e79c79775eb8..4d9b736ff8b7 100644 +--- a/include/linux/mtd/nand-qpic-common.h ++++ b/include/linux/mtd/nand-qpic-common.h +@@ -254,14 +254,17 @@ struct bam_transaction { + struct dma_async_tx_descriptor *last_data_desc; + struct dma_async_tx_descriptor *last_cmd_desc; + struct completion txn_done; +- u32 bam_ce_pos; +- u32 bam_ce_start; +- u32 cmd_sgl_pos; +- u32 cmd_sgl_start; +- u32 tx_sgl_pos; +- u32 tx_sgl_start; +- u32 rx_sgl_pos; +- u32 rx_sgl_start; ++ struct_group(bam_positions, ++ u32 bam_ce_pos; ++ u32 bam_ce_start; ++ u32 cmd_sgl_pos; ++ u32 cmd_sgl_start; ++ u32 tx_sgl_pos; ++ u32 tx_sgl_start; ++ u32 rx_sgl_pos; ++ u32 rx_sgl_start; ++ ++ ); + }; + + /* +-- +2.51.0 + + +From ab61cede0b93c3d9c961220f76bf9918611d2884 Mon Sep 17 00:00:00 2001 +From: Md Sadre Alam +Date: Mon, 24 Feb 2025 16:44:14 +0530 +Subject: [PATCH 016/517] spi: spi-qpic: add driver for QCOM SPI NAND flash + Interface + +This driver implements support for the SPI-NAND mode of QCOM NAND Flash +Interface as a SPI-MEM controller with pipelined ECC capability. + +Co-developed-by: Sricharan Ramabadhran +Signed-off-by: Sricharan Ramabadhran +Co-developed-by: Varadarajan Narayanan +Signed-off-by: Varadarajan Narayanan +Signed-off-by: Md Sadre Alam +Link: https://patch.msgid.link/20250224111414.2809669-3-quic_mdalam@quicinc.com +Signed-off-by: Mark Brown +--- + drivers/mtd/nand/Makefile | 4 + + drivers/spi/Kconfig | 9 + + drivers/spi/Makefile | 1 + + drivers/spi/spi-qpic-snand.c | 1631 ++++++++++++++++++++++++++ + include/linux/mtd/nand-qpic-common.h | 7 + + 5 files changed, 1652 insertions(+) + create mode 100644 drivers/spi/spi-qpic-snand.c + +diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile +index da1586a36574..db516a45f0c5 100644 +--- a/drivers/mtd/nand/Makefile ++++ b/drivers/mtd/nand/Makefile +@@ -3,7 +3,11 @@ + nandcore-objs := core.o bbt.o + obj-$(CONFIG_MTD_NAND_CORE) += nandcore.o + obj-$(CONFIG_MTD_NAND_ECC_MEDIATEK) += ecc-mtk.o ++ifeq ($(CONFIG_SPI_QPIC_SNAND),y) ++obj-$(CONFIG_SPI_QPIC_SNAND) += qpic_common.o ++else + obj-$(CONFIG_MTD_NAND_QCOM) += qpic_common.o ++endif + obj-y += onenand/ + obj-y += raw/ + obj-y += spi/ +diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig +index 823797217404..98c5fa460fb1 100644 +--- a/drivers/spi/Kconfig ++++ b/drivers/spi/Kconfig +@@ -898,6 +898,15 @@ config SPI_QCOM_QSPI + help + QSPI(Quad SPI) driver for Qualcomm QSPI controller. + ++config SPI_QPIC_SNAND ++ bool "QPIC SNAND controller" ++ depends on ARCH_QCOM || COMPILE_TEST ++ select MTD ++ help ++ QPIC_SNAND (QPIC SPI NAND) driver for Qualcomm QPIC controller. ++ QPIC controller supports both parallel nand and serial nand. ++ This config will enable serial nand driver for QPIC controller. ++ + config SPI_QUP + tristate "Qualcomm SPI controller with QUP interface" + depends on ARCH_QCOM || COMPILE_TEST +diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile +index a9b1bc259b68..d9d674eb84a6 100644 +--- a/drivers/spi/Makefile ++++ b/drivers/spi/Makefile +@@ -114,6 +114,7 @@ obj-$(CONFIG_SPI_PXA2XX) += spi-pxa2xx-platform.o + obj-$(CONFIG_SPI_PXA2XX_PCI) += spi-pxa2xx-pci.o + obj-$(CONFIG_SPI_QCOM_GENI) += spi-geni-qcom.o + obj-$(CONFIG_SPI_QCOM_QSPI) += spi-qcom-qspi.o ++obj-$(CONFIG_SPI_QPIC_SNAND) += spi-qpic-snand.o + obj-$(CONFIG_SPI_QUP) += spi-qup.o + obj-$(CONFIG_SPI_ROCKCHIP) += spi-rockchip.o + obj-$(CONFIG_SPI_ROCKCHIP_SFC) += spi-rockchip-sfc.o +diff --git a/drivers/spi/spi-qpic-snand.c b/drivers/spi/spi-qpic-snand.c +new file mode 100644 +index 000000000000..1a4746d0fd62 +--- /dev/null ++++ b/drivers/spi/spi-qpic-snand.c +@@ -0,0 +1,1631 @@ ++/* ++ * SPDX-License-Identifier: GPL-2.0 ++ * ++ * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. ++ * ++ * Authors: ++ * Md Sadre Alam ++ * Sricharan R ++ * Varadarajan Narayanan ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define NAND_FLASH_SPI_CFG 0xc0 ++#define NAND_NUM_ADDR_CYCLES 0xc4 ++#define NAND_BUSY_CHECK_WAIT_CNT 0xc8 ++#define NAND_FLASH_FEATURES 0xf64 ++ ++/* QSPI NAND config reg bits */ ++#define LOAD_CLK_CNTR_INIT_EN BIT(28) ++#define CLK_CNTR_INIT_VAL_VEC 0x924 ++#define CLK_CNTR_INIT_VAL_VEC_MASK GENMASK(27, 16) ++#define FEA_STATUS_DEV_ADDR 0xc0 ++#define FEA_STATUS_DEV_ADDR_MASK GENMASK(15, 8) ++#define SPI_CFG BIT(0) ++#define SPI_NUM_ADDR 0xDA4DB ++#define SPI_WAIT_CNT 0x10 ++#define QPIC_QSPI_NUM_CS 1 ++#define SPI_TRANSFER_MODE_x1 BIT(29) ++#define SPI_TRANSFER_MODE_x4 (3 << 29) ++#define SPI_WP BIT(28) ++#define SPI_HOLD BIT(27) ++#define QPIC_SET_FEATURE BIT(31) ++ ++#define SPINAND_RESET 0xff ++#define SPINAND_READID 0x9f ++#define SPINAND_GET_FEATURE 0x0f ++#define SPINAND_SET_FEATURE 0x1f ++#define SPINAND_READ 0x13 ++#define SPINAND_ERASE 0xd8 ++#define SPINAND_WRITE_EN 0x06 ++#define SPINAND_PROGRAM_EXECUTE 0x10 ++#define SPINAND_PROGRAM_LOAD 0x84 ++ ++#define ACC_FEATURE 0xe ++#define BAD_BLOCK_MARKER_SIZE 0x2 ++#define OOB_BUF_SIZE 128 ++#define ecceng_to_qspi(eng) container_of(eng, struct qpic_spi_nand, ecc_eng) ++ ++struct qpic_snand_op { ++ u32 cmd_reg; ++ u32 addr1_reg; ++ u32 addr2_reg; ++}; ++ ++struct snandc_read_status { ++ __le32 snandc_flash; ++ __le32 snandc_buffer; ++ __le32 snandc_erased_cw; ++}; ++ ++/* ++ * ECC state struct ++ * @corrected: ECC corrected ++ * @bitflips: Max bit flip ++ * @failed: ECC failed ++ */ ++struct qcom_ecc_stats { ++ u32 corrected; ++ u32 bitflips; ++ u32 failed; ++}; ++ ++struct qpic_ecc { ++ struct device *dev; ++ int ecc_bytes_hw; ++ int spare_bytes; ++ int bbm_size; ++ int ecc_mode; ++ int bytes; ++ int steps; ++ int step_size; ++ int strength; ++ int cw_size; ++ int cw_data; ++ u32 cfg0; ++ u32 cfg1; ++ u32 cfg0_raw; ++ u32 cfg1_raw; ++ u32 ecc_buf_cfg; ++ u32 ecc_bch_cfg; ++ u32 clrflashstatus; ++ u32 clrreadstatus; ++ bool bch_enabled; ++}; ++ ++struct qpic_spi_nand { ++ struct qcom_nand_controller *snandc; ++ struct spi_controller *ctlr; ++ struct mtd_info *mtd; ++ struct clk *iomacro_clk; ++ struct qpic_ecc *ecc; ++ struct qcom_ecc_stats ecc_stats; ++ struct nand_ecc_engine ecc_eng; ++ u8 *data_buf; ++ u8 *oob_buf; ++ u32 wlen; ++ __le32 addr1; ++ __le32 addr2; ++ __le32 cmd; ++ u32 num_cw; ++ bool oob_rw; ++ bool page_rw; ++ bool raw_rw; ++}; ++ ++static void qcom_spi_set_read_loc_first(struct qcom_nand_controller *snandc, ++ int reg, int cw_offset, int read_size, ++ int is_last_read_loc) ++{ ++ __le32 locreg_val; ++ u32 val = (((cw_offset) << READ_LOCATION_OFFSET) | ++ ((read_size) << READ_LOCATION_SIZE) | ((is_last_read_loc) ++ << READ_LOCATION_LAST)); ++ ++ locreg_val = cpu_to_le32(val); ++ ++ if (reg == NAND_READ_LOCATION_0) ++ snandc->regs->read_location0 = locreg_val; ++ else if (reg == NAND_READ_LOCATION_1) ++ snandc->regs->read_location1 = locreg_val; ++ else if (reg == NAND_READ_LOCATION_2) ++ snandc->regs->read_location1 = locreg_val; ++ else if (reg == NAND_READ_LOCATION_3) ++ snandc->regs->read_location3 = locreg_val; ++} ++ ++static void qcom_spi_set_read_loc_last(struct qcom_nand_controller *snandc, ++ int reg, int cw_offset, int read_size, ++ int is_last_read_loc) ++{ ++ __le32 locreg_val; ++ u32 val = (((cw_offset) << READ_LOCATION_OFFSET) | ++ ((read_size) << READ_LOCATION_SIZE) | ((is_last_read_loc) ++ << READ_LOCATION_LAST)); ++ ++ locreg_val = cpu_to_le32(val); ++ ++ if (reg == NAND_READ_LOCATION_LAST_CW_0) ++ snandc->regs->read_location_last0 = locreg_val; ++ else if (reg == NAND_READ_LOCATION_LAST_CW_1) ++ snandc->regs->read_location_last1 = locreg_val; ++ else if (reg == NAND_READ_LOCATION_LAST_CW_2) ++ snandc->regs->read_location_last2 = locreg_val; ++ else if (reg == NAND_READ_LOCATION_LAST_CW_3) ++ snandc->regs->read_location_last3 = locreg_val; ++} ++ ++static struct qcom_nand_controller *nand_to_qcom_snand(struct nand_device *nand) ++{ ++ struct nand_ecc_engine *eng = nand->ecc.engine; ++ struct qpic_spi_nand *qspi = ecceng_to_qspi(eng); ++ ++ return qspi->snandc; ++} ++ ++static int qcom_spi_init(struct qcom_nand_controller *snandc) ++{ ++ u32 snand_cfg_val = 0x0; ++ int ret; ++ ++ snand_cfg_val = FIELD_PREP(CLK_CNTR_INIT_VAL_VEC_MASK, CLK_CNTR_INIT_VAL_VEC) | ++ FIELD_PREP(LOAD_CLK_CNTR_INIT_EN, 0) | ++ FIELD_PREP(FEA_STATUS_DEV_ADDR_MASK, FEA_STATUS_DEV_ADDR) | ++ FIELD_PREP(SPI_CFG, 0); ++ ++ snandc->regs->spi_cfg = cpu_to_le32(snand_cfg_val); ++ snandc->regs->num_addr_cycle = cpu_to_le32(SPI_NUM_ADDR); ++ snandc->regs->busy_wait_cnt = cpu_to_le32(SPI_WAIT_CNT); ++ ++ qcom_write_reg_dma(snandc, &snandc->regs->spi_cfg, NAND_FLASH_SPI_CFG, 1, 0); ++ ++ snand_cfg_val &= ~LOAD_CLK_CNTR_INIT_EN; ++ snandc->regs->spi_cfg = cpu_to_le32(snand_cfg_val); ++ ++ qcom_write_reg_dma(snandc, &snandc->regs->spi_cfg, NAND_FLASH_SPI_CFG, 1, 0); ++ ++ qcom_write_reg_dma(snandc, &snandc->regs->num_addr_cycle, NAND_NUM_ADDR_CYCLES, 1, 0); ++ qcom_write_reg_dma(snandc, &snandc->regs->busy_wait_cnt, NAND_BUSY_CHECK_WAIT_CNT, 1, ++ NAND_BAM_NEXT_SGL); ++ ++ ret = qcom_submit_descs(snandc); ++ if (ret) { ++ dev_err(snandc->dev, "failure in submitting spi init descriptor\n"); ++ return ret; ++ } ++ ++ return ret; ++} ++ ++static int qcom_spi_ooblayout_ecc(struct mtd_info *mtd, int section, ++ struct mtd_oob_region *oobregion) ++{ ++ struct nand_device *nand = mtd_to_nanddev(mtd); ++ struct qcom_nand_controller *snandc = nand_to_qcom_snand(nand); ++ struct qpic_ecc *qecc = snandc->qspi->ecc; ++ ++ if (section > 1) ++ return -ERANGE; ++ ++ oobregion->length = qecc->ecc_bytes_hw + qecc->spare_bytes; ++ oobregion->offset = mtd->oobsize - oobregion->length; ++ ++ return 0; ++} ++ ++static int qcom_spi_ooblayout_free(struct mtd_info *mtd, int section, ++ struct mtd_oob_region *oobregion) ++{ ++ struct nand_device *nand = mtd_to_nanddev(mtd); ++ struct qcom_nand_controller *snandc = nand_to_qcom_snand(nand); ++ struct qpic_ecc *qecc = snandc->qspi->ecc; ++ ++ if (section) ++ return -ERANGE; ++ ++ oobregion->length = qecc->steps * 4; ++ oobregion->offset = ((qecc->steps - 1) * qecc->bytes) + qecc->bbm_size; ++ ++ return 0; ++} ++ ++static const struct mtd_ooblayout_ops qcom_spi_ooblayout = { ++ .ecc = qcom_spi_ooblayout_ecc, ++ .free = qcom_spi_ooblayout_free, ++}; ++ ++static int qcom_spi_ecc_init_ctx_pipelined(struct nand_device *nand) ++{ ++ struct qcom_nand_controller *snandc = nand_to_qcom_snand(nand); ++ struct nand_ecc_props *conf = &nand->ecc.ctx.conf; ++ struct mtd_info *mtd = nanddev_to_mtd(nand); ++ int cwperpage, bad_block_byte; ++ struct qpic_ecc *ecc_cfg; ++ ++ cwperpage = mtd->writesize / NANDC_STEP_SIZE; ++ snandc->qspi->num_cw = cwperpage; ++ ++ ecc_cfg = kzalloc(sizeof(*ecc_cfg), GFP_KERNEL); ++ if (!ecc_cfg) ++ return -ENOMEM; ++ snandc->qspi->oob_buf = kzalloc(mtd->writesize + mtd->oobsize, ++ GFP_KERNEL); ++ if (!snandc->qspi->oob_buf) ++ return -ENOMEM; ++ ++ memset(snandc->qspi->oob_buf, 0xff, mtd->writesize + mtd->oobsize); ++ ++ nand->ecc.ctx.priv = ecc_cfg; ++ snandc->qspi->mtd = mtd; ++ ++ ecc_cfg->ecc_bytes_hw = 7; ++ ecc_cfg->spare_bytes = 4; ++ ecc_cfg->bbm_size = 1; ++ ecc_cfg->bch_enabled = true; ++ ecc_cfg->bytes = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes + ecc_cfg->bbm_size; ++ ++ ecc_cfg->steps = 4; ++ ecc_cfg->strength = 4; ++ ecc_cfg->step_size = 512; ++ ecc_cfg->cw_data = 516; ++ ecc_cfg->cw_size = ecc_cfg->cw_data + ecc_cfg->bytes; ++ bad_block_byte = mtd->writesize - ecc_cfg->cw_size * (cwperpage - 1) + 1; ++ ++ mtd_set_ooblayout(mtd, &qcom_spi_ooblayout); ++ ++ ecc_cfg->cfg0 = FIELD_PREP(CW_PER_PAGE_MASK, (cwperpage - 1)) | ++ FIELD_PREP(UD_SIZE_BYTES_MASK, ecc_cfg->cw_data) | ++ FIELD_PREP(DISABLE_STATUS_AFTER_WRITE, 1) | ++ FIELD_PREP(NUM_ADDR_CYCLES_MASK, 3) | ++ FIELD_PREP(ECC_PARITY_SIZE_BYTES_RS, ecc_cfg->ecc_bytes_hw) | ++ FIELD_PREP(STATUS_BFR_READ, 0) | ++ FIELD_PREP(SET_RD_MODE_AFTER_STATUS, 1) | ++ FIELD_PREP(SPARE_SIZE_BYTES_MASK, ecc_cfg->spare_bytes); ++ ++ ecc_cfg->cfg1 = FIELD_PREP(NAND_RECOVERY_CYCLES_MASK, 0) | ++ FIELD_PREP(CS_ACTIVE_BSY, 0) | ++ FIELD_PREP(BAD_BLOCK_BYTE_NUM_MASK, bad_block_byte) | ++ FIELD_PREP(BAD_BLOCK_IN_SPARE_AREA, 0) | ++ FIELD_PREP(WR_RD_BSY_GAP_MASK, 20) | ++ FIELD_PREP(WIDE_FLASH, 0) | ++ FIELD_PREP(ENABLE_BCH_ECC, ecc_cfg->bch_enabled); ++ ++ ecc_cfg->cfg0_raw = FIELD_PREP(CW_PER_PAGE_MASK, (cwperpage - 1)) | ++ FIELD_PREP(NUM_ADDR_CYCLES_MASK, 3) | ++ FIELD_PREP(UD_SIZE_BYTES_MASK, ecc_cfg->cw_size) | ++ FIELD_PREP(SPARE_SIZE_BYTES_MASK, 0); ++ ++ ecc_cfg->cfg1_raw = FIELD_PREP(NAND_RECOVERY_CYCLES_MASK, 0) | ++ FIELD_PREP(CS_ACTIVE_BSY, 0) | ++ FIELD_PREP(BAD_BLOCK_BYTE_NUM_MASK, 17) | ++ FIELD_PREP(BAD_BLOCK_IN_SPARE_AREA, 1) | ++ FIELD_PREP(WR_RD_BSY_GAP_MASK, 20) | ++ FIELD_PREP(WIDE_FLASH, 0) | ++ FIELD_PREP(DEV0_CFG1_ECC_DISABLE, 1); ++ ++ ecc_cfg->ecc_bch_cfg = FIELD_PREP(ECC_CFG_ECC_DISABLE, !ecc_cfg->bch_enabled) | ++ FIELD_PREP(ECC_SW_RESET, 0) | ++ FIELD_PREP(ECC_NUM_DATA_BYTES_MASK, ecc_cfg->cw_data) | ++ FIELD_PREP(ECC_FORCE_CLK_OPEN, 1) | ++ FIELD_PREP(ECC_MODE_MASK, 0) | ++ FIELD_PREP(ECC_PARITY_SIZE_BYTES_BCH_MASK, ecc_cfg->ecc_bytes_hw); ++ ++ ecc_cfg->ecc_buf_cfg = 0x203 << NUM_STEPS; ++ ecc_cfg->clrflashstatus = FS_READY_BSY_N; ++ ecc_cfg->clrreadstatus = 0xc0; ++ ++ conf->step_size = ecc_cfg->step_size; ++ conf->strength = ecc_cfg->strength; ++ ++ snandc->regs->erased_cw_detect_cfg_clr = cpu_to_le32(CLR_ERASED_PAGE_DET); ++ snandc->regs->erased_cw_detect_cfg_set = cpu_to_le32(SET_ERASED_PAGE_DET); ++ ++ dev_dbg(snandc->dev, "ECC strength: %u bits per %u bytes\n", ++ ecc_cfg->strength, ecc_cfg->step_size); ++ ++ return 0; ++} ++ ++static void qcom_spi_ecc_cleanup_ctx_pipelined(struct nand_device *nand) ++{ ++ struct qpic_ecc *ecc_cfg = nand_to_ecc_ctx(nand); ++ ++ kfree(ecc_cfg); ++} ++ ++static int qcom_spi_ecc_prepare_io_req_pipelined(struct nand_device *nand, ++ struct nand_page_io_req *req) ++{ ++ struct qcom_nand_controller *snandc = nand_to_qcom_snand(nand); ++ struct qpic_ecc *ecc_cfg = nand_to_ecc_ctx(nand); ++ ++ snandc->qspi->ecc = ecc_cfg; ++ snandc->qspi->raw_rw = false; ++ snandc->qspi->oob_rw = false; ++ snandc->qspi->page_rw = false; ++ ++ if (req->datalen) ++ snandc->qspi->page_rw = true; ++ ++ if (req->ooblen) ++ snandc->qspi->oob_rw = true; ++ ++ if (req->mode == MTD_OPS_RAW) ++ snandc->qspi->raw_rw = true; ++ ++ return 0; ++} ++ ++static int qcom_spi_ecc_finish_io_req_pipelined(struct nand_device *nand, ++ struct nand_page_io_req *req) ++{ ++ struct qcom_nand_controller *snandc = nand_to_qcom_snand(nand); ++ struct mtd_info *mtd = nanddev_to_mtd(nand); ++ ++ if (req->mode == MTD_OPS_RAW || req->type != NAND_PAGE_READ) ++ return 0; ++ ++ if (snandc->qspi->ecc_stats.failed) ++ mtd->ecc_stats.failed += snandc->qspi->ecc_stats.failed; ++ else ++ mtd->ecc_stats.corrected += snandc->qspi->ecc_stats.corrected; ++ ++ if (snandc->qspi->ecc_stats.failed) ++ return -EBADMSG; ++ else ++ return snandc->qspi->ecc_stats.bitflips; ++} ++ ++static struct nand_ecc_engine_ops qcom_spi_ecc_engine_ops_pipelined = { ++ .init_ctx = qcom_spi_ecc_init_ctx_pipelined, ++ .cleanup_ctx = qcom_spi_ecc_cleanup_ctx_pipelined, ++ .prepare_io_req = qcom_spi_ecc_prepare_io_req_pipelined, ++ .finish_io_req = qcom_spi_ecc_finish_io_req_pipelined, ++}; ++ ++/* helper to configure location register values */ ++static void qcom_spi_set_read_loc(struct qcom_nand_controller *snandc, int cw, int reg, ++ int cw_offset, int read_size, int is_last_read_loc) ++{ ++ int reg_base = NAND_READ_LOCATION_0; ++ int num_cw = snandc->qspi->num_cw; ++ ++ if (cw == (num_cw - 1)) ++ reg_base = NAND_READ_LOCATION_LAST_CW_0; ++ ++ reg_base += reg * 4; ++ ++ if (cw == (num_cw - 1)) ++ return qcom_spi_set_read_loc_last(snandc, reg_base, cw_offset, ++ read_size, is_last_read_loc); ++ else ++ return qcom_spi_set_read_loc_first(snandc, reg_base, cw_offset, ++ read_size, is_last_read_loc); ++} ++ ++static void ++qcom_spi_config_cw_read(struct qcom_nand_controller *snandc, bool use_ecc, int cw) ++{ ++ __le32 *reg = &snandc->regs->read_location0; ++ int num_cw = snandc->qspi->num_cw; ++ ++ qcom_write_reg_dma(snandc, reg, NAND_READ_LOCATION_0, 4, NAND_BAM_NEXT_SGL); ++ if (cw == (num_cw - 1)) { ++ reg = &snandc->regs->read_location_last0; ++ qcom_write_reg_dma(snandc, reg, NAND_READ_LOCATION_LAST_CW_0, 4, ++ NAND_BAM_NEXT_SGL); ++ } ++ ++ qcom_write_reg_dma(snandc, &snandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL); ++ qcom_write_reg_dma(snandc, &snandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); ++ ++ qcom_read_reg_dma(snandc, NAND_FLASH_STATUS, 2, 0); ++ qcom_read_reg_dma(snandc, NAND_ERASED_CW_DETECT_STATUS, 1, ++ NAND_BAM_NEXT_SGL); ++} ++ ++static int qcom_spi_block_erase(struct qcom_nand_controller *snandc) ++{ ++ struct qpic_ecc *ecc_cfg = snandc->qspi->ecc; ++ int ret; ++ ++ snandc->buf_count = 0; ++ snandc->buf_start = 0; ++ qcom_clear_read_regs(snandc); ++ qcom_clear_bam_transaction(snandc); ++ ++ snandc->regs->cmd = snandc->qspi->cmd; ++ snandc->regs->addr0 = snandc->qspi->addr1; ++ snandc->regs->addr1 = snandc->qspi->addr2; ++ snandc->regs->cfg0 = cpu_to_le32(ecc_cfg->cfg0_raw & ~(7 << CW_PER_PAGE)); ++ snandc->regs->cfg1 = cpu_to_le32(ecc_cfg->cfg1_raw); ++ snandc->regs->exec = cpu_to_le32(1); ++ ++ qcom_write_reg_dma(snandc, &snandc->regs->cmd, NAND_FLASH_CMD, 3, NAND_BAM_NEXT_SGL); ++ qcom_write_reg_dma(snandc, &snandc->regs->cfg0, NAND_DEV0_CFG0, 2, NAND_BAM_NEXT_SGL); ++ qcom_write_reg_dma(snandc, &snandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); ++ ++ ret = qcom_submit_descs(snandc); ++ if (ret) { ++ dev_err(snandc->dev, "failure to erase block\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static void qcom_spi_config_single_cw_page_read(struct qcom_nand_controller *snandc, ++ bool use_ecc, int cw) ++{ ++ __le32 *reg = &snandc->regs->read_location0; ++ int num_cw = snandc->qspi->num_cw; ++ ++ qcom_write_reg_dma(snandc, &snandc->regs->addr0, NAND_ADDR0, 2, 0); ++ qcom_write_reg_dma(snandc, &snandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0); ++ qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_clr, ++ NAND_ERASED_CW_DETECT_CFG, 1, 0); ++ qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_set, ++ NAND_ERASED_CW_DETECT_CFG, 1, ++ NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL); ++ ++ if (cw == (num_cw - 1)) { ++ reg = &snandc->regs->read_location_last0; ++ qcom_write_reg_dma(snandc, reg, NAND_READ_LOCATION_LAST_CW_0, 4, NAND_BAM_NEXT_SGL); ++ } ++ qcom_write_reg_dma(snandc, &snandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL); ++ qcom_write_reg_dma(snandc, &snandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); ++ ++ qcom_read_reg_dma(snandc, NAND_FLASH_STATUS, 1, 0); ++} ++ ++static int qcom_spi_read_last_cw(struct qcom_nand_controller *snandc, ++ const struct spi_mem_op *op) ++{ ++ struct qpic_ecc *ecc_cfg = snandc->qspi->ecc; ++ struct mtd_info *mtd = snandc->qspi->mtd; ++ int size, ret = 0; ++ int col, bbpos; ++ u32 cfg0, cfg1, ecc_bch_cfg; ++ u32 num_cw = snandc->qspi->num_cw; ++ ++ qcom_clear_bam_transaction(snandc); ++ qcom_clear_read_regs(snandc); ++ ++ size = ecc_cfg->cw_size; ++ col = ecc_cfg->cw_size * (num_cw - 1); ++ ++ memset(snandc->data_buffer, 0xff, size); ++ snandc->regs->addr0 = (snandc->qspi->addr1 | cpu_to_le32(col)); ++ snandc->regs->addr1 = snandc->qspi->addr2; ++ ++ cfg0 = (ecc_cfg->cfg0_raw & ~(7U << CW_PER_PAGE)) | ++ 0 << CW_PER_PAGE; ++ cfg1 = ecc_cfg->cfg1_raw; ++ ecc_bch_cfg = 1 << ECC_CFG_ECC_DISABLE; ++ ++ snandc->regs->cmd = snandc->qspi->cmd; ++ snandc->regs->cfg0 = cpu_to_le32(cfg0); ++ snandc->regs->cfg1 = cpu_to_le32(cfg1); ++ snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg); ++ snandc->regs->clrflashstatus = cpu_to_le32(ecc_cfg->clrflashstatus); ++ snandc->regs->clrreadstatus = cpu_to_le32(ecc_cfg->clrreadstatus); ++ snandc->regs->exec = cpu_to_le32(1); ++ ++ qcom_spi_set_read_loc(snandc, num_cw - 1, 0, 0, ecc_cfg->cw_size, 1); ++ ++ qcom_spi_config_single_cw_page_read(snandc, false, num_cw - 1); ++ ++ qcom_read_data_dma(snandc, FLASH_BUF_ACC, snandc->data_buffer, size, 0); ++ ++ ret = qcom_submit_descs(snandc); ++ if (ret) { ++ dev_err(snandc->dev, "failed to read last cw\n"); ++ return ret; ++ } ++ ++ qcom_nandc_dev_to_mem(snandc, true); ++ u32 flash = le32_to_cpu(snandc->reg_read_buf[0]); ++ ++ if (flash & (FS_OP_ERR | FS_MPU_ERR)) ++ return -EIO; ++ ++ bbpos = mtd->writesize - ecc_cfg->cw_size * (num_cw - 1); ++ ++ if (snandc->data_buffer[bbpos] == 0xff) ++ snandc->data_buffer[bbpos + 1] = 0xff; ++ if (snandc->data_buffer[bbpos] != 0xff) ++ snandc->data_buffer[bbpos + 1] = snandc->data_buffer[bbpos]; ++ ++ memcpy(op->data.buf.in, snandc->data_buffer + bbpos, op->data.nbytes); ++ ++ return ret; ++} ++ ++static int qcom_spi_check_error(struct qcom_nand_controller *snandc, u8 *data_buf, u8 *oob_buf) ++{ ++ struct snandc_read_status *buf; ++ struct qpic_ecc *ecc_cfg = snandc->qspi->ecc; ++ int i, num_cw = snandc->qspi->num_cw; ++ bool flash_op_err = false, erased; ++ unsigned int max_bitflips = 0; ++ unsigned int uncorrectable_cws = 0; ++ ++ snandc->qspi->ecc_stats.failed = 0; ++ snandc->qspi->ecc_stats.corrected = 0; ++ ++ qcom_nandc_dev_to_mem(snandc, true); ++ buf = (struct snandc_read_status *)snandc->reg_read_buf; ++ ++ for (i = 0; i < num_cw; i++, buf++) { ++ u32 flash, buffer, erased_cw; ++ int data_len, oob_len; ++ ++ if (i == (num_cw - 1)) { ++ data_len = NANDC_STEP_SIZE - ((num_cw - 1) << 2); ++ oob_len = num_cw << 2; ++ } else { ++ data_len = ecc_cfg->cw_data; ++ oob_len = 0; ++ } ++ ++ flash = le32_to_cpu(buf->snandc_flash); ++ buffer = le32_to_cpu(buf->snandc_buffer); ++ erased_cw = le32_to_cpu(buf->snandc_erased_cw); ++ ++ if ((flash & FS_OP_ERR) && (buffer & BS_UNCORRECTABLE_BIT)) { ++ if (ecc_cfg->bch_enabled) ++ erased = (erased_cw & ERASED_CW) == ERASED_CW; ++ else ++ erased = false; ++ ++ if (!erased) ++ uncorrectable_cws |= BIT(i); ++ ++ } else if (flash & (FS_OP_ERR | FS_MPU_ERR)) { ++ flash_op_err = true; ++ } else { ++ unsigned int stat; ++ ++ stat = buffer & BS_CORRECTABLE_ERR_MSK; ++ snandc->qspi->ecc_stats.corrected += stat; ++ max_bitflips = max(max_bitflips, stat); ++ } ++ ++ if (data_buf) ++ data_buf += data_len; ++ if (oob_buf) ++ oob_buf += oob_len + ecc_cfg->bytes; ++ } ++ ++ if (flash_op_err) ++ return -EIO; ++ ++ if (!uncorrectable_cws) ++ snandc->qspi->ecc_stats.bitflips = max_bitflips; ++ else ++ snandc->qspi->ecc_stats.failed++; ++ ++ return 0; ++} ++ ++static int qcom_spi_check_raw_flash_errors(struct qcom_nand_controller *snandc, int cw_cnt) ++{ ++ int i; ++ ++ qcom_nandc_dev_to_mem(snandc, true); ++ ++ for (i = 0; i < cw_cnt; i++) { ++ u32 flash = le32_to_cpu(snandc->reg_read_buf[i]); ++ ++ if (flash & (FS_OP_ERR | FS_MPU_ERR)) ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++static int qcom_spi_read_cw_raw(struct qcom_nand_controller *snandc, u8 *data_buf, ++ u8 *oob_buf, int cw) ++{ ++ struct qpic_ecc *ecc_cfg = snandc->qspi->ecc; ++ struct mtd_info *mtd = snandc->qspi->mtd; ++ int data_size1, data_size2, oob_size1, oob_size2; ++ int ret, reg_off = FLASH_BUF_ACC, read_loc = 0; ++ int raw_cw = cw; ++ u32 cfg0, cfg1, ecc_bch_cfg, num_cw = snandc->qspi->num_cw; ++ int col; ++ ++ snandc->buf_count = 0; ++ snandc->buf_start = 0; ++ qcom_clear_read_regs(snandc); ++ qcom_clear_bam_transaction(snandc); ++ raw_cw = num_cw - 1; ++ ++ cfg0 = (ecc_cfg->cfg0_raw & ~(7U << CW_PER_PAGE)) | ++ 0 << CW_PER_PAGE; ++ cfg1 = ecc_cfg->cfg1_raw; ++ ecc_bch_cfg = ECC_CFG_ECC_DISABLE; ++ ++ col = ecc_cfg->cw_size * cw; ++ ++ snandc->regs->addr0 = (snandc->qspi->addr1 | cpu_to_le32(col)); ++ snandc->regs->addr1 = snandc->qspi->addr2; ++ snandc->regs->cmd = snandc->qspi->cmd; ++ snandc->regs->cfg0 = cpu_to_le32(cfg0); ++ snandc->regs->cfg1 = cpu_to_le32(cfg1); ++ snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg); ++ snandc->regs->clrflashstatus = cpu_to_le32(ecc_cfg->clrflashstatus); ++ snandc->regs->clrreadstatus = cpu_to_le32(ecc_cfg->clrreadstatus); ++ snandc->regs->exec = cpu_to_le32(1); ++ ++ qcom_spi_set_read_loc(snandc, raw_cw, 0, 0, ecc_cfg->cw_size, 1); ++ ++ qcom_write_reg_dma(snandc, &snandc->regs->addr0, NAND_ADDR0, 2, 0); ++ qcom_write_reg_dma(snandc, &snandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0); ++ qcom_write_reg_dma(snandc, &snandc->regs->ecc_buf_cfg, NAND_EBI2_ECC_BUF_CFG, 1, 0); ++ ++ qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_clr, ++ NAND_ERASED_CW_DETECT_CFG, 1, 0); ++ qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_set, ++ NAND_ERASED_CW_DETECT_CFG, 1, ++ NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL); ++ ++ data_size1 = mtd->writesize - ecc_cfg->cw_size * (num_cw - 1); ++ oob_size1 = ecc_cfg->bbm_size; ++ ++ if (cw == (num_cw - 1)) { ++ data_size2 = NANDC_STEP_SIZE - data_size1 - ++ ((num_cw - 1) * 4); ++ oob_size2 = (num_cw * 4) + ecc_cfg->ecc_bytes_hw + ++ ecc_cfg->spare_bytes; ++ } else { ++ data_size2 = ecc_cfg->cw_data - data_size1; ++ oob_size2 = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes; ++ } ++ ++ qcom_spi_set_read_loc(snandc, cw, 0, read_loc, data_size1, 0); ++ read_loc += data_size1; ++ ++ qcom_spi_set_read_loc(snandc, cw, 1, read_loc, oob_size1, 0); ++ read_loc += oob_size1; ++ ++ qcom_spi_set_read_loc(snandc, cw, 2, read_loc, data_size2, 0); ++ read_loc += data_size2; ++ ++ qcom_spi_set_read_loc(snandc, cw, 3, read_loc, oob_size2, 1); ++ ++ qcom_spi_config_cw_read(snandc, false, raw_cw); ++ ++ qcom_read_data_dma(snandc, reg_off, data_buf, data_size1, 0); ++ reg_off += data_size1; ++ ++ qcom_read_data_dma(snandc, reg_off, oob_buf, oob_size1, 0); ++ reg_off += oob_size1; ++ ++ qcom_read_data_dma(snandc, reg_off, data_buf + data_size1, data_size2, 0); ++ reg_off += data_size2; ++ ++ qcom_read_data_dma(snandc, reg_off, oob_buf + oob_size1, oob_size2, 0); ++ ++ ret = qcom_submit_descs(snandc); ++ if (ret) { ++ dev_err(snandc->dev, "failure to read raw cw %d\n", cw); ++ return ret; ++ } ++ ++ return qcom_spi_check_raw_flash_errors(snandc, 1); ++} ++ ++static int qcom_spi_read_page_raw(struct qcom_nand_controller *snandc, ++ const struct spi_mem_op *op) ++{ ++ struct qpic_ecc *ecc_cfg = snandc->qspi->ecc; ++ u8 *data_buf = NULL, *oob_buf = NULL; ++ int ret, cw; ++ u32 num_cw = snandc->qspi->num_cw; ++ ++ if (snandc->qspi->page_rw) ++ data_buf = op->data.buf.in; ++ ++ oob_buf = snandc->qspi->oob_buf; ++ memset(oob_buf, 0xff, OOB_BUF_SIZE); ++ ++ for (cw = 0; cw < num_cw; cw++) { ++ ret = qcom_spi_read_cw_raw(snandc, data_buf, oob_buf, cw); ++ if (ret) ++ return ret; ++ ++ if (data_buf) ++ data_buf += ecc_cfg->cw_data; ++ if (oob_buf) ++ oob_buf += ecc_cfg->bytes; ++ } ++ ++ return 0; ++} ++ ++static int qcom_spi_read_page_ecc(struct qcom_nand_controller *snandc, ++ const struct spi_mem_op *op) ++{ ++ struct qpic_ecc *ecc_cfg = snandc->qspi->ecc; ++ u8 *data_buf = NULL, *data_buf_start, *oob_buf = NULL, *oob_buf_start; ++ int ret, i; ++ u32 cfg0, cfg1, ecc_bch_cfg, num_cw = snandc->qspi->num_cw; ++ ++ data_buf = op->data.buf.in; ++ data_buf_start = data_buf; ++ ++ oob_buf = snandc->qspi->oob_buf; ++ oob_buf_start = oob_buf; ++ ++ snandc->buf_count = 0; ++ snandc->buf_start = 0; ++ qcom_clear_read_regs(snandc); ++ ++ cfg0 = (ecc_cfg->cfg0 & ~(7U << CW_PER_PAGE)) | ++ (num_cw - 1) << CW_PER_PAGE; ++ cfg1 = ecc_cfg->cfg1; ++ ecc_bch_cfg = ecc_cfg->ecc_bch_cfg; ++ ++ snandc->regs->addr0 = snandc->qspi->addr1; ++ snandc->regs->addr1 = snandc->qspi->addr2; ++ snandc->regs->cmd = snandc->qspi->cmd; ++ snandc->regs->cfg0 = cpu_to_le32(cfg0); ++ snandc->regs->cfg1 = cpu_to_le32(cfg1); ++ snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg); ++ snandc->regs->clrflashstatus = cpu_to_le32(ecc_cfg->clrflashstatus); ++ snandc->regs->clrreadstatus = cpu_to_le32(ecc_cfg->clrreadstatus); ++ snandc->regs->exec = cpu_to_le32(1); ++ ++ qcom_spi_set_read_loc(snandc, 0, 0, 0, ecc_cfg->cw_data, 1); ++ ++ qcom_clear_bam_transaction(snandc); ++ ++ qcom_write_reg_dma(snandc, &snandc->regs->addr0, NAND_ADDR0, 2, 0); ++ qcom_write_reg_dma(snandc, &snandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0); ++ qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_clr, ++ NAND_ERASED_CW_DETECT_CFG, 1, 0); ++ qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_set, ++ NAND_ERASED_CW_DETECT_CFG, 1, ++ NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL); ++ ++ for (i = 0; i < num_cw; i++) { ++ int data_size, oob_size; ++ ++ if (i == (num_cw - 1)) { ++ data_size = 512 - ((num_cw - 1) << 2); ++ oob_size = (num_cw << 2) + ecc_cfg->ecc_bytes_hw + ++ ecc_cfg->spare_bytes; ++ } else { ++ data_size = ecc_cfg->cw_data; ++ oob_size = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes; ++ } ++ ++ if (data_buf && oob_buf) { ++ qcom_spi_set_read_loc(snandc, i, 0, 0, data_size, 0); ++ qcom_spi_set_read_loc(snandc, i, 1, data_size, oob_size, 1); ++ } else if (data_buf) { ++ qcom_spi_set_read_loc(snandc, i, 0, 0, data_size, 1); ++ } else { ++ qcom_spi_set_read_loc(snandc, i, 0, data_size, oob_size, 1); ++ } ++ ++ qcom_spi_config_cw_read(snandc, true, i); ++ ++ if (data_buf) ++ qcom_read_data_dma(snandc, FLASH_BUF_ACC, data_buf, ++ data_size, 0); ++ if (oob_buf) { ++ int j; ++ ++ for (j = 0; j < ecc_cfg->bbm_size; j++) ++ *oob_buf++ = 0xff; ++ ++ qcom_read_data_dma(snandc, FLASH_BUF_ACC + data_size, ++ oob_buf, oob_size, 0); ++ } ++ ++ if (data_buf) ++ data_buf += data_size; ++ if (oob_buf) ++ oob_buf += oob_size; ++ } ++ ++ ret = qcom_submit_descs(snandc); ++ if (ret) { ++ dev_err(snandc->dev, "failure to read page\n"); ++ return ret; ++ } ++ ++ return qcom_spi_check_error(snandc, data_buf_start, oob_buf_start); ++} ++ ++static int qcom_spi_read_page_oob(struct qcom_nand_controller *snandc, ++ const struct spi_mem_op *op) ++{ ++ struct qpic_ecc *ecc_cfg = snandc->qspi->ecc; ++ u8 *data_buf = NULL, *data_buf_start, *oob_buf = NULL, *oob_buf_start; ++ int ret, i; ++ u32 cfg0, cfg1, ecc_bch_cfg, num_cw = snandc->qspi->num_cw; ++ ++ oob_buf = op->data.buf.in; ++ oob_buf_start = oob_buf; ++ ++ data_buf_start = data_buf; ++ ++ snandc->buf_count = 0; ++ snandc->buf_start = 0; ++ qcom_clear_read_regs(snandc); ++ qcom_clear_bam_transaction(snandc); ++ ++ cfg0 = (ecc_cfg->cfg0 & ~(7U << CW_PER_PAGE)) | ++ (num_cw - 1) << CW_PER_PAGE; ++ cfg1 = ecc_cfg->cfg1; ++ ecc_bch_cfg = ecc_cfg->ecc_bch_cfg; ++ ++ snandc->regs->addr0 = snandc->qspi->addr1; ++ snandc->regs->addr1 = snandc->qspi->addr2; ++ snandc->regs->cmd = snandc->qspi->cmd; ++ snandc->regs->cfg0 = cpu_to_le32(cfg0); ++ snandc->regs->cfg1 = cpu_to_le32(cfg1); ++ snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg); ++ snandc->regs->clrflashstatus = cpu_to_le32(ecc_cfg->clrflashstatus); ++ snandc->regs->clrreadstatus = cpu_to_le32(ecc_cfg->clrreadstatus); ++ snandc->regs->exec = cpu_to_le32(1); ++ ++ qcom_spi_set_read_loc(snandc, 0, 0, 0, ecc_cfg->cw_data, 1); ++ ++ qcom_write_reg_dma(snandc, &snandc->regs->addr0, NAND_ADDR0, 2, 0); ++ qcom_write_reg_dma(snandc, &snandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0); ++ qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_clr, ++ NAND_ERASED_CW_DETECT_CFG, 1, 0); ++ qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_set, ++ NAND_ERASED_CW_DETECT_CFG, 1, ++ NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL); ++ ++ for (i = 0; i < num_cw; i++) { ++ int data_size, oob_size; ++ ++ if (i == (num_cw - 1)) { ++ data_size = NANDC_STEP_SIZE - ((num_cw - 1) << 2); ++ oob_size = (num_cw << 2) + ecc_cfg->ecc_bytes_hw + ++ ecc_cfg->spare_bytes; ++ } else { ++ data_size = ecc_cfg->cw_data; ++ oob_size = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes; ++ } ++ ++ qcom_spi_set_read_loc(snandc, i, 0, data_size, oob_size, 1); ++ ++ qcom_spi_config_cw_read(snandc, true, i); ++ ++ if (oob_buf) { ++ int j; ++ ++ for (j = 0; j < ecc_cfg->bbm_size; j++) ++ *oob_buf++ = 0xff; ++ ++ qcom_read_data_dma(snandc, FLASH_BUF_ACC + data_size, ++ oob_buf, oob_size, 0); ++ } ++ ++ if (oob_buf) ++ oob_buf += oob_size; ++ } ++ ++ ret = qcom_submit_descs(snandc); ++ if (ret) { ++ dev_err(snandc->dev, "failure to read oob\n"); ++ return ret; ++ } ++ ++ return qcom_spi_check_error(snandc, data_buf_start, oob_buf_start); ++} ++ ++static int qcom_spi_read_page(struct qcom_nand_controller *snandc, ++ const struct spi_mem_op *op) ++{ ++ if (snandc->qspi->page_rw && snandc->qspi->raw_rw) ++ return qcom_spi_read_page_raw(snandc, op); ++ ++ if (snandc->qspi->page_rw) ++ return qcom_spi_read_page_ecc(snandc, op); ++ ++ if (snandc->qspi->oob_rw && snandc->qspi->raw_rw) ++ return qcom_spi_read_last_cw(snandc, op); ++ ++ if (snandc->qspi->oob_rw) ++ return qcom_spi_read_page_oob(snandc, op); ++ ++ return 0; ++} ++ ++static void qcom_spi_config_page_write(struct qcom_nand_controller *snandc) ++{ ++ qcom_write_reg_dma(snandc, &snandc->regs->addr0, NAND_ADDR0, 2, 0); ++ qcom_write_reg_dma(snandc, &snandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0); ++ qcom_write_reg_dma(snandc, &snandc->regs->ecc_buf_cfg, NAND_EBI2_ECC_BUF_CFG, ++ 1, NAND_BAM_NEXT_SGL); ++} ++ ++static void qcom_spi_config_cw_write(struct qcom_nand_controller *snandc) ++{ ++ qcom_write_reg_dma(snandc, &snandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL); ++ qcom_write_reg_dma(snandc, &snandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); ++ qcom_read_reg_dma(snandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL); ++ ++ qcom_write_reg_dma(snandc, &snandc->regs->clrflashstatus, NAND_FLASH_STATUS, 1, 0); ++ qcom_write_reg_dma(snandc, &snandc->regs->clrreadstatus, NAND_READ_STATUS, 1, ++ NAND_BAM_NEXT_SGL); ++} ++ ++static int qcom_spi_program_raw(struct qcom_nand_controller *snandc, ++ const struct spi_mem_op *op) ++{ ++ struct qpic_ecc *ecc_cfg = snandc->qspi->ecc; ++ struct mtd_info *mtd = snandc->qspi->mtd; ++ u8 *data_buf = NULL, *oob_buf = NULL; ++ int i, ret; ++ int num_cw = snandc->qspi->num_cw; ++ u32 cfg0, cfg1, ecc_bch_cfg; ++ ++ cfg0 = (ecc_cfg->cfg0_raw & ~(7U << CW_PER_PAGE)) | ++ (num_cw - 1) << CW_PER_PAGE; ++ cfg1 = ecc_cfg->cfg1_raw; ++ ecc_bch_cfg = ECC_CFG_ECC_DISABLE; ++ ++ data_buf = snandc->qspi->data_buf; ++ ++ oob_buf = snandc->qspi->oob_buf; ++ memset(oob_buf, 0xff, OOB_BUF_SIZE); ++ ++ snandc->buf_count = 0; ++ snandc->buf_start = 0; ++ qcom_clear_read_regs(snandc); ++ qcom_clear_bam_transaction(snandc); ++ ++ snandc->regs->addr0 = snandc->qspi->addr1; ++ snandc->regs->addr1 = snandc->qspi->addr2; ++ snandc->regs->cmd = snandc->qspi->cmd; ++ snandc->regs->cfg0 = cpu_to_le32(cfg0); ++ snandc->regs->cfg1 = cpu_to_le32(cfg1); ++ snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg); ++ snandc->regs->clrflashstatus = cpu_to_le32(ecc_cfg->clrflashstatus); ++ snandc->regs->clrreadstatus = cpu_to_le32(ecc_cfg->clrreadstatus); ++ snandc->regs->exec = cpu_to_le32(1); ++ ++ qcom_spi_config_page_write(snandc); ++ ++ for (i = 0; i < num_cw; i++) { ++ int data_size1, data_size2, oob_size1, oob_size2; ++ int reg_off = FLASH_BUF_ACC; ++ ++ data_size1 = mtd->writesize - ecc_cfg->cw_size * (num_cw - 1); ++ oob_size1 = ecc_cfg->bbm_size; ++ ++ if (i == (num_cw - 1)) { ++ data_size2 = NANDC_STEP_SIZE - data_size1 - ++ ((num_cw - 1) << 2); ++ oob_size2 = (num_cw << 2) + ecc_cfg->ecc_bytes_hw + ++ ecc_cfg->spare_bytes; ++ } else { ++ data_size2 = ecc_cfg->cw_data - data_size1; ++ oob_size2 = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes; ++ } ++ ++ qcom_write_data_dma(snandc, reg_off, data_buf, data_size1, ++ NAND_BAM_NO_EOT); ++ reg_off += data_size1; ++ data_buf += data_size1; ++ ++ qcom_write_data_dma(snandc, reg_off, oob_buf, oob_size1, ++ NAND_BAM_NO_EOT); ++ oob_buf += oob_size1; ++ reg_off += oob_size1; ++ ++ qcom_write_data_dma(snandc, reg_off, data_buf, data_size2, ++ NAND_BAM_NO_EOT); ++ reg_off += data_size2; ++ data_buf += data_size2; ++ ++ qcom_write_data_dma(snandc, reg_off, oob_buf, oob_size2, 0); ++ oob_buf += oob_size2; ++ ++ qcom_spi_config_cw_write(snandc); ++ } ++ ++ ret = qcom_submit_descs(snandc); ++ if (ret) { ++ dev_err(snandc->dev, "failure to write raw page\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int qcom_spi_program_ecc(struct qcom_nand_controller *snandc, ++ const struct spi_mem_op *op) ++{ ++ struct qpic_ecc *ecc_cfg = snandc->qspi->ecc; ++ u8 *data_buf = NULL, *oob_buf = NULL; ++ int i, ret; ++ int num_cw = snandc->qspi->num_cw; ++ u32 cfg0, cfg1, ecc_bch_cfg, ecc_buf_cfg; ++ ++ cfg0 = (ecc_cfg->cfg0 & ~(7U << CW_PER_PAGE)) | ++ (num_cw - 1) << CW_PER_PAGE; ++ cfg1 = ecc_cfg->cfg1; ++ ecc_bch_cfg = ecc_cfg->ecc_bch_cfg; ++ ecc_buf_cfg = ecc_cfg->ecc_buf_cfg; ++ ++ if (snandc->qspi->data_buf) ++ data_buf = snandc->qspi->data_buf; ++ ++ oob_buf = snandc->qspi->oob_buf; ++ ++ snandc->buf_count = 0; ++ snandc->buf_start = 0; ++ qcom_clear_read_regs(snandc); ++ qcom_clear_bam_transaction(snandc); ++ ++ snandc->regs->addr0 = snandc->qspi->addr1; ++ snandc->regs->addr1 = snandc->qspi->addr2; ++ snandc->regs->cmd = snandc->qspi->cmd; ++ snandc->regs->cfg0 = cpu_to_le32(cfg0); ++ snandc->regs->cfg1 = cpu_to_le32(cfg1); ++ snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg); ++ snandc->regs->ecc_buf_cfg = cpu_to_le32(ecc_buf_cfg); ++ snandc->regs->exec = cpu_to_le32(1); ++ ++ qcom_spi_config_page_write(snandc); ++ ++ for (i = 0; i < num_cw; i++) { ++ int data_size, oob_size; ++ ++ if (i == (num_cw - 1)) { ++ data_size = NANDC_STEP_SIZE - ((num_cw - 1) << 2); ++ oob_size = (num_cw << 2) + ecc_cfg->ecc_bytes_hw + ++ ecc_cfg->spare_bytes; ++ } else { ++ data_size = ecc_cfg->cw_data; ++ oob_size = ecc_cfg->bytes; ++ } ++ ++ if (data_buf) ++ qcom_write_data_dma(snandc, FLASH_BUF_ACC, data_buf, data_size, ++ i == (num_cw - 1) ? NAND_BAM_NO_EOT : 0); ++ ++ if (i == (num_cw - 1)) { ++ if (oob_buf) { ++ oob_buf += ecc_cfg->bbm_size; ++ qcom_write_data_dma(snandc, FLASH_BUF_ACC + data_size, ++ oob_buf, oob_size, 0); ++ } ++ } ++ ++ qcom_spi_config_cw_write(snandc); ++ ++ if (data_buf) ++ data_buf += data_size; ++ if (oob_buf) ++ oob_buf += oob_size; ++ } ++ ++ ret = qcom_submit_descs(snandc); ++ if (ret) { ++ dev_err(snandc->dev, "failure to write page\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int qcom_spi_program_oob(struct qcom_nand_controller *snandc, ++ const struct spi_mem_op *op) ++{ ++ struct qpic_ecc *ecc_cfg = snandc->qspi->ecc; ++ u8 *oob_buf = NULL; ++ int ret, col, data_size, oob_size; ++ int num_cw = snandc->qspi->num_cw; ++ u32 cfg0, cfg1, ecc_bch_cfg, ecc_buf_cfg; ++ ++ cfg0 = (ecc_cfg->cfg0 & ~(7U << CW_PER_PAGE)) | ++ (num_cw - 1) << CW_PER_PAGE; ++ cfg1 = ecc_cfg->cfg1; ++ ecc_bch_cfg = ecc_cfg->ecc_bch_cfg; ++ ecc_buf_cfg = ecc_cfg->ecc_buf_cfg; ++ ++ col = ecc_cfg->cw_size * (num_cw - 1); ++ ++ oob_buf = snandc->qspi->data_buf; ++ ++ snandc->buf_count = 0; ++ snandc->buf_start = 0; ++ qcom_clear_read_regs(snandc); ++ qcom_clear_bam_transaction(snandc); ++ snandc->regs->addr0 = (snandc->qspi->addr1 | cpu_to_le32(col)); ++ snandc->regs->addr1 = snandc->qspi->addr2; ++ snandc->regs->cmd = snandc->qspi->cmd; ++ snandc->regs->cfg0 = cpu_to_le32(cfg0); ++ snandc->regs->cfg1 = cpu_to_le32(cfg1); ++ snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg); ++ snandc->regs->ecc_buf_cfg = cpu_to_le32(ecc_buf_cfg); ++ snandc->regs->exec = cpu_to_le32(1); ++ ++ /* calculate the data and oob size for the last codeword/step */ ++ data_size = NANDC_STEP_SIZE - ((num_cw - 1) << 2); ++ oob_size = snandc->qspi->mtd->oobavail; ++ ++ memset(snandc->data_buffer, 0xff, ecc_cfg->cw_data); ++ /* override new oob content to last codeword */ ++ mtd_ooblayout_get_databytes(snandc->qspi->mtd, snandc->data_buffer + data_size, ++ oob_buf, 0, snandc->qspi->mtd->oobavail); ++ qcom_spi_config_page_write(snandc); ++ qcom_write_data_dma(snandc, FLASH_BUF_ACC, snandc->data_buffer, data_size + oob_size, 0); ++ qcom_spi_config_cw_write(snandc); ++ ++ ret = qcom_submit_descs(snandc); ++ if (ret) { ++ dev_err(snandc->dev, "failure to write oob\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int qcom_spi_program_execute(struct qcom_nand_controller *snandc, ++ const struct spi_mem_op *op) ++{ ++ if (snandc->qspi->page_rw && snandc->qspi->raw_rw) ++ return qcom_spi_program_raw(snandc, op); ++ ++ if (snandc->qspi->page_rw) ++ return qcom_spi_program_ecc(snandc, op); ++ ++ if (snandc->qspi->oob_rw) ++ return qcom_spi_program_oob(snandc, op); ++ ++ return 0; ++} ++ ++static int qcom_spi_cmd_mapping(struct qcom_nand_controller *snandc, u32 opcode, u32 *cmd) ++{ ++ switch (opcode) { ++ case SPINAND_RESET: ++ *cmd = (SPI_WP | SPI_HOLD | SPI_TRANSFER_MODE_x1 | OP_RESET_DEVICE); ++ break; ++ case SPINAND_READID: ++ *cmd = (SPI_WP | SPI_HOLD | SPI_TRANSFER_MODE_x1 | OP_FETCH_ID); ++ break; ++ case SPINAND_GET_FEATURE: ++ *cmd = (SPI_TRANSFER_MODE_x1 | SPI_WP | SPI_HOLD | ACC_FEATURE); ++ break; ++ case SPINAND_SET_FEATURE: ++ *cmd = (SPI_TRANSFER_MODE_x1 | SPI_WP | SPI_HOLD | ACC_FEATURE | ++ QPIC_SET_FEATURE); ++ break; ++ case SPINAND_READ: ++ if (snandc->qspi->raw_rw) { ++ *cmd = (PAGE_ACC | LAST_PAGE | SPI_TRANSFER_MODE_x1 | ++ SPI_WP | SPI_HOLD | OP_PAGE_READ); ++ } else { ++ *cmd = (PAGE_ACC | LAST_PAGE | SPI_TRANSFER_MODE_x1 | ++ SPI_WP | SPI_HOLD | OP_PAGE_READ_WITH_ECC); ++ } ++ ++ break; ++ case SPINAND_ERASE: ++ *cmd = OP_BLOCK_ERASE | PAGE_ACC | LAST_PAGE | SPI_WP | ++ SPI_HOLD | SPI_TRANSFER_MODE_x1; ++ break; ++ case SPINAND_WRITE_EN: ++ *cmd = SPINAND_WRITE_EN; ++ break; ++ case SPINAND_PROGRAM_EXECUTE: ++ *cmd = (PAGE_ACC | LAST_PAGE | SPI_TRANSFER_MODE_x1 | ++ SPI_WP | SPI_HOLD | OP_PROGRAM_PAGE); ++ break; ++ case SPINAND_PROGRAM_LOAD: ++ *cmd = SPINAND_PROGRAM_LOAD; ++ break; ++ default: ++ dev_err(snandc->dev, "Opcode not supported: %u\n", opcode); ++ return -EOPNOTSUPP; ++ } ++ ++ return 0; ++} ++ ++static int qcom_spi_write_page(struct qcom_nand_controller *snandc, ++ const struct spi_mem_op *op) ++{ ++ int ret; ++ u32 cmd; ++ ++ ret = qcom_spi_cmd_mapping(snandc, op->cmd.opcode, &cmd); ++ if (ret < 0) ++ return ret; ++ ++ if (op->cmd.opcode == SPINAND_PROGRAM_LOAD) ++ snandc->qspi->data_buf = (u8 *)op->data.buf.out; ++ ++ return 0; ++} ++ ++static int qcom_spi_send_cmdaddr(struct qcom_nand_controller *snandc, ++ const struct spi_mem_op *op) ++{ ++ struct qpic_snand_op s_op = {}; ++ u32 cmd; ++ int ret, opcode; ++ ++ ret = qcom_spi_cmd_mapping(snandc, op->cmd.opcode, &cmd); ++ if (ret < 0) ++ return ret; ++ ++ s_op.cmd_reg = cmd; ++ s_op.addr1_reg = op->addr.val; ++ s_op.addr2_reg = 0; ++ ++ opcode = op->cmd.opcode; ++ ++ switch (opcode) { ++ case SPINAND_WRITE_EN: ++ return 0; ++ case SPINAND_PROGRAM_EXECUTE: ++ s_op.addr1_reg = op->addr.val << 16; ++ s_op.addr2_reg = op->addr.val >> 16 & 0xff; ++ snandc->qspi->addr1 = cpu_to_le32(s_op.addr1_reg); ++ snandc->qspi->addr2 = cpu_to_le32(s_op.addr2_reg); ++ snandc->qspi->cmd = cpu_to_le32(cmd); ++ return qcom_spi_program_execute(snandc, op); ++ case SPINAND_READ: ++ s_op.addr1_reg = (op->addr.val << 16); ++ s_op.addr2_reg = op->addr.val >> 16 & 0xff; ++ snandc->qspi->addr1 = cpu_to_le32(s_op.addr1_reg); ++ snandc->qspi->addr2 = cpu_to_le32(s_op.addr2_reg); ++ snandc->qspi->cmd = cpu_to_le32(cmd); ++ return 0; ++ case SPINAND_ERASE: ++ s_op.addr2_reg = (op->addr.val >> 16) & 0xffff; ++ s_op.addr1_reg = op->addr.val; ++ snandc->qspi->addr1 = cpu_to_le32(s_op.addr1_reg << 16); ++ snandc->qspi->addr2 = cpu_to_le32(s_op.addr2_reg); ++ snandc->qspi->cmd = cpu_to_le32(cmd); ++ qcom_spi_block_erase(snandc); ++ return 0; ++ default: ++ break; ++ } ++ ++ snandc->buf_count = 0; ++ snandc->buf_start = 0; ++ qcom_clear_read_regs(snandc); ++ qcom_clear_bam_transaction(snandc); ++ ++ snandc->regs->cmd = cpu_to_le32(s_op.cmd_reg); ++ snandc->regs->exec = cpu_to_le32(1); ++ snandc->regs->addr0 = cpu_to_le32(s_op.addr1_reg); ++ snandc->regs->addr1 = cpu_to_le32(s_op.addr2_reg); ++ ++ qcom_write_reg_dma(snandc, &snandc->regs->cmd, NAND_FLASH_CMD, 3, NAND_BAM_NEXT_SGL); ++ qcom_write_reg_dma(snandc, &snandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); ++ ++ ret = qcom_submit_descs(snandc); ++ if (ret) ++ dev_err(snandc->dev, "failure in submitting cmd descriptor\n"); ++ ++ return ret; ++} ++ ++static int qcom_spi_io_op(struct qcom_nand_controller *snandc, const struct spi_mem_op *op) ++{ ++ int ret, val, opcode; ++ bool copy = false, copy_ftr = false; ++ ++ ret = qcom_spi_send_cmdaddr(snandc, op); ++ if (ret) ++ return ret; ++ ++ snandc->buf_count = 0; ++ snandc->buf_start = 0; ++ qcom_clear_read_regs(snandc); ++ qcom_clear_bam_transaction(snandc); ++ opcode = op->cmd.opcode; ++ ++ switch (opcode) { ++ case SPINAND_READID: ++ snandc->buf_count = 4; ++ qcom_read_reg_dma(snandc, NAND_READ_ID, 1, NAND_BAM_NEXT_SGL); ++ copy = true; ++ break; ++ case SPINAND_GET_FEATURE: ++ snandc->buf_count = 4; ++ qcom_read_reg_dma(snandc, NAND_FLASH_FEATURES, 1, NAND_BAM_NEXT_SGL); ++ copy_ftr = true; ++ break; ++ case SPINAND_SET_FEATURE: ++ snandc->regs->flash_feature = cpu_to_le32(*(u32 *)op->data.buf.out); ++ qcom_write_reg_dma(snandc, &snandc->regs->flash_feature, ++ NAND_FLASH_FEATURES, 1, NAND_BAM_NEXT_SGL); ++ break; ++ case SPINAND_PROGRAM_EXECUTE: ++ case SPINAND_WRITE_EN: ++ case SPINAND_RESET: ++ case SPINAND_ERASE: ++ case SPINAND_READ: ++ return 0; ++ default: ++ return -EOPNOTSUPP; ++ } ++ ++ ret = qcom_submit_descs(snandc); ++ if (ret) ++ dev_err(snandc->dev, "failure in submitting descriptor for:%d\n", opcode); ++ ++ if (copy) { ++ qcom_nandc_dev_to_mem(snandc, true); ++ memcpy(op->data.buf.in, snandc->reg_read_buf, snandc->buf_count); ++ } ++ ++ if (copy_ftr) { ++ qcom_nandc_dev_to_mem(snandc, true); ++ val = le32_to_cpu(*(__le32 *)snandc->reg_read_buf); ++ val >>= 8; ++ memcpy(op->data.buf.in, &val, snandc->buf_count); ++ } ++ ++ return ret; ++} ++ ++static bool qcom_spi_is_page_op(const struct spi_mem_op *op) ++{ ++ if (op->addr.buswidth != 1 && op->addr.buswidth != 2 && op->addr.buswidth != 4) ++ return false; ++ ++ if (op->data.dir == SPI_MEM_DATA_IN) { ++ if (op->addr.buswidth == 4 && op->data.buswidth == 4) ++ return true; ++ ++ if (op->addr.nbytes == 2 && op->addr.buswidth == 1) ++ return true; ++ ++ } else if (op->data.dir == SPI_MEM_DATA_OUT) { ++ if (op->data.buswidth == 4) ++ return true; ++ if (op->addr.nbytes == 2 && op->addr.buswidth == 1) ++ return true; ++ } ++ ++ return false; ++} ++ ++static bool qcom_spi_supports_op(struct spi_mem *mem, const struct spi_mem_op *op) ++{ ++ if (!spi_mem_default_supports_op(mem, op)) ++ return false; ++ ++ if (op->cmd.nbytes != 1 || op->cmd.buswidth != 1) ++ return false; ++ ++ if (qcom_spi_is_page_op(op)) ++ return true; ++ ++ return ((!op->addr.nbytes || op->addr.buswidth == 1) && ++ (!op->dummy.nbytes || op->dummy.buswidth == 1) && ++ (!op->data.nbytes || op->data.buswidth == 1)); ++} ++ ++static int qcom_spi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) ++{ ++ struct qcom_nand_controller *snandc = spi_controller_get_devdata(mem->spi->controller); ++ ++ dev_dbg(snandc->dev, "OP %02x ADDR %08llX@%d:%u DATA %d:%u", op->cmd.opcode, ++ op->addr.val, op->addr.buswidth, op->addr.nbytes, ++ op->data.buswidth, op->data.nbytes); ++ ++ if (qcom_spi_is_page_op(op)) { ++ if (op->data.dir == SPI_MEM_DATA_IN) ++ return qcom_spi_read_page(snandc, op); ++ if (op->data.dir == SPI_MEM_DATA_OUT) ++ return qcom_spi_write_page(snandc, op); ++ } else { ++ return qcom_spi_io_op(snandc, op); ++ } ++ ++ return 0; ++} ++ ++static const struct spi_controller_mem_ops qcom_spi_mem_ops = { ++ .supports_op = qcom_spi_supports_op, ++ .exec_op = qcom_spi_exec_op, ++}; ++ ++static const struct spi_controller_mem_caps qcom_spi_mem_caps = { ++ .ecc = true, ++}; ++ ++static int qcom_spi_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct spi_controller *ctlr; ++ struct qcom_nand_controller *snandc; ++ struct qpic_spi_nand *qspi; ++ struct qpic_ecc *ecc; ++ struct resource *res; ++ const void *dev_data; ++ int ret; ++ ++ ecc = devm_kzalloc(dev, sizeof(*ecc), GFP_KERNEL); ++ if (!ecc) ++ return -ENOMEM; ++ ++ qspi = devm_kzalloc(dev, sizeof(*qspi), GFP_KERNEL); ++ if (!qspi) ++ return -ENOMEM; ++ ++ ctlr = __devm_spi_alloc_controller(dev, sizeof(*snandc), false); ++ if (!ctlr) ++ return -ENOMEM; ++ ++ platform_set_drvdata(pdev, ctlr); ++ ++ snandc = spi_controller_get_devdata(ctlr); ++ qspi->snandc = snandc; ++ ++ snandc->dev = dev; ++ snandc->qspi = qspi; ++ snandc->qspi->ctlr = ctlr; ++ snandc->qspi->ecc = ecc; ++ ++ dev_data = of_device_get_match_data(dev); ++ if (!dev_data) { ++ dev_err(&pdev->dev, "failed to get device data\n"); ++ return -ENODEV; ++ } ++ ++ snandc->props = dev_data; ++ snandc->dev = &pdev->dev; ++ ++ snandc->core_clk = devm_clk_get(dev, "core"); ++ if (IS_ERR(snandc->core_clk)) ++ return PTR_ERR(snandc->core_clk); ++ ++ snandc->aon_clk = devm_clk_get(dev, "aon"); ++ if (IS_ERR(snandc->aon_clk)) ++ return PTR_ERR(snandc->aon_clk); ++ ++ snandc->qspi->iomacro_clk = devm_clk_get(dev, "iom"); ++ if (IS_ERR(snandc->qspi->iomacro_clk)) ++ return PTR_ERR(snandc->qspi->iomacro_clk); ++ ++ snandc->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); ++ if (IS_ERR(snandc->base)) ++ return PTR_ERR(snandc->base); ++ ++ snandc->base_phys = res->start; ++ snandc->base_dma = dma_map_resource(dev, res->start, resource_size(res), ++ DMA_BIDIRECTIONAL, 0); ++ if (dma_mapping_error(dev, snandc->base_dma)) ++ return -ENXIO; ++ ++ ret = clk_prepare_enable(snandc->core_clk); ++ if (ret) ++ goto err_dis_core_clk; ++ ++ ret = clk_prepare_enable(snandc->aon_clk); ++ if (ret) ++ goto err_dis_aon_clk; ++ ++ ret = clk_prepare_enable(snandc->qspi->iomacro_clk); ++ if (ret) ++ goto err_dis_iom_clk; ++ ++ ret = qcom_nandc_alloc(snandc); ++ if (ret) ++ goto err_snand_alloc; ++ ++ ret = qcom_spi_init(snandc); ++ if (ret) ++ goto err_spi_init; ++ ++ /* setup ECC engine */ ++ snandc->qspi->ecc_eng.dev = &pdev->dev; ++ snandc->qspi->ecc_eng.integration = NAND_ECC_ENGINE_INTEGRATION_PIPELINED; ++ snandc->qspi->ecc_eng.ops = &qcom_spi_ecc_engine_ops_pipelined; ++ snandc->qspi->ecc_eng.priv = snandc; ++ ++ ret = nand_ecc_register_on_host_hw_engine(&snandc->qspi->ecc_eng); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to register ecc engine:%d\n", ret); ++ goto err_spi_init; ++ } ++ ++ ctlr->num_chipselect = QPIC_QSPI_NUM_CS; ++ ctlr->mem_ops = &qcom_spi_mem_ops; ++ ctlr->mem_caps = &qcom_spi_mem_caps; ++ ctlr->dev.of_node = pdev->dev.of_node; ++ ctlr->mode_bits = SPI_TX_DUAL | SPI_RX_DUAL | ++ SPI_TX_QUAD | SPI_RX_QUAD; ++ ++ ret = spi_register_controller(ctlr); ++ if (ret) { ++ dev_err(&pdev->dev, "spi_register_controller failed.\n"); ++ goto err_spi_init; ++ } ++ ++ return 0; ++ ++err_spi_init: ++ qcom_nandc_unalloc(snandc); ++err_snand_alloc: ++ clk_disable_unprepare(snandc->qspi->iomacro_clk); ++err_dis_iom_clk: ++ clk_disable_unprepare(snandc->aon_clk); ++err_dis_aon_clk: ++ clk_disable_unprepare(snandc->core_clk); ++err_dis_core_clk: ++ dma_unmap_resource(dev, res->start, resource_size(res), ++ DMA_BIDIRECTIONAL, 0); ++ return ret; ++} ++ ++static void qcom_spi_remove(struct platform_device *pdev) ++{ ++ struct spi_controller *ctlr = platform_get_drvdata(pdev); ++ struct qcom_nand_controller *snandc = spi_controller_get_devdata(ctlr); ++ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ ++ spi_unregister_controller(ctlr); ++ ++ qcom_nandc_unalloc(snandc); ++ ++ clk_disable_unprepare(snandc->aon_clk); ++ clk_disable_unprepare(snandc->core_clk); ++ clk_disable_unprepare(snandc->qspi->iomacro_clk); ++ ++ dma_unmap_resource(&pdev->dev, snandc->base_dma, resource_size(res), ++ DMA_BIDIRECTIONAL, 0); ++} ++ ++static const struct qcom_nandc_props ipq9574_snandc_props = { ++ .dev_cmd_reg_start = 0x7000, ++ .supports_bam = true, ++}; ++ ++static const struct of_device_id qcom_snandc_of_match[] = { ++ { ++ .compatible = "qcom,ipq9574-snand", ++ .data = &ipq9574_snandc_props, ++ }, ++ {} ++} ++MODULE_DEVICE_TABLE(of, qcom_snandc_of_match); ++ ++static struct platform_driver qcom_spi_driver = { ++ .driver = { ++ .name = "qcom_snand", ++ .of_match_table = qcom_snandc_of_match, ++ }, ++ .probe = qcom_spi_probe, ++ .remove_new = qcom_spi_remove, ++}; ++module_platform_driver(qcom_spi_driver); ++ ++MODULE_DESCRIPTION("SPI driver for QPIC QSPI cores"); ++MODULE_AUTHOR("Md Sadre Alam "); ++MODULE_LICENSE("GPL"); ++ +diff --git a/include/linux/mtd/nand-qpic-common.h b/include/linux/mtd/nand-qpic-common.h +index 4d9b736ff8b7..7760154de581 100644 +--- a/include/linux/mtd/nand-qpic-common.h ++++ b/include/linux/mtd/nand-qpic-common.h +@@ -325,6 +325,10 @@ struct nandc_regs { + __le32 read_location_last1; + __le32 read_location_last2; + __le32 read_location_last3; ++ __le32 spi_cfg; ++ __le32 num_addr_cycle; ++ __le32 busy_wait_cnt; ++ __le32 flash_feature; + + __le32 erased_cw_detect_cfg_clr; + __le32 erased_cw_detect_cfg_set; +@@ -339,6 +343,7 @@ struct nandc_regs { + * + * @core_clk: controller clock + * @aon_clk: another controller clock ++ * @iomacro_clk: io macro clock + * + * @regs: a contiguous chunk of memory for DMA register + * writes. contains the register values to be +@@ -348,6 +353,7 @@ struct nandc_regs { + * initialized via DT match data + * + * @controller: base controller structure ++ * @qspi: qpic spi structure + * @host_list: list containing all the chips attached to the + * controller + * +@@ -392,6 +398,7 @@ struct qcom_nand_controller { + const struct qcom_nandc_props *props; + + struct nand_controller *controller; ++ struct qpic_spi_nand *qspi; + struct list_head host_list; + + union { +-- +2.51.0 + + +From 5f4a73da9c92fc7c87503e7865997fb54a39783c Mon Sep 17 00:00:00 2001 +From: Dan Carpenter +Date: Thu, 6 Mar 2025 12:40:01 +0300 +Subject: [PATCH 017/517] spi: spi-qpic-snand: Fix ECC_CFG_ECC_DISABLE shift in + qcom_spi_read_last_cw() + +The ECC_CFG_ECC_DISABLE define is BIT(0). It's supposed to be used +directly instead of used as a shifter. + +Fixes: 7304d1909080 ("spi: spi-qpic: add driver for QCOM SPI NAND flash Interface") +Signed-off-by: Dan Carpenter +Link: https://patch.msgid.link/2f4b0a0b-2c03-41c0-8a4a-3d789a83832d@stanley.mountain +Signed-off-by: Mark Brown +--- + drivers/spi/spi-qpic-snand.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/spi/spi-qpic-snand.c b/drivers/spi/spi-qpic-snand.c +index 1a4746d0fd62..d7a43ed5e304 100644 +--- a/drivers/spi/spi-qpic-snand.c ++++ b/drivers/spi/spi-qpic-snand.c +@@ -514,7 +514,7 @@ static int qcom_spi_read_last_cw(struct qcom_nand_controller *snandc, + cfg0 = (ecc_cfg->cfg0_raw & ~(7U << CW_PER_PAGE)) | + 0 << CW_PER_PAGE; + cfg1 = ecc_cfg->cfg1_raw; +- ecc_bch_cfg = 1 << ECC_CFG_ECC_DISABLE; ++ ecc_bch_cfg = ECC_CFG_ECC_DISABLE; + + snandc->regs->cmd = snandc->qspi->cmd; + snandc->regs->cfg0 = cpu_to_le32(cfg0); +-- +2.51.0 + + +From 619c0af9a03bdca0c0346277ba75b1d42c4d6f04 Mon Sep 17 00:00:00 2001 +From: Gabor Juhos +Date: Thu, 13 Mar 2025 19:31:21 +0100 +Subject: [PATCH 018/517] spi: spi-qpic-snand: avoid memleak in + qcom_spi_ecc_init_ctx_pipelined() + +When the allocation of the OOB buffer fails, the +qcom_spi_ecc_init_ctx_pipelined() function returns without freeing +the memory allocated for 'ecc_cfg' thus it can cause a memory leak. + +Call kfree() to free 'ecc_cfg' before returning from the function +to avoid that. + +Fixes: 7304d1909080 ("spi: spi-qpic: add driver for QCOM SPI NAND flash Interface") +Signed-off-by: Gabor Juhos +Link: https://patch.msgid.link/20250313-qpic-snand-memleak-fix-v1-1-e54e78d1da3a@gmail.com +Signed-off-by: Mark Brown +--- + drivers/spi/spi-qpic-snand.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/spi/spi-qpic-snand.c b/drivers/spi/spi-qpic-snand.c +index d7a43ed5e304..3b8020f37f97 100644 +--- a/drivers/spi/spi-qpic-snand.c ++++ b/drivers/spi/spi-qpic-snand.c +@@ -263,8 +263,10 @@ static int qcom_spi_ecc_init_ctx_pipelined(struct nand_device *nand) + return -ENOMEM; + snandc->qspi->oob_buf = kzalloc(mtd->writesize + mtd->oobsize, + GFP_KERNEL); +- if (!snandc->qspi->oob_buf) ++ if (!snandc->qspi->oob_buf) { ++ kfree(ecc_cfg); + return -ENOMEM; ++ } + + memset(snandc->qspi->oob_buf, 0xff, mtd->writesize + mtd->oobsize); + +-- +2.51.0 + + +From 420047e7ae6f00cf8aa3e6d37b679f63390f586b Mon Sep 17 00:00:00 2001 +From: Geert Uytterhoeven +Date: Wed, 26 Mar 2025 15:22:19 +0100 +Subject: [PATCH 019/517] spi: SPI_QPIC_SNAND should be tristate and depend on + MTD + +SPI_QPIC_SNAND is the only driver that selects MTD instead of depending +on it, which could lead to circular dependencies. Moreover, as +SPI_QPIC_SNAND is bool, this forces MTD (and various related symbols) to +be built-in, as can be seen in an allmodconfig kernel. + +Except for a missing semicolon, there is no reason why SPI_QPIC_SNAND +cannot be tristate; all MODULE_*() boilerplate is already present. +Hence make SPI_QPIC_SNAND tristate, let it depend on MTD, and add the +missing semicolon. + +Fixes: 7304d1909080ef0c ("spi: spi-qpic: add driver for QCOM SPI NAND flash Interface") +Signed-off-by: Geert Uytterhoeven +Link: https://patch.msgid.link/b63db431cbf35223a4400e44c296293d32c4543c.1742998909.git.geert+renesas@glider.be +Signed-off-by: Mark Brown +--- + drivers/spi/Kconfig | 4 ++-- + drivers/spi/spi-qpic-snand.c | 2 +- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig +index 98c5fa460fb1..712cf74a73d9 100644 +--- a/drivers/spi/Kconfig ++++ b/drivers/spi/Kconfig +@@ -899,9 +899,9 @@ config SPI_QCOM_QSPI + QSPI(Quad SPI) driver for Qualcomm QSPI controller. + + config SPI_QPIC_SNAND +- bool "QPIC SNAND controller" ++ tristate "QPIC SNAND controller" + depends on ARCH_QCOM || COMPILE_TEST +- select MTD ++ depends on MTD + help + QPIC_SNAND (QPIC SPI NAND) driver for Qualcomm QPIC controller. + QPIC controller supports both parallel nand and serial nand. +diff --git a/drivers/spi/spi-qpic-snand.c b/drivers/spi/spi-qpic-snand.c +index 3b8020f37f97..10ce98bcacef 100644 +--- a/drivers/spi/spi-qpic-snand.c ++++ b/drivers/spi/spi-qpic-snand.c +@@ -1614,7 +1614,7 @@ static const struct of_device_id qcom_snandc_of_match[] = { + .data = &ipq9574_snandc_props, + }, + {} +-} ++}; + MODULE_DEVICE_TABLE(of, qcom_snandc_of_match); + + static struct platform_driver qcom_spi_driver = { +-- +2.51.0 + + +From 4c2cc0b314a1f1635b9e563add9ef8b5f99fd4f3 Mon Sep 17 00:00:00 2001 +From: Gabor Juhos +Date: Wed, 23 Apr 2025 21:31:57 +0200 +Subject: [PATCH 020/517] spi: spi-qpic-snand: propagate errors from + qcom_spi_block_erase() + +The qcom_spi_block_erase() function returns with error in case of +failure. Change the qcom_spi_send_cmdaddr() function to propagate +these errors to the callers instead of returning with success. + +Fixes: 7304d1909080 ("spi: spi-qpic: add driver for QCOM SPI NAND flash Interface") +Signed-off-by: Gabor Juhos +Reviewed-by: Abel Vesa +Reviewed-by: Md Sadre Alam +--- + drivers/spi/spi-qpic-snand.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/spi/spi-qpic-snand.c b/drivers/spi/spi-qpic-snand.c +index 10ce98bcacef..4f08cd0e41cc 100644 +--- a/drivers/spi/spi-qpic-snand.c ++++ b/drivers/spi/spi-qpic-snand.c +@@ -1307,8 +1307,7 @@ static int qcom_spi_send_cmdaddr(struct qcom_nand_controller *snandc, + snandc->qspi->addr1 = cpu_to_le32(s_op.addr1_reg << 16); + snandc->qspi->addr2 = cpu_to_le32(s_op.addr2_reg); + snandc->qspi->cmd = cpu_to_le32(cmd); +- qcom_spi_block_erase(snandc); +- return 0; ++ return qcom_spi_block_erase(snandc); + default: + break; + } +-- +2.51.0 + + +From 3a06d824412d2e8082d82f9f527b7b805e849a33 Mon Sep 17 00:00:00 2001 +From: Gabor Juhos +Date: Mon, 28 Apr 2025 09:30:55 +0200 +Subject: [PATCH 021/517] spi: spi-qpic-snand: fix NAND_READ_LOCATION_2 + register handling + +The precomputed value for the NAND_READ_LOCATION_2 register should be +stored in 'snandc->regs->read_location2'. + +Fix the qcom_spi_set_read_loc_first() function accordingly. + +Fixes: 7304d1909080 ("spi: spi-qpic: add driver for QCOM SPI NAND flash Interface") +Signed-off-by: Gabor Juhos +Reviewed-by: Md Sadre Alam +--- + drivers/spi/spi-qpic-snand.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/spi/spi-qpic-snand.c b/drivers/spi/spi-qpic-snand.c +index 4f08cd0e41cc..f01f9517c15d 100644 +--- a/drivers/spi/spi-qpic-snand.c ++++ b/drivers/spi/spi-qpic-snand.c +@@ -142,7 +142,7 @@ static void qcom_spi_set_read_loc_first(struct qcom_nand_controller *snandc, + else if (reg == NAND_READ_LOCATION_1) + snandc->regs->read_location1 = locreg_val; + else if (reg == NAND_READ_LOCATION_2) +- snandc->regs->read_location1 = locreg_val; ++ snandc->regs->read_location2 = locreg_val; + else if (reg == NAND_READ_LOCATION_3) + snandc->regs->read_location3 = locreg_val; + } +-- +2.51.0 + + +From 4de9243c76e9bb34f53b9804e1fe7479084a896d Mon Sep 17 00:00:00 2001 +From: Gabor Juhos +Date: Thu, 20 Mar 2025 19:11:59 +0100 +Subject: [PATCH 022/517] spi: spi-qpic-snand: use kmalloc() for OOB buffer + allocation + +The qcom_spi_ecc_init_ctx_pipelined() function allocates zeroed +memory for the OOB buffer, then it fills the buffer with '0xff' +bytes right after the allocation. In this case zeroing the memory +during allocation is superfluous, so use kmalloc() instead of +kzalloc() to avoid that. + +Signed-off-by: Gabor Juhos +Link: https://patch.msgid.link/20250320-qpic-snand-kmalloc-v1-1-94e267550675@gmail.com +Signed-off-by: Mark Brown +--- + drivers/spi/spi-qpic-snand.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/spi/spi-qpic-snand.c b/drivers/spi/spi-qpic-snand.c +index f01f9517c15d..b03ab39727da 100644 +--- a/drivers/spi/spi-qpic-snand.c ++++ b/drivers/spi/spi-qpic-snand.c +@@ -261,7 +261,7 @@ static int qcom_spi_ecc_init_ctx_pipelined(struct nand_device *nand) + ecc_cfg = kzalloc(sizeof(*ecc_cfg), GFP_KERNEL); + if (!ecc_cfg) + return -ENOMEM; +- snandc->qspi->oob_buf = kzalloc(mtd->writesize + mtd->oobsize, ++ snandc->qspi->oob_buf = kmalloc(mtd->writesize + mtd->oobsize, + GFP_KERNEL); + if (!snandc->qspi->oob_buf) { + kfree(ecc_cfg); +-- +2.51.0 + + +From c07685fe8817b098d96bf963114d077fb44574da Mon Sep 17 00:00:00 2001 +From: Gabor Juhos +Date: Thu, 24 Apr 2025 20:10:59 +0200 +Subject: [PATCH 023/517] spi: spi-qpic-snand: remove unused 'wlen' member of + 'struct qpic_spi_nand' + +The 'wlen' member of the qpic_spi_nand structure is never used in the +code so remove that. + +Signed-off-by: Gabor Juhos +--- + drivers/spi/spi-qpic-snand.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/drivers/spi/spi-qpic-snand.c b/drivers/spi/spi-qpic-snand.c +index b03ab39727da..98d32d269d55 100644 +--- a/drivers/spi/spi-qpic-snand.c ++++ b/drivers/spi/spi-qpic-snand.c +@@ -116,7 +116,6 @@ struct qpic_spi_nand { + struct nand_ecc_engine ecc_eng; + u8 *data_buf; + u8 *oob_buf; +- u32 wlen; + __le32 addr1; + __le32 addr2; + __le32 cmd; +-- +2.51.0 + + +From 992315f651da18bc66f4c200cdfcb5f54ed9acd7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= +Date: Wed, 14 May 2025 08:14:54 +0200 +Subject: [PATCH 024/517] mtd: rawnand: brcmnand: remove unused parameters +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +last_cmd and last_byte are now unused brcmnand_host members. +last_addr is only written and never read so we can remove it too. + +Signed-off-by: Ãlvaro Fernández Rojas +Reviewed-by: Florian Fainelli +Reviewed-by: William Zhang +Signed-off-by: Miquel Raynal +--- + drivers/mtd/nand/raw/brcmnand/brcmnand.c | 24 ++++++------------------ + 1 file changed, 6 insertions(+), 18 deletions(-) + +diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c +index 2eb44c1428fb..3bea54fe5a73 100644 +--- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c ++++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c +@@ -310,9 +310,6 @@ struct brcmnand_host { + struct platform_device *pdev; + int cs; + +- unsigned int last_cmd; +- unsigned int last_byte; +- u64 last_addr; + struct brcmnand_cfg hwcfg; + struct brcmnand_controller *ctrl; + }; +@@ -2233,14 +2230,11 @@ static int brcmnand_read_page(struct nand_chip *chip, uint8_t *buf, + int oob_required, int page) + { + struct mtd_info *mtd = nand_to_mtd(chip); +- struct brcmnand_host *host = nand_get_controller_data(chip); + u8 *oob = oob_required ? (u8 *)chip->oob_poi : NULL; + u64 addr = (u64)page << chip->page_shift; + +- host->last_addr = addr; +- +- return brcmnand_read(mtd, chip, host->last_addr, +- mtd->writesize >> FC_SHIFT, (u32 *)buf, oob); ++ return brcmnand_read(mtd, chip, addr, mtd->writesize >> FC_SHIFT, ++ (u32 *)buf, oob); + } + + static int brcmnand_read_page_raw(struct nand_chip *chip, uint8_t *buf, +@@ -2252,11 +2246,9 @@ static int brcmnand_read_page_raw(struct nand_chip *chip, uint8_t *buf, + int ret; + u64 addr = (u64)page << chip->page_shift; + +- host->last_addr = addr; +- + brcmnand_set_ecc_enabled(host, 0); +- ret = brcmnand_read(mtd, chip, host->last_addr, +- mtd->writesize >> FC_SHIFT, (u32 *)buf, oob); ++ ret = brcmnand_read(mtd, chip, addr, mtd->writesize >> FC_SHIFT, ++ (u32 *)buf, oob); + brcmnand_set_ecc_enabled(host, 1); + return ret; + } +@@ -2363,13 +2355,10 @@ static int brcmnand_write_page(struct nand_chip *chip, const uint8_t *buf, + int oob_required, int page) + { + struct mtd_info *mtd = nand_to_mtd(chip); +- struct brcmnand_host *host = nand_get_controller_data(chip); + void *oob = oob_required ? chip->oob_poi : NULL; + u64 addr = (u64)page << chip->page_shift; + +- host->last_addr = addr; +- +- return brcmnand_write(mtd, chip, host->last_addr, (const u32 *)buf, oob); ++ return brcmnand_write(mtd, chip, addr, (const u32 *)buf, oob); + } + + static int brcmnand_write_page_raw(struct nand_chip *chip, const uint8_t *buf, +@@ -2381,9 +2370,8 @@ static int brcmnand_write_page_raw(struct nand_chip *chip, const uint8_t *buf, + u64 addr = (u64)page << chip->page_shift; + int ret = 0; + +- host->last_addr = addr; + brcmnand_set_ecc_enabled(host, 0); +- ret = brcmnand_write(mtd, chip, host->last_addr, (const u32 *)buf, oob); ++ ret = brcmnand_write(mtd, chip, addr, (const u32 *)buf, oob); + brcmnand_set_ecc_enabled(host, 1); + + return ret; +-- +2.51.0 + + +From c59673659b207ba134af6ede988607ee22aa3f57 Mon Sep 17 00:00:00 2001 +From: David Regan +Date: Thu, 22 May 2025 10:25:17 -0700 +Subject: [PATCH 025/517] mtd: nand: brcmnand: fix NAND timeout when accessing + eMMC + +When booting a board to NAND and accessing NAND while eMMC +transactions are occurring the NAND will sometimes timeout. This +is due to both NAND and eMMC controller sharing the same data bus +on BCMBCA chips. Fix is to extend NAND timeout to allow eMMC +transactions time to complete. + +Signed-off-by: David Regan +Reviewed-by: William Zhang +Reviewed-by: Florian Fainelli +Signed-off-by: Miquel Raynal +--- + drivers/mtd/nand/raw/brcmnand/brcmnand.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c +index 3bea54fe5a73..7593b88f7c99 100644 +--- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c ++++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c +@@ -101,7 +101,7 @@ struct brcm_nand_dma_desc { + #define BRCMNAND_MIN_DEVSIZE (4ULL * 1024 * 1024) + + #define NAND_CTRL_RDY (INTFC_CTLR_READY | INTFC_FLASH_READY) +-#define NAND_POLL_STATUS_TIMEOUT_MS 100 ++#define NAND_POLL_STATUS_TIMEOUT_MS 500 + + #define EDU_CMD_WRITE 0x00 + #define EDU_CMD_READ 0x01 +-- +2.51.0 + + +From bdbbf888ee66c9275304629c89a7f57d977d1074 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= +Date: Wed, 21 May 2025 10:03:25 +0200 +Subject: [PATCH 026/517] mtd: rawnand: brcmnand: legacy exec_op implementation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Commit 3c8260ce7663 ("mtd: rawnand: brcmnand: exec_op implementation") +removed legacy interface functions, breaking < v5.0 controllers support. +In order to fix older controllers we need to add an alternative exec_op +implementation which doesn't rely on low level registers. + +Fixes: 3c8260ce7663 ("mtd: rawnand: brcmnand: exec_op implementation") +Signed-off-by: Ãlvaro Fernández Rojas +Reviewed-by: David Regan +Reviewed-by: Florian Fainelli +Reviewed-by: William Zhang +Signed-off-by: Miquel Raynal +--- + drivers/mtd/nand/raw/brcmnand/brcmnand.c | 222 ++++++++++++++++++++++- + 1 file changed, 215 insertions(+), 7 deletions(-) + +diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c +index 7593b88f7c99..59568c430315 100644 +--- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c ++++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c +@@ -65,6 +65,7 @@ module_param(wp_on, int, 0444); + #define CMD_PARAMETER_READ 0x0e + #define CMD_PARAMETER_CHANGE_COL 0x0f + #define CMD_LOW_LEVEL_OP 0x10 ++#define CMD_NOT_SUPPORTED 0xff + + struct brcm_nand_dma_desc { + u32 next_desc; +@@ -199,6 +200,30 @@ static const u16 flash_dma_regs_v4[] = { + [FLASH_DMA_CURRENT_DESC_EXT] = 0x34, + }; + ++/* Native command conversion for legacy controllers (< v5.0) */ ++static const u8 native_cmd_conv[] = { ++ [NAND_CMD_READ0] = CMD_NOT_SUPPORTED, ++ [NAND_CMD_READ1] = CMD_NOT_SUPPORTED, ++ [NAND_CMD_RNDOUT] = CMD_PARAMETER_CHANGE_COL, ++ [NAND_CMD_PAGEPROG] = CMD_NOT_SUPPORTED, ++ [NAND_CMD_READOOB] = CMD_NOT_SUPPORTED, ++ [NAND_CMD_ERASE1] = CMD_BLOCK_ERASE, ++ [NAND_CMD_STATUS] = CMD_NOT_SUPPORTED, ++ [NAND_CMD_SEQIN] = CMD_NOT_SUPPORTED, ++ [NAND_CMD_RNDIN] = CMD_NOT_SUPPORTED, ++ [NAND_CMD_READID] = CMD_DEVICE_ID_READ, ++ [NAND_CMD_ERASE2] = CMD_NULL, ++ [NAND_CMD_PARAM] = CMD_PARAMETER_READ, ++ [NAND_CMD_GET_FEATURES] = CMD_NOT_SUPPORTED, ++ [NAND_CMD_SET_FEATURES] = CMD_NOT_SUPPORTED, ++ [NAND_CMD_RESET] = CMD_NOT_SUPPORTED, ++ [NAND_CMD_READSTART] = CMD_NOT_SUPPORTED, ++ [NAND_CMD_READCACHESEQ] = CMD_NOT_SUPPORTED, ++ [NAND_CMD_READCACHEEND] = CMD_NOT_SUPPORTED, ++ [NAND_CMD_RNDOUTSTART] = CMD_NULL, ++ [NAND_CMD_CACHEDPROG] = CMD_NOT_SUPPORTED, ++}; ++ + /* Controller feature flags */ + enum { + BRCMNAND_HAS_1K_SECTORS = BIT(0), +@@ -237,6 +262,12 @@ struct brcmnand_controller { + /* List of NAND hosts (one for each chip-select) */ + struct list_head host_list; + ++ /* Functions to be called from exec_op */ ++ int (*check_instr)(struct nand_chip *chip, ++ const struct nand_operation *op); ++ int (*exec_instr)(struct nand_chip *chip, ++ const struct nand_operation *op); ++ + /* EDU info, per-transaction */ + const u16 *edu_offsets; + void __iomem *edu_base; +@@ -2478,18 +2509,190 @@ static int brcmnand_op_is_reset(const struct nand_operation *op) + return 0; + } + ++static int brcmnand_check_instructions(struct nand_chip *chip, ++ const struct nand_operation *op) ++{ ++ return 0; ++} ++ ++static int brcmnand_exec_instructions(struct nand_chip *chip, ++ const struct nand_operation *op) ++{ ++ struct brcmnand_host *host = nand_get_controller_data(chip); ++ unsigned int i; ++ int ret = 0; ++ ++ for (i = 0; i < op->ninstrs; i++) { ++ ret = brcmnand_exec_instr(host, i, op); ++ if (ret) ++ break; ++ } ++ ++ return ret; ++} ++ ++static int brcmnand_check_instructions_legacy(struct nand_chip *chip, ++ const struct nand_operation *op) ++{ ++ const struct nand_op_instr *instr; ++ unsigned int i; ++ u8 cmd; ++ ++ for (i = 0; i < op->ninstrs; i++) { ++ instr = &op->instrs[i]; ++ ++ switch (instr->type) { ++ case NAND_OP_CMD_INSTR: ++ cmd = native_cmd_conv[instr->ctx.cmd.opcode]; ++ if (cmd == CMD_NOT_SUPPORTED) ++ return -EOPNOTSUPP; ++ break; ++ case NAND_OP_ADDR_INSTR: ++ case NAND_OP_DATA_IN_INSTR: ++ case NAND_OP_WAITRDY_INSTR: ++ break; ++ default: ++ return -EOPNOTSUPP; ++ } ++ } ++ ++ return 0; ++} ++ ++static int brcmnand_exec_instructions_legacy(struct nand_chip *chip, ++ const struct nand_operation *op) ++{ ++ struct mtd_info *mtd = nand_to_mtd(chip); ++ struct brcmnand_host *host = nand_get_controller_data(chip); ++ struct brcmnand_controller *ctrl = host->ctrl; ++ const struct nand_op_instr *instr; ++ unsigned int i, j; ++ u8 cmd = CMD_NULL, last_cmd = CMD_NULL; ++ int ret = 0; ++ u64 last_addr; ++ ++ for (i = 0; i < op->ninstrs; i++) { ++ instr = &op->instrs[i]; ++ ++ if (instr->type == NAND_OP_CMD_INSTR) { ++ cmd = native_cmd_conv[instr->ctx.cmd.opcode]; ++ if (cmd == CMD_NOT_SUPPORTED) { ++ dev_err(ctrl->dev, "unsupported cmd=%d\n", ++ instr->ctx.cmd.opcode); ++ ret = -EOPNOTSUPP; ++ break; ++ } ++ } else if (instr->type == NAND_OP_ADDR_INSTR) { ++ u64 addr = 0; ++ ++ if (cmd == CMD_NULL) ++ continue; ++ ++ if (instr->ctx.addr.naddrs > 8) { ++ dev_err(ctrl->dev, "unsupported naddrs=%u\n", ++ instr->ctx.addr.naddrs); ++ ret = -EOPNOTSUPP; ++ break; ++ } ++ ++ for (j = 0; j < instr->ctx.addr.naddrs; j++) ++ addr |= (instr->ctx.addr.addrs[j]) << (j << 3); ++ ++ if (cmd == CMD_BLOCK_ERASE) ++ addr <<= chip->page_shift; ++ else if (cmd == CMD_PARAMETER_CHANGE_COL) ++ addr &= ~((u64)(FC_BYTES - 1)); ++ ++ brcmnand_set_cmd_addr(mtd, addr); ++ brcmnand_send_cmd(host, cmd); ++ last_addr = addr; ++ last_cmd = cmd; ++ cmd = CMD_NULL; ++ brcmnand_waitfunc(chip); ++ ++ if (last_cmd == CMD_PARAMETER_READ || ++ last_cmd == CMD_PARAMETER_CHANGE_COL) { ++ /* Copy flash cache word-wise */ ++ u32 *flash_cache = (u32 *)ctrl->flash_cache; ++ ++ brcmnand_soc_data_bus_prepare(ctrl->soc, true); ++ ++ /* ++ * Must cache the FLASH_CACHE now, since changes in ++ * SECTOR_SIZE_1K may invalidate it ++ */ ++ for (j = 0; j < FC_WORDS; j++) ++ /* ++ * Flash cache is big endian for parameter pages, at ++ * least on STB SoCs ++ */ ++ flash_cache[j] = be32_to_cpu(brcmnand_read_fc(ctrl, j)); ++ ++ brcmnand_soc_data_bus_unprepare(ctrl->soc, true); ++ } ++ } else if (instr->type == NAND_OP_DATA_IN_INSTR) { ++ u8 *in = instr->ctx.data.buf.in; ++ ++ if (last_cmd == CMD_DEVICE_ID_READ) { ++ u32 val; ++ ++ if (instr->ctx.data.len > 8) { ++ dev_err(ctrl->dev, "unsupported len=%u\n", ++ instr->ctx.data.len); ++ ret = -EOPNOTSUPP; ++ break; ++ } ++ ++ for (j = 0; j < instr->ctx.data.len; j++) { ++ if (j == 0) ++ val = brcmnand_read_reg(ctrl, BRCMNAND_ID); ++ else if (j == 4) ++ val = brcmnand_read_reg(ctrl, BRCMNAND_ID_EXT); ++ ++ in[j] = (val >> (24 - ((j % 4) << 3))) & 0xff; ++ } ++ } else if (last_cmd == CMD_PARAMETER_READ || ++ last_cmd == CMD_PARAMETER_CHANGE_COL) { ++ u64 addr; ++ u32 offs; ++ ++ for (j = 0; j < instr->ctx.data.len; j++) { ++ addr = last_addr + j; ++ offs = addr & (FC_BYTES - 1); ++ ++ if (j > 0 && offs == 0) ++ nand_change_read_column_op(chip, addr, NULL, 0, ++ false); ++ ++ in[j] = ctrl->flash_cache[offs]; ++ } ++ } ++ } else if (instr->type == NAND_OP_WAITRDY_INSTR) { ++ ret = bcmnand_ctrl_poll_status(host, NAND_CTRL_RDY, NAND_CTRL_RDY, 0); ++ if (ret) ++ break; ++ } else { ++ dev_err(ctrl->dev, "unsupported instruction type: %d\n", instr->type); ++ ret = -EOPNOTSUPP; ++ break; ++ } ++ } ++ ++ return ret; ++} ++ + static int brcmnand_exec_op(struct nand_chip *chip, + const struct nand_operation *op, + bool check_only) + { + struct brcmnand_host *host = nand_get_controller_data(chip); ++ struct brcmnand_controller *ctrl = host->ctrl; + struct mtd_info *mtd = nand_to_mtd(chip); + u8 *status; +- unsigned int i; + int ret = 0; + + if (check_only) +- return 0; ++ return ctrl->check_instr(chip, op); + + if (brcmnand_op_is_status(op)) { + status = op->instrs[1].ctx.data.buf.in; +@@ -2513,11 +2716,7 @@ static int brcmnand_exec_op(struct nand_chip *chip, + if (op->deassert_wp) + brcmnand_wp(mtd, 0); + +- for (i = 0; i < op->ninstrs; i++) { +- ret = brcmnand_exec_instr(host, i, op); +- if (ret) +- break; +- } ++ ret = ctrl->exec_instr(chip, op); + + if (op->deassert_wp) + brcmnand_wp(mtd, 1); +@@ -3130,6 +3329,15 @@ int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc) + if (ret) + goto err; + ++ /* Only v5.0+ controllers have low level ops support */ ++ if (ctrl->nand_version >= 0x0500) { ++ ctrl->check_instr = brcmnand_check_instructions; ++ ctrl->exec_instr = brcmnand_exec_instructions; ++ } else { ++ ctrl->check_instr = brcmnand_check_instructions_legacy; ++ ctrl->exec_instr = brcmnand_exec_instructions_legacy; ++ } ++ + /* + * Most chips have this cache at a fixed offset within 'nand' block. + * Some must specify this region separately. +-- +2.51.0 + + +From 498ecabf18426e22786a167b9f59652ff36cdb26 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Thu, 3 Oct 2024 00:11:41 +0200 +Subject: [PATCH 027/517] block: add support for defining read-only partitions + +Add support for defining read-only partitions and complete support for +it in the cmdline partition parser as the additional "ro" after a +partition is scanned but never actually applied. + +Signed-off-by: Christian Marangi +Reviewed-by: Christoph Hellwig +Link: https://lore.kernel.org/r/20241002221306.4403-2-ansuelsmth@gmail.com +Signed-off-by: Jens Axboe +--- + block/blk.h | 1 + + block/partitions/cmdline.c | 3 +++ + block/partitions/core.c | 3 +++ + 3 files changed, 7 insertions(+) + +diff --git a/block/blk.h b/block/blk.h +index e91012247ff2..a8ac9c6dbb85 100644 +--- a/block/blk.h ++++ b/block/blk.h +@@ -556,6 +556,7 @@ void blk_free_ext_minor(unsigned int minor); + #define ADDPART_FLAG_NONE 0 + #define ADDPART_FLAG_RAID 1 + #define ADDPART_FLAG_WHOLEDISK 2 ++#define ADDPART_FLAG_READONLY 4 + int bdev_add_partition(struct gendisk *disk, int partno, sector_t start, + sector_t length); + int bdev_del_partition(struct gendisk *disk, int partno); +diff --git a/block/partitions/cmdline.c b/block/partitions/cmdline.c +index 152c85df92b2..da3e719d8e51 100644 +--- a/block/partitions/cmdline.c ++++ b/block/partitions/cmdline.c +@@ -237,6 +237,9 @@ static int add_part(int slot, struct cmdline_subpart *subpart, + put_partition(state, slot, subpart->from >> 9, + subpart->size >> 9); + ++ if (subpart->flags & PF_RDONLY) ++ state->parts[slot].flags |= ADDPART_FLAG_READONLY; ++ + info = &state->parts[slot].info; + + strscpy(info->volname, subpart->name, sizeof(info->volname)); +diff --git a/block/partitions/core.c b/block/partitions/core.c +index 5bd7a603092e..629ed08b9ab9 100644 +--- a/block/partitions/core.c ++++ b/block/partitions/core.c +@@ -373,6 +373,9 @@ static struct block_device *add_partition(struct gendisk *disk, int partno, + goto out_del; + } + ++ if (flags & ADDPART_FLAG_READONLY) ++ bdev_set_flag(bdev, BD_READ_ONLY); ++ + /* everything is up and running, commence */ + err = xa_insert(&disk->part_tbl, partno, bdev, GFP_KERNEL); + if (err) +-- +2.51.0 + + +From b9b466eecefdedee1240f5f182b4083a0cd8627b Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Thu, 3 Oct 2024 00:11:43 +0200 +Subject: [PATCH 028/517] block: introduce add_disk_fwnode() + +Introduce add_disk_fwnode() as a replacement of device_add_disk() that +permits to pass and attach a fwnode to disk dev. + +This variant can be useful for eMMC that might have the partition table +for the disk defined in DT. A parser can later make use of the attached +fwnode to parse the related table and init the hardcoded partition for +the disk. + +device_add_disk() is converted to a simple wrapper of add_disk_fwnode() +with the fwnode entry set as NULL. + +Signed-off-by: Christian Marangi +Reviewed-by: Christoph Hellwig +Link: https://lore.kernel.org/r/20241002221306.4403-4-ansuelsmth@gmail.com +Signed-off-by: Jens Axboe +--- + block/genhd.c | 28 ++++++++++++++++++++++++---- + include/linux/blkdev.h | 3 +++ + 2 files changed, 27 insertions(+), 4 deletions(-) + +diff --git a/block/genhd.c b/block/genhd.c +index 99344f53c789..342a92f1391e 100644 +--- a/block/genhd.c ++++ b/block/genhd.c +@@ -383,16 +383,18 @@ int disk_scan_partitions(struct gendisk *disk, blk_mode_t mode) + } + + /** +- * device_add_disk - add disk information to kernel list ++ * add_disk_fwnode - add disk information to kernel list with fwnode + * @parent: parent device for the disk + * @disk: per-device partitioning information + * @groups: Additional per-device sysfs groups ++ * @fwnode: attached disk fwnode + * + * This function registers the partitioning information in @disk +- * with the kernel. ++ * with the kernel. Also attach a fwnode to the disk device. + */ +-int __must_check device_add_disk(struct device *parent, struct gendisk *disk, +- const struct attribute_group **groups) ++int __must_check add_disk_fwnode(struct device *parent, struct gendisk *disk, ++ const struct attribute_group **groups, ++ struct fwnode_handle *fwnode) + + { + struct device *ddev = disk_to_dev(disk); +@@ -452,6 +454,8 @@ int __must_check device_add_disk(struct device *parent, struct gendisk *disk, + ddev->parent = parent; + ddev->groups = groups; + dev_set_name(ddev, "%s", disk->disk_name); ++ if (fwnode) ++ device_set_node(ddev, fwnode); + if (!(disk->flags & GENHD_FL_HIDDEN)) + ddev->devt = MKDEV(disk->major, disk->first_minor); + ret = device_add(ddev); +@@ -553,6 +557,22 @@ int __must_check device_add_disk(struct device *parent, struct gendisk *disk, + elevator_exit(disk->queue); + return ret; + } ++EXPORT_SYMBOL_GPL(add_disk_fwnode); ++ ++/** ++ * device_add_disk - add disk information to kernel list ++ * @parent: parent device for the disk ++ * @disk: per-device partitioning information ++ * @groups: Additional per-device sysfs groups ++ * ++ * This function registers the partitioning information in @disk ++ * with the kernel. ++ */ ++int __must_check device_add_disk(struct device *parent, struct gendisk *disk, ++ const struct attribute_group **groups) ++{ ++ return add_disk_fwnode(parent, disk, groups, NULL); ++} + EXPORT_SYMBOL(device_add_disk); + + static void blk_report_disk_dead(struct gendisk *disk, bool surprise) +diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h +index cd9c97f6f948..fa9d324b7069 100644 +--- a/include/linux/blkdev.h ++++ b/include/linux/blkdev.h +@@ -789,6 +789,9 @@ static inline unsigned int blk_queue_depth(struct request_queue *q) + #define for_each_bio(_bio) \ + for (; _bio; _bio = _bio->bi_next) + ++int __must_check add_disk_fwnode(struct device *parent, struct gendisk *disk, ++ const struct attribute_group **groups, ++ struct fwnode_handle *fwnode); + int __must_check device_add_disk(struct device *parent, struct gendisk *disk, + const struct attribute_group **groups); + static inline int __must_check add_disk(struct gendisk *disk) +-- +2.51.0 + + +From 3272770722c2740510bba41e7d07d4ccda7b7439 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Thu, 3 Oct 2024 00:11:44 +0200 +Subject: [PATCH 029/517] mmc: block: attach partitions fwnode if found in + mmc-card + +Attach partitions fwnode if found in mmc-card and register disk with it. + +This permits block partition to reference the node and register a +partition table defined in DT for the special case for embedded device +that doesn't have a partition table flashed but have an hardcoded +partition table passed from the system. + +JEDEC BOOT partition boot0/boot1 are supported but in DT we refer with +the JEDEC name of boot1 and boot2 to better adhere to documentation. + +Also JEDEC GP partition gp0/1/2/3 are supported but in DT we refer with +the JEDEC name of gp1/2/3/4 to better adhere to documentration. + +Signed-off-by: Christian Marangi +Reviewed-by: Linus Walleij +Link: https://lore.kernel.org/r/20241002221306.4403-5-ansuelsmth@gmail.com +Signed-off-by: Jens Axboe +--- + drivers/mmc/core/block.c | 55 +++++++++++++++++++++++++++++++++++++++- + 1 file changed, 54 insertions(+), 1 deletion(-) + +diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c +index 08b8276e1da9..28882b75ba26 100644 +--- a/drivers/mmc/core/block.c ++++ b/drivers/mmc/core/block.c +@@ -2517,6 +2517,56 @@ static inline int mmc_blk_readonly(struct mmc_card *card) + !(card->csd.cmdclass & CCC_BLOCK_WRITE); + } + ++/* ++ * Search for a declared partitions node for the disk in mmc-card related node. ++ * ++ * This is to permit support for partition table defined in DT in special case ++ * where a partition table is not written in the disk and is expected to be ++ * passed from the running system. ++ * ++ * For the user disk, "partitions" node is searched. ++ * For the special HW disk, "partitions-" node with the appended name is used ++ * following this conversion table (to adhere to JEDEC naming) ++ * - boot0 -> partitions-boot1 ++ * - boot1 -> partitions-boot2 ++ * - gp0 -> partitions-gp1 ++ * - gp1 -> partitions-gp2 ++ * - gp2 -> partitions-gp3 ++ * - gp3 -> partitions-gp4 ++ */ ++static struct fwnode_handle *mmc_blk_get_partitions_node(struct device *mmc_dev, ++ const char *subname) ++{ ++ const char *node_name = "partitions"; ++ ++ if (subname) { ++ mmc_dev = mmc_dev->parent; ++ ++ /* ++ * Check if we are allocating a BOOT disk boot0/1 disk. ++ * In DT we use the JEDEC naming boot1/2. ++ */ ++ if (!strcmp(subname, "boot0")) ++ node_name = "partitions-boot1"; ++ if (!strcmp(subname, "boot1")) ++ node_name = "partitions-boot2"; ++ /* ++ * Check if we are allocating a GP disk gp0/1/2/3 disk. ++ * In DT we use the JEDEC naming gp1/2/3/4. ++ */ ++ if (!strcmp(subname, "gp0")) ++ node_name = "partitions-gp1"; ++ if (!strcmp(subname, "gp1")) ++ node_name = "partitions-gp2"; ++ if (!strcmp(subname, "gp2")) ++ node_name = "partitions-gp3"; ++ if (!strcmp(subname, "gp3")) ++ node_name = "partitions-gp4"; ++ } ++ ++ return device_get_named_child_node(mmc_dev, node_name); ++} ++ + static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, + struct device *parent, + sector_t size, +@@ -2525,6 +2575,7 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, + int area_type, + unsigned int part_type) + { ++ struct fwnode_handle *disk_fwnode; + struct mmc_blk_data *md; + int devidx, ret; + char cap_str[10]; +@@ -2626,7 +2677,9 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, + /* used in ->open, must be set before add_disk: */ + if (area_type == MMC_BLK_DATA_AREA_MAIN) + dev_set_drvdata(&card->dev, md); +- ret = device_add_disk(md->parent, md->disk, mmc_disk_attr_groups); ++ disk_fwnode = mmc_blk_get_partitions_node(parent, subname); ++ ret = add_disk_fwnode(md->parent, md->disk, mmc_disk_attr_groups, ++ disk_fwnode); + if (ret) + goto err_put_disk; + return md; +-- +2.51.0 + + +From 230f71eab625c48464071341ff4c0170831bce2c Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Thu, 3 Oct 2024 00:11:45 +0200 +Subject: [PATCH 030/517] block: add support for partition table defined in OF + +Add support for partition table defined in Device Tree. Similar to how +it's done with MTD, add support for defining a fixed partition table in +device tree. + +A common scenario for this is fixed block (eMMC) embedded devices that +have no MBR or GPT partition table to save storage space. Bootloader +access the block device with absolute address of data. + +This is to complete the functionality with an equivalent implementation +with providing partition table with bootargs, for case where the booargs +can't be modified and tweaking the Device Tree is the only solution to +have an usabe partition table. + +The implementation follow the fixed-partitions parser used on MTD +devices where a "partitions" node is expected to be declared with +"fixed-partitions" compatible in the OF node of the disk device +(mmc-card for eMMC for example) and each child node declare a label +and a reg with offset and size. If label is not declared, the node name +is used as fallback. Eventually is also possible to declare the read-only +property to flag the partition as read-only. + +Signed-off-by: Christian Marangi +Reviewed-by: Christoph Hellwig +Link: https://lore.kernel.org/r/20241002221306.4403-6-ansuelsmth@gmail.com +Signed-off-by: Jens Axboe +--- + block/partitions/Kconfig | 9 ++++ + block/partitions/Makefile | 1 + + block/partitions/check.h | 1 + + block/partitions/core.c | 3 ++ + block/partitions/of.c | 110 ++++++++++++++++++++++++++++++++++++++ + 5 files changed, 124 insertions(+) + create mode 100644 block/partitions/of.c + +diff --git a/block/partitions/Kconfig b/block/partitions/Kconfig +index 7aff4eb81c60..ce17e41451af 100644 +--- a/block/partitions/Kconfig ++++ b/block/partitions/Kconfig +@@ -270,4 +270,13 @@ config CMDLINE_PARTITION + Say Y here if you want to read the partition table from bootargs. + The format for the command line is just like mtdparts. + ++config OF_PARTITION ++ bool "Device Tree partition support" if PARTITION_ADVANCED ++ depends on OF ++ help ++ Say Y here if you want to enable support for partition table ++ defined in Device Tree. (mainly for eMMC) ++ The format for the device tree node is just like MTD fixed-partition ++ schema. ++ + endmenu +diff --git a/block/partitions/Makefile b/block/partitions/Makefile +index a7f05cdb02a8..25d424922c6e 100644 +--- a/block/partitions/Makefile ++++ b/block/partitions/Makefile +@@ -12,6 +12,7 @@ obj-$(CONFIG_CMDLINE_PARTITION) += cmdline.o + obj-$(CONFIG_MAC_PARTITION) += mac.o + obj-$(CONFIG_LDM_PARTITION) += ldm.o + obj-$(CONFIG_MSDOS_PARTITION) += msdos.o ++obj-$(CONFIG_OF_PARTITION) += of.o + obj-$(CONFIG_OSF_PARTITION) += osf.o + obj-$(CONFIG_SGI_PARTITION) += sgi.o + obj-$(CONFIG_SUN_PARTITION) += sun.o +diff --git a/block/partitions/check.h b/block/partitions/check.h +index 8d70a880c372..e5c1c61eb353 100644 +--- a/block/partitions/check.h ++++ b/block/partitions/check.h +@@ -62,6 +62,7 @@ int karma_partition(struct parsed_partitions *state); + int ldm_partition(struct parsed_partitions *state); + int mac_partition(struct parsed_partitions *state); + int msdos_partition(struct parsed_partitions *state); ++int of_partition(struct parsed_partitions *state); + int osf_partition(struct parsed_partitions *state); + int sgi_partition(struct parsed_partitions *state); + int sun_partition(struct parsed_partitions *state); +diff --git a/block/partitions/core.c b/block/partitions/core.c +index 629ed08b9ab9..cdad05f97647 100644 +--- a/block/partitions/core.c ++++ b/block/partitions/core.c +@@ -43,6 +43,9 @@ static int (*const check_part[])(struct parsed_partitions *) = { + #ifdef CONFIG_CMDLINE_PARTITION + cmdline_partition, + #endif ++#ifdef CONFIG_OF_PARTITION ++ of_partition, /* cmdline have priority to OF */ ++#endif + #ifdef CONFIG_EFI_PARTITION + efi_partition, /* this must come before msdos */ + #endif +diff --git a/block/partitions/of.c b/block/partitions/of.c +new file mode 100644 +index 000000000000..4e760fdffb3f +--- /dev/null ++++ b/block/partitions/of.c +@@ -0,0 +1,110 @@ ++// SPDX-License-Identifier: GPL-2.0 ++ ++#include ++#include ++#include ++#include ++#include "check.h" ++ ++static int validate_of_partition(struct device_node *np, int slot) ++{ ++ u64 offset, size; ++ int len; ++ ++ const __be32 *reg = of_get_property(np, "reg", &len); ++ int a_cells = of_n_addr_cells(np); ++ int s_cells = of_n_size_cells(np); ++ ++ /* Make sure reg len match the expected addr and size cells */ ++ if (len / sizeof(*reg) != a_cells + s_cells) ++ return -EINVAL; ++ ++ /* Validate offset conversion from bytes to sectors */ ++ offset = of_read_number(reg, a_cells); ++ if (offset % SECTOR_SIZE) ++ return -EINVAL; ++ ++ /* Validate size conversion from bytes to sectors */ ++ size = of_read_number(reg + a_cells, s_cells); ++ if (!size || size % SECTOR_SIZE) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static void add_of_partition(struct parsed_partitions *state, int slot, ++ struct device_node *np) ++{ ++ struct partition_meta_info *info; ++ char tmp[sizeof(info->volname) + 4]; ++ const char *partname; ++ int len; ++ ++ const __be32 *reg = of_get_property(np, "reg", &len); ++ int a_cells = of_n_addr_cells(np); ++ int s_cells = of_n_size_cells(np); ++ ++ /* Convert bytes to sector size */ ++ u64 offset = of_read_number(reg, a_cells) / SECTOR_SIZE; ++ u64 size = of_read_number(reg + a_cells, s_cells) / SECTOR_SIZE; ++ ++ put_partition(state, slot, offset, size); ++ ++ if (of_property_read_bool(np, "read-only")) ++ state->parts[slot].flags |= ADDPART_FLAG_READONLY; ++ ++ /* ++ * Follow MTD label logic, search for label property, ++ * fallback to node name if not found. ++ */ ++ info = &state->parts[slot].info; ++ partname = of_get_property(np, "label", &len); ++ if (!partname) ++ partname = of_get_property(np, "name", &len); ++ strscpy(info->volname, partname, sizeof(info->volname)); ++ ++ snprintf(tmp, sizeof(tmp), "(%s)", info->volname); ++ strlcat(state->pp_buf, tmp, PAGE_SIZE); ++} ++ ++int of_partition(struct parsed_partitions *state) ++{ ++ struct device *ddev = disk_to_dev(state->disk); ++ struct device_node *np; ++ int slot; ++ ++ struct device_node *partitions_np = of_node_get(ddev->of_node); ++ ++ if (!partitions_np || ++ !of_device_is_compatible(partitions_np, "fixed-partitions")) ++ return 0; ++ ++ slot = 1; ++ /* Validate parition offset and size */ ++ for_each_child_of_node(partitions_np, np) { ++ if (validate_of_partition(np, slot)) { ++ of_node_put(np); ++ of_node_put(partitions_np); ++ ++ return -1; ++ } ++ ++ slot++; ++ } ++ ++ slot = 1; ++ for_each_child_of_node(partitions_np, np) { ++ if (slot >= state->limit) { ++ of_node_put(np); ++ break; ++ } ++ ++ add_of_partition(state, slot, np); ++ ++ slot++; ++ } ++ ++ strlcat(state->pp_buf, "\n", PAGE_SIZE); ++ ++ return 1; ++} +-- +2.51.0 + + +From 564834bbaef7bec34bc5c34c25ad2f5a509c23f9 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Fri, 8 Nov 2024 16:01:44 +0000 +Subject: [PATCH 031/517] net: phylink: move manual flow control setting + +Move the handling of manual flow control configuration to a common +location during resolve. We currently evaluate this for all but +fixed links. + +Signed-off-by: Russell King (Oracle) +Link: https://patch.msgid.link/E1t9RQe-002Feh-T1@rmk-PC.armlinux.org.uk +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/phylink.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c +index b78dfcbec936..8fc59aba1ded 100644 +--- a/drivers/net/phy/phylink.c ++++ b/drivers/net/phy/phylink.c +@@ -1484,7 +1484,6 @@ static void phylink_resolve(struct work_struct *w) + switch (pl->cur_link_an_mode) { + case MLO_AN_PHY: + link_state = pl->phy_state; +- phylink_apply_manual_flow(pl, &link_state); + mac_config = link_state.link; + break; + +@@ -1545,11 +1544,13 @@ static void phylink_resolve(struct work_struct *w) + link_state.pause = pl->phy_state.pause; + mac_config = true; + } +- phylink_apply_manual_flow(pl, &link_state); + break; + } + } + ++ if (pl->cur_link_an_mode != MLO_AN_FIXED) ++ phylink_apply_manual_flow(pl, &link_state); ++ + if (mac_config) { + if (link_state.interface != pl->link_config.interface) { + /* The interface has changed, force the link down and +-- +2.51.0 + + +From b2650f725996177178c95ba69b7d2fe5edd85eca Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Fri, 8 Nov 2024 16:01:50 +0000 +Subject: [PATCH 032/517] net: phylink: move MLO_AN_FIXED resolve handling to + if() statement + +The switch() statement doesn't sit very well with the preceeding if() +statements, and results in excessive indentation that spoils code +readability. Begin cleaning this up by converting the MLO_AN_FIXED case +to an if() statement. + +Signed-off-by: Russell King (Oracle) +Link: https://patch.msgid.link/E1t9RQk-002Fen-1A@rmk-PC.armlinux.org.uk +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/phylink.c | 8 +++----- + 1 file changed, 3 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c +index 8fc59aba1ded..f1d97db70f58 100644 +--- a/drivers/net/phy/phylink.c ++++ b/drivers/net/phy/phylink.c +@@ -1480,6 +1480,9 @@ static void phylink_resolve(struct work_struct *w) + } else if (pl->link_failed) { + link_state.link = false; + retrigger = true; ++ } else if (pl->cur_link_an_mode == MLO_AN_FIXED) { ++ phylink_get_fixed_state(pl, &link_state); ++ mac_config = link_state.link; + } else { + switch (pl->cur_link_an_mode) { + case MLO_AN_PHY: +@@ -1487,11 +1490,6 @@ static void phylink_resolve(struct work_struct *w) + mac_config = link_state.link; + break; + +- case MLO_AN_FIXED: +- phylink_get_fixed_state(pl, &link_state); +- mac_config = link_state.link; +- break; +- + case MLO_AN_INBAND: + phylink_mac_pcs_get_state(pl, &link_state); + +-- +2.51.0 + + +From 3740814469f6222bdbaa014e71911970fb45223f Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Fri, 8 Nov 2024 16:01:55 +0000 +Subject: [PATCH 033/517] net: phylink: move MLO_AN_PHY resolve handling to + if() statement + +The switch() statement doesn't sit very well with the preceeding if() +statements, and results in excessive indentation that spoils code +readability. Continue cleaning this up by converting the MLO_AN_PHY +case to use an if() statmeent. + +Signed-off-by: Russell King (Oracle) +Link: https://patch.msgid.link/E1t9RQp-002Fet-5W@rmk-PC.armlinux.org.uk +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/phylink.c | 8 +++----- + 1 file changed, 3 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c +index f1d97db70f58..1169ffb30a31 100644 +--- a/drivers/net/phy/phylink.c ++++ b/drivers/net/phy/phylink.c +@@ -1483,13 +1483,11 @@ static void phylink_resolve(struct work_struct *w) + } else if (pl->cur_link_an_mode == MLO_AN_FIXED) { + phylink_get_fixed_state(pl, &link_state); + mac_config = link_state.link; ++ } else if (pl->cur_link_an_mode == MLO_AN_PHY) { ++ link_state = pl->phy_state; ++ mac_config = link_state.link; + } else { + switch (pl->cur_link_an_mode) { +- case MLO_AN_PHY: +- link_state = pl->phy_state; +- mac_config = link_state.link; +- break; +- + case MLO_AN_INBAND: + phylink_mac_pcs_get_state(pl, &link_state); + +-- +2.51.0 + + +From 001a54bc68e2061d58af85a76f1cb9d2908c0031 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Fri, 8 Nov 2024 16:02:00 +0000 +Subject: [PATCH 034/517] net: phylink: remove switch() statement in resolve + handling + +The switch() statement doesn't sit very well with the preceeding if() +statements, so let's just convert everything to if()s. As a result of +the two preceding commits, there is now only one case in the switch() +statement. Remove the switch statement and reduce the code indentation. +Code reformatting will be in the following commit. + +Signed-off-by: Russell King (Oracle) +Link: https://patch.msgid.link/E1t9RQu-002Fez-AA@rmk-PC.armlinux.org.uk +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/phylink.c | 94 +++++++++++++++++++-------------------- + 1 file changed, 45 insertions(+), 49 deletions(-) + +diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c +index 1169ffb30a31..cee1f1aa11a1 100644 +--- a/drivers/net/phy/phylink.c ++++ b/drivers/net/phy/phylink.c +@@ -1487,60 +1487,56 @@ static void phylink_resolve(struct work_struct *w) + link_state = pl->phy_state; + mac_config = link_state.link; + } else { +- switch (pl->cur_link_an_mode) { +- case MLO_AN_INBAND: +- phylink_mac_pcs_get_state(pl, &link_state); +- +- /* The PCS may have a latching link-fail indicator. +- * If the link was up, bring the link down and +- * re-trigger the resolve. Otherwise, re-read the +- * PCS state to get the current status of the link. ++ phylink_mac_pcs_get_state(pl, &link_state); ++ ++ /* The PCS may have a latching link-fail indicator. ++ * If the link was up, bring the link down and ++ * re-trigger the resolve. Otherwise, re-read the ++ * PCS state to get the current status of the link. ++ */ ++ if (!link_state.link) { ++ if (cur_link_state) ++ retrigger = true; ++ else ++ phylink_mac_pcs_get_state(pl, ++ &link_state); ++ } ++ ++ /* If we have a phy, the "up" state is the union of ++ * both the PHY and the MAC ++ */ ++ if (pl->phydev) ++ link_state.link &= pl->phy_state.link; ++ ++ /* Only update if the PHY link is up */ ++ if (pl->phydev && pl->phy_state.link) { ++ /* If the interface has changed, force a ++ * link down event if the link isn't already ++ * down, and re-resolve. + */ +- if (!link_state.link) { +- if (cur_link_state) +- retrigger = true; +- else +- phylink_mac_pcs_get_state(pl, +- &link_state); ++ if (link_state.interface != ++ pl->phy_state.interface) { ++ retrigger = true; ++ link_state.link = false; + } ++ link_state.interface = pl->phy_state.interface; + +- /* If we have a phy, the "up" state is the union of +- * both the PHY and the MAC ++ /* If we are doing rate matching, then the ++ * link speed/duplex comes from the PHY + */ +- if (pl->phydev) +- link_state.link &= pl->phy_state.link; +- +- /* Only update if the PHY link is up */ +- if (pl->phydev && pl->phy_state.link) { +- /* If the interface has changed, force a +- * link down event if the link isn't already +- * down, and re-resolve. +- */ +- if (link_state.interface != +- pl->phy_state.interface) { +- retrigger = true; +- link_state.link = false; +- } +- link_state.interface = pl->phy_state.interface; +- +- /* If we are doing rate matching, then the +- * link speed/duplex comes from the PHY +- */ +- if (pl->phy_state.rate_matching) { +- link_state.rate_matching = +- pl->phy_state.rate_matching; +- link_state.speed = pl->phy_state.speed; +- link_state.duplex = +- pl->phy_state.duplex; +- } +- +- /* If we have a PHY, we need to update with +- * the PHY flow control bits. +- */ +- link_state.pause = pl->phy_state.pause; +- mac_config = true; ++ if (pl->phy_state.rate_matching) { ++ link_state.rate_matching = ++ pl->phy_state.rate_matching; ++ link_state.speed = pl->phy_state.speed; ++ link_state.duplex = ++ pl->phy_state.duplex; + } +- break; ++ ++ /* If we have a PHY, we need to update with ++ * the PHY flow control bits. ++ */ ++ link_state.pause = pl->phy_state.pause; ++ mac_config = true; + } + } + +-- +2.51.0 + + +From 921cbed2099d406e77b90ae879b77b716398851f Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Fri, 8 Nov 2024 16:02:05 +0000 +Subject: [PATCH 035/517] net: phylink: clean up phylink_resolve() + +Now that we have reduced the indentation level, clean up the code +formatting. + +Signed-off-by: Russell King (Oracle) +Link: https://patch.msgid.link/E1t9RQz-002Ff5-EA@rmk-PC.armlinux.org.uk +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/phylink.c | 35 ++++++++++++++++------------------- + 1 file changed, 16 insertions(+), 19 deletions(-) + +diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c +index cee1f1aa11a1..e4fc28820bd5 100644 +--- a/drivers/net/phy/phylink.c ++++ b/drivers/net/phy/phylink.c +@@ -1489,51 +1489,48 @@ static void phylink_resolve(struct work_struct *w) + } else { + phylink_mac_pcs_get_state(pl, &link_state); + +- /* The PCS may have a latching link-fail indicator. +- * If the link was up, bring the link down and +- * re-trigger the resolve. Otherwise, re-read the +- * PCS state to get the current status of the link. ++ /* The PCS may have a latching link-fail indicator. If the link ++ * was up, bring the link down and re-trigger the resolve. ++ * Otherwise, re-read the PCS state to get the current status ++ * of the link. + */ + if (!link_state.link) { + if (cur_link_state) + retrigger = true; + else +- phylink_mac_pcs_get_state(pl, +- &link_state); ++ phylink_mac_pcs_get_state(pl, &link_state); + } + +- /* If we have a phy, the "up" state is the union of +- * both the PHY and the MAC ++ /* If we have a phy, the "up" state is the union of both the ++ * PHY and the MAC + */ + if (pl->phydev) + link_state.link &= pl->phy_state.link; + + /* Only update if the PHY link is up */ + if (pl->phydev && pl->phy_state.link) { +- /* If the interface has changed, force a +- * link down event if the link isn't already +- * down, and re-resolve. ++ /* If the interface has changed, force a link down ++ * event if the link isn't already down, and re-resolve. + */ +- if (link_state.interface != +- pl->phy_state.interface) { ++ if (link_state.interface != pl->phy_state.interface) { + retrigger = true; + link_state.link = false; + } ++ + link_state.interface = pl->phy_state.interface; + +- /* If we are doing rate matching, then the +- * link speed/duplex comes from the PHY ++ /* If we are doing rate matching, then the link ++ * speed/duplex comes from the PHY + */ + if (pl->phy_state.rate_matching) { + link_state.rate_matching = + pl->phy_state.rate_matching; + link_state.speed = pl->phy_state.speed; +- link_state.duplex = +- pl->phy_state.duplex; ++ link_state.duplex = pl->phy_state.duplex; + } + +- /* If we have a PHY, we need to update with +- * the PHY flow control bits. ++ /* If we have a PHY, we need to update with the PHY ++ * flow control bits. + */ + link_state.pause = pl->phy_state.pause; + mac_config = true; +-- +2.51.0 + + +From 7d2cfc89b6392219e11a8f9d30313f5177a84611 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Tue, 3 Dec 2024 15:30:47 +0000 +Subject: [PATCH 036/517] net: phylink: pass phylink and pcs into + phylink_pcs_neg_mode() + +Move the call to phylink_pcs_neg_mode() in phylink_major_config() after +we have selected the appropriate PCS to allow the PCS to be passed in. + +Add struct phylink and struct phylink_pcs pointers to +phylink_pcs_neg_mode() and pass in the appropriate structures. Set +pl->pcs_neg_mode before returning, and remove the return value. + +This will allow the capabilities of the PCS and any PHY to be used when +deciding which pcs_neg_mode should be used. + +Reviewed-by: Andrew Lunn +Signed-off-by: Russell King (Oracle) +Link: https://patch.msgid.link/E1tIUrP-006ITh-6u@rmk-PC.armlinux.org.uk +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/phylink.c | 26 +++++++++++++------------- + 1 file changed, 13 insertions(+), 13 deletions(-) + +diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c +index e4fc28820bd5..ae7e529c70e2 100644 +--- a/drivers/net/phy/phylink.c ++++ b/drivers/net/phy/phylink.c +@@ -1102,7 +1102,8 @@ static void phylink_pcs_an_restart(struct phylink *pl) + + /** + * phylink_pcs_neg_mode() - helper to determine PCS inband mode +- * @mode: one of %MLO_AN_FIXED, %MLO_AN_PHY, %MLO_AN_INBAND. ++ * @pl: a pointer to a &struct phylink returned from phylink_create() ++ * @pcs: a pointer to &struct phylink_pcs + * @interface: interface mode to be used + * @advertising: adertisement ethtool link mode mask + * +@@ -1119,11 +1120,13 @@ static void phylink_pcs_an_restart(struct phylink *pl) + * Note: this is for cases where the PCS itself is involved in negotiation + * (e.g. Clause 37, SGMII and similar) not Clause 73. + */ +-static unsigned int phylink_pcs_neg_mode(unsigned int mode, +- phy_interface_t interface, +- const unsigned long *advertising) ++static void phylink_pcs_neg_mode(struct phylink *pl, struct phylink_pcs *pcs, ++ phy_interface_t interface, ++ const unsigned long *advertising) + { +- unsigned int neg_mode; ++ unsigned int neg_mode, mode; ++ ++ mode = pl->cur_link_an_mode; + + switch (interface) { + case PHY_INTERFACE_MODE_SGMII: +@@ -1164,7 +1167,7 @@ static unsigned int phylink_pcs_neg_mode(unsigned int mode, + break; + } + +- return neg_mode; ++ pl->pcs_neg_mode = neg_mode; + } + + static void phylink_major_config(struct phylink *pl, bool restart, +@@ -1178,10 +1181,6 @@ static void phylink_major_config(struct phylink *pl, bool restart, + + phylink_dbg(pl, "major config %s\n", phy_modes(state->interface)); + +- pl->pcs_neg_mode = phylink_pcs_neg_mode(pl->cur_link_an_mode, +- state->interface, +- state->advertising); +- + if (pl->using_mac_select_pcs) { + pcs = pl->mac_ops->mac_select_pcs(pl->config, state->interface); + if (IS_ERR(pcs)) { +@@ -1194,6 +1193,8 @@ static void phylink_major_config(struct phylink *pl, bool restart, + pcs_changed = pcs && pl->pcs != pcs; + } + ++ phylink_pcs_neg_mode(pl, pcs, state->interface, state->advertising); ++ + phylink_pcs_poll_stop(pl); + + if (pl->mac_ops->mac_prepare) { +@@ -1284,9 +1285,8 @@ static int phylink_change_inband_advert(struct phylink *pl) + pl->link_config.pause); + + /* Recompute the PCS neg mode */ +- pl->pcs_neg_mode = phylink_pcs_neg_mode(pl->cur_link_an_mode, +- pl->link_config.interface, +- pl->link_config.advertising); ++ phylink_pcs_neg_mode(pl, pl->pcs, pl->link_config.interface, ++ pl->link_config.advertising); + + neg_mode = pl->cur_link_an_mode; + if (pl->pcs->neg_mode) +-- +2.51.0 + + +From fa2a79a5315cad8983a76f23e445621b9d34cd2c Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Tue, 3 Dec 2024 15:30:52 +0000 +Subject: [PATCH 037/517] net: phylink: split cur_link_an_mode into requested + and active + +There is an interdependence between the current link_an_mode and +pcs_neg_mode that some drivers rely upon to know whether inband or PHY +mode will be used. + +In order to support detection of PCS and PHY inband capabilities +resulting in automatic selection of inband or PHY mode, we need to +cater for this, and support changing the MAC link_an_mode. However, we +end up with an inter-dependency between the current link_an_mode and +pcs_neg_mode. + +To solve this, split the current link_an_mode into the requested +link_an_mode and active link_an_mode. The requested link_an_mode will +always be passed to phylink_pcs_neg_mode(), and the active link_an_mode +will be used for everything else, and only updated during +phylink_major_config(). This will ensure that phylink_pcs_neg_mode()'s +link_an_mode will not depend on the active link_an_mode that will, +in a future patch, depend on pcs_neg_mode. + +Reviewed-by: Andrew Lunn +Signed-off-by: Russell King (Oracle) +Link: https://patch.msgid.link/E1tIUrU-006ITn-Ai@rmk-PC.armlinux.org.uk +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/phylink.c | 60 ++++++++++++++++++++------------------- + 1 file changed, 31 insertions(+), 29 deletions(-) + +diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c +index ae7e529c70e2..5290afd0f54e 100644 +--- a/drivers/net/phy/phylink.c ++++ b/drivers/net/phy/phylink.c +@@ -56,7 +56,8 @@ struct phylink { + struct phy_device *phydev; + phy_interface_t link_interface; /* PHY_INTERFACE_xxx */ + u8 cfg_link_an_mode; /* MLO_AN_xxx */ +- u8 cur_link_an_mode; ++ u8 req_link_an_mode; /* Requested MLO_AN_xxx mode */ ++ u8 act_link_an_mode; /* Active MLO_AN_xxx mode */ + u8 link_port; /* The current non-phy ethtool port */ + __ETHTOOL_DECLARE_LINK_MODE_MASK(supported); + +@@ -1082,13 +1083,13 @@ static void phylink_mac_config(struct phylink *pl, + + phylink_dbg(pl, + "%s: mode=%s/%s/%s adv=%*pb pause=%02x\n", +- __func__, phylink_an_mode_str(pl->cur_link_an_mode), ++ __func__, phylink_an_mode_str(pl->act_link_an_mode), + phy_modes(st.interface), + phy_rate_matching_to_str(st.rate_matching), + __ETHTOOL_LINK_MODE_MASK_NBITS, st.advertising, + st.pause); + +- pl->mac_ops->mac_config(pl->config, pl->cur_link_an_mode, &st); ++ pl->mac_ops->mac_config(pl->config, pl->act_link_an_mode, &st); + } + + static void phylink_pcs_an_restart(struct phylink *pl) +@@ -1096,7 +1097,7 @@ static void phylink_pcs_an_restart(struct phylink *pl) + if (pl->pcs && linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, + pl->link_config.advertising) && + phy_interface_mode_is_8023z(pl->link_config.interface) && +- phylink_autoneg_inband(pl->cur_link_an_mode)) ++ phylink_autoneg_inband(pl->act_link_an_mode)) + pl->pcs->ops->pcs_an_restart(pl->pcs); + } + +@@ -1126,7 +1127,7 @@ static void phylink_pcs_neg_mode(struct phylink *pl, struct phylink_pcs *pcs, + { + unsigned int neg_mode, mode; + +- mode = pl->cur_link_an_mode; ++ mode = pl->req_link_an_mode; + + switch (interface) { + case PHY_INTERFACE_MODE_SGMII: +@@ -1168,6 +1169,7 @@ static void phylink_pcs_neg_mode(struct phylink *pl, struct phylink_pcs *pcs, + } + + pl->pcs_neg_mode = neg_mode; ++ pl->act_link_an_mode = mode; + } + + static void phylink_major_config(struct phylink *pl, bool restart, +@@ -1198,7 +1200,7 @@ static void phylink_major_config(struct phylink *pl, bool restart, + phylink_pcs_poll_stop(pl); + + if (pl->mac_ops->mac_prepare) { +- err = pl->mac_ops->mac_prepare(pl->config, pl->cur_link_an_mode, ++ err = pl->mac_ops->mac_prepare(pl->config, pl->act_link_an_mode, + state->interface); + if (err < 0) { + phylink_err(pl, "mac_prepare failed: %pe\n", +@@ -1232,7 +1234,7 @@ static void phylink_major_config(struct phylink *pl, bool restart, + if (pl->pcs_state == PCS_STATE_STARTING || pcs_changed) + phylink_pcs_enable(pl->pcs); + +- neg_mode = pl->cur_link_an_mode; ++ neg_mode = pl->act_link_an_mode; + if (pl->pcs && pl->pcs->neg_mode) + neg_mode = pl->pcs_neg_mode; + +@@ -1248,7 +1250,7 @@ static void phylink_major_config(struct phylink *pl, bool restart, + phylink_pcs_an_restart(pl); + + if (pl->mac_ops->mac_finish) { +- err = pl->mac_ops->mac_finish(pl->config, pl->cur_link_an_mode, ++ err = pl->mac_ops->mac_finish(pl->config, pl->act_link_an_mode, + state->interface); + if (err < 0) + phylink_err(pl, "mac_finish failed: %pe\n", +@@ -1279,7 +1281,7 @@ static int phylink_change_inband_advert(struct phylink *pl) + return 0; + + phylink_dbg(pl, "%s: mode=%s/%s adv=%*pb pause=%02x\n", __func__, +- phylink_an_mode_str(pl->cur_link_an_mode), ++ phylink_an_mode_str(pl->req_link_an_mode), + phy_modes(pl->link_config.interface), + __ETHTOOL_LINK_MODE_MASK_NBITS, pl->link_config.advertising, + pl->link_config.pause); +@@ -1288,7 +1290,7 @@ static int phylink_change_inband_advert(struct phylink *pl) + phylink_pcs_neg_mode(pl, pl->pcs, pl->link_config.interface, + pl->link_config.advertising); + +- neg_mode = pl->cur_link_an_mode; ++ neg_mode = pl->act_link_an_mode; + if (pl->pcs->neg_mode) + neg_mode = pl->pcs_neg_mode; + +@@ -1353,7 +1355,7 @@ static void phylink_mac_initial_config(struct phylink *pl, bool force_restart) + { + struct phylink_link_state link_state; + +- switch (pl->cur_link_an_mode) { ++ switch (pl->req_link_an_mode) { + case MLO_AN_PHY: + link_state = pl->phy_state; + break; +@@ -1427,14 +1429,14 @@ static void phylink_link_up(struct phylink *pl, + + pl->cur_interface = link_state.interface; + +- neg_mode = pl->cur_link_an_mode; ++ neg_mode = pl->act_link_an_mode; + if (pl->pcs && pl->pcs->neg_mode) + neg_mode = pl->pcs_neg_mode; + + phylink_pcs_link_up(pl->pcs, neg_mode, pl->cur_interface, speed, + duplex); + +- pl->mac_ops->mac_link_up(pl->config, pl->phydev, pl->cur_link_an_mode, ++ pl->mac_ops->mac_link_up(pl->config, pl->phydev, pl->act_link_an_mode, + pl->cur_interface, speed, duplex, + !!(link_state.pause & MLO_PAUSE_TX), rx_pause); + +@@ -1454,7 +1456,7 @@ static void phylink_link_down(struct phylink *pl) + + if (ndev) + netif_carrier_off(ndev); +- pl->mac_ops->mac_link_down(pl->config, pl->cur_link_an_mode, ++ pl->mac_ops->mac_link_down(pl->config, pl->act_link_an_mode, + pl->cur_interface); + phylink_info(pl, "Link is Down\n"); + } +@@ -1480,10 +1482,10 @@ static void phylink_resolve(struct work_struct *w) + } else if (pl->link_failed) { + link_state.link = false; + retrigger = true; +- } else if (pl->cur_link_an_mode == MLO_AN_FIXED) { ++ } else if (pl->act_link_an_mode == MLO_AN_FIXED) { + phylink_get_fixed_state(pl, &link_state); + mac_config = link_state.link; +- } else if (pl->cur_link_an_mode == MLO_AN_PHY) { ++ } else if (pl->act_link_an_mode == MLO_AN_PHY) { + link_state = pl->phy_state; + mac_config = link_state.link; + } else { +@@ -1537,7 +1539,7 @@ static void phylink_resolve(struct work_struct *w) + } + } + +- if (pl->cur_link_an_mode != MLO_AN_FIXED) ++ if (pl->act_link_an_mode != MLO_AN_FIXED) + phylink_apply_manual_flow(pl, &link_state); + + if (mac_config) { +@@ -1661,7 +1663,7 @@ int phylink_set_fixed_link(struct phylink *pl, + pl->link_config.an_complete = 1; + + pl->cfg_link_an_mode = MLO_AN_FIXED; +- pl->cur_link_an_mode = pl->cfg_link_an_mode; ++ pl->req_link_an_mode = pl->cfg_link_an_mode; + + return 0; + } +@@ -1756,7 +1758,7 @@ struct phylink *phylink_create(struct phylink_config *config, + } + } + +- pl->cur_link_an_mode = pl->cfg_link_an_mode; ++ pl->req_link_an_mode = pl->cfg_link_an_mode; + + ret = phylink_register_sfp(pl, fwnode); + if (ret < 0) { +@@ -2213,7 +2215,7 @@ void phylink_start(struct phylink *pl) + ASSERT_RTNL(); + + phylink_info(pl, "configuring for %s/%s link mode\n", +- phylink_an_mode_str(pl->cur_link_an_mode), ++ phylink_an_mode_str(pl->req_link_an_mode), + phy_modes(pl->link_config.interface)); + + /* Always set the carrier off */ +@@ -2472,7 +2474,7 @@ int phylink_ethtool_ksettings_get(struct phylink *pl, + + linkmode_copy(kset->link_modes.supported, pl->supported); + +- switch (pl->cur_link_an_mode) { ++ switch (pl->act_link_an_mode) { + case MLO_AN_FIXED: + /* We are using fixed settings. Report these as the + * current link settings - and note that these also +@@ -2564,7 +2566,7 @@ int phylink_ethtool_ksettings_set(struct phylink *pl, + /* If we have a fixed link, refuse to change link parameters. + * If the link parameters match, accept them but do nothing. + */ +- if (pl->cur_link_an_mode == MLO_AN_FIXED) { ++ if (pl->req_link_an_mode == MLO_AN_FIXED) { + if (s->speed != pl->link_config.speed || + s->duplex != pl->link_config.duplex) + return -EINVAL; +@@ -2580,7 +2582,7 @@ int phylink_ethtool_ksettings_set(struct phylink *pl, + * is our default case) but do not allow the advertisement to + * be changed. If the advertisement matches, simply return. + */ +- if (pl->cur_link_an_mode == MLO_AN_FIXED) { ++ if (pl->req_link_an_mode == MLO_AN_FIXED) { + if (!linkmode_equal(config.advertising, + pl->link_config.advertising)) + return -EINVAL; +@@ -2620,7 +2622,7 @@ int phylink_ethtool_ksettings_set(struct phylink *pl, + linkmode_copy(support, pl->supported); + if (phylink_validate(pl, support, &config)) { + phylink_err(pl, "validation of %s/%s with support %*pb failed\n", +- phylink_an_mode_str(pl->cur_link_an_mode), ++ phylink_an_mode_str(pl->req_link_an_mode), + phy_modes(config.interface), + __ETHTOOL_LINK_MODE_MASK_NBITS, support); + return -EINVAL; +@@ -2720,7 +2722,7 @@ int phylink_ethtool_set_pauseparam(struct phylink *pl, + + ASSERT_RTNL(); + +- if (pl->cur_link_an_mode == MLO_AN_FIXED) ++ if (pl->req_link_an_mode == MLO_AN_FIXED) + return -EOPNOTSUPP; + + if (!phylink_test(pl->supported, Pause) && +@@ -2984,7 +2986,7 @@ static int phylink_mii_read(struct phylink *pl, unsigned int phy_id, + struct phylink_link_state state; + int val = 0xffff; + +- switch (pl->cur_link_an_mode) { ++ switch (pl->act_link_an_mode) { + case MLO_AN_FIXED: + if (phy_id == 0) { + phylink_get_fixed_state(pl, &state); +@@ -3009,7 +3011,7 @@ static int phylink_mii_read(struct phylink *pl, unsigned int phy_id, + static int phylink_mii_write(struct phylink *pl, unsigned int phy_id, + unsigned int reg, unsigned int val) + { +- switch (pl->cur_link_an_mode) { ++ switch (pl->act_link_an_mode) { + case MLO_AN_FIXED: + break; + +@@ -3199,9 +3201,9 @@ static void phylink_sfp_set_config(struct phylink *pl, u8 mode, + changed = true; + } + +- if (pl->cur_link_an_mode != mode || ++ if (pl->req_link_an_mode != mode || + pl->link_config.interface != state->interface) { +- pl->cur_link_an_mode = mode; ++ pl->req_link_an_mode = mode; + pl->link_config.interface = state->interface; + + changed = true; +-- +2.51.0 + + +From 015e4e7cba0f05b10e53d1ce833f5dc67d2db231 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Tue, 3 Dec 2024 15:30:57 +0000 +Subject: [PATCH 038/517] net: phylink: add debug for phylink_major_config() + +Now that we have a more complexity in phylink_major_config(), augment +the debugging so we can see what's going on there. + +Reviewed-by: Andrew Lunn +Signed-off-by: Russell King (Oracle) +Link: https://patch.msgid.link/E1tIUrZ-006ITt-Fa@rmk-PC.armlinux.org.uk +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/phylink.c | 27 ++++++++++++++++++++++++++- + 1 file changed, 26 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c +index 5290afd0f54e..aa89c1f4706e 100644 +--- a/drivers/net/phy/phylink.c ++++ b/drivers/net/phy/phylink.c +@@ -176,6 +176,24 @@ static const char *phylink_an_mode_str(unsigned int mode) + return mode < ARRAY_SIZE(modestr) ? modestr[mode] : "unknown"; + } + ++static const char *phylink_pcs_mode_str(unsigned int mode) ++{ ++ if (!mode) ++ return "none"; ++ ++ if (mode & PHYLINK_PCS_NEG_OUTBAND) ++ return "outband"; ++ ++ if (mode & PHYLINK_PCS_NEG_INBAND) { ++ if (mode & PHYLINK_PCS_NEG_ENABLED) ++ return "inband,an-enabled"; ++ else ++ return "inband,an-disabled"; ++ } ++ ++ return "unknown"; ++} ++ + static unsigned int phylink_interface_signal_rate(phy_interface_t interface) + { + switch (interface) { +@@ -1181,7 +1199,9 @@ static void phylink_major_config(struct phylink *pl, bool restart, + unsigned int neg_mode; + int err; + +- phylink_dbg(pl, "major config %s\n", phy_modes(state->interface)); ++ phylink_dbg(pl, "major config, requested %s/%s\n", ++ phylink_an_mode_str(pl->req_link_an_mode), ++ phy_modes(state->interface)); + + if (pl->using_mac_select_pcs) { + pcs = pl->mac_ops->mac_select_pcs(pl->config, state->interface); +@@ -1197,6 +1217,11 @@ static void phylink_major_config(struct phylink *pl, bool restart, + + phylink_pcs_neg_mode(pl, pcs, state->interface, state->advertising); + ++ phylink_dbg(pl, "major config, active %s/%s/%s\n", ++ phylink_an_mode_str(pl->act_link_an_mode), ++ phylink_pcs_mode_str(pl->pcs_neg_mode), ++ phy_modes(state->interface)); ++ + phylink_pcs_poll_stop(pl); + + if (pl->mac_ops->mac_prepare) { +-- +2.51.0 + + +From 6d67fd0b655cd00cc2da9f15e01e6a26d8ec9f8e Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Tue, 3 Dec 2024 15:31:02 +0000 +Subject: [PATCH 039/517] net: phy: add phy_inband_caps() + +Add a method to query the PHY's in-band capabilities for a PHY +interface mode. + +Where the interface mode does not have in-band capability, or the PHY +driver has not been updated to return this information, then +phy_inband_caps() should return zero. Otherwise, PHY drivers will +return a value consisting of the following flags: + +LINK_INBAND_DISABLE indicates that the hardware does not support +in-band signalling, or can have in-band signalling configured via +software to be disabled. + +LINK_INBAND_ENABLE indicates that the hardware will use in-band +signalling, or can have in-band signalling configured via software +to be enabled. + +LINK_INBAND_BYPASS indicates that the hardware has the ability to +bypass in-band signalling when enabled after a timeout if the link +partner does not respond to its in-band signalling. + +This reports the PHY capabilities for the particular interface mode, +not the current configuration. + +Reviewed-by: Andrew Lunn +Signed-off-by: Russell King (Oracle) +Link: https://patch.msgid.link/E1tIUre-006ITz-KF@rmk-PC.armlinux.org.uk +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/phy.c | 21 +++++++++++++++++++++ + include/linux/phy.h | 28 ++++++++++++++++++++++++++++ + 2 files changed, 49 insertions(+) + +diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c +index c9cfdc33fc5f..8d91922d3bb9 100644 +--- a/drivers/net/phy/phy.c ++++ b/drivers/net/phy/phy.c +@@ -1048,6 +1048,27 @@ static int phy_check_link_status(struct phy_device *phydev) + return 0; + } + ++/** ++ * phy_inband_caps - query which in-band signalling modes are supported ++ * @phydev: a pointer to a &struct phy_device ++ * @interface: the interface mode for the PHY ++ * ++ * Returns zero if it is unknown what in-band signalling is supported by the ++ * PHY (e.g. because the PHY driver doesn't implement the method.) Otherwise, ++ * returns a bit mask of the LINK_INBAND_* values from ++ * &enum link_inband_signalling to describe which inband modes are supported ++ * by the PHY for this interface mode. ++ */ ++unsigned int phy_inband_caps(struct phy_device *phydev, ++ phy_interface_t interface) ++{ ++ if (phydev->drv && phydev->drv->inband_caps) ++ return phydev->drv->inband_caps(phydev, interface); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(phy_inband_caps); ++ + /** + * _phy_start_aneg - start auto-negotiation for this PHY device + * @phydev: the phy_device struct +diff --git a/include/linux/phy.h b/include/linux/phy.h +index dfc7b97f9648..fee0fad7538d 100644 +--- a/include/linux/phy.h ++++ b/include/linux/phy.h +@@ -815,6 +815,24 @@ struct phy_tdr_config { + }; + #define PHY_PAIR_ALL -1 + ++/** ++ * enum link_inband_signalling - in-band signalling modes that are supported ++ * ++ * @LINK_INBAND_DISABLE: in-band signalling can be disabled ++ * @LINK_INBAND_ENABLE: in-band signalling can be enabled without bypass ++ * @LINK_INBAND_BYPASS: in-band signalling can be enabled with bypass ++ * ++ * The possible and required bits can only be used if the valid bit is set. ++ * If possible is clear, that means inband signalling can not be used. ++ * Required is only valid when possible is set, and means that inband ++ * signalling must be used. ++ */ ++enum link_inband_signalling { ++ LINK_INBAND_DISABLE = BIT(0), ++ LINK_INBAND_ENABLE = BIT(1), ++ LINK_INBAND_BYPASS = BIT(2), ++}; ++ + /** + * struct phy_plca_cfg - Configuration of the PLCA (Physical Layer Collision + * Avoidance) Reconciliation Sublayer. +@@ -953,6 +971,14 @@ struct phy_driver { + */ + int (*get_features)(struct phy_device *phydev); + ++ /** ++ * @inband_caps: query whether in-band is supported for the given PHY ++ * interface mode. Returns a bitmask of bits defined by enum ++ * link_inband_signalling. ++ */ ++ unsigned int (*inband_caps)(struct phy_device *phydev, ++ phy_interface_t interface); ++ + /** + * @get_rate_matching: Get the supported type of rate matching for a + * particular phy interface. This is used by phy consumers to determine +@@ -1832,6 +1858,8 @@ int phy_config_aneg(struct phy_device *phydev); + int _phy_start_aneg(struct phy_device *phydev); + int phy_start_aneg(struct phy_device *phydev); + int phy_aneg_done(struct phy_device *phydev); ++unsigned int phy_inband_caps(struct phy_device *phydev, ++ phy_interface_t interface); + int phy_speed_down(struct phy_device *phydev, bool sync); + int phy_speed_up(struct phy_device *phydev); + bool phy_check_valid(int speed, int duplex, unsigned long *features); +-- +2.51.0 + + +From 8c321641d38995ad5b4412960e323283add4ecac Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Tue, 3 Dec 2024 15:31:07 +0000 +Subject: [PATCH 040/517] net: phy: bcm84881: implement phy_inband_caps() + method + +BCM84881 has no support for inband signalling, so this is a trivial +implementation that returns no support for inband. + +Reviewed-by: Andrew Lunn +Signed-off-by: Russell King (Oracle) +Acked-by: Florian Fainelli +Link: https://patch.msgid.link/E1tIUrj-006IU6-ON@rmk-PC.armlinux.org.uk +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/bcm84881.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/drivers/net/phy/bcm84881.c b/drivers/net/phy/bcm84881.c +index 97da3aee4942..47405bded677 100644 +--- a/drivers/net/phy/bcm84881.c ++++ b/drivers/net/phy/bcm84881.c +@@ -235,11 +235,21 @@ static int bcm84881_read_status(struct phy_device *phydev) + return genphy_c45_read_mdix(phydev); + } + ++/* The Broadcom BCM84881 in the Methode DM7052 is unable to provide a SGMII ++ * or 802.3z control word, so inband will not work. ++ */ ++static unsigned int bcm84881_inband_caps(struct phy_device *phydev, ++ phy_interface_t interface) ++{ ++ return LINK_INBAND_DISABLE; ++} ++ + static struct phy_driver bcm84881_drivers[] = { + { + .phy_id = 0xae025150, + .phy_id_mask = 0xfffffff0, + .name = "Broadcom BCM84881", ++ .inband_caps = bcm84881_inband_caps, + .config_init = bcm84881_config_init, + .probe = bcm84881_probe, + .get_features = bcm84881_get_features, +-- +2.51.0 + + +From d51b2838d0daaf2ca36abb4dd616b7ba170a2992 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Tue, 3 Dec 2024 15:31:12 +0000 +Subject: [PATCH 041/517] net: phy: marvell: implement phy_inband_caps() method + +Provide an implementation for phy_inband_caps() for Marvell PHYs used +on SFP modules, so that phylink knows the PHYs capabilities. + +Reviewed-by: Andrew Lunn +Signed-off-by: Russell King (Oracle) +Link: https://patch.msgid.link/E1tIUro-006IUC-Rq@rmk-PC.armlinux.org.uk +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/marvell.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c +index 9964bf3dea2f..53f6711df93b 100644 +--- a/drivers/net/phy/marvell.c ++++ b/drivers/net/phy/marvell.c +@@ -716,6 +716,20 @@ static int marvell_config_aneg_fiber(struct phy_device *phydev) + return genphy_check_and_restart_aneg(phydev, changed); + } + ++static unsigned int m88e1111_inband_caps(struct phy_device *phydev, ++ phy_interface_t interface) ++{ ++ /* In 1000base-X and SGMII modes, the inband mode can be changed ++ * through the Fibre page BMCR ANENABLE bit. ++ */ ++ if (interface == PHY_INTERFACE_MODE_1000BASEX || ++ interface == PHY_INTERFACE_MODE_SGMII) ++ return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE | ++ LINK_INBAND_BYPASS; ++ ++ return 0; ++} ++ + static int m88e1111_config_aneg(struct phy_device *phydev) + { + int extsr = phy_read(phydev, MII_M1111_PHY_EXT_SR); +@@ -3667,6 +3681,7 @@ static struct phy_driver marvell_drivers[] = { + .name = "Marvell 88E1112", + /* PHY_GBIT_FEATURES */ + .probe = marvell_probe, ++ .inband_caps = m88e1111_inband_caps, + .config_init = m88e1112_config_init, + .config_aneg = marvell_config_aneg, + .config_intr = marvell_config_intr, +@@ -3688,6 +3703,7 @@ static struct phy_driver marvell_drivers[] = { + /* PHY_GBIT_FEATURES */ + .flags = PHY_POLL_CABLE_TEST, + .probe = marvell_probe, ++ .inband_caps = m88e1111_inband_caps, + .config_init = m88e1111gbe_config_init, + .config_aneg = m88e1111_config_aneg, + .read_status = marvell_read_status, +@@ -3711,6 +3727,7 @@ static struct phy_driver marvell_drivers[] = { + .name = "Marvell 88E1111 (Finisar)", + /* PHY_GBIT_FEATURES */ + .probe = marvell_probe, ++ .inband_caps = m88e1111_inband_caps, + .config_init = m88e1111gbe_config_init, + .config_aneg = m88e1111_config_aneg, + .read_status = marvell_read_status, +-- +2.51.0 + + +From 3f3d8f3025892a86b501b3b2247438dc6d23f3bd Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Tue, 3 Dec 2024 15:31:18 +0000 +Subject: [PATCH 042/517] net: phy: add phy_config_inband() + +Add a method to configure the PHY's in-band mode. + +Reviewed-by: Andrew Lunn +Signed-off-by: Russell King (Oracle) +Link: https://patch.msgid.link/E1tIUru-006IUI-08@rmk-PC.armlinux.org.uk +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/phy.c | 32 ++++++++++++++++++++++++++++++++ + include/linux/phy.h | 6 ++++++ + 2 files changed, 38 insertions(+) + +diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c +index 8d91922d3bb9..1ab58bb5e6db 100644 +--- a/drivers/net/phy/phy.c ++++ b/drivers/net/phy/phy.c +@@ -1069,6 +1069,38 @@ unsigned int phy_inband_caps(struct phy_device *phydev, + } + EXPORT_SYMBOL_GPL(phy_inband_caps); + ++/** ++ * phy_config_inband - configure the desired PHY in-band mode ++ * @phydev: the phy_device struct ++ * @modes: in-band modes to configure ++ * ++ * Description: disables, enables or enables-with-bypass in-band signalling ++ * between the PHY and host system. ++ * ++ * Returns: zero on success, or negative errno value. ++ */ ++int phy_config_inband(struct phy_device *phydev, unsigned int modes) ++{ ++ int err; ++ ++ if (!!(modes & LINK_INBAND_DISABLE) + ++ !!(modes & LINK_INBAND_ENABLE) + ++ !!(modes & LINK_INBAND_BYPASS) != 1) ++ return -EINVAL; ++ ++ mutex_lock(&phydev->lock); ++ if (!phydev->drv) ++ err = -EIO; ++ else if (!phydev->drv->config_inband) ++ err = -EOPNOTSUPP; ++ else ++ err = phydev->drv->config_inband(phydev, modes); ++ mutex_unlock(&phydev->lock); ++ ++ return err; ++} ++EXPORT_SYMBOL(phy_config_inband); ++ + /** + * _phy_start_aneg - start auto-negotiation for this PHY device + * @phydev: the phy_device struct +diff --git a/include/linux/phy.h b/include/linux/phy.h +index fee0fad7538d..81c504d9850e 100644 +--- a/include/linux/phy.h ++++ b/include/linux/phy.h +@@ -979,6 +979,11 @@ struct phy_driver { + unsigned int (*inband_caps)(struct phy_device *phydev, + phy_interface_t interface); + ++ /** ++ * @config_inband: configure in-band mode for the PHY ++ */ ++ int (*config_inband)(struct phy_device *phydev, unsigned int modes); ++ + /** + * @get_rate_matching: Get the supported type of rate matching for a + * particular phy interface. This is used by phy consumers to determine +@@ -1860,6 +1865,7 @@ int phy_start_aneg(struct phy_device *phydev); + int phy_aneg_done(struct phy_device *phydev); + unsigned int phy_inband_caps(struct phy_device *phydev, + phy_interface_t interface); ++int phy_config_inband(struct phy_device *phydev, unsigned int modes); + int phy_speed_down(struct phy_device *phydev, bool sync); + int phy_speed_up(struct phy_device *phydev); + bool phy_check_valid(int speed, int duplex, unsigned long *features); +-- +2.51.0 + + +From e46d8359ab3011442c642952753d45c2482a605c Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Tue, 3 Dec 2024 15:31:23 +0000 +Subject: [PATCH 043/517] net: phy: marvell: implement config_inband() method + +Implement the config_inband() method for Marvell 88E1112, 88E1111, +and Finisar's 88E1111 variant. + +Reviewed-by: Andrew Lunn +Signed-off-by: Russell King (Oracle) +Link: https://patch.msgid.link/E1tIUrz-006IUO-3r@rmk-PC.armlinux.org.uk +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/marvell.c | 31 +++++++++++++++++++++++++++++++ + 1 file changed, 31 insertions(+) + +diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c +index 53f6711df93b..b7d2951d979d 100644 +--- a/drivers/net/phy/marvell.c ++++ b/drivers/net/phy/marvell.c +@@ -730,6 +730,34 @@ static unsigned int m88e1111_inband_caps(struct phy_device *phydev, + return 0; + } + ++static int m88e1111_config_inband(struct phy_device *phydev, unsigned int modes) ++{ ++ u16 extsr, bmcr; ++ int err; ++ ++ if (phydev->interface != PHY_INTERFACE_MODE_1000BASEX && ++ phydev->interface != PHY_INTERFACE_MODE_SGMII) ++ return -EINVAL; ++ ++ if (modes == LINK_INBAND_BYPASS) ++ extsr = MII_M1111_HWCFG_SERIAL_AN_BYPASS; ++ else ++ extsr = 0; ++ ++ if (modes == LINK_INBAND_DISABLE) ++ bmcr = 0; ++ else ++ bmcr = BMCR_ANENABLE; ++ ++ err = phy_modify(phydev, MII_M1111_PHY_EXT_SR, ++ MII_M1111_HWCFG_SERIAL_AN_BYPASS, extsr); ++ if (err < 0) ++ return extsr; ++ ++ return phy_modify_paged(phydev, MII_MARVELL_FIBER_PAGE, MII_BMCR, ++ BMCR_ANENABLE, bmcr); ++} ++ + static int m88e1111_config_aneg(struct phy_device *phydev) + { + int extsr = phy_read(phydev, MII_M1111_PHY_EXT_SR); +@@ -3682,6 +3710,7 @@ static struct phy_driver marvell_drivers[] = { + /* PHY_GBIT_FEATURES */ + .probe = marvell_probe, + .inband_caps = m88e1111_inband_caps, ++ .config_inband = m88e1111_config_inband, + .config_init = m88e1112_config_init, + .config_aneg = marvell_config_aneg, + .config_intr = marvell_config_intr, +@@ -3704,6 +3733,7 @@ static struct phy_driver marvell_drivers[] = { + .flags = PHY_POLL_CABLE_TEST, + .probe = marvell_probe, + .inband_caps = m88e1111_inband_caps, ++ .config_inband = m88e1111_config_inband, + .config_init = m88e1111gbe_config_init, + .config_aneg = m88e1111_config_aneg, + .read_status = marvell_read_status, +@@ -3728,6 +3758,7 @@ static struct phy_driver marvell_drivers[] = { + /* PHY_GBIT_FEATURES */ + .probe = marvell_probe, + .inband_caps = m88e1111_inband_caps, ++ .config_inband = m88e1111_config_inband, + .config_init = m88e1111gbe_config_init, + .config_aneg = m88e1111_config_aneg, + .read_status = marvell_read_status, +-- +2.51.0 + + +From 53185318bdfaf4dbfcc0568513e3b3883e30520c Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Tue, 3 Dec 2024 15:31:28 +0000 +Subject: [PATCH 044/517] net: phylink: add pcs_inband_caps() method + +Add a pcs_inband_caps() method to query the PCS for its inband link +capabilities, and use this to determine whether link modes used with +optical SFPs can be supported. + +When a PCS does not provide a method, we allow inband negotiation to +be either on or off, making this a no-op until the pcs_inband_caps() +method is implemented by a PCS driver. + +Reviewed-by: Andrew Lunn +Signed-off-by: Russell King (Oracle) +Link: https://patch.msgid.link/E1tIUs4-006IUU-7K@rmk-PC.armlinux.org.uk +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/phylink.c | 60 +++++++++++++++++++++++++++++++++++++++ + include/linux/phylink.h | 17 +++++++++++ + 2 files changed, 77 insertions(+) + +diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c +index aa89c1f4706e..c358ab5c16a7 100644 +--- a/drivers/net/phy/phylink.c ++++ b/drivers/net/phy/phylink.c +@@ -1007,6 +1007,15 @@ static void phylink_resolve_an_pause(struct phylink_link_state *state) + } + } + ++static unsigned int phylink_pcs_inband_caps(struct phylink_pcs *pcs, ++ phy_interface_t interface) ++{ ++ if (pcs && pcs->ops->pcs_inband_caps) ++ return pcs->ops->pcs_inband_caps(pcs, interface); ++ ++ return 0; ++} ++ + static void phylink_pcs_pre_config(struct phylink_pcs *pcs, + phy_interface_t interface) + { +@@ -1060,6 +1069,24 @@ static void phylink_pcs_link_up(struct phylink_pcs *pcs, unsigned int neg_mode, + pcs->ops->pcs_link_up(pcs, neg_mode, interface, speed, duplex); + } + ++/* Query inband for a specific interface mode, asking the MAC for the ++ * PCS which will be used to handle the interface mode. ++ */ ++static unsigned int phylink_inband_caps(struct phylink *pl, ++ phy_interface_t interface) ++{ ++ struct phylink_pcs *pcs; ++ ++ if (!pl->mac_ops->mac_select_pcs) ++ return 0; ++ ++ pcs = pl->mac_ops->mac_select_pcs(pl->config, interface); ++ if (!pcs) ++ return 0; ++ ++ return phylink_pcs_inband_caps(pcs, interface); ++} ++ + static void phylink_pcs_poll_stop(struct phylink *pl) + { + if (pl->cfg_link_an_mode == MLO_AN_INBAND) +@@ -2530,6 +2557,26 @@ int phylink_ethtool_ksettings_get(struct phylink *pl, + } + EXPORT_SYMBOL_GPL(phylink_ethtool_ksettings_get); + ++static bool phylink_validate_pcs_inband_autoneg(struct phylink *pl, ++ phy_interface_t interface, ++ unsigned long *adv) ++{ ++ unsigned int inband = phylink_inband_caps(pl, interface); ++ unsigned int mask; ++ ++ /* If the PCS doesn't implement inband support, be permissive. */ ++ if (!inband) ++ return true; ++ ++ if (linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, adv)) ++ mask = LINK_INBAND_ENABLE; ++ else ++ mask = LINK_INBAND_DISABLE; ++ ++ /* Check whether the PCS implements the required mode */ ++ return !!(inband & mask); ++} ++ + /** + * phylink_ethtool_ksettings_set() - set the link settings + * @pl: a pointer to a &struct phylink returned from phylink_create() +@@ -2665,6 +2712,13 @@ int phylink_ethtool_ksettings_set(struct phylink *pl, + phylink_is_empty_linkmode(config.advertising)) + return -EINVAL; + ++ /* Validate the autonegotiation state. We don't have a PHY in this ++ * situation, so the PCS is the media-facing entity. ++ */ ++ if (!phylink_validate_pcs_inband_autoneg(pl, config.interface, ++ config.advertising)) ++ return -EINVAL; ++ + mutex_lock(&pl->state_mutex); + pl->link_config.speed = config.speed; + pl->link_config.duplex = config.duplex; +@@ -3349,6 +3403,12 @@ static int phylink_sfp_config_optical(struct phylink *pl) + phylink_dbg(pl, "optical SFP: chosen %s interface\n", + phy_modes(interface)); + ++ if (!phylink_validate_pcs_inband_autoneg(pl, interface, ++ config.advertising)) { ++ phylink_err(pl, "autoneg setting not compatible with PCS"); ++ return -EINVAL; ++ } ++ + config.interface = interface; + + /* Ignore errors if we're expecting a PHY to attach later */ +diff --git a/include/linux/phylink.h b/include/linux/phylink.h +index 5c01048860c4..5462cc6a37dc 100644 +--- a/include/linux/phylink.h ++++ b/include/linux/phylink.h +@@ -419,6 +419,7 @@ struct phylink_pcs { + /** + * struct phylink_pcs_ops - MAC PCS operations structure. + * @pcs_validate: validate the link configuration. ++ * @pcs_inband_caps: query inband support for interface mode. + * @pcs_enable: enable the PCS. + * @pcs_disable: disable the PCS. + * @pcs_pre_config: pre-mac_config method (for errata) +@@ -434,6 +435,8 @@ struct phylink_pcs { + struct phylink_pcs_ops { + int (*pcs_validate)(struct phylink_pcs *pcs, unsigned long *supported, + const struct phylink_link_state *state); ++ unsigned int (*pcs_inband_caps)(struct phylink_pcs *pcs, ++ phy_interface_t interface); + int (*pcs_enable)(struct phylink_pcs *pcs); + void (*pcs_disable)(struct phylink_pcs *pcs); + void (*pcs_pre_config)(struct phylink_pcs *pcs, +@@ -470,6 +473,20 @@ struct phylink_pcs_ops { + int pcs_validate(struct phylink_pcs *pcs, unsigned long *supported, + const struct phylink_link_state *state); + ++/** ++ * pcs_inband_caps - query PCS in-band capabilities for interface mode. ++ * @pcs: a pointer to a &struct phylink_pcs. ++ * @interface: interface mode to be queried ++ * ++ * Returns zero if it is unknown what in-band signalling is supported by the ++ * PHY (e.g. because the PHY driver doesn't implement the method.) Otherwise, ++ * returns a bit mask of the LINK_INBAND_* values from ++ * &enum link_inband_signalling to describe which inband modes are supported ++ * for this interface mode. ++ */ ++unsigned int pcs_inband_caps(struct phylink_pcs *pcs, ++ phy_interface_t interface); ++ + /** + * pcs_enable() - enable the PCS. + * @pcs: a pointer to a &struct phylink_pcs. +-- +2.51.0 + + +From d39d93def7796638ddfe476907564390b4a97191 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Tue, 3 Dec 2024 15:31:33 +0000 +Subject: [PATCH 045/517] net: mvneta: implement pcs_inband_caps() method + +Report the PCS in-band capabilities to phylink for Marvell NETA +interfaces. + +Reviewed-by: Andrew Lunn +Signed-off-by: Russell King (Oracle) +Link: https://patch.msgid.link/E1tIUs9-006IUb-Au@rmk-PC.armlinux.org.uk +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/marvell/mvneta.c | 27 +++++++++++++++++---------- + 1 file changed, 17 insertions(+), 10 deletions(-) + +diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c +index d72b2d5f96db..0a5b93857fb5 100644 +--- a/drivers/net/ethernet/marvell/mvneta.c ++++ b/drivers/net/ethernet/marvell/mvneta.c +@@ -3960,20 +3960,27 @@ static struct mvneta_port *mvneta_pcs_to_port(struct phylink_pcs *pcs) + return container_of(pcs, struct mvneta_port, phylink_pcs); + } + +-static int mvneta_pcs_validate(struct phylink_pcs *pcs, +- unsigned long *supported, +- const struct phylink_link_state *state) ++static unsigned int mvneta_pcs_inband_caps(struct phylink_pcs *pcs, ++ phy_interface_t interface) + { +- /* We only support QSGMII, SGMII, 802.3z and RGMII modes. +- * When in 802.3z mode, we must have AN enabled: ++ /* When operating in an 802.3z mode, we must have AN enabled: + * "Bit 2 Field InBandAnEn In-band Auto-Negotiation enable. ... + * When = 1 (1000BASE-X) this field must be set to 1." ++ * Therefore, inband is "required". + */ +- if (phy_interface_mode_is_8023z(state->interface) && +- !phylink_test(state->advertising, Autoneg)) +- return -EINVAL; ++ if (phy_interface_mode_is_8023z(interface)) ++ return LINK_INBAND_ENABLE; + +- return 0; ++ /* QSGMII, SGMII and RGMII can be configured to use inband ++ * signalling of the AN result. Indicate these as "possible". ++ */ ++ if (interface == PHY_INTERFACE_MODE_SGMII || ++ interface == PHY_INTERFACE_MODE_QSGMII || ++ phy_interface_mode_is_rgmii(interface)) ++ return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE; ++ ++ /* For any other modes, indicate that inband is not supported. */ ++ return LINK_INBAND_DISABLE; + } + + static void mvneta_pcs_get_state(struct phylink_pcs *pcs, +@@ -4071,7 +4078,7 @@ static void mvneta_pcs_an_restart(struct phylink_pcs *pcs) + } + + static const struct phylink_pcs_ops mvneta_phylink_pcs_ops = { +- .pcs_validate = mvneta_pcs_validate, ++ .pcs_inband_caps = mvneta_pcs_inband_caps, + .pcs_get_state = mvneta_pcs_get_state, + .pcs_config = mvneta_pcs_config, + .pcs_an_restart = mvneta_pcs_an_restart, +-- +2.51.0 + + +From a1520f83646272782f463024a858f31623494124 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Tue, 3 Dec 2024 15:31:38 +0000 +Subject: [PATCH 046/517] net: mvpp2: implement pcs_inband_caps() method + +Report the PCS in-band capabilities to phylink for Marvell PP2 +interfaces. + +Reviewed-by: Andrew Lunn +Signed-off-by: Russell King (Oracle) +Link: https://patch.msgid.link/E1tIUsE-006IUh-E7@rmk-PC.armlinux.org.uk +Signed-off-by: Jakub Kicinski +--- + .../net/ethernet/marvell/mvpp2/mvpp2_main.c | 25 ++++++++++++------- + 1 file changed, 16 insertions(+), 9 deletions(-) + +diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +index 66b5a80c9c28..ebb49c04a7a0 100644 +--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c ++++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +@@ -6237,19 +6237,26 @@ static const struct phylink_pcs_ops mvpp2_phylink_xlg_pcs_ops = { + .pcs_config = mvpp2_xlg_pcs_config, + }; + +-static int mvpp2_gmac_pcs_validate(struct phylink_pcs *pcs, +- unsigned long *supported, +- const struct phylink_link_state *state) ++static unsigned int mvpp2_gmac_pcs_inband_caps(struct phylink_pcs *pcs, ++ phy_interface_t interface) + { +- /* When in 802.3z mode, we must have AN enabled: ++ /* When operating in an 802.3z mode, we must have AN enabled: + * Bit 2 Field InBandAnEn In-band Auto-Negotiation enable. ... + * When = 1 (1000BASE-X) this field must be set to 1. ++ * Therefore, inband is "required". + */ +- if (phy_interface_mode_is_8023z(state->interface) && +- !phylink_test(state->advertising, Autoneg)) +- return -EINVAL; ++ if (phy_interface_mode_is_8023z(interface)) ++ return LINK_INBAND_ENABLE; + +- return 0; ++ /* SGMII and RGMII can be configured to use inband signalling of the ++ * AN result. Indicate these as "possible". ++ */ ++ if (interface == PHY_INTERFACE_MODE_SGMII || ++ phy_interface_mode_is_rgmii(interface)) ++ return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE; ++ ++ /* For any other modes, indicate that inband is not supported. */ ++ return LINK_INBAND_DISABLE; + } + + static void mvpp2_gmac_pcs_get_state(struct phylink_pcs *pcs, +@@ -6356,7 +6363,7 @@ static void mvpp2_gmac_pcs_an_restart(struct phylink_pcs *pcs) + } + + static const struct phylink_pcs_ops mvpp2_phylink_gmac_pcs_ops = { +- .pcs_validate = mvpp2_gmac_pcs_validate, ++ .pcs_inband_caps = mvpp2_gmac_pcs_inband_caps, + .pcs_get_state = mvpp2_gmac_pcs_get_state, + .pcs_config = mvpp2_gmac_pcs_config, + .pcs_an_restart = mvpp2_gmac_pcs_an_restart, +-- +2.51.0 + + +From c34544c535d20859435b80f2dd0052323036eb9e Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Tue, 3 Dec 2024 15:31:43 +0000 +Subject: [PATCH 047/517] net: phylink: add negotiation of in-band capabilities + +Support for in-band signalling with Serdes links is uncertain. Some +PHYs do not support in-band for e.g. SGMII. Some PCS do not support +in-band for 2500Base-X. Some PCS require in-band for Base-X protocols. + +Simply using what is in DT is insufficient when we have hot-pluggable +PHYs e.g. in the form of SFP modules, which may not provide the +in-band signalling. + +In order to address this, we have introduced phy_inband_caps() and +pcs_inband_caps() functions to allow phylink to retrieve the +capabilities from each end of the PCS/PHY link. This commit adds code +to resolve whether in-band will be used in the various scenarios that +we have: In-band not being used, PHY present using SGMII or Base-X, +PHY not present. We also deal with no capabilties provided. + +Signed-off-by: Russell King (Oracle) +Link: https://patch.msgid.link/E1tIUsJ-006IUn-H3@rmk-PC.armlinux.org.uk +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/phylink.c | 154 +++++++++++++++++++++++++++++++++++--- + 1 file changed, 144 insertions(+), 10 deletions(-) + +diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c +index c358ab5c16a7..f07c674816db 100644 +--- a/drivers/net/phy/phylink.c ++++ b/drivers/net/phy/phylink.c +@@ -75,6 +75,7 @@ struct phylink { + + struct mutex state_mutex; + struct phylink_link_state phy_state; ++ unsigned int phy_ib_mode; + struct work_struct resolve; + unsigned int pcs_neg_mode; + unsigned int pcs_state; +@@ -1170,10 +1171,18 @@ static void phylink_pcs_neg_mode(struct phylink *pl, struct phylink_pcs *pcs, + phy_interface_t interface, + const unsigned long *advertising) + { ++ unsigned int pcs_ib_caps = 0; ++ unsigned int phy_ib_caps = 0; + unsigned int neg_mode, mode; ++ enum { ++ INBAND_CISCO_SGMII, ++ INBAND_BASEX, ++ } type; + + mode = pl->req_link_an_mode; + ++ pl->phy_ib_mode = 0; ++ + switch (interface) { + case PHY_INTERFACE_MODE_SGMII: + case PHY_INTERFACE_MODE_QSGMII: +@@ -1185,10 +1194,7 @@ static void phylink_pcs_neg_mode(struct phylink *pl, struct phylink_pcs *pcs, + * inband communication. Note: there exist PHYs that run + * with SGMII but do not send the inband data. + */ +- if (!phylink_autoneg_inband(mode)) +- neg_mode = PHYLINK_PCS_NEG_OUTBAND; +- else +- neg_mode = PHYLINK_PCS_NEG_INBAND_ENABLED; ++ type = INBAND_CISCO_SGMII; + break; + + case PHY_INTERFACE_MODE_1000BASEX: +@@ -1199,18 +1205,139 @@ static void phylink_pcs_neg_mode(struct phylink *pl, struct phylink_pcs *pcs, + * as well, but drivers may not support this, so may + * need to override this. + */ +- if (!phylink_autoneg_inband(mode)) ++ type = INBAND_BASEX; ++ break; ++ ++ default: ++ pl->pcs_neg_mode = PHYLINK_PCS_NEG_NONE; ++ pl->act_link_an_mode = mode; ++ return; ++ } ++ ++ if (pcs) ++ pcs_ib_caps = phylink_pcs_inband_caps(pcs, interface); ++ ++ if (pl->phydev) ++ phy_ib_caps = phy_inband_caps(pl->phydev, interface); ++ ++ phylink_dbg(pl, "interface %s inband modes: pcs=%02x phy=%02x\n", ++ phy_modes(interface), pcs_ib_caps, phy_ib_caps); ++ ++ if (!phylink_autoneg_inband(mode)) { ++ bool pcs_ib_only = false; ++ bool phy_ib_only = false; ++ ++ if (pcs_ib_caps && pcs_ib_caps != LINK_INBAND_DISABLE) { ++ /* PCS supports reporting in-band capabilities, and ++ * supports more than disable mode. ++ */ ++ if (pcs_ib_caps & LINK_INBAND_DISABLE) ++ neg_mode = PHYLINK_PCS_NEG_OUTBAND; ++ else if (pcs_ib_caps & LINK_INBAND_ENABLE) ++ pcs_ib_only = true; ++ } ++ ++ if (phy_ib_caps && phy_ib_caps != LINK_INBAND_DISABLE) { ++ /* PHY supports in-band capabilities, and supports ++ * more than disable mode. ++ */ ++ if (phy_ib_caps & LINK_INBAND_DISABLE) ++ pl->phy_ib_mode = LINK_INBAND_DISABLE; ++ else if (phy_ib_caps & LINK_INBAND_BYPASS) ++ pl->phy_ib_mode = LINK_INBAND_BYPASS; ++ else if (phy_ib_caps & LINK_INBAND_ENABLE) ++ phy_ib_only = true; ++ } ++ ++ /* If either the PCS or PHY requires inband to be enabled, ++ * this is an invalid configuration. Provide a diagnostic ++ * message for this case, but don't try to force the issue. ++ */ ++ if (pcs_ib_only || phy_ib_only) ++ phylink_warn(pl, ++ "firmware wants %s mode, but %s%s%s requires inband\n", ++ phylink_an_mode_str(mode), ++ pcs_ib_only ? "PCS" : "", ++ pcs_ib_only && phy_ib_only ? " and " : "", ++ phy_ib_only ? "PHY" : ""); ++ ++ neg_mode = PHYLINK_PCS_NEG_OUTBAND; ++ } else if (type == INBAND_CISCO_SGMII || pl->phydev) { ++ /* For SGMII modes which are designed to be used with PHYs, or ++ * Base-X with a PHY, we try to use in-band mode where-ever ++ * possible. However, there are some PHYs e.g. BCM84881 which ++ * do not support in-band. ++ */ ++ const unsigned int inband_ok = LINK_INBAND_ENABLE | ++ LINK_INBAND_BYPASS; ++ const unsigned int outband_ok = LINK_INBAND_DISABLE | ++ LINK_INBAND_BYPASS; ++ /* PCS PHY ++ * D E D E ++ * 0 0 0 0 no information inband enabled ++ * 1 0 0 0 pcs doesn't support outband ++ * 0 1 0 0 pcs required inband enabled ++ * 1 1 0 0 pcs optional inband enabled ++ * 0 0 1 0 phy doesn't support outband ++ * 1 0 1 0 pcs+phy doesn't support outband ++ * 0 1 1 0 pcs required, phy doesn't support, invalid ++ * 1 1 1 0 pcs optional, phy doesn't support, outband ++ * 0 0 0 1 phy required inband enabled ++ * 1 0 0 1 pcs doesn't support, phy required, invalid ++ * 0 1 0 1 pcs+phy required inband enabled ++ * 1 1 0 1 pcs optional, phy required inband enabled ++ * 0 0 1 1 phy optional inband enabled ++ * 1 0 1 1 pcs doesn't support, phy optional, outband ++ * 0 1 1 1 pcs required, phy optional inband enabled ++ * 1 1 1 1 pcs+phy optional inband enabled ++ */ ++ if ((!pcs_ib_caps || pcs_ib_caps & inband_ok) && ++ (!phy_ib_caps || phy_ib_caps & inband_ok)) { ++ /* In-band supported or unknown at both ends. Enable ++ * in-band mode with or without bypass at the PHY. ++ */ ++ if (phy_ib_caps & LINK_INBAND_ENABLE) ++ pl->phy_ib_mode = LINK_INBAND_ENABLE; ++ else if (phy_ib_caps & LINK_INBAND_BYPASS) ++ pl->phy_ib_mode = LINK_INBAND_BYPASS; ++ ++ neg_mode = PHYLINK_PCS_NEG_INBAND_ENABLED; ++ } else if ((!pcs_ib_caps || pcs_ib_caps & outband_ok) && ++ (!phy_ib_caps || phy_ib_caps & outband_ok)) { ++ /* Either in-band not supported at at least one end. ++ * In-band bypass at the other end is possible. ++ */ ++ if (phy_ib_caps & LINK_INBAND_DISABLE) ++ pl->phy_ib_mode = LINK_INBAND_DISABLE; ++ else if (phy_ib_caps & LINK_INBAND_BYPASS) ++ pl->phy_ib_mode = LINK_INBAND_BYPASS; ++ + neg_mode = PHYLINK_PCS_NEG_OUTBAND; ++ if (pl->phydev) ++ mode = MLO_AN_PHY; ++ } else { ++ /* invalid */ ++ phylink_warn(pl, "%s: incompatible in-band capabilities, trying in-band", ++ phy_modes(interface)); ++ neg_mode = PHYLINK_PCS_NEG_INBAND_ENABLED; ++ } ++ } else { ++ /* For Base-X without a PHY */ ++ if (pcs_ib_caps == LINK_INBAND_DISABLE) ++ /* If the PCS doesn't support inband, then inband must ++ * be disabled. ++ */ ++ neg_mode = PHYLINK_PCS_NEG_INBAND_DISABLED; ++ else if (pcs_ib_caps == LINK_INBAND_ENABLE) ++ /* If the PCS requires inband, then inband must always ++ * be enabled. ++ */ ++ neg_mode = PHYLINK_PCS_NEG_INBAND_ENABLED; + else if (linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, + advertising)) + neg_mode = PHYLINK_PCS_NEG_INBAND_ENABLED; + else + neg_mode = PHYLINK_PCS_NEG_INBAND_DISABLED; +- break; +- +- default: +- neg_mode = PHYLINK_PCS_NEG_NONE; +- break; + } + + pl->pcs_neg_mode = neg_mode; +@@ -1309,6 +1436,13 @@ static void phylink_major_config(struct phylink *pl, bool restart, + ERR_PTR(err)); + } + ++ if (pl->phydev && pl->phy_ib_mode) { ++ err = phy_config_inband(pl->phydev, pl->phy_ib_mode); ++ if (err < 0) ++ phylink_err(pl, "phy_config_inband: %pe\n", ++ ERR_PTR(err)); ++ } ++ + if (pl->sfp_bus) { + rate_kbd = phylink_interface_signal_rate(state->interface); + if (rate_kbd) +-- +2.51.0 + + +From 99013b966414b56578184ade8275d7065a49d243 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Tue, 3 Dec 2024 15:31:48 +0000 +Subject: [PATCH 048/517] net: phylink: remove phylink_phy_no_inband() + +Remove phylink_phy_no_inband() now that we are handling the lack of +inband negotiation by querying the capabilities of the PHY and PCS, +and the BCM84881 PHY driver provides us the information necessary to +make the decision. + +Reviewed-by: Andrew Lunn +Signed-off-by: Russell King (Oracle) +Link: https://patch.msgid.link/E1tIUsO-006IUt-KN@rmk-PC.armlinux.org.uk +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/phylink.c | 29 +++++++---------------------- + 1 file changed, 7 insertions(+), 22 deletions(-) + +diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c +index f07c674816db..ede93109f9c5 100644 +--- a/drivers/net/phy/phylink.c ++++ b/drivers/net/phy/phylink.c +@@ -3394,10 +3394,11 @@ static phy_interface_t phylink_choose_sfp_interface(struct phylink *pl, + return interface; + } + +-static void phylink_sfp_set_config(struct phylink *pl, u8 mode, ++static void phylink_sfp_set_config(struct phylink *pl, + unsigned long *supported, + struct phylink_link_state *state) + { ++ u8 mode = MLO_AN_INBAND; + bool changed = false; + + phylink_dbg(pl, "requesting link mode %s/%s with support %*pb\n", +@@ -3431,8 +3432,7 @@ static void phylink_sfp_set_config(struct phylink *pl, u8 mode, + phylink_mac_initial_config(pl, false); + } + +-static int phylink_sfp_config_phy(struct phylink *pl, u8 mode, +- struct phy_device *phy) ++static int phylink_sfp_config_phy(struct phylink *pl, struct phy_device *phy) + { + __ETHTOOL_DECLARE_LINK_MODE_MASK(support1); + __ETHTOOL_DECLARE_LINK_MODE_MASK(support); +@@ -3472,7 +3472,7 @@ static int phylink_sfp_config_phy(struct phylink *pl, u8 mode, + if (ret) { + phylink_err(pl, + "validation of %s/%s with support %*pb failed: %pe\n", +- phylink_an_mode_str(mode), ++ phylink_an_mode_str(pl->req_link_an_mode), + phy_modes(config.interface), + __ETHTOOL_LINK_MODE_MASK_NBITS, support, + ERR_PTR(ret)); +@@ -3481,7 +3481,7 @@ static int phylink_sfp_config_phy(struct phylink *pl, u8 mode, + + pl->link_port = pl->sfp_port; + +- phylink_sfp_set_config(pl, mode, support, &config); ++ phylink_sfp_set_config(pl, support, &config); + + return 0; + } +@@ -3556,7 +3556,7 @@ static int phylink_sfp_config_optical(struct phylink *pl) + + pl->link_port = pl->sfp_port; + +- phylink_sfp_set_config(pl, MLO_AN_INBAND, pl->sfp_support, &config); ++ phylink_sfp_set_config(pl, pl->sfp_support, &config); + + return 0; + } +@@ -3627,20 +3627,10 @@ static void phylink_sfp_link_up(void *upstream) + phylink_enable_and_run_resolve(pl, PHYLINK_DISABLE_LINK); + } + +-/* The Broadcom BCM84881 in the Methode DM7052 is unable to provide a SGMII +- * or 802.3z control word, so inband will not work. +- */ +-static bool phylink_phy_no_inband(struct phy_device *phy) +-{ +- return phy->is_c45 && phy_id_compare(phy->c45_ids.device_ids[1], +- 0xae025150, 0xfffffff0); +-} +- + static int phylink_sfp_connect_phy(void *upstream, struct phy_device *phy) + { + struct phylink *pl = upstream; + phy_interface_t interface; +- u8 mode; + int ret; + + /* +@@ -3652,17 +3642,12 @@ static int phylink_sfp_connect_phy(void *upstream, struct phy_device *phy) + */ + phy_support_asym_pause(phy); + +- if (phylink_phy_no_inband(phy)) +- mode = MLO_AN_PHY; +- else +- mode = MLO_AN_INBAND; +- + /* Set the PHY's host supported interfaces */ + phy_interface_and(phy->host_interfaces, phylink_sfp_interfaces, + pl->config->supported_interfaces); + + /* Do the initial configuration */ +- ret = phylink_sfp_config_phy(pl, mode, phy); ++ ret = phylink_sfp_config_phy(pl, phy); + if (ret < 0) + return ret; + +-- +2.51.0 + + +From 68b5488d76a29ee77592a116997e837791415755 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Thu, 5 Dec 2024 09:42:24 +0000 +Subject: [PATCH 049/517] net: pcs: pcs-lynx: implement pcs_inband_caps() + method + +Report the PCS in-band capabilities to phylink for the Lynx PCS. + +Reviewed-by: Maxime Chevallier +Signed-off-by: Russell King (Oracle) +Link: https://patch.msgid.link/E1tJ8NM-006L5J-AH@rmk-PC.armlinux.org.uk +Signed-off-by: Jakub Kicinski +--- + drivers/net/pcs/pcs-lynx.c | 22 ++++++++++++++++++++++ + 1 file changed, 22 insertions(+) + +diff --git a/drivers/net/pcs/pcs-lynx.c b/drivers/net/pcs/pcs-lynx.c +index b79aedad855b..767a8c0714ac 100644 +--- a/drivers/net/pcs/pcs-lynx.c ++++ b/drivers/net/pcs/pcs-lynx.c +@@ -35,6 +35,27 @@ enum sgmii_speed { + #define phylink_pcs_to_lynx(pl_pcs) container_of((pl_pcs), struct lynx_pcs, pcs) + #define lynx_to_phylink_pcs(lynx) (&(lynx)->pcs) + ++static unsigned int lynx_pcs_inband_caps(struct phylink_pcs *pcs, ++ phy_interface_t interface) ++{ ++ switch (interface) { ++ case PHY_INTERFACE_MODE_1000BASEX: ++ case PHY_INTERFACE_MODE_SGMII: ++ case PHY_INTERFACE_MODE_QSGMII: ++ return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE; ++ ++ case PHY_INTERFACE_MODE_10GBASER: ++ case PHY_INTERFACE_MODE_2500BASEX: ++ return LINK_INBAND_DISABLE; ++ ++ case PHY_INTERFACE_MODE_USXGMII: ++ return LINK_INBAND_ENABLE; ++ ++ default: ++ return 0; ++ } ++} ++ + static void lynx_pcs_get_state_usxgmii(struct mdio_device *pcs, + struct phylink_link_state *state) + { +@@ -306,6 +327,7 @@ static void lynx_pcs_link_up(struct phylink_pcs *pcs, unsigned int neg_mode, + } + + static const struct phylink_pcs_ops lynx_pcs_phylink_ops = { ++ .pcs_inband_caps = lynx_pcs_inband_caps, + .pcs_get_state = lynx_pcs_get_state, + .pcs_config = lynx_pcs_config, + .pcs_an_restart = lynx_pcs_an_restart, +-- +2.51.0 + + +From 82dcb9cbcc5292ffb27082e1f6376298cca39999 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Thu, 5 Dec 2024 09:42:29 +0000 +Subject: [PATCH 050/517] net: pcs: pcs-mtk-lynxi: implement pcs_inband_caps() + method + +Report the PCS in-band capabilities to phylink for the LynxI PCS. + +Signed-off-by: Russell King (Oracle) +Link: https://patch.msgid.link/E1tJ8NR-006L5P-E3@rmk-PC.armlinux.org.uk +Signed-off-by: Jakub Kicinski +--- + drivers/net/pcs/pcs-mtk-lynxi.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/drivers/net/pcs/pcs-mtk-lynxi.c b/drivers/net/pcs/pcs-mtk-lynxi.c +index 4f63abe638c4..7de804535229 100644 +--- a/drivers/net/pcs/pcs-mtk-lynxi.c ++++ b/drivers/net/pcs/pcs-mtk-lynxi.c +@@ -88,6 +88,21 @@ static struct mtk_pcs_lynxi *pcs_to_mtk_pcs_lynxi(struct phylink_pcs *pcs) + return container_of(pcs, struct mtk_pcs_lynxi, pcs); + } + ++static unsigned int mtk_pcs_lynxi_inband_caps(struct phylink_pcs *pcs, ++ phy_interface_t interface) ++{ ++ switch (interface) { ++ case PHY_INTERFACE_MODE_1000BASEX: ++ case PHY_INTERFACE_MODE_2500BASEX: ++ case PHY_INTERFACE_MODE_SGMII: ++ case PHY_INTERFACE_MODE_QSGMII: ++ return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE; ++ ++ default: ++ return 0; ++ } ++} ++ + static void mtk_pcs_lynxi_get_state(struct phylink_pcs *pcs, + struct phylink_link_state *state) + { +@@ -241,6 +256,7 @@ static void mtk_pcs_lynxi_disable(struct phylink_pcs *pcs) + } + + static const struct phylink_pcs_ops mtk_pcs_lynxi_ops = { ++ .pcs_inband_caps = mtk_pcs_lynxi_inband_caps, + .pcs_get_state = mtk_pcs_lynxi_get_state, + .pcs_config = mtk_pcs_lynxi_config, + .pcs_an_restart = mtk_pcs_lynxi_restart_an, +-- +2.51.0 + + +From 4e4de8707612bd5ed15b49af0be4f10efdaec455 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Thu, 5 Dec 2024 09:42:34 +0000 +Subject: [PATCH 051/517] net: pcs: xpcs: implement pcs_inband_caps() method + +Report the PCS inband capabilities to phylink for XPCS. + +Signed-off-by: Russell King (Oracle) +Link: https://patch.msgid.link/E1tJ8NW-006L5V-I9@rmk-PC.armlinux.org.uk +Signed-off-by: Jakub Kicinski +--- + drivers/net/pcs/pcs-xpcs.c | 28 ++++++++++++++++++++++++++++ + 1 file changed, 28 insertions(+) + +diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c +index 82463f9d50c8..1f0ec847895c 100644 +--- a/drivers/net/pcs/pcs-xpcs.c ++++ b/drivers/net/pcs/pcs-xpcs.c +@@ -608,6 +608,33 @@ static int xpcs_validate(struct phylink_pcs *pcs, unsigned long *supported, + return 0; + } + ++static unsigned int xpcs_inband_caps(struct phylink_pcs *pcs, ++ phy_interface_t interface) ++{ ++ struct dw_xpcs *xpcs = phylink_pcs_to_xpcs(pcs); ++ const struct dw_xpcs_compat *compat; ++ ++ compat = xpcs_find_compat(xpcs->desc, interface); ++ if (!compat) ++ return 0; ++ ++ switch (compat->an_mode) { ++ case DW_AN_C73: ++ return LINK_INBAND_ENABLE; ++ ++ case DW_AN_C37_SGMII: ++ case DW_AN_C37_1000BASEX: ++ return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE; ++ ++ case DW_10GBASER: ++ case DW_2500BASEX: ++ return LINK_INBAND_DISABLE; ++ ++ default: ++ return 0; ++ } ++} ++ + void xpcs_get_interfaces(struct dw_xpcs *xpcs, unsigned long *interfaces) + { + int i, j; +@@ -1365,6 +1392,7 @@ static const struct dw_xpcs_desc xpcs_desc_list[] = { + + static const struct phylink_pcs_ops xpcs_phylink_ops = { + .pcs_validate = xpcs_validate, ++ .pcs_inband_caps = xpcs_inband_caps, + .pcs_config = xpcs_config, + .pcs_get_state = xpcs_get_state, + .pcs_an_restart = xpcs_an_restart, +-- +2.51.0 + + +From 7c06d850aae8abcc6caefb76d9bebe7013353c3e Mon Sep 17 00:00:00 2001 +From: Rosen Penev +Date: Sun, 27 Oct 2024 21:48:28 -0700 +Subject: [PATCH 052/517] net: dsa: use ethtool string helpers + +These are the preferred way to copy ethtool strings. + +Avoids incrementing pointers all over the place. + +Signed-off-by: Rosen Penev +(for hellcreek driver) +Reviewed-by: Kurt Kanzenbach +Link: https://patch.msgid.link/20241028044828.1639668-1-rosenp@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/dsa/b53/b53_common.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c +index c903c6fcc666..ad07efa44c55 100644 +--- a/drivers/net/dsa/b53/b53_common.c ++++ b/drivers/net/dsa/b53/b53_common.c +@@ -1086,8 +1086,7 @@ void b53_get_strings(struct dsa_switch *ds, int port, u32 stringset, + + if (stringset == ETH_SS_STATS) { + for (i = 0; i < mib_size; i++) +- strscpy(data + i * ETH_GSTRING_LEN, +- mibs[i].name, ETH_GSTRING_LEN); ++ ethtool_puts(&data, mibs[i].name); + } else if (stringset == ETH_SS_PHY_STATS) { + phydev = b53_get_phy_device(ds, port); + if (!phydev) +-- +2.51.0 + + +From 6eb6aee9c622b03602f9189203fd73d5f11bfc6b Mon Sep 17 00:00:00 2001 +From: Torben Nielsen +Date: Mon, 17 Feb 2025 09:05:01 +0100 +Subject: [PATCH 053/517] net: dsa: b53: mdio: add support for BCM53101 + +BCM53101 is a ethernet switch, very similar to the BCM53115. +Enable support for it, in the existing b53 dsa driver. + +Signed-off-by: Torben Nielsen +Signed-off-by: Claus Stovgaard +Link: https://patch.msgid.link/20250217080503.1390282-1-claus.stovgaard@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/dsa/b53/b53_common.c | 14 ++++++++++++++ + drivers/net/dsa/b53/b53_mdio.c | 1 + + drivers/net/dsa/b53/b53_priv.h | 2 ++ + 3 files changed, 17 insertions(+) + +diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c +index ad07efa44c55..0598c8c60c85 100644 +--- a/drivers/net/dsa/b53/b53_common.c ++++ b/drivers/net/dsa/b53/b53_common.c +@@ -2583,6 +2583,19 @@ static const struct b53_chip_data b53_switch_chips[] = { + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + }, ++ { ++ .chip_id = BCM53101_DEVICE_ID, ++ .dev_name = "BCM53101", ++ .vlans = 4096, ++ .enabled_ports = 0x11f, ++ .arl_bins = 4, ++ .arl_buckets = 512, ++ .vta_regs = B53_VTA_REGS, ++ .imp_port = 8, ++ .duplex_reg = B53_DUPLEX_STAT_GE, ++ .jumbo_pm_reg = B53_JUMBO_PORT_MASK, ++ .jumbo_size_reg = B53_JUMBO_MAX_SIZE, ++ }, + { + .chip_id = BCM53115_DEVICE_ID, + .dev_name = "BCM53115", +@@ -2964,6 +2977,7 @@ int b53_switch_detect(struct b53_device *dev) + return ret; + + switch (id32) { ++ case BCM53101_DEVICE_ID: + case BCM53115_DEVICE_ID: + case BCM53125_DEVICE_ID: + case BCM53128_DEVICE_ID: +diff --git a/drivers/net/dsa/b53/b53_mdio.c b/drivers/net/dsa/b53/b53_mdio.c +index 31d070bf161a..43a3b37b731b 100644 +--- a/drivers/net/dsa/b53/b53_mdio.c ++++ b/drivers/net/dsa/b53/b53_mdio.c +@@ -374,6 +374,7 @@ static void b53_mdio_shutdown(struct mdio_device *mdiodev) + + static const struct of_device_id b53_of_match[] = { + { .compatible = "brcm,bcm5325" }, ++ { .compatible = "brcm,bcm53101" }, + { .compatible = "brcm,bcm53115" }, + { .compatible = "brcm,bcm53125" }, + { .compatible = "brcm,bcm53128" }, +diff --git a/drivers/net/dsa/b53/b53_priv.h b/drivers/net/dsa/b53/b53_priv.h +index e908397e8b9a..4b52a4807029 100644 +--- a/drivers/net/dsa/b53/b53_priv.h ++++ b/drivers/net/dsa/b53/b53_priv.h +@@ -66,6 +66,7 @@ enum { + BCM5395_DEVICE_ID = 0x95, + BCM5397_DEVICE_ID = 0x97, + BCM5398_DEVICE_ID = 0x98, ++ BCM53101_DEVICE_ID = 0x53101, + BCM53115_DEVICE_ID = 0x53115, + BCM53125_DEVICE_ID = 0x53125, + BCM53128_DEVICE_ID = 0x53128, +@@ -190,6 +191,7 @@ static inline int is531x5(struct b53_device *dev) + { + return dev->chip_id == BCM53115_DEVICE_ID || + dev->chip_id == BCM53125_DEVICE_ID || ++ dev->chip_id == BCM53101_DEVICE_ID || + dev->chip_id == BCM53128_DEVICE_ID || + dev->chip_id == BCM53134_DEVICE_ID; + } +-- +2.51.0 + + +From 427c593a29ae93f1675b83cc6ee5562c7a05ee23 Mon Sep 17 00:00:00 2001 +From: Jonas Gorski +Date: Sat, 10 May 2025 11:22:11 +0200 +Subject: [PATCH 054/517] net: dsa: b53: implement setting ageing time + +b53 supported switches support configuring ageing time between 1 and +1,048,575 seconds, so add an appropriate setter. + +This allows b53 to pass the FDB learning test for both vlan aware and +vlan unaware bridges. + +Signed-off-by: Jonas Gorski +Reviewed-by: Florian Fainelli +Link: https://patch.msgid.link/20250510092211.276541-1-jonas.gorski@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/dsa/b53/b53_common.c | 28 ++++++++++++++++++++++++++++ + drivers/net/dsa/b53/b53_priv.h | 1 + + drivers/net/dsa/b53/b53_regs.h | 7 +++++++ + 3 files changed, 36 insertions(+) + +diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c +index 0598c8c60c85..d3589b94c356 100644 +--- a/drivers/net/dsa/b53/b53_common.c ++++ b/drivers/net/dsa/b53/b53_common.c +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -1227,6 +1228,10 @@ static int b53_setup(struct dsa_switch *ds) + */ + ds->untag_vlan_aware_bridge_pvid = true; + ++ /* Ageing time is set in seconds */ ++ ds->ageing_time_min = 1 * 1000; ++ ds->ageing_time_max = AGE_TIME_MAX * 1000; ++ + ret = b53_reset_switch(dev); + if (ret) { + dev_err(ds->dev, "failed to reset switch\n"); +@@ -2444,6 +2449,28 @@ static int b53_get_max_mtu(struct dsa_switch *ds, int port) + return B53_MAX_MTU; + } + ++int b53_set_ageing_time(struct dsa_switch *ds, unsigned int msecs) ++{ ++ struct b53_device *dev = ds->priv; ++ u32 atc; ++ int reg; ++ ++ if (is63xx(dev)) ++ reg = B53_AGING_TIME_CONTROL_63XX; ++ else ++ reg = B53_AGING_TIME_CONTROL; ++ ++ atc = DIV_ROUND_CLOSEST(msecs, 1000); ++ ++ if (!is5325(dev) && !is5365(dev)) ++ atc |= AGE_CHANGE; ++ ++ b53_write32(dev, B53_MGMT_PAGE, reg, atc); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(b53_set_ageing_time); ++ + static const struct phylink_mac_ops b53_phylink_mac_ops = { + .mac_select_pcs = b53_phylink_mac_select_pcs, + .mac_config = b53_phylink_mac_config, +@@ -2468,6 +2495,7 @@ static const struct dsa_switch_ops b53_switch_ops = { + .support_eee = b53_support_eee, + .get_mac_eee = b53_get_mac_eee, + .set_mac_eee = b53_set_mac_eee, ++ .set_ageing_time = b53_set_ageing_time, + .port_bridge_join = b53_br_join, + .port_bridge_leave = b53_br_leave, + .port_pre_bridge_flags = b53_br_flags_pre, +diff --git a/drivers/net/dsa/b53/b53_priv.h b/drivers/net/dsa/b53/b53_priv.h +index 4b52a4807029..72f00f9e177c 100644 +--- a/drivers/net/dsa/b53/b53_priv.h ++++ b/drivers/net/dsa/b53/b53_priv.h +@@ -343,6 +343,7 @@ void b53_get_strings(struct dsa_switch *ds, int port, u32 stringset, + void b53_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *data); + int b53_get_sset_count(struct dsa_switch *ds, int port, int sset); + void b53_get_ethtool_phy_stats(struct dsa_switch *ds, int port, uint64_t *data); ++int b53_set_ageing_time(struct dsa_switch *ds, unsigned int msecs); + int b53_br_join(struct dsa_switch *ds, int port, struct dsa_bridge bridge, + bool *tx_fwd_offload, struct netlink_ext_ack *extack); + void b53_br_leave(struct dsa_switch *ds, int port, struct dsa_bridge bridge); +diff --git a/drivers/net/dsa/b53/b53_regs.h b/drivers/net/dsa/b53/b53_regs.h +index 5741231e0841..f2caf8fe5699 100644 +--- a/drivers/net/dsa/b53/b53_regs.h ++++ b/drivers/net/dsa/b53/b53_regs.h +@@ -225,6 +225,13 @@ + #define BRCM_HDR_P5_EN BIT(1) /* Enable tagging on port 5 */ + #define BRCM_HDR_P7_EN BIT(2) /* Enable tagging on port 7 */ + ++/* Aging Time control register (32 bit) */ ++#define B53_AGING_TIME_CONTROL 0x06 ++#define B53_AGING_TIME_CONTROL_63XX 0x08 ++#define AGE_CHANGE BIT(20) ++#define AGE_TIME_MASK 0x7ffff ++#define AGE_TIME_MAX 1048575 ++ + /* Mirror capture control register (16 bit) */ + #define B53_MIR_CAP_CTL 0x10 + #define CAP_PORT_MASK 0xf +-- +2.51.0 + + +From 3198631f2e9d7a63611917584f509b56dfbd7401 Mon Sep 17 00:00:00 2001 +From: Jonas Gorski +Date: Mon, 2 Jun 2025 21:39:51 +0200 +Subject: [PATCH 055/517] net: dsa: b53: do not configure bcm63xx's IMP port + interface + +The IMP port is not a valid RGMII interface, but hard wired to internal, +so we shouldn't touch the undefined register B53_RGMII_CTRL_IMP. + +While this does not seem to have any side effects, let's not touch it at +all, so limit RGMII configuration on bcm63xx to the actual RGMII ports. + +Fixes: ce3bf94871f7 ("net: dsa: b53: add support for BCM63xx RGMIIs") +Signed-off-by: Jonas Gorski +Reviewed-by: Florian Fainelli +Link: https://patch.msgid.link/20250602193953.1010487-4-jonas.gorski@gmail.com +Signed-off-by: Paolo Abeni +--- + drivers/net/dsa/b53/b53_common.c | 22 ++++++++-------------- + 1 file changed, 8 insertions(+), 14 deletions(-) + +diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c +index d3589b94c356..d7a56dbc7d07 100644 +--- a/drivers/net/dsa/b53/b53_common.c ++++ b/drivers/net/dsa/b53/b53_common.c +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -1360,24 +1361,17 @@ static void b53_adjust_63xx_rgmii(struct dsa_switch *ds, int port, + phy_interface_t interface) + { + struct b53_device *dev = ds->priv; +- u8 rgmii_ctrl = 0, off; +- +- if (port == dev->imp_port) +- off = B53_RGMII_CTRL_IMP; +- else +- off = B53_RGMII_CTRL_P(port); ++ u8 rgmii_ctrl = 0; + +- b53_read8(dev, B53_CTRL_PAGE, off, &rgmii_ctrl); ++ b53_read8(dev, B53_CTRL_PAGE, B53_RGMII_CTRL_P(port), &rgmii_ctrl); + rgmii_ctrl &= ~(RGMII_CTRL_DLL_RXC | RGMII_CTRL_DLL_TXC); + +- if (port != dev->imp_port) { +- if (is63268(dev)) +- rgmii_ctrl |= RGMII_CTRL_MII_OVERRIDE; ++ if (is63268(dev)) ++ rgmii_ctrl |= RGMII_CTRL_MII_OVERRIDE; + +- rgmii_ctrl |= RGMII_CTRL_ENABLE_GMII; +- } ++ rgmii_ctrl |= RGMII_CTRL_ENABLE_GMII; + +- b53_write8(dev, B53_CTRL_PAGE, off, rgmii_ctrl); ++ b53_write8(dev, B53_CTRL_PAGE, B53_RGMII_CTRL_P(port), rgmii_ctrl); + + dev_dbg(ds->dev, "Configured port %d for %s\n", port, + phy_modes(interface)); +@@ -1528,7 +1522,7 @@ static void b53_phylink_mac_config(struct phylink_config *config, + struct b53_device *dev = ds->priv; + int port = dp->index; + +- if (is63xx(dev) && port >= B53_63XX_RGMII0) ++ if (is63xx(dev) && in_range(port, B53_63XX_RGMII0, 4)) + b53_adjust_63xx_rgmii(ds, port, interface); + + if (mode == MLO_AN_FIXED) { +-- +2.51.0 + + +From 58ff441b8e9051c9495e489887994c702ad0abe7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= +Date: Sat, 14 Jun 2025 09:59:47 +0200 +Subject: [PATCH 056/517] net: dsa: tag_brcm: legacy: reorganize functions +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Move brcm_leg_tag_rcv() definition to top. +This function is going to be shared between two different tags. + +Reviewed-by: Florian Fainelli +Signed-off-by: Ãlvaro Fernández Rojas +Link: https://patch.msgid.link/20250614080000.1884236-2-noltari@gmail.com +Signed-off-by: Jakub Kicinski +--- + net/dsa/tag_brcm.c | 64 +++++++++++++++++++++++----------------------- + 1 file changed, 32 insertions(+), 32 deletions(-) + +diff --git a/net/dsa/tag_brcm.c b/net/dsa/tag_brcm.c +index fe75821623a4..9f4b0bcd95cd 100644 +--- a/net/dsa/tag_brcm.c ++++ b/net/dsa/tag_brcm.c +@@ -213,6 +213,38 @@ MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_BRCM, BRCM_NAME); + #endif + + #if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_LEGACY) ++static struct sk_buff *brcm_leg_tag_rcv(struct sk_buff *skb, ++ struct net_device *dev) ++{ ++ int len = BRCM_LEG_TAG_LEN; ++ int source_port; ++ u8 *brcm_tag; ++ ++ if (unlikely(!pskb_may_pull(skb, BRCM_LEG_TAG_LEN + VLAN_HLEN))) ++ return NULL; ++ ++ brcm_tag = dsa_etype_header_pos_rx(skb); ++ ++ source_port = brcm_tag[5] & BRCM_LEG_PORT_ID; ++ ++ skb->dev = dsa_conduit_find_user(dev, 0, source_port); ++ if (!skb->dev) ++ return NULL; ++ ++ /* VLAN tag is added by BCM63xx internal switch */ ++ if (netdev_uses_dsa(skb->dev)) ++ len += VLAN_HLEN; ++ ++ /* Remove Broadcom tag and update checksum */ ++ skb_pull_rcsum(skb, len); ++ ++ dsa_default_offload_fwd_mark(skb); ++ ++ dsa_strip_etype_header(skb, len); ++ ++ return skb; ++} ++ + static struct sk_buff *brcm_leg_tag_xmit(struct sk_buff *skb, + struct net_device *dev) + { +@@ -250,38 +282,6 @@ static struct sk_buff *brcm_leg_tag_xmit(struct sk_buff *skb, + return skb; + } + +-static struct sk_buff *brcm_leg_tag_rcv(struct sk_buff *skb, +- struct net_device *dev) +-{ +- int len = BRCM_LEG_TAG_LEN; +- int source_port; +- u8 *brcm_tag; +- +- if (unlikely(!pskb_may_pull(skb, BRCM_LEG_TAG_LEN + VLAN_HLEN))) +- return NULL; +- +- brcm_tag = dsa_etype_header_pos_rx(skb); +- +- source_port = brcm_tag[5] & BRCM_LEG_PORT_ID; +- +- skb->dev = dsa_conduit_find_user(dev, 0, source_port); +- if (!skb->dev) +- return NULL; +- +- /* VLAN tag is added by BCM63xx internal switch */ +- if (netdev_uses_dsa(skb->dev)) +- len += VLAN_HLEN; +- +- /* Remove Broadcom tag and update checksum */ +- skb_pull_rcsum(skb, len); +- +- dsa_default_offload_fwd_mark(skb); +- +- dsa_strip_etype_header(skb, len); +- +- return skb; +-} +- + static const struct dsa_device_ops brcm_legacy_netdev_ops = { + .name = BRCM_LEGACY_NAME, + .proto = DSA_TAG_PROTO_BRCM_LEGACY, +-- +2.51.0 + + +From fe2df740c952ccd825ba3eea0797b7eb5690ef1a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= +Date: Sat, 14 Jun 2025 09:59:48 +0200 +Subject: [PATCH 057/517] net: dsa: tag_brcm: add support for legacy FCS tags +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add support for legacy Broadcom FCS tags, which are similar to +DSA_TAG_PROTO_BRCM_LEGACY. +BCM5325 and BCM5365 switches require including the original FCS value and +length, as opposed to BCM63xx switches. +Adding the original FCS value and length to DSA_TAG_PROTO_BRCM_LEGACY would +impact performance of BCM63xx switches, so it's better to create a new tag. + +Signed-off-by: Ãlvaro Fernández Rojas +Reviewed-by: Florian Fainelli +Link: https://patch.msgid.link/20250614080000.1884236-3-noltari@gmail.com +Signed-off-by: Jakub Kicinski +--- + include/net/dsa.h | 2 ++ + net/dsa/Kconfig | 16 ++++++++-- + net/dsa/tag_brcm.c | 73 +++++++++++++++++++++++++++++++++++++++++++++- + 3 files changed, 88 insertions(+), 3 deletions(-) + +diff --git a/include/net/dsa.h b/include/net/dsa.h +index 877f9b270cf6..6f2a397fbe1c 100644 +--- a/include/net/dsa.h ++++ b/include/net/dsa.h +@@ -54,11 +54,13 @@ struct tc_action; + #define DSA_TAG_PROTO_RZN1_A5PSW_VALUE 26 + #define DSA_TAG_PROTO_LAN937X_VALUE 27 + #define DSA_TAG_PROTO_VSC73XX_8021Q_VALUE 28 ++#define DSA_TAG_PROTO_BRCM_LEGACY_FCS_VALUE 29 + + enum dsa_tag_protocol { + DSA_TAG_PROTO_NONE = DSA_TAG_PROTO_NONE_VALUE, + DSA_TAG_PROTO_BRCM = DSA_TAG_PROTO_BRCM_VALUE, + DSA_TAG_PROTO_BRCM_LEGACY = DSA_TAG_PROTO_BRCM_LEGACY_VALUE, ++ DSA_TAG_PROTO_BRCM_LEGACY_FCS = DSA_TAG_PROTO_BRCM_LEGACY_FCS_VALUE, + DSA_TAG_PROTO_BRCM_PREPEND = DSA_TAG_PROTO_BRCM_PREPEND_VALUE, + DSA_TAG_PROTO_DSA = DSA_TAG_PROTO_DSA_VALUE, + DSA_TAG_PROTO_EDSA = DSA_TAG_PROTO_EDSA_VALUE, +diff --git a/net/dsa/Kconfig b/net/dsa/Kconfig +index 2dfe9063613f..869cbe57162f 100644 +--- a/net/dsa/Kconfig ++++ b/net/dsa/Kconfig +@@ -42,12 +42,24 @@ config NET_DSA_TAG_BRCM + Broadcom switches which place the tag after the MAC source address. + + config NET_DSA_TAG_BRCM_LEGACY +- tristate "Tag driver for Broadcom legacy switches using in-frame headers" ++ tristate "Tag driver for BCM63xx legacy switches using in-frame headers" + select NET_DSA_TAG_BRCM_COMMON + help + Say Y if you want to enable support for tagging frames for the +- Broadcom legacy switches which place the tag after the MAC source ++ BCM63xx legacy switches which place the tag after the MAC source + address. ++ This tag is used in BCM63xx legacy switches which work without the ++ original FCS and length before the tag insertion. ++ ++config NET_DSA_TAG_BRCM_LEGACY_FCS ++ tristate "Tag driver for BCM53xx legacy switches using in-frame headers" ++ select NET_DSA_TAG_BRCM_COMMON ++ help ++ Say Y if you want to enable support for tagging frames for the ++ BCM53xx legacy switches which place the tag after the MAC source ++ address. ++ This tag is used in BCM53xx legacy switches which expect original ++ FCS and length before the tag insertion to be present. + + config NET_DSA_TAG_BRCM_PREPEND + tristate "Tag driver for Broadcom switches using prepended headers" +diff --git a/net/dsa/tag_brcm.c b/net/dsa/tag_brcm.c +index 9f4b0bcd95cd..26bb657ceac3 100644 +--- a/net/dsa/tag_brcm.c ++++ b/net/dsa/tag_brcm.c +@@ -15,6 +15,7 @@ + + #define BRCM_NAME "brcm" + #define BRCM_LEGACY_NAME "brcm-legacy" ++#define BRCM_LEGACY_FCS_NAME "brcm-legacy-fcs" + #define BRCM_PREPEND_NAME "brcm-prepend" + + /* Legacy Broadcom tag (6 bytes) */ +@@ -32,6 +33,10 @@ + #define BRCM_LEG_MULTICAST (1 << 5) + #define BRCM_LEG_EGRESS (2 << 5) + #define BRCM_LEG_INGRESS (3 << 5) ++#define BRCM_LEG_LEN_HI(x) (((x) >> 8) & 0x7) ++ ++/* 4th byte in the tag */ ++#define BRCM_LEG_LEN_LO(x) ((x) & 0xff) + + /* 6th byte in the tag */ + #define BRCM_LEG_PORT_ID (0xf) +@@ -212,7 +217,8 @@ DSA_TAG_DRIVER(brcm_netdev_ops); + MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_BRCM, BRCM_NAME); + #endif + +-#if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_LEGACY) ++#if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_LEGACY) || \ ++ IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_LEGACY_FCS) + static struct sk_buff *brcm_leg_tag_rcv(struct sk_buff *skb, + struct net_device *dev) + { +@@ -244,7 +250,9 @@ static struct sk_buff *brcm_leg_tag_rcv(struct sk_buff *skb, + + return skb; + } ++#endif /* CONFIG_NET_DSA_TAG_BRCM_LEGACY || CONFIG_NET_DSA_TAG_BRCM_LEGACY_FCS */ + ++#if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_LEGACY) + static struct sk_buff *brcm_leg_tag_xmit(struct sk_buff *skb, + struct net_device *dev) + { +@@ -294,6 +302,66 @@ DSA_TAG_DRIVER(brcm_legacy_netdev_ops); + MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_BRCM_LEGACY, BRCM_LEGACY_NAME); + #endif /* CONFIG_NET_DSA_TAG_BRCM_LEGACY */ + ++#if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_LEGACY_FCS) ++static struct sk_buff *brcm_leg_fcs_tag_xmit(struct sk_buff *skb, ++ struct net_device *dev) ++{ ++ struct dsa_port *dp = dsa_user_to_port(dev); ++ unsigned int fcs_len; ++ __le32 fcs_val; ++ u8 *brcm_tag; ++ ++ /* The Ethernet switch we are interfaced with needs packets to be at ++ * least 64 bytes (including FCS) otherwise they will be discarded when ++ * they enter the switch port logic. When Broadcom tags are enabled, we ++ * need to make sure that packets are at least 70 bytes (including FCS ++ * and tag) because the length verification is done after the Broadcom ++ * tag is stripped off the ingress packet. ++ * ++ * Let dsa_user_xmit() free the SKB. ++ */ ++ if (__skb_put_padto(skb, ETH_ZLEN + BRCM_LEG_TAG_LEN, false)) ++ return NULL; ++ ++ fcs_len = skb->len; ++ fcs_val = cpu_to_le32(crc32_le(~0, skb->data, fcs_len) ^ ~0); ++ ++ skb_push(skb, BRCM_LEG_TAG_LEN); ++ ++ dsa_alloc_etype_header(skb, BRCM_LEG_TAG_LEN); ++ ++ brcm_tag = skb->data + 2 * ETH_ALEN; ++ ++ /* Broadcom tag type */ ++ brcm_tag[0] = BRCM_LEG_TYPE_HI; ++ brcm_tag[1] = BRCM_LEG_TYPE_LO; ++ ++ /* Broadcom tag value */ ++ brcm_tag[2] = BRCM_LEG_EGRESS | BRCM_LEG_LEN_HI(fcs_len); ++ brcm_tag[3] = BRCM_LEG_LEN_LO(fcs_len); ++ brcm_tag[4] = 0; ++ brcm_tag[5] = dp->index & BRCM_LEG_PORT_ID; ++ ++ /* Original FCS value */ ++ if (__skb_pad(skb, ETH_FCS_LEN, false)) ++ return NULL; ++ skb_put_data(skb, &fcs_val, ETH_FCS_LEN); ++ ++ return skb; ++} ++ ++static const struct dsa_device_ops brcm_legacy_fcs_netdev_ops = { ++ .name = BRCM_LEGACY_FCS_NAME, ++ .proto = DSA_TAG_PROTO_BRCM_LEGACY_FCS, ++ .xmit = brcm_leg_fcs_tag_xmit, ++ .rcv = brcm_leg_tag_rcv, ++ .needed_headroom = BRCM_LEG_TAG_LEN, ++}; ++ ++DSA_TAG_DRIVER(brcm_legacy_fcs_netdev_ops); ++MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_BRCM_LEGACY_FCS, BRCM_LEGACY_FCS_NAME); ++#endif /* CONFIG_NET_DSA_TAG_BRCM_LEGACY_FCS */ ++ + #if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_PREPEND) + static struct sk_buff *brcm_tag_xmit_prepend(struct sk_buff *skb, + struct net_device *dev) +@@ -328,6 +396,9 @@ static struct dsa_tag_driver *dsa_tag_driver_array[] = { + #if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_LEGACY) + &DSA_TAG_DRIVER_NAME(brcm_legacy_netdev_ops), + #endif ++#if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_LEGACY_FCS) ++ &DSA_TAG_DRIVER_NAME(brcm_legacy_fcs_netdev_ops), ++#endif + #if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_PREPEND) + &DSA_TAG_DRIVER_NAME(brcm_prepend_netdev_ops), + #endif +-- +2.51.0 + + +From 57d5fd907ba1839df4933da2fd6c7f3924f4030c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= +Date: Sat, 14 Jun 2025 09:59:49 +0200 +Subject: [PATCH 058/517] net: dsa: b53: support legacy FCS tags +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Commit 46c5176c586c ("net: dsa: b53: support legacy tags") introduced +support for legacy tags, but it turns out that BCM5325 and BCM5365 +switches require the original FCS value and length, so they have to be +treated differently. + +Reviewed-by: Florian Fainelli +Signed-off-by: Ãlvaro Fernández Rojas +Link: https://patch.msgid.link/20250614080000.1884236-4-noltari@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/dsa/b53/Kconfig | 1 + + drivers/net/dsa/b53/b53_common.c | 7 +++++-- + 2 files changed, 6 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/dsa/b53/Kconfig b/drivers/net/dsa/b53/Kconfig +index ebaa4a80d544..915008e8eff5 100644 +--- a/drivers/net/dsa/b53/Kconfig ++++ b/drivers/net/dsa/b53/Kconfig +@@ -5,6 +5,7 @@ menuconfig B53 + select NET_DSA_TAG_NONE + select NET_DSA_TAG_BRCM + select NET_DSA_TAG_BRCM_LEGACY ++ select NET_DSA_TAG_BRCM_LEGACY_FCS + select NET_DSA_TAG_BRCM_PREPEND + help + This driver adds support for Broadcom managed switch chips. It supports +diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c +index d7a56dbc7d07..4291f2be7de4 100644 +--- a/drivers/net/dsa/b53/b53_common.c ++++ b/drivers/net/dsa/b53/b53_common.c +@@ -2285,8 +2285,11 @@ enum dsa_tag_protocol b53_get_tag_protocol(struct dsa_switch *ds, int port, + goto out; + } + +- /* Older models require a different 6 byte tag */ +- if (is5325(dev) || is5365(dev) || is63xx(dev)) { ++ /* Older models require different 6 byte tags */ ++ if (is5325(dev) || is5365(dev)) { ++ dev->tag_protocol = DSA_TAG_PROTO_BRCM_LEGACY_FCS; ++ goto out; ++ } else if (is63xx(dev)) { + dev->tag_protocol = DSA_TAG_PROTO_BRCM_LEGACY; + goto out; + } +-- +2.51.0 + + +From 9341e0f0fe6412e8a855c2f0188d38091904152c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= +Date: Sat, 14 Jun 2025 09:59:50 +0200 +Subject: [PATCH 059/517] net: dsa: b53: detect BCM5325 variants +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +We need to be able to differentiate the BCM5325 variants because: +- BCM5325M switches lack the ARLIO_PAGE->VLAN_ID_IDX register. +- BCM5325E have less 512 ARL buckets instead of 1024. + +Signed-off-by: Ãlvaro Fernández Rojas +Reviewed-by: Florian Fainelli +Link: https://patch.msgid.link/20250614080000.1884236-5-noltari@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/dsa/b53/b53_common.c | 24 +++++++++++++++++++++--- + drivers/net/dsa/b53/b53_priv.h | 19 +++++++++++++++++++ + 2 files changed, 40 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c +index 4291f2be7de4..1b4445d90612 100644 +--- a/drivers/net/dsa/b53/b53_common.c ++++ b/drivers/net/dsa/b53/b53_common.c +@@ -1816,7 +1816,8 @@ static int b53_arl_op(struct b53_device *dev, int op, int port, + + /* Perform a read for the given MAC and VID */ + b53_write48(dev, B53_ARLIO_PAGE, B53_MAC_ADDR_IDX, mac); +- b53_write16(dev, B53_ARLIO_PAGE, B53_VLAN_ID_IDX, vid); ++ if (!is5325m(dev)) ++ b53_write16(dev, B53_ARLIO_PAGE, B53_VLAN_ID_IDX, vid); + + /* Issue a read operation for this MAC */ + ret = b53_arl_rw_op(dev, 1); +@@ -2884,6 +2885,9 @@ static int b53_switch_init(struct b53_device *dev) + } + } + ++ if (is5325e(dev)) ++ dev->num_arl_buckets = 512; ++ + dev->num_ports = fls(dev->enabled_ports); + + dev->ds->num_ports = min_t(unsigned int, dev->num_ports, DSA_MAX_PORTS); +@@ -2985,10 +2989,24 @@ int b53_switch_detect(struct b53_device *dev) + b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_TABLE_ACCESS_25, 0xf); + b53_read16(dev, B53_VLAN_PAGE, B53_VLAN_TABLE_ACCESS_25, &tmp); + +- if (tmp == 0xf) ++ if (tmp == 0xf) { ++ u32 phy_id; ++ int val; ++ + dev->chip_id = BCM5325_DEVICE_ID; +- else ++ ++ val = b53_phy_read16(dev->ds, 0, MII_PHYSID1); ++ phy_id = (val & 0xffff) << 16; ++ val = b53_phy_read16(dev->ds, 0, MII_PHYSID2); ++ phy_id |= (val & 0xfff0); ++ ++ if (phy_id == 0x00406330) ++ dev->variant_id = B53_VARIANT_5325M; ++ else if (phy_id == 0x0143bc30) ++ dev->variant_id = B53_VARIANT_5325E; ++ } else { + dev->chip_id = BCM5365_DEVICE_ID; ++ } + break; + case BCM5389_DEVICE_ID: + case BCM5395_DEVICE_ID: +diff --git a/drivers/net/dsa/b53/b53_priv.h b/drivers/net/dsa/b53/b53_priv.h +index 72f00f9e177c..6bf8f591cdc1 100644 +--- a/drivers/net/dsa/b53/b53_priv.h ++++ b/drivers/net/dsa/b53/b53_priv.h +@@ -84,6 +84,12 @@ enum { + BCM53134_DEVICE_ID = 0x5075, + }; + ++enum b53_variant_id { ++ B53_VARIANT_NONE = 0, ++ B53_VARIANT_5325E, ++ B53_VARIANT_5325M, ++}; ++ + struct b53_pcs { + struct phylink_pcs pcs; + struct b53_device *dev; +@@ -118,6 +124,7 @@ struct b53_device { + + /* chip specific data */ + u32 chip_id; ++ enum b53_variant_id variant_id; + u8 core_rev; + u8 vta_regs[3]; + u8 duplex_reg; +@@ -165,6 +172,18 @@ static inline int is5325(struct b53_device *dev) + return dev->chip_id == BCM5325_DEVICE_ID; + } + ++static inline int is5325e(struct b53_device *dev) ++{ ++ return is5325(dev) && ++ dev->variant_id == B53_VARIANT_5325E; ++} ++ ++static inline int is5325m(struct b53_device *dev) ++{ ++ return is5325(dev) && ++ dev->variant_id == B53_VARIANT_5325M; ++} ++ + static inline int is5365(struct b53_device *dev) + { + #ifdef CONFIG_BCM47XX +-- +2.51.0 + + +From 3fccfaadb3356a5d30d38bcec04eca1ef60691c5 Mon Sep 17 00:00:00 2001 +From: Florian Fainelli +Date: Sat, 14 Jun 2025 09:59:51 +0200 +Subject: [PATCH 060/517] net: dsa: b53: add support for FDB operations on + 5325/5365 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +BCM5325 and BCM5365 are part of a much older generation of switches which, +due to their limited number of ports and VLAN entries (up to 256) allowed +a single 64-bit register to hold a full ARL entry. +This requires a little bit of massaging when reading, writing and +converting ARL entries in both directions. + +Signed-off-by: Florian Fainelli +Signed-off-by: Ãlvaro Fernández Rojas +Link: https://patch.msgid.link/20250614080000.1884236-6-noltari@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/dsa/b53/b53_common.c | 101 +++++++++++++++++++++++++------ + drivers/net/dsa/b53/b53_priv.h | 29 +++++++++ + drivers/net/dsa/b53/b53_regs.h | 7 ++- + 3 files changed, 115 insertions(+), 22 deletions(-) + +diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c +index 1b4445d90612..807c49880932 100644 +--- a/drivers/net/dsa/b53/b53_common.c ++++ b/drivers/net/dsa/b53/b53_common.c +@@ -1802,6 +1802,45 @@ static int b53_arl_read(struct b53_device *dev, u64 mac, + return *idx >= dev->num_arl_bins ? -ENOSPC : -ENOENT; + } + ++static int b53_arl_read_25(struct b53_device *dev, u64 mac, ++ u16 vid, struct b53_arl_entry *ent, u8 *idx) ++{ ++ DECLARE_BITMAP(free_bins, B53_ARLTBL_MAX_BIN_ENTRIES); ++ unsigned int i; ++ int ret; ++ ++ ret = b53_arl_op_wait(dev); ++ if (ret) ++ return ret; ++ ++ bitmap_zero(free_bins, dev->num_arl_bins); ++ ++ /* Read the bins */ ++ for (i = 0; i < dev->num_arl_bins; i++) { ++ u64 mac_vid; ++ ++ b53_read64(dev, B53_ARLIO_PAGE, ++ B53_ARLTBL_MAC_VID_ENTRY(i), &mac_vid); ++ ++ b53_arl_to_entry_25(ent, mac_vid); ++ ++ if (!(mac_vid & ARLTBL_VALID_25)) { ++ set_bit(i, free_bins); ++ continue; ++ } ++ if ((mac_vid & ARLTBL_MAC_MASK) != mac) ++ continue; ++ if (dev->vlan_enabled && ++ ((mac_vid >> ARLTBL_VID_S_65) & ARLTBL_VID_MASK_25) != vid) ++ continue; ++ *idx = i; ++ return 0; ++ } ++ ++ *idx = find_first_bit(free_bins, dev->num_arl_bins); ++ return *idx >= dev->num_arl_bins ? -ENOSPC : -ENOENT; ++} ++ + static int b53_arl_op(struct b53_device *dev, int op, int port, + const unsigned char *addr, u16 vid, bool is_valid) + { +@@ -1824,7 +1863,10 @@ static int b53_arl_op(struct b53_device *dev, int op, int port, + if (ret) + return ret; + +- ret = b53_arl_read(dev, mac, vid, &ent, &idx); ++ if (is5325(dev) || is5365(dev)) ++ ret = b53_arl_read_25(dev, mac, vid, &ent, &idx); ++ else ++ ret = b53_arl_read(dev, mac, vid, &ent, &idx); + + /* If this is a read, just finish now */ + if (op) +@@ -1868,12 +1910,17 @@ static int b53_arl_op(struct b53_device *dev, int op, int port, + ent.is_static = true; + ent.is_age = false; + memcpy(ent.mac, addr, ETH_ALEN); +- b53_arl_from_entry(&mac_vid, &fwd_entry, &ent); ++ if (is5325(dev) || is5365(dev)) ++ b53_arl_from_entry_25(&mac_vid, &ent); ++ else ++ b53_arl_from_entry(&mac_vid, &fwd_entry, &ent); + + b53_write64(dev, B53_ARLIO_PAGE, + B53_ARLTBL_MAC_VID_ENTRY(idx), mac_vid); +- b53_write32(dev, B53_ARLIO_PAGE, +- B53_ARLTBL_DATA_ENTRY(idx), fwd_entry); ++ ++ if (!is5325(dev) && !is5365(dev)) ++ b53_write32(dev, B53_ARLIO_PAGE, ++ B53_ARLTBL_DATA_ENTRY(idx), fwd_entry); + + return b53_arl_rw_op(dev, 0); + } +@@ -1885,12 +1932,6 @@ int b53_fdb_add(struct dsa_switch *ds, int port, + struct b53_device *priv = ds->priv; + int ret; + +- /* 5325 and 5365 require some more massaging, but could +- * be supported eventually +- */ +- if (is5325(priv) || is5365(priv)) +- return -EOPNOTSUPP; +- + mutex_lock(&priv->arl_mutex); + ret = b53_arl_op(priv, 0, port, addr, vid, true); + mutex_unlock(&priv->arl_mutex); +@@ -1917,10 +1958,15 @@ EXPORT_SYMBOL(b53_fdb_del); + static int b53_arl_search_wait(struct b53_device *dev) + { + unsigned int timeout = 1000; +- u8 reg; ++ u8 reg, offset; ++ ++ if (is5325(dev) || is5365(dev)) ++ offset = B53_ARL_SRCH_CTL_25; ++ else ++ offset = B53_ARL_SRCH_CTL; + + do { +- b53_read8(dev, B53_ARLIO_PAGE, B53_ARL_SRCH_CTL, ®); ++ b53_read8(dev, B53_ARLIO_PAGE, offset, ®); + if (!(reg & ARL_SRCH_STDN)) + return 0; + +@@ -1937,13 +1983,24 @@ static void b53_arl_search_rd(struct b53_device *dev, u8 idx, + struct b53_arl_entry *ent) + { + u64 mac_vid; +- u32 fwd_entry; + +- b53_read64(dev, B53_ARLIO_PAGE, +- B53_ARL_SRCH_RSTL_MACVID(idx), &mac_vid); +- b53_read32(dev, B53_ARLIO_PAGE, +- B53_ARL_SRCH_RSTL(idx), &fwd_entry); +- b53_arl_to_entry(ent, mac_vid, fwd_entry); ++ if (is5325(dev)) { ++ b53_read64(dev, B53_ARLIO_PAGE, B53_ARL_SRCH_RSTL_0_MACVID_25, ++ &mac_vid); ++ b53_arl_to_entry_25(ent, mac_vid); ++ } else if (is5365(dev)) { ++ b53_read64(dev, B53_ARLIO_PAGE, B53_ARL_SRCH_RSTL_0_MACVID_65, ++ &mac_vid); ++ b53_arl_to_entry_25(ent, mac_vid); ++ } else { ++ u32 fwd_entry; ++ ++ b53_read64(dev, B53_ARLIO_PAGE, B53_ARL_SRCH_RSTL_MACVID(idx), ++ &mac_vid); ++ b53_read32(dev, B53_ARLIO_PAGE, B53_ARL_SRCH_RSTL(idx), ++ &fwd_entry); ++ b53_arl_to_entry(ent, mac_vid, fwd_entry); ++ } + } + + static int b53_fdb_copy(int port, const struct b53_arl_entry *ent, +@@ -1964,14 +2021,20 @@ int b53_fdb_dump(struct dsa_switch *ds, int port, + struct b53_device *priv = ds->priv; + struct b53_arl_entry results[2]; + unsigned int count = 0; ++ u8 offset; + int ret; + u8 reg; + + mutex_lock(&priv->arl_mutex); + ++ if (is5325(priv) || is5365(priv)) ++ offset = B53_ARL_SRCH_CTL_25; ++ else ++ offset = B53_ARL_SRCH_CTL; ++ + /* Start search operation */ + reg = ARL_SRCH_STDN; +- b53_write8(priv, B53_ARLIO_PAGE, B53_ARL_SRCH_CTL, reg); ++ b53_write8(priv, offset, B53_ARL_SRCH_CTL, reg); + + do { + ret = b53_arl_search_wait(priv); +diff --git a/drivers/net/dsa/b53/b53_priv.h b/drivers/net/dsa/b53/b53_priv.h +index 6bf8f591cdc1..3e8204c7c02e 100644 +--- a/drivers/net/dsa/b53/b53_priv.h ++++ b/drivers/net/dsa/b53/b53_priv.h +@@ -317,6 +317,19 @@ static inline void b53_arl_to_entry(struct b53_arl_entry *ent, + ent->vid = mac_vid >> ARLTBL_VID_S; + } + ++static inline void b53_arl_to_entry_25(struct b53_arl_entry *ent, ++ u64 mac_vid) ++{ ++ memset(ent, 0, sizeof(*ent)); ++ ent->port = (mac_vid >> ARLTBL_DATA_PORT_ID_S_25) & ++ ARLTBL_DATA_PORT_ID_MASK_25; ++ ent->is_valid = !!(mac_vid & ARLTBL_VALID_25); ++ ent->is_age = !!(mac_vid & ARLTBL_AGE_25); ++ ent->is_static = !!(mac_vid & ARLTBL_STATIC_25); ++ u64_to_ether_addr(mac_vid, ent->mac); ++ ent->vid = mac_vid >> ARLTBL_VID_S_65; ++} ++ + static inline void b53_arl_from_entry(u64 *mac_vid, u32 *fwd_entry, + const struct b53_arl_entry *ent) + { +@@ -331,6 +344,22 @@ static inline void b53_arl_from_entry(u64 *mac_vid, u32 *fwd_entry, + *fwd_entry |= ARLTBL_AGE; + } + ++static inline void b53_arl_from_entry_25(u64 *mac_vid, ++ const struct b53_arl_entry *ent) ++{ ++ *mac_vid = ether_addr_to_u64(ent->mac); ++ *mac_vid |= (u64)(ent->port & ARLTBL_DATA_PORT_ID_MASK_25) << ++ ARLTBL_DATA_PORT_ID_S_25; ++ *mac_vid |= (u64)(ent->vid & ARLTBL_VID_MASK_25) << ++ ARLTBL_VID_S_65; ++ if (ent->is_valid) ++ *mac_vid |= ARLTBL_VALID_25; ++ if (ent->is_static) ++ *mac_vid |= ARLTBL_STATIC_25; ++ if (ent->is_age) ++ *mac_vid |= ARLTBL_AGE_25; ++} ++ + #ifdef CONFIG_BCM47XX + + #include +diff --git a/drivers/net/dsa/b53/b53_regs.h b/drivers/net/dsa/b53/b53_regs.h +index f2caf8fe5699..b6ef32d481ca 100644 +--- a/drivers/net/dsa/b53/b53_regs.h ++++ b/drivers/net/dsa/b53/b53_regs.h +@@ -329,9 +329,10 @@ + #define ARLTBL_VID_MASK 0xfff + #define ARLTBL_DATA_PORT_ID_S_25 48 + #define ARLTBL_DATA_PORT_ID_MASK_25 0xf +-#define ARLTBL_AGE_25 BIT(61) +-#define ARLTBL_STATIC_25 BIT(62) +-#define ARLTBL_VALID_25 BIT(63) ++#define ARLTBL_VID_S_65 53 ++#define ARLTBL_AGE_25 BIT_ULL(61) ++#define ARLTBL_STATIC_25 BIT_ULL(62) ++#define ARLTBL_VALID_25 BIT_ULL(63) + + /* ARL Table Data Entry N Registers (32 bit) */ + #define B53_ARLTBL_DATA_ENTRY(n) ((0x10 * (n)) + 0x18) +-- +2.51.0 + + +From ca4b9423fc2d29191875ce73e57afc26bfd12194 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= +Date: Sat, 14 Jun 2025 09:59:52 +0200 +Subject: [PATCH 061/517] net: dsa: b53: prevent FAST_AGE access on BCM5325 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +BCM5325 doesn't implement FAST_AGE registers so we should avoid reading or +writing them. + +Signed-off-by: Ãlvaro Fernández Rojas +Reviewed-by: Florian Fainelli +Link: https://patch.msgid.link/20250614080000.1884236-7-noltari@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/dsa/b53/b53_common.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c +index 807c49880932..8606eabcaaa8 100644 +--- a/drivers/net/dsa/b53/b53_common.c ++++ b/drivers/net/dsa/b53/b53_common.c +@@ -492,6 +492,9 @@ static int b53_flush_arl(struct b53_device *dev, u8 mask) + { + unsigned int i; + ++ if (is5325(dev)) ++ return 0; ++ + b53_write8(dev, B53_CTRL_PAGE, B53_FAST_AGE_CTRL, + FAST_AGE_DONE | FAST_AGE_DYNAMIC | mask); + +@@ -516,6 +519,9 @@ static int b53_flush_arl(struct b53_device *dev, u8 mask) + + static int b53_fast_age_port(struct b53_device *dev, int port) + { ++ if (is5325(dev)) ++ return 0; ++ + b53_write8(dev, B53_CTRL_PAGE, B53_FAST_AGE_PORT_CTRL, port); + + return b53_flush_arl(dev, FAST_AGE_PORT); +@@ -523,6 +529,9 @@ static int b53_fast_age_port(struct b53_device *dev, int port) + + static int b53_fast_age_vlan(struct b53_device *dev, u16 vid) + { ++ if (is5325(dev)) ++ return 0; ++ + b53_write16(dev, B53_CTRL_PAGE, B53_FAST_AGE_VID_CTRL, vid); + + return b53_flush_arl(dev, FAST_AGE_VLAN); +-- +2.51.0 + + +From 3d97487faefb90c06ad9e3d5b52d2f4c80bf96a5 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= +Date: Sat, 14 Jun 2025 09:59:56 +0200 +Subject: [PATCH 062/517] net: dsa: b53: prevent BRCM_HDR access on older + devices +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Older switches don't implement BRCM_HDR register so we should avoid +reading or writing it. + +Reviewed-by: Florian Fainelli +Signed-off-by: Ãlvaro Fernández Rojas +Link: https://patch.msgid.link/20250614080000.1884236-11-noltari@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/dsa/b53/b53_common.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c +index 8606eabcaaa8..f3c01ac88e3a 100644 +--- a/drivers/net/dsa/b53/b53_common.c ++++ b/drivers/net/dsa/b53/b53_common.c +@@ -747,6 +747,11 @@ void b53_brcm_hdr_setup(struct dsa_switch *ds, int port) + hdr_ctl |= GC_FRM_MGMT_PORT_M; + b53_write8(dev, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, hdr_ctl); + ++ /* B53_BRCM_HDR not present on devices with legacy tags */ ++ if (dev->tag_protocol == DSA_TAG_PROTO_BRCM_LEGACY || ++ dev->tag_protocol == DSA_TAG_PROTO_BRCM_LEGACY_FCS) ++ return; ++ + /* Enable Broadcom tags for IMP port */ + b53_read8(dev, B53_MGMT_PAGE, B53_BRCM_HDR, &hdr_ctl); + if (tag_en) +-- +2.51.0 + + +From 1f5369fdb49ca6051756ed11be3600e0c3535e70 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= +Date: Sat, 14 Jun 2025 09:59:58 +0200 +Subject: [PATCH 063/517] net: dsa: b53: fix unicast/multicast flooding on + BCM5325 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +BCM5325 doesn't implement UC_FLOOD_MASK, MC_FLOOD_MASK and IPMC_FLOOD_MASK +registers. +This has to be handled differently with other pages and registers. + +Signed-off-by: Ãlvaro Fernández Rojas +Reviewed-by: Florian Fainelli +Link: https://patch.msgid.link/20250614080000.1884236-13-noltari@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/dsa/b53/b53_common.c | 60 ++++++++++++++++++++++---------- + drivers/net/dsa/b53/b53_regs.h | 13 +++++++ + 2 files changed, 55 insertions(+), 18 deletions(-) + +diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c +index f3c01ac88e3a..051d9504b0de 100644 +--- a/drivers/net/dsa/b53/b53_common.c ++++ b/drivers/net/dsa/b53/b53_common.c +@@ -564,12 +564,24 @@ static void b53_port_set_ucast_flood(struct b53_device *dev, int port, + { + u16 uc; + +- b53_read16(dev, B53_CTRL_PAGE, B53_UC_FLOOD_MASK, &uc); +- if (unicast) +- uc |= BIT(port); +- else +- uc &= ~BIT(port); +- b53_write16(dev, B53_CTRL_PAGE, B53_UC_FLOOD_MASK, uc); ++ if (is5325(dev)) { ++ if (port == B53_CPU_PORT_25) ++ port = B53_CPU_PORT; ++ ++ b53_read16(dev, B53_IEEE_PAGE, B53_IEEE_UCAST_DLF, &uc); ++ if (unicast) ++ uc |= BIT(port) | B53_IEEE_UCAST_DROP_EN; ++ else ++ uc &= ~BIT(port); ++ b53_write16(dev, B53_IEEE_PAGE, B53_IEEE_UCAST_DLF, uc); ++ } else { ++ b53_read16(dev, B53_CTRL_PAGE, B53_UC_FLOOD_MASK, &uc); ++ if (unicast) ++ uc |= BIT(port); ++ else ++ uc &= ~BIT(port); ++ b53_write16(dev, B53_CTRL_PAGE, B53_UC_FLOOD_MASK, uc); ++ } + } + + static void b53_port_set_mcast_flood(struct b53_device *dev, int port, +@@ -577,19 +589,31 @@ static void b53_port_set_mcast_flood(struct b53_device *dev, int port, + { + u16 mc; + +- b53_read16(dev, B53_CTRL_PAGE, B53_MC_FLOOD_MASK, &mc); +- if (multicast) +- mc |= BIT(port); +- else +- mc &= ~BIT(port); +- b53_write16(dev, B53_CTRL_PAGE, B53_MC_FLOOD_MASK, mc); ++ if (is5325(dev)) { ++ if (port == B53_CPU_PORT_25) ++ port = B53_CPU_PORT; + +- b53_read16(dev, B53_CTRL_PAGE, B53_IPMC_FLOOD_MASK, &mc); +- if (multicast) +- mc |= BIT(port); +- else +- mc &= ~BIT(port); +- b53_write16(dev, B53_CTRL_PAGE, B53_IPMC_FLOOD_MASK, mc); ++ b53_read16(dev, B53_IEEE_PAGE, B53_IEEE_MCAST_DLF, &mc); ++ if (multicast) ++ mc |= BIT(port) | B53_IEEE_MCAST_DROP_EN; ++ else ++ mc &= ~BIT(port); ++ b53_write16(dev, B53_IEEE_PAGE, B53_IEEE_MCAST_DLF, mc); ++ } else { ++ b53_read16(dev, B53_CTRL_PAGE, B53_MC_FLOOD_MASK, &mc); ++ if (multicast) ++ mc |= BIT(port); ++ else ++ mc &= ~BIT(port); ++ b53_write16(dev, B53_CTRL_PAGE, B53_MC_FLOOD_MASK, mc); ++ ++ b53_read16(dev, B53_CTRL_PAGE, B53_IPMC_FLOOD_MASK, &mc); ++ if (multicast) ++ mc |= BIT(port); ++ else ++ mc &= ~BIT(port); ++ b53_write16(dev, B53_CTRL_PAGE, B53_IPMC_FLOOD_MASK, mc); ++ } + } + + static void b53_port_set_learning(struct b53_device *dev, int port, +diff --git a/drivers/net/dsa/b53/b53_regs.h b/drivers/net/dsa/b53/b53_regs.h +index b6ef32d481ca..309fe0e46dad 100644 +--- a/drivers/net/dsa/b53/b53_regs.h ++++ b/drivers/net/dsa/b53/b53_regs.h +@@ -29,6 +29,7 @@ + #define B53_ARLIO_PAGE 0x05 /* ARL Access */ + #define B53_FRAMEBUF_PAGE 0x06 /* Management frame access */ + #define B53_MEM_ACCESS_PAGE 0x08 /* Memory access */ ++#define B53_IEEE_PAGE 0x0a /* IEEE 802.1X */ + + /* PHY Registers */ + #define B53_PORT_MII_PAGE(i) (0x10 + (i)) /* Port i MII Registers */ +@@ -371,6 +372,18 @@ + #define B53_ARL_SRCH_RSTL_MACVID(x) (B53_ARL_SRCH_RSTL_0_MACVID + ((x) * 0x10)) + #define B53_ARL_SRCH_RSTL(x) (B53_ARL_SRCH_RSTL_0 + ((x) * 0x10)) + ++/************************************************************************* ++ * IEEE 802.1X Registers ++ *************************************************************************/ ++ ++/* Multicast DLF Drop Control register (16 bit) */ ++#define B53_IEEE_MCAST_DLF 0x94 ++#define B53_IEEE_MCAST_DROP_EN BIT(11) ++ ++/* Unicast DLF Drop Control register (16 bit) */ ++#define B53_IEEE_UCAST_DLF 0x96 ++#define B53_IEEE_UCAST_DROP_EN BIT(11) ++ + /************************************************************************* + * Port VLAN Registers + *************************************************************************/ +-- +2.51.0 + + +From ca931dc100c6aa5d9857b962ed84febb44c3b8d1 Mon Sep 17 00:00:00 2001 +From: Qingfang Deng +Date: Sat, 1 Mar 2025 21:55:16 +0800 +Subject: [PATCH 064/517] ppp: use IFF_NO_QUEUE in virtual interfaces +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +For PPPoE, PPTP, and PPPoL2TP, the start_xmit() function directly +forwards packets to the underlying network stack and never returns +anything other than 1. So these interfaces do not require a qdisc, +and the IFF_NO_QUEUE flag should be set. + +Introduces a direct_xmit flag in struct ppp_channel to indicate when +IFF_NO_QUEUE should be applied. The flag is set in ppp_connect_channel() +for relevant protocols. + +While at it, remove the usused latency member from struct ppp_channel. + +Signed-off-by: Qingfang Deng +Reviewed-by: Toke Høiland-Jørgensen +Link: https://patch.msgid.link/20250301135517.695809-1-dqfext@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/ppp/ppp_generic.c | 4 ++++ + drivers/net/ppp/pppoe.c | 1 + + drivers/net/ppp/pptp.c | 1 + + include/linux/ppp_channel.h | 3 +-- + net/l2tp/l2tp_ppp.c | 1 + + 5 files changed, 8 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c +index afc1566488b3..9b8ddf644ac3 100644 +--- a/drivers/net/ppp/ppp_generic.c ++++ b/drivers/net/ppp/ppp_generic.c +@@ -3504,6 +3504,10 @@ ppp_connect_channel(struct channel *pch, int unit) + ret = -ENOTCONN; + goto outl; + } ++ if (pch->chan->direct_xmit) ++ ppp->dev->priv_flags |= IFF_NO_QUEUE; ++ else ++ ppp->dev->priv_flags &= ~IFF_NO_QUEUE; + spin_unlock_bh(&pch->downl); + if (pch->file.hdrlen > ppp->file.hdrlen) + ppp->file.hdrlen = pch->file.hdrlen; +diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c +index 2ea4f4890d23..68e631718ab0 100644 +--- a/drivers/net/ppp/pppoe.c ++++ b/drivers/net/ppp/pppoe.c +@@ -693,6 +693,7 @@ static int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr, + po->chan.mtu = dev->mtu - sizeof(struct pppoe_hdr) - 2; + po->chan.private = sk; + po->chan.ops = &pppoe_chan_ops; ++ po->chan.direct_xmit = true; + + error = ppp_register_net_channel(dev_net(dev), &po->chan); + if (error) { +diff --git a/drivers/net/ppp/pptp.c b/drivers/net/ppp/pptp.c +index cec3bb22471b..90737cb71892 100644 +--- a/drivers/net/ppp/pptp.c ++++ b/drivers/net/ppp/pptp.c +@@ -469,6 +469,7 @@ static int pptp_connect(struct socket *sock, struct sockaddr *uservaddr, + po->chan.mtu -= PPTP_HEADER_OVERHEAD; + + po->chan.hdrlen = 2 + sizeof(struct pptp_gre_header); ++ po->chan.direct_xmit = true; + error = ppp_register_channel(&po->chan); + if (error) { + pr_err("PPTP: failed to register PPP channel (%d)\n", error); +diff --git a/include/linux/ppp_channel.h b/include/linux/ppp_channel.h +index 45e6e427ceb8..f73fbea0dbc2 100644 +--- a/include/linux/ppp_channel.h ++++ b/include/linux/ppp_channel.h +@@ -42,8 +42,7 @@ struct ppp_channel { + int hdrlen; /* amount of headroom channel needs */ + void *ppp; /* opaque to channel */ + int speed; /* transfer rate (bytes/second) */ +- /* the following is not used at present */ +- int latency; /* overhead time in milliseconds */ ++ bool direct_xmit; /* no qdisc, xmit directly */ + }; + + #ifdef __KERNEL__ +diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c +index 16c514f628ea..5e12e7ce17d8 100644 +--- a/net/l2tp/l2tp_ppp.c ++++ b/net/l2tp/l2tp_ppp.c +@@ -796,6 +796,7 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr, + po->chan.private = sk; + po->chan.ops = &pppol2tp_chan_ops; + po->chan.mtu = pppol2tp_tunnel_mtu(tunnel); ++ po->chan.direct_xmit = true; + + error = ppp_register_net_channel(sock_net(sk), &po->chan); + if (error) { +-- +2.51.0 + + +From 1bdc62e6e933d77990348c17ebbff861f37e160a Mon Sep 17 00:00:00 2001 +From: Shengyu Qu +Date: Mon, 14 Apr 2025 18:56:01 +0800 +Subject: [PATCH 065/517] net: bridge: locally receive all multicast packets if + IFF_ALLMULTI is set + +If multicast snooping is enabled, multicast packets may not always end up +on the local bridge interface, if the host is not a member of the multicast +group. Similar to how IFF_PROMISC allows all packets to be received +locally, let IFF_ALLMULTI allow all multicast packets to be received. + +OpenWrt uses a user space daemon for DHCPv6/RA/NDP handling, and in relay +mode it sets the ALLMULTI flag in order to receive all relevant queries on +the network. + +This works for normal network interfaces and non-snooping bridges, but not +snooping bridges (unless multicast routing is enabled). + +Reported-by: Felix Fietkau +Closes: https://github.com/openwrt/openwrt/issues/15857#issuecomment-2662851243 +Signed-off-by: Shengyu Qu +Reviewed-by: Ido Schimmel +Acked-by: Nikolay Aleksandrov +Link: https://patch.msgid.link/OSZPR01MB8434308370ACAFA90A22980798B32@OSZPR01MB8434.jpnprd01.prod.outlook.com +Signed-off-by: Jakub Kicinski +--- + net/bridge/br_input.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c +index ceaa5a89b947..c059e5657db3 100644 +--- a/net/bridge/br_input.c ++++ b/net/bridge/br_input.c +@@ -184,7 +184,8 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb + if ((mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) && + br_multicast_querier_exists(brmctx, eth_hdr(skb), mdst)) { + if ((mdst && mdst->host_joined) || +- br_multicast_is_router(brmctx, skb)) { ++ br_multicast_is_router(brmctx, skb) || ++ br->dev->flags & IFF_ALLMULTI) { + local_rcv = true; + DEV_STATS_INC(br->dev, multicast); + } +-- +2.51.0 + + +From a0238cb711e97c201f11e6686882562dab61e6d4 Mon Sep 17 00:00:00 2001 +From: Rui Salvaterra +Date: Wed, 5 Mar 2025 11:53:56 +0000 +Subject: [PATCH 066/517] igc: enable HW vlan tag insertion/stripping by + default + +This is enabled by default in other Intel drivers I've checked (e1000, e1000e, +iavf, igb and ice). Fixes an out-of-the-box performance issue when running +OpenWrt on typical mini-PCs with igc-supported Ethernet controllers and 802.1Q +VLAN configurations, as ethtool isn't part of the default packages and sane +defaults are expected. + +In my specific case, with an Intel N100-based machine with four I226-V Ethernet +controllers, my upload performance increased from under 30 Mb/s to the expected +~1 Gb/s. + +Signed-off-by: Rui Salvaterra +--- + drivers/net/ethernet/intel/igc/igc_main.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c +index 9ba41a427e14..cbe751d963bc 100644 +--- a/drivers/net/ethernet/intel/igc/igc_main.c ++++ b/drivers/net/ethernet/intel/igc/igc_main.c +@@ -7070,6 +7070,9 @@ static int igc_probe(struct pci_dev *pdev, + netdev->xdp_features = NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT | + NETDEV_XDP_ACT_XSK_ZEROCOPY; + ++ /* enable HW vlan tag insertion/stripping by default */ ++ netdev->features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX; ++ + /* MTU range: 68 - 9216 */ + netdev->min_mtu = ETH_MIN_MTU; + netdev->max_mtu = MAX_STD_JUMBO_FRAME_SIZE; +-- +2.51.0 + + +From d358cb92d517772c5cf4267a1ecf504178bd5439 Mon Sep 17 00:00:00 2001 +From: "SkyLake.Huang" +Date: Thu, 17 Oct 2024 11:22:11 +0800 +Subject: [PATCH 067/517] net: phy: mediatek-ge-soc: Fix coding style + +This patch fixes spelling errors, re-arrange vars with +reverse Xmas tree and remove unnecessary parens in +mediatek-ge-soc.c. + +Signed-off-by: SkyLake.Huang +Reviewed-by: Simon Horman +Signed-off-by: Andrew Lunn +--- + drivers/net/phy/mediatek-ge-soc.c | 36 ++++++++++++++++--------------- + 1 file changed, 19 insertions(+), 17 deletions(-) + +diff --git a/drivers/net/phy/mediatek-ge-soc.c b/drivers/net/phy/mediatek-ge-soc.c +index f4f9412d0cd7..e9c422f4e24b 100644 +--- a/drivers/net/phy/mediatek-ge-soc.c ++++ b/drivers/net/phy/mediatek-ge-soc.c +@@ -408,16 +408,17 @@ static int tx_offset_cal_efuse(struct phy_device *phydev, u32 *buf) + + static int tx_amp_fill_result(struct phy_device *phydev, u16 *buf) + { +- int i; +- int bias[16] = {}; +- const int vals_9461[16] = { 7, 1, 4, 7, +- 7, 1, 4, 7, +- 7, 1, 4, 7, +- 7, 1, 4, 7 }; + const int vals_9481[16] = { 10, 6, 6, 10, + 10, 6, 6, 10, + 10, 6, 6, 10, + 10, 6, 6, 10 }; ++ const int vals_9461[16] = { 7, 1, 4, 7, ++ 7, 1, 4, 7, ++ 7, 1, 4, 7, ++ 7, 1, 4, 7 }; ++ int bias[16] = {}; ++ int i; ++ + switch (phydev->drv->phy_id) { + case MTK_GPHY_ID_MT7981: + /* We add some calibration to efuse values +@@ -1069,10 +1070,10 @@ static int start_cal(struct phy_device *phydev, enum CAL_ITEM cal_item, + + static int mt798x_phy_calibration(struct phy_device *phydev) + { ++ struct nvmem_cell *cell; + int ret = 0; +- u32 *buf; + size_t len; +- struct nvmem_cell *cell; ++ u32 *buf; + + cell = nvmem_cell_get(&phydev->mdio.dev, "phy-cal-data"); + if (IS_ERR(cell)) { +@@ -1210,14 +1211,15 @@ static int mt798x_phy_led_brightness_set(struct phy_device *phydev, + return mt798x_phy_hw_led_on_set(phydev, index, (value != LED_OFF)); + } + +-static const unsigned long supported_triggers = (BIT(TRIGGER_NETDEV_FULL_DUPLEX) | +- BIT(TRIGGER_NETDEV_HALF_DUPLEX) | +- BIT(TRIGGER_NETDEV_LINK) | +- BIT(TRIGGER_NETDEV_LINK_10) | +- BIT(TRIGGER_NETDEV_LINK_100) | +- BIT(TRIGGER_NETDEV_LINK_1000) | +- BIT(TRIGGER_NETDEV_RX) | +- BIT(TRIGGER_NETDEV_TX)); ++static const unsigned long supported_triggers = ++ BIT(TRIGGER_NETDEV_FULL_DUPLEX) | ++ BIT(TRIGGER_NETDEV_HALF_DUPLEX) | ++ BIT(TRIGGER_NETDEV_LINK) | ++ BIT(TRIGGER_NETDEV_LINK_10) | ++ BIT(TRIGGER_NETDEV_LINK_100) | ++ BIT(TRIGGER_NETDEV_LINK_1000) | ++ BIT(TRIGGER_NETDEV_RX) | ++ BIT(TRIGGER_NETDEV_TX); + + static int mt798x_phy_led_hw_is_supported(struct phy_device *phydev, u8 index, + unsigned long rules) +@@ -1415,7 +1417,7 @@ static int mt7988_phy_probe_shared(struct phy_device *phydev) + * LED_C and LED_D respectively. At the same time those pins are used to + * bootstrap configuration of the reference clock source (LED_A), + * DRAM DDRx16b x2/x1 (LED_B) and boot device (LED_C, LED_D). +- * In practise this is done using a LED and a resistor pulling the pin ++ * In practice this is done using a LED and a resistor pulling the pin + * either to GND or to VIO. + * The detected value at boot time is accessible at run-time using the + * TPBANK0 register located in the gpio base of the pinctrl, in order +-- +2.51.0 + + +From 450ae2beafadb9d3a78227c4c882e9635a55b0f3 Mon Sep 17 00:00:00 2001 +From: "SkyLake.Huang" +Date: Thu, 17 Oct 2024 11:22:12 +0800 +Subject: [PATCH 068/517] net: phy: mediatek-ge-soc: Shrink line wrapping to 80 + characters + +This patch shrinks line wrapping to 80 chars. Also, in +tx_amp_fill_result(), use FIELD_PREP() to prettify code. + +Signed-off-by: SkyLake.Huang +Reviewed-by: Simon Horman +Signed-off-by: Andrew Lunn +--- + drivers/net/phy/mediatek-ge-soc.c | 125 +++++++++++++++++++++--------- + 1 file changed, 88 insertions(+), 37 deletions(-) + +diff --git a/drivers/net/phy/mediatek-ge-soc.c b/drivers/net/phy/mediatek-ge-soc.c +index e9c422f4e24b..1d7719b6c351 100644 +--- a/drivers/net/phy/mediatek-ge-soc.c ++++ b/drivers/net/phy/mediatek-ge-soc.c +@@ -342,7 +342,8 @@ static int cal_cycle(struct phy_device *phydev, int devad, + ret = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_AD_CAL_CLK, reg_val, + reg_val & MTK_PHY_DA_CAL_CLK, 500, +- ANALOG_INTERNAL_OPERATION_MAX_US, false); ++ ANALOG_INTERNAL_OPERATION_MAX_US, ++ false); + if (ret) { + phydev_err(phydev, "Calibration cycle timeout\n"); + return ret; +@@ -441,40 +442,72 @@ static int tx_amp_fill_result(struct phy_device *phydev, u16 *buf) + } + + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG, +- MTK_PHY_DA_TX_I2MPB_A_GBE_MASK, (buf[0] + bias[0]) << 10); ++ MTK_PHY_DA_TX_I2MPB_A_GBE_MASK, ++ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_GBE_MASK, ++ buf[0] + bias[0])); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG, +- MTK_PHY_DA_TX_I2MPB_A_TBT_MASK, buf[0] + bias[1]); ++ MTK_PHY_DA_TX_I2MPB_A_TBT_MASK, ++ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_TBT_MASK, ++ buf[0] + bias[1])); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2, +- MTK_PHY_DA_TX_I2MPB_A_HBT_MASK, (buf[0] + bias[2]) << 10); ++ MTK_PHY_DA_TX_I2MPB_A_HBT_MASK, ++ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_HBT_MASK, ++ buf[0] + bias[2])); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2, +- MTK_PHY_DA_TX_I2MPB_A_TST_MASK, buf[0] + bias[3]); ++ MTK_PHY_DA_TX_I2MPB_A_TST_MASK, ++ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_TST_MASK, ++ buf[0] + bias[3])); + + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1, +- MTK_PHY_DA_TX_I2MPB_B_GBE_MASK, (buf[1] + bias[4]) << 8); ++ MTK_PHY_DA_TX_I2MPB_B_GBE_MASK, ++ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_GBE_MASK, ++ buf[1] + bias[4])); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1, +- MTK_PHY_DA_TX_I2MPB_B_TBT_MASK, buf[1] + bias[5]); ++ MTK_PHY_DA_TX_I2MPB_B_TBT_MASK, ++ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_TBT_MASK, ++ buf[1] + bias[5])); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2, +- MTK_PHY_DA_TX_I2MPB_B_HBT_MASK, (buf[1] + bias[6]) << 8); ++ MTK_PHY_DA_TX_I2MPB_B_HBT_MASK, ++ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_HBT_MASK, ++ buf[1] + bias[6])); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2, +- MTK_PHY_DA_TX_I2MPB_B_TST_MASK, buf[1] + bias[7]); ++ MTK_PHY_DA_TX_I2MPB_B_TST_MASK, ++ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_TST_MASK, ++ buf[1] + bias[7])); + + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1, +- MTK_PHY_DA_TX_I2MPB_C_GBE_MASK, (buf[2] + bias[8]) << 8); ++ MTK_PHY_DA_TX_I2MPB_C_GBE_MASK, ++ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_GBE_MASK, ++ buf[2] + bias[8])); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1, +- MTK_PHY_DA_TX_I2MPB_C_TBT_MASK, buf[2] + bias[9]); ++ MTK_PHY_DA_TX_I2MPB_C_TBT_MASK, ++ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_TBT_MASK, ++ buf[2] + bias[9])); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2, +- MTK_PHY_DA_TX_I2MPB_C_HBT_MASK, (buf[2] + bias[10]) << 8); ++ MTK_PHY_DA_TX_I2MPB_C_HBT_MASK, ++ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_HBT_MASK, ++ buf[2] + bias[10])); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2, +- MTK_PHY_DA_TX_I2MPB_C_TST_MASK, buf[2] + bias[11]); ++ MTK_PHY_DA_TX_I2MPB_C_TST_MASK, ++ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_TST_MASK, ++ buf[2] + bias[11])); + + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1, +- MTK_PHY_DA_TX_I2MPB_D_GBE_MASK, (buf[3] + bias[12]) << 8); ++ MTK_PHY_DA_TX_I2MPB_D_GBE_MASK, ++ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_GBE_MASK, ++ buf[3] + bias[12])); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1, +- MTK_PHY_DA_TX_I2MPB_D_TBT_MASK, buf[3] + bias[13]); ++ MTK_PHY_DA_TX_I2MPB_D_TBT_MASK, ++ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_TBT_MASK, ++ buf[3] + bias[13])); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2, +- MTK_PHY_DA_TX_I2MPB_D_HBT_MASK, (buf[3] + bias[14]) << 8); ++ MTK_PHY_DA_TX_I2MPB_D_HBT_MASK, ++ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_HBT_MASK, ++ buf[3] + bias[14])); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2, +- MTK_PHY_DA_TX_I2MPB_D_TST_MASK, buf[3] + bias[15]); ++ MTK_PHY_DA_TX_I2MPB_D_TST_MASK, ++ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_TST_MASK, ++ buf[3] + bias[15])); + + return 0; + } +@@ -663,7 +696,8 @@ static int tx_vcm_cal_sw(struct phy_device *phydev, u8 rg_txreserve_x) + goto restore; + + /* We calibrate TX-VCM in different logic. Check upper index and then +- * lower index. If this calibration is valid, apply lower index's result. ++ * lower index. If this calibration is valid, apply lower index's ++ * result. + */ + ret = upper_ret - lower_ret; + if (ret == 1) { +@@ -692,7 +726,8 @@ static int tx_vcm_cal_sw(struct phy_device *phydev, u8 rg_txreserve_x) + } else if (upper_idx == TXRESERVE_MAX && upper_ret == 0 && + lower_ret == 0) { + ret = 0; +- phydev_warn(phydev, "TX-VCM SW cal result at high margin 0x%x\n", ++ phydev_warn(phydev, ++ "TX-VCM SW cal result at high margin 0x%x\n", + upper_idx); + } else { + ret = -EINVAL; +@@ -796,7 +831,8 @@ static void mt7981_phy_finetune(struct phy_device *phydev) + + /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 9 */ + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234, +- MTK_PHY_TR_OPEN_LOOP_EN_MASK | MTK_PHY_LPF_X_AVERAGE_MASK, ++ MTK_PHY_TR_OPEN_LOOP_EN_MASK | ++ MTK_PHY_LPF_X_AVERAGE_MASK, + BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0x9)); + + /* rg_tr_lpf_cnt_val = 512 */ +@@ -865,7 +901,8 @@ static void mt7988_phy_finetune(struct phy_device *phydev) + + /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 10 */ + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234, +- MTK_PHY_TR_OPEN_LOOP_EN_MASK | MTK_PHY_LPF_X_AVERAGE_MASK, ++ MTK_PHY_TR_OPEN_LOOP_EN_MASK | ++ MTK_PHY_LPF_X_AVERAGE_MASK, + BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0xa)); + + /* rg_tr_lpf_cnt_val = 1023 */ +@@ -977,7 +1014,8 @@ static void mt798x_phy_eee(struct phy_device *phydev) + phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0); + + phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_3); +- __phy_modify(phydev, MTK_PHY_LPI_REG_14, MTK_PHY_LPI_WAKE_TIMER_1000_MASK, ++ __phy_modify(phydev, MTK_PHY_LPI_REG_14, ++ MTK_PHY_LPI_WAKE_TIMER_1000_MASK, + FIELD_PREP(MTK_PHY_LPI_WAKE_TIMER_1000_MASK, 0x19c)); + + __phy_modify(phydev, MTK_PHY_LPI_REG_1c, MTK_PHY_SMI_DET_ON_THRESH_MASK, +@@ -987,7 +1025,8 @@ static void mt798x_phy_eee(struct phy_device *phydev) + phy_modify_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122, + MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK, +- FIELD_PREP(MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK, 0xff)); ++ FIELD_PREP(MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK, ++ 0xff)); + } + + static int cal_sw(struct phy_device *phydev, enum CAL_ITEM cal_item, +@@ -1147,7 +1186,8 @@ static int mt798x_phy_hw_led_on_set(struct phy_device *phydev, u8 index, + (index ? 16 : 0), &priv->led_state); + if (changed) + return phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ? +- MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL, ++ MTK_PHY_LED1_ON_CTRL : ++ MTK_PHY_LED0_ON_CTRL, + MTK_PHY_LED_ON_MASK, + on ? MTK_PHY_LED_ON_FORCE_ON : 0); + else +@@ -1157,7 +1197,8 @@ static int mt798x_phy_hw_led_on_set(struct phy_device *phydev, u8 index, + static int mt798x_phy_hw_led_blink_set(struct phy_device *phydev, u8 index, + bool blinking) + { +- unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK + (index ? 16 : 0); ++ unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK + ++ (index ? 16 : 0); + struct mtk_socphy_priv *priv = phydev->priv; + bool changed; + +@@ -1170,8 +1211,10 @@ static int mt798x_phy_hw_led_blink_set(struct phy_device *phydev, u8 index, + (index ? 16 : 0), &priv->led_state); + if (changed) + return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ? +- MTK_PHY_LED1_BLINK_CTRL : MTK_PHY_LED0_BLINK_CTRL, +- blinking ? MTK_PHY_LED_BLINK_FORCE_BLINK : 0); ++ MTK_PHY_LED1_BLINK_CTRL : ++ MTK_PHY_LED0_BLINK_CTRL, ++ blinking ? ++ MTK_PHY_LED_BLINK_FORCE_BLINK : 0); + else + return 0; + } +@@ -1237,7 +1280,8 @@ static int mt798x_phy_led_hw_is_supported(struct phy_device *phydev, u8 index, + static int mt798x_phy_led_hw_control_get(struct phy_device *phydev, u8 index, + unsigned long *rules) + { +- unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK + (index ? 16 : 0); ++ unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK + ++ (index ? 16 : 0); + unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0); + unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0); + struct mtk_socphy_priv *priv = phydev->priv; +@@ -1258,8 +1302,8 @@ static int mt798x_phy_led_hw_control_get(struct phy_device *phydev, u8 index, + if (blink < 0) + return -EIO; + +- if ((on & (MTK_PHY_LED_ON_LINK | MTK_PHY_LED_ON_FDX | MTK_PHY_LED_ON_HDX | +- MTK_PHY_LED_ON_LINKDOWN)) || ++ if ((on & (MTK_PHY_LED_ON_LINK | MTK_PHY_LED_ON_FDX | ++ MTK_PHY_LED_ON_HDX | MTK_PHY_LED_ON_LINKDOWN)) || + (blink & (MTK_PHY_LED_BLINK_RX | MTK_PHY_LED_BLINK_TX))) + set_bit(bit_netdev, &priv->led_state); + else +@@ -1333,17 +1377,23 @@ static int mt798x_phy_led_hw_control_set(struct phy_device *phydev, u8 index, + + if (rules & BIT(TRIGGER_NETDEV_RX)) { + blink |= (on & MTK_PHY_LED_ON_LINK) ? +- (((on & MTK_PHY_LED_ON_LINK10) ? MTK_PHY_LED_BLINK_10RX : 0) | +- ((on & MTK_PHY_LED_ON_LINK100) ? MTK_PHY_LED_BLINK_100RX : 0) | +- ((on & MTK_PHY_LED_ON_LINK1000) ? MTK_PHY_LED_BLINK_1000RX : 0)) : ++ (((on & MTK_PHY_LED_ON_LINK10) ? ++ MTK_PHY_LED_BLINK_10RX : 0) | ++ ((on & MTK_PHY_LED_ON_LINK100) ? ++ MTK_PHY_LED_BLINK_100RX : 0) | ++ ((on & MTK_PHY_LED_ON_LINK1000) ? ++ MTK_PHY_LED_BLINK_1000RX : 0)) : + MTK_PHY_LED_BLINK_RX; + } + + if (rules & BIT(TRIGGER_NETDEV_TX)) { + blink |= (on & MTK_PHY_LED_ON_LINK) ? +- (((on & MTK_PHY_LED_ON_LINK10) ? MTK_PHY_LED_BLINK_10TX : 0) | +- ((on & MTK_PHY_LED_ON_LINK100) ? MTK_PHY_LED_BLINK_100TX : 0) | +- ((on & MTK_PHY_LED_ON_LINK1000) ? MTK_PHY_LED_BLINK_1000TX : 0)) : ++ (((on & MTK_PHY_LED_ON_LINK10) ? ++ MTK_PHY_LED_BLINK_10TX : 0) | ++ ((on & MTK_PHY_LED_ON_LINK100) ? ++ MTK_PHY_LED_BLINK_100TX : 0) | ++ ((on & MTK_PHY_LED_ON_LINK1000) ? ++ MTK_PHY_LED_BLINK_1000TX : 0)) : + MTK_PHY_LED_BLINK_TX; + } + +@@ -1400,7 +1450,8 @@ static int mt7988_phy_fix_leds_polarities(struct phy_device *phydev) + /* Only now setup pinctrl to avoid bogus blinking */ + pinctrl = devm_pinctrl_get_select(&phydev->mdio.dev, "gbe-led"); + if (IS_ERR(pinctrl)) +- dev_err(&phydev->mdio.bus->dev, "Failed to setup PHY LED pinctrl\n"); ++ dev_err(&phydev->mdio.bus->dev, ++ "Failed to setup PHY LED pinctrl\n"); + + return 0; + } +-- +2.51.0 + + +From 2c093d2f19967ec88a8f318d63fbad315b3435df Mon Sep 17 00:00:00 2001 +From: "SkyLake.Huang" +Date: Thu, 17 Oct 2024 11:22:13 +0800 +Subject: [PATCH 069/517] net: phy: mediatek-ge-soc: Propagate error code + correctly in cal_cycle() + +This patch propagates error code correctly in cal_cycle() +and improve with FIELD_GET(). + +Signed-off-by: SkyLake.Huang +Reviewed-by: Simon Horman +Signed-off-by: Andrew Lunn +--- + drivers/net/phy/mediatek-ge-soc.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/phy/mediatek-ge-soc.c b/drivers/net/phy/mediatek-ge-soc.c +index 1d7719b6c351..a931832b1418 100644 +--- a/drivers/net/phy/mediatek-ge-soc.c ++++ b/drivers/net/phy/mediatek-ge-soc.c +@@ -110,7 +110,7 @@ + #define MTK_PHY_CR_TX_AMP_OFFSET_D_MASK GENMASK(6, 0) + + #define MTK_PHY_RG_AD_CAL_COMP 0x17a +-#define MTK_PHY_AD_CAL_COMP_OUT_SHIFT (8) ++#define MTK_PHY_AD_CAL_COMP_OUT_MASK GENMASK(8, 8) + + #define MTK_PHY_RG_AD_CAL_CLK 0x17b + #define MTK_PHY_DA_CAL_CLK BIT(0) +@@ -351,8 +351,10 @@ static int cal_cycle(struct phy_device *phydev, int devad, + + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CALIN, + MTK_PHY_DA_CALIN_FLAG); +- ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CAL_COMP) >> +- MTK_PHY_AD_CAL_COMP_OUT_SHIFT; ++ ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CAL_COMP); ++ if (ret < 0) ++ return ret; ++ ret = FIELD_GET(MTK_PHY_AD_CAL_COMP_OUT_MASK, ret); + phydev_dbg(phydev, "cal_val: 0x%x, ret: %d\n", cal_val, ret); + + return ret; +-- +2.51.0 + + +From d0e33fc271ee343d7da7e84dbbc07e3999b2b5af Mon Sep 17 00:00:00 2001 +From: "SkyLake.Huang" +Date: Sat, 9 Nov 2024 00:34:51 +0800 +Subject: [PATCH 070/517] net: phy: mediatek: Re-organize MediaTek ethernet phy + drivers + +Re-organize MediaTek ethernet phy driver files and get ready to integrate +some common functions and add new 2.5G phy driver. +mtk-ge.c: MT7530 Gphy on MT7621 & MT7531 Gphy +mtk-ge-soc.c: Built-in Gphy on MT7981 & Built-in switch Gphy on MT7988 +mtk-2p5ge.c: Planned for built-in 2.5G phy on MT7988 + +Reviewed-by: Andrew Lunn +Signed-off-by: SkyLake.Huang +Signed-off-by: David S. Miller +--- + MAINTAINERS | 4 ++-- + drivers/net/phy/Kconfig | 17 +------------- + drivers/net/phy/Makefile | 3 +-- + drivers/net/phy/mediatek/Kconfig | 22 +++++++++++++++++++ + drivers/net/phy/mediatek/Makefile | 3 +++ + .../mtk-ge-soc.c} | 0 + .../phy/{mediatek-ge.c => mediatek/mtk-ge.c} | 0 + 7 files changed, 29 insertions(+), 20 deletions(-) + create mode 100644 drivers/net/phy/mediatek/Kconfig + create mode 100644 drivers/net/phy/mediatek/Makefile + rename drivers/net/phy/{mediatek-ge-soc.c => mediatek/mtk-ge-soc.c} (100%) + rename drivers/net/phy/{mediatek-ge.c => mediatek/mtk-ge.c} (100%) + +diff --git a/MAINTAINERS b/MAINTAINERS +index d0f18fdba068..7aab943889e0 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -14427,8 +14427,8 @@ M: Qingfang Deng + M: SkyLake Huang + L: netdev@vger.kernel.org + S: Maintained +-F: drivers/net/phy/mediatek-ge-soc.c +-F: drivers/net/phy/mediatek-ge.c ++F: drivers/net/phy/mediatek/mtk-ge-soc.c ++F: drivers/net/phy/mediatek/mtk-ge.c + F: drivers/phy/mediatek/phy-mtk-xfi-tphy.c + + MEDIATEK I2C CONTROLLER DRIVER +diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig +index 01b235b3bb7e..4e78a4d8fd2a 100644 +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -266,22 +266,7 @@ config MAXLINEAR_GPHY + Support for the Maxlinear GPY115, GPY211, GPY212, GPY215, + GPY241, GPY245 PHYs. + +-config MEDIATEK_GE_PHY +- tristate "MediaTek Gigabit Ethernet PHYs" +- help +- Supports the MediaTek Gigabit Ethernet PHYs. +- +-config MEDIATEK_GE_SOC_PHY +- tristate "MediaTek SoC Ethernet PHYs" +- depends on (ARM64 && ARCH_MEDIATEK) || COMPILE_TEST +- depends on NVMEM_MTK_EFUSE +- help +- Supports MediaTek SoC built-in Gigabit Ethernet PHYs. +- +- Include support for built-in Ethernet PHYs which are present in +- the MT7981 and MT7988 SoCs. These PHYs need calibration data +- present in the SoCs efuse and will dynamically calibrate VCM +- (common-mode voltage) during startup. ++source "drivers/net/phy/mediatek/Kconfig" + + config MICREL_PHY + tristate "Micrel PHYs" +diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile +index 90f886844381..e6145153e837 100644 +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -74,8 +74,7 @@ obj-$(CONFIG_MARVELL_PHY) += marvell.o + obj-$(CONFIG_MARVELL_88Q2XXX_PHY) += marvell-88q2xxx.o + obj-$(CONFIG_MARVELL_88X2222_PHY) += marvell-88x2222.o + obj-$(CONFIG_MAXLINEAR_GPHY) += mxl-gpy.o +-obj-$(CONFIG_MEDIATEK_GE_PHY) += mediatek-ge.o +-obj-$(CONFIG_MEDIATEK_GE_SOC_PHY) += mediatek-ge-soc.o ++obj-y += mediatek/ + obj-$(CONFIG_MESON_GXL_PHY) += meson-gxl.o + obj-$(CONFIG_MICREL_KS8995MA) += spi_ks8995.o + obj-$(CONFIG_MICREL_PHY) += micrel.o +diff --git a/drivers/net/phy/mediatek/Kconfig b/drivers/net/phy/mediatek/Kconfig +new file mode 100644 +index 000000000000..112d9c0f219c +--- /dev/null ++++ b/drivers/net/phy/mediatek/Kconfig +@@ -0,0 +1,22 @@ ++# SPDX-License-Identifier: GPL-2.0-only ++config MEDIATEK_GE_PHY ++ tristate "MediaTek Gigabit Ethernet PHYs" ++ help ++ Supports the MediaTek non-built-in Gigabit Ethernet PHYs. ++ ++ Non-built-in Gigabit Ethernet PHYs include mt7530/mt7531. ++ You may find mt7530 inside mt7621. This driver shares some ++ common operations with MediaTek SoC built-in Gigabit ++ Ethernet PHYs. ++ ++config MEDIATEK_GE_SOC_PHY ++ tristate "MediaTek SoC Ethernet PHYs" ++ depends on (ARM64 && ARCH_MEDIATEK) || COMPILE_TEST ++ depends on NVMEM_MTK_EFUSE ++ help ++ Supports MediaTek SoC built-in Gigabit Ethernet PHYs. ++ ++ Include support for built-in Ethernet PHYs which are present in ++ the MT7981 and MT7988 SoCs. These PHYs need calibration data ++ present in the SoCs efuse and will dynamically calibrate VCM ++ (common-mode voltage) during startup. +diff --git a/drivers/net/phy/mediatek/Makefile b/drivers/net/phy/mediatek/Makefile +new file mode 100644 +index 000000000000..005bde26c1d7 +--- /dev/null ++++ b/drivers/net/phy/mediatek/Makefile +@@ -0,0 +1,3 @@ ++# SPDX-License-Identifier: GPL-2.0 ++obj-$(CONFIG_MEDIATEK_GE_PHY) += mtk-ge.o ++obj-$(CONFIG_MEDIATEK_GE_SOC_PHY) += mtk-ge-soc.o +diff --git a/drivers/net/phy/mediatek-ge-soc.c b/drivers/net/phy/mediatek/mtk-ge-soc.c +similarity index 100% +rename from drivers/net/phy/mediatek-ge-soc.c +rename to drivers/net/phy/mediatek/mtk-ge-soc.c +diff --git a/drivers/net/phy/mediatek-ge.c b/drivers/net/phy/mediatek/mtk-ge.c +similarity index 100% +rename from drivers/net/phy/mediatek-ge.c +rename to drivers/net/phy/mediatek/mtk-ge.c +-- +2.51.0 + + +From fcd36b51e49bdef0ba98bc6e63df359b475f2870 Mon Sep 17 00:00:00 2001 +From: "SkyLake.Huang" +Date: Sat, 9 Nov 2024 00:34:52 +0800 +Subject: [PATCH 071/517] net: phy: mediatek: Move LED helper functions into + mtk phy lib + +This patch creates mtk-phy-lib.c & mtk-phy.h and integrates mtk-ge-soc.c's +LED helper functions so that we can use those helper functions in other +MTK's ethernet phy driver. + +Reviewed-by: Andrew Lunn +Signed-off-by: SkyLake.Huang +Signed-off-by: David S. Miller +--- + MAINTAINERS | 2 + + drivers/net/phy/mediatek/Kconfig | 4 + + drivers/net/phy/mediatek/Makefile | 1 + + drivers/net/phy/mediatek/mtk-ge-soc.c | 280 +++---------------------- + drivers/net/phy/mediatek/mtk-phy-lib.c | 254 ++++++++++++++++++++++ + drivers/net/phy/mediatek/mtk.h | 86 ++++++++ + 6 files changed, 372 insertions(+), 255 deletions(-) + create mode 100644 drivers/net/phy/mediatek/mtk-phy-lib.c + create mode 100644 drivers/net/phy/mediatek/mtk.h + +diff --git a/MAINTAINERS b/MAINTAINERS +index 7aab943889e0..7d694e7b4f42 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -14428,7 +14428,9 @@ M: SkyLake Huang + L: netdev@vger.kernel.org + S: Maintained + F: drivers/net/phy/mediatek/mtk-ge-soc.c ++F: drivers/net/phy/mediatek/mtk-phy-lib.c + F: drivers/net/phy/mediatek/mtk-ge.c ++F: drivers/net/phy/mediatek/mtk.h + F: drivers/phy/mediatek/phy-mtk-xfi-tphy.c + + MEDIATEK I2C CONTROLLER DRIVER +diff --git a/drivers/net/phy/mediatek/Kconfig b/drivers/net/phy/mediatek/Kconfig +index 112d9c0f219c..19b5d23e7cd0 100644 +--- a/drivers/net/phy/mediatek/Kconfig ++++ b/drivers/net/phy/mediatek/Kconfig +@@ -1,4 +1,7 @@ + # SPDX-License-Identifier: GPL-2.0-only ++config MTK_NET_PHYLIB ++ tristate ++ + config MEDIATEK_GE_PHY + tristate "MediaTek Gigabit Ethernet PHYs" + help +@@ -13,6 +16,7 @@ config MEDIATEK_GE_SOC_PHY + tristate "MediaTek SoC Ethernet PHYs" + depends on (ARM64 && ARCH_MEDIATEK) || COMPILE_TEST + depends on NVMEM_MTK_EFUSE ++ select MTK_NET_PHYLIB + help + Supports MediaTek SoC built-in Gigabit Ethernet PHYs. + +diff --git a/drivers/net/phy/mediatek/Makefile b/drivers/net/phy/mediatek/Makefile +index 005bde26c1d7..814879d0abe5 100644 +--- a/drivers/net/phy/mediatek/Makefile ++++ b/drivers/net/phy/mediatek/Makefile +@@ -1,3 +1,4 @@ + # SPDX-License-Identifier: GPL-2.0 ++obj-$(CONFIG_MTK_NET_PHYLIB) += mtk-phy-lib.o + obj-$(CONFIG_MEDIATEK_GE_PHY) += mtk-ge.o + obj-$(CONFIG_MEDIATEK_GE_SOC_PHY) += mtk-ge-soc.o +diff --git a/drivers/net/phy/mediatek/mtk-ge-soc.c b/drivers/net/phy/mediatek/mtk-ge-soc.c +index a931832b1418..d3a8b3946056 100644 +--- a/drivers/net/phy/mediatek/mtk-ge-soc.c ++++ b/drivers/net/phy/mediatek/mtk-ge-soc.c +@@ -8,6 +8,8 @@ + #include + #include + ++#include "mtk.h" ++ + #define MTK_GPHY_ID_MT7981 0x03a29461 + #define MTK_GPHY_ID_MT7988 0x03a29481 + +@@ -210,41 +212,6 @@ + #define MTK_PHY_DA_TX_R50_PAIR_D 0x540 + + /* Registers on MDIO_MMD_VEND2 */ +-#define MTK_PHY_LED0_ON_CTRL 0x24 +-#define MTK_PHY_LED1_ON_CTRL 0x26 +-#define MTK_PHY_LED_ON_MASK GENMASK(6, 0) +-#define MTK_PHY_LED_ON_LINK1000 BIT(0) +-#define MTK_PHY_LED_ON_LINK100 BIT(1) +-#define MTK_PHY_LED_ON_LINK10 BIT(2) +-#define MTK_PHY_LED_ON_LINK (MTK_PHY_LED_ON_LINK10 |\ +- MTK_PHY_LED_ON_LINK100 |\ +- MTK_PHY_LED_ON_LINK1000) +-#define MTK_PHY_LED_ON_LINKDOWN BIT(3) +-#define MTK_PHY_LED_ON_FDX BIT(4) /* Full duplex */ +-#define MTK_PHY_LED_ON_HDX BIT(5) /* Half duplex */ +-#define MTK_PHY_LED_ON_FORCE_ON BIT(6) +-#define MTK_PHY_LED_ON_POLARITY BIT(14) +-#define MTK_PHY_LED_ON_ENABLE BIT(15) +- +-#define MTK_PHY_LED0_BLINK_CTRL 0x25 +-#define MTK_PHY_LED1_BLINK_CTRL 0x27 +-#define MTK_PHY_LED_BLINK_1000TX BIT(0) +-#define MTK_PHY_LED_BLINK_1000RX BIT(1) +-#define MTK_PHY_LED_BLINK_100TX BIT(2) +-#define MTK_PHY_LED_BLINK_100RX BIT(3) +-#define MTK_PHY_LED_BLINK_10TX BIT(4) +-#define MTK_PHY_LED_BLINK_10RX BIT(5) +-#define MTK_PHY_LED_BLINK_RX (MTK_PHY_LED_BLINK_10RX |\ +- MTK_PHY_LED_BLINK_100RX |\ +- MTK_PHY_LED_BLINK_1000RX) +-#define MTK_PHY_LED_BLINK_TX (MTK_PHY_LED_BLINK_10TX |\ +- MTK_PHY_LED_BLINK_100TX |\ +- MTK_PHY_LED_BLINK_1000TX) +-#define MTK_PHY_LED_BLINK_COLLISION BIT(6) +-#define MTK_PHY_LED_BLINK_RX_CRC_ERR BIT(7) +-#define MTK_PHY_LED_BLINK_RX_IDLE_ERR BIT(8) +-#define MTK_PHY_LED_BLINK_FORCE_BLINK BIT(9) +- + #define MTK_PHY_LED1_DEFAULT_POLARITIES BIT(1) + + #define MTK_PHY_RG_BG_RASEL 0x115 +@@ -299,14 +266,6 @@ enum CAL_MODE { + SW_M + }; + +-#define MTK_PHY_LED_STATE_FORCE_ON 0 +-#define MTK_PHY_LED_STATE_FORCE_BLINK 1 +-#define MTK_PHY_LED_STATE_NETDEV 2 +- +-struct mtk_socphy_priv { +- unsigned long led_state; +-}; +- + struct mtk_socphy_shared { + u32 boottrap; + struct mtk_socphy_priv priv[4]; +@@ -1172,76 +1131,23 @@ static int mt798x_phy_config_init(struct phy_device *phydev) + return mt798x_phy_calibration(phydev); + } + +-static int mt798x_phy_hw_led_on_set(struct phy_device *phydev, u8 index, +- bool on) +-{ +- unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0); +- struct mtk_socphy_priv *priv = phydev->priv; +- bool changed; +- +- if (on) +- changed = !test_and_set_bit(bit_on, &priv->led_state); +- else +- changed = !!test_and_clear_bit(bit_on, &priv->led_state); +- +- changed |= !!test_and_clear_bit(MTK_PHY_LED_STATE_NETDEV + +- (index ? 16 : 0), &priv->led_state); +- if (changed) +- return phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ? +- MTK_PHY_LED1_ON_CTRL : +- MTK_PHY_LED0_ON_CTRL, +- MTK_PHY_LED_ON_MASK, +- on ? MTK_PHY_LED_ON_FORCE_ON : 0); +- else +- return 0; +-} +- +-static int mt798x_phy_hw_led_blink_set(struct phy_device *phydev, u8 index, +- bool blinking) +-{ +- unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK + +- (index ? 16 : 0); +- struct mtk_socphy_priv *priv = phydev->priv; +- bool changed; +- +- if (blinking) +- changed = !test_and_set_bit(bit_blink, &priv->led_state); +- else +- changed = !!test_and_clear_bit(bit_blink, &priv->led_state); +- +- changed |= !!test_bit(MTK_PHY_LED_STATE_NETDEV + +- (index ? 16 : 0), &priv->led_state); +- if (changed) +- return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ? +- MTK_PHY_LED1_BLINK_CTRL : +- MTK_PHY_LED0_BLINK_CTRL, +- blinking ? +- MTK_PHY_LED_BLINK_FORCE_BLINK : 0); +- else +- return 0; +-} +- + static int mt798x_phy_led_blink_set(struct phy_device *phydev, u8 index, + unsigned long *delay_on, + unsigned long *delay_off) + { + bool blinking = false; +- int err = 0; +- +- if (index > 1) +- return -EINVAL; ++ int err; + +- if (delay_on && delay_off && (*delay_on > 0) && (*delay_off > 0)) { +- blinking = true; +- *delay_on = 50; +- *delay_off = 50; +- } ++ err = mtk_phy_led_num_dly_cfg(index, delay_on, delay_off, &blinking); ++ if (err < 0) ++ return err; + +- err = mt798x_phy_hw_led_blink_set(phydev, index, blinking); ++ err = mtk_phy_hw_led_blink_set(phydev, index, blinking); + if (err) + return err; + +- return mt798x_phy_hw_led_on_set(phydev, index, false); ++ return mtk_phy_hw_led_on_set(phydev, index, MTK_GPHY_LED_ON_MASK, ++ false); + } + + static int mt798x_phy_led_brightness_set(struct phy_device *phydev, +@@ -1249,11 +1155,12 @@ static int mt798x_phy_led_brightness_set(struct phy_device *phydev, + { + int err; + +- err = mt798x_phy_hw_led_blink_set(phydev, index, false); ++ err = mtk_phy_hw_led_blink_set(phydev, index, false); + if (err) + return err; + +- return mt798x_phy_hw_led_on_set(phydev, index, (value != LED_OFF)); ++ return mtk_phy_hw_led_on_set(phydev, index, MTK_GPHY_LED_ON_MASK, ++ (value != LED_OFF)); + } + + static const unsigned long supported_triggers = +@@ -1269,155 +1176,26 @@ static const unsigned long supported_triggers = + static int mt798x_phy_led_hw_is_supported(struct phy_device *phydev, u8 index, + unsigned long rules) + { +- if (index > 1) +- return -EINVAL; +- +- /* All combinations of the supported triggers are allowed */ +- if (rules & ~supported_triggers) +- return -EOPNOTSUPP; +- +- return 0; +-}; ++ return mtk_phy_led_hw_is_supported(phydev, index, rules, ++ supported_triggers); ++} + + static int mt798x_phy_led_hw_control_get(struct phy_device *phydev, u8 index, + unsigned long *rules) + { +- unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK + +- (index ? 16 : 0); +- unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0); +- unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0); +- struct mtk_socphy_priv *priv = phydev->priv; +- int on, blink; +- +- if (index > 1) +- return -EINVAL; +- +- on = phy_read_mmd(phydev, MDIO_MMD_VEND2, +- index ? MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL); +- +- if (on < 0) +- return -EIO; +- +- blink = phy_read_mmd(phydev, MDIO_MMD_VEND2, +- index ? MTK_PHY_LED1_BLINK_CTRL : +- MTK_PHY_LED0_BLINK_CTRL); +- if (blink < 0) +- return -EIO; +- +- if ((on & (MTK_PHY_LED_ON_LINK | MTK_PHY_LED_ON_FDX | +- MTK_PHY_LED_ON_HDX | MTK_PHY_LED_ON_LINKDOWN)) || +- (blink & (MTK_PHY_LED_BLINK_RX | MTK_PHY_LED_BLINK_TX))) +- set_bit(bit_netdev, &priv->led_state); +- else +- clear_bit(bit_netdev, &priv->led_state); +- +- if (on & MTK_PHY_LED_ON_FORCE_ON) +- set_bit(bit_on, &priv->led_state); +- else +- clear_bit(bit_on, &priv->led_state); +- +- if (blink & MTK_PHY_LED_BLINK_FORCE_BLINK) +- set_bit(bit_blink, &priv->led_state); +- else +- clear_bit(bit_blink, &priv->led_state); +- +- if (!rules) +- return 0; +- +- if (on & MTK_PHY_LED_ON_LINK) +- *rules |= BIT(TRIGGER_NETDEV_LINK); +- +- if (on & MTK_PHY_LED_ON_LINK10) +- *rules |= BIT(TRIGGER_NETDEV_LINK_10); +- +- if (on & MTK_PHY_LED_ON_LINK100) +- *rules |= BIT(TRIGGER_NETDEV_LINK_100); +- +- if (on & MTK_PHY_LED_ON_LINK1000) +- *rules |= BIT(TRIGGER_NETDEV_LINK_1000); +- +- if (on & MTK_PHY_LED_ON_FDX) +- *rules |= BIT(TRIGGER_NETDEV_FULL_DUPLEX); +- +- if (on & MTK_PHY_LED_ON_HDX) +- *rules |= BIT(TRIGGER_NETDEV_HALF_DUPLEX); +- +- if (blink & MTK_PHY_LED_BLINK_RX) +- *rules |= BIT(TRIGGER_NETDEV_RX); +- +- if (blink & MTK_PHY_LED_BLINK_TX) +- *rules |= BIT(TRIGGER_NETDEV_TX); +- +- return 0; ++ return mtk_phy_led_hw_ctrl_get(phydev, index, rules, ++ MTK_GPHY_LED_ON_SET, ++ MTK_GPHY_LED_RX_BLINK_SET, ++ MTK_GPHY_LED_TX_BLINK_SET); + }; + + static int mt798x_phy_led_hw_control_set(struct phy_device *phydev, u8 index, + unsigned long rules) + { +- unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0); +- struct mtk_socphy_priv *priv = phydev->priv; +- u16 on = 0, blink = 0; +- int ret; +- +- if (index > 1) +- return -EINVAL; +- +- if (rules & BIT(TRIGGER_NETDEV_FULL_DUPLEX)) +- on |= MTK_PHY_LED_ON_FDX; +- +- if (rules & BIT(TRIGGER_NETDEV_HALF_DUPLEX)) +- on |= MTK_PHY_LED_ON_HDX; +- +- if (rules & (BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK))) +- on |= MTK_PHY_LED_ON_LINK10; +- +- if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK))) +- on |= MTK_PHY_LED_ON_LINK100; +- +- if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK))) +- on |= MTK_PHY_LED_ON_LINK1000; +- +- if (rules & BIT(TRIGGER_NETDEV_RX)) { +- blink |= (on & MTK_PHY_LED_ON_LINK) ? +- (((on & MTK_PHY_LED_ON_LINK10) ? +- MTK_PHY_LED_BLINK_10RX : 0) | +- ((on & MTK_PHY_LED_ON_LINK100) ? +- MTK_PHY_LED_BLINK_100RX : 0) | +- ((on & MTK_PHY_LED_ON_LINK1000) ? +- MTK_PHY_LED_BLINK_1000RX : 0)) : +- MTK_PHY_LED_BLINK_RX; +- } +- +- if (rules & BIT(TRIGGER_NETDEV_TX)) { +- blink |= (on & MTK_PHY_LED_ON_LINK) ? +- (((on & MTK_PHY_LED_ON_LINK10) ? +- MTK_PHY_LED_BLINK_10TX : 0) | +- ((on & MTK_PHY_LED_ON_LINK100) ? +- MTK_PHY_LED_BLINK_100TX : 0) | +- ((on & MTK_PHY_LED_ON_LINK1000) ? +- MTK_PHY_LED_BLINK_1000TX : 0)) : +- MTK_PHY_LED_BLINK_TX; +- } +- +- if (blink || on) +- set_bit(bit_netdev, &priv->led_state); +- else +- clear_bit(bit_netdev, &priv->led_state); +- +- ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ? +- MTK_PHY_LED1_ON_CTRL : +- MTK_PHY_LED0_ON_CTRL, +- MTK_PHY_LED_ON_FDX | +- MTK_PHY_LED_ON_HDX | +- MTK_PHY_LED_ON_LINK, +- on); +- +- if (ret) +- return ret; +- +- return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ? +- MTK_PHY_LED1_BLINK_CTRL : +- MTK_PHY_LED0_BLINK_CTRL, blink); ++ return mtk_phy_led_hw_ctrl_set(phydev, index, rules, ++ MTK_GPHY_LED_ON_SET, ++ MTK_GPHY_LED_RX_BLINK_SET, ++ MTK_GPHY_LED_TX_BLINK_SET); + }; + + static bool mt7988_phy_led_get_polarity(struct phy_device *phydev, int led_num) +@@ -1492,14 +1270,6 @@ static int mt7988_phy_probe_shared(struct phy_device *phydev) + return 0; + } + +-static void mt798x_phy_leds_state_init(struct phy_device *phydev) +-{ +- int i; +- +- for (i = 0; i < 2; ++i) +- mt798x_phy_led_hw_control_get(phydev, i, NULL); +-} +- + static int mt7988_phy_probe(struct phy_device *phydev) + { + struct mtk_socphy_shared *shared; +@@ -1525,7 +1295,7 @@ static int mt7988_phy_probe(struct phy_device *phydev) + + phydev->priv = priv; + +- mt798x_phy_leds_state_init(phydev); ++ mtk_phy_leds_state_init(phydev); + + err = mt7988_phy_fix_leds_polarities(phydev); + if (err) +@@ -1552,7 +1322,7 @@ static int mt7981_phy_probe(struct phy_device *phydev) + + phydev->priv = priv; + +- mt798x_phy_leds_state_init(phydev); ++ mtk_phy_leds_state_init(phydev); + + return mt798x_phy_calibration(phydev); + } +diff --git a/drivers/net/phy/mediatek/mtk-phy-lib.c b/drivers/net/phy/mediatek/mtk-phy-lib.c +new file mode 100644 +index 000000000000..34b0957b201b +--- /dev/null ++++ b/drivers/net/phy/mediatek/mtk-phy-lib.c +@@ -0,0 +1,254 @@ ++// SPDX-License-Identifier: GPL-2.0 ++#include ++#include ++ ++#include ++ ++#include "mtk.h" ++ ++int mtk_phy_led_hw_is_supported(struct phy_device *phydev, u8 index, ++ unsigned long rules, ++ unsigned long supported_triggers) ++{ ++ if (index > 1) ++ return -EINVAL; ++ ++ /* All combinations of the supported triggers are allowed */ ++ if (rules & ~supported_triggers) ++ return -EOPNOTSUPP; ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(mtk_phy_led_hw_is_supported); ++ ++int mtk_phy_led_hw_ctrl_get(struct phy_device *phydev, u8 index, ++ unsigned long *rules, u16 on_set, ++ u16 rx_blink_set, u16 tx_blink_set) ++{ ++ unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK + ++ (index ? 16 : 0); ++ unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0); ++ unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0); ++ struct mtk_socphy_priv *priv = phydev->priv; ++ int on, blink; ++ ++ if (index > 1) ++ return -EINVAL; ++ ++ on = phy_read_mmd(phydev, MDIO_MMD_VEND2, ++ index ? MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL); ++ ++ if (on < 0) ++ return -EIO; ++ ++ blink = phy_read_mmd(phydev, MDIO_MMD_VEND2, ++ index ? MTK_PHY_LED1_BLINK_CTRL : ++ MTK_PHY_LED0_BLINK_CTRL); ++ if (blink < 0) ++ return -EIO; ++ ++ if ((on & (on_set | MTK_PHY_LED_ON_FDX | ++ MTK_PHY_LED_ON_HDX | MTK_PHY_LED_ON_LINKDOWN)) || ++ (blink & (rx_blink_set | tx_blink_set))) ++ set_bit(bit_netdev, &priv->led_state); ++ else ++ clear_bit(bit_netdev, &priv->led_state); ++ ++ if (on & MTK_PHY_LED_ON_FORCE_ON) ++ set_bit(bit_on, &priv->led_state); ++ else ++ clear_bit(bit_on, &priv->led_state); ++ ++ if (blink & MTK_PHY_LED_BLINK_FORCE_BLINK) ++ set_bit(bit_blink, &priv->led_state); ++ else ++ clear_bit(bit_blink, &priv->led_state); ++ ++ if (!rules) ++ return 0; ++ ++ if (on & on_set) ++ *rules |= BIT(TRIGGER_NETDEV_LINK); ++ ++ if (on & MTK_PHY_LED_ON_LINK10) ++ *rules |= BIT(TRIGGER_NETDEV_LINK_10); ++ ++ if (on & MTK_PHY_LED_ON_LINK100) ++ *rules |= BIT(TRIGGER_NETDEV_LINK_100); ++ ++ if (on & MTK_PHY_LED_ON_LINK1000) ++ *rules |= BIT(TRIGGER_NETDEV_LINK_1000); ++ ++ if (on & MTK_PHY_LED_ON_LINK2500) ++ *rules |= BIT(TRIGGER_NETDEV_LINK_2500); ++ ++ if (on & MTK_PHY_LED_ON_FDX) ++ *rules |= BIT(TRIGGER_NETDEV_FULL_DUPLEX); ++ ++ if (on & MTK_PHY_LED_ON_HDX) ++ *rules |= BIT(TRIGGER_NETDEV_HALF_DUPLEX); ++ ++ if (blink & rx_blink_set) ++ *rules |= BIT(TRIGGER_NETDEV_RX); ++ ++ if (blink & tx_blink_set) ++ *rules |= BIT(TRIGGER_NETDEV_TX); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(mtk_phy_led_hw_ctrl_get); ++ ++int mtk_phy_led_hw_ctrl_set(struct phy_device *phydev, u8 index, ++ unsigned long rules, u16 on_set, ++ u16 rx_blink_set, u16 tx_blink_set) ++{ ++ unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0); ++ struct mtk_socphy_priv *priv = phydev->priv; ++ u16 on = 0, blink = 0; ++ int ret; ++ ++ if (index > 1) ++ return -EINVAL; ++ ++ if (rules & BIT(TRIGGER_NETDEV_FULL_DUPLEX)) ++ on |= MTK_PHY_LED_ON_FDX; ++ ++ if (rules & BIT(TRIGGER_NETDEV_HALF_DUPLEX)) ++ on |= MTK_PHY_LED_ON_HDX; ++ ++ if (rules & (BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK))) ++ on |= MTK_PHY_LED_ON_LINK10; ++ ++ if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK))) ++ on |= MTK_PHY_LED_ON_LINK100; ++ ++ if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK))) ++ on |= MTK_PHY_LED_ON_LINK1000; ++ ++ if (rules & (BIT(TRIGGER_NETDEV_LINK_2500) | BIT(TRIGGER_NETDEV_LINK))) ++ on |= MTK_PHY_LED_ON_LINK2500; ++ ++ if (rules & BIT(TRIGGER_NETDEV_RX)) { ++ blink |= (on & on_set) ? ++ (((on & MTK_PHY_LED_ON_LINK10) ? ++ MTK_PHY_LED_BLINK_10RX : 0) | ++ ((on & MTK_PHY_LED_ON_LINK100) ? ++ MTK_PHY_LED_BLINK_100RX : 0) | ++ ((on & MTK_PHY_LED_ON_LINK1000) ? ++ MTK_PHY_LED_BLINK_1000RX : 0) | ++ ((on & MTK_PHY_LED_ON_LINK2500) ? ++ MTK_PHY_LED_BLINK_2500RX : 0)) : ++ rx_blink_set; ++ } ++ ++ if (rules & BIT(TRIGGER_NETDEV_TX)) { ++ blink |= (on & on_set) ? ++ (((on & MTK_PHY_LED_ON_LINK10) ? ++ MTK_PHY_LED_BLINK_10TX : 0) | ++ ((on & MTK_PHY_LED_ON_LINK100) ? ++ MTK_PHY_LED_BLINK_100TX : 0) | ++ ((on & MTK_PHY_LED_ON_LINK1000) ? ++ MTK_PHY_LED_BLINK_1000TX : 0) | ++ ((on & MTK_PHY_LED_ON_LINK2500) ? ++ MTK_PHY_LED_BLINK_2500TX : 0)) : ++ tx_blink_set; ++ } ++ ++ if (blink || on) ++ set_bit(bit_netdev, &priv->led_state); ++ else ++ clear_bit(bit_netdev, &priv->led_state); ++ ++ ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ? ++ MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL, ++ MTK_PHY_LED_ON_FDX | MTK_PHY_LED_ON_HDX | on_set, ++ on); ++ ++ if (ret) ++ return ret; ++ ++ return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ? ++ MTK_PHY_LED1_BLINK_CTRL : ++ MTK_PHY_LED0_BLINK_CTRL, blink); ++} ++EXPORT_SYMBOL_GPL(mtk_phy_led_hw_ctrl_set); ++ ++int mtk_phy_led_num_dly_cfg(u8 index, unsigned long *delay_on, ++ unsigned long *delay_off, bool *blinking) ++{ ++ if (index > 1) ++ return -EINVAL; ++ ++ if (delay_on && delay_off && (*delay_on > 0) && (*delay_off > 0)) { ++ *blinking = true; ++ *delay_on = 50; ++ *delay_off = 50; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(mtk_phy_led_num_dly_cfg); ++ ++int mtk_phy_hw_led_on_set(struct phy_device *phydev, u8 index, ++ u16 led_on_mask, bool on) ++{ ++ unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0); ++ struct mtk_socphy_priv *priv = phydev->priv; ++ bool changed; ++ ++ if (on) ++ changed = !test_and_set_bit(bit_on, &priv->led_state); ++ else ++ changed = !!test_and_clear_bit(bit_on, &priv->led_state); ++ ++ changed |= !!test_and_clear_bit(MTK_PHY_LED_STATE_NETDEV + ++ (index ? 16 : 0), &priv->led_state); ++ if (changed) ++ return phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ? ++ MTK_PHY_LED1_ON_CTRL : ++ MTK_PHY_LED0_ON_CTRL, ++ led_on_mask, ++ on ? MTK_PHY_LED_ON_FORCE_ON : 0); ++ else ++ return 0; ++} ++EXPORT_SYMBOL_GPL(mtk_phy_hw_led_on_set); ++ ++int mtk_phy_hw_led_blink_set(struct phy_device *phydev, u8 index, bool blinking) ++{ ++ unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK + ++ (index ? 16 : 0); ++ struct mtk_socphy_priv *priv = phydev->priv; ++ bool changed; ++ ++ if (blinking) ++ changed = !test_and_set_bit(bit_blink, &priv->led_state); ++ else ++ changed = !!test_and_clear_bit(bit_blink, &priv->led_state); ++ ++ changed |= !!test_bit(MTK_PHY_LED_STATE_NETDEV + ++ (index ? 16 : 0), &priv->led_state); ++ if (changed) ++ return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ? ++ MTK_PHY_LED1_BLINK_CTRL : ++ MTK_PHY_LED0_BLINK_CTRL, ++ blinking ? ++ MTK_PHY_LED_BLINK_FORCE_BLINK : 0); ++ else ++ return 0; ++} ++EXPORT_SYMBOL_GPL(mtk_phy_hw_led_blink_set); ++ ++void mtk_phy_leds_state_init(struct phy_device *phydev) ++{ ++ int i; ++ ++ for (i = 0; i < 2; ++i) ++ phydev->drv->led_hw_control_get(phydev, i, NULL); ++} ++EXPORT_SYMBOL_GPL(mtk_phy_leds_state_init); ++ ++MODULE_DESCRIPTION("MediaTek Ethernet PHY driver common"); ++MODULE_AUTHOR("Sky Huang "); ++MODULE_AUTHOR("Daniel Golle "); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/net/phy/mediatek/mtk.h b/drivers/net/phy/mediatek/mtk.h +new file mode 100644 +index 000000000000..9aaff2c2270d +--- /dev/null ++++ b/drivers/net/phy/mediatek/mtk.h +@@ -0,0 +1,86 @@ ++/* SPDX-License-Identifier: GPL-2.0 ++ * ++ * Common definition for Mediatek Ethernet PHYs ++ * Author: SkyLake Huang ++ * Copyright (c) 2024 MediaTek Inc. ++ */ ++ ++#ifndef _MTK_EPHY_H_ ++#define _MTK_EPHY_H_ ++ ++#define MTK_EXT_PAGE_ACCESS 0x1f ++ ++/* Registers on MDIO_MMD_VEND2 */ ++#define MTK_PHY_LED0_ON_CTRL 0x24 ++#define MTK_PHY_LED1_ON_CTRL 0x26 ++#define MTK_GPHY_LED_ON_MASK GENMASK(6, 0) ++#define MTK_2P5GPHY_LED_ON_MASK GENMASK(7, 0) ++#define MTK_PHY_LED_ON_LINK1000 BIT(0) ++#define MTK_PHY_LED_ON_LINK100 BIT(1) ++#define MTK_PHY_LED_ON_LINK10 BIT(2) ++#define MTK_PHY_LED_ON_LINKDOWN BIT(3) ++#define MTK_PHY_LED_ON_FDX BIT(4) /* Full duplex */ ++#define MTK_PHY_LED_ON_HDX BIT(5) /* Half duplex */ ++#define MTK_PHY_LED_ON_FORCE_ON BIT(6) ++#define MTK_PHY_LED_ON_LINK2500 BIT(7) ++#define MTK_PHY_LED_ON_POLARITY BIT(14) ++#define MTK_PHY_LED_ON_ENABLE BIT(15) ++ ++#define MTK_PHY_LED0_BLINK_CTRL 0x25 ++#define MTK_PHY_LED1_BLINK_CTRL 0x27 ++#define MTK_PHY_LED_BLINK_1000TX BIT(0) ++#define MTK_PHY_LED_BLINK_1000RX BIT(1) ++#define MTK_PHY_LED_BLINK_100TX BIT(2) ++#define MTK_PHY_LED_BLINK_100RX BIT(3) ++#define MTK_PHY_LED_BLINK_10TX BIT(4) ++#define MTK_PHY_LED_BLINK_10RX BIT(5) ++#define MTK_PHY_LED_BLINK_COLLISION BIT(6) ++#define MTK_PHY_LED_BLINK_RX_CRC_ERR BIT(7) ++#define MTK_PHY_LED_BLINK_RX_IDLE_ERR BIT(8) ++#define MTK_PHY_LED_BLINK_FORCE_BLINK BIT(9) ++#define MTK_PHY_LED_BLINK_2500TX BIT(10) ++#define MTK_PHY_LED_BLINK_2500RX BIT(11) ++ ++#define MTK_GPHY_LED_ON_SET (MTK_PHY_LED_ON_LINK1000 | \ ++ MTK_PHY_LED_ON_LINK100 | \ ++ MTK_PHY_LED_ON_LINK10) ++#define MTK_GPHY_LED_RX_BLINK_SET (MTK_PHY_LED_BLINK_1000RX | \ ++ MTK_PHY_LED_BLINK_100RX | \ ++ MTK_PHY_LED_BLINK_10RX) ++#define MTK_GPHY_LED_TX_BLINK_SET (MTK_PHY_LED_BLINK_1000RX | \ ++ MTK_PHY_LED_BLINK_100RX | \ ++ MTK_PHY_LED_BLINK_10RX) ++ ++#define MTK_2P5GPHY_LED_ON_SET (MTK_PHY_LED_ON_LINK2500 | \ ++ MTK_GPHY_LED_ON_SET) ++#define MTK_2P5GPHY_LED_RX_BLINK_SET (MTK_PHY_LED_BLINK_2500RX | \ ++ MTK_GPHY_LED_RX_BLINK_SET) ++#define MTK_2P5GPHY_LED_TX_BLINK_SET (MTK_PHY_LED_BLINK_2500RX | \ ++ MTK_GPHY_LED_TX_BLINK_SET) ++ ++#define MTK_PHY_LED_STATE_FORCE_ON 0 ++#define MTK_PHY_LED_STATE_FORCE_BLINK 1 ++#define MTK_PHY_LED_STATE_NETDEV 2 ++ ++struct mtk_socphy_priv { ++ unsigned long led_state; ++}; ++ ++int mtk_phy_led_hw_is_supported(struct phy_device *phydev, u8 index, ++ unsigned long rules, ++ unsigned long supported_triggers); ++int mtk_phy_led_hw_ctrl_set(struct phy_device *phydev, u8 index, ++ unsigned long rules, u16 on_set, ++ u16 rx_blink_set, u16 tx_blink_set); ++int mtk_phy_led_hw_ctrl_get(struct phy_device *phydev, u8 index, ++ unsigned long *rules, u16 on_set, ++ u16 rx_blink_set, u16 tx_blink_set); ++int mtk_phy_led_num_dly_cfg(u8 index, unsigned long *delay_on, ++ unsigned long *delay_off, bool *blinking); ++int mtk_phy_hw_led_on_set(struct phy_device *phydev, u8 index, ++ u16 led_on_mask, bool on); ++int mtk_phy_hw_led_blink_set(struct phy_device *phydev, u8 index, ++ bool blinking); ++void mtk_phy_leds_state_init(struct phy_device *phydev); ++ ++#endif /* _MTK_EPHY_H_ */ +-- +2.51.0 + + +From 6dc997fe3e72a302032cfcc171a4a7ee5f4faf5c Mon Sep 17 00:00:00 2001 +From: "SkyLake.Huang" +Date: Sat, 9 Nov 2024 00:34:53 +0800 +Subject: [PATCH 072/517] net: phy: mediatek: Improve readability of + mtk-phy-lib.c's mtk_phy_led_hw_ctrl_set() + +This patch removes parens around TRIGGER_NETDEV_RX/TRIGGER_NETDEV_TX in +mtk_phy_led_hw_ctrl_set(), which improves readability. + +Reviewed-by: Andrew Lunn +Signed-off-by: SkyLake.Huang +Signed-off-by: David S. Miller +--- + drivers/net/phy/mediatek/mtk-phy-lib.c | 44 ++++++++++++++------------ + 1 file changed, 24 insertions(+), 20 deletions(-) + +diff --git a/drivers/net/phy/mediatek/mtk-phy-lib.c b/drivers/net/phy/mediatek/mtk-phy-lib.c +index 34b0957b201b..8d795bcc8b2d 100644 +--- a/drivers/net/phy/mediatek/mtk-phy-lib.c ++++ b/drivers/net/phy/mediatek/mtk-phy-lib.c +@@ -129,29 +129,33 @@ int mtk_phy_led_hw_ctrl_set(struct phy_device *phydev, u8 index, + on |= MTK_PHY_LED_ON_LINK2500; + + if (rules & BIT(TRIGGER_NETDEV_RX)) { +- blink |= (on & on_set) ? +- (((on & MTK_PHY_LED_ON_LINK10) ? +- MTK_PHY_LED_BLINK_10RX : 0) | +- ((on & MTK_PHY_LED_ON_LINK100) ? +- MTK_PHY_LED_BLINK_100RX : 0) | +- ((on & MTK_PHY_LED_ON_LINK1000) ? +- MTK_PHY_LED_BLINK_1000RX : 0) | +- ((on & MTK_PHY_LED_ON_LINK2500) ? +- MTK_PHY_LED_BLINK_2500RX : 0)) : +- rx_blink_set; ++ if (on & on_set) { ++ if (on & MTK_PHY_LED_ON_LINK10) ++ blink |= MTK_PHY_LED_BLINK_10RX; ++ if (on & MTK_PHY_LED_ON_LINK100) ++ blink |= MTK_PHY_LED_BLINK_100RX; ++ if (on & MTK_PHY_LED_ON_LINK1000) ++ blink |= MTK_PHY_LED_BLINK_1000RX; ++ if (on & MTK_PHY_LED_ON_LINK2500) ++ blink |= MTK_PHY_LED_BLINK_2500RX; ++ } else { ++ blink |= rx_blink_set; ++ } + } + + if (rules & BIT(TRIGGER_NETDEV_TX)) { +- blink |= (on & on_set) ? +- (((on & MTK_PHY_LED_ON_LINK10) ? +- MTK_PHY_LED_BLINK_10TX : 0) | +- ((on & MTK_PHY_LED_ON_LINK100) ? +- MTK_PHY_LED_BLINK_100TX : 0) | +- ((on & MTK_PHY_LED_ON_LINK1000) ? +- MTK_PHY_LED_BLINK_1000TX : 0) | +- ((on & MTK_PHY_LED_ON_LINK2500) ? +- MTK_PHY_LED_BLINK_2500TX : 0)) : +- tx_blink_set; ++ if (on & on_set) { ++ if (on & MTK_PHY_LED_ON_LINK10) ++ blink |= MTK_PHY_LED_BLINK_10TX; ++ if (on & MTK_PHY_LED_ON_LINK100) ++ blink |= MTK_PHY_LED_BLINK_100TX; ++ if (on & MTK_PHY_LED_ON_LINK1000) ++ blink |= MTK_PHY_LED_BLINK_1000TX; ++ if (on & MTK_PHY_LED_ON_LINK2500) ++ blink |= MTK_PHY_LED_BLINK_2500TX; ++ } else { ++ blink |= tx_blink_set; ++ } + } + + if (blink || on) +-- +2.51.0 + + +From 2d3dc5ebaa6a3858e2132c14bbf9245f26979f40 Mon Sep 17 00:00:00 2001 +From: "SkyLake.Huang" +Date: Sat, 9 Nov 2024 00:34:54 +0800 +Subject: [PATCH 073/517] net: phy: mediatek: Integrate read/write page helper + functions + +This patch integrates read/write page helper functions as MTK phy lib. +They are basically the same in mtk-ge.c & mtk-ge-soc.c. + +Signed-off-by: SkyLake.Huang +Signed-off-by: David S. Miller +--- + drivers/net/phy/mediatek/Kconfig | 1 + + drivers/net/phy/mediatek/mtk-ge-soc.c | 18 ++++-------------- + drivers/net/phy/mediatek/mtk-ge.c | 20 ++++++-------------- + drivers/net/phy/mediatek/mtk-phy-lib.c | 12 ++++++++++++ + drivers/net/phy/mediatek/mtk.h | 3 +++ + 5 files changed, 26 insertions(+), 28 deletions(-) + +diff --git a/drivers/net/phy/mediatek/Kconfig b/drivers/net/phy/mediatek/Kconfig +index 19b5d23e7cd0..2a8ac5aed0f8 100644 +--- a/drivers/net/phy/mediatek/Kconfig ++++ b/drivers/net/phy/mediatek/Kconfig +@@ -4,6 +4,7 @@ config MTK_NET_PHYLIB + + config MEDIATEK_GE_PHY + tristate "MediaTek Gigabit Ethernet PHYs" ++ select MTK_NET_PHYLIB + help + Supports the MediaTek non-built-in Gigabit Ethernet PHYs. + +diff --git a/drivers/net/phy/mediatek/mtk-ge-soc.c b/drivers/net/phy/mediatek/mtk-ge-soc.c +index d3a8b3946056..38dc898eaf7b 100644 +--- a/drivers/net/phy/mediatek/mtk-ge-soc.c ++++ b/drivers/net/phy/mediatek/mtk-ge-soc.c +@@ -271,16 +271,6 @@ struct mtk_socphy_shared { + struct mtk_socphy_priv priv[4]; + }; + +-static int mtk_socphy_read_page(struct phy_device *phydev) +-{ +- return __phy_read(phydev, MTK_EXT_PAGE_ACCESS); +-} +- +-static int mtk_socphy_write_page(struct phy_device *phydev, int page) +-{ +- return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page); +-} +- + /* One calibration cycle consists of: + * 1.Set DA_CALIN_FLAG high to start calibration. Keep it high + * until AD_CAL_COMP is ready to output calibration result. +@@ -1337,8 +1327,8 @@ static struct phy_driver mtk_socphy_driver[] = { + .probe = mt7981_phy_probe, + .suspend = genphy_suspend, + .resume = genphy_resume, +- .read_page = mtk_socphy_read_page, +- .write_page = mtk_socphy_write_page, ++ .read_page = mtk_phy_read_page, ++ .write_page = mtk_phy_write_page, + .led_blink_set = mt798x_phy_led_blink_set, + .led_brightness_set = mt798x_phy_led_brightness_set, + .led_hw_is_supported = mt798x_phy_led_hw_is_supported, +@@ -1354,8 +1344,8 @@ static struct phy_driver mtk_socphy_driver[] = { + .probe = mt7988_phy_probe, + .suspend = genphy_suspend, + .resume = genphy_resume, +- .read_page = mtk_socphy_read_page, +- .write_page = mtk_socphy_write_page, ++ .read_page = mtk_phy_read_page, ++ .write_page = mtk_phy_write_page, + .led_blink_set = mt798x_phy_led_blink_set, + .led_brightness_set = mt798x_phy_led_brightness_set, + .led_hw_is_supported = mt798x_phy_led_hw_is_supported, +diff --git a/drivers/net/phy/mediatek/mtk-ge.c b/drivers/net/phy/mediatek/mtk-ge.c +index 54ea64a37ab3..912289928fb3 100644 +--- a/drivers/net/phy/mediatek/mtk-ge.c ++++ b/drivers/net/phy/mediatek/mtk-ge.c +@@ -3,6 +3,8 @@ + #include + #include + ++#include "mtk.h" ++ + #define MTK_EXT_PAGE_ACCESS 0x1f + #define MTK_PHY_PAGE_STANDARD 0x0000 + #define MTK_PHY_PAGE_EXTENDED 0x0001 +@@ -11,16 +13,6 @@ + #define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30 + #define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5 + +-static int mtk_gephy_read_page(struct phy_device *phydev) +-{ +- return __phy_read(phydev, MTK_EXT_PAGE_ACCESS); +-} +- +-static int mtk_gephy_write_page(struct phy_device *phydev, int page) +-{ +- return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page); +-} +- + static void mtk_gephy_config_init(struct phy_device *phydev) + { + /* Enable HW auto downshift */ +@@ -77,8 +69,8 @@ static struct phy_driver mtk_gephy_driver[] = { + .handle_interrupt = genphy_handle_interrupt_no_ack, + .suspend = genphy_suspend, + .resume = genphy_resume, +- .read_page = mtk_gephy_read_page, +- .write_page = mtk_gephy_write_page, ++ .read_page = mtk_phy_read_page, ++ .write_page = mtk_phy_write_page, + }, + { + PHY_ID_MATCH_EXACT(0x03a29441), +@@ -91,8 +83,8 @@ static struct phy_driver mtk_gephy_driver[] = { + .handle_interrupt = genphy_handle_interrupt_no_ack, + .suspend = genphy_suspend, + .resume = genphy_resume, +- .read_page = mtk_gephy_read_page, +- .write_page = mtk_gephy_write_page, ++ .read_page = mtk_phy_read_page, ++ .write_page = mtk_phy_write_page, + }, + }; + +diff --git a/drivers/net/phy/mediatek/mtk-phy-lib.c b/drivers/net/phy/mediatek/mtk-phy-lib.c +index 8d795bcc8b2d..98a09d670e9c 100644 +--- a/drivers/net/phy/mediatek/mtk-phy-lib.c ++++ b/drivers/net/phy/mediatek/mtk-phy-lib.c +@@ -6,6 +6,18 @@ + + #include "mtk.h" + ++int mtk_phy_read_page(struct phy_device *phydev) ++{ ++ return __phy_read(phydev, MTK_EXT_PAGE_ACCESS); ++} ++EXPORT_SYMBOL_GPL(mtk_phy_read_page); ++ ++int mtk_phy_write_page(struct phy_device *phydev, int page) ++{ ++ return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page); ++} ++EXPORT_SYMBOL_GPL(mtk_phy_write_page); ++ + int mtk_phy_led_hw_is_supported(struct phy_device *phydev, u8 index, + unsigned long rules, + unsigned long supported_triggers) +diff --git a/drivers/net/phy/mediatek/mtk.h b/drivers/net/phy/mediatek/mtk.h +index 9aaff2c2270d..63d9fe179b8f 100644 +--- a/drivers/net/phy/mediatek/mtk.h ++++ b/drivers/net/phy/mediatek/mtk.h +@@ -66,6 +66,9 @@ struct mtk_socphy_priv { + unsigned long led_state; + }; + ++int mtk_phy_read_page(struct phy_device *phydev); ++int mtk_phy_write_page(struct phy_device *phydev, int page); ++ + int mtk_phy_led_hw_is_supported(struct phy_device *phydev, u8 index, + unsigned long rules, + unsigned long supported_triggers); +-- +2.51.0 + + +From c856cf37c2c09bc633f445f7b106868ecbecf773 Mon Sep 17 00:00:00 2001 +From: "SkyLake.Huang" +Date: Sat, 9 Nov 2024 00:34:55 +0800 +Subject: [PATCH 074/517] net: phy: mediatek: add MT7530 & MT7531's PHY ID + macros + +This patch adds MT7530 & MT7531's PHY ID macros in mtk-ge.c so that +it follows the same rule of mtk-ge-soc.c. + +Reviewed-by: Andrew Lunn +Signed-off-by: SkyLake.Huang +Signed-off-by: David S. Miller +--- + drivers/net/phy/mediatek/mtk-ge.c | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/phy/mediatek/mtk-ge.c b/drivers/net/phy/mediatek/mtk-ge.c +index 912289928fb3..ed2617bc20f4 100644 +--- a/drivers/net/phy/mediatek/mtk-ge.c ++++ b/drivers/net/phy/mediatek/mtk-ge.c +@@ -5,6 +5,9 @@ + + #include "mtk.h" + ++#define MTK_GPHY_ID_MT7530 0x03a29412 ++#define MTK_GPHY_ID_MT7531 0x03a29441 ++ + #define MTK_EXT_PAGE_ACCESS 0x1f + #define MTK_PHY_PAGE_STANDARD 0x0000 + #define MTK_PHY_PAGE_EXTENDED 0x0001 +@@ -59,7 +62,7 @@ static int mt7531_phy_config_init(struct phy_device *phydev) + + static struct phy_driver mtk_gephy_driver[] = { + { +- PHY_ID_MATCH_EXACT(0x03a29412), ++ PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7530), + .name = "MediaTek MT7530 PHY", + .config_init = mt7530_phy_config_init, + /* Interrupts are handled by the switch, not the PHY +@@ -73,7 +76,7 @@ static struct phy_driver mtk_gephy_driver[] = { + .write_page = mtk_phy_write_page, + }, + { +- PHY_ID_MATCH_EXACT(0x03a29441), ++ PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7531), + .name = "MediaTek MT7531 PHY", + .config_init = mt7531_phy_config_init, + /* Interrupts are handled by the switch, not the PHY +@@ -91,8 +94,8 @@ static struct phy_driver mtk_gephy_driver[] = { + module_phy_driver(mtk_gephy_driver); + + static struct mdio_device_id __maybe_unused mtk_gephy_tbl[] = { +- { PHY_ID_MATCH_EXACT(0x03a29441) }, +- { PHY_ID_MATCH_EXACT(0x03a29412) }, ++ { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7530) }, ++ { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7531) }, + { } + }; + +-- +2.51.0 + + +From 7a3462a3d00deab364b02b53bb9dd57e767b0a38 Mon Sep 17 00:00:00 2001 +From: Christophe JAILLET +Date: Sun, 12 Jan 2025 15:14:50 +0100 +Subject: [PATCH 075/517] net: phy: Constify struct mdio_device_id + +'struct mdio_device_id' is not modified in these drivers. + +Constifying these structures moves some data to a read-only section, so +increase overall security. + +On a x86_64, with allmodconfig, as an example: +Before: +====== + text data bss dec hex filename + 27014 12792 0 39806 9b7e drivers/net/phy/broadcom.o + +After: +===== + text data bss dec hex filename + 27206 12600 0 39806 9b7e drivers/net/phy/broadcom.o + +Signed-off-by: Christophe JAILLET +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/403c381b7d9156b67ad68ffc44b8eee70c5e86a9.1736691226.git.christophe.jaillet@wanadoo.fr +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/adin.c | 2 +- + drivers/net/phy/adin1100.c | 2 +- + drivers/net/phy/air_en8811h.c | 2 +- + drivers/net/phy/amd.c | 2 +- + drivers/net/phy/aquantia/aquantia_main.c | 2 +- + drivers/net/phy/ax88796b.c | 2 +- + drivers/net/phy/bcm-cygnus.c | 2 +- + drivers/net/phy/bcm54140.c | 2 +- + drivers/net/phy/bcm63xx.c | 2 +- + drivers/net/phy/bcm7xxx.c | 2 +- + drivers/net/phy/bcm84881.c | 2 +- + drivers/net/phy/broadcom.c | 2 +- + drivers/net/phy/cicada.c | 2 +- + drivers/net/phy/cortina.c | 2 +- + drivers/net/phy/davicom.c | 2 +- + drivers/net/phy/dp83640.c | 2 +- + drivers/net/phy/dp83822.c | 2 +- + drivers/net/phy/dp83848.c | 2 +- + drivers/net/phy/dp83867.c | 2 +- + drivers/net/phy/dp83869.c | 2 +- + drivers/net/phy/dp83tc811.c | 2 +- + drivers/net/phy/dp83td510.c | 2 +- + drivers/net/phy/dp83tg720.c | 2 +- + drivers/net/phy/et1011c.c | 2 +- + drivers/net/phy/icplus.c | 2 +- + drivers/net/phy/intel-xway.c | 2 +- + drivers/net/phy/lxt.c | 2 +- + drivers/net/phy/marvell-88q2xxx.c | 2 +- + drivers/net/phy/marvell-88x2222.c | 2 +- + drivers/net/phy/marvell.c | 2 +- + drivers/net/phy/marvell10g.c | 2 +- + drivers/net/phy/mediatek/mtk-ge-soc.c | 2 +- + drivers/net/phy/mediatek/mtk-ge.c | 2 +- + drivers/net/phy/meson-gxl.c | 2 +- + drivers/net/phy/micrel.c | 2 +- + drivers/net/phy/microchip.c | 2 +- + drivers/net/phy/microchip_t1.c | 2 +- + drivers/net/phy/microchip_t1s.c | 2 +- + drivers/net/phy/mscc/mscc_main.c | 2 +- + drivers/net/phy/mxl-gpy.c | 2 +- + drivers/net/phy/national.c | 2 +- + drivers/net/phy/ncn26000.c | 2 +- + drivers/net/phy/nxp-c45-tja11xx.c | 2 +- + drivers/net/phy/nxp-cbtx.c | 2 +- + drivers/net/phy/nxp-tja11xx.c | 2 +- + drivers/net/phy/qcom/at803x.c | 2 +- + drivers/net/phy/qcom/qca807x.c | 2 +- + drivers/net/phy/qcom/qca808x.c | 2 +- + drivers/net/phy/qcom/qca83xx.c | 2 +- + drivers/net/phy/qsemi.c | 2 +- + drivers/net/phy/rockchip.c | 2 +- + drivers/net/phy/smsc.c | 2 +- + drivers/net/phy/ste10Xp.c | 2 +- + drivers/net/phy/teranetics.c | 2 +- + drivers/net/phy/uPD60620.c | 2 +- + drivers/net/phy/vitesse.c | 2 +- + 56 files changed, 56 insertions(+), 56 deletions(-) + +diff --git a/drivers/net/phy/adin.c b/drivers/net/phy/adin.c +index 2e1a46e121d9..fcd5eecbbf77 100644 +--- a/drivers/net/phy/adin.c ++++ b/drivers/net/phy/adin.c +@@ -1040,7 +1040,7 @@ static struct phy_driver adin_driver[] = { + + module_phy_driver(adin_driver); + +-static struct mdio_device_id __maybe_unused adin_tbl[] = { ++static const struct mdio_device_id __maybe_unused adin_tbl[] = { + { PHY_ID_MATCH_MODEL(PHY_ID_ADIN1200) }, + { PHY_ID_MATCH_MODEL(PHY_ID_ADIN1300) }, + { } +diff --git a/drivers/net/phy/adin1100.c b/drivers/net/phy/adin1100.c +index 85f910e2d4fb..6bb469429b9d 100644 +--- a/drivers/net/phy/adin1100.c ++++ b/drivers/net/phy/adin1100.c +@@ -340,7 +340,7 @@ static struct phy_driver adin_driver[] = { + + module_phy_driver(adin_driver); + +-static struct mdio_device_id __maybe_unused adin_tbl[] = { ++static const struct mdio_device_id __maybe_unused adin_tbl[] = { + { PHY_ID_MATCH_MODEL(PHY_ID_ADIN1100) }, + { PHY_ID_MATCH_MODEL(PHY_ID_ADIN1110) }, + { PHY_ID_MATCH_MODEL(PHY_ID_ADIN2111) }, +diff --git a/drivers/net/phy/air_en8811h.c b/drivers/net/phy/air_en8811h.c +index 8d076b9609fd..e9fd24cb7270 100644 +--- a/drivers/net/phy/air_en8811h.c ++++ b/drivers/net/phy/air_en8811h.c +@@ -1075,7 +1075,7 @@ static struct phy_driver en8811h_driver[] = { + + module_phy_driver(en8811h_driver); + +-static struct mdio_device_id __maybe_unused en8811h_tbl[] = { ++static const struct mdio_device_id __maybe_unused en8811h_tbl[] = { + { PHY_ID_MATCH_MODEL(EN8811H_PHY_ID) }, + { } + }; +diff --git a/drivers/net/phy/amd.c b/drivers/net/phy/amd.c +index 930b15fa6ce9..75b5fe65500a 100644 +--- a/drivers/net/phy/amd.c ++++ b/drivers/net/phy/amd.c +@@ -111,7 +111,7 @@ static struct phy_driver am79c_drivers[] = { + + module_phy_driver(am79c_drivers); + +-static struct mdio_device_id __maybe_unused amd_tbl[] = { ++static const struct mdio_device_id __maybe_unused amd_tbl[] = { + { PHY_ID_AC101L, 0xfffffff0 }, + { PHY_ID_AM79C874, 0xfffffff0 }, + { } +diff --git a/drivers/net/phy/aquantia/aquantia_main.c b/drivers/net/phy/aquantia/aquantia_main.c +index c33a5ef34ba0..840ef5ad07ff 100644 +--- a/drivers/net/phy/aquantia/aquantia_main.c ++++ b/drivers/net/phy/aquantia/aquantia_main.c +@@ -1096,7 +1096,7 @@ static struct phy_driver aqr_driver[] = { + + module_phy_driver(aqr_driver); + +-static struct mdio_device_id __maybe_unused aqr_tbl[] = { ++static const struct mdio_device_id __maybe_unused aqr_tbl[] = { + { PHY_ID_MATCH_MODEL(PHY_ID_AQ1202) }, + { PHY_ID_MATCH_MODEL(PHY_ID_AQ2104) }, + { PHY_ID_MATCH_MODEL(PHY_ID_AQR105) }, +diff --git a/drivers/net/phy/ax88796b.c b/drivers/net/phy/ax88796b.c +index eb74a8cf8df1..694df1401aa2 100644 +--- a/drivers/net/phy/ax88796b.c ++++ b/drivers/net/phy/ax88796b.c +@@ -121,7 +121,7 @@ static struct phy_driver asix_driver[] = { + + module_phy_driver(asix_driver); + +-static struct mdio_device_id __maybe_unused asix_tbl[] = { ++static const struct mdio_device_id __maybe_unused asix_tbl[] = { + { PHY_ID_MATCH_EXACT(PHY_ID_ASIX_AX88772A) }, + { PHY_ID_MATCH_EXACT(PHY_ID_ASIX_AX88772C) }, + { PHY_ID_ASIX_AX88796B, 0xfffffff0 }, +diff --git a/drivers/net/phy/bcm-cygnus.c b/drivers/net/phy/bcm-cygnus.c +index da8f7cb41b44..15cbef8202bc 100644 +--- a/drivers/net/phy/bcm-cygnus.c ++++ b/drivers/net/phy/bcm-cygnus.c +@@ -278,7 +278,7 @@ static struct phy_driver bcm_cygnus_phy_driver[] = { + } + }; + +-static struct mdio_device_id __maybe_unused bcm_cygnus_phy_tbl[] = { ++static const struct mdio_device_id __maybe_unused bcm_cygnus_phy_tbl[] = { + { PHY_ID_BCM_CYGNUS, 0xfffffff0, }, + { PHY_ID_BCM_OMEGA, 0xfffffff0, }, + { } +diff --git a/drivers/net/phy/bcm54140.c b/drivers/net/phy/bcm54140.c +index 2eea3d09b1e6..7969345f6b35 100644 +--- a/drivers/net/phy/bcm54140.c ++++ b/drivers/net/phy/bcm54140.c +@@ -883,7 +883,7 @@ static struct phy_driver bcm54140_drivers[] = { + }; + module_phy_driver(bcm54140_drivers); + +-static struct mdio_device_id __maybe_unused bcm54140_tbl[] = { ++static const struct mdio_device_id __maybe_unused bcm54140_tbl[] = { + { PHY_ID_BCM54140, BCM54140_PHY_ID_MASK }, + { } + }; +diff --git a/drivers/net/phy/bcm63xx.c b/drivers/net/phy/bcm63xx.c +index 0eb33be824f1..b46a736a3130 100644 +--- a/drivers/net/phy/bcm63xx.c ++++ b/drivers/net/phy/bcm63xx.c +@@ -93,7 +93,7 @@ static struct phy_driver bcm63xx_driver[] = { + + module_phy_driver(bcm63xx_driver); + +-static struct mdio_device_id __maybe_unused bcm63xx_tbl[] = { ++static const struct mdio_device_id __maybe_unused bcm63xx_tbl[] = { + { 0x00406000, 0xfffffc00 }, + { 0x002bdc00, 0xfffffc00 }, + { } +diff --git a/drivers/net/phy/bcm7xxx.c b/drivers/net/phy/bcm7xxx.c +index 97638ba7ae85..00e8fa14aa77 100644 +--- a/drivers/net/phy/bcm7xxx.c ++++ b/drivers/net/phy/bcm7xxx.c +@@ -929,7 +929,7 @@ static struct phy_driver bcm7xxx_driver[] = { + BCM7XXX_16NM_EPHY(PHY_ID_BCM7712, "Broadcom BCM7712"), + }; + +-static struct mdio_device_id __maybe_unused bcm7xxx_tbl[] = { ++static const struct mdio_device_id __maybe_unused bcm7xxx_tbl[] = { + { PHY_ID_BCM72113, 0xfffffff0 }, + { PHY_ID_BCM72116, 0xfffffff0, }, + { PHY_ID_BCM72165, 0xfffffff0, }, +diff --git a/drivers/net/phy/bcm84881.c b/drivers/net/phy/bcm84881.c +index 47405bded677..d7f7cc44c532 100644 +--- a/drivers/net/phy/bcm84881.c ++++ b/drivers/net/phy/bcm84881.c +@@ -262,7 +262,7 @@ static struct phy_driver bcm84881_drivers[] = { + module_phy_driver(bcm84881_drivers); + + /* FIXME: module auto-loading for Clause 45 PHYs seems non-functional */ +-static struct mdio_device_id __maybe_unused bcm84881_tbl[] = { ++static const struct mdio_device_id __maybe_unused bcm84881_tbl[] = { + { 0xae025150, 0xfffffff0 }, + { }, + }; +diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c +index 9260c822e467..f4b1d98d6b18 100644 +--- a/drivers/net/phy/broadcom.c ++++ b/drivers/net/phy/broadcom.c +@@ -1734,7 +1734,7 @@ static struct phy_driver broadcom_drivers[] = { + + module_phy_driver(broadcom_drivers); + +-static struct mdio_device_id __maybe_unused broadcom_tbl[] = { ++static const struct mdio_device_id __maybe_unused broadcom_tbl[] = { + { PHY_ID_BCM5411, 0xfffffff0 }, + { PHY_ID_BCM5421, 0xfffffff0 }, + { PHY_ID_BCM54210E, 0xfffffff0 }, +diff --git a/drivers/net/phy/cicada.c b/drivers/net/phy/cicada.c +index ef5f412e101f..d87cf8b94cf8 100644 +--- a/drivers/net/phy/cicada.c ++++ b/drivers/net/phy/cicada.c +@@ -145,7 +145,7 @@ static struct phy_driver cis820x_driver[] = { + + module_phy_driver(cis820x_driver); + +-static struct mdio_device_id __maybe_unused cicada_tbl[] = { ++static const struct mdio_device_id __maybe_unused cicada_tbl[] = { + { 0x000fc410, 0x000ffff0 }, + { 0x000fc440, 0x000fffc0 }, + { } +diff --git a/drivers/net/phy/cortina.c b/drivers/net/phy/cortina.c +index 40514a94e6ff..3b65f37f1c57 100644 +--- a/drivers/net/phy/cortina.c ++++ b/drivers/net/phy/cortina.c +@@ -87,7 +87,7 @@ static struct phy_driver cortina_driver[] = { + + module_phy_driver(cortina_driver); + +-static struct mdio_device_id __maybe_unused cortina_tbl[] = { ++static const struct mdio_device_id __maybe_unused cortina_tbl[] = { + { PHY_ID_CS4340, 0xffffffff}, + {}, + }; +diff --git a/drivers/net/phy/davicom.c b/drivers/net/phy/davicom.c +index 4ac4bce1bf32..fa3692508f16 100644 +--- a/drivers/net/phy/davicom.c ++++ b/drivers/net/phy/davicom.c +@@ -209,7 +209,7 @@ static struct phy_driver dm91xx_driver[] = { + + module_phy_driver(dm91xx_driver); + +-static struct mdio_device_id __maybe_unused davicom_tbl[] = { ++static const struct mdio_device_id __maybe_unused davicom_tbl[] = { + { 0x0181b880, 0x0ffffff0 }, + { 0x0181b8b0, 0x0ffffff0 }, + { 0x0181b8a0, 0x0ffffff0 }, +diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c +index 075d2beea716..85e231451093 100644 +--- a/drivers/net/phy/dp83640.c ++++ b/drivers/net/phy/dp83640.c +@@ -1548,7 +1548,7 @@ MODULE_LICENSE("GPL"); + module_init(dp83640_init); + module_exit(dp83640_exit); + +-static struct mdio_device_id __maybe_unused dp83640_tbl[] = { ++static const struct mdio_device_id __maybe_unused dp83640_tbl[] = { + { DP83640_PHY_ID, 0xfffffff0 }, + { } + }; +diff --git a/drivers/net/phy/dp83822.c b/drivers/net/phy/dp83822.c +index 3ab64e04a01c..537e152dd156 100644 +--- a/drivers/net/phy/dp83822.c ++++ b/drivers/net/phy/dp83822.c +@@ -825,7 +825,7 @@ static struct phy_driver dp83822_driver[] = { + }; + module_phy_driver(dp83822_driver); + +-static struct mdio_device_id __maybe_unused dp83822_tbl[] = { ++static const struct mdio_device_id __maybe_unused dp83822_tbl[] = { + { DP83822_PHY_ID, 0xfffffff0 }, + { DP83825I_PHY_ID, 0xfffffff0 }, + { DP83826C_PHY_ID, 0xfffffff0 }, +diff --git a/drivers/net/phy/dp83848.c b/drivers/net/phy/dp83848.c +index 351411f0aa6f..d88b1999d596 100644 +--- a/drivers/net/phy/dp83848.c ++++ b/drivers/net/phy/dp83848.c +@@ -123,7 +123,7 @@ static int dp83848_config_init(struct phy_device *phydev) + return 0; + } + +-static struct mdio_device_id __maybe_unused dp83848_tbl[] = { ++static const struct mdio_device_id __maybe_unused dp83848_tbl[] = { + { TI_DP83848C_PHY_ID, 0xfffffff0 }, + { NS_DP83848C_PHY_ID, 0xfffffff0 }, + { TI_DP83620_PHY_ID, 0xfffffff0 }, +diff --git a/drivers/net/phy/dp83867.c b/drivers/net/phy/dp83867.c +index 4120385c5a79..c1451df430ac 100644 +--- a/drivers/net/phy/dp83867.c ++++ b/drivers/net/phy/dp83867.c +@@ -1210,7 +1210,7 @@ static struct phy_driver dp83867_driver[] = { + }; + module_phy_driver(dp83867_driver); + +-static struct mdio_device_id __maybe_unused dp83867_tbl[] = { ++static const struct mdio_device_id __maybe_unused dp83867_tbl[] = { + { DP83867_PHY_ID, 0xfffffff0 }, + { } + }; +diff --git a/drivers/net/phy/dp83869.c b/drivers/net/phy/dp83869.c +index b6b38caf9c0e..a62cd838a9ea 100644 +--- a/drivers/net/phy/dp83869.c ++++ b/drivers/net/phy/dp83869.c +@@ -928,7 +928,7 @@ static struct phy_driver dp83869_driver[] = { + }; + module_phy_driver(dp83869_driver); + +-static struct mdio_device_id __maybe_unused dp83869_tbl[] = { ++static const struct mdio_device_id __maybe_unused dp83869_tbl[] = { + { PHY_ID_MATCH_MODEL(DP83869_PHY_ID) }, + { PHY_ID_MATCH_MODEL(DP83561_PHY_ID) }, + { } +diff --git a/drivers/net/phy/dp83tc811.c b/drivers/net/phy/dp83tc811.c +index 7ea32fb77190..e480c2a07450 100644 +--- a/drivers/net/phy/dp83tc811.c ++++ b/drivers/net/phy/dp83tc811.c +@@ -403,7 +403,7 @@ static struct phy_driver dp83811_driver[] = { + }; + module_phy_driver(dp83811_driver); + +-static struct mdio_device_id __maybe_unused dp83811_tbl[] = { ++static const struct mdio_device_id __maybe_unused dp83811_tbl[] = { + { DP83TC811_PHY_ID, 0xfffffff0 }, + { }, + }; +diff --git a/drivers/net/phy/dp83td510.c b/drivers/net/phy/dp83td510.c +index 92aa3a2b9744..56ae24ad6c90 100644 +--- a/drivers/net/phy/dp83td510.c ++++ b/drivers/net/phy/dp83td510.c +@@ -605,7 +605,7 @@ static struct phy_driver dp83td510_driver[] = { + } }; + module_phy_driver(dp83td510_driver); + +-static struct mdio_device_id __maybe_unused dp83td510_tbl[] = { ++static const struct mdio_device_id __maybe_unused dp83td510_tbl[] = { + { PHY_ID_MATCH_MODEL(DP83TD510E_PHY_ID) }, + { } + }; +diff --git a/drivers/net/phy/dp83tg720.c b/drivers/net/phy/dp83tg720.c +index 0ef4d7dba065..da9230b1ba30 100644 +--- a/drivers/net/phy/dp83tg720.c ++++ b/drivers/net/phy/dp83tg720.c +@@ -361,7 +361,7 @@ static struct phy_driver dp83tg720_driver[] = { + } }; + module_phy_driver(dp83tg720_driver); + +-static struct mdio_device_id __maybe_unused dp83tg720_tbl[] = { ++static const struct mdio_device_id __maybe_unused dp83tg720_tbl[] = { + { PHY_ID_MATCH_MODEL(DP83TG720S_PHY_ID) }, + { } + }; +diff --git a/drivers/net/phy/et1011c.c b/drivers/net/phy/et1011c.c +index be1b71d7cab7..6cd8d77586fd 100644 +--- a/drivers/net/phy/et1011c.c ++++ b/drivers/net/phy/et1011c.c +@@ -94,7 +94,7 @@ static struct phy_driver et1011c_driver[] = { { + + module_phy_driver(et1011c_driver); + +-static struct mdio_device_id __maybe_unused et1011c_tbl[] = { ++static const struct mdio_device_id __maybe_unused et1011c_tbl[] = { + { 0x0282f014, 0xfffffff0 }, + { } + }; +diff --git a/drivers/net/phy/icplus.c b/drivers/net/phy/icplus.c +index a00a667454a9..feed270ab4ea 100644 +--- a/drivers/net/phy/icplus.c ++++ b/drivers/net/phy/icplus.c +@@ -624,7 +624,7 @@ static struct phy_driver icplus_driver[] = { + + module_phy_driver(icplus_driver); + +-static struct mdio_device_id __maybe_unused icplus_tbl[] = { ++static const struct mdio_device_id __maybe_unused icplus_tbl[] = { + { PHY_ID_MATCH_MODEL(IP175C_PHY_ID) }, + { PHY_ID_MATCH_MODEL(IP1001_PHY_ID) }, + { PHY_ID_MATCH_EXACT(IP101A_PHY_ID) }, +diff --git a/drivers/net/phy/intel-xway.c b/drivers/net/phy/intel-xway.c +index 3c032868ef04..fad411b93c15 100644 +--- a/drivers/net/phy/intel-xway.c ++++ b/drivers/net/phy/intel-xway.c +@@ -456,7 +456,7 @@ static struct phy_driver xway_gphy[] = { + }; + module_phy_driver(xway_gphy); + +-static struct mdio_device_id __maybe_unused xway_gphy_tbl[] = { ++static const struct mdio_device_id __maybe_unused xway_gphy_tbl[] = { + { PHY_ID_PHY11G_1_3, 0xffffffff }, + { PHY_ID_PHY22F_1_3, 0xffffffff }, + { PHY_ID_PHY11G_1_4, 0xffffffff }, +diff --git a/drivers/net/phy/lxt.c b/drivers/net/phy/lxt.c +index e3bf827b7959..5251a61c8b0f 100644 +--- a/drivers/net/phy/lxt.c ++++ b/drivers/net/phy/lxt.c +@@ -348,7 +348,7 @@ static struct phy_driver lxt97x_driver[] = { + + module_phy_driver(lxt97x_driver); + +-static struct mdio_device_id __maybe_unused lxt_tbl[] = { ++static const struct mdio_device_id __maybe_unused lxt_tbl[] = { + { 0x78100000, 0xfffffff0 }, + { 0x001378e0, 0xfffffff0 }, + { 0x00137a10, 0xfffffff0 }, +diff --git a/drivers/net/phy/marvell-88q2xxx.c b/drivers/net/phy/marvell-88q2xxx.c +index b3a5a0af19da..d0856a06a9e7 100644 +--- a/drivers/net/phy/marvell-88q2xxx.c ++++ b/drivers/net/phy/marvell-88q2xxx.c +@@ -940,7 +940,7 @@ static struct phy_driver mv88q2xxx_driver[] = { + + module_phy_driver(mv88q2xxx_driver); + +-static struct mdio_device_id __maybe_unused mv88q2xxx_tbl[] = { ++static const struct mdio_device_id __maybe_unused mv88q2xxx_tbl[] = { + { MARVELL_PHY_ID_88Q2110, MARVELL_PHY_ID_MASK }, + { MARVELL_PHY_ID_88Q2220, MARVELL_PHY_ID_MASK }, + { /*sentinel*/ } +diff --git a/drivers/net/phy/marvell-88x2222.c b/drivers/net/phy/marvell-88x2222.c +index 0b777cdd7078..fad2f54c1eac 100644 +--- a/drivers/net/phy/marvell-88x2222.c ++++ b/drivers/net/phy/marvell-88x2222.c +@@ -613,7 +613,7 @@ static struct phy_driver mv2222_drivers[] = { + }; + module_phy_driver(mv2222_drivers); + +-static struct mdio_device_id __maybe_unused mv2222_tbl[] = { ++static const struct mdio_device_id __maybe_unused mv2222_tbl[] = { + { MARVELL_PHY_ID_88X2222, MARVELL_PHY_ID_MASK }, + { } + }; +diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c +index b7d2951d979d..9c761b855026 100644 +--- a/drivers/net/phy/marvell.c ++++ b/drivers/net/phy/marvell.c +@@ -4181,7 +4181,7 @@ static struct phy_driver marvell_drivers[] = { + + module_phy_driver(marvell_drivers); + +-static struct mdio_device_id __maybe_unused marvell_tbl[] = { ++static const struct mdio_device_id __maybe_unused marvell_tbl[] = { + { MARVELL_PHY_ID_88E1101, MARVELL_PHY_ID_MASK }, + { MARVELL_PHY_ID_88E3082, MARVELL_PHY_ID_MASK }, + { MARVELL_PHY_ID_88E1112, MARVELL_PHY_ID_MASK }, +diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c +index 6642eb642d4b..623bdb8466b8 100644 +--- a/drivers/net/phy/marvell10g.c ++++ b/drivers/net/phy/marvell10g.c +@@ -1484,7 +1484,7 @@ static struct phy_driver mv3310_drivers[] = { + + module_phy_driver(mv3310_drivers); + +-static struct mdio_device_id __maybe_unused mv3310_tbl[] = { ++static const struct mdio_device_id __maybe_unused mv3310_tbl[] = { + { MARVELL_PHY_ID_88X3310, MARVELL_PHY_ID_MASK }, + { MARVELL_PHY_ID_88E2110, MARVELL_PHY_ID_MASK }, + { }, +diff --git a/drivers/net/phy/mediatek/mtk-ge-soc.c b/drivers/net/phy/mediatek/mtk-ge-soc.c +index 38dc898eaf7b..bdf99b327029 100644 +--- a/drivers/net/phy/mediatek/mtk-ge-soc.c ++++ b/drivers/net/phy/mediatek/mtk-ge-soc.c +@@ -1356,7 +1356,7 @@ static struct phy_driver mtk_socphy_driver[] = { + + module_phy_driver(mtk_socphy_driver); + +-static struct mdio_device_id __maybe_unused mtk_socphy_tbl[] = { ++static const struct mdio_device_id __maybe_unused mtk_socphy_tbl[] = { + { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7981) }, + { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7988) }, + { } +diff --git a/drivers/net/phy/mediatek/mtk-ge.c b/drivers/net/phy/mediatek/mtk-ge.c +index ed2617bc20f4..b517ca8573e7 100644 +--- a/drivers/net/phy/mediatek/mtk-ge.c ++++ b/drivers/net/phy/mediatek/mtk-ge.c +@@ -93,7 +93,7 @@ static struct phy_driver mtk_gephy_driver[] = { + + module_phy_driver(mtk_gephy_driver); + +-static struct mdio_device_id __maybe_unused mtk_gephy_tbl[] = { ++static const struct mdio_device_id __maybe_unused mtk_gephy_tbl[] = { + { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7530) }, + { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7531) }, + { } +diff --git a/drivers/net/phy/meson-gxl.c b/drivers/net/phy/meson-gxl.c +index bb9b33b6bce2..962ebbbc1348 100644 +--- a/drivers/net/phy/meson-gxl.c ++++ b/drivers/net/phy/meson-gxl.c +@@ -221,7 +221,7 @@ static struct phy_driver meson_gxl_phy[] = { + }, + }; + +-static struct mdio_device_id __maybe_unused meson_gxl_tbl[] = { ++static const struct mdio_device_id __maybe_unused meson_gxl_tbl[] = { + { PHY_ID_MATCH_VENDOR(0x01814400) }, + { PHY_ID_MATCH_VENDOR(0x01803301) }, + { } +diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c +index 92e9eb4146d9..655769765bc8 100644 +--- a/drivers/net/phy/micrel.c ++++ b/drivers/net/phy/micrel.c +@@ -5701,7 +5701,7 @@ MODULE_DESCRIPTION("Micrel PHY driver"); + MODULE_AUTHOR("David J. Choi"); + MODULE_LICENSE("GPL"); + +-static struct mdio_device_id __maybe_unused micrel_tbl[] = { ++static const struct mdio_device_id __maybe_unused micrel_tbl[] = { + { PHY_ID_KSZ9021, 0x000ffffe }, + { PHY_ID_KSZ9031, MICREL_PHY_ID_MASK }, + { PHY_ID_KSZ9131, MICREL_PHY_ID_MASK }, +diff --git a/drivers/net/phy/microchip.c b/drivers/net/phy/microchip.c +index ffca1cec4ec9..55822d36889c 100644 +--- a/drivers/net/phy/microchip.c ++++ b/drivers/net/phy/microchip.c +@@ -509,7 +509,7 @@ static struct phy_driver microchip_phy_driver[] = { + + module_phy_driver(microchip_phy_driver); + +-static struct mdio_device_id __maybe_unused microchip_tbl[] = { ++static const struct mdio_device_id __maybe_unused microchip_tbl[] = { + { 0x0007c132, 0xfffffff2 }, + { PHY_ID_MATCH_MODEL(PHY_ID_LAN937X_TX) }, + { } +diff --git a/drivers/net/phy/microchip_t1.c b/drivers/net/phy/microchip_t1.c +index a5ef8fe50704..4ddc407e405c 100644 +--- a/drivers/net/phy/microchip_t1.c ++++ b/drivers/net/phy/microchip_t1.c +@@ -1886,7 +1886,7 @@ static struct phy_driver microchip_t1_phy_driver[] = { + + module_phy_driver(microchip_t1_phy_driver); + +-static struct mdio_device_id __maybe_unused microchip_t1_tbl[] = { ++static const struct mdio_device_id __maybe_unused microchip_t1_tbl[] = { + { PHY_ID_MATCH_MODEL(PHY_ID_LAN87XX) }, + { PHY_ID_MATCH_MODEL(PHY_ID_LAN937X) }, + { PHY_ID_MATCH_MODEL(PHY_ID_LAN887X) }, +diff --git a/drivers/net/phy/microchip_t1s.c b/drivers/net/phy/microchip_t1s.c +index 3614839a8e51..78c54d826c97 100644 +--- a/drivers/net/phy/microchip_t1s.c ++++ b/drivers/net/phy/microchip_t1s.c +@@ -323,7 +323,7 @@ static struct phy_driver microchip_t1s_driver[] = { + + module_phy_driver(microchip_t1s_driver); + +-static struct mdio_device_id __maybe_unused tbl[] = { ++static const struct mdio_device_id __maybe_unused tbl[] = { + { PHY_ID_MATCH_EXACT(PHY_ID_LAN867X_REVB1) }, + { PHY_ID_MATCH_EXACT(PHY_ID_LAN865X_REVB0) }, + { } +diff --git a/drivers/net/phy/mscc/mscc_main.c b/drivers/net/phy/mscc/mscc_main.c +index 19983b206405..cc2bb9ed4fd2 100644 +--- a/drivers/net/phy/mscc/mscc_main.c ++++ b/drivers/net/phy/mscc/mscc_main.c +@@ -2710,7 +2710,7 @@ static struct phy_driver vsc85xx_driver[] = { + + module_phy_driver(vsc85xx_driver); + +-static struct mdio_device_id __maybe_unused vsc85xx_tbl[] = { ++static const struct mdio_device_id __maybe_unused vsc85xx_tbl[] = { + { PHY_ID_MATCH_VENDOR(PHY_VENDOR_MSCC) }, + { } + }; +diff --git a/drivers/net/phy/mxl-gpy.c b/drivers/net/phy/mxl-gpy.c +index e5f8ac4b4604..d145b67a067f 100644 +--- a/drivers/net/phy/mxl-gpy.c ++++ b/drivers/net/phy/mxl-gpy.c +@@ -1047,7 +1047,7 @@ static struct phy_driver gpy_drivers[] = { + }; + module_phy_driver(gpy_drivers); + +-static struct mdio_device_id __maybe_unused gpy_tbl[] = { ++static const struct mdio_device_id __maybe_unused gpy_tbl[] = { + {PHY_ID_MATCH_MODEL(PHY_ID_GPY2xx)}, + {PHY_ID_GPY115B, PHY_ID_GPYx15B_MASK}, + {PHY_ID_MATCH_MODEL(PHY_ID_GPY115C)}, +diff --git a/drivers/net/phy/national.c b/drivers/net/phy/national.c +index 9ae9cc6b23c2..7f3ff322892e 100644 +--- a/drivers/net/phy/national.c ++++ b/drivers/net/phy/national.c +@@ -173,7 +173,7 @@ MODULE_DESCRIPTION("NatSemi PHY driver"); + MODULE_AUTHOR("Stuart Menefy"); + MODULE_LICENSE("GPL"); + +-static struct mdio_device_id __maybe_unused ns_tbl[] = { ++static const struct mdio_device_id __maybe_unused ns_tbl[] = { + { DP83865_PHY_ID, 0xfffffff0 }, + { } + }; +diff --git a/drivers/net/phy/ncn26000.c b/drivers/net/phy/ncn26000.c +index 5680584f659e..cabdd83c614f 100644 +--- a/drivers/net/phy/ncn26000.c ++++ b/drivers/net/phy/ncn26000.c +@@ -159,7 +159,7 @@ static struct phy_driver ncn26000_driver[] = { + + module_phy_driver(ncn26000_driver); + +-static struct mdio_device_id __maybe_unused ncn26000_tbl[] = { ++static const struct mdio_device_id __maybe_unused ncn26000_tbl[] = { + { PHY_ID_MATCH_MODEL(PHY_ID_NCN26000) }, + { } + }; +diff --git a/drivers/net/phy/nxp-c45-tja11xx.c b/drivers/net/phy/nxp-c45-tja11xx.c +index 99a5eee77bec..9d6b336f9971 100644 +--- a/drivers/net/phy/nxp-c45-tja11xx.c ++++ b/drivers/net/phy/nxp-c45-tja11xx.c +@@ -2102,7 +2102,7 @@ static struct phy_driver nxp_c45_driver[] = { + + module_phy_driver(nxp_c45_driver); + +-static struct mdio_device_id __maybe_unused nxp_c45_tbl[] = { ++static const struct mdio_device_id __maybe_unused nxp_c45_tbl[] = { + { PHY_ID_MATCH_MODEL(PHY_ID_TJA_1103) }, + { PHY_ID_MATCH_MODEL(PHY_ID_TJA_1120) }, + { /*sentinel*/ }, +diff --git a/drivers/net/phy/nxp-cbtx.c b/drivers/net/phy/nxp-cbtx.c +index 145703f0a406..d0ff22f68cd2 100644 +--- a/drivers/net/phy/nxp-cbtx.c ++++ b/drivers/net/phy/nxp-cbtx.c +@@ -215,7 +215,7 @@ static struct phy_driver cbtx_driver[] = { + + module_phy_driver(cbtx_driver); + +-static struct mdio_device_id __maybe_unused cbtx_tbl[] = { ++static const struct mdio_device_id __maybe_unused cbtx_tbl[] = { + { PHY_ID_MATCH_MODEL(PHY_ID_CBTX_SJA1110) }, + { }, + }; +diff --git a/drivers/net/phy/nxp-tja11xx.c b/drivers/net/phy/nxp-tja11xx.c +index 2c263ae44b4f..ed7fa26bac8e 100644 +--- a/drivers/net/phy/nxp-tja11xx.c ++++ b/drivers/net/phy/nxp-tja11xx.c +@@ -888,7 +888,7 @@ static struct phy_driver tja11xx_driver[] = { + + module_phy_driver(tja11xx_driver); + +-static struct mdio_device_id __maybe_unused tja11xx_tbl[] = { ++static const struct mdio_device_id __maybe_unused tja11xx_tbl[] = { + { PHY_ID_MATCH_MODEL(PHY_ID_TJA1100) }, + { PHY_ID_MATCH_MODEL(PHY_ID_TJA1101) }, + { PHY_ID_MATCH_MODEL(PHY_ID_TJA1102) }, +diff --git a/drivers/net/phy/qcom/at803x.c b/drivers/net/phy/qcom/at803x.c +index ac909ad8a87b..8f26e395e39f 100644 +--- a/drivers/net/phy/qcom/at803x.c ++++ b/drivers/net/phy/qcom/at803x.c +@@ -1071,7 +1071,7 @@ static struct phy_driver at803x_driver[] = { + + module_phy_driver(at803x_driver); + +-static struct mdio_device_id __maybe_unused atheros_tbl[] = { ++static const struct mdio_device_id __maybe_unused atheros_tbl[] = { + { ATH8030_PHY_ID, AT8030_PHY_ID_MASK }, + { PHY_ID_MATCH_EXACT(ATH8031_PHY_ID) }, + { PHY_ID_MATCH_EXACT(ATH8032_PHY_ID) }, +diff --git a/drivers/net/phy/qcom/qca807x.c b/drivers/net/phy/qcom/qca807x.c +index ec336c3e338d..2ad8c2586d64 100644 +--- a/drivers/net/phy/qcom/qca807x.c ++++ b/drivers/net/phy/qcom/qca807x.c +@@ -828,7 +828,7 @@ static struct phy_driver qca807x_drivers[] = { + }; + module_phy_driver(qca807x_drivers); + +-static struct mdio_device_id __maybe_unused qca807x_tbl[] = { ++static const struct mdio_device_id __maybe_unused qca807x_tbl[] = { + { PHY_ID_MATCH_EXACT(PHY_ID_QCA8072) }, + { PHY_ID_MATCH_EXACT(PHY_ID_QCA8075) }, + { } +diff --git a/drivers/net/phy/qcom/qca808x.c b/drivers/net/phy/qcom/qca808x.c +index c3aad0e6b700..6de16c0eaa08 100644 +--- a/drivers/net/phy/qcom/qca808x.c ++++ b/drivers/net/phy/qcom/qca808x.c +@@ -655,7 +655,7 @@ static struct phy_driver qca808x_driver[] = { + + module_phy_driver(qca808x_driver); + +-static struct mdio_device_id __maybe_unused qca808x_tbl[] = { ++static const struct mdio_device_id __maybe_unused qca808x_tbl[] = { + { PHY_ID_MATCH_EXACT(QCA8081_PHY_ID) }, + { } + }; +diff --git a/drivers/net/phy/qcom/qca83xx.c b/drivers/net/phy/qcom/qca83xx.c +index a05d0df6fa16..b32c2fbec927 100644 +--- a/drivers/net/phy/qcom/qca83xx.c ++++ b/drivers/net/phy/qcom/qca83xx.c +@@ -261,7 +261,7 @@ static struct phy_driver qca83xx_driver[] = { + + module_phy_driver(qca83xx_driver); + +-static struct mdio_device_id __maybe_unused qca83xx_tbl[] = { ++static const struct mdio_device_id __maybe_unused qca83xx_tbl[] = { + { PHY_ID_MATCH_EXACT(QCA8337_PHY_ID) }, + { PHY_ID_MATCH_EXACT(QCA8327_A_PHY_ID) }, + { PHY_ID_MATCH_EXACT(QCA8327_B_PHY_ID) }, +diff --git a/drivers/net/phy/qsemi.c b/drivers/net/phy/qsemi.c +index 30d15f7c9b03..7b70ba6cab66 100644 +--- a/drivers/net/phy/qsemi.c ++++ b/drivers/net/phy/qsemi.c +@@ -155,7 +155,7 @@ static struct phy_driver qs6612_driver[] = { { + + module_phy_driver(qs6612_driver); + +-static struct mdio_device_id __maybe_unused qs6612_tbl[] = { ++static const struct mdio_device_id __maybe_unused qs6612_tbl[] = { + { 0x00181440, 0xfffffff0 }, + { } + }; +diff --git a/drivers/net/phy/rockchip.c b/drivers/net/phy/rockchip.c +index bb13e75183ee..b338f385e15a 100644 +--- a/drivers/net/phy/rockchip.c ++++ b/drivers/net/phy/rockchip.c +@@ -188,7 +188,7 @@ static struct phy_driver rockchip_phy_driver[] = { + + module_phy_driver(rockchip_phy_driver); + +-static struct mdio_device_id __maybe_unused rockchip_phy_tbl[] = { ++static const struct mdio_device_id __maybe_unused rockchip_phy_tbl[] = { + { INTERNAL_EPHY_ID, 0xfffffff0 }, + { } + }; +diff --git a/drivers/net/phy/smsc.c b/drivers/net/phy/smsc.c +index de66b621eb99..1acac288972d 100644 +--- a/drivers/net/phy/smsc.c ++++ b/drivers/net/phy/smsc.c +@@ -885,7 +885,7 @@ MODULE_DESCRIPTION("SMSC PHY driver"); + MODULE_AUTHOR("Herbert Valerio Riedel"); + MODULE_LICENSE("GPL"); + +-static struct mdio_device_id __maybe_unused smsc_tbl[] = { ++static const struct mdio_device_id __maybe_unused smsc_tbl[] = { + { 0x0007c0a0, 0xfffffff0 }, + { 0x0007c0b0, 0xfffffff0 }, + { 0x0007c0c0, 0xfffffff0 }, +diff --git a/drivers/net/phy/ste10Xp.c b/drivers/net/phy/ste10Xp.c +index 309e4c3496c4..d4835d4c50e0 100644 +--- a/drivers/net/phy/ste10Xp.c ++++ b/drivers/net/phy/ste10Xp.c +@@ -124,7 +124,7 @@ static struct phy_driver ste10xp_pdriver[] = { + + module_phy_driver(ste10xp_pdriver); + +-static struct mdio_device_id __maybe_unused ste10Xp_tbl[] = { ++static const struct mdio_device_id __maybe_unused ste10Xp_tbl[] = { + { STE101P_PHY_ID, 0xfffffff0 }, + { STE100P_PHY_ID, 0xffffffff }, + { } +diff --git a/drivers/net/phy/teranetics.c b/drivers/net/phy/teranetics.c +index 8057ea8dbc21..752d4bf7bb99 100644 +--- a/drivers/net/phy/teranetics.c ++++ b/drivers/net/phy/teranetics.c +@@ -87,7 +87,7 @@ static struct phy_driver teranetics_driver[] = { + + module_phy_driver(teranetics_driver); + +-static struct mdio_device_id __maybe_unused teranetics_tbl[] = { ++static const struct mdio_device_id __maybe_unused teranetics_tbl[] = { + { PHY_ID_TN2020, 0xffffffff }, + { } + }; +diff --git a/drivers/net/phy/uPD60620.c b/drivers/net/phy/uPD60620.c +index 38834347a427..900cb756c366 100644 +--- a/drivers/net/phy/uPD60620.c ++++ b/drivers/net/phy/uPD60620.c +@@ -90,7 +90,7 @@ static struct phy_driver upd60620_driver[1] = { { + + module_phy_driver(upd60620_driver); + +-static struct mdio_device_id __maybe_unused upd60620_tbl[] = { ++static const struct mdio_device_id __maybe_unused upd60620_tbl[] = { + { UPD60620_PHY_ID, 0xfffffffe }, + { } + }; +diff --git a/drivers/net/phy/vitesse.c b/drivers/net/phy/vitesse.c +index 2377179de017..b1b7bbba284e 100644 +--- a/drivers/net/phy/vitesse.c ++++ b/drivers/net/phy/vitesse.c +@@ -674,7 +674,7 @@ static struct phy_driver vsc82xx_driver[] = { + + module_phy_driver(vsc82xx_driver); + +-static struct mdio_device_id __maybe_unused vitesse_tbl[] = { ++static const struct mdio_device_id __maybe_unused vitesse_tbl[] = { + { PHY_ID_VSC8234, 0x000ffff0 }, + { PHY_ID_VSC8244, 0x000fffc0 }, + { PHY_ID_VSC8572, 0x000ffff0 }, +-- +2.51.0 + + +From 9c63de87a5aab32fe251f0d50e2da397138cf3a2 Mon Sep 17 00:00:00 2001 +From: Sky Huang +Date: Thu, 13 Feb 2025 16:05:49 +0800 +Subject: [PATCH 076/517] net: phy: mediatek: Change to more meaningful macros + +Replace magic number with more meaningful macros in mtk-ge.c. +Also, move some common macros into mtk-phy-lib.c. + +Signed-off-by: Sky Huang +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/20250213080553.921434-2-SkyLake.Huang@mediatek.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/mediatek/mtk-ge-soc.c | 1 - + drivers/net/phy/mediatek/mtk-ge.c | 71 +++++++++++++++++++++------ + drivers/net/phy/mediatek/mtk.h | 2 + + 3 files changed, 57 insertions(+), 17 deletions(-) + +diff --git a/drivers/net/phy/mediatek/mtk-ge-soc.c b/drivers/net/phy/mediatek/mtk-ge-soc.c +index bdf99b327029..69cd6a1cbad4 100644 +--- a/drivers/net/phy/mediatek/mtk-ge-soc.c ++++ b/drivers/net/phy/mediatek/mtk-ge-soc.c +@@ -24,7 +24,6 @@ + #define MTK_PHY_SMI_DET_ON_THRESH_MASK GENMASK(13, 8) + + #define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30 +-#define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5 + + #define ANALOG_INTERNAL_OPERATION_MAX_US 20 + #define TXRESERVE_MIN 0 +diff --git a/drivers/net/phy/mediatek/mtk-ge.c b/drivers/net/phy/mediatek/mtk-ge.c +index b517ca8573e7..75e1b0387710 100644 +--- a/drivers/net/phy/mediatek/mtk-ge.c ++++ b/drivers/net/phy/mediatek/mtk-ge.c +@@ -8,18 +8,38 @@ + #define MTK_GPHY_ID_MT7530 0x03a29412 + #define MTK_GPHY_ID_MT7531 0x03a29441 + +-#define MTK_EXT_PAGE_ACCESS 0x1f +-#define MTK_PHY_PAGE_STANDARD 0x0000 +-#define MTK_PHY_PAGE_EXTENDED 0x0001 +-#define MTK_PHY_PAGE_EXTENDED_2 0x0002 +-#define MTK_PHY_PAGE_EXTENDED_3 0x0003 +-#define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30 +-#define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5 ++#define MTK_PHY_PAGE_EXTENDED_1 0x0001 ++#define MTK_PHY_AUX_CTRL_AND_STATUS 0x14 ++#define MTK_PHY_ENABLE_DOWNSHIFT BIT(4) ++ ++#define MTK_PHY_PAGE_EXTENDED_2 0x0002 ++#define MTK_PHY_PAGE_EXTENDED_3 0x0003 ++#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG11 0x11 ++ ++#define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30 ++ ++/* Registers on MDIO_MMD_VEND1 */ ++#define MTK_PHY_GBE_MODE_TX_DELAY_SEL 0x13 ++#define MTK_PHY_TEST_MODE_TX_DELAY_SEL 0x14 ++#define MTK_TX_DELAY_PAIR_B_MASK GENMASK(10, 8) ++#define MTK_TX_DELAY_PAIR_D_MASK GENMASK(2, 0) ++ ++#define MTK_PHY_MCC_CTRL_AND_TX_POWER_CTRL 0xa6 ++#define MTK_MCC_NEARECHO_OFFSET_MASK GENMASK(15, 8) ++ ++#define MTK_PHY_RXADC_CTRL_RG7 0xc6 ++#define MTK_PHY_DA_AD_BUF_BIAS_LP_MASK GENMASK(9, 8) ++ ++#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG123 0x123 ++#define MTK_PHY_LPI_NORM_MSE_LO_THRESH100_MASK GENMASK(15, 8) ++#define MTK_PHY_LPI_NORM_MSE_HI_THRESH100_MASK GENMASK(7, 0) + + static void mtk_gephy_config_init(struct phy_device *phydev) + { + /* Enable HW auto downshift */ +- phy_modify_paged(phydev, MTK_PHY_PAGE_EXTENDED, 0x14, 0, BIT(4)); ++ phy_modify_paged(phydev, MTK_PHY_PAGE_EXTENDED_1, ++ MTK_PHY_AUX_CTRL_AND_STATUS, ++ 0, MTK_PHY_ENABLE_DOWNSHIFT); + + /* Increase SlvDPSready time */ + phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5); +@@ -29,10 +49,20 @@ static void mtk_gephy_config_init(struct phy_device *phydev) + phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0); + + /* Adjust 100_mse_threshold */ +- phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x123, 0xffff); +- +- /* Disable mcc */ +- phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xa6, 0x300); ++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, ++ MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG123, ++ MTK_PHY_LPI_NORM_MSE_LO_THRESH100_MASK | ++ MTK_PHY_LPI_NORM_MSE_HI_THRESH100_MASK, ++ FIELD_PREP(MTK_PHY_LPI_NORM_MSE_LO_THRESH100_MASK, ++ 0xff) | ++ FIELD_PREP(MTK_PHY_LPI_NORM_MSE_HI_THRESH100_MASK, ++ 0xff)); ++ ++ /* If echo time is narrower than 0x3, it will be regarded as noise */ ++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, ++ MTK_PHY_MCC_CTRL_AND_TX_POWER_CTRL, ++ MTK_MCC_NEARECHO_OFFSET_MASK, ++ FIELD_PREP(MTK_MCC_NEARECHO_OFFSET_MASK, 0x3)); + } + + static int mt7530_phy_config_init(struct phy_device *phydev) +@@ -40,7 +70,8 @@ static int mt7530_phy_config_init(struct phy_device *phydev) + mtk_gephy_config_init(phydev); + + /* Increase post_update_timer */ +- phy_write_paged(phydev, MTK_PHY_PAGE_EXTENDED_3, 0x11, 0x4b); ++ phy_write_paged(phydev, MTK_PHY_PAGE_EXTENDED_3, ++ MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG11, 0x4b); + + return 0; + } +@@ -51,11 +82,19 @@ static int mt7531_phy_config_init(struct phy_device *phydev) + + /* PHY link down power saving enable */ + phy_set_bits(phydev, 0x17, BIT(4)); +- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, 0xc6, 0x300); ++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG7, ++ MTK_PHY_DA_AD_BUF_BIAS_LP_MASK, ++ FIELD_PREP(MTK_PHY_DA_AD_BUF_BIAS_LP_MASK, 0x3)); + + /* Set TX Pair delay selection */ +- phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x13, 0x404); +- phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x14, 0x404); ++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_GBE_MODE_TX_DELAY_SEL, ++ MTK_TX_DELAY_PAIR_B_MASK | MTK_TX_DELAY_PAIR_D_MASK, ++ FIELD_PREP(MTK_TX_DELAY_PAIR_B_MASK, 0x4) | ++ FIELD_PREP(MTK_TX_DELAY_PAIR_D_MASK, 0x4)); ++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TEST_MODE_TX_DELAY_SEL, ++ MTK_TX_DELAY_PAIR_B_MASK | MTK_TX_DELAY_PAIR_D_MASK, ++ FIELD_PREP(MTK_TX_DELAY_PAIR_B_MASK, 0x4) | ++ FIELD_PREP(MTK_TX_DELAY_PAIR_D_MASK, 0x4)); + + return 0; + } +diff --git a/drivers/net/phy/mediatek/mtk.h b/drivers/net/phy/mediatek/mtk.h +index 63d9fe179b8f..a888e2e1dd6b 100644 +--- a/drivers/net/phy/mediatek/mtk.h ++++ b/drivers/net/phy/mediatek/mtk.h +@@ -9,6 +9,8 @@ + #define _MTK_EPHY_H_ + + #define MTK_EXT_PAGE_ACCESS 0x1f ++#define MTK_PHY_PAGE_STANDARD 0x0000 ++#define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5 + + /* Registers on MDIO_MMD_VEND2 */ + #define MTK_PHY_LED0_ON_CTRL 0x24 +-- +2.51.0 + + +From 0b2e6555cf36c1011c636b73e0202590247ca124 Mon Sep 17 00:00:00 2001 +From: Sky Huang +Date: Thu, 13 Feb 2025 16:05:50 +0800 +Subject: [PATCH 077/517] net: phy: mediatek: Add token ring access helper + functions in mtk-phy-lib + +This patch adds TR(token ring) manipulations and adds correct +macro names for those magic numbers. TR is a way to access +proprietary registers on page 52b5. Use these helper functions +so we can see which fields we're going to modify/set/clear. + +TR functions with __* prefix mean that the operations inside +aren't wrapped by page select/restore functions. + +This patch doesn't really change registers' settings but just +enhances readability and maintainability. + +Signed-off-by: Sky Huang +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/20250213080553.921434-3-SkyLake.Huang@mediatek.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/mediatek/mtk-ge-soc.c | 231 +++++++++++++++++-------- + drivers/net/phy/mediatek/mtk-ge.c | 11 +- + drivers/net/phy/mediatek/mtk-phy-lib.c | 63 +++++++ + drivers/net/phy/mediatek/mtk.h | 5 + + 4 files changed, 230 insertions(+), 80 deletions(-) + +diff --git a/drivers/net/phy/mediatek/mtk-ge-soc.c b/drivers/net/phy/mediatek/mtk-ge-soc.c +index 69cd6a1cbad4..5d7373793659 100644 +--- a/drivers/net/phy/mediatek/mtk-ge-soc.c ++++ b/drivers/net/phy/mediatek/mtk-ge-soc.c +@@ -25,6 +25,90 @@ + + #define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30 + ++/* Registers on Token Ring debug nodes */ ++/* ch_addr = 0x0, node_addr = 0x7, data_addr = 0x15 */ ++/* NormMseLoThresh */ ++#define NORMAL_MSE_LO_THRESH_MASK GENMASK(15, 8) ++ ++/* ch_addr = 0x0, node_addr = 0xf, data_addr = 0x3c */ ++/* RemAckCntLimitCtrl */ ++#define REMOTE_ACK_COUNT_LIMIT_CTRL_MASK GENMASK(2, 1) ++ ++/* ch_addr = 0x1, node_addr = 0xd, data_addr = 0x20 */ ++/* VcoSlicerThreshBitsHigh */ ++#define VCO_SLICER_THRESH_HIGH_MASK GENMASK(23, 0) ++ ++/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x0 */ ++/* DfeTailEnableVgaThresh1000 */ ++#define DFE_TAIL_EANBLE_VGA_TRHESH_1000 GENMASK(5, 1) ++ ++/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x1 */ ++/* MrvlTrFix100Kp */ ++#define MRVL_TR_FIX_100KP_MASK GENMASK(22, 20) ++/* MrvlTrFix100Kf */ ++#define MRVL_TR_FIX_100KF_MASK GENMASK(19, 17) ++/* MrvlTrFix1000Kp */ ++#define MRVL_TR_FIX_1000KP_MASK GENMASK(16, 14) ++/* MrvlTrFix1000Kf */ ++#define MRVL_TR_FIX_1000KF_MASK GENMASK(13, 11) ++ ++/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x12 */ ++/* VgaDecRate */ ++#define VGA_DECIMATION_RATE_MASK GENMASK(8, 5) ++ ++/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x17 */ ++/* SlvDSPreadyTime */ ++#define SLAVE_DSP_READY_TIME_MASK GENMASK(22, 15) ++/* MasDSPreadyTime */ ++#define MASTER_DSP_READY_TIME_MASK GENMASK(14, 7) ++ ++/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x20 */ ++/* ResetSyncOffset */ ++#define RESET_SYNC_OFFSET_MASK GENMASK(11, 8) ++ ++/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x0 */ ++/* FfeUpdGainForceVal */ ++#define FFE_UPDATE_GAIN_FORCE_VAL_MASK GENMASK(9, 7) ++/* FfeUpdGainForce */ ++#define FFE_UPDATE_GAIN_FORCE BIT(6) ++ ++/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x6 */ ++/* SS: Steady-state, KP: Proportional Gain */ ++/* SSTrKp100 */ ++#define SS_TR_KP100_MASK GENMASK(21, 19) ++/* SSTrKf100 */ ++#define SS_TR_KF100_MASK GENMASK(18, 16) ++/* SSTrKp1000Mas */ ++#define SS_TR_KP1000_MASTER_MASK GENMASK(15, 13) ++/* SSTrKf1000Mas */ ++#define SS_TR_KF1000_MASTER_MASK GENMASK(12, 10) ++/* SSTrKp1000Slv */ ++#define SS_TR_KP1000_SLAVE_MASK GENMASK(9, 7) ++/* SSTrKf1000Slv */ ++#define SS_TR_KF1000_SLAVE_MASK GENMASK(6, 4) ++ ++/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0xd */ ++/* RegEEE_st2TrKf1000 */ ++#define EEE1000_STAGE2_TR_KF_MASK GENMASK(13, 11) ++ ++/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0xf */ ++/* RegEEE_slv_waketr_timer_tar */ ++#define SLAVE_WAKETR_TIMER_MASK GENMASK(20, 11) ++/* RegEEE_slv_remtx_timer_tar */ ++#define SLAVE_REMTX_TIMER_MASK GENMASK(10, 1) ++ ++/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x10 */ ++/* RegEEE_slv_wake_int_timer_tar */ ++#define SLAVE_WAKEINT_TIMER_MASK GENMASK(10, 1) ++ ++/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x14 */ ++/* RegEEE_trfreeze_timer2 */ ++#define TR_FREEZE_TIMER2_MASK GENMASK(9, 0) ++ ++/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x1c */ ++/* RegEEE100Stg1_tar */ ++#define EEE100_LPSYNC_STAGE1_UPDATE_TIMER_MASK GENMASK(8, 0) ++ + #define ANALOG_INTERNAL_OPERATION_MAX_US 20 + #define TXRESERVE_MIN 0 + #define TXRESERVE_MAX 7 +@@ -700,40 +784,41 @@ static int tx_vcm_cal_sw(struct phy_device *phydev, u8 rg_txreserve_x) + static void mt798x_phy_common_finetune(struct phy_device *phydev) + { + phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5); +- /* SlvDSPreadyTime = 24, MasDSPreadyTime = 24 */ +- __phy_write(phydev, 0x11, 0xc71); +- __phy_write(phydev, 0x12, 0xc); +- __phy_write(phydev, 0x10, 0x8fae); ++ __mtk_tr_modify(phydev, 0x1, 0xf, 0x17, ++ SLAVE_DSP_READY_TIME_MASK | MASTER_DSP_READY_TIME_MASK, ++ FIELD_PREP(SLAVE_DSP_READY_TIME_MASK, 0x18) | ++ FIELD_PREP(MASTER_DSP_READY_TIME_MASK, 0x18)); + + /* EnabRandUpdTrig = 1 */ + __phy_write(phydev, 0x11, 0x2f00); + __phy_write(phydev, 0x12, 0xe); + __phy_write(phydev, 0x10, 0x8fb0); + +- /* NormMseLoThresh = 85 */ +- __phy_write(phydev, 0x11, 0x55a0); +- __phy_write(phydev, 0x12, 0x0); +- __phy_write(phydev, 0x10, 0x83aa); ++ __mtk_tr_modify(phydev, 0x0, 0x7, 0x15, ++ NORMAL_MSE_LO_THRESH_MASK, ++ FIELD_PREP(NORMAL_MSE_LO_THRESH_MASK, 0x55)); + +- /* FfeUpdGainForce = 1(Enable), FfeUpdGainForceVal = 4 */ +- __phy_write(phydev, 0x11, 0x240); +- __phy_write(phydev, 0x12, 0x0); +- __phy_write(phydev, 0x10, 0x9680); ++ __mtk_tr_modify(phydev, 0x2, 0xd, 0x0, ++ FFE_UPDATE_GAIN_FORCE_VAL_MASK, ++ FIELD_PREP(FFE_UPDATE_GAIN_FORCE_VAL_MASK, 0x4) | ++ FFE_UPDATE_GAIN_FORCE); + + /* TrFreeze = 0 (mt7988 default) */ + __phy_write(phydev, 0x11, 0x0); + __phy_write(phydev, 0x12, 0x0); + __phy_write(phydev, 0x10, 0x9686); + +- /* SSTrKp100 = 5 */ +- /* SSTrKf100 = 6 */ +- /* SSTrKp1000Mas = 5 */ +- /* SSTrKf1000Mas = 6 */ +- /* SSTrKp1000Slv = 5 */ +- /* SSTrKf1000Slv = 6 */ +- __phy_write(phydev, 0x11, 0xbaef); +- __phy_write(phydev, 0x12, 0x2e); +- __phy_write(phydev, 0x10, 0x968c); ++ __mtk_tr_modify(phydev, 0x2, 0xd, 0x6, ++ SS_TR_KP100_MASK | SS_TR_KF100_MASK | ++ SS_TR_KP1000_MASTER_MASK | SS_TR_KF1000_MASTER_MASK | ++ SS_TR_KP1000_SLAVE_MASK | SS_TR_KF1000_SLAVE_MASK, ++ FIELD_PREP(SS_TR_KP100_MASK, 0x5) | ++ FIELD_PREP(SS_TR_KF100_MASK, 0x6) | ++ FIELD_PREP(SS_TR_KP1000_MASTER_MASK, 0x5) | ++ FIELD_PREP(SS_TR_KF1000_MASTER_MASK, 0x6) | ++ FIELD_PREP(SS_TR_KP1000_SLAVE_MASK, 0x5) | ++ FIELD_PREP(SS_TR_KF1000_SLAVE_MASK, 0x6)); ++ + phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0); + } + +@@ -756,27 +841,29 @@ static void mt7981_phy_finetune(struct phy_device *phydev) + } + + phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5); +- /* ResetSyncOffset = 6 */ +- __phy_write(phydev, 0x11, 0x600); +- __phy_write(phydev, 0x12, 0x0); +- __phy_write(phydev, 0x10, 0x8fc0); ++ __mtk_tr_modify(phydev, 0x1, 0xf, 0x20, ++ RESET_SYNC_OFFSET_MASK, ++ FIELD_PREP(RESET_SYNC_OFFSET_MASK, 0x6)); + +- /* VgaDecRate = 1 */ +- __phy_write(phydev, 0x11, 0x4c2a); +- __phy_write(phydev, 0x12, 0x3e); +- __phy_write(phydev, 0x10, 0x8fa4); ++ __mtk_tr_modify(phydev, 0x1, 0xf, 0x12, ++ VGA_DECIMATION_RATE_MASK, ++ FIELD_PREP(VGA_DECIMATION_RATE_MASK, 0x1)); + + /* MrvlTrFix100Kp = 3, MrvlTrFix100Kf = 2, + * MrvlTrFix1000Kp = 3, MrvlTrFix1000Kf = 2 + */ +- __phy_write(phydev, 0x11, 0xd10a); +- __phy_write(phydev, 0x12, 0x34); +- __phy_write(phydev, 0x10, 0x8f82); ++ __mtk_tr_modify(phydev, 0x1, 0xf, 0x1, ++ MRVL_TR_FIX_100KP_MASK | MRVL_TR_FIX_100KF_MASK | ++ MRVL_TR_FIX_1000KP_MASK | MRVL_TR_FIX_1000KF_MASK, ++ FIELD_PREP(MRVL_TR_FIX_100KP_MASK, 0x3) | ++ FIELD_PREP(MRVL_TR_FIX_100KF_MASK, 0x2) | ++ FIELD_PREP(MRVL_TR_FIX_1000KP_MASK, 0x3) | ++ FIELD_PREP(MRVL_TR_FIX_1000KF_MASK, 0x2)); + + /* VcoSlicerThreshBitsHigh */ +- __phy_write(phydev, 0x11, 0x5555); +- __phy_write(phydev, 0x12, 0x55); +- __phy_write(phydev, 0x10, 0x8ec0); ++ __mtk_tr_modify(phydev, 0x1, 0xd, 0x20, ++ VCO_SLICER_THRESH_HIGH_MASK, ++ FIELD_PREP(VCO_SLICER_THRESH_HIGH_MASK, 0x555555)); + phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0); + + /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 9 */ +@@ -828,25 +915,23 @@ static void mt7988_phy_finetune(struct phy_device *phydev) + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_TX_FILTER, 0x5); + + phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5); +- /* ResetSyncOffset = 5 */ +- __phy_write(phydev, 0x11, 0x500); +- __phy_write(phydev, 0x12, 0x0); +- __phy_write(phydev, 0x10, 0x8fc0); ++ __mtk_tr_modify(phydev, 0x1, 0xf, 0x20, ++ RESET_SYNC_OFFSET_MASK, ++ FIELD_PREP(RESET_SYNC_OFFSET_MASK, 0x5)); + + /* VgaDecRate is 1 at default on mt7988 */ + +- /* MrvlTrFix100Kp = 6, MrvlTrFix100Kf = 7, +- * MrvlTrFix1000Kp = 6, MrvlTrFix1000Kf = 7 +- */ +- __phy_write(phydev, 0x11, 0xb90a); +- __phy_write(phydev, 0x12, 0x6f); +- __phy_write(phydev, 0x10, 0x8f82); +- +- /* RemAckCntLimitCtrl = 1 */ +- __phy_write(phydev, 0x11, 0xfbba); +- __phy_write(phydev, 0x12, 0xc3); +- __phy_write(phydev, 0x10, 0x87f8); +- ++ __mtk_tr_modify(phydev, 0x1, 0xf, 0x1, ++ MRVL_TR_FIX_100KP_MASK | MRVL_TR_FIX_100KF_MASK | ++ MRVL_TR_FIX_1000KP_MASK | MRVL_TR_FIX_1000KF_MASK, ++ FIELD_PREP(MRVL_TR_FIX_100KP_MASK, 0x6) | ++ FIELD_PREP(MRVL_TR_FIX_100KF_MASK, 0x7) | ++ FIELD_PREP(MRVL_TR_FIX_1000KP_MASK, 0x6) | ++ FIELD_PREP(MRVL_TR_FIX_1000KF_MASK, 0x7)); ++ ++ __mtk_tr_modify(phydev, 0x0, 0xf, 0x3c, ++ REMOTE_ACK_COUNT_LIMIT_CTRL_MASK, ++ FIELD_PREP(REMOTE_ACK_COUNT_LIMIT_CTRL_MASK, 0x1)); + phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0); + + /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 10 */ +@@ -927,40 +1012,36 @@ static void mt798x_phy_eee(struct phy_device *phydev) + __phy_write(phydev, 0x12, 0x0); + __phy_write(phydev, 0x10, 0x9690); + +- /* REG_EEE_st2TrKf1000 = 2 */ +- __phy_write(phydev, 0x11, 0x114f); +- __phy_write(phydev, 0x12, 0x2); +- __phy_write(phydev, 0x10, 0x969a); ++ __mtk_tr_modify(phydev, 0x2, 0xd, 0xd, ++ EEE1000_STAGE2_TR_KF_MASK, ++ FIELD_PREP(EEE1000_STAGE2_TR_KF_MASK, 0x2)); + +- /* RegEEE_slv_wake_tr_timer_tar = 6, RegEEE_slv_remtx_timer_tar = 20 */ +- __phy_write(phydev, 0x11, 0x3028); +- __phy_write(phydev, 0x12, 0x0); +- __phy_write(phydev, 0x10, 0x969e); ++ __mtk_tr_modify(phydev, 0x2, 0xd, 0xf, ++ SLAVE_WAKETR_TIMER_MASK | SLAVE_REMTX_TIMER_MASK, ++ FIELD_PREP(SLAVE_WAKETR_TIMER_MASK, 0x6) | ++ FIELD_PREP(SLAVE_REMTX_TIMER_MASK, 0x14)); + +- /* RegEEE_slv_wake_int_timer_tar = 8 */ +- __phy_write(phydev, 0x11, 0x5010); +- __phy_write(phydev, 0x12, 0x0); +- __phy_write(phydev, 0x10, 0x96a0); ++ __mtk_tr_modify(phydev, 0x2, 0xd, 0x10, ++ SLAVE_WAKEINT_TIMER_MASK, ++ FIELD_PREP(SLAVE_WAKEINT_TIMER_MASK, 0x8)); + +- /* RegEEE_trfreeze_timer2 = 586 */ +- __phy_write(phydev, 0x11, 0x24a); +- __phy_write(phydev, 0x12, 0x0); +- __phy_write(phydev, 0x10, 0x96a8); ++ __mtk_tr_modify(phydev, 0x2, 0xd, 0x14, ++ TR_FREEZE_TIMER2_MASK, ++ FIELD_PREP(TR_FREEZE_TIMER2_MASK, 0x24a)); + +- /* RegEEE100Stg1_tar = 16 */ +- __phy_write(phydev, 0x11, 0x3210); +- __phy_write(phydev, 0x12, 0x0); +- __phy_write(phydev, 0x10, 0x96b8); ++ __mtk_tr_modify(phydev, 0x2, 0xd, 0x1c, ++ EEE100_LPSYNC_STAGE1_UPDATE_TIMER_MASK, ++ FIELD_PREP(EEE100_LPSYNC_STAGE1_UPDATE_TIMER_MASK, ++ 0x10)); + + /* REGEEE_wake_slv_tr_wait_dfesigdet_en = 0 */ + __phy_write(phydev, 0x11, 0x1463); + __phy_write(phydev, 0x12, 0x0); + __phy_write(phydev, 0x10, 0x96ca); + +- /* DfeTailEnableVgaThresh1000 = 27 */ +- __phy_write(phydev, 0x11, 0x36); +- __phy_write(phydev, 0x12, 0x0); +- __phy_write(phydev, 0x10, 0x8f80); ++ __mtk_tr_modify(phydev, 0x1, 0xf, 0x0, ++ DFE_TAIL_EANBLE_VGA_TRHESH_1000, ++ FIELD_PREP(DFE_TAIL_EANBLE_VGA_TRHESH_1000, 0x1b)); + phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0); + + phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_3); +diff --git a/drivers/net/phy/mediatek/mtk-ge.c b/drivers/net/phy/mediatek/mtk-ge.c +index 75e1b0387710..a24c5ba469ba 100644 +--- a/drivers/net/phy/mediatek/mtk-ge.c ++++ b/drivers/net/phy/mediatek/mtk-ge.c +@@ -18,6 +18,10 @@ + + #define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30 + ++/* Registers on Token Ring debug nodes */ ++/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x17 */ ++#define SLAVE_DSP_READY_TIME_MASK GENMASK(22, 15) ++ + /* Registers on MDIO_MMD_VEND1 */ + #define MTK_PHY_GBE_MODE_TX_DELAY_SEL 0x13 + #define MTK_PHY_TEST_MODE_TX_DELAY_SEL 0x14 +@@ -42,11 +46,8 @@ static void mtk_gephy_config_init(struct phy_device *phydev) + 0, MTK_PHY_ENABLE_DOWNSHIFT); + + /* Increase SlvDPSready time */ +- phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5); +- __phy_write(phydev, 0x10, 0xafae); +- __phy_write(phydev, 0x12, 0x2f); +- __phy_write(phydev, 0x10, 0x8fae); +- phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0); ++ mtk_tr_modify(phydev, 0x1, 0xf, 0x17, SLAVE_DSP_READY_TIME_MASK, ++ FIELD_PREP(SLAVE_DSP_READY_TIME_MASK, 0x5e)); + + /* Adjust 100_mse_threshold */ + phy_modify_mmd(phydev, MDIO_MMD_VEND1, +diff --git a/drivers/net/phy/mediatek/mtk-phy-lib.c b/drivers/net/phy/mediatek/mtk-phy-lib.c +index 98a09d670e9c..7275e4ee2298 100644 +--- a/drivers/net/phy/mediatek/mtk-phy-lib.c ++++ b/drivers/net/phy/mediatek/mtk-phy-lib.c +@@ -6,6 +6,69 @@ + + #include "mtk.h" + ++/* Difference between functions with mtk_tr* and __mtk_tr* prefixes is ++ * mtk_tr* functions: wrapped by page switching operations ++ * __mtk_tr* functions: no page switching operations ++ */ ++ ++static void __mtk_tr_access(struct phy_device *phydev, bool read, u8 ch_addr, ++ u8 node_addr, u8 data_addr) ++{ ++ u16 tr_cmd = BIT(15); /* bit 14 & 0 are reserved */ ++ ++ if (read) ++ tr_cmd |= BIT(13); ++ ++ tr_cmd |= (((ch_addr & 0x3) << 11) | ++ ((node_addr & 0xf) << 7) | ++ ((data_addr & 0x3f) << 1)); ++ dev_dbg(&phydev->mdio.dev, "tr_cmd: 0x%x\n", tr_cmd); ++ __phy_write(phydev, 0x10, tr_cmd); ++} ++ ++static void __mtk_tr_read(struct phy_device *phydev, u8 ch_addr, u8 node_addr, ++ u8 data_addr, u16 *tr_high, u16 *tr_low) ++{ ++ __mtk_tr_access(phydev, true, ch_addr, node_addr, data_addr); ++ *tr_low = __phy_read(phydev, 0x11); ++ *tr_high = __phy_read(phydev, 0x12); ++ dev_dbg(&phydev->mdio.dev, "tr_high read: 0x%x, tr_low read: 0x%x\n", ++ *tr_high, *tr_low); ++} ++ ++static void __mtk_tr_write(struct phy_device *phydev, u8 ch_addr, u8 node_addr, ++ u8 data_addr, u32 tr_data) ++{ ++ __phy_write(phydev, 0x11, tr_data & 0xffff); ++ __phy_write(phydev, 0x12, tr_data >> 16); ++ dev_dbg(&phydev->mdio.dev, "tr_high write: 0x%x, tr_low write: 0x%x\n", ++ tr_data >> 16, tr_data & 0xffff); ++ __mtk_tr_access(phydev, false, ch_addr, node_addr, data_addr); ++} ++ ++void __mtk_tr_modify(struct phy_device *phydev, u8 ch_addr, u8 node_addr, ++ u8 data_addr, u32 mask, u32 set) ++{ ++ u32 tr_data; ++ u16 tr_high; ++ u16 tr_low; ++ ++ __mtk_tr_read(phydev, ch_addr, node_addr, data_addr, &tr_high, &tr_low); ++ tr_data = (tr_high << 16) | tr_low; ++ tr_data = (tr_data & ~mask) | set; ++ __mtk_tr_write(phydev, ch_addr, node_addr, data_addr, tr_data); ++} ++EXPORT_SYMBOL_GPL(__mtk_tr_modify); ++ ++void mtk_tr_modify(struct phy_device *phydev, u8 ch_addr, u8 node_addr, ++ u8 data_addr, u32 mask, u32 set) ++{ ++ phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5); ++ __mtk_tr_modify(phydev, ch_addr, node_addr, data_addr, mask, set); ++ phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0); ++} ++EXPORT_SYMBOL_GPL(mtk_tr_modify); ++ + int mtk_phy_read_page(struct phy_device *phydev) + { + return __phy_read(phydev, MTK_EXT_PAGE_ACCESS); +diff --git a/drivers/net/phy/mediatek/mtk.h b/drivers/net/phy/mediatek/mtk.h +index a888e2e1dd6b..af44d1ad8c9e 100644 +--- a/drivers/net/phy/mediatek/mtk.h ++++ b/drivers/net/phy/mediatek/mtk.h +@@ -68,6 +68,11 @@ struct mtk_socphy_priv { + unsigned long led_state; + }; + ++void __mtk_tr_modify(struct phy_device *phydev, u8 ch_addr, u8 node_addr, ++ u8 data_addr, u32 mask, u32 set); ++void mtk_tr_modify(struct phy_device *phydev, u8 ch_addr, u8 node_addr, ++ u8 data_addr, u32 mask, u32 set); ++ + int mtk_phy_read_page(struct phy_device *phydev); + int mtk_phy_write_page(struct phy_device *phydev, int page); + +-- +2.51.0 + + +From 3452f1a79d2394d16043c7d1ac424f16db88c232 Mon Sep 17 00:00:00 2001 +From: Sky Huang +Date: Thu, 13 Feb 2025 16:05:51 +0800 +Subject: [PATCH 078/517] net: phy: mediatek: Add token ring set bit operation + support + +Previously in mtk-ge-soc.c, we set some register bits via token +ring, which were implemented in three __phy_write(). +Now we can do the same thing via __mtk_tr_set_bits() helper. + +Signed-off-by: Sky Huang +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/20250213080553.921434-4-SkyLake.Huang@mediatek.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/mediatek/mtk-ge-soc.c | 10 ++++++---- + drivers/net/phy/mediatek/mtk-phy-lib.c | 7 +++++++ + drivers/net/phy/mediatek/mtk.h | 2 ++ + 3 files changed, 15 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/phy/mediatek/mtk-ge-soc.c b/drivers/net/phy/mediatek/mtk-ge-soc.c +index 5d7373793659..37777ad104d8 100644 +--- a/drivers/net/phy/mediatek/mtk-ge-soc.c ++++ b/drivers/net/phy/mediatek/mtk-ge-soc.c +@@ -62,6 +62,10 @@ + /* MasDSPreadyTime */ + #define MASTER_DSP_READY_TIME_MASK GENMASK(14, 7) + ++/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x18 */ ++/* EnabRandUpdTrig */ ++#define ENABLE_RANDOM_UPDOWN_COUNTER_TRIGGER BIT(8) ++ + /* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x20 */ + /* ResetSyncOffset */ + #define RESET_SYNC_OFFSET_MASK GENMASK(11, 8) +@@ -789,10 +793,8 @@ static void mt798x_phy_common_finetune(struct phy_device *phydev) + FIELD_PREP(SLAVE_DSP_READY_TIME_MASK, 0x18) | + FIELD_PREP(MASTER_DSP_READY_TIME_MASK, 0x18)); + +- /* EnabRandUpdTrig = 1 */ +- __phy_write(phydev, 0x11, 0x2f00); +- __phy_write(phydev, 0x12, 0xe); +- __phy_write(phydev, 0x10, 0x8fb0); ++ __mtk_tr_set_bits(phydev, 0x1, 0xf, 0x18, ++ ENABLE_RANDOM_UPDOWN_COUNTER_TRIGGER); + + __mtk_tr_modify(phydev, 0x0, 0x7, 0x15, + NORMAL_MSE_LO_THRESH_MASK, +diff --git a/drivers/net/phy/mediatek/mtk-phy-lib.c b/drivers/net/phy/mediatek/mtk-phy-lib.c +index 7275e4ee2298..df8fdadcc0f4 100644 +--- a/drivers/net/phy/mediatek/mtk-phy-lib.c ++++ b/drivers/net/phy/mediatek/mtk-phy-lib.c +@@ -69,6 +69,13 @@ void mtk_tr_modify(struct phy_device *phydev, u8 ch_addr, u8 node_addr, + } + EXPORT_SYMBOL_GPL(mtk_tr_modify); + ++void __mtk_tr_set_bits(struct phy_device *phydev, u8 ch_addr, u8 node_addr, ++ u8 data_addr, u32 set) ++{ ++ __mtk_tr_modify(phydev, ch_addr, node_addr, data_addr, 0, set); ++} ++EXPORT_SYMBOL_GPL(__mtk_tr_set_bits); ++ + int mtk_phy_read_page(struct phy_device *phydev) + { + return __phy_read(phydev, MTK_EXT_PAGE_ACCESS); +diff --git a/drivers/net/phy/mediatek/mtk.h b/drivers/net/phy/mediatek/mtk.h +index af44d1ad8c9e..2d8e5b934a02 100644 +--- a/drivers/net/phy/mediatek/mtk.h ++++ b/drivers/net/phy/mediatek/mtk.h +@@ -72,6 +72,8 @@ void __mtk_tr_modify(struct phy_device *phydev, u8 ch_addr, u8 node_addr, + u8 data_addr, u32 mask, u32 set); + void mtk_tr_modify(struct phy_device *phydev, u8 ch_addr, u8 node_addr, + u8 data_addr, u32 mask, u32 set); ++void __mtk_tr_set_bits(struct phy_device *phydev, u8 ch_addr, u8 node_addr, ++ u8 data_addr, u32 set); + + int mtk_phy_read_page(struct phy_device *phydev); + int mtk_phy_write_page(struct phy_device *phydev, int page); +-- +2.51.0 + + +From ed0b08bbd81086c8298ae9dee01d0d935a74f374 Mon Sep 17 00:00:00 2001 +From: Sky Huang +Date: Thu, 13 Feb 2025 16:05:52 +0800 +Subject: [PATCH 079/517] net: phy: mediatek: Add token ring clear bit + operation support + +Similar to __mtk_tr_set_bits() support. Previously in mtk-ge-soc.c, +we clear some register bits via token ring, which were also implemented +in three __phy_write(). Now we can do the same thing via +__mtk_tr_clr_bits() helper. + +Signed-off-by: Sky Huang +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/20250213080553.921434-5-SkyLake.Huang@mediatek.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/mediatek/mtk-ge-soc.c | 30 +++++++++++++++----------- + drivers/net/phy/mediatek/mtk-phy-lib.c | 7 ++++++ + drivers/net/phy/mediatek/mtk.h | 2 ++ + 3 files changed, 27 insertions(+), 12 deletions(-) + +diff --git a/drivers/net/phy/mediatek/mtk-ge-soc.c b/drivers/net/phy/mediatek/mtk-ge-soc.c +index 37777ad104d8..9de6fbb45564 100644 +--- a/drivers/net/phy/mediatek/mtk-ge-soc.c ++++ b/drivers/net/phy/mediatek/mtk-ge-soc.c +@@ -76,6 +76,10 @@ + /* FfeUpdGainForce */ + #define FFE_UPDATE_GAIN_FORCE BIT(6) + ++/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x3 */ ++/* TrFreeze */ ++#define TR_FREEZE_MASK GENMASK(11, 0) ++ + /* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x6 */ + /* SS: Steady-state, KP: Proportional Gain */ + /* SSTrKp100 */ +@@ -91,6 +95,11 @@ + /* SSTrKf1000Slv */ + #define SS_TR_KF1000_SLAVE_MASK GENMASK(6, 4) + ++/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x8 */ ++/* clear this bit if wanna select from AFE */ ++/* Regsigdet_sel_1000 */ ++#define EEE1000_SELECT_SIGNAL_DETECTION_FROM_DFE BIT(4) ++ + /* ch_addr = 0x2, node_addr = 0xd, data_addr = 0xd */ + /* RegEEE_st2TrKf1000 */ + #define EEE1000_STAGE2_TR_KF_MASK GENMASK(13, 11) +@@ -113,6 +122,10 @@ + /* RegEEE100Stg1_tar */ + #define EEE100_LPSYNC_STAGE1_UPDATE_TIMER_MASK GENMASK(8, 0) + ++/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x25 */ ++/* REGEEE_wake_slv_tr_wait_dfesigdet_en */ ++#define WAKE_SLAVE_TR_WAIT_DFE_DETECTION_EN BIT(11) ++ + #define ANALOG_INTERNAL_OPERATION_MAX_US 20 + #define TXRESERVE_MIN 0 + #define TXRESERVE_MAX 7 +@@ -805,10 +818,7 @@ static void mt798x_phy_common_finetune(struct phy_device *phydev) + FIELD_PREP(FFE_UPDATE_GAIN_FORCE_VAL_MASK, 0x4) | + FFE_UPDATE_GAIN_FORCE); + +- /* TrFreeze = 0 (mt7988 default) */ +- __phy_write(phydev, 0x11, 0x0); +- __phy_write(phydev, 0x12, 0x0); +- __phy_write(phydev, 0x10, 0x9686); ++ __mtk_tr_clr_bits(phydev, 0x2, 0xd, 0x3, TR_FREEZE_MASK); + + __mtk_tr_modify(phydev, 0x2, 0xd, 0x6, + SS_TR_KP100_MASK | SS_TR_KF100_MASK | +@@ -1009,10 +1019,8 @@ static void mt798x_phy_eee(struct phy_device *phydev) + MTK_PHY_TR_READY_SKIP_AFE_WAKEUP); + + phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5); +- /* Regsigdet_sel_1000 = 0 */ +- __phy_write(phydev, 0x11, 0xb); +- __phy_write(phydev, 0x12, 0x0); +- __phy_write(phydev, 0x10, 0x9690); ++ __mtk_tr_clr_bits(phydev, 0x2, 0xd, 0x8, ++ EEE1000_SELECT_SIGNAL_DETECTION_FROM_DFE); + + __mtk_tr_modify(phydev, 0x2, 0xd, 0xd, + EEE1000_STAGE2_TR_KF_MASK, +@@ -1036,10 +1044,8 @@ static void mt798x_phy_eee(struct phy_device *phydev) + FIELD_PREP(EEE100_LPSYNC_STAGE1_UPDATE_TIMER_MASK, + 0x10)); + +- /* REGEEE_wake_slv_tr_wait_dfesigdet_en = 0 */ +- __phy_write(phydev, 0x11, 0x1463); +- __phy_write(phydev, 0x12, 0x0); +- __phy_write(phydev, 0x10, 0x96ca); ++ __mtk_tr_clr_bits(phydev, 0x2, 0xd, 0x25, ++ WAKE_SLAVE_TR_WAIT_DFE_DETECTION_EN); + + __mtk_tr_modify(phydev, 0x1, 0xf, 0x0, + DFE_TAIL_EANBLE_VGA_TRHESH_1000, +diff --git a/drivers/net/phy/mediatek/mtk-phy-lib.c b/drivers/net/phy/mediatek/mtk-phy-lib.c +index df8fdadcc0f4..dfd0f4e439a2 100644 +--- a/drivers/net/phy/mediatek/mtk-phy-lib.c ++++ b/drivers/net/phy/mediatek/mtk-phy-lib.c +@@ -76,6 +76,13 @@ void __mtk_tr_set_bits(struct phy_device *phydev, u8 ch_addr, u8 node_addr, + } + EXPORT_SYMBOL_GPL(__mtk_tr_set_bits); + ++void __mtk_tr_clr_bits(struct phy_device *phydev, u8 ch_addr, u8 node_addr, ++ u8 data_addr, u32 clr) ++{ ++ __mtk_tr_modify(phydev, ch_addr, node_addr, data_addr, clr, 0); ++} ++EXPORT_SYMBOL_GPL(__mtk_tr_clr_bits); ++ + int mtk_phy_read_page(struct phy_device *phydev) + { + return __phy_read(phydev, MTK_EXT_PAGE_ACCESS); +diff --git a/drivers/net/phy/mediatek/mtk.h b/drivers/net/phy/mediatek/mtk.h +index 2d8e5b934a02..4e4468dc0234 100644 +--- a/drivers/net/phy/mediatek/mtk.h ++++ b/drivers/net/phy/mediatek/mtk.h +@@ -74,6 +74,8 @@ void mtk_tr_modify(struct phy_device *phydev, u8 ch_addr, u8 node_addr, + u8 data_addr, u32 mask, u32 set); + void __mtk_tr_set_bits(struct phy_device *phydev, u8 ch_addr, u8 node_addr, + u8 data_addr, u32 set); ++void __mtk_tr_clr_bits(struct phy_device *phydev, u8 ch_addr, u8 node_addr, ++ u8 data_addr, u32 clr); + + int mtk_phy_read_page(struct phy_device *phydev); + int mtk_phy_write_page(struct phy_device *phydev, int page); +-- +2.51.0 + + +From d3ad9045643e6c80993d9e1e033bf6fc8b4c35a5 Mon Sep 17 00:00:00 2001 +From: Sky Huang +Date: Thu, 13 Feb 2025 16:05:53 +0800 +Subject: [PATCH 080/517] net: phy: mediatek: Move some macros to phy-lib for + later use + +Move some macros to phy-lib because MediaTek's 2.5G built-in +ethernet PHY will also use them. + +Signed-off-by: Sky Huang +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/20250213080553.921434-6-SkyLake.Huang@mediatek.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/mediatek/mtk-ge.c | 4 ---- + drivers/net/phy/mediatek/mtk.h | 4 ++++ + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/phy/mediatek/mtk-ge.c b/drivers/net/phy/mediatek/mtk-ge.c +index a24c5ba469ba..73d9b72f9d9e 100644 +--- a/drivers/net/phy/mediatek/mtk-ge.c ++++ b/drivers/net/phy/mediatek/mtk-ge.c +@@ -8,10 +8,6 @@ + #define MTK_GPHY_ID_MT7530 0x03a29412 + #define MTK_GPHY_ID_MT7531 0x03a29441 + +-#define MTK_PHY_PAGE_EXTENDED_1 0x0001 +-#define MTK_PHY_AUX_CTRL_AND_STATUS 0x14 +-#define MTK_PHY_ENABLE_DOWNSHIFT BIT(4) +- + #define MTK_PHY_PAGE_EXTENDED_2 0x0002 + #define MTK_PHY_PAGE_EXTENDED_3 0x0003 + #define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG11 0x11 +diff --git a/drivers/net/phy/mediatek/mtk.h b/drivers/net/phy/mediatek/mtk.h +index 4e4468dc0234..320f76ffa81f 100644 +--- a/drivers/net/phy/mediatek/mtk.h ++++ b/drivers/net/phy/mediatek/mtk.h +@@ -8,7 +8,11 @@ + #ifndef _MTK_EPHY_H_ + #define _MTK_EPHY_H_ + ++#define MTK_PHY_AUX_CTRL_AND_STATUS 0x14 ++#define MTK_PHY_ENABLE_DOWNSHIFT BIT(4) ++ + #define MTK_EXT_PAGE_ACCESS 0x1f ++#define MTK_PHY_PAGE_EXTENDED_1 0x0001 + #define MTK_PHY_PAGE_STANDARD 0x0000 + #define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5 + +-- +2.51.0 + + +From af060cc711880b488a95c56cf7e0fb28f2e71b22 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Thu, 10 Apr 2025 12:04:03 +0200 +Subject: [PATCH 081/517] net: phy: mediatek: permit to compile test GE SOC PHY + driver + +When commit 462a3daad679 ("net: phy: mediatek: fix compile-test +dependencies") fixed the dependency, it should have also introduced +an or on COMPILE_TEST to permit this driver to be compile-tested even if +NVMEM_MTK_EFUSE wasn't selected. The driver makes use of NVMEM API that +are always compiled (return error) so the driver can actually be +compiled even without that config. + +Fix and simplify the dependency condition of this kernel config. + +Fixes: 462a3daad679 ("net: phy: mediatek: fix compile-test dependencies") +Acked-by: Daniel Golle +Reviewed-by: Andrew Lunn +Signed-off-by: Christian Marangi +Acked-by: Arnd Bergmann +Link: https://patch.msgid.link/20250410100410.348-1-ansuelsmth@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/mediatek/Kconfig | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/net/phy/mediatek/Kconfig b/drivers/net/phy/mediatek/Kconfig +index 2a8ac5aed0f8..6a4c2b328c41 100644 +--- a/drivers/net/phy/mediatek/Kconfig ++++ b/drivers/net/phy/mediatek/Kconfig +@@ -15,8 +15,7 @@ config MEDIATEK_GE_PHY + + config MEDIATEK_GE_SOC_PHY + tristate "MediaTek SoC Ethernet PHYs" +- depends on (ARM64 && ARCH_MEDIATEK) || COMPILE_TEST +- depends on NVMEM_MTK_EFUSE ++ depends on (ARM64 && ARCH_MEDIATEK && NVMEM_MTK_EFUSE) || COMPILE_TEST + select MTK_NET_PHYLIB + help + Supports MediaTek SoC built-in Gigabit Ethernet PHYs. +-- +2.51.0 + + +From 42073f8fa909d98142b7754ce0f020d96b0bf48e Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Thu, 10 Apr 2025 12:04:04 +0200 +Subject: [PATCH 082/517] net: phy: mediatek: add Airoha PHY ID to SoC driver + +Airoha AN7581 SoC ship with a Switch based on the MT753x Switch embedded +in other SoC like the MT7581 and the MT7988. Similar to these they +require configuring some pin to enable LED PHYs. + +Add support for the PHY ID for the Airoha embedded Switch and define a +simple probe function to toggle these pins. Also fill the LED functions +and add dedicated function to define LED polarity. + +Reviewed-by: Andrew Lunn +Signed-off-by: Christian Marangi +Link: https://patch.msgid.link/20250410100410.348-2-ansuelsmth@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/mediatek/Kconfig | 4 +- + drivers/net/phy/mediatek/mtk-ge-soc.c | 62 +++++++++++++++++++++++++++ + 2 files changed, 65 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/phy/mediatek/Kconfig b/drivers/net/phy/mediatek/Kconfig +index 6a4c2b328c41..4308002bb82c 100644 +--- a/drivers/net/phy/mediatek/Kconfig ++++ b/drivers/net/phy/mediatek/Kconfig +@@ -15,7 +15,9 @@ config MEDIATEK_GE_PHY + + config MEDIATEK_GE_SOC_PHY + tristate "MediaTek SoC Ethernet PHYs" +- depends on (ARM64 && ARCH_MEDIATEK && NVMEM_MTK_EFUSE) || COMPILE_TEST ++ depends on ARM64 || COMPILE_TEST ++ depends on ARCH_AIROHA || (ARCH_MEDIATEK && NVMEM_MTK_EFUSE) || \ ++ COMPILE_TEST + select MTK_NET_PHYLIB + help + Supports MediaTek SoC built-in Gigabit Ethernet PHYs. +diff --git a/drivers/net/phy/mediatek/mtk-ge-soc.c b/drivers/net/phy/mediatek/mtk-ge-soc.c +index 9de6fbb45564..fea2a55764f1 100644 +--- a/drivers/net/phy/mediatek/mtk-ge-soc.c ++++ b/drivers/net/phy/mediatek/mtk-ge-soc.c +@@ -10,8 +10,11 @@ + + #include "mtk.h" + ++#define MTK_PHY_MAX_LEDS 2 ++ + #define MTK_GPHY_ID_MT7981 0x03a29461 + #define MTK_GPHY_ID_MT7988 0x03a29481 ++#define MTK_GPHY_ID_AN7581 0x03a294c1 + + #define MTK_EXT_PAGE_ACCESS 0x1f + #define MTK_PHY_PAGE_STANDARD 0x0000 +@@ -1405,6 +1408,53 @@ static int mt7981_phy_probe(struct phy_device *phydev) + return mt798x_phy_calibration(phydev); + } + ++static int an7581_phy_probe(struct phy_device *phydev) ++{ ++ struct mtk_socphy_priv *priv; ++ struct pinctrl *pinctrl; ++ ++ /* Toggle pinctrl to enable PHY LED */ ++ pinctrl = devm_pinctrl_get_select(&phydev->mdio.dev, "gbe-led"); ++ if (IS_ERR(pinctrl)) ++ dev_err(&phydev->mdio.bus->dev, ++ "Failed to setup PHY LED pinctrl\n"); ++ ++ priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ phydev->priv = priv; ++ ++ return 0; ++} ++ ++static int an7581_phy_led_polarity_set(struct phy_device *phydev, int index, ++ unsigned long modes) ++{ ++ u32 mode; ++ u16 val; ++ ++ if (index >= MTK_PHY_MAX_LEDS) ++ return -EINVAL; ++ ++ for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) { ++ switch (mode) { ++ case PHY_LED_ACTIVE_LOW: ++ val = MTK_PHY_LED_ON_POLARITY; ++ break; ++ case PHY_LED_ACTIVE_HIGH: ++ val = 0; ++ break; ++ default: ++ return -EINVAL; ++ } ++ } ++ ++ return phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ? ++ MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL, ++ MTK_PHY_LED_ON_POLARITY, val); ++} ++ + static struct phy_driver mtk_socphy_driver[] = { + { + PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7981), +@@ -1440,6 +1490,17 @@ static struct phy_driver mtk_socphy_driver[] = { + .led_hw_control_set = mt798x_phy_led_hw_control_set, + .led_hw_control_get = mt798x_phy_led_hw_control_get, + }, ++ { ++ PHY_ID_MATCH_EXACT(MTK_GPHY_ID_AN7581), ++ .name = "Airoha AN7581 PHY", ++ .probe = an7581_phy_probe, ++ .led_blink_set = mt798x_phy_led_blink_set, ++ .led_brightness_set = mt798x_phy_led_brightness_set, ++ .led_hw_is_supported = mt798x_phy_led_hw_is_supported, ++ .led_hw_control_set = mt798x_phy_led_hw_control_set, ++ .led_hw_control_get = mt798x_phy_led_hw_control_get, ++ .led_polarity_set = an7581_phy_led_polarity_set, ++ }, + }; + + module_phy_driver(mtk_socphy_driver); +@@ -1447,6 +1508,7 @@ module_phy_driver(mtk_socphy_driver); + static const struct mdio_device_id __maybe_unused mtk_socphy_tbl[] = { + { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7981) }, + { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7988) }, ++ { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_AN7581) }, + { } + }; + +-- +2.51.0 + + +From 1b9be68d030e01f77d09abc1307fb7abb7f3a351 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Tue, 15 Apr 2025 12:53:05 +0200 +Subject: [PATCH 083/517] net: phy: mediatek: init val in .phy_led_polarity_set + for AN7581 + +Fix smatch warning for uninitialised val in .phy_led_polarity_set for +AN7581 driver. + +Correctly init to 0 to set polarity high by default. + +Reported-by: Simon Horman +Fixes: 6a325aed130b ("net: phy: mediatek: add Airoha PHY ID to SoC driver") +Signed-off-by: Christian Marangi +Link: https://patch.msgid.link/20250415105313.3409-1-ansuelsmth@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/mediatek/mtk-ge-soc.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/net/phy/mediatek/mtk-ge-soc.c b/drivers/net/phy/mediatek/mtk-ge-soc.c +index fea2a55764f1..6be49447d10d 100644 +--- a/drivers/net/phy/mediatek/mtk-ge-soc.c ++++ b/drivers/net/phy/mediatek/mtk-ge-soc.c +@@ -1431,8 +1431,8 @@ static int an7581_phy_probe(struct phy_device *phydev) + static int an7581_phy_led_polarity_set(struct phy_device *phydev, int index, + unsigned long modes) + { ++ u16 val = 0; + u32 mode; +- u16 val; + + if (index >= MTK_PHY_MAX_LEDS) + return -EINVAL; +@@ -1443,7 +1443,6 @@ static int an7581_phy_led_polarity_set(struct phy_device *phydev, int index, + val = MTK_PHY_LED_ON_POLARITY; + break; + case PHY_LED_ACTIVE_HIGH: +- val = 0; + break; + default: + return -EINVAL; +-- +2.51.0 + + +From 613f6f7764030e9abaace9416e36333b26dbbd65 Mon Sep 17 00:00:00 2001 +From: Qingfang Deng +Date: Mon, 17 Feb 2025 17:40:21 +0800 +Subject: [PATCH 084/517] net: ethernet: mediatek: add EEE support + +Add EEE support to MediaTek SoC Ethernet. The register fields are +similar to the ones in MT7531, except that the LPI threshold is in +milliseconds. + +Signed-off-by: Qingfang Deng +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 69 +++++++++++++++++++++ + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 13 ++++ + 2 files changed, 82 insertions(+) + +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +index 64d86068b51e..2a0be107b3d7 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -782,6 +782,7 @@ static void mtk_mac_link_up(struct phylink_config *config, + + mcr = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id)); + mcr &= ~(MAC_MCR_SPEED_100 | MAC_MCR_SPEED_1000 | ++ MAC_MCR_EEE100M | MAC_MCR_EEE1G | + MAC_MCR_FORCE_DPX | MAC_MCR_FORCE_TX_FC | + MAC_MCR_FORCE_RX_FC); + +@@ -807,6 +808,15 @@ static void mtk_mac_link_up(struct phylink_config *config, + if (rx_pause) + mcr |= MAC_MCR_FORCE_RX_FC; + ++ if (mode == MLO_AN_PHY && phy && mac->tx_lpi_enabled && phy_init_eee(phy, false) >= 0) { ++ mcr |= MAC_MCR_EEE100M | MAC_MCR_EEE1G; ++ mtk_w32(mac->hw, ++ FIELD_PREP(MAC_EEE_WAKEUP_TIME_1000, 17) | ++ FIELD_PREP(MAC_EEE_WAKEUP_TIME_100, 36) | ++ FIELD_PREP(MAC_EEE_LPI_TXIDLE_THD, mac->txidle_thd_ms), ++ MTK_MAC_EEECR(mac->id)); ++ } ++ + mcr |= MAC_MCR_TX_EN | MAC_MCR_RX_EN | MAC_MCR_FORCE_LINK; + mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id)); + } +@@ -4514,6 +4524,61 @@ static int mtk_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam + return phylink_ethtool_set_pauseparam(mac->phylink, pause); + } + ++static int mtk_get_eee(struct net_device *dev, struct ethtool_keee *eee) ++{ ++ struct mtk_mac *mac = netdev_priv(dev); ++ u32 reg; ++ int ret; ++ ++ ret = phylink_ethtool_get_eee(mac->phylink, eee); ++ if (ret) ++ return ret; ++ ++ reg = mtk_r32(mac->hw, MTK_MAC_EEECR(mac->id)); ++ eee->tx_lpi_enabled = mac->tx_lpi_enabled; ++ eee->tx_lpi_timer = FIELD_GET(MAC_EEE_LPI_TXIDLE_THD, reg) * 1000; ++ ++ return 0; ++} ++ ++static int mtk_set_eee(struct net_device *dev, struct ethtool_keee *eee) ++{ ++ struct mtk_mac *mac = netdev_priv(dev); ++ u32 txidle_thd_ms, reg; ++ int ret; ++ ++ /* Tx idle timer in ms */ ++ txidle_thd_ms = DIV_ROUND_UP(eee->tx_lpi_timer, 1000); ++ if (!FIELD_FIT(MAC_EEE_LPI_TXIDLE_THD, txidle_thd_ms)) ++ return -EINVAL; ++ ++ reg = FIELD_PREP(MAC_EEE_LPI_TXIDLE_THD, txidle_thd_ms); ++ ++ /* PHY Wake-up time, this field does not have a reset value, so use the ++ * reset value from MT7531 (36us for 100BaseT and 17us for 1000BaseT). ++ */ ++ reg |= FIELD_PREP(MAC_EEE_WAKEUP_TIME_1000, 17) | ++ FIELD_PREP(MAC_EEE_WAKEUP_TIME_100, 36); ++ ++ if (!txidle_thd_ms) ++ /* Force LPI Mode without a delay */ ++ reg |= MAC_EEE_LPI_MODE; ++ ++ ret = phylink_ethtool_set_eee(mac->phylink, eee); ++ if (ret) ++ return ret; ++ ++ mac->tx_lpi_enabled = eee->tx_lpi_enabled; ++ mac->txidle_thd_ms = txidle_thd_ms; ++ mtk_w32(mac->hw, reg, MTK_MAC_EEECR(mac->id)); ++ if (eee->eee_enabled && eee->eee_active && eee->tx_lpi_enabled) ++ mtk_m32(mac->hw, 0, MAC_MCR_EEE100M | MAC_MCR_EEE1G, MTK_MAC_MCR(mac->id)); ++ else ++ mtk_m32(mac->hw, MAC_MCR_EEE100M | MAC_MCR_EEE1G, 0, MTK_MAC_MCR(mac->id)); ++ ++ return 0; ++} ++ + static u16 mtk_select_queue(struct net_device *dev, struct sk_buff *skb, + struct net_device *sb_dev) + { +@@ -4546,6 +4611,8 @@ static const struct ethtool_ops mtk_ethtool_ops = { + .set_pauseparam = mtk_set_pauseparam, + .get_rxnfc = mtk_get_rxnfc, + .set_rxnfc = mtk_set_rxnfc, ++ .get_eee = mtk_get_eee, ++ .set_eee = mtk_set_eee, + }; + + static const struct net_device_ops mtk_netdev_ops = { +@@ -4606,6 +4673,8 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) + } + mac = netdev_priv(eth->netdev[id]); + eth->mac[id] = mac; ++ mac->tx_lpi_enabled = true; ++ mac->txidle_thd_ms = 1; + mac->id = id; + mac->hw = eth; + mac->of_node = np; +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +index 0570623e569d..723475570ff7 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -461,6 +461,8 @@ + #define MAC_MCR_RX_FIFO_CLR_DIS BIT(12) + #define MAC_MCR_BACKOFF_EN BIT(9) + #define MAC_MCR_BACKPR_EN BIT(8) ++#define MAC_MCR_EEE1G BIT(7) ++#define MAC_MCR_EEE100M BIT(6) + #define MAC_MCR_FORCE_RX_FC BIT(5) + #define MAC_MCR_FORCE_TX_FC BIT(4) + #define MAC_MCR_SPEED_1000 BIT(3) +@@ -469,6 +471,15 @@ + #define MAC_MCR_FORCE_LINK BIT(0) + #define MAC_MCR_FORCE_LINK_DOWN (MAC_MCR_FORCE_MODE) + ++/* Mac EEE control registers */ ++#define MTK_MAC_EEECR(x) (0x10104 + (x * 0x100)) ++#define MAC_EEE_WAKEUP_TIME_1000 GENMASK(31, 24) ++#define MAC_EEE_WAKEUP_TIME_100 GENMASK(23, 16) ++#define MAC_EEE_LPI_TXIDLE_THD GENMASK(15, 8) ++#define MAC_EEE_CKG_TXIDLE BIT(3) ++#define MAC_EEE_CKG_RXLPI BIT(2) ++#define MAC_EEE_LPI_MODE BIT(0) ++ + /* Mac status registers */ + #define MTK_MAC_MSR(x) (0x10108 + (x * 0x100)) + #define MAC_MSR_EEE1G BIT(7) +@@ -1316,6 +1327,8 @@ struct mtk_mac { + int id; + phy_interface_t interface; + u8 ppe_idx; ++ bool tx_lpi_enabled; ++ u8 txidle_thd_ms; + int speed; + struct device_node *of_node; + struct phylink *phylink; +-- +2.51.0 + + +From 14f7dbcdc4a40f631df9774ef69d7ba583ad830d Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Fri, 4 Oct 2024 17:18:16 +0100 +Subject: [PATCH 085/517] net: phy: aquantia: allow forcing order of MDI pairs + +Despite supporting Auto MDI-X, it looks like Aquantia only supports +swapping pair (1,2) with pair (3,6) like it used to be for MDI-X on +100MBit/s networks. + +When all 4 pairs are in use (for 1000MBit/s or faster) the link does not +come up with pair order is not configured correctly, either using +MDI_CFG pin or using the "PMA Receive Reserved Vendor Provisioning 1" +register. + +Normally, the order of MDI pairs being either ABCD or DCBA is configured +by pulling the MDI_CFG pin. + +However, some hardware designs require overriding the value configured +by that bootstrap pin. The PHY allows doing that by setting a bit in +"PMA Receive Reserved Vendor Provisioning 1" register which allows +ignoring the state of the MDI_CFG pin and another bit configuring +whether the order of MDI pairs should be normal (ABCD) or reverse +(DCBA). Pair polarity is not affected and remains identical in both +settings. + +Introduce property "marvell,mdi-cfg-order" which allows forcing either +normal or reverse order of the MDI pairs from DT. + +If the property isn't present, the behavior is unchanged and MDI pair +order configuration is untouched (ie. either the result of MDI_CFG pin +pull-up/pull-down, or pair order override already configured by the +bootloader before Linux is started). + +Forcing normal pair order is required on the Adtran SDG-8733A Wi-Fi 7 +residential gateway. + +Signed-off-by: Daniel Golle +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/9ed760ff87d5fc456f31e407ead548bbb754497d.1728058550.git.daniel@makrotopia.org +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/aquantia/aquantia_main.c | 33 ++++++++++++++++++++++++ + 1 file changed, 33 insertions(+) + +diff --git a/drivers/net/phy/aquantia/aquantia_main.c b/drivers/net/phy/aquantia/aquantia_main.c +index 840ef5ad07ff..5cdc16fade22 100644 +--- a/drivers/net/phy/aquantia/aquantia_main.c ++++ b/drivers/net/phy/aquantia/aquantia_main.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + #include + + #include "aquantia.h" +@@ -71,6 +72,11 @@ + #define MDIO_AN_TX_VEND_INT_MASK2 0xd401 + #define MDIO_AN_TX_VEND_INT_MASK2_LINK BIT(0) + ++#define PMAPMD_RSVD_VEND_PROV 0xe400 ++#define PMAPMD_RSVD_VEND_PROV_MDI_CONF GENMASK(1, 0) ++#define PMAPMD_RSVD_VEND_PROV_MDI_REVERSE BIT(0) ++#define PMAPMD_RSVD_VEND_PROV_MDI_FORCE BIT(1) ++ + #define MDIO_AN_RX_LP_STAT1 0xe820 + #define MDIO_AN_RX_LP_STAT1_1000BASET_FULL BIT(15) + #define MDIO_AN_RX_LP_STAT1_1000BASET_HALF BIT(14) +@@ -485,6 +491,29 @@ static void aqr107_chip_info(struct phy_device *phydev) + fw_major, fw_minor, build_id, prov_id); + } + ++static int aqr107_config_mdi(struct phy_device *phydev) ++{ ++ struct device_node *np = phydev->mdio.dev.of_node; ++ u32 mdi_conf; ++ int ret; ++ ++ ret = of_property_read_u32(np, "marvell,mdi-cfg-order", &mdi_conf); ++ ++ /* Do nothing in case property "marvell,mdi-cfg-order" is not present */ ++ if (ret == -ENOENT) ++ return 0; ++ ++ if (ret) ++ return ret; ++ ++ if (mdi_conf & ~PMAPMD_RSVD_VEND_PROV_MDI_REVERSE) ++ return -EINVAL; ++ ++ return phy_modify_mmd(phydev, MDIO_MMD_PMAPMD, PMAPMD_RSVD_VEND_PROV, ++ PMAPMD_RSVD_VEND_PROV_MDI_CONF, ++ mdi_conf | PMAPMD_RSVD_VEND_PROV_MDI_FORCE); ++} ++ + static int aqr107_config_init(struct phy_device *phydev) + { + struct aqr107_priv *priv = phydev->priv; +@@ -514,6 +543,10 @@ static int aqr107_config_init(struct phy_device *phydev) + if (ret) + return ret; + ++ ret = aqr107_config_mdi(phydev); ++ if (ret) ++ return ret; ++ + /* Restore LED polarity state after reset */ + for_each_set_bit(led_active_low, &priv->leds_active_low, AQR_MAX_LEDS) { + ret = aqr_phy_led_active_low_set(phydev, led_active_low, true); +-- +2.51.0 + + +From 4894e830a84456398eef38e8084612ae21934af3 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Fri, 11 Oct 2024 22:28:43 +0100 +Subject: [PATCH 086/517] net: phy: aquantia: fix return value check in + aqr107_config_mdi() + +of_property_read_u32() returns -EINVAL in case the property cannot be +found rather than -ENOENT. Fix the check to not abort probing in case +of the property being missing, and also in case CONFIG_OF is not set +which will result in -ENOSYS. + +Fixes: a2e1ba275eae ("net: phy: aquantia: allow forcing order of MDI pairs") +Reported-by: Jon Hunter +Closes: https://lore.kernel.org/all/114b4c03-5d16-42ed-945d-cf78eabea12b@nvidia.com/ +Suggested-by: Hans-Frieder Vogt +Signed-off-by: Daniel Golle +--- + drivers/net/phy/aquantia/aquantia_main.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/phy/aquantia/aquantia_main.c b/drivers/net/phy/aquantia/aquantia_main.c +index 5cdc16fade22..2c9bc3ea6b7e 100644 +--- a/drivers/net/phy/aquantia/aquantia_main.c ++++ b/drivers/net/phy/aquantia/aquantia_main.c +@@ -500,7 +500,7 @@ static int aqr107_config_mdi(struct phy_device *phydev) + ret = of_property_read_u32(np, "marvell,mdi-cfg-order", &mdi_conf); + + /* Do nothing in case property "marvell,mdi-cfg-order" is not present */ +- if (ret == -ENOENT) ++ if (ret == -EINVAL || ret == -ENOSYS) + return 0; + + if (ret) +-- +2.51.0 + + +From 287435caf87bb50f31293db553d5a838b668c98b Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Thu, 10 Oct 2024 13:54:19 +0100 +Subject: [PATCH 087/517] net: phy: support 'active-high' property for PHY LEDs + +In addition to 'active-low' and 'inactive-high-impedance' also +support 'active-high' property for PHY LED pin configuration. +As only either 'active-high' or 'active-low' can be set at the +same time, WARN and return an error in case both are set. + +Signed-off-by: Daniel Golle +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/91598487773d768f254d5faf06cf65b13e972f0e.1728558223.git.daniel@makrotopia.org +Signed-off-by: Paolo Abeni +--- + drivers/net/phy/phy_device.c | 6 ++++++ + include/linux/phy.h | 5 +++-- + 2 files changed, 9 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c +index 834624a61060..762f909242b4 100644 +--- a/drivers/net/phy/phy_device.c ++++ b/drivers/net/phy/phy_device.c +@@ -3387,11 +3387,17 @@ static int of_phy_led(struct phy_device *phydev, + if (index > U8_MAX) + return -EINVAL; + ++ if (of_property_read_bool(led, "active-high")) ++ set_bit(PHY_LED_ACTIVE_HIGH, &modes); + if (of_property_read_bool(led, "active-low")) + set_bit(PHY_LED_ACTIVE_LOW, &modes); + if (of_property_read_bool(led, "inactive-high-impedance")) + set_bit(PHY_LED_INACTIVE_HIGH_IMPEDANCE, &modes); + ++ if (WARN_ON(modes & BIT(PHY_LED_ACTIVE_LOW) && ++ modes & BIT(PHY_LED_ACTIVE_HIGH))) ++ return -EINVAL; ++ + if (modes) { + /* Return error if asked to set polarity modes but not supported */ + if (!phydev->drv->led_polarity_set) +diff --git a/include/linux/phy.h b/include/linux/phy.h +index 81c504d9850e..df147d9d302f 100644 +--- a/include/linux/phy.h ++++ b/include/linux/phy.h +@@ -892,8 +892,9 @@ struct phy_plca_status { + + /* Modes for PHY LED configuration */ + enum phy_led_modes { +- PHY_LED_ACTIVE_LOW = 0, +- PHY_LED_INACTIVE_HIGH_IMPEDANCE = 1, ++ PHY_LED_ACTIVE_HIGH = 0, ++ PHY_LED_ACTIVE_LOW = 1, ++ PHY_LED_INACTIVE_HIGH_IMPEDANCE = 2, + + /* keep it last */ + __PHY_LED_MODES_NUM, +-- +2.51.0 + + +From ade63dd8be886ca940ab87741aa9497e52fec15f Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Thu, 10 Oct 2024 13:55:00 +0100 +Subject: [PATCH 088/517] net: phy: aquantia: correctly describe LED polarity + override + +Use newly defined 'active-high' property to set the +VEND1_GLOBAL_LED_DRIVE_VDD bit and let 'active-low' clear that bit. This +reflects the technical reality which was inverted in the previous +description in which the 'active-low' property was used to actually set +the VEND1_GLOBAL_LED_DRIVE_VDD bit, which means that VDD (ie. supply +voltage) of the LED is driven rather than GND. + +Signed-off-by: Daniel Golle +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/86a413b4387c42dcb54f587cc2433a06f16aae83.1728558223.git.daniel@makrotopia.org +Signed-off-by: Paolo Abeni +--- + drivers/net/phy/aquantia/aquantia.h | 1 + + drivers/net/phy/aquantia/aquantia_leds.c | 19 ++++++++++++++----- + drivers/net/phy/aquantia/aquantia_main.c | 12 +++++++++--- + 3 files changed, 24 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/phy/aquantia/aquantia.h b/drivers/net/phy/aquantia/aquantia.h +index 2465345081f8..0c78bfabace5 100644 +--- a/drivers/net/phy/aquantia/aquantia.h ++++ b/drivers/net/phy/aquantia/aquantia.h +@@ -177,6 +177,7 @@ static const struct aqr107_hw_stat aqr107_hw_stats[] = { + struct aqr107_priv { + u64 sgmii_stats[AQR107_SGMII_STAT_SZ]; + unsigned long leds_active_low; ++ unsigned long leds_active_high; + }; + + #if IS_REACHABLE(CONFIG_HWMON) +diff --git a/drivers/net/phy/aquantia/aquantia_leds.c b/drivers/net/phy/aquantia/aquantia_leds.c +index 201c8df93fad..00ad2313fed3 100644 +--- a/drivers/net/phy/aquantia/aquantia_leds.c ++++ b/drivers/net/phy/aquantia/aquantia_leds.c +@@ -121,13 +121,13 @@ int aqr_phy_led_active_low_set(struct phy_device *phydev, int index, bool enable + { + return phy_modify_mmd(phydev, MDIO_MMD_VEND1, AQR_LED_DRIVE(index), + VEND1_GLOBAL_LED_DRIVE_VDD, +- enable ? VEND1_GLOBAL_LED_DRIVE_VDD : 0); ++ enable ? 0 : VEND1_GLOBAL_LED_DRIVE_VDD); + } + + int aqr_phy_led_polarity_set(struct phy_device *phydev, int index, unsigned long modes) + { ++ bool force_active_low = false, force_active_high = false; + struct aqr107_priv *priv = phydev->priv; +- bool active_low = false; + u32 mode; + + if (index >= AQR_MAX_LEDS) +@@ -136,7 +136,10 @@ int aqr_phy_led_polarity_set(struct phy_device *phydev, int index, unsigned long + for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) { + switch (mode) { + case PHY_LED_ACTIVE_LOW: +- active_low = true; ++ force_active_low = true; ++ break; ++ case PHY_LED_ACTIVE_HIGH: ++ force_active_high = true; + break; + default: + return -EINVAL; +@@ -144,8 +147,14 @@ int aqr_phy_led_polarity_set(struct phy_device *phydev, int index, unsigned long + } + + /* Save LED driver vdd state to restore on SW reset */ +- if (active_low) ++ if (force_active_low) + priv->leds_active_low |= BIT(index); + +- return aqr_phy_led_active_low_set(phydev, index, active_low); ++ if (force_active_high) ++ priv->leds_active_high |= BIT(index); ++ ++ if (force_active_high || force_active_low) ++ return aqr_phy_led_active_low_set(phydev, index, force_active_low); ++ ++ unreachable(); + } +diff --git a/drivers/net/phy/aquantia/aquantia_main.c b/drivers/net/phy/aquantia/aquantia_main.c +index 2c9bc3ea6b7e..2008b98c689e 100644 +--- a/drivers/net/phy/aquantia/aquantia_main.c ++++ b/drivers/net/phy/aquantia/aquantia_main.c +@@ -517,7 +517,7 @@ static int aqr107_config_mdi(struct phy_device *phydev) + static int aqr107_config_init(struct phy_device *phydev) + { + struct aqr107_priv *priv = phydev->priv; +- u32 led_active_low; ++ u32 led_idx; + int ret; + + /* Check that the PHY interface type is compatible */ +@@ -548,8 +548,14 @@ static int aqr107_config_init(struct phy_device *phydev) + return ret; + + /* Restore LED polarity state after reset */ +- for_each_set_bit(led_active_low, &priv->leds_active_low, AQR_MAX_LEDS) { +- ret = aqr_phy_led_active_low_set(phydev, led_active_low, true); ++ for_each_set_bit(led_idx, &priv->leds_active_low, AQR_MAX_LEDS) { ++ ret = aqr_phy_led_active_low_set(phydev, led_idx, true); ++ if (ret) ++ return ret; ++ } ++ ++ for_each_set_bit(led_idx, &priv->leds_active_high, AQR_MAX_LEDS) { ++ ret = aqr_phy_led_active_low_set(phydev, led_idx, false); + if (ret) + return ret; + } +-- +2.51.0 + + +From a42b398e079cfe3f521ca96540d1b2c7f5ce4a57 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Tue, 1 Oct 2024 01:17:18 +0100 +Subject: [PATCH 089/517] net: phy: mxl-gpy: add basic LED support + +Add basic support for LEDs connected to MaxLinear GPY2xx and GPY115 PHYs. +The PHYs allow up to 4 LEDs to be connected. +Implement controlling LEDs in software as well as netdev trigger offloading +and LED polarity setup. + +The hardware claims to support 16 PWM brightness levels but there is no +documentation on how to use that feature, hence this is not supported. + +Signed-off-by: Daniel Golle +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/b6ec9050339f8244ff898898a1cecc33b13a48fc.1727741563.git.daniel@makrotopia.org +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/mxl-gpy.c | 218 ++++++++++++++++++++++++++++++++++++++ + 1 file changed, 218 insertions(+) + +diff --git a/drivers/net/phy/mxl-gpy.c b/drivers/net/phy/mxl-gpy.c +index d145b67a067f..9930e6167f89 100644 +--- a/drivers/net/phy/mxl-gpy.c ++++ b/drivers/net/phy/mxl-gpy.c +@@ -38,6 +38,7 @@ + #define PHY_MIISTAT 0x18 /* MII state */ + #define PHY_IMASK 0x19 /* interrupt mask */ + #define PHY_ISTAT 0x1A /* interrupt status */ ++#define PHY_LED 0x1B /* LEDs */ + #define PHY_FWV 0x1E /* firmware version */ + + #define PHY_MIISTAT_SPD_MASK GENMASK(2, 0) +@@ -61,6 +62,11 @@ + PHY_IMASK_ADSC | \ + PHY_IMASK_ANC) + ++#define GPY_MAX_LEDS 4 ++#define PHY_LED_POLARITY(idx) BIT(12 + (idx)) ++#define PHY_LED_HWCONTROL(idx) BIT(8 + (idx)) ++#define PHY_LED_ON(idx) BIT(idx) ++ + #define PHY_FWV_REL_MASK BIT(15) + #define PHY_FWV_MAJOR_MASK GENMASK(11, 8) + #define PHY_FWV_MINOR_MASK GENMASK(7, 0) +@@ -72,6 +78,23 @@ + #define PHY_MDI_MDI_X_CD 0x1 + #define PHY_MDI_MDI_X_CROSS 0x0 + ++/* LED */ ++#define VSPEC1_LED(idx) (1 + (idx)) ++#define VSPEC1_LED_BLINKS GENMASK(15, 12) ++#define VSPEC1_LED_PULSE GENMASK(11, 8) ++#define VSPEC1_LED_CON GENMASK(7, 4) ++#define VSPEC1_LED_BLINKF GENMASK(3, 0) ++ ++#define VSPEC1_LED_LINK10 BIT(0) ++#define VSPEC1_LED_LINK100 BIT(1) ++#define VSPEC1_LED_LINK1000 BIT(2) ++#define VSPEC1_LED_LINK2500 BIT(3) ++ ++#define VSPEC1_LED_TXACT BIT(0) ++#define VSPEC1_LED_RXACT BIT(1) ++#define VSPEC1_LED_COL BIT(2) ++#define VSPEC1_LED_NO_CON BIT(3) ++ + /* SGMII */ + #define VSPEC1_SGMII_CTRL 0x08 + #define VSPEC1_SGMII_CTRL_ANEN BIT(12) /* Aneg enable */ +@@ -835,6 +858,156 @@ static int gpy115_loopback(struct phy_device *phydev, bool enable) + return genphy_soft_reset(phydev); + } + ++static int gpy_led_brightness_set(struct phy_device *phydev, ++ u8 index, enum led_brightness value) ++{ ++ int ret; ++ ++ if (index >= GPY_MAX_LEDS) ++ return -EINVAL; ++ ++ /* clear HWCONTROL and set manual LED state */ ++ ret = phy_modify(phydev, PHY_LED, ++ ((value == LED_OFF) ? PHY_LED_HWCONTROL(index) : 0) | ++ PHY_LED_ON(index), ++ (value == LED_OFF) ? 0 : PHY_LED_ON(index)); ++ if (ret) ++ return ret; ++ ++ /* ToDo: set PWM brightness */ ++ ++ /* clear HW LED setup */ ++ if (value == LED_OFF) ++ return phy_write_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_LED(index), 0); ++ else ++ return 0; ++} ++ ++static const unsigned long supported_triggers = (BIT(TRIGGER_NETDEV_LINK) | ++ BIT(TRIGGER_NETDEV_LINK_100) | ++ BIT(TRIGGER_NETDEV_LINK_1000) | ++ BIT(TRIGGER_NETDEV_LINK_2500) | ++ BIT(TRIGGER_NETDEV_RX) | ++ BIT(TRIGGER_NETDEV_TX)); ++ ++static int gpy_led_hw_is_supported(struct phy_device *phydev, u8 index, ++ unsigned long rules) ++{ ++ if (index >= GPY_MAX_LEDS) ++ return -EINVAL; ++ ++ /* All combinations of the supported triggers are allowed */ ++ if (rules & ~supported_triggers) ++ return -EOPNOTSUPP; ++ ++ return 0; ++} ++ ++static int gpy_led_hw_control_get(struct phy_device *phydev, u8 index, ++ unsigned long *rules) ++{ ++ int val; ++ ++ if (index >= GPY_MAX_LEDS) ++ return -EINVAL; ++ ++ val = phy_read_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_LED(index)); ++ if (val < 0) ++ return val; ++ ++ if (FIELD_GET(VSPEC1_LED_CON, val) & VSPEC1_LED_LINK10) ++ *rules |= BIT(TRIGGER_NETDEV_LINK_10); ++ ++ if (FIELD_GET(VSPEC1_LED_CON, val) & VSPEC1_LED_LINK100) ++ *rules |= BIT(TRIGGER_NETDEV_LINK_100); ++ ++ if (FIELD_GET(VSPEC1_LED_CON, val) & VSPEC1_LED_LINK1000) ++ *rules |= BIT(TRIGGER_NETDEV_LINK_1000); ++ ++ if (FIELD_GET(VSPEC1_LED_CON, val) & VSPEC1_LED_LINK2500) ++ *rules |= BIT(TRIGGER_NETDEV_LINK_2500); ++ ++ if (FIELD_GET(VSPEC1_LED_CON, val) == (VSPEC1_LED_LINK10 | ++ VSPEC1_LED_LINK100 | ++ VSPEC1_LED_LINK1000 | ++ VSPEC1_LED_LINK2500)) ++ *rules |= BIT(TRIGGER_NETDEV_LINK); ++ ++ if (FIELD_GET(VSPEC1_LED_PULSE, val) & VSPEC1_LED_TXACT) ++ *rules |= BIT(TRIGGER_NETDEV_TX); ++ ++ if (FIELD_GET(VSPEC1_LED_PULSE, val) & VSPEC1_LED_RXACT) ++ *rules |= BIT(TRIGGER_NETDEV_RX); ++ ++ return 0; ++} ++ ++static int gpy_led_hw_control_set(struct phy_device *phydev, u8 index, ++ unsigned long rules) ++{ ++ u16 val = 0; ++ int ret; ++ ++ if (index >= GPY_MAX_LEDS) ++ return -EINVAL; ++ ++ if (rules & BIT(TRIGGER_NETDEV_LINK) || ++ rules & BIT(TRIGGER_NETDEV_LINK_10)) ++ val |= FIELD_PREP(VSPEC1_LED_CON, VSPEC1_LED_LINK10); ++ ++ if (rules & BIT(TRIGGER_NETDEV_LINK) || ++ rules & BIT(TRIGGER_NETDEV_LINK_100)) ++ val |= FIELD_PREP(VSPEC1_LED_CON, VSPEC1_LED_LINK100); ++ ++ if (rules & BIT(TRIGGER_NETDEV_LINK) || ++ rules & BIT(TRIGGER_NETDEV_LINK_1000)) ++ val |= FIELD_PREP(VSPEC1_LED_CON, VSPEC1_LED_LINK1000); ++ ++ if (rules & BIT(TRIGGER_NETDEV_LINK) || ++ rules & BIT(TRIGGER_NETDEV_LINK_2500)) ++ val |= FIELD_PREP(VSPEC1_LED_CON, VSPEC1_LED_LINK2500); ++ ++ if (rules & BIT(TRIGGER_NETDEV_TX)) ++ val |= FIELD_PREP(VSPEC1_LED_PULSE, VSPEC1_LED_TXACT); ++ ++ if (rules & BIT(TRIGGER_NETDEV_RX)) ++ val |= FIELD_PREP(VSPEC1_LED_PULSE, VSPEC1_LED_RXACT); ++ ++ /* allow RX/TX pulse without link indication */ ++ if ((rules & BIT(TRIGGER_NETDEV_TX) || rules & BIT(TRIGGER_NETDEV_RX)) && ++ !(val & VSPEC1_LED_CON)) ++ val |= FIELD_PREP(VSPEC1_LED_PULSE, VSPEC1_LED_NO_CON) | VSPEC1_LED_CON; ++ ++ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_LED(index), val); ++ if (ret) ++ return ret; ++ ++ return phy_set_bits(phydev, PHY_LED, PHY_LED_HWCONTROL(index)); ++} ++ ++static int gpy_led_polarity_set(struct phy_device *phydev, int index, ++ unsigned long modes) ++{ ++ bool active_low = false; ++ u32 mode; ++ ++ if (index >= GPY_MAX_LEDS) ++ return -EINVAL; ++ ++ for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) { ++ switch (mode) { ++ case PHY_LED_ACTIVE_LOW: ++ active_low = true; ++ break; ++ default: ++ return -EINVAL; ++ } ++ } ++ ++ return phy_modify(phydev, PHY_LED, PHY_LED_POLARITY(index), ++ active_low ? 0 : PHY_LED_POLARITY(index)); ++} ++ + static struct phy_driver gpy_drivers[] = { + { + PHY_ID_MATCH_MODEL(PHY_ID_GPY2xx), +@@ -852,6 +1025,11 @@ static struct phy_driver gpy_drivers[] = { + .set_wol = gpy_set_wol, + .get_wol = gpy_get_wol, + .set_loopback = gpy_loopback, ++ .led_brightness_set = gpy_led_brightness_set, ++ .led_hw_is_supported = gpy_led_hw_is_supported, ++ .led_hw_control_get = gpy_led_hw_control_get, ++ .led_hw_control_set = gpy_led_hw_control_set, ++ .led_polarity_set = gpy_led_polarity_set, + }, + { + .phy_id = PHY_ID_GPY115B, +@@ -870,6 +1048,11 @@ static struct phy_driver gpy_drivers[] = { + .set_wol = gpy_set_wol, + .get_wol = gpy_get_wol, + .set_loopback = gpy115_loopback, ++ .led_brightness_set = gpy_led_brightness_set, ++ .led_hw_is_supported = gpy_led_hw_is_supported, ++ .led_hw_control_get = gpy_led_hw_control_get, ++ .led_hw_control_set = gpy_led_hw_control_set, ++ .led_polarity_set = gpy_led_polarity_set, + }, + { + PHY_ID_MATCH_MODEL(PHY_ID_GPY115C), +@@ -887,6 +1070,11 @@ static struct phy_driver gpy_drivers[] = { + .set_wol = gpy_set_wol, + .get_wol = gpy_get_wol, + .set_loopback = gpy115_loopback, ++ .led_brightness_set = gpy_led_brightness_set, ++ .led_hw_is_supported = gpy_led_hw_is_supported, ++ .led_hw_control_get = gpy_led_hw_control_get, ++ .led_hw_control_set = gpy_led_hw_control_set, ++ .led_polarity_set = gpy_led_polarity_set, + }, + { + .phy_id = PHY_ID_GPY211B, +@@ -905,6 +1093,11 @@ static struct phy_driver gpy_drivers[] = { + .set_wol = gpy_set_wol, + .get_wol = gpy_get_wol, + .set_loopback = gpy_loopback, ++ .led_brightness_set = gpy_led_brightness_set, ++ .led_hw_is_supported = gpy_led_hw_is_supported, ++ .led_hw_control_get = gpy_led_hw_control_get, ++ .led_hw_control_set = gpy_led_hw_control_set, ++ .led_polarity_set = gpy_led_polarity_set, + }, + { + PHY_ID_MATCH_MODEL(PHY_ID_GPY211C), +@@ -922,6 +1115,11 @@ static struct phy_driver gpy_drivers[] = { + .set_wol = gpy_set_wol, + .get_wol = gpy_get_wol, + .set_loopback = gpy_loopback, ++ .led_brightness_set = gpy_led_brightness_set, ++ .led_hw_is_supported = gpy_led_hw_is_supported, ++ .led_hw_control_get = gpy_led_hw_control_get, ++ .led_hw_control_set = gpy_led_hw_control_set, ++ .led_polarity_set = gpy_led_polarity_set, + }, + { + .phy_id = PHY_ID_GPY212B, +@@ -940,6 +1138,11 @@ static struct phy_driver gpy_drivers[] = { + .set_wol = gpy_set_wol, + .get_wol = gpy_get_wol, + .set_loopback = gpy_loopback, ++ .led_brightness_set = gpy_led_brightness_set, ++ .led_hw_is_supported = gpy_led_hw_is_supported, ++ .led_hw_control_get = gpy_led_hw_control_get, ++ .led_hw_control_set = gpy_led_hw_control_set, ++ .led_polarity_set = gpy_led_polarity_set, + }, + { + PHY_ID_MATCH_MODEL(PHY_ID_GPY212C), +@@ -957,6 +1160,11 @@ static struct phy_driver gpy_drivers[] = { + .set_wol = gpy_set_wol, + .get_wol = gpy_get_wol, + .set_loopback = gpy_loopback, ++ .led_brightness_set = gpy_led_brightness_set, ++ .led_hw_is_supported = gpy_led_hw_is_supported, ++ .led_hw_control_get = gpy_led_hw_control_get, ++ .led_hw_control_set = gpy_led_hw_control_set, ++ .led_polarity_set = gpy_led_polarity_set, + }, + { + .phy_id = PHY_ID_GPY215B, +@@ -975,6 +1183,11 @@ static struct phy_driver gpy_drivers[] = { + .set_wol = gpy_set_wol, + .get_wol = gpy_get_wol, + .set_loopback = gpy_loopback, ++ .led_brightness_set = gpy_led_brightness_set, ++ .led_hw_is_supported = gpy_led_hw_is_supported, ++ .led_hw_control_get = gpy_led_hw_control_get, ++ .led_hw_control_set = gpy_led_hw_control_set, ++ .led_polarity_set = gpy_led_polarity_set, + }, + { + PHY_ID_MATCH_MODEL(PHY_ID_GPY215C), +@@ -992,6 +1205,11 @@ static struct phy_driver gpy_drivers[] = { + .set_wol = gpy_set_wol, + .get_wol = gpy_get_wol, + .set_loopback = gpy_loopback, ++ .led_brightness_set = gpy_led_brightness_set, ++ .led_hw_is_supported = gpy_led_hw_is_supported, ++ .led_hw_control_get = gpy_led_hw_control_get, ++ .led_hw_control_set = gpy_led_hw_control_set, ++ .led_polarity_set = gpy_led_polarity_set, + }, + { + PHY_ID_MATCH_MODEL(PHY_ID_GPY241B), +-- +2.51.0 + + +From 4f581169cc4a1bc0610a94c19e7a7e7dcee4bc42 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Fri, 4 Oct 2024 16:56:35 +0100 +Subject: [PATCH 090/517] net: phy: mxl-gpy: add missing support for + TRIGGER_NETDEV_LINK_10 + +The PHY also support 10MBit/s links as well as the corresponding link +indication trigger to be offloaded. Add TRIGGER_NETDEV_LINK_10 to the +supported triggers. + +Signed-off-by: Daniel Golle +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/cc5da0a989af8b0d49d823656d88053c4de2ab98.1728057367.git.daniel@makrotopia.org +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/mxl-gpy.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/phy/mxl-gpy.c b/drivers/net/phy/mxl-gpy.c +index 9930e6167f89..9864b9d2944f 100644 +--- a/drivers/net/phy/mxl-gpy.c ++++ b/drivers/net/phy/mxl-gpy.c +@@ -884,6 +884,7 @@ static int gpy_led_brightness_set(struct phy_device *phydev, + } + + static const unsigned long supported_triggers = (BIT(TRIGGER_NETDEV_LINK) | ++ BIT(TRIGGER_NETDEV_LINK_10) | + BIT(TRIGGER_NETDEV_LINK_100) | + BIT(TRIGGER_NETDEV_LINK_1000) | + BIT(TRIGGER_NETDEV_LINK_2500) | +-- +2.51.0 + + +From af00b072a7746a00880530c75cd1b9d35e1427e8 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Thu, 10 Oct 2024 13:55:17 +0100 +Subject: [PATCH 091/517] net: phy: mxl-gpy: correctly describe LED polarity + +According the datasheet covering the LED (0x1b) register: +0B Active High LEDx pin driven high when activated +1B Active Low LEDx pin driven low when activated + +Make use of the now available 'active-high' property and correctly +reflect the polarity setting which was previously inverted. + +Signed-off-by: Daniel Golle +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/180ccafa837f09908b852a8a874a3808c5ecd2d0.1728558223.git.daniel@makrotopia.org +Signed-off-by: Paolo Abeni +--- + drivers/net/phy/mxl-gpy.c | 16 ++++++++++++---- + 1 file changed, 12 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/phy/mxl-gpy.c b/drivers/net/phy/mxl-gpy.c +index 9864b9d2944f..e0bdbb66df5c 100644 +--- a/drivers/net/phy/mxl-gpy.c ++++ b/drivers/net/phy/mxl-gpy.c +@@ -989,7 +989,7 @@ static int gpy_led_hw_control_set(struct phy_device *phydev, u8 index, + static int gpy_led_polarity_set(struct phy_device *phydev, int index, + unsigned long modes) + { +- bool active_low = false; ++ bool force_active_low = false, force_active_high = false; + u32 mode; + + if (index >= GPY_MAX_LEDS) +@@ -998,15 +998,23 @@ static int gpy_led_polarity_set(struct phy_device *phydev, int index, + for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) { + switch (mode) { + case PHY_LED_ACTIVE_LOW: +- active_low = true; ++ force_active_low = true; ++ break; ++ case PHY_LED_ACTIVE_HIGH: ++ force_active_high = true; + break; + default: + return -EINVAL; + } + } + +- return phy_modify(phydev, PHY_LED, PHY_LED_POLARITY(index), +- active_low ? 0 : PHY_LED_POLARITY(index)); ++ if (force_active_low) ++ return phy_set_bits(phydev, PHY_LED, PHY_LED_POLARITY(index)); ++ ++ if (force_active_high) ++ return phy_clear_bits(phydev, PHY_LED, PHY_LED_POLARITY(index)); ++ ++ unreachable(); + } + + static struct phy_driver gpy_drivers[] = { +-- +2.51.0 + + +From 7ca1cf2b83a6acbdebc09b38921704e387945d88 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Thu, 10 Oct 2024 13:55:29 +0100 +Subject: [PATCH 092/517] net: phy: intel-xway: add support for PHY LEDs + +The intel-xway PHY driver predates the PHY LED framework and currently +initializes all LED pins to equal default values. + +Add PHY LED functions to the drivers and don't set default values if +LEDs are defined in device tree. + +According the datasheets 3 LEDs are supported on all Intel XWAY PHYs. + +Signed-off-by: Daniel Golle +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/81f4717ab9acf38f3239727a4540ae96fd01109b.1728558223.git.daniel@makrotopia.org +Signed-off-by: Paolo Abeni +--- + drivers/net/phy/intel-xway.c | 253 +++++++++++++++++++++++++++++++++-- + 1 file changed, 244 insertions(+), 9 deletions(-) + +diff --git a/drivers/net/phy/intel-xway.c b/drivers/net/phy/intel-xway.c +index fad411b93c15..62ab1fbef16c 100644 +--- a/drivers/net/phy/intel-xway.c ++++ b/drivers/net/phy/intel-xway.c +@@ -151,6 +151,13 @@ + #define XWAY_MMD_LED3H 0x01E8 + #define XWAY_MMD_LED3L 0x01E9 + ++#define XWAY_GPHY_MAX_LEDS 3 ++#define XWAY_GPHY_LED_INV(idx) BIT(12 + (idx)) ++#define XWAY_GPHY_LED_EN(idx) BIT(8 + (idx)) ++#define XWAY_GPHY_LED_DA(idx) BIT(idx) ++#define XWAY_MMD_LEDxH(idx) (XWAY_MMD_LED0H + 2 * (idx)) ++#define XWAY_MMD_LEDxL(idx) (XWAY_MMD_LED0L + 2 * (idx)) ++ + #define PHY_ID_PHY11G_1_3 0x030260D1 + #define PHY_ID_PHY22F_1_3 0x030260E1 + #define PHY_ID_PHY11G_1_4 0xD565A400 +@@ -229,20 +236,12 @@ static int xway_gphy_rgmii_init(struct phy_device *phydev) + XWAY_MDIO_MIICTRL_TXSKEW_MASK, val); + } + +-static int xway_gphy_config_init(struct phy_device *phydev) ++static int xway_gphy_init_leds(struct phy_device *phydev) + { + int err; + u32 ledxh; + u32 ledxl; + +- /* Mask all interrupts */ +- err = phy_write(phydev, XWAY_MDIO_IMASK, 0); +- if (err) +- return err; +- +- /* Clear all pending interrupts */ +- phy_read(phydev, XWAY_MDIO_ISTAT); +- + /* Ensure that integrated led function is enabled for all leds */ + err = phy_write(phydev, XWAY_MDIO_LED, + XWAY_MDIO_LED_LED0_EN | +@@ -276,6 +275,26 @@ static int xway_gphy_config_init(struct phy_device *phydev) + phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LED2H, ledxh); + phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LED2L, ledxl); + ++ return 0; ++} ++ ++static int xway_gphy_config_init(struct phy_device *phydev) ++{ ++ struct device_node *np = phydev->mdio.dev.of_node; ++ int err; ++ ++ /* Mask all interrupts */ ++ err = phy_write(phydev, XWAY_MDIO_IMASK, 0); ++ if (err) ++ return err; ++ ++ /* Use default LED configuration if 'leds' node isn't defined */ ++ if (!of_get_child_by_name(np, "leds")) ++ xway_gphy_init_leds(phydev); ++ ++ /* Clear all pending interrupts */ ++ phy_read(phydev, XWAY_MDIO_ISTAT); ++ + err = xway_gphy_rgmii_init(phydev); + if (err) + return err; +@@ -347,6 +366,172 @@ static irqreturn_t xway_gphy_handle_interrupt(struct phy_device *phydev) + return IRQ_HANDLED; + } + ++static int xway_gphy_led_brightness_set(struct phy_device *phydev, ++ u8 index, enum led_brightness value) ++{ ++ int ret; ++ ++ if (index >= XWAY_GPHY_MAX_LEDS) ++ return -EINVAL; ++ ++ /* clear EN and set manual LED state */ ++ ret = phy_modify(phydev, XWAY_MDIO_LED, ++ ((value == LED_OFF) ? XWAY_GPHY_LED_EN(index) : 0) | ++ XWAY_GPHY_LED_DA(index), ++ (value == LED_OFF) ? 0 : XWAY_GPHY_LED_DA(index)); ++ if (ret) ++ return ret; ++ ++ /* clear HW LED setup */ ++ if (value == LED_OFF) { ++ ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxH(index), 0); ++ if (ret) ++ return ret; ++ ++ return phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxL(index), 0); ++ } else { ++ return 0; ++ } ++} ++ ++static const unsigned long supported_triggers = (BIT(TRIGGER_NETDEV_LINK) | ++ BIT(TRIGGER_NETDEV_LINK_10) | ++ BIT(TRIGGER_NETDEV_LINK_100) | ++ BIT(TRIGGER_NETDEV_LINK_1000) | ++ BIT(TRIGGER_NETDEV_RX) | ++ BIT(TRIGGER_NETDEV_TX)); ++ ++static int xway_gphy_led_hw_is_supported(struct phy_device *phydev, u8 index, ++ unsigned long rules) ++{ ++ if (index >= XWAY_GPHY_MAX_LEDS) ++ return -EINVAL; ++ ++ /* activity triggers are not possible without combination with a link ++ * trigger. ++ */ ++ if (rules & (BIT(TRIGGER_NETDEV_RX) | BIT(TRIGGER_NETDEV_TX)) && ++ !(rules & (BIT(TRIGGER_NETDEV_LINK) | ++ BIT(TRIGGER_NETDEV_LINK_10) | ++ BIT(TRIGGER_NETDEV_LINK_100) | ++ BIT(TRIGGER_NETDEV_LINK_1000)))) ++ return -EOPNOTSUPP; ++ ++ /* All other combinations of the supported triggers are allowed */ ++ if (rules & ~supported_triggers) ++ return -EOPNOTSUPP; ++ ++ return 0; ++} ++ ++static int xway_gphy_led_hw_control_get(struct phy_device *phydev, u8 index, ++ unsigned long *rules) ++{ ++ int lval, hval; ++ ++ if (index >= XWAY_GPHY_MAX_LEDS) ++ return -EINVAL; ++ ++ hval = phy_read_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxH(index)); ++ if (hval < 0) ++ return hval; ++ ++ lval = phy_read_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxL(index)); ++ if (lval < 0) ++ return lval; ++ ++ if (hval & XWAY_MMD_LEDxH_CON_LINK10) ++ *rules |= BIT(TRIGGER_NETDEV_LINK_10); ++ ++ if (hval & XWAY_MMD_LEDxH_CON_LINK100) ++ *rules |= BIT(TRIGGER_NETDEV_LINK_100); ++ ++ if (hval & XWAY_MMD_LEDxH_CON_LINK1000) ++ *rules |= BIT(TRIGGER_NETDEV_LINK_1000); ++ ++ if ((hval & XWAY_MMD_LEDxH_CON_LINK10) && ++ (hval & XWAY_MMD_LEDxH_CON_LINK100) && ++ (hval & XWAY_MMD_LEDxH_CON_LINK1000)) ++ *rules |= BIT(TRIGGER_NETDEV_LINK); ++ ++ if (lval & XWAY_MMD_LEDxL_PULSE_TXACT) ++ *rules |= BIT(TRIGGER_NETDEV_TX); ++ ++ if (lval & XWAY_MMD_LEDxL_PULSE_RXACT) ++ *rules |= BIT(TRIGGER_NETDEV_RX); ++ ++ return 0; ++} ++ ++static int xway_gphy_led_hw_control_set(struct phy_device *phydev, u8 index, ++ unsigned long rules) ++{ ++ u16 hval = 0, lval = 0; ++ int ret; ++ ++ if (index >= XWAY_GPHY_MAX_LEDS) ++ return -EINVAL; ++ ++ if (rules & BIT(TRIGGER_NETDEV_LINK) || ++ rules & BIT(TRIGGER_NETDEV_LINK_10)) ++ hval |= XWAY_MMD_LEDxH_CON_LINK10; ++ ++ if (rules & BIT(TRIGGER_NETDEV_LINK) || ++ rules & BIT(TRIGGER_NETDEV_LINK_100)) ++ hval |= XWAY_MMD_LEDxH_CON_LINK100; ++ ++ if (rules & BIT(TRIGGER_NETDEV_LINK) || ++ rules & BIT(TRIGGER_NETDEV_LINK_1000)) ++ hval |= XWAY_MMD_LEDxH_CON_LINK1000; ++ ++ if (rules & BIT(TRIGGER_NETDEV_TX)) ++ lval |= XWAY_MMD_LEDxL_PULSE_TXACT; ++ ++ if (rules & BIT(TRIGGER_NETDEV_RX)) ++ lval |= XWAY_MMD_LEDxL_PULSE_RXACT; ++ ++ ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxH(index), hval); ++ if (ret) ++ return ret; ++ ++ ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxL(index), lval); ++ if (ret) ++ return ret; ++ ++ return phy_set_bits(phydev, XWAY_MDIO_LED, XWAY_GPHY_LED_EN(index)); ++} ++ ++static int xway_gphy_led_polarity_set(struct phy_device *phydev, int index, ++ unsigned long modes) ++{ ++ bool force_active_low = false, force_active_high = false; ++ u32 mode; ++ ++ if (index >= XWAY_GPHY_MAX_LEDS) ++ return -EINVAL; ++ ++ for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) { ++ switch (mode) { ++ case PHY_LED_ACTIVE_LOW: ++ force_active_low = true; ++ break; ++ case PHY_LED_ACTIVE_HIGH: ++ force_active_high = true; ++ break; ++ default: ++ return -EINVAL; ++ } ++ } ++ ++ if (force_active_low) ++ return phy_set_bits(phydev, XWAY_MDIO_LED, XWAY_GPHY_LED_INV(index)); ++ ++ if (force_active_high) ++ return phy_clear_bits(phydev, XWAY_MDIO_LED, XWAY_GPHY_LED_INV(index)); ++ ++ unreachable(); ++} ++ + static struct phy_driver xway_gphy[] = { + { + .phy_id = PHY_ID_PHY11G_1_3, +@@ -359,6 +544,11 @@ static struct phy_driver xway_gphy[] = { + .config_intr = xway_gphy_config_intr, + .suspend = genphy_suspend, + .resume = genphy_resume, ++ .led_brightness_set = xway_gphy_led_brightness_set, ++ .led_hw_is_supported = xway_gphy_led_hw_is_supported, ++ .led_hw_control_get = xway_gphy_led_hw_control_get, ++ .led_hw_control_set = xway_gphy_led_hw_control_set, ++ .led_polarity_set = xway_gphy_led_polarity_set, + }, { + .phy_id = PHY_ID_PHY22F_1_3, + .phy_id_mask = 0xffffffff, +@@ -370,6 +560,11 @@ static struct phy_driver xway_gphy[] = { + .config_intr = xway_gphy_config_intr, + .suspend = genphy_suspend, + .resume = genphy_resume, ++ .led_brightness_set = xway_gphy_led_brightness_set, ++ .led_hw_is_supported = xway_gphy_led_hw_is_supported, ++ .led_hw_control_get = xway_gphy_led_hw_control_get, ++ .led_hw_control_set = xway_gphy_led_hw_control_set, ++ .led_polarity_set = xway_gphy_led_polarity_set, + }, { + .phy_id = PHY_ID_PHY11G_1_4, + .phy_id_mask = 0xffffffff, +@@ -381,6 +576,11 @@ static struct phy_driver xway_gphy[] = { + .config_intr = xway_gphy_config_intr, + .suspend = genphy_suspend, + .resume = genphy_resume, ++ .led_brightness_set = xway_gphy_led_brightness_set, ++ .led_hw_is_supported = xway_gphy_led_hw_is_supported, ++ .led_hw_control_get = xway_gphy_led_hw_control_get, ++ .led_hw_control_set = xway_gphy_led_hw_control_set, ++ .led_polarity_set = xway_gphy_led_polarity_set, + }, { + .phy_id = PHY_ID_PHY22F_1_4, + .phy_id_mask = 0xffffffff, +@@ -392,6 +592,11 @@ static struct phy_driver xway_gphy[] = { + .config_intr = xway_gphy_config_intr, + .suspend = genphy_suspend, + .resume = genphy_resume, ++ .led_brightness_set = xway_gphy_led_brightness_set, ++ .led_hw_is_supported = xway_gphy_led_hw_is_supported, ++ .led_hw_control_get = xway_gphy_led_hw_control_get, ++ .led_hw_control_set = xway_gphy_led_hw_control_set, ++ .led_polarity_set = xway_gphy_led_polarity_set, + }, { + .phy_id = PHY_ID_PHY11G_1_5, + .phy_id_mask = 0xffffffff, +@@ -402,6 +607,11 @@ static struct phy_driver xway_gphy[] = { + .config_intr = xway_gphy_config_intr, + .suspend = genphy_suspend, + .resume = genphy_resume, ++ .led_brightness_set = xway_gphy_led_brightness_set, ++ .led_hw_is_supported = xway_gphy_led_hw_is_supported, ++ .led_hw_control_get = xway_gphy_led_hw_control_get, ++ .led_hw_control_set = xway_gphy_led_hw_control_set, ++ .led_polarity_set = xway_gphy_led_polarity_set, + }, { + .phy_id = PHY_ID_PHY22F_1_5, + .phy_id_mask = 0xffffffff, +@@ -412,6 +622,11 @@ static struct phy_driver xway_gphy[] = { + .config_intr = xway_gphy_config_intr, + .suspend = genphy_suspend, + .resume = genphy_resume, ++ .led_brightness_set = xway_gphy_led_brightness_set, ++ .led_hw_is_supported = xway_gphy_led_hw_is_supported, ++ .led_hw_control_get = xway_gphy_led_hw_control_get, ++ .led_hw_control_set = xway_gphy_led_hw_control_set, ++ .led_polarity_set = xway_gphy_led_polarity_set, + }, { + .phy_id = PHY_ID_PHY11G_VR9_1_1, + .phy_id_mask = 0xffffffff, +@@ -422,6 +637,11 @@ static struct phy_driver xway_gphy[] = { + .config_intr = xway_gphy_config_intr, + .suspend = genphy_suspend, + .resume = genphy_resume, ++ .led_brightness_set = xway_gphy_led_brightness_set, ++ .led_hw_is_supported = xway_gphy_led_hw_is_supported, ++ .led_hw_control_get = xway_gphy_led_hw_control_get, ++ .led_hw_control_set = xway_gphy_led_hw_control_set, ++ .led_polarity_set = xway_gphy_led_polarity_set, + }, { + .phy_id = PHY_ID_PHY22F_VR9_1_1, + .phy_id_mask = 0xffffffff, +@@ -432,6 +652,11 @@ static struct phy_driver xway_gphy[] = { + .config_intr = xway_gphy_config_intr, + .suspend = genphy_suspend, + .resume = genphy_resume, ++ .led_brightness_set = xway_gphy_led_brightness_set, ++ .led_hw_is_supported = xway_gphy_led_hw_is_supported, ++ .led_hw_control_get = xway_gphy_led_hw_control_get, ++ .led_hw_control_set = xway_gphy_led_hw_control_set, ++ .led_polarity_set = xway_gphy_led_polarity_set, + }, { + .phy_id = PHY_ID_PHY11G_VR9_1_2, + .phy_id_mask = 0xffffffff, +@@ -442,6 +667,11 @@ static struct phy_driver xway_gphy[] = { + .config_intr = xway_gphy_config_intr, + .suspend = genphy_suspend, + .resume = genphy_resume, ++ .led_brightness_set = xway_gphy_led_brightness_set, ++ .led_hw_is_supported = xway_gphy_led_hw_is_supported, ++ .led_hw_control_get = xway_gphy_led_hw_control_get, ++ .led_hw_control_set = xway_gphy_led_hw_control_set, ++ .led_polarity_set = xway_gphy_led_polarity_set, + }, { + .phy_id = PHY_ID_PHY22F_VR9_1_2, + .phy_id_mask = 0xffffffff, +@@ -452,6 +682,11 @@ static struct phy_driver xway_gphy[] = { + .config_intr = xway_gphy_config_intr, + .suspend = genphy_suspend, + .resume = genphy_resume, ++ .led_brightness_set = xway_gphy_led_brightness_set, ++ .led_hw_is_supported = xway_gphy_led_hw_is_supported, ++ .led_hw_control_get = xway_gphy_led_hw_control_get, ++ .led_hw_control_set = xway_gphy_led_hw_control_set, ++ .led_polarity_set = xway_gphy_led_polarity_set, + }, + }; + module_phy_driver(xway_gphy); +-- +2.51.0 + + +From 1bb33829d7d380fe3083f49d28968e268c6faf00 Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Tue, 12 Aug 2025 06:57:23 +0200 +Subject: [PATCH 093/517] net: mediatek: wed: Introduce MT7992 WED support to + MT7988 SoC + +Introduce the second WDMA RX ring in WED driver for MT7988 SoC since the +Mediatek MT7992 WiFi chipset supports two separated WDMA rings. +Add missing MT7988 configurations to properly support WED for MT7992 in +MT76 driver. + +Co-developed-by: Rex Lu +Signed-off-by: Rex Lu +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20250812-mt7992-wed-support-v3-1-9ada78a819a4@kernel.org +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/mediatek/mtk_wed.c | 33 ++++++++++++++++++++----- + drivers/net/ethernet/mediatek/mtk_wed.h | 2 +- + include/linux/soc/mediatek/mtk_wed.h | 2 +- + 3 files changed, 29 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/ethernet/mediatek/mtk_wed.c b/drivers/net/ethernet/mediatek/mtk_wed.c +index 499ca7000125..e7021d0622b0 100644 +--- a/drivers/net/ethernet/mediatek/mtk_wed.c ++++ b/drivers/net/ethernet/mediatek/mtk_wed.c +@@ -59,7 +59,9 @@ struct mtk_wed_flow_block_priv { + static const struct mtk_wed_soc_data mt7622_data = { + .regmap = { + .tx_bm_tkid = 0x088, +- .wpdma_rx_ring0 = 0x770, ++ .wpdma_rx_ring = { ++ 0x770, ++ }, + .reset_idx_tx_mask = GENMASK(3, 0), + .reset_idx_rx_mask = GENMASK(17, 16), + }, +@@ -70,7 +72,9 @@ static const struct mtk_wed_soc_data mt7622_data = { + static const struct mtk_wed_soc_data mt7986_data = { + .regmap = { + .tx_bm_tkid = 0x0c8, +- .wpdma_rx_ring0 = 0x770, ++ .wpdma_rx_ring = { ++ 0x770, ++ }, + .reset_idx_tx_mask = GENMASK(1, 0), + .reset_idx_rx_mask = GENMASK(7, 6), + }, +@@ -81,7 +85,10 @@ static const struct mtk_wed_soc_data mt7986_data = { + static const struct mtk_wed_soc_data mt7988_data = { + .regmap = { + .tx_bm_tkid = 0x0c8, +- .wpdma_rx_ring0 = 0x7d0, ++ .wpdma_rx_ring = { ++ 0x7d0, ++ 0x7d8, ++ }, + .reset_idx_tx_mask = GENMASK(1, 0), + .reset_idx_rx_mask = GENMASK(7, 6), + }, +@@ -621,8 +628,8 @@ mtk_wed_amsdu_init(struct mtk_wed_device *dev) + return ret; + } + +- /* eagle E1 PCIE1 tx ring 22 flow control issue */ +- if (dev->wlan.id == 0x7991) ++ /* Kite and Eagle E1 PCIE1 tx ring 22 flow control issue */ ++ if (dev->wlan.id == 0x7991 || dev->wlan.id == 0x7992) + wed_clr(dev, MTK_WED_AMSDU_FIFO, MTK_WED_AMSDU_IS_PRIOR0_RING); + + wed_set(dev, MTK_WED_CTRL, MTK_WED_CTRL_TX_AMSDU_EN); +@@ -1239,7 +1246,11 @@ mtk_wed_set_wpdma(struct mtk_wed_device *dev) + return; + + wed_w32(dev, MTK_WED_WPDMA_RX_GLO_CFG, dev->wlan.wpdma_rx_glo); +- wed_w32(dev, dev->hw->soc->regmap.wpdma_rx_ring0, dev->wlan.wpdma_rx); ++ wed_w32(dev, dev->hw->soc->regmap.wpdma_rx_ring[0], ++ dev->wlan.wpdma_rx[0]); ++ if (mtk_wed_is_v3_or_greater(dev->hw)) ++ wed_w32(dev, dev->hw->soc->regmap.wpdma_rx_ring[1], ++ dev->wlan.wpdma_rx[1]); + + if (!dev->wlan.hw_rro) + return; +@@ -2335,6 +2346,16 @@ mtk_wed_start(struct mtk_wed_device *dev, u32 irq_mask) + if (!dev->rx_wdma[i].desc) + mtk_wed_wdma_rx_ring_setup(dev, i, 16, false); + ++ if (dev->wlan.hw_rro) { ++ for (i = 0; i < MTK_WED_RX_PAGE_QUEUES; i++) { ++ u32 addr = MTK_WED_RRO_MSDU_PG_CTRL0(i) + ++ MTK_WED_RING_OFS_COUNT; ++ ++ if (!wed_r32(dev, addr)) ++ wed_w32(dev, addr, 1); ++ } ++ } ++ + mtk_wed_hw_init(dev); + mtk_wed_configure_irq(dev, irq_mask); + +diff --git a/drivers/net/ethernet/mediatek/mtk_wed.h b/drivers/net/ethernet/mediatek/mtk_wed.h +index c1f0479d7a71..b49aee9a8b65 100644 +--- a/drivers/net/ethernet/mediatek/mtk_wed.h ++++ b/drivers/net/ethernet/mediatek/mtk_wed.h +@@ -17,7 +17,7 @@ struct mtk_wed_wo; + struct mtk_wed_soc_data { + struct { + u32 tx_bm_tkid; +- u32 wpdma_rx_ring0; ++ u32 wpdma_rx_ring[MTK_WED_RX_QUEUES]; + u32 reset_idx_tx_mask; + u32 reset_idx_rx_mask; + } regmap; +diff --git a/include/linux/soc/mediatek/mtk_wed.h b/include/linux/soc/mediatek/mtk_wed.h +index a476648858a6..5ab3a93a7be9 100644 +--- a/include/linux/soc/mediatek/mtk_wed.h ++++ b/include/linux/soc/mediatek/mtk_wed.h +@@ -147,7 +147,7 @@ struct mtk_wed_device { + u32 wpdma_tx; + u32 wpdma_txfree; + u32 wpdma_rx_glo; +- u32 wpdma_rx; ++ u32 wpdma_rx[MTK_WED_RX_QUEUES]; + u32 wpdma_rx_rro[MTK_WED_RX_QUEUES]; + u32 wpdma_rx_pg; + +-- +2.51.0 + + +From 528e2e4d166e49dadcb780d5a37cda03bbe9e399 Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Wed, 8 Oct 2025 12:41:48 +0200 +Subject: [PATCH 094/517] wifi: mt76: wed: use proper wed reference in mt76 wed + driver callabacks + +MT7996 driver can use both wed and wed_hif2 devices to offload traffic +from/to the wireless NIC. In the current codebase we assume to always +use the primary wed device in wed callbacks resulting in the following +crash if the hw runs wed_hif2 (e.g. 6GHz link). + +[ 297.455876] Unable to handle kernel read from unreadable memory at virtual address 000000000000080a +[ 297.464928] Mem abort info: +[ 297.467722] ESR = 0x0000000096000005 +[ 297.471461] EC = 0x25: DABT (current EL), IL = 32 bits +[ 297.476766] SET = 0, FnV = 0 +[ 297.479809] EA = 0, S1PTW = 0 +[ 297.482940] FSC = 0x05: level 1 translation fault +[ 297.487809] Data abort info: +[ 297.490679] ISV = 0, ISS = 0x00000005, ISS2 = 0x00000000 +[ 297.496156] CM = 0, WnR = 0, TnD = 0, TagAccess = 0 +[ 297.501196] GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0 +[ 297.506500] user pgtable: 4k pages, 39-bit VAs, pgdp=0000000107480000 +[ 297.512927] [000000000000080a] pgd=08000001097fb003, p4d=08000001097fb003, pud=08000001097fb003, pmd=0000000000000000 +[ 297.523532] Internal error: Oops: 0000000096000005 [#1] SMP +[ 297.715393] CPU: 2 UID: 0 PID: 45 Comm: kworker/u16:2 Tainted: G O 6.12.50 #0 +[ 297.723908] Tainted: [O]=OOT_MODULE +[ 297.727384] Hardware name: Banana Pi BPI-R4 (2x SFP+) (DT) +[ 297.732857] Workqueue: nf_ft_offload_del nf_flow_rule_route_ipv6 [nf_flow_table] +[ 297.740254] pstate: 60400005 (nZCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--) +[ 297.747205] pc : mt76_wed_offload_disable+0x64/0xa0 [mt76] +[ 297.752688] lr : mtk_wed_flow_remove+0x58/0x80 +[ 297.757126] sp : ffffffc080fe3ae0 +[ 297.760430] x29: ffffffc080fe3ae0 x28: ffffffc080fe3be0 x27: 00000000deadbef7 +[ 297.767557] x26: ffffff80c5ebca00 x25: 0000000000000001 x24: ffffff80c85f4c00 +[ 297.774683] x23: ffffff80c1875b78 x22: ffffffc080d42cd0 x21: ffffffc080660018 +[ 297.781809] x20: ffffff80c6a076d0 x19: ffffff80c6a043c8 x18: 0000000000000000 +[ 297.788935] x17: 0000000000000000 x16: 0000000000000001 x15: 0000000000000000 +[ 297.796060] x14: 0000000000000019 x13: ffffff80c0ad8ec0 x12: 00000000fa83b2da +[ 297.803185] x11: ffffff80c02700c0 x10: ffffff80c0ad8ec0 x9 : ffffff81fef96200 +[ 297.810311] x8 : ffffff80c02700c0 x7 : ffffff80c02700d0 x6 : 0000000000000002 +[ 297.817435] x5 : 0000000000000400 x4 : 0000000000000000 x3 : 0000000000000000 +[ 297.824561] x2 : 0000000000000001 x1 : 0000000000000800 x0 : ffffff80c6a063c8 +[ 297.831686] Call trace: +[ 297.834123] mt76_wed_offload_disable+0x64/0xa0 [mt76] +[ 297.839254] mtk_wed_flow_remove+0x58/0x80 +[ 297.843342] mtk_flow_offload_cmd+0x434/0x574 +[ 297.847689] mtk_wed_setup_tc_block_cb+0x30/0x40 +[ 297.852295] nf_flow_offload_ipv6_hook+0x7f4/0x964 [nf_flow_table] +[ 297.858466] nf_flow_rule_route_ipv6+0x438/0x4a4 [nf_flow_table] +[ 297.864463] process_one_work+0x174/0x300 +[ 297.868465] worker_thread+0x278/0x430 +[ 297.872204] kthread+0xd8/0xdc +[ 297.875251] ret_from_fork+0x10/0x20 +[ 297.878820] Code: 928b5ae0 8b000273 91400a60 f943fa61 (79401421) +[ 297.884901] ---[ end trace 0000000000000000 ]--- + +Fix the issue detecting the proper wed reference to use running wed +callabacks. + +-- Partial backport for data structure change only (rest is in the mt76 package) + +Fixes: 83eafc9251d6 ("wifi: mt76: mt7996: add wed tx support") +Tested-by: Daniel Pawlik +Tested-by: Matteo Croce +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20251008-wed-fixes-v1-1-8f7678583385@kernel.org +Signed-off-by: Felix Fietkau +--- + include/linux/soc/mediatek/mtk_wed.h | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/include/linux/soc/mediatek/mtk_wed.h b/include/linux/soc/mediatek/mtk_wed.h +index 5ab3a93a7be9..5c3358e033df 100644 +--- a/include/linux/soc/mediatek/mtk_wed.h ++++ b/include/linux/soc/mediatek/mtk_wed.h +@@ -154,6 +154,7 @@ struct mtk_wed_device { + bool wcid_512; + bool hw_rro; + bool msi; ++ bool hif2; + + u16 token_start; + unsigned int nbuf; +-- +2.51.0 + + +From 91f5d4afc87aa13b8a58ce06713b4166ec5aeae0 Mon Sep 17 00:00:00 2001 +From: Rex Lu +Date: Thu, 9 Oct 2025 08:29:34 +0200 +Subject: [PATCH 095/517] net: mtk: wed: add dma mask limitation and GFP_DMA32 + for device with more than 4GB DRAM + +Limit tx/rx buffer address to 32-bit address space for board with more +than 4GB DRAM. + +Fixes: 804775dfc2885 ("net: ethernet: mtk_eth_soc: add support for Wireless Ethernet Dispatch (WED)") +Fixes: 6757d345dd7db ("net: ethernet: mtk_wed: introduce hw_rro support for MT7988") +Tested-by: Daniel Pawlik +Tested-by: Matteo Croce +Signed-off-by: Rex Lu +Co-developed-by: Lorenzo Bianconi +Signed-off-by: Lorenzo Bianconi +Reviewed-by: Simon Horman +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/mediatek/mtk_wed.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/mediatek/mtk_wed.c b/drivers/net/ethernet/mediatek/mtk_wed.c +index e7021d0622b0..1e369a059edd 100644 +--- a/drivers/net/ethernet/mediatek/mtk_wed.c ++++ b/drivers/net/ethernet/mediatek/mtk_wed.c +@@ -677,7 +677,7 @@ mtk_wed_tx_buffer_alloc(struct mtk_wed_device *dev) + void *buf; + int s; + +- page = __dev_alloc_page(GFP_KERNEL); ++ page = __dev_alloc_page(GFP_KERNEL | GFP_DMA32); + if (!page) + return -ENOMEM; + +@@ -800,7 +800,7 @@ mtk_wed_hwrro_buffer_alloc(struct mtk_wed_device *dev) + struct page *page; + int s; + +- page = __dev_alloc_page(GFP_KERNEL); ++ page = __dev_alloc_page(GFP_KERNEL | GFP_DMA32); + if (!page) + return -ENOMEM; + +@@ -2438,6 +2438,10 @@ mtk_wed_attach(struct mtk_wed_device *dev) + dev->version = hw->version; + dev->hw->pcie_base = mtk_wed_get_pcie_base(dev); + ++ ret = dma_set_mask_and_coherent(hw->dev, DMA_BIT_MASK(32)); ++ if (ret) ++ goto out; ++ + if (hw->eth->dma_dev == hw->eth->dev && + of_dma_is_coherent(hw->eth->dev->of_node)) + mtk_eth_set_dma_device(hw->eth, hw->dev); +-- +2.51.0 + + +From 41f6a1b75d6742130804539509cff2ef9294196b Mon Sep 17 00:00:00 2001 +From: Linus Walleij +Date: Fri, 13 Oct 2023 00:08:35 +0200 +Subject: [PATCH 096/517] net: dsa: mv88e6xxx: Support LED control + +This adds control over the hardware LEDs in the Marvell +MV88E6xxx DSA switch and enables it for MV88E6352. + +This fixes an imminent problem on the Inteno XG6846 which +has a WAN LED that simply do not work with hardware +defaults: driver amendment is necessary. + +The patch is modeled after Christian Marangis LED support +code for the QCA8k DSA switch, I got help with the register +definitions from Tim Harvey. + +After this patch it is possible to activate hardware link +indication like this (or with a similar script): + + cd /sys/class/leds/Marvell\ 88E6352:05:00:green:wan/ + echo netdev > trigger + echo 1 > link + +This makes the green link indicator come up on any link +speed. It is also possible to be more elaborate, like this: + + cd /sys/class/leds/Marvell\ 88E6352:05:00:green:wan/ + echo netdev > trigger + echo 1 > link_1000 + cd /sys/class/leds/Marvell\ 88E6352:05:01:amber:wan/ + echo netdev > trigger + echo 1 > link_100 + +Making the green LED come on for a gigabit link and the +amber LED come on for a 100 mbit link. + +Each port has 2 LED slots (the hardware may use just one or +none) and the hardware triggers are specified in four bits per +LED, and some of the hardware triggers are only available on the +SFP (fiber) uplink. The restrictions are described in the +port.h header file where the registers are described. For +example, selector 1 set for LED 1 on port 5 or 6 will indicate +Fiber 1000 (gigabit) and activity with a blinking LED, but +ONLY for an SFP connection. If port 5/6 is used with something +not SFP, this selector is a noop: something else need to be +selected. + +After the previous series rewriting the MV88E6xxx DT +bindings to use YAML a "leds" subnode is already valid +for each port, in my scratch device tree it looks like +this: + + leds { + #address-cells = <1>; + #size-cells = <0>; + + led@0 { + reg = <0>; + color = ; + function = LED_FUNCTION_LAN; + default-state = "off"; + linux,default-trigger = "netdev"; + }; + led@1 { + reg = <1>; + color = ; + function = LED_FUNCTION_LAN; + default-state = "off"; + }; + }; + +This DT config is not yet configuring everything: when the netdev +default trigger is assigned the hw acceleration callbacks are +not called, and there is no way to set the netdev sub-trigger +type (such as link_1000) from the device tree, such as if you want +a gigabit link indicator. This has to be done from userspace at +this point. + +We add LED operations to all switches in the 6352 family: +6172, 6176, 6240 and 6352. + +Signed-off-by: Linus Walleij +--- + drivers/net/dsa/mv88e6xxx/Kconfig | 10 + + drivers/net/dsa/mv88e6xxx/Makefile | 1 + + drivers/net/dsa/mv88e6xxx/chip.c | 38 +- + drivers/net/dsa/mv88e6xxx/chip.h | 11 + + drivers/net/dsa/mv88e6xxx/leds.c | 839 +++++++++++++++++++++++++++++ + drivers/net/dsa/mv88e6xxx/port.c | 1 + + drivers/net/dsa/mv88e6xxx/port.h | 133 +++++ + 7 files changed, 1031 insertions(+), 2 deletions(-) + create mode 100644 drivers/net/dsa/mv88e6xxx/leds.c + +diff --git a/drivers/net/dsa/mv88e6xxx/Kconfig b/drivers/net/dsa/mv88e6xxx/Kconfig +index e3181d5471df..64ae3882d17c 100644 +--- a/drivers/net/dsa/mv88e6xxx/Kconfig ++++ b/drivers/net/dsa/mv88e6xxx/Kconfig +@@ -17,3 +17,13 @@ config NET_DSA_MV88E6XXX_PTP + help + Say Y to enable PTP hardware timestamping on Marvell 88E6xxx switch + chips that support it. ++ ++config NET_DSA_MV88E6XXX_LEDS ++ bool "LED support for Marvell 88E6xxx" ++ default y ++ depends on NET_DSA_MV88E6XXX ++ depends on LEDS_CLASS=y || LEDS_CLASS=NET_DSA_MV88E6XXX ++ depends on LEDS_TRIGGERS ++ help ++ This enabled support for controlling the LEDs attached to the ++ Marvell 88E6xxx switch chips. +diff --git a/drivers/net/dsa/mv88e6xxx/Makefile b/drivers/net/dsa/mv88e6xxx/Makefile +index a9a9651187db..dd961081d631 100644 +--- a/drivers/net/dsa/mv88e6xxx/Makefile ++++ b/drivers/net/dsa/mv88e6xxx/Makefile +@@ -9,6 +9,7 @@ mv88e6xxx-objs += global2.o + mv88e6xxx-objs += global2_avb.o + mv88e6xxx-objs += global2_scratch.o + mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_PTP) += hwtstamp.o ++mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_LEDS) += leds.o + mv88e6xxx-objs += pcs-6185.o + mv88e6xxx-objs += pcs-6352.o + mv88e6xxx-objs += pcs-639x.o +diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c +index 211c219dd52d..43e0482fe1fd 100644 +--- a/drivers/net/dsa/mv88e6xxx/chip.c ++++ b/drivers/net/dsa/mv88e6xxx/chip.c +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -3412,14 +3413,43 @@ static int mv88e6xxx_setup_upstream_port(struct mv88e6xxx_chip *chip, int port) + static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port) + { + struct device_node *phy_handle = NULL; ++ struct fwnode_handle *ports_fwnode; ++ struct fwnode_handle *port_fwnode; + struct dsa_switch *ds = chip->ds; ++ struct mv88e6xxx_port *p; + struct dsa_port *dp; + int tx_amp; + int err; + u16 reg; ++ u32 val; ++ ++ p = &chip->ports[port]; ++ p->chip = chip; ++ p->port = port; ++ ++ /* Look up corresponding fwnode if any */ ++ ports_fwnode = device_get_named_child_node(chip->dev, "ethernet-ports"); ++ if (!ports_fwnode) ++ ports_fwnode = device_get_named_child_node(chip->dev, "ports"); ++ if (ports_fwnode) { ++ fwnode_for_each_child_node(ports_fwnode, port_fwnode) { ++ if (fwnode_property_read_u32(port_fwnode, "reg", &val)) ++ continue; ++ if (val == port) { ++ p->fwnode = port_fwnode; ++ p->fiber = fwnode_property_present(port_fwnode, "sfp"); ++ break; ++ } ++ } ++ } else { ++ dev_dbg(chip->dev, "no ethernet ports node defined for the device\n"); ++ } + +- chip->ports[port].chip = chip; +- chip->ports[port].port = port; ++ if (chip->info->ops->port_setup_leds) { ++ err = chip->info->ops->port_setup_leds(chip, port); ++ if (err && err != -EOPNOTSUPP) ++ return err; ++ } + + err = mv88e6xxx_port_setup_mac(chip, port, LINK_UNFORCED, + SPEED_UNFORCED, DUPLEX_UNFORCED, +@@ -4653,6 +4683,7 @@ static const struct mv88e6xxx_ops mv88e6172_ops = { + .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, + .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, + .port_get_cmode = mv88e6352_port_get_cmode, ++ .port_setup_leds = mv88e6xxx_port_setup_leds, + .port_setup_message_port = mv88e6xxx_setup_message_port, + .stats_snapshot = mv88e6320_g1_stats_snapshot, + .stats_set_histogram = mv88e6095_g1_stats_set_histogram, +@@ -4755,6 +4786,7 @@ static const struct mv88e6xxx_ops mv88e6176_ops = { + .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, + .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, + .port_get_cmode = mv88e6352_port_get_cmode, ++ .port_setup_leds = mv88e6xxx_port_setup_leds, + .port_setup_message_port = mv88e6xxx_setup_message_port, + .stats_snapshot = mv88e6320_g1_stats_snapshot, + .stats_set_histogram = mv88e6095_g1_stats_set_histogram, +@@ -5030,6 +5062,7 @@ static const struct mv88e6xxx_ops mv88e6240_ops = { + .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, + .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, + .port_get_cmode = mv88e6352_port_get_cmode, ++ .port_setup_leds = mv88e6xxx_port_setup_leds, + .port_setup_message_port = mv88e6xxx_setup_message_port, + .stats_snapshot = mv88e6320_g1_stats_snapshot, + .stats_set_histogram = mv88e6095_g1_stats_set_histogram, +@@ -5460,6 +5493,7 @@ static const struct mv88e6xxx_ops mv88e6352_ops = { + .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, + .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, + .port_get_cmode = mv88e6352_port_get_cmode, ++ .port_setup_leds = mv88e6xxx_port_setup_leds, + .port_setup_message_port = mv88e6xxx_setup_message_port, + .stats_snapshot = mv88e6320_g1_stats_snapshot, + .stats_set_histogram = mv88e6095_g1_stats_set_histogram, +diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h +index a54682240839..71a8fd9ff374 100644 +--- a/drivers/net/dsa/mv88e6xxx/chip.h ++++ b/drivers/net/dsa/mv88e6xxx/chip.h +@@ -13,7 +13,9 @@ + #include + #include + #include ++#include + #include ++#include + #include + #include + #include +@@ -276,6 +278,7 @@ struct mv88e6xxx_vlan { + struct mv88e6xxx_port { + struct mv88e6xxx_chip *chip; + int port; ++ struct fwnode_handle *fwnode; + struct mv88e6xxx_vlan bridge_pvid; + u64 serdes_stats[2]; + u64 atu_member_violation; +@@ -290,6 +293,11 @@ struct mv88e6xxx_port { + struct devlink_region *region; + void *pcs_private; + ++ /* LED related information */ ++ bool fiber; ++ struct led_classdev led0; ++ struct led_classdev led1; ++ + /* MacAuth Bypass control flag */ + bool mab; + }; +@@ -574,6 +582,9 @@ struct mv88e6xxx_ops { + phy_interface_t mode); + int (*port_get_cmode)(struct mv88e6xxx_chip *chip, int port, u8 *cmode); + ++ /* LED control */ ++ int (*port_setup_leds)(struct mv88e6xxx_chip *chip, int port); ++ + /* Some devices have a per port register indicating what is + * the upstream port this port should forward to. + */ +diff --git a/drivers/net/dsa/mv88e6xxx/leds.c b/drivers/net/dsa/mv88e6xxx/leds.c +new file mode 100644 +index 000000000000..1c88bfaea46b +--- /dev/null ++++ b/drivers/net/dsa/mv88e6xxx/leds.c +@@ -0,0 +1,839 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++#include ++#include ++#include ++ ++#include "chip.h" ++#include "global2.h" ++#include "port.h" ++ ++/* Offset 0x16: LED control */ ++ ++static int mv88e6xxx_port_led_write(struct mv88e6xxx_chip *chip, int port, u16 reg) ++{ ++ reg |= MV88E6XXX_PORT_LED_CONTROL_UPDATE; ++ ++ return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_LED_CONTROL, reg); ++} ++ ++static int mv88e6xxx_port_led_read(struct mv88e6xxx_chip *chip, int port, ++ u16 ptr, u16 *val) ++{ ++ int err; ++ ++ err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_LED_CONTROL, ptr); ++ if (err) ++ return err; ++ ++ err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_LED_CONTROL, val); ++ *val &= 0x3ff; ++ ++ return err; ++} ++ ++static int mv88e6xxx_led_brightness_set(struct mv88e6xxx_port *p, int led, ++ int brightness) ++{ ++ u16 reg; ++ int err; ++ ++ err = mv88e6xxx_port_led_read(p->chip, p->port, ++ MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL, ++ ®); ++ if (err) ++ return err; ++ ++ if (led == 1) ++ reg &= ~MV88E6XXX_PORT_LED_CONTROL_LED1_SEL_MASK; ++ else ++ reg &= ~MV88E6XXX_PORT_LED_CONTROL_LED0_SEL_MASK; ++ ++ if (brightness) { ++ /* Selector 0x0f == Force LED ON */ ++ if (led == 1) ++ reg |= MV88E6XXX_PORT_LED_CONTROL_LED1_SELF; ++ else ++ reg |= MV88E6XXX_PORT_LED_CONTROL_LED0_SELF; ++ } else { ++ /* Selector 0x0e == Force LED OFF */ ++ if (led == 1) ++ reg |= MV88E6XXX_PORT_LED_CONTROL_LED1_SELE; ++ else ++ reg |= MV88E6XXX_PORT_LED_CONTROL_LED0_SELE; ++ } ++ ++ reg |= MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL; ++ ++ return mv88e6xxx_port_led_write(p->chip, p->port, reg); ++} ++ ++static int mv88e6xxx_led0_brightness_set_blocking(struct led_classdev *ldev, ++ enum led_brightness brightness) ++{ ++ struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led0); ++ int err; ++ ++ mv88e6xxx_reg_lock(p->chip); ++ err = mv88e6xxx_led_brightness_set(p, 0, brightness); ++ mv88e6xxx_reg_unlock(p->chip); ++ ++ return err; ++} ++ ++static int mv88e6xxx_led1_brightness_set_blocking(struct led_classdev *ldev, ++ enum led_brightness brightness) ++{ ++ struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led1); ++ int err; ++ ++ mv88e6xxx_reg_lock(p->chip); ++ err = mv88e6xxx_led_brightness_set(p, 1, brightness); ++ mv88e6xxx_reg_unlock(p->chip); ++ ++ return err; ++} ++ ++struct mv88e6xxx_led_hwconfig { ++ int led; ++ u8 portmask; ++ unsigned long rules; ++ bool fiber; ++ bool blink_activity; ++ u16 selector; ++}; ++ ++/* The following is a lookup table to check what rules we can support on a ++ * certain LED given restrictions such as that some rules only work with fiber ++ * (SFP) connections and some blink on activity by default. ++ */ ++#define MV88E6XXX_PORTS_0_3 (BIT(0) | BIT(1) | BIT(2) | BIT(3)) ++#define MV88E6XXX_PORTS_4_5 (BIT(4) | BIT(5)) ++#define MV88E6XXX_PORT_4 BIT(4) ++#define MV88E6XXX_PORT_5 BIT(5) ++ ++/* Entries are listed in selector order. ++ * ++ * These configurations vary across different switch families, list ++ * different tables per-family here. ++ */ ++static const struct mv88e6xxx_led_hwconfig mv88e6352_led_hwconfigs[] = { ++ { ++ .led = 0, ++ .portmask = MV88E6XXX_PORT_4, ++ .rules = BIT(TRIGGER_NETDEV_LINK), ++ .blink_activity = true, ++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL0, ++ }, ++ { ++ .led = 1, ++ .portmask = MV88E6XXX_PORT_5, ++ .rules = BIT(TRIGGER_NETDEV_LINK_1000), ++ .blink_activity = true, ++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL0, ++ }, ++ { ++ .led = 0, ++ .portmask = MV88E6XXX_PORTS_0_3, ++ .rules = BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK_1000), ++ .blink_activity = true, ++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL1, ++ }, ++ { ++ .led = 1, ++ .portmask = MV88E6XXX_PORTS_0_3, ++ .rules = BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK_100), ++ .blink_activity = true, ++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL1, ++ }, ++ { ++ .led = 0, ++ .portmask = MV88E6XXX_PORTS_4_5, ++ .rules = BIT(TRIGGER_NETDEV_LINK_100), ++ .blink_activity = true, ++ .fiber = true, ++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL1, ++ }, ++ { ++ .led = 1, ++ .portmask = MV88E6XXX_PORTS_4_5, ++ .rules = BIT(TRIGGER_NETDEV_LINK_1000), ++ .blink_activity = true, ++ .fiber = true, ++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL1, ++ }, ++ { ++ .led = 0, ++ .portmask = MV88E6XXX_PORTS_0_3, ++ .rules = BIT(TRIGGER_NETDEV_LINK_1000), ++ .blink_activity = true, ++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL2, ++ }, ++ { ++ .led = 1, ++ .portmask = MV88E6XXX_PORTS_0_3, ++ .rules = BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK_100), ++ .blink_activity = true, ++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL2, ++ }, ++ { ++ .led = 0, ++ .portmask = MV88E6XXX_PORTS_4_5, ++ .rules = BIT(TRIGGER_NETDEV_LINK_1000), ++ .blink_activity = true, ++ .fiber = true, ++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL2, ++ }, ++ { ++ .led = 1, ++ .portmask = MV88E6XXX_PORTS_4_5, ++ .rules = BIT(TRIGGER_NETDEV_LINK_100), ++ .blink_activity = true, ++ .fiber = true, ++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL2, ++ }, ++ { ++ .led = 0, ++ .portmask = MV88E6XXX_PORTS_0_3, ++ .rules = BIT(TRIGGER_NETDEV_LINK), ++ .blink_activity = true, ++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL3, ++ }, ++ { ++ .led = 1, ++ .portmask = MV88E6XXX_PORTS_0_3, ++ .rules = BIT(TRIGGER_NETDEV_LINK_1000), ++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL3, ++ }, ++ { ++ .led = 1, ++ .portmask = MV88E6XXX_PORTS_4_5, ++ .rules = BIT(TRIGGER_NETDEV_LINK), ++ .fiber = true, ++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL3, ++ }, ++ { ++ .led = 1, ++ .portmask = MV88E6XXX_PORT_4, ++ .rules = BIT(TRIGGER_NETDEV_LINK), ++ .blink_activity = true, ++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL4, ++ }, ++ { ++ .led = 1, ++ .portmask = MV88E6XXX_PORT_5, ++ .rules = BIT(TRIGGER_NETDEV_LINK), ++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL5, ++ }, ++ { ++ .led = 0, ++ .portmask = MV88E6XXX_PORTS_0_3, ++ .rules = BIT(TRIGGER_NETDEV_FULL_DUPLEX), ++ .blink_activity = true, ++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL6, ++ }, ++ { ++ .led = 1, ++ .portmask = MV88E6XXX_PORTS_0_3, ++ .rules = BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK_1000), ++ .blink_activity = true, ++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL6, ++ }, ++ { ++ .led = 0, ++ .portmask = MV88E6XXX_PORT_4, ++ .rules = BIT(TRIGGER_NETDEV_FULL_DUPLEX), ++ .blink_activity = true, ++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL6, ++ }, ++ { ++ .led = 1, ++ .portmask = MV88E6XXX_PORT_5, ++ .rules = BIT(TRIGGER_NETDEV_FULL_DUPLEX), ++ .blink_activity = true, ++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL6, ++ }, ++ { ++ .led = 0, ++ .portmask = MV88E6XXX_PORTS_0_3, ++ .rules = BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK_1000), ++ .blink_activity = true, ++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL7, ++ }, ++ { ++ .led = 1, ++ .portmask = MV88E6XXX_PORTS_0_3, ++ .rules = BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK_1000), ++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL7, ++ }, ++ { ++ .led = 0, ++ .portmask = MV88E6XXX_PORTS_0_3, ++ .rules = BIT(TRIGGER_NETDEV_LINK), ++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL8, ++ }, ++ { ++ .led = 1, ++ .portmask = MV88E6XXX_PORTS_0_3, ++ .rules = BIT(TRIGGER_NETDEV_LINK), ++ .blink_activity = true, ++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL8, ++ }, ++ { ++ .led = 0, ++ .portmask = MV88E6XXX_PORT_5, ++ .rules = BIT(TRIGGER_NETDEV_LINK), ++ .blink_activity = true, ++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL8, ++ }, ++ { ++ .led = 0, ++ .portmask = MV88E6XXX_PORTS_0_3, ++ .rules = BIT(TRIGGER_NETDEV_LINK_10), ++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL9, ++ }, ++ { ++ .led = 1, ++ .portmask = MV88E6XXX_PORTS_0_3, ++ .rules = BIT(TRIGGER_NETDEV_LINK_100), ++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL9, ++ }, ++ { ++ .led = 0, ++ .portmask = MV88E6XXX_PORTS_0_3, ++ .rules = BIT(TRIGGER_NETDEV_LINK_10), ++ .blink_activity = true, ++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SELA, ++ }, ++ { ++ .led = 1, ++ .portmask = MV88E6XXX_PORTS_0_3, ++ .rules = BIT(TRIGGER_NETDEV_LINK_100), ++ .blink_activity = true, ++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SELA, ++ }, ++ { ++ .led = 0, ++ .portmask = MV88E6XXX_PORTS_0_3, ++ .rules = BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK_1000), ++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SELB, ++ }, ++ { ++ .led = 1, ++ .portmask = MV88E6XXX_PORTS_0_3, ++ .rules = BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK_1000), ++ .blink_activity = true, ++ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SELB, ++ }, ++}; ++ ++/* mv88e6xxx_led_match_selector() - look up the appropriate LED mode selector ++ * @p: port state container ++ * @led: LED number, 0 or 1 ++ * @blink_activity: blink the LED (usually blink on indicated activity) ++ * @fiber: the link is connected to fiber such as SFP ++ * @rules: LED status flags from the LED classdev core ++ * @selector: fill in the selector in this parameter with an OR operation ++ */ ++static int mv88e6xxx_led_match_selector(struct mv88e6xxx_port *p, int led, bool blink_activity, ++ bool fiber, unsigned long rules, u16 *selector) ++{ ++ const struct mv88e6xxx_led_hwconfig *conf; ++ int i; ++ ++ /* No rules means we turn the LED off */ ++ if (!rules) { ++ if (led == 1) ++ *selector |= MV88E6XXX_PORT_LED_CONTROL_LED1_SELE; ++ else ++ *selector |= MV88E6XXX_PORT_LED_CONTROL_LED0_SELE; ++ return 0; ++ } ++ ++ /* TODO: these rules are for MV88E6352, when adding other families, ++ * think about making sure you select the table that match the ++ * specific switch family. ++ */ ++ for (i = 0; i < ARRAY_SIZE(mv88e6352_led_hwconfigs); i++) { ++ conf = &mv88e6352_led_hwconfigs[i]; ++ ++ if (conf->led != led) ++ continue; ++ ++ if (!(conf->portmask & BIT(p->port))) ++ continue; ++ ++ if (conf->blink_activity != blink_activity) ++ continue; ++ ++ if (conf->fiber != fiber) ++ continue; ++ ++ if (conf->rules == rules) { ++ dev_dbg(p->chip->dev, "port%d LED %d set selector %04x for rules %08lx\n", ++ p->port, led, conf->selector, rules); ++ *selector |= conf->selector; ++ return 0; ++ } ++ } ++ ++ return -EOPNOTSUPP; ++} ++ ++/* mv88e6xxx_led_match_selector() - find Linux netdev rules from a selector value ++ * @p: port state container ++ * @selector: the selector value from the LED actity register ++ * @led: LED number, 0 or 1 ++ * @rules: Linux netdev activity rules found from selector ++ */ ++static int ++mv88e6xxx_led_match_rule(struct mv88e6xxx_port *p, u16 selector, int led, unsigned long *rules) ++{ ++ const struct mv88e6xxx_led_hwconfig *conf; ++ int i; ++ ++ /* Find the selector in the table, we just look for the right selector ++ * and ignore if the activity has special properties such as blinking ++ * or is fiber-only. ++ */ ++ for (i = 0; i < ARRAY_SIZE(mv88e6352_led_hwconfigs); i++) { ++ conf = &mv88e6352_led_hwconfigs[i]; ++ ++ if (conf->led != led) ++ continue; ++ ++ if (!(conf->portmask & BIT(p->port))) ++ continue; ++ ++ if (conf->selector == selector) { ++ dev_dbg(p->chip->dev, "port%d LED %d has selector %04x, rules %08lx\n", ++ p->port, led, selector, conf->rules); ++ *rules = conf->rules; ++ return 0; ++ } ++ } ++ ++ return -EINVAL; ++} ++ ++/* mv88e6xxx_led_get_selector() - get the appropriate LED mode selector ++ * @p: port state container ++ * @led: LED number, 0 or 1 ++ * @fiber: the link is connected to fiber such as SFP ++ * @rules: LED status flags from the LED classdev core ++ * @selector: fill in the selector in this parameter with an OR operation ++ */ ++static int mv88e6xxx_led_get_selector(struct mv88e6xxx_port *p, int led, ++ bool fiber, unsigned long rules, u16 *selector) ++{ ++ int err; ++ ++ /* What happens here is that we first try to locate a trigger with solid ++ * indicator (such as LED is on for a 1000 link) else we try a second ++ * sweep to find something suitable with a trigger that will blink on ++ * activity. ++ */ ++ err = mv88e6xxx_led_match_selector(p, led, false, fiber, rules, selector); ++ if (err) ++ return mv88e6xxx_led_match_selector(p, led, true, fiber, rules, selector); ++ ++ return 0; ++} ++ ++/* Sets up the hardware blinking period */ ++static int mv88e6xxx_led_set_blinking_period(struct mv88e6xxx_port *p, int led, ++ unsigned long delay_on, unsigned long delay_off) ++{ ++ unsigned long period; ++ u16 reg; ++ ++ period = delay_on + delay_off; ++ ++ reg = 0; ++ ++ switch (period) { ++ case 21: ++ reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_21MS; ++ break; ++ case 42: ++ reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_42MS; ++ break; ++ case 84: ++ reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_84MS; ++ break; ++ case 168: ++ reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_168MS; ++ break; ++ case 336: ++ reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_336MS; ++ break; ++ case 672: ++ reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_672MS; ++ break; ++ default: ++ /* Fall back to software blinking */ ++ return -EINVAL; ++ } ++ ++ /* This is essentially PWM duty cycle: how long time of the period ++ * will the LED be on. Zero isn't great in most cases. ++ */ ++ switch (delay_on) { ++ case 0: ++ /* This is usually pretty useless and will make the LED look OFF */ ++ reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_NONE; ++ break; ++ case 21: ++ reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_21MS; ++ break; ++ case 42: ++ reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_42MS; ++ break; ++ case 84: ++ reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_84MS; ++ break; ++ case 168: ++ reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_168MS; ++ break; ++ default: ++ /* Just use something non-zero */ ++ reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_21MS; ++ break; ++ } ++ ++ /* Set up blink rate */ ++ reg |= MV88E6XXX_PORT_LED_CONTROL_POINTER_STRETCH_BLINK; ++ ++ return mv88e6xxx_port_led_write(p->chip, p->port, reg); ++} ++ ++static int mv88e6xxx_led_blink_set(struct mv88e6xxx_port *p, int led, ++ unsigned long *delay_on, unsigned long *delay_off) ++{ ++ u16 reg; ++ int err; ++ ++ /* Choose a sensible default 336 ms (~3 Hz) */ ++ if ((*delay_on == 0) && (*delay_off == 0)) { ++ *delay_on = 168; ++ *delay_off = 168; ++ } ++ ++ /* No off delay is just on */ ++ if (*delay_off == 0) ++ return mv88e6xxx_led_brightness_set(p, led, 1); ++ ++ err = mv88e6xxx_led_set_blinking_period(p, led, *delay_on, *delay_off); ++ if (err) ++ return err; ++ ++ err = mv88e6xxx_port_led_read(p->chip, p->port, ++ MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL, ++ ®); ++ if (err) ++ return err; ++ ++ if (led == 1) ++ reg &= ~MV88E6XXX_PORT_LED_CONTROL_LED1_SEL_MASK; ++ else ++ reg &= ~MV88E6XXX_PORT_LED_CONTROL_LED0_SEL_MASK; ++ ++ /* This will select the forced blinking status */ ++ if (led == 1) ++ reg |= MV88E6XXX_PORT_LED_CONTROL_LED1_SELD; ++ else ++ reg |= MV88E6XXX_PORT_LED_CONTROL_LED0_SELD; ++ ++ reg |= MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL; ++ ++ return mv88e6xxx_port_led_write(p->chip, p->port, reg); ++} ++ ++static int mv88e6xxx_led0_blink_set(struct led_classdev *ldev, ++ unsigned long *delay_on, ++ unsigned long *delay_off) ++{ ++ struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led0); ++ int err; ++ ++ mv88e6xxx_reg_lock(p->chip); ++ err = mv88e6xxx_led_blink_set(p, 0, delay_on, delay_off); ++ mv88e6xxx_reg_unlock(p->chip); ++ ++ return err; ++} ++ ++static int mv88e6xxx_led1_blink_set(struct led_classdev *ldev, ++ unsigned long *delay_on, ++ unsigned long *delay_off) ++{ ++ struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led1); ++ int err; ++ ++ mv88e6xxx_reg_lock(p->chip); ++ err = mv88e6xxx_led_blink_set(p, 1, delay_on, delay_off); ++ mv88e6xxx_reg_unlock(p->chip); ++ ++ return err; ++} ++ ++static int ++mv88e6xxx_led0_hw_control_is_supported(struct led_classdev *ldev, unsigned long rules) ++{ ++ struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led0); ++ u16 selector = 0; ++ ++ return mv88e6xxx_led_get_selector(p, 0, p->fiber, rules, &selector); ++} ++ ++static int ++mv88e6xxx_led1_hw_control_is_supported(struct led_classdev *ldev, unsigned long rules) ++{ ++ struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led1); ++ u16 selector = 0; ++ ++ return mv88e6xxx_led_get_selector(p, 1, p->fiber, rules, &selector); ++} ++ ++static int mv88e6xxx_led_hw_control_set(struct mv88e6xxx_port *p, ++ int led, unsigned long rules) ++{ ++ u16 reg; ++ int err; ++ ++ err = mv88e6xxx_port_led_read(p->chip, p->port, ++ MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL, ++ ®); ++ if (err) ++ return err; ++ ++ if (led == 1) ++ reg &= ~MV88E6XXX_PORT_LED_CONTROL_LED1_SEL_MASK; ++ else ++ reg &= ~MV88E6XXX_PORT_LED_CONTROL_LED0_SEL_MASK; ++ ++ err = mv88e6xxx_led_get_selector(p, led, p->fiber, rules, ®); ++ if (err) ++ return err; ++ ++ reg |= MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL; ++ ++ if (led == 0) ++ dev_dbg(p->chip->dev, "LED 0 hw control on port %d trigger selector 0x%02x\n", ++ p->port, ++ (unsigned int)(reg & MV88E6XXX_PORT_LED_CONTROL_LED0_SEL_MASK)); ++ else ++ dev_dbg(p->chip->dev, "LED 1 hw control on port %d trigger selector 0x%02x\n", ++ p->port, ++ (unsigned int)(reg & MV88E6XXX_PORT_LED_CONTROL_LED1_SEL_MASK) >> 4); ++ ++ return mv88e6xxx_port_led_write(p->chip, p->port, reg); ++} ++ ++static int ++mv88e6xxx_led_hw_control_get(struct mv88e6xxx_port *p, int led, unsigned long *rules) ++{ ++ u16 val; ++ int err; ++ ++ mv88e6xxx_reg_lock(p->chip); ++ err = mv88e6xxx_port_led_read(p->chip, p->port, ++ MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL, &val); ++ mv88e6xxx_reg_unlock(p->chip); ++ if (err) ++ return err; ++ ++ /* Mask out the selector bits for this port */ ++ if (led == 1) { ++ val &= MV88E6XXX_PORT_LED_CONTROL_LED1_SEL_MASK; ++ /* It's forced blinking/OFF/ON */ ++ if (val == MV88E6XXX_PORT_LED_CONTROL_LED1_SELD || ++ val == MV88E6XXX_PORT_LED_CONTROL_LED1_SELE || ++ val == MV88E6XXX_PORT_LED_CONTROL_LED1_SELF) { ++ *rules = 0; ++ return 0; ++ } ++ } else { ++ val &= MV88E6XXX_PORT_LED_CONTROL_LED0_SEL_MASK; ++ /* It's forced blinking/OFF/ON */ ++ if (val == MV88E6XXX_PORT_LED_CONTROL_LED0_SELD || ++ val == MV88E6XXX_PORT_LED_CONTROL_LED0_SELE || ++ val == MV88E6XXX_PORT_LED_CONTROL_LED0_SELF) { ++ *rules = 0; ++ return 0; ++ } ++ } ++ ++ err = mv88e6xxx_led_match_rule(p, val, led, rules); ++ if (!err) ++ return 0; ++ ++ dev_dbg(p->chip->dev, "couldn't find matching selector for %04x\n", val); ++ *rules = 0; ++ return 0; ++} ++ ++static int ++mv88e6xxx_led0_hw_control_set(struct led_classdev *ldev, unsigned long rules) ++{ ++ struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led0); ++ int err; ++ ++ mv88e6xxx_reg_lock(p->chip); ++ err = mv88e6xxx_led_hw_control_set(p, 0, rules); ++ mv88e6xxx_reg_unlock(p->chip); ++ ++ return err; ++} ++ ++static int ++mv88e6xxx_led1_hw_control_set(struct led_classdev *ldev, unsigned long rules) ++{ ++ struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led1); ++ int err; ++ ++ mv88e6xxx_reg_lock(p->chip); ++ err = mv88e6xxx_led_hw_control_set(p, 1, rules); ++ mv88e6xxx_reg_unlock(p->chip); ++ ++ return err; ++} ++ ++static int ++mv88e6xxx_led0_hw_control_get(struct led_classdev *ldev, unsigned long *rules) ++{ ++ struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led0); ++ ++ return mv88e6xxx_led_hw_control_get(p, 0, rules); ++} ++ ++static int ++mv88e6xxx_led1_hw_control_get(struct led_classdev *ldev, unsigned long *rules) ++{ ++ struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led1); ++ ++ return mv88e6xxx_led_hw_control_get(p, 1, rules); ++} ++ ++static struct device *mv88e6xxx_led_hw_control_get_device(struct mv88e6xxx_port *p) ++{ ++ struct dsa_port *dp; ++ ++ dp = dsa_to_port(p->chip->ds, p->port); ++ if (!dp) ++ return NULL; ++ if (dp->user) ++ return &dp->user->dev; ++ return NULL; ++} ++ ++static struct device * ++mv88e6xxx_led0_hw_control_get_device(struct led_classdev *ldev) ++{ ++ struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led0); ++ ++ return mv88e6xxx_led_hw_control_get_device(p); ++} ++ ++static struct device * ++mv88e6xxx_led1_hw_control_get_device(struct led_classdev *ldev) ++{ ++ struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led1); ++ ++ return mv88e6xxx_led_hw_control_get_device(p); ++} ++ ++int mv88e6xxx_port_setup_leds(struct mv88e6xxx_chip *chip, int port) ++{ ++ struct fwnode_handle *led = NULL, *leds = NULL; ++ struct led_init_data init_data = { }; ++ enum led_default_state state; ++ struct mv88e6xxx_port *p; ++ struct led_classdev *l; ++ struct device *dev; ++ u32 led_num; ++ int ret; ++ ++ /* LEDs are on ports 1,2,3,4, 5 and 6 (index 0..5), no more */ ++ if (port > 5) ++ return -EOPNOTSUPP; ++ ++ p = &chip->ports[port]; ++ if (!p->fwnode) ++ return 0; ++ ++ dev = chip->dev; ++ ++ leds = fwnode_get_named_child_node(p->fwnode, "leds"); ++ if (!leds) { ++ dev_dbg(dev, "No Leds node specified in device tree for port %d!\n", ++ port); ++ return 0; ++ } ++ ++ fwnode_for_each_child_node(leds, led) { ++ /* Reg represent the led number of the port, max 2 ++ * LEDs can be connected to each port, in some designs ++ * only one LED is connected. ++ */ ++ if (fwnode_property_read_u32(led, "reg", &led_num)) ++ continue; ++ if (led_num > 1) { ++ dev_err(dev, "invalid LED specified port %d\n", port); ++ return -EINVAL; ++ } ++ ++ if (led_num == 0) ++ l = &p->led0; ++ else ++ l = &p->led1; ++ ++ state = led_init_default_state_get(led); ++ switch (state) { ++ case LEDS_DEFSTATE_ON: ++ l->brightness = 1; ++ mv88e6xxx_led_brightness_set(p, led_num, 1); ++ break; ++ case LEDS_DEFSTATE_KEEP: ++ break; ++ default: ++ l->brightness = 0; ++ mv88e6xxx_led_brightness_set(p, led_num, 0); ++ } ++ ++ l->max_brightness = 1; ++ if (led_num == 0) { ++ l->brightness_set_blocking = mv88e6xxx_led0_brightness_set_blocking; ++ l->blink_set = mv88e6xxx_led0_blink_set; ++ l->hw_control_is_supported = mv88e6xxx_led0_hw_control_is_supported; ++ l->hw_control_set = mv88e6xxx_led0_hw_control_set; ++ l->hw_control_get = mv88e6xxx_led0_hw_control_get; ++ l->hw_control_get_device = mv88e6xxx_led0_hw_control_get_device; ++ } else { ++ l->brightness_set_blocking = mv88e6xxx_led1_brightness_set_blocking; ++ l->blink_set = mv88e6xxx_led1_blink_set; ++ l->hw_control_is_supported = mv88e6xxx_led1_hw_control_is_supported; ++ l->hw_control_set = mv88e6xxx_led1_hw_control_set; ++ l->hw_control_get = mv88e6xxx_led1_hw_control_get; ++ l->hw_control_get_device = mv88e6xxx_led1_hw_control_get_device; ++ } ++ l->hw_control_trigger = "netdev"; ++ ++ init_data.default_label = ":port"; ++ init_data.fwnode = led; ++ init_data.devname_mandatory = true; ++ init_data.devicename = kasprintf(GFP_KERNEL, "%s:0%d:0%d", chip->info->name, ++ port, led_num); ++ if (!init_data.devicename) ++ return -ENOMEM; ++ ++ ret = devm_led_classdev_register_ext(dev, l, &init_data); ++ kfree(init_data.devicename); ++ ++ if (ret) { ++ dev_err(dev, "Failed to init LED %d for port %d", led_num, port); ++ return ret; ++ } ++ } ++ ++ return 0; ++} +diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c +index 04053fdc6489..dc777ddce1f3 100644 +--- a/drivers/net/dsa/mv88e6xxx/port.c ++++ b/drivers/net/dsa/mv88e6xxx/port.c +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include + + #include "chip.h" + #include "global2.h" +diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h +index ddadeb9bfdae..c1d2f99efb1c 100644 +--- a/drivers/net/dsa/mv88e6xxx/port.h ++++ b/drivers/net/dsa/mv88e6xxx/port.h +@@ -309,6 +309,130 @@ + /* Offset 0x13: OutFiltered Counter */ + #define MV88E6XXX_PORT_OUT_FILTERED 0x13 + ++/* Offset 0x16: LED Control */ ++#define MV88E6XXX_PORT_LED_CONTROL 0x16 ++#define MV88E6XXX_PORT_LED_CONTROL_UPDATE BIT(15) ++#define MV88E6XXX_PORT_LED_CONTROL_POINTER_MASK GENMASK(14, 12) ++#define MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL (0x00 << 12) /* Control for LED 0 and 1 */ ++#define MV88E6XXX_PORT_LED_CONTROL_POINTER_STRETCH_BLINK (0x06 << 12) /* Stetch and Blink Rate */ ++#define MV88E6XXX_PORT_LED_CONTROL_POINTER_CNTL_SPECIAL (0x07 << 12) /* Control for the Port's Special LED */ ++#define MV88E6XXX_PORT_LED_CONTROL_DATA_MASK GENMASK(10, 0) ++/* Selection masks valid for either port 1,2,3,4 or 5 */ ++#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL_MASK GENMASK(3, 0) ++#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL_MASK GENMASK(7, 4) ++/* Selection control for LED 0 and 1, ports 5 and 6 only has LED 0 ++ * Bits Function ++ * 0..3 LED 0 control selector on ports 1-5 ++ * 4..7 LED 1 control selector on ports 1-4 on port 5 this controls LED 0 of port 6 ++ * ++ * Sel Port LED Function for the 6352 family: ++ * 0 1-4 0 Link/Act/Speed by Blink Rate (off=no link, on=link, blink=activity, blink speed=link speed) ++ * 1-4 1 Port 2's Special LED ++ * 5-6 0 Port 5 Link/Act (off=no link, on=link, blink=activity) ++ * 5-6 1 Port 6 Link/Act (off=no link, on=link 1000, blink=activity) ++ * 1 1-4 0 100/1000 Link/Act (off=no link, on=100 or 1000 link, blink=activity) ++ * 1-4 1 10/100 Link Act (off=no link, on=10 or 100 link, blink=activity) ++ * 5-6 0 Fiber 100 Link/Act (off=no link, on=link 100, blink=activity) ++ * 5-6 1 Fiber 1000 Link/Act (off=no link, on=link 1000, blink=activity) ++ * 2 1-4 0 1000 Link/Act (off=no link, on=link 1000, blink=activity) ++ * 1-4 1 10/100 Link/Act (off=no link, on=10 or 100 link, blink=activity) ++ * 5-6 0 Fiber 1000 Link/Act (off=no link, on=link 1000, blink=activity) ++ * 5-6 1 Fiber 100 Link/Act (off=no link, on=link 100, blink=activity) ++ * 3 1-4 0 Link/Act (off=no link, on=link, blink=activity) ++ * 1-4 1 1000 Link (off=no link, on=1000 link) ++ * 5-6 0 Port 0's Special LED ++ * 5-6 1 Fiber Link (off=no link, on=link) ++ * 4 1-4 0 Port 0's Special LED ++ * 1-4 1 Port 1's Special LED ++ * 5-6 0 Port 1's Special LED ++ * 5-6 1 Port 5 Link/Act (off=no link, on=link, blink=activity) ++ * 5 1-4 0 Reserved ++ * 1-4 1 Reserved ++ * 5-6 0 Port 2's Special LED ++ * 5-6 1 Port 6 Link (off=no link, on=link) ++ * 6 1-4 0 Duplex/Collision (off=half-duplex,on=full-duplex,blink=collision) ++ * 1-4 1 10/1000 Link/Act (off=no link, on=10 or 1000 link, blink=activity) ++ * 5-6 0 Port 5 Duplex/Collision (off=half-duplex, on=full-duplex, blink=col) ++ * 5-6 1 Port 6 Duplex/Collision (off=half-duplex, on=full-duplex, blink=col) ++ * 7 1-4 0 10/1000 Link/Act (off=no link, on=10 or 1000 link, blink=activity) ++ * 1-4 1 10/1000 Link (off=no link, on=10 or 1000 link) ++ * 5-6 0 Port 5 Link/Act/Speed by Blink rate (off=no link, on=link, blink=activity, blink speed=link speed) ++ * 5-6 1 Port 6 Link/Act/Speed by Blink rate (off=no link, on=link, blink=activity, blink speed=link speed) ++ * 8 1-4 0 Link (off=no link, on=link) ++ * 1-4 1 Activity (off=no link, blink on=activity) ++ * 5-6 0 Port 6 Link/Act (off=no link, on=link, blink=activity) ++ * 5-6 1 Port 0's Special LED ++ * 9 1-4 0 10 Link (off=no link, on=10 link) ++ * 1-4 1 100 Link (off=no link, on=100 link) ++ * 5-6 0 Reserved ++ * 5-6 1 Port 1's Special LED ++ * a 1-4 0 10 Link/Act (off=no link, on=10 link, blink=activity) ++ * 1-4 1 100 Link/Act (off=no link, on=100 link, blink=activity) ++ * 5-6 0 Reserved ++ * 5-6 1 Port 2's Special LED ++ * b 1-4 0 100/1000 Link (off=no link, on=100 or 1000 link) ++ * 1-4 1 10/100 Link (off=no link, on=100 link, blink=activity) ++ * 5-6 0 Reserved ++ * 5-6 1 Reserved ++ * c * * PTP Act (blink on=PTP activity) ++ * d * * Force Blink ++ * e * * Force Off ++ * f * * Force On ++ */ ++/* Select LED0 output */ ++#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL0 0x0 ++#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL1 0x1 ++#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL2 0x2 ++#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL3 0x3 ++#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL4 0x4 ++#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL5 0x5 ++#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL6 0x6 ++#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL7 0x7 ++#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL8 0x8 ++#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL9 0x9 ++#define MV88E6XXX_PORT_LED_CONTROL_LED0_SELA 0xa ++#define MV88E6XXX_PORT_LED_CONTROL_LED0_SELB 0xb ++#define MV88E6XXX_PORT_LED_CONTROL_LED0_SELC 0xc ++#define MV88E6XXX_PORT_LED_CONTROL_LED0_SELD 0xd ++#define MV88E6XXX_PORT_LED_CONTROL_LED0_SELE 0xe ++#define MV88E6XXX_PORT_LED_CONTROL_LED0_SELF 0xf ++#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL0 (0x0 << 4) ++#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL1 (0x1 << 4) ++#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL2 (0x2 << 4) ++#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL3 (0x3 << 4) ++#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL4 (0x4 << 4) ++#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL5 (0x5 << 4) ++#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL6 (0x6 << 4) ++#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL7 (0x7 << 4) ++#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL8 (0x8 << 4) ++#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL9 (0x9 << 4) ++#define MV88E6XXX_PORT_LED_CONTROL_LED1_SELA (0xa << 4) ++#define MV88E6XXX_PORT_LED_CONTROL_LED1_SELB (0xb << 4) ++#define MV88E6XXX_PORT_LED_CONTROL_LED1_SELC (0xc << 4) ++#define MV88E6XXX_PORT_LED_CONTROL_LED1_SELD (0xd << 4) ++#define MV88E6XXX_PORT_LED_CONTROL_LED1_SELE (0xe << 4) ++#define MV88E6XXX_PORT_LED_CONTROL_LED1_SELF (0xf << 4) ++/* Stretch and Blink Rate Control (Index 0x06 of LED Control) */ ++/* Pulse Stretch Selection for all LED's on this port */ ++#define MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_NONE (0 << 4) ++#define MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_21MS (1 << 4) ++#define MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_42MS (2 << 4) ++#define MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_84MS (3 << 4) ++#define MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_168MS (4 << 4) ++/* Blink Rate Selection for all LEDs on this port */ ++#define MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_21MS 0 ++#define MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_42MS 1 ++#define MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_84MS 2 ++#define MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_168MS 3 ++#define MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_336MS 4 ++#define MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_672MS 5 ++ /* Control for Special LED (Index 0x7 of LED Control on Port0) */ ++#define MV88E6XXX_PORT_LED_CONTROL_0x07_P0_LAN_LINKACT_SHIFT 0 /* bits 6:0 LAN Link Activity LED */ ++/* Control for Special LED (Index 0x7 of LED Control on Port 1) */ ++#define MV88E6XXX_PORT_LED_CONTROL_0x07_P1_WAN_LINKACT_SHIFT 0 /* bits 6:0 WAN Link Activity LED */ ++/* Control for Special LED (Index 0x7 of LED Control on Port 2) */ ++#define MV88E6XXX_PORT_LED_CONTROL_0x07_P2_PTP_ACT 0 /* bits 6:0 PTP Activity */ ++ + /* Offset 0x18: IEEE Priority Mapping Table */ + #define MV88E6390_PORT_IEEE_PRIO_MAP_TABLE 0x18 + #define MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_UPDATE 0x8000 +@@ -457,6 +581,15 @@ int mv88e6393x_port_set_cmode(struct mv88e6xxx_chip *chip, int port, + phy_interface_t mode); + int mv88e6185_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode); + int mv88e6352_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode); ++#ifdef CONFIG_NET_DSA_MV88E6XXX_LEDS ++int mv88e6xxx_port_setup_leds(struct mv88e6xxx_chip *chip, int port); ++#else ++static inline int mv88e6xxx_port_setup_leds(struct mv88e6xxx_chip *chip, ++ int port) ++{ ++ return 0; ++} ++#endif + int mv88e6xxx_port_drop_untagged(struct mv88e6xxx_chip *chip, int port, + bool drop_untagged); + int mv88e6xxx_port_set_map_da(struct mv88e6xxx_chip *chip, int port, bool map); +-- +2.51.0 + + +From 75caf17387cec21649e7981585617b6f1bd850ea Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Wed, 9 Oct 2024 07:48:05 +0200 +Subject: [PATCH 097/517] r8169: remove original workaround for RTL8125 broken + rx issue + +Now that we have b9c7ac4fe22c ("r8169: disable ALDPS per default for +RTL8125"), the first attempt to fix the issue shouldn't be needed +any longer. So let's effectively revert 621735f59064 ("r8169: fix +rare issue with broken rx after link-down on RTL8125") and see +whether anybody complains. + +Signed-off-by: Heiner Kallweit +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/382d8c88-cbce-400f-ad62-fda0181c7e38@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/realtek/r8169_main.c | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c +index 80b5262d0d57..4ef3a23f9f95 100644 +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -4813,11 +4813,7 @@ static void r8169_phylink_handler(struct net_device *ndev) + if (netif_carrier_ok(ndev)) { + rtl_link_chg_patch(tp); + pm_request_resume(d); +- netif_wake_queue(tp->dev); + } else { +- /* In few cases rx is broken after link-down otherwise */ +- if (rtl_is_8125(tp)) +- rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_NO_QUEUE_WAKE); + pm_runtime_idle(d); + } + +-- +2.51.0 + + +From 876e8c0219f3c916926131747aded27d275a1cfd Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Thu, 10 Oct 2024 12:58:02 +0200 +Subject: [PATCH 098/517] r8169: enable SG/TSO on selected chip versions per + default + +Due to problem reports in the past SG and TSO/TSO6 are disabled per +default. It's not fully clear which chip versions are affected, so we +may impact also users of unaffected chip versions, unless they know +how to use ethtool for enabling SG/TSO/TSO6. +Vendor drivers r8168/r8125 enable SG/TSO/TSO6 for selected chip +versions per default, I'd interpret this as confirmation that these +chip versions are unaffected. So let's do the same here. + +Signed-off-by: Heiner Kallweit +Reviewed-by: Simon Horman +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/realtek/r8169_main.c | 16 +++++++++++----- + 1 file changed, 11 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c +index 4ef3a23f9f95..9a01b5a9facd 100644 +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -5527,11 +5527,6 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) + + dev->features |= dev->hw_features; + +- /* There has been a number of reports that using SG/TSO results in +- * tx timeouts. However for a lot of people SG/TSO works fine. +- * Therefore disable both features by default, but allow users to +- * enable them. Use at own risk! +- */ + if (rtl_chip_supports_csum_v2(tp)) { + dev->hw_features |= NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6; + netif_set_tso_max_size(dev, RTL_GSO_MAX_SIZE_V2); +@@ -5542,6 +5537,17 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) + netif_set_tso_max_segs(dev, RTL_GSO_MAX_SEGS_V1); + } + ++ /* There has been a number of reports that using SG/TSO results in ++ * tx timeouts. However for a lot of people SG/TSO works fine. ++ * It's not fully clear which chip versions are affected. Vendor ++ * drivers enable SG/TSO for certain chip versions per default, ++ * let's mimic this here. On other chip versions users can ++ * use ethtool to enable SG/TSO, use at own risk! ++ */ ++ if (tp->mac_version >= RTL_GIGA_MAC_VER_46 && ++ tp->mac_version != RTL_GIGA_MAC_VER_61) ++ dev->features |= dev->hw_features; ++ + dev->hw_features |= NETIF_F_RXALL; + dev->hw_features |= NETIF_F_RXFCS; + +-- +2.51.0 + + +From cc333d732be713e617a9e2673d01e660ca905e2e Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Sun, 13 Oct 2024 11:17:39 +0200 +Subject: [PATCH 099/517] r8169: implement additional ethtool stats ops + +This adds support for ethtool standard statistics, and makes use of the +extended hardware statistics being available from RTl8125. + +Signed-off-by: Heiner Kallweit +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/58e0da73-a7dd-4be3-82ae-d5b3f9069bde@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/realtek/r8169_main.c | 82 +++++++++++++++++++++++ + 1 file changed, 82 insertions(+) + +diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c +index 9a01b5a9facd..27633b4802f8 100644 +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -2160,6 +2160,19 @@ static void rtl8169_get_ringparam(struct net_device *dev, + data->tx_pending = NUM_TX_DESC; + } + ++static void rtl8169_get_pause_stats(struct net_device *dev, ++ struct ethtool_pause_stats *pause_stats) ++{ ++ struct rtl8169_private *tp = netdev_priv(dev); ++ ++ if (!rtl_is_8125(tp)) ++ return; ++ ++ rtl8169_update_counters(tp); ++ pause_stats->tx_pause_frames = le32_to_cpu(tp->counters->tx_pause_on); ++ pause_stats->rx_pause_frames = le32_to_cpu(tp->counters->rx_pause_on); ++} ++ + static void rtl8169_get_pauseparam(struct net_device *dev, + struct ethtool_pauseparam *data) + { +@@ -2186,6 +2199,69 @@ static int rtl8169_set_pauseparam(struct net_device *dev, + return 0; + } + ++static void rtl8169_get_eth_mac_stats(struct net_device *dev, ++ struct ethtool_eth_mac_stats *mac_stats) ++{ ++ struct rtl8169_private *tp = netdev_priv(dev); ++ ++ rtl8169_update_counters(tp); ++ ++ mac_stats->FramesTransmittedOK = ++ le64_to_cpu(tp->counters->tx_packets); ++ mac_stats->SingleCollisionFrames = ++ le32_to_cpu(tp->counters->tx_one_collision); ++ mac_stats->MultipleCollisionFrames = ++ le32_to_cpu(tp->counters->tx_multi_collision); ++ mac_stats->FramesReceivedOK = ++ le64_to_cpu(tp->counters->rx_packets); ++ mac_stats->AlignmentErrors = ++ le16_to_cpu(tp->counters->align_errors); ++ mac_stats->FramesLostDueToIntMACXmitError = ++ le64_to_cpu(tp->counters->tx_errors); ++ mac_stats->BroadcastFramesReceivedOK = ++ le64_to_cpu(tp->counters->rx_broadcast); ++ mac_stats->MulticastFramesReceivedOK = ++ le32_to_cpu(tp->counters->rx_multicast); ++ ++ if (!rtl_is_8125(tp)) ++ return; ++ ++ mac_stats->AlignmentErrors = ++ le32_to_cpu(tp->counters->align_errors32); ++ mac_stats->OctetsTransmittedOK = ++ le64_to_cpu(tp->counters->tx_octets); ++ mac_stats->LateCollisions = ++ le32_to_cpu(tp->counters->tx_late_collision); ++ mac_stats->FramesAbortedDueToXSColls = ++ le32_to_cpu(tp->counters->tx_aborted32); ++ mac_stats->OctetsReceivedOK = ++ le64_to_cpu(tp->counters->rx_octets); ++ mac_stats->FramesLostDueToIntMACRcvError = ++ le32_to_cpu(tp->counters->rx_mac_error); ++ mac_stats->MulticastFramesXmittedOK = ++ le64_to_cpu(tp->counters->tx_multicast64); ++ mac_stats->BroadcastFramesXmittedOK = ++ le64_to_cpu(tp->counters->tx_broadcast64); ++ mac_stats->MulticastFramesReceivedOK = ++ le64_to_cpu(tp->counters->rx_multicast64); ++ mac_stats->FrameTooLongErrors = ++ le32_to_cpu(tp->counters->rx_frame_too_long); ++} ++ ++static void rtl8169_get_eth_ctrl_stats(struct net_device *dev, ++ struct ethtool_eth_ctrl_stats *ctrl_stats) ++{ ++ struct rtl8169_private *tp = netdev_priv(dev); ++ ++ if (!rtl_is_8125(tp)) ++ return; ++ ++ rtl8169_update_counters(tp); ++ ++ ctrl_stats->UnsupportedOpcodesReceived = ++ le32_to_cpu(tp->counters->rx_unknown_opcode); ++} ++ + static const struct ethtool_ops rtl8169_ethtool_ops = { + .supported_coalesce_params = ETHTOOL_COALESCE_USECS | + ETHTOOL_COALESCE_MAX_FRAMES, +@@ -2207,8 +2283,11 @@ static const struct ethtool_ops rtl8169_ethtool_ops = { + .get_link_ksettings = phy_ethtool_get_link_ksettings, + .set_link_ksettings = phy_ethtool_set_link_ksettings, + .get_ringparam = rtl8169_get_ringparam, ++ .get_pause_stats = rtl8169_get_pause_stats, + .get_pauseparam = rtl8169_get_pauseparam, + .set_pauseparam = rtl8169_set_pauseparam, ++ .get_eth_mac_stats = rtl8169_get_eth_mac_stats, ++ .get_eth_ctrl_stats = rtl8169_get_eth_ctrl_stats, + }; + + static enum mac_version rtl8169_get_mac_version(u16 xid, bool gmii) +@@ -3929,6 +4008,9 @@ static void rtl_hw_start_8125(struct rtl8169_private *tp) + break; + } + ++ /* enable extended tally counter */ ++ r8168_mac_ocp_modify(tp, 0xea84, 0, BIT(1) | BIT(0)); ++ + rtl_hw_config(tp); + } + +-- +2.51.0 + + +From 346f3face3f8c7e50c37eb4c9afa0fedc0231401 Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Wed, 16 Oct 2024 22:05:57 +0200 +Subject: [PATCH 100/517] r8169: don't take RTNL lock in rtl_task() + +There's not really a benefit here in taking the RTNL lock. The task +handler does exception handling only, so we're in trouble anyway when +we come here, and there's no need to protect against e.g. a parallel +ethtool call. +A benefit of removing the RTNL lock here is that we now can +synchronously cancel the workqueue from a context holding the RTNL mutex. + +Signed-off-by: Heiner Kallweit +Signed-off-by: Andrew Lunn +--- + drivers/net/ethernet/realtek/r8169_main.c | 8 ++------ + 1 file changed, 2 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c +index 27633b4802f8..793c3740b623 100644 +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -4836,10 +4836,8 @@ static void rtl_task(struct work_struct *work) + container_of(work, struct rtl8169_private, wk.work); + int ret; + +- rtnl_lock(); +- + if (!test_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags)) +- goto out_unlock; ++ return; + + if (test_and_clear_bit(RTL_FLAG_TASK_TX_TIMEOUT, tp->wk.flags)) { + /* if chip isn't accessible, reset bus to revive it */ +@@ -4848,7 +4846,7 @@ static void rtl_task(struct work_struct *work) + if (ret < 0) { + netdev_err(tp->dev, "Can't reset secondary PCI bus, detach NIC\n"); + netif_device_detach(tp->dev); +- goto out_unlock; ++ return; + } + } + +@@ -4867,8 +4865,6 @@ static void rtl_task(struct work_struct *work) + } else if (test_and_clear_bit(RTL_FLAG_TASK_RESET_NO_QUEUE_WAKE, tp->wk.flags)) { + rtl_reset_work(tp); + } +-out_unlock: +- rtnl_unlock(); + } + + static int rtl8169_poll(struct napi_struct *napi, int budget) +-- +2.51.0 + + +From 946357f990b9bdbdfcea45e565acafab66b877f8 Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Wed, 16 Oct 2024 22:06:53 +0200 +Subject: [PATCH 101/517] r8169: replace custom flag with disable_work() et al + +So far we use a custom flag to define when a task can be scheduled and +when not. Let's use the standard mechanism with disable_work() et al +instead. +Note that in rtl8169_close() we can remove the call to cancel_work() +because we now call disable_work_sync() in rtl8169_down() already. + +Signed-off-by: Heiner Kallweit +Signed-off-by: Andrew Lunn +--- + drivers/net/ethernet/realtek/r8169_main.c | 18 ++++++------------ + 1 file changed, 6 insertions(+), 12 deletions(-) + +diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c +index 793c3740b623..a4d659612c0b 100644 +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -619,7 +619,6 @@ struct rtl8169_tc_offsets { + }; + + enum rtl_flag { +- RTL_FLAG_TASK_ENABLED = 0, + RTL_FLAG_TASK_RESET_PENDING, + RTL_FLAG_TASK_RESET_NO_QUEUE_WAKE, + RTL_FLAG_TASK_TX_TIMEOUT, +@@ -2505,11 +2504,9 @@ u16 rtl8168h_2_get_adc_bias_ioffset(struct rtl8169_private *tp) + + static void rtl_schedule_task(struct rtl8169_private *tp, enum rtl_flag flag) + { +- if (!test_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags)) +- return; +- + set_bit(flag, tp->wk.flags); +- schedule_work(&tp->wk.work); ++ if (!schedule_work(&tp->wk.work)) ++ clear_bit(flag, tp->wk.flags); + } + + static void rtl8169_init_phy(struct rtl8169_private *tp) +@@ -4836,9 +4833,6 @@ static void rtl_task(struct work_struct *work) + container_of(work, struct rtl8169_private, wk.work); + int ret; + +- if (!test_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags)) +- return; +- + if (test_and_clear_bit(RTL_FLAG_TASK_TX_TIMEOUT, tp->wk.flags)) { + /* if chip isn't accessible, reset bus to revive it */ + if (RTL_R32(tp, TxConfig) == ~0) { +@@ -4922,6 +4916,7 @@ static int r8169_phy_connect(struct rtl8169_private *tp) + + static void rtl8169_down(struct rtl8169_private *tp) + { ++ disable_work_sync(&tp->wk.work); + /* Clear all task flags */ + bitmap_zero(tp->wk.flags, RTL_FLAG_MAX); + +@@ -4950,7 +4945,7 @@ static void rtl8169_up(struct rtl8169_private *tp) + phy_resume(tp->phydev); + rtl8169_init_phy(tp); + napi_enable(&tp->napi); +- set_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags); ++ enable_work(&tp->wk.work); + rtl_reset_work(tp); + + phy_start(tp->phydev); +@@ -4967,8 +4962,6 @@ static int rtl8169_close(struct net_device *dev) + rtl8169_down(tp); + rtl8169_rx_clear(tp); + +- cancel_work(&tp->wk.work); +- + free_irq(tp->irq, tp); + + phy_disconnect(tp->phydev); +@@ -5202,7 +5195,7 @@ static void rtl_remove_one(struct pci_dev *pdev) + if (pci_dev_run_wake(pdev)) + pm_runtime_get_noresume(&pdev->dev); + +- cancel_work_sync(&tp->wk.work); ++ disable_work_sync(&tp->wk.work); + + if (IS_ENABLED(CONFIG_R8169_LEDS)) + r8169_remove_leds(tp->leds); +@@ -5580,6 +5573,7 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) + tp->irq = pci_irq_vector(pdev, 0); + + INIT_WORK(&tp->wk.work, rtl_task); ++ disable_work(&tp->wk.work); + + rtl_init_mac_address(tp); + +-- +2.51.0 + + +From a96d084288956bdc353e2d978982680e65c30f55 Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Wed, 16 Oct 2024 22:29:39 +0200 +Subject: [PATCH 102/517] r8169: avoid duplicated messages if loading firmware + fails and switch to warn level + +In case of a problem with firmware loading we inform at the driver level, +in addition the firmware load code itself issues warnings. Therefore +switch to firmware_request_nowarn() to avoid duplicated error messages. +In addition switch to warn level because the firmware is optional and +typically just fixes compatibility issues. + +Signed-off-by: Heiner Kallweit +Reviewed-by: Simon Horman +Message-ID: +Signed-off-by: Andrew Lunn +--- + drivers/net/ethernet/realtek/r8169_firmware.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/realtek/r8169_firmware.c b/drivers/net/ethernet/realtek/r8169_firmware.c +index ed6e721b1555..bf055078a855 100644 +--- a/drivers/net/ethernet/realtek/r8169_firmware.c ++++ b/drivers/net/ethernet/realtek/r8169_firmware.c +@@ -215,7 +215,7 @@ int rtl_fw_request_firmware(struct rtl_fw *rtl_fw) + { + int rc; + +- rc = request_firmware(&rtl_fw->fw, rtl_fw->fw_name, rtl_fw->dev); ++ rc = firmware_request_nowarn(&rtl_fw->fw, rtl_fw->fw_name, rtl_fw->dev); + if (rc < 0) + goto out; + +@@ -227,7 +227,7 @@ int rtl_fw_request_firmware(struct rtl_fw *rtl_fw) + + return 0; + out: +- dev_err(rtl_fw->dev, "Unable to load firmware %s (%d)\n", +- rtl_fw->fw_name, rc); ++ dev_warn(rtl_fw->dev, "Unable to load firmware %s (%d)\n", ++ rtl_fw->fw_name, rc); + return rc; + } +-- +2.51.0 + + +From 56661855d12fe1c72a1028936f9d3e5fb9c82478 Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Wed, 16 Oct 2024 22:31:10 +0200 +Subject: [PATCH 103/517] r8169: remove rtl_dash_loop_wait_high/low + +Remove rtl_dash_loop_wait_high/low to simplify the code. + +Signed-off-by: Heiner Kallweit +Reviewed-by: Simon Horman +Message-ID: +Signed-off-by: Andrew Lunn +--- + drivers/net/ethernet/realtek/r8169_main.c | 35 ++++++----------------- + 1 file changed, 8 insertions(+), 27 deletions(-) + +diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c +index a4d659612c0b..d9682329f6e7 100644 +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -1348,40 +1348,19 @@ static void rtl8168ep_stop_cmac(struct rtl8169_private *tp) + RTL_W8(tp, IBCR0, RTL_R8(tp, IBCR0) & ~0x01); + } + +-static void rtl_dash_loop_wait(struct rtl8169_private *tp, +- const struct rtl_cond *c, +- unsigned long usecs, int n, bool high) +-{ +- if (!tp->dash_enabled) +- return; +- rtl_loop_wait(tp, c, usecs, n, high); +-} +- +-static void rtl_dash_loop_wait_high(struct rtl8169_private *tp, +- const struct rtl_cond *c, +- unsigned long d, int n) +-{ +- rtl_dash_loop_wait(tp, c, d, n, true); +-} +- +-static void rtl_dash_loop_wait_low(struct rtl8169_private *tp, +- const struct rtl_cond *c, +- unsigned long d, int n) +-{ +- rtl_dash_loop_wait(tp, c, d, n, false); +-} +- + static void rtl8168dp_driver_start(struct rtl8169_private *tp) + { + r8168dp_oob_notify(tp, OOB_CMD_DRIVER_START); +- rtl_dash_loop_wait_high(tp, &rtl_dp_ocp_read_cond, 10000, 10); ++ if (tp->dash_enabled) ++ rtl_loop_wait_high(tp, &rtl_dp_ocp_read_cond, 10000, 10); + } + + static void rtl8168ep_driver_start(struct rtl8169_private *tp) + { + r8168ep_ocp_write(tp, 0x01, 0x180, OOB_CMD_DRIVER_START); + r8168ep_ocp_write(tp, 0x01, 0x30, r8168ep_ocp_read(tp, 0x30) | 0x01); +- rtl_dash_loop_wait_high(tp, &rtl_ep_ocp_read_cond, 10000, 30); ++ if (tp->dash_enabled) ++ rtl_loop_wait_high(tp, &rtl_ep_ocp_read_cond, 10000, 30); + } + + static void rtl8168_driver_start(struct rtl8169_private *tp) +@@ -1395,7 +1374,8 @@ static void rtl8168_driver_start(struct rtl8169_private *tp) + static void rtl8168dp_driver_stop(struct rtl8169_private *tp) + { + r8168dp_oob_notify(tp, OOB_CMD_DRIVER_STOP); +- rtl_dash_loop_wait_low(tp, &rtl_dp_ocp_read_cond, 10000, 10); ++ if (tp->dash_enabled) ++ rtl_loop_wait_low(tp, &rtl_dp_ocp_read_cond, 10000, 10); + } + + static void rtl8168ep_driver_stop(struct rtl8169_private *tp) +@@ -1403,7 +1383,8 @@ static void rtl8168ep_driver_stop(struct rtl8169_private *tp) + rtl8168ep_stop_cmac(tp); + r8168ep_ocp_write(tp, 0x01, 0x180, OOB_CMD_DRIVER_STOP); + r8168ep_ocp_write(tp, 0x01, 0x30, r8168ep_ocp_read(tp, 0x30) | 0x01); +- rtl_dash_loop_wait_low(tp, &rtl_ep_ocp_read_cond, 10000, 10); ++ if (tp->dash_enabled) ++ rtl_loop_wait_low(tp, &rtl_ep_ocp_read_cond, 10000, 10); + } + + static void rtl8168_driver_stop(struct rtl8169_private *tp) +-- +2.51.0 + + +From 7f019b21702006b9e9dd50ad8c9e2107face00db Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Thu, 17 Oct 2024 22:27:44 +0200 +Subject: [PATCH 104/517] r8169: enable EEE at 2.5G per default on RTL8125B + +Register a6d/12 is shadowing register MDIO_AN_EEE_ADV2. So this line +disables advertisement of EEE at 2.5G. Latest vendor driver r8125 +doesn't do this (any longer?), so this mode seems to be safe. +EEE saves quite some energy, therefore enable this mode per default. + +Signed-off-by: Heiner Kallweit +Reviewed-by: Simon Horman +Message-ID: <95dd5a0c-09ea-4847-94d9-b7aa3063e8ff@gmail.com> +Signed-off-by: Andrew Lunn +--- + drivers/net/ethernet/realtek/r8169_phy_config.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/drivers/net/ethernet/realtek/r8169_phy_config.c b/drivers/net/ethernet/realtek/r8169_phy_config.c +index d09b2a41cd06..8739f4b42aaf 100644 +--- a/drivers/net/ethernet/realtek/r8169_phy_config.c ++++ b/drivers/net/ethernet/realtek/r8169_phy_config.c +@@ -99,7 +99,6 @@ static void rtl8125a_config_eee_phy(struct phy_device *phydev) + + static void rtl8125b_config_eee_phy(struct phy_device *phydev) + { +- phy_modify_paged(phydev, 0xa6d, 0x12, 0x0001, 0x0000); + phy_modify_paged(phydev, 0xa6d, 0x14, 0x0010, 0x0000); + phy_modify_paged(phydev, 0xa42, 0x14, 0x0080, 0x0000); + phy_modify_paged(phydev, 0xa4a, 0x11, 0x0200, 0x0000); +-- +2.51.0 + + +From 28b4af371b12a73bf9a0fef04753076b4d5446e1 Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Thu, 24 Oct 2024 22:48:59 +0200 +Subject: [PATCH 105/517] r8169: fix inconsistent indenting in + rtl8169_get_eth_mac_stats + +This fixes an inconsistent indenting introduced with e3fc5139bd8f +("r8169: implement additional ethtool stats ops"). + +Reported-by: kernel test robot +Closes: https://lore.kernel.org/oe-kbuild-all/202410220413.1gAxIJ4t-lkp@intel.com/ +Signed-off-by: Heiner Kallweit +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20fd6f39-3c1b-4af0-9adc-7d1f49728fad@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/realtek/r8169_main.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c +index d9682329f6e7..0091f1460036 100644 +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -2224,7 +2224,7 @@ static void rtl8169_get_eth_mac_stats(struct net_device *dev, + le64_to_cpu(tp->counters->tx_broadcast64); + mac_stats->MulticastFramesReceivedOK = + le64_to_cpu(tp->counters->rx_multicast64); +- mac_stats->FrameTooLongErrors = ++ mac_stats->FrameTooLongErrors = + le32_to_cpu(tp->counters->rx_frame_too_long); + } + +-- +2.51.0 + + +From c325ddc8e8248f828deef9638176039f3f83eae5 Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Thu, 31 Oct 2024 22:42:52 +0100 +Subject: [PATCH 106/517] r8169: align RTL8125 EEE config with vendor driver + +Align the EEE config for RTL8125A/RTL8125B with vendor driver r8125. +This should help to avoid compatibility issues. + +Signed-off-by: Heiner Kallweit +Link: https://patch.msgid.link/044c925e-8669-4b98-87df-95b4056f4f5f@gmail.com +Signed-off-by: Jakub Kicinski +--- + .../net/ethernet/realtek/r8169_phy_config.c | 18 ++++++++++++------ + 1 file changed, 12 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/ethernet/realtek/r8169_phy_config.c b/drivers/net/ethernet/realtek/r8169_phy_config.c +index 8739f4b42aaf..a0ecfa9c60ae 100644 +--- a/drivers/net/ethernet/realtek/r8169_phy_config.c ++++ b/drivers/net/ethernet/realtek/r8169_phy_config.c +@@ -89,19 +89,25 @@ static void rtl8168h_config_eee_phy(struct phy_device *phydev) + phy_modify_paged(phydev, 0xa42, 0x14, 0x0000, 0x0080); + } + +-static void rtl8125a_config_eee_phy(struct phy_device *phydev) ++static void rtl8125_common_config_eee_phy(struct phy_device *phydev) + { +- rtl8168h_config_eee_phy(phydev); ++ phy_modify_paged(phydev, 0xa6d, 0x14, 0x0010, 0x0000); ++ phy_modify_paged(phydev, 0xa42, 0x14, 0x0080, 0x0000); ++ phy_modify_paged(phydev, 0xa4a, 0x11, 0x0200, 0x0000); ++} + ++static void rtl8125a_config_eee_phy(struct phy_device *phydev) ++{ ++ rtl8168g_config_eee_phy(phydev); ++ /* disable EEE at 2.5Gbps */ + phy_modify_paged(phydev, 0xa6d, 0x12, 0x0001, 0x0000); +- phy_modify_paged(phydev, 0xa6d, 0x14, 0x0010, 0x0000); ++ rtl8125_common_config_eee_phy(phydev); + } + + static void rtl8125b_config_eee_phy(struct phy_device *phydev) + { +- phy_modify_paged(phydev, 0xa6d, 0x14, 0x0010, 0x0000); +- phy_modify_paged(phydev, 0xa42, 0x14, 0x0080, 0x0000); +- phy_modify_paged(phydev, 0xa4a, 0x11, 0x0200, 0x0000); ++ rtl8168g_config_eee_phy(phydev); ++ rtl8125_common_config_eee_phy(phydev); + } + + static void rtl8169s_hw_phy_config(struct rtl8169_private *tp, +-- +2.51.0 + + +From 0ec8e3bb0f649ceb7c034d76957b3e74999f95dd Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Thu, 31 Oct 2024 22:43:45 +0100 +Subject: [PATCH 107/517] r8169: align RTL8125/RTL8126 PHY config with vendor + driver + +This aligns some parameters with vendor driver r8125/r8126 to avoid +compatibility issues. Note that for RTL8125B there's no functional +change, just the open-coded version of the function is replaced. + +Signed-off-by: Heiner Kallweit +Link: https://patch.msgid.link/a8a9d896-fbe6-41f2-bf87-666567d3cdb3@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/realtek/r8169_phy_config.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/realtek/r8169_phy_config.c b/drivers/net/ethernet/realtek/r8169_phy_config.c +index a0ecfa9c60ae..54b254b9bf6c 100644 +--- a/drivers/net/ethernet/realtek/r8169_phy_config.c ++++ b/drivers/net/ethernet/realtek/r8169_phy_config.c +@@ -1073,8 +1073,8 @@ static void rtl8125b_hw_phy_config(struct rtl8169_private *tp, + struct phy_device *phydev) + { + r8169_apply_firmware(tp); ++ rtl8168g_enable_gphy_10m(phydev); + +- phy_modify_paged(phydev, 0xa44, 0x11, 0x0000, 0x0800); + phy_modify_paged(phydev, 0xac4, 0x13, 0x00f0, 0x0090); + phy_modify_paged(phydev, 0xad3, 0x10, 0x0003, 0x0001); + +@@ -1113,6 +1113,7 @@ static void rtl8125d_hw_phy_config(struct rtl8169_private *tp, + struct phy_device *phydev) + { + r8169_apply_firmware(tp); ++ rtl8168g_enable_gphy_10m(phydev); + rtl8125_legacy_force_mode(phydev); + rtl8168g_disable_aldps(phydev); + rtl8125b_config_eee_phy(phydev); +@@ -1122,6 +1123,9 @@ static void rtl8126a_hw_phy_config(struct rtl8169_private *tp, + struct phy_device *phydev) + { + r8169_apply_firmware(tp); ++ rtl8168g_enable_gphy_10m(phydev); ++ rtl8125_legacy_force_mode(phydev); ++ rtl8168g_disable_aldps(phydev); + } + + void r8169_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev, +-- +2.51.0 + + +From 390ace441dd012d005dddb5aed3bfb7e022f4c2a Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Thu, 31 Oct 2024 22:44:36 +0100 +Subject: [PATCH 108/517] r8169: align RTL8126 EEE config with vendor driver + +Align the EEE config for RTL8126A with vendor driver r8126 to avoid +compatibility issues. + +Signed-off-by: Heiner Kallweit +Link: https://patch.msgid.link/71e4859e-4cd0-4b6b-b7fa-621d7721992f@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/realtek/r8169_phy_config.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/ethernet/realtek/r8169_phy_config.c b/drivers/net/ethernet/realtek/r8169_phy_config.c +index 54b254b9bf6c..1d5b33f6c4b5 100644 +--- a/drivers/net/ethernet/realtek/r8169_phy_config.c ++++ b/drivers/net/ethernet/realtek/r8169_phy_config.c +@@ -1126,6 +1126,7 @@ static void rtl8126a_hw_phy_config(struct rtl8169_private *tp, + rtl8168g_enable_gphy_10m(phydev); + rtl8125_legacy_force_mode(phydev); + rtl8168g_disable_aldps(phydev); ++ rtl8125_common_config_eee_phy(phydev); + } + + void r8169_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev, +-- +2.51.0 + + +From b40777ebd76e985658185127b635c20e00c38199 Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Sat, 2 Nov 2024 14:49:01 +0100 +Subject: [PATCH 109/517] r8169: improve initialization of RSS registers on + RTL8125/RTL8126 + +Replace the register addresses with the names used in r8125/r8126 +vendor driver, and consider that RSS_CTRL_8125 is a 32 bit register. + +Signed-off-by: Heiner Kallweit +Link: https://patch.msgid.link/3bf2f340-b369-4174-97bf-fd38d4217492@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/realtek/r8169_main.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c +index 0091f1460036..ab8300984a2b 100644 +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -346,6 +346,8 @@ enum rtl8125_registers { + TxPoll_8125 = 0x90, + LEDSEL3 = 0x96, + MAC0_BKP = 0x19e0, ++ RSS_CTRL_8125 = 0x4500, ++ Q_NUM_CTRL_8125 = 0x4800, + EEE_TXIDLE_TIMER_8125 = 0x6048, + }; + +@@ -3791,8 +3793,8 @@ static void rtl_hw_start_8125_common(struct rtl8169_private *tp) + rtl_pcie_state_l2l3_disable(tp); + + RTL_W16(tp, 0x382, 0x221b); +- RTL_W8(tp, 0x4500, 0); +- RTL_W16(tp, 0x4800, 0); ++ RTL_W32(tp, RSS_CTRL_8125, 0); ++ RTL_W16(tp, Q_NUM_CTRL_8125, 0); + + /* disable UPS */ + r8168_mac_ocp_modify(tp, 0xd40a, 0x0010, 0x0000); +-- +2.51.0 + + +From aa67f9dc507adfc19a82b9392692926658de1590 Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Mon, 4 Nov 2024 23:16:20 +0100 +Subject: [PATCH 110/517] r8169: remove leftover locks after reverted change + +After e31a9fedc7d8 ("Revert "r8169: disable ASPM during NAPI poll"") +these locks aren't needed any longer. + +Signed-off-by: Heiner Kallweit +Link: https://patch.msgid.link/680f2606-ac7d-4ced-8694-e5033855da9b@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/realtek/r8169_main.c | 29 ++--------------------- + 1 file changed, 2 insertions(+), 27 deletions(-) + +diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c +index ab8300984a2b..5d708053c37c 100644 +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -661,13 +661,9 @@ struct rtl8169_private { + struct work_struct work; + } wk; + +- raw_spinlock_t config25_lock; + raw_spinlock_t mac_ocp_lock; + struct mutex led_lock; /* serialize LED ctrl RMW access */ + +- raw_spinlock_t cfg9346_usage_lock; +- int cfg9346_usage_count; +- + unsigned supports_gmii:1; + unsigned aspm_manageable:1; + unsigned dash_enabled:1; +@@ -721,22 +717,12 @@ static inline struct device *tp_to_dev(struct rtl8169_private *tp) + + static void rtl_lock_config_regs(struct rtl8169_private *tp) + { +- unsigned long flags; +- +- raw_spin_lock_irqsave(&tp->cfg9346_usage_lock, flags); +- if (!--tp->cfg9346_usage_count) +- RTL_W8(tp, Cfg9346, Cfg9346_Lock); +- raw_spin_unlock_irqrestore(&tp->cfg9346_usage_lock, flags); ++ RTL_W8(tp, Cfg9346, Cfg9346_Lock); + } + + static void rtl_unlock_config_regs(struct rtl8169_private *tp) + { +- unsigned long flags; +- +- raw_spin_lock_irqsave(&tp->cfg9346_usage_lock, flags); +- if (!tp->cfg9346_usage_count++) +- RTL_W8(tp, Cfg9346, Cfg9346_Unlock); +- raw_spin_unlock_irqrestore(&tp->cfg9346_usage_lock, flags); ++ RTL_W8(tp, Cfg9346, Cfg9346_Unlock); + } + + static void rtl_pci_commit(struct rtl8169_private *tp) +@@ -747,24 +733,18 @@ static void rtl_pci_commit(struct rtl8169_private *tp) + + static void rtl_mod_config2(struct rtl8169_private *tp, u8 clear, u8 set) + { +- unsigned long flags; + u8 val; + +- raw_spin_lock_irqsave(&tp->config25_lock, flags); + val = RTL_R8(tp, Config2); + RTL_W8(tp, Config2, (val & ~clear) | set); +- raw_spin_unlock_irqrestore(&tp->config25_lock, flags); + } + + static void rtl_mod_config5(struct rtl8169_private *tp, u8 clear, u8 set) + { +- unsigned long flags; + u8 val; + +- raw_spin_lock_irqsave(&tp->config25_lock, flags); + val = RTL_R8(tp, Config5); + RTL_W8(tp, Config5, (val & ~clear) | set); +- raw_spin_unlock_irqrestore(&tp->config25_lock, flags); + } + + static bool rtl_is_8125(struct rtl8169_private *tp) +@@ -1570,7 +1550,6 @@ static void __rtl8169_set_wol(struct rtl8169_private *tp, u32 wolopts) + { WAKE_MAGIC, Config3, MagicPacket } + }; + unsigned int i, tmp = ARRAY_SIZE(cfg); +- unsigned long flags; + u8 options; + + rtl_unlock_config_regs(tp); +@@ -1589,14 +1568,12 @@ static void __rtl8169_set_wol(struct rtl8169_private *tp, u32 wolopts) + r8168_mac_ocp_modify(tp, 0xc0b6, BIT(0), 0); + } + +- raw_spin_lock_irqsave(&tp->config25_lock, flags); + for (i = 0; i < tmp; i++) { + options = RTL_R8(tp, cfg[i].reg) & ~cfg[i].mask; + if (wolopts & cfg[i].opt) + options |= cfg[i].mask; + RTL_W8(tp, cfg[i].reg, options); + } +- raw_spin_unlock_irqrestore(&tp->config25_lock, flags); + + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_02 ... RTL_GIGA_MAC_VER_06: +@@ -5480,8 +5457,6 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) + tp->supports_gmii = ent->driver_data == RTL_CFG_NO_GBIT ? 0 : 1; + tp->ocp_base = OCP_STD_PHY_BASE; + +- raw_spin_lock_init(&tp->cfg9346_usage_lock); +- raw_spin_lock_init(&tp->config25_lock); + raw_spin_lock_init(&tp->mac_ocp_lock); + mutex_init(&tp->led_lock); + +-- +2.51.0 + + +From 70713cb39f81777f2e78d556869f76dbc9ec6879 Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Wed, 6 Nov 2024 17:55:45 +0100 +Subject: [PATCH 111/517] r8169: improve __rtl8169_set_wol + +Add helper r8169_mod_reg8_cond() what allows to significantly simplify +__rtl8169_set_wol(). + +Signed-off-by: Heiner Kallweit +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/697b197a-8eac-40c6-8847-27093cacec36@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/realtek/r8169_main.c | 55 ++++++++++------------- + 1 file changed, 24 insertions(+), 31 deletions(-) + +diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c +index 5d708053c37c..bb5784654cec 100644 +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -747,6 +747,20 @@ static void rtl_mod_config5(struct rtl8169_private *tp, u8 clear, u8 set) + RTL_W8(tp, Config5, (val & ~clear) | set); + } + ++static void r8169_mod_reg8_cond(struct rtl8169_private *tp, int reg, ++ u8 bits, bool cond) ++{ ++ u8 val, old_val; ++ ++ old_val = RTL_R8(tp, reg); ++ if (cond) ++ val = old_val | bits; ++ else ++ val = old_val & ~bits; ++ if (val != old_val) ++ RTL_W8(tp, reg, val); ++} ++ + static bool rtl_is_8125(struct rtl8169_private *tp) + { + return tp->mac_version >= RTL_GIGA_MAC_VER_61; +@@ -1537,58 +1551,37 @@ static void rtl8169_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) + + static void __rtl8169_set_wol(struct rtl8169_private *tp, u32 wolopts) + { +- static const struct { +- u32 opt; +- u16 reg; +- u8 mask; +- } cfg[] = { +- { WAKE_PHY, Config3, LinkUp }, +- { WAKE_UCAST, Config5, UWF }, +- { WAKE_BCAST, Config5, BWF }, +- { WAKE_MCAST, Config5, MWF }, +- { WAKE_ANY, Config5, LanWake }, +- { WAKE_MAGIC, Config3, MagicPacket } +- }; +- unsigned int i, tmp = ARRAY_SIZE(cfg); +- u8 options; +- + rtl_unlock_config_regs(tp); + + if (rtl_is_8168evl_up(tp)) { +- tmp--; + if (wolopts & WAKE_MAGIC) + rtl_eri_set_bits(tp, 0x0dc, MagicPacket_v2); + else + rtl_eri_clear_bits(tp, 0x0dc, MagicPacket_v2); + } else if (rtl_is_8125(tp)) { +- tmp--; + if (wolopts & WAKE_MAGIC) + r8168_mac_ocp_modify(tp, 0xc0b6, 0, BIT(0)); + else + r8168_mac_ocp_modify(tp, 0xc0b6, BIT(0), 0); ++ } else { ++ r8169_mod_reg8_cond(tp, Config3, MagicPacket, ++ wolopts & WAKE_MAGIC); + } + +- for (i = 0; i < tmp; i++) { +- options = RTL_R8(tp, cfg[i].reg) & ~cfg[i].mask; +- if (wolopts & cfg[i].opt) +- options |= cfg[i].mask; +- RTL_W8(tp, cfg[i].reg, options); +- } ++ r8169_mod_reg8_cond(tp, Config3, LinkUp, wolopts & WAKE_PHY); ++ r8169_mod_reg8_cond(tp, Config5, UWF, wolopts & WAKE_UCAST); ++ r8169_mod_reg8_cond(tp, Config5, BWF, wolopts & WAKE_BCAST); ++ r8169_mod_reg8_cond(tp, Config5, MWF, wolopts & WAKE_MCAST); ++ r8169_mod_reg8_cond(tp, Config5, LanWake, wolopts); + + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_02 ... RTL_GIGA_MAC_VER_06: +- options = RTL_R8(tp, Config1) & ~PMEnable; +- if (wolopts) +- options |= PMEnable; +- RTL_W8(tp, Config1, options); ++ r8169_mod_reg8_cond(tp, Config1, PMEnable, wolopts); + break; + case RTL_GIGA_MAC_VER_34: + case RTL_GIGA_MAC_VER_37: + case RTL_GIGA_MAC_VER_39 ... RTL_GIGA_MAC_VER_66: +- if (wolopts) +- rtl_mod_config2(tp, 0, PME_SIGNAL); +- else +- rtl_mod_config2(tp, PME_SIGNAL, 0); ++ r8169_mod_reg8_cond(tp, Config2, PME_SIGNAL, wolopts); + break; + default: + break; +-- +2.51.0 + + +From d3852405b70dcc37cc63b0f66bf77a7fbf825e8f Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Wed, 6 Nov 2024 17:56:28 +0100 +Subject: [PATCH 112/517] r8169: improve rtl_set_d3_pll_down + +Make use of new helper r8169_mod_reg8_cond() and move from a switch() +to an if() clause. Benefit is that we don't have to touch this piece of +code each time support for a new chip version is added. + +Signed-off-by: Heiner Kallweit +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/e1ccdb85-a4ed-4800-89c2-89770ff06452@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/realtek/r8169_main.c | 18 +++++------------- + 1 file changed, 5 insertions(+), 13 deletions(-) + +diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c +index bb5784654cec..e963e4f9fff7 100644 +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -1430,19 +1430,11 @@ static enum rtl_dash_type rtl_get_dash_type(struct rtl8169_private *tp) + + static void rtl_set_d3_pll_down(struct rtl8169_private *tp, bool enable) + { +- switch (tp->mac_version) { +- case RTL_GIGA_MAC_VER_25 ... RTL_GIGA_MAC_VER_26: +- case RTL_GIGA_MAC_VER_29 ... RTL_GIGA_MAC_VER_30: +- case RTL_GIGA_MAC_VER_32 ... RTL_GIGA_MAC_VER_37: +- case RTL_GIGA_MAC_VER_39 ... RTL_GIGA_MAC_VER_66: +- if (enable) +- RTL_W8(tp, PMCH, RTL_R8(tp, PMCH) & ~D3_NO_PLL_DOWN); +- else +- RTL_W8(tp, PMCH, RTL_R8(tp, PMCH) | D3_NO_PLL_DOWN); +- break; +- default: +- break; +- } ++ if (tp->mac_version >= RTL_GIGA_MAC_VER_25 && ++ tp->mac_version != RTL_GIGA_MAC_VER_28 && ++ tp->mac_version != RTL_GIGA_MAC_VER_31 && ++ tp->mac_version != RTL_GIGA_MAC_VER_38) ++ r8169_mod_reg8_cond(tp, PMCH, D3_NO_PLL_DOWN, !enable); + } + + static void rtl_reset_packet_filter(struct rtl8169_private *tp) +-- +2.51.0 + + +From 45dd32ce075f308916c99e45bb6b5e140e299dbd Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Wed, 6 Nov 2024 17:57:08 +0100 +Subject: [PATCH 113/517] r8169: align WAKE_PHY handling with r8125/r8126 + vendor drivers + +Vendor drivers r8125/r8126 apply this additional magic setting when +enabling WAKE_PHY, so do the same here. + +Signed-off-by: Heiner Kallweit +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/51130715-45be-4db5-abb7-05d87e1f5df9@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/realtek/r8169_main.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c +index e963e4f9fff7..bd42f548fbda 100644 +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -1561,6 +1561,9 @@ static void __rtl8169_set_wol(struct rtl8169_private *tp, u32 wolopts) + } + + r8169_mod_reg8_cond(tp, Config3, LinkUp, wolopts & WAKE_PHY); ++ if (rtl_is_8125(tp)) ++ r8168_mac_ocp_modify(tp, 0xe0c6, 0x3f, ++ wolopts & WAKE_PHY ? 0x13 : 0); + r8169_mod_reg8_cond(tp, Config5, UWF, wolopts & WAKE_UCAST); + r8169_mod_reg8_cond(tp, Config5, BWF, wolopts & WAKE_BCAST); + r8169_mod_reg8_cond(tp, Config5, MWF, wolopts & WAKE_MCAST); +-- +2.51.0 + + +From 5d248ce8f3584802bfc97c437bff82778b2517a3 Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Sat, 9 Nov 2024 23:12:12 +0100 +Subject: [PATCH 114/517] r8169: use helper r8169_mod_reg8_cond to simplify + rtl_jumbo_config + +Use recently added helper r8169_mod_reg8_cond() to simplify jumbo +mode configuration. + +Signed-off-by: Heiner Kallweit +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/3df1d484-a02e-46e7-8f75-db5b428e422e@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/realtek/r8169_main.c | 77 ++++------------------- + 1 file changed, 11 insertions(+), 66 deletions(-) + +diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c +index bd42f548fbda..aafe113d3bed 100644 +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -2542,86 +2542,31 @@ static void rtl8169_init_ring_indexes(struct rtl8169_private *tp) + tp->dirty_tx = tp->cur_tx = tp->cur_rx = 0; + } + +-static void r8168c_hw_jumbo_enable(struct rtl8169_private *tp) +-{ +- RTL_W8(tp, Config3, RTL_R8(tp, Config3) | Jumbo_En0); +- RTL_W8(tp, Config4, RTL_R8(tp, Config4) | Jumbo_En1); +-} +- +-static void r8168c_hw_jumbo_disable(struct rtl8169_private *tp) +-{ +- RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Jumbo_En0); +- RTL_W8(tp, Config4, RTL_R8(tp, Config4) & ~Jumbo_En1); +-} +- +-static void r8168dp_hw_jumbo_enable(struct rtl8169_private *tp) +-{ +- RTL_W8(tp, Config3, RTL_R8(tp, Config3) | Jumbo_En0); +-} +- +-static void r8168dp_hw_jumbo_disable(struct rtl8169_private *tp) +-{ +- RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Jumbo_En0); +-} +- +-static void r8168e_hw_jumbo_enable(struct rtl8169_private *tp) +-{ +- RTL_W8(tp, MaxTxPacketSize, 0x24); +- RTL_W8(tp, Config3, RTL_R8(tp, Config3) | Jumbo_En0); +- RTL_W8(tp, Config4, RTL_R8(tp, Config4) | 0x01); +-} +- +-static void r8168e_hw_jumbo_disable(struct rtl8169_private *tp) +-{ +- RTL_W8(tp, MaxTxPacketSize, 0x3f); +- RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Jumbo_En0); +- RTL_W8(tp, Config4, RTL_R8(tp, Config4) & ~0x01); +-} +- +-static void r8168b_1_hw_jumbo_enable(struct rtl8169_private *tp) +-{ +- RTL_W8(tp, Config4, RTL_R8(tp, Config4) | (1 << 0)); +-} +- +-static void r8168b_1_hw_jumbo_disable(struct rtl8169_private *tp) +-{ +- RTL_W8(tp, Config4, RTL_R8(tp, Config4) & ~(1 << 0)); +-} +- + static void rtl_jumbo_config(struct rtl8169_private *tp) + { + bool jumbo = tp->dev->mtu > ETH_DATA_LEN; + int readrq = 4096; + ++ if (jumbo && tp->mac_version >= RTL_GIGA_MAC_VER_17 && ++ tp->mac_version <= RTL_GIGA_MAC_VER_26) ++ readrq = 512; ++ + rtl_unlock_config_regs(tp); + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_17: +- if (jumbo) { +- readrq = 512; +- r8168b_1_hw_jumbo_enable(tp); +- } else { +- r8168b_1_hw_jumbo_disable(tp); +- } ++ r8169_mod_reg8_cond(tp, Config4, BIT(0), jumbo); + break; + case RTL_GIGA_MAC_VER_18 ... RTL_GIGA_MAC_VER_26: +- if (jumbo) { +- readrq = 512; +- r8168c_hw_jumbo_enable(tp); +- } else { +- r8168c_hw_jumbo_disable(tp); +- } ++ r8169_mod_reg8_cond(tp, Config3, Jumbo_En0, jumbo); ++ r8169_mod_reg8_cond(tp, Config4, Jumbo_En1, jumbo); + break; + case RTL_GIGA_MAC_VER_28: +- if (jumbo) +- r8168dp_hw_jumbo_enable(tp); +- else +- r8168dp_hw_jumbo_disable(tp); ++ r8169_mod_reg8_cond(tp, Config3, Jumbo_En0, jumbo); + break; + case RTL_GIGA_MAC_VER_31 ... RTL_GIGA_MAC_VER_33: +- if (jumbo) +- r8168e_hw_jumbo_enable(tp); +- else +- r8168e_hw_jumbo_disable(tp); ++ RTL_W8(tp, MaxTxPacketSize, jumbo ? 0x24 : 0x3f); ++ r8169_mod_reg8_cond(tp, Config3, Jumbo_En0, jumbo); ++ r8169_mod_reg8_cond(tp, Config4, BIT(0), jumbo); + break; + default: + break; +-- +2.51.0 + + +From 5c600144ed1b77cb7771b5d1e43098850d6d01fe Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Fri, 8 Nov 2024 08:08:24 +0100 +Subject: [PATCH 115/517] r8169: copy vendor driver 2.5G/5G EEE advertisement + constraints + +Vendor driver r8125 doesn't advertise 2.5G EEE on RTL8125A, and r8126 +doesn't advertise 5G EEE. Likely there are compatibility issues, +therefore do the same in r8169. +With this change we don't have to disable 2.5G EEE advertisement in +rtl8125a_config_eee_phy() any longer. +We use new phylib accessor phy_set_eee_broken() to mark the respective +EEE modes as broken. + +Signed-off-by: Heiner Kallweit +Link: https://patch.msgid.link/ce185e10-8a2f-4cf8-a49b-fd8fb3c3c8a1@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/realtek/r8169_main.c | 5 +++++ + drivers/net/ethernet/realtek/r8169_phy_config.c | 16 ++++------------ + 2 files changed, 9 insertions(+), 12 deletions(-) + +diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c +index aafe113d3bed..1f519eecc1f7 100644 +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -5256,6 +5256,11 @@ static int r8169_mdio_register(struct rtl8169_private *tp) + phy_support_eee(tp->phydev); + phy_support_asym_pause(tp->phydev); + ++ /* mimic behavior of r8125/r8126 vendor drivers */ ++ if (tp->mac_version == RTL_GIGA_MAC_VER_61) ++ tp->phydev->eee_broken_modes |= MDIO_EEE_2_5GT; ++ tp->phydev->eee_broken_modes |= MDIO_EEE_5GT; ++ + /* PHY will be woken up in rtl_open() */ + phy_suspend(tp->phydev); + +diff --git a/drivers/net/ethernet/realtek/r8169_phy_config.c b/drivers/net/ethernet/realtek/r8169_phy_config.c +index 1d5b33f6c4b5..5307c6ff4e25 100644 +--- a/drivers/net/ethernet/realtek/r8169_phy_config.c ++++ b/drivers/net/ethernet/realtek/r8169_phy_config.c +@@ -96,15 +96,7 @@ static void rtl8125_common_config_eee_phy(struct phy_device *phydev) + phy_modify_paged(phydev, 0xa4a, 0x11, 0x0200, 0x0000); + } + +-static void rtl8125a_config_eee_phy(struct phy_device *phydev) +-{ +- rtl8168g_config_eee_phy(phydev); +- /* disable EEE at 2.5Gbps */ +- phy_modify_paged(phydev, 0xa6d, 0x12, 0x0001, 0x0000); +- rtl8125_common_config_eee_phy(phydev); +-} +- +-static void rtl8125b_config_eee_phy(struct phy_device *phydev) ++static void rtl8125_config_eee_phy(struct phy_device *phydev) + { + rtl8168g_config_eee_phy(phydev); + rtl8125_common_config_eee_phy(phydev); +@@ -1066,7 +1058,7 @@ static void rtl8125a_2_hw_phy_config(struct rtl8169_private *tp, + rtl8168g_enable_gphy_10m(phydev); + + rtl8168g_disable_aldps(phydev); +- rtl8125a_config_eee_phy(phydev); ++ rtl8125_config_eee_phy(phydev); + } + + static void rtl8125b_hw_phy_config(struct rtl8169_private *tp, +@@ -1106,7 +1098,7 @@ static void rtl8125b_hw_phy_config(struct rtl8169_private *tp, + + rtl8125_legacy_force_mode(phydev); + rtl8168g_disable_aldps(phydev); +- rtl8125b_config_eee_phy(phydev); ++ rtl8125_config_eee_phy(phydev); + } + + static void rtl8125d_hw_phy_config(struct rtl8169_private *tp, +@@ -1116,7 +1108,7 @@ static void rtl8125d_hw_phy_config(struct rtl8169_private *tp, + rtl8168g_enable_gphy_10m(phydev); + rtl8125_legacy_force_mode(phydev); + rtl8168g_disable_aldps(phydev); +- rtl8125b_config_eee_phy(phydev); ++ rtl8125_config_eee_phy(phydev); + } + + static void rtl8126a_hw_phy_config(struct rtl8169_private *tp, +-- +2.51.0 + + +From a924fb5a747c493e99bae0ce528f55ae30a93a8e Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Mon, 2 Dec 2024 21:14:35 +0100 +Subject: [PATCH 116/517] r8169: remove unused flag + RTL_FLAG_TASK_RESET_NO_QUEUE_WAKE + +After 854d71c555dfc3 ("r8169: remove original workaround for RTL8125 +broken rx issue") this flag isn't used any longer. So remove it. + +Signed-off-by: Heiner Kallweit +Reviewed-by: Michal Swiatkowski +Link: https://patch.msgid.link/d9dd214b-3027-4f60-b0e8-6f34a0c76582@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/realtek/r8169_main.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c +index 1f519eecc1f7..4ec51251615b 100644 +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -622,7 +622,6 @@ struct rtl8169_tc_offsets { + + enum rtl_flag { + RTL_FLAG_TASK_RESET_PENDING, +- RTL_FLAG_TASK_RESET_NO_QUEUE_WAKE, + RTL_FLAG_TASK_TX_TIMEOUT, + RTL_FLAG_MAX + }; +@@ -4749,8 +4748,6 @@ static void rtl_task(struct work_struct *work) + reset: + rtl_reset_work(tp); + netif_wake_queue(tp->dev); +- } else if (test_and_clear_bit(RTL_FLAG_TASK_RESET_NO_QUEUE_WAKE, tp->wk.flags)) { +- rtl_reset_work(tp); + } + } + +-- +2.51.0 + + +From 31e5c12785164a84028c96e7cc39f3cb6e81c27e Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Mon, 2 Dec 2024 21:20:02 +0100 +Subject: [PATCH 117/517] r8169: remove support for chip version 11 + +This is a follow-up to 982300c115d2 ("r8169: remove detection of chip +version 11 (early RTL8168b)"). Nobody complained yet, so remove +support for this chip version. + +Signed-off-by: Heiner Kallweit +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/b689ab6d-20b5-4b64-bd7e-531a0a972ba3@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/realtek/r8169.h | 2 +- + drivers/net/ethernet/realtek/r8169_main.c | 14 +------------- + drivers/net/ethernet/realtek/r8169_phy_config.c | 10 ---------- + 3 files changed, 2 insertions(+), 24 deletions(-) + +diff --git a/drivers/net/ethernet/realtek/r8169.h b/drivers/net/ethernet/realtek/r8169.h +index be4c9622618d..8904aae41aca 100644 +--- a/drivers/net/ethernet/realtek/r8169.h ++++ b/drivers/net/ethernet/realtek/r8169.h +@@ -23,7 +23,7 @@ enum mac_version { + RTL_GIGA_MAC_VER_08, + RTL_GIGA_MAC_VER_09, + RTL_GIGA_MAC_VER_10, +- RTL_GIGA_MAC_VER_11, ++ /* support for RTL_GIGA_MAC_VER_11 has been removed */ + /* RTL_GIGA_MAC_VER_12 was handled the same as VER_17 */ + /* RTL_GIGA_MAC_VER_13 was merged with VER_10 */ + RTL_GIGA_MAC_VER_14, +diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c +index 4ec51251615b..e435f17fa722 100644 +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -103,7 +103,6 @@ static const struct { + [RTL_GIGA_MAC_VER_08] = {"RTL8102e" }, + [RTL_GIGA_MAC_VER_09] = {"RTL8102e/RTL8103e" }, + [RTL_GIGA_MAC_VER_10] = {"RTL8101e/RTL8100e" }, +- [RTL_GIGA_MAC_VER_11] = {"RTL8168b/8111b" }, + [RTL_GIGA_MAC_VER_14] = {"RTL8401" }, + [RTL_GIGA_MAC_VER_17] = {"RTL8168b/8111b" }, + [RTL_GIGA_MAC_VER_18] = {"RTL8168cp/8111cp" }, +@@ -2334,7 +2333,7 @@ static enum mac_version rtl8169_get_mac_version(u16 xid, bool gmii) + + /* 8168B family. */ + { 0x7c8, 0x380, RTL_GIGA_MAC_VER_17 }, +- /* This one is very old and rare, let's see if anybody complains. ++ /* This one is very old and rare, support has been removed. + * { 0x7c8, 0x300, RTL_GIGA_MAC_VER_11 }, + */ + +@@ -3829,7 +3828,6 @@ static void rtl_hw_config(struct rtl8169_private *tp) + [RTL_GIGA_MAC_VER_08] = rtl_hw_start_8102e_3, + [RTL_GIGA_MAC_VER_09] = rtl_hw_start_8102e_2, + [RTL_GIGA_MAC_VER_10] = NULL, +- [RTL_GIGA_MAC_VER_11] = rtl_hw_start_8168b, + [RTL_GIGA_MAC_VER_14] = rtl_hw_start_8401, + [RTL_GIGA_MAC_VER_17] = rtl_hw_start_8168b, + [RTL_GIGA_MAC_VER_18] = rtl_hw_start_8168cp_1, +@@ -4705,12 +4703,6 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance) + if (status & LinkChg) + phy_mac_interrupt(tp->phydev); + +- if (unlikely(status & RxFIFOOver && +- tp->mac_version == RTL_GIGA_MAC_VER_11)) { +- netif_stop_queue(tp->dev); +- rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_PENDING); +- } +- + rtl_irq_disable(tp); + napi_schedule(&tp->napi); + out: +@@ -5127,9 +5119,6 @@ static void rtl_set_irq_mask(struct rtl8169_private *tp) + + if (tp->mac_version <= RTL_GIGA_MAC_VER_06) + tp->irq_mask |= SYSErr | RxFIFOOver; +- else if (tp->mac_version == RTL_GIGA_MAC_VER_11) +- /* special workaround needed */ +- tp->irq_mask |= RxFIFOOver; + } + + static int rtl_alloc_irq(struct rtl8169_private *tp) +@@ -5324,7 +5313,6 @@ static int rtl_jumbo_max(struct rtl8169_private *tp) + case RTL_GIGA_MAC_VER_02 ... RTL_GIGA_MAC_VER_06: + return JUMBO_7K; + /* RTL8168b */ +- case RTL_GIGA_MAC_VER_11: + case RTL_GIGA_MAC_VER_17: + return JUMBO_4K; + /* RTL8168c */ +diff --git a/drivers/net/ethernet/realtek/r8169_phy_config.c b/drivers/net/ethernet/realtek/r8169_phy_config.c +index 5307c6ff4e25..b28b30390e84 100644 +--- a/drivers/net/ethernet/realtek/r8169_phy_config.c ++++ b/drivers/net/ethernet/realtek/r8169_phy_config.c +@@ -276,15 +276,6 @@ static void rtl8169sce_hw_phy_config(struct rtl8169_private *tp, + rtl_writephy_batch(phydev, phy_reg_init); + } + +-static void rtl8168bb_hw_phy_config(struct rtl8169_private *tp, +- struct phy_device *phydev) +-{ +- phy_write(phydev, 0x1f, 0x0001); +- phy_set_bits(phydev, 0x16, BIT(0)); +- phy_write(phydev, 0x10, 0xf41b); +- phy_write(phydev, 0x1f, 0x0000); +-} +- + static void rtl8168bef_hw_phy_config(struct rtl8169_private *tp, + struct phy_device *phydev) + { +@@ -1136,7 +1127,6 @@ void r8169_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev, + [RTL_GIGA_MAC_VER_08] = rtl8102e_hw_phy_config, + [RTL_GIGA_MAC_VER_09] = rtl8102e_hw_phy_config, + [RTL_GIGA_MAC_VER_10] = NULL, +- [RTL_GIGA_MAC_VER_11] = rtl8168bb_hw_phy_config, + [RTL_GIGA_MAC_VER_14] = rtl8401_hw_phy_config, + [RTL_GIGA_MAC_VER_17] = rtl8168bef_hw_phy_config, + [RTL_GIGA_MAC_VER_18] = rtl8168cp_1_hw_phy_config, +-- +2.51.0 + + +From 29bfd059af1164901861876a59ff00abe5571d04 Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Fri, 13 Dec 2024 20:01:41 +0100 +Subject: [PATCH 118/517] r8169: adjust version numbering for RTL8126 + +Adjust version numbering for RTL8126, so that it doesn't overlap with +new RTL8125 versions. + +Signed-off-by: Heiner Kallweit +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/6a354364-20e9-48ad-a198-468264288757@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/realtek/r8169.h | 4 +- + drivers/net/ethernet/realtek/r8169_main.c | 62 +++++++++---------- + .../net/ethernet/realtek/r8169_phy_config.c | 4 +- + 3 files changed, 35 insertions(+), 35 deletions(-) + +diff --git a/drivers/net/ethernet/realtek/r8169.h b/drivers/net/ethernet/realtek/r8169.h +index 8904aae41aca..00d74e76c6f2 100644 +--- a/drivers/net/ethernet/realtek/r8169.h ++++ b/drivers/net/ethernet/realtek/r8169.h +@@ -69,8 +69,8 @@ enum mac_version { + RTL_GIGA_MAC_VER_61, + RTL_GIGA_MAC_VER_63, + RTL_GIGA_MAC_VER_64, +- RTL_GIGA_MAC_VER_65, +- RTL_GIGA_MAC_VER_66, ++ RTL_GIGA_MAC_VER_70, ++ RTL_GIGA_MAC_VER_71, + RTL_GIGA_MAC_NONE + }; + +diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c +index e435f17fa722..f0d6261f92bb 100644 +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -139,8 +139,8 @@ static const struct { + /* reserve 62 for CFG_METHOD_4 in the vendor driver */ + [RTL_GIGA_MAC_VER_63] = {"RTL8125B", FIRMWARE_8125B_2}, + [RTL_GIGA_MAC_VER_64] = {"RTL8125D", FIRMWARE_8125D_1}, +- [RTL_GIGA_MAC_VER_65] = {"RTL8126A", FIRMWARE_8126A_2}, +- [RTL_GIGA_MAC_VER_66] = {"RTL8126A", FIRMWARE_8126A_3}, ++ [RTL_GIGA_MAC_VER_70] = {"RTL8126A", FIRMWARE_8126A_2}, ++ [RTL_GIGA_MAC_VER_71] = {"RTL8126A", FIRMWARE_8126A_3}, + }; + + static const struct pci_device_id rtl8169_pci_tbl[] = { +@@ -1227,7 +1227,7 @@ static void rtl_writephy(struct rtl8169_private *tp, int location, int val) + case RTL_GIGA_MAC_VER_31: + r8168dp_2_mdio_write(tp, location, val); + break; +- case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_66: ++ case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_71: + r8168g_mdio_write(tp, location, val); + break; + default: +@@ -1242,7 +1242,7 @@ static int rtl_readphy(struct rtl8169_private *tp, int location) + case RTL_GIGA_MAC_VER_28: + case RTL_GIGA_MAC_VER_31: + return r8168dp_2_mdio_read(tp, location); +- case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_66: ++ case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_71: + return r8168g_mdio_read(tp, location); + default: + return r8169_mdio_read(tp, location); +@@ -1573,7 +1573,7 @@ static void __rtl8169_set_wol(struct rtl8169_private *tp, u32 wolopts) + break; + case RTL_GIGA_MAC_VER_34: + case RTL_GIGA_MAC_VER_37: +- case RTL_GIGA_MAC_VER_39 ... RTL_GIGA_MAC_VER_66: ++ case RTL_GIGA_MAC_VER_39 ... RTL_GIGA_MAC_VER_71: + r8169_mod_reg8_cond(tp, Config2, PME_SIGNAL, wolopts); + break; + default: +@@ -2046,7 +2046,7 @@ static void rtl_set_eee_txidle_timer(struct rtl8169_private *tp) + tp->tx_lpi_timer = timer_val; + r8168_mac_ocp_write(tp, 0xe048, timer_val); + break; +- case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_66: ++ case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_71: + tp->tx_lpi_timer = timer_val; + RTL_W16(tp, EEE_TXIDLE_TIMER_8125, timer_val); + break; +@@ -2254,8 +2254,8 @@ static enum mac_version rtl8169_get_mac_version(u16 xid, bool gmii) + enum mac_version ver; + } mac_info[] = { + /* 8126A family. */ +- { 0x7cf, 0x64a, RTL_GIGA_MAC_VER_66 }, +- { 0x7cf, 0x649, RTL_GIGA_MAC_VER_65 }, ++ { 0x7cf, 0x64a, RTL_GIGA_MAC_VER_71 }, ++ { 0x7cf, 0x649, RTL_GIGA_MAC_VER_70 }, + + /* 8125D family. */ + { 0x7cf, 0x688, RTL_GIGA_MAC_VER_64 }, +@@ -2525,7 +2525,7 @@ static void rtl_init_rxcfg(struct rtl8169_private *tp) + case RTL_GIGA_MAC_VER_61: + RTL_W32(tp, RxConfig, RX_FETCH_DFLT_8125 | RX_DMA_BURST); + break; +- case RTL_GIGA_MAC_VER_63 ... RTL_GIGA_MAC_VER_66: ++ case RTL_GIGA_MAC_VER_63 ... RTL_GIGA_MAC_VER_71: + RTL_W32(tp, RxConfig, RX_FETCH_DFLT_8125 | RX_DMA_BURST | + RX_PAUSE_SLOT_ON); + break; +@@ -2657,7 +2657,7 @@ static void rtl_wait_txrx_fifo_empty(struct rtl8169_private *tp) + case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_61: + rtl_loop_wait_high(tp, &rtl_rxtx_empty_cond, 100, 42); + break; +- case RTL_GIGA_MAC_VER_63 ... RTL_GIGA_MAC_VER_66: ++ case RTL_GIGA_MAC_VER_63 ... RTL_GIGA_MAC_VER_71: + RTL_W8(tp, ChipCmd, RTL_R8(tp, ChipCmd) | StopReq); + rtl_loop_wait_high(tp, &rtl_rxtx_empty_cond, 100, 42); + rtl_loop_wait_high(tp, &rtl_rxtx_empty_cond_2, 100, 42); +@@ -2926,7 +2926,7 @@ static void rtl_enable_exit_l1(struct rtl8169_private *tp) + case RTL_GIGA_MAC_VER_37 ... RTL_GIGA_MAC_VER_38: + rtl_eri_set_bits(tp, 0xd4, 0x0c00); + break; +- case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_66: ++ case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_71: + r8168_mac_ocp_modify(tp, 0xc0ac, 0, 0x1f80); + break; + default: +@@ -2940,7 +2940,7 @@ static void rtl_disable_exit_l1(struct rtl8169_private *tp) + case RTL_GIGA_MAC_VER_34 ... RTL_GIGA_MAC_VER_38: + rtl_eri_clear_bits(tp, 0xd4, 0x1f00); + break; +- case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_66: ++ case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_71: + r8168_mac_ocp_modify(tp, 0xc0ac, 0x1f80, 0); + break; + default: +@@ -2966,8 +2966,8 @@ static void rtl_hw_aspm_clkreq_enable(struct rtl8169_private *tp, bool enable) + + rtl_mod_config5(tp, 0, ASPM_en); + switch (tp->mac_version) { +- case RTL_GIGA_MAC_VER_65: +- case RTL_GIGA_MAC_VER_66: ++ case RTL_GIGA_MAC_VER_70: ++ case RTL_GIGA_MAC_VER_71: + val8 = RTL_R8(tp, INT_CFG0_8125) | INT_CFG0_CLKREQEN; + RTL_W8(tp, INT_CFG0_8125, val8); + break; +@@ -2978,7 +2978,7 @@ static void rtl_hw_aspm_clkreq_enable(struct rtl8169_private *tp, bool enable) + + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_46 ... RTL_GIGA_MAC_VER_48: +- case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_66: ++ case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_71: + /* reset ephy tx/rx disable timer */ + r8168_mac_ocp_modify(tp, 0xe094, 0xff00, 0); + /* chip can trigger L1.2 */ +@@ -2990,7 +2990,7 @@ static void rtl_hw_aspm_clkreq_enable(struct rtl8169_private *tp, bool enable) + } else { + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_46 ... RTL_GIGA_MAC_VER_48: +- case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_66: ++ case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_71: + r8168_mac_ocp_modify(tp, 0xe092, 0x00ff, 0); + break; + default: +@@ -2998,8 +2998,8 @@ static void rtl_hw_aspm_clkreq_enable(struct rtl8169_private *tp, bool enable) + } + + switch (tp->mac_version) { +- case RTL_GIGA_MAC_VER_65: +- case RTL_GIGA_MAC_VER_66: ++ case RTL_GIGA_MAC_VER_70: ++ case RTL_GIGA_MAC_VER_71: + val8 = RTL_R8(tp, INT_CFG0_8125) & ~INT_CFG0_CLKREQEN; + RTL_W8(tp, INT_CFG0_8125, val8); + break; +@@ -3719,12 +3719,12 @@ static void rtl_hw_start_8125_common(struct rtl8169_private *tp) + /* disable new tx descriptor format */ + r8168_mac_ocp_modify(tp, 0xeb58, 0x0001, 0x0000); + +- if (tp->mac_version == RTL_GIGA_MAC_VER_65 || +- tp->mac_version == RTL_GIGA_MAC_VER_66) ++ if (tp->mac_version == RTL_GIGA_MAC_VER_70 || ++ tp->mac_version == RTL_GIGA_MAC_VER_71) + RTL_W8(tp, 0xD8, RTL_R8(tp, 0xD8) & ~0x02); + +- if (tp->mac_version == RTL_GIGA_MAC_VER_65 || +- tp->mac_version == RTL_GIGA_MAC_VER_66) ++ if (tp->mac_version == RTL_GIGA_MAC_VER_70 || ++ tp->mac_version == RTL_GIGA_MAC_VER_71) + r8168_mac_ocp_modify(tp, 0xe614, 0x0700, 0x0400); + else if (tp->mac_version == RTL_GIGA_MAC_VER_63) + r8168_mac_ocp_modify(tp, 0xe614, 0x0700, 0x0200); +@@ -3742,8 +3742,8 @@ static void rtl_hw_start_8125_common(struct rtl8169_private *tp) + r8168_mac_ocp_modify(tp, 0xe056, 0x00f0, 0x0030); + r8168_mac_ocp_modify(tp, 0xe040, 0x1000, 0x0000); + r8168_mac_ocp_modify(tp, 0xea1c, 0x0003, 0x0001); +- if (tp->mac_version == RTL_GIGA_MAC_VER_65 || +- tp->mac_version == RTL_GIGA_MAC_VER_66) ++ if (tp->mac_version == RTL_GIGA_MAC_VER_70 || ++ tp->mac_version == RTL_GIGA_MAC_VER_71) + r8168_mac_ocp_modify(tp, 0xea1c, 0x0300, 0x0000); + else + r8168_mac_ocp_modify(tp, 0xea1c, 0x0004, 0x0000); +@@ -3863,8 +3863,8 @@ static void rtl_hw_config(struct rtl8169_private *tp) + [RTL_GIGA_MAC_VER_61] = rtl_hw_start_8125a_2, + [RTL_GIGA_MAC_VER_63] = rtl_hw_start_8125b, + [RTL_GIGA_MAC_VER_64] = rtl_hw_start_8125d, +- [RTL_GIGA_MAC_VER_65] = rtl_hw_start_8126a, +- [RTL_GIGA_MAC_VER_66] = rtl_hw_start_8126a, ++ [RTL_GIGA_MAC_VER_70] = rtl_hw_start_8126a, ++ [RTL_GIGA_MAC_VER_71] = rtl_hw_start_8126a, + }; + + if (hw_configs[tp->mac_version]) +@@ -3885,8 +3885,8 @@ static void rtl_hw_start_8125(struct rtl8169_private *tp) + RTL_W32(tp, i, 0); + break; + case RTL_GIGA_MAC_VER_63: +- case RTL_GIGA_MAC_VER_65: +- case RTL_GIGA_MAC_VER_66: ++ case RTL_GIGA_MAC_VER_70: ++ case RTL_GIGA_MAC_VER_71: + for (i = 0xa00; i < 0xa80; i += 4) + RTL_W32(tp, i, 0); + RTL_W16(tp, INT_CFG1_8125, 0x0000); +@@ -4118,7 +4118,7 @@ static void rtl8169_cleanup(struct rtl8169_private *tp) + RTL_W8(tp, ChipCmd, RTL_R8(tp, ChipCmd) | StopReq); + rtl_loop_wait_high(tp, &rtl_txcfg_empty_cond, 100, 666); + break; +- case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_66: ++ case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_71: + rtl_enable_rxdvgate(tp); + fsleep(2000); + break; +@@ -4275,7 +4275,7 @@ static unsigned int rtl_quirk_packet_padto(struct rtl8169_private *tp, + + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_34: +- case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_66: ++ case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_71: + padto = max_t(unsigned int, padto, ETH_ZLEN); + break; + default: +@@ -5294,7 +5294,7 @@ static void rtl_hw_initialize(struct rtl8169_private *tp) + case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_48: + rtl_hw_init_8168g(tp); + break; +- case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_66: ++ case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_71: + rtl_hw_init_8125(tp); + break; + default: +diff --git a/drivers/net/ethernet/realtek/r8169_phy_config.c b/drivers/net/ethernet/realtek/r8169_phy_config.c +index b28b30390e84..bc498ea78034 100644 +--- a/drivers/net/ethernet/realtek/r8169_phy_config.c ++++ b/drivers/net/ethernet/realtek/r8169_phy_config.c +@@ -1162,8 +1162,8 @@ void r8169_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev, + [RTL_GIGA_MAC_VER_61] = rtl8125a_2_hw_phy_config, + [RTL_GIGA_MAC_VER_63] = rtl8125b_hw_phy_config, + [RTL_GIGA_MAC_VER_64] = rtl8125d_hw_phy_config, +- [RTL_GIGA_MAC_VER_65] = rtl8126a_hw_phy_config, +- [RTL_GIGA_MAC_VER_66] = rtl8126a_hw_phy_config, ++ [RTL_GIGA_MAC_VER_70] = rtl8126a_hw_phy_config, ++ [RTL_GIGA_MAC_VER_71] = rtl8126a_hw_phy_config, + }; + + if (phy_configs[ver]) +-- +2.51.0 + + +From df24521b323b138471e6ea933e24af5f77c30f33 Mon Sep 17 00:00:00 2001 +From: ChunHao Lin +Date: Fri, 13 Dec 2024 20:02:58 +0100 +Subject: [PATCH 119/517] r8169: add support for RTL8125D rev.b + +Add support for RTL8125D rev.b. Its XID is 0x689. It is basically +based on the one with XID 0x688, but with different firmware file. + +Signed-off-by: ChunHao Lin +[hkallweit1@gmail.com: rebased after adjusted version numbering] +Signed-off-by: Heiner Kallweit +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/75e5e9ec-d01f-43ac-b0f4-e7456baf18d1@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/realtek/r8169.h | 1 + + drivers/net/ethernet/realtek/r8169_main.c | 6 ++++++ + drivers/net/ethernet/realtek/r8169_phy_config.c | 1 + + 3 files changed, 8 insertions(+) + +diff --git a/drivers/net/ethernet/realtek/r8169.h b/drivers/net/ethernet/realtek/r8169.h +index 00d74e76c6f2..e0817f2a311a 100644 +--- a/drivers/net/ethernet/realtek/r8169.h ++++ b/drivers/net/ethernet/realtek/r8169.h +@@ -69,6 +69,7 @@ enum mac_version { + RTL_GIGA_MAC_VER_61, + RTL_GIGA_MAC_VER_63, + RTL_GIGA_MAC_VER_64, ++ RTL_GIGA_MAC_VER_65, + RTL_GIGA_MAC_VER_70, + RTL_GIGA_MAC_VER_71, + RTL_GIGA_MAC_NONE +diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c +index f0d6261f92bb..16c1e74554b2 100644 +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -56,6 +56,7 @@ + #define FIRMWARE_8125A_3 "rtl_nic/rtl8125a-3.fw" + #define FIRMWARE_8125B_2 "rtl_nic/rtl8125b-2.fw" + #define FIRMWARE_8125D_1 "rtl_nic/rtl8125d-1.fw" ++#define FIRMWARE_8125D_2 "rtl_nic/rtl8125d-2.fw" + #define FIRMWARE_8126A_2 "rtl_nic/rtl8126a-2.fw" + #define FIRMWARE_8126A_3 "rtl_nic/rtl8126a-3.fw" + +@@ -139,6 +140,7 @@ static const struct { + /* reserve 62 for CFG_METHOD_4 in the vendor driver */ + [RTL_GIGA_MAC_VER_63] = {"RTL8125B", FIRMWARE_8125B_2}, + [RTL_GIGA_MAC_VER_64] = {"RTL8125D", FIRMWARE_8125D_1}, ++ [RTL_GIGA_MAC_VER_65] = {"RTL8125D", FIRMWARE_8125D_2}, + [RTL_GIGA_MAC_VER_70] = {"RTL8126A", FIRMWARE_8126A_2}, + [RTL_GIGA_MAC_VER_71] = {"RTL8126A", FIRMWARE_8126A_3}, + }; +@@ -705,6 +707,7 @@ MODULE_FIRMWARE(FIRMWARE_8107E_2); + MODULE_FIRMWARE(FIRMWARE_8125A_3); + MODULE_FIRMWARE(FIRMWARE_8125B_2); + MODULE_FIRMWARE(FIRMWARE_8125D_1); ++MODULE_FIRMWARE(FIRMWARE_8125D_2); + MODULE_FIRMWARE(FIRMWARE_8126A_2); + MODULE_FIRMWARE(FIRMWARE_8126A_3); + +@@ -2258,6 +2261,7 @@ static enum mac_version rtl8169_get_mac_version(u16 xid, bool gmii) + { 0x7cf, 0x649, RTL_GIGA_MAC_VER_70 }, + + /* 8125D family. */ ++ { 0x7cf, 0x689, RTL_GIGA_MAC_VER_65 }, + { 0x7cf, 0x688, RTL_GIGA_MAC_VER_64 }, + + /* 8125B family. */ +@@ -3863,6 +3867,7 @@ static void rtl_hw_config(struct rtl8169_private *tp) + [RTL_GIGA_MAC_VER_61] = rtl_hw_start_8125a_2, + [RTL_GIGA_MAC_VER_63] = rtl_hw_start_8125b, + [RTL_GIGA_MAC_VER_64] = rtl_hw_start_8125d, ++ [RTL_GIGA_MAC_VER_65] = rtl_hw_start_8125d, + [RTL_GIGA_MAC_VER_70] = rtl_hw_start_8126a, + [RTL_GIGA_MAC_VER_71] = rtl_hw_start_8126a, + }; +@@ -3881,6 +3886,7 @@ static void rtl_hw_start_8125(struct rtl8169_private *tp) + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_61: + case RTL_GIGA_MAC_VER_64: ++ case RTL_GIGA_MAC_VER_65: + for (i = 0xa00; i < 0xb00; i += 4) + RTL_W32(tp, i, 0); + break; +diff --git a/drivers/net/ethernet/realtek/r8169_phy_config.c b/drivers/net/ethernet/realtek/r8169_phy_config.c +index bc498ea78034..968c8a2185a4 100644 +--- a/drivers/net/ethernet/realtek/r8169_phy_config.c ++++ b/drivers/net/ethernet/realtek/r8169_phy_config.c +@@ -1162,6 +1162,7 @@ void r8169_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev, + [RTL_GIGA_MAC_VER_61] = rtl8125a_2_hw_phy_config, + [RTL_GIGA_MAC_VER_63] = rtl8125b_hw_phy_config, + [RTL_GIGA_MAC_VER_64] = rtl8125d_hw_phy_config, ++ [RTL_GIGA_MAC_VER_65] = rtl8125d_hw_phy_config, + [RTL_GIGA_MAC_VER_70] = rtl8126a_hw_phy_config, + [RTL_GIGA_MAC_VER_71] = rtl8126a_hw_phy_config, + }; +-- +2.51.0 + + +From acdb177b82422fdb3c015b9cc048720f11cc944e Mon Sep 17 00:00:00 2001 +From: ChunHao Lin +Date: Tue, 7 Jan 2025 14:43:55 +0800 +Subject: [PATCH 120/517] r8169: add support for RTL8125BP rev.b + +Add support for RTL8125BP rev.b. Its XID is 0x689. This chip supports +DASH and its dash type is "RTL_DASH_25_BP". + +Signed-off-by: ChunHao Lin +Reviewed-by: Heiner Kallweit +Link: https://patch.msgid.link/20250107064355.104711-1-hau@realtek.com +Signed-off-by: Paolo Abeni +--- + drivers/net/ethernet/realtek/r8169.h | 1 + + drivers/net/ethernet/realtek/r8169_main.c | 30 +++++++++++++++++++ + .../net/ethernet/realtek/r8169_phy_config.c | 23 ++++++++++++++ + 3 files changed, 54 insertions(+) + +diff --git a/drivers/net/ethernet/realtek/r8169.h b/drivers/net/ethernet/realtek/r8169.h +index e0817f2a311a..7a194a8ab989 100644 +--- a/drivers/net/ethernet/realtek/r8169.h ++++ b/drivers/net/ethernet/realtek/r8169.h +@@ -70,6 +70,7 @@ enum mac_version { + RTL_GIGA_MAC_VER_63, + RTL_GIGA_MAC_VER_64, + RTL_GIGA_MAC_VER_65, ++ RTL_GIGA_MAC_VER_66, + RTL_GIGA_MAC_VER_70, + RTL_GIGA_MAC_VER_71, + RTL_GIGA_MAC_NONE +diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c +index 16c1e74554b2..b99ddcbec526 100644 +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -57,6 +57,7 @@ + #define FIRMWARE_8125B_2 "rtl_nic/rtl8125b-2.fw" + #define FIRMWARE_8125D_1 "rtl_nic/rtl8125d-1.fw" + #define FIRMWARE_8125D_2 "rtl_nic/rtl8125d-2.fw" ++#define FIRMWARE_8125BP_2 "rtl_nic/rtl8125bp-2.fw" + #define FIRMWARE_8126A_2 "rtl_nic/rtl8126a-2.fw" + #define FIRMWARE_8126A_3 "rtl_nic/rtl8126a-3.fw" + +@@ -141,6 +142,7 @@ static const struct { + [RTL_GIGA_MAC_VER_63] = {"RTL8125B", FIRMWARE_8125B_2}, + [RTL_GIGA_MAC_VER_64] = {"RTL8125D", FIRMWARE_8125D_1}, + [RTL_GIGA_MAC_VER_65] = {"RTL8125D", FIRMWARE_8125D_2}, ++ [RTL_GIGA_MAC_VER_66] = {"RTL8125BP", FIRMWARE_8125BP_2}, + [RTL_GIGA_MAC_VER_70] = {"RTL8126A", FIRMWARE_8126A_2}, + [RTL_GIGA_MAC_VER_71] = {"RTL8126A", FIRMWARE_8126A_3}, + }; +@@ -631,6 +633,7 @@ enum rtl_dash_type { + RTL_DASH_NONE, + RTL_DASH_DP, + RTL_DASH_EP, ++ RTL_DASH_25_BP, + }; + + struct rtl8169_private { +@@ -708,6 +711,7 @@ MODULE_FIRMWARE(FIRMWARE_8125A_3); + MODULE_FIRMWARE(FIRMWARE_8125B_2); + MODULE_FIRMWARE(FIRMWARE_8125D_1); + MODULE_FIRMWARE(FIRMWARE_8125D_2); ++MODULE_FIRMWARE(FIRMWARE_8125BP_2); + MODULE_FIRMWARE(FIRMWARE_8126A_2); + MODULE_FIRMWARE(FIRMWARE_8126A_3); + +@@ -1360,10 +1364,19 @@ static void rtl8168ep_driver_start(struct rtl8169_private *tp) + rtl_loop_wait_high(tp, &rtl_ep_ocp_read_cond, 10000, 30); + } + ++static void rtl8125bp_driver_start(struct rtl8169_private *tp) ++{ ++ r8168ep_ocp_write(tp, 0x01, 0x14, OOB_CMD_DRIVER_START); ++ r8168ep_ocp_write(tp, 0x01, 0x18, 0x00); ++ r8168ep_ocp_write(tp, 0x01, 0x10, 0x01); ++} ++ + static void rtl8168_driver_start(struct rtl8169_private *tp) + { + if (tp->dash_type == RTL_DASH_DP) + rtl8168dp_driver_start(tp); ++ else if (tp->dash_type == RTL_DASH_25_BP) ++ rtl8125bp_driver_start(tp); + else + rtl8168ep_driver_start(tp); + } +@@ -1384,10 +1397,19 @@ static void rtl8168ep_driver_stop(struct rtl8169_private *tp) + rtl_loop_wait_low(tp, &rtl_ep_ocp_read_cond, 10000, 10); + } + ++static void rtl8125bp_driver_stop(struct rtl8169_private *tp) ++{ ++ r8168ep_ocp_write(tp, 0x01, 0x14, OOB_CMD_DRIVER_STOP); ++ r8168ep_ocp_write(tp, 0x01, 0x18, 0x00); ++ r8168ep_ocp_write(tp, 0x01, 0x10, 0x01); ++} ++ + static void rtl8168_driver_stop(struct rtl8169_private *tp) + { + if (tp->dash_type == RTL_DASH_DP) + rtl8168dp_driver_stop(tp); ++ else if (tp->dash_type == RTL_DASH_25_BP) ++ rtl8125bp_driver_stop(tp); + else + rtl8168ep_driver_stop(tp); + } +@@ -1410,6 +1432,7 @@ static bool rtl_dash_is_enabled(struct rtl8169_private *tp) + case RTL_DASH_DP: + return r8168dp_check_dash(tp); + case RTL_DASH_EP: ++ case RTL_DASH_25_BP: + return r8168ep_check_dash(tp); + default: + return false; +@@ -1424,6 +1447,8 @@ static enum rtl_dash_type rtl_get_dash_type(struct rtl8169_private *tp) + return RTL_DASH_DP; + case RTL_GIGA_MAC_VER_51 ... RTL_GIGA_MAC_VER_53: + return RTL_DASH_EP; ++ case RTL_GIGA_MAC_VER_66: ++ return RTL_DASH_25_BP; + default: + return RTL_DASH_NONE; + } +@@ -2260,6 +2285,9 @@ static enum mac_version rtl8169_get_mac_version(u16 xid, bool gmii) + { 0x7cf, 0x64a, RTL_GIGA_MAC_VER_71 }, + { 0x7cf, 0x649, RTL_GIGA_MAC_VER_70 }, + ++ /* 8125BP family. */ ++ { 0x7cf, 0x681, RTL_GIGA_MAC_VER_66 }, ++ + /* 8125D family. */ + { 0x7cf, 0x689, RTL_GIGA_MAC_VER_65 }, + { 0x7cf, 0x688, RTL_GIGA_MAC_VER_64 }, +@@ -3868,6 +3896,7 @@ static void rtl_hw_config(struct rtl8169_private *tp) + [RTL_GIGA_MAC_VER_63] = rtl_hw_start_8125b, + [RTL_GIGA_MAC_VER_64] = rtl_hw_start_8125d, + [RTL_GIGA_MAC_VER_65] = rtl_hw_start_8125d, ++ [RTL_GIGA_MAC_VER_66] = rtl_hw_start_8125d, + [RTL_GIGA_MAC_VER_70] = rtl_hw_start_8126a, + [RTL_GIGA_MAC_VER_71] = rtl_hw_start_8126a, + }; +@@ -3887,6 +3916,7 @@ static void rtl_hw_start_8125(struct rtl8169_private *tp) + case RTL_GIGA_MAC_VER_61: + case RTL_GIGA_MAC_VER_64: + case RTL_GIGA_MAC_VER_65: ++ case RTL_GIGA_MAC_VER_66: + for (i = 0xa00; i < 0xb00; i += 4) + RTL_W32(tp, i, 0); + break; +diff --git a/drivers/net/ethernet/realtek/r8169_phy_config.c b/drivers/net/ethernet/realtek/r8169_phy_config.c +index 968c8a2185a4..cf95e579c65d 100644 +--- a/drivers/net/ethernet/realtek/r8169_phy_config.c ++++ b/drivers/net/ethernet/realtek/r8169_phy_config.c +@@ -1102,6 +1102,28 @@ static void rtl8125d_hw_phy_config(struct rtl8169_private *tp, + rtl8125_config_eee_phy(phydev); + } + ++static void rtl8125bp_hw_phy_config(struct rtl8169_private *tp, ++ struct phy_device *phydev) ++{ ++ r8169_apply_firmware(tp); ++ rtl8168g_enable_gphy_10m(phydev); ++ ++ r8168g_phy_param(phydev, 0x8010, 0x0800, 0x0000); ++ ++ phy_write(phydev, 0x1f, 0x0b87); ++ phy_write(phydev, 0x16, 0x8088); ++ phy_modify(phydev, 0x17, 0xff00, 0x9000); ++ phy_write(phydev, 0x16, 0x808f); ++ phy_modify(phydev, 0x17, 0xff00, 0x9000); ++ phy_write(phydev, 0x1f, 0x0000); ++ ++ r8168g_phy_param(phydev, 0x8174, 0x2000, 0x1800); ++ ++ rtl8125_legacy_force_mode(phydev); ++ rtl8168g_disable_aldps(phydev); ++ rtl8125_config_eee_phy(phydev); ++} ++ + static void rtl8126a_hw_phy_config(struct rtl8169_private *tp, + struct phy_device *phydev) + { +@@ -1163,6 +1185,7 @@ void r8169_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev, + [RTL_GIGA_MAC_VER_63] = rtl8125b_hw_phy_config, + [RTL_GIGA_MAC_VER_64] = rtl8125d_hw_phy_config, + [RTL_GIGA_MAC_VER_65] = rtl8125d_hw_phy_config, ++ [RTL_GIGA_MAC_VER_66] = rtl8125bp_hw_phy_config, + [RTL_GIGA_MAC_VER_70] = rtl8126a_hw_phy_config, + [RTL_GIGA_MAC_VER_71] = rtl8126a_hw_phy_config, + }; +-- +2.51.0 + + +From 3ff41a19c5246bfa3fbe37fe5d4b091393dd949a Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Mon, 3 Feb 2025 21:35:24 +0100 +Subject: [PATCH 121/517] r8169: make Kconfig option for LED support + user-visible + +Make config option R8169_LEDS user-visible, so that users can remove +support if not needed. + +Signed-off-by: Heiner Kallweit +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/d29f0cdb-32bf-435f-b59d-dc96bca1e3ab@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/realtek/Kconfig | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/realtek/Kconfig b/drivers/net/ethernet/realtek/Kconfig +index 8a8ea51c639e..fe136f61586f 100644 +--- a/drivers/net/ethernet/realtek/Kconfig ++++ b/drivers/net/ethernet/realtek/Kconfig +@@ -114,7 +114,8 @@ config R8169 + will be called r8169. This is recommended. + + config R8169_LEDS +- def_bool R8169 && LEDS_TRIGGER_NETDEV ++ bool "Support for controlling the NIC LEDs" ++ depends on R8169 && LEDS_TRIGGER_NETDEV + depends on !(R8169=y && LEDS_CLASS=m) + help + Optional support for controlling the NIC LED's with the netdev +-- +2.51.0 + + +From f0f1c081b8621b6572e2e1fb59c598b8ebca85d5 Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Wed, 12 Feb 2025 08:03:56 +0100 +Subject: [PATCH 122/517] r8169: add support for Intel Killer E5000 + +This adds support for the Intel Killer E5000 which seems to be a +rebranded RTL8126. Copied from r8126 vendor driver. + +Signed-off-by: Heiner Kallweit +Link: https://patch.msgid.link/9db73e9b-e2e8-45de-97a5-041c5f71d774@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/realtek/r8169_main.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c +index b99ddcbec526..c6acf6709524 100644 +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -169,6 +169,7 @@ static const struct pci_device_id rtl8169_pci_tbl[] = { + { PCI_VDEVICE(REALTEK, 0x8125) }, + { PCI_VDEVICE(REALTEK, 0x8126) }, + { PCI_VDEVICE(REALTEK, 0x3000) }, ++ { PCI_VDEVICE(REALTEK, 0x5000) }, + {} + }; + +-- +2.51.0 + + +From 6c0325b41afeb91bf75bf5e75b0062834b033190 Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Thu, 13 Feb 2025 20:15:42 +0100 +Subject: [PATCH 123/517] r8169: add PHY c45 ops for MDIO_MMD_VENDOR2 registers + +The integrated PHYs on chip versions from RTL8168g allow to address +MDIO_MMD_VEND2 registers. All c22 standard registers are mapped to +MDIO_MMD_VEND2 registers. So far the paging mechanism is used to +address PHY registers. Add support for c45 ops to address MDIO_MMD_VEND2 +registers directly, w/o the paging. + +Signed-off-by: Heiner Kallweit +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/d6f97eaa-0f13-468f-89cb-75a41087bc4a@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/realtek/r8169_main.c | 32 +++++++++++++++++++++++ + 1 file changed, 32 insertions(+) + +diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c +index c6acf6709524..d974461db6b0 100644 +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -5228,6 +5228,33 @@ static int r8169_mdio_write_reg(struct mii_bus *mii_bus, int phyaddr, + return 0; + } + ++static int r8169_mdio_read_reg_c45(struct mii_bus *mii_bus, int addr, ++ int devnum, int regnum) ++{ ++ struct rtl8169_private *tp = mii_bus->priv; ++ ++ if (addr > 0) ++ return -ENODEV; ++ ++ if (devnum == MDIO_MMD_VEND2 && regnum > MDIO_STAT2) ++ return r8168_phy_ocp_read(tp, regnum); ++ ++ return 0; ++} ++ ++static int r8169_mdio_write_reg_c45(struct mii_bus *mii_bus, int addr, ++ int devnum, int regnum, u16 val) ++{ ++ struct rtl8169_private *tp = mii_bus->priv; ++ ++ if (addr > 0 || devnum != MDIO_MMD_VEND2 || regnum <= MDIO_STAT2) ++ return -ENODEV; ++ ++ r8168_phy_ocp_write(tp, regnum, val); ++ ++ return 0; ++} ++ + static int r8169_mdio_register(struct rtl8169_private *tp) + { + struct pci_dev *pdev = tp->pci_dev; +@@ -5258,6 +5285,11 @@ static int r8169_mdio_register(struct rtl8169_private *tp) + new_bus->read = r8169_mdio_read_reg; + new_bus->write = r8169_mdio_write_reg; + ++ if (tp->mac_version >= RTL_GIGA_MAC_VER_40) { ++ new_bus->read_c45 = r8169_mdio_read_reg_c45; ++ new_bus->write_c45 = r8169_mdio_write_reg_c45; ++ } ++ + ret = devm_mdiobus_register(&pdev->dev, new_bus); + if (ret) + return ret; +-- +2.51.0 + + +From 8589e361c146c0a256bfa01874126364a1a6c540 Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Fri, 7 Mar 2025 08:29:47 +0100 +Subject: [PATCH 124/517] r8169: increase max jumbo packet size on + RTL8125/RTL8126 + +Realtek confirmed that all RTL8125/RTL8126 chip versions support up to +16K jumbo packets. Reflect this in the driver. + +Tested by Rui on RTL8125B with 12K jumbo packets. + +Suggested-by: Rui Salvaterra +Tested-by: Rui Salvaterra +Signed-off-by: Heiner Kallweit +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/396762ad-cc65-4e60-b01e-8847db89e98b@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/realtek/r8169_main.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c +index d974461db6b0..90585f44ed77 100644 +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -89,6 +89,7 @@ + #define JUMBO_6K (6 * SZ_1K - VLAN_ETH_HLEN - ETH_FCS_LEN) + #define JUMBO_7K (7 * SZ_1K - VLAN_ETH_HLEN - ETH_FCS_LEN) + #define JUMBO_9K (9 * SZ_1K - VLAN_ETH_HLEN - ETH_FCS_LEN) ++#define JUMBO_16K (SZ_16K - VLAN_ETH_HLEN - ETH_FCS_LEN) + + static const struct { + const char *name; +@@ -5387,6 +5388,9 @@ static int rtl_jumbo_max(struct rtl8169_private *tp) + /* RTL8168c */ + case RTL_GIGA_MAC_VER_18 ... RTL_GIGA_MAC_VER_24: + return JUMBO_6K; ++ /* RTL8125/8126 */ ++ case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_71: ++ return JUMBO_16K; + default: + return JUMBO_9K; + } +-- +2.51.0 + + +From 685a636e3096ae8ba35b8f928ba1bc4ec10462ba Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Wed, 12 Mar 2025 20:21:42 +0100 +Subject: [PATCH 125/517] r8169: switch away from deprecated pcim_iomap_table + +Avoid using deprecated pcim_iomap_table by switching to +pcim_iomap_region. + +Signed-off-by: Heiner Kallweit +Reviewed-by: Jacob Keller +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/a36b4cf3-c792-40fa-8164-5dc9d5f14dd0@gmail.com +Signed-off-by: Paolo Abeni +--- + drivers/net/ethernet/realtek/r8169_main.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c +index 90585f44ed77..37e1cbf87e2d 100644 +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -5474,11 +5474,10 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) + if (region < 0) + return dev_err_probe(&pdev->dev, -ENODEV, "no MMIO resource found\n"); + +- rc = pcim_iomap_regions(pdev, BIT(region), KBUILD_MODNAME); +- if (rc < 0) +- return dev_err_probe(&pdev->dev, rc, "cannot remap MMIO, aborting\n"); +- +- tp->mmio_addr = pcim_iomap_table(pdev)[region]; ++ tp->mmio_addr = pcim_iomap_region(pdev, region, KBUILD_MODNAME); ++ if (IS_ERR(tp->mmio_addr)) ++ return dev_err_probe(&pdev->dev, PTR_ERR(tp->mmio_addr), ++ "cannot remap MMIO, aborting\n"); + + txconfig = RTL_R32(tp, TxConfig); + if (txconfig == ~0U) +-- +2.51.0 + + +From ae7d0b24a7b500d0d2b5f87dc2311464714542d9 Mon Sep 17 00:00:00 2001 +From: ChunHao Lin +Date: Tue, 18 Mar 2025 16:37:20 +0800 +Subject: [PATCH 126/517] r8169: enable RTL8168H/RTL8168EP/RTL8168FP ASPM + support + +This patch will enable RTL8168H/RTL8168EP/RTL8168FP ASPM support on +the platforms that have tested with ASPM enabled. + +Signed-off-by: ChunHao Lin +Reviewed-by: Heiner Kallweit +Link: https://patch.msgid.link/20250318083721.4127-2-hau@realtek.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/realtek/r8169_main.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c +index 37e1cbf87e2d..f5150c9a0f66 100644 +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -5425,7 +5425,7 @@ static void rtl_init_mac_address(struct rtl8169_private *tp) + /* register is set if system vendor successfully tested ASPM 1.2 */ + static bool rtl_aspm_is_safe(struct rtl8169_private *tp) + { +- if (tp->mac_version >= RTL_GIGA_MAC_VER_61 && ++ if (tp->mac_version >= RTL_GIGA_MAC_VER_46 && + r8168_mac_ocp_read(tp, 0xc0b2) & 0xf) + return true; + +-- +2.51.0 + + +From c20f71142b7d50326a236e242a375831f453193a Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Wed, 9 Apr 2025 21:05:37 +0200 +Subject: [PATCH 127/517] r8169: add helper rtl_csi_mod for accessing extended + config space + +Add a helper for the Realtek-specific mechanism for accessing extended +config space if native access isn't possible. +This avoids code duplication. + +Signed-off-by: Heiner Kallweit +Link: https://patch.msgid.link/b368fd91-57d7-4cb5-9342-98b4d8fe9aea@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/realtek/r8169_main.c | 26 ++++++++++++++--------- + 1 file changed, 16 insertions(+), 10 deletions(-) + +diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c +index f5150c9a0f66..efdfa95ff693 100644 +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -2852,10 +2852,23 @@ static u32 rtl_csi_read(struct rtl8169_private *tp, int addr) + RTL_R32(tp, CSIDR) : ~0; + } + ++static void rtl_csi_mod(struct rtl8169_private *tp, int addr, ++ u32 mask, u32 set) ++{ ++ u32 val; ++ ++ WARN(addr % 4, "Invalid CSI address %#x\n", addr); ++ ++ netdev_notice_once(tp->dev, ++ "No native access to PCI extended config space, falling back to CSI\n"); ++ ++ val = rtl_csi_read(tp, addr); ++ rtl_csi_write(tp, addr, (val & ~mask) | set); ++} ++ + static void rtl_disable_zrxdc_timeout(struct rtl8169_private *tp) + { + struct pci_dev *pdev = tp->pci_dev; +- u32 csi; + int rc; + u8 val; + +@@ -2872,16 +2885,12 @@ static void rtl_disable_zrxdc_timeout(struct rtl8169_private *tp) + } + } + +- netdev_notice_once(tp->dev, +- "No native access to PCI extended config space, falling back to CSI\n"); +- csi = rtl_csi_read(tp, RTL_GEN3_RELATED_OFF); +- rtl_csi_write(tp, RTL_GEN3_RELATED_OFF, csi & ~RTL_GEN3_ZRXDC_NONCOMPL); ++ rtl_csi_mod(tp, RTL_GEN3_RELATED_OFF, RTL_GEN3_ZRXDC_NONCOMPL, 0); + } + + static void rtl_set_aspm_entry_latency(struct rtl8169_private *tp, u8 val) + { + struct pci_dev *pdev = tp->pci_dev; +- u32 csi; + + /* According to Realtek the value at config space address 0x070f + * controls the L0s/L1 entrance latency. We try standard ECAM access +@@ -2893,10 +2902,7 @@ static void rtl_set_aspm_entry_latency(struct rtl8169_private *tp, u8 val) + pci_write_config_byte(pdev, 0x070f, val) == PCIBIOS_SUCCESSFUL) + return; + +- netdev_notice_once(tp->dev, +- "No native access to PCI extended config space, falling back to CSI\n"); +- csi = rtl_csi_read(tp, 0x070c) & 0x00ffffff; +- rtl_csi_write(tp, 0x070c, csi | val << 24); ++ rtl_csi_mod(tp, 0x070c, 0xff000000, val << 24); + } + + static void rtl_set_def_aspm_entry_latency(struct rtl8169_private *tp) +-- +2.51.0 + + +From aaf2eb9eaec5f513d9a4870701574ca85343f144 Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Wed, 9 Apr 2025 21:14:47 +0200 +Subject: [PATCH 128/517] r8169: add helper rtl8125_phy_param + +The integrated PHY's of RTL8125/8126 have an own mechanism to access +PHY parameters, similar to what r8168g_phy_param does on earlier PHY +versions. Add helper rtl8125_phy_param to simplify the code. + +Signed-off-by: Heiner Kallweit +Link: https://patch.msgid.link/847b7356-12d6-441b-ade9-4b6e1539b84a@gmail.com +Signed-off-by: Jakub Kicinski +--- + .../net/ethernet/realtek/r8169_phy_config.c | 36 +++++++++---------- + 1 file changed, 16 insertions(+), 20 deletions(-) + +diff --git a/drivers/net/ethernet/realtek/r8169_phy_config.c b/drivers/net/ethernet/realtek/r8169_phy_config.c +index cf95e579c65d..748ca8b212ba 100644 +--- a/drivers/net/ethernet/realtek/r8169_phy_config.c ++++ b/drivers/net/ethernet/realtek/r8169_phy_config.c +@@ -50,6 +50,15 @@ static void r8168g_phy_param(struct phy_device *phydev, u16 parm, + phy_restore_page(phydev, oldpage, 0); + } + ++static void rtl8125_phy_param(struct phy_device *phydev, u16 parm, ++ u16 mask, u16 val) ++{ ++ phy_lock_mdio_bus(phydev); ++ __phy_write_mmd(phydev, MDIO_MMD_VEND2, 0xb87c, parm); ++ __phy_modify_mmd(phydev, MDIO_MMD_VEND2, 0xb87e, mask, val); ++ phy_unlock_mdio_bus(phydev); ++} ++ + struct phy_reg { + u16 reg; + u16 val; +@@ -1004,12 +1013,8 @@ static void rtl8125a_2_hw_phy_config(struct rtl8169_private *tp, + phy_write_paged(phydev, 0xac5, 0x16, 0x01ff); + phy_modify_paged(phydev, 0xac8, 0x15, 0x00f0, 0x0030); + +- phy_write(phydev, 0x1f, 0x0b87); +- phy_write(phydev, 0x16, 0x80a2); +- phy_write(phydev, 0x17, 0x0153); +- phy_write(phydev, 0x16, 0x809c); +- phy_write(phydev, 0x17, 0x0153); +- phy_write(phydev, 0x1f, 0x0000); ++ rtl8125_phy_param(phydev, 0x80a2, 0xffff, 0x0153); ++ rtl8125_phy_param(phydev, 0x809c, 0xffff, 0x0153); + + phy_write(phydev, 0x1f, 0x0a43); + phy_write(phydev, 0x13, 0x81B3); +@@ -1061,14 +1066,9 @@ static void rtl8125b_hw_phy_config(struct rtl8169_private *tp, + phy_modify_paged(phydev, 0xac4, 0x13, 0x00f0, 0x0090); + phy_modify_paged(phydev, 0xad3, 0x10, 0x0003, 0x0001); + +- phy_write(phydev, 0x1f, 0x0b87); +- phy_write(phydev, 0x16, 0x80f5); +- phy_write(phydev, 0x17, 0x760e); +- phy_write(phydev, 0x16, 0x8107); +- phy_write(phydev, 0x17, 0x360e); +- phy_write(phydev, 0x16, 0x8551); +- phy_modify(phydev, 0x17, 0xff00, 0x0800); +- phy_write(phydev, 0x1f, 0x0000); ++ rtl8125_phy_param(phydev, 0x80f5, 0xffff, 0x760e); ++ rtl8125_phy_param(phydev, 0x8107, 0xffff, 0x360e); ++ rtl8125_phy_param(phydev, 0x8551, 0xff00, 0x0800); + + phy_modify_paged(phydev, 0xbf0, 0x10, 0xe000, 0xa000); + phy_modify_paged(phydev, 0xbf4, 0x13, 0x0f00, 0x0300); +@@ -1110,12 +1110,8 @@ static void rtl8125bp_hw_phy_config(struct rtl8169_private *tp, + + r8168g_phy_param(phydev, 0x8010, 0x0800, 0x0000); + +- phy_write(phydev, 0x1f, 0x0b87); +- phy_write(phydev, 0x16, 0x8088); +- phy_modify(phydev, 0x17, 0xff00, 0x9000); +- phy_write(phydev, 0x16, 0x808f); +- phy_modify(phydev, 0x17, 0xff00, 0x9000); +- phy_write(phydev, 0x1f, 0x0000); ++ rtl8125_phy_param(phydev, 0x8088, 0xff00, 0x9000); ++ rtl8125_phy_param(phydev, 0x808f, 0xff00, 0x9000); + + r8168g_phy_param(phydev, 0x8174, 0x2000, 0x1800); + +-- +2.51.0 + + +From 09aaa64852d52817e4cd8421cc789e862de34eae Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Tue, 15 Apr 2025 21:29:34 +0200 +Subject: [PATCH 129/517] r8169: refactor chip version detection + +Refactor chip version detection and merge both configuration tables. +Apart from reducing the code by a third, this paves the way for +merging chip version handling if only difference is the firmware. + +Signed-off-by: Heiner Kallweit +Reviewed-by: Michal Swiatkowski +Link: https://patch.msgid.link/1fea533a-dd5a-4198-a9e2-895e11083947@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/realtek/r8169_main.c | 325 +++++++++------------- + 1 file changed, 128 insertions(+), 197 deletions(-) + +diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c +index efdfa95ff693..140577e626bd 100644 +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -91,61 +91,114 @@ + #define JUMBO_9K (9 * SZ_1K - VLAN_ETH_HLEN - ETH_FCS_LEN) + #define JUMBO_16K (SZ_16K - VLAN_ETH_HLEN - ETH_FCS_LEN) + +-static const struct { ++static const struct rtl_chip_info { ++ u16 mask; ++ u16 val; ++ enum mac_version mac_version; + const char *name; + const char *fw_name; + } rtl_chip_infos[] = { +- /* PCI devices. */ +- [RTL_GIGA_MAC_VER_02] = {"RTL8169s" }, +- [RTL_GIGA_MAC_VER_03] = {"RTL8110s" }, +- [RTL_GIGA_MAC_VER_04] = {"RTL8169sb/8110sb" }, +- [RTL_GIGA_MAC_VER_05] = {"RTL8169sc/8110sc" }, +- [RTL_GIGA_MAC_VER_06] = {"RTL8169sc/8110sc" }, +- /* PCI-E devices. */ +- [RTL_GIGA_MAC_VER_07] = {"RTL8102e" }, +- [RTL_GIGA_MAC_VER_08] = {"RTL8102e" }, +- [RTL_GIGA_MAC_VER_09] = {"RTL8102e/RTL8103e" }, +- [RTL_GIGA_MAC_VER_10] = {"RTL8101e/RTL8100e" }, +- [RTL_GIGA_MAC_VER_14] = {"RTL8401" }, +- [RTL_GIGA_MAC_VER_17] = {"RTL8168b/8111b" }, +- [RTL_GIGA_MAC_VER_18] = {"RTL8168cp/8111cp" }, +- [RTL_GIGA_MAC_VER_19] = {"RTL8168c/8111c" }, +- [RTL_GIGA_MAC_VER_20] = {"RTL8168c/8111c" }, +- [RTL_GIGA_MAC_VER_21] = {"RTL8168c/8111c" }, +- [RTL_GIGA_MAC_VER_22] = {"RTL8168c/8111c" }, +- [RTL_GIGA_MAC_VER_23] = {"RTL8168cp/8111cp" }, +- [RTL_GIGA_MAC_VER_24] = {"RTL8168cp/8111cp" }, +- [RTL_GIGA_MAC_VER_25] = {"RTL8168d/8111d", FIRMWARE_8168D_1}, +- [RTL_GIGA_MAC_VER_26] = {"RTL8168d/8111d", FIRMWARE_8168D_2}, +- [RTL_GIGA_MAC_VER_28] = {"RTL8168dp/8111dp" }, +- [RTL_GIGA_MAC_VER_29] = {"RTL8105e", FIRMWARE_8105E_1}, +- [RTL_GIGA_MAC_VER_30] = {"RTL8105e", FIRMWARE_8105E_1}, +- [RTL_GIGA_MAC_VER_31] = {"RTL8168dp/8111dp" }, +- [RTL_GIGA_MAC_VER_32] = {"RTL8168e/8111e", FIRMWARE_8168E_1}, +- [RTL_GIGA_MAC_VER_33] = {"RTL8168e/8111e", FIRMWARE_8168E_2}, +- [RTL_GIGA_MAC_VER_34] = {"RTL8168evl/8111evl", FIRMWARE_8168E_3}, +- [RTL_GIGA_MAC_VER_35] = {"RTL8168f/8111f", FIRMWARE_8168F_1}, +- [RTL_GIGA_MAC_VER_36] = {"RTL8168f/8111f", FIRMWARE_8168F_2}, +- [RTL_GIGA_MAC_VER_37] = {"RTL8402", FIRMWARE_8402_1 }, +- [RTL_GIGA_MAC_VER_38] = {"RTL8411", FIRMWARE_8411_1 }, +- [RTL_GIGA_MAC_VER_39] = {"RTL8106e", FIRMWARE_8106E_1}, +- [RTL_GIGA_MAC_VER_40] = {"RTL8168g/8111g", FIRMWARE_8168G_2}, +- [RTL_GIGA_MAC_VER_42] = {"RTL8168gu/8111gu", FIRMWARE_8168G_3}, +- [RTL_GIGA_MAC_VER_43] = {"RTL8106eus", FIRMWARE_8106E_2}, +- [RTL_GIGA_MAC_VER_44] = {"RTL8411b", FIRMWARE_8411_2 }, +- [RTL_GIGA_MAC_VER_46] = {"RTL8168h/8111h", FIRMWARE_8168H_2}, +- [RTL_GIGA_MAC_VER_48] = {"RTL8107e", FIRMWARE_8107E_2}, +- [RTL_GIGA_MAC_VER_51] = {"RTL8168ep/8111ep" }, +- [RTL_GIGA_MAC_VER_52] = {"RTL8168fp/RTL8117", FIRMWARE_8168FP_3}, +- [RTL_GIGA_MAC_VER_53] = {"RTL8168fp/RTL8117", }, +- [RTL_GIGA_MAC_VER_61] = {"RTL8125A", FIRMWARE_8125A_3}, +- /* reserve 62 for CFG_METHOD_4 in the vendor driver */ +- [RTL_GIGA_MAC_VER_63] = {"RTL8125B", FIRMWARE_8125B_2}, +- [RTL_GIGA_MAC_VER_64] = {"RTL8125D", FIRMWARE_8125D_1}, +- [RTL_GIGA_MAC_VER_65] = {"RTL8125D", FIRMWARE_8125D_2}, +- [RTL_GIGA_MAC_VER_66] = {"RTL8125BP", FIRMWARE_8125BP_2}, +- [RTL_GIGA_MAC_VER_70] = {"RTL8126A", FIRMWARE_8126A_2}, +- [RTL_GIGA_MAC_VER_71] = {"RTL8126A", FIRMWARE_8126A_3}, ++ /* 8126A family. */ ++ { 0x7cf, 0x64a, RTL_GIGA_MAC_VER_71, "RTL8126A", FIRMWARE_8126A_3 }, ++ { 0x7cf, 0x649, RTL_GIGA_MAC_VER_70, "RTL8126A", FIRMWARE_8126A_2 }, ++ ++ /* 8125BP family. */ ++ { 0x7cf, 0x681, RTL_GIGA_MAC_VER_66, "RTL8125BP", FIRMWARE_8125BP_2 }, ++ ++ /* 8125D family. */ ++ { 0x7cf, 0x689, RTL_GIGA_MAC_VER_65, "RTL8125D", FIRMWARE_8125D_2 }, ++ { 0x7cf, 0x688, RTL_GIGA_MAC_VER_64, "RTL8125D", FIRMWARE_8125D_1 }, ++ ++ /* 8125B family. */ ++ { 0x7cf, 0x641, RTL_GIGA_MAC_VER_63, "RTL8125B", FIRMWARE_8125B_2 }, ++ ++ /* 8125A family. */ ++ { 0x7cf, 0x609, RTL_GIGA_MAC_VER_61, "RTL8125A", FIRMWARE_8125A_3 }, ++ ++ /* RTL8117 */ ++ { 0x7cf, 0x54b, RTL_GIGA_MAC_VER_53, "RTL8168fp/RTL8117" }, ++ { 0x7cf, 0x54a, RTL_GIGA_MAC_VER_52, "RTL8168fp/RTL8117", ++ FIRMWARE_8168FP_3 }, ++ ++ /* 8168EP family. */ ++ { 0x7cf, 0x502, RTL_GIGA_MAC_VER_51, "RTL8168ep/8111ep" }, ++ ++ /* 8168H family. */ ++ { 0x7cf, 0x541, RTL_GIGA_MAC_VER_46, "RTL8168h/8111h", ++ FIRMWARE_8168H_2 }, ++ /* Realtek calls it RTL8168M, but it's handled like RTL8168H */ ++ { 0x7cf, 0x6c0, RTL_GIGA_MAC_VER_46, "RTL8168M", FIRMWARE_8168H_2 }, ++ ++ /* 8168G family. */ ++ { 0x7cf, 0x5c8, RTL_GIGA_MAC_VER_44, "RTL8411b", FIRMWARE_8411_2 }, ++ { 0x7cf, 0x509, RTL_GIGA_MAC_VER_42, "RTL8168gu/8111gu", ++ FIRMWARE_8168G_3 }, ++ { 0x7cf, 0x4c0, RTL_GIGA_MAC_VER_40, "RTL8168g/8111g", ++ FIRMWARE_8168G_2 }, ++ ++ /* 8168F family. */ ++ { 0x7c8, 0x488, RTL_GIGA_MAC_VER_38, "RTL8411", FIRMWARE_8411_1 }, ++ { 0x7cf, 0x481, RTL_GIGA_MAC_VER_36, "RTL8168f/8111f", ++ FIRMWARE_8168F_2 }, ++ { 0x7cf, 0x480, RTL_GIGA_MAC_VER_35, "RTL8168f/8111f", ++ FIRMWARE_8168F_1 }, ++ ++ /* 8168E family. */ ++ { 0x7c8, 0x2c8, RTL_GIGA_MAC_VER_34, "RTL8168evl/8111evl", ++ FIRMWARE_8168E_3 }, ++ { 0x7cf, 0x2c1, RTL_GIGA_MAC_VER_32, "RTL8168e/8111e", ++ FIRMWARE_8168E_1 }, ++ { 0x7c8, 0x2c0, RTL_GIGA_MAC_VER_33, "RTL8168e/8111e", ++ FIRMWARE_8168E_2 }, ++ ++ /* 8168D family. */ ++ { 0x7cf, 0x281, RTL_GIGA_MAC_VER_25, "RTL8168d/8111d", ++ FIRMWARE_8168D_1 }, ++ { 0x7c8, 0x280, RTL_GIGA_MAC_VER_26, "RTL8168d/8111d", ++ FIRMWARE_8168D_2 }, ++ ++ /* 8168DP family. */ ++ { 0x7cf, 0x28a, RTL_GIGA_MAC_VER_28, "RTL8168dp/8111dp" }, ++ { 0x7cf, 0x28b, RTL_GIGA_MAC_VER_31, "RTL8168dp/8111dp" }, ++ ++ /* 8168C family. */ ++ { 0x7cf, 0x3c9, RTL_GIGA_MAC_VER_23, "RTL8168cp/8111cp" }, ++ { 0x7cf, 0x3c8, RTL_GIGA_MAC_VER_18, "RTL8168cp/8111cp" }, ++ { 0x7c8, 0x3c8, RTL_GIGA_MAC_VER_24, "RTL8168cp/8111cp" }, ++ { 0x7cf, 0x3c0, RTL_GIGA_MAC_VER_19, "RTL8168c/8111c" }, ++ { 0x7cf, 0x3c2, RTL_GIGA_MAC_VER_20, "RTL8168c/8111c" }, ++ { 0x7cf, 0x3c3, RTL_GIGA_MAC_VER_21, "RTL8168c/8111c" }, ++ { 0x7c8, 0x3c0, RTL_GIGA_MAC_VER_22, "RTL8168c/8111c" }, ++ ++ /* 8168B family. */ ++ { 0x7c8, 0x380, RTL_GIGA_MAC_VER_17, "RTL8168b/8111b" }, ++ /* This one is very old and rare, support has been removed. ++ * { 0x7c8, 0x300, RTL_GIGA_MAC_VER_11, "RTL8168b/8111b" }, ++ */ ++ ++ /* 8101 family. */ ++ { 0x7c8, 0x448, RTL_GIGA_MAC_VER_39, "RTL8106e", FIRMWARE_8106E_1 }, ++ { 0x7c8, 0x440, RTL_GIGA_MAC_VER_37, "RTL8402", FIRMWARE_8402_1 }, ++ { 0x7cf, 0x409, RTL_GIGA_MAC_VER_29, "RTL8105e", FIRMWARE_8105E_1 }, ++ { 0x7c8, 0x408, RTL_GIGA_MAC_VER_30, "RTL8105e", FIRMWARE_8105E_1 }, ++ { 0x7cf, 0x349, RTL_GIGA_MAC_VER_08, "RTL8102e" }, ++ { 0x7cf, 0x249, RTL_GIGA_MAC_VER_08, "RTL8102e" }, ++ { 0x7cf, 0x348, RTL_GIGA_MAC_VER_07, "RTL8102e" }, ++ { 0x7cf, 0x248, RTL_GIGA_MAC_VER_07, "RTL8102e" }, ++ { 0x7cf, 0x240, RTL_GIGA_MAC_VER_14, "RTL8401" }, ++ { 0x7c8, 0x348, RTL_GIGA_MAC_VER_09, "RTL8102e/RTL8103e" }, ++ { 0x7c8, 0x248, RTL_GIGA_MAC_VER_09, "RTL8102e/RTL8103e" }, ++ { 0x7c8, 0x340, RTL_GIGA_MAC_VER_10, "RTL8101e/RTL8100e" }, ++ ++ /* 8110 family. */ ++ { 0xfc8, 0x980, RTL_GIGA_MAC_VER_06, "RTL8169sc/8110sc" }, ++ { 0xfc8, 0x180, RTL_GIGA_MAC_VER_05, "RTL8169sc/8110sc" }, ++ { 0xfc8, 0x100, RTL_GIGA_MAC_VER_04, "RTL8169sb/8110sb" }, ++ { 0xfc8, 0x040, RTL_GIGA_MAC_VER_03, "RTL8110s" }, ++ { 0xfc8, 0x008, RTL_GIGA_MAC_VER_02, "RTL8169s" }, ++ ++ /* Catch-all */ ++ { 0x000, 0x000, RTL_GIGA_MAC_NONE } + }; + + static const struct pci_device_id rtl8169_pci_tbl[] = { +@@ -2265,151 +2318,30 @@ static const struct ethtool_ops rtl8169_ethtool_ops = { + .get_eth_ctrl_stats = rtl8169_get_eth_ctrl_stats, + }; + +-static enum mac_version rtl8169_get_mac_version(u16 xid, bool gmii) ++static const struct rtl_chip_info *rtl8169_get_chip_version(u16 xid, bool gmii) + { +- /* +- * The driver currently handles the 8168Bf and the 8168Be identically +- * but they can be identified more specifically through the test below +- * if needed: +- * +- * (RTL_R32(tp, TxConfig) & 0x700000) == 0x500000 ? 8168Bf : 8168Be +- * +- * Same thing for the 8101Eb and the 8101Ec: +- * +- * (RTL_R32(tp, TxConfig) & 0x700000) == 0x200000 ? 8101Eb : 8101Ec +- */ +- static const struct rtl_mac_info { +- u16 mask; +- u16 val; +- enum mac_version ver; +- } mac_info[] = { +- /* 8126A family. */ +- { 0x7cf, 0x64a, RTL_GIGA_MAC_VER_71 }, +- { 0x7cf, 0x649, RTL_GIGA_MAC_VER_70 }, +- +- /* 8125BP family. */ +- { 0x7cf, 0x681, RTL_GIGA_MAC_VER_66 }, +- +- /* 8125D family. */ +- { 0x7cf, 0x689, RTL_GIGA_MAC_VER_65 }, +- { 0x7cf, 0x688, RTL_GIGA_MAC_VER_64 }, +- +- /* 8125B family. */ +- { 0x7cf, 0x641, RTL_GIGA_MAC_VER_63 }, +- +- /* 8125A family. */ +- { 0x7cf, 0x609, RTL_GIGA_MAC_VER_61 }, +- /* It seems only XID 609 made it to the mass market. +- * { 0x7cf, 0x608, RTL_GIGA_MAC_VER_60 }, +- * { 0x7c8, 0x608, RTL_GIGA_MAC_VER_61 }, +- */ +- +- /* RTL8117 */ +- { 0x7cf, 0x54b, RTL_GIGA_MAC_VER_53 }, +- { 0x7cf, 0x54a, RTL_GIGA_MAC_VER_52 }, +- +- /* 8168EP family. */ +- { 0x7cf, 0x502, RTL_GIGA_MAC_VER_51 }, +- /* It seems this chip version never made it to +- * the wild. Let's disable detection. +- * { 0x7cf, 0x501, RTL_GIGA_MAC_VER_50 }, +- * { 0x7cf, 0x500, RTL_GIGA_MAC_VER_49 }, +- */ +- +- /* 8168H family. */ +- { 0x7cf, 0x541, RTL_GIGA_MAC_VER_46 }, +- /* It seems this chip version never made it to +- * the wild. Let's disable detection. +- * { 0x7cf, 0x540, RTL_GIGA_MAC_VER_45 }, +- */ +- /* Realtek calls it RTL8168M, but it's handled like RTL8168H */ +- { 0x7cf, 0x6c0, RTL_GIGA_MAC_VER_46 }, +- +- /* 8168G family. */ +- { 0x7cf, 0x5c8, RTL_GIGA_MAC_VER_44 }, +- { 0x7cf, 0x509, RTL_GIGA_MAC_VER_42 }, +- /* It seems this chip version never made it to +- * the wild. Let's disable detection. +- * { 0x7cf, 0x4c1, RTL_GIGA_MAC_VER_41 }, +- */ +- { 0x7cf, 0x4c0, RTL_GIGA_MAC_VER_40 }, +- +- /* 8168F family. */ +- { 0x7c8, 0x488, RTL_GIGA_MAC_VER_38 }, +- { 0x7cf, 0x481, RTL_GIGA_MAC_VER_36 }, +- { 0x7cf, 0x480, RTL_GIGA_MAC_VER_35 }, +- +- /* 8168E family. */ +- { 0x7c8, 0x2c8, RTL_GIGA_MAC_VER_34 }, +- { 0x7cf, 0x2c1, RTL_GIGA_MAC_VER_32 }, +- { 0x7c8, 0x2c0, RTL_GIGA_MAC_VER_33 }, +- +- /* 8168D family. */ +- { 0x7cf, 0x281, RTL_GIGA_MAC_VER_25 }, +- { 0x7c8, 0x280, RTL_GIGA_MAC_VER_26 }, +- +- /* 8168DP family. */ +- /* It seems this early RTL8168dp version never made it to +- * the wild. Support has been removed. +- * { 0x7cf, 0x288, RTL_GIGA_MAC_VER_27 }, +- */ +- { 0x7cf, 0x28a, RTL_GIGA_MAC_VER_28 }, +- { 0x7cf, 0x28b, RTL_GIGA_MAC_VER_31 }, +- +- /* 8168C family. */ +- { 0x7cf, 0x3c9, RTL_GIGA_MAC_VER_23 }, +- { 0x7cf, 0x3c8, RTL_GIGA_MAC_VER_18 }, +- { 0x7c8, 0x3c8, RTL_GIGA_MAC_VER_24 }, +- { 0x7cf, 0x3c0, RTL_GIGA_MAC_VER_19 }, +- { 0x7cf, 0x3c2, RTL_GIGA_MAC_VER_20 }, +- { 0x7cf, 0x3c3, RTL_GIGA_MAC_VER_21 }, +- { 0x7c8, 0x3c0, RTL_GIGA_MAC_VER_22 }, +- +- /* 8168B family. */ +- { 0x7c8, 0x380, RTL_GIGA_MAC_VER_17 }, +- /* This one is very old and rare, support has been removed. +- * { 0x7c8, 0x300, RTL_GIGA_MAC_VER_11 }, +- */ +- +- /* 8101 family. */ +- { 0x7c8, 0x448, RTL_GIGA_MAC_VER_39 }, +- { 0x7c8, 0x440, RTL_GIGA_MAC_VER_37 }, +- { 0x7cf, 0x409, RTL_GIGA_MAC_VER_29 }, +- { 0x7c8, 0x408, RTL_GIGA_MAC_VER_30 }, +- { 0x7cf, 0x349, RTL_GIGA_MAC_VER_08 }, +- { 0x7cf, 0x249, RTL_GIGA_MAC_VER_08 }, +- { 0x7cf, 0x348, RTL_GIGA_MAC_VER_07 }, +- { 0x7cf, 0x248, RTL_GIGA_MAC_VER_07 }, +- { 0x7cf, 0x240, RTL_GIGA_MAC_VER_14 }, +- { 0x7c8, 0x348, RTL_GIGA_MAC_VER_09 }, +- { 0x7c8, 0x248, RTL_GIGA_MAC_VER_09 }, +- { 0x7c8, 0x340, RTL_GIGA_MAC_VER_10 }, +- +- /* 8110 family. */ +- { 0xfc8, 0x980, RTL_GIGA_MAC_VER_06 }, +- { 0xfc8, 0x180, RTL_GIGA_MAC_VER_05 }, +- { 0xfc8, 0x100, RTL_GIGA_MAC_VER_04 }, +- { 0xfc8, 0x040, RTL_GIGA_MAC_VER_03 }, +- { 0xfc8, 0x008, RTL_GIGA_MAC_VER_02 }, +- +- /* Catch-all */ +- { 0x000, 0x000, RTL_GIGA_MAC_NONE } ++ /* Chips combining a 1Gbps MAC with a 100Mbps PHY */ ++ static const struct rtl_chip_info rtl8106eus_info = { ++ .mac_version = RTL_GIGA_MAC_VER_43, ++ .name = "RTL8106eus", ++ .fw_name = FIRMWARE_8106E_2, ++ }; ++ static const struct rtl_chip_info rtl8107e_info = { ++ .mac_version = RTL_GIGA_MAC_VER_48, ++ .name = "RTL8107e", ++ .fw_name = FIRMWARE_8107E_2, + }; +- const struct rtl_mac_info *p = mac_info; +- enum mac_version ver; ++ const struct rtl_chip_info *p = rtl_chip_infos; + + while ((xid & p->mask) != p->val) + p++; +- ver = p->ver; + +- if (ver != RTL_GIGA_MAC_NONE && !gmii) { +- if (ver == RTL_GIGA_MAC_VER_42) +- ver = RTL_GIGA_MAC_VER_43; +- else if (ver == RTL_GIGA_MAC_VER_46) +- ver = RTL_GIGA_MAC_VER_48; +- } ++ if (p->mac_version == RTL_GIGA_MAC_VER_42 && !gmii) ++ return &rtl8106eus_info; ++ if (p->mac_version == RTL_GIGA_MAC_VER_46 && !gmii) ++ return &rtl8107e_info; + +- return ver; ++ return p; + } + + static void rtl_release_firmware(struct rtl8169_private *tp) +@@ -5440,9 +5372,9 @@ static bool rtl_aspm_is_safe(struct rtl8169_private *tp) + + static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) + { ++ const struct rtl_chip_info *chip; + struct rtl8169_private *tp; + int jumbo_max, region, rc; +- enum mac_version chipset; + struct net_device *dev; + u32 txconfig; + u16 xid; +@@ -5492,12 +5424,13 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) + xid = (txconfig >> 20) & 0xfcf; + + /* Identify chip attached to board */ +- chipset = rtl8169_get_mac_version(xid, tp->supports_gmii); +- if (chipset == RTL_GIGA_MAC_NONE) ++ chip = rtl8169_get_chip_version(xid, tp->supports_gmii); ++ if (chip->mac_version == RTL_GIGA_MAC_NONE) + return dev_err_probe(&pdev->dev, -ENODEV, + "unknown chip XID %03x, contact r8169 maintainers (see MAINTAINERS file)\n", + xid); +- tp->mac_version = chipset; ++ tp->mac_version = chip->mac_version; ++ tp->fw_name = chip->fw_name; + + /* Disable ASPM L1 as that cause random device stop working + * problems as well as full system hangs for some PCIe devices users. +@@ -5602,8 +5535,6 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) + + rtl_set_irq_mask(tp); + +- tp->fw_name = rtl_chip_infos[chipset].fw_name; +- + tp->counters = dmam_alloc_coherent (&pdev->dev, sizeof(*tp->counters), + &tp->counters_phys_addr, + GFP_KERNEL); +@@ -5628,7 +5559,7 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) + } + + netdev_info(dev, "%s, %pM, XID %03x, IRQ %d\n", +- rtl_chip_infos[chipset].name, dev->dev_addr, xid, tp->irq); ++ chip->name, dev->dev_addr, xid, tp->irq); + + if (jumbo_max) + netdev_info(dev, "jumbo features [frames: %d bytes, tx checksumming: %s]\n", +-- +2.51.0 + + +From 6d1a8e18dcd206964f87e9b4cf3b0296eb2aea68 Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Tue, 15 Apr 2025 21:39:23 +0200 +Subject: [PATCH 130/517] r8169: add RTL_GIGA_MAC_VER_LAST to facilitate adding + support for new chip versions + +Add a new mac_version enum value RTL_GIGA_MAC_VER_LAST. Benefit is that +when adding support for a new chip version we have to touch less code, +except something changes fundamentally. + +Signed-off-by: Heiner Kallweit +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/06991f47-2aec-4aa2-8918-2c6e79332303@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/realtek/r8169.h | 3 ++- + drivers/net/ethernet/realtek/r8169_main.c | 28 +++++++++++------------ + 2 files changed, 16 insertions(+), 15 deletions(-) + +diff --git a/drivers/net/ethernet/realtek/r8169.h b/drivers/net/ethernet/realtek/r8169.h +index 7a194a8ab989..9f784840ea0d 100644 +--- a/drivers/net/ethernet/realtek/r8169.h ++++ b/drivers/net/ethernet/realtek/r8169.h +@@ -73,7 +73,8 @@ enum mac_version { + RTL_GIGA_MAC_VER_66, + RTL_GIGA_MAC_VER_70, + RTL_GIGA_MAC_VER_71, +- RTL_GIGA_MAC_NONE ++ RTL_GIGA_MAC_NONE, ++ RTL_GIGA_MAC_VER_LAST = RTL_GIGA_MAC_NONE - 1 + }; + + struct rtl8169_private; +diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c +index 140577e626bd..55fd902da0a0 100644 +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -1289,7 +1289,7 @@ static void rtl_writephy(struct rtl8169_private *tp, int location, int val) + case RTL_GIGA_MAC_VER_31: + r8168dp_2_mdio_write(tp, location, val); + break; +- case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_71: ++ case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_LAST: + r8168g_mdio_write(tp, location, val); + break; + default: +@@ -1304,7 +1304,7 @@ static int rtl_readphy(struct rtl8169_private *tp, int location) + case RTL_GIGA_MAC_VER_28: + case RTL_GIGA_MAC_VER_31: + return r8168dp_2_mdio_read(tp, location); +- case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_71: ++ case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_LAST: + return r8168g_mdio_read(tp, location); + default: + return r8169_mdio_read(tp, location); +@@ -1656,7 +1656,7 @@ static void __rtl8169_set_wol(struct rtl8169_private *tp, u32 wolopts) + break; + case RTL_GIGA_MAC_VER_34: + case RTL_GIGA_MAC_VER_37: +- case RTL_GIGA_MAC_VER_39 ... RTL_GIGA_MAC_VER_71: ++ case RTL_GIGA_MAC_VER_39 ... RTL_GIGA_MAC_VER_LAST: + r8169_mod_reg8_cond(tp, Config2, PME_SIGNAL, wolopts); + break; + default: +@@ -2129,7 +2129,7 @@ static void rtl_set_eee_txidle_timer(struct rtl8169_private *tp) + tp->tx_lpi_timer = timer_val; + r8168_mac_ocp_write(tp, 0xe048, timer_val); + break; +- case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_71: ++ case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_LAST: + tp->tx_lpi_timer = timer_val; + RTL_W16(tp, EEE_TXIDLE_TIMER_8125, timer_val); + break; +@@ -2491,7 +2491,7 @@ static void rtl_init_rxcfg(struct rtl8169_private *tp) + case RTL_GIGA_MAC_VER_61: + RTL_W32(tp, RxConfig, RX_FETCH_DFLT_8125 | RX_DMA_BURST); + break; +- case RTL_GIGA_MAC_VER_63 ... RTL_GIGA_MAC_VER_71: ++ case RTL_GIGA_MAC_VER_63 ... RTL_GIGA_MAC_VER_LAST: + RTL_W32(tp, RxConfig, RX_FETCH_DFLT_8125 | RX_DMA_BURST | + RX_PAUSE_SLOT_ON); + break; +@@ -2623,7 +2623,7 @@ static void rtl_wait_txrx_fifo_empty(struct rtl8169_private *tp) + case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_61: + rtl_loop_wait_high(tp, &rtl_rxtx_empty_cond, 100, 42); + break; +- case RTL_GIGA_MAC_VER_63 ... RTL_GIGA_MAC_VER_71: ++ case RTL_GIGA_MAC_VER_63 ... RTL_GIGA_MAC_VER_LAST: + RTL_W8(tp, ChipCmd, RTL_R8(tp, ChipCmd) | StopReq); + rtl_loop_wait_high(tp, &rtl_rxtx_empty_cond, 100, 42); + rtl_loop_wait_high(tp, &rtl_rxtx_empty_cond_2, 100, 42); +@@ -2898,7 +2898,7 @@ static void rtl_enable_exit_l1(struct rtl8169_private *tp) + case RTL_GIGA_MAC_VER_37 ... RTL_GIGA_MAC_VER_38: + rtl_eri_set_bits(tp, 0xd4, 0x0c00); + break; +- case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_71: ++ case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_LAST: + r8168_mac_ocp_modify(tp, 0xc0ac, 0, 0x1f80); + break; + default: +@@ -2912,7 +2912,7 @@ static void rtl_disable_exit_l1(struct rtl8169_private *tp) + case RTL_GIGA_MAC_VER_34 ... RTL_GIGA_MAC_VER_38: + rtl_eri_clear_bits(tp, 0xd4, 0x1f00); + break; +- case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_71: ++ case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_LAST: + r8168_mac_ocp_modify(tp, 0xc0ac, 0x1f80, 0); + break; + default: +@@ -2950,7 +2950,7 @@ static void rtl_hw_aspm_clkreq_enable(struct rtl8169_private *tp, bool enable) + + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_46 ... RTL_GIGA_MAC_VER_48: +- case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_71: ++ case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_LAST: + /* reset ephy tx/rx disable timer */ + r8168_mac_ocp_modify(tp, 0xe094, 0xff00, 0); + /* chip can trigger L1.2 */ +@@ -2962,7 +2962,7 @@ static void rtl_hw_aspm_clkreq_enable(struct rtl8169_private *tp, bool enable) + } else { + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_46 ... RTL_GIGA_MAC_VER_48: +- case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_71: ++ case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_LAST: + r8168_mac_ocp_modify(tp, 0xe092, 0x00ff, 0); + break; + default: +@@ -4094,7 +4094,7 @@ static void rtl8169_cleanup(struct rtl8169_private *tp) + RTL_W8(tp, ChipCmd, RTL_R8(tp, ChipCmd) | StopReq); + rtl_loop_wait_high(tp, &rtl_txcfg_empty_cond, 100, 666); + break; +- case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_71: ++ case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_LAST: + rtl_enable_rxdvgate(tp); + fsleep(2000); + break; +@@ -4251,7 +4251,7 @@ static unsigned int rtl_quirk_packet_padto(struct rtl8169_private *tp, + + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_34: +- case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_71: ++ case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_LAST: + padto = max_t(unsigned int, padto, ETH_ZLEN); + break; + default: +@@ -5302,7 +5302,7 @@ static void rtl_hw_initialize(struct rtl8169_private *tp) + case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_48: + rtl_hw_init_8168g(tp); + break; +- case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_71: ++ case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_LAST: + rtl_hw_init_8125(tp); + break; + default: +@@ -5327,7 +5327,7 @@ static int rtl_jumbo_max(struct rtl8169_private *tp) + case RTL_GIGA_MAC_VER_18 ... RTL_GIGA_MAC_VER_24: + return JUMBO_6K; + /* RTL8125/8126 */ +- case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_71: ++ case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_LAST: + return JUMBO_16K; + default: + return JUMBO_9K; +-- +2.51.0 + + +From 4e4662eb811cb1f8b8d71110751c9e3a8ba11a94 Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Mon, 21 Apr 2025 11:25:18 +0200 +Subject: [PATCH 131/517] r8169: use pci_prepare_to_sleep in rtl_shutdown + +Use pci_prepare_to_sleep() like PCI core does in pci_pm_suspend_noirq. +This aligns setting a low-power mode during shutdown with the handling +of the transition to system suspend. Also the transition to runtime +suspend uses pci_target_state() instead of setting D3hot unconditionally. + +Note: pci_prepare_to_sleep() uses device_may_wakeup() to check whether + device may generate wakeup events. So we don't lose anything by + not passing tp->saved_wolopts any longer. + +Signed-off-by: Heiner Kallweit +Reviewed-by: Jacob Keller +Link: https://patch.msgid.link/f573fdbd-ba6d-41c1-b68f-311d3c88db2c@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/realtek/r8169_main.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c +index 55fd902da0a0..6e353efd342f 100644 +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -5040,10 +5040,8 @@ static void rtl_shutdown(struct pci_dev *pdev) + /* Restore original MAC address */ + rtl_rar_set(tp, tp->dev->perm_addr); + +- if (system_state == SYSTEM_POWER_OFF && !tp->dash_enabled) { +- pci_wake_from_d3(pdev, tp->saved_wolopts); +- pci_set_power_state(pdev, PCI_D3hot); +- } ++ if (system_state == SYSTEM_POWER_OFF && !tp->dash_enabled) ++ pci_prepare_to_sleep(pdev); + } + + static void rtl_remove_one(struct pci_dev *pdev) +-- +2.51.0 + + +From 871a69f8e15d5804a59dca57da8ede9740f16d3f Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Fri, 18 Apr 2025 11:23:45 +0200 +Subject: [PATCH 132/517] r8169: merge chip versions 70 and 71 (RTL8126A) + +Handling of both chip versions is the same, only difference is +the firmware. So we can merge handling of both chip versions. + +Signed-off-by: Heiner Kallweit +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/97d7ae79-d021-4b6b-b424-89e5e305b029@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/realtek/r8169.h | 1 - + drivers/net/ethernet/realtek/r8169_main.c | 15 ++++----------- + drivers/net/ethernet/realtek/r8169_phy_config.c | 1 - + 3 files changed, 4 insertions(+), 13 deletions(-) + +diff --git a/drivers/net/ethernet/realtek/r8169.h b/drivers/net/ethernet/realtek/r8169.h +index 9f784840ea0d..3f7182dc8c9e 100644 +--- a/drivers/net/ethernet/realtek/r8169.h ++++ b/drivers/net/ethernet/realtek/r8169.h +@@ -72,7 +72,6 @@ enum mac_version { + RTL_GIGA_MAC_VER_65, + RTL_GIGA_MAC_VER_66, + RTL_GIGA_MAC_VER_70, +- RTL_GIGA_MAC_VER_71, + RTL_GIGA_MAC_NONE, + RTL_GIGA_MAC_VER_LAST = RTL_GIGA_MAC_NONE - 1 + }; +diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c +index 6e353efd342f..b7ff554ca611 100644 +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -99,7 +99,7 @@ static const struct rtl_chip_info { + const char *fw_name; + } rtl_chip_infos[] = { + /* 8126A family. */ +- { 0x7cf, 0x64a, RTL_GIGA_MAC_VER_71, "RTL8126A", FIRMWARE_8126A_3 }, ++ { 0x7cf, 0x64a, RTL_GIGA_MAC_VER_70, "RTL8126A", FIRMWARE_8126A_3 }, + { 0x7cf, 0x649, RTL_GIGA_MAC_VER_70, "RTL8126A", FIRMWARE_8126A_2 }, + + /* 8125BP family. */ +@@ -2939,7 +2939,6 @@ static void rtl_hw_aspm_clkreq_enable(struct rtl8169_private *tp, bool enable) + rtl_mod_config5(tp, 0, ASPM_en); + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_70: +- case RTL_GIGA_MAC_VER_71: + val8 = RTL_R8(tp, INT_CFG0_8125) | INT_CFG0_CLKREQEN; + RTL_W8(tp, INT_CFG0_8125, val8); + break; +@@ -2971,7 +2970,6 @@ static void rtl_hw_aspm_clkreq_enable(struct rtl8169_private *tp, bool enable) + + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_70: +- case RTL_GIGA_MAC_VER_71: + val8 = RTL_R8(tp, INT_CFG0_8125) & ~INT_CFG0_CLKREQEN; + RTL_W8(tp, INT_CFG0_8125, val8); + break; +@@ -3691,12 +3689,10 @@ static void rtl_hw_start_8125_common(struct rtl8169_private *tp) + /* disable new tx descriptor format */ + r8168_mac_ocp_modify(tp, 0xeb58, 0x0001, 0x0000); + +- if (tp->mac_version == RTL_GIGA_MAC_VER_70 || +- tp->mac_version == RTL_GIGA_MAC_VER_71) ++ if (tp->mac_version == RTL_GIGA_MAC_VER_70) + RTL_W8(tp, 0xD8, RTL_R8(tp, 0xD8) & ~0x02); + +- if (tp->mac_version == RTL_GIGA_MAC_VER_70 || +- tp->mac_version == RTL_GIGA_MAC_VER_71) ++ if (tp->mac_version == RTL_GIGA_MAC_VER_70) + r8168_mac_ocp_modify(tp, 0xe614, 0x0700, 0x0400); + else if (tp->mac_version == RTL_GIGA_MAC_VER_63) + r8168_mac_ocp_modify(tp, 0xe614, 0x0700, 0x0200); +@@ -3714,8 +3710,7 @@ static void rtl_hw_start_8125_common(struct rtl8169_private *tp) + r8168_mac_ocp_modify(tp, 0xe056, 0x00f0, 0x0030); + r8168_mac_ocp_modify(tp, 0xe040, 0x1000, 0x0000); + r8168_mac_ocp_modify(tp, 0xea1c, 0x0003, 0x0001); +- if (tp->mac_version == RTL_GIGA_MAC_VER_70 || +- tp->mac_version == RTL_GIGA_MAC_VER_71) ++ if (tp->mac_version == RTL_GIGA_MAC_VER_70) + r8168_mac_ocp_modify(tp, 0xea1c, 0x0300, 0x0000); + else + r8168_mac_ocp_modify(tp, 0xea1c, 0x0004, 0x0000); +@@ -3838,7 +3833,6 @@ static void rtl_hw_config(struct rtl8169_private *tp) + [RTL_GIGA_MAC_VER_65] = rtl_hw_start_8125d, + [RTL_GIGA_MAC_VER_66] = rtl_hw_start_8125d, + [RTL_GIGA_MAC_VER_70] = rtl_hw_start_8126a, +- [RTL_GIGA_MAC_VER_71] = rtl_hw_start_8126a, + }; + + if (hw_configs[tp->mac_version]) +@@ -3862,7 +3856,6 @@ static void rtl_hw_start_8125(struct rtl8169_private *tp) + break; + case RTL_GIGA_MAC_VER_63: + case RTL_GIGA_MAC_VER_70: +- case RTL_GIGA_MAC_VER_71: + for (i = 0xa00; i < 0xa80; i += 4) + RTL_W32(tp, i, 0); + RTL_W16(tp, INT_CFG1_8125, 0x0000); +diff --git a/drivers/net/ethernet/realtek/r8169_phy_config.c b/drivers/net/ethernet/realtek/r8169_phy_config.c +index 748ca8b212ba..7f513086ba96 100644 +--- a/drivers/net/ethernet/realtek/r8169_phy_config.c ++++ b/drivers/net/ethernet/realtek/r8169_phy_config.c +@@ -1183,7 +1183,6 @@ void r8169_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev, + [RTL_GIGA_MAC_VER_65] = rtl8125d_hw_phy_config, + [RTL_GIGA_MAC_VER_66] = rtl8125bp_hw_phy_config, + [RTL_GIGA_MAC_VER_70] = rtl8126a_hw_phy_config, +- [RTL_GIGA_MAC_VER_71] = rtl8126a_hw_phy_config, + }; + + if (phy_configs[ver]) +-- +2.51.0 + + +From 26be2181b358372db7fb62af9e69d9f4fb70d0b0 Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Fri, 18 Apr 2025 11:24:30 +0200 +Subject: [PATCH 133/517] r8169: merge chip versions 64 and 65 (RTL8125D) + +Handling of both chip versions is the same, only difference is +the firmware. So we can merge handling of both chip versions. + +Signed-off-by: Heiner Kallweit +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/0baad123-c679-4154-923f-fdc12783e900@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/realtek/r8169.h | 1 - + drivers/net/ethernet/realtek/r8169_main.c | 4 +--- + drivers/net/ethernet/realtek/r8169_phy_config.c | 1 - + 3 files changed, 1 insertion(+), 5 deletions(-) + +diff --git a/drivers/net/ethernet/realtek/r8169.h b/drivers/net/ethernet/realtek/r8169.h +index 3f7182dc8c9e..1878c44ece91 100644 +--- a/drivers/net/ethernet/realtek/r8169.h ++++ b/drivers/net/ethernet/realtek/r8169.h +@@ -69,7 +69,6 @@ enum mac_version { + RTL_GIGA_MAC_VER_61, + RTL_GIGA_MAC_VER_63, + RTL_GIGA_MAC_VER_64, +- RTL_GIGA_MAC_VER_65, + RTL_GIGA_MAC_VER_66, + RTL_GIGA_MAC_VER_70, + RTL_GIGA_MAC_NONE, +diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c +index b7ff554ca611..0c5afbc8f5fe 100644 +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -106,7 +106,7 @@ static const struct rtl_chip_info { + { 0x7cf, 0x681, RTL_GIGA_MAC_VER_66, "RTL8125BP", FIRMWARE_8125BP_2 }, + + /* 8125D family. */ +- { 0x7cf, 0x689, RTL_GIGA_MAC_VER_65, "RTL8125D", FIRMWARE_8125D_2 }, ++ { 0x7cf, 0x689, RTL_GIGA_MAC_VER_64, "RTL8125D", FIRMWARE_8125D_2 }, + { 0x7cf, 0x688, RTL_GIGA_MAC_VER_64, "RTL8125D", FIRMWARE_8125D_1 }, + + /* 8125B family. */ +@@ -3830,7 +3830,6 @@ static void rtl_hw_config(struct rtl8169_private *tp) + [RTL_GIGA_MAC_VER_61] = rtl_hw_start_8125a_2, + [RTL_GIGA_MAC_VER_63] = rtl_hw_start_8125b, + [RTL_GIGA_MAC_VER_64] = rtl_hw_start_8125d, +- [RTL_GIGA_MAC_VER_65] = rtl_hw_start_8125d, + [RTL_GIGA_MAC_VER_66] = rtl_hw_start_8125d, + [RTL_GIGA_MAC_VER_70] = rtl_hw_start_8126a, + }; +@@ -3849,7 +3848,6 @@ static void rtl_hw_start_8125(struct rtl8169_private *tp) + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_61: + case RTL_GIGA_MAC_VER_64: +- case RTL_GIGA_MAC_VER_65: + case RTL_GIGA_MAC_VER_66: + for (i = 0xa00; i < 0xb00; i += 4) + RTL_W32(tp, i, 0); +diff --git a/drivers/net/ethernet/realtek/r8169_phy_config.c b/drivers/net/ethernet/realtek/r8169_phy_config.c +index 7f513086ba96..e3adfafa2b1b 100644 +--- a/drivers/net/ethernet/realtek/r8169_phy_config.c ++++ b/drivers/net/ethernet/realtek/r8169_phy_config.c +@@ -1180,7 +1180,6 @@ void r8169_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev, + [RTL_GIGA_MAC_VER_61] = rtl8125a_2_hw_phy_config, + [RTL_GIGA_MAC_VER_63] = rtl8125b_hw_phy_config, + [RTL_GIGA_MAC_VER_64] = rtl8125d_hw_phy_config, +- [RTL_GIGA_MAC_VER_65] = rtl8125d_hw_phy_config, + [RTL_GIGA_MAC_VER_66] = rtl8125bp_hw_phy_config, + [RTL_GIGA_MAC_VER_70] = rtl8126a_hw_phy_config, + }; +-- +2.51.0 + + +From 6d604938ecae971d603aeae185c08c65492c24e4 Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Fri, 18 Apr 2025 11:25:17 +0200 +Subject: [PATCH 134/517] r8169: merge chip versions 52 and 53 (RTL8117) + +Handling of both chip versions is the same, only difference is +the firmware. So we can merge handling of both chip versions. + +Signed-off-by: Heiner Kallweit +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/ae866b71-c904-434e-befb-848c831e33ff@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/realtek/r8169.h | 1 - + drivers/net/ethernet/realtek/r8169_main.c | 17 +++++++---------- + drivers/net/ethernet/realtek/r8169_phy_config.c | 1 - + 3 files changed, 7 insertions(+), 12 deletions(-) + +diff --git a/drivers/net/ethernet/realtek/r8169.h b/drivers/net/ethernet/realtek/r8169.h +index 1878c44ece91..f05231030925 100644 +--- a/drivers/net/ethernet/realtek/r8169.h ++++ b/drivers/net/ethernet/realtek/r8169.h +@@ -64,7 +64,6 @@ enum mac_version { + /* support for RTL_GIGA_MAC_VER_50 has been removed */ + RTL_GIGA_MAC_VER_51, + RTL_GIGA_MAC_VER_52, +- RTL_GIGA_MAC_VER_53, + /* support for RTL_GIGA_MAC_VER_60 has been removed */ + RTL_GIGA_MAC_VER_61, + RTL_GIGA_MAC_VER_63, +diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c +index 0c5afbc8f5fe..1af644a62968 100644 +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -116,7 +116,7 @@ static const struct rtl_chip_info { + { 0x7cf, 0x609, RTL_GIGA_MAC_VER_61, "RTL8125A", FIRMWARE_8125A_3 }, + + /* RTL8117 */ +- { 0x7cf, 0x54b, RTL_GIGA_MAC_VER_53, "RTL8168fp/RTL8117" }, ++ { 0x7cf, 0x54b, RTL_GIGA_MAC_VER_52, "RTL8168fp/RTL8117" }, + { 0x7cf, 0x54a, RTL_GIGA_MAC_VER_52, "RTL8168fp/RTL8117", + FIRMWARE_8168FP_3 }, + +@@ -830,7 +830,7 @@ static bool rtl_is_8168evl_up(struct rtl8169_private *tp) + { + return tp->mac_version >= RTL_GIGA_MAC_VER_34 && + tp->mac_version != RTL_GIGA_MAC_VER_39 && +- tp->mac_version <= RTL_GIGA_MAC_VER_53; ++ tp->mac_version <= RTL_GIGA_MAC_VER_52; + } + + static bool rtl_supports_eee(struct rtl8169_private *tp) +@@ -998,9 +998,7 @@ void r8169_get_led_name(struct rtl8169_private *tp, int idx, + static void r8168fp_adjust_ocp_cmd(struct rtl8169_private *tp, u32 *cmd, int type) + { + /* based on RTL8168FP_OOBMAC_BASE in vendor driver */ +- if (type == ERIAR_OOB && +- (tp->mac_version == RTL_GIGA_MAC_VER_52 || +- tp->mac_version == RTL_GIGA_MAC_VER_53)) ++ if (type == ERIAR_OOB && tp->mac_version == RTL_GIGA_MAC_VER_52) + *cmd |= 0xf70 << 18; + } + +@@ -1500,7 +1498,7 @@ static enum rtl_dash_type rtl_get_dash_type(struct rtl8169_private *tp) + case RTL_GIGA_MAC_VER_28: + case RTL_GIGA_MAC_VER_31: + return RTL_DASH_DP; +- case RTL_GIGA_MAC_VER_51 ... RTL_GIGA_MAC_VER_53: ++ case RTL_GIGA_MAC_VER_51 ... RTL_GIGA_MAC_VER_52: + return RTL_DASH_EP; + case RTL_GIGA_MAC_VER_66: + return RTL_DASH_25_BP; +@@ -2485,7 +2483,7 @@ static void rtl_init_rxcfg(struct rtl8169_private *tp) + case RTL_GIGA_MAC_VER_38: + RTL_W32(tp, RxConfig, RX128_INT_EN | RX_MULTI_EN | RX_DMA_BURST); + break; +- case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_53: ++ case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_52: + RTL_W32(tp, RxConfig, RX128_INT_EN | RX_MULTI_EN | RX_DMA_BURST | RX_EARLY_OFF); + break; + case RTL_GIGA_MAC_VER_61: +@@ -2616,7 +2614,7 @@ DECLARE_RTL_COND(rtl_rxtx_empty_cond_2) + static void rtl_wait_txrx_fifo_empty(struct rtl8169_private *tp) + { + switch (tp->mac_version) { +- case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_53: ++ case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_52: + rtl_loop_wait_high(tp, &rtl_txcfg_empty_cond, 100, 42); + rtl_loop_wait_high(tp, &rtl_rxtx_empty_cond, 100, 42); + break; +@@ -3826,7 +3824,6 @@ static void rtl_hw_config(struct rtl8169_private *tp) + [RTL_GIGA_MAC_VER_48] = rtl_hw_start_8168h_1, + [RTL_GIGA_MAC_VER_51] = rtl_hw_start_8168ep_3, + [RTL_GIGA_MAC_VER_52] = rtl_hw_start_8117, +- [RTL_GIGA_MAC_VER_53] = rtl_hw_start_8117, + [RTL_GIGA_MAC_VER_61] = rtl_hw_start_8125a_2, + [RTL_GIGA_MAC_VER_63] = rtl_hw_start_8125b, + [RTL_GIGA_MAC_VER_64] = rtl_hw_start_8125d, +@@ -5285,7 +5282,7 @@ static void rtl_hw_init_8125(struct rtl8169_private *tp) + static void rtl_hw_initialize(struct rtl8169_private *tp) + { + switch (tp->mac_version) { +- case RTL_GIGA_MAC_VER_51 ... RTL_GIGA_MAC_VER_53: ++ case RTL_GIGA_MAC_VER_51 ... RTL_GIGA_MAC_VER_52: + rtl8168ep_stop_cmac(tp); + fallthrough; + case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_48: +diff --git a/drivers/net/ethernet/realtek/r8169_phy_config.c b/drivers/net/ethernet/realtek/r8169_phy_config.c +index e3adfafa2b1b..5403f8202c79 100644 +--- a/drivers/net/ethernet/realtek/r8169_phy_config.c ++++ b/drivers/net/ethernet/realtek/r8169_phy_config.c +@@ -1176,7 +1176,6 @@ void r8169_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev, + [RTL_GIGA_MAC_VER_48] = rtl8168h_2_hw_phy_config, + [RTL_GIGA_MAC_VER_51] = rtl8168ep_2_hw_phy_config, + [RTL_GIGA_MAC_VER_52] = rtl8117_hw_phy_config, +- [RTL_GIGA_MAC_VER_53] = rtl8117_hw_phy_config, + [RTL_GIGA_MAC_VER_61] = rtl8125a_2_hw_phy_config, + [RTL_GIGA_MAC_VER_63] = rtl8125b_hw_phy_config, + [RTL_GIGA_MAC_VER_64] = rtl8125d_hw_phy_config, +-- +2.51.0 + + +From c3fdac7c0b9944f77753c0293f813b86ea29a0e4 Mon Sep 17 00:00:00 2001 +From: ChunHao Lin +Date: Thu, 15 May 2025 17:53:03 +0800 +Subject: [PATCH 135/517] r8169: add support for RTL8127A + +This adds support for 10Gbs chip RTL8127A. + +Signed-off-by: ChunHao Lin +Reviewed-by: Heiner Kallweit +Link: https://patch.msgid.link/20250515095303.3138-1-hau@realtek.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/realtek/r8169.h | 1 + + drivers/net/ethernet/realtek/r8169_main.c | 29 ++- + .../net/ethernet/realtek/r8169_phy_config.c | 166 ++++++++++++++++++ + 3 files changed, 193 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/realtek/r8169.h b/drivers/net/ethernet/realtek/r8169.h +index f05231030925..2c1a0c21af8d 100644 +--- a/drivers/net/ethernet/realtek/r8169.h ++++ b/drivers/net/ethernet/realtek/r8169.h +@@ -70,6 +70,7 @@ enum mac_version { + RTL_GIGA_MAC_VER_64, + RTL_GIGA_MAC_VER_66, + RTL_GIGA_MAC_VER_70, ++ RTL_GIGA_MAC_VER_80, + RTL_GIGA_MAC_NONE, + RTL_GIGA_MAC_VER_LAST = RTL_GIGA_MAC_NONE - 1 + }; +diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c +index 1af644a62968..c16741eec0bd 100644 +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -60,6 +60,7 @@ + #define FIRMWARE_8125BP_2 "rtl_nic/rtl8125bp-2.fw" + #define FIRMWARE_8126A_2 "rtl_nic/rtl8126a-2.fw" + #define FIRMWARE_8126A_3 "rtl_nic/rtl8126a-3.fw" ++#define FIRMWARE_8127A_1 "rtl_nic/rtl8127a-1.fw" + + #define TX_DMA_BURST 7 /* Maximum PCI burst, '7' is unlimited */ + #define InterFrameGap 0x03 /* 3 means InterFrameGap = the shortest one */ +@@ -98,6 +99,9 @@ static const struct rtl_chip_info { + const char *name; + const char *fw_name; + } rtl_chip_infos[] = { ++ /* 8127A family. */ ++ { 0x7cf, 0x6c9, RTL_GIGA_MAC_VER_80, "RTL8127A", FIRMWARE_8127A_1 }, ++ + /* 8126A family. */ + { 0x7cf, 0x64a, RTL_GIGA_MAC_VER_70, "RTL8126A", FIRMWARE_8126A_3 }, + { 0x7cf, 0x649, RTL_GIGA_MAC_VER_70, "RTL8126A", FIRMWARE_8126A_2 }, +@@ -222,8 +226,10 @@ static const struct pci_device_id rtl8169_pci_tbl[] = { + { 0x0001, 0x8168, PCI_ANY_ID, 0x2410 }, + { PCI_VDEVICE(REALTEK, 0x8125) }, + { PCI_VDEVICE(REALTEK, 0x8126) }, ++ { PCI_VDEVICE(REALTEK, 0x8127) }, + { PCI_VDEVICE(REALTEK, 0x3000) }, + { PCI_VDEVICE(REALTEK, 0x5000) }, ++ { PCI_VDEVICE(REALTEK, 0x0e10) }, + {} + }; + +@@ -769,6 +775,7 @@ MODULE_FIRMWARE(FIRMWARE_8125D_2); + MODULE_FIRMWARE(FIRMWARE_8125BP_2); + MODULE_FIRMWARE(FIRMWARE_8126A_2); + MODULE_FIRMWARE(FIRMWARE_8126A_3); ++MODULE_FIRMWARE(FIRMWARE_8127A_1); + + static inline struct device *tp_to_dev(struct rtl8169_private *tp) + { +@@ -2937,6 +2944,7 @@ static void rtl_hw_aspm_clkreq_enable(struct rtl8169_private *tp, bool enable) + rtl_mod_config5(tp, 0, ASPM_en); + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_70: ++ case RTL_GIGA_MAC_VER_80: + val8 = RTL_R8(tp, INT_CFG0_8125) | INT_CFG0_CLKREQEN; + RTL_W8(tp, INT_CFG0_8125, val8); + break; +@@ -2968,6 +2976,7 @@ static void rtl_hw_aspm_clkreq_enable(struct rtl8169_private *tp, bool enable) + + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_70: ++ case RTL_GIGA_MAC_VER_80: + val8 = RTL_R8(tp, INT_CFG0_8125) & ~INT_CFG0_CLKREQEN; + RTL_W8(tp, INT_CFG0_8125, val8); + break; +@@ -3687,10 +3696,13 @@ static void rtl_hw_start_8125_common(struct rtl8169_private *tp) + /* disable new tx descriptor format */ + r8168_mac_ocp_modify(tp, 0xeb58, 0x0001, 0x0000); + +- if (tp->mac_version == RTL_GIGA_MAC_VER_70) ++ if (tp->mac_version == RTL_GIGA_MAC_VER_70 || ++ tp->mac_version == RTL_GIGA_MAC_VER_80) + RTL_W8(tp, 0xD8, RTL_R8(tp, 0xD8) & ~0x02); + +- if (tp->mac_version == RTL_GIGA_MAC_VER_70) ++ if (tp->mac_version == RTL_GIGA_MAC_VER_80) ++ r8168_mac_ocp_modify(tp, 0xe614, 0x0f00, 0x0f00); ++ else if (tp->mac_version == RTL_GIGA_MAC_VER_70) + r8168_mac_ocp_modify(tp, 0xe614, 0x0700, 0x0400); + else if (tp->mac_version == RTL_GIGA_MAC_VER_63) + r8168_mac_ocp_modify(tp, 0xe614, 0x0700, 0x0200); +@@ -3708,7 +3720,8 @@ static void rtl_hw_start_8125_common(struct rtl8169_private *tp) + r8168_mac_ocp_modify(tp, 0xe056, 0x00f0, 0x0030); + r8168_mac_ocp_modify(tp, 0xe040, 0x1000, 0x0000); + r8168_mac_ocp_modify(tp, 0xea1c, 0x0003, 0x0001); +- if (tp->mac_version == RTL_GIGA_MAC_VER_70) ++ if (tp->mac_version == RTL_GIGA_MAC_VER_70 || ++ tp->mac_version == RTL_GIGA_MAC_VER_80) + r8168_mac_ocp_modify(tp, 0xea1c, 0x0300, 0x0000); + else + r8168_mac_ocp_modify(tp, 0xea1c, 0x0004, 0x0000); +@@ -3786,6 +3799,12 @@ static void rtl_hw_start_8126a(struct rtl8169_private *tp) + rtl_hw_start_8125_common(tp); + } + ++static void rtl_hw_start_8127a(struct rtl8169_private *tp) ++{ ++ rtl_set_def_aspm_entry_latency(tp); ++ rtl_hw_start_8125_common(tp); ++} ++ + static void rtl_hw_config(struct rtl8169_private *tp) + { + static const rtl_generic_fct hw_configs[] = { +@@ -3829,6 +3848,7 @@ static void rtl_hw_config(struct rtl8169_private *tp) + [RTL_GIGA_MAC_VER_64] = rtl_hw_start_8125d, + [RTL_GIGA_MAC_VER_66] = rtl_hw_start_8125d, + [RTL_GIGA_MAC_VER_70] = rtl_hw_start_8126a, ++ [RTL_GIGA_MAC_VER_80] = rtl_hw_start_8127a, + }; + + if (hw_configs[tp->mac_version]) +@@ -3846,8 +3866,11 @@ static void rtl_hw_start_8125(struct rtl8169_private *tp) + case RTL_GIGA_MAC_VER_61: + case RTL_GIGA_MAC_VER_64: + case RTL_GIGA_MAC_VER_66: ++ case RTL_GIGA_MAC_VER_80: + for (i = 0xa00; i < 0xb00; i += 4) + RTL_W32(tp, i, 0); ++ if (tp->mac_version == RTL_GIGA_MAC_VER_80) ++ RTL_W16(tp, INT_CFG1_8125, 0x0000); + break; + case RTL_GIGA_MAC_VER_63: + case RTL_GIGA_MAC_VER_70: +diff --git a/drivers/net/ethernet/realtek/r8169_phy_config.c b/drivers/net/ethernet/realtek/r8169_phy_config.c +index 5403f8202c79..032d9d2cfa2a 100644 +--- a/drivers/net/ethernet/realtek/r8169_phy_config.c ++++ b/drivers/net/ethernet/realtek/r8169_phy_config.c +@@ -1130,6 +1130,171 @@ static void rtl8126a_hw_phy_config(struct rtl8169_private *tp, + rtl8125_common_config_eee_phy(phydev); + } + ++static void rtl8127a_1_hw_phy_config(struct rtl8169_private *tp, ++ struct phy_device *phydev) ++{ ++ r8169_apply_firmware(tp); ++ rtl8168g_enable_gphy_10m(phydev); ++ ++ r8168g_phy_param(phydev, 0x8415, 0xff00, 0x9300); ++ r8168g_phy_param(phydev, 0x81a3, 0xff00, 0x0f00); ++ r8168g_phy_param(phydev, 0x81ae, 0xff00, 0x0f00); ++ r8168g_phy_param(phydev, 0x81b9, 0xff00, 0xb900); ++ rtl8125_phy_param(phydev, 0x83b0, 0x0e00, 0x0000); ++ rtl8125_phy_param(phydev, 0x83C5, 0x0e00, 0x0000); ++ rtl8125_phy_param(phydev, 0x83da, 0x0e00, 0x0000); ++ rtl8125_phy_param(phydev, 0x83ef, 0x0e00, 0x0000); ++ phy_modify_paged(phydev, 0x0bf3, 0x14, 0x01f0, 0x0160); ++ phy_modify_paged(phydev, 0x0bf3, 0x15, 0x001f, 0x0014); ++ phy_modify_paged(phydev, 0x0bf2, 0x14, 0x6000, 0x0000); ++ phy_modify_paged(phydev, 0x0bf2, 0x16, 0xc000, 0x0000); ++ phy_modify_paged(phydev, 0x0bf2, 0x14, 0x1fff, 0x0187); ++ phy_modify_paged(phydev, 0x0bf2, 0x15, 0x003f, 0x0003); ++ ++ r8168g_phy_param(phydev, 0x8173, 0xffff, 0x8620); ++ r8168g_phy_param(phydev, 0x8175, 0xffff, 0x8671); ++ r8168g_phy_param(phydev, 0x817c, 0x0000, 0x2000); ++ r8168g_phy_param(phydev, 0x8187, 0x0000, 0x2000); ++ r8168g_phy_param(phydev, 0x8192, 0x0000, 0x2000); ++ r8168g_phy_param(phydev, 0x819d, 0x0000, 0x2000); ++ r8168g_phy_param(phydev, 0x81a8, 0x2000, 0x0000); ++ r8168g_phy_param(phydev, 0x81b3, 0x2000, 0x0000); ++ r8168g_phy_param(phydev, 0x81be, 0x0000, 0x2000); ++ r8168g_phy_param(phydev, 0x817d, 0xff00, 0xa600); ++ r8168g_phy_param(phydev, 0x8188, 0xff00, 0xa600); ++ r8168g_phy_param(phydev, 0x8193, 0xff00, 0xa600); ++ r8168g_phy_param(phydev, 0x819e, 0xff00, 0xa600); ++ r8168g_phy_param(phydev, 0x81a9, 0xff00, 0x1400); ++ r8168g_phy_param(phydev, 0x81b4, 0xff00, 0x1400); ++ r8168g_phy_param(phydev, 0x81bf, 0xff00, 0xa600); ++ ++ phy_modify_paged(phydev, 0x0aea, 0x15, 0x0028, 0x0000); ++ ++ rtl8125_phy_param(phydev, 0x84f0, 0xffff, 0x201c); ++ rtl8125_phy_param(phydev, 0x84f2, 0xffff, 0x3117); ++ ++ phy_write_paged(phydev, 0x0aec, 0x13, 0x0000); ++ phy_write_paged(phydev, 0x0ae2, 0x10, 0xffff); ++ phy_write_paged(phydev, 0x0aec, 0x17, 0xffff); ++ phy_write_paged(phydev, 0x0aed, 0x11, 0xffff); ++ phy_write_paged(phydev, 0x0aec, 0x14, 0x0000); ++ phy_modify_paged(phydev, 0x0aed, 0x10, 0x0001, 0x0000); ++ phy_write_paged(phydev, 0x0adb, 0x14, 0x0150); ++ rtl8125_phy_param(phydev, 0x8197, 0xff00, 0x5000); ++ rtl8125_phy_param(phydev, 0x8231, 0xff00, 0x5000); ++ rtl8125_phy_param(phydev, 0x82cb, 0xff00, 0x5000); ++ rtl8125_phy_param(phydev, 0x82cd, 0xff00, 0x5700); ++ rtl8125_phy_param(phydev, 0x8233, 0xff00, 0x5700); ++ rtl8125_phy_param(phydev, 0x8199, 0xff00, 0x5700); ++ ++ rtl8125_phy_param(phydev, 0x815a, 0xffff, 0x0150); ++ rtl8125_phy_param(phydev, 0x81f4, 0xffff, 0x0150); ++ rtl8125_phy_param(phydev, 0x828e, 0xffff, 0x0150); ++ rtl8125_phy_param(phydev, 0x81b1, 0xffff, 0x0000); ++ rtl8125_phy_param(phydev, 0x824b, 0xffff, 0x0000); ++ rtl8125_phy_param(phydev, 0x82e5, 0xffff, 0x0000); ++ ++ rtl8125_phy_param(phydev, 0x84f7, 0xff00, 0x2800); ++ phy_modify_paged(phydev, 0x0aec, 0x11, 0x0000, 0x1000); ++ rtl8125_phy_param(phydev, 0x81b3, 0xff00, 0xad00); ++ rtl8125_phy_param(phydev, 0x824d, 0xff00, 0xad00); ++ rtl8125_phy_param(phydev, 0x82e7, 0xff00, 0xad00); ++ phy_modify_paged(phydev, 0x0ae4, 0x17, 0x000f, 0x0001); ++ rtl8125_phy_param(phydev, 0x82ce, 0xf000, 0x4000); ++ ++ rtl8125_phy_param(phydev, 0x84ac, 0xffff, 0x0000); ++ rtl8125_phy_param(phydev, 0x84ae, 0xffff, 0x0000); ++ rtl8125_phy_param(phydev, 0x84b0, 0xffff, 0xf818); ++ rtl8125_phy_param(phydev, 0x84b2, 0xff00, 0x6000); ++ ++ rtl8125_phy_param(phydev, 0x8ffc, 0xffff, 0x6008); ++ rtl8125_phy_param(phydev, 0x8ffe, 0xffff, 0xf450); ++ ++ rtl8125_phy_param(phydev, 0x8015, 0x0000, 0x0200); ++ rtl8125_phy_param(phydev, 0x8016, 0x0800, 0x0000); ++ rtl8125_phy_param(phydev, 0x8fe6, 0xff00, 0x0800); ++ rtl8125_phy_param(phydev, 0x8fe4, 0xffff, 0x2114); ++ ++ rtl8125_phy_param(phydev, 0x8647, 0xffff, 0xa7b1); ++ rtl8125_phy_param(phydev, 0x8649, 0xffff, 0xbbca); ++ rtl8125_phy_param(phydev, 0x864b, 0xff00, 0xdc00); ++ ++ rtl8125_phy_param(phydev, 0x8154, 0xc000, 0x4000); ++ rtl8125_phy_param(phydev, 0x8158, 0xc000, 0x0000); ++ ++ rtl8125_phy_param(phydev, 0x826c, 0xffff, 0xffff); ++ rtl8125_phy_param(phydev, 0x826e, 0xffff, 0xffff); ++ ++ rtl8125_phy_param(phydev, 0x8872, 0xff00, 0x0e00); ++ r8168g_phy_param(phydev, 0x8012, 0x0000, 0x0800); ++ r8168g_phy_param(phydev, 0x8012, 0x0000, 0x4000); ++ phy_modify_paged(phydev, 0x0b57, 0x13, 0x0000, 0x0001); ++ r8168g_phy_param(phydev, 0x834a, 0xff00, 0x0700); ++ rtl8125_phy_param(phydev, 0x8217, 0x3f00, 0x2a00); ++ r8168g_phy_param(phydev, 0x81b1, 0xff00, 0x0b00); ++ rtl8125_phy_param(phydev, 0x8fed, 0xff00, 0x4e00); ++ ++ rtl8125_phy_param(phydev, 0x88ac, 0xff00, 0x2300); ++ phy_modify_paged(phydev, 0x0bf0, 0x16, 0x0000, 0x3800); ++ rtl8125_phy_param(phydev, 0x88de, 0xff00, 0x0000); ++ rtl8125_phy_param(phydev, 0x80b4, 0xffff, 0x5195); ++ ++ r8168g_phy_param(phydev, 0x8370, 0xffff, 0x8671); ++ r8168g_phy_param(phydev, 0x8372, 0xffff, 0x86c8); ++ ++ r8168g_phy_param(phydev, 0x8401, 0xffff, 0x86c8); ++ r8168g_phy_param(phydev, 0x8403, 0xffff, 0x86da); ++ r8168g_phy_param(phydev, 0x8406, 0x1800, 0x1000); ++ r8168g_phy_param(phydev, 0x8408, 0x1800, 0x1000); ++ r8168g_phy_param(phydev, 0x840a, 0x1800, 0x1000); ++ r8168g_phy_param(phydev, 0x840c, 0x1800, 0x1000); ++ r8168g_phy_param(phydev, 0x840e, 0x1800, 0x1000); ++ r8168g_phy_param(phydev, 0x8410, 0x1800, 0x1000); ++ r8168g_phy_param(phydev, 0x8412, 0x1800, 0x1000); ++ r8168g_phy_param(phydev, 0x8414, 0x1800, 0x1000); ++ r8168g_phy_param(phydev, 0x8416, 0x1800, 0x1000); ++ ++ r8168g_phy_param(phydev, 0x82bd, 0xffff, 0x1f40); ++ ++ phy_modify_paged(phydev, 0x0bfb, 0x12, 0x07ff, 0x0328); ++ phy_write_paged(phydev, 0x0bfb, 0x13, 0x3e14); ++ ++ r8168g_phy_param(phydev, 0x81c4, 0xffff, 0x003b); ++ r8168g_phy_param(phydev, 0x81c6, 0xffff, 0x0086); ++ r8168g_phy_param(phydev, 0x81c8, 0xffff, 0x00b7); ++ r8168g_phy_param(phydev, 0x81ca, 0xffff, 0x00db); ++ r8168g_phy_param(phydev, 0x81cc, 0xffff, 0x00fe); ++ r8168g_phy_param(phydev, 0x81ce, 0xffff, 0x00fe); ++ r8168g_phy_param(phydev, 0x81d0, 0xffff, 0x00fe); ++ r8168g_phy_param(phydev, 0x81d2, 0xffff, 0x00fe); ++ r8168g_phy_param(phydev, 0x81d4, 0xffff, 0x00c3); ++ r8168g_phy_param(phydev, 0x81d6, 0xffff, 0x0078); ++ r8168g_phy_param(phydev, 0x81d8, 0xffff, 0x0047); ++ r8168g_phy_param(phydev, 0x81da, 0xffff, 0x0023); ++ ++ rtl8125_phy_param(phydev, 0x88d7, 0xffff, 0x01a0); ++ rtl8125_phy_param(phydev, 0x88d9, 0xffff, 0x01a0); ++ rtl8125_phy_param(phydev, 0x8ffa, 0xffff, 0x002a); ++ ++ rtl8125_phy_param(phydev, 0x8fee, 0xffff, 0xffdf); ++ rtl8125_phy_param(phydev, 0x8ff0, 0xffff, 0xffff); ++ rtl8125_phy_param(phydev, 0x8ff2, 0xffff, 0x0a4a); ++ rtl8125_phy_param(phydev, 0x8ff4, 0xffff, 0xaa5a); ++ rtl8125_phy_param(phydev, 0x8ff6, 0xffff, 0x0a4a); ++ ++ rtl8125_phy_param(phydev, 0x8ff8, 0xffff, 0xaa5a); ++ rtl8125_phy_param(phydev, 0x88d5, 0xff00, 0x0200); ++ ++ r8168g_phy_param(phydev, 0x84bb, 0xff00, 0x0a00); ++ r8168g_phy_param(phydev, 0x84c0, 0xff00, 0x1600); ++ ++ phy_modify_paged(phydev, 0x0a43, 0x10, 0x0000, 0x0003); ++ ++ rtl8125_legacy_force_mode(phydev); ++ rtl8168g_disable_aldps(phydev); ++ rtl8125_common_config_eee_phy(phydev); ++} ++ + void r8169_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev, + enum mac_version ver) + { +@@ -1181,6 +1346,7 @@ void r8169_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev, + [RTL_GIGA_MAC_VER_64] = rtl8125d_hw_phy_config, + [RTL_GIGA_MAC_VER_66] = rtl8125bp_hw_phy_config, + [RTL_GIGA_MAC_VER_70] = rtl8126a_hw_phy_config, ++ [RTL_GIGA_MAC_VER_80] = rtl8127a_1_hw_phy_config, + }; + + if (phy_configs[ver]) +-- +2.51.0 + + +From 76bb2f3d8a700c0e1e0de6582d7c4469d51dbee6 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Thu, 10 Oct 2024 14:07:16 +0100 +Subject: [PATCH 136/517] net: phy: realtek: read duplex and gbit master from + PHYSR register + +The PHYSR MMD register is present and defined equally for all RTL82xx +Ethernet PHYs. +Read duplex and Gbit master bits from rtlgen_decode_speed() and rename +it to rtlgen_decode_physr(). + +Signed-off-by: Daniel Golle +Link: https://patch.msgid.link/b9a76341da851a18c985bc4774fa295babec79bb.1728565530.git.daniel@makrotopia.org +Signed-off-by: Paolo Abeni +--- + drivers/net/phy/realtek.c | 41 +++++++++++++++++++++++++++++++-------- + 1 file changed, 33 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c +index 8ce5705af69c..f620cd7b17c8 100644 +--- a/drivers/net/phy/realtek.c ++++ b/drivers/net/phy/realtek.c +@@ -80,15 +80,18 @@ + + #define RTL822X_VND2_GANLPAR 0xa414 + +-#define RTL822X_VND2_PHYSR 0xa434 +- + #define RTL8366RB_POWER_SAVE 0x15 + #define RTL8366RB_POWER_SAVE_ON BIT(12) + + #define RTL9000A_GINMR 0x14 + #define RTL9000A_GINMR_LINK_STATUS BIT(4) + +-#define RTLGEN_SPEED_MASK 0x0630 ++#define RTL_VND2_PHYSR 0xa434 ++#define RTL_VND2_PHYSR_DUPLEX BIT(3) ++#define RTL_VND2_PHYSR_SPEEDL GENMASK(5, 4) ++#define RTL_VND2_PHYSR_SPEEDH GENMASK(10, 9) ++#define RTL_VND2_PHYSR_MASTER BIT(11) ++#define RTL_VND2_PHYSR_SPEED_MASK (RTL_VND2_PHYSR_SPEEDL | RTL_VND2_PHYSR_SPEEDH) + + #define RTL_GENERIC_PHYID 0x001cc800 + #define RTL_8211FVD_PHYID 0x001cc878 +@@ -661,9 +664,18 @@ static int rtl8366rb_config_init(struct phy_device *phydev) + } + + /* get actual speed to cover the downshift case */ +-static void rtlgen_decode_speed(struct phy_device *phydev, int val) ++static void rtlgen_decode_physr(struct phy_device *phydev, int val) + { +- switch (val & RTLGEN_SPEED_MASK) { ++ /* bit 3 ++ * 0: Half Duplex ++ * 1: Full Duplex ++ */ ++ if (val & RTL_VND2_PHYSR_DUPLEX) ++ phydev->duplex = DUPLEX_FULL; ++ else ++ phydev->duplex = DUPLEX_HALF; ++ ++ switch (val & RTL_VND2_PHYSR_SPEED_MASK) { + case 0x0000: + phydev->speed = SPEED_10; + break; +@@ -685,6 +697,19 @@ static void rtlgen_decode_speed(struct phy_device *phydev, int val) + default: + break; + } ++ ++ /* bit 11 ++ * 0: Slave Mode ++ * 1: Master Mode ++ */ ++ if (phydev->speed >= 1000) { ++ if (val & RTL_VND2_PHYSR_MASTER) ++ phydev->master_slave_state = MASTER_SLAVE_STATE_MASTER; ++ else ++ phydev->master_slave_state = MASTER_SLAVE_STATE_SLAVE; ++ } else { ++ phydev->master_slave_state = MASTER_SLAVE_STATE_UNSUPPORTED; ++ } + } + + static int rtlgen_read_status(struct phy_device *phydev) +@@ -702,7 +727,7 @@ static int rtlgen_read_status(struct phy_device *phydev) + if (val < 0) + return val; + +- rtlgen_decode_speed(phydev, val); ++ rtlgen_decode_physr(phydev, val); + + return 0; + } +@@ -1008,11 +1033,11 @@ static int rtl822x_c45_read_status(struct phy_device *phydev) + return 0; + + /* Read actual speed from vendor register. */ +- val = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL822X_VND2_PHYSR); ++ val = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL_VND2_PHYSR); + if (val < 0) + return val; + +- rtlgen_decode_speed(phydev, val); ++ rtlgen_decode_physr(phydev, val); + + return 0; + } +-- +2.51.0 + + +From 8044888966fcc83cca44c0ed9d74bfbc9b342d31 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Thu, 10 Oct 2024 14:07:26 +0100 +Subject: [PATCH 137/517] net: phy: realtek: change order of calls in C22 + read_status() + +Always call rtlgen_read_status() first, so genphy_read_status() which +is called by it clears bits in case auto-negotiation has not completed. +Also clear 10GBT link-partner advertisement bits in case auto-negotiation +is disabled or has not completed. + +Suggested-by: Russell King (Oracle) +Signed-off-by: Daniel Golle +Link: https://patch.msgid.link/b15929a41621d215c6b2b57393368086589569ec.1728565530.git.daniel@makrotopia.org +Signed-off-by: Paolo Abeni +--- + drivers/net/phy/realtek.c | 22 +++++++++++++++------- + 1 file changed, 15 insertions(+), 7 deletions(-) + +diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c +index f620cd7b17c8..c724ab0c4501 100644 +--- a/drivers/net/phy/realtek.c ++++ b/drivers/net/phy/realtek.c +@@ -950,17 +950,25 @@ static void rtl822xb_update_interface(struct phy_device *phydev) + + static int rtl822x_read_status(struct phy_device *phydev) + { +- if (phydev->autoneg == AUTONEG_ENABLE) { +- int lpadv = phy_read_paged(phydev, 0xa5d, 0x13); ++ int lpadv, ret; + +- if (lpadv < 0) +- return lpadv; ++ ret = rtlgen_read_status(phydev); ++ if (ret < 0) ++ return ret; + +- mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising, +- lpadv); ++ if (phydev->autoneg == AUTONEG_DISABLE || ++ !phydev->autoneg_complete) { ++ mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising, 0); ++ return 0; + } + +- return rtlgen_read_status(phydev); ++ lpadv = phy_read_paged(phydev, 0xa5d, 0x13); ++ if (lpadv < 0) ++ return lpadv; ++ ++ mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising, lpadv); ++ ++ return 0; + } + + static int rtl822xb_read_status(struct phy_device *phydev) +-- +2.51.0 + + +From 12f9b03a9a0219fb6995129ff24d18858903e949 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Thu, 10 Oct 2024 14:07:39 +0100 +Subject: [PATCH 138/517] net: phy: realtek: clear 1000Base-T link partner + advertisement + +Clear 1000Base-T link partner advertisement bits in Clause-45 +read_status() function in case auto-negotiation is disabled or has not +been completed. + +Signed-off-by: Daniel Golle +Link: https://patch.msgid.link/9dc9b47b2d675708afef3ad366bfd78eb584d958.1728565530.git.daniel@makrotopia.org +Signed-off-by: Paolo Abeni +--- + drivers/net/phy/realtek.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c +index c724ab0c4501..f65d7f1f348e 100644 +--- a/drivers/net/phy/realtek.c ++++ b/drivers/net/phy/realtek.c +@@ -1027,6 +1027,10 @@ static int rtl822x_c45_read_status(struct phy_device *phydev) + if (ret < 0) + return ret; + ++ if (phydev->autoneg == AUTONEG_DISABLE || ++ !genphy_c45_aneg_done(phydev)) ++ mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, 0); ++ + /* Vendor register as C45 has no standardized support for 1000BaseT */ + if (phydev->autoneg == AUTONEG_ENABLE) { + val = phy_read_mmd(phydev, MDIO_MMD_VEND2, +-- +2.51.0 + + +From af5aaa6a8e593cc32687a2d570336c20a446b23a Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Sat, 11 Jan 2025 21:49:31 +0100 +Subject: [PATCH 139/517] net: phy: realtek: add support for reading + MDIO_MMD_VEND2 regs on RTL8125/RTL8126 + +RTL8125/RTL8126 don't support MMD access to the internal PHY, but +provide a mechanism to access at least all MDIO_MMD_VEND2 registers. +By exposing this mechanism standard MMD access functions can be used +to access the MDIO_MMD_VEND2 registers. + +Signed-off-by: Heiner Kallweit +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/e821b302-5fe6-49ab-aabd-05da500581c0@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/realtek.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c +index f65d7f1f348e..af9874143f0c 100644 +--- a/drivers/net/phy/realtek.c ++++ b/drivers/net/phy/realtek.c +@@ -736,7 +736,11 @@ static int rtlgen_read_mmd(struct phy_device *phydev, int devnum, u16 regnum) + { + int ret; + +- if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE) { ++ if (devnum == MDIO_MMD_VEND2) { ++ rtl821x_write_page(phydev, regnum >> 4); ++ ret = __phy_read(phydev, 0x10 + ((regnum & 0xf) >> 1)); ++ rtl821x_write_page(phydev, 0); ++ } else if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE) { + rtl821x_write_page(phydev, 0xa5c); + ret = __phy_read(phydev, 0x12); + rtl821x_write_page(phydev, 0); +@@ -760,7 +764,11 @@ static int rtlgen_write_mmd(struct phy_device *phydev, int devnum, u16 regnum, + { + int ret; + +- if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) { ++ if (devnum == MDIO_MMD_VEND2) { ++ rtl821x_write_page(phydev, regnum >> 4); ++ ret = __phy_write(phydev, 0x10 + ((regnum & 0xf) >> 1), val); ++ rtl821x_write_page(phydev, 0); ++ } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) { + rtl821x_write_page(phydev, 0xa5d); + ret = __phy_write(phydev, 0x10, val); + rtl821x_write_page(phydev, 0); +-- +2.51.0 + + +From 99f16566ae0a8e2efe07c07dc3bdfa47c42563d0 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Wed, 15 Jan 2025 14:43:35 +0000 +Subject: [PATCH 140/517] net: phy: realtek: clear 1000Base-T lpa if link is + down + +Only read 1000Base-T link partner advertisement if autonegotiation has +completed and otherwise 1000Base-T link partner advertisement bits. + +This fixes bogus 1000Base-T link partner advertisement after link goes +down (eg. by disconnecting the wire). +Fixes: 5cb409b3960e ("net: phy: realtek: clear 1000Base-T link partner advertisement") +Signed-off-by: Daniel Golle +Reviewed-by: Michal Swiatkowski +Signed-off-by: David S. Miller +--- + drivers/net/phy/realtek.c | 19 ++++++++----------- + 1 file changed, 8 insertions(+), 11 deletions(-) + +diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c +index af9874143f0c..201c10f3718a 100644 +--- a/drivers/net/phy/realtek.c ++++ b/drivers/net/phy/realtek.c +@@ -1031,23 +1031,20 @@ static int rtl822x_c45_read_status(struct phy_device *phydev) + { + int ret, val; + +- ret = genphy_c45_read_status(phydev); +- if (ret < 0) +- return ret; +- +- if (phydev->autoneg == AUTONEG_DISABLE || +- !genphy_c45_aneg_done(phydev)) +- mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, 0); +- + /* Vendor register as C45 has no standardized support for 1000BaseT */ +- if (phydev->autoneg == AUTONEG_ENABLE) { ++ if (phydev->autoneg == AUTONEG_ENABLE && genphy_c45_aneg_done(phydev)) { + val = phy_read_mmd(phydev, MDIO_MMD_VEND2, + RTL822X_VND2_GANLPAR); + if (val < 0) + return val; +- +- mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, val); ++ } else { ++ val = 0; + } ++ mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, val); ++ ++ ret = genphy_c45_read_status(phydev); ++ if (ret < 0) ++ return ret; + + if (!phydev->link) + return 0; +-- +2.51.0 + + +From 2020fe683da044996ed029f65c578d58f01b6a34 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Wed, 15 Jan 2025 14:43:43 +0000 +Subject: [PATCH 141/517] net: phy: realtek: clear master_slave_state if link + is down + +rtlgen_decode_physr() which sets master_slave_state isn't called in case +the link is down and other than rtlgen_read_status(), +rtl822x_c45_read_status() doesn't implicitely clear master_slave_state. + +Avoid stale master_slave_state by always setting it to +MASTER_SLAVE_STATE_UNKNOWN in rtl822x_c45_read_status() in case the link +is down. + +Fixes: 081c9c0265c9 ("net: phy: realtek: read duplex and gbit master from PHYSR register") +Signed-off-by: Daniel Golle +Reviewed-by: Michal Swiatkowski +Signed-off-by: David S. Miller +--- + drivers/net/phy/realtek.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c +index 201c10f3718a..138e608c4043 100644 +--- a/drivers/net/phy/realtek.c ++++ b/drivers/net/phy/realtek.c +@@ -1046,8 +1046,10 @@ static int rtl822x_c45_read_status(struct phy_device *phydev) + if (ret < 0) + return ret; + +- if (!phydev->link) ++ if (!phydev->link) { ++ phydev->master_slave_state = MASTER_SLAVE_STATE_UNKNOWN; + return 0; ++ } + + /* Read actual speed from vendor register. */ + val = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL_VND2_PHYSR); +-- +2.51.0 + + +From cb90466e609fa150db720a90f4a79a3b1c1899a2 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Wed, 15 Jan 2025 14:45:00 +0000 +Subject: [PATCH 142/517] net: phy: realtek: always clear NBase-T lpa + +Clear NBase-T link partner advertisement before calling +rtlgen_read_status() to avoid phy_resolve_aneg_linkmode() wrongly +setting speed and duplex. + +This fixes bogus 2.5G/5G/10G link partner advertisement and thus +speed and duplex being set by phy_resolve_aneg_linkmode() due to stale +NBase-T lpa. + +Fixes: 68d5cd09e891 ("net: phy: realtek: change order of calls in C22 read_status()") +Signed-off-by: Daniel Golle +Reviewed-by: Michal Swiatkowski +Signed-off-by: David S. Miller +--- + drivers/net/phy/realtek.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c +index 138e608c4043..44c7bdb88d76 100644 +--- a/drivers/net/phy/realtek.c ++++ b/drivers/net/phy/realtek.c +@@ -960,15 +960,15 @@ static int rtl822x_read_status(struct phy_device *phydev) + { + int lpadv, ret; + ++ mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising, 0); ++ + ret = rtlgen_read_status(phydev); + if (ret < 0) + return ret; + + if (phydev->autoneg == AUTONEG_DISABLE || +- !phydev->autoneg_complete) { +- mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising, 0); ++ !phydev->autoneg_complete) + return 0; +- } + + lpadv = phy_read_paged(phydev, 0xa5d, 0x13); + if (lpadv < 0) +-- +2.51.0 + + +From 4ea28dcb44149566275d2f6ef46787057043cdb2 Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Sat, 11 Jan 2025 21:50:19 +0100 +Subject: [PATCH 143/517] net: phy: move realtek PHY driver to its own + subdirectory + +In preparation of adding a source file with hwmon support, move the +Realtek PHY driver to its own subdirectory and rename realtek.c to +realtek_main.c. + +Signed-off-by: Heiner Kallweit +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/c566551b-c915-4e34-9b33-129a6ddd6e4c@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/Kconfig | 5 +---- + drivers/net/phy/Makefile | 2 +- + drivers/net/phy/realtek/Kconfig | 5 +++++ + drivers/net/phy/realtek/Makefile | 3 +++ + drivers/net/phy/{realtek.c => realtek/realtek_main.c} | 0 + 5 files changed, 10 insertions(+), 5 deletions(-) + create mode 100644 drivers/net/phy/realtek/Kconfig + create mode 100644 drivers/net/phy/realtek/Makefile + rename drivers/net/phy/{realtek.c => realtek/realtek_main.c} (100%) + +diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig +index 4e78a4d8fd2a..f7e21a2761b8 100644 +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -343,10 +343,7 @@ config QSEMI_PHY + help + Currently supports the qs6612 + +-config REALTEK_PHY +- tristate "Realtek PHYs" +- help +- Supports the Realtek 821x PHY. ++source "drivers/net/phy/realtek/Kconfig" + + config RENESAS_PHY + tristate "Renesas PHYs" +diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile +index e6145153e837..a38b01f74db7 100644 +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -94,7 +94,7 @@ obj-$(CONFIG_NXP_CBTX_PHY) += nxp-cbtx.o + obj-$(CONFIG_NXP_TJA11XX_PHY) += nxp-tja11xx.o + obj-y += qcom/ + obj-$(CONFIG_QSEMI_PHY) += qsemi.o +-obj-$(CONFIG_REALTEK_PHY) += realtek.o ++obj-$(CONFIG_REALTEK_PHY) += realtek/ + obj-$(CONFIG_RENESAS_PHY) += uPD60620.o + obj-$(CONFIG_ROCKCHIP_PHY) += rockchip.o + obj-$(CONFIG_SMSC_PHY) += smsc.o +diff --git a/drivers/net/phy/realtek/Kconfig b/drivers/net/phy/realtek/Kconfig +new file mode 100644 +index 000000000000..5b9e6e6db834 +--- /dev/null ++++ b/drivers/net/phy/realtek/Kconfig +@@ -0,0 +1,5 @@ ++# SPDX-License-Identifier: GPL-2.0-only ++config REALTEK_PHY ++ tristate "Realtek PHYs" ++ help ++ Currently supports RTL821x/RTL822x and fast ethernet PHYs +diff --git a/drivers/net/phy/realtek/Makefile b/drivers/net/phy/realtek/Makefile +new file mode 100644 +index 000000000000..996a80642431 +--- /dev/null ++++ b/drivers/net/phy/realtek/Makefile +@@ -0,0 +1,3 @@ ++# SPDX-License-Identifier: GPL-2.0 ++realtek-y += realtek_main.o ++obj-$(CONFIG_REALTEK_PHY) += realtek.o +diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek/realtek_main.c +similarity index 100% +rename from drivers/net/phy/realtek.c +rename to drivers/net/phy/realtek/realtek_main.c +-- +2.51.0 + + +From 4dd3c0207f8b32828710d42d82ba2fa24497dcf4 Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Sat, 11 Jan 2025 21:51:24 +0100 +Subject: [PATCH 144/517] net: phy: realtek: add hwmon support for temp sensor + on RTL822x + +This adds hwmon support for the temperature sensor on RTL822x. +It's available on the standalone versions of the PHY's, and on +the integrated PHY's in RTL8125B/RTL8125D/RTL8126. + +Signed-off-by: Heiner Kallweit +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/ad6bfe9f-6375-4a00-84b4-bfb38a21bd71@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/realtek/Kconfig | 6 ++ + drivers/net/phy/realtek/Makefile | 1 + + drivers/net/phy/realtek/realtek.h | 10 ++++ + drivers/net/phy/realtek/realtek_hwmon.c | 79 +++++++++++++++++++++++++ + drivers/net/phy/realtek/realtek_main.c | 12 ++++ + 5 files changed, 108 insertions(+) + create mode 100644 drivers/net/phy/realtek/realtek.h + create mode 100644 drivers/net/phy/realtek/realtek_hwmon.c + +diff --git a/drivers/net/phy/realtek/Kconfig b/drivers/net/phy/realtek/Kconfig +index 5b9e6e6db834..31935f147d87 100644 +--- a/drivers/net/phy/realtek/Kconfig ++++ b/drivers/net/phy/realtek/Kconfig +@@ -3,3 +3,9 @@ config REALTEK_PHY + tristate "Realtek PHYs" + help + Currently supports RTL821x/RTL822x and fast ethernet PHYs ++ ++config REALTEK_PHY_HWMON ++ def_bool REALTEK_PHY && HWMON ++ depends on !(REALTEK_PHY=y && HWMON=m) ++ help ++ Optional hwmon support for the temperature sensor +diff --git a/drivers/net/phy/realtek/Makefile b/drivers/net/phy/realtek/Makefile +index 996a80642431..dd21cf87f2f1 100644 +--- a/drivers/net/phy/realtek/Makefile ++++ b/drivers/net/phy/realtek/Makefile +@@ -1,3 +1,4 @@ + # SPDX-License-Identifier: GPL-2.0 + realtek-y += realtek_main.o ++realtek-$(CONFIG_REALTEK_PHY_HWMON) += realtek_hwmon.o + obj-$(CONFIG_REALTEK_PHY) += realtek.o +diff --git a/drivers/net/phy/realtek/realtek.h b/drivers/net/phy/realtek/realtek.h +new file mode 100644 +index 000000000000..a39b44fa18a0 +--- /dev/null ++++ b/drivers/net/phy/realtek/realtek.h +@@ -0,0 +1,10 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++ ++#ifndef REALTEK_H ++#define REALTEK_H ++ ++#include ++ ++int rtl822x_hwmon_init(struct phy_device *phydev); ++ ++#endif /* REALTEK_H */ +diff --git a/drivers/net/phy/realtek/realtek_hwmon.c b/drivers/net/phy/realtek/realtek_hwmon.c +new file mode 100644 +index 000000000000..1ecb410bb941 +--- /dev/null ++++ b/drivers/net/phy/realtek/realtek_hwmon.c +@@ -0,0 +1,79 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * HWMON support for Realtek PHY's ++ * ++ * Author: Heiner Kallweit ++ */ ++ ++#include ++#include ++ ++#include "realtek.h" ++ ++#define RTL822X_VND2_TSALRM 0xa662 ++#define RTL822X_VND2_TSRR 0xbd84 ++#define RTL822X_VND2_TSSR 0xb54c ++ ++static int rtl822x_hwmon_get_temp(int raw) ++{ ++ if (raw >= 512) ++ raw -= 1024; ++ ++ return 1000 * raw / 2; ++} ++ ++static int rtl822x_hwmon_read(struct device *dev, enum hwmon_sensor_types type, ++ u32 attr, int channel, long *val) ++{ ++ struct phy_device *phydev = dev_get_drvdata(dev); ++ int raw; ++ ++ switch (attr) { ++ case hwmon_temp_input: ++ raw = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL822X_VND2_TSRR) & 0x3ff; ++ *val = rtl822x_hwmon_get_temp(raw); ++ break; ++ case hwmon_temp_max: ++ /* Chip reduces speed to 1G if threshold is exceeded */ ++ raw = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL822X_VND2_TSSR) >> 6; ++ *val = rtl822x_hwmon_get_temp(raw); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static const struct hwmon_ops rtl822x_hwmon_ops = { ++ .visible = 0444, ++ .read = rtl822x_hwmon_read, ++}; ++ ++static const struct hwmon_channel_info * const rtl822x_hwmon_info[] = { ++ HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MAX), ++ NULL ++}; ++ ++static const struct hwmon_chip_info rtl822x_hwmon_chip_info = { ++ .ops = &rtl822x_hwmon_ops, ++ .info = rtl822x_hwmon_info, ++}; ++ ++int rtl822x_hwmon_init(struct phy_device *phydev) ++{ ++ struct device *hwdev, *dev = &phydev->mdio.dev; ++ const char *name; ++ ++ /* Ensure over-temp alarm is reset. */ ++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, RTL822X_VND2_TSALRM, 3); ++ ++ name = devm_hwmon_sanitize_name(dev, dev_name(dev)); ++ if (IS_ERR(name)) ++ return PTR_ERR(name); ++ ++ hwdev = devm_hwmon_device_register_with_info(dev, name, phydev, ++ &rtl822x_hwmon_chip_info, ++ NULL); ++ return PTR_ERR_OR_ZERO(hwdev); ++} +diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c +index 44c7bdb88d76..1eaa66a613a1 100644 +--- a/drivers/net/phy/realtek/realtek_main.c ++++ b/drivers/net/phy/realtek/realtek_main.c +@@ -14,6 +14,8 @@ + #include + #include + ++#include "realtek.h" ++ + #define RTL821x_PHYSR 0x11 + #define RTL821x_PHYSR_DUPLEX BIT(13) + #define RTL821x_PHYSR_SPEED GENMASK(15, 14) +@@ -820,6 +822,15 @@ static int rtl822x_write_mmd(struct phy_device *phydev, int devnum, u16 regnum, + return ret; + } + ++static int rtl822x_probe(struct phy_device *phydev) ++{ ++ if (IS_ENABLED(CONFIG_REALTEK_PHY_HWMON) && ++ phydev->phy_id != RTL_GENERIC_PHYID) ++ return rtl822x_hwmon_init(phydev); ++ ++ return 0; ++} ++ + static int rtl822xb_config_init(struct phy_device *phydev) + { + bool has_2500, has_sgmii; +@@ -1518,6 +1529,7 @@ static struct phy_driver realtek_drvs[] = { + .match_phy_device = rtl_internal_nbaset_match_phy_device, + .name = "Realtek Internal NBASE-T PHY", + .flags = PHY_IS_INTERNAL, ++ .probe = rtl822x_probe, + .get_features = rtl822x_get_features, + .config_aneg = rtl822x_config_aneg, + .read_status = rtl822x_read_status, +-- +2.51.0 + + +From 9d206755298602fa6e1ac888d793a898b6e3c27c Mon Sep 17 00:00:00 2001 +From: Aleksander Jan Bajkowski +Date: Fri, 17 Jan 2025 23:24:21 +0100 +Subject: [PATCH 145/517] net: phy: realtek: HWMON support for standalone + versions of RTL8221B and RTL8251 + +HWMON support has been added for the RTL8221/8251 PHYs integrated together +with the MAC inside the RTL8125/8126 chips. This patch extends temperature +reading support for standalone variants of the mentioned PHYs. + +I don't know whether the earlier revisions of the RTL8226 also have a +built-in temperature sensor, so they have been skipped for now. + +Tested on RTL8221B-VB-CG. + +Signed-off-by: Aleksander Jan Bajkowski +Reviewed-by: Andrew Lunn +Signed-off-by: David S. Miller +--- + drivers/net/phy/realtek/realtek_main.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c +index 1eaa66a613a1..572a933636b0 100644 +--- a/drivers/net/phy/realtek/realtek_main.c ++++ b/drivers/net/phy/realtek/realtek_main.c +@@ -1474,6 +1474,7 @@ static struct phy_driver realtek_drvs[] = { + }, { + .match_phy_device = rtl8221b_vb_cg_c22_match_phy_device, + .name = "RTL8221B-VB-CG 2.5Gbps PHY (C22)", ++ .probe = rtl822x_probe, + .get_features = rtl822x_get_features, + .config_aneg = rtl822x_config_aneg, + .config_init = rtl822xb_config_init, +@@ -1486,6 +1487,7 @@ static struct phy_driver realtek_drvs[] = { + }, { + .match_phy_device = rtl8221b_vb_cg_c45_match_phy_device, + .name = "RTL8221B-VB-CG 2.5Gbps PHY (C45)", ++ .probe = rtl822x_probe, + .config_init = rtl822xb_config_init, + .get_rate_matching = rtl822xb_get_rate_matching, + .get_features = rtl822x_c45_get_features, +@@ -1496,6 +1498,7 @@ static struct phy_driver realtek_drvs[] = { + }, { + .match_phy_device = rtl8221b_vn_cg_c22_match_phy_device, + .name = "RTL8221B-VM-CG 2.5Gbps PHY (C22)", ++ .probe = rtl822x_probe, + .get_features = rtl822x_get_features, + .config_aneg = rtl822x_config_aneg, + .config_init = rtl822xb_config_init, +@@ -1508,6 +1511,7 @@ static struct phy_driver realtek_drvs[] = { + }, { + .match_phy_device = rtl8221b_vn_cg_c45_match_phy_device, + .name = "RTL8221B-VN-CG 2.5Gbps PHY (C45)", ++ .probe = rtl822x_probe, + .config_init = rtl822xb_config_init, + .get_rate_matching = rtl822xb_get_rate_matching, + .get_features = rtl822x_c45_get_features, +@@ -1518,6 +1522,7 @@ static struct phy_driver realtek_drvs[] = { + }, { + .match_phy_device = rtl8251b_c45_match_phy_device, + .name = "RTL8251B 5Gbps PHY", ++ .probe = rtl822x_probe, + .get_features = rtl822x_get_features, + .config_aneg = rtl822x_config_aneg, + .read_status = rtl822x_read_status, +-- +2.51.0 + + +From df5a2f57e71d7ecb6eb08c4f26f7fbc216d44c73 Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Mon, 3 Feb 2025 21:33:39 +0100 +Subject: [PATCH 146/517] net: phy: realtek: make HWMON support a user-visible + Kconfig symbol + +Make config symbol REALTEK_PHY_HWMON user-visible, so that users can +remove support if not needed. + +Suggested-by: Geert Uytterhoeven +Signed-off-by: Heiner Kallweit +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/3466ee92-166a-4b0f-9ae7-42b9e046f333@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/realtek/Kconfig | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/phy/realtek/Kconfig b/drivers/net/phy/realtek/Kconfig +index 31935f147d87..b05c2a1e9024 100644 +--- a/drivers/net/phy/realtek/Kconfig ++++ b/drivers/net/phy/realtek/Kconfig +@@ -4,8 +4,12 @@ config REALTEK_PHY + help + Currently supports RTL821x/RTL822x and fast ethernet PHYs + ++if REALTEK_PHY ++ + config REALTEK_PHY_HWMON +- def_bool REALTEK_PHY && HWMON +- depends on !(REALTEK_PHY=y && HWMON=m) ++ bool "HWMON support for Realtek PHYs" ++ depends on HWMON && !(REALTEK_PHY=y && HWMON=m) + help + Optional hwmon support for the temperature sensor ++ ++endif # REALTEK_PHY +-- +2.51.0 + + +From 24028387bf45cc84b5c1eeb792b2466b8edf4564 Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Mon, 3 Feb 2025 21:41:36 +0100 +Subject: [PATCH 147/517] net: phy: realtek: use string choices helpers + +Use string choices helpers to simplify the code. + +Reported-by: kernel test robot +Closes: https://lore.kernel.org/oe-kbuild-all/202501190707.qQS8PGHW-lkp@intel.com/ +Signed-off-by: Heiner Kallweit +Reviewed-by: Simon Horman +Signed-off-by: David S. Miller +--- + drivers/net/phy/realtek/realtek_main.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c +index 572a933636b0..210fefac44d4 100644 +--- a/drivers/net/phy/realtek/realtek_main.c ++++ b/drivers/net/phy/realtek/realtek_main.c +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + + #include "realtek.h" + +@@ -422,11 +423,11 @@ static int rtl8211f_config_init(struct phy_device *phydev) + } else if (ret) { + dev_dbg(dev, + "%s 2ns TX delay (and changing the value from pin-strapping RXD1 or the bootloader)\n", +- val_txdly ? "Enabling" : "Disabling"); ++ str_enable_disable(val_txdly)); + } else { + dev_dbg(dev, + "2ns TX delay was already %s (by pin-strapping RXD1 or bootloader configuration)\n", +- val_txdly ? "enabled" : "disabled"); ++ str_enabled_disabled(val_txdly)); + } + + ret = phy_modify_paged_changed(phydev, 0xd08, 0x15, RTL8211F_RX_DELAY, +@@ -437,11 +438,11 @@ static int rtl8211f_config_init(struct phy_device *phydev) + } else if (ret) { + dev_dbg(dev, + "%s 2ns RX delay (and changing the value from pin-strapping RXD0 or the bootloader)\n", +- val_rxdly ? "Enabling" : "Disabling"); ++ str_enable_disable(val_rxdly)); + } else { + dev_dbg(dev, + "2ns RX delay was already %s (by pin-strapping RXD0 or bootloader configuration)\n", +- val_rxdly ? "enabled" : "disabled"); ++ str_enabled_disabled(val_rxdly)); + } + + if (priv->has_phycr2) { +-- +2.51.0 + + +From c7696aeb0135b79aa1648db6b358c5ab33ffd849 Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Thu, 13 Feb 2025 20:18:17 +0100 +Subject: [PATCH 148/517] net: phy: realtek: improve mmd register access for + internal PHY's + +r8169 provides the MDIO bus for the internal PHY's. It has been extended +with c45 access functions for addressing MDIO_MMD_VEND2 registers. +So we can switch from paged access to directly addressing the +MDIO_MMD_VEND2 registers. + +Signed-off-by: Heiner Kallweit +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/a5f2333c-dda9-48ad-9801-77049766e632@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/realtek/realtek_main.c | 79 +++++++++++--------------- + 1 file changed, 33 insertions(+), 46 deletions(-) + +diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c +index 210fefac44d4..2e2c5353c5af 100644 +--- a/drivers/net/phy/realtek/realtek_main.c ++++ b/drivers/net/phy/realtek/realtek_main.c +@@ -735,29 +735,31 @@ static int rtlgen_read_status(struct phy_device *phydev) + return 0; + } + ++static int rtlgen_read_vend2(struct phy_device *phydev, int regnum) ++{ ++ return __mdiobus_c45_read(phydev->mdio.bus, 0, MDIO_MMD_VEND2, regnum); ++} ++ ++static int rtlgen_write_vend2(struct phy_device *phydev, int regnum, u16 val) ++{ ++ return __mdiobus_c45_write(phydev->mdio.bus, 0, MDIO_MMD_VEND2, regnum, ++ val); ++} ++ + static int rtlgen_read_mmd(struct phy_device *phydev, int devnum, u16 regnum) + { + int ret; + +- if (devnum == MDIO_MMD_VEND2) { +- rtl821x_write_page(phydev, regnum >> 4); +- ret = __phy_read(phydev, 0x10 + ((regnum & 0xf) >> 1)); +- rtl821x_write_page(phydev, 0); +- } else if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE) { +- rtl821x_write_page(phydev, 0xa5c); +- ret = __phy_read(phydev, 0x12); +- rtl821x_write_page(phydev, 0); +- } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) { +- rtl821x_write_page(phydev, 0xa5d); +- ret = __phy_read(phydev, 0x10); +- rtl821x_write_page(phydev, 0); +- } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE) { +- rtl821x_write_page(phydev, 0xa5d); +- ret = __phy_read(phydev, 0x11); +- rtl821x_write_page(phydev, 0); +- } else { ++ if (devnum == MDIO_MMD_VEND2) ++ ret = rtlgen_read_vend2(phydev, regnum); ++ else if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE) ++ ret = rtlgen_read_vend2(phydev, 0xa5c4); ++ else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) ++ ret = rtlgen_read_vend2(phydev, 0xa5d0); ++ else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE) ++ ret = rtlgen_read_vend2(phydev, 0xa5d2); ++ else + ret = -EOPNOTSUPP; +- } + + return ret; + } +@@ -767,17 +769,12 @@ static int rtlgen_write_mmd(struct phy_device *phydev, int devnum, u16 regnum, + { + int ret; + +- if (devnum == MDIO_MMD_VEND2) { +- rtl821x_write_page(phydev, regnum >> 4); +- ret = __phy_write(phydev, 0x10 + ((regnum & 0xf) >> 1), val); +- rtl821x_write_page(phydev, 0); +- } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) { +- rtl821x_write_page(phydev, 0xa5d); +- ret = __phy_write(phydev, 0x10, val); +- rtl821x_write_page(phydev, 0); +- } else { ++ if (devnum == MDIO_MMD_VEND2) ++ ret = rtlgen_write_vend2(phydev, regnum, val); ++ else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) ++ ret = rtlgen_write_vend2(phydev, regnum, 0xa5d0); ++ else + ret = -EOPNOTSUPP; +- } + + return ret; + } +@@ -789,19 +786,12 @@ static int rtl822x_read_mmd(struct phy_device *phydev, int devnum, u16 regnum) + if (ret != -EOPNOTSUPP) + return ret; + +- if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE2) { +- rtl821x_write_page(phydev, 0xa6e); +- ret = __phy_read(phydev, 0x16); +- rtl821x_write_page(phydev, 0); +- } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV2) { +- rtl821x_write_page(phydev, 0xa6d); +- ret = __phy_read(phydev, 0x12); +- rtl821x_write_page(phydev, 0); +- } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE2) { +- rtl821x_write_page(phydev, 0xa6d); +- ret = __phy_read(phydev, 0x10); +- rtl821x_write_page(phydev, 0); +- } ++ if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE2) ++ ret = rtlgen_read_vend2(phydev, 0xa6ec); ++ else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV2) ++ ret = rtlgen_read_vend2(phydev, 0xa6d4); ++ else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE2) ++ ret = rtlgen_read_vend2(phydev, 0xa6d0); + + return ret; + } +@@ -814,11 +804,8 @@ static int rtl822x_write_mmd(struct phy_device *phydev, int devnum, u16 regnum, + if (ret != -EOPNOTSUPP) + return ret; + +- if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV2) { +- rtl821x_write_page(phydev, 0xa6d); +- ret = __phy_write(phydev, 0x12, val); +- rtl821x_write_page(phydev, 0); +- } ++ if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV2) ++ ret = rtlgen_write_vend2(phydev, 0xa6d4, val); + + return ret; + } +-- +2.51.0 + + +From 0a937df4d8245909b4d8777209ee0dfb07340350 Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Thu, 13 Feb 2025 20:19:14 +0100 +Subject: [PATCH 149/517] net: phy: realtek: switch from paged to MMD ops in + rtl822x functions + +The MDIO bus provided by r8169 for the internal PHY's now supports +c45 ops for the MDIO_MMD_VEND2 device. So we can switch to standard +MMD ops here. + +Signed-off-by: Heiner Kallweit +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/81416f95-0fac-4225-87b4-828e3738b8ed@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/realtek/realtek_main.c | 11 +++++------ + 1 file changed, 5 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c +index 2e2c5353c5af..34be1d752ef8 100644 +--- a/drivers/net/phy/realtek/realtek_main.c ++++ b/drivers/net/phy/realtek/realtek_main.c +@@ -901,7 +901,7 @@ static int rtl822x_get_features(struct phy_device *phydev) + { + int val; + +- val = phy_read_paged(phydev, 0xa61, 0x13); ++ val = phy_read_mmd(phydev, MDIO_MMD_VEND2, 0xa616); + if (val < 0) + return val; + +@@ -922,10 +922,9 @@ static int rtl822x_config_aneg(struct phy_device *phydev) + if (phydev->autoneg == AUTONEG_ENABLE) { + u16 adv = linkmode_adv_to_mii_10gbt_adv_t(phydev->advertising); + +- ret = phy_modify_paged_changed(phydev, 0xa5d, 0x12, +- MDIO_AN_10GBT_CTRL_ADV2_5G | +- MDIO_AN_10GBT_CTRL_ADV5G, +- adv); ++ ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, 0xa5d4, ++ MDIO_AN_10GBT_CTRL_ADV2_5G | ++ MDIO_AN_10GBT_CTRL_ADV5G, adv); + if (ret < 0) + return ret; + } +@@ -969,7 +968,7 @@ static int rtl822x_read_status(struct phy_device *phydev) + !phydev->autoneg_complete) + return 0; + +- lpadv = phy_read_paged(phydev, 0xa5d, 0x13); ++ lpadv = phy_read_mmd(phydev, MDIO_MMD_VEND2, 0xa5d6); + if (lpadv < 0) + return lpadv; + +-- +2.51.0 + + +From a30ba9540ea58da2d711e0ec47a05fdabcdf04fe Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Fri, 14 Feb 2025 21:31:14 +0100 +Subject: [PATCH 150/517] net: phy: realtek: add helper RTL822X_VND2_C22_REG + +C22 register space is mapped to 0xa400 in MMD VEND2 register space. +Add a helper to access mapped C22 registers. + +Signed-off-by: Heiner Kallweit +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/6344277b-c5c7-449b-ac89-d5425306ca76@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/realtek/realtek_main.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c +index 34be1d752ef8..b877057348d5 100644 +--- a/drivers/net/phy/realtek/realtek_main.c ++++ b/drivers/net/phy/realtek/realtek_main.c +@@ -79,9 +79,7 @@ + /* RTL822X_VND2_XXXXX registers are only accessible when phydev->is_c45 + * is set, they cannot be accessed by C45-over-C22. + */ +-#define RTL822X_VND2_GBCR 0xa412 +- +-#define RTL822X_VND2_GANLPAR 0xa414 ++#define RTL822X_VND2_C22_REG(reg) (0xa400 + 2 * (reg)) + + #define RTL8366RB_POWER_SAVE 0x15 + #define RTL8366RB_POWER_SAVE_ON BIT(12) +@@ -1015,7 +1013,8 @@ static int rtl822x_c45_config_aneg(struct phy_device *phydev) + val = linkmode_adv_to_mii_ctrl1000_t(phydev->advertising); + + /* Vendor register as C45 has no standardized support for 1000BaseT */ +- ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, RTL822X_VND2_GBCR, ++ ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, ++ RTL822X_VND2_C22_REG(MII_CTRL1000), + ADVERTISE_1000FULL, val); + if (ret < 0) + return ret; +@@ -1032,7 +1031,7 @@ static int rtl822x_c45_read_status(struct phy_device *phydev) + /* Vendor register as C45 has no standardized support for 1000BaseT */ + if (phydev->autoneg == AUTONEG_ENABLE && genphy_c45_aneg_done(phydev)) { + val = phy_read_mmd(phydev, MDIO_MMD_VEND2, +- RTL822X_VND2_GANLPAR); ++ RTL822X_VND2_C22_REG(MII_STAT1000)); + if (val < 0) + return val; + } else { +-- +2.51.0 + + +From 10dc716faf022f4c1e733b7cc7730effb0387309 Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Sat, 15 Feb 2025 14:29:15 +0100 +Subject: [PATCH 151/517] net: phy: realtek: add defines for shadowed c45 + standard registers + +Realtek shadows standard c45 registers in VEND2 device register space. +Add defines for these VEND2 registers, based on the names of the +standard c45 registers. + +Signed-off-by: Heiner Kallweit +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/c90bdf76-f8b8-4d06-9656-7a52d5658ee6@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/realtek/realtek_main.c | 33 +++++++++++++++++--------- + 1 file changed, 22 insertions(+), 11 deletions(-) + +diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c +index b877057348d5..7a0b19d66aca 100644 +--- a/drivers/net/phy/realtek/realtek_main.c ++++ b/drivers/net/phy/realtek/realtek_main.c +@@ -94,6 +94,16 @@ + #define RTL_VND2_PHYSR_MASTER BIT(11) + #define RTL_VND2_PHYSR_SPEED_MASK (RTL_VND2_PHYSR_SPEEDL | RTL_VND2_PHYSR_SPEEDH) + ++#define RTL_MDIO_PCS_EEE_ABLE 0xa5c4 ++#define RTL_MDIO_AN_EEE_ADV 0xa5d0 ++#define RTL_MDIO_AN_EEE_LPABLE 0xa5d2 ++#define RTL_MDIO_AN_10GBT_CTRL 0xa5d4 ++#define RTL_MDIO_AN_10GBT_STAT 0xa5d6 ++#define RTL_MDIO_PMA_SPEED 0xa616 ++#define RTL_MDIO_AN_EEE_LPABLE2 0xa6d0 ++#define RTL_MDIO_AN_EEE_ADV2 0xa6d4 ++#define RTL_MDIO_PCS_EEE_ABLE2 0xa6ec ++ + #define RTL_GENERIC_PHYID 0x001cc800 + #define RTL_8211FVD_PHYID 0x001cc878 + #define RTL_8221B 0x001cc840 +@@ -751,11 +761,11 @@ static int rtlgen_read_mmd(struct phy_device *phydev, int devnum, u16 regnum) + if (devnum == MDIO_MMD_VEND2) + ret = rtlgen_read_vend2(phydev, regnum); + else if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE) +- ret = rtlgen_read_vend2(phydev, 0xa5c4); ++ ret = rtlgen_read_vend2(phydev, RTL_MDIO_PCS_EEE_ABLE); + else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) +- ret = rtlgen_read_vend2(phydev, 0xa5d0); ++ ret = rtlgen_read_vend2(phydev, RTL_MDIO_AN_EEE_ADV); + else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE) +- ret = rtlgen_read_vend2(phydev, 0xa5d2); ++ ret = rtlgen_read_vend2(phydev, RTL_MDIO_AN_EEE_LPABLE); + else + ret = -EOPNOTSUPP; + +@@ -770,7 +780,7 @@ static int rtlgen_write_mmd(struct phy_device *phydev, int devnum, u16 regnum, + if (devnum == MDIO_MMD_VEND2) + ret = rtlgen_write_vend2(phydev, regnum, val); + else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) +- ret = rtlgen_write_vend2(phydev, regnum, 0xa5d0); ++ ret = rtlgen_write_vend2(phydev, regnum, RTL_MDIO_AN_EEE_ADV); + else + ret = -EOPNOTSUPP; + +@@ -785,11 +795,11 @@ static int rtl822x_read_mmd(struct phy_device *phydev, int devnum, u16 regnum) + return ret; + + if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE2) +- ret = rtlgen_read_vend2(phydev, 0xa6ec); ++ ret = rtlgen_read_vend2(phydev, RTL_MDIO_PCS_EEE_ABLE2); + else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV2) +- ret = rtlgen_read_vend2(phydev, 0xa6d4); ++ ret = rtlgen_read_vend2(phydev, RTL_MDIO_AN_EEE_ADV2); + else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE2) +- ret = rtlgen_read_vend2(phydev, 0xa6d0); ++ ret = rtlgen_read_vend2(phydev, RTL_MDIO_AN_EEE_LPABLE2); + + return ret; + } +@@ -803,7 +813,7 @@ static int rtl822x_write_mmd(struct phy_device *phydev, int devnum, u16 regnum, + return ret; + + if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV2) +- ret = rtlgen_write_vend2(phydev, 0xa6d4, val); ++ ret = rtlgen_write_vend2(phydev, RTL_MDIO_AN_EEE_ADV2, val); + + return ret; + } +@@ -899,7 +909,7 @@ static int rtl822x_get_features(struct phy_device *phydev) + { + int val; + +- val = phy_read_mmd(phydev, MDIO_MMD_VEND2, 0xa616); ++ val = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL_MDIO_PMA_SPEED); + if (val < 0) + return val; + +@@ -920,7 +930,8 @@ static int rtl822x_config_aneg(struct phy_device *phydev) + if (phydev->autoneg == AUTONEG_ENABLE) { + u16 adv = linkmode_adv_to_mii_10gbt_adv_t(phydev->advertising); + +- ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, 0xa5d4, ++ ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, ++ RTL_MDIO_AN_10GBT_CTRL, + MDIO_AN_10GBT_CTRL_ADV2_5G | + MDIO_AN_10GBT_CTRL_ADV5G, adv); + if (ret < 0) +@@ -966,7 +977,7 @@ static int rtl822x_read_status(struct phy_device *phydev) + !phydev->autoneg_complete) + return 0; + +- lpadv = phy_read_mmd(phydev, MDIO_MMD_VEND2, 0xa5d6); ++ lpadv = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL_MDIO_AN_10GBT_STAT); + if (lpadv < 0) + return lpadv; + +-- +2.51.0 + + +From 0f352608b9659c2a38aaae383a9dfb7198c92550 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Sun, 16 Mar 2025 12:39:54 +0000 +Subject: [PATCH 152/517] net: phy: realtek: disable PHY-mode EEE + +Realtek RTL8211F has a "PHY-mode" EEE support which interferes with an +IEEE 802.3 compliant implementation. This mode defaults to enabled, and +results in the MAC receive path not seeing the link transition to LPI +state. + +Fix this by disabling PHY-mode EEE. + +Signed-off-by: Russell King (Oracle) +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/E1ttnHW-00785s-Uq@rmk-PC.armlinux.org.uk +Signed-off-by: Paolo Abeni +--- + drivers/net/phy/realtek/realtek_main.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c +index 7a0b19d66aca..893c82479671 100644 +--- a/drivers/net/phy/realtek/realtek_main.c ++++ b/drivers/net/phy/realtek/realtek_main.c +@@ -33,6 +33,9 @@ + + #define RTL8211F_PHYCR1 0x18 + #define RTL8211F_PHYCR2 0x19 ++#define RTL8211F_CLKOUT_EN BIT(0) ++#define RTL8211F_PHYCR2_PHY_EEE_ENABLE BIT(5) ++ + #define RTL8211F_INSR 0x1d + + #define RTL8211F_LEDCR 0x10 +@@ -55,8 +58,6 @@ + #define RTL8211E_TX_DELAY BIT(12) + #define RTL8211E_RX_DELAY BIT(11) + +-#define RTL8211F_CLKOUT_EN BIT(0) +- + #define RTL8201F_ISR 0x1e + #define RTL8201F_ISR_ANERR BIT(15) + #define RTL8201F_ISR_DUPLEX BIT(13) +@@ -453,6 +454,12 @@ static int rtl8211f_config_init(struct phy_device *phydev) + str_enabled_disabled(val_rxdly)); + } + ++ /* Disable PHY-mode EEE so LPI is passed to the MAC */ ++ ret = phy_modify_paged(phydev, 0xa43, RTL8211F_PHYCR2, ++ RTL8211F_PHYCR2_PHY_EEE_ENABLE, 0); ++ if (ret) ++ return ret; ++ + if (priv->has_phycr2) { + ret = phy_modify_paged(phydev, 0xa43, RTL8211F_PHYCR2, + RTL8211F_CLKOUT_EN, priv->phycr2); +-- +2.51.0 + + +From 94a3d70ce477f33f92c9a49223563adc2382a80b Mon Sep 17 00:00:00 2001 +From: Daniel Braunwarth +Date: Tue, 29 Apr 2025 13:33:37 +0200 +Subject: [PATCH 153/517] net: phy: realtek: Add support for WOL magic packet + on RTL8211F + +The RTL8211F supports multiple WOL modes. This patch adds support for +magic packets. + +The PHY notifies the system via the INTB/PMEB pin when a WOL event +occurs. + +Signed-off-by: Daniel Braunwarth +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/20250429-realtek_wol-v2-1-8f84def1ef2c@kuka.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/realtek/realtek_main.c | 69 ++++++++++++++++++++++++++ + 1 file changed, 69 insertions(+) + +diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c +index 893c82479671..05c4f4d394a5 100644 +--- a/drivers/net/phy/realtek/realtek_main.c ++++ b/drivers/net/phy/realtek/realtek_main.c +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -38,6 +39,24 @@ + + #define RTL8211F_INSR 0x1d + ++/* RTL8211F WOL interrupt configuration */ ++#define RTL8211F_INTBCR_PAGE 0xd40 ++#define RTL8211F_INTBCR 0x16 ++#define RTL8211F_INTBCR_INTB_PMEB BIT(5) ++ ++/* RTL8211F WOL settings */ ++#define RTL8211F_WOL_SETTINGS_PAGE 0xd8a ++#define RTL8211F_WOL_SETTINGS_EVENTS 16 ++#define RTL8211F_WOL_EVENT_MAGIC BIT(12) ++#define RTL8211F_WOL_SETTINGS_STATUS 17 ++#define RTL8211F_WOL_STATUS_RESET (BIT(15) | 0x1fff) ++ ++/* RTL8211F Unique phyiscal and multicast address (WOL) */ ++#define RTL8211F_PHYSICAL_ADDR_PAGE 0xd8c ++#define RTL8211F_PHYSICAL_ADDR_WORD0 16 ++#define RTL8211F_PHYSICAL_ADDR_WORD1 17 ++#define RTL8211F_PHYSICAL_ADDR_WORD2 18 ++ + #define RTL8211F_LEDCR 0x10 + #define RTL8211F_LEDCR_MODE BIT(15) + #define RTL8211F_LEDCR_ACT_TXRX BIT(4) +@@ -123,6 +142,7 @@ struct rtl821x_priv { + u16 phycr2; + bool has_phycr2; + struct clk *clk; ++ u32 saved_wolopts; + }; + + static int rtl821x_read_page(struct phy_device *phydev) +@@ -354,6 +374,53 @@ static irqreturn_t rtl8211f_handle_interrupt(struct phy_device *phydev) + return IRQ_HANDLED; + } + ++static void rtl8211f_get_wol(struct phy_device *dev, struct ethtool_wolinfo *wol) ++{ ++ wol->supported = WAKE_MAGIC; ++ if (phy_read_paged(dev, RTL8211F_WOL_SETTINGS_PAGE, RTL8211F_WOL_SETTINGS_EVENTS) ++ & RTL8211F_WOL_EVENT_MAGIC) ++ wol->wolopts = WAKE_MAGIC; ++} ++ ++static int rtl8211f_set_wol(struct phy_device *dev, struct ethtool_wolinfo *wol) ++{ ++ const u8 *mac_addr = dev->attached_dev->dev_addr; ++ int oldpage; ++ ++ oldpage = phy_save_page(dev); ++ if (oldpage < 0) ++ goto err; ++ ++ if (wol->wolopts & WAKE_MAGIC) { ++ /* Store the device address for the magic packet */ ++ rtl821x_write_page(dev, RTL8211F_PHYSICAL_ADDR_PAGE); ++ __phy_write(dev, RTL8211F_PHYSICAL_ADDR_WORD0, mac_addr[1] << 8 | (mac_addr[0])); ++ __phy_write(dev, RTL8211F_PHYSICAL_ADDR_WORD1, mac_addr[3] << 8 | (mac_addr[2])); ++ __phy_write(dev, RTL8211F_PHYSICAL_ADDR_WORD2, mac_addr[5] << 8 | (mac_addr[4])); ++ ++ /* Enable magic packet matching and reset WOL status */ ++ rtl821x_write_page(dev, RTL8211F_WOL_SETTINGS_PAGE); ++ __phy_write(dev, RTL8211F_WOL_SETTINGS_EVENTS, RTL8211F_WOL_EVENT_MAGIC); ++ __phy_write(dev, RTL8211F_WOL_SETTINGS_STATUS, RTL8211F_WOL_STATUS_RESET); ++ ++ /* Enable the WOL interrupt */ ++ rtl821x_write_page(dev, RTL8211F_INTBCR_PAGE); ++ __phy_set_bits(dev, RTL8211F_INTBCR, RTL8211F_INTBCR_INTB_PMEB); ++ } else { ++ /* Disable the WOL interrupt */ ++ rtl821x_write_page(dev, RTL8211F_INTBCR_PAGE); ++ __phy_clear_bits(dev, RTL8211F_INTBCR, RTL8211F_INTBCR_INTB_PMEB); ++ ++ /* Disable magic packet matching and reset WOL status */ ++ rtl821x_write_page(dev, RTL8211F_WOL_SETTINGS_PAGE); ++ __phy_write(dev, RTL8211F_WOL_SETTINGS_EVENTS, 0); ++ __phy_write(dev, RTL8211F_WOL_SETTINGS_STATUS, RTL8211F_WOL_STATUS_RESET); ++ } ++ ++err: ++ return phy_restore_page(dev, oldpage, 0); ++} ++ + static int rtl8211_config_aneg(struct phy_device *phydev) + { + int ret; +@@ -1400,6 +1467,8 @@ static struct phy_driver realtek_drvs[] = { + .read_status = rtlgen_read_status, + .config_intr = &rtl8211f_config_intr, + .handle_interrupt = rtl8211f_handle_interrupt, ++ .set_wol = rtl8211f_set_wol, ++ .get_wol = rtl8211f_get_wol, + .suspend = rtl821x_suspend, + .resume = rtl821x_resume, + .read_page = rtl821x_read_page, +-- +2.51.0 + + +From ddd234bd4736f05f5f0ed506bee9f1a9b26cbd07 Mon Sep 17 00:00:00 2001 +From: Michael Klein +Date: Sun, 4 May 2025 19:29:11 +0200 +Subject: [PATCH 154/517] net: phy: realtek: remove unsed RTL821x_PHYSR* macros + +These macros have there since the first revision but were never used, so +let's just remove them. + +Signed-off-by: Michael Klein +Link: https://patch.msgid.link/20250504172916.243185-2-michael@fossekall.de +Signed-off-by: Paolo Abeni +--- + drivers/net/phy/realtek/realtek_main.c | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c +index 05c4f4d394a5..a6d21dfb1073 100644 +--- a/drivers/net/phy/realtek/realtek_main.c ++++ b/drivers/net/phy/realtek/realtek_main.c +@@ -18,10 +18,6 @@ + + #include "realtek.h" + +-#define RTL821x_PHYSR 0x11 +-#define RTL821x_PHYSR_DUPLEX BIT(13) +-#define RTL821x_PHYSR_SPEED GENMASK(15, 14) +- + #define RTL821x_INER 0x12 + #define RTL8211B_INER_INIT 0x6400 + #define RTL8211E_INER_LINK_STATUS BIT(10) +-- +2.51.0 + + +From 66803c7f8be64574b376190cc5b712c2f46c124d Mon Sep 17 00:00:00 2001 +From: Michael Klein +Date: Sun, 4 May 2025 19:29:12 +0200 +Subject: [PATCH 155/517] net: phy: realtek: Clean up RTL821x ExtPage access + +Factor out RTL8211E extension page access code to +rtl821x_modify_ext_page() and clean up rtl8211e_config_init() + +Signed-off-by: Michael Klein +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/20250504172916.243185-3-michael@fossekall.de +Signed-off-by: Paolo Abeni +--- + drivers/net/phy/realtek/realtek_main.c | 38 ++++++++++++++++---------- + 1 file changed, 23 insertions(+), 15 deletions(-) + +diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c +index a6d21dfb1073..0f005a449719 100644 +--- a/drivers/net/phy/realtek/realtek_main.c ++++ b/drivers/net/phy/realtek/realtek_main.c +@@ -26,7 +26,9 @@ + #define RTL821x_INSR 0x13 + + #define RTL821x_EXT_PAGE_SELECT 0x1e ++ + #define RTL821x_PAGE_SELECT 0x1f ++#define RTL821x_SET_EXT_PAGE 0x07 + + #define RTL8211F_PHYCR1 0x18 + #define RTL8211F_PHYCR2 0x19 +@@ -69,9 +71,12 @@ + #define RTL8211F_ALDPS_ENABLE BIT(2) + #define RTL8211F_ALDPS_XTAL_OFF BIT(12) + ++#define RTL8211E_RGMII_EXT_PAGE 0xa4 ++#define RTL8211E_RGMII_DELAY 0x1c + #define RTL8211E_CTRL_DELAY BIT(13) + #define RTL8211E_TX_DELAY BIT(12) + #define RTL8211E_RX_DELAY BIT(11) ++#define RTL8211E_DELAY_MASK GENMASK(13, 11) + + #define RTL8201F_ISR 0x1e + #define RTL8201F_ISR_ANERR BIT(15) +@@ -151,6 +156,21 @@ static int rtl821x_write_page(struct phy_device *phydev, int page) + return __phy_write(phydev, RTL821x_PAGE_SELECT, page); + } + ++static int rtl821x_modify_ext_page(struct phy_device *phydev, u16 ext_page, ++ u32 regnum, u16 mask, u16 set) ++{ ++ int oldpage, ret = 0; ++ ++ oldpage = phy_select_page(phydev, RTL821x_SET_EXT_PAGE); ++ if (oldpage >= 0) { ++ ret = __phy_write(phydev, RTL821x_EXT_PAGE_SELECT, ext_page); ++ if (ret == 0) ++ ret = __phy_modify(phydev, regnum, mask, set); ++ } ++ ++ return phy_restore_page(phydev, oldpage, ret); ++} ++ + static int rtl821x_probe(struct phy_device *phydev) + { + struct device *dev = &phydev->mdio.dev; +@@ -670,7 +690,6 @@ static int rtl8211f_led_hw_control_set(struct phy_device *phydev, u8 index, + + static int rtl8211e_config_init(struct phy_device *phydev) + { +- int ret = 0, oldpage; + u16 val; + + /* enable TX/RX delay for rgmii-* modes, and disable them for rgmii. */ +@@ -700,20 +719,9 @@ static int rtl8211e_config_init(struct phy_device *phydev) + * 12 = RX Delay, 11 = TX Delay + * 10:0 = Test && debug settings reserved by realtek + */ +- oldpage = phy_select_page(phydev, 0x7); +- if (oldpage < 0) +- goto err_restore_page; +- +- ret = __phy_write(phydev, RTL821x_EXT_PAGE_SELECT, 0xa4); +- if (ret) +- goto err_restore_page; +- +- ret = __phy_modify(phydev, 0x1c, RTL8211E_CTRL_DELAY +- | RTL8211E_TX_DELAY | RTL8211E_RX_DELAY, +- val); +- +-err_restore_page: +- return phy_restore_page(phydev, oldpage, ret); ++ return rtl821x_modify_ext_page(phydev, RTL8211E_RGMII_EXT_PAGE, ++ RTL8211E_RGMII_DELAY, ++ RTL8211E_DELAY_MASK, val); + } + + static int rtl8211b_suspend(struct phy_device *phydev) +-- +2.51.0 + + +From 798b8b7ae7fd1757c5106f7bcd71938f31cb4296 Mon Sep 17 00:00:00 2001 +From: Michael Klein +Date: Sun, 4 May 2025 19:29:13 +0200 +Subject: [PATCH 156/517] net: phy: realtek: add RTL8211F register defines + +Add some more defines for RTL8211F page and register numbers. + +Signed-off-by: Michael Klein +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/20250504172916.243185-4-michael@fossekall.de +Signed-off-by: Paolo Abeni +--- + drivers/net/phy/realtek/realtek_main.c | 34 ++++++++++++++++++-------- + 1 file changed, 24 insertions(+), 10 deletions(-) + +diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c +index 0f005a449719..ca6d2903b1c9 100644 +--- a/drivers/net/phy/realtek/realtek_main.c ++++ b/drivers/net/phy/realtek/realtek_main.c +@@ -30,11 +30,14 @@ + #define RTL821x_PAGE_SELECT 0x1f + #define RTL821x_SET_EXT_PAGE 0x07 + ++/* RTL8211F PHY configuration */ ++#define RTL8211F_PHYCR_PAGE 0xa43 + #define RTL8211F_PHYCR1 0x18 + #define RTL8211F_PHYCR2 0x19 + #define RTL8211F_CLKOUT_EN BIT(0) + #define RTL8211F_PHYCR2_PHY_EEE_ENABLE BIT(5) + ++#define RTL8211F_INSR_PAGE 0xa43 + #define RTL8211F_INSR 0x1d + + /* RTL8211F WOL interrupt configuration */ +@@ -55,6 +58,8 @@ + #define RTL8211F_PHYSICAL_ADDR_WORD1 17 + #define RTL8211F_PHYSICAL_ADDR_WORD2 18 + ++/* RTL8211F LED configuration */ ++#define RTL8211F_LEDCR_PAGE 0xd04 + #define RTL8211F_LEDCR 0x10 + #define RTL8211F_LEDCR_MODE BIT(15) + #define RTL8211F_LEDCR_ACT_TXRX BIT(4) +@@ -64,7 +69,13 @@ + #define RTL8211F_LEDCR_MASK GENMASK(4, 0) + #define RTL8211F_LEDCR_SHIFT 5 + ++/* RTL8211F RGMII configuration */ ++#define RTL8211F_RGMII_PAGE 0xd08 ++ ++#define RTL8211F_TXCR 0x11 + #define RTL8211F_TX_DELAY BIT(8) ++ ++#define RTL8211F_RXCR 0x15 + #define RTL8211F_RX_DELAY BIT(3) + + #define RTL8211F_ALDPS_PLL_OFF BIT(1) +@@ -187,7 +198,7 @@ static int rtl821x_probe(struct phy_device *phydev) + return dev_err_probe(dev, PTR_ERR(priv->clk), + "failed to get phy clock\n"); + +- ret = phy_read_paged(phydev, 0xa43, RTL8211F_PHYCR1); ++ ret = phy_read_paged(phydev, RTL8211F_PHYCR_PAGE, RTL8211F_PHYCR1); + if (ret < 0) + return ret; + +@@ -197,7 +208,7 @@ static int rtl821x_probe(struct phy_device *phydev) + + priv->has_phycr2 = !(phy_id == RTL_8211FVD_PHYID); + if (priv->has_phycr2) { +- ret = phy_read_paged(phydev, 0xa43, RTL8211F_PHYCR2); ++ ret = phy_read_paged(phydev, RTL8211F_PHYCR_PAGE, RTL8211F_PHYCR2); + if (ret < 0) + return ret; + +@@ -233,7 +244,7 @@ static int rtl8211f_ack_interrupt(struct phy_device *phydev) + { + int err; + +- err = phy_read_paged(phydev, 0xa43, RTL8211F_INSR); ++ err = phy_read_paged(phydev, RTL8211F_INSR_PAGE, RTL8211F_INSR); + + return (err < 0) ? err : 0; + } +@@ -376,7 +387,7 @@ static irqreturn_t rtl8211f_handle_interrupt(struct phy_device *phydev) + { + int irq_status; + +- irq_status = phy_read_paged(phydev, 0xa43, RTL8211F_INSR); ++ irq_status = phy_read_paged(phydev, RTL8211F_INSR_PAGE, RTL8211F_INSR); + if (irq_status < 0) { + phy_error(phydev); + return IRQ_NONE; +@@ -473,7 +484,7 @@ static int rtl8211f_config_init(struct phy_device *phydev) + u16 val_txdly, val_rxdly; + int ret; + +- ret = phy_modify_paged_changed(phydev, 0xa43, RTL8211F_PHYCR1, ++ ret = phy_modify_paged_changed(phydev, RTL8211F_PHYCR_PAGE, RTL8211F_PHYCR1, + RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF, + priv->phycr1); + if (ret < 0) { +@@ -507,7 +518,8 @@ static int rtl8211f_config_init(struct phy_device *phydev) + return 0; + } + +- ret = phy_modify_paged_changed(phydev, 0xd08, 0x11, RTL8211F_TX_DELAY, ++ ret = phy_modify_paged_changed(phydev, RTL8211F_RGMII_PAGE, ++ RTL8211F_TXCR, RTL8211F_TX_DELAY, + val_txdly); + if (ret < 0) { + dev_err(dev, "Failed to update the TX delay register\n"); +@@ -522,7 +534,8 @@ static int rtl8211f_config_init(struct phy_device *phydev) + str_enabled_disabled(val_txdly)); + } + +- ret = phy_modify_paged_changed(phydev, 0xd08, 0x15, RTL8211F_RX_DELAY, ++ ret = phy_modify_paged_changed(phydev, RTL8211F_RGMII_PAGE, ++ RTL8211F_RXCR, RTL8211F_RX_DELAY, + val_rxdly); + if (ret < 0) { + dev_err(dev, "Failed to update the RX delay register\n"); +@@ -538,14 +551,15 @@ static int rtl8211f_config_init(struct phy_device *phydev) + } + + /* Disable PHY-mode EEE so LPI is passed to the MAC */ +- ret = phy_modify_paged(phydev, 0xa43, RTL8211F_PHYCR2, ++ ret = phy_modify_paged(phydev, RTL8211F_PHYCR_PAGE, RTL8211F_PHYCR2, + RTL8211F_PHYCR2_PHY_EEE_ENABLE, 0); + if (ret) + return ret; + + if (priv->has_phycr2) { +- ret = phy_modify_paged(phydev, 0xa43, RTL8211F_PHYCR2, +- RTL8211F_CLKOUT_EN, priv->phycr2); ++ ret = phy_modify_paged(phydev, RTL8211F_PHYCR_PAGE, ++ RTL8211F_PHYCR2, RTL8211F_CLKOUT_EN, ++ priv->phycr2); + if (ret < 0) { + dev_err(dev, "clkout configuration failed: %pe\n", + ERR_PTR(ret)); +-- +2.51.0 + + +From 825c23aae9ae86718d9d0b15090994b8e2b99265 Mon Sep 17 00:00:00 2001 +From: Michael Klein +Date: Sun, 4 May 2025 19:29:14 +0200 +Subject: [PATCH 157/517] net: phy: realtek: Group RTL82* macro definitions + +Group macro definitions by PHY in lexicographic order. Within each PHY +block, definitions are order by page number and then register number. + +Signed-off-by: Michael Klein +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/20250504172916.243185-5-michael@fossekall.de +Signed-off-by: Paolo Abeni +--- + drivers/net/phy/realtek/realtek_main.c | 72 +++++++++++++------------- + 1 file changed, 37 insertions(+), 35 deletions(-) + +diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c +index ca6d2903b1c9..e01b13a9b5c3 100644 +--- a/drivers/net/phy/realtek/realtek_main.c ++++ b/drivers/net/phy/realtek/realtek_main.c +@@ -18,6 +18,16 @@ + + #include "realtek.h" + ++#define RTL8201F_IER 0x13 ++ ++#define RTL8201F_ISR 0x1e ++#define RTL8201F_ISR_ANERR BIT(15) ++#define RTL8201F_ISR_DUPLEX BIT(13) ++#define RTL8201F_ISR_LINK BIT(11) ++#define RTL8201F_ISR_MASK (RTL8201F_ISR_ANERR | \ ++ RTL8201F_ISR_DUPLEX | \ ++ RTL8201F_ISR_LINK) ++ + #define RTL821x_INER 0x12 + #define RTL8211B_INER_INIT 0x6400 + #define RTL8211E_INER_LINK_STATUS BIT(10) +@@ -30,9 +40,21 @@ + #define RTL821x_PAGE_SELECT 0x1f + #define RTL821x_SET_EXT_PAGE 0x07 + ++/* RTL8211E extension page 164/0xa4 */ ++#define RTL8211E_RGMII_EXT_PAGE 0xa4 ++#define RTL8211E_RGMII_DELAY 0x1c ++#define RTL8211E_CTRL_DELAY BIT(13) ++#define RTL8211E_TX_DELAY BIT(12) ++#define RTL8211E_RX_DELAY BIT(11) ++#define RTL8211E_DELAY_MASK GENMASK(13, 11) ++ + /* RTL8211F PHY configuration */ + #define RTL8211F_PHYCR_PAGE 0xa43 + #define RTL8211F_PHYCR1 0x18 ++#define RTL8211F_ALDPS_PLL_OFF BIT(1) ++#define RTL8211F_ALDPS_ENABLE BIT(2) ++#define RTL8211F_ALDPS_XTAL_OFF BIT(12) ++ + #define RTL8211F_PHYCR2 0x19 + #define RTL8211F_CLKOUT_EN BIT(0) + #define RTL8211F_PHYCR2_PHY_EEE_ENABLE BIT(5) +@@ -40,24 +62,6 @@ + #define RTL8211F_INSR_PAGE 0xa43 + #define RTL8211F_INSR 0x1d + +-/* RTL8211F WOL interrupt configuration */ +-#define RTL8211F_INTBCR_PAGE 0xd40 +-#define RTL8211F_INTBCR 0x16 +-#define RTL8211F_INTBCR_INTB_PMEB BIT(5) +- +-/* RTL8211F WOL settings */ +-#define RTL8211F_WOL_SETTINGS_PAGE 0xd8a +-#define RTL8211F_WOL_SETTINGS_EVENTS 16 +-#define RTL8211F_WOL_EVENT_MAGIC BIT(12) +-#define RTL8211F_WOL_SETTINGS_STATUS 17 +-#define RTL8211F_WOL_STATUS_RESET (BIT(15) | 0x1fff) +- +-/* RTL8211F Unique phyiscal and multicast address (WOL) */ +-#define RTL8211F_PHYSICAL_ADDR_PAGE 0xd8c +-#define RTL8211F_PHYSICAL_ADDR_WORD0 16 +-#define RTL8211F_PHYSICAL_ADDR_WORD1 17 +-#define RTL8211F_PHYSICAL_ADDR_WORD2 18 +- + /* RTL8211F LED configuration */ + #define RTL8211F_LEDCR_PAGE 0xd04 + #define RTL8211F_LEDCR 0x10 +@@ -78,25 +82,23 @@ + #define RTL8211F_RXCR 0x15 + #define RTL8211F_RX_DELAY BIT(3) + +-#define RTL8211F_ALDPS_PLL_OFF BIT(1) +-#define RTL8211F_ALDPS_ENABLE BIT(2) +-#define RTL8211F_ALDPS_XTAL_OFF BIT(12) ++/* RTL8211F WOL interrupt configuration */ ++#define RTL8211F_INTBCR_PAGE 0xd40 ++#define RTL8211F_INTBCR 0x16 ++#define RTL8211F_INTBCR_INTB_PMEB BIT(5) + +-#define RTL8211E_RGMII_EXT_PAGE 0xa4 +-#define RTL8211E_RGMII_DELAY 0x1c +-#define RTL8211E_CTRL_DELAY BIT(13) +-#define RTL8211E_TX_DELAY BIT(12) +-#define RTL8211E_RX_DELAY BIT(11) +-#define RTL8211E_DELAY_MASK GENMASK(13, 11) ++/* RTL8211F WOL settings */ ++#define RTL8211F_WOL_SETTINGS_PAGE 0xd8a ++#define RTL8211F_WOL_SETTINGS_EVENTS 16 ++#define RTL8211F_WOL_EVENT_MAGIC BIT(12) ++#define RTL8211F_WOL_SETTINGS_STATUS 17 ++#define RTL8211F_WOL_STATUS_RESET (BIT(15) | 0x1fff) + +-#define RTL8201F_ISR 0x1e +-#define RTL8201F_ISR_ANERR BIT(15) +-#define RTL8201F_ISR_DUPLEX BIT(13) +-#define RTL8201F_ISR_LINK BIT(11) +-#define RTL8201F_ISR_MASK (RTL8201F_ISR_ANERR | \ +- RTL8201F_ISR_DUPLEX | \ +- RTL8201F_ISR_LINK) +-#define RTL8201F_IER 0x13 ++/* RTL8211F Unique phyiscal and multicast address (WOL) */ ++#define RTL8211F_PHYSICAL_ADDR_PAGE 0xd8c ++#define RTL8211F_PHYSICAL_ADDR_WORD0 16 ++#define RTL8211F_PHYSICAL_ADDR_WORD1 17 ++#define RTL8211F_PHYSICAL_ADDR_WORD2 18 + + #define RTL822X_VND1_SERDES_OPTION 0x697a + #define RTL822X_VND1_SERDES_OPTION_MODE_MASK GENMASK(5, 0) +-- +2.51.0 + + +From 6013af9a8dd65b8c5e941f33ec2dcf99f78c67d7 Mon Sep 17 00:00:00 2001 +From: Michael Klein +Date: Sun, 4 May 2025 19:29:15 +0200 +Subject: [PATCH 158/517] net: phy: realtek: use __set_bit() in + rtl8211f_led_hw_control_get() + +rtl8211f_led_hw_control_get() does not need atomic bit operations, +replace set_bit() by __set_bit(). + +Signed-off-by: Michael Klein +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/20250504172916.243185-6-michael@fossekall.de +Signed-off-by: Paolo Abeni +--- + drivers/net/phy/realtek/realtek_main.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c +index e01b13a9b5c3..e26098a2ff27 100644 +--- a/drivers/net/phy/realtek/realtek_main.c ++++ b/drivers/net/phy/realtek/realtek_main.c +@@ -659,17 +659,17 @@ static int rtl8211f_led_hw_control_get(struct phy_device *phydev, u8 index, + val &= RTL8211F_LEDCR_MASK; + + if (val & RTL8211F_LEDCR_LINK_10) +- set_bit(TRIGGER_NETDEV_LINK_10, rules); ++ __set_bit(TRIGGER_NETDEV_LINK_10, rules); + + if (val & RTL8211F_LEDCR_LINK_100) +- set_bit(TRIGGER_NETDEV_LINK_100, rules); ++ __set_bit(TRIGGER_NETDEV_LINK_100, rules); + + if (val & RTL8211F_LEDCR_LINK_1000) +- set_bit(TRIGGER_NETDEV_LINK_1000, rules); ++ __set_bit(TRIGGER_NETDEV_LINK_1000, rules); + + if (val & RTL8211F_LEDCR_ACT_TXRX) { +- set_bit(TRIGGER_NETDEV_RX, rules); +- set_bit(TRIGGER_NETDEV_TX, rules); ++ __set_bit(TRIGGER_NETDEV_RX, rules); ++ __set_bit(TRIGGER_NETDEV_TX, rules); + } + + return 0; +-- +2.51.0 + + +From af5ac7b353e93a7d31448c80a90f687b38805116 Mon Sep 17 00:00:00 2001 +From: Michael Klein +Date: Sun, 4 May 2025 19:29:16 +0200 +Subject: [PATCH 159/517] net: phy: realtek: Add support for PHY LEDs on + RTL8211E + +Like the RTL8211F, the RTL8211E PHY supports up to three LEDs. +Add netdev trigger support for them, too. + +Signed-off-by: Michael Klein +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/20250504172916.243185-7-michael@fossekall.de +Signed-off-by: Paolo Abeni +--- + drivers/net/phy/realtek/realtek_main.c | 125 +++++++++++++++++++++++-- + 1 file changed, 119 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c +index e26098a2ff27..301fbe141b9b 100644 +--- a/drivers/net/phy/realtek/realtek_main.c ++++ b/drivers/net/phy/realtek/realtek_main.c +@@ -40,6 +40,20 @@ + #define RTL821x_PAGE_SELECT 0x1f + #define RTL821x_SET_EXT_PAGE 0x07 + ++/* RTL8211E extension page 44/0x2c */ ++#define RTL8211E_LEDCR_EXT_PAGE 0x2c ++#define RTL8211E_LEDCR1 0x1a ++#define RTL8211E_LEDCR1_ACT_TXRX BIT(4) ++#define RTL8211E_LEDCR1_MASK BIT(4) ++#define RTL8211E_LEDCR1_SHIFT 1 ++ ++#define RTL8211E_LEDCR2 0x1c ++#define RTL8211E_LEDCR2_LINK_1000 BIT(2) ++#define RTL8211E_LEDCR2_LINK_100 BIT(1) ++#define RTL8211E_LEDCR2_LINK_10 BIT(0) ++#define RTL8211E_LEDCR2_MASK GENMASK(2, 0) ++#define RTL8211E_LEDCR2_SHIFT 4 ++ + /* RTL8211E extension page 164/0xa4 */ + #define RTL8211E_RGMII_EXT_PAGE 0xa4 + #define RTL8211E_RGMII_DELAY 0x1c +@@ -145,7 +159,8 @@ + #define RTL_8221B_VN_CG 0x001cc84a + #define RTL_8251B 0x001cc862 + +-#define RTL8211F_LED_COUNT 3 ++/* RTL8211E and RTL8211F support up to three LEDs */ ++#define RTL8211x_LED_COUNT 3 + + MODULE_DESCRIPTION("Realtek PHY driver"); + MODULE_AUTHOR("Johnson Leung"); +@@ -169,6 +184,21 @@ static int rtl821x_write_page(struct phy_device *phydev, int page) + return __phy_write(phydev, RTL821x_PAGE_SELECT, page); + } + ++static int rtl821x_read_ext_page(struct phy_device *phydev, u16 ext_page, ++ u32 regnum) ++{ ++ int oldpage, ret = 0; ++ ++ oldpage = phy_select_page(phydev, RTL821x_SET_EXT_PAGE); ++ if (oldpage >= 0) { ++ ret = __phy_write(phydev, RTL821x_EXT_PAGE_SELECT, ext_page); ++ if (ret == 0) ++ ret = __phy_read(phydev, regnum); ++ } ++ ++ return phy_restore_page(phydev, oldpage, ret); ++} ++ + static int rtl821x_modify_ext_page(struct phy_device *phydev, u16 ext_page, + u32 regnum, u16 mask, u16 set) + { +@@ -608,7 +638,7 @@ static int rtl821x_resume(struct phy_device *phydev) + return 0; + } + +-static int rtl8211f_led_hw_is_supported(struct phy_device *phydev, u8 index, ++static int rtl8211x_led_hw_is_supported(struct phy_device *phydev, u8 index, + unsigned long rules) + { + const unsigned long mask = BIT(TRIGGER_NETDEV_LINK_10) | +@@ -627,9 +657,11 @@ static int rtl8211f_led_hw_is_supported(struct phy_device *phydev, u8 index, + * rates and Active indication always at all three 10+100+1000 + * link rates. + * This code currently uses mode B only. ++ * ++ * RTL8211E PHY LED has one mode, which works like RTL8211F mode B. + */ + +- if (index >= RTL8211F_LED_COUNT) ++ if (index >= RTL8211x_LED_COUNT) + return -EINVAL; + + /* Filter out any other unsupported triggers. */ +@@ -648,7 +680,7 @@ static int rtl8211f_led_hw_control_get(struct phy_device *phydev, u8 index, + { + int val; + +- if (index >= RTL8211F_LED_COUNT) ++ if (index >= RTL8211x_LED_COUNT) + return -EINVAL; + + val = phy_read_paged(phydev, 0xd04, RTL8211F_LEDCR); +@@ -681,7 +713,7 @@ static int rtl8211f_led_hw_control_set(struct phy_device *phydev, u8 index, + const u16 mask = RTL8211F_LEDCR_MASK << (RTL8211F_LEDCR_SHIFT * index); + u16 reg = 0; + +- if (index >= RTL8211F_LED_COUNT) ++ if (index >= RTL8211x_LED_COUNT) + return -EINVAL; + + if (test_bit(TRIGGER_NETDEV_LINK_10, &rules)) +@@ -704,6 +736,84 @@ static int rtl8211f_led_hw_control_set(struct phy_device *phydev, u8 index, + return phy_modify_paged(phydev, 0xd04, RTL8211F_LEDCR, mask, reg); + } + ++static int rtl8211e_led_hw_control_get(struct phy_device *phydev, u8 index, ++ unsigned long *rules) ++{ ++ int ret; ++ u16 cr1, cr2; ++ ++ if (index >= RTL8211x_LED_COUNT) ++ return -EINVAL; ++ ++ ret = rtl821x_read_ext_page(phydev, RTL8211E_LEDCR_EXT_PAGE, ++ RTL8211E_LEDCR1); ++ if (ret < 0) ++ return ret; ++ ++ cr1 = ret >> RTL8211E_LEDCR1_SHIFT * index; ++ if (cr1 & RTL8211E_LEDCR1_ACT_TXRX) { ++ __set_bit(TRIGGER_NETDEV_RX, rules); ++ __set_bit(TRIGGER_NETDEV_TX, rules); ++ } ++ ++ ret = rtl821x_read_ext_page(phydev, RTL8211E_LEDCR_EXT_PAGE, ++ RTL8211E_LEDCR2); ++ if (ret < 0) ++ return ret; ++ ++ cr2 = ret >> RTL8211E_LEDCR2_SHIFT * index; ++ if (cr2 & RTL8211E_LEDCR2_LINK_10) ++ __set_bit(TRIGGER_NETDEV_LINK_10, rules); ++ ++ if (cr2 & RTL8211E_LEDCR2_LINK_100) ++ __set_bit(TRIGGER_NETDEV_LINK_100, rules); ++ ++ if (cr2 & RTL8211E_LEDCR2_LINK_1000) ++ __set_bit(TRIGGER_NETDEV_LINK_1000, rules); ++ ++ return ret; ++} ++ ++static int rtl8211e_led_hw_control_set(struct phy_device *phydev, u8 index, ++ unsigned long rules) ++{ ++ const u16 cr1mask = ++ RTL8211E_LEDCR1_MASK << (RTL8211E_LEDCR1_SHIFT * index); ++ const u16 cr2mask = ++ RTL8211E_LEDCR2_MASK << (RTL8211E_LEDCR2_SHIFT * index); ++ u16 cr1 = 0, cr2 = 0; ++ int ret; ++ ++ if (index >= RTL8211x_LED_COUNT) ++ return -EINVAL; ++ ++ if (test_bit(TRIGGER_NETDEV_RX, &rules) || ++ test_bit(TRIGGER_NETDEV_TX, &rules)) { ++ cr1 |= RTL8211E_LEDCR1_ACT_TXRX; ++ } ++ ++ cr1 <<= RTL8211E_LEDCR1_SHIFT * index; ++ ret = rtl821x_modify_ext_page(phydev, RTL8211E_LEDCR_EXT_PAGE, ++ RTL8211E_LEDCR1, cr1mask, cr1); ++ if (ret < 0) ++ return ret; ++ ++ if (test_bit(TRIGGER_NETDEV_LINK_10, &rules)) ++ cr2 |= RTL8211E_LEDCR2_LINK_10; ++ ++ if (test_bit(TRIGGER_NETDEV_LINK_100, &rules)) ++ cr2 |= RTL8211E_LEDCR2_LINK_100; ++ ++ if (test_bit(TRIGGER_NETDEV_LINK_1000, &rules)) ++ cr2 |= RTL8211E_LEDCR2_LINK_1000; ++ ++ cr2 <<= RTL8211E_LEDCR2_SHIFT * index; ++ ret = rtl821x_modify_ext_page(phydev, RTL8211E_LEDCR_EXT_PAGE, ++ RTL8211E_LEDCR2, cr2mask, cr2); ++ ++ return ret; ++} ++ + static int rtl8211e_config_init(struct phy_device *phydev) + { + u16 val; +@@ -1479,6 +1589,9 @@ static struct phy_driver realtek_drvs[] = { + .resume = genphy_resume, + .read_page = rtl821x_read_page, + .write_page = rtl821x_write_page, ++ .led_hw_is_supported = rtl8211x_led_hw_is_supported, ++ .led_hw_control_get = rtl8211e_led_hw_control_get, ++ .led_hw_control_set = rtl8211e_led_hw_control_set, + }, { + PHY_ID_MATCH_EXACT(0x001cc916), + .name = "RTL8211F Gigabit Ethernet", +@@ -1494,7 +1607,7 @@ static struct phy_driver realtek_drvs[] = { + .read_page = rtl821x_read_page, + .write_page = rtl821x_write_page, + .flags = PHY_ALWAYS_CALL_SUSPEND, +- .led_hw_is_supported = rtl8211f_led_hw_is_supported, ++ .led_hw_is_supported = rtl8211x_led_hw_is_supported, + .led_hw_control_get = rtl8211f_led_hw_control_get, + .led_hw_control_set = rtl8211f_led_hw_control_set, + }, { +-- +2.51.0 + + +From 955251d7b04d32610229bef09ec0a27ccbd8e370 Mon Sep 17 00:00:00 2001 +From: ChunHao Lin +Date: Fri, 16 May 2025 13:56:22 +0800 +Subject: [PATCH 160/517] net: phy: realtek: add RTL8127-internal PHY + +RTL8127-internal PHY is RTL8261C which is a integrated 10Gbps PHY with ID +0x001cc890. It follows the code path of RTL8125/RTL8126 internal NBase-T +PHY. + +Signed-off-by: ChunHao Lin +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/20250516055622.3772-1-hau@realtek.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/realtek/realtek_main.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c +index 301fbe141b9b..b5e00cdf0123 100644 +--- a/drivers/net/phy/realtek/realtek_main.c ++++ b/drivers/net/phy/realtek/realtek_main.c +@@ -158,6 +158,7 @@ + #define RTL_8221B_VB_CG 0x001cc849 + #define RTL_8221B_VN_CG 0x001cc84a + #define RTL_8251B 0x001cc862 ++#define RTL_8261C 0x001cc890 + + /* RTL8211E and RTL8211F support up to three LEDs */ + #define RTL8211x_LED_COUNT 3 +@@ -1370,6 +1371,7 @@ static int rtl_internal_nbaset_match_phy_device(struct phy_device *phydev) + case RTL_GENERIC_PHYID: + case RTL_8221B: + case RTL_8251B: ++ case RTL_8261C: + case 0x001cc841: + break; + default: +-- +2.51.0 + + +From c1c8742b69103888ee85bb7e55353066d4ef5457 Mon Sep 17 00:00:00 2001 +From: Markus Stockhausen +Date: Wed, 13 Aug 2025 01:44:07 -0400 +Subject: [PATCH 161/517] net: phy: realtek: convert RTL8226-CG to c45 only + +Short: Convert the RTL8226-CG to c45 so it can be used in its +Realtek based ecosystems. + +Long: The RTL8226-CG can be mainly found on devices of the +Realtek Otto switch platform. Devices like the Zyxel XGS1210-12 +are based on it. These implement a hardware based phy polling +in the background to update SoC status registers. + +The hardware provides 4 smi busses where phys are attached to. +For each bus one can decide if it is polled in c45 or c22 mode. +See https://svanheule.net/realtek/longan/register/smi_glb_ctrl +With this setting the register access will be limited by the +hardware. This is very complex (including caching and special +c45-over-c22 handling). But basically it boils down to "enable +protocol x and SoC will disable register access via protocol y". + +Mainline already gained support for the rtl9300 mdio driver +in commit 24e31e474769 ("net: mdio: Add RTL9300 MDIO driver"). + +It covers the basic features, but a lot effort is still needed +to understand hardware properly. So it runs a simple setup by +selecting the proper bus mode during startup. + + /* Put the interfaces into C45 mode if required */ + glb_ctrl_mask = GENMASK(19, 16); + for (i = 0; i < MAX_SMI_BUSSES; i++) + if (priv->smi_bus_is_c45[i]) + glb_ctrl_val |= GLB_CTRL_INTF_SEL(i); + ... + err = regmap_update_bits(regmap, SMI_GLB_CTRL, + glb_ctrl_mask, glb_ctrl_val); + +To avoid complex coding later on, it limits access by only +providing either c22 or c45: + + bus->name = "Realtek Switch MDIO Bus"; + if (priv->smi_bus_is_c45[mdio_bus]) { + bus->read_c45 = rtl9300_mdio_read_c45; + bus->write_c45 = rtl9300_mdio_write_c45; + } else { + bus->read = rtl9300_mdio_read_c22; + bus->write = rtl9300_mdio_write_c22; + } + +Because of these limitations the existing RTL8226 phy driver +is not working at all on Realtek switches. Convert the driver +to c45-only. + +Luckily the RTL8226 seems to support proper MDIO_PMA_EXTABLE +flags. So standard function genphy_c45_pma_read_abilities() can +call genphy_c45_pma_read_ext_abilities() and 10/100/1000 is +populated right. Thus conversion is straight forward. + +Outputs before - REMARK: For this a "hacked" bus was used that +toggles the mode for each c22/c45 access. But that is slow and +produces unstable data in the SoC status registers). + +Settings for lan9: + Supported ports: [ TP MII ] + Supported link modes: 10baseT/Half 10baseT/Full + 100baseT/Half 100baseT/Full + 1000baseT/Full + 2500baseT/Full + Supported pause frame use: Symmetric Receive-only + Supports auto-negotiation: Yes + Supported FEC modes: Not reported + Advertised link modes: 10baseT/Half 10baseT/Full + 100baseT/Half 100baseT/Full + 1000baseT/Full + 2500baseT/Full + Advertised pause frame use: Symmetric Receive-only + Advertised auto-negotiation: Yes + Advertised FEC modes: Not reported + Speed: Unknown! + Duplex: Unknown! (255) + Port: Twisted Pair + PHYAD: 24 + Transceiver: external + Auto-negotiation: on + MDI-X: Unknown + Supports Wake-on: d + Wake-on: d + Link detected: no + +Outputs with this commit: + +Settings for lan9: + Supported ports: [ TP ] + Supported link modes: 10baseT/Half 10baseT/Full + 100baseT/Half 100baseT/Full + 1000baseT/Full + 2500baseT/Full + Supported pause frame use: Symmetric Receive-only + Supports auto-negotiation: Yes + Supported FEC modes: Not reported + Advertised link modes: 10baseT/Half 10baseT/Full + 100baseT/Half 100baseT/Full + 1000baseT/Full + 2500baseT/Full + Advertised pause frame use: Symmetric Receive-only + Advertised auto-negotiation: Yes + Advertised FEC modes: Not reported + Speed: Unknown! + Duplex: Unknown! (255) + Port: Twisted Pair + PHYAD: 24 + Transceiver: external + Auto-negotiation: on + MDI-X: Unknown + Supports Wake-on: d + Wake-on: d + Link detected: no + +Signed-off-by: Markus Stockhausen +Link: https://patch.msgid.link/20250813054407.1108285-1-markus.stockhausen@gmx.de +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/realtek/realtek_main.c | 28 +++++++++++++++++++------- + 1 file changed, 21 insertions(+), 7 deletions(-) + +diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c +index b5e00cdf0123..bcfd9305e8b7 100644 +--- a/drivers/net/phy/realtek/realtek_main.c ++++ b/drivers/net/phy/realtek/realtek_main.c +@@ -1274,6 +1274,21 @@ static int rtl822x_c45_read_status(struct phy_device *phydev) + return 0; + } + ++static int rtl822x_c45_soft_reset(struct phy_device *phydev) ++{ ++ int ret, val; ++ ++ ret = phy_modify_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL1, ++ MDIO_CTRL1_RESET, MDIO_CTRL1_RESET); ++ if (ret < 0) ++ return ret; ++ ++ return phy_read_mmd_poll_timeout(phydev, MDIO_MMD_PMAPMD, ++ MDIO_CTRL1, val, ++ !(val & MDIO_CTRL1_RESET), ++ 5000, 100000, true); ++} ++ + static int rtl822xb_c45_read_status(struct phy_device *phydev) + { + int ret; +@@ -1660,13 +1675,12 @@ static struct phy_driver realtek_drvs[] = { + }, { + PHY_ID_MATCH_EXACT(0x001cc838), + .name = "RTL8226-CG 2.5Gbps PHY", +- .get_features = rtl822x_get_features, +- .config_aneg = rtl822x_config_aneg, +- .read_status = rtl822x_read_status, +- .suspend = genphy_suspend, +- .resume = rtlgen_resume, +- .read_page = rtl821x_read_page, +- .write_page = rtl821x_write_page, ++ .soft_reset = rtl822x_c45_soft_reset, ++ .get_features = rtl822x_c45_get_features, ++ .config_aneg = rtl822x_c45_config_aneg, ++ .read_status = rtl822x_c45_read_status, ++ .suspend = genphy_c45_pma_suspend, ++ .resume = rtlgen_c45_resume, + }, { + PHY_ID_MATCH_EXACT(0x001cc848), + .name = "RTL8226B-CG_RTL8221B-CG 2.5Gbps PHY", +-- +2.51.0 + + +From 19770c92bfab8e1cfb144fa63e2a6fa8a9a9c791 Mon Sep 17 00:00:00 2001 +From: Markus Stockhausen +Date: Fri, 15 Aug 2025 04:20:09 -0400 +Subject: [PATCH 162/517] net: phy: realtek: enable serdes option mode for + RTL8226-CG + +The RTL8226-CG can make use of the serdes option mode feature to +dynamically switch between SGMII and 2500base-X. From what is +known the setup sequence is much simpler with no magic values. + +Convert the exiting config_init() into a helper that configures +the PHY depending on generation 1 or 2. Call the helper from two +separated new config_init() functions. + +Finally convert the phy_driver specs of the RTL8226-CG to make +use of the new configuration and switch over to the extended +read_status() function to dynamically change the interface +according to the serdes mode. + +Remark! The logic could be simpler if the serdes mode could be +set before all other generation 2 magic values. Due to missing +RTL8221B test hardware the mmd command order was kept. + +Tested on Zyxel XGS1210-12. + +Signed-off-by: Markus Stockhausen +Link: https://patch.msgid.link/20250815082009.3678865-1-markus.stockhausen@gmx.de +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/realtek/realtek_main.c | 26 ++++++++++++++++++++------ + 1 file changed, 20 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c +index bcfd9305e8b7..c0981932429b 100644 +--- a/drivers/net/phy/realtek/realtek_main.c ++++ b/drivers/net/phy/realtek/realtek_main.c +@@ -1032,7 +1032,7 @@ static int rtl822x_probe(struct phy_device *phydev) + return 0; + } + +-static int rtl822xb_config_init(struct phy_device *phydev) ++static int rtl822x_set_serdes_option_mode(struct phy_device *phydev, bool gen1) + { + bool has_2500, has_sgmii; + u16 mode; +@@ -1067,15 +1067,18 @@ static int rtl822xb_config_init(struct phy_device *phydev) + /* the following sequence with magic numbers sets up the SerDes + * option mode + */ +- ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x75f3, 0); +- if (ret < 0) +- return ret; ++ ++ if (!gen1) { ++ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x75f3, 0); ++ if (ret < 0) ++ return ret; ++ } + + ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND1, + RTL822X_VND1_SERDES_OPTION, + RTL822X_VND1_SERDES_OPTION_MODE_MASK, + mode); +- if (ret < 0) ++ if (gen1 || ret < 0) + return ret; + + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6a04, 0x0503); +@@ -1089,6 +1092,16 @@ static int rtl822xb_config_init(struct phy_device *phydev) + return phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6f11, 0x8020); + } + ++static int rtl822x_config_init(struct phy_device *phydev) ++{ ++ return rtl822x_set_serdes_option_mode(phydev, true); ++} ++ ++static int rtl822xb_config_init(struct phy_device *phydev) ++{ ++ return rtl822x_set_serdes_option_mode(phydev, false); ++} ++ + static int rtl822xb_get_rate_matching(struct phy_device *phydev, + phy_interface_t iface) + { +@@ -1678,7 +1691,8 @@ static struct phy_driver realtek_drvs[] = { + .soft_reset = rtl822x_c45_soft_reset, + .get_features = rtl822x_c45_get_features, + .config_aneg = rtl822x_c45_config_aneg, +- .read_status = rtl822x_c45_read_status, ++ .config_init = rtl822x_config_init, ++ .read_status = rtl822xb_c45_read_status, + .suspend = genphy_c45_pma_suspend, + .resume = rtlgen_c45_resume, + }, { +-- +2.51.0 + + +From 3eda64f56ef81929d383b568d8642b7439cba90e Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Sat, 17 May 2025 22:13:45 +0200 +Subject: [PATCH 163/517] net: phy: pass PHY driver to .match_phy_device OP + +Pass PHY driver pointer to .match_phy_device OP in addition to phydev. +Having access to the PHY driver struct might be useful to check the +PHY ID of the driver is being matched for in case the PHY ID scanned in +the phydev is not consistent. + +A scenario for this is a PHY that change PHY ID after a firmware is +loaded, in such case, the PHY ID stored in PHY device struct is not +valid anymore and PHY will manually scan the ID in the match_phy_device +function. + +Having the PHY driver info is also useful for those PHY driver that +implement multiple simple .match_phy_device OP to match specific MMD PHY +ID. With this extra info if the parsing logic is the same, the matching +function can be generalized by using the phy_id in the PHY driver +instead of hardcoding. + +Rust wrapper callback is updated to align to the new match_phy_device +arguments. + +Suggested-by: Russell King (Oracle) +Reviewed-by: Russell King (Oracle) +Signed-off-by: Christian Marangi +Reviewed-by: Benno Lossin # for Rust +Reviewed-by: FUJITA Tomonori +Link: https://patch.msgid.link/20250517201353.5137-2-ansuelsmth@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/bcm87xx.c | 6 ++++-- + drivers/net/phy/icplus.c | 6 ++++-- + drivers/net/phy/marvell10g.c | 12 ++++++++---- + drivers/net/phy/micrel.c | 6 ++++-- + drivers/net/phy/nxp-c45-tja11xx.c | 6 ++++-- + drivers/net/phy/nxp-tja11xx.c | 6 ++++-- + drivers/net/phy/phy_device.c | 2 +- + drivers/net/phy/realtek/realtek_main.c | 27 +++++++++++++++++--------- + drivers/net/phy/teranetics.c | 3 ++- + include/linux/phy.h | 3 ++- + rust/kernel/net/phy.rs | 1 + + 11 files changed, 52 insertions(+), 26 deletions(-) + +diff --git a/drivers/net/phy/bcm87xx.c b/drivers/net/phy/bcm87xx.c +index e81404bf8994..1e1e2259fc2b 100644 +--- a/drivers/net/phy/bcm87xx.c ++++ b/drivers/net/phy/bcm87xx.c +@@ -185,12 +185,14 @@ static irqreturn_t bcm87xx_handle_interrupt(struct phy_device *phydev) + return IRQ_HANDLED; + } + +-static int bcm8706_match_phy_device(struct phy_device *phydev) ++static int bcm8706_match_phy_device(struct phy_device *phydev, ++ const struct phy_driver *phydrv) + { + return phydev->c45_ids.device_ids[4] == PHY_ID_BCM8706; + } + +-static int bcm8727_match_phy_device(struct phy_device *phydev) ++static int bcm8727_match_phy_device(struct phy_device *phydev, ++ const struct phy_driver *phydrv) + { + return phydev->c45_ids.device_ids[4] == PHY_ID_BCM8727; + } +diff --git a/drivers/net/phy/icplus.c b/drivers/net/phy/icplus.c +index feed270ab4ea..c6950b7145c1 100644 +--- a/drivers/net/phy/icplus.c ++++ b/drivers/net/phy/icplus.c +@@ -520,12 +520,14 @@ static int ip101a_g_match_phy_device(struct phy_device *phydev, bool ip101a) + return ip101a == !ret; + } + +-static int ip101a_match_phy_device(struct phy_device *phydev) ++static int ip101a_match_phy_device(struct phy_device *phydev, ++ const struct phy_driver *phydrv) + { + return ip101a_g_match_phy_device(phydev, true); + } + +-static int ip101g_match_phy_device(struct phy_device *phydev) ++static int ip101g_match_phy_device(struct phy_device *phydev, ++ const struct phy_driver *phydrv) + { + return ip101a_g_match_phy_device(phydev, false); + } +diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c +index 623bdb8466b8..2994a3570128 100644 +--- a/drivers/net/phy/marvell10g.c ++++ b/drivers/net/phy/marvell10g.c +@@ -1284,7 +1284,8 @@ static int mv3310_get_number_of_ports(struct phy_device *phydev) + return ret + 1; + } + +-static int mv3310_match_phy_device(struct phy_device *phydev) ++static int mv3310_match_phy_device(struct phy_device *phydev, ++ const struct phy_driver *phydrv) + { + if ((phydev->c45_ids.device_ids[MDIO_MMD_PMAPMD] & + MARVELL_PHY_ID_MASK) != MARVELL_PHY_ID_88X3310) +@@ -1293,7 +1294,8 @@ static int mv3310_match_phy_device(struct phy_device *phydev) + return mv3310_get_number_of_ports(phydev) == 1; + } + +-static int mv3340_match_phy_device(struct phy_device *phydev) ++static int mv3340_match_phy_device(struct phy_device *phydev, ++ const struct phy_driver *phydrv) + { + if ((phydev->c45_ids.device_ids[MDIO_MMD_PMAPMD] & + MARVELL_PHY_ID_MASK) != MARVELL_PHY_ID_88X3310) +@@ -1317,12 +1319,14 @@ static int mv211x_match_phy_device(struct phy_device *phydev, bool has_5g) + return !!(val & MDIO_PCS_SPEED_5G) == has_5g; + } + +-static int mv2110_match_phy_device(struct phy_device *phydev) ++static int mv2110_match_phy_device(struct phy_device *phydev, ++ const struct phy_driver *phydrv) + { + return mv211x_match_phy_device(phydev, true); + } + +-static int mv2111_match_phy_device(struct phy_device *phydev) ++static int mv2111_match_phy_device(struct phy_device *phydev, ++ const struct phy_driver *phydrv) + { + return mv211x_match_phy_device(phydev, false); + } +diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c +index 655769765bc8..2c6e75789eb7 100644 +--- a/drivers/net/phy/micrel.c ++++ b/drivers/net/phy/micrel.c +@@ -768,7 +768,8 @@ static int ksz8051_ksz8795_match_phy_device(struct phy_device *phydev, + return !ret; + } + +-static int ksz8051_match_phy_device(struct phy_device *phydev) ++static int ksz8051_match_phy_device(struct phy_device *phydev, ++ const struct phy_driver *phydrv) + { + return ksz8051_ksz8795_match_phy_device(phydev, true); + } +@@ -888,7 +889,8 @@ static int ksz8061_config_init(struct phy_device *phydev) + return kszphy_config_init(phydev); + } + +-static int ksz8795_match_phy_device(struct phy_device *phydev) ++static int ksz8795_match_phy_device(struct phy_device *phydev, ++ const struct phy_driver *phydrv) + { + return ksz8051_ksz8795_match_phy_device(phydev, false); + } +diff --git a/drivers/net/phy/nxp-c45-tja11xx.c b/drivers/net/phy/nxp-c45-tja11xx.c +index 9d6b336f9971..9aeae2a6c638 100644 +--- a/drivers/net/phy/nxp-c45-tja11xx.c ++++ b/drivers/net/phy/nxp-c45-tja11xx.c +@@ -1944,13 +1944,15 @@ static int nxp_c45_macsec_ability(struct phy_device *phydev) + return macsec_ability; + } + +-static int tja1103_match_phy_device(struct phy_device *phydev) ++static int tja1103_match_phy_device(struct phy_device *phydev, ++ const struct phy_driver *phydrv) + { + return phy_id_compare(phydev->phy_id, PHY_ID_TJA_1103, PHY_ID_MASK) && + !nxp_c45_macsec_ability(phydev); + } + +-static int tja1104_match_phy_device(struct phy_device *phydev) ++static int tja1104_match_phy_device(struct phy_device *phydev, ++ const struct phy_driver *phydrv) + { + return phy_id_compare(phydev->phy_id, PHY_ID_TJA_1103, PHY_ID_MASK) && + nxp_c45_macsec_ability(phydev); +diff --git a/drivers/net/phy/nxp-tja11xx.c b/drivers/net/phy/nxp-tja11xx.c +index ed7fa26bac8e..08dda6926732 100644 +--- a/drivers/net/phy/nxp-tja11xx.c ++++ b/drivers/net/phy/nxp-tja11xx.c +@@ -646,12 +646,14 @@ static int tja1102_match_phy_device(struct phy_device *phydev, bool port0) + return !ret; + } + +-static int tja1102_p0_match_phy_device(struct phy_device *phydev) ++static int tja1102_p0_match_phy_device(struct phy_device *phydev, ++ const struct phy_driver *phydrv) + { + return tja1102_match_phy_device(phydev, true); + } + +-static int tja1102_p1_match_phy_device(struct phy_device *phydev) ++static int tja1102_p1_match_phy_device(struct phy_device *phydev, ++ const struct phy_driver *phydrv) + { + return tja1102_match_phy_device(phydev, false); + } +diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c +index 762f909242b4..71f6cadde109 100644 +--- a/drivers/net/phy/phy_device.c ++++ b/drivers/net/phy/phy_device.c +@@ -600,7 +600,7 @@ static int phy_bus_match(struct device *dev, const struct device_driver *drv) + return 0; + + if (phydrv->match_phy_device) +- return phydrv->match_phy_device(phydev); ++ return phydrv->match_phy_device(phydev, phydrv); + + if (phydev->is_c45) { + for (i = 1; i < num_ids; i++) { +diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c +index c0981932429b..114d219562f1 100644 +--- a/drivers/net/phy/realtek/realtek_main.c ++++ b/drivers/net/phy/realtek/realtek_main.c +@@ -1343,13 +1343,15 @@ static bool rtlgen_supports_mmd(struct phy_device *phydev) + return val > 0; + } + +-static int rtlgen_match_phy_device(struct phy_device *phydev) ++static int rtlgen_match_phy_device(struct phy_device *phydev, ++ const struct phy_driver *phydrv) + { + return phydev->phy_id == RTL_GENERIC_PHYID && + !rtlgen_supports_2_5gbps(phydev); + } + +-static int rtl8226_match_phy_device(struct phy_device *phydev) ++static int rtl8226_match_phy_device(struct phy_device *phydev, ++ const struct phy_driver *phydrv) + { + return phydev->phy_id == RTL_GENERIC_PHYID && + rtlgen_supports_2_5gbps(phydev) && +@@ -1365,32 +1367,38 @@ static int rtlgen_is_c45_match(struct phy_device *phydev, unsigned int id, + return !is_c45 && (id == phydev->phy_id); + } + +-static int rtl8221b_match_phy_device(struct phy_device *phydev) ++static int rtl8221b_match_phy_device(struct phy_device *phydev, ++ const struct phy_driver *phydrv) + { + return phydev->phy_id == RTL_8221B && rtlgen_supports_mmd(phydev); + } + +-static int rtl8221b_vb_cg_c22_match_phy_device(struct phy_device *phydev) ++static int rtl8221b_vb_cg_c22_match_phy_device(struct phy_device *phydev, ++ const struct phy_driver *phydrv) + { + return rtlgen_is_c45_match(phydev, RTL_8221B_VB_CG, false); + } + +-static int rtl8221b_vb_cg_c45_match_phy_device(struct phy_device *phydev) ++static int rtl8221b_vb_cg_c45_match_phy_device(struct phy_device *phydev, ++ const struct phy_driver *phydrv) + { + return rtlgen_is_c45_match(phydev, RTL_8221B_VB_CG, true); + } + +-static int rtl8221b_vn_cg_c22_match_phy_device(struct phy_device *phydev) ++static int rtl8221b_vn_cg_c22_match_phy_device(struct phy_device *phydev, ++ const struct phy_driver *phydrv) + { + return rtlgen_is_c45_match(phydev, RTL_8221B_VN_CG, false); + } + +-static int rtl8221b_vn_cg_c45_match_phy_device(struct phy_device *phydev) ++static int rtl8221b_vn_cg_c45_match_phy_device(struct phy_device *phydev, ++ const struct phy_driver *phydrv) + { + return rtlgen_is_c45_match(phydev, RTL_8221B_VN_CG, true); + } + +-static int rtl_internal_nbaset_match_phy_device(struct phy_device *phydev) ++static int rtl_internal_nbaset_match_phy_device(struct phy_device *phydev, ++ const struct phy_driver *phydrv) + { + if (phydev->is_c45) + return false; +@@ -1409,7 +1417,8 @@ static int rtl_internal_nbaset_match_phy_device(struct phy_device *phydev) + return rtlgen_supports_2_5gbps(phydev) && !rtlgen_supports_mmd(phydev); + } + +-static int rtl8251b_c45_match_phy_device(struct phy_device *phydev) ++static int rtl8251b_c45_match_phy_device(struct phy_device *phydev, ++ const struct phy_driver *phydrv) + { + return rtlgen_is_c45_match(phydev, RTL_8251B, true); + } +diff --git a/drivers/net/phy/teranetics.c b/drivers/net/phy/teranetics.c +index 752d4bf7bb99..46c5ff7d7b56 100644 +--- a/drivers/net/phy/teranetics.c ++++ b/drivers/net/phy/teranetics.c +@@ -67,7 +67,8 @@ static int teranetics_read_status(struct phy_device *phydev) + return 0; + } + +-static int teranetics_match_phy_device(struct phy_device *phydev) ++static int teranetics_match_phy_device(struct phy_device *phydev, ++ const struct phy_driver *phydrv) + { + return phydev->c45_ids.device_ids[3] == PHY_ID_TN2020; + } +diff --git a/include/linux/phy.h b/include/linux/phy.h +index df147d9d302f..1bdcc3dd8b66 100644 +--- a/include/linux/phy.h ++++ b/include/linux/phy.h +@@ -1035,7 +1035,8 @@ struct phy_driver { + * driver for the given phydev. If NULL, matching is based on + * phy_id and phy_id_mask. + */ +- int (*match_phy_device)(struct phy_device *phydev); ++ int (*match_phy_device)(struct phy_device *phydev, ++ const struct phy_driver *phydrv); + + /** + * @set_wol: Some devices (e.g. qnap TS-119P II) require PHY +diff --git a/rust/kernel/net/phy.rs b/rust/kernel/net/phy.rs +index beb62ec712c3..40214bbe4677 100644 +--- a/rust/kernel/net/phy.rs ++++ b/rust/kernel/net/phy.rs +@@ -421,6 +421,7 @@ impl Adapter { + /// `phydev` must be passed by the corresponding callback in `phy_driver`. + unsafe extern "C" fn match_phy_device_callback( + phydev: *mut bindings::phy_device, ++ _phydrv: *const bindings::phy_driver, + ) -> crate::ffi::c_int { + // SAFETY: This callback is called only in contexts + // where we hold `phy_device->lock`, so the accessors on +-- +2.51.0 + + +From 175ba11ce1ac5beacdbe65b7fd3acbe9002f8d1f Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Sat, 17 May 2025 22:13:48 +0200 +Subject: [PATCH 164/517] net: phy: introduce genphy_match_phy_device() + +Introduce new API, genphy_match_phy_device(), to provide a way to check +to match a PHY driver for a PHY device based on the info stored in the +PHY device struct. + +The function generalize the logic used in phy_bus_match() to check the +PHY ID whether if C45 or C22 ID should be used for matching. + +This is useful for custom .match_phy_device function that wants to use +the generic logic under some condition. (example a PHY is already setup +and provide the correct PHY ID) + +Reviewed-by: Russell King (Oracle) +Signed-off-by: Christian Marangi +Link: https://patch.msgid.link/20250517201353.5137-5-ansuelsmth@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/phy_device.c | 52 +++++++++++++++++++++++++----------- + include/linux/phy.h | 3 +++ + 2 files changed, 40 insertions(+), 15 deletions(-) + +diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c +index 71f6cadde109..2e08d20a3cfb 100644 +--- a/drivers/net/phy/phy_device.c ++++ b/drivers/net/phy/phy_device.c +@@ -589,20 +589,26 @@ static int phy_scan_fixups(struct phy_device *phydev) + return 0; + } + +-static int phy_bus_match(struct device *dev, const struct device_driver *drv) ++/** ++ * genphy_match_phy_device - match a PHY device with a PHY driver ++ * @phydev: target phy_device struct ++ * @phydrv: target phy_driver struct ++ * ++ * Description: Checks whether the given PHY device matches the specified ++ * PHY driver. For Clause 45 PHYs, iterates over the available device ++ * identifiers and compares them against the driver's expected PHY ID, ++ * applying the provided mask. For Clause 22 PHYs, a direct ID comparison ++ * is performed. ++ * ++ * Return: 1 if the PHY device matches the driver, 0 otherwise. ++ */ ++int genphy_match_phy_device(struct phy_device *phydev, ++ const struct phy_driver *phydrv) + { +- struct phy_device *phydev = to_phy_device(dev); +- const struct phy_driver *phydrv = to_phy_driver(drv); +- const int num_ids = ARRAY_SIZE(phydev->c45_ids.device_ids); +- int i; +- +- if (!(phydrv->mdiodrv.flags & MDIO_DEVICE_IS_PHY)) +- return 0; +- +- if (phydrv->match_phy_device) +- return phydrv->match_phy_device(phydev, phydrv); +- + if (phydev->is_c45) { ++ const int num_ids = ARRAY_SIZE(phydev->c45_ids.device_ids); ++ int i; ++ + for (i = 1; i < num_ids; i++) { + if (phydev->c45_ids.device_ids[i] == 0xffffffff) + continue; +@@ -611,11 +617,27 @@ static int phy_bus_match(struct device *dev, const struct device_driver *drv) + phydrv->phy_id, phydrv->phy_id_mask)) + return 1; + } ++ + return 0; +- } else { +- return phy_id_compare(phydev->phy_id, phydrv->phy_id, +- phydrv->phy_id_mask); + } ++ ++ return phy_id_compare(phydev->phy_id, phydrv->phy_id, ++ phydrv->phy_id_mask); ++} ++EXPORT_SYMBOL_GPL(genphy_match_phy_device); ++ ++static int phy_bus_match(struct device *dev, const struct device_driver *drv) ++{ ++ struct phy_device *phydev = to_phy_device(dev); ++ const struct phy_driver *phydrv = to_phy_driver(drv); ++ ++ if (!(phydrv->mdiodrv.flags & MDIO_DEVICE_IS_PHY)) ++ return 0; ++ ++ if (phydrv->match_phy_device) ++ return phydrv->match_phy_device(phydev, phydrv); ++ ++ return genphy_match_phy_device(phydev, phydrv); + } + + static ssize_t +diff --git a/include/linux/phy.h b/include/linux/phy.h +index 1bdcc3dd8b66..85217937e489 100644 +--- a/include/linux/phy.h ++++ b/include/linux/phy.h +@@ -1940,6 +1940,9 @@ char *phy_attached_info_irq(struct phy_device *phydev) + __malloc; + void phy_attached_info(struct phy_device *phydev); + ++int genphy_match_phy_device(struct phy_device *phydev, ++ const struct phy_driver *phydrv); ++ + /* Clause 22 PHY */ + int genphy_read_abilities(struct phy_device *phydev); + int genphy_setup_forced(struct phy_device *phydev); +-- +2.51.0 + + +From 607e13a6b9b9484da3e5e549dee6883ad71fe0d3 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Sat, 17 May 2025 22:13:49 +0200 +Subject: [PATCH 165/517] net: phy: Add support for Aeonsemi AS21xxx PHYs + +Add support for Aeonsemi AS21xxx 10G C45 PHYs. These PHYs integrate +an IPC to setup some configuration and require special handling to +sync with the parity bit. The parity bit is a way the IPC use to +follow correct order of command sent. + +Supported PHYs AS21011JB1, AS21011PB1, AS21010JB1, AS21010PB1, +AS21511JB1, AS21511PB1, AS21510JB1, AS21510PB1, AS21210JB1, +AS21210PB1 that all register with the PHY ID 0x7500 0x7510 +before the firmware is loaded. + +They all support up to 5 LEDs with various HW mode supported. + +While implementing it was found some strange coincidence with using the +same logic for implementing C22 in MMD regs in Broadcom PHYs. + +For reference here the AS21xxx PHY name logic: + +AS21x1xxB1 + ^ ^^ + | |J: Supports SyncE/PTP + | |P: No SyncE/PTP support + | 1: Supports 2nd Serdes + | 2: Not 2nd Serdes support + 0: 10G, 5G, 2.5G + 5: 5G, 2.5G + 2: 2.5G + +Reviewed-by: Andrew Lunn +Signed-off-by: Christian Marangi +Link: https://patch.msgid.link/20250517201353.5137-6-ansuelsmth@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/Kconfig | 12 + + drivers/net/phy/Makefile | 1 + + drivers/net/phy/as21xxx.c | 1087 +++++++++++++++++++++++++++++++++++++ + 3 files changed, 1100 insertions(+) + create mode 100644 drivers/net/phy/as21xxx.c + +diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig +index f7e21a2761b8..01cc31817357 100644 +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -79,6 +79,18 @@ config SFP + + comment "MII PHY device drivers" + ++config AS21XXX_PHY ++ tristate "Aeonsemi AS21xxx PHYs" ++ help ++ Currently supports the Aeonsemi AS21xxx PHY. ++ ++ These are C45 PHYs 10G that require all a generic firmware. ++ ++ Supported PHYs AS21011JB1, AS21011PB1, AS21010JB1, AS21010PB1, ++ AS21511JB1, AS21511PB1, AS21510JB1, AS21510PB1, AS21210JB1, ++ AS21210PB1 that all register with the PHY ID 0x7500 0x7500 ++ before the firmware is loaded. ++ + config AIR_EN8811H_PHY + tristate "Airoha EN8811H 2.5 Gigabit PHY" + help +diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile +index a38b01f74db7..768d1e8ebf80 100644 +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -39,6 +39,7 @@ obj-$(CONFIG_AIR_EN8811H_PHY) += air_en8811h.o + obj-$(CONFIG_AMD_PHY) += amd.o + obj-$(CONFIG_AMCC_QT2025_PHY) += qt2025.o + obj-$(CONFIG_AQUANTIA_PHY) += aquantia/ ++obj-$(CONFIG_AS21XXX_PHY) += as21xxx.o + ifdef CONFIG_AX88796B_RUST_PHY + obj-$(CONFIG_AX88796B_PHY) += ax88796b_rust.o + else +diff --git a/drivers/net/phy/as21xxx.c b/drivers/net/phy/as21xxx.c +new file mode 100644 +index 000000000000..037d79944eca +--- /dev/null ++++ b/drivers/net/phy/as21xxx.c +@@ -0,0 +1,1087 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Aeonsemi AS21XXxX PHY Driver ++ * ++ * Author: Christian Marangi ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#define VEND1_GLB_REG_CPU_RESET_ADDR_LO_BASEADDR 0x3 ++#define VEND1_GLB_REG_CPU_RESET_ADDR_HI_BASEADDR 0x4 ++ ++#define VEND1_GLB_REG_CPU_CTRL 0xe ++#define VEND1_GLB_CPU_CTRL_MASK GENMASK(4, 0) ++#define VEND1_GLB_CPU_CTRL_LED_POLARITY_MASK GENMASK(12, 8) ++#define VEND1_GLB_CPU_CTRL_LED_POLARITY(_n) FIELD_PREP(VEND1_GLB_CPU_CTRL_LED_POLARITY_MASK, \ ++ BIT(_n)) ++ ++#define VEND1_FW_START_ADDR 0x100 ++ ++#define VEND1_GLB_REG_MDIO_INDIRECT_ADDRCMD 0x101 ++#define VEND1_GLB_REG_MDIO_INDIRECT_LOAD 0x102 ++ ++#define VEND1_GLB_REG_MDIO_INDIRECT_STATUS 0x103 ++ ++#define VEND1_PTP_CLK 0x142 ++#define VEND1_PTP_CLK_EN BIT(6) ++ ++/* 5 LED at step of 0x20 ++ * FE: Fast-Ethernet (10/100) ++ * GE: Gigabit-Ethernet (1000) ++ * NG: New-Generation (2500/5000/10000) ++ */ ++#define VEND1_LED_REG(_n) (0x1800 + ((_n) * 0x10)) ++#define VEND1_LED_REG_A_EVENT GENMASK(15, 11) ++#define VEND1_LED_CONF 0x1881 ++#define VEND1_LED_CONFG_BLINK GENMASK(7, 0) ++ ++#define VEND1_SPEED_STATUS 0x4002 ++#define VEND1_SPEED_MASK GENMASK(7, 0) ++#define VEND1_SPEED_10000 FIELD_PREP_CONST(VEND1_SPEED_MASK, 0x3) ++#define VEND1_SPEED_5000 FIELD_PREP_CONST(VEND1_SPEED_MASK, 0x5) ++#define VEND1_SPEED_2500 FIELD_PREP_CONST(VEND1_SPEED_MASK, 0x9) ++#define VEND1_SPEED_1000 FIELD_PREP_CONST(VEND1_SPEED_MASK, 0x10) ++#define VEND1_SPEED_100 FIELD_PREP_CONST(VEND1_SPEED_MASK, 0x20) ++#define VEND1_SPEED_10 FIELD_PREP_CONST(VEND1_SPEED_MASK, 0x0) ++ ++#define VEND1_IPC_CMD 0x5801 ++#define AEON_IPC_CMD_PARITY BIT(15) ++#define AEON_IPC_CMD_SIZE GENMASK(10, 6) ++#define AEON_IPC_CMD_OPCODE GENMASK(5, 0) ++ ++#define IPC_CMD_NOOP 0x0 /* Do nothing */ ++#define IPC_CMD_INFO 0x1 /* Get Firmware Version */ ++#define IPC_CMD_SYS_CPU 0x2 /* SYS_CPU */ ++#define IPC_CMD_BULK_DATA 0xa /* Pass bulk data in ipc registers. */ ++#define IPC_CMD_BULK_WRITE 0xc /* Write bulk data to memory */ ++#define IPC_CMD_CFG_PARAM 0x1a /* Write config parameters to memory */ ++#define IPC_CMD_NG_TESTMODE 0x1b /* Set NG test mode and tone */ ++#define IPC_CMD_TEMP_MON 0x15 /* Temperature monitoring function */ ++#define IPC_CMD_SET_LED 0x23 /* Set led */ ++ ++#define VEND1_IPC_STS 0x5802 ++#define AEON_IPC_STS_PARITY BIT(15) ++#define AEON_IPC_STS_SIZE GENMASK(14, 10) ++#define AEON_IPC_STS_OPCODE GENMASK(9, 4) ++#define AEON_IPC_STS_STATUS GENMASK(3, 0) ++#define AEON_IPC_STS_STATUS_RCVD FIELD_PREP_CONST(AEON_IPC_STS_STATUS, 0x1) ++#define AEON_IPC_STS_STATUS_PROCESS FIELD_PREP_CONST(AEON_IPC_STS_STATUS, 0x2) ++#define AEON_IPC_STS_STATUS_SUCCESS FIELD_PREP_CONST(AEON_IPC_STS_STATUS, 0x4) ++#define AEON_IPC_STS_STATUS_ERROR FIELD_PREP_CONST(AEON_IPC_STS_STATUS, 0x8) ++#define AEON_IPC_STS_STATUS_BUSY FIELD_PREP_CONST(AEON_IPC_STS_STATUS, 0xe) ++#define AEON_IPC_STS_STATUS_READY FIELD_PREP_CONST(AEON_IPC_STS_STATUS, 0xf) ++ ++#define VEND1_IPC_DATA0 0x5808 ++#define VEND1_IPC_DATA1 0x5809 ++#define VEND1_IPC_DATA2 0x580a ++#define VEND1_IPC_DATA3 0x580b ++#define VEND1_IPC_DATA4 0x580c ++#define VEND1_IPC_DATA5 0x580d ++#define VEND1_IPC_DATA6 0x580e ++#define VEND1_IPC_DATA7 0x580f ++#define VEND1_IPC_DATA(_n) (VEND1_IPC_DATA0 + (_n)) ++ ++/* Sub command of CMD_INFO */ ++#define IPC_INFO_VERSION 0x1 ++ ++/* Sub command of CMD_SYS_CPU */ ++#define IPC_SYS_CPU_REBOOT 0x3 ++#define IPC_SYS_CPU_IMAGE_OFST 0x4 ++#define IPC_SYS_CPU_IMAGE_CHECK 0x5 ++#define IPC_SYS_CPU_PHY_ENABLE 0x6 ++ ++/* Sub command of CMD_CFG_PARAM */ ++#define IPC_CFG_PARAM_DIRECT 0x4 ++ ++/* CFG DIRECT sub command */ ++#define IPC_CFG_PARAM_DIRECT_NG_PHYCTRL 0x1 ++#define IPC_CFG_PARAM_DIRECT_CU_AN 0x2 ++#define IPC_CFG_PARAM_DIRECT_SDS_PCS 0x3 ++#define IPC_CFG_PARAM_DIRECT_AUTO_EEE 0x4 ++#define IPC_CFG_PARAM_DIRECT_SDS_PMA 0x5 ++#define IPC_CFG_PARAM_DIRECT_DPC_RA 0x6 ++#define IPC_CFG_PARAM_DIRECT_DPC_PKT_CHK 0x7 ++#define IPC_CFG_PARAM_DIRECT_DPC_SDS_WAIT_ETH 0x8 ++#define IPC_CFG_PARAM_DIRECT_WDT 0x9 ++#define IPC_CFG_PARAM_DIRECT_SDS_RESTART_AN 0x10 ++#define IPC_CFG_PARAM_DIRECT_TEMP_MON 0x11 ++#define IPC_CFG_PARAM_DIRECT_WOL 0x12 ++ ++/* Sub command of CMD_TEMP_MON */ ++#define IPC_CMD_TEMP_MON_GET 0x4 ++ ++#define AS21XXX_MDIO_AN_C22 0xffe0 ++ ++#define PHY_ID_AS21XXX 0x75009410 ++/* AS21xxx ID Legend ++ * AS21x1xxB1 ++ * ^ ^^ ++ * | |J: Supports SyncE/PTP ++ * | |P: No SyncE/PTP support ++ * | 1: Supports 2nd Serdes ++ * | 2: Not 2nd Serdes support ++ * 0: 10G, 5G, 2.5G ++ * 5: 5G, 2.5G ++ * 2: 2.5G ++ */ ++#define PHY_ID_AS21011JB1 0x75009402 ++#define PHY_ID_AS21011PB1 0x75009412 ++#define PHY_ID_AS21010JB1 0x75009422 ++#define PHY_ID_AS21010PB1 0x75009432 ++#define PHY_ID_AS21511JB1 0x75009442 ++#define PHY_ID_AS21511PB1 0x75009452 ++#define PHY_ID_AS21510JB1 0x75009462 ++#define PHY_ID_AS21510PB1 0x75009472 ++#define PHY_ID_AS21210JB1 0x75009482 ++#define PHY_ID_AS21210PB1 0x75009492 ++#define PHY_VENDOR_AEONSEMI 0x75009400 ++ ++#define AEON_MAX_LEDS 5 ++#define AEON_IPC_DELAY 10000 ++#define AEON_IPC_TIMEOUT (AEON_IPC_DELAY * 100) ++#define AEON_IPC_DATA_NUM_REGISTERS 8 ++#define AEON_IPC_DATA_MAX (AEON_IPC_DATA_NUM_REGISTERS * sizeof(u16)) ++ ++#define AEON_BOOT_ADDR 0x1000 ++#define AEON_CPU_BOOT_ADDR 0x2000 ++#define AEON_CPU_CTRL_FW_LOAD (BIT(4) | BIT(2) | BIT(1) | BIT(0)) ++#define AEON_CPU_CTRL_FW_START BIT(0) ++ ++enum as21xxx_led_event { ++ VEND1_LED_REG_A_EVENT_ON_10 = 0x0, ++ VEND1_LED_REG_A_EVENT_ON_100, ++ VEND1_LED_REG_A_EVENT_ON_1000, ++ VEND1_LED_REG_A_EVENT_ON_2500, ++ VEND1_LED_REG_A_EVENT_ON_5000, ++ VEND1_LED_REG_A_EVENT_ON_10000, ++ VEND1_LED_REG_A_EVENT_ON_FE_GE, ++ VEND1_LED_REG_A_EVENT_ON_NG, ++ VEND1_LED_REG_A_EVENT_ON_FULL_DUPLEX, ++ VEND1_LED_REG_A_EVENT_ON_COLLISION, ++ VEND1_LED_REG_A_EVENT_BLINK_TX, ++ VEND1_LED_REG_A_EVENT_BLINK_RX, ++ VEND1_LED_REG_A_EVENT_BLINK_ACT, ++ VEND1_LED_REG_A_EVENT_ON_LINK, ++ VEND1_LED_REG_A_EVENT_ON_LINK_BLINK_ACT, ++ VEND1_LED_REG_A_EVENT_ON_LINK_BLINK_RX, ++ VEND1_LED_REG_A_EVENT_ON_FE_GE_BLINK_ACT, ++ VEND1_LED_REG_A_EVENT_ON_NG_BLINK_ACT, ++ VEND1_LED_REG_A_EVENT_ON_NG_BLINK_FE_GE, ++ VEND1_LED_REG_A_EVENT_ON_FD_BLINK_COLLISION, ++ VEND1_LED_REG_A_EVENT_ON, ++ VEND1_LED_REG_A_EVENT_OFF, ++}; ++ ++struct as21xxx_led_pattern_info { ++ unsigned int pattern; ++ u16 val; ++}; ++ ++struct as21xxx_priv { ++ bool parity_status; ++ /* Protect concurrent IPC access */ ++ struct mutex ipc_lock; ++}; ++ ++static struct as21xxx_led_pattern_info as21xxx_led_supported_pattern[] = { ++ { ++ .pattern = BIT(TRIGGER_NETDEV_LINK_10), ++ .val = VEND1_LED_REG_A_EVENT_ON_10 ++ }, ++ { ++ .pattern = BIT(TRIGGER_NETDEV_LINK_100), ++ .val = VEND1_LED_REG_A_EVENT_ON_100 ++ }, ++ { ++ .pattern = BIT(TRIGGER_NETDEV_LINK_1000), ++ .val = VEND1_LED_REG_A_EVENT_ON_1000 ++ }, ++ { ++ .pattern = BIT(TRIGGER_NETDEV_LINK_2500), ++ .val = VEND1_LED_REG_A_EVENT_ON_2500 ++ }, ++ { ++ .pattern = BIT(TRIGGER_NETDEV_LINK_5000), ++ .val = VEND1_LED_REG_A_EVENT_ON_5000 ++ }, ++ { ++ .pattern = BIT(TRIGGER_NETDEV_LINK_10000), ++ .val = VEND1_LED_REG_A_EVENT_ON_10000 ++ }, ++ { ++ .pattern = BIT(TRIGGER_NETDEV_LINK), ++ .val = VEND1_LED_REG_A_EVENT_ON_LINK ++ }, ++ { ++ .pattern = BIT(TRIGGER_NETDEV_LINK_10) | ++ BIT(TRIGGER_NETDEV_LINK_100) | ++ BIT(TRIGGER_NETDEV_LINK_1000), ++ .val = VEND1_LED_REG_A_EVENT_ON_FE_GE ++ }, ++ { ++ .pattern = BIT(TRIGGER_NETDEV_LINK_2500) | ++ BIT(TRIGGER_NETDEV_LINK_5000) | ++ BIT(TRIGGER_NETDEV_LINK_10000), ++ .val = VEND1_LED_REG_A_EVENT_ON_NG ++ }, ++ { ++ .pattern = BIT(TRIGGER_NETDEV_FULL_DUPLEX), ++ .val = VEND1_LED_REG_A_EVENT_ON_FULL_DUPLEX ++ }, ++ { ++ .pattern = BIT(TRIGGER_NETDEV_TX), ++ .val = VEND1_LED_REG_A_EVENT_BLINK_TX ++ }, ++ { ++ .pattern = BIT(TRIGGER_NETDEV_RX), ++ .val = VEND1_LED_REG_A_EVENT_BLINK_RX ++ }, ++ { ++ .pattern = BIT(TRIGGER_NETDEV_TX) | ++ BIT(TRIGGER_NETDEV_RX), ++ .val = VEND1_LED_REG_A_EVENT_BLINK_ACT ++ }, ++ { ++ .pattern = BIT(TRIGGER_NETDEV_LINK_10) | ++ BIT(TRIGGER_NETDEV_LINK_100) | ++ BIT(TRIGGER_NETDEV_LINK_1000) | ++ BIT(TRIGGER_NETDEV_LINK_2500) | ++ BIT(TRIGGER_NETDEV_LINK_5000) | ++ BIT(TRIGGER_NETDEV_LINK_10000), ++ .val = VEND1_LED_REG_A_EVENT_ON_LINK ++ }, ++ { ++ .pattern = BIT(TRIGGER_NETDEV_LINK_10) | ++ BIT(TRIGGER_NETDEV_LINK_100) | ++ BIT(TRIGGER_NETDEV_LINK_1000) | ++ BIT(TRIGGER_NETDEV_LINK_2500) | ++ BIT(TRIGGER_NETDEV_LINK_5000) | ++ BIT(TRIGGER_NETDEV_LINK_10000) | ++ BIT(TRIGGER_NETDEV_TX) | ++ BIT(TRIGGER_NETDEV_RX), ++ .val = VEND1_LED_REG_A_EVENT_ON_LINK_BLINK_ACT ++ }, ++ { ++ .pattern = BIT(TRIGGER_NETDEV_LINK_10) | ++ BIT(TRIGGER_NETDEV_LINK_100) | ++ BIT(TRIGGER_NETDEV_LINK_1000) | ++ BIT(TRIGGER_NETDEV_LINK_2500) | ++ BIT(TRIGGER_NETDEV_LINK_5000) | ++ BIT(TRIGGER_NETDEV_LINK_10000) | ++ BIT(TRIGGER_NETDEV_RX), ++ .val = VEND1_LED_REG_A_EVENT_ON_LINK_BLINK_RX ++ }, ++ { ++ .pattern = BIT(TRIGGER_NETDEV_LINK_10) | ++ BIT(TRIGGER_NETDEV_LINK_100) | ++ BIT(TRIGGER_NETDEV_LINK_1000) | ++ BIT(TRIGGER_NETDEV_TX) | ++ BIT(TRIGGER_NETDEV_RX), ++ .val = VEND1_LED_REG_A_EVENT_ON_FE_GE_BLINK_ACT ++ }, ++ { ++ .pattern = BIT(TRIGGER_NETDEV_LINK_2500) | ++ BIT(TRIGGER_NETDEV_LINK_5000) | ++ BIT(TRIGGER_NETDEV_LINK_10000) | ++ BIT(TRIGGER_NETDEV_TX) | ++ BIT(TRIGGER_NETDEV_RX), ++ .val = VEND1_LED_REG_A_EVENT_ON_NG_BLINK_ACT ++ } ++}; ++ ++static int aeon_firmware_boot(struct phy_device *phydev, const u8 *data, ++ size_t size) ++{ ++ int i, ret; ++ u16 val; ++ ++ ret = phy_modify_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLB_REG_CPU_CTRL, ++ VEND1_GLB_CPU_CTRL_MASK, AEON_CPU_CTRL_FW_LOAD); ++ if (ret) ++ return ret; ++ ++ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_FW_START_ADDR, ++ AEON_BOOT_ADDR); ++ if (ret) ++ return ret; ++ ++ ret = phy_modify_mmd(phydev, MDIO_MMD_VEND1, ++ VEND1_GLB_REG_MDIO_INDIRECT_ADDRCMD, ++ 0x3ffc, 0xc000); ++ if (ret) ++ return ret; ++ ++ val = phy_read_mmd(phydev, MDIO_MMD_VEND1, ++ VEND1_GLB_REG_MDIO_INDIRECT_STATUS); ++ if (val > 1) { ++ phydev_err(phydev, "wrong origin mdio_indirect_status: %x\n", val); ++ return -EINVAL; ++ } ++ ++ /* Firmware is always aligned to u16 */ ++ for (i = 0; i < size; i += 2) { ++ val = data[i + 1] << 8 | data[i]; ++ ++ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, ++ VEND1_GLB_REG_MDIO_INDIRECT_LOAD, val); ++ if (ret) ++ return ret; ++ } ++ ++ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, ++ VEND1_GLB_REG_CPU_RESET_ADDR_LO_BASEADDR, ++ lower_16_bits(AEON_CPU_BOOT_ADDR)); ++ if (ret) ++ return ret; ++ ++ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, ++ VEND1_GLB_REG_CPU_RESET_ADDR_HI_BASEADDR, ++ upper_16_bits(AEON_CPU_BOOT_ADDR)); ++ if (ret) ++ return ret; ++ ++ return phy_modify_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLB_REG_CPU_CTRL, ++ VEND1_GLB_CPU_CTRL_MASK, AEON_CPU_CTRL_FW_START); ++} ++ ++static int aeon_firmware_load(struct phy_device *phydev) ++{ ++ struct device *dev = &phydev->mdio.dev; ++ const struct firmware *fw; ++ const char *fw_name; ++ int ret; ++ ++ ret = of_property_read_string(dev->of_node, "firmware-name", ++ &fw_name); ++ if (ret) ++ return ret; ++ ++ ret = request_firmware(&fw, fw_name, dev); ++ if (ret) { ++ phydev_err(phydev, "failed to find FW file %s (%d)\n", ++ fw_name, ret); ++ return ret; ++ } ++ ++ ret = aeon_firmware_boot(phydev, fw->data, fw->size); ++ ++ release_firmware(fw); ++ ++ return ret; ++} ++ ++static bool aeon_ipc_ready(u16 val, bool parity_status) ++{ ++ u16 status; ++ ++ if (FIELD_GET(AEON_IPC_STS_PARITY, val) != parity_status) ++ return false; ++ ++ status = val & AEON_IPC_STS_STATUS; ++ ++ return status != AEON_IPC_STS_STATUS_RCVD && ++ status != AEON_IPC_STS_STATUS_PROCESS && ++ status != AEON_IPC_STS_STATUS_BUSY; ++} ++ ++static int aeon_ipc_wait_cmd(struct phy_device *phydev, bool parity_status) ++{ ++ u16 val; ++ ++ /* Exit condition logic: ++ * - Wait for parity bit equal ++ * - Wait for status success, error OR ready ++ */ ++ return phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1, VEND1_IPC_STS, val, ++ aeon_ipc_ready(val, parity_status), ++ AEON_IPC_DELAY, AEON_IPC_TIMEOUT, false); ++} ++ ++static int aeon_ipc_send_cmd(struct phy_device *phydev, ++ struct as21xxx_priv *priv, ++ u16 cmd, u16 *ret_sts) ++{ ++ bool curr_parity; ++ int ret; ++ ++ /* The IPC sync by using a single parity bit. ++ * Each CMD have alternately this bit set or clear ++ * to understand correct flow and packet order. ++ */ ++ curr_parity = priv->parity_status; ++ if (priv->parity_status) ++ cmd |= AEON_IPC_CMD_PARITY; ++ ++ /* Always update parity for next packet */ ++ priv->parity_status = !priv->parity_status; ++ ++ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_IPC_CMD, cmd); ++ if (ret) ++ return ret; ++ ++ /* Wait for packet to be processed */ ++ usleep_range(AEON_IPC_DELAY, AEON_IPC_DELAY + 5000); ++ ++ /* With no ret_sts, ignore waiting for packet completion ++ * (ipc parity bit sync) ++ */ ++ if (!ret_sts) ++ return 0; ++ ++ ret = aeon_ipc_wait_cmd(phydev, curr_parity); ++ if (ret) ++ return ret; ++ ++ ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_IPC_STS); ++ if (ret < 0) ++ return ret; ++ ++ *ret_sts = ret; ++ if ((*ret_sts & AEON_IPC_STS_STATUS) != AEON_IPC_STS_STATUS_SUCCESS) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++/* If data is NULL, return 0 or negative error. ++ * If data not NULL, return number of Bytes received from IPC or ++ * a negative error. ++ */ ++static int aeon_ipc_send_msg(struct phy_device *phydev, ++ u16 opcode, u16 *data, unsigned int data_len, ++ u16 *ret_data) ++{ ++ struct as21xxx_priv *priv = phydev->priv; ++ unsigned int ret_size; ++ u16 cmd, ret_sts; ++ int ret; ++ int i; ++ ++ /* IPC have a max of 8 register to transfer data, ++ * make sure we never exceed this. ++ */ ++ if (data_len > AEON_IPC_DATA_MAX) ++ return -EINVAL; ++ ++ for (i = 0; i < data_len / sizeof(u16); i++) ++ phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_IPC_DATA(i), ++ data[i]); ++ ++ cmd = FIELD_PREP(AEON_IPC_CMD_SIZE, data_len) | ++ FIELD_PREP(AEON_IPC_CMD_OPCODE, opcode); ++ ++ mutex_lock(&priv->ipc_lock); ++ ++ ret = aeon_ipc_send_cmd(phydev, priv, cmd, &ret_sts); ++ if (ret) { ++ phydev_err(phydev, "failed to send ipc msg for %x: %d\n", ++ opcode, ret); ++ goto out; ++ } ++ ++ if (!data) ++ goto out; ++ ++ if ((ret_sts & AEON_IPC_STS_STATUS) == AEON_IPC_STS_STATUS_ERROR) { ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ /* Prevent IPC from stack smashing the kernel. ++ * We can't trust IPC to return a good value and we always ++ * preallocate space for 16 Bytes. ++ */ ++ ret_size = FIELD_GET(AEON_IPC_STS_SIZE, ret_sts); ++ if (ret_size > AEON_IPC_DATA_MAX) { ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ /* Read data from IPC data register for ret_size value from IPC */ ++ for (i = 0; i < DIV_ROUND_UP(ret_size, sizeof(u16)); i++) { ++ ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_IPC_DATA(i)); ++ if (ret < 0) ++ goto out; ++ ++ ret_data[i] = ret; ++ } ++ ++ ret = ret_size; ++ ++out: ++ mutex_unlock(&priv->ipc_lock); ++ ++ return ret; ++} ++ ++static int aeon_ipc_noop(struct phy_device *phydev, ++ struct as21xxx_priv *priv, u16 *ret_sts) ++{ ++ u16 cmd; ++ ++ cmd = FIELD_PREP(AEON_IPC_CMD_SIZE, 0) | ++ FIELD_PREP(AEON_IPC_CMD_OPCODE, IPC_CMD_NOOP); ++ ++ return aeon_ipc_send_cmd(phydev, priv, cmd, ret_sts); ++} ++ ++/* Logic to sync parity bit with IPC. ++ * We send 2 NOP cmd with same partity and we wait for IPC ++ * to handle the packet only for the second one. This way ++ * we make sure we are sync for every next cmd. ++ */ ++static int aeon_ipc_sync_parity(struct phy_device *phydev, ++ struct as21xxx_priv *priv) ++{ ++ u16 ret_sts; ++ int ret; ++ ++ mutex_lock(&priv->ipc_lock); ++ ++ /* Send NOP with no parity */ ++ aeon_ipc_noop(phydev, priv, NULL); ++ ++ /* Reset packet parity */ ++ priv->parity_status = false; ++ ++ /* Send second NOP with no parity */ ++ ret = aeon_ipc_noop(phydev, priv, &ret_sts); ++ ++ mutex_unlock(&priv->ipc_lock); ++ ++ /* We expect to return -EINVAL */ ++ if (ret != -EINVAL) ++ return ret; ++ ++ if ((ret_sts & AEON_IPC_STS_STATUS) != AEON_IPC_STS_STATUS_READY) { ++ phydev_err(phydev, "Invalid IPC status on sync parity: %x\n", ++ ret_sts); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int aeon_ipc_get_fw_version(struct phy_device *phydev) ++{ ++ u16 ret_data[AEON_IPC_DATA_NUM_REGISTERS], data[1]; ++ char fw_version[AEON_IPC_DATA_MAX + 1]; ++ int ret; ++ ++ data[0] = IPC_INFO_VERSION; ++ ++ ret = aeon_ipc_send_msg(phydev, IPC_CMD_INFO, data, ++ sizeof(data), ret_data); ++ if (ret < 0) ++ return ret; ++ ++ /* Make sure FW version is NULL terminated */ ++ memcpy(fw_version, ret_data, ret); ++ fw_version[ret] = '\0'; ++ ++ phydev_info(phydev, "Firmware Version: %s\n", fw_version); ++ ++ return 0; ++} ++ ++static int aeon_dpc_ra_enable(struct phy_device *phydev) ++{ ++ u16 data[2]; ++ ++ data[0] = IPC_CFG_PARAM_DIRECT; ++ data[1] = IPC_CFG_PARAM_DIRECT_DPC_RA; ++ ++ return aeon_ipc_send_msg(phydev, IPC_CMD_CFG_PARAM, data, ++ sizeof(data), NULL); ++} ++ ++static int as21xxx_probe(struct phy_device *phydev) ++{ ++ struct as21xxx_priv *priv; ++ int ret; ++ ++ priv = devm_kzalloc(&phydev->mdio.dev, ++ sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ phydev->priv = priv; ++ ++ ret = devm_mutex_init(&phydev->mdio.dev, ++ &priv->ipc_lock); ++ if (ret) ++ return ret; ++ ++ ret = aeon_ipc_sync_parity(phydev, priv); ++ if (ret) ++ return ret; ++ ++ ret = aeon_ipc_get_fw_version(phydev); ++ if (ret) ++ return ret; ++ ++ /* Enable PTP clk if not already Enabled */ ++ ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_PTP_CLK, ++ VEND1_PTP_CLK_EN); ++ if (ret) ++ return ret; ++ ++ return aeon_dpc_ra_enable(phydev); ++} ++ ++static int as21xxx_read_link(struct phy_device *phydev, int *bmcr) ++{ ++ int status; ++ ++ /* Normal C22 BMCR report inconsistent data, use ++ * the mapped C22 in C45 to have more consistent link info. ++ */ ++ *bmcr = phy_read_mmd(phydev, MDIO_MMD_AN, ++ AS21XXX_MDIO_AN_C22 + MII_BMCR); ++ if (*bmcr < 0) ++ return *bmcr; ++ ++ /* Autoneg is being started, therefore disregard current ++ * link status and report link as down. ++ */ ++ if (*bmcr & BMCR_ANRESTART) { ++ phydev->link = 0; ++ return 0; ++ } ++ ++ status = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1); ++ if (status < 0) ++ return status; ++ ++ phydev->link = !!(status & MDIO_STAT1_LSTATUS); ++ ++ return 0; ++} ++ ++static int as21xxx_read_c22_lpa(struct phy_device *phydev) ++{ ++ int lpagb; ++ ++ /* MII_STAT1000 are only filled in the mapped C22 ++ * in C45, use that to fill lpagb values and check. ++ */ ++ lpagb = phy_read_mmd(phydev, MDIO_MMD_AN, ++ AS21XXX_MDIO_AN_C22 + MII_STAT1000); ++ if (lpagb < 0) ++ return lpagb; ++ ++ if (lpagb & LPA_1000MSFAIL) { ++ int adv = phy_read_mmd(phydev, MDIO_MMD_AN, ++ AS21XXX_MDIO_AN_C22 + MII_CTRL1000); ++ ++ if (adv < 0) ++ return adv; ++ ++ if (adv & CTL1000_ENABLE_MASTER) ++ phydev_err(phydev, "Master/Slave resolution failed, maybe conflicting manual settings?\n"); ++ else ++ phydev_err(phydev, "Master/Slave resolution failed\n"); ++ return -ENOLINK; ++ } ++ ++ mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, ++ lpagb); ++ ++ return 0; ++} ++ ++static int as21xxx_read_status(struct phy_device *phydev) ++{ ++ int bmcr, old_link = phydev->link; ++ int ret; ++ ++ ret = as21xxx_read_link(phydev, &bmcr); ++ if (ret) ++ return ret; ++ ++ /* why bother the PHY if nothing can have changed */ ++ if (phydev->autoneg == AUTONEG_ENABLE && old_link && phydev->link) ++ return 0; ++ ++ phydev->speed = SPEED_UNKNOWN; ++ phydev->duplex = DUPLEX_UNKNOWN; ++ phydev->pause = 0; ++ phydev->asym_pause = 0; ++ ++ if (phydev->autoneg == AUTONEG_ENABLE) { ++ ret = genphy_c45_read_lpa(phydev); ++ if (ret) ++ return ret; ++ ++ ret = as21xxx_read_c22_lpa(phydev); ++ if (ret) ++ return ret; ++ ++ phy_resolve_aneg_linkmode(phydev); ++ } else { ++ int speed; ++ ++ linkmode_zero(phydev->lp_advertising); ++ ++ speed = phy_read_mmd(phydev, MDIO_MMD_VEND1, ++ VEND1_SPEED_STATUS); ++ if (speed < 0) ++ return speed; ++ ++ switch (speed & VEND1_SPEED_STATUS) { ++ case VEND1_SPEED_10000: ++ phydev->speed = SPEED_10000; ++ phydev->duplex = DUPLEX_FULL; ++ break; ++ case VEND1_SPEED_5000: ++ phydev->speed = SPEED_5000; ++ phydev->duplex = DUPLEX_FULL; ++ break; ++ case VEND1_SPEED_2500: ++ phydev->speed = SPEED_2500; ++ phydev->duplex = DUPLEX_FULL; ++ break; ++ case VEND1_SPEED_1000: ++ phydev->speed = SPEED_1000; ++ if (bmcr & BMCR_FULLDPLX) ++ phydev->duplex = DUPLEX_FULL; ++ else ++ phydev->duplex = DUPLEX_HALF; ++ break; ++ case VEND1_SPEED_100: ++ phydev->speed = SPEED_100; ++ phydev->duplex = DUPLEX_FULL; ++ break; ++ case VEND1_SPEED_10: ++ phydev->speed = SPEED_10; ++ phydev->duplex = DUPLEX_FULL; ++ break; ++ default: ++ return -EINVAL; ++ } ++ } ++ ++ return 0; ++} ++ ++static int as21xxx_led_brightness_set(struct phy_device *phydev, ++ u8 index, enum led_brightness value) ++{ ++ u16 val = VEND1_LED_REG_A_EVENT_OFF; ++ ++ if (index > AEON_MAX_LEDS) ++ return -EINVAL; ++ ++ if (value) ++ val = VEND1_LED_REG_A_EVENT_ON; ++ ++ return phy_modify_mmd(phydev, MDIO_MMD_VEND1, ++ VEND1_LED_REG(index), ++ VEND1_LED_REG_A_EVENT, ++ FIELD_PREP(VEND1_LED_REG_A_EVENT, val)); ++} ++ ++static int as21xxx_led_hw_is_supported(struct phy_device *phydev, u8 index, ++ unsigned long rules) ++{ ++ int i; ++ ++ if (index > AEON_MAX_LEDS) ++ return -EINVAL; ++ ++ for (i = 0; i < ARRAY_SIZE(as21xxx_led_supported_pattern); i++) ++ if (rules == as21xxx_led_supported_pattern[i].pattern) ++ return 0; ++ ++ return -EOPNOTSUPP; ++} ++ ++static int as21xxx_led_hw_control_get(struct phy_device *phydev, u8 index, ++ unsigned long *rules) ++{ ++ int i, val; ++ ++ if (index > AEON_MAX_LEDS) ++ return -EINVAL; ++ ++ val = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_LED_REG(index)); ++ if (val < 0) ++ return val; ++ ++ val = FIELD_GET(VEND1_LED_REG_A_EVENT, val); ++ for (i = 0; i < ARRAY_SIZE(as21xxx_led_supported_pattern); i++) ++ if (val == as21xxx_led_supported_pattern[i].val) { ++ *rules = as21xxx_led_supported_pattern[i].pattern; ++ return 0; ++ } ++ ++ /* Should be impossible */ ++ return -EINVAL; ++} ++ ++static int as21xxx_led_hw_control_set(struct phy_device *phydev, u8 index, ++ unsigned long rules) ++{ ++ u16 val = 0; ++ int i; ++ ++ if (index > AEON_MAX_LEDS) ++ return -EINVAL; ++ ++ for (i = 0; i < ARRAY_SIZE(as21xxx_led_supported_pattern); i++) ++ if (rules == as21xxx_led_supported_pattern[i].pattern) { ++ val = as21xxx_led_supported_pattern[i].val; ++ break; ++ } ++ ++ return phy_modify_mmd(phydev, MDIO_MMD_VEND1, ++ VEND1_LED_REG(index), ++ VEND1_LED_REG_A_EVENT, ++ FIELD_PREP(VEND1_LED_REG_A_EVENT, val)); ++} ++ ++static int as21xxx_led_polarity_set(struct phy_device *phydev, int index, ++ unsigned long modes) ++{ ++ bool led_active_low = false; ++ u16 mask, val = 0; ++ u32 mode; ++ ++ if (index > AEON_MAX_LEDS) ++ return -EINVAL; ++ ++ for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) { ++ switch (mode) { ++ case PHY_LED_ACTIVE_LOW: ++ led_active_low = true; ++ break; ++ case PHY_LED_ACTIVE_HIGH: /* default mode */ ++ led_active_low = false; ++ break; ++ default: ++ return -EINVAL; ++ } ++ } ++ ++ mask = VEND1_GLB_CPU_CTRL_LED_POLARITY(index); ++ if (led_active_low) ++ val = VEND1_GLB_CPU_CTRL_LED_POLARITY(index); ++ ++ return phy_modify_mmd(phydev, MDIO_MMD_VEND1, ++ VEND1_GLB_REG_CPU_CTRL, ++ mask, val); ++} ++ ++static int as21xxx_match_phy_device(struct phy_device *phydev, ++ const struct phy_driver *phydrv) ++{ ++ struct as21xxx_priv *priv; ++ u16 ret_sts; ++ u32 phy_id; ++ int ret; ++ ++ /* Skip PHY that are not AS21xxx or already have firmware loaded */ ++ if (phydev->c45_ids.device_ids[MDIO_MMD_PCS] != PHY_ID_AS21XXX) ++ return genphy_match_phy_device(phydev, (struct phy_driver *)phydrv); ++ ++ /* Read PHY ID to handle firmware just loaded */ ++ ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MII_PHYSID1); ++ if (ret < 0) ++ return ret; ++ phy_id = ret << 16; ++ ++ ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MII_PHYSID2); ++ if (ret < 0) ++ return ret; ++ phy_id |= ret; ++ ++ /* With PHY ID not the generic AS21xxx one assume ++ * the firmware just loaded ++ */ ++ if (phy_id != PHY_ID_AS21XXX) ++ return phy_id == phydrv->phy_id; ++ ++ /* Allocate temp priv and load the firmware */ ++ priv = kzalloc(sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ mutex_init(&priv->ipc_lock); ++ ++ ret = aeon_firmware_load(phydev); ++ if (ret) ++ goto out; ++ ++ /* Sync parity... */ ++ ret = aeon_ipc_sync_parity(phydev, priv); ++ if (ret) ++ goto out; ++ ++ /* ...and send a third NOOP cmd to wait for firmware finish loading */ ++ ret = aeon_ipc_noop(phydev, priv, &ret_sts); ++ if (ret) ++ goto out; ++ ++out: ++ mutex_destroy(&priv->ipc_lock); ++ kfree(priv); ++ ++ /* Return can either be 0 or a negative error code. ++ * Returning 0 here means THIS is NOT a suitable PHY. ++ * ++ * For the specific case of the generic Aeonsemi PHY ID that ++ * needs the firmware the be loaded first to have a correct PHY ID, ++ * this is OK as a matching PHY ID will be found right after. ++ * This relies on the driver probe order where the first PHY driver ++ * probed is the generic one. ++ */ ++ return ret; ++} ++ ++static struct phy_driver as21xxx_drivers[] = { ++ { ++ /* PHY expose in C45 as 0x7500 0x9410 ++ * before firmware is loaded. ++ * This driver entry must be attempted first to load ++ * the firmware and thus update the ID registers. ++ */ ++ PHY_ID_MATCH_EXACT(PHY_ID_AS21XXX), ++ .name = "Aeonsemi AS21xxx", ++ .match_phy_device = as21xxx_match_phy_device, ++ }, ++ { ++ PHY_ID_MATCH_EXACT(PHY_ID_AS21011JB1), ++ .name = "Aeonsemi AS21011JB1", ++ .probe = as21xxx_probe, ++ .match_phy_device = as21xxx_match_phy_device, ++ .read_status = as21xxx_read_status, ++ .led_brightness_set = as21xxx_led_brightness_set, ++ .led_hw_is_supported = as21xxx_led_hw_is_supported, ++ .led_hw_control_set = as21xxx_led_hw_control_set, ++ .led_hw_control_get = as21xxx_led_hw_control_get, ++ .led_polarity_set = as21xxx_led_polarity_set, ++ }, ++ { ++ PHY_ID_MATCH_EXACT(PHY_ID_AS21011PB1), ++ .name = "Aeonsemi AS21011PB1", ++ .probe = as21xxx_probe, ++ .match_phy_device = as21xxx_match_phy_device, ++ .read_status = as21xxx_read_status, ++ .led_brightness_set = as21xxx_led_brightness_set, ++ .led_hw_is_supported = as21xxx_led_hw_is_supported, ++ .led_hw_control_set = as21xxx_led_hw_control_set, ++ .led_hw_control_get = as21xxx_led_hw_control_get, ++ .led_polarity_set = as21xxx_led_polarity_set, ++ }, ++ { ++ PHY_ID_MATCH_EXACT(PHY_ID_AS21010PB1), ++ .name = "Aeonsemi AS21010PB1", ++ .probe = as21xxx_probe, ++ .match_phy_device = as21xxx_match_phy_device, ++ .read_status = as21xxx_read_status, ++ .led_brightness_set = as21xxx_led_brightness_set, ++ .led_hw_is_supported = as21xxx_led_hw_is_supported, ++ .led_hw_control_set = as21xxx_led_hw_control_set, ++ .led_hw_control_get = as21xxx_led_hw_control_get, ++ .led_polarity_set = as21xxx_led_polarity_set, ++ }, ++ { ++ PHY_ID_MATCH_EXACT(PHY_ID_AS21010JB1), ++ .name = "Aeonsemi AS21010JB1", ++ .probe = as21xxx_probe, ++ .match_phy_device = as21xxx_match_phy_device, ++ .read_status = as21xxx_read_status, ++ .led_brightness_set = as21xxx_led_brightness_set, ++ .led_hw_is_supported = as21xxx_led_hw_is_supported, ++ .led_hw_control_set = as21xxx_led_hw_control_set, ++ .led_hw_control_get = as21xxx_led_hw_control_get, ++ .led_polarity_set = as21xxx_led_polarity_set, ++ }, ++ { ++ PHY_ID_MATCH_EXACT(PHY_ID_AS21210PB1), ++ .name = "Aeonsemi AS21210PB1", ++ .probe = as21xxx_probe, ++ .match_phy_device = as21xxx_match_phy_device, ++ .read_status = as21xxx_read_status, ++ .led_brightness_set = as21xxx_led_brightness_set, ++ .led_hw_is_supported = as21xxx_led_hw_is_supported, ++ .led_hw_control_set = as21xxx_led_hw_control_set, ++ .led_hw_control_get = as21xxx_led_hw_control_get, ++ .led_polarity_set = as21xxx_led_polarity_set, ++ }, ++ { ++ PHY_ID_MATCH_EXACT(PHY_ID_AS21510JB1), ++ .name = "Aeonsemi AS21510JB1", ++ .probe = as21xxx_probe, ++ .match_phy_device = as21xxx_match_phy_device, ++ .read_status = as21xxx_read_status, ++ .led_brightness_set = as21xxx_led_brightness_set, ++ .led_hw_is_supported = as21xxx_led_hw_is_supported, ++ .led_hw_control_set = as21xxx_led_hw_control_set, ++ .led_hw_control_get = as21xxx_led_hw_control_get, ++ .led_polarity_set = as21xxx_led_polarity_set, ++ }, ++ { ++ PHY_ID_MATCH_EXACT(PHY_ID_AS21510PB1), ++ .name = "Aeonsemi AS21510PB1", ++ .probe = as21xxx_probe, ++ .match_phy_device = as21xxx_match_phy_device, ++ .read_status = as21xxx_read_status, ++ .led_brightness_set = as21xxx_led_brightness_set, ++ .led_hw_is_supported = as21xxx_led_hw_is_supported, ++ .led_hw_control_set = as21xxx_led_hw_control_set, ++ .led_hw_control_get = as21xxx_led_hw_control_get, ++ .led_polarity_set = as21xxx_led_polarity_set, ++ }, ++ { ++ PHY_ID_MATCH_EXACT(PHY_ID_AS21511JB1), ++ .name = "Aeonsemi AS21511JB1", ++ .probe = as21xxx_probe, ++ .match_phy_device = as21xxx_match_phy_device, ++ .read_status = as21xxx_read_status, ++ .led_brightness_set = as21xxx_led_brightness_set, ++ .led_hw_is_supported = as21xxx_led_hw_is_supported, ++ .led_hw_control_set = as21xxx_led_hw_control_set, ++ .led_hw_control_get = as21xxx_led_hw_control_get, ++ .led_polarity_set = as21xxx_led_polarity_set, ++ }, ++ { ++ PHY_ID_MATCH_EXACT(PHY_ID_AS21210JB1), ++ .name = "Aeonsemi AS21210JB1", ++ .probe = as21xxx_probe, ++ .match_phy_device = as21xxx_match_phy_device, ++ .read_status = as21xxx_read_status, ++ .led_brightness_set = as21xxx_led_brightness_set, ++ .led_hw_is_supported = as21xxx_led_hw_is_supported, ++ .led_hw_control_set = as21xxx_led_hw_control_set, ++ .led_hw_control_get = as21xxx_led_hw_control_get, ++ .led_polarity_set = as21xxx_led_polarity_set, ++ }, ++ { ++ PHY_ID_MATCH_EXACT(PHY_ID_AS21511PB1), ++ .name = "Aeonsemi AS21511PB1", ++ .probe = as21xxx_probe, ++ .match_phy_device = as21xxx_match_phy_device, ++ .read_status = as21xxx_read_status, ++ .led_brightness_set = as21xxx_led_brightness_set, ++ .led_hw_is_supported = as21xxx_led_hw_is_supported, ++ .led_hw_control_set = as21xxx_led_hw_control_set, ++ .led_hw_control_get = as21xxx_led_hw_control_get, ++ .led_polarity_set = as21xxx_led_polarity_set, ++ }, ++}; ++module_phy_driver(as21xxx_drivers); ++ ++static struct mdio_device_id __maybe_unused as21xxx_tbl[] = { ++ { PHY_ID_MATCH_VENDOR(PHY_VENDOR_AEONSEMI) }, ++ { } ++}; ++MODULE_DEVICE_TABLE(mdio, as21xxx_tbl); ++ ++MODULE_DESCRIPTION("Aeonsemi AS21xxx PHY driver"); ++MODULE_AUTHOR("Christian Marangi "); ++MODULE_LICENSE("GPL"); +-- +2.51.0 + + +From 1eef9ac782f05b464534e831280399d76c3eba32 Mon Sep 17 00:00:00 2001 +From: Linus Walleij +Date: Wed, 13 Aug 2025 23:43:03 +0200 +Subject: [PATCH 166/517] net: dsa: Move KS8995 to the DSA subsystem + +By reading the datasheets for the KS8995 it is obvious that this +is a 100 Mbit DSA switch. + +Let us start the refactoring by moving it to the DSA subsystem to +preserve development history. + +Verified that the chip still probes the same after this patch +provided CONFIG_HAVE_NET_DSA, CONFIG_NET_DSA and CONFIG_DSA_KS8995 +are selected. + +Signed-off-by: Linus Walleij +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/20250813-ks8995-to-dsa-v1-1-75c359ede3a5@linaro.org +Signed-off-by: Jakub Kicinski +--- + drivers/net/dsa/Kconfig | 7 +++++++ + drivers/net/dsa/Makefile | 1 + + drivers/net/{phy/spi_ks8995.c => dsa/ks8995.c} | 0 + drivers/net/phy/Kconfig | 4 ---- + drivers/net/phy/Makefile | 1 - + 5 files changed, 8 insertions(+), 5 deletions(-) + rename drivers/net/{phy/spi_ks8995.c => dsa/ks8995.c} (100%) + +diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig +index 2d10b4d6cfbb..4367cbdb92d5 100644 +--- a/drivers/net/dsa/Kconfig ++++ b/drivers/net/dsa/Kconfig +@@ -98,6 +98,13 @@ config NET_DSA_RZN1_A5PSW + This driver supports the A5PSW switch, which is embedded in Renesas + RZ/N1 SoC. + ++config NET_DSA_KS8995 ++ tristate "Micrel KS8995 family 5-ports 10/100 Ethernet switches" ++ depends on SPI ++ help ++ This driver supports the Micrel KS8995 family of 10/100 Mbit ethernet ++ switches, managed over SPI. ++ + config NET_DSA_SMSC_LAN9303 + tristate + select NET_DSA_TAG_LAN9303 +diff --git a/drivers/net/dsa/Makefile b/drivers/net/dsa/Makefile +index cb9a97340e58..23dbdf1a36a8 100644 +--- a/drivers/net/dsa/Makefile ++++ b/drivers/net/dsa/Makefile +@@ -5,6 +5,7 @@ obj-$(CONFIG_NET_DSA_LOOP) += dsa_loop.o + ifdef CONFIG_NET_DSA_LOOP + obj-$(CONFIG_FIXED_PHY) += dsa_loop_bdinfo.o + endif ++obj-$(CONFIG_NET_DSA_KS8995) += ks8995.o + obj-$(CONFIG_NET_DSA_LANTIQ_GSWIP) += lantiq_gswip.o + obj-$(CONFIG_NET_DSA_MT7530) += mt7530.o + obj-$(CONFIG_NET_DSA_MT7530_MDIO) += mt7530-mdio.o +diff --git a/drivers/net/phy/spi_ks8995.c b/drivers/net/dsa/ks8995.c +similarity index 100% +rename from drivers/net/phy/spi_ks8995.c +rename to drivers/net/dsa/ks8995.c +diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig +index 01cc31817357..bf7c34402e74 100644 +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -443,7 +443,3 @@ config XILINX_GMII2RGMII + Ethernet physical media devices and the Gigabit Ethernet controller. + + endif # PHYLIB +- +-config MICREL_KS8995MA +- tristate "Micrel KS8995MA 5-ports 10/100 managed Ethernet switch" +- depends on SPI +diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile +index 768d1e8ebf80..a9080b8d604e 100644 +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -77,7 +77,6 @@ obj-$(CONFIG_MARVELL_88X2222_PHY) += marvell-88x2222.o + obj-$(CONFIG_MAXLINEAR_GPHY) += mxl-gpy.o + obj-y += mediatek/ + obj-$(CONFIG_MESON_GXL_PHY) += meson-gxl.o +-obj-$(CONFIG_MICREL_KS8995MA) += spi_ks8995.o + obj-$(CONFIG_MICREL_PHY) += micrel.o + obj-$(CONFIG_MICROCHIP_PHY) += microchip.o + obj-$(CONFIG_MICROCHIP_T1_PHY) += microchip_t1.o +-- +2.51.0 + + +From b5868880d0272cf14e28b438c869027c53ce97e8 Mon Sep 17 00:00:00 2001 +From: Linus Walleij +Date: Wed, 13 Aug 2025 23:43:04 +0200 +Subject: [PATCH 167/517] net: dsa: ks8995: Add proper RESET delay + +According to the datasheet we need to wait 100us before accessing +any registers in the KS8995 after a reset de-assertion. + +Add this delay, if and only if we obtained a GPIO descriptor, +otherwise it is just a pointless delay. + +Signed-off-by: Linus Walleij +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/20250813-ks8995-to-dsa-v1-2-75c359ede3a5@linaro.org +Signed-off-by: Jakub Kicinski +--- + drivers/net/dsa/ks8995.c | 12 +++++++++--- + 1 file changed, 9 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/dsa/ks8995.c b/drivers/net/dsa/ks8995.c +index 7196e927c2cd..ab266b3ead02 100644 +--- a/drivers/net/dsa/ks8995.c ++++ b/drivers/net/dsa/ks8995.c +@@ -438,9 +438,15 @@ static int ks8995_probe(struct spi_device *spi) + if (err) + return err; + +- /* de-assert switch reset */ +- /* FIXME: this likely requires a delay */ +- gpiod_set_value_cansleep(ks->reset_gpio, 0); ++ if (ks->reset_gpio) { ++ /* ++ * If a reset line was obtained, wait for 100us after ++ * de-asserting RESET before accessing any registers, see ++ * the KS8995MA datasheet, page 44. ++ */ ++ gpiod_set_value_cansleep(ks->reset_gpio, 0); ++ udelay(100); ++ } + + spi_set_drvdata(spi, ks); + +-- +2.51.0 + + +From eb531dff7bf14239f05748e1f299a346633f6165 Mon Sep 17 00:00:00 2001 +From: Linus Walleij +Date: Wed, 13 Aug 2025 23:43:05 +0200 +Subject: [PATCH 168/517] net: dsa: ks8995: Delete sysfs register access + +There is some sysfs file to read and write registers randomly +in the ks8995 driver. + +The contemporary way to achieve the same thing is to implement +regmap abstractions, if needed. Delete this and implement +regmap later if we want to be able to inspect individual registers. + +Signed-off-by: Linus Walleij +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/20250813-ks8995-to-dsa-v1-3-75c359ede3a5@linaro.org +Signed-off-by: Jakub Kicinski +--- + drivers/net/dsa/ks8995.c | 48 ---------------------------------------- + 1 file changed, 48 deletions(-) + +diff --git a/drivers/net/dsa/ks8995.c b/drivers/net/dsa/ks8995.c +index ab266b3ead02..45f01c81d0b8 100644 +--- a/drivers/net/dsa/ks8995.c ++++ b/drivers/net/dsa/ks8995.c +@@ -140,7 +140,6 @@ struct ks8995_switch { + struct spi_device *spi; + struct mutex lock; + struct gpio_desc *reset_gpio; +- struct bin_attribute regs_attr; + const struct ks8995_chip_params *chip; + int revision_id; + }; +@@ -288,30 +287,6 @@ static int ks8995_reset(struct ks8995_switch *ks) + return ks8995_start(ks); + } + +-static ssize_t ks8995_registers_read(struct file *filp, struct kobject *kobj, +- struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) +-{ +- struct device *dev; +- struct ks8995_switch *ks8995; +- +- dev = kobj_to_dev(kobj); +- ks8995 = dev_get_drvdata(dev); +- +- return ks8995_read(ks8995, buf, off, count); +-} +- +-static ssize_t ks8995_registers_write(struct file *filp, struct kobject *kobj, +- struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) +-{ +- struct device *dev; +- struct ks8995_switch *ks8995; +- +- dev = kobj_to_dev(kobj); +- ks8995 = dev_get_drvdata(dev); +- +- return ks8995_write(ks8995, buf, off, count); +-} +- + /* ks8995_get_revision - get chip revision + * @ks: pointer to switch instance + * +@@ -395,16 +370,6 @@ static int ks8995_get_revision(struct ks8995_switch *ks) + return err; + } + +-static const struct bin_attribute ks8995_registers_attr = { +- .attr = { +- .name = "registers", +- .mode = 0600, +- }, +- .size = KS8995_REGS_SIZE, +- .read = ks8995_registers_read, +- .write = ks8995_registers_write, +-}; +- + /* ------------------------------------------------------------------------ */ + static int ks8995_probe(struct spi_device *spi) + { +@@ -462,21 +427,10 @@ static int ks8995_probe(struct spi_device *spi) + if (err) + return err; + +- memcpy(&ks->regs_attr, &ks8995_registers_attr, sizeof(ks->regs_attr)); +- ks->regs_attr.size = ks->chip->regs_size; +- + err = ks8995_reset(ks); + if (err) + return err; + +- sysfs_attr_init(&ks->regs_attr.attr); +- err = sysfs_create_bin_file(&spi->dev.kobj, &ks->regs_attr); +- if (err) { +- dev_err(&spi->dev, "unable to create sysfs file, err=%d\n", +- err); +- return err; +- } +- + dev_info(&spi->dev, "%s device found, Chip ID:%x, Revision:%x\n", + ks->chip->name, ks->chip->chip_id, ks->revision_id); + +@@ -487,8 +441,6 @@ static void ks8995_remove(struct spi_device *spi) + { + struct ks8995_switch *ks = spi_get_drvdata(spi); + +- sysfs_remove_bin_file(&spi->dev.kobj, &ks->regs_attr); +- + /* assert reset */ + gpiod_set_value_cansleep(ks->reset_gpio, 1); + } +-- +2.51.0 + + +From 20f057c95e429fc9d1a85736837129570f4714b1 Mon Sep 17 00:00:00 2001 +From: Linus Walleij +Date: Wed, 13 Aug 2025 23:43:06 +0200 +Subject: [PATCH 169/517] net: dsa: ks8995: Add basic switch set-up + +We start to extend the KS8995 driver by simply registering it +as a DSA device and implementing a few switch callbacks for +STP set-up and such to begin with. + +No special tags or other advanced stuff: we use DSA_TAG_NONE +and rely on the default set-up in the switch with the special +DSA tags turned off. This makes the switch wire up properly +to all its PHY's and simple bridge traffic works properly. + +After this the bridge DT bindings are respected, ports and their +PHYs get connected to the switch and react appropriately through +the phylib when cables are plugged in etc. + +Tested like this in a hacky OpenWrt image: + +Bring up conduit interface manually: +ixp4xx_eth c8009000.ethernet eth0: eth0: link up, + speed 100 Mb/s, full duplex + +spi-ks8995 spi0.0: enable port 0 +spi-ks8995 spi0.0: set KS8995_REG_PC2 for port 0 to 06 +spi-ks8995 spi0.0 lan1: configuring for phy/mii link mode +spi-ks8995 spi0.0 lan1: Link is Up - 100Mbps/Full - flow control rx/tx + +PING 169.254.1.1 (169.254.1.1): 56 data bytes +64 bytes from 169.254.1.1: seq=0 ttl=64 time=1.629 ms +64 bytes from 169.254.1.1: seq=1 ttl=64 time=0.951 ms + +I also tested SSH from the device to the host and it works fine. + +It also works fine to ping the device from the host and to SSH +into the device from the host. + +This brings the ks8995 driver to a reasonable state where it can +be used from the current device tree bindings and the existing +device trees in the kernel. + +Signed-off-by: Linus Walleij +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/20250813-ks8995-to-dsa-v1-4-75c359ede3a5@linaro.org +Signed-off-by: Jakub Kicinski +--- + drivers/net/dsa/Kconfig | 1 + + drivers/net/dsa/ks8995.c | 398 ++++++++++++++++++++++++++++++++++++++- + 2 files changed, 396 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig +index 4367cbdb92d5..b7b473e3fc02 100644 +--- a/drivers/net/dsa/Kconfig ++++ b/drivers/net/dsa/Kconfig +@@ -101,6 +101,7 @@ config NET_DSA_RZN1_A5PSW + config NET_DSA_KS8995 + tristate "Micrel KS8995 family 5-ports 10/100 Ethernet switches" + depends on SPI ++ select NET_DSA_TAG_NONE + help + This driver supports the Micrel KS8995 family of 10/100 Mbit ethernet + switches, managed over SPI. +diff --git a/drivers/net/dsa/ks8995.c b/drivers/net/dsa/ks8995.c +index 45f01c81d0b8..364e8d16c936 100644 +--- a/drivers/net/dsa/ks8995.c ++++ b/drivers/net/dsa/ks8995.c +@@ -3,6 +3,7 @@ + * SPI driver for Micrel/Kendin KS8995M and KSZ8864RMN ethernet switches + * + * Copyright (C) 2008 Gabor Juhos ++ * Copyright (C) 2025 Linus Walleij + * + * This file was based on: drivers/spi/at25.c + * Copyright (C) 2006 David Brownell +@@ -10,6 +11,9 @@ + + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + ++#include ++#include ++#include + #include + #include + #include +@@ -17,8 +21,8 @@ + #include + #include + #include +- + #include ++#include + + #define DRV_VERSION "0.1.1" + #define DRV_DESC "Micrel KS8995 Ethernet switch SPI driver" +@@ -29,18 +33,59 @@ + #define KS8995_REG_ID1 0x01 /* Chip ID1 */ + + #define KS8995_REG_GC0 0x02 /* Global Control 0 */ ++ ++#define KS8995_GC0_P5_PHY BIT(3) /* Port 5 PHY enabled */ ++ + #define KS8995_REG_GC1 0x03 /* Global Control 1 */ + #define KS8995_REG_GC2 0x04 /* Global Control 2 */ ++ ++#define KS8995_GC2_HUGE BIT(2) /* Huge packet support */ ++#define KS8995_GC2_LEGAL BIT(1) /* Legal size override */ ++ + #define KS8995_REG_GC3 0x05 /* Global Control 3 */ + #define KS8995_REG_GC4 0x06 /* Global Control 4 */ ++ ++#define KS8995_GC4_10BT BIT(4) /* Force switch to 10Mbit */ ++#define KS8995_GC4_MII_FLOW BIT(5) /* MII full-duplex flow control enable */ ++#define KS8995_GC4_MII_HD BIT(6) /* MII half-duplex mode enable */ ++ + #define KS8995_REG_GC5 0x07 /* Global Control 5 */ + #define KS8995_REG_GC6 0x08 /* Global Control 6 */ + #define KS8995_REG_GC7 0x09 /* Global Control 7 */ + #define KS8995_REG_GC8 0x0a /* Global Control 8 */ + #define KS8995_REG_GC9 0x0b /* Global Control 9 */ + +-#define KS8995_REG_PC(p, r) ((0x10 * p) + r) /* Port Control */ +-#define KS8995_REG_PS(p, r) ((0x10 * p) + r + 0xe) /* Port Status */ ++#define KS8995_GC9_SPECIAL BIT(0) /* Special tagging mode (DSA) */ ++ ++/* In DSA the ports 1-4 are numbered 0-3 and the CPU port is port 4 */ ++#define KS8995_REG_PC(p, r) (0x10 + (0x10 * (p)) + (r)) /* Port Control */ ++#define KS8995_REG_PS(p, r) (0x1e + (0x10 * (p)) + (r)) /* Port Status */ ++ ++#define KS8995_REG_PC0 0x00 /* Port Control 0 */ ++#define KS8995_REG_PC1 0x01 /* Port Control 1 */ ++#define KS8995_REG_PC2 0x02 /* Port Control 2 */ ++#define KS8995_REG_PC3 0x03 /* Port Control 3 */ ++#define KS8995_REG_PC4 0x04 /* Port Control 4 */ ++#define KS8995_REG_PC5 0x05 /* Port Control 5 */ ++#define KS8995_REG_PC6 0x06 /* Port Control 6 */ ++#define KS8995_REG_PC7 0x07 /* Port Control 7 */ ++#define KS8995_REG_PC8 0x08 /* Port Control 8 */ ++#define KS8995_REG_PC9 0x09 /* Port Control 9 */ ++#define KS8995_REG_PC10 0x0a /* Port Control 10 */ ++#define KS8995_REG_PC11 0x0b /* Port Control 11 */ ++#define KS8995_REG_PC12 0x0c /* Port Control 12 */ ++#define KS8995_REG_PC13 0x0d /* Port Control 13 */ ++ ++#define KS8995_PC0_TAG_INS BIT(2) /* Enable tag insertion on port */ ++#define KS8995_PC0_TAG_REM BIT(1) /* Enable tag removal on port */ ++#define KS8995_PC0_PRIO_EN BIT(0) /* Enable priority handling */ ++ ++#define KS8995_PC2_TXEN BIT(2) /* Enable TX on port */ ++#define KS8995_PC2_RXEN BIT(1) /* Enable RX on port */ ++#define KS8995_PC2_LEARN_DIS BIT(0) /* Disable learning on port */ ++ ++#define KS8995_PC13_TXDIS BIT(6) /* Disable transmitter */ ++#define KS8995_PC13_PWDN BIT(3) /* Power down */ + + #define KS8995_REG_TPC0 0x60 /* TOS Priority Control 0 */ + #define KS8995_REG_TPC1 0x61 /* TOS Priority Control 1 */ +@@ -91,6 +136,8 @@ + #define KS8995_CMD_WRITE 0x02U + #define KS8995_CMD_READ 0x03U + ++#define KS8995_CPU_PORT 4 ++#define KS8995_NUM_PORTS 5 /* 5 ports including the CPU port */ + #define KS8995_RESET_DELAY 10 /* usec */ + + enum ks8995_chip_variant { +@@ -138,10 +185,13 @@ static const struct ks8995_chip_params ks8995_chip[] = { + + struct ks8995_switch { + struct spi_device *spi; ++ struct device *dev; ++ struct dsa_switch *ds; + struct mutex lock; + struct gpio_desc *reset_gpio; + const struct ks8995_chip_params *chip; + int revision_id; ++ unsigned int max_mtu[KS8995_NUM_PORTS]; + }; + + static const struct spi_device_id ks8995_id[] = { +@@ -370,6 +420,327 @@ static int ks8995_get_revision(struct ks8995_switch *ks) + return err; + } + ++static int ks8995_check_config(struct ks8995_switch *ks) ++{ ++ int ret; ++ u8 val; ++ ++ ret = ks8995_read_reg(ks, KS8995_REG_GC0, &val); ++ if (ret) { ++ dev_err(ks->dev, "failed to read KS8995_REG_GC0\n"); ++ return ret; ++ } ++ ++ dev_dbg(ks->dev, "port 5 PHY %senabled\n", ++ (val & KS8995_GC0_P5_PHY) ? "" : "not "); ++ ++ val |= KS8995_GC0_P5_PHY; ++ ret = ks8995_write_reg(ks, KS8995_REG_GC0, val); ++ if (ret) ++ dev_err(ks->dev, "failed to set KS8995_REG_GC0\n"); ++ ++ dev_dbg(ks->dev, "set KS8995_REG_GC0 to 0x%02x\n", val); ++ ++ return 0; ++} ++ ++static void ++ks8995_mac_config(struct phylink_config *config, unsigned int mode, ++ const struct phylink_link_state *state) ++{ ++} ++ ++static void ++ks8995_mac_link_up(struct phylink_config *config, struct phy_device *phydev, ++ unsigned int mode, phy_interface_t interface, ++ int speed, int duplex, bool tx_pause, bool rx_pause) ++{ ++ struct dsa_port *dp = dsa_phylink_to_port(config); ++ struct ks8995_switch *ks = dp->ds->priv; ++ int port = dp->index; ++ int ret; ++ u8 val; ++ ++ /* Allow forcing the mode on the fixed CPU port, no autonegotiation. ++ * We assume autonegotiation works on the PHY-facing ports. ++ */ ++ if (port != KS8995_CPU_PORT) ++ return; ++ ++ dev_dbg(ks->dev, "MAC link up on CPU port (%d)\n", port); ++ ++ ret = ks8995_read_reg(ks, KS8995_REG_GC4, &val); ++ if (ret) { ++ dev_err(ks->dev, "failed to read KS8995_REG_GC4\n"); ++ return; ++ } ++ ++ /* Conjure port config */ ++ switch (speed) { ++ case SPEED_10: ++ dev_dbg(ks->dev, "set switch MII to 100Mbit mode\n"); ++ val |= KS8995_GC4_10BT; ++ break; ++ case SPEED_100: ++ default: ++ dev_dbg(ks->dev, "set switch MII to 100Mbit mode\n"); ++ val &= ~KS8995_GC4_10BT; ++ break; ++ } ++ ++ if (duplex == DUPLEX_HALF) { ++ dev_dbg(ks->dev, "set switch MII to half duplex\n"); ++ val |= KS8995_GC4_MII_HD; ++ } else { ++ dev_dbg(ks->dev, "set switch MII to full duplex\n"); ++ val &= ~KS8995_GC4_MII_HD; ++ } ++ ++ dev_dbg(ks->dev, "set KS8995_REG_GC4 to %02x\n", val); ++ ++ /* Enable the CPU port */ ++ ret = ks8995_write_reg(ks, KS8995_REG_GC4, val); ++ if (ret) ++ dev_err(ks->dev, "failed to set KS8995_REG_GC4\n"); ++} ++ ++static void ++ks8995_mac_link_down(struct phylink_config *config, unsigned int mode, ++ phy_interface_t interface) ++{ ++ struct dsa_port *dp = dsa_phylink_to_port(config); ++ struct ks8995_switch *ks = dp->ds->priv; ++ int port = dp->index; ++ ++ if (port != KS8995_CPU_PORT) ++ return; ++ ++ dev_dbg(ks->dev, "MAC link down on CPU port (%d)\n", port); ++ ++ /* Disable the CPU port */ ++} ++ ++static const struct phylink_mac_ops ks8995_phylink_mac_ops = { ++ .mac_config = ks8995_mac_config, ++ .mac_link_up = ks8995_mac_link_up, ++ .mac_link_down = ks8995_mac_link_down, ++}; ++ ++static enum ++dsa_tag_protocol ks8995_get_tag_protocol(struct dsa_switch *ds, ++ int port, ++ enum dsa_tag_protocol mp) ++{ ++ /* This switch actually uses the 6 byte KS8995 protocol */ ++ return DSA_TAG_PROTO_NONE; ++} ++ ++static int ks8995_setup(struct dsa_switch *ds) ++{ ++ return 0; ++} ++ ++static int ks8995_port_enable(struct dsa_switch *ds, int port, ++ struct phy_device *phy) ++{ ++ struct ks8995_switch *ks = ds->priv; ++ ++ dev_dbg(ks->dev, "enable port %d\n", port); ++ ++ return 0; ++} ++ ++static void ks8995_port_disable(struct dsa_switch *ds, int port) ++{ ++ struct ks8995_switch *ks = ds->priv; ++ ++ dev_dbg(ks->dev, "disable port %d\n", port); ++} ++ ++static int ks8995_port_pre_bridge_flags(struct dsa_switch *ds, int port, ++ struct switchdev_brport_flags flags, ++ struct netlink_ext_ack *extack) ++{ ++ /* We support enabling/disabling learning */ ++ if (flags.mask & ~(BR_LEARNING)) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static int ks8995_port_bridge_flags(struct dsa_switch *ds, int port, ++ struct switchdev_brport_flags flags, ++ struct netlink_ext_ack *extack) ++{ ++ struct ks8995_switch *ks = ds->priv; ++ int ret; ++ u8 val; ++ ++ if (flags.mask & BR_LEARNING) { ++ ret = ks8995_read_reg(ks, KS8995_REG_PC(port, KS8995_REG_PC2), &val); ++ if (ret) { ++ dev_err(ks->dev, "failed to read KS8995_REG_PC2 on port %d\n", port); ++ return ret; ++ } ++ ++ if (flags.val & BR_LEARNING) ++ val &= ~KS8995_PC2_LEARN_DIS; ++ else ++ val |= KS8995_PC2_LEARN_DIS; ++ ++ ret = ks8995_write_reg(ks, KS8995_REG_PC(port, KS8995_REG_PC2), val); ++ if (ret) { ++ dev_err(ks->dev, "failed to write KS8995_REG_PC2 on port %d\n", port); ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ ++static void ks8995_port_stp_state_set(struct dsa_switch *ds, int port, u8 state) ++{ ++ struct ks8995_switch *ks = ds->priv; ++ int ret; ++ u8 val; ++ ++ ret = ks8995_read_reg(ks, KS8995_REG_PC(port, KS8995_REG_PC2), &val); ++ if (ret) { ++ dev_err(ks->dev, "failed to read KS8995_REG_PC2 on port %d\n", port); ++ return; ++ } ++ ++ /* Set the bits for the different STP states in accordance with ++ * the datasheet, pages 36-37 "Spanning tree support". ++ */ ++ switch (state) { ++ case BR_STATE_DISABLED: ++ case BR_STATE_BLOCKING: ++ case BR_STATE_LISTENING: ++ val &= ~KS8995_PC2_TXEN; ++ val &= ~KS8995_PC2_RXEN; ++ val |= KS8995_PC2_LEARN_DIS; ++ break; ++ case BR_STATE_LEARNING: ++ val &= ~KS8995_PC2_TXEN; ++ val &= ~KS8995_PC2_RXEN; ++ val &= ~KS8995_PC2_LEARN_DIS; ++ break; ++ case BR_STATE_FORWARDING: ++ val |= KS8995_PC2_TXEN; ++ val |= KS8995_PC2_RXEN; ++ val &= ~KS8995_PC2_LEARN_DIS; ++ break; ++ default: ++ dev_err(ks->dev, "unknown bridge state requested\n"); ++ return; ++ } ++ ++ ret = ks8995_write_reg(ks, KS8995_REG_PC(port, KS8995_REG_PC2), val); ++ if (ret) { ++ dev_err(ks->dev, "failed to write KS8995_REG_PC2 on port %d\n", port); ++ return; ++ } ++ ++ dev_dbg(ks->dev, "set KS8995_REG_PC2 for port %d to %02x\n", port, val); ++} ++ ++static void ks8995_phylink_get_caps(struct dsa_switch *dsa, int port, ++ struct phylink_config *config) ++{ ++ unsigned long *interfaces = config->supported_interfaces; ++ ++ if (port == KS8995_CPU_PORT) ++ __set_bit(PHY_INTERFACE_MODE_MII, interfaces); ++ ++ if (port <= 3) { ++ /* Internal PHYs */ ++ __set_bit(PHY_INTERFACE_MODE_INTERNAL, interfaces); ++ /* phylib default */ ++ __set_bit(PHY_INTERFACE_MODE_MII, interfaces); ++ } ++ ++ config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100; ++} ++ ++/* Huge packet support up to 1916 byte packages "inclusive" ++ * which means that tags are included. If the bit is not set ++ * it is 1536 bytes "inclusive". We present the length without ++ * tags or ethernet headers. The setting affects all ports. ++ */ ++static int ks8995_change_mtu(struct dsa_switch *ds, int port, int new_mtu) ++{ ++ struct ks8995_switch *ks = ds->priv; ++ unsigned int max_mtu; ++ int ret; ++ u8 val; ++ int i; ++ ++ ks->max_mtu[port] = new_mtu; ++ ++ /* Roof out the MTU for the entire switch to the greatest ++ * common denominator: the biggest set for any one port will ++ * be the biggest MTU for the switch. ++ */ ++ max_mtu = ETH_DATA_LEN; ++ for (i = 0; i < KS8995_NUM_PORTS; i++) { ++ if (ks->max_mtu[i] > max_mtu) ++ max_mtu = ks->max_mtu[i]; ++ } ++ ++ /* Translate to layer 2 size. ++ * Add ethernet and (possible) VLAN headers, and checksum to the size. ++ * For ETH_DATA_LEN (1500 bytes) this will add up to 1522 bytes. ++ */ ++ max_mtu += VLAN_ETH_HLEN; ++ max_mtu += ETH_FCS_LEN; ++ ++ ret = ks8995_read_reg(ks, KS8995_REG_GC2, &val); ++ if (ret) { ++ dev_err(ks->dev, "failed to read KS8995_REG_GC2\n"); ++ return ret; ++ } ++ ++ if (max_mtu <= 1522) { ++ val &= ~KS8995_GC2_HUGE; ++ val &= ~KS8995_GC2_LEGAL; ++ } else if (max_mtu > 1522 && max_mtu <= 1536) { ++ /* This accepts packets up to 1536 bytes */ ++ val &= ~KS8995_GC2_HUGE; ++ val |= KS8995_GC2_LEGAL; ++ } else { ++ /* This accepts packets up to 1916 bytes */ ++ val |= KS8995_GC2_HUGE; ++ val |= KS8995_GC2_LEGAL; ++ } ++ ++ dev_dbg(ks->dev, "new max MTU %d bytes (inclusive)\n", max_mtu); ++ ++ ret = ks8995_write_reg(ks, KS8995_REG_GC2, val); ++ if (ret) ++ dev_err(ks->dev, "failed to set KS8995_REG_GC2\n"); ++ ++ return ret; ++} ++ ++static int ks8995_get_max_mtu(struct dsa_switch *ds, int port) ++{ ++ return 1916 - ETH_HLEN - ETH_FCS_LEN; ++} ++ ++static const struct dsa_switch_ops ks8995_ds_ops = { ++ .get_tag_protocol = ks8995_get_tag_protocol, ++ .setup = ks8995_setup, ++ .port_pre_bridge_flags = ks8995_port_pre_bridge_flags, ++ .port_bridge_flags = ks8995_port_bridge_flags, ++ .port_enable = ks8995_port_enable, ++ .port_disable = ks8995_port_disable, ++ .port_stp_state_set = ks8995_port_stp_state_set, ++ .port_change_mtu = ks8995_change_mtu, ++ .port_max_mtu = ks8995_get_max_mtu, ++ .phylink_get_caps = ks8995_phylink_get_caps, ++}; ++ + /* ------------------------------------------------------------------------ */ + static int ks8995_probe(struct spi_device *spi) + { +@@ -388,6 +759,7 @@ static int ks8995_probe(struct spi_device *spi) + + mutex_init(&ks->lock); + ks->spi = spi; ++ ks->dev = &spi->dev; + ks->chip = &ks8995_chip[variant]; + + ks->reset_gpio = devm_gpiod_get_optional(&spi->dev, "reset", +@@ -434,6 +806,25 @@ static int ks8995_probe(struct spi_device *spi) + dev_info(&spi->dev, "%s device found, Chip ID:%x, Revision:%x\n", + ks->chip->name, ks->chip->chip_id, ks->revision_id); + ++ err = ks8995_check_config(ks); ++ if (err) ++ return err; ++ ++ ks->ds = devm_kzalloc(&spi->dev, sizeof(*ks->ds), GFP_KERNEL); ++ if (!ks->ds) ++ return -ENOMEM; ++ ++ ks->ds->dev = &spi->dev; ++ ks->ds->num_ports = KS8995_NUM_PORTS; ++ ks->ds->ops = &ks8995_ds_ops; ++ ks->ds->phylink_mac_ops = &ks8995_phylink_mac_ops; ++ ks->ds->priv = ks; ++ ++ err = dsa_register_switch(ks->ds); ++ if (err) ++ return dev_err_probe(&spi->dev, err, ++ "unable to register DSA switch\n"); ++ + return 0; + } + +@@ -441,6 +832,7 @@ static void ks8995_remove(struct spi_device *spi) + { + struct ks8995_switch *ks = spi_get_drvdata(spi); + ++ dsa_unregister_switch(ks->ds); + /* assert reset */ + gpiod_set_value_cansleep(ks->reset_gpio, 1); + } +-- +2.51.0 + + +From c5a714e79548a715750999c9547a52a486e0e851 Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Thu, 10 Oct 2024 21:35:42 +0200 +Subject: [PATCH 170/517] hwmon: Add static visibility member to struct + hwmon_ops + +Several drivers return the same static value in their is_visible +callback, what results in code duplication. Therefore add an option +for drivers to specify a static visibility directly. + +Signed-off-by: Heiner Kallweit +Message-ID: <89690b81-2c73-47ae-9ae9-45c77b45ca0c@gmail.com> +groeck: Renamed hwmon_ops_is_visible -> hwmon_is_visible +Signed-off-by: Guenter Roeck +--- + drivers/hwmon/hwmon.c | 19 +++++++++++++++---- + include/linux/hwmon.h | 5 ++++- + 2 files changed, 19 insertions(+), 5 deletions(-) + +diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c +index 9c35c4d0369d..49b366254529 100644 +--- a/drivers/hwmon/hwmon.c ++++ b/drivers/hwmon/hwmon.c +@@ -145,6 +145,17 @@ static const struct class hwmon_class = { + + static DEFINE_IDA(hwmon_ida); + ++static umode_t hwmon_is_visible(const struct hwmon_ops *ops, ++ const void *drvdata, ++ enum hwmon_sensor_types type, ++ u32 attr, int channel) ++{ ++ if (ops->visible) ++ return ops->visible; ++ ++ return ops->is_visible(drvdata, type, attr, channel); ++} ++ + /* Thermal zone handling */ + + /* +@@ -267,8 +278,8 @@ static int hwmon_thermal_register_sensors(struct device *dev) + int err; + + if (!(info[i]->config[j] & HWMON_T_INPUT) || +- !chip->ops->is_visible(drvdata, hwmon_temp, +- hwmon_temp_input, j)) ++ !hwmon_is_visible(chip->ops, drvdata, hwmon_temp, ++ hwmon_temp_input, j)) + continue; + + err = hwmon_thermal_add_sensor(dev, j); +@@ -506,7 +517,7 @@ static struct attribute *hwmon_genattr(const void *drvdata, + const char *name; + bool is_string = is_string_attr(type, attr); + +- mode = ops->is_visible(drvdata, type, attr, index); ++ mode = hwmon_is_visible(ops, drvdata, type, attr, index); + if (!mode) + return ERR_PTR(-ENOENT); + +@@ -1033,7 +1044,7 @@ hwmon_device_register_with_info(struct device *dev, const char *name, + if (!dev || !name || !chip) + return ERR_PTR(-EINVAL); + +- if (!chip->ops || !chip->ops->is_visible || !chip->info) ++ if (!chip->ops || !(chip->ops->visible || chip->ops->is_visible) || !chip->info) + return ERR_PTR(-EINVAL); + + return __hwmon_device_register(dev, name, drvdata, chip, extra_groups); +diff --git a/include/linux/hwmon.h b/include/linux/hwmon.h +index 5c6a421ad580..3a63dff62d03 100644 +--- a/include/linux/hwmon.h ++++ b/include/linux/hwmon.h +@@ -368,7 +368,9 @@ enum hwmon_intrusion_attributes { + + /** + * struct hwmon_ops - hwmon device operations +- * @is_visible: Callback to return attribute visibility. Mandatory. ++ * @visible: Static visibility. If non-zero, 'is_visible' is ignored. ++ * @is_visible: Callback to return attribute visibility. Mandatory unless ++ * 'visible' is non-zero. + * Parameters are: + * @const void *drvdata: + * Pointer to driver-private data structure passed +@@ -412,6 +414,7 @@ enum hwmon_intrusion_attributes { + * The function returns 0 on success or a negative error number. + */ + struct hwmon_ops { ++ umode_t visible; + umode_t (*is_visible)(const void *drvdata, enum hwmon_sensor_types type, + u32 attr, int channel); + int (*read)(struct device *dev, enum hwmon_sensor_types type, +-- +2.51.0 + + +From e49d38bee83d91a1cf8d4e8fa67b2bc455ddd028 Mon Sep 17 00:00:00 2001 +From: Heiko Stuebner +Date: Fri, 6 Sep 2024 10:25:07 +0200 +Subject: [PATCH 171/517] dt-bindings: clocks: add binding for + gated-fixed-clocks + +In contrast to fixed clocks that are described as ungateable, boards +sometimes use additional oscillators for things like PCIe reference +clocks, that need actual supplies to get enabled and enable-gpios to be +toggled for them to work. + +This adds a binding for such oscillators that are not configurable +themself, but need to handle supplies for them to work. + +In schematics they often can be seen as + + ---------------- +Enable - | 100MHz,3.3V, | - VDD + | 3225 | + GND - | | - OUT + ---------------- + +or similar. The enable pin might be separate but can also just be tied +to the vdd supply, hence it is optional in the binding. + +Signed-off-by: Heiko Stuebner +Reviewed-by: Rob Herring (Arm) +Reviewed-by: Conor Dooley +Link: https://lore.kernel.org/r/20240906082511.2963890-2-heiko@sntech.de +Signed-off-by: Stephen Boyd +--- + .../bindings/clock/gated-fixed-clock.yaml | 49 +++++++++++++++++++ + 1 file changed, 49 insertions(+) + create mode 100644 Documentation/devicetree/bindings/clock/gated-fixed-clock.yaml + +diff --git a/Documentation/devicetree/bindings/clock/gated-fixed-clock.yaml b/Documentation/devicetree/bindings/clock/gated-fixed-clock.yaml +new file mode 100644 +index 000000000000..d3e0faf3c64d +--- /dev/null ++++ b/Documentation/devicetree/bindings/clock/gated-fixed-clock.yaml +@@ -0,0 +1,49 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/clock/gated-fixed-clock.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Gated Fixed clock ++ ++maintainers: ++ - Heiko Stuebner ++ ++properties: ++ compatible: ++ const: gated-fixed-clock ++ ++ "#clock-cells": ++ const: 0 ++ ++ clock-frequency: true ++ ++ clock-output-names: ++ maxItems: 1 ++ ++ enable-gpios: ++ description: ++ Contains a single GPIO specifier for the GPIO that enables and disables ++ the oscillator. ++ maxItems: 1 ++ ++ vdd-supply: ++ description: handle of the regulator that provides the supply voltage ++ ++required: ++ - compatible ++ - "#clock-cells" ++ - clock-frequency ++ - vdd-supply ++ ++additionalProperties: false ++ ++examples: ++ - | ++ clock-1000000000 { ++ compatible = "gated-fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <1000000000>; ++ vdd-supply = <®_vdd>; ++ }; ++... +-- +2.51.0 + + +From a821d7186c5d4f7289edfbcc0091f744729e0880 Mon Sep 17 00:00:00 2001 +From: Heiko Stuebner +Date: Fri, 6 Sep 2024 10:25:08 +0200 +Subject: [PATCH 172/517] clk: clk-gpio: update documentation for gpio-gate + clock + +The main documentation block seems to be from a time before the driver +handled sleeping and non-sleeping gpios and with that change it seems +updating the doc was overlooked. So do that now. + +Signed-off-by: Heiko Stuebner +Link: https://lore.kernel.org/r/20240906082511.2963890-3-heiko@sntech.de +Signed-off-by: Stephen Boyd +--- + drivers/clk/clk-gpio.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/clk-gpio.c b/drivers/clk/clk-gpio.c +index 5b114043771d..98415782f9a2 100644 +--- a/drivers/clk/clk-gpio.c ++++ b/drivers/clk/clk-gpio.c +@@ -22,8 +22,9 @@ + * DOC: basic gpio gated clock which can be enabled and disabled + * with gpio output + * Traits of this clock: +- * prepare - clk_(un)prepare only ensures parent is (un)prepared +- * enable - clk_enable and clk_disable are functional & control gpio ++ * prepare - clk_(un)prepare are functional and control a gpio that can sleep ++ * enable - clk_enable and clk_disable are functional & control ++ * non-sleeping gpio + * rate - inherits rate from parent. No clk_set_rate support + * parent - fixed parent. No clk_set_parent support + */ +-- +2.51.0 + + +From 1d8ecd6adc09ddf3d97c8d3db6c13fc109f9f24d Mon Sep 17 00:00:00 2001 +From: Heiko Stuebner +Date: Fri, 6 Sep 2024 10:25:09 +0200 +Subject: [PATCH 173/517] clk: clk-gpio: use dev_err_probe for gpio-get failure + +This is a real driver and dev_err_probe will hide the distinction between +EPROBE_DEFER and other errors automatically, so there is no need to +open-code this. + +Signed-off-by: Heiko Stuebner +Link: https://lore.kernel.org/r/20240906082511.2963890-4-heiko@sntech.de +Signed-off-by: Stephen Boyd +--- + drivers/clk/clk-gpio.c | 15 +++------------ + 1 file changed, 3 insertions(+), 12 deletions(-) + +diff --git a/drivers/clk/clk-gpio.c b/drivers/clk/clk-gpio.c +index 98415782f9a2..cda362a2eca0 100644 +--- a/drivers/clk/clk-gpio.c ++++ b/drivers/clk/clk-gpio.c +@@ -200,7 +200,6 @@ static int gpio_clk_driver_probe(struct platform_device *pdev) + struct gpio_desc *gpiod; + struct clk_hw *hw; + bool is_mux; +- int ret; + + is_mux = of_device_is_compatible(node, "gpio-mux-clock"); + +@@ -212,17 +211,9 @@ static int gpio_clk_driver_probe(struct platform_device *pdev) + + gpio_name = is_mux ? "select" : "enable"; + gpiod = devm_gpiod_get(dev, gpio_name, GPIOD_OUT_LOW); +- if (IS_ERR(gpiod)) { +- ret = PTR_ERR(gpiod); +- if (ret == -EPROBE_DEFER) +- pr_debug("%pOFn: %s: GPIOs not yet available, retry later\n", +- node, __func__); +- else +- pr_err("%pOFn: %s: Can't get '%s' named GPIO property\n", +- node, __func__, +- gpio_name); +- return ret; +- } ++ if (IS_ERR(gpiod)) ++ return dev_err_probe(dev, PTR_ERR(gpiod), ++ "Can't get '%s' named GPIO property\n", gpio_name); + + if (is_mux) + hw = clk_hw_register_gpio_mux(dev, gpiod); +-- +2.51.0 + + +From ee31cfe9b43e3d8aa62c15b695cdb655bf428db5 Mon Sep 17 00:00:00 2001 +From: Heiko Stuebner +Date: Fri, 6 Sep 2024 10:25:10 +0200 +Subject: [PATCH 174/517] clk: clk-gpio: add driver for gated-fixed-clocks + +In contrast to fixed clocks that are described as ungateable, boards +sometimes use additional oscillators for things like PCIe reference +clocks, that need actual supplies to get enabled and enable-gpios to be +toggled for them to work. + +This adds a driver for those generic gated-fixed-clocks +that can show up in schematics looking like + + ---------------- +Enable - | 100MHz,3.3V, | - VDD + | 3225 | + GND - | | - OUT + ---------------- + +The new driver gets grouped together with the existing gpio-gate and +gpio-mux, as it for one re-uses a lot of the gpio-gate functions +and also in its core it's just another gpio-controlled clock, just +with a fixed rate and a regulator-supply added in. + +The regulator-API provides function stubs for the !CONFIG_REGULATOR case, +so no special handling is necessary. + +Signed-off-by: Heiko Stuebner +Link: https://lore.kernel.org/r/20240906082511.2963890-5-heiko@sntech.de +Signed-off-by: Stephen Boyd +--- + drivers/clk/clk-gpio.c | 185 +++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 185 insertions(+) + +diff --git a/drivers/clk/clk-gpio.c b/drivers/clk/clk-gpio.c +index cda362a2eca0..9099c57e2715 100644 +--- a/drivers/clk/clk-gpio.c ++++ b/drivers/clk/clk-gpio.c +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + + /** + * DOC: basic gpio gated clock which can be enabled and disabled +@@ -239,3 +240,187 @@ static struct platform_driver gpio_clk_driver = { + }, + }; + builtin_platform_driver(gpio_clk_driver); ++ ++/** ++ * DOC: gated fixed clock, controlled with a gpio output and a regulator ++ * Traits of this clock: ++ * prepare - clk_prepare and clk_unprepare are function & control regulator ++ * optionally a gpio that can sleep ++ * enable - clk_enable and clk_disable are functional & control gpio ++ * rate - rate is fixed and set on clock registration ++ * parent - fixed clock is a root clock and has no parent ++ */ ++ ++/** ++ * struct clk_gated_fixed - Gateable fixed rate clock ++ * @clk_gpio: instance of clk_gpio for gate-gpio ++ * @supply: supply regulator ++ * @rate: fixed rate ++ */ ++struct clk_gated_fixed { ++ struct clk_gpio clk_gpio; ++ struct regulator *supply; ++ unsigned long rate; ++}; ++ ++#define to_clk_gated_fixed(_clk_gpio) container_of(_clk_gpio, struct clk_gated_fixed, clk_gpio) ++ ++static unsigned long clk_gated_fixed_recalc_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ return to_clk_gated_fixed(to_clk_gpio(hw))->rate; ++} ++ ++static int clk_gated_fixed_prepare(struct clk_hw *hw) ++{ ++ struct clk_gated_fixed *clk = to_clk_gated_fixed(to_clk_gpio(hw)); ++ ++ if (!clk->supply) ++ return 0; ++ ++ return regulator_enable(clk->supply); ++} ++ ++static void clk_gated_fixed_unprepare(struct clk_hw *hw) ++{ ++ struct clk_gated_fixed *clk = to_clk_gated_fixed(to_clk_gpio(hw)); ++ ++ if (!clk->supply) ++ return; ++ ++ regulator_disable(clk->supply); ++} ++ ++static int clk_gated_fixed_is_prepared(struct clk_hw *hw) ++{ ++ struct clk_gated_fixed *clk = to_clk_gated_fixed(to_clk_gpio(hw)); ++ ++ if (!clk->supply) ++ return true; ++ ++ return regulator_is_enabled(clk->supply); ++} ++ ++/* ++ * Fixed gated clock with non-sleeping gpio. ++ * ++ * Prepare operation turns on the supply regulator ++ * and the enable operation switches the enable-gpio. ++ */ ++static const struct clk_ops clk_gated_fixed_ops = { ++ .prepare = clk_gated_fixed_prepare, ++ .unprepare = clk_gated_fixed_unprepare, ++ .is_prepared = clk_gated_fixed_is_prepared, ++ .enable = clk_gpio_gate_enable, ++ .disable = clk_gpio_gate_disable, ++ .is_enabled = clk_gpio_gate_is_enabled, ++ .recalc_rate = clk_gated_fixed_recalc_rate, ++}; ++ ++static int clk_sleeping_gated_fixed_prepare(struct clk_hw *hw) ++{ ++ int ret; ++ ++ ret = clk_gated_fixed_prepare(hw); ++ if (ret) ++ return ret; ++ ++ ret = clk_sleeping_gpio_gate_prepare(hw); ++ if (ret) ++ clk_gated_fixed_unprepare(hw); ++ ++ return ret; ++} ++ ++static void clk_sleeping_gated_fixed_unprepare(struct clk_hw *hw) ++{ ++ clk_gated_fixed_unprepare(hw); ++ clk_sleeping_gpio_gate_unprepare(hw); ++} ++ ++/* ++ * Fixed gated clock with non-sleeping gpio. ++ * ++ * Enabling the supply regulator and switching the enable-gpio happens ++ * both in the prepare step. ++ * is_prepared only needs to check the gpio state, as toggling the ++ * gpio is the last step when preparing. ++ */ ++static const struct clk_ops clk_sleeping_gated_fixed_ops = { ++ .prepare = clk_sleeping_gated_fixed_prepare, ++ .unprepare = clk_sleeping_gated_fixed_unprepare, ++ .is_prepared = clk_sleeping_gpio_gate_is_prepared, ++ .recalc_rate = clk_gated_fixed_recalc_rate, ++}; ++ ++static int clk_gated_fixed_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct clk_gated_fixed *clk; ++ const struct clk_ops *ops; ++ const char *clk_name; ++ u32 rate; ++ int ret; ++ ++ clk = devm_kzalloc(dev, sizeof(*clk), GFP_KERNEL); ++ if (!clk) ++ return -ENOMEM; ++ ++ ret = device_property_read_u32(dev, "clock-frequency", &rate); ++ if (ret) ++ return dev_err_probe(dev, ret, "Failed to get clock-frequency\n"); ++ clk->rate = rate; ++ ++ ret = device_property_read_string(dev, "clock-output-names", &clk_name); ++ if (ret) ++ clk_name = fwnode_get_name(dev->fwnode); ++ ++ clk->supply = devm_regulator_get_optional(dev, "vdd"); ++ if (IS_ERR(clk->supply)) { ++ if (PTR_ERR(clk->supply) != -ENODEV) ++ return dev_err_probe(dev, PTR_ERR(clk->supply), ++ "Failed to get regulator\n"); ++ clk->supply = NULL; ++ } ++ ++ clk->clk_gpio.gpiod = devm_gpiod_get_optional(dev, "enable", ++ GPIOD_OUT_LOW); ++ if (IS_ERR(clk->clk_gpio.gpiod)) ++ return dev_err_probe(dev, PTR_ERR(clk->clk_gpio.gpiod), ++ "Failed to get gpio\n"); ++ ++ if (gpiod_cansleep(clk->clk_gpio.gpiod)) ++ ops = &clk_sleeping_gated_fixed_ops; ++ else ++ ops = &clk_gated_fixed_ops; ++ ++ clk->clk_gpio.hw.init = CLK_HW_INIT_NO_PARENT(clk_name, ops, 0); ++ ++ /* register the clock */ ++ ret = devm_clk_hw_register(dev, &clk->clk_gpio.hw); ++ if (ret) ++ return dev_err_probe(dev, ret, ++ "Failed to register clock\n"); ++ ++ ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, ++ &clk->clk_gpio.hw); ++ if (ret) ++ return dev_err_probe(dev, ret, ++ "Failed to register clock provider\n"); ++ ++ return 0; ++} ++ ++static const struct of_device_id gated_fixed_clk_match_table[] = { ++ { .compatible = "gated-fixed-clock" }, ++ { /* sentinel */ } ++}; ++ ++static struct platform_driver gated_fixed_clk_driver = { ++ .probe = clk_gated_fixed_probe, ++ .driver = { ++ .name = "gated-fixed-clk", ++ .of_match_table = gated_fixed_clk_match_table, ++ }, ++}; ++builtin_platform_driver(gated_fixed_clk_driver); +-- +2.51.0 + + +From 039a2eb86e84a84208a807044b945bde9f844f55 Mon Sep 17 00:00:00 2001 +From: Sander Vanheule +Date: Tue, 7 Jan 2025 21:16:20 +0100 +Subject: [PATCH 175/517] gpio: regmap: Use generic request/free ops + +Set the gpiochip request and free ops to the generic implementations. +This way a user can provide a gpio-ranges property defined for a pinmux, +easing muxing of gpio functions. Provided that the pin controller +implementents the pinmux op .gpio_request_enable(), pins will +automatically be muxed to their GPIO function when requested. + +Signed-off-by: Sander Vanheule +Acked-by: Michael Walle +Link: https://lore.kernel.org/r/20250107201621.12467-1-sander@svanheule.net +Signed-off-by: Bartosz Golaszewski +--- + drivers/gpio/gpio-regmap.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/gpio/gpio-regmap.c b/drivers/gpio/gpio-regmap.c +index 71684dee2ca5..05f8781b5204 100644 +--- a/drivers/gpio/gpio-regmap.c ++++ b/drivers/gpio/gpio-regmap.c +@@ -262,6 +262,8 @@ struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config + chip->label = config->label ?: dev_name(config->parent); + chip->can_sleep = regmap_might_sleep(config->regmap); + ++ chip->request = gpiochip_generic_request; ++ chip->free = gpiochip_generic_free; + chip->get = gpio_regmap_get; + if (gpio->reg_set_base && gpio->reg_clr_base) + chip->set = gpio_regmap_set_with_clear; +-- +2.51.0 + + +From 555fd2a1b2e46bbede23b8477230cd77af346fe2 Mon Sep 17 00:00:00 2001 +From: Kees Cook +Date: Wed, 16 Apr 2025 15:27:41 -0700 +Subject: [PATCH 176/517] power: supply: sysfs: Remove duplicate NUL + termination + +GCC 15's new -Wunterminated-string-initialization notices that one of +the sysfs attr strings would lack the implicit trailing NUL byte during +initialization: + +drivers/power/supply/power_supply_sysfs.c:183:57: warning: initializer-string for array of 'char' truncates NUL terminator but destination lacks 'nonstring' attribute (32 chars into 31 available) [-Wunterminated-string-initialization] + 183 | POWER_SUPPLY_ATTR(CHARGE_CONTROL_START_THRESHOLD), + | ^ +drivers/power/supply/power_supply_sysfs.c:36:23: note: in definition of macro '_POWER_SUPPLY_ATTR' + 36 | .attr_name = #_name "\0", \ + | ^~~~~ +drivers/power/supply/power_supply_sysfs.c:183:9: note: in expansion of macro 'POWER_SUPPLY_ATTR' + 183 | POWER_SUPPLY_ATTR(CHARGE_CONTROL_START_THRESHOLD), + | ^~~~~~~~~~~~~~~~~ + +However, the macro used was explicitly adding a trailing NUL byte (which +is not needed). Remove this to avoid the GCC warning. No binary +differences are seen after this change (there was always run for a NUL +byte, it's just that the _second_ NUL byte was getting truncated). + +Signed-off-by: Kees Cook +Link: https://lore.kernel.org/r/20250416222740.work.569-kees@kernel.org +Signed-off-by: Sebastian Reichel +--- + drivers/power/supply/power_supply_sysfs.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c +index 16b3c5880cd8..df6b16c77279 100644 +--- a/drivers/power/supply/power_supply_sysfs.c ++++ b/drivers/power/supply/power_supply_sysfs.c +@@ -33,7 +33,7 @@ struct power_supply_attr { + [POWER_SUPPLY_PROP_ ## _name] = \ + { \ + .prop_name = #_name, \ +- .attr_name = #_name "\0", \ ++ .attr_name = #_name, \ + .text_values = _text, \ + .text_values_len = _len, \ + } +-- +2.51.0 + + +From 7fb95e70810dd24974c57ab56fb2dc919e5b1665 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Thu, 22 Oct 2020 22:00:03 +0200 +Subject: [PATCH 177/517] compiler.h: only include asm/rwonce.h for kernel code + +This header file is not in uapi, which makes any user space code that includes +linux/compiler.h to fail with the error 'asm/rwonce.h: No such file or directory' + +Fixes: e506ea451254 ("compiler.h: Split {READ,WRITE}_ONCE definitions out into rwonce.h") +Signed-off-by: Felix Fietkau +--- + include/linux/compiler.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/include/linux/compiler.h b/include/linux/compiler.h +index d18542d7e17b..23b43f6093b1 100644 +--- a/include/linux/compiler.h ++++ b/include/linux/compiler.h +@@ -191,6 +191,8 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val, + __v; \ + }) + ++#include ++ + #endif /* __KERNEL__ */ + + /** +@@ -298,6 +300,4 @@ static inline void *offset_to_ptr(const int *off) + */ + #define prevent_tail_call_optimization() mb() + +-#include +- + #endif /* __LINUX_COMPILER_H */ +-- +2.51.0 + + +From 65c264e73e6464600d94d7aa80a1513b0cc13d77 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Wed, 18 Apr 2018 10:50:05 +0200 +Subject: [PATCH 178/517] MIPS: only process negative stack offsets on stack + traces + +Fixes endless back traces in cases where the compiler emits a stack +pointer increase in a branch delay slot (probably for some form of +function return). + +[ 3.475442] BUG: MAX_STACK_TRACE_ENTRIES too low! +[ 3.480070] turning off the locking correctness validator. +[ 3.485521] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.14.34 #0 +[ 3.491475] Stack : 00000000 00000000 00000000 00000000 80e0fce2 00000034 00000000 00000000 +[ 3.499764] 87c3838c 80696377 8061047c 00000000 00000001 00000001 87c2d850 6534689f +[ 3.508059] 00000000 00000000 80e10000 00000000 00000000 000000cf 0000000f 00000000 +[ 3.516353] 00000000 806a0000 00076891 00000000 00000000 00000000 ffffffff 00000000 +[ 3.524648] 806c0000 00000004 80e10000 806a0000 00000003 80690000 00000000 80700000 +[ 3.532942] ... +[ 3.535362] Call Trace: +[ 3.537818] [<80010a48>] show_stack+0x58/0x100 +[ 3.542207] [<804c2f78>] dump_stack+0xe8/0x170 +[ 3.546613] [<80079f90>] save_trace+0xf0/0x110 +[ 3.551010] [<8007b1ec>] mark_lock+0x33c/0x78c +[ 3.555413] [<8007bf48>] __lock_acquire+0x2ac/0x1a08 +[ 3.560337] [<8007de60>] lock_acquire+0x64/0x8c +[ 3.564846] [<804e1570>] _raw_spin_lock_irqsave+0x54/0x78 +[ 3.570186] [<801b618c>] kernfs_notify+0x94/0xac +[ 3.574770] [<801b7b10>] sysfs_notify+0x74/0xa0 +[ 3.579257] [<801b618c>] kernfs_notify+0x94/0xac +[ 3.583839] [<801b7b10>] sysfs_notify+0x74/0xa0 +[ 3.588329] [<801b618c>] kernfs_notify+0x94/0xac +[ 3.592911] [<801b7b10>] sysfs_notify+0x74/0xa0 +[ 3.597401] [<801b618c>] kernfs_notify+0x94/0xac +[ 3.601983] [<801b7b10>] sysfs_notify+0x74/0xa0 +[ 3.606473] [<801b618c>] kernfs_notify+0x94/0xac +[ 3.611055] [<801b7b10>] sysfs_notify+0x74/0xa0 +[ 3.615545] [<801b618c>] kernfs_notify+0x94/0xac +[ 3.620125] [<801b7b10>] sysfs_notify+0x74/0xa0 +[ 3.624619] [<801b618c>] kernfs_notify+0x94/0xac +[ 3.629197] [<801b7b10>] sysfs_notify+0x74/0xa0 +[ 3.633691] [<801b618c>] kernfs_notify+0x94/0xac +[ 3.638269] [<801b7b10>] sysfs_notify+0x74/0xa0 +[ 3.642763] [<801b618c>] kernfs_notify+0x94/0xac + +Signed-off-by: Felix Fietkau +--- + arch/mips/kernel/process.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c +index 02aa6a04a21d..d84ff2484e6b 100644 +--- a/arch/mips/kernel/process.c ++++ b/arch/mips/kernel/process.c +@@ -395,6 +395,8 @@ static inline int is_sp_move_ins(union mips_instruction *ip, int *frame_size) + + if (ip->i_format.opcode == addiu_op || + ip->i_format.opcode == daddiu_op) { ++ if (ip->i_format.simmediate > 0) ++ return 0; + *frame_size = -ip->i_format.simmediate; + return 1; + } +-- +2.51.0 + + +From 5fb9ed3fa96df7607d624af7500a8b28005008bb Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Sun, 9 Jul 2017 00:26:53 +0200 +Subject: [PATCH 179/517] kernel: add compile fix for linux 4.9 on x86 + +Signed-off-by: Felix Fietkau +--- + Makefile | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Makefile b/Makefile +index d4c679b2d4bc..adebb89c7db4 100644 +--- a/Makefile ++++ b/Makefile +@@ -589,7 +589,7 @@ export RUSTC_BOOTSTRAP := 1 + # Allows finding `.clippy.toml` in out-of-srctree builds. + export CLIPPY_CONF_DIR := $(srctree) + +-export ARCH SRCARCH CONFIG_SHELL BASH HOSTCC KBUILD_HOSTCFLAGS CROSS_COMPILE LD CC HOSTPKG_CONFIG ++export ARCH SRCARCH SUBARCH CONFIG_SHELL BASH HOSTCC KBUILD_HOSTCFLAGS CROSS_COMPILE LD CC HOSTPKG_CONFIG + export RUSTC RUSTDOC RUSTFMT RUSTC_OR_CLIPPY_QUIET RUSTC_OR_CLIPPY BINDGEN + export HOSTRUSTC KBUILD_HOSTRUSTFLAGS + export CPP AR NM STRIP OBJCOPY OBJDUMP READELF PAHOLE RESOLVE_BTFIDS LEX YACC AWK INSTALLKERNEL +-- +2.51.0 + + +From 24ba3611cd2096392227e4f47f8970e7fc03d445 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pali=20Roh=C3=A1r?= +Date: Thu, 28 Apr 2022 11:13:23 +0200 +Subject: [PATCH 180/517] watchdog: max63xx_wdt: Add support for specifying WDI + logic via GPIO +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +On some boards is WDI logic of max6370 chip connected via GPIO. +So extend max63xx_wdt driver to allow specifying WDI logic via GPIO. + +Signed-off-by: Pali Rohár +--- + drivers/watchdog/max63xx_wdt.c | 24 ++++++++++++++++++++++++ + 1 file changed, 24 insertions(+) + +diff --git a/drivers/watchdog/max63xx_wdt.c b/drivers/watchdog/max63xx_wdt.c +index 21935f9620e4..041ae121f981 100644 +--- a/drivers/watchdog/max63xx_wdt.c ++++ b/drivers/watchdog/max63xx_wdt.c +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + + #define DEFAULT_HEARTBEAT 60 + #define MAX_HEARTBEAT 60 +@@ -50,6 +51,9 @@ struct max63xx_wdt { + void __iomem *base; + spinlock_t lock; + ++ /* GPIOs */ ++ struct gpio_desc *gpio_wdi; ++ + /* WDI and WSET bits write access routines */ + void (*ping)(struct max63xx_wdt *wdt); + void (*set)(struct max63xx_wdt *wdt, u8 set); +@@ -155,6 +159,17 @@ static const struct watchdog_info max63xx_wdt_info = { + .identity = "max63xx Watchdog", + }; + ++static void max63xx_gpio_ping(struct max63xx_wdt *wdt) ++{ ++ spin_lock(&wdt->lock); ++ ++ gpiod_set_value(wdt->gpio_wdi, 1); ++ udelay(1); ++ gpiod_set_value(wdt->gpio_wdi, 0); ++ ++ spin_unlock(&wdt->lock); ++} ++ + static void max63xx_mmap_ping(struct max63xx_wdt *wdt) + { + u8 val; +@@ -222,10 +237,19 @@ static int max63xx_wdt_probe(struct platform_device *pdev) + return -EINVAL; + } + ++ wdt->gpio_wdi = devm_gpiod_get(dev, NULL, GPIOD_FLAGS_BIT_DIR_OUT); ++ if (IS_ERR(wdt->gpio_wdi) && PTR_ERR(wdt->gpio_wdi) != -ENOENT) ++ return dev_err_probe(dev, PTR_ERR(wdt->gpio_wdi), ++ "unable to request gpio: %ld\n", ++ PTR_ERR(wdt->gpio_wdi)); ++ + err = max63xx_mmap_init(pdev, wdt); + if (err) + return err; + ++ if (!IS_ERR(wdt->gpio_wdi)) ++ wdt->ping = max63xx_gpio_ping; ++ + platform_set_drvdata(pdev, &wdt->wdd); + watchdog_set_drvdata(&wdt->wdd, wdt); + +-- +2.51.0 + + +From 3a45749cae25f2d9e0eb86b03f7283dab7086b14 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Mon, 3 Nov 2025 15:49:31 +0100 +Subject: [PATCH 181/517] jffs2: use .rename2 and add RENAME_WHITEOUT support + +It is required for renames on overlayfs + +Signed-off-by: Felix Fietkau +--- + fs/jffs2/dir.c | 36 +++++++++++++++++++++++++++++------- + 1 file changed, 29 insertions(+), 7 deletions(-) + +diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c +index 2b2938970da3..8ceef593258e 100644 +--- a/fs/jffs2/dir.c ++++ b/fs/jffs2/dir.c +@@ -620,8 +620,8 @@ static int jffs2_rmdir (struct inode *dir_i, struct dentry *dentry) + return ret; + } + +-static int jffs2_mknod (struct mnt_idmap *idmap, struct inode *dir_i, +- struct dentry *dentry, umode_t mode, dev_t rdev) ++static int __jffs2_mknod (struct mnt_idmap *idmap, struct inode *dir_i, ++ struct dentry *dentry, umode_t mode, dev_t rdev, bool whiteout) + { + struct jffs2_inode_info *f, *dir_f; + struct jffs2_sb_info *c; +@@ -761,7 +761,11 @@ static int jffs2_mknod (struct mnt_idmap *idmap, struct inode *dir_i, + mutex_unlock(&dir_f->sem); + jffs2_complete_reservation(c); + +- d_instantiate_new(dentry, inode); ++ if (!whiteout) ++ d_instantiate_new(dentry, inode); ++ else ++ unlock_new_inode(inode); ++ + return 0; + + fail: +@@ -769,6 +773,19 @@ static int jffs2_mknod (struct mnt_idmap *idmap, struct inode *dir_i, + return ret; + } + ++static int jffs2_mknod (struct mnt_idmap *idmap, struct inode *dir_i, ++ struct dentry *dentry, umode_t mode, dev_t rdev) ++{ ++ return __jffs2_mknod(idmap, dir_i, dentry, mode, rdev, false); ++} ++ ++static int jffs2_whiteout (struct mnt_idmap *idmap, struct inode *old_dir, ++ struct dentry *old_dentry) ++{ ++ return __jffs2_mknod(idmap, old_dir, old_dentry, S_IFCHR | WHITEOUT_MODE, ++ WHITEOUT_DEV, true); ++} ++ + static int jffs2_rename (struct mnt_idmap *idmap, + struct inode *old_dir_i, struct dentry *old_dentry, + struct inode *new_dir_i, struct dentry *new_dentry, +@@ -780,7 +797,7 @@ static int jffs2_rename (struct mnt_idmap *idmap, + uint8_t type; + uint32_t now; + +- if (flags & ~RENAME_NOREPLACE) ++ if (flags & ~(RENAME_NOREPLACE|RENAME_WHITEOUT)) + return -EINVAL; + + /* The VFS will check for us and prevent trying to rename a +@@ -846,9 +863,14 @@ static int jffs2_rename (struct mnt_idmap *idmap, + if (d_is_dir(old_dentry) && !victim_f) + inc_nlink(new_dir_i); + +- /* Unlink the original */ +- ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i), +- old_dentry->d_name.name, old_dentry->d_name.len, NULL, now); ++ if (flags & RENAME_WHITEOUT) ++ /* Replace with whiteout */ ++ ret = jffs2_whiteout(idmap, old_dir_i, old_dentry); ++ else ++ /* Unlink the original */ ++ ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i), ++ old_dentry->d_name.name, ++ old_dentry->d_name.len, NULL, now); + + /* We don't touch inode->i_nlink */ + +-- +2.51.0 + + +From 3b035d50ebdd949b59df84accf8c390e5857869b Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Mon, 3 Nov 2025 15:49:32 +0100 +Subject: [PATCH 182/517] jffs2: add RENAME_EXCHANGE support + +Signed-off-by: Felix Fietkau +--- + fs/jffs2/dir.c | 27 +++++++++++++++++++++++---- + 1 file changed, 23 insertions(+), 4 deletions(-) + +diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c +index 8ceef593258e..198bc4bf6aed 100644 +--- a/fs/jffs2/dir.c ++++ b/fs/jffs2/dir.c +@@ -794,18 +794,31 @@ static int jffs2_rename (struct mnt_idmap *idmap, + int ret; + struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb); + struct jffs2_inode_info *victim_f = NULL; ++ struct inode *fst_inode = d_inode(old_dentry); ++ struct inode *snd_inode = d_inode(new_dentry); + uint8_t type; + uint32_t now; + +- if (flags & ~(RENAME_NOREPLACE|RENAME_WHITEOUT)) ++ if (flags & ~(RENAME_NOREPLACE|RENAME_WHITEOUT|RENAME_EXCHANGE)) + return -EINVAL; + ++ if ((flags & RENAME_EXCHANGE) && (old_dir_i != new_dir_i)) { ++ if (S_ISDIR(fst_inode->i_mode) && !S_ISDIR(snd_inode->i_mode)) { ++ inc_nlink(new_dir_i); ++ drop_nlink(old_dir_i); ++ } ++ else if (!S_ISDIR(fst_inode->i_mode) && S_ISDIR(snd_inode->i_mode)) { ++ drop_nlink(new_dir_i); ++ inc_nlink(old_dir_i); ++ } ++ } ++ + /* The VFS will check for us and prevent trying to rename a + * file over a directory and vice versa, but if it's a directory, + * the VFS can't check whether the victim is empty. The filesystem + * needs to do that for itself. + */ +- if (d_really_is_positive(new_dentry)) { ++ if (d_really_is_positive(new_dentry) && !(flags & RENAME_EXCHANGE)) { + victim_f = JFFS2_INODE_INFO(d_inode(new_dentry)); + if (d_is_dir(new_dentry)) { + struct jffs2_full_dirent *fd; +@@ -840,7 +853,7 @@ static int jffs2_rename (struct mnt_idmap *idmap, + if (ret) + return ret; + +- if (victim_f) { ++ if (victim_f && !(flags & RENAME_EXCHANGE)) { + /* There was a victim. Kill it off nicely */ + if (d_is_dir(new_dentry)) + clear_nlink(d_inode(new_dentry)); +@@ -866,6 +879,12 @@ static int jffs2_rename (struct mnt_idmap *idmap, + if (flags & RENAME_WHITEOUT) + /* Replace with whiteout */ + ret = jffs2_whiteout(idmap, old_dir_i, old_dentry); ++ else if (flags & RENAME_EXCHANGE) ++ /* Replace the original */ ++ ret = jffs2_do_link(c, JFFS2_INODE_INFO(old_dir_i), ++ d_inode(new_dentry)->i_ino, type, ++ old_dentry->d_name.name, old_dentry->d_name.len, ++ now); + else + /* Unlink the original */ + ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i), +@@ -898,7 +917,7 @@ static int jffs2_rename (struct mnt_idmap *idmap, + return ret; + } + +- if (d_is_dir(old_dentry)) ++ if (d_is_dir(old_dentry) && !(flags & RENAME_EXCHANGE)) + drop_nlink(old_dir_i); + + inode_set_mtime_to_ts(old_dir_i, +-- +2.51.0 + + +From 45c9e05782807facb6e64541dc9a86119ed266f1 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Mon, 3 Nov 2025 15:49:32 +0100 +Subject: [PATCH 183/517] jffs2: add splice ops + +Add splice_read using generic_file_splice_read. +Add splice_write using iter_file_splice_write + +Signed-off-by: Felix Fietkau +--- + fs/jffs2/file.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c +index 13c18ccc13b0..b08616967891 100644 +--- a/fs/jffs2/file.c ++++ b/fs/jffs2/file.c +@@ -53,6 +53,8 @@ const struct file_operations jffs2_file_operations = + .open = generic_file_open, + .read_iter = generic_file_read_iter, + .write_iter = generic_file_write_iter, ++ .splice_read = filemap_splice_read, ++ .splice_write = iter_file_splice_write, + .unlocked_ioctl=jffs2_ioctl, + .mmap = generic_file_readonly_mmap, + .fsync = jffs2_fsync, +-- +2.51.0 + + +From f772c8f03f55a56dc910561555de3b1237994f1e Mon Sep 17 00:00:00 2001 +From: Stephen Hemminger +Date: Mon, 3 Nov 2025 15:49:32 +0100 +Subject: [PATCH 184/517] bridge: allow receiption on disabled port + +When an ethernet device is enslaved to a bridge, and the bridge STP +detects loss of carrier (or operational state down), then normally +packet receiption is blocked. + +This breaks control applications like WPA which maybe expecting to +receive packets to negotiate to bring link up. The bridge needs to +block forwarding packets from these disabled ports, but there is no +hard requirement to not allow local packet delivery. + +Signed-off-by: Stephen Hemminger +Signed-off-by: Felix Fietkau +--- + net/bridge/br_input.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c +index c059e5657db3..0332371d19ab 100644 +--- a/net/bridge/br_input.c ++++ b/net/bridge/br_input.c +@@ -245,6 +245,9 @@ static void __br_handle_local_finish(struct sk_buff *skb) + /* note: already called with rcu_read_lock */ + static int br_handle_local_finish(struct net *net, struct sock *sk, struct sk_buff *skb) + { ++ struct net_bridge_port *p = br_port_get_rcu(skb->dev); ++ ++ if (p->state != BR_STATE_DISABLED) + __br_handle_local_finish(skb); + + /* return 1 to signal the okfn() was called so it's ok to use the skb */ +@@ -416,6 +419,17 @@ static rx_handler_result_t br_handle_frame(struct sk_buff **pskb) + goto defer_stp_filtering; + + switch (p->state) { ++ case BR_STATE_DISABLED: ++ if (ether_addr_equal(p->br->dev->dev_addr, dest)) ++ skb->pkt_type = PACKET_HOST; ++ ++ if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, ++ dev_net(skb->dev), NULL, skb, skb->dev, NULL, ++ br_handle_local_finish) == 1) { ++ return RX_HANDLER_PASS; ++ } ++ break; ++ + case BR_STATE_FORWARDING: + case BR_STATE_LEARNING: + defer_stp_filtering: +-- +2.51.0 + + +From f8a675acf745105364469ccd2c10ae11f0ff58dd Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Thu, 4 Jan 2024 15:21:21 +0100 +Subject: [PATCH 185/517] net: bridge: do not send arp replies if src and + target hw addr is the same + +There are broken devices in the wild that handle duplicate IP address +detection by sending out ARP requests for the IP that they received from a +DHCP server and refuse the address if they get a reply. +When proxyarp is enabled, they would go into a loop of requesting an address +and then NAKing it again. + +Link: https://github.com/openwrt/openwrt/issues/14309 +Signed-off-by: Felix Fietkau +--- + net/bridge/br_arp_nd_proxy.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/net/bridge/br_arp_nd_proxy.c b/net/bridge/br_arp_nd_proxy.c +index c7869a286df4..3a2770938374 100644 +--- a/net/bridge/br_arp_nd_proxy.c ++++ b/net/bridge/br_arp_nd_proxy.c +@@ -204,7 +204,10 @@ void br_do_proxy_suppress_arp(struct sk_buff *skb, struct net_bridge *br, + if ((p && (p->flags & BR_PROXYARP)) || + (f->dst && (f->dst->flags & BR_PROXYARP_WIFI)) || + br_is_neigh_suppress_enabled(f->dst, vid)) { +- if (!vid) ++ replied = true; ++ if (!memcmp(n->ha, sha, dev->addr_len)) ++ replied = false; ++ else if (!vid) + br_arp_send(br, p, skb->dev, sip, tip, + sha, n->ha, sha, 0, 0); + else +@@ -212,7 +215,6 @@ void br_do_proxy_suppress_arp(struct sk_buff *skb, struct net_bridge *br, + sha, n->ha, sha, + skb->vlan_proto, + skb_vlan_tag_get(skb)); +- replied = true; + } + + /* If we have replied or as long as we know the +-- +2.51.0 + + +From 5e09714675351cc1bfc7be2cdf06a96371415a00 Mon Sep 17 00:00:00 2001 +From: Kees Cook +Date: Wed, 21 May 2025 23:27:04 +0200 +Subject: [PATCH 186/517] wireguard: global: add __nonstring annotations for + unterminated strings + +When a character array without a terminating NUL character has a static +initializer, GCC 15's -Wunterminated-string-initialization will only +warn if the array lacks the "nonstring" attribute[1]. Mark the arrays +with __nonstring to correctly identify the char array as "not a C string" +and thereby eliminate the warning: + +../drivers/net/wireguard/cookie.c:29:56: warning: initializer-string for array of 'unsigned char' truncates NUL terminator but destination lacks 'nonstring' attribute (9 chars into 8 available) [-Wunterminated-string-initialization] + 29 | static const u8 mac1_key_label[COOKIE_KEY_LABEL_LEN] = "mac1----"; + | ^~~~~~~~~~ +../drivers/net/wireguard/cookie.c:30:58: warning: initializer-string for array of 'unsigned char' truncates NUL terminator but destination lacks 'nonstring' attribute (9 chars into 8 available) [-Wunterminated-string-initialization] + 30 | static const u8 cookie_key_label[COOKIE_KEY_LABEL_LEN] = "cookie--"; + | ^~~~~~~~~~ +../drivers/net/wireguard/noise.c:28:38: warning: initializer-string for array of 'unsigned char' truncates NUL terminator but destination lacks 'nonstring' attribute (38 chars into 37 available) [-Wunterminated-string-initialization] + 28 | static const u8 handshake_name[37] = "Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s"; + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +../drivers/net/wireguard/noise.c:29:39: warning: initializer-string for array of 'unsigned char' truncates NUL terminator but destination lacks 'nonstring' attribute (35 chars into 34 available) [-Wunterminated-string-initialization] + 29 | static const u8 identifier_name[34] = "WireGuard v1 zx2c4 Jason@zx2c4.com"; + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The arrays are always used with their fixed size, so use __nonstring. + +Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117178 [1] +Signed-off-by: Kees Cook +Signed-off-by: Jason A. Donenfeld +Link: https://patch.msgid.link/20250521212707.1767879-3-Jason@zx2c4.com +Signed-off-by: Paolo Abeni +--- + drivers/net/wireguard/cookie.c | 4 ++-- + drivers/net/wireguard/noise.c | 4 ++-- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/wireguard/cookie.c b/drivers/net/wireguard/cookie.c +index f89581b5e8cb..94d0a7206084 100644 +--- a/drivers/net/wireguard/cookie.c ++++ b/drivers/net/wireguard/cookie.c +@@ -26,8 +26,8 @@ void wg_cookie_checker_init(struct cookie_checker *checker, + } + + enum { COOKIE_KEY_LABEL_LEN = 8 }; +-static const u8 mac1_key_label[COOKIE_KEY_LABEL_LEN] = "mac1----"; +-static const u8 cookie_key_label[COOKIE_KEY_LABEL_LEN] = "cookie--"; ++static const u8 mac1_key_label[COOKIE_KEY_LABEL_LEN] __nonstring = "mac1----"; ++static const u8 cookie_key_label[COOKIE_KEY_LABEL_LEN] __nonstring = "cookie--"; + + static void precompute_key(u8 key[NOISE_SYMMETRIC_KEY_LEN], + const u8 pubkey[NOISE_PUBLIC_KEY_LEN], +diff --git a/drivers/net/wireguard/noise.c b/drivers/net/wireguard/noise.c +index 202a33af5a72..7eb9a23a3d4d 100644 +--- a/drivers/net/wireguard/noise.c ++++ b/drivers/net/wireguard/noise.c +@@ -25,8 +25,8 @@ + * <- e, ee, se, psk, {} + */ + +-static const u8 handshake_name[37] = "Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s"; +-static const u8 identifier_name[34] = "WireGuard v1 zx2c4 Jason@zx2c4.com"; ++static const u8 handshake_name[37] __nonstring = "Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s"; ++static const u8 identifier_name[34] __nonstring = "WireGuard v1 zx2c4 Jason@zx2c4.com"; + static u8 handshake_init_hash[NOISE_HASH_LEN] __ro_after_init; + static u8 handshake_init_chaining_key[NOISE_HASH_LEN] __ro_after_init; + static atomic64_t keypair_counter = ATOMIC64_INIT(0); +-- +2.51.0 + + +From 521a25813c3413cc25032dd5b0b090950f0057c8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Daniel=20Gonz=C3=A1lez=20Cabanelas?= +Date: Mon, 3 Nov 2025 15:49:33 +0100 +Subject: [PATCH 187/517] rtc: rs5c372: support alarms up to 1 week +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The Ricoh R2221x, R2223x, RS5C372, RV5C387A chips can handle 1 week +alarms. + +Read the "wday" alarm register and convert it to a date to support up 1 +week in our driver. + +Signed-off-by: Daniel González Cabanelas +--- + drivers/rtc/rtc-rs5c372.c | 48 ++++++++++++++++++++++++++++++++++----- + 1 file changed, 42 insertions(+), 6 deletions(-) + +diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c +index f8fab0205f8c..e19aef158938 100644 +--- a/drivers/rtc/rtc-rs5c372.c ++++ b/drivers/rtc/rtc-rs5c372.c +@@ -399,7 +399,9 @@ static int rs5c_read_alarm(struct device *dev, struct rtc_wkalrm *t) + { + struct i2c_client *client = to_i2c_client(dev); + struct rs5c372 *rs5c = i2c_get_clientdata(client); +- int status; ++ int status, wday_offs; ++ struct rtc_time rtc; ++ unsigned long alarm_secs; + + status = rs5c_get_regs(rs5c); + if (status < 0) +@@ -409,6 +411,30 @@ static int rs5c_read_alarm(struct device *dev, struct rtc_wkalrm *t) + t->time.tm_sec = 0; + t->time.tm_min = bcd2bin(rs5c->regs[RS5C_REG_ALARM_A_MIN] & 0x7f); + t->time.tm_hour = rs5c_reg2hr(rs5c, rs5c->regs[RS5C_REG_ALARM_A_HOURS]); ++ t->time.tm_wday = ffs(rs5c->regs[RS5C_REG_ALARM_A_WDAY] & 0x7f) - 1; ++ ++ /* determine the day, month and year based on alarm wday, taking as a ++ * reference the current time from the rtc ++ */ ++ status = rs5c372_rtc_read_time(dev, &rtc); ++ if (status < 0) ++ return status; ++ ++ wday_offs = t->time.tm_wday - rtc.tm_wday; ++ alarm_secs = mktime64(rtc.tm_year + 1900, ++ rtc.tm_mon + 1, ++ rtc.tm_mday + wday_offs, ++ t->time.tm_hour, ++ t->time.tm_min, ++ t->time.tm_sec); ++ ++ if (wday_offs < 0 || (wday_offs == 0 && ++ (t->time.tm_hour < rtc.tm_hour || ++ (t->time.tm_hour == rtc.tm_hour && ++ t->time.tm_min <= rtc.tm_min)))) ++ alarm_secs += 7 * 86400; ++ ++ rtc_time64_to_tm(alarm_secs, &t->time); + + /* ... and status */ + t->enabled = !!(rs5c->regs[RS5C_REG_CTRL1] & RS5C_CTRL1_AALE); +@@ -423,12 +449,20 @@ static int rs5c_set_alarm(struct device *dev, struct rtc_wkalrm *t) + struct rs5c372 *rs5c = i2c_get_clientdata(client); + int status, addr, i; + unsigned char buf[3]; ++ struct rtc_time rtc_tm; ++ unsigned long rtc_secs, alarm_secs; + +- /* only handle up to 24 hours in the future, like RTC_ALM_SET */ +- if (t->time.tm_mday != -1 +- || t->time.tm_mon != -1 +- || t->time.tm_year != -1) ++ /* chip only can handle alarms up to one week in the future*/ ++ status = rs5c372_rtc_read_time(dev, &rtc_tm); ++ if (status) ++ return status; ++ rtc_secs = rtc_tm_to_time64(&rtc_tm); ++ alarm_secs = rtc_tm_to_time64(&t->time); ++ if (alarm_secs >= rtc_secs + 7 * 86400) { ++ dev_err(dev, "%s: alarm maximum is one week in the future (%d)\n", ++ __func__, status); + return -EINVAL; ++ } + + /* REVISIT: round up tm_sec */ + +@@ -449,7 +483,9 @@ static int rs5c_set_alarm(struct device *dev, struct rtc_wkalrm *t) + /* set alarm */ + buf[0] = bin2bcd(t->time.tm_min); + buf[1] = rs5c_hr2reg(rs5c, t->time.tm_hour); +- buf[2] = 0x7f; /* any/all days */ ++ /* each bit is the day of the week, 0x7f means all days */ ++ buf[2] = (t->time.tm_wday >= 0 && t->time.tm_wday < 7) ? ++ BIT(t->time.tm_wday) : 0x7f; + + for (i = 0; i < sizeof(buf); i++) { + addr = RS5C_ADDR(RS5C_REG_ALARM_A_MIN + i); +-- +2.51.0 + + +From 3625b65094981635964c425d20e84532c4f9ac11 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Daniel=20Gonz=C3=A1lez=20Cabanelas?= +Date: Mon, 3 Nov 2025 15:49:33 +0100 +Subject: [PATCH 188/517] rtc: rs5c372: let the alarm to be used as wakeup + source +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Currently there is no use for the interrupts on the rs5c372 RTC and the +wakealarm isn't enabled. There are some devices like NASes which use this +RTC to wake up from the power off state when the INTR pin is activated by +the alarm clock. + +Enable the alarm and let to be used as a wakeup source. + +Tested on a Buffalo LS421DE NAS. + +Signed-off-by: Daniel González Cabanelas +--- + drivers/rtc/rtc-rs5c372.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c +index e19aef158938..b3f7e859e5d5 100644 +--- a/drivers/rtc/rtc-rs5c372.c ++++ b/drivers/rtc/rtc-rs5c372.c +@@ -832,6 +832,7 @@ static int rs5c372_probe(struct i2c_client *client) + int err = 0; + int smbus_mode = 0; + struct rs5c372 *rs5c372; ++ bool rs5c372_can_wakeup_device = false; + + dev_dbg(&client->dev, "%s\n", __func__); + +@@ -868,6 +869,12 @@ static int rs5c372_probe(struct i2c_client *client) + rs5c372->type = id->driver_data; + } + ++#ifdef CONFIG_OF ++ if(of_property_read_bool(client->dev.of_node, ++ "wakeup-source")) ++ rs5c372_can_wakeup_device = true; ++#endif ++ + /* we read registers 0x0f then 0x00-0x0f; skip the first one */ + rs5c372->regs = &rs5c372->buf[1]; + rs5c372->smbus = smbus_mode; +@@ -901,6 +908,8 @@ static int rs5c372_probe(struct i2c_client *client) + goto exit; + } + ++ rs5c372->has_irq = 1; ++ + /* if the oscillator lost power and no other software (like + * the bootloader) set it up, do it here. + * +@@ -927,6 +936,10 @@ static int rs5c372_probe(struct i2c_client *client) + ); + + /* REVISIT use client->irq to register alarm irq ... */ ++ if (rs5c372_can_wakeup_device) { ++ device_init_wakeup(&client->dev, true); ++ } ++ + rs5c372->rtc = devm_rtc_device_register(&client->dev, + rs5c372_driver.driver.name, + &rs5c372_rtc_ops, THIS_MODULE); +@@ -940,6 +953,10 @@ static int rs5c372_probe(struct i2c_client *client) + if (err) + goto exit; + ++ /* the rs5c372 alarm only supports a minute accuracy */ ++ set_bit(RTC_FEATURE_ALARM_RES_MINUTE, rs5c372->rtc->features); ++ clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rs5c372->rtc->features); ++ + return 0; + + exit: +-- +2.51.0 + + +From aaa9613d88cfc960918632f6cdc33972cf14729b Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Tue, 15 Apr 2025 23:16:40 +0200 +Subject: [PATCH 189/517] ARM: 9404/1: arm32: fix boot hang with + HAVE_LD_DEAD_CODE_DATA_ELIMINATION + +It was reported that some SoC (mvebu based for example) hang on kernel +loading. A variant of the feature was present in OpenWrt from long ago +and adding the additional entry with KEEP, fix the problem. + +Fixes: ed0f94102251 ("ARM: 9404/1: arm32: enable HAVE_LD_DEAD_CODE_DATA_ELIMINATION") +Signed-off-by: Christian Marangi +--- + arch/arm/include/asm/vmlinux.lds.h | 10 +++++----- + arch/arm/kernel/vmlinux.lds.S | 4 ++-- + 2 files changed, 7 insertions(+), 7 deletions(-) + +diff --git a/arch/arm/include/asm/vmlinux.lds.h b/arch/arm/include/asm/vmlinux.lds.h +index 14811b4f48ec..c69205878256 100644 +--- a/arch/arm/include/asm/vmlinux.lds.h ++++ b/arch/arm/include/asm/vmlinux.lds.h +@@ -54,7 +54,7 @@ + #define IDMAP_TEXT \ + ALIGN_FUNCTION(); \ + __idmap_text_start = .; \ +- *(.idmap.text) \ ++ KEEP(*(.idmap.text)) \ + __idmap_text_end = .; \ + + #define ARM_DISCARD \ +@@ -114,12 +114,12 @@ + . = ALIGN(8); \ + .ARM.unwind_idx : { \ + __start_unwind_idx = .; \ +- *(.ARM.exidx*) \ ++ KEEP(*(.ARM.exidx*)) \ + __stop_unwind_idx = .; \ + } \ + .ARM.unwind_tab : { \ + __start_unwind_tab = .; \ +- *(.ARM.extab*) \ ++ KEEP(*(.ARM.extab*)) \ + __stop_unwind_tab = .; \ + } + +@@ -131,7 +131,7 @@ + __vectors_lma = .; \ + OVERLAY 0xffff0000 : NOCROSSREFS AT(__vectors_lma) { \ + .vectors { \ +- OVERLAY_KEEP(*(.vectors)) \ ++ KEEP(*(.vectors)) \ + } \ + .vectors.bhb.loop8 { \ + OVERLAY_KEEP(*(.vectors.bhb.loop8)) \ +@@ -149,7 +149,7 @@ + \ + __stubs_lma = .; \ + .stubs ADDR(.vectors) + 0x1000 : AT(__stubs_lma) { \ +- *(.stubs) \ ++ KEEP(*(.stubs)) \ + } \ + ARM_LMA(__stubs, .stubs); \ + . = __stubs_lma + SIZEOF(.stubs); \ +diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S +index de373c6c2ae8..4d2ea49d6f84 100644 +--- a/arch/arm/kernel/vmlinux.lds.S ++++ b/arch/arm/kernel/vmlinux.lds.S +@@ -104,13 +104,13 @@ SECTIONS + } + .init.tagtable : { + __tagtable_begin = .; +- *(.taglist.init) ++ KEEP(*(.taglist.init)) + __tagtable_end = .; + } + #ifdef CONFIG_SMP_ON_UP + .init.smpalt : { + __smpalt_begin = .; +- *(.alt.smp.init) ++ KEEP(*(.alt.smp.init)) + __smpalt_end = .; + } + #endif +-- +2.51.0 + + +From 66801cda68c3e0f05d3962565caf52d4abb6c98b Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Mon, 3 Nov 2025 15:49:34 +0100 +Subject: [PATCH 190/517] kernel: add a config option for keeping the kallsyms + table uncompressed, saving ~9kb kernel size after lzma on ar71xx + +[john@phrozen.org: added to my upstream queue 30.12.2016] +lede-commit: e0e3509b5ce2ccf93d4d67ea907613f5f7ec2eed +Signed-off-by: Felix Fietkau +--- + init/Kconfig | 11 +++++++++ + kernel/kallsyms.c | 8 ++++++ + kernel/vmcore_info.c | 2 ++ + scripts/kallsyms.c | 54 ++++++++++++++++++++++++++--------------- + scripts/link-vmlinux.sh | 4 +++ + 5 files changed, 59 insertions(+), 20 deletions(-) + +diff --git a/init/Kconfig b/init/Kconfig +index 219ccdb0af73..9b04e413be82 100644 +--- a/init/Kconfig ++++ b/init/Kconfig +@@ -1534,6 +1534,17 @@ config SYSCTL_ARCH_UNALIGN_ALLOW + the unaligned access emulation. + see arch/parisc/kernel/unaligned.c for reference + ++config KALLSYMS_UNCOMPRESSED ++ bool "Keep kallsyms uncompressed" ++ depends on KALLSYMS ++ help ++ Normally kallsyms contains compressed symbols (using a token table), ++ reducing the uncompressed kernel image size. Keeping the symbol table ++ uncompressed significantly improves the size of this part in compressed ++ kernel images. ++ ++ Say N unless you need compressed kernel images to be small. ++ + config HAVE_PCSPKR_PLATFORM + bool + +diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c +index a9a0ca605d4a..82c9b31f5bf3 100644 +--- a/kernel/kallsyms.c ++++ b/kernel/kallsyms.c +@@ -69,6 +69,11 @@ static unsigned int kallsyms_expand_symbol(unsigned int off, + * For every byte on the compressed symbol data, copy the table + * entry for that byte. + */ ++#ifdef CONFIG_KALLSYMS_UNCOMPRESSED ++ memcpy(result, data + 1, len - 1); ++ result += len - 1; ++ len = 0; ++#endif + while (len) { + tptr = &kallsyms_token_table[kallsyms_token_index[*data]]; + data++; +@@ -101,6 +106,9 @@ static unsigned int kallsyms_expand_symbol(unsigned int off, + */ + static char kallsyms_get_symbol_type(unsigned int off) + { ++#ifdef CONFIG_KALLSYMS_UNCOMPRESSED ++ return kallsyms_names[off + 1]; ++#endif + /* + * Get just the first code, look it up in the token table, + * and return the first char from this token. +diff --git a/kernel/vmcore_info.c b/kernel/vmcore_info.c +index 1fec61603ef3..9345ac6cb454 100644 +--- a/kernel/vmcore_info.c ++++ b/kernel/vmcore_info.c +@@ -214,8 +214,10 @@ static int __init crash_save_vmcoreinfo_init(void) + #ifdef CONFIG_KALLSYMS + VMCOREINFO_SYMBOL(kallsyms_names); + VMCOREINFO_SYMBOL(kallsyms_num_syms); ++#ifndef CONFIG_KALLSYMS_UNCOMPRESSED + VMCOREINFO_SYMBOL(kallsyms_token_table); + VMCOREINFO_SYMBOL(kallsyms_token_index); ++#endif + VMCOREINFO_SYMBOL(kallsyms_offsets); + VMCOREINFO_SYMBOL(kallsyms_relative_base); + #endif /* CONFIG_KALLSYMS */ +diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c +index 03852da3d249..0c50cc494850 100644 +--- a/scripts/kallsyms.c ++++ b/scripts/kallsyms.c +@@ -62,6 +62,7 @@ static struct addr_range percpu_range = { + static struct sym_entry **table; + static unsigned int table_size, table_cnt; + static int all_symbols; ++static int uncompressed; + static int absolute_percpu; + + static int token_profit[0x10000]; +@@ -412,13 +413,17 @@ static void write_src(void) + for (k = 0; k < table[i]->len; k++) + printf(", 0x%02x", table[i]->sym[k]); + +- /* +- * Now that we wrote out the compressed symbol name, restore the +- * original name and print it in the comment. +- */ +- expand_symbol(table[i]->sym, table[i]->len, buf); +- strcpy((char *)table[i]->sym, buf); +- printf("\t/* %s */\n", table[i]->sym); ++ if (!uncompressed) { ++ /* ++ * Now that we wrote out the compressed symbol name, restore the ++ * original name and print it in the comment. ++ */ ++ expand_symbol(table[i]->sym, table[i]->len, buf); ++ strcpy((char *)table[i]->sym, buf); ++ printf("\t/* %s */\n", table[i]->sym); ++ } else { ++ printf("\n"); ++ } + } + printf("\n"); + +@@ -429,20 +434,22 @@ static void write_src(void) + + free(markers); + +- output_label("kallsyms_token_table"); +- off = 0; +- for (i = 0; i < 256; i++) { +- best_idx[i] = off; +- expand_symbol(best_table[i], best_table_len[i], buf); +- printf("\t.asciz\t\"%s\"\n", buf); +- off += strlen(buf) + 1; +- } +- printf("\n"); ++ if (!uncompressed) { ++ output_label("kallsyms_token_table"); ++ off = 0; ++ for (i = 0; i < 256; i++) { ++ best_idx[i] = off; ++ expand_symbol(best_table[i], best_table_len[i], buf); ++ printf("\t.asciz\t\"%s\"\n", buf); ++ off += strlen(buf) + 1; ++ } ++ printf("\n"); + +- output_label("kallsyms_token_index"); +- for (i = 0; i < 256; i++) +- printf("\t.short\t%d\n", best_idx[i]); +- printf("\n"); ++ output_label("kallsyms_token_index"); ++ for (i = 0; i < 256; i++) ++ printf("\t.short\t%d\n", best_idx[i]); ++ printf("\n"); ++ } + + output_label("kallsyms_offsets"); + +@@ -532,6 +539,9 @@ static unsigned char *find_token(unsigned char *str, int len, + { + int i; + ++ if (uncompressed) ++ return NULL; ++ + for (i = 0; i < len - 1; i++) { + if (str[i] == token[0] && str[i+1] == token[1]) + return &str[i]; +@@ -604,6 +614,9 @@ static void optimize_result(void) + { + int i, best; + ++ if (uncompressed) ++ return; ++ + /* using the '\0' symbol last allows compress_symbols to use standard + * fast string functions */ + for (i = 255; i >= 0; i--) { +@@ -763,6 +776,7 @@ int main(int argc, char **argv) + static const struct option long_options[] = { + {"all-symbols", no_argument, &all_symbols, 1}, + {"absolute-percpu", no_argument, &absolute_percpu, 1}, ++ {"uncompressed", no_argument, &uncompressed, 1}, + {}, + }; + +diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh +index a9b3f34a78d2..8013f57047b1 100755 +--- a/scripts/link-vmlinux.sh ++++ b/scripts/link-vmlinux.sh +@@ -144,6 +144,10 @@ kallsyms() + kallsymopt="${kallsymopt} --absolute-percpu" + fi + ++ if is_enabled CONFIG_KALLSYMS_UNCOMPRESSED; then ++ kallsymopt="${kallsymopt} --uncompressed" ++ fi ++ + info KSYMS "${2}.S" + scripts/kallsyms ${kallsymopt} "${1}" > "${2}.S" + +-- +2.51.0 + + +From 27f5413d1222b8bde41e5383d85ecf0c9b1db242 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Mon, 3 Nov 2025 15:49:34 +0100 +Subject: [PATCH 191/517] kernel: when KALLSYMS is disabled, print module + address + size for matching backtrace entries + +[john@phrozen.org: felix will add this to his upstream queue] + +lede-commit 53827cdc824556cda910b23ce5030c363b8f1461 +Signed-off-by: Felix Fietkau +--- + lib/vsprintf.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +diff --git a/lib/vsprintf.c b/lib/vsprintf.c +index a69e71a1ca55..5026d8912563 100644 +--- a/lib/vsprintf.c ++++ b/lib/vsprintf.c +@@ -983,8 +983,10 @@ char *symbol_string(char *buf, char *end, void *ptr, + struct printf_spec spec, const char *fmt) + { + unsigned long value; +-#ifdef CONFIG_KALLSYMS + char sym[KSYM_SYMBOL_LEN]; ++#ifndef CONFIG_KALLSYMS ++ struct module *mod; ++ int len; + #endif + + if (fmt[1] == 'R') +@@ -1005,8 +1007,14 @@ char *symbol_string(char *buf, char *end, void *ptr, + + return string_nocheck(buf, end, sym, spec); + #else +- return special_hex_number(buf, end, value, sizeof(void *)); ++ len = snprintf(sym, sizeof(sym), "0x%lx", value); ++ mod = __module_address(value); ++ if (mod) ++ snprintf(sym + len, sizeof(sym) - len, " [%s@%p+0x%x]", ++ mod->name, mod->mem[MOD_TEXT].base, ++ mod->mem[MOD_TEXT].size); + #endif ++ return string(buf, end, sym, spec); + } + + static const struct printf_spec default_str_spec = { +-- +2.51.0 + + +From 30746abd35d5550aed9f5b0152ebece730c5a889 Mon Sep 17 00:00:00 2001 +From: Gabor Juhos +Date: Mon, 3 Nov 2025 15:49:34 +0100 +Subject: [PATCH 192/517] usr: sanitize deps_initramfs list + +If any filename in the intramfs dependency +list contains a colon, that causes a kernel +build error like this: + +/devel/openwrt/build_dir/linux-ar71xx_generic/linux-3.6.6/usr/Makefile:58: *** multiple target patterns. Stop. +make[5]: *** [usr] Error 2 + +Fix it by removing such filenames from the +deps_initramfs list. + +Signed-off-by: Gabor Juhos +Signed-off-by: Felix Fietkau +--- + usr/Makefile | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/usr/Makefile b/usr/Makefile +index f1779496bca7..90398a751588 100644 +--- a/usr/Makefile ++++ b/usr/Makefile +@@ -56,6 +56,8 @@ hostprogs := gen_init_cpio + # The dependency list is generated by gen_initramfs.sh -l + -include $(obj)/.initramfs_data.cpio.d + ++deps_initramfs := $(foreach v,$(deps_initramfs),$(if $(findstring :,$(v)),,$(v))) ++ + # do not try to update files included in initramfs + $(deps_initramfs): ; + +-- +2.51.0 + + +From 49d8ded1302b4decccc20ce90bc53db1b63a2107 Mon Sep 17 00:00:00 2001 +From: Hauke Mehrtens +Date: Fri, 27 Jun 2025 11:09:04 +0100 +Subject: [PATCH 193/517] kernel/fork: Increase minimum number of allowed + threads + +A modern Linux system creates much more than 20 threads at bootup. +When I booted up OpenWrt in qemu the system sometimes failed to boot up +when it wanted to create the 419th thread. The VM had 128MB RAM and the +calculation in set_max_threads() calculated that max_threads should be +set to 419. When the system booted up it tried to notify the user space +about every device it created because CONFIG_UEVENT_HELPER was set and +used. I counted 1299 calls to call_usermodehelper_setup(), all of +them try to create a new thread and call the userspace hotplug script in +it. + +This fixes bootup of Linux on systems with low memory. + +I saw the problem with qemu 10.0.2 using these commands: +qemu-system-aarch64 -machine virt -cpu cortex-a57 -nographic + +Cc: stable@vger.kernel.org +Signed-off-by: Hauke Mehrtens +--- + kernel/fork.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/fork.c b/kernel/fork.c +index e5ec098a6f61..4e2c63a1e737 100644 +--- a/kernel/fork.c ++++ b/kernel/fork.c +@@ -123,7 +123,7 @@ + /* + * Minimum number of threads to boot the kernel + */ +-#define MIN_THREADS 20 ++#define MIN_THREADS 600 + + /* + * Maximum number of threads +-- +2.51.0 + + +From 2efc136e2a89b64cb447127e0ebc0624a54e79f6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Thibaut=20VAR=C3=88NE?= +Date: Sat, 28 Mar 2020 12:11:50 +0100 +Subject: [PATCH 194/517] generic: platform/mikrotik build bits (5.4) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This patch adds platform/mikrotik kernel build bits + +Signed-off-by: Thibaut VARÈNE +--- + drivers/platform/Kconfig | 2 ++ + drivers/platform/Makefile | 1 + + 2 files changed, 3 insertions(+) + +diff --git a/drivers/platform/Kconfig b/drivers/platform/Kconfig +index 960fd6a82450..ca7df46dcfd7 100644 +--- a/drivers/platform/Kconfig ++++ b/drivers/platform/Kconfig +@@ -18,3 +18,5 @@ source "drivers/platform/surface/Kconfig" + source "drivers/platform/x86/Kconfig" + + source "drivers/platform/arm64/Kconfig" ++ ++source "drivers/platform/mikrotik/Kconfig" +diff --git a/drivers/platform/Makefile b/drivers/platform/Makefile +index 19ac54648586..b77585bdc5cf 100644 +--- a/drivers/platform/Makefile ++++ b/drivers/platform/Makefile +@@ -13,3 +13,4 @@ obj-$(CONFIG_CHROME_PLATFORMS) += chrome/ + obj-$(CONFIG_CZNIC_PLATFORMS) += cznic/ + obj-$(CONFIG_SURFACE_PLATFORMS) += surface/ + obj-$(CONFIG_ARM64_PLATFORM_DEVICES) += arm64/ ++obj-$(CONFIG_MIKROTIK) += mikrotik/ +-- +2.51.0 + + +From 1db3bd42bc37da847f5708ddaea12d9e1dc1c667 Mon Sep 17 00:00:00 2001 +From: Mark Miller +Date: Mon, 3 Nov 2025 15:49:35 +0100 +Subject: [PATCH 195/517] mips: expose CONFIG_BOOT_RAW + +This exposes the CONFIG_BOOT_RAW symbol in Kconfig. This is needed on +certain Broadcom chipsets running CFE in order to load the kernel. + +Signed-off-by: Mark Miller +Acked-by: Rob Landley +--- + arch/mips/Kconfig | 15 ++++++++++++--- + 1 file changed, 12 insertions(+), 3 deletions(-) + +diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig +index 5078ebf071ec..a330c7152049 100644 +--- a/arch/mips/Kconfig ++++ b/arch/mips/Kconfig +@@ -1055,9 +1055,6 @@ config FW_ARC + config ARCH_MAY_HAVE_PC_FDC + bool + +-config BOOT_RAW +- bool +- + config CEVT_BCM1480 + bool + +@@ -2990,6 +2987,18 @@ choice + bool "Extend builtin kernel arguments with bootloader arguments" + endchoice + ++config BOOT_RAW ++ bool "Enable the kernel to be executed from the load address" ++ default n ++ help ++ Allow the kernel to be executed from the load address for ++ bootloaders which cannot read the ELF format. This places ++ a jump to start_kernel at the load address. ++ ++ If unsure, say N. ++ ++ ++ + endmenu + + config LOCKDEP_SUPPORT +-- +2.51.0 + + +From cab68d173bcc34e6e4d7cfec9c69bb102bd5a6a9 Mon Sep 17 00:00:00 2001 +From: Paul Burton +Date: Mon, 22 Feb 2016 18:09:44 +0000 +Subject: [PATCH 196/517] MIPS: Add barriers between dcache & icache flushes + +Index-based cache operations may be arbitrarily reordered by out of +order CPUs. Thus code which writes back the dcache & then invalidates +the icache using indexed cache ops must include a barrier between +operating on the 2 caches in order to prevent the scenario in which: + + - icache invalidation occurs. + + - icache fetch occurs, due to speculation. + + - dcache writeback occurs. + +If the above were allowed to happen then the icache would contain stale +data. Forcing the dcache writeback to complete before the icache +invalidation avoids this. + +Signed-off-by: Paul Burton +Cc: James Hogan +--- + arch/mips/mm/c-r4k.c | 13 +++++++++++-- + 1 file changed, 11 insertions(+), 2 deletions(-) + +diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c +index 10413b6f6662..8e263048280f 100644 +--- a/arch/mips/mm/c-r4k.c ++++ b/arch/mips/mm/c-r4k.c +@@ -403,6 +403,7 @@ static inline void local_r4k___flush_cache_all(void * args) + + default: + r4k_blast_dcache(); ++ mb(); /* cache instructions may be reordered */ + r4k_blast_icache(); + break; + } +@@ -483,8 +484,10 @@ static inline void local_r4k_flush_cache_range(void * args) + if (cpu_has_dc_aliases || (exec && !cpu_has_ic_fills_f_dc)) + r4k_blast_dcache(); + /* If executable, blast stale lines from icache */ +- if (exec) ++ if (exec) { ++ mb(); /* cache instructions may be reordered */ + r4k_blast_icache(); ++ } + } + + static void r4k_flush_cache_range(struct vm_area_struct *vma, +@@ -586,8 +589,13 @@ static inline void local_r4k_flush_cache_page(void *args) + if (cpu_has_dc_aliases || (exec && !cpu_has_ic_fills_f_dc)) { + vaddr ? r4k_blast_dcache_page(addr) : + r4k_blast_dcache_user_page(addr); +- if (exec && !cpu_icache_snoops_remote_store) ++ if (exec) ++ mb(); /* cache instructions may be reordered */ ++ ++ if (exec && !cpu_icache_snoops_remote_store) { + r4k_blast_scache_page(addr); ++ mb(); /* cache instructions may be reordered */ ++ } + } + if (exec) { + if (vaddr && cpu_has_vtag_icache && mm == current->active_mm) { +@@ -654,6 +662,7 @@ static inline void __local_r4k_flush_icache_range(unsigned long start, + else + blast_dcache_range(start, end); + } ++ mb(); /* cache instructions may be reordered */ + } + + if (type == R4K_INDEX || +-- +2.51.0 + + +From 554dfd27393451b9120c52c5712714b3c1adf213 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Mon, 3 Nov 2025 15:49:36 +0100 +Subject: [PATCH 197/517] mips: use -mno-branch-likely for kernel and userspace + +saves ~11k kernel size after lzma and ~12k squashfs size in the + +lede-commit: 41a039f46450ffae9483d6216422098669da2900 +Signed-off-by: Felix Fietkau +--- + arch/mips/Makefile | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/mips/Makefile b/arch/mips/Makefile +index 5785a3d5ccfb..3e673b4a4a72 100644 +--- a/arch/mips/Makefile ++++ b/arch/mips/Makefile +@@ -94,7 +94,7 @@ all-$(CONFIG_SYS_SUPPORTS_ZBOOT)+= vmlinuz + # machines may also. Since BFD is incredibly buggy with respect to + # crossformat linking we rely on the elf2ecoff tool for format conversion. + # +-cflags-y += -G 0 -mno-abicalls -fno-pic -pipe ++cflags-y += -G 0 -mno-abicalls -fno-pic -pipe -mno-branch-likely + cflags-y += -msoft-float -Wa,-msoft-float + LDFLAGS_vmlinux += -G 0 -static -n -nostdlib + KBUILD_AFLAGS_MODULE += -mlong-calls +-- +2.51.0 + + +From 7c5fa3df92251694f8253c39f0ee00b486676db5 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Mon, 3 Nov 2025 15:49:36 +0100 +Subject: [PATCH 198/517] kernel: add -mtune=34kc to MIPS CFLAGS when building + for mips32r2 + +This provides a good tradeoff across at least 24Kc-74Kc, while also +producing smaller code. + +Signed-off-by: Felix Fietkau +--- + arch/mips/Makefile | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/mips/Makefile b/arch/mips/Makefile +index 3e673b4a4a72..2a770f13a0cc 100644 +--- a/arch/mips/Makefile ++++ b/arch/mips/Makefile +@@ -153,7 +153,7 @@ cflags-$(CONFIG_CPU_R4300) += $(call cc-option,-march=r4300,-march=mips3) -Wa,-- + cflags-$(CONFIG_CPU_R4X00) += $(call cc-option,-march=r4600,-march=mips3) -Wa,--trap + cflags-$(CONFIG_CPU_TX49XX) += $(call cc-option,-march=r4600,-march=mips3) -Wa,--trap + cflags-$(CONFIG_CPU_MIPS32_R1) += -march=mips32 -Wa,--trap +-cflags-$(CONFIG_CPU_MIPS32_R2) += -march=mips32r2 -Wa,--trap ++cflags-$(CONFIG_CPU_MIPS32_R2) += -march=mips32r2 -mtune=34kc -Wa,--trap + cflags-$(CONFIG_CPU_MIPS32_R5) += -march=mips32r5 -Wa,--trap -modd-spreg + cflags-$(CONFIG_CPU_MIPS32_R6) += -march=mips32r6 -Wa,--trap -modd-spreg + cflags-$(CONFIG_CPU_MIPS64_R1) += -march=mips64 -Wa,--trap +-- +2.51.0 + + +From ace85c5c8e52425cb032edeba73b212530ee01f3 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Mon, 3 Nov 2025 15:49:36 +0100 +Subject: [PATCH 199/517] fix errors in unresolved weak symbols on arm + +lede-commit: 570699d4838a907c3ef9f2819bf19eb72997b32f +Signed-off-by: Felix Fietkau +--- + arch/arm/kernel/module.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/arch/arm/kernel/module.c b/arch/arm/kernel/module.c +index da488d92e7a0..2c4772fc494d 100644 +--- a/arch/arm/kernel/module.c ++++ b/arch/arm/kernel/module.c +@@ -112,6 +112,10 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex, + return -ENOEXEC; + } + ++ if ((IS_ERR_VALUE(sym->st_value) || !sym->st_value) && ++ ELF_ST_BIND(sym->st_info) == STB_WEAK) ++ continue; ++ + loc = dstsec->sh_addr + rel->r_offset; + + switch (ELF32_R_TYPE(rel->r_info)) { +-- +2.51.0 + + +From 52f2fac4a7eb8fb01f41028391e9f5686c11ecb6 Mon Sep 17 00:00:00 2001 +From: Yousong Zhou +Date: Mon, 3 Nov 2025 15:49:37 +0100 +Subject: [PATCH 200/517] MIPS: kexec: Accept command line parameters from + userspace. + +Signed-off-by: Yousong Zhou +--- + arch/mips/kernel/machine_kexec.c | 140 ++++++++++++++++++++++++++--- + arch/mips/kernel/machine_kexec.h | 20 +++++ + arch/mips/kernel/relocate_kernel.S | 20 +++-- + 3 files changed, 162 insertions(+), 18 deletions(-) + create mode 100644 arch/mips/kernel/machine_kexec.h + +diff --git a/arch/mips/kernel/machine_kexec.c b/arch/mips/kernel/machine_kexec.c +index 4e3579bbd620..528880faad34 100644 +--- a/arch/mips/kernel/machine_kexec.c ++++ b/arch/mips/kernel/machine_kexec.c +@@ -10,14 +10,11 @@ + #include + #include + ++#include + #include + #include +- +-extern const unsigned char relocate_new_kernel[]; +-extern const size_t relocate_new_kernel_size; +- +-extern unsigned long kexec_start_address; +-extern unsigned long kexec_indirection_page; ++#include ++#include "machine_kexec.h" + + static unsigned long reboot_code_buffer; + +@@ -31,6 +28,101 @@ void (*_crash_smp_send_stop)(void) = NULL; + void (*_machine_kexec_shutdown)(void) = NULL; + void (*_machine_crash_shutdown)(struct pt_regs *regs) = NULL; + ++static void machine_kexec_print_args(void) ++{ ++ unsigned long argc = (int)kexec_args[0]; ++ int i; ++ ++ pr_info("kexec_args[0] (argc): %lu\n", argc); ++ pr_info("kexec_args[1] (argv): %p\n", (void *)kexec_args[1]); ++ pr_info("kexec_args[2] (env ): %p\n", (void *)kexec_args[2]); ++ pr_info("kexec_args[3] (desc): %p\n", (void *)kexec_args[3]); ++ ++ for (i = 0; i < argc; i++) { ++ pr_info("kexec_argv[%d] = %p, %s\n", ++ i, kexec_argv[i], kexec_argv[i]); ++ } ++} ++ ++static void machine_kexec_init_argv(struct kimage *image) ++{ ++ void __user *buf = NULL; ++ size_t bufsz; ++ size_t size; ++ int i; ++ ++ bufsz = 0; ++ for (i = 0; i < image->nr_segments; i++) { ++ struct kexec_segment *seg; ++ ++ seg = &image->segment[i]; ++ if (seg->bufsz < 6) ++ continue; ++ ++ if (strncmp((char *) seg->buf, "kexec ", 6)) ++ continue; ++ ++ buf = seg->buf; ++ bufsz = seg->bufsz; ++ break; ++ } ++ ++ if (!buf) ++ return; ++ ++ size = KEXEC_COMMAND_LINE_SIZE; ++ size = min(size, bufsz); ++ if (size < bufsz) ++ pr_warn("kexec command line truncated to %zd bytes\n", size); ++ ++ /* Copy to kernel space */ ++ if (copy_from_user(kexec_argv_buf, buf, size)) ++ pr_warn("kexec command line copy to kernel space failed\n"); ++ ++ kexec_argv_buf[size - 1] = 0; ++} ++ ++static void machine_kexec_parse_argv(struct kimage *image) ++{ ++ char *reboot_code_buffer; ++ int reloc_delta; ++ char *ptr; ++ int argc; ++ int i; ++ ++ ptr = kexec_argv_buf; ++ argc = 0; ++ ++ /* ++ * convert command line string to array of parameters ++ * (as bootloader does). ++ */ ++ while (ptr && *ptr && (KEXEC_MAX_ARGC > argc)) { ++ if (*ptr == ' ') { ++ *ptr++ = '\0'; ++ continue; ++ } ++ ++ kexec_argv[argc++] = ptr; ++ ptr = strchr(ptr, ' '); ++ } ++ ++ if (!argc) ++ return; ++ ++ kexec_args[0] = argc; ++ kexec_args[1] = (unsigned long)kexec_argv; ++ kexec_args[2] = 0; ++ kexec_args[3] = 0; ++ ++ reboot_code_buffer = page_address(image->control_code_page); ++ reloc_delta = reboot_code_buffer - (char *)kexec_relocate_new_kernel; ++ ++ kexec_args[1] += reloc_delta; ++ for (i = 0; i < argc; i++) ++ kexec_argv[i] += reloc_delta; ++} ++ + static void kexec_image_info(const struct kimage *kimage) + { + unsigned long i; +@@ -100,6 +192,18 @@ machine_kexec_prepare(struct kimage *kimage) + #endif + + kexec_image_info(kimage); ++ /* ++ * Whenever arguments passed from kexec-tools, Init the arguments as ++ * the original ones to try avoiding booting failure. ++ */ ++ ++ kexec_args[0] = fw_arg0; ++ kexec_args[1] = fw_arg1; ++ kexec_args[2] = fw_arg2; ++ kexec_args[3] = fw_arg3; ++ ++ machine_kexec_init_argv(kimage); ++ machine_kexec_parse_argv(kimage); + + if (_machine_kexec_prepare) + return _machine_kexec_prepare(kimage); +@@ -162,7 +266,7 @@ machine_crash_shutdown(struct pt_regs *regs) + void kexec_nonboot_cpu_jump(void) + { + local_flush_icache_range((unsigned long)relocated_kexec_smp_wait, +- reboot_code_buffer + relocate_new_kernel_size); ++ reboot_code_buffer + KEXEC_RELOCATE_NEW_KERNEL_SIZE); + + relocated_kexec_smp_wait(NULL); + } +@@ -200,7 +304,7 @@ void kexec_reboot(void) + * machine_kexec() CPU. + */ + local_flush_icache_range(reboot_code_buffer, +- reboot_code_buffer + relocate_new_kernel_size); ++ reboot_code_buffer + KEXEC_RELOCATE_NEW_KERNEL_SIZE); + + do_kexec = (void *)reboot_code_buffer; + do_kexec(); +@@ -213,10 +317,12 @@ machine_kexec(struct kimage *image) + unsigned long *ptr; + + reboot_code_buffer = +- (unsigned long)page_address(image->control_code_page); ++ (unsigned long)page_address(image->control_code_page); ++ pr_info("reboot_code_buffer = %p\n", (void *)reboot_code_buffer); + + kexec_start_address = + (unsigned long) phys_to_virt(image->start); ++ pr_info("kexec_start_address = %p\n", (void *)kexec_start_address); + + if (image->type == KEXEC_TYPE_DEFAULT) { + kexec_indirection_page = +@@ -224,9 +330,19 @@ machine_kexec(struct kimage *image) + } else { + kexec_indirection_page = (unsigned long)&image->head; + } ++ pr_info("kexec_indirection_page = %p\n", (void *)kexec_indirection_page); ++ ++ pr_info("Where is memcpy: %p\n", memcpy); ++ pr_info("kexec_relocate_new_kernel = %p, kexec_relocate_new_kernel_end = %p\n", ++ (void *)kexec_relocate_new_kernel, &kexec_relocate_new_kernel_end); ++ pr_info("Copy %lu bytes from %p to %p\n", KEXEC_RELOCATE_NEW_KERNEL_SIZE, ++ (void *)kexec_relocate_new_kernel, (void *)reboot_code_buffer); ++ memcpy((void*)reboot_code_buffer, kexec_relocate_new_kernel, ++ KEXEC_RELOCATE_NEW_KERNEL_SIZE); + +- memcpy((void*)reboot_code_buffer, relocate_new_kernel, +- relocate_new_kernel_size); ++ pr_info("Before _print_args().\n"); ++ machine_kexec_print_args(); ++ pr_info("Before eval loop.\n"); + + /* + * The generic kexec code builds a page list with physical +@@ -257,7 +373,7 @@ machine_kexec(struct kimage *image) + #ifdef CONFIG_SMP + /* All secondary cpus now may jump to kexec_wait cycle */ + relocated_kexec_smp_wait = reboot_code_buffer + +- (void *)(kexec_smp_wait - relocate_new_kernel); ++ (void *)(kexec_smp_wait - kexec_relocate_new_kernel); + smp_wmb(); + atomic_set(&kexec_ready_to_reboot, 1); + #endif +diff --git a/arch/mips/kernel/machine_kexec.h b/arch/mips/kernel/machine_kexec.h +new file mode 100644 +index 000000000000..ae0961e29820 +--- /dev/null ++++ b/arch/mips/kernel/machine_kexec.h +@@ -0,0 +1,20 @@ ++#ifndef _MACHINE_KEXEC_H ++#define _MACHINE_KEXEC_H ++ ++#ifndef __ASSEMBLY__ ++extern const unsigned char kexec_relocate_new_kernel[]; ++extern unsigned long kexec_relocate_new_kernel_end; ++extern unsigned long kexec_start_address; ++extern unsigned long kexec_indirection_page; ++ ++extern char kexec_argv_buf[]; ++extern char *kexec_argv[]; ++ ++#define KEXEC_RELOCATE_NEW_KERNEL_SIZE ((unsigned long)&kexec_relocate_new_kernel_end - (unsigned long)kexec_relocate_new_kernel) ++#endif /* !__ASSEMBLY__ */ ++ ++#define KEXEC_COMMAND_LINE_SIZE 256 ++#define KEXEC_ARGV_SIZE (KEXEC_COMMAND_LINE_SIZE / 16) ++#define KEXEC_MAX_ARGC (KEXEC_ARGV_SIZE / sizeof(long)) ++ ++#endif +diff --git a/arch/mips/kernel/relocate_kernel.S b/arch/mips/kernel/relocate_kernel.S +index de894a0211d7..a43c683cfd2b 100644 +--- a/arch/mips/kernel/relocate_kernel.S ++++ b/arch/mips/kernel/relocate_kernel.S +@@ -10,10 +10,11 @@ + #include + #include + #include ++#include "machine_kexec.h" + + #include + +-LEAF(relocate_new_kernel) ++LEAF(kexec_relocate_new_kernel) + PTR_L a0, arg0 + PTR_L a1, arg1 + PTR_L a2, arg2 +@@ -97,7 +98,7 @@ done: + #endif + /* jump to kexec_start_address */ + j s1 +- END(relocate_new_kernel) ++ END(kexec_relocate_new_kernel) + + #ifdef CONFIG_SMP + /* +@@ -176,8 +177,15 @@ EXPORT(kexec_indirection_page) + PTR_WD 0 + .size kexec_indirection_page, PTRSIZE + +-relocate_new_kernel_end: ++kexec_argv_buf: ++ EXPORT(kexec_argv_buf) ++ .skip KEXEC_COMMAND_LINE_SIZE ++ .size kexec_argv_buf, KEXEC_COMMAND_LINE_SIZE + +-EXPORT(relocate_new_kernel_size) +- PTR_WD relocate_new_kernel_end - relocate_new_kernel +- .size relocate_new_kernel_size, PTRSIZE ++kexec_argv: ++ EXPORT(kexec_argv) ++ .skip KEXEC_ARGV_SIZE ++ .size kexec_argv, KEXEC_ARGV_SIZE ++ ++kexec_relocate_new_kernel_end: ++ EXPORT(kexec_relocate_new_kernel_end) +-- +2.51.0 + + +From 5c80cdad5775fcd000f09a0bc2895dd3c6140644 Mon Sep 17 00:00:00 2001 +From: Evgeniy Didin +Date: Fri, 15 Mar 2019 18:53:38 +0300 +Subject: [PATCH 201/517] arc add OWRTDTB section + +This change allows OpenWRT to patch resulting kernel binary with +external .dtb. + +That allows us to re-use exactky the same vmlinux on different boards +given its ARC core configurations match (at least cache line sizes etc). + +""patch-dtb" searches for ASCII "OWRTDTB:" strign and copies external +.dtb right after it, keeping the string in place. + +Signed-off-by: Eugeniy Paltsev +Signed-off-by: Alexey Brodkin +Signed-off-by: Evgeniy Didin +--- + arch/arc/kernel/head.S | 10 ++++++++++ + arch/arc/kernel/setup.c | 4 +++- + arch/arc/kernel/vmlinux.lds.S | 13 +++++++++++++ + 3 files changed, 26 insertions(+), 1 deletion(-) + +diff --git a/arch/arc/kernel/head.S b/arch/arc/kernel/head.S +index 8d541f53fae3..c37f130c4bcc 100644 +--- a/arch/arc/kernel/head.S ++++ b/arch/arc/kernel/head.S +@@ -88,6 +88,16 @@ + DSP_EARLY_INIT + .endm + ++ ; Here "patch-dtb" will embed external .dtb ++ ; Note "patch-dtb" searches for ASCII "OWRTDTB:" string ++ ; and pastes .dtb right after it, hense the string precedes ++ ; __image_dtb symbol. ++ .section .owrt, "aw",@progbits ++ .ascii "OWRTDTB:" ++ENTRY(__image_dtb) ++ .fill 0x4000 ++END(__image_dtb) ++ + .section .init.text, "ax",@progbits + + ;---------------------------------------------------------------- +diff --git a/arch/arc/kernel/setup.c b/arch/arc/kernel/setup.c +index 7b6a9beba9db..0d07dfea5c00 100644 +--- a/arch/arc/kernel/setup.c ++++ b/arch/arc/kernel/setup.c +@@ -450,6 +450,8 @@ static inline bool uboot_arg_invalid(unsigned long addr) + /* We always pass 0 as magic from U-boot */ + #define UBOOT_MAGIC_VALUE 0 + ++extern struct boot_param_header __image_dtb; ++ + void __init handle_uboot_args(void) + { + bool use_embedded_dtb = true; +@@ -488,7 +490,7 @@ void __init handle_uboot_args(void) + ignore_uboot_args: + + if (use_embedded_dtb) { +- machine_desc = setup_machine_fdt(__dtb_start); ++ machine_desc = setup_machine_fdt(&__image_dtb); + if (!machine_desc) + panic("Embedded DT invalid\n"); + } +diff --git a/arch/arc/kernel/vmlinux.lds.S b/arch/arc/kernel/vmlinux.lds.S +index 61a1b2b96e1d..eef52a1711dd 100644 +--- a/arch/arc/kernel/vmlinux.lds.S ++++ b/arch/arc/kernel/vmlinux.lds.S +@@ -27,6 +27,19 @@ SECTIONS + + . = CONFIG_LINUX_LINK_BASE; + ++ /* ++ * In OpenWRT we want to patch built binary embedding .dtb of choice. ++ * This is implemented with "patch-dtb" utility which searches for ++ * "OWRTDTB:" string in first 16k of image and if it is found ++ * copies .dtb right after mentioned string. ++ * ++ * Note: "OWRTDTB:" won't be overwritten with .dtb, .dtb will follow it. ++ */ ++ .owrt : { ++ *(.owrt) ++ . = ALIGN(PAGE_SIZE); ++ } ++ + _int_vec_base_lds = .; + .vector : { + *(.vector) +-- +2.51.0 + + +From f935ead65589a7cd7b0ad26c3927095d6431cc61 Mon Sep 17 00:00:00 2001 +From: Alexey Brodkin +Date: Mon, 3 Nov 2025 15:49:37 +0100 +Subject: [PATCH 202/517] arc: enable unaligned access in kernel mode + +This enables misaligned access handling even in kernel mode. +Some wireless drivers (ath9k-htc and mt7601u) use misaligned accesses +here and there and to cope with that without fixing stuff in the drivers +we're just gracefully handling it on ARC. + +Signed-off-by: Alexey Brodkin +--- + arch/arc/kernel/unaligned.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arc/kernel/unaligned.c b/arch/arc/kernel/unaligned.c +index d2f5ceaaed1b..691db93b7808 100644 +--- a/arch/arc/kernel/unaligned.c ++++ b/arch/arc/kernel/unaligned.c +@@ -203,7 +203,7 @@ int misaligned_fixup(unsigned long address, struct pt_regs *regs, + char buf[TASK_COMM_LEN]; + + /* handle user mode only and only if enabled by sysadmin */ +- if (!user_mode(regs) || !unaligned_enabled) ++ if (!unaligned_enabled) + return 1; + + if (no_unaligned_warning) { +-- +2.51.0 + + +From 1bcfd87046f51fc0cee1585efd6503f2ab964de2 Mon Sep 17 00:00:00 2001 +From: Pawel Dembicki +Date: Fri, 24 May 2019 17:56:19 +0200 +Subject: [PATCH 203/517] powerpc: Enable kernel XZ compression option on + PPC_85xx + +Enable kernel XZ compression option on PPC_85xx. Tested with +simpleImage on TP-Link TL-WDR4900 (Freescale P1014 processor). + +Suggested-by: Christian Lamparter +Signed-off-by: Pawel Dembicki +--- + arch/powerpc/Kconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig +index c7b420d6787c..3ac7c2b165bf 100644 +--- a/arch/powerpc/Kconfig ++++ b/arch/powerpc/Kconfig +@@ -254,7 +254,7 @@ config PPC + select HAVE_KERNEL_GZIP + select HAVE_KERNEL_LZMA if DEFAULT_UIMAGE + select HAVE_KERNEL_LZO if DEFAULT_UIMAGE +- select HAVE_KERNEL_XZ if PPC_BOOK3S || 44x ++ select HAVE_KERNEL_XZ if PPC_BOOK3S || 44x || PPC_85xx + select HAVE_KPROBES + select HAVE_KPROBES_ON_FTRACE + select HAVE_KRETPROBES +-- +2.51.0 + + +From 1d71b6137b632023a25f974e578be3d2c522c4d7 Mon Sep 17 00:00:00 2001 +From: Shiji Yang +Date: Wed, 13 Mar 2024 20:28:37 +0800 +Subject: [PATCH 204/517] mips: kernel: fix detect_memory_region() function + +1. Do not use memcmp() on unallocated memory, as the new introduced + fortify dynamic object size check[1] will report unexpected result. +2. Use a fixed pattern instead of a random function pointer as the + magic value. +3. Flip magic value and double check it. +4. Enable this feature only for 32-bit CPUs. Currently, only ath79 and + ralink CPUs are using it. + +[1] 439a1bcac648 ("fortify: Use __builtin_dynamic_object_size() when available") +Signed-off-by: Shiji Yang +--- + arch/mips/include/asm/bootinfo.h | 2 ++ + arch/mips/kernel/setup.c | 17 ++++++++++++----- + 2 files changed, 14 insertions(+), 5 deletions(-) + +diff --git a/arch/mips/include/asm/bootinfo.h b/arch/mips/include/asm/bootinfo.h +index 2128ba903391..8516c11916a4 100644 +--- a/arch/mips/include/asm/bootinfo.h ++++ b/arch/mips/include/asm/bootinfo.h +@@ -93,7 +93,9 @@ const char *get_system_type(void); + + extern unsigned long mips_machtype; + ++#ifndef CONFIG_64BIT + extern void detect_memory_region(phys_addr_t start, phys_addr_t sz_min, phys_addr_t sz_max); ++#endif + + extern void prom_init(void); + extern void prom_free_prom_memory(void); +diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c +index 12a1a4ffb602..3a3bc1b7e62e 100644 +--- a/arch/mips/kernel/setup.c ++++ b/arch/mips/kernel/setup.c +@@ -86,21 +86,27 @@ static struct resource bss_resource = { .name = "Kernel bss", }; + unsigned long __kaslr_offset __ro_after_init; + EXPORT_SYMBOL(__kaslr_offset); + +-static void *detect_magic __initdata = detect_memory_region; +- + #ifdef CONFIG_MIPS_AUTO_PFN_OFFSET + unsigned long ARCH_PFN_OFFSET; + EXPORT_SYMBOL(ARCH_PFN_OFFSET); + #endif + ++#ifndef CONFIG_64BIT ++static u32 detect_magic __initdata; ++#define MIPS_MEM_TEST_PATTERN 0xaa5555aa ++ + void __init detect_memory_region(phys_addr_t start, phys_addr_t sz_min, phys_addr_t sz_max) + { +- void *dm = &detect_magic; ++ void *dm = (void *)KSEG1ADDR(&detect_magic); + phys_addr_t size; + + for (size = sz_min; size < sz_max; size <<= 1) { +- if (!memcmp(dm, dm + size, sizeof(detect_magic))) +- break; ++ __raw_writel(MIPS_MEM_TEST_PATTERN, dm); ++ if (__raw_readl(dm) == __raw_readl(dm + size)) { ++ __raw_writel(~MIPS_MEM_TEST_PATTERN, dm); ++ if (__raw_readl(dm) == __raw_readl(dm + size)) ++ break; ++ } + } + + pr_debug("Memory: %lluMB of RAM detected at 0x%llx (min: %lluMB, max: %lluMB)\n", +@@ -111,6 +117,7 @@ void __init detect_memory_region(phys_addr_t start, phys_addr_t sz_min, phys_add + + memblock_add(start, size); + } ++#endif /* CONFIG_64BIT */ + + /* + * Manage initrd +-- +2.51.0 + + +From ee65cfab6741cd60ae4734b50f82919a58205ae2 Mon Sep 17 00:00:00 2001 +From: OpenWrt community +Date: Wed, 13 Jul 2022 11:47:35 +0200 +Subject: [PATCH 205/517] mtd: mtdsplit support + +--- + drivers/mtd/Kconfig | 19 ++++ + drivers/mtd/Makefile | 2 + + drivers/mtd/mtdpart.c | 170 ++++++++++++++++++++++++++++----- + include/linux/mtd/mtd.h | 25 +++++ + include/linux/mtd/partitions.h | 7 ++ + 5 files changed, 198 insertions(+), 25 deletions(-) + +diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig +index 796a2eccbef0..f9ed93c4cf0f 100644 +--- a/drivers/mtd/Kconfig ++++ b/drivers/mtd/Kconfig +@@ -12,6 +12,25 @@ menuconfig MTD + + if MTD + ++menu "OpenWrt specific MTD options" ++ ++config MTD_ROOTFS_ROOT_DEV ++ bool "Automatically set 'rootfs' partition to be root filesystem" ++ default y ++ ++config MTD_SPLIT_FIRMWARE ++ bool "Automatically split firmware partition for kernel+rootfs" ++ default y ++ ++config MTD_SPLIT_FIRMWARE_NAME ++ string "Firmware partition name" ++ depends on MTD_SPLIT_FIRMWARE ++ default "firmware" ++ ++source "drivers/mtd/mtdsplit/Kconfig" ++ ++endmenu ++ + config MTD_TESTS + tristate "MTD tests support (DANGEROUS)" + depends on m +diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile +index 593d0593a038..b14b7fe0f597 100644 +--- a/drivers/mtd/Makefile ++++ b/drivers/mtd/Makefile +@@ -9,6 +9,8 @@ mtd-y := mtdcore.o mtdsuper.o mtdconcat.o mtdpart.o mtdchar.o + + obj-y += parsers/ + ++obj-$(CONFIG_MTD_SPLIT) += mtdsplit/ ++ + # 'Users' - code which presents functionality to userspace. + obj-$(CONFIG_MTD_BLKDEVS) += mtd_blkdevs.o + obj-$(CONFIG_MTD_BLOCK) += mtdblock.o +diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c +index 6811a714349d..10ae49b9702a 100644 +--- a/drivers/mtd/mtdpart.c ++++ b/drivers/mtd/mtdpart.c +@@ -15,11 +15,13 @@ + #include + #include + #include ++#include + #include + #include + #include + + #include "mtdcore.h" ++#include "mtdsplit/mtdsplit.h" + + /* + * MTD methods which simply translate the effective address and pass through +@@ -242,6 +244,147 @@ static int mtd_add_partition_attrs(struct mtd_info *new) + return ret; + } + ++static DEFINE_SPINLOCK(part_parser_lock); ++static LIST_HEAD(part_parsers); ++ ++static struct mtd_part_parser *mtd_part_parser_get(const char *name) ++{ ++ struct mtd_part_parser *p, *ret = NULL; ++ ++ spin_lock(&part_parser_lock); ++ ++ list_for_each_entry(p, &part_parsers, list) ++ if (!strcmp(p->name, name) && try_module_get(p->owner)) { ++ ret = p; ++ break; ++ } ++ ++ spin_unlock(&part_parser_lock); ++ ++ return ret; ++} ++ ++static inline void mtd_part_parser_put(const struct mtd_part_parser *p) ++{ ++ module_put(p->owner); ++} ++ ++static struct mtd_part_parser * ++get_partition_parser_by_type(enum mtd_parser_type type, ++ struct mtd_part_parser *start) ++{ ++ struct mtd_part_parser *p, *ret = NULL; ++ ++ spin_lock(&part_parser_lock); ++ ++ p = list_prepare_entry(start, &part_parsers, list); ++ if (start) ++ mtd_part_parser_put(start); ++ ++ list_for_each_entry_continue(p, &part_parsers, list) { ++ if (p->type == type && try_module_get(p->owner)) { ++ ret = p; ++ break; ++ } ++ } ++ ++ spin_unlock(&part_parser_lock); ++ ++ return ret; ++} ++ ++static int parse_mtd_partitions_by_type(struct mtd_info *master, ++ enum mtd_parser_type type, ++ const struct mtd_partition **pparts, ++ struct mtd_part_parser_data *data) ++{ ++ struct mtd_part_parser *prev = NULL; ++ int ret = 0; ++ ++ while (1) { ++ struct mtd_part_parser *parser; ++ ++ parser = get_partition_parser_by_type(type, prev); ++ if (!parser) ++ break; ++ ++ ret = (*parser->parse_fn)(master, pparts, data); ++ ++ if (ret > 0) { ++ mtd_part_parser_put(parser); ++ printk(KERN_NOTICE ++ "%d %s partitions found on MTD device %s\n", ++ ret, parser->name, master->name); ++ break; ++ } ++ ++ prev = parser; ++ } ++ ++ return ret; ++} ++ ++static int ++run_parsers_by_type(struct mtd_info *child, enum mtd_parser_type type) ++{ ++ struct mtd_partition *parts; ++ int nr_parts; ++ int i; ++ ++ nr_parts = parse_mtd_partitions_by_type(child, type, (const struct mtd_partition **)&parts, ++ NULL); ++ if (nr_parts <= 0) ++ return nr_parts; ++ ++ if (WARN_ON(!parts)) ++ return 0; ++ ++ for (i = 0; i < nr_parts; i++) { ++ /* adjust partition offsets */ ++ parts[i].offset += child->part.offset; ++ ++ mtd_add_partition(child->parent, ++ parts[i].name, ++ parts[i].offset, ++ parts[i].size); ++ } ++ ++ kfree(parts); ++ ++ return nr_parts; ++} ++ ++#ifdef CONFIG_MTD_SPLIT_FIRMWARE_NAME ++#define SPLIT_FIRMWARE_NAME CONFIG_MTD_SPLIT_FIRMWARE_NAME ++#else ++#define SPLIT_FIRMWARE_NAME "unused" ++#endif ++ ++static void split_firmware(struct mtd_info *master, struct mtd_info *part) ++{ ++ run_parsers_by_type(part, MTD_PARSER_TYPE_FIRMWARE); ++} ++ ++static void mtd_partition_split(struct mtd_info *master, struct mtd_info *part) ++{ ++ static int rootfs_found = 0; ++ ++ if (rootfs_found) ++ return; ++ ++ if (of_find_property(mtd_get_of_node(part), "linux,rootfs", NULL) || ++ !strcmp(part->name, "rootfs")) { ++ run_parsers_by_type(part, MTD_PARSER_TYPE_ROOTFS); ++ ++ rootfs_found = 1; ++ } ++ ++ if (IS_ENABLED(CONFIG_MTD_SPLIT_FIRMWARE) && ++ !strcmp(part->name, SPLIT_FIRMWARE_NAME) && ++ !of_find_property(mtd_get_of_node(part), "compatible", NULL)) ++ split_firmware(master, part); ++} ++ + int mtd_add_partition(struct mtd_info *parent, const char *name, + long long offset, long long length) + { +@@ -280,6 +423,7 @@ int mtd_add_partition(struct mtd_info *parent, const char *name, + if (ret) + goto err_remove_part; + ++ mtd_partition_split(parent, child); + mtd_add_partition_attrs(child); + + return 0; +@@ -423,6 +567,7 @@ int add_mtd_partitions(struct mtd_info *parent, + goto err_del_partitions; + } + ++ mtd_partition_split(master, child); + mtd_add_partition_attrs(child); + + /* Look for subpartitions */ +@@ -443,31 +588,6 @@ int add_mtd_partitions(struct mtd_info *parent, + return ret; + } + +-static DEFINE_SPINLOCK(part_parser_lock); +-static LIST_HEAD(part_parsers); +- +-static struct mtd_part_parser *mtd_part_parser_get(const char *name) +-{ +- struct mtd_part_parser *p, *ret = NULL; +- +- spin_lock(&part_parser_lock); +- +- list_for_each_entry(p, &part_parsers, list) +- if (!strcmp(p->name, name) && try_module_get(p->owner)) { +- ret = p; +- break; +- } +- +- spin_unlock(&part_parser_lock); +- +- return ret; +-} +- +-static inline void mtd_part_parser_put(const struct mtd_part_parser *p) +-{ +- module_put(p->owner); +-} +- + /* + * Many partition parsers just expected the core to kfree() all their data in + * one chunk. Do that by default. +diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h +index 8d10d9d2e830..ed22b5e4cfc6 100644 +--- a/include/linux/mtd/mtd.h ++++ b/include/linux/mtd/mtd.h +@@ -615,6 +615,24 @@ static inline void mtd_align_erase_req(struct mtd_info *mtd, + req->len += mtd->erasesize - mod; + } + ++static inline uint64_t mtd_roundup_to_eb(uint64_t sz, struct mtd_info *mtd) ++{ ++ if (mtd_mod_by_eb(sz, mtd) == 0) ++ return sz; ++ ++ /* Round up to next erase block */ ++ return (mtd_div_by_eb(sz, mtd) + 1) * mtd->erasesize; ++} ++ ++static inline uint64_t mtd_rounddown_to_eb(uint64_t sz, struct mtd_info *mtd) ++{ ++ if (mtd_mod_by_eb(sz, mtd) == 0) ++ return sz; ++ ++ /* Round down to the start of the current erase block */ ++ return (mtd_div_by_eb(sz, mtd)) * mtd->erasesize; ++} ++ + static inline uint32_t mtd_div_by_ws(uint64_t sz, struct mtd_info *mtd) + { + if (mtd->writesize_shift) +@@ -688,6 +706,13 @@ extern struct mtd_info *of_get_mtd_device_by_node(struct device_node *np); + extern struct mtd_info *get_mtd_device_nm(const char *name); + extern void put_mtd_device(struct mtd_info *mtd); + ++static inline uint64_t mtdpart_get_offset(const struct mtd_info *mtd) ++{ ++ if (!mtd_is_partition(mtd)) ++ return 0; ++ ++ return mtd->part.offset; ++} + + struct mtd_notifier { + void (*add)(struct mtd_info *mtd); +diff --git a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h +index b74a539ec581..65ba0dbf961d 100644 +--- a/include/linux/mtd/partitions.h ++++ b/include/linux/mtd/partitions.h +@@ -75,6 +75,12 @@ struct mtd_part_parser_data { + * Functions dealing with the various ways of partitioning the space + */ + ++enum mtd_parser_type { ++ MTD_PARSER_TYPE_DEVICE = 0, ++ MTD_PARSER_TYPE_ROOTFS, ++ MTD_PARSER_TYPE_FIRMWARE, ++}; ++ + struct mtd_part_parser { + struct list_head list; + struct module *owner; +@@ -83,6 +89,7 @@ struct mtd_part_parser { + int (*parse_fn)(struct mtd_info *, const struct mtd_partition **, + struct mtd_part_parser_data *); + void (*cleanup)(const struct mtd_partition *pparts, int nr_parts); ++ enum mtd_parser_type type; + }; + + /* Container for passing around a set of parsed partitions */ +-- +2.51.0 + + +From b1bb268ee57b27be82e74377901ac602f9d049e4 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Tue, 31 Oct 2023 15:51:01 +0100 +Subject: [PATCH 206/517] mtd: don't register NVMEM devices for partitions with + custom drivers +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This fixes issue exposed by upstream commit f4cf4e5db331 ("Revert +"nvmem: add new config option""). + +Signed-off-by: RafaÅ‚ MiÅ‚ecki +--- + drivers/mtd/mtdcore.c | 23 +++++++++++++++++++++++ + 1 file changed, 23 insertions(+) + +diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c +index 724f917f91ba..0aa3f8e44fa1 100644 +--- a/drivers/mtd/mtdcore.c ++++ b/drivers/mtd/mtdcore.c +@@ -549,6 +549,29 @@ static int mtd_nvmem_add(struct mtd_info *mtd) + struct device_node *node = mtd_get_of_node(mtd); + struct nvmem_config config = {}; + ++ /* ++ * Do NOT register NVMEM device for any partition that is meant to be ++ * handled by a U-Boot env driver. That would result in associating two ++ * different NVMEM devices with the same OF node. ++ * ++ * An example of unwanted behaviour of above (forwardtrace): ++ * of_get_mac_addr_nvmem() ++ * of_nvmem_cell_get() ++ * __nvmem_device_get() ++ * ++ * We can't have __nvmem_device_get() return "mtdX" NVMEM device instead ++ * of U-Boot env NVMEM device. That would result in failing to find ++ * NVMEM cell. ++ * ++ * This issue seems to affect U-Boot env case only and will go away with ++ * switch to NVMEM layouts. ++ */ ++ if (of_device_is_compatible(node, "u-boot,env") || ++ of_device_is_compatible(node, "u-boot,env-redundant-bool") || ++ of_device_is_compatible(node, "u-boot,env-redundant-count") || ++ of_device_is_compatible(node, "brcm,env")) ++ return 0; ++ + config.id = NVMEM_DEVID_NONE; + config.dev = &mtd->dev; + config.name = dev_name(&mtd->dev); +-- +2.51.0 + + +From afeb87fd61a00460b0302e447b98e086f03485a7 Mon Sep 17 00:00:00 2001 +From: John Thomson +Date: Fri, 25 Dec 2020 18:50:08 +1000 +Subject: [PATCH 207/517] mtd: spi-nor: write support for minor aligned + partitions +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Do not prevent writing to mtd partitions where a partition boundary sits +on a minor erasesize boundary. +This addresses a FIXME that has been present since the start of the +linux git history: +/* Doesn't start on a boundary of major erase size */ +/* FIXME: Let it be writable if it is on a boundary of + * _minor_ erase size though */ + +Allow a uniform erase region spi-nor device to be configured +to use the non-uniform erase regions code path for an erase with: +CONFIG_MTD_SPI_NOR_USE_VARIABLE_ERASE=y + +On supporting hardware (SECT_4K: majority of current SPI-NOR device) +provide the facility for an erase to use the least number +of SPI-NOR operations, as well as access to 4K erase without +requiring CONFIG_MTD_SPI_NOR_USE_4K_SECTORS + +Introduce erasesize_minor to the mtd struct, +the smallest erasesize supported by the device + +On existing devices, this is useful where write support is wanted +for data on a 4K partition, such as some u-boot-env partitions, +or RouterBoot soft_config, while still netting the performance +benefits of using 64K sectors + +Performance: +time mtd erase firmware +OpenWrt 5.10 ramips MT7621 w25q128jv 0xfc0000 partition length + +Without this patch +MTD_SPI_NOR_USE_4K_SECTORS=y |n +real 2m 11.66s |0m 50.86s +user 0m 0.00s |0m 0.00s +sys 1m 56.20s |0m 50.80s + +With this patch +MTD_SPI_NOR_USE_VARIABLE_ERASE=n|y |4K_SECTORS=y +real 0m 51.68s |0m 50.85s |2m 12.89s +user 0m 0.00s |0m 0.00s |0m 0.01s +sys 0m 46.94s |0m 50.38s |2m 12.46s + +Signed-off-by: John Thomson +Signed-off-by: Thibaut VARÈNE +--- + drivers/mtd/mtdcore.c | 10 ++++++++++ + drivers/mtd/mtdpart.c | 35 +++++++++++++++++++++++++---------- + drivers/mtd/spi-nor/Kconfig | 10 ++++++++++ + drivers/mtd/spi-nor/core.c | 11 +++++++++-- + include/linux/mtd/mtd.h | 2 ++ + 5 files changed, 56 insertions(+), 12 deletions(-) + +diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c +index 0aa3f8e44fa1..6b98d581ceeb 100644 +--- a/drivers/mtd/mtdcore.c ++++ b/drivers/mtd/mtdcore.c +@@ -199,6 +199,15 @@ static ssize_t mtd_erasesize_show(struct device *dev, + } + MTD_DEVICE_ATTR_RO(erasesize); + ++static ssize_t mtd_erasesize_minor_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct mtd_info *mtd = dev_get_drvdata(dev); ++ ++ return sysfs_emit(buf, "%lu\n", (unsigned long)mtd->erasesize_minor); ++} ++MTD_DEVICE_ATTR_RO(erasesize_minor); ++ + static ssize_t mtd_writesize_show(struct device *dev, + struct device_attribute *attr, char *buf) + { +@@ -344,6 +353,7 @@ static struct attribute *mtd_attrs[] = { + &dev_attr_flags.attr, + &dev_attr_size.attr, + &dev_attr_erasesize.attr, ++ &dev_attr_erasesize_minor.attr, + &dev_attr_writesize.attr, + &dev_attr_subpagesize.attr, + &dev_attr_oobsize.attr, +diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c +index 10ae49b9702a..58eb32021874 100644 +--- a/drivers/mtd/mtdpart.c ++++ b/drivers/mtd/mtdpart.c +@@ -47,6 +47,7 @@ static struct mtd_info *allocate_partition(struct mtd_info *parent, + struct mtd_info *master = mtd_get_master(parent); + int wr_alignment = (parent->flags & MTD_NO_ERASE) ? + master->writesize : master->erasesize; ++ int wr_alignment_minor = 0; + u64 parent_size = mtd_is_partition(parent) ? + parent->part.size : parent->size; + struct mtd_info *child; +@@ -171,6 +172,7 @@ static struct mtd_info *allocate_partition(struct mtd_info *parent, + } else { + /* Single erase size */ + child->erasesize = master->erasesize; ++ child->erasesize_minor = master->erasesize_minor; + } + + /* +@@ -178,26 +180,39 @@ static struct mtd_info *allocate_partition(struct mtd_info *parent, + * exposes several regions with different erasesize. Adjust + * wr_alignment accordingly. + */ +- if (!(child->flags & MTD_NO_ERASE)) ++ if (!(child->flags & MTD_NO_ERASE)) { + wr_alignment = child->erasesize; ++ wr_alignment_minor = child->erasesize_minor; ++ } + + tmp = mtd_get_master_ofs(child, 0); + remainder = do_div(tmp, wr_alignment); + if ((child->flags & MTD_WRITEABLE) && remainder) { +- /* Doesn't start on a boundary of major erase size */ +- /* FIXME: Let it be writable if it is on a boundary of +- * _minor_ erase size though */ +- child->flags &= ~MTD_WRITEABLE; +- printk(KERN_WARNING"mtd: partition \"%s\" doesn't start on an erase/write block boundary -- force read-only\n", +- part->name); ++ if (wr_alignment_minor) { ++ /* rely on minor being a factor of major erasesize */ ++ tmp = remainder; ++ remainder = do_div(tmp, wr_alignment_minor); ++ } ++ if (remainder) { ++ child->flags &= ~MTD_WRITEABLE; ++ printk(KERN_WARNING"mtd: partition \"%s\" doesn't start on an erase/write block boundary -- force read-only\n", ++ part->name); ++ } + } + + tmp = mtd_get_master_ofs(child, 0) + child->part.size; + remainder = do_div(tmp, wr_alignment); + if ((child->flags & MTD_WRITEABLE) && remainder) { +- child->flags &= ~MTD_WRITEABLE; +- printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase/write block -- force read-only\n", +- part->name); ++ if (wr_alignment_minor) { ++ tmp = remainder; ++ remainder = do_div(tmp, wr_alignment_minor); ++ } ++ ++ if (remainder) { ++ child->flags &= ~MTD_WRITEABLE; ++ printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase/write block -- force read-only\n", ++ part->name); ++ } + } + + child->size = child->part.size; +diff --git a/drivers/mtd/spi-nor/Kconfig b/drivers/mtd/spi-nor/Kconfig +index 24cd25de2b8b..09df9f1a8127 100644 +--- a/drivers/mtd/spi-nor/Kconfig ++++ b/drivers/mtd/spi-nor/Kconfig +@@ -10,6 +10,16 @@ menuconfig MTD_SPI_NOR + + if MTD_SPI_NOR + ++config MTD_SPI_NOR_USE_VARIABLE_ERASE ++ bool "Disable uniform_erase to allow use of all hardware supported erasesizes" ++ depends on !MTD_SPI_NOR_USE_4K_SECTORS ++ default n ++ help ++ Allow mixed use of all hardware supported erasesizes, ++ by forcing spi_nor to use the multiple eraseregions code path. ++ For example: A 68K erase will use one 64K erase, and one 4K erase ++ on supporting hardware. ++ + config MTD_SPI_NOR_USE_4K_SECTORS + bool "Use small 4096 B erase sectors" + default y +diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c +index 9d6e85bf227b..8da860d84e6d 100644 +--- a/drivers/mtd/spi-nor/core.c ++++ b/drivers/mtd/spi-nor/core.c +@@ -1158,6 +1158,8 @@ static u8 spi_nor_convert_3to4_erase(u8 opcode) + + static bool spi_nor_has_uniform_erase(const struct spi_nor *nor) + { ++ if (IS_ENABLED(CONFIG_MTD_SPI_NOR_USE_VARIABLE_ERASE)) ++ return false; + return !!nor->params->erase_map.uniform_region.erase_mask; + } + +@@ -2516,6 +2518,7 @@ static int spi_nor_select_erase(struct spi_nor *nor) + { + struct spi_nor_erase_map *map = &nor->params->erase_map; + const struct spi_nor_erase_type *erase = NULL; ++ const struct spi_nor_erase_type *erase_minor = NULL; + struct mtd_info *mtd = &nor->mtd; + int i; + +@@ -2542,8 +2545,9 @@ static int spi_nor_select_erase(struct spi_nor *nor) + */ + for (i = SNOR_ERASE_TYPE_MAX - 1; i >= 0; i--) { + if (map->erase_type[i].size) { +- erase = &map->erase_type[i]; +- break; ++ if (!erase) ++ erase = &map->erase_type[i]; ++ erase_minor = &map->erase_type[i]; + } + } + +@@ -2551,6 +2555,9 @@ static int spi_nor_select_erase(struct spi_nor *nor) + return -EINVAL; + + mtd->erasesize = erase->size; ++ if (IS_ENABLED(CONFIG_MTD_SPI_NOR_USE_VARIABLE_ERASE) && ++ erase_minor && erase_minor->size < erase->size) ++ mtd->erasesize_minor = erase_minor->size; + return 0; + } + +diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h +index ed22b5e4cfc6..86f7efa43faa 100644 +--- a/include/linux/mtd/mtd.h ++++ b/include/linux/mtd/mtd.h +@@ -245,6 +245,8 @@ struct mtd_info { + * information below if they desire + */ + uint32_t erasesize; ++ /* "Minor" (smallest) erase size supported by the whole device */ ++ uint32_t erasesize_minor; + /* Minimal writable flash unit size. In case of NOR flash it is 1 (even + * though individual bits can be cleared), in case of NAND flash it is + * one NAND page (or half, or one-fourths of it), in case of ECC-ed NOR +-- +2.51.0 + + +From c1e81cf689836ae1cc7a75f0d3b749cf98818a0e Mon Sep 17 00:00:00 2001 +From: Mikhail Kshevetskiy +Date: Sun, 3 Aug 2025 17:23:27 +0300 +Subject: [PATCH 208/517] mtd: spinand: fix direct mapping creation sizes + +Continuous mode is only supported for data reads, thus writing +requires only single flash page mapping. + +Signed-off-by: Mikhail Kshevetskiy +--- + drivers/mtd/nand/spi/core.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c +index 8e4c825b9789..abae584de706 100644 +--- a/drivers/mtd/nand/spi/core.c ++++ b/drivers/mtd/nand/spi/core.c +@@ -1028,18 +1028,13 @@ static int spinand_create_dirmap(struct spinand_device *spinand, + unsigned int plane) + { + struct nand_device *nand = spinand_to_nand(spinand); +- struct spi_mem_dirmap_info info = { +- .length = nanddev_page_size(nand) + +- nanddev_per_page_oobsize(nand), +- }; ++ struct spi_mem_dirmap_info info = { 0 }; + struct spi_mem_dirmap_desc *desc; + +- if (spinand->cont_read_possible) +- info.length = nanddev_eraseblock_size(nand); +- + /* The plane number is passed in MSB just above the column address */ + info.offset = plane << fls(nand->memorg.pagesize); + ++ info.length = nanddev_page_size(nand) + nanddev_per_page_oobsize(nand); + info.op_tmpl = *spinand->op_templates.update_cache; + desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev, + spinand->spimem, &info); +@@ -1048,6 +1043,8 @@ static int spinand_create_dirmap(struct spinand_device *spinand, + + spinand->dirmaps[plane].wdesc = desc; + ++ if (spinand->cont_read_possible) ++ info.length = nanddev_eraseblock_size(nand); + info.op_tmpl = *spinand->op_templates.read_cache; + desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev, + spinand->spimem, &info); +@@ -1063,6 +1060,7 @@ static int spinand_create_dirmap(struct spinand_device *spinand, + return 0; + } + ++ info.length = nanddev_page_size(nand) + nanddev_per_page_oobsize(nand); + info.op_tmpl = *spinand->op_templates.update_cache; + info.op_tmpl.data.ecc = true; + desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev, +@@ -1072,6 +1070,8 @@ static int spinand_create_dirmap(struct spinand_device *spinand, + + spinand->dirmaps[plane].wdesc_ecc = desc; + ++ if (spinand->cont_read_possible) ++ info.length = nanddev_eraseblock_size(nand); + info.op_tmpl = *spinand->op_templates.read_cache; + info.op_tmpl.data.ecc = true; + desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev, +-- +2.51.0 + + +From f2aa382fe9e8fd76760cbd59e6463011f116ca30 Mon Sep 17 00:00:00 2001 +From: Mikhail Kshevetskiy +Date: Sun, 3 Aug 2025 19:06:40 +0300 +Subject: [PATCH 209/517] mtd: spinand: try a regular dirmap if creating a + dirmap for continuous reading fails + +Continuous reading may result in multiple flash pages reading in one +operation. Typically only one flash page has read/written (a little bit +more than 2-4 Kb), but continuous reading requires the spi controller +to read up to 512 Kb in one operation without toggling CS in beetween. + +Roughly speaking spi controllers can be divided on 2 categories: + * spi controllers without dirmap acceleration support + * spi controllers with dirmap acceleration support + +Firt of them will have issues with continuous reading if restriction on +the transfer length is implemented in the adjust_op_size() handler. +Second group often supports acceleration of single page only reading. +Thus enabling of continuous reading can break flash reading. + +This patch tries to create dirmap for continuous reading first and +fallback to regular reading if spi controller refuses to create it. + +Signed-off-by: Mikhail Kshevetskiy +--- + drivers/mtd/nand/spi/core.c | 43 ++++++++++++++++++++++++++++++------- + 1 file changed, 35 insertions(+), 8 deletions(-) + +diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c +index abae584de706..cb96b9cd2a73 100644 +--- a/drivers/mtd/nand/spi/core.c ++++ b/drivers/mtd/nand/spi/core.c +@@ -1024,6 +1024,39 @@ static int spinand_mtd_block_isreserved(struct mtd_info *mtd, loff_t offs) + return ret; + } + ++static struct spi_mem_dirmap_desc *spinand_create_rdesc( ++ struct spinand_device *spinand, ++ struct spi_mem_dirmap_info *info) ++{ ++ struct nand_device *nand = spinand_to_nand(spinand); ++ struct spi_mem_dirmap_desc *desc = NULL; ++ ++ if (spinand->cont_read_possible) { ++ /* ++ * spi controller may return an error if info->length is ++ * too large ++ */ ++ info->length = nanddev_eraseblock_size(nand); ++ desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev, ++ spinand->spimem, info); ++ } ++ ++ if (IS_ERR_OR_NULL(desc)) { ++ /* ++ * continuous reading is not supported by flash or ++ * its spi controller, use regular reading ++ */ ++ spinand->cont_read_possible = false; ++ ++ info->length = nanddev_page_size(nand) + ++ nanddev_per_page_oobsize(nand); ++ desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev, ++ spinand->spimem, info); ++ } ++ ++ return desc; ++} ++ + static int spinand_create_dirmap(struct spinand_device *spinand, + unsigned int plane) + { +@@ -1043,11 +1076,8 @@ static int spinand_create_dirmap(struct spinand_device *spinand, + + spinand->dirmaps[plane].wdesc = desc; + +- if (spinand->cont_read_possible) +- info.length = nanddev_eraseblock_size(nand); + info.op_tmpl = *spinand->op_templates.read_cache; +- desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev, +- spinand->spimem, &info); ++ desc = spinand_create_rdesc(spinand, &info); + if (IS_ERR(desc)) + return PTR_ERR(desc); + +@@ -1070,12 +1100,9 @@ static int spinand_create_dirmap(struct spinand_device *spinand, + + spinand->dirmaps[plane].wdesc_ecc = desc; + +- if (spinand->cont_read_possible) +- info.length = nanddev_eraseblock_size(nand); + info.op_tmpl = *spinand->op_templates.read_cache; + info.op_tmpl.data.ecc = true; +- desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev, +- spinand->spimem, &info); ++ desc = spinand_create_rdesc(spinand, &info); + if (IS_ERR(desc)) + return PTR_ERR(desc); + +-- +2.51.0 + + +From e713688e842578fcfa97303206ae0b1f7c3da4bc Mon Sep 17 00:00:00 2001 +From: Mikhail Kshevetskiy +Date: Sun, 3 Aug 2025 17:54:17 +0300 +Subject: [PATCH 210/517] mtd: spinand: repeat reading in regular mode if + continuous reading fails + +Continuous reading may result in multiple flash pages reading in one +operation. Unfortunately, not all spinand controllers support such +large reading. They will read less data. Unfortunately, the operation +can't be continued. + +In this case: + * disable continuous reading on this (not good enough) spi controller + * repeat reading in regular mode. + +Signed-off-by: Mikhail Kshevetskiy +--- + drivers/mtd/nand/spi/core.c | 25 +++++++++++++++++++++---- + 1 file changed, 21 insertions(+), 4 deletions(-) + +diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c +index cb96b9cd2a73..f3787a63a355 100644 +--- a/drivers/mtd/nand/spi/core.c ++++ b/drivers/mtd/nand/spi/core.c +@@ -427,8 +427,16 @@ static int spinand_read_from_cache_op(struct spinand_device *spinand, + * Dirmap accesses are allowed to toggle the CS. + * Toggling the CS during a continuous read is forbidden. + */ +- if (nbytes && req->continuous) +- return -EIO; ++ if (nbytes && req->continuous) { ++ /* ++ * Spi controller with broken support of continuous ++ * reading was detected. Disable future use of ++ * continuous reading and return -EAGAIN to retry ++ * reading within regular mode. ++ */ ++ spinand->cont_read_possible = false; ++ return -EAGAIN; ++ } + } + + if (req->datalen) +@@ -841,10 +849,19 @@ static int spinand_mtd_read(struct mtd_info *mtd, loff_t from, + + old_stats = mtd->ecc_stats; + +- if (spinand_use_cont_read(mtd, from, ops)) ++ if (spinand_use_cont_read(mtd, from, ops)) { + ret = spinand_mtd_continuous_page_read(mtd, from, ops, &max_bitflips); +- else ++ if (ret == -EAGAIN && !spinand->cont_read_possible) { ++ /* ++ * Spi controller with broken support of continuous ++ * reading was detected (see spinand_read_from_cache_op()), ++ * repeat reading in regular mode. ++ */ ++ ret = spinand_mtd_regular_page_read(mtd, from, ops, &max_bitflips); ++ } ++ } else { + ret = spinand_mtd_regular_page_read(mtd, from, ops, &max_bitflips); ++ } + + if (ops->stats) { + ops->stats->uncorrectable_errors += +-- +2.51.0 + + +From 59fce38e6f0e95196bc9523cf5447c5aa1f597bc Mon Sep 17 00:00:00 2001 +From: Gabor Juhos +Date: Thu, 1 May 2025 18:19:16 +0200 +Subject: [PATCH 211/517] spi: spi-qpic-snand: validate user/chip specific ECC + properties + +The driver only supports 512 bytes ECC step size and 4 bit ECC strength +at the moment, however it does not reject unsupported step/strength +configurations. Due to this, whenever the driver is used with a flash +chip which needs stronger ECC protection, the following warning is shown +in the kernel log: + + [ 0.574648] spi-nand spi0.0: GigaDevice SPI NAND was found. + [ 0.635748] spi-nand spi0.0: 256 MiB, block size: 128 KiB, page size: 2048, OOB size: 128 + [ 0.649079] nand: WARNING: (null): the ECC used on your system is too weak compared to the one required by the NAND chip + +Although the message indicates that something is wrong, but it often gets +unnoticed, which can cause serious problems. For example when the user +writes something into the flash chip despite the warning, the written data +may won't be readable by the bootloader or by the boot ROM. In the worst +case, when the attached SPI NAND chip is the boot device, the board may not +be able to boot anymore. + +Also, it is not even possible to create a backup of the flash, because +reading its content results in bogus data. For example, dumping the first +page of the flash gives this: + + # hexdump -C -n 2048 /dev/mtd0 + 00000000 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f |................| + * + 00000040 0f 0f 0f 0f 0f 0f 0f 0d 0f 0f 0f 0f 0f 0f 0f 0f |................| + 00000050 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f |................| + * + 000001c0 0f 0f 0f 0f ff 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f |................| + 000001d0 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f |................| + * + 00000200 0f 0f 0f 0f f5 5b ff ff 0f 0f 0f 0f 0f 0f 0f 0f |.....[..........| + 00000210 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f |................| + * + 000002f0 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 1f 0f 0f |................| + 00000300 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f |................| + * + 000003c0 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ff 0f 0f 0f |................| + 000003d0 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f |................| + * + 00000400 0f 0f 0f 0f 0f 0f 0f 0f e9 74 c9 06 f5 5b ff ff |.........t...[..| + 00000410 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f |................| + * + 000005d0 0f 0f 0f 0f ff 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f |................| + 000005e0 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f |................| + * + 00000600 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f c6 be 0f c3 |................| + 00000610 e9 74 c9 06 f5 5b ff ff 0f 0f 0f 0f 0f 0f 0f 0f |.t...[..........| + 00000620 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f |................| + * + 00000770 0f 0f 0f 0f 8f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f |................| + 00000780 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f |................| + * + 00000800 + # + +Doing the same by using the downstream kernel results in different output: + + # hexdump -C -n 2048 /dev/mtd0 + 00000000 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f |................| + * + 00000800 + # + +This patch adds some sanity checks to the code to prevent using the driver +with unsupported ECC step/strength configurations. After the change, probing +of the driver fails in such cases: + + [ 0.655038] spi-nand spi0.0: GigaDevice SPI NAND was found. + [ 0.659159] spi-nand spi0.0: 256 MiB, block size: 128 KiB, page size: 2048, OOB size: 128 + [ 0.669138] qcom_snand 79b0000.spi: only 4 bits ECC strength is supported + [ 0.677476] nand: No suitable ECC configuration + [ 0.689909] spi-nand spi0.0: probe with driver spi-nand failed with error -95 + +This helps to avoid the aforementioned hassles until support for 8 bit ECC +strength gets implemented. + +Fixes: 7304d1909080 ("spi: spi-qpic: add driver for QCOM SPI NAND flash Interface") +Signed-off-by: Gabor Juhos +--- + drivers/spi/spi-qpic-snand.c | 42 +++++++++++++++++++++++++++++++----- + 1 file changed, 37 insertions(+), 5 deletions(-) + +diff --git a/drivers/spi/spi-qpic-snand.c b/drivers/spi/spi-qpic-snand.c +index 98d32d269d55..3fa50db3b824 100644 +--- a/drivers/spi/spi-qpic-snand.c ++++ b/drivers/spi/spi-qpic-snand.c +@@ -249,9 +249,11 @@ static const struct mtd_ooblayout_ops qcom_spi_ooblayout = { + static int qcom_spi_ecc_init_ctx_pipelined(struct nand_device *nand) + { + struct qcom_nand_controller *snandc = nand_to_qcom_snand(nand); ++ struct nand_ecc_props *reqs = &nand->ecc.requirements; ++ struct nand_ecc_props *user = &nand->ecc.user_conf; + struct nand_ecc_props *conf = &nand->ecc.ctx.conf; + struct mtd_info *mtd = nanddev_to_mtd(nand); +- int cwperpage, bad_block_byte; ++ int cwperpage, bad_block_byte, ret; + struct qpic_ecc *ecc_cfg; + + cwperpage = mtd->writesize / NANDC_STEP_SIZE; +@@ -260,11 +262,39 @@ static int qcom_spi_ecc_init_ctx_pipelined(struct nand_device *nand) + ecc_cfg = kzalloc(sizeof(*ecc_cfg), GFP_KERNEL); + if (!ecc_cfg) + return -ENOMEM; ++ ++ if (user->step_size && user->strength) { ++ ecc_cfg->step_size = user->step_size; ++ ecc_cfg->strength = user->strength; ++ } else if (reqs->step_size && reqs->strength) { ++ ecc_cfg->step_size = reqs->step_size; ++ ecc_cfg->strength = reqs->strength; ++ } else { ++ /* use defaults */ ++ ecc_cfg->step_size = NANDC_STEP_SIZE; ++ ecc_cfg->strength = 4; ++ } ++ ++ if (ecc_cfg->step_size != NANDC_STEP_SIZE) { ++ dev_err(snandc->dev, ++ "only %u bytes ECC step size is supported\n", ++ NANDC_STEP_SIZE); ++ ret = -EOPNOTSUPP; ++ goto err_free_ecc_cfg; ++ } ++ ++ if (ecc_cfg->strength != 4) { ++ dev_err(snandc->dev, ++ "only 4 bits ECC strength is supported\n"); ++ ret = -EOPNOTSUPP; ++ goto err_free_ecc_cfg; ++ } ++ + snandc->qspi->oob_buf = kmalloc(mtd->writesize + mtd->oobsize, + GFP_KERNEL); + if (!snandc->qspi->oob_buf) { +- kfree(ecc_cfg); +- return -ENOMEM; ++ ret = -ENOMEM; ++ goto err_free_ecc_cfg; + } + + memset(snandc->qspi->oob_buf, 0xff, mtd->writesize + mtd->oobsize); +@@ -279,8 +309,6 @@ static int qcom_spi_ecc_init_ctx_pipelined(struct nand_device *nand) + ecc_cfg->bytes = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes + ecc_cfg->bbm_size; + + ecc_cfg->steps = 4; +- ecc_cfg->strength = 4; +- ecc_cfg->step_size = 512; + ecc_cfg->cw_data = 516; + ecc_cfg->cw_size = ecc_cfg->cw_data + ecc_cfg->bytes; + bad_block_byte = mtd->writesize - ecc_cfg->cw_size * (cwperpage - 1) + 1; +@@ -338,6 +366,10 @@ static int qcom_spi_ecc_init_ctx_pipelined(struct nand_device *nand) + ecc_cfg->strength, ecc_cfg->step_size); + + return 0; ++ ++err_free_ecc_cfg: ++ kfree(ecc_cfg); ++ return ret; + } + + static void qcom_spi_ecc_cleanup_ctx_pipelined(struct nand_device *nand) +-- +2.51.0 + + +From de42aad3a7d57d9e1d896b8e613a62c35cdf4201 Mon Sep 17 00:00:00 2001 +From: Gabor Juhos +Date: Fri, 2 May 2025 21:31:16 +0200 +Subject: [PATCH 212/517] mtd: nand: qpic-common: add defines for ECC_MODE + values + +Add defines for the values of the ECC_MODE field of the NAND_DEV0_ECC_CFG +register and change both the 'qcom-nandc' and 'spi-qpic-snand' drivers to +use those instead of magic numbers. + +No functional changes. This is in preparation for adding 8 bit ECC strength +support for the 'spi-qpic-snand' driver. + +Signed-off-by: Gabor Juhos +--- + drivers/mtd/nand/raw/qcom_nandc.c | 6 +++--- + drivers/spi/spi-qpic-snand.c | 2 +- + include/linux/mtd/nand-qpic-common.h | 2 ++ + 3 files changed, 6 insertions(+), 4 deletions(-) + +diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c +index c3b26fee55a8..efceee833abc 100644 +--- a/drivers/mtd/nand/raw/qcom_nandc.c ++++ b/drivers/mtd/nand/raw/qcom_nandc.c +@@ -1379,7 +1379,7 @@ static int qcom_nand_attach_chip(struct nand_chip *chip) + struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); + int cwperpage, bad_block_byte, ret; + bool wide_bus; +- int ecc_mode = 1; ++ int ecc_mode = ECC_MODE_8BIT; + + /* controller only supports 512 bytes data steps */ + ecc->size = NANDC_STEP_SIZE; +@@ -1400,7 +1400,7 @@ static int qcom_nand_attach_chip(struct nand_chip *chip) + if (ecc->strength >= 8) { + /* 8 bit ECC defaults to BCH ECC on all platforms */ + host->bch_enabled = true; +- ecc_mode = 1; ++ ecc_mode = ECC_MODE_8BIT; + + if (wide_bus) { + host->ecc_bytes_hw = 14; +@@ -1420,7 +1420,7 @@ static int qcom_nand_attach_chip(struct nand_chip *chip) + if (nandc->props->ecc_modes & ECC_BCH_4BIT) { + /* BCH */ + host->bch_enabled = true; +- ecc_mode = 0; ++ ecc_mode = ECC_MODE_4BIT; + + if (wide_bus) { + host->ecc_bytes_hw = 8; +diff --git a/drivers/spi/spi-qpic-snand.c b/drivers/spi/spi-qpic-snand.c +index 3fa50db3b824..d1b32453d33b 100644 +--- a/drivers/spi/spi-qpic-snand.c ++++ b/drivers/spi/spi-qpic-snand.c +@@ -349,7 +349,7 @@ static int qcom_spi_ecc_init_ctx_pipelined(struct nand_device *nand) + FIELD_PREP(ECC_SW_RESET, 0) | + FIELD_PREP(ECC_NUM_DATA_BYTES_MASK, ecc_cfg->cw_data) | + FIELD_PREP(ECC_FORCE_CLK_OPEN, 1) | +- FIELD_PREP(ECC_MODE_MASK, 0) | ++ FIELD_PREP(ECC_MODE_MASK, ECC_MODE_4BIT) | + FIELD_PREP(ECC_PARITY_SIZE_BYTES_BCH_MASK, ecc_cfg->ecc_bytes_hw); + + ecc_cfg->ecc_buf_cfg = 0x203 << NUM_STEPS; +diff --git a/include/linux/mtd/nand-qpic-common.h b/include/linux/mtd/nand-qpic-common.h +index 7760154de581..00c718a22a6f 100644 +--- a/include/linux/mtd/nand-qpic-common.h ++++ b/include/linux/mtd/nand-qpic-common.h +@@ -101,6 +101,8 @@ + #define ECC_SW_RESET BIT(1) + #define ECC_MODE 4 + #define ECC_MODE_MASK GENMASK(5, 4) ++#define ECC_MODE_4BIT 0 ++#define ECC_MODE_8BIT 1 + #define ECC_PARITY_SIZE_BYTES_BCH 8 + #define ECC_PARITY_SIZE_BYTES_BCH_MASK GENMASK(12, 8) + #define ECC_NUM_DATA_BYTES 16 +-- +2.51.0 + + +From 52969428d8075f5f312e7e6ac566fc4fa7b3bd6c Mon Sep 17 00:00:00 2001 +From: Gabor Juhos +Date: Fri, 2 May 2025 21:31:17 +0200 +Subject: [PATCH 213/517] spi: spi-qpic-snand: add support for 8 bits ECC + strength + +Even though the hardware supports 8 bits ECC strength, but that is not +handled in the driver yet. This change adds the missing bits in order +to allow using the driver with chips which require 8 bits ECC strength. + +No functional changes intended with regard to the existing 4 bits ECC +strength support. + +Tested on an IPQ9574 platform using a GigaDevice GD5F2GM7REYIG chip. + +Signed-off-by: Gabor Juhos +--- + drivers/spi/spi-qpic-snand.c | 21 ++++++++++++++++----- + 1 file changed, 16 insertions(+), 5 deletions(-) + +diff --git a/drivers/spi/spi-qpic-snand.c b/drivers/spi/spi-qpic-snand.c +index d1b32453d33b..79e815062db7 100644 +--- a/drivers/spi/spi-qpic-snand.c ++++ b/drivers/spi/spi-qpic-snand.c +@@ -283,9 +283,22 @@ static int qcom_spi_ecc_init_ctx_pipelined(struct nand_device *nand) + goto err_free_ecc_cfg; + } + +- if (ecc_cfg->strength != 4) { ++ switch (ecc_cfg->strength) { ++ case 4: ++ ecc_cfg->ecc_mode = ECC_MODE_4BIT; ++ ecc_cfg->ecc_bytes_hw = 7; ++ ecc_cfg->spare_bytes = 4; ++ break; ++ ++ case 8: ++ ecc_cfg->ecc_mode = ECC_MODE_8BIT; ++ ecc_cfg->ecc_bytes_hw = 13; ++ ecc_cfg->spare_bytes = 2; ++ break; ++ ++ default: + dev_err(snandc->dev, +- "only 4 bits ECC strength is supported\n"); ++ "only 4 or 8 bits ECC strength is supported\n"); + ret = -EOPNOTSUPP; + goto err_free_ecc_cfg; + } +@@ -302,8 +315,6 @@ static int qcom_spi_ecc_init_ctx_pipelined(struct nand_device *nand) + nand->ecc.ctx.priv = ecc_cfg; + snandc->qspi->mtd = mtd; + +- ecc_cfg->ecc_bytes_hw = 7; +- ecc_cfg->spare_bytes = 4; + ecc_cfg->bbm_size = 1; + ecc_cfg->bch_enabled = true; + ecc_cfg->bytes = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes + ecc_cfg->bbm_size; +@@ -349,7 +360,7 @@ static int qcom_spi_ecc_init_ctx_pipelined(struct nand_device *nand) + FIELD_PREP(ECC_SW_RESET, 0) | + FIELD_PREP(ECC_NUM_DATA_BYTES_MASK, ecc_cfg->cw_data) | + FIELD_PREP(ECC_FORCE_CLK_OPEN, 1) | +- FIELD_PREP(ECC_MODE_MASK, ECC_MODE_4BIT) | ++ FIELD_PREP(ECC_MODE_MASK, ecc_cfg->ecc_mode) | + FIELD_PREP(ECC_PARITY_SIZE_BYTES_BCH_MASK, ecc_cfg->ecc_bytes_hw); + + ecc_cfg->ecc_buf_cfg = 0x203 << NUM_STEPS; +-- +2.51.0 + + +From 8475879cf5aeed333f5a449a806f4e54afa7cf9d Mon Sep 17 00:00:00 2001 +From: Chukun Pan +Date: Tue, 10 Jun 2025 23:10:16 +0800 +Subject: [PATCH 214/517] mtd: spi-nand: macronix: disable continuous read for + MX35LFxGE4AD + +In on-die ECC mode, enabling continuous read will cause ubi_io_read error. +[ 7.852000] ubi0 warning: ubi_io_read: error -5 while reading ... + +So disable it first. Tested on GL.iNet GL-MT3000 with MX35LF2GE4AD flash. + +Fixes: 11813857864f ("mtd: spi-nand: macronix: Continuous read support") +Signed-off-by: Chukun Pan +--- + drivers/mtd/nand/spi/macronix.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/drivers/mtd/nand/spi/macronix.c b/drivers/mtd/nand/spi/macronix.c +index d277c3220fdc..49ee3fd4581f 100644 +--- a/drivers/mtd/nand/spi/macronix.c ++++ b/drivers/mtd/nand/spi/macronix.c +@@ -167,8 +167,7 @@ static const struct spinand_info macronix_spinand_table[] = { + &update_cache_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, +- macronix_ecc_get_status), +- SPINAND_CONT_READ(macronix_set_cont_read)), ++ macronix_ecc_get_status)), + SPINAND_INFO("MX35LF4GE4AD", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x37, 0x03), + NAND_MEMORG(1, 4096, 128, 64, 2048, 40, 1, 1, 1), +@@ -178,8 +177,7 @@ static const struct spinand_info macronix_spinand_table[] = { + &update_cache_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, +- macronix_ecc_get_status), +- SPINAND_CONT_READ(macronix_set_cont_read)), ++ macronix_ecc_get_status)), + SPINAND_INFO("MX35LF1G24AD", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x14, 0x03), + NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), +-- +2.51.0 + + +From df45909871c0bf05bc62ee888a5d45230be19f27 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Mon, 3 Nov 2025 15:49:41 +0100 +Subject: [PATCH 215/517] add patch for including unpartitioned space in the + rootfs partition for redboot devices (if applicable) + +[john@phrozen.org: used by ixp and others] + +lede-commit: 394918851f84e4d00fa16eb900e7700e95091f00 +Signed-off-by: Felix Fietkau +--- + drivers/mtd/parsers/redboot.c | 19 +++++++++++++------ + 1 file changed, 13 insertions(+), 6 deletions(-) + +diff --git a/drivers/mtd/parsers/redboot.c b/drivers/mtd/parsers/redboot.c +index 3b55b676ca6b..979427ffef9e 100644 +--- a/drivers/mtd/parsers/redboot.c ++++ b/drivers/mtd/parsers/redboot.c +@@ -278,14 +278,21 @@ static int parse_redboot_partitions(struct mtd_info *master, + #endif + names += strlen(names) + 1; + +-#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED + if (fl->next && fl->img->flash_base + fl->img->size + master->erasesize <= fl->next->img->flash_base) { +- i++; +- parts[i].offset = parts[i - 1].size + parts[i - 1].offset; +- parts[i].size = fl->next->img->flash_base - parts[i].offset; +- parts[i].name = nullname; +- } ++ if (!strcmp(parts[i].name, "rootfs")) { ++ parts[i].size = fl->next->img->flash_base; ++ parts[i].size &= ~(master->erasesize - 1); ++ parts[i].size -= parts[i].offset; ++#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED ++ nrparts--; ++ } else { ++ i++; ++ parts[i].offset = parts[i-1].size + parts[i-1].offset; ++ parts[i].size = fl->next->img->flash_base - parts[i].offset; ++ parts[i].name = nullname; + #endif ++ } ++ } + tmp_fl = fl; + fl = fl->next; + kfree(tmp_fl); +-- +2.51.0 + + +From 683715c54bf280f2544981603e8a8ea167738833 Mon Sep 17 00:00:00 2001 +From: Florian Fainelli +Date: Mon, 3 Nov 2025 15:49:41 +0100 +Subject: [PATCH 216/517] Add myloader partition table parser + +[john@phozen.org: shoud be upstreamable] + +lede-commit: d8bf22859b51faa09d22c056fe221a45d2f7a3b8 +Signed-off-by: Florian Fainelli +[adjust for kernel 5.4, add myloader.c to patch] +Signed-off-by: Adrian Schmutzler +--- + drivers/mtd/parsers/Kconfig | 16 +++ + drivers/mtd/parsers/Makefile | 1 + + drivers/mtd/parsers/myloader.c | 181 +++++++++++++++++++++++++++++++++ + 3 files changed, 198 insertions(+) + create mode 100644 drivers/mtd/parsers/myloader.c + +diff --git a/drivers/mtd/parsers/Kconfig b/drivers/mtd/parsers/Kconfig +index da03ab6efe04..879d193f83f7 100644 +--- a/drivers/mtd/parsers/Kconfig ++++ b/drivers/mtd/parsers/Kconfig +@@ -62,6 +62,22 @@ config MTD_CMDLINE_PARTS + + If unsure, say 'N'. + ++config MTD_MYLOADER_PARTS ++ tristate "MyLoader partition parsing" ++ depends on ADM5120 || ATH79 ++ help ++ MyLoader is a bootloader which allows the user to define partitions ++ in flash devices, by putting a table in the second erase block ++ on the device, similar to a partition table. This table gives the ++ offsets and lengths of the user defined partitions. ++ ++ If you need code which can detect and parse these tables, and ++ register MTD 'partitions' corresponding to each image detected, ++ enable this option. ++ ++ You will still need the parsing functions to be called by the driver ++ for your particular device. It won't happen automatically. ++ + config MTD_OF_PARTS + tristate "OpenFirmware (device tree) partitioning parser" + default y +diff --git a/drivers/mtd/parsers/Makefile b/drivers/mtd/parsers/Makefile +index 9b00c62b837a..e3d3ade33a48 100644 +--- a/drivers/mtd/parsers/Makefile ++++ b/drivers/mtd/parsers/Makefile +@@ -3,6 +3,7 @@ obj-$(CONFIG_MTD_BCM47XX_PARTS) += bcm47xxpart.o + obj-$(CONFIG_MTD_BCM63XX_PARTS) += bcm63xxpart.o + obj-$(CONFIG_MTD_BRCM_U_BOOT) += brcm_u-boot.o + obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o ++obj-$(CONFIG_MTD_MYLOADER_PARTS) += myloader.o + obj-$(CONFIG_MTD_OF_PARTS) += ofpart.o + ofpart-y += ofpart_core.o + ofpart-$(CONFIG_MTD_OF_PARTS_BCM4908) += ofpart_bcm4908.o +diff --git a/drivers/mtd/parsers/myloader.c b/drivers/mtd/parsers/myloader.c +new file mode 100644 +index 000000000000..50ed8b197ed2 +--- /dev/null ++++ b/drivers/mtd/parsers/myloader.c +@@ -0,0 +1,181 @@ ++/* ++ * Parse MyLoader-style flash partition tables and produce a Linux partition ++ * array to match. ++ * ++ * Copyright (C) 2007-2009 Gabor Juhos ++ * ++ * This file was based on drivers/mtd/redboot.c ++ * Author: Red Hat, Inc. - David Woodhouse ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define BLOCK_LEN_MIN 0x10000 ++#define PART_NAME_LEN 32 ++ ++struct part_data { ++ struct mylo_partition_table tab; ++ char names[MYLO_MAX_PARTITIONS][PART_NAME_LEN]; ++}; ++ ++static int myloader_parse_partitions(struct mtd_info *master, ++ const struct mtd_partition **pparts, ++ struct mtd_part_parser_data *data) ++{ ++ struct part_data *buf; ++ struct mylo_partition_table *tab; ++ struct mylo_partition *part; ++ struct mtd_partition *mtd_parts; ++ struct mtd_partition *mtd_part; ++ int num_parts; ++ int ret, i; ++ size_t retlen; ++ char *names; ++ unsigned long offset; ++ unsigned long blocklen; ++ ++ buf = vmalloc(sizeof(*buf)); ++ if (!buf) { ++ return -ENOMEM; ++ goto out; ++ } ++ tab = &buf->tab; ++ ++ blocklen = master->erasesize; ++ if (blocklen < BLOCK_LEN_MIN) ++ blocklen = BLOCK_LEN_MIN; ++ ++ offset = blocklen; ++ ++ /* Find the partition table */ ++ for (i = 0; i < 4; i++, offset += blocklen) { ++ printk(KERN_DEBUG "%s: searching for MyLoader partition table" ++ " at offset 0x%lx\n", master->name, offset); ++ ++ ret = mtd_read(master, offset, sizeof(*buf), &retlen, ++ (void *)buf); ++ if (ret) ++ goto out_free_buf; ++ ++ if (retlen != sizeof(*buf)) { ++ ret = -EIO; ++ goto out_free_buf; ++ } ++ ++ /* Check for Partition Table magic number */ ++ if (tab->magic == le32_to_cpu(MYLO_MAGIC_PARTITIONS)) ++ break; ++ ++ } ++ ++ if (tab->magic != le32_to_cpu(MYLO_MAGIC_PARTITIONS)) { ++ printk(KERN_DEBUG "%s: no MyLoader partition table found\n", ++ master->name); ++ ret = 0; ++ goto out_free_buf; ++ } ++ ++ /* The MyLoader and the Partition Table is always present */ ++ num_parts = 2; ++ ++ /* Detect number of used partitions */ ++ for (i = 0; i < MYLO_MAX_PARTITIONS; i++) { ++ part = &tab->partitions[i]; ++ ++ if (le16_to_cpu(part->type) == PARTITION_TYPE_FREE) ++ continue; ++ ++ num_parts++; ++ } ++ ++ mtd_parts = kzalloc((num_parts * sizeof(*mtd_part) + ++ num_parts * PART_NAME_LEN), GFP_KERNEL); ++ ++ if (!mtd_parts) { ++ ret = -ENOMEM; ++ goto out_free_buf; ++ } ++ ++ mtd_part = mtd_parts; ++ names = (char *)&mtd_parts[num_parts]; ++ ++ strncpy(names, "myloader", PART_NAME_LEN); ++ mtd_part->name = names; ++ mtd_part->offset = 0; ++ mtd_part->size = offset; ++ mtd_part->mask_flags = MTD_WRITEABLE; ++ mtd_part++; ++ names += PART_NAME_LEN; ++ ++ strncpy(names, "partition_table", PART_NAME_LEN); ++ mtd_part->name = names; ++ mtd_part->offset = offset; ++ mtd_part->size = blocklen; ++ mtd_part->mask_flags = MTD_WRITEABLE; ++ mtd_part++; ++ names += PART_NAME_LEN; ++ ++ for (i = 0; i < MYLO_MAX_PARTITIONS; i++) { ++ part = &tab->partitions[i]; ++ ++ if (le16_to_cpu(part->type) == PARTITION_TYPE_FREE) ++ continue; ++ ++ if ((buf->names[i][0]) && (buf->names[i][0] != '\xff')) ++ strncpy(names, buf->names[i], PART_NAME_LEN); ++ else ++ snprintf(names, PART_NAME_LEN, "partition%d", i); ++ ++ mtd_part->offset = le32_to_cpu(part->addr); ++ mtd_part->size = le32_to_cpu(part->size); ++ mtd_part->name = names; ++ mtd_part++; ++ names += PART_NAME_LEN; ++ } ++ ++ *pparts = mtd_parts; ++ ret = num_parts; ++ ++ out_free_buf: ++ vfree(buf); ++ out: ++ return ret; ++} ++ ++static struct mtd_part_parser myloader_mtd_parser = { ++ .owner = THIS_MODULE, ++ .parse_fn = myloader_parse_partitions, ++ .name = "MyLoader", ++}; ++ ++static int __init myloader_mtd_parser_init(void) ++{ ++ register_mtd_parser(&myloader_mtd_parser); ++ ++ return 0; ++} ++ ++static void __exit myloader_mtd_parser_exit(void) ++{ ++ deregister_mtd_parser(&myloader_mtd_parser); ++} ++ ++module_init(myloader_mtd_parser_init); ++module_exit(myloader_mtd_parser_exit); ++ ++MODULE_AUTHOR("Gabor Juhos "); ++MODULE_DESCRIPTION("Parsing code for MyLoader partition tables"); ++MODULE_LICENSE("GPL v2"); +-- +2.51.0 + + +From bd16a24ae191e56a7073eceb9961fa21e017a00d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Mon, 3 Nov 2025 15:49:42 +0100 +Subject: [PATCH 217/517] mtd: bcm47xxpart: check for bad blocks when + calculating offsets +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: RafaÅ‚ MiÅ‚ecki +--- + drivers/mtd/parsers/parser_trx.c | 35 ++++++++++++++++++++++++++++---- + 1 file changed, 31 insertions(+), 4 deletions(-) + +diff --git a/drivers/mtd/parsers/parser_trx.c b/drivers/mtd/parsers/parser_trx.c +index 4814cf218e17..a1aed25d433f 100644 +--- a/drivers/mtd/parsers/parser_trx.c ++++ b/drivers/mtd/parsers/parser_trx.c +@@ -25,6 +25,33 @@ struct trx_header { + uint32_t offset[3]; + } __packed; + ++/* ++ * Calculate real end offset (address) for a given amount of data. It checks ++ * all blocks skipping bad ones. ++ */ ++static size_t parser_trx_real_offset(struct mtd_info *mtd, size_t bytes) ++{ ++ size_t real_offset = 0; ++ ++ if (mtd_block_isbad(mtd, real_offset)) ++ pr_warn("Base offset shouldn't be at bad block"); ++ ++ while (bytes >= mtd->erasesize) { ++ bytes -= mtd->erasesize; ++ real_offset += mtd->erasesize; ++ while (mtd_block_isbad(mtd, real_offset)) { ++ real_offset += mtd->erasesize; ++ ++ if (real_offset >= mtd->size) ++ return real_offset - mtd->erasesize; ++ } ++ } ++ ++ real_offset += bytes; ++ ++ return real_offset; ++} ++ + static const char *parser_trx_data_part_name(struct mtd_info *master, + size_t offset) + { +@@ -86,21 +113,21 @@ static int parser_trx_parse(struct mtd_info *mtd, + if (trx.offset[2]) { + part = &parts[curr_part++]; + part->name = "loader"; +- part->offset = trx.offset[i]; ++ part->offset = parser_trx_real_offset(mtd, trx.offset[i]); + i++; + } + + if (trx.offset[i]) { + part = &parts[curr_part++]; + part->name = "linux"; +- part->offset = trx.offset[i]; ++ part->offset = parser_trx_real_offset(mtd, trx.offset[i]); + i++; + } + + if (trx.offset[i]) { + part = &parts[curr_part++]; +- part->name = parser_trx_data_part_name(mtd, trx.offset[i]); +- part->offset = trx.offset[i]; ++ part->offset = parser_trx_real_offset(mtd, trx.offset[i]); ++ part->name = parser_trx_data_part_name(mtd, part->offset); + i++; + } + +-- +2.51.0 + + +From cf018b2b9b3a91fe6a8f81ebc86aed81c9feb202 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Mon, 3 Nov 2025 15:49:42 +0100 +Subject: [PATCH 218/517] mtd: bcm47xxpart: detect T_Meter partition +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +It can be found on many Netgear devices. It consists of many 0x30 blocks +starting with 4D 54. + +Signed-off-by: RafaÅ‚ MiÅ‚ecki +--- + drivers/mtd/parsers/bcm47xxpart.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/drivers/mtd/parsers/bcm47xxpart.c b/drivers/mtd/parsers/bcm47xxpart.c +index 49c8e7f27f21..b4a5391afce7 100644 +--- a/drivers/mtd/parsers/bcm47xxpart.c ++++ b/drivers/mtd/parsers/bcm47xxpart.c +@@ -35,6 +35,7 @@ + #define NVRAM_HEADER 0x48534C46 /* FLSH */ + #define POT_MAGIC1 0x54544f50 /* POTT */ + #define POT_MAGIC2 0x504f /* OP */ ++#define T_METER_MAGIC 0x4D540000 /* MT */ + #define ML_MAGIC1 0x39685a42 + #define ML_MAGIC2 0x26594131 + #define TRX_MAGIC 0x30524448 +@@ -179,6 +180,15 @@ static int bcm47xxpart_parse(struct mtd_info *master, + continue; + } + ++ /* T_Meter */ ++ if ((le32_to_cpu(buf[0x000 / 4]) & 0xFFFF0000) == T_METER_MAGIC && ++ (le32_to_cpu(buf[0x030 / 4]) & 0xFFFF0000) == T_METER_MAGIC && ++ (le32_to_cpu(buf[0x060 / 4]) & 0xFFFF0000) == T_METER_MAGIC) { ++ bcm47xxpart_add_part(&parts[curr_part++], "T_Meter", offset, ++ MTD_WRITEABLE); ++ continue; ++ } ++ + /* TRX */ + if (buf[0x000 / 4] == TRX_MAGIC) { + struct trx_header *trx; +-- +2.51.0 + + +From b7841b2dd346ac51024fd841247b87267a41eaf2 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Thibaut=20VAR=C3=88NE?= +Date: Tue, 24 Mar 2020 11:45:07 +0100 +Subject: [PATCH 219/517] generic: routerboot partition build bits (5.4) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This patch adds routerbootpart kernel build bits + +Signed-off-by: Thibaut VARÈNE +--- + drivers/mtd/parsers/Kconfig | 9 +++++++++ + drivers/mtd/parsers/Makefile | 1 + + 2 files changed, 10 insertions(+) + +diff --git a/drivers/mtd/parsers/Kconfig b/drivers/mtd/parsers/Kconfig +index 879d193f83f7..87dde317f9dd 100644 +--- a/drivers/mtd/parsers/Kconfig ++++ b/drivers/mtd/parsers/Kconfig +@@ -231,3 +231,12 @@ config MTD_SERCOMM_PARTS + partition map. This partition table contains real partition + offsets, which may differ from device to device depending on the + number and location of bad blocks on NAND. ++ ++config MTD_ROUTERBOOT_PARTS ++ tristate "RouterBoot flash partition parser" ++ depends on MTD && OF ++ help ++ MikroTik RouterBoot is implemented as a multi segment system on the ++ flash, some of which are fixed and some of which are located at ++ variable offsets. This parser handles both cases via properly ++ formatted DTS. +diff --git a/drivers/mtd/parsers/Makefile b/drivers/mtd/parsers/Makefile +index e3d3ade33a48..e6b06b56b046 100644 +--- a/drivers/mtd/parsers/Makefile ++++ b/drivers/mtd/parsers/Makefile +@@ -16,3 +16,4 @@ obj-$(CONFIG_MTD_SERCOMM_PARTS) += scpart.o + obj-$(CONFIG_MTD_SHARPSL_PARTS) += sharpslpart.o + obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o + obj-$(CONFIG_MTD_QCOMSMEM_PARTS) += qcomsmempart.o ++obj-$(CONFIG_MTD_ROUTERBOOT_PARTS) += routerbootpart.o +-- +2.51.0 + + +From 539d84630ee1e7d03afccbf4d62527fa34d0e592 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Mon, 7 Oct 2024 23:36:14 +0100 +Subject: [PATCH 220/517] block: allow setting partition of_node + +Allow partition parsers to set the Device Tree node for a partition by +introducing of_put_partition() and extending struct parsed_partitions +accordingly. + +As the partition information is preallocated independently of the actual +number of partitions the additional pointer takes about 2 kiB of allocated +memory which is worth avoiding in case CONFIG_OF is not set. This is +achieved by only adding the corresponding field to the struct in case +CONFIG_OF is set using #ifdef'ery. + +Signed-off-by: Daniel Golle +--- + block/partitions/check.h | 16 +++++++++++++++- + block/partitions/core.c | 14 +++++++++++--- + 2 files changed, 26 insertions(+), 4 deletions(-) + +diff --git a/block/partitions/check.h b/block/partitions/check.h +index e5c1c61eb353..0b326086b1b6 100644 +--- a/block/partitions/check.h ++++ b/block/partitions/check.h +@@ -1,6 +1,7 @@ + /* SPDX-License-Identifier: GPL-2.0 */ + #include + #include ++#include + #include "../blk.h" + + /* +@@ -16,6 +17,9 @@ struct parsed_partitions { + int flags; + bool has_info; + struct partition_meta_info info; ++#ifdef CONFIG_OF ++ struct device_node *np; ++#endif + } *parts; + int next; + int limit; +@@ -34,18 +38,28 @@ static inline void put_dev_sector(Sector p) + } + + static inline void +-put_partition(struct parsed_partitions *p, int n, sector_t from, sector_t size) ++of_put_partition(struct parsed_partitions *p, int n, sector_t from, sector_t size, ++ struct device_node *np) + { + if (n < p->limit) { + char tmp[1 + BDEVNAME_SIZE + 10 + 1]; + + p->parts[n].from = from; + p->parts[n].size = size; ++#ifdef CONFIG_OF ++ p->parts[n].np = np; ++#endif + snprintf(tmp, sizeof(tmp), " %s%d", p->name, n); + strlcat(p->pp_buf, tmp, PAGE_SIZE); + } + } + ++static inline void ++put_partition(struct parsed_partitions *p, int n, sector_t from, sector_t size) ++{ ++ of_put_partition(p, n, from, size, NULL); ++} ++ + /* detection routines go here in alphabetical order: */ + int adfspart_check_ADFS(struct parsed_partitions *state); + int adfspart_check_CUMANA(struct parsed_partitions *state); +diff --git a/block/partitions/core.c b/block/partitions/core.c +index cdad05f97647..f5b5360dd518 100644 +--- a/block/partitions/core.c ++++ b/block/partitions/core.c +@@ -9,6 +9,7 @@ + #include + #include + #include ++#include + #include + #include "check.h" + +@@ -290,7 +291,8 @@ static const DEVICE_ATTR(whole_disk, 0444, whole_disk_show, NULL); + */ + static struct block_device *add_partition(struct gendisk *disk, int partno, + sector_t start, sector_t len, int flags, +- struct partition_meta_info *info) ++ struct partition_meta_info *info, ++ struct device_node *np) + { + dev_t devt = MKDEV(0, 0); + struct device *ddev = disk_to_dev(disk); +@@ -339,6 +341,7 @@ static struct block_device *add_partition(struct gendisk *disk, int partno, + pdev->class = &block_class; + pdev->type = &part_type; + pdev->parent = ddev; ++ device_set_node(pdev, of_fwnode_handle(np)); + + /* in consecutive minor range? */ + if (bdev_partno(bdev) < disk->minors) { +@@ -445,7 +448,7 @@ int bdev_add_partition(struct gendisk *disk, int partno, sector_t start, + } + + part = add_partition(disk, partno, start, length, +- ADDPART_FLAG_NONE, NULL); ++ ADDPART_FLAG_NONE, NULL, NULL); + ret = PTR_ERR_OR_ZERO(part); + out: + mutex_unlock(&disk->open_mutex); +@@ -559,8 +562,13 @@ static bool blk_add_partition(struct gendisk *disk, + size = get_capacity(disk) - from; + } + ++#ifdef CONFIG_OF + part = add_partition(disk, p, from, size, state->parts[p].flags, +- &state->parts[p].info); ++ &state->parts[p].info, state->parts[p].np); ++#else ++ part = add_partition(disk, p, from, size, state->parts[p].flags, ++ &state->parts[p].info, NULL); ++#endif + if (IS_ERR(part)) { + if (PTR_ERR(part) != -ENXIO) { + printk(KERN_ERR " %s: p%d could not be added: %pe\n", +-- +2.51.0 + + +From f63140ada721fe7cd8818daf12912032df2dff53 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Mon, 7 Oct 2024 23:43:32 +0100 +Subject: [PATCH 221/517] block: partitions: of: assign Device Tree node to + partition + +Assign partition of_node so other drivers are able to identify a +partition by its Device Tree node. + +Signed-off-by: Daniel Golle +--- + block/partitions/of.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/block/partitions/of.c b/block/partitions/of.c +index 4e760fdffb3f..8b82f9f39686 100644 +--- a/block/partitions/of.c ++++ b/block/partitions/of.c +@@ -48,7 +48,7 @@ static void add_of_partition(struct parsed_partitions *state, int slot, + u64 offset = of_read_number(reg, a_cells) / SECTOR_SIZE; + u64 size = of_read_number(reg + a_cells, s_cells) / SECTOR_SIZE; + +- put_partition(state, slot, offset, size); ++ of_put_partition(state, slot, offset, size, np); + + if (of_property_read_bool(np, "read-only")) + state->parts[slot].flags |= ADDPART_FLAG_READONLY; +-- +2.51.0 + + +From 15a3c6b896f516d704bf3b54a4f3f2837e738481 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Mon, 7 Oct 2024 23:22:53 +0100 +Subject: [PATCH 222/517] partitions/efi: apply Linux code style + +Fix (mostly white space related) coding style issues in +block/partitions/efi.c by use of clang-format. + +Signed-off-by: Daniel Golle +--- + block/partitions/efi.c | 235 +++++++++++++++++++++-------------------- + 1 file changed, 121 insertions(+), 114 deletions(-) + +diff --git a/block/partitions/efi.c b/block/partitions/efi.c +index 7acba66eed48..4e31f6c09f70 100644 +--- a/block/partitions/efi.c ++++ b/block/partitions/efi.c +@@ -95,15 +95,13 @@ + * the partition tables happens after init too. + */ + static int force_gpt; +-static int __init +-force_gpt_fn(char *str) ++static int __init force_gpt_fn(char *str) + { + force_gpt = 1; + return 1; + } + __setup("gpt", force_gpt_fn); + +- + /** + * efi_crc32() - EFI version of crc32 function + * @buf: buffer to calculate crc32 of +@@ -116,8 +114,7 @@ __setup("gpt", force_gpt_fn); + * Note, the EFI Specification, v1.02, has a reference to + * Dr. Dobbs Journal, May 1994 (actually it's in May 1992). + */ +-static inline u32 +-efi_crc32(const void *buf, unsigned long len) ++static inline u32 efi_crc32(const void *buf, unsigned long len) + { + return (crc32(~0L, buf, len) ^ ~0L); + } +@@ -134,7 +131,8 @@ efi_crc32(const void *buf, unsigned long len) + static u64 last_lba(struct gendisk *disk) + { + return div_u64(bdev_nr_bytes(disk->part0), +- queue_logical_block_size(disk->queue)) - 1ULL; ++ queue_logical_block_size(disk->queue)) - ++ 1ULL; + } + + static inline int pmbr_part_valid(gpt_mbr_record *part) +@@ -195,7 +193,7 @@ static int is_pmbr_valid(legacy_mbr *mbr, sector_t total_sectors) + check_hybrid: + for (i = 0; i < 4; i++) + if ((mbr->partition_record[i].os_type != +- EFI_PMBR_OSTYPE_EFI_GPT) && ++ EFI_PMBR_OSTYPE_EFI_GPT) && + (mbr->partition_record[i].os_type != 0x00)) + ret = GPT_MBR_HYBRID; + +@@ -213,10 +211,11 @@ static int is_pmbr_valid(legacy_mbr *mbr, sector_t total_sectors) + */ + if (ret == GPT_MBR_PROTECTIVE) { + sz = le32_to_cpu(mbr->partition_record[part].size_in_lba); +- if (sz != (uint32_t) total_sectors - 1 && sz != 0xFFFFFFFF) +- pr_debug("GPT: mbr size in lba (%u) different than whole disk (%u).\n", +- sz, min_t(uint32_t, +- total_sectors - 1, 0xFFFFFFFF)); ++ if (sz != (uint32_t)total_sectors - 1 && sz != 0xFFFFFFFF) ++ pr_debug( ++ "GPT: mbr size in lba (%u) different than whole disk (%u).\n", ++ sz, ++ min_t(uint32_t, total_sectors - 1, 0xFFFFFFFF)); + } + done: + return ret; +@@ -232,15 +231,14 @@ static int is_pmbr_valid(legacy_mbr *mbr, sector_t total_sectors) + * Description: Reads @count bytes from @state->disk into @buffer. + * Returns number of bytes read on success, 0 on error. + */ +-static size_t read_lba(struct parsed_partitions *state, +- u64 lba, u8 *buffer, size_t count) ++static size_t read_lba(struct parsed_partitions *state, u64 lba, u8 *buffer, ++ size_t count) + { + size_t totalreadcount = 0; +- sector_t n = lba * +- (queue_logical_block_size(state->disk->queue) / 512); ++ sector_t n = lba * (queue_logical_block_size(state->disk->queue) / 512); + + if (!buffer || lba > last_lba(state->disk)) +- return 0; ++ return 0; + + while (count) { + int copied = 512; +@@ -253,7 +251,7 @@ static size_t read_lba(struct parsed_partitions *state, + memcpy(buffer, data, copied); + put_dev_sector(sect); + buffer += copied; +- totalreadcount +=copied; ++ totalreadcount += copied; + count -= copied; + } + return totalreadcount; +@@ -278,17 +276,17 @@ static gpt_entry *alloc_read_gpt_entries(struct parsed_partitions *state, + return NULL; + + count = (size_t)le32_to_cpu(gpt->num_partition_entries) * +- le32_to_cpu(gpt->sizeof_partition_entry); ++ le32_to_cpu(gpt->sizeof_partition_entry); + if (!count) + return NULL; + pte = kmalloc(count, GFP_KERNEL); + if (!pte) + return NULL; + +- if (read_lba(state, le64_to_cpu(gpt->partition_entry_lba), +- (u8 *) pte, count) < count) { ++ if (read_lba(state, le64_to_cpu(gpt->partition_entry_lba), (u8 *)pte, ++ count) < count) { + kfree(pte); +- pte=NULL; ++ pte = NULL; + return NULL; + } + return pte; +@@ -313,9 +311,9 @@ static gpt_header *alloc_read_gpt_header(struct parsed_partitions *state, + if (!gpt) + return NULL; + +- if (read_lba(state, lba, (u8 *) gpt, ssz) < ssz) { ++ if (read_lba(state, lba, (u8 *)gpt, ssz) < ssz) { + kfree(gpt); +- gpt=NULL; ++ gpt = NULL; + return NULL; + } + +@@ -354,8 +352,9 @@ static int is_gpt_valid(struct parsed_partitions *state, u64 lba, + + /* Check the GUID Partition Table header size is too big */ + if (le32_to_cpu((*gpt)->header_size) > +- queue_logical_block_size(state->disk->queue)) { +- pr_debug("GUID Partition Table Header size is too large: %u > %u\n", ++ queue_logical_block_size(state->disk->queue)) { ++ pr_debug( ++ "GUID Partition Table Header size is too large: %u > %u\n", + le32_to_cpu((*gpt)->header_size), + queue_logical_block_size(state->disk->queue)); + goto fail; +@@ -363,16 +362,17 @@ static int is_gpt_valid(struct parsed_partitions *state, u64 lba, + + /* Check the GUID Partition Table header size is too small */ + if (le32_to_cpu((*gpt)->header_size) < sizeof(gpt_header)) { +- pr_debug("GUID Partition Table Header size is too small: %u < %zu\n", +- le32_to_cpu((*gpt)->header_size), +- sizeof(gpt_header)); ++ pr_debug( ++ "GUID Partition Table Header size is too small: %u < %zu\n", ++ le32_to_cpu((*gpt)->header_size), sizeof(gpt_header)); + goto fail; + } + + /* Check the GUID Partition Table CRC */ + origcrc = le32_to_cpu((*gpt)->header_crc32); + (*gpt)->header_crc32 = 0; +- crc = efi_crc32((const unsigned char *) (*gpt), le32_to_cpu((*gpt)->header_size)); ++ crc = efi_crc32((const unsigned char *)(*gpt), ++ le32_to_cpu((*gpt)->header_size)); + + if (crc != origcrc) { + pr_debug("GUID Partition Table Header CRC is wrong: %x != %x\n", +@@ -396,20 +396,25 @@ static int is_gpt_valid(struct parsed_partitions *state, u64 lba, + lastlba = last_lba(state->disk); + if (le64_to_cpu((*gpt)->first_usable_lba) > lastlba) { + pr_debug("GPT: first_usable_lba incorrect: %lld > %lld\n", +- (unsigned long long)le64_to_cpu((*gpt)->first_usable_lba), ++ (unsigned long long)le64_to_cpu( ++ (*gpt)->first_usable_lba), + (unsigned long long)lastlba); + goto fail; + } + if (le64_to_cpu((*gpt)->last_usable_lba) > lastlba) { + pr_debug("GPT: last_usable_lba incorrect: %lld > %lld\n", +- (unsigned long long)le64_to_cpu((*gpt)->last_usable_lba), ++ (unsigned long long)le64_to_cpu( ++ (*gpt)->last_usable_lba), + (unsigned long long)lastlba); + goto fail; + } +- if (le64_to_cpu((*gpt)->last_usable_lba) < le64_to_cpu((*gpt)->first_usable_lba)) { ++ if (le64_to_cpu((*gpt)->last_usable_lba) < ++ le64_to_cpu((*gpt)->first_usable_lba)) { + pr_debug("GPT: last_usable_lba incorrect: %lld > %lld\n", +- (unsigned long long)le64_to_cpu((*gpt)->last_usable_lba), +- (unsigned long long)le64_to_cpu((*gpt)->first_usable_lba)); ++ (unsigned long long)le64_to_cpu( ++ (*gpt)->last_usable_lba), ++ (unsigned long long)le64_to_cpu( ++ (*gpt)->first_usable_lba)); + goto fail; + } + /* Check that sizeof_partition_entry has the correct value */ +@@ -420,10 +425,11 @@ static int is_gpt_valid(struct parsed_partitions *state, u64 lba, + + /* Sanity check partition table size */ + pt_size = (u64)le32_to_cpu((*gpt)->num_partition_entries) * +- le32_to_cpu((*gpt)->sizeof_partition_entry); ++ le32_to_cpu((*gpt)->sizeof_partition_entry); + if (pt_size > KMALLOC_MAX_SIZE) { +- pr_debug("GUID Partition Table is too large: %llu > %lu bytes\n", +- (unsigned long long)pt_size, KMALLOC_MAX_SIZE); ++ pr_debug( ++ "GUID Partition Table is too large: %llu > %lu bytes\n", ++ (unsigned long long)pt_size, KMALLOC_MAX_SIZE); + goto fail; + } + +@@ -431,7 +437,7 @@ static int is_gpt_valid(struct parsed_partitions *state, u64 lba, + goto fail; + + /* Check the GUID Partition Entry Array CRC */ +- crc = efi_crc32((const unsigned char *) (*ptes), pt_size); ++ crc = efi_crc32((const unsigned char *)(*ptes), pt_size); + + if (crc != le32_to_cpu((*gpt)->partition_entry_array_crc32)) { + pr_debug("GUID Partition Entry Array CRC check failed.\n"); +@@ -441,10 +447,10 @@ static int is_gpt_valid(struct parsed_partitions *state, u64 lba, + /* We're done, all's well */ + return 1; + +- fail_ptes: ++fail_ptes: + kfree(*ptes); + *ptes = NULL; +- fail: ++fail: + kfree(*gpt); + *gpt = NULL; + return 0; +@@ -457,12 +463,11 @@ static int is_gpt_valid(struct parsed_partitions *state, u64 lba, + * + * Description: returns 1 if valid, 0 on error. + */ +-static inline int +-is_pte_valid(const gpt_entry *pte, const u64 lastlba) ++static inline int is_pte_valid(const gpt_entry *pte, const u64 lastlba) + { + if ((!efi_guidcmp(pte->partition_type_guid, NULL_GUID)) || +- le64_to_cpu(pte->starting_lba) > lastlba || +- le64_to_cpu(pte->ending_lba) > lastlba) ++ le64_to_cpu(pte->starting_lba) > lastlba || ++ le64_to_cpu(pte->ending_lba) > lastlba) + return 0; + return 1; + } +@@ -477,8 +482,7 @@ is_pte_valid(const gpt_entry *pte, const u64 lastlba) + * and prints warnings on discrepancies. + * + */ +-static void +-compare_gpts(gpt_header *pgpt, gpt_header *agpt, u64 lastlba) ++static void compare_gpts(gpt_header *pgpt, gpt_header *agpt, u64 lastlba) + { + int error_found = 0; + if (!pgpt || !agpt) +@@ -486,31 +490,32 @@ compare_gpts(gpt_header *pgpt, gpt_header *agpt, u64 lastlba) + if (le64_to_cpu(pgpt->my_lba) != le64_to_cpu(agpt->alternate_lba)) { + pr_warn("GPT:Primary header LBA != Alt. header alternate_lba\n"); + pr_warn("GPT:%lld != %lld\n", +- (unsigned long long)le64_to_cpu(pgpt->my_lba), +- (unsigned long long)le64_to_cpu(agpt->alternate_lba)); ++ (unsigned long long)le64_to_cpu(pgpt->my_lba), ++ (unsigned long long)le64_to_cpu(agpt->alternate_lba)); + error_found++; + } + if (le64_to_cpu(pgpt->alternate_lba) != le64_to_cpu(agpt->my_lba)) { + pr_warn("GPT:Primary header alternate_lba != Alt. header my_lba\n"); + pr_warn("GPT:%lld != %lld\n", +- (unsigned long long)le64_to_cpu(pgpt->alternate_lba), +- (unsigned long long)le64_to_cpu(agpt->my_lba)); ++ (unsigned long long)le64_to_cpu(pgpt->alternate_lba), ++ (unsigned long long)le64_to_cpu(agpt->my_lba)); + error_found++; + } + if (le64_to_cpu(pgpt->first_usable_lba) != +- le64_to_cpu(agpt->first_usable_lba)) { ++ le64_to_cpu(agpt->first_usable_lba)) { + pr_warn("GPT:first_usable_lbas don't match.\n"); + pr_warn("GPT:%lld != %lld\n", +- (unsigned long long)le64_to_cpu(pgpt->first_usable_lba), +- (unsigned long long)le64_to_cpu(agpt->first_usable_lba)); ++ (unsigned long long)le64_to_cpu(pgpt->first_usable_lba), ++ (unsigned long long)le64_to_cpu( ++ agpt->first_usable_lba)); + error_found++; + } + if (le64_to_cpu(pgpt->last_usable_lba) != +- le64_to_cpu(agpt->last_usable_lba)) { ++ le64_to_cpu(agpt->last_usable_lba)) { + pr_warn("GPT:last_usable_lbas don't match.\n"); + pr_warn("GPT:%lld != %lld\n", +- (unsigned long long)le64_to_cpu(pgpt->last_usable_lba), +- (unsigned long long)le64_to_cpu(agpt->last_usable_lba)); ++ (unsigned long long)le64_to_cpu(pgpt->last_usable_lba), ++ (unsigned long long)le64_to_cpu(agpt->last_usable_lba)); + error_found++; + } + if (efi_guidcmp(pgpt->disk_guid, agpt->disk_guid)) { +@@ -518,27 +523,27 @@ compare_gpts(gpt_header *pgpt, gpt_header *agpt, u64 lastlba) + error_found++; + } + if (le32_to_cpu(pgpt->num_partition_entries) != +- le32_to_cpu(agpt->num_partition_entries)) { ++ le32_to_cpu(agpt->num_partition_entries)) { + pr_warn("GPT:num_partition_entries don't match: " +- "0x%x != 0x%x\n", +- le32_to_cpu(pgpt->num_partition_entries), +- le32_to_cpu(agpt->num_partition_entries)); ++ "0x%x != 0x%x\n", ++ le32_to_cpu(pgpt->num_partition_entries), ++ le32_to_cpu(agpt->num_partition_entries)); + error_found++; + } + if (le32_to_cpu(pgpt->sizeof_partition_entry) != +- le32_to_cpu(agpt->sizeof_partition_entry)) { ++ le32_to_cpu(agpt->sizeof_partition_entry)) { + pr_warn("GPT:sizeof_partition_entry values don't match: " +- "0x%x != 0x%x\n", +- le32_to_cpu(pgpt->sizeof_partition_entry), +- le32_to_cpu(agpt->sizeof_partition_entry)); ++ "0x%x != 0x%x\n", ++ le32_to_cpu(pgpt->sizeof_partition_entry), ++ le32_to_cpu(agpt->sizeof_partition_entry)); + error_found++; + } + if (le32_to_cpu(pgpt->partition_entry_array_crc32) != +- le32_to_cpu(agpt->partition_entry_array_crc32)) { ++ le32_to_cpu(agpt->partition_entry_array_crc32)) { + pr_warn("GPT:partition_entry_array_crc32 values don't match: " +- "0x%x != 0x%x\n", +- le32_to_cpu(pgpt->partition_entry_array_crc32), +- le32_to_cpu(agpt->partition_entry_array_crc32)); ++ "0x%x != 0x%x\n", ++ le32_to_cpu(pgpt->partition_entry_array_crc32), ++ le32_to_cpu(agpt->partition_entry_array_crc32)); + error_found++; + } + if (le64_to_cpu(pgpt->alternate_lba) != lastlba) { +@@ -594,7 +599,7 @@ static int find_valid_gpt(struct parsed_partitions *state, gpt_header **gpt, + return 0; + + lastlba = last_lba(state->disk); +- if (!force_gpt) { ++ if (!force_gpt) { + /* This will be added to the EFI Spec. per Intel after v1.02. */ + legacymbr = kzalloc(sizeof(*legacymbr), GFP_KERNEL); + if (!legacymbr) +@@ -608,18 +613,17 @@ static int find_valid_gpt(struct parsed_partitions *state, gpt_header **gpt, + goto fail; + + pr_debug("Device has a %s MBR\n", +- good_pmbr == GPT_MBR_PROTECTIVE ? +- "protective" : "hybrid"); ++ good_pmbr == GPT_MBR_PROTECTIVE ? "protective" : ++ "hybrid"); + } + +- good_pgpt = is_gpt_valid(state, GPT_PRIMARY_PARTITION_TABLE_LBA, +- &pgpt, &pptes); +- if (good_pgpt) +- good_agpt = is_gpt_valid(state, +- le64_to_cpu(pgpt->alternate_lba), +- &agpt, &aptes); +- if (!good_agpt && force_gpt) +- good_agpt = is_gpt_valid(state, lastlba, &agpt, &aptes); ++ good_pgpt = is_gpt_valid(state, GPT_PRIMARY_PARTITION_TABLE_LBA, &pgpt, ++ &pptes); ++ if (good_pgpt) ++ good_agpt = is_gpt_valid( ++ state, le64_to_cpu(pgpt->alternate_lba), &agpt, &aptes); ++ if (!good_agpt && force_gpt) ++ good_agpt = is_gpt_valid(state, lastlba, &agpt, &aptes); + + if (!good_agpt && force_gpt && fops->alternative_gpt_sector) { + sector_t agpt_sector; +@@ -627,43 +631,42 @@ static int find_valid_gpt(struct parsed_partitions *state, gpt_header **gpt, + + err = fops->alternative_gpt_sector(disk, &agpt_sector); + if (!err) +- good_agpt = is_gpt_valid(state, agpt_sector, +- &agpt, &aptes); ++ good_agpt = ++ is_gpt_valid(state, agpt_sector, &agpt, &aptes); + } + +- /* The obviously unsuccessful case */ +- if (!good_pgpt && !good_agpt) +- goto fail; ++ /* The obviously unsuccessful case */ ++ if (!good_pgpt && !good_agpt) ++ goto fail; + +- compare_gpts(pgpt, agpt, lastlba); ++ compare_gpts(pgpt, agpt, lastlba); + +- /* The good cases */ +- if (good_pgpt) { +- *gpt = pgpt; +- *ptes = pptes; +- kfree(agpt); +- kfree(aptes); ++ /* The good cases */ ++ if (good_pgpt) { ++ *gpt = pgpt; ++ *ptes = pptes; ++ kfree(agpt); ++ kfree(aptes); + if (!good_agpt) +- pr_warn("Alternate GPT is invalid, using primary GPT.\n"); +- return 1; +- } +- else if (good_agpt) { +- *gpt = agpt; +- *ptes = aptes; +- kfree(pgpt); +- kfree(pptes); ++ pr_warn("Alternate GPT is invalid, using primary GPT.\n"); ++ return 1; ++ } else if (good_agpt) { ++ *gpt = agpt; ++ *ptes = aptes; ++ kfree(pgpt); ++ kfree(pptes); + pr_warn("Primary GPT is invalid, using alternate GPT.\n"); +- return 1; +- } +- +- fail: +- kfree(pgpt); +- kfree(agpt); +- kfree(pptes); +- kfree(aptes); +- *gpt = NULL; +- *ptes = NULL; +- return 0; ++ return 1; ++ } ++ ++fail: ++ kfree(pgpt); ++ kfree(agpt); ++ kfree(pptes); ++ kfree(aptes); ++ *gpt = NULL; ++ *ptes = NULL; ++ return 0; + } + + /** +@@ -725,7 +728,9 @@ int efi_partition(struct parsed_partitions *state) + + pr_debug("GUID Partition Table is valid! Yea!\n"); + +- for (i = 0; i < le32_to_cpu(gpt->num_partition_entries) && i < state->limit-1; i++) { ++ for (i = 0; i < le32_to_cpu(gpt->num_partition_entries) && ++ i < state->limit - 1; ++ i++) { + struct partition_meta_info *info; + unsigned label_max; + u64 start = le64_to_cpu(ptes[i].starting_lba); +@@ -735,10 +740,11 @@ int efi_partition(struct parsed_partitions *state) + if (!is_pte_valid(&ptes[i], last_lba(state->disk))) + continue; + +- put_partition(state, i+1, start * ssz, size * ssz); ++ put_partition(state, i + 1, start * ssz, size * ssz); + + /* If this is a RAID volume, tell md */ +- if (!efi_guidcmp(ptes[i].partition_type_guid, PARTITION_LINUX_RAID_GUID)) ++ if (!efi_guidcmp(ptes[i].partition_type_guid, ++ PARTITION_LINUX_RAID_GUID)) + state->parts[i + 1].flags = ADDPART_FLAG_RAID; + + info = &state->parts[i + 1].info; +@@ -747,7 +753,8 @@ int efi_partition(struct parsed_partitions *state) + /* Naively convert UTF16-LE to 7 bits. */ + label_max = min(ARRAY_SIZE(info->volname) - 1, + ARRAY_SIZE(ptes[i].partition_name)); +- utf16_le_to_7bit(ptes[i].partition_name, label_max, info->volname); ++ utf16_le_to_7bit(ptes[i].partition_name, label_max, ++ info->volname); + state->parts[i + 1].has_info = true; + } + kfree(ptes); +-- +2.51.0 + + +From fb79f53b4383405a574e9d12a6101ea4ff10e3d2 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Tue, 8 Oct 2024 00:25:12 +0100 +Subject: [PATCH 223/517] partitions/efi: allow assigning partition Device Tree + node + +Signed-off-by: Daniel Golle +--- + block/partitions/efi.c | 34 +++++++++++++++++++++++++++++++++- + 1 file changed, 33 insertions(+), 1 deletion(-) + +diff --git a/block/partitions/efi.c b/block/partitions/efi.c +index 4e31f6c09f70..ac2c7d3c4993 100644 +--- a/block/partitions/efi.c ++++ b/block/partitions/efi.c +@@ -86,6 +86,7 @@ + #include + #include + #include ++#include + #include + #include "check.h" + #include "efi.h" +@@ -694,6 +695,34 @@ static void utf16_le_to_7bit(const __le16 *in, unsigned int size, u8 *out) + } + } + ++static struct device_node *find_partition_of_node(struct device_node *partitions_np, ++ gpt_entry *ptes) ++{ ++ char volname[64], partuuid[UUID_STRING_LEN + 1]; ++ const char *uuid, *name; ++ ++ if (!partitions_np || ++ !of_device_is_compatible(partitions_np, "gpt-partitions")) ++ return NULL; ++ ++ efi_guid_to_str(&ptes->unique_partition_guid, partuuid); ++ utf16_le_to_7bit(ptes->partition_name, ARRAY_SIZE(volname) - 1, volname); ++ ++ for_each_available_child_of_node_scoped(partitions_np, np) { ++ if (!of_property_read_string(np, "uuid", &uuid) && ++ strncmp(uuid, partuuid, ARRAY_SIZE(partuuid))) ++ continue; ++ ++ if (!of_property_read_string(np, "partname", &name) && ++ strncmp(name, volname, ARRAY_SIZE(volname))) ++ continue; ++ ++ return np; ++ } ++ ++ return NULL; ++} ++ + /** + * efi_partition - scan for GPT partitions + * @state: disk parsed partitions +@@ -719,6 +748,8 @@ int efi_partition(struct parsed_partitions *state) + gpt_entry *ptes = NULL; + u32 i; + unsigned ssz = queue_logical_block_size(state->disk->queue) / 512; ++ struct device *ddev = disk_to_dev(state->disk); ++ struct device_node *partitions_np = of_node_get(ddev->of_node); + + if (!find_valid_gpt(state, &gpt, &ptes) || !gpt || !ptes) { + kfree(gpt); +@@ -740,7 +771,8 @@ int efi_partition(struct parsed_partitions *state) + if (!is_pte_valid(&ptes[i], last_lba(state->disk))) + continue; + +- put_partition(state, i + 1, start * ssz, size * ssz); ++ of_put_partition(state, i + 1, start * ssz, size * ssz, ++ find_partition_of_node(partitions_np, &ptes[i])); + + /* If this is a RAID volume, tell md */ + if (!efi_guidcmp(ptes[i].partition_type_guid, +-- +2.51.0 + + +From d4f29e2f7c6db41a6ea7112427078c805d8bd3e3 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Wed, 15 May 2024 08:19:51 +0100 +Subject: [PATCH 224/517] block: add support for notifications + +Add notifier block to notify other subsystems about the addition or +removal of block devices. + +Signed-off-by: Daniel Golle +--- + block/Kconfig | 6 +++ + block/Makefile | 1 + + block/blk-notify.c | 107 +++++++++++++++++++++++++++++++++++++++++ + include/linux/blkdev.h | 8 +++ + 4 files changed, 122 insertions(+) + create mode 100644 block/blk-notify.c + +diff --git a/block/Kconfig b/block/Kconfig +index 5b623b876d3b..67cd4f92378a 100644 +--- a/block/Kconfig ++++ b/block/Kconfig +@@ -209,6 +209,12 @@ config BLK_INLINE_ENCRYPTION_FALLBACK + by falling back to the kernel crypto API when inline + encryption hardware is not present. + ++config BLOCK_NOTIFIERS ++ bool "Enable support for notifications in block layer" ++ help ++ Enable this option to provide notifiers for other subsystems ++ upon addition or removal of block devices. ++ + source "block/partitions/Kconfig" + + config BLK_MQ_PCI +diff --git a/block/Makefile b/block/Makefile +index ddfd21c1a9ff..a131fa7d6b26 100644 +--- a/block/Makefile ++++ b/block/Makefile +@@ -38,3 +38,4 @@ obj-$(CONFIG_BLK_INLINE_ENCRYPTION) += blk-crypto.o blk-crypto-profile.o \ + blk-crypto-sysfs.o + obj-$(CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK) += blk-crypto-fallback.o + obj-$(CONFIG_BLOCK_HOLDER_DEPRECATED) += holder.o ++obj-$(CONFIG_BLOCK_NOTIFIERS) += blk-notify.o +diff --git a/block/blk-notify.c b/block/blk-notify.c +new file mode 100644 +index 000000000000..880e48a3f765 +--- /dev/null ++++ b/block/blk-notify.c +@@ -0,0 +1,107 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Notifiers for addition and removal of block devices ++ * ++ * Copyright (c) 2024 Daniel Golle ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "blk.h" ++ ++struct blk_device_list { ++ struct device *dev; ++ struct list_head list; ++}; ++ ++static RAW_NOTIFIER_HEAD(blk_notifier_list); ++static DEFINE_MUTEX(blk_notifier_lock); ++static LIST_HEAD(blk_devices); ++ ++struct blk_notify_event { ++ struct delayed_work work; ++ struct device *dev; ++}; ++ ++void blk_register_notify(struct notifier_block *nb) ++{ ++ struct blk_device_list *existing_blkdev; ++ ++ mutex_lock(&blk_notifier_lock); ++ raw_notifier_chain_register(&blk_notifier_list, nb); ++ ++ list_for_each_entry(existing_blkdev, &blk_devices, list) ++ nb->notifier_call(nb, BLK_DEVICE_ADD, existing_blkdev->dev); ++ ++ mutex_unlock(&blk_notifier_lock); ++} ++EXPORT_SYMBOL_GPL(blk_register_notify); ++ ++void blk_unregister_notify(struct notifier_block *nb) ++{ ++ mutex_lock(&blk_notifier_lock); ++ raw_notifier_chain_unregister(&blk_notifier_list, nb); ++ mutex_unlock(&blk_notifier_lock); ++} ++EXPORT_SYMBOL_GPL(blk_unregister_notify); ++ ++static void blk_notify_work(struct work_struct *work) ++{ ++ struct blk_notify_event *ev = ++ container_of(work, struct blk_notify_event, work.work); ++ ++ raw_notifier_call_chain(&blk_notifier_list, BLK_DEVICE_ADD, ev->dev); ++ kfree(ev); ++} ++ ++static int blk_call_notifier_add(struct device *dev) ++{ ++ struct blk_device_list *new_blkdev; ++ struct blk_notify_event *ev; ++ ++ new_blkdev = kmalloc(sizeof (*new_blkdev), GFP_KERNEL); ++ if (!new_blkdev) ++ return -ENOMEM; ++ ++ ev = kmalloc(sizeof(*ev), GFP_KERNEL); ++ INIT_DEFERRABLE_WORK(&ev->work, blk_notify_work); ++ ev->dev = dev; ++ new_blkdev->dev = dev; ++ mutex_lock(&blk_notifier_lock); ++ list_add_tail(&new_blkdev->list, &blk_devices); ++ schedule_delayed_work(&ev->work, msecs_to_jiffies(500)); ++ mutex_unlock(&blk_notifier_lock); ++ ++ return 0; ++} ++ ++static void blk_call_notifier_remove(struct device *dev) ++{ ++ struct blk_device_list *old_blkdev, *tmp; ++ ++ mutex_lock(&blk_notifier_lock); ++ list_for_each_entry_safe(old_blkdev, tmp, &blk_devices, list) { ++ if (old_blkdev->dev != dev) ++ continue; ++ ++ list_del(&old_blkdev->list); ++ kfree(old_blkdev); ++ } ++ raw_notifier_call_chain(&blk_notifier_list, BLK_DEVICE_REMOVE, dev); ++ mutex_unlock(&blk_notifier_lock); ++} ++ ++static struct class_interface blk_notifications_bus_interface __refdata = { ++ .class = &block_class, ++ .add_dev = &blk_call_notifier_add, ++ .remove_dev = &blk_call_notifier_remove, ++}; ++ ++static int __init blk_notifications_init(void) ++{ ++ return class_interface_register(&blk_notifications_bus_interface); ++} ++device_initcall(blk_notifications_init); +diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h +index fa9d324b7069..822b8daec45d 100644 +--- a/include/linux/blkdev.h ++++ b/include/linux/blkdev.h +@@ -1753,4 +1753,12 @@ static inline bool bdev_can_atomic_write(struct block_device *bdev) + + #define DEFINE_IO_COMP_BATCH(name) struct io_comp_batch name = { } + ++ ++#ifdef CONFIG_BLOCK_NOTIFIERS ++#define BLK_DEVICE_ADD 1 ++#define BLK_DEVICE_REMOVE 2 ++extern void blk_register_notify(struct notifier_block *nb); ++extern void blk_unregister_notify(struct notifier_block *nb); ++#endif ++ + #endif /* _LINUX_BLKDEV_H */ +-- +2.51.0 + + +From 80ab21df365232ab1db9e4734a474940f24b741e Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Thu, 21 Mar 2024 19:33:49 +0000 +Subject: [PATCH 225/517] block: add new genhd flag GENHD_FL_NVMEM + +Add new flag to destinguish block devices which may act as an NVMEM +provider. + +Signed-off-by: Daniel Golle +--- + include/linux/blkdev.h | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h +index 822b8daec45d..8213eb3670fe 100644 +--- a/include/linux/blkdev.h ++++ b/include/linux/blkdev.h +@@ -82,11 +82,13 @@ struct partition_meta_info { + * ``GENHD_FL_NO_PART``: partition support is disabled. The kernel will not + * scan for partitions from add_disk, and users can't add partitions manually. + * ++ * ``GENHD_FL_NVMEM``: the block device should be considered as NVMEM provider. + */ + enum { + GENHD_FL_REMOVABLE = 1 << 0, + GENHD_FL_HIDDEN = 1 << 1, + GENHD_FL_NO_PART = 1 << 2, ++ GENHD_FL_NVMEM = 1 << 3, + }; + + enum { +-- +2.51.0 + + +From 505eb071cbc1260ffb37d27dd638d2154af1cea8 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Wed, 15 May 2024 18:18:37 +0300 +Subject: [PATCH 226/517] nvmem: implement block NVMEM provider + +On embedded devices using an eMMC it is common that one or more partitions +on the eMMC are used to store MAC addresses and Wi-Fi calibration EEPROM +data. Allow referencing any block device or partition in Device Tree to +allow e.g. Ethernet and Wi-Fi drivers accessing them via the NVMEM layer. + +Signed-off-by: Daniel Golle +--- + drivers/nvmem/Kconfig | 11 +++ + drivers/nvmem/Makefile | 2 + + drivers/nvmem/block.c | 198 +++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 211 insertions(+) + create mode 100644 drivers/nvmem/block.c + +diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig +index d2c384f58028..40b5fd1bfde4 100644 +--- a/drivers/nvmem/Kconfig ++++ b/drivers/nvmem/Kconfig +@@ -40,6 +40,17 @@ config NVMEM_APPLE_EFUSES + This driver can also be built as a module. If so, the module will + be called nvmem-apple-efuses. + ++config NVMEM_BLOCK ++ tristate "Block device NVMEM provider" ++ depends on BLOCK ++ depends on OF ++ depends on NVMEM ++ select BLOCK_NOTIFIERS ++ help ++ Allow block devices (or partitions) to act as NVMEM prodivers, ++ typically used with eMMC to store MAC addresses or Wi-Fi ++ calibration data on embedded devices. ++ + config NVMEM_BCM_OCOTP + tristate "Broadcom On-Chip OTP Controller support" + depends on ARCH_BCM_IPROC || COMPILE_TEST +diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile +index cdd01fbf1313..68fcf845f417 100644 +--- a/drivers/nvmem/Makefile ++++ b/drivers/nvmem/Makefile +@@ -14,6 +14,8 @@ obj-$(CONFIG_NVMEM_APPLE_EFUSES) += nvmem-apple-efuses.o + nvmem-apple-efuses-y := apple-efuses.o + obj-$(CONFIG_NVMEM_BCM_OCOTP) += nvmem-bcm-ocotp.o + nvmem-bcm-ocotp-y := bcm-ocotp.o ++obj-$(CONFIG_NVMEM_BLOCK) += nvmem-block.o ++nvmem-block-y := block.o + obj-$(CONFIG_NVMEM_BRCM_NVRAM) += nvmem_brcm_nvram.o + nvmem_brcm_nvram-y := brcm_nvram.o + obj-$(CONFIG_NVMEM_IMX_IIM) += nvmem-imx-iim.o +diff --git a/drivers/nvmem/block.c b/drivers/nvmem/block.c +new file mode 100644 +index 000000000000..dc9e43f98616 +--- /dev/null ++++ b/drivers/nvmem/block.c +@@ -0,0 +1,198 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * block device NVMEM provider ++ * ++ * Copyright (c) 2024 Daniel Golle ++ * ++ * Useful on devices using a partition on an eMMC for MAC addresses or ++ * Wi-Fi calibration EEPROM data. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++/* List of all NVMEM devices */ ++static LIST_HEAD(nvmem_devices); ++static DEFINE_MUTEX(devices_mutex); ++ ++struct blk_nvmem { ++ struct nvmem_device *nvmem; ++ struct device *dev; ++ struct list_head list; ++}; ++ ++static int blk_nvmem_reg_read(void *priv, unsigned int from, ++ void *val, size_t bytes) ++{ ++ blk_mode_t mode = BLK_OPEN_READ | BLK_OPEN_RESTRICT_WRITES; ++ unsigned long offs = from & ~PAGE_MASK, to_read; ++ pgoff_t f_index = from >> PAGE_SHIFT; ++ struct blk_nvmem *bnv = priv; ++ size_t bytes_left = bytes; ++ struct file *bdev_file; ++ struct folio *folio; ++ void *p; ++ int ret = 0; ++ ++ bdev_file = bdev_file_open_by_dev(bnv->dev->devt, mode, priv, NULL); ++ if (!bdev_file) ++ return -ENODEV; ++ ++ if (IS_ERR(bdev_file)) ++ return PTR_ERR(bdev_file); ++ ++ while (bytes_left) { ++ folio = read_mapping_folio(bdev_file->f_mapping, f_index++, NULL); ++ if (IS_ERR(folio)) { ++ ret = PTR_ERR(folio); ++ goto err_release_bdev; ++ } ++ to_read = min_t(unsigned long, bytes_left, PAGE_SIZE - offs); ++ p = folio_address(folio) + offset_in_folio(folio, offs); ++ memcpy(val, p, to_read); ++ offs = 0; ++ bytes_left -= to_read; ++ val += to_read; ++ folio_put(folio); ++ } ++ ++err_release_bdev: ++ fput(bdev_file); ++ ++ return ret; ++} ++ ++static int blk_nvmem_register(struct device *dev) ++{ ++ struct block_device *bdev = dev_to_bdev(dev); ++ struct device_node *np = dev_of_node(dev); ++ struct nvmem_config config = {}; ++ struct blk_nvmem *bnv; ++ ++ /* skip devices which do not have a device tree node */ ++ if (!np) ++ return 0; ++ ++ /* skip devices without an nvmem layout defined */ ++ if (!of_get_child_by_name(np, "nvmem-layout")) ++ return 0; ++ ++ /* ++ * skip devices which don't have GENHD_FL_NVMEM set ++ * ++ * This flag is used for mtdblock and ubiblock devices because ++ * both, MTD and UBI already implement their own NVMEM provider. ++ * To avoid registering multiple NVMEM providers for the same ++ * device node, don't register the block NVMEM provider for them. ++ */ ++ if (!(bdev->bd_disk->flags & GENHD_FL_NVMEM)) ++ return 0; ++ ++ /* ++ * skip block device too large to be represented as NVMEM devices ++ * which are using an 'int' as address ++ */ ++ if (bdev_nr_bytes(bdev) > INT_MAX) ++ return -EFBIG; ++ ++ bnv = kzalloc(sizeof(struct blk_nvmem), GFP_KERNEL); ++ if (!bnv) ++ return -ENOMEM; ++ ++ config.id = NVMEM_DEVID_NONE; ++ config.dev = &bdev->bd_device; ++ config.name = dev_name(&bdev->bd_device); ++ config.owner = THIS_MODULE; ++ config.priv = bnv; ++ config.reg_read = blk_nvmem_reg_read; ++ config.size = bdev_nr_bytes(bdev); ++ config.word_size = 1; ++ config.stride = 1; ++ config.read_only = true; ++ config.root_only = true; ++ config.ignore_wp = true; ++ config.of_node = to_of_node(dev->fwnode); ++ ++ bnv->dev = &bdev->bd_device; ++ bnv->nvmem = nvmem_register(&config); ++ if (IS_ERR(bnv->nvmem)) { ++ dev_err_probe(&bdev->bd_device, PTR_ERR(bnv->nvmem), ++ "Failed to register NVMEM device\n"); ++ ++ kfree(bnv); ++ return PTR_ERR(bnv->nvmem); ++ } ++ ++ mutex_lock(&devices_mutex); ++ list_add_tail(&bnv->list, &nvmem_devices); ++ mutex_unlock(&devices_mutex); ++ ++ return 0; ++} ++ ++static void blk_nvmem_unregister(struct device *dev) ++{ ++ struct blk_nvmem *bnv_c, *bnv = NULL; ++ ++ mutex_lock(&devices_mutex); ++ list_for_each_entry(bnv_c, &nvmem_devices, list) { ++ if (bnv_c->dev == dev) { ++ bnv = bnv_c; ++ break; ++ } ++ } ++ ++ if (!bnv) { ++ mutex_unlock(&devices_mutex); ++ return; ++ } ++ ++ list_del(&bnv->list); ++ mutex_unlock(&devices_mutex); ++ nvmem_unregister(bnv->nvmem); ++ kfree(bnv); ++} ++ ++static int blk_nvmem_handler(struct notifier_block *this, unsigned long code, void *obj) ++{ ++ struct device *dev = (struct device *)obj; ++ ++ switch (code) { ++ case BLK_DEVICE_ADD: ++ return blk_nvmem_register(dev); ++ break; ++ case BLK_DEVICE_REMOVE: ++ blk_nvmem_unregister(dev); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static struct notifier_block blk_nvmem_notifier = { ++ .notifier_call = blk_nvmem_handler, ++}; ++ ++static int __init blk_nvmem_init(void) ++{ ++ blk_register_notify(&blk_nvmem_notifier); ++ ++ return 0; ++} ++ ++static void __exit blk_nvmem_exit(void) ++{ ++ blk_unregister_notify(&blk_nvmem_notifier); ++} ++ ++module_init(blk_nvmem_init); ++module_exit(blk_nvmem_exit); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Daniel Golle "); ++MODULE_DESCRIPTION("block device NVMEM provider"); +-- +2.51.0 + + +From a157318671df5bf489e72723f2b02b462415855f Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Thu, 20 Jul 2023 17:36:44 +0100 +Subject: [PATCH 227/517] mmc: block: set GENHD_FL_NVMEM + +Set flag to consider MMC block devices as NVMEM providers. + +Signed-off-by: Daniel Golle +--- + drivers/mmc/core/block.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c +index 28882b75ba26..f56eb44ec450 100644 +--- a/drivers/mmc/core/block.c ++++ b/drivers/mmc/core/block.c +@@ -2644,6 +2644,7 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, + md->disk->major = MMC_BLOCK_MAJOR; + md->disk->minors = perdev_minors; + md->disk->first_minor = devidx * perdev_minors; ++ md->disk->flags = GENHD_FL_NVMEM; + md->disk->fops = &mmc_bdops; + md->disk->private_data = md; + md->parent = parent; +-- +2.51.0 + + +From 601eabca6855ce5433b4753cf64b7de87cfbd935 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Mon, 3 Nov 2025 15:49:45 +0100 +Subject: [PATCH 228/517] kernel: disable cfi cmdset 0002 erase suspend + +on some platforms, erase suspend leads to data corruption and lockups when write +ops collide with erase ops. this has been observed on the buffalo wzr-hp-g300nh. +rather than play whack-a-mole with a hard to reproduce issue on a variety of devices, +simply disable erase suspend, as it will usually not produce any useful gain on +the small filesystems used on embedded hardware. + +Signed-off-by: Felix Fietkau +--- + drivers/mtd/chips/cfi_cmdset_0002.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c +index 9f2223d3e8e1..cd513f719177 100644 +--- a/drivers/mtd/chips/cfi_cmdset_0002.c ++++ b/drivers/mtd/chips/cfi_cmdset_0002.c +@@ -906,7 +906,7 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr + return 0; + + case FL_ERASING: +- if (!cfip || !(cfip->EraseSuspend & (0x1|0x2)) || ++ if (1 /* no suspend */ || !cfip || !(cfip->EraseSuspend & (0x1|0x2)) || + !(mode == FL_READY || mode == FL_POINT || + (mode == FL_WRITING && (cfip->EraseSuspend & 0x2)))) + goto sleep; +-- +2.51.0 + + +From 0aca8172b13a5bbbbd97f3d2ece4e916bbdb41d4 Mon Sep 17 00:00:00 2001 +From: George Kashperko +Date: Mon, 3 Nov 2025 15:49:45 +0100 +Subject: [PATCH 229/517] Issue map read after Write Buffer Load command to + ensure chip is ready to receive data. + +Signed-off-by: George Kashperko +--- + drivers/mtd/chips/cfi_cmdset_0002.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c +index cd513f719177..b589ddc4a3c9 100644 +--- a/drivers/mtd/chips/cfi_cmdset_0002.c ++++ b/drivers/mtd/chips/cfi_cmdset_0002.c +@@ -2050,6 +2050,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, + + /* Write Buffer Load */ + map_write(map, CMD(0x25), cmd_adr); ++ (void) map_read(map, cmd_adr); + + chip->state = FL_WRITING_TO_BUFFER; + +-- +2.51.0 + + +From 1e60d2ebf7e0a305b8ba49ff8bdcad70ef15bd63 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Mon, 3 Nov 2025 15:49:45 +0100 +Subject: [PATCH 230/517] Disable software protection bits for Macronix + flashes. + +Signed-off-by: Felix Fietkau +--- + drivers/mtd/spi-nor/macronix.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/mtd/spi-nor/macronix.c b/drivers/mtd/spi-nor/macronix.c +index ea6be95e75a5..ac125b89e7ba 100644 +--- a/drivers/mtd/spi-nor/macronix.c ++++ b/drivers/mtd/spi-nor/macronix.c +@@ -194,6 +194,7 @@ static int macronix_nor_late_init(struct spi_nor *nor) + { + if (!nor->params->set_4byte_addr_mode) + nor->params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_en4b_ex4b; ++ nor->flags |= SNOR_F_HAS_LOCK; + + return 0; + } +-- +2.51.0 + + +From de1e4ccd801c181b0f1d543e91f63a1743d3a092 Mon Sep 17 00:00:00 2001 +From: Piotr Dymacz +Date: Mon, 3 Nov 2025 15:49:46 +0100 +Subject: [PATCH 231/517] kernel/mtd: add support for EON EN25Q128 + +Signed-off-by: Piotr Dymacz +--- + drivers/mtd/spi-nor/eon.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/mtd/spi-nor/eon.c b/drivers/mtd/spi-nor/eon.c +index c1ddf662f782..d43b68873cf1 100644 +--- a/drivers/mtd/spi-nor/eon.c ++++ b/drivers/mtd/spi-nor/eon.c +@@ -17,6 +17,11 @@ static const struct flash_info eon_nor_parts[] = { + .id = SNOR_ID(0x1c, 0x20, 0x17), + .name = "en25p64", + .size = SZ_8M, ++ }, { ++ .id = SNOR_ID(0x1c, 0x30, 0x18), ++ .name = "en25q128", ++ .size = SZ_16M, ++ .no_sfdp_flags = SECT_4K, + }, { + .id = SNOR_ID(0x1c, 0x30, 0x14), + .name = "en25q80a", +-- +2.51.0 + + +From ebe89a767bbf9f8a9704db8a1364c28f6c8bf044 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Mon, 3 Nov 2025 15:49:46 +0100 +Subject: [PATCH 232/517] kernel/mtd: add support for EON EN25QX128A + +Add support for EON EN25QX128A with no flags as it does +support SFDP parsing. + +Signed-off-by: Christian Marangi +--- + drivers/mtd/spi-nor/eon.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/mtd/spi-nor/eon.c b/drivers/mtd/spi-nor/eon.c +index d43b68873cf1..a3b57a6871a3 100644 +--- a/drivers/mtd/spi-nor/eon.c ++++ b/drivers/mtd/spi-nor/eon.c +@@ -22,6 +22,10 @@ static const struct flash_info eon_nor_parts[] = { + .name = "en25q128", + .size = SZ_16M, + .no_sfdp_flags = SECT_4K, ++ }, { ++ .id = SNOR_ID(0x1c, 0x71, 0x18), ++ .name = "en25qx128a", ++ .size = SZ_16M, + }, { + .id = SNOR_ID(0x1c, 0x30, 0x14), + .name = "en25q80a", +-- +2.51.0 + + +From 7eefc27020e72b4715c3a3e0570c8c3ea96710e3 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Thu, 6 Feb 2020 19:19:41 +0200 +Subject: [PATCH 233/517] mtd: spi-nor: Add support for xt25f128b chip + +Add XT25F128B made by XTX Technology (Shenzhen) Limited. +This chip supports dual and quad read and uniform 4K-byte erase. +Verified on Teltonika RUT955 which comes with XT25F128B in recent +versions of the device. + +Signed-off-by: Daniel Golle +Signed-off-by: Felix Fietkau +--- + drivers/mtd/spi-nor/Makefile | 1 + + drivers/mtd/spi-nor/core.c | 1 + + drivers/mtd/spi-nor/core.h | 1 + + drivers/mtd/spi-nor/xtx.c | 20 ++++++++++++++++++++ + 4 files changed, 23 insertions(+) + create mode 100644 drivers/mtd/spi-nor/xtx.c + +diff --git a/drivers/mtd/spi-nor/Makefile b/drivers/mtd/spi-nor/Makefile +index 5dd9c35f6b6f..1072cf609dac 100644 +--- a/drivers/mtd/spi-nor/Makefile ++++ b/drivers/mtd/spi-nor/Makefile +@@ -14,6 +14,7 @@ spi-nor-objs += spansion.o + spi-nor-objs += sst.o + spi-nor-objs += winbond.o + spi-nor-objs += xmc.o ++spi-nor-objs += xtx.o + spi-nor-$(CONFIG_DEBUG_FS) += debugfs.o + obj-$(CONFIG_MTD_SPI_NOR) += spi-nor.o + +diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c +index 8da860d84e6d..5bb7da0ef34d 100644 +--- a/drivers/mtd/spi-nor/core.c ++++ b/drivers/mtd/spi-nor/core.c +@@ -1979,6 +1979,7 @@ static const struct spi_nor_manufacturer *manufacturers[] = { + &spi_nor_sst, + &spi_nor_winbond, + &spi_nor_xmc, ++ &spi_nor_xtx, + }; + + static const struct flash_info spi_nor_generic_flash = { +diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h +index 1516b6d0dc37..c81829b01cfd 100644 +--- a/drivers/mtd/spi-nor/core.h ++++ b/drivers/mtd/spi-nor/core.h +@@ -593,6 +593,7 @@ extern const struct spi_nor_manufacturer spi_nor_spansion; + extern const struct spi_nor_manufacturer spi_nor_sst; + extern const struct spi_nor_manufacturer spi_nor_winbond; + extern const struct spi_nor_manufacturer spi_nor_xmc; ++extern const struct spi_nor_manufacturer spi_nor_xtx; + + extern const struct attribute_group *spi_nor_sysfs_groups[]; + +diff --git a/drivers/mtd/spi-nor/xtx.c b/drivers/mtd/spi-nor/xtx.c +new file mode 100644 +index 000000000000..f16d08db483f +--- /dev/null ++++ b/drivers/mtd/spi-nor/xtx.c +@@ -0,0 +1,20 @@ ++// SPDX-License-Identifier: GPL-2.0 ++#include ++ ++#include "core.h" ++ ++static const struct flash_info xtx_parts[] = { ++ /* XTX Technology (Shenzhen) Limited */ ++ { ++ .id = SNOR_ID(0x0B, 0x40, 0x18), ++ .name = "xt25f128b", ++ .size = SZ_16M, ++ .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, ++ }, ++}; ++ ++const struct spi_nor_manufacturer spi_nor_xtx = { ++ .name = "xtx", ++ .parts = xtx_parts, ++ .nparts = ARRAY_SIZE(xtx_parts), ++}; +-- +2.51.0 + + +From be18324af44ad5c426c6168eb7d8b071d76937c9 Mon Sep 17 00:00:00 2001 +From: Koen Vandeputte +Date: Mon, 6 Jan 2020 13:07:56 +0100 +Subject: [PATCH 234/517] mtd: spi-nor: add support for Gigadevice GD25D05 + +Signed-off-by: Koen Vandeputte +--- + drivers/mtd/spi-nor/gigadevice.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/mtd/spi-nor/gigadevice.c b/drivers/mtd/spi-nor/gigadevice.c +index ef1edd0add70..2cf2db123751 100644 +--- a/drivers/mtd/spi-nor/gigadevice.c ++++ b/drivers/mtd/spi-nor/gigadevice.c +@@ -35,6 +35,12 @@ static const struct spi_nor_fixups gd25q256_fixups = { + + static const struct flash_info gigadevice_nor_parts[] = { + { ++ .id = SNOR_ID(0xc8, 0x40, 0x10), ++ .name = "gd25q05", ++ .size = SZ_64K, ++ .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB, ++ .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, ++ }, { + .id = SNOR_ID(0xc8, 0x40, 0x15), + .name = "gd25q16", + .size = SZ_2M, +-- +2.51.0 + + +From b044e7954a158d0fc0b2414e4e6a9f1a937bf08f Mon Sep 17 00:00:00 2001 +From: OpenWrt community +Date: Thu, 14 Jul 2022 08:38:07 +0200 +Subject: [PATCH 235/517] spi-nor/gigadevic: add gd25q512 + +--- + drivers/mtd/spi-nor/gigadevice.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/mtd/spi-nor/gigadevice.c b/drivers/mtd/spi-nor/gigadevice.c +index 2cf2db123751..c4bf82b41914 100644 +--- a/drivers/mtd/spi-nor/gigadevice.c ++++ b/drivers/mtd/spi-nor/gigadevice.c +@@ -70,6 +70,13 @@ static const struct flash_info gigadevice_nor_parts[] = { + .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_TB_SR_BIT6, + .fixups = &gd25q256_fixups, + .fixup_flags = SPI_NOR_4B_OPCODES, ++ }, { ++ .id = SNOR_ID(0xc8, 0x40, 0x20), ++ .name = "gd25q512", ++ .size = SZ_64M, ++ .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB, ++ .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, ++ .fixup_flags = SPI_NOR_4B_OPCODES, + }, { + .id = SNOR_ID(0xc8, 0x60, 0x16), + .name = "gd25lq32", +-- +2.51.0 + + +From 5c449e62a92715acb21fdf74e0ec3d3b7188ff8c Mon Sep 17 00:00:00 2001 +From: OpenWrt community +Date: Wed, 13 Jul 2022 12:17:21 +0200 +Subject: [PATCH 236/517] spi-nor/esmt.c: add esmt f25l16pa + +This fixes support for Dongwon T&I DW02-412H which uses F25L16PA(2S) +flash. +--- + drivers/mtd/spi-nor/esmt.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/mtd/spi-nor/esmt.c b/drivers/mtd/spi-nor/esmt.c +index 089fcd1aa794..3c546c5d5d9b 100644 +--- a/drivers/mtd/spi-nor/esmt.c ++++ b/drivers/mtd/spi-nor/esmt.c +@@ -10,6 +10,12 @@ + + static const struct flash_info esmt_nor_parts[] = { + { ++ .id = SNOR_ID(0x8c, 0x21, 0x15), ++ .name = "f25l16pa-2s", ++ .size = SZ_2M, ++ .flags = SPI_NOR_HAS_LOCK, ++ .no_sfdp_flags = SECT_4K, ++ }, { + .id = SNOR_ID(0x8c, 0x20, 0x16), + .name = "f25l32pa", + .size = SZ_4M, +-- +2.51.0 + + +From 769f8546d57a69c758d67e0dcaf5f63b8aa163cb Mon Sep 17 00:00:00 2001 +From: OpenWrt community +Date: Wed, 13 Jul 2022 12:19:01 +0200 +Subject: [PATCH 237/517] spi-nor/xmc.c: add xm25qh128c + +The XMC XM25QH128C is a 16MB SPI NOR chip. The patch is verified on +Ruijie RG-EW3200GX PRO. +Datasheet available at https://www.xmcwh.com/uploads/435/XM25QH128C.pdf +--- + drivers/mtd/spi-nor/xmc.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/mtd/spi-nor/xmc.c b/drivers/mtd/spi-nor/xmc.c +index d5a06054b0dd..8eb2d957c8ad 100644 +--- a/drivers/mtd/spi-nor/xmc.c ++++ b/drivers/mtd/spi-nor/xmc.c +@@ -19,6 +19,11 @@ static const struct flash_info xmc_nor_parts[] = { + .name = "XM25QH128A", + .size = SZ_16M, + .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, ++ }, { ++ .id = SNOR_ID(0x20, 0x40, 0x18), ++ .name = "XM25QH128C", ++ .size = SZ_16M, ++ .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, + }, + }; + +-- +2.51.0 + + +From 5fcfdcd3d02f2707b544005c7f657ebb852d3e46 Mon Sep 17 00:00:00 2001 +From: Daniel Danzberger +Date: Wed, 3 Aug 2022 17:31:03 +0200 +Subject: [PATCH 238/517] mtd: spinand: Add support for Etron EM73D044VCx + +Airoha is a new ARM platform based on Cortex-A53 which has recently been +merged into linux-next. + +Due to BootROM limitations on this platform, the Cortex-A53 can't run in +Aarch64 mode and code must be compiled for 32-Bit ARM. + +This support is based mostly on those linux-next commits backported +for kernel 5.15. + +Patches: +1 - platform support = linux-next +2 - clock driver = linux-next +3 - gpio driver = linux-next +4 - linux,usable-memory-range dts support = linux-next +5 - mtd spinand driver +6 - spi driver +7 - pci driver (kconfig only, uses mediatek PCI) = linux-next + +Still missing: +- Ethernet driver +- Sysupgrade support + +A.t.m there exists one subtarget EN7523 with only one evaluation +board. + +The initramfs can be run with the following commands from u-boot: +- +u-boot> setenv bootfile \ + openwrt-airoha-airoha_en7523-evb-initramfs-kernel.bin +u-boot> tftpboot +u-boot> bootm 0x81800000 +- + +Submitted-by: Daniel Danzberger +--- + drivers/mtd/nand/spi/Makefile | 4 +- + drivers/mtd/nand/spi/core.c | 1 + + drivers/mtd/nand/spi/etron.c | 98 +++++++++++++++++++++++++++++++++++ + include/linux/mtd/spinand.h | 1 + + 4 files changed, 102 insertions(+), 2 deletions(-) + create mode 100644 drivers/mtd/nand/spi/etron.c + +diff --git a/drivers/mtd/nand/spi/Makefile b/drivers/mtd/nand/spi/Makefile +index 32a696055d9f..f725f0c67307 100644 +--- a/drivers/mtd/nand/spi/Makefile ++++ b/drivers/mtd/nand/spi/Makefile +@@ -1,4 +1,4 @@ + # SPDX-License-Identifier: GPL-2.0 +-spinand-objs := core.o alliancememory.o ato.o esmt.o fmsh.o foresee.o gigadevice.o macronix.o +-spinand-objs += micron.o paragon.o toshiba.o winbond.o xtx.o ++spinand-objs := core.o alliancememory.o ato.o esmt.o etron.o fmsh.o foresee.o gigadevice.o ++spinand-objs += macronix.o micron.o paragon.o toshiba.o winbond.o xtx.o + obj-$(CONFIG_MTD_SPI_NAND) += spinand.o +diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c +index f3787a63a355..8e56ca65ac4f 100644 +--- a/drivers/mtd/nand/spi/core.c ++++ b/drivers/mtd/nand/spi/core.c +@@ -1159,6 +1159,7 @@ static const struct spinand_manufacturer *spinand_manufacturers[] = { + &alliancememory_spinand_manufacturer, + &ato_spinand_manufacturer, + &esmt_c8_spinand_manufacturer, ++ &etron_spinand_manufacturer, + &fmsh_spinand_manufacturer, + &foresee_spinand_manufacturer, + &gigadevice_spinand_manufacturer, +diff --git a/drivers/mtd/nand/spi/etron.c b/drivers/mtd/nand/spi/etron.c +new file mode 100644 +index 000000000000..653092be5938 +--- /dev/null ++++ b/drivers/mtd/nand/spi/etron.c +@@ -0,0 +1,98 @@ ++// SPDX-License-Identifier: GPL-2.0 ++ ++#include ++#include ++#include ++ ++#define SPINAND_MFR_ETRON 0xd5 ++ ++ ++static SPINAND_OP_VARIANTS(read_cache_variants, ++ SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0)); ++ ++static SPINAND_OP_VARIANTS(write_cache_variants, ++ SPINAND_PROG_LOAD_X4(true, 0, NULL, 0), ++ SPINAND_PROG_LOAD(true, 0, NULL, 0)); ++ ++static SPINAND_OP_VARIANTS(update_cache_variants, ++ SPINAND_PROG_LOAD_X4(false, 0, NULL, 0), ++ SPINAND_PROG_LOAD(false, 0, NULL, 0)); ++ ++static int etron_ooblayout_ecc(struct mtd_info *mtd, int section, ++ struct mtd_oob_region *oobregion) ++{ ++ if (section) ++ return -ERANGE; ++ ++ oobregion->offset = 72; ++ oobregion->length = 56; ++ ++ return 0; ++} ++ ++static int etron_ooblayout_free(struct mtd_info *mtd, int section, ++ struct mtd_oob_region *oobregion) ++{ ++ if (section) ++ return -ERANGE; ++ ++ oobregion->offset = 1; ++ oobregion->length = 71; ++ ++ return 0; ++} ++ ++static int etron_ecc_get_status(struct spinand_device *spinand, u8 status) ++{ ++ switch (status & STATUS_ECC_MASK) { ++ case STATUS_ECC_NO_BITFLIPS: ++ return 0; ++ ++ case STATUS_ECC_HAS_BITFLIPS: ++ /* Between 1-7 bitflips were corrected */ ++ return 7; ++ ++ case STATUS_ECC_MASK: ++ /* Maximum bitflips were corrected */ ++ return 8; ++ ++ case STATUS_ECC_UNCOR_ERROR: ++ return -EBADMSG; ++ } ++ ++ return -EINVAL; ++} ++ ++static const struct mtd_ooblayout_ops etron_ooblayout = { ++ .ecc = etron_ooblayout_ecc, ++ .free = etron_ooblayout_free, ++}; ++ ++static const struct spinand_info etron_spinand_table[] = { ++ SPINAND_INFO("EM73D044VCx", ++ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x1f), ++ // bpc, pagesize, oobsize, pagesperblock, bperlun, maxbadplun, ppl, lpt, #t ++ NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), ++ NAND_ECCREQ(8, 512), ++ SPINAND_INFO_OP_VARIANTS(&read_cache_variants, ++ &write_cache_variants, ++ &update_cache_variants), ++ SPINAND_HAS_QE_BIT, ++ SPINAND_ECCINFO(&etron_ooblayout, etron_ecc_get_status)), ++}; ++ ++static const struct spinand_manufacturer_ops etron_spinand_manuf_ops = { ++}; ++ ++const struct spinand_manufacturer etron_spinand_manufacturer = { ++ .id = SPINAND_MFR_ETRON, ++ .name = "Etron", ++ .chips = etron_spinand_table, ++ .nchips = ARRAY_SIZE(etron_spinand_table), ++ .ops = &etron_spinand_manuf_ops, ++}; +diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h +index ba7b73c9675e..e5b6ac340383 100644 +--- a/include/linux/mtd/spinand.h ++++ b/include/linux/mtd/spinand.h +@@ -263,6 +263,7 @@ struct spinand_manufacturer { + extern const struct spinand_manufacturer alliancememory_spinand_manufacturer; + extern const struct spinand_manufacturer ato_spinand_manufacturer; + extern const struct spinand_manufacturer esmt_c8_spinand_manufacturer; ++extern const struct spinand_manufacturer etron_spinand_manufacturer; + extern const struct spinand_manufacturer fmsh_spinand_manufacturer; + extern const struct spinand_manufacturer foresee_spinand_manufacturer; + extern const struct spinand_manufacturer gigadevice_spinand_manufacturer; +-- +2.51.0 + + +From 41816d01e19a9ff217b6851b822598895cc37a48 Mon Sep 17 00:00:00 2001 +From: Joe Mullally +Date: Mon, 3 Nov 2025 15:49:48 +0100 +Subject: [PATCH 239/517] mtd/spi-nor/xmc: add support for XMC XM25QH64C + +The XMC XM25QH64C is a 8MB SPI NOR chip. The patch is verified on TL-WPA8631P v3. +Datasheet available at https://www.xmcwh.com/uploads/442/XM25QH64C.pdf + +Signed-off-by: Joe Mullally +--- + drivers/mtd/spi-nor/xmc.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/mtd/spi-nor/xmc.c b/drivers/mtd/spi-nor/xmc.c +index 8eb2d957c8ad..d52756562489 100644 +--- a/drivers/mtd/spi-nor/xmc.c ++++ b/drivers/mtd/spi-nor/xmc.c +@@ -14,6 +14,11 @@ static const struct flash_info xmc_nor_parts[] = { + .name = "XM25QH64A", + .size = SZ_8M, + .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, ++ }, { ++ .id = SNOR_ID(0x20, 0x40, 0x17), ++ .name = "XM25QH64C", ++ .size = SZ_8M, ++ .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, + }, { + .id = SNOR_ID(0x20, 0x70, 0x18), + .name = "XM25QH128A", +-- +2.51.0 + + +From e361d0ef02084d0b709b8930a3aaf52a75df6ecc Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Mon, 3 Nov 2025 15:49:48 +0100 +Subject: [PATCH 240/517] ubi: auto-attach mtd device named "ubi" or "data" on + boot + +Signed-off-by: Daniel Golle +--- + drivers/mtd/ubi/build.c | 80 +++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 80 insertions(+) + +diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c +index ef6a22f372f9..82247bfe0332 100644 +--- a/drivers/mtd/ubi/build.c ++++ b/drivers/mtd/ubi/build.c +@@ -1263,6 +1263,80 @@ static struct mtd_notifier ubi_mtd_notifier = { + .remove = ubi_notify_remove, + }; + ++ ++/* ++ * This function tries attaching mtd partitions named either "ubi" or "data" ++ * during boot. ++ */ ++static void __init ubi_auto_attach(void) ++{ ++ int err; ++ struct mtd_info *mtd; ++ struct device_node *np; ++ loff_t offset = 0; ++ size_t len; ++ char magic[4]; ++ ++ /* try attaching mtd device named "ubi" or "data" */ ++ mtd = open_mtd_device("ubi"); ++ if (IS_ERR(mtd)) ++ mtd = open_mtd_device("data"); ++ ++ if (IS_ERR(mtd)) ++ return; ++ ++ /* skip "linux,ubi" mtd as it has already been attached */ ++ np = mtd_get_of_node(mtd); ++ if (of_device_is_compatible(np, "linux,ubi")) ++ goto cleanup; ++ ++ /* get the first not bad block */ ++ if (mtd_can_have_bb(mtd)) ++ while (mtd_block_isbad(mtd, offset)) { ++ offset += mtd->erasesize; ++ ++ if (offset > mtd->size) { ++ pr_err("UBI error: Failed to find a non-bad " ++ "block on mtd%d\n", mtd->index); ++ goto cleanup; ++ } ++ } ++ ++ /* check if the read from flash was successful */ ++ err = mtd_read(mtd, offset, 4, &len, (void *) magic); ++ if ((err && !mtd_is_bitflip(err)) || len != 4) { ++ pr_err("UBI error: unable to read from mtd%d\n", mtd->index); ++ goto cleanup; ++ } ++ ++ /* check for a valid ubi magic */ ++ if (strncmp(magic, "UBI#", 4)) { ++ pr_err("UBI error: no valid UBI magic found inside mtd%d\n", mtd->index); ++ goto cleanup; ++ } ++ ++ /* don't auto-add media types where UBI doesn't makes sense */ ++ if (mtd->type != MTD_NANDFLASH && ++ mtd->type != MTD_NORFLASH && ++ mtd->type != MTD_DATAFLASH && ++ mtd->type != MTD_MLCNANDFLASH) ++ goto cleanup; ++ ++ mutex_lock(&ubi_devices_mutex); ++ pr_notice("UBI: auto-attach mtd%d\n", mtd->index); ++ err = ubi_attach_mtd_dev(mtd, UBI_DEV_NUM_AUTO, 0, 0, false, false); ++ mutex_unlock(&ubi_devices_mutex); ++ if (err < 0) { ++ pr_err("UBI error: cannot attach mtd%d\n", mtd->index); ++ goto cleanup; ++ } ++ ++ return; ++ ++cleanup: ++ put_mtd_device(mtd); ++} ++ + static int __init ubi_init_attach(void) + { + int err, i, k; +@@ -1314,6 +1388,12 @@ static int __init ubi_init_attach(void) + } + } + ++ /* auto-attach mtd devices only if built-in to the kernel and no ubi.mtd ++ * parameter was given */ ++ if (IS_ENABLED(CONFIG_MTD_ROOTFS_ROOT_DEV) && ++ !ubi_is_module() && !mtd_devs) ++ ubi_auto_attach(); ++ + return 0; + + out_detach: +-- +2.51.0 + + +From cad4fa01f1219cb6fa41fd18dc398100e5963f23 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Mon, 3 Nov 2025 15:49:48 +0100 +Subject: [PATCH 241/517] ubi: auto-create ubiblock device for rootfs + +Signed-off-by: Daniel Golle +--- + drivers/mtd/ubi/block.c | 42 +++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 42 insertions(+) + +diff --git a/drivers/mtd/ubi/block.c b/drivers/mtd/ubi/block.c +index 60d0155be869..3d2f89cfbab0 100644 +--- a/drivers/mtd/ubi/block.c ++++ b/drivers/mtd/ubi/block.c +@@ -575,10 +575,47 @@ match_volume_desc(struct ubi_volume_info *vi, const char *name, int ubi_num, int + return true; + } + ++#define UBIFS_NODE_MAGIC 0x06101831 ++static inline int ubi_vol_is_ubifs(struct ubi_volume_desc *desc) ++{ ++ int ret; ++ uint32_t magic_of, magic; ++ ret = ubi_read(desc, 0, (char *)&magic_of, 0, 4); ++ if (ret) ++ return 0; ++ magic = le32_to_cpu(magic_of); ++ return magic == UBIFS_NODE_MAGIC; ++} ++ ++static void ubiblock_create_auto_rootfs(struct ubi_volume_info *vi) ++{ ++ int ret, is_ubifs; ++ struct ubi_volume_desc *desc; ++ ++ if (strcmp(vi->name, "rootfs") && ++ strcmp(vi->name, "fit")) ++ return; ++ ++ desc = ubi_open_volume(vi->ubi_num, vi->vol_id, UBI_READONLY); ++ if (IS_ERR(desc)) ++ return; ++ ++ is_ubifs = ubi_vol_is_ubifs(desc); ++ ubi_close_volume(desc); ++ if (is_ubifs) ++ return; ++ ++ ret = ubiblock_create(vi); ++ if (ret) ++ pr_err("UBI error: block: can't add '%s' volume, err=%d\n", ++ vi->name, ret); ++} ++ + static void + ubiblock_create_from_param(struct ubi_volume_info *vi) + { + int i, ret = 0; ++ bool got_param = false; + struct ubiblock_param *p; + + /* +@@ -591,6 +628,7 @@ ubiblock_create_from_param(struct ubi_volume_info *vi) + if (!match_volume_desc(vi, p->name, p->ubi_num, p->vol_id)) + continue; + ++ got_param = true; + ret = ubiblock_create(vi); + if (ret) { + pr_err( +@@ -599,6 +637,10 @@ ubiblock_create_from_param(struct ubi_volume_info *vi) + } + break; + } ++ ++ /* auto-attach "rootfs" volume if existing and non-ubifs */ ++ if (!got_param && IS_ENABLED(CONFIG_MTD_ROOTFS_ROOT_DEV)) ++ ubiblock_create_auto_rootfs(vi); + } + + static int ubiblock_notify(struct notifier_block *nb, +-- +2.51.0 + + +From 74dbb1605aced27216d2caa82680008159d34baf Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Mon, 3 Nov 2025 15:49:49 +0100 +Subject: [PATCH 242/517] try auto-mounting ubi0:rootfs in init/do_mounts.c + +Signed-off-by: Daniel Golle +--- + init/do_mounts.c | 30 +++++++++++++++++++++++++++++- + 1 file changed, 29 insertions(+), 1 deletion(-) + +diff --git a/init/do_mounts.c b/init/do_mounts.c +index 6af29da8889e..cbb4237700aa 100644 +--- a/init/do_mounts.c ++++ b/init/do_mounts.c +@@ -250,7 +250,30 @@ void __init mount_root_generic(char *name, char *pretty_name, int flags) + out: + put_page(page); + } +- ++ ++#ifdef CONFIG_MTD_ROOTFS_ROOT_DEV ++static int __init mount_ubi_rootfs(void) ++{ ++ int flags = MS_SILENT; ++ int err, tried = 0; ++ ++ while (tried < 2) { ++ err = do_mount_root("ubi0:rootfs", "ubifs", flags, \ ++ root_mount_data); ++ switch (err) { ++ case -EACCES: ++ flags |= MS_RDONLY; ++ tried++; ++ break; ++ default: ++ return err; ++ } ++ } ++ ++ return -EINVAL; ++} ++#endif ++ + #ifdef CONFIG_ROOT_NFS + + #define NFSROOT_TIMEOUT_MIN 5 +@@ -387,6 +410,11 @@ static inline void mount_block_root(char *root_device_name) + + void __init mount_root(char *root_device_name) + { ++#ifdef CONFIG_MTD_ROOTFS_ROOT_DEV ++ if (!mount_ubi_rootfs()) ++ return; ++#endif ++ + switch (ROOT_DEV) { + case Root_NFS: + mount_nfs_root(); +-- +2.51.0 + + +From 91bf41024ca9e5396631a8b1aadf12b6c3396d3b Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Mon, 3 Nov 2025 15:49:49 +0100 +Subject: [PATCH 243/517] ubi: set ROOT_DEV to ubiblock "rootfs" if unset + +Signed-off-by: Daniel Golle +--- + drivers/mtd/ubi/block.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/drivers/mtd/ubi/block.c b/drivers/mtd/ubi/block.c +index 3d2f89cfbab0..b45f9ca8866a 100644 +--- a/drivers/mtd/ubi/block.c ++++ b/drivers/mtd/ubi/block.c +@@ -41,6 +41,7 @@ + #include + #include + #include ++#include + + #include "ubi-media.h" + #include "ubi.h" +@@ -431,6 +432,15 @@ int ubiblock_create(struct ubi_volume_info *vi) + dev_info(disk_to_dev(dev->gd), "created from ubi%d:%d(%s)", + dev->ubi_num, dev->vol_id, vi->name); + mutex_unlock(&devices_mutex); ++ ++ if (!strcmp(vi->name, "rootfs") && ++ IS_ENABLED(CONFIG_MTD_ROOTFS_ROOT_DEV) && ++ ROOT_DEV == 0) { ++ pr_notice("ubiblock: device ubiblock%d_%d (%s) set to be root filesystem\n", ++ dev->ubi_num, dev->vol_id, vi->name); ++ ROOT_DEV = MKDEV(gd->major, gd->first_minor); ++ } ++ + return 0; + + out_remove_minor: +-- +2.51.0 + + +From e756171aa3fa371557bab27c509acd4f23b1f2f8 Mon Sep 17 00:00:00 2001 +From: Gabor Juhos +Date: Mon, 3 Nov 2025 15:49:49 +0100 +Subject: [PATCH 244/517] mtd: add EOF marker support to the UBI layer + +Signed-off-by: Gabor Juhos +--- + drivers/mtd/ubi/attach.c | 25 ++++++++++++++++++++++--- + drivers/mtd/ubi/ubi.h | 1 + + 2 files changed, 23 insertions(+), 3 deletions(-) + +diff --git a/drivers/mtd/ubi/attach.c b/drivers/mtd/ubi/attach.c +index adc47b87b38a..7eae13888f1c 100644 +--- a/drivers/mtd/ubi/attach.c ++++ b/drivers/mtd/ubi/attach.c +@@ -926,6 +926,13 @@ static bool vol_ignored(int vol_id) + #endif + } + ++static bool ec_hdr_has_eof(struct ubi_ec_hdr *ech) ++{ ++ return ech->padding1[0] == 'E' && ++ ech->padding1[1] == 'O' && ++ ech->padding1[2] == 'F'; ++} ++ + /** + * scan_peb - scan and process UBI headers of a PEB. + * @ubi: UBI device description object +@@ -958,9 +965,21 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai, + return 0; + } + +- err = ubi_io_read_ec_hdr(ubi, pnum, ech, 0); +- if (err < 0) +- return err; ++ if (!ai->eof_found) { ++ err = ubi_io_read_ec_hdr(ubi, pnum, ech, 0); ++ if (err < 0) ++ return err; ++ ++ if (ec_hdr_has_eof(ech)) { ++ pr_notice("UBI: EOF marker found, PEBs from %d will be erased\n", ++ pnum); ++ ai->eof_found = true; ++ } ++ } ++ ++ if (ai->eof_found) ++ err = UBI_IO_FF_BITFLIPS; ++ + switch (err) { + case 0: + break; +diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h +index 1c9e874e8ede..690f25ffddc2 100644 +--- a/drivers/mtd/ubi/ubi.h ++++ b/drivers/mtd/ubi/ubi.h +@@ -778,6 +778,7 @@ struct ubi_attach_info { + int mean_ec; + uint64_t ec_sum; + int ec_count; ++ bool eof_found; + struct kmem_cache *aeb_slab_cache; + struct ubi_ec_hdr *ech; + struct ubi_vid_io_buf *vidb; +-- +2.51.0 + + +From 4604417d761220471f5000b78a352f879a81b611 Mon Sep 17 00:00:00 2001 +From: Bernhard Frauendienst +Date: Wed, 5 Sep 2018 01:32:51 +0200 +Subject: [PATCH 245/517] dt-bindings: add bindings for mtd-concat devices + +Document virtual mtd-concat device bindings. + +Signed-off-by: Bernhard Frauendienst +--- + .../devicetree/bindings/mtd/mtd-concat.txt | 36 +++++++++++++++++++ + 1 file changed, 36 insertions(+) + create mode 100644 Documentation/devicetree/bindings/mtd/mtd-concat.txt + +diff --git a/Documentation/devicetree/bindings/mtd/mtd-concat.txt b/Documentation/devicetree/bindings/mtd/mtd-concat.txt +new file mode 100644 +index 000000000000..2daf3157b163 +--- /dev/null ++++ b/Documentation/devicetree/bindings/mtd/mtd-concat.txt +@@ -0,0 +1,36 @@ ++Virtual MTD concat device ++ ++Requires properties: ++- devices: list of phandles to mtd nodes that should be concatenated ++ ++Example: ++ ++&spi { ++ flash0: flash@0 { ++ ... ++ }; ++ flash1: flash@1 { ++ ... ++ }; ++}; ++ ++flash { ++ compatible = "mtd-concat"; ++ ++ devices = <&flash0 &flash1>; ++ ++ partitions { ++ compatible = "fixed-partitions"; ++ ++ partition@0 { ++ label = "boot"; ++ reg = <0x0000000 0x0040000>; ++ read-only; ++ }; ++ ++ partition@40000 { ++ label = "firmware"; ++ reg = <0x0040000 0x1fc0000>; ++ }; ++ } ++} +-- +2.51.0 + + +From f8d352e43303fc728b050bad1ec4f0684a348978 Mon Sep 17 00:00:00 2001 +From: Bernhard Frauendienst +Date: Sat, 25 Aug 2018 12:35:22 +0200 +Subject: [PATCH 246/517] mtd: mtdconcat: add dt driver for concat devices + +Some mtd drivers like physmap variants have support for concatenating +multiple mtd devices, but there is no generic way to define such a +concat device from within the device tree. + +This is useful for some SoC boards that use multiple flash chips as +memory banks of a single mtd device, with partitions spanning chip +borders. + +This commit adds a driver for creating virtual mtd-concat devices. They +must have a compatible = "mtd-concat" line, and define a list of devices +to concat in the 'devices' property, for example: + +flash { + compatible = "mtd-concat"; + + devices = <&flash0 &flash1>; + + partitions { + ... + }; +}; + +The driver is added to the very end of the mtd Makefile to increase the +likelyhood of all child devices already being loaded at the time of +probing, preventing unnecessary deferred probes. + +Signed-off-by: Bernhard Frauendienst +--- + drivers/mtd/Kconfig | 2 + + drivers/mtd/Makefile | 3 + + drivers/mtd/composite/Kconfig | 12 +++ + drivers/mtd/composite/Makefile | 6 ++ + drivers/mtd/composite/virt_concat.c | 127 ++++++++++++++++++++++++++++ + 5 files changed, 150 insertions(+) + create mode 100644 drivers/mtd/composite/Kconfig + create mode 100644 drivers/mtd/composite/Makefile + create mode 100644 drivers/mtd/composite/virt_concat.c + +diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig +index f9ed93c4cf0f..7e4a3fa1dfd0 100644 +--- a/drivers/mtd/Kconfig ++++ b/drivers/mtd/Kconfig +@@ -241,4 +241,6 @@ source "drivers/mtd/ubi/Kconfig" + + source "drivers/mtd/hyperbus/Kconfig" + ++source "drivers/mtd/composite/Kconfig" ++ + endif # MTD +diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile +index b14b7fe0f597..fbea3736b488 100644 +--- a/drivers/mtd/Makefile ++++ b/drivers/mtd/Makefile +@@ -33,3 +33,6 @@ obj-y += chips/ lpddr/ maps/ devices/ nand/ tests/ + obj-$(CONFIG_MTD_SPI_NOR) += spi-nor/ + obj-$(CONFIG_MTD_UBI) += ubi/ + obj-$(CONFIG_MTD_HYPERBUS) += hyperbus/ ++ ++# Composite drivers must be loaded last ++obj-y += composite/ +diff --git a/drivers/mtd/composite/Kconfig b/drivers/mtd/composite/Kconfig +new file mode 100644 +index 000000000000..0490fc0284bb +--- /dev/null ++++ b/drivers/mtd/composite/Kconfig +@@ -0,0 +1,12 @@ ++menu "Composite MTD device drivers" ++ depends on MTD!=n ++ ++config MTD_VIRT_CONCAT ++ tristate "Virtual concat MTD device" ++ help ++ This driver allows creation of a virtual MTD concat device, which ++ concatenates multiple underlying MTD devices to a single device. ++ This is required by some SoC boards where multiple memory banks are ++ used as one device with partitions spanning across device boundaries. ++ ++endmenu +diff --git a/drivers/mtd/composite/Makefile b/drivers/mtd/composite/Makefile +new file mode 100644 +index 000000000000..8421a0a30606 +--- /dev/null ++++ b/drivers/mtd/composite/Makefile +@@ -0,0 +1,6 @@ ++# SPDX-License-Identifier: GPL-2.0 ++# ++# linux/drivers/mtd/composite/Makefile ++# ++ ++obj-$(CONFIG_MTD_VIRT_CONCAT) += virt_concat.o +diff --git a/drivers/mtd/composite/virt_concat.c b/drivers/mtd/composite/virt_concat.c +new file mode 100644 +index 000000000000..05b4b9a7539e +--- /dev/null ++++ b/drivers/mtd/composite/virt_concat.c +@@ -0,0 +1,127 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Virtual concat MTD device driver ++ * ++ * Copyright (C) 2018 Bernhard Frauendienst ++ * Author: Bernhard Frauendienst, kernel@nospam.obeliks.de ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * struct of_virt_concat - platform device driver data. ++ * @cmtd the final mtd_concat device ++ * @num_devices the number of devices in @devices ++ * @devices points to an array of devices already loaded ++ */ ++struct of_virt_concat { ++ struct mtd_info *cmtd; ++ int num_devices; ++ struct mtd_info **devices; ++}; ++ ++static void virt_concat_remove(struct platform_device *pdev) ++{ ++ struct of_virt_concat *info; ++ int i; ++ ++ info = platform_get_drvdata(pdev); ++ if (!info) ++ return; ++ ++ // unset data for when this is called after a probe error ++ platform_set_drvdata(pdev, NULL); ++ ++ if (info->cmtd) { ++ mtd_device_unregister(info->cmtd); ++ mtd_concat_destroy(info->cmtd); ++ } ++ ++ if (info->devices) { ++ for (i = 0; i < info->num_devices; i++) ++ put_mtd_device(info->devices[i]); ++ } ++} ++ ++static int virt_concat_probe(struct platform_device *pdev) ++{ ++ struct device_node *node = pdev->dev.of_node; ++ struct of_phandle_iterator it; ++ struct of_virt_concat *info; ++ struct mtd_info *mtd; ++ int err = 0, count; ++ ++ count = of_count_phandle_with_args(node, "devices", NULL); ++ if (count <= 0) ++ return -EINVAL; ++ ++ info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); ++ if (!info) ++ return -ENOMEM; ++ info->devices = devm_kcalloc(&pdev->dev, count, ++ sizeof(*(info->devices)), GFP_KERNEL); ++ if (!info->devices) { ++ err = -ENOMEM; ++ goto err_remove; ++ } ++ ++ platform_set_drvdata(pdev, info); ++ ++ of_for_each_phandle(&it, err, node, "devices", NULL, 0) { ++ mtd = of_get_mtd_device_by_node(it.node); ++ if (IS_ERR(mtd)) { ++ of_node_put(it.node); ++ err = -EPROBE_DEFER; ++ goto err_remove; ++ } ++ ++ info->devices[info->num_devices++] = mtd; ++ } ++ ++ info->cmtd = mtd_concat_create(info->devices, info->num_devices, ++ dev_name(&pdev->dev)); ++ if (!info->cmtd) { ++ err = -ENXIO; ++ goto err_remove; ++ } ++ ++ info->cmtd->dev.parent = &pdev->dev; ++ mtd_set_of_node(info->cmtd, node); ++ mtd_device_register(info->cmtd, NULL, 0); ++ ++ return 0; ++ ++err_remove: ++ virt_concat_remove(pdev); ++ ++ return err; ++} ++ ++static const struct of_device_id virt_concat_of_match[] = { ++ { .compatible = "mtd-concat", }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, virt_concat_of_match); ++ ++static struct platform_driver virt_concat_driver = { ++ .probe = virt_concat_probe, ++ .remove = virt_concat_remove, ++ .driver = { ++ .name = "virt-mtdconcat", ++ .of_match_table = virt_concat_of_match, ++ }, ++}; ++ ++module_platform_driver(virt_concat_driver); ++ ++MODULE_LICENSE("GPL v2"); ++MODULE_AUTHOR("Bernhard Frauendienst "); ++MODULE_DESCRIPTION("Virtual concat MTD device driver"); +-- +2.51.0 + + +From 347c5537f56a96c67c3a22c4f3779c4b95dc11a5 Mon Sep 17 00:00:00 2001 +From: Nick Hainke +Date: Mon, 27 Dec 2021 00:38:13 +0100 +Subject: [PATCH 247/517] mtd: spi-nor: locking support for MX25L6405D + +Macronix MX25L6405D supports locking with four block-protection bits. +Currently, the driver only sets three bits. If the bootloader does not +sustain the flash chip in an unlocked state, the flash might be +non-writeable. Add the corresponding flag to enable locking support with +four bits in the status register. + +Tested on Nanostation M2 XM. + +Similar to commit 7ea40b54e83b ("mtd: spi-nor: enable locking support for +MX25L12805D") + +Signed-off-by: David Bauer +Signed-off-by: Nick Hainke +--- + drivers/mtd/spi-nor/macronix.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/mtd/spi-nor/macronix.c b/drivers/mtd/spi-nor/macronix.c +index ac125b89e7ba..d31b2590c849 100644 +--- a/drivers/mtd/spi-nor/macronix.c ++++ b/drivers/mtd/spi-nor/macronix.c +@@ -66,6 +66,7 @@ static const struct flash_info macronix_nor_parts[] = { + .id = SNOR_ID(0xc2, 0x20, 0x17), + .name = "mx25l6405d", + .size = SZ_8M, ++ .flags = SPI_NOR_HAS_LOCK | SPI_NOR_4BIT_BP, + .no_sfdp_flags = SECT_4K, + }, { + .id = SNOR_ID(0xc2, 0x20, 0x18), +-- +2.51.0 + + +From 9fa9e3569e11cbb64b50a208ae98a4b2e09e00c4 Mon Sep 17 00:00:00 2001 +From: Nick Hainke +Date: Mon, 27 Dec 2021 09:33:13 +0100 +Subject: [PATCH 248/517] mtd: spi-nor: disable 16-bit-sr for macronix + +Macronix flash chips seem to consist of only one status register. +These chips will not work with the "16-bit Write Status (01h) Command". +Disable SNOR_F_HAS_16BIT_SR for all Macronix chips. + +Tested with MX25L6405D. + +Fixes: 39d1e3340c73 ("mtd: spi-nor: Fix clearing of QE bit on +lock()/unlock()") + +Signed-off-by: David Bauer +Signed-off-by: Nick Hainke +--- + drivers/mtd/spi-nor/macronix.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/mtd/spi-nor/macronix.c b/drivers/mtd/spi-nor/macronix.c +index d31b2590c849..873c199616ee 100644 +--- a/drivers/mtd/spi-nor/macronix.c ++++ b/drivers/mtd/spi-nor/macronix.c +@@ -195,6 +195,7 @@ static int macronix_nor_late_init(struct spi_nor *nor) + { + if (!nor->params->set_4byte_addr_mode) + nor->params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_en4b_ex4b; ++ nor->flags &= ~SNOR_F_HAS_16BIT_SR; + nor->flags |= SNOR_F_HAS_LOCK; + + return 0; +-- +2.51.0 + + +From c57f1d7da4a3684160aad8280a29764983fc99e0 Mon Sep 17 00:00:00 2001 +From: OpenWrt community +Date: Wed, 13 Jul 2022 12:21:15 +0200 +Subject: [PATCH 249/517] fs: add cdrom dependency + +--- + fs/hfs/Kconfig | 1 + + fs/hfsplus/Kconfig | 1 + + fs/isofs/Kconfig | 1 + + fs/udf/Kconfig | 1 + + 4 files changed, 4 insertions(+) + +diff --git a/fs/hfs/Kconfig b/fs/hfs/Kconfig +index 5ea5cd8ecea9..8a0ca259dc58 100644 +--- a/fs/hfs/Kconfig ++++ b/fs/hfs/Kconfig +@@ -2,6 +2,7 @@ + config HFS_FS + tristate "Apple Macintosh file system support" + depends on BLOCK ++ select CDROM + select BUFFER_HEAD + select NLS + select LEGACY_DIRECT_IO +diff --git a/fs/hfsplus/Kconfig b/fs/hfsplus/Kconfig +index 8ce4a33a9ac7..f3f07878dbbd 100644 +--- a/fs/hfsplus/Kconfig ++++ b/fs/hfsplus/Kconfig +@@ -2,6 +2,7 @@ + config HFSPLUS_FS + tristate "Apple Extended HFS file system support" + depends on BLOCK ++ select CDROM + select BUFFER_HEAD + select NLS + select NLS_UTF8 +diff --git a/fs/isofs/Kconfig b/fs/isofs/Kconfig +index 51434f2a471b..9847d2e3aac2 100644 +--- a/fs/isofs/Kconfig ++++ b/fs/isofs/Kconfig +@@ -1,6 +1,7 @@ + # SPDX-License-Identifier: GPL-2.0-only + config ISO9660_FS + tristate "ISO 9660 CDROM file system support" ++ select CDROM + select BUFFER_HEAD + help + This is the standard file system used on CD-ROMs. It was previously +diff --git a/fs/udf/Kconfig b/fs/udf/Kconfig +index 8f7ce30d47fd..0b015b1a455a 100644 +--- a/fs/udf/Kconfig ++++ b/fs/udf/Kconfig +@@ -1,6 +1,7 @@ + # SPDX-License-Identifier: GPL-2.0-only + config UDF_FS + tristate "UDF file system support" ++ select CDROM + select BUFFER_HEAD + select CRC_ITU_T + select NLS +-- +2.51.0 + + +From 518d8e07b43f2428a02fef795710a7ddab3e7ae1 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Wed, 16 Nov 2022 12:49:52 +0000 +Subject: [PATCH 250/517] block: add uImage.FIT subimage block driver + +Add a small block driver which exposes filesystem sub-images contained +in U-Boot uImage.FIT images as block devices. + +The uImage.FIT image has to be stored directly on a block device or +partition, MTD device or partition, or UBI volume. + +The driver is intended for systems using the U-Boot bootloader and +uses the root device hint left by the bootloader (or the user) in +the 'chosen' section of the device-tree. + +Example: +/dts-v1/; +/ { + chosen { + rootdisk = <&mmc0_part3>; + }; +}; + +Signed-off-by: Daniel Golle +--- + MAINTAINERS | 6 + + drivers/block/Kconfig | 12 + + drivers/block/Makefile | 2 + + drivers/block/fitblk.c | 660 ++++++++++++++++++++++++++++++++++++ + include/uapi/linux/fitblk.h | 10 + + 5 files changed, 690 insertions(+) + create mode 100644 drivers/block/fitblk.c + create mode 100644 include/uapi/linux/fitblk.h + +diff --git a/MAINTAINERS b/MAINTAINERS +index 7d694e7b4f42..dcb5c71bc204 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -23668,6 +23668,12 @@ F: Documentation/filesystems/ubifs-authentication.rst + F: Documentation/filesystems/ubifs.rst + F: fs/ubifs/ + ++U-BOOT UIMAGE.FIT PARSER ++M: Daniel Golle ++L: linux-block@vger.kernel.org ++S: Maintained ++F: drivers/block/fitblk.c ++ + UBLK USERSPACE BLOCK DRIVER + M: Ming Lei + L: linux-block@vger.kernel.org +diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig +index ed209f4f2798..c777065f70e4 100644 +--- a/drivers/block/Kconfig ++++ b/drivers/block/Kconfig +@@ -363,6 +363,18 @@ config BLK_DEV_RUST_NULL + + If unsure, say N. + ++config UIMAGE_FIT_BLK ++ bool "uImage.FIT block driver" ++ help ++ This driver allows using filesystems contained in uImage.FIT images ++ by mapping them as block devices. ++ ++ It can currently not be built as a module due to libfdt symbols not ++ being exported. ++ ++ Say Y if you want to mount filesystems sub-images of a uImage.FIT ++ stored in a block device partition, mtdblock or ubiblock device. ++ + config BLK_DEV_RBD + tristate "Rados block device (RBD)" + depends on INET && BLOCK +diff --git a/drivers/block/Makefile b/drivers/block/Makefile +index 1105a2d4fdcb..2ba7b5ad8f6f 100644 +--- a/drivers/block/Makefile ++++ b/drivers/block/Makefile +@@ -42,4 +42,6 @@ obj-$(CONFIG_BLK_DEV_NULL_BLK) += null_blk/ + + obj-$(CONFIG_BLK_DEV_UBLK) += ublk_drv.o + ++obj-$(CONFIG_UIMAGE_FIT_BLK) += fitblk.o ++ + swim_mod-y := swim.o swim_asm.o +diff --git a/drivers/block/fitblk.c b/drivers/block/fitblk.c +new file mode 100644 +index 000000000000..b6d8e0fd25a0 +--- /dev/null ++++ b/drivers/block/fitblk.c +@@ -0,0 +1,660 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * uImage.FIT virtual block device driver. ++ * ++ * Copyright (C) 2023 Daniel Golle ++ * Copyright (C) 2007 Nick Piggin ++ * Copyright (C) 2007 Novell Inc. ++ * ++ * Initially derived from drivers/block/brd.c which is in parts derived from ++ * drivers/block/rd.c, and drivers/block/loop.c, copyright of their respective ++ * owners. ++ * ++ * uImage.FIT headers extracted from Das U-Boot ++ * (C) Copyright 2008 Semihalf ++ * (C) Copyright 2000-2005 ++ * Wolfgang Denk, DENX Software Engineering, wd@denx.de. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define FIT_DEVICE_PREFIX "fit" ++ ++/* maximum number of pages used for the uImage.FIT index structure */ ++#define FIT_MAX_PAGES 1024 ++ ++/* minimum free sectors to map as read-write "remainder" volume */ ++#define MIN_FREE_SECT 16 ++ ++/* maximum number of mapped loadables */ ++#define MAX_FIT_LOADABLES 16 ++ ++/* constants for uImage.FIT structrure traversal */ ++#define FIT_IMAGES_PATH "/images" ++#define FIT_CONFS_PATH "/configurations" ++ ++/* hash/signature/key node */ ++#define FIT_HASH_NODENAME "hash" ++#define FIT_ALGO_PROP "algo" ++#define FIT_VALUE_PROP "value" ++#define FIT_IGNORE_PROP "uboot-ignore" ++#define FIT_SIG_NODENAME "signature" ++#define FIT_KEY_REQUIRED "required" ++#define FIT_KEY_HINT "key-name-hint" ++ ++/* cipher node */ ++#define FIT_CIPHER_NODENAME "cipher" ++#define FIT_ALGO_PROP "algo" ++ ++/* image node */ ++#define FIT_DATA_PROP "data" ++#define FIT_DATA_POSITION_PROP "data-position" ++#define FIT_DATA_OFFSET_PROP "data-offset" ++#define FIT_DATA_SIZE_PROP "data-size" ++#define FIT_TIMESTAMP_PROP "timestamp" ++#define FIT_DESC_PROP "description" ++#define FIT_ARCH_PROP "arch" ++#define FIT_TYPE_PROP "type" ++#define FIT_OS_PROP "os" ++#define FIT_COMP_PROP "compression" ++#define FIT_ENTRY_PROP "entry" ++#define FIT_LOAD_PROP "load" ++ ++/* configuration node */ ++#define FIT_KERNEL_PROP "kernel" ++#define FIT_FILESYSTEM_PROP "filesystem" ++#define FIT_RAMDISK_PROP "ramdisk" ++#define FIT_FDT_PROP "fdt" ++#define FIT_LOADABLE_PROP "loadables" ++#define FIT_DEFAULT_PROP "default" ++#define FIT_SETUP_PROP "setup" ++#define FIT_FPGA_PROP "fpga" ++#define FIT_FIRMWARE_PROP "firmware" ++#define FIT_STANDALONE_PROP "standalone" ++ ++/* fitblk driver data */ ++static const char *_fitblk_claim_ptr = "I belong to fitblk"; ++static const char *ubootver; ++struct device_node *rootdisk; ++static struct platform_device *pdev; ++static LIST_HEAD(fitblk_devices); ++static DEFINE_MUTEX(devices_mutex); ++refcount_t num_devs; ++ ++struct fitblk { ++ struct platform_device *pdev; ++ struct file *bdev_file; ++ sector_t start_sect; ++ struct gendisk *disk; ++ struct work_struct remove_work; ++ struct list_head list; ++ bool dead; ++}; ++ ++static int fitblk_open(struct gendisk *disk, fmode_t mode) ++{ ++ struct fitblk *fitblk = disk->private_data; ++ ++ if (fitblk->dead) ++ return -ENOENT; ++ ++ return 0; ++} ++ ++static void fitblk_release(struct gendisk *disk) ++{ ++ return; ++} ++ ++static void fitblk_submit_bio(struct bio *orig_bio) ++{ ++ struct bio *bio = orig_bio; ++ struct fitblk *fitblk = bio->bi_bdev->bd_disk->private_data; ++ ++ if (fitblk->dead) ++ return; ++ ++ /* mangle bio and re-submit */ ++ while (bio) { ++ bio->bi_iter.bi_sector += fitblk->start_sect; ++ bio->bi_bdev = file_bdev(fitblk->bdev_file); ++ bio = bio->bi_next; ++ } ++ submit_bio(orig_bio); ++} ++ ++static void fitblk_remove(struct fitblk *fitblk) ++{ ++ blk_mark_disk_dead(fitblk->disk); ++ mutex_lock(&devices_mutex); ++ fitblk->dead = true; ++ list_del(&fitblk->list); ++ mutex_unlock(&devices_mutex); ++ ++ schedule_work(&fitblk->remove_work); ++} ++ ++static int fitblk_ioctl(struct block_device *bdev, fmode_t mode, ++ unsigned int cmd, unsigned long arg) ++{ ++ struct fitblk *fitblk = bdev->bd_disk->private_data; ++ ++ if (!capable(CAP_SYS_ADMIN)) ++ return -EACCES; ++ ++ if (fitblk->dead) ++ return -ENOENT; ++ ++ switch (cmd) { ++ case FITBLK_RELEASE: ++ fitblk_remove(fitblk); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static const struct block_device_operations fitblk_fops = { ++ .owner = THIS_MODULE, ++ .ioctl = fitblk_ioctl, ++ .open = fitblk_open, ++ .release = fitblk_release, ++ .submit_bio = fitblk_submit_bio, ++}; ++ ++static void fitblk_purge(struct work_struct *work) ++{ ++ struct fitblk *fitblk = container_of(work, struct fitblk, remove_work); ++ ++ del_gendisk(fitblk->disk); ++ refcount_dec(&num_devs); ++ platform_device_del(fitblk->pdev); ++ platform_device_put(fitblk->pdev); ++ ++ if (refcount_dec_if_one(&num_devs)) { ++ sysfs_remove_link(&pdev->dev.kobj, "lower_dev"); ++ fput(fitblk->bdev_file); ++ } ++ ++ kfree(fitblk); ++} ++ ++static int add_fit_subimage_device(struct file *bdev_file, ++ unsigned int slot, sector_t start_sect, ++ sector_t nr_sect, bool readonly) ++{ ++ struct block_device *bdev = file_bdev(bdev_file); ++ struct fitblk *fitblk; ++ struct gendisk *disk; ++ int err; ++ ++ mutex_lock(&devices_mutex); ++ if (!refcount_inc_not_zero(&num_devs)) ++ return -EBADF; ++ ++ fitblk = kzalloc(sizeof(struct fitblk), GFP_KERNEL); ++ if (!fitblk) { ++ err = -ENOMEM; ++ goto out_unlock; ++ } ++ ++ fitblk->bdev_file = bdev_file; ++ fitblk->start_sect = start_sect; ++ INIT_WORK(&fitblk->remove_work, fitblk_purge); ++ ++ disk = blk_alloc_disk(&bdev->bd_disk->queue->limits, NUMA_NO_NODE); ++ if (!disk) { ++ err = -ENOMEM; ++ goto out_free_fitblk; ++ } ++ ++ disk->first_minor = 0; ++ disk->flags = bdev->bd_disk->flags | GENHD_FL_NO_PART; ++ disk->fops = &fitblk_fops; ++ disk->private_data = fitblk; ++ if (readonly) { ++ set_disk_ro(disk, 1); ++ snprintf(disk->disk_name, sizeof(disk->disk_name), FIT_DEVICE_PREFIX "%u", slot); ++ } else { ++ strcpy(disk->disk_name, FIT_DEVICE_PREFIX "rw"); ++ } ++ ++ set_capacity(disk, nr_sect); ++ disk->queue->queue_flags = bdev->bd_disk->queue->queue_flags; ++ ++ fitblk->disk = disk; ++ fitblk->pdev = platform_device_alloc(disk->disk_name, PLATFORM_DEVID_NONE); ++ if (!fitblk->pdev) { ++ err = -ENOMEM; ++ goto out_cleanup_disk; ++ } ++ ++ fitblk->pdev->dev.parent = &pdev->dev; ++ err = platform_device_add(fitblk->pdev); ++ if (err) ++ goto out_put_pdev; ++ ++ err = device_add_disk(&fitblk->pdev->dev, disk, NULL); ++ if (err) ++ goto out_del_pdev; ++ ++ if (!ROOT_DEV) ++ ROOT_DEV = disk->part0->bd_dev; ++ ++ list_add_tail(&fitblk->list, &fitblk_devices); ++ ++ mutex_unlock(&devices_mutex); ++ ++ return 0; ++ ++out_del_pdev: ++ platform_device_del(fitblk->pdev); ++out_put_pdev: ++ platform_device_put(fitblk->pdev); ++out_cleanup_disk: ++ put_disk(disk); ++out_free_fitblk: ++ kfree(fitblk); ++out_unlock: ++ refcount_dec(&num_devs); ++ mutex_unlock(&devices_mutex); ++ return err; ++} ++ ++static void fitblk_mark_dead(struct block_device *bdev, bool surprise) ++{ ++ struct list_head *n, *tmp; ++ struct fitblk *fitblk; ++ ++ mutex_lock(&devices_mutex); ++ list_for_each_safe(n, tmp, &fitblk_devices) { ++ fitblk = list_entry(n, struct fitblk, list); ++ if (file_bdev(fitblk->bdev_file) != bdev) ++ continue; ++ ++ fitblk->dead = true; ++ list_del(&fitblk->list); ++ /* removal needs to be deferred to avoid deadlock */ ++ schedule_work(&fitblk->remove_work); ++ } ++ mutex_unlock(&devices_mutex); ++} ++ ++static const struct blk_holder_ops fitblk_hops = { ++ .mark_dead = fitblk_mark_dead, ++}; ++ ++static int parse_fit_on_dev(struct device *dev) ++{ ++ struct file *bdev_file; ++ struct block_device *bdev; ++ struct address_space *mapping; ++ struct folio *folio; ++ pgoff_t f_index = 0; ++ size_t bytes_left, bytes_to_copy; ++ void *pre_fit, *fit, *fit_c; ++ u64 dsize, dsectors, imgmaxsect = 0; ++ u32 size, image_pos, image_len; ++ const __be32 *image_offset_be, *image_len_be, *image_pos_be; ++ int ret = 0, node, images, config; ++ const char *image_name, *image_type, *image_description, ++ *config_default, *config_description, *config_loadables; ++ u32 image_name_len, image_type_len, image_description_len, ++ bootconf_len, config_default_len, config_description_len, ++ config_loadables_len; ++ sector_t start_sect, nr_sects; ++ struct device_node *np = NULL; ++ const char *bootconf_c; ++ const char *loadable; ++ char *bootconf = NULL, *bootconf_term; ++ bool found; ++ int loadables_rem_len, loadable_len; ++ u16 loadcnt; ++ unsigned int slot = 0; ++ ++ /* Exclusive open the block device to receive holder notifications */ ++ bdev_file = bdev_file_open_by_dev(dev->devt, ++ BLK_OPEN_READ | BLK_OPEN_RESTRICT_WRITES, ++ &_fitblk_claim_ptr, &fitblk_hops); ++ if (!bdev_file) ++ return -ENODEV; ++ ++ if (IS_ERR(bdev_file)) ++ return PTR_ERR(bdev_file); ++ ++ bdev = file_bdev(bdev_file); ++ mapping = bdev_file->f_mapping; ++ ++ /* map first page */ ++ folio = read_mapping_folio(mapping, f_index++, NULL); ++ if (IS_ERR(folio)) { ++ ret = PTR_ERR(folio); ++ goto out_blkdev; ++ } ++ pre_fit = folio_address(folio) + offset_in_folio(folio, 0); ++ ++ /* uImage.FIT is based on flattened device tree structure */ ++ if (fdt_check_header(pre_fit)) { ++ ret = -EINVAL; ++ folio_put(folio); ++ goto out_blkdev; ++ } ++ ++ size = fdt_totalsize(pre_fit); ++ ++ if (size > PAGE_SIZE * FIT_MAX_PAGES) { ++ ret = -EOPNOTSUPP; ++ folio_put(folio); ++ goto out_blkdev; ++ } ++ ++ /* acquire disk size */ ++ dsectors = bdev_nr_sectors(bdev); ++ dsize = dsectors << SECTOR_SHIFT; ++ ++ /* abort if FIT structure is larger than disk or partition size */ ++ if (size >= dsize) { ++ ret = -EFBIG; ++ folio_put(folio); ++ goto out_blkdev; ++ } ++ ++ fit = kmalloc(size, GFP_KERNEL); ++ if (!fit) { ++ ret = -ENOMEM; ++ folio_put(folio); ++ goto out_blkdev; ++ } ++ ++ bytes_left = size; ++ fit_c = fit; ++ while (bytes_left > 0) { ++ bytes_to_copy = min_t(size_t, bytes_left, ++ folio_size(folio) - offset_in_folio(folio, 0)); ++ memcpy(fit_c, pre_fit, bytes_to_copy); ++ fit_c += bytes_to_copy; ++ bytes_left -= bytes_to_copy; ++ if (bytes_left) { ++ folio_put(folio); ++ folio = read_mapping_folio(mapping, f_index++, NULL); ++ if (IS_ERR(folio)) { ++ ret = PTR_ERR(folio); ++ goto out_blkdev; ++ }; ++ pre_fit = folio_address(folio) + offset_in_folio(folio, 0); ++ } ++ } ++ folio_put(folio); ++ ++ /* set boot config node name U-Boot may have added to the device tree */ ++ np = of_find_node_by_path("/chosen"); ++ if (np) { ++ bootconf_c = of_get_property(np, "u-boot,bootconf", &bootconf_len); ++ if (bootconf_c && bootconf_len) ++ bootconf = kmemdup_nul(bootconf_c, bootconf_len, GFP_KERNEL); ++ } ++ ++ if (bootconf) { ++ bootconf_term = strchr(bootconf, '#'); ++ if (bootconf_term) ++ *bootconf_term = '\0'; ++ } ++ ++ /* find configuration path in uImage.FIT */ ++ config = fdt_path_offset(fit, FIT_CONFS_PATH); ++ if (config < 0) { ++ pr_err("FIT: Cannot find %s node: %d\n", ++ FIT_CONFS_PATH, config); ++ ret = -ENOENT; ++ goto out_bootconf; ++ } ++ ++ /* get default configuration node name */ ++ config_default = ++ fdt_getprop(fit, config, FIT_DEFAULT_PROP, &config_default_len); ++ ++ /* make sure we got either default or selected boot config node name */ ++ if (!config_default && !bootconf) { ++ pr_err("FIT: Cannot find default configuration\n"); ++ ret = -ENOENT; ++ goto out_bootconf; ++ } ++ ++ /* find selected boot config node, fallback on default config node */ ++ node = fdt_subnode_offset(fit, config, bootconf ?: config_default); ++ if (node < 0) { ++ pr_err("FIT: Cannot find %s node: %d\n", ++ bootconf ?: config_default, node); ++ ret = -ENOENT; ++ goto out_bootconf; ++ } ++ ++ pr_info("FIT: Detected U-Boot %s\n", ubootver); ++ ++ /* get selected configuration data */ ++ config_description = ++ fdt_getprop(fit, node, FIT_DESC_PROP, &config_description_len); ++ config_loadables = fdt_getprop(fit, node, FIT_LOADABLE_PROP, ++ &config_loadables_len); ++ ++ pr_info("FIT: %s configuration: \"%.*s\"%s%.*s%s\n", ++ bootconf ? "Selected" : "Default", ++ bootconf ? bootconf_len : config_default_len, ++ bootconf ?: config_default, ++ config_description ? " (" : "", ++ config_description ? config_description_len : 0, ++ config_description ?: "", ++ config_description ? ")" : ""); ++ ++ if (!config_loadables || !config_loadables_len) { ++ pr_err("FIT: No loadables configured in \"%s\"\n", ++ bootconf ?: config_default); ++ ret = -ENOENT; ++ goto out_bootconf; ++ } ++ ++ /* get images path in uImage.FIT */ ++ images = fdt_path_offset(fit, FIT_IMAGES_PATH); ++ if (images < 0) { ++ pr_err("FIT: Cannot find %s node: %d\n", FIT_IMAGES_PATH, images); ++ ret = -EINVAL; ++ goto out_bootconf; ++ } ++ ++ /* iterate over images in uImage.FIT */ ++ fdt_for_each_subnode(node, fit, images) { ++ image_name = fdt_get_name(fit, node, &image_name_len); ++ image_type = fdt_getprop(fit, node, FIT_TYPE_PROP, &image_type_len); ++ image_offset_be = fdt_getprop(fit, node, FIT_DATA_OFFSET_PROP, NULL); ++ image_pos_be = fdt_getprop(fit, node, FIT_DATA_POSITION_PROP, NULL); ++ image_len_be = fdt_getprop(fit, node, FIT_DATA_SIZE_PROP, NULL); ++ ++ if (!image_name || !image_type || !image_len_be || ++ !image_name_len || !image_type_len) ++ continue; ++ ++ image_len = be32_to_cpu(*image_len_be); ++ if (!image_len) ++ continue; ++ ++ if (image_offset_be) ++ image_pos = be32_to_cpu(*image_offset_be) + size; ++ else if (image_pos_be) ++ image_pos = be32_to_cpu(*image_pos_be); ++ else ++ continue; ++ ++ image_description = fdt_getprop(fit, node, FIT_DESC_PROP, ++ &image_description_len); ++ ++ pr_info("FIT: %16s sub-image 0x%08x..0x%08x \"%.*s\"%s%.*s%s\n", ++ image_type, image_pos, image_pos + image_len - 1, ++ image_name_len, image_name, image_description ? " (" : "", ++ image_description ? image_description_len : 0, ++ image_description ?: "", image_description ? ") " : ""); ++ ++ /* only 'filesystem' images should be mapped as partitions */ ++ if (strncmp(image_type, FIT_FILESYSTEM_PROP, image_type_len)) ++ continue; ++ ++ /* check if sub-image is part of configured loadables */ ++ found = false; ++ loadable = config_loadables; ++ loadables_rem_len = config_loadables_len; ++ for (loadcnt = 0; loadables_rem_len > 1 && ++ loadcnt < MAX_FIT_LOADABLES; ++loadcnt) { ++ loadable_len = ++ strnlen(loadable, loadables_rem_len - 1) + 1; ++ loadables_rem_len -= loadable_len; ++ if (!strncmp(image_name, loadable, loadable_len)) { ++ found = true; ++ break; ++ } ++ loadable += loadable_len; ++ } ++ if (!found) ++ continue; ++ ++ if (image_pos % (1 << PAGE_SHIFT)) { ++ dev_err(dev, "FIT: image %.*s start not aligned to page boundaries, skipping\n", ++ image_name_len, image_name); ++ continue; ++ } ++ ++ if (image_len % (1 << PAGE_SHIFT)) { ++ dev_err(dev, "FIT: sub-image %.*s end not aligned to page boundaries, skipping\n", ++ image_name_len, image_name); ++ continue; ++ } ++ ++ start_sect = image_pos >> SECTOR_SHIFT; ++ nr_sects = image_len >> SECTOR_SHIFT; ++ imgmaxsect = max_t(sector_t, imgmaxsect, start_sect + nr_sects); ++ ++ if (start_sect + nr_sects > dsectors) { ++ dev_err(dev, "FIT: sub-image %.*s disk access beyond EOD\n", ++ image_name_len, image_name); ++ continue; ++ } ++ ++ if (!slot) { ++ ret = sysfs_create_link_nowarn(&pdev->dev.kobj, bdev_kobj(bdev), "lower_dev"); ++ if (ret && ret != -EEXIST) ++ goto out_bootconf; ++ ++ ret = 0; ++ } ++ ++ add_fit_subimage_device(bdev_file, slot++, start_sect, nr_sects, true); ++ } ++ ++ if (!slot) ++ goto out_bootconf; ++ ++ dev_info(dev, "mapped %u uImage.FIT filesystem sub-image%s as /dev/fit%s%u%s\n", ++ slot, (slot > 1)?"s":"", (slot > 1)?"[0...":"", slot - 1, ++ (slot > 1)?"]":""); ++ ++ /* in case uImage.FIT is stored in a partition, map the remaining space */ ++ if (!bdev_read_only(bdev) && bdev_is_partition(bdev) && ++ (imgmaxsect + MIN_FREE_SECT) < dsectors) { ++ add_fit_subimage_device(bdev_file, slot++, imgmaxsect, ++ dsectors - imgmaxsect, false); ++ dev_info(dev, "mapped remaining space as /dev/fitrw\n"); ++ } ++ ++out_bootconf: ++ kfree(bootconf); ++ kfree(fit); ++out_blkdev: ++ if (!slot) ++ fput(bdev_file); ++ ++ return ret; ++} ++ ++static int fitblk_match_of_node(struct device *dev, const void *np) ++{ ++ int ret; ++ ++ ret = device_match_of_node(dev, np); ++ if (ret) ++ return ret; ++ ++ /* ++ * To match ubiblock and mtdblock devices by their parent ubi ++ * or mtd device, also consider block device parent ++ */ ++ if (!dev->parent) ++ return 0; ++ ++ return device_match_of_node(dev->parent, np); ++} ++ ++static int fitblk_probe(struct platform_device *pdev) ++{ ++ struct device *dev; ++ ++ dev = class_find_device(&block_class, NULL, rootdisk, fitblk_match_of_node); ++ if (!dev) ++ return -EPROBE_DEFER; ++ ++ return parse_fit_on_dev(dev); ++} ++ ++static struct platform_driver fitblk_driver = { ++ .probe = fitblk_probe, ++ .driver = { ++ .name = "fitblk", ++ }, ++}; ++ ++static int __init fitblk_init(void) ++{ ++ /* detect U-Boot firmware */ ++ ubootver = of_get_property(of_chosen, "u-boot,version", NULL); ++ if (!ubootver) ++ return 0; ++ ++ /* parse 'rootdisk' property phandle */ ++ rootdisk = of_parse_phandle(of_chosen, "rootdisk", 0); ++ if (!rootdisk) ++ return 0; ++ ++ if (platform_driver_register(&fitblk_driver)) ++ return -ENODEV; ++ ++ refcount_set(&num_devs, 1); ++ pdev = platform_device_register_simple("fitblk", -1, NULL, 0); ++ if (IS_ERR(pdev)) ++ return PTR_ERR(pdev); ++ ++ return 0; ++} ++device_initcall(fitblk_init); +diff --git a/include/uapi/linux/fitblk.h b/include/uapi/linux/fitblk.h +new file mode 100644 +index 000000000000..a8f80a5e990a +--- /dev/null ++++ b/include/uapi/linux/fitblk.h +@@ -0,0 +1,10 @@ ++/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ ++#ifndef _UAPI_LINUX_FITBLK_H ++#define _UAPI_LINUX_FITBLK_H ++ ++/* ++ * IOCTL commands --- we will commandeer 0x46 ('F') ++ */ ++#define FITBLK_RELEASE 0x4600 ++ ++#endif /* _UAPI_LINUX_FITBLK_H */ +-- +2.51.0 + + +From fa659019e6589fd4399c41dc7e4d4543fc7a54b3 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Mon, 12 Jun 2023 03:58:42 +0100 +Subject: [PATCH 251/517] init: bypass device lookup for /dev/fit* rootfs + +Allow 'rootwait' as /dev/fit* can show up late if the underlaying +device is probed late. + +Signed-off-by: Daniel Golle +--- + init/do_mounts.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/init/do_mounts.c b/init/do_mounts.c +index cbb4237700aa..113708a9eb3d 100644 +--- a/init/do_mounts.c ++++ b/init/do_mounts.c +@@ -465,7 +465,8 @@ static dev_t __init parse_root_device(char *root_device_name) + int error; + dev_t dev; + +- if (!strncmp(root_device_name, "mtd", 3) || ++ if (!strncmp(root_device_name, "fit", 3) || ++ !strncmp(root_device_name, "mtd", 3) || + !strncmp(root_device_name, "ubi", 3)) + return Root_Generic; + if (strcmp(root_device_name, "/dev/nfs") == 0) +-- +2.51.0 + + +From 43633b0334e99dc60bb38af2f75632f17506046d Mon Sep 17 00:00:00 2001 +From: "Alexandros C. Couloumbis" +Date: Mon, 3 Nov 2025 15:49:52 +0100 +Subject: [PATCH 252/517] fs: add jffs2/lzma support (not activated by default + yet) + +lede-commit: c2c88d315fa0e881f8b19da07b62859b915b11b2 +Signed-off-by: Alexandros C. Couloumbis +--- + fs/jffs2/Kconfig | 9 + + fs/jffs2/Makefile | 3 + + fs/jffs2/compr.c | 6 + + fs/jffs2/compr.h | 13 +- + fs/jffs2/compr_lzma.c | 128 ++ + fs/jffs2/super.c | 33 +- + include/linux/lzma.h | 62 + + include/linux/lzma/LzFind.h | 115 ++ + include/linux/lzma/LzHash.h | 54 + + include/linux/lzma/LzmaDec.h | 231 ++++ + include/linux/lzma/LzmaEnc.h | 80 ++ + include/linux/lzma/Types.h | 226 ++++ + include/uapi/linux/jffs2.h | 1 + + lib/Kconfig | 6 + + lib/Makefile | 12 + + lib/lzma/LzFind.c | 761 ++++++++++++ + lib/lzma/LzmaDec.c | 999 +++++++++++++++ + lib/lzma/LzmaEnc.c | 2271 ++++++++++++++++++++++++++++++++++ + lib/lzma/Makefile | 7 + + 19 files changed, 5011 insertions(+), 6 deletions(-) + create mode 100644 fs/jffs2/compr_lzma.c + create mode 100644 include/linux/lzma.h + create mode 100644 include/linux/lzma/LzFind.h + create mode 100644 include/linux/lzma/LzHash.h + create mode 100644 include/linux/lzma/LzmaDec.h + create mode 100644 include/linux/lzma/LzmaEnc.h + create mode 100644 include/linux/lzma/Types.h + create mode 100644 lib/lzma/LzFind.c + create mode 100644 lib/lzma/LzmaDec.c + create mode 100644 lib/lzma/LzmaEnc.c + create mode 100644 lib/lzma/Makefile + +diff --git a/fs/jffs2/Kconfig b/fs/jffs2/Kconfig +index 560187d61562..9c7b1df2206d 100644 +--- a/fs/jffs2/Kconfig ++++ b/fs/jffs2/Kconfig +@@ -136,6 +136,15 @@ config JFFS2_LZO + This feature was added in July, 2007. Say 'N' if you need + compatibility with older bootloaders or kernels. + ++config JFFS2_LZMA ++ bool "JFFS2 LZMA compression support" if JFFS2_COMPRESSION_OPTIONS ++ select LZMA_COMPRESS ++ select LZMA_DECOMPRESS ++ depends on JFFS2_FS ++ default n ++ help ++ JFFS2 wrapper to the LZMA C SDK ++ + config JFFS2_RTIME + bool "JFFS2 RTIME compression support" if JFFS2_COMPRESSION_OPTIONS + depends on JFFS2_FS +diff --git a/fs/jffs2/Makefile b/fs/jffs2/Makefile +index 5294969d5bf9..11a89b96e5f3 100644 +--- a/fs/jffs2/Makefile ++++ b/fs/jffs2/Makefile +@@ -19,4 +19,7 @@ jffs2-$(CONFIG_JFFS2_RUBIN) += compr_rubin.o + jffs2-$(CONFIG_JFFS2_RTIME) += compr_rtime.o + jffs2-$(CONFIG_JFFS2_ZLIB) += compr_zlib.o + jffs2-$(CONFIG_JFFS2_LZO) += compr_lzo.o ++jffs2-$(CONFIG_JFFS2_LZMA) += compr_lzma.o + jffs2-$(CONFIG_JFFS2_SUMMARY) += summary.o ++ ++CFLAGS_compr_lzma.o += -Iinclude/linux -Ilib/lzma +diff --git a/fs/jffs2/compr.c b/fs/jffs2/compr.c +index 764f19dec3f0..6b5e82b3f6c6 100644 +--- a/fs/jffs2/compr.c ++++ b/fs/jffs2/compr.c +@@ -381,6 +381,9 @@ int __init jffs2_compressors_init(void) + ret = jffs2_lzo_init(); + if (ret) + goto exit_dynrubin; ++ ret = jffs2_lzma_init(); ++ if (ret) ++ goto exit_lzo; + + + /* Setting default compression mode */ +@@ -402,6 +405,8 @@ int __init jffs2_compressors_init(void) + #endif + return 0; + ++exit_lzo: ++ jffs2_lzo_exit(); + exit_dynrubin: + jffs2_dynrubin_exit(); + exit_runinmips: +@@ -417,6 +422,7 @@ int __init jffs2_compressors_init(void) + int jffs2_compressors_exit(void) + { + /* Unregistering compressors */ ++ jffs2_lzma_exit(); + jffs2_lzo_exit(); + jffs2_dynrubin_exit(); + jffs2_rubinmips_exit(); +diff --git a/fs/jffs2/compr.h b/fs/jffs2/compr.h +index 3716b6b7924c..00689727a1c5 100644 +--- a/fs/jffs2/compr.h ++++ b/fs/jffs2/compr.h +@@ -29,9 +29,9 @@ + #define JFFS2_DYNRUBIN_PRIORITY 20 + #define JFFS2_LZARI_PRIORITY 30 + #define JFFS2_RTIME_PRIORITY 50 +-#define JFFS2_ZLIB_PRIORITY 60 +-#define JFFS2_LZO_PRIORITY 80 +- ++#define JFFS2_LZMA_PRIORITY 70 ++#define JFFS2_ZLIB_PRIORITY 80 ++#define JFFS2_LZO_PRIORITY 90 + + #define JFFS2_RUBINMIPS_DISABLED /* RUBINs will be used only */ + #define JFFS2_DYNRUBIN_DISABLED /* for decompression */ +@@ -115,5 +115,12 @@ extern void jffs2_lzo_exit(void); + static inline int jffs2_lzo_init(void) { return 0; } + static inline void jffs2_lzo_exit(void) {} + #endif ++#ifdef CONFIG_JFFS2_LZMA ++extern int jffs2_lzma_init(void); ++extern void jffs2_lzma_exit(void); ++#else ++static inline int jffs2_lzma_init(void) { return 0; } ++static inline void jffs2_lzma_exit(void) {} ++#endif + + #endif /* __JFFS2_COMPR_H__ */ +diff --git a/fs/jffs2/compr_lzma.c b/fs/jffs2/compr_lzma.c +new file mode 100644 +index 000000000000..ec0d9a6020de +--- /dev/null ++++ b/fs/jffs2/compr_lzma.c +@@ -0,0 +1,128 @@ ++/* ++ * JFFS2 -- Journalling Flash File System, Version 2. ++ * ++ * For licensing information, see the file 'LICENCE' in this directory. ++ * ++ * JFFS2 wrapper to the LZMA C SDK ++ * ++ */ ++ ++#include ++#include "compr.h" ++ ++#ifdef __KERNEL__ ++ static DEFINE_MUTEX(deflate_mutex); ++#endif ++ ++CLzmaEncHandle *p; ++Byte propsEncoded[LZMA_PROPS_SIZE]; ++SizeT propsSize = sizeof(propsEncoded); ++ ++STATIC void lzma_free_workspace(void) ++{ ++ LzmaEnc_Destroy(p, &lzma_alloc, &lzma_alloc); ++} ++ ++STATIC int INIT lzma_alloc_workspace(CLzmaEncProps *props) ++{ ++ if ((p = (CLzmaEncHandle *)LzmaEnc_Create(&lzma_alloc)) == NULL) ++ { ++ PRINT_ERROR("Failed to allocate lzma deflate workspace\n"); ++ return -ENOMEM; ++ } ++ ++ if (LzmaEnc_SetProps(p, props) != SZ_OK) ++ { ++ lzma_free_workspace(); ++ return -1; ++ } ++ ++ if (LzmaEnc_WriteProperties(p, propsEncoded, &propsSize) != SZ_OK) ++ { ++ lzma_free_workspace(); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++STATIC int jffs2_lzma_compress(unsigned char *data_in, unsigned char *cpage_out, ++ uint32_t *sourcelen, uint32_t *dstlen) ++{ ++ SizeT compress_size = (SizeT)(*dstlen); ++ int ret; ++ ++ #ifdef __KERNEL__ ++ mutex_lock(&deflate_mutex); ++ #endif ++ ++ ret = LzmaEnc_MemEncode(p, cpage_out, &compress_size, data_in, *sourcelen, ++ 0, NULL, &lzma_alloc, &lzma_alloc); ++ ++ #ifdef __KERNEL__ ++ mutex_unlock(&deflate_mutex); ++ #endif ++ ++ if (ret != SZ_OK) ++ return -1; ++ ++ *dstlen = (uint32_t)compress_size; ++ ++ return 0; ++} ++ ++STATIC int jffs2_lzma_decompress(unsigned char *data_in, unsigned char *cpage_out, ++ uint32_t srclen, uint32_t destlen) ++{ ++ int ret; ++ SizeT dl = (SizeT)destlen; ++ SizeT sl = (SizeT)srclen; ++ ELzmaStatus status; ++ ++ ret = LzmaDecode(cpage_out, &dl, data_in, &sl, propsEncoded, ++ propsSize, LZMA_FINISH_ANY, &status, &lzma_alloc); ++ ++ if (ret != SZ_OK || status == LZMA_STATUS_NOT_FINISHED || dl != (SizeT)destlen) ++ return -1; ++ ++ return 0; ++} ++ ++static struct jffs2_compressor jffs2_lzma_comp = { ++ .priority = JFFS2_LZMA_PRIORITY, ++ .name = "lzma", ++ .compr = JFFS2_COMPR_LZMA, ++ .compress = &jffs2_lzma_compress, ++ .decompress = &jffs2_lzma_decompress, ++ .disabled = 0, ++}; ++ ++int INIT jffs2_lzma_init(void) ++{ ++ int ret; ++ CLzmaEncProps props; ++ LzmaEncProps_Init(&props); ++ ++ props.dictSize = LZMA_BEST_DICT(0x2000); ++ props.level = LZMA_BEST_LEVEL; ++ props.lc = LZMA_BEST_LC; ++ props.lp = LZMA_BEST_LP; ++ props.pb = LZMA_BEST_PB; ++ props.fb = LZMA_BEST_FB; ++ ++ ret = lzma_alloc_workspace(&props); ++ if (ret < 0) ++ return ret; ++ ++ ret = jffs2_register_compressor(&jffs2_lzma_comp); ++ if (ret) ++ lzma_free_workspace(); ++ ++ return ret; ++} ++ ++void jffs2_lzma_exit(void) ++{ ++ jffs2_unregister_compressor(&jffs2_lzma_comp); ++ lzma_free_workspace(); ++} +diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c +index 4545f885c41e..ef4b26ff04c6 100644 +--- a/fs/jffs2/super.c ++++ b/fs/jffs2/super.c +@@ -376,14 +376,41 @@ static int __init init_jffs2_fs(void) + BUILD_BUG_ON(sizeof(struct jffs2_raw_inode) != 68); + BUILD_BUG_ON(sizeof(struct jffs2_raw_summary) != 32); + +- pr_info("version 2.2." ++ pr_info("version 2.2" + #ifdef CONFIG_JFFS2_FS_WRITEBUFFER + " (NAND)" + #endif + #ifdef CONFIG_JFFS2_SUMMARY +- " (SUMMARY) " ++ " (SUMMARY)" + #endif +- " © 2001-2006 Red Hat, Inc.\n"); ++#ifdef CONFIG_JFFS2_ZLIB ++ " (ZLIB)" ++#endif ++#ifdef CONFIG_JFFS2_LZO ++ " (LZO)" ++#endif ++#ifdef CONFIG_JFFS2_LZMA ++ " (LZMA)" ++#endif ++#ifdef CONFIG_JFFS2_RTIME ++ " (RTIME)" ++#endif ++#ifdef CONFIG_JFFS2_RUBIN ++ " (RUBIN)" ++#endif ++#ifdef CONFIG_JFFS2_CMODE_NONE ++ " (CMODE_NONE)" ++#endif ++#ifdef CONFIG_JFFS2_CMODE_PRIORITY ++ " (CMODE_PRIORITY)" ++#endif ++#ifdef CONFIG_JFFS2_CMODE_SIZE ++ " (CMODE_SIZE)" ++#endif ++#ifdef CONFIG_JFFS2_CMODE_FAVOURLZO ++ " (CMODE_FAVOURLZO)" ++#endif ++ " (c) 2001-2006 Red Hat, Inc.\n"); + + jffs2_inode_cachep = kmem_cache_create("jffs2_i", + sizeof(struct jffs2_inode_info), +diff --git a/include/linux/lzma.h b/include/linux/lzma.h +new file mode 100644 +index 000000000000..492ad6c4405c +--- /dev/null ++++ b/include/linux/lzma.h +@@ -0,0 +1,62 @@ ++#ifndef __LZMA_H__ ++#define __LZMA_H__ ++ ++#ifdef __KERNEL__ ++ #include ++ #include ++ #include ++ #include ++ #include ++ #define LZMA_MALLOC vmalloc ++ #define LZMA_FREE vfree ++ #define PRINT_ERROR(msg) printk(KERN_WARNING #msg) ++ #define INIT __init ++ #define STATIC static ++#else ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ #ifndef PAGE_SIZE ++ extern int page_size; ++ #define PAGE_SIZE page_size ++ #endif ++ #define LZMA_MALLOC malloc ++ #define LZMA_FREE free ++ #define PRINT_ERROR(msg) fprintf(stderr, msg) ++ #define INIT ++ #define STATIC ++#endif ++ ++#include "lzma/LzmaDec.h" ++#include "lzma/LzmaEnc.h" ++ ++#define LZMA_BEST_LEVEL (9) ++#define LZMA_BEST_LC (0) ++#define LZMA_BEST_LP (0) ++#define LZMA_BEST_PB (0) ++#define LZMA_BEST_FB (273) ++ ++#define LZMA_BEST_DICT(n) (((int)((n) / 2)) * 2) ++ ++static void *p_lzma_malloc(void *p, size_t size) ++{ ++ if (size == 0) ++ return NULL; ++ ++ return LZMA_MALLOC(size); ++} ++ ++static void p_lzma_free(void *p, void *address) ++{ ++ if (address != NULL) ++ LZMA_FREE(address); ++} ++ ++static ISzAlloc lzma_alloc = { .Alloc = p_lzma_malloc, .Free = p_lzma_free }; ++ ++#endif +diff --git a/include/linux/lzma/LzFind.h b/include/linux/lzma/LzFind.h +new file mode 100644 +index 000000000000..010c4b92ba33 +--- /dev/null ++++ b/include/linux/lzma/LzFind.h +@@ -0,0 +1,115 @@ ++/* LzFind.h -- Match finder for LZ algorithms ++2009-04-22 : Igor Pavlov : Public domain */ ++ ++#ifndef __LZ_FIND_H ++#define __LZ_FIND_H ++ ++#include "Types.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++typedef UInt32 CLzRef; ++ ++typedef struct _CMatchFinder ++{ ++ Byte *buffer; ++ UInt32 pos; ++ UInt32 posLimit; ++ UInt32 streamPos; ++ UInt32 lenLimit; ++ ++ UInt32 cyclicBufferPos; ++ UInt32 cyclicBufferSize; /* it must be = (historySize + 1) */ ++ ++ UInt32 matchMaxLen; ++ CLzRef *hash; ++ CLzRef *son; ++ UInt32 hashMask; ++ UInt32 cutValue; ++ ++ Byte *bufferBase; ++ ISeqInStream *stream; ++ int streamEndWasReached; ++ ++ UInt32 blockSize; ++ UInt32 keepSizeBefore; ++ UInt32 keepSizeAfter; ++ ++ UInt32 numHashBytes; ++ int directInput; ++ size_t directInputRem; ++ int btMode; ++ int bigHash; ++ UInt32 historySize; ++ UInt32 fixedHashSize; ++ UInt32 hashSizeSum; ++ UInt32 numSons; ++ SRes result; ++ UInt32 crc[256]; ++} CMatchFinder; ++ ++#define Inline_MatchFinder_GetPointerToCurrentPos(p) ((p)->buffer) ++#define Inline_MatchFinder_GetIndexByte(p, index) ((p)->buffer[(Int32)(index)]) ++ ++#define Inline_MatchFinder_GetNumAvailableBytes(p) ((p)->streamPos - (p)->pos) ++ ++int MatchFinder_NeedMove(CMatchFinder *p); ++Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p); ++void MatchFinder_MoveBlock(CMatchFinder *p); ++void MatchFinder_ReadIfRequired(CMatchFinder *p); ++ ++void MatchFinder_Construct(CMatchFinder *p); ++ ++/* Conditions: ++ historySize <= 3 GB ++ keepAddBufferBefore + matchMaxLen + keepAddBufferAfter < 511MB ++*/ ++int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, ++ UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ++ ISzAlloc *alloc); ++void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc); ++void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems); ++void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue); ++ ++UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *buffer, CLzRef *son, ++ UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue, ++ UInt32 *distances, UInt32 maxLen); ++ ++/* ++Conditions: ++ Mf_GetNumAvailableBytes_Func must be called before each Mf_GetMatchLen_Func. ++ Mf_GetPointerToCurrentPos_Func's result must be used only before any other function ++*/ ++ ++typedef void (*Mf_Init_Func)(void *object); ++typedef Byte (*Mf_GetIndexByte_Func)(void *object, Int32 index); ++typedef UInt32 (*Mf_GetNumAvailableBytes_Func)(void *object); ++typedef const Byte * (*Mf_GetPointerToCurrentPos_Func)(void *object); ++typedef UInt32 (*Mf_GetMatches_Func)(void *object, UInt32 *distances); ++typedef void (*Mf_Skip_Func)(void *object, UInt32); ++ ++typedef struct _IMatchFinder ++{ ++ Mf_Init_Func Init; ++ Mf_GetIndexByte_Func GetIndexByte; ++ Mf_GetNumAvailableBytes_Func GetNumAvailableBytes; ++ Mf_GetPointerToCurrentPos_Func GetPointerToCurrentPos; ++ Mf_GetMatches_Func GetMatches; ++ Mf_Skip_Func Skip; ++} IMatchFinder; ++ ++void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable); ++ ++void MatchFinder_Init(CMatchFinder *p); ++UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances); ++UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances); ++void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num); ++void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif +diff --git a/include/linux/lzma/LzHash.h b/include/linux/lzma/LzHash.h +new file mode 100644 +index 000000000000..f3e89966cc70 +--- /dev/null ++++ b/include/linux/lzma/LzHash.h +@@ -0,0 +1,54 @@ ++/* LzHash.h -- HASH functions for LZ algorithms ++2009-02-07 : Igor Pavlov : Public domain */ ++ ++#ifndef __LZ_HASH_H ++#define __LZ_HASH_H ++ ++#define kHash2Size (1 << 10) ++#define kHash3Size (1 << 16) ++#define kHash4Size (1 << 20) ++ ++#define kFix3HashSize (kHash2Size) ++#define kFix4HashSize (kHash2Size + kHash3Size) ++#define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size) ++ ++#define HASH2_CALC hashValue = cur[0] | ((UInt32)cur[1] << 8); ++ ++#define HASH3_CALC { \ ++ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ ++ hash2Value = temp & (kHash2Size - 1); \ ++ hashValue = (temp ^ ((UInt32)cur[2] << 8)) & p->hashMask; } ++ ++#define HASH4_CALC { \ ++ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ ++ hash2Value = temp & (kHash2Size - 1); \ ++ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \ ++ hashValue = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & p->hashMask; } ++ ++#define HASH5_CALC { \ ++ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ ++ hash2Value = temp & (kHash2Size - 1); \ ++ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \ ++ hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)); \ ++ hashValue = (hash4Value ^ (p->crc[cur[4]] << 3)) & p->hashMask; \ ++ hash4Value &= (kHash4Size - 1); } ++ ++/* #define HASH_ZIP_CALC hashValue = ((cur[0] | ((UInt32)cur[1] << 8)) ^ p->crc[cur[2]]) & 0xFFFF; */ ++#define HASH_ZIP_CALC hashValue = ((cur[2] | ((UInt32)cur[0] << 8)) ^ p->crc[cur[1]]) & 0xFFFF; ++ ++ ++#define MT_HASH2_CALC \ ++ hash2Value = (p->crc[cur[0]] ^ cur[1]) & (kHash2Size - 1); ++ ++#define MT_HASH3_CALC { \ ++ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ ++ hash2Value = temp & (kHash2Size - 1); \ ++ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); } ++ ++#define MT_HASH4_CALC { \ ++ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ ++ hash2Value = temp & (kHash2Size - 1); \ ++ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \ ++ hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & (kHash4Size - 1); } ++ ++#endif +diff --git a/include/linux/lzma/LzmaDec.h b/include/linux/lzma/LzmaDec.h +new file mode 100644 +index 000000000000..7927acd0d4eb +--- /dev/null ++++ b/include/linux/lzma/LzmaDec.h +@@ -0,0 +1,231 @@ ++/* LzmaDec.h -- LZMA Decoder ++2009-02-07 : Igor Pavlov : Public domain */ ++ ++#ifndef __LZMA_DEC_H ++#define __LZMA_DEC_H ++ ++#include "Types.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/* #define _LZMA_PROB32 */ ++/* _LZMA_PROB32 can increase the speed on some CPUs, ++ but memory usage for CLzmaDec::probs will be doubled in that case */ ++ ++#ifdef _LZMA_PROB32 ++#define CLzmaProb UInt32 ++#else ++#define CLzmaProb UInt16 ++#endif ++ ++ ++/* ---------- LZMA Properties ---------- */ ++ ++#define LZMA_PROPS_SIZE 5 ++ ++typedef struct _CLzmaProps ++{ ++ unsigned lc, lp, pb; ++ UInt32 dicSize; ++} CLzmaProps; ++ ++/* LzmaProps_Decode - decodes properties ++Returns: ++ SZ_OK ++ SZ_ERROR_UNSUPPORTED - Unsupported properties ++*/ ++ ++SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size); ++ ++ ++/* ---------- LZMA Decoder state ---------- */ ++ ++/* LZMA_REQUIRED_INPUT_MAX = number of required input bytes for worst case. ++ Num bits = log2((2^11 / 31) ^ 22) + 26 < 134 + 26 = 160; */ ++ ++#define LZMA_REQUIRED_INPUT_MAX 20 ++ ++typedef struct ++{ ++ CLzmaProps prop; ++ CLzmaProb *probs; ++ Byte *dic; ++ const Byte *buf; ++ UInt32 range, code; ++ SizeT dicPos; ++ SizeT dicBufSize; ++ UInt32 processedPos; ++ UInt32 checkDicSize; ++ unsigned state; ++ UInt32 reps[4]; ++ unsigned remainLen; ++ int needFlush; ++ int needInitState; ++ UInt32 numProbs; ++ unsigned tempBufSize; ++ Byte tempBuf[LZMA_REQUIRED_INPUT_MAX]; ++} CLzmaDec; ++ ++#define LzmaDec_Construct(p) { (p)->dic = 0; (p)->probs = 0; } ++ ++void LzmaDec_Init(CLzmaDec *p); ++ ++/* There are two types of LZMA streams: ++ 0) Stream with end mark. That end mark adds about 6 bytes to compressed size. ++ 1) Stream without end mark. You must know exact uncompressed size to decompress such stream. */ ++ ++typedef enum ++{ ++ LZMA_FINISH_ANY, /* finish at any point */ ++ LZMA_FINISH_END /* block must be finished at the end */ ++} ELzmaFinishMode; ++ ++/* ELzmaFinishMode has meaning only if the decoding reaches output limit !!! ++ ++ You must use LZMA_FINISH_END, when you know that current output buffer ++ covers last bytes of block. In other cases you must use LZMA_FINISH_ANY. ++ ++ If LZMA decoder sees end marker before reaching output limit, it returns SZ_OK, ++ and output value of destLen will be less than output buffer size limit. ++ You can check status result also. ++ ++ You can use multiple checks to test data integrity after full decompression: ++ 1) Check Result and "status" variable. ++ 2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize. ++ 3) Check that output(srcLen) = compressedSize, if you know real compressedSize. ++ You must use correct finish mode in that case. */ ++ ++typedef enum ++{ ++ LZMA_STATUS_NOT_SPECIFIED, /* use main error code instead */ ++ LZMA_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */ ++ LZMA_STATUS_NOT_FINISHED, /* stream was not finished */ ++ LZMA_STATUS_NEEDS_MORE_INPUT, /* you must provide more input bytes */ ++ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK /* there is probability that stream was finished without end mark */ ++} ELzmaStatus; ++ ++/* ELzmaStatus is used only as output value for function call */ ++ ++ ++/* ---------- Interfaces ---------- */ ++ ++/* There are 3 levels of interfaces: ++ 1) Dictionary Interface ++ 2) Buffer Interface ++ 3) One Call Interface ++ You can select any of these interfaces, but don't mix functions from different ++ groups for same object. */ ++ ++ ++/* There are two variants to allocate state for Dictionary Interface: ++ 1) LzmaDec_Allocate / LzmaDec_Free ++ 2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs ++ You can use variant 2, if you set dictionary buffer manually. ++ For Buffer Interface you must always use variant 1. ++ ++LzmaDec_Allocate* can return: ++ SZ_OK ++ SZ_ERROR_MEM - Memory allocation error ++ SZ_ERROR_UNSUPPORTED - Unsupported properties ++*/ ++ ++SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc); ++void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc); ++ ++SRes LzmaDec_Allocate(CLzmaDec *state, const Byte *prop, unsigned propsSize, ISzAlloc *alloc); ++void LzmaDec_Free(CLzmaDec *state, ISzAlloc *alloc); ++ ++/* ---------- Dictionary Interface ---------- */ ++ ++/* You can use it, if you want to eliminate the overhead for data copying from ++ dictionary to some other external buffer. ++ You must work with CLzmaDec variables directly in this interface. ++ ++ STEPS: ++ LzmaDec_Constr() ++ LzmaDec_Allocate() ++ for (each new stream) ++ { ++ LzmaDec_Init() ++ while (it needs more decompression) ++ { ++ LzmaDec_DecodeToDic() ++ use data from CLzmaDec::dic and update CLzmaDec::dicPos ++ } ++ } ++ LzmaDec_Free() ++*/ ++ ++/* LzmaDec_DecodeToDic ++ ++ The decoding to internal dictionary buffer (CLzmaDec::dic). ++ You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!! ++ ++finishMode: ++ It has meaning only if the decoding reaches output limit (dicLimit). ++ LZMA_FINISH_ANY - Decode just dicLimit bytes. ++ LZMA_FINISH_END - Stream must be finished after dicLimit. ++ ++Returns: ++ SZ_OK ++ status: ++ LZMA_STATUS_FINISHED_WITH_MARK ++ LZMA_STATUS_NOT_FINISHED ++ LZMA_STATUS_NEEDS_MORE_INPUT ++ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK ++ SZ_ERROR_DATA - Data error ++*/ ++ ++SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, ++ const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); ++ ++ ++/* ---------- Buffer Interface ---------- */ ++ ++/* It's zlib-like interface. ++ See LzmaDec_DecodeToDic description for information about STEPS and return results, ++ but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need ++ to work with CLzmaDec variables manually. ++ ++finishMode: ++ It has meaning only if the decoding reaches output limit (*destLen). ++ LZMA_FINISH_ANY - Decode just destLen bytes. ++ LZMA_FINISH_END - Stream must be finished after (*destLen). ++*/ ++ ++SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, ++ const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); ++ ++ ++/* ---------- One Call Interface ---------- */ ++ ++/* LzmaDecode ++ ++finishMode: ++ It has meaning only if the decoding reaches output limit (*destLen). ++ LZMA_FINISH_ANY - Decode just destLen bytes. ++ LZMA_FINISH_END - Stream must be finished after (*destLen). ++ ++Returns: ++ SZ_OK ++ status: ++ LZMA_STATUS_FINISHED_WITH_MARK ++ LZMA_STATUS_NOT_FINISHED ++ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK ++ SZ_ERROR_DATA - Data error ++ SZ_ERROR_MEM - Memory allocation error ++ SZ_ERROR_UNSUPPORTED - Unsupported properties ++ SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). ++*/ ++ ++SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ++ const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, ++ ELzmaStatus *status, ISzAlloc *alloc); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif +diff --git a/include/linux/lzma/LzmaEnc.h b/include/linux/lzma/LzmaEnc.h +new file mode 100644 +index 000000000000..200d60eb83cd +--- /dev/null ++++ b/include/linux/lzma/LzmaEnc.h +@@ -0,0 +1,80 @@ ++/* LzmaEnc.h -- LZMA Encoder ++2009-02-07 : Igor Pavlov : Public domain */ ++ ++#ifndef __LZMA_ENC_H ++#define __LZMA_ENC_H ++ ++#include "Types.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++#define LZMA_PROPS_SIZE 5 ++ ++typedef struct _CLzmaEncProps ++{ ++ int level; /* 0 <= level <= 9 */ ++ UInt32 dictSize; /* (1 << 12) <= dictSize <= (1 << 27) for 32-bit version ++ (1 << 12) <= dictSize <= (1 << 30) for 64-bit version ++ default = (1 << 24) */ ++ int lc; /* 0 <= lc <= 8, default = 3 */ ++ int lp; /* 0 <= lp <= 4, default = 0 */ ++ int pb; /* 0 <= pb <= 4, default = 2 */ ++ int algo; /* 0 - fast, 1 - normal, default = 1 */ ++ int fb; /* 5 <= fb <= 273, default = 32 */ ++ int btMode; /* 0 - hashChain Mode, 1 - binTree mode - normal, default = 1 */ ++ int numHashBytes; /* 2, 3 or 4, default = 4 */ ++ UInt32 mc; /* 1 <= mc <= (1 << 30), default = 32 */ ++ unsigned writeEndMark; /* 0 - do not write EOPM, 1 - write EOPM, default = 0 */ ++ int numThreads; /* 1 or 2, default = 2 */ ++} CLzmaEncProps; ++ ++void LzmaEncProps_Init(CLzmaEncProps *p); ++void LzmaEncProps_Normalize(CLzmaEncProps *p); ++UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2); ++ ++ ++/* ---------- CLzmaEncHandle Interface ---------- */ ++ ++/* LzmaEnc_* functions can return the following exit codes: ++Returns: ++ SZ_OK - OK ++ SZ_ERROR_MEM - Memory allocation error ++ SZ_ERROR_PARAM - Incorrect paramater in props ++ SZ_ERROR_WRITE - Write callback error. ++ SZ_ERROR_PROGRESS - some break from progress callback ++ SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version) ++*/ ++ ++typedef void * CLzmaEncHandle; ++ ++CLzmaEncHandle LzmaEnc_Create(ISzAlloc *alloc); ++void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig); ++SRes LzmaEnc_SetProps(CLzmaEncHandle p, const CLzmaEncProps *props); ++SRes LzmaEnc_WriteProperties(CLzmaEncHandle p, Byte *properties, SizeT *size); ++SRes LzmaEnc_Encode(CLzmaEncHandle p, ISeqOutStream *outStream, ISeqInStream *inStream, ++ ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); ++SRes LzmaEnc_MemEncode(CLzmaEncHandle p, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, ++ int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); ++ ++/* ---------- One Call Interface ---------- */ ++ ++/* LzmaEncode ++Return code: ++ SZ_OK - OK ++ SZ_ERROR_MEM - Memory allocation error ++ SZ_ERROR_PARAM - Incorrect paramater ++ SZ_ERROR_OUTPUT_EOF - output buffer overflow ++ SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version) ++*/ ++ ++SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, ++ const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, ++ ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif +diff --git a/include/linux/lzma/Types.h b/include/linux/lzma/Types.h +new file mode 100644 +index 000000000000..4751acde0722 +--- /dev/null ++++ b/include/linux/lzma/Types.h +@@ -0,0 +1,226 @@ ++/* Types.h -- Basic types ++2009-11-23 : Igor Pavlov : Public domain */ ++ ++#ifndef __7Z_TYPES_H ++#define __7Z_TYPES_H ++ ++#include ++ ++#ifdef _WIN32 ++#include ++#endif ++ ++#ifndef EXTERN_C_BEGIN ++#ifdef __cplusplus ++#define EXTERN_C_BEGIN extern "C" { ++#define EXTERN_C_END } ++#else ++#define EXTERN_C_BEGIN ++#define EXTERN_C_END ++#endif ++#endif ++ ++EXTERN_C_BEGIN ++ ++#define SZ_OK 0 ++ ++#define SZ_ERROR_DATA 1 ++#define SZ_ERROR_MEM 2 ++#define SZ_ERROR_CRC 3 ++#define SZ_ERROR_UNSUPPORTED 4 ++#define SZ_ERROR_PARAM 5 ++#define SZ_ERROR_INPUT_EOF 6 ++#define SZ_ERROR_OUTPUT_EOF 7 ++#define SZ_ERROR_READ 8 ++#define SZ_ERROR_WRITE 9 ++#define SZ_ERROR_PROGRESS 10 ++#define SZ_ERROR_FAIL 11 ++#define SZ_ERROR_THREAD 12 ++ ++#define SZ_ERROR_ARCHIVE 16 ++#define SZ_ERROR_NO_ARCHIVE 17 ++ ++typedef int SRes; ++ ++#ifdef _WIN32 ++typedef DWORD WRes; ++#else ++typedef int WRes; ++#endif ++ ++#ifndef RINOK ++#define RINOK(x) { int __result__ = (x); if (__result__ != 0) return __result__; } ++#endif ++ ++typedef unsigned char Byte; ++typedef short Int16; ++typedef unsigned short UInt16; ++ ++#ifdef _LZMA_UINT32_IS_ULONG ++typedef long Int32; ++typedef unsigned long UInt32; ++#else ++typedef int Int32; ++typedef unsigned int UInt32; ++#endif ++ ++#ifdef _SZ_NO_INT_64 ++ ++/* define _SZ_NO_INT_64, if your compiler doesn't support 64-bit integers. ++ NOTES: Some code will work incorrectly in that case! */ ++ ++typedef long Int64; ++typedef unsigned long UInt64; ++ ++#else ++ ++#if defined(_MSC_VER) || defined(__BORLANDC__) ++typedef __int64 Int64; ++typedef unsigned __int64 UInt64; ++#else ++typedef long long int Int64; ++typedef unsigned long long int UInt64; ++#endif ++ ++#endif ++ ++#ifdef _LZMA_NO_SYSTEM_SIZE_T ++typedef UInt32 SizeT; ++#else ++typedef size_t SizeT; ++#endif ++ ++typedef int Bool; ++#define True 1 ++#define False 0 ++ ++ ++#ifdef _WIN32 ++#define MY_STD_CALL __stdcall ++#else ++#define MY_STD_CALL ++#endif ++ ++#ifdef _MSC_VER ++ ++#if _MSC_VER >= 1300 ++#define MY_NO_INLINE __declspec(noinline) ++#else ++#define MY_NO_INLINE ++#endif ++ ++#define MY_CDECL __cdecl ++#define MY_FAST_CALL __fastcall ++ ++#else ++ ++#define MY_CDECL ++#define MY_FAST_CALL ++ ++#endif ++ ++ ++/* The following interfaces use first parameter as pointer to structure */ ++ ++typedef struct ++{ ++ SRes (*Read)(void *p, void *buf, size_t *size); ++ /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. ++ (output(*size) < input(*size)) is allowed */ ++} ISeqInStream; ++ ++/* it can return SZ_ERROR_INPUT_EOF */ ++SRes SeqInStream_Read(ISeqInStream *stream, void *buf, size_t size); ++SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType); ++SRes SeqInStream_ReadByte(ISeqInStream *stream, Byte *buf); ++ ++typedef struct ++{ ++ size_t (*Write)(void *p, const void *buf, size_t size); ++ /* Returns: result - the number of actually written bytes. ++ (result < size) means error */ ++} ISeqOutStream; ++ ++typedef enum ++{ ++ SZ_SEEK_SET = 0, ++ SZ_SEEK_CUR = 1, ++ SZ_SEEK_END = 2 ++} ESzSeek; ++ ++typedef struct ++{ ++ SRes (*Read)(void *p, void *buf, size_t *size); /* same as ISeqInStream::Read */ ++ SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin); ++} ISeekInStream; ++ ++typedef struct ++{ ++ SRes (*Look)(void *p, void **buf, size_t *size); ++ /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. ++ (output(*size) > input(*size)) is not allowed ++ (output(*size) < input(*size)) is allowed */ ++ SRes (*Skip)(void *p, size_t offset); ++ /* offset must be <= output(*size) of Look */ ++ ++ SRes (*Read)(void *p, void *buf, size_t *size); ++ /* reads directly (without buffer). It's same as ISeqInStream::Read */ ++ SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin); ++} ILookInStream; ++ ++SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size); ++SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset); ++ ++/* reads via ILookInStream::Read */ ++SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType); ++SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size); ++ ++#define LookToRead_BUF_SIZE (1 << 14) ++ ++typedef struct ++{ ++ ILookInStream s; ++ ISeekInStream *realStream; ++ size_t pos; ++ size_t size; ++ Byte buf[LookToRead_BUF_SIZE]; ++} CLookToRead; ++ ++void LookToRead_CreateVTable(CLookToRead *p, int lookahead); ++void LookToRead_Init(CLookToRead *p); ++ ++typedef struct ++{ ++ ISeqInStream s; ++ ILookInStream *realStream; ++} CSecToLook; ++ ++void SecToLook_CreateVTable(CSecToLook *p); ++ ++typedef struct ++{ ++ ISeqInStream s; ++ ILookInStream *realStream; ++} CSecToRead; ++ ++void SecToRead_CreateVTable(CSecToRead *p); ++ ++typedef struct ++{ ++ SRes (*Progress)(void *p, UInt64 inSize, UInt64 outSize); ++ /* Returns: result. (result != SZ_OK) means break. ++ Value (UInt64)(Int64)-1 for size means unknown value. */ ++} ICompressProgress; ++ ++typedef struct ++{ ++ void *(*Alloc)(void *p, size_t size); ++ void (*Free)(void *p, void *address); /* address can be 0 */ ++} ISzAlloc; ++ ++#define IAlloc_Alloc(p, size) (p)->Alloc((p), size) ++#define IAlloc_Free(p, a) (p)->Free((p), a) ++ ++EXTERN_C_END ++ ++#endif +diff --git a/include/uapi/linux/jffs2.h b/include/uapi/linux/jffs2.h +index 637ee4a793cf..11aeaa4e8520 100644 +--- a/include/uapi/linux/jffs2.h ++++ b/include/uapi/linux/jffs2.h +@@ -46,6 +46,7 @@ + #define JFFS2_COMPR_DYNRUBIN 0x05 + #define JFFS2_COMPR_ZLIB 0x06 + #define JFFS2_COMPR_LZO 0x07 ++#define JFFS2_COMPR_LZMA 0x08 + /* Compatibility flags. */ + #define JFFS2_COMPAT_MASK 0xc000 /* What do to if an unknown nodetype is found */ + #define JFFS2_NODE_ACCURATE 0x2000 +diff --git a/lib/Kconfig b/lib/Kconfig +index b893c9288c14..e9088bd10a6c 100644 +--- a/lib/Kconfig ++++ b/lib/Kconfig +@@ -353,6 +353,12 @@ config ZSTD_DECOMPRESS + + source "lib/xz/Kconfig" + ++config LZMA_COMPRESS ++ tristate ++ ++config LZMA_DECOMPRESS ++ tristate ++ + # + # These all provide a common interface (hence the apparent duplication with + # ZLIB_INFLATE; DECOMPRESS_GZIP is just a wrapper.) +diff --git a/lib/Makefile b/lib/Makefile +index fc878e716825..460d99a479be 100644 +--- a/lib/Makefile ++++ b/lib/Makefile +@@ -126,6 +126,16 @@ CFLAGS_kobject.o += -DDEBUG + CFLAGS_kobject_uevent.o += -DDEBUG + endif + ++ifdef CONFIG_JFFS2_ZLIB ++ CONFIG_ZLIB_INFLATE:=y ++ CONFIG_ZLIB_DEFLATE:=y ++endif ++ ++ifdef CONFIG_JFFS2_LZMA ++ CONFIG_LZMA_DECOMPRESS:=y ++ CONFIG_LZMA_COMPRESS:=y ++endif ++ + obj-$(CONFIG_DEBUG_INFO_REDUCED) += debug_info.o + CFLAGS_debug_info.o += $(call cc-option, -femit-struct-debug-detailed=any) + +@@ -185,6 +195,8 @@ obj-$(CONFIG_ZSTD_COMPRESS) += zstd/ + obj-$(CONFIG_ZSTD_DECOMPRESS) += zstd/ + obj-$(CONFIG_XZ_DEC) += xz/ + obj-$(CONFIG_RAID6_PQ) += raid6/ ++obj-$(CONFIG_LZMA_COMPRESS) += lzma/ ++obj-$(CONFIG_LZMA_DECOMPRESS) += lzma/ + + lib-$(CONFIG_DECOMPRESS_GZIP) += decompress_inflate.o + lib-$(CONFIG_DECOMPRESS_BZIP2) += decompress_bunzip2.o +diff --git a/lib/lzma/LzFind.c b/lib/lzma/LzFind.c +new file mode 100644 +index 000000000000..a02621a1f8f5 +--- /dev/null ++++ b/lib/lzma/LzFind.c +@@ -0,0 +1,761 @@ ++/* LzFind.c -- Match finder for LZ algorithms ++2009-04-22 : Igor Pavlov : Public domain */ ++ ++#include ++ ++#include "LzFind.h" ++#include "LzHash.h" ++ ++#define kEmptyHashValue 0 ++#define kMaxValForNormalize ((UInt32)0xFFFFFFFF) ++#define kNormalizeStepMin (1 << 10) /* it must be power of 2 */ ++#define kNormalizeMask (~(kNormalizeStepMin - 1)) ++#define kMaxHistorySize ((UInt32)3 << 30) ++ ++#define kStartMaxLen 3 ++ ++static void LzInWindow_Free(CMatchFinder *p, ISzAlloc *alloc) ++{ ++ if (!p->directInput) ++ { ++ alloc->Free(alloc, p->bufferBase); ++ p->bufferBase = 0; ++ } ++} ++ ++/* keepSizeBefore + keepSizeAfter + keepSizeReserv must be < 4G) */ ++ ++static int LzInWindow_Create(CMatchFinder *p, UInt32 keepSizeReserv, ISzAlloc *alloc) ++{ ++ UInt32 blockSize = p->keepSizeBefore + p->keepSizeAfter + keepSizeReserv; ++ if (p->directInput) ++ { ++ p->blockSize = blockSize; ++ return 1; ++ } ++ if (p->bufferBase == 0 || p->blockSize != blockSize) ++ { ++ LzInWindow_Free(p, alloc); ++ p->blockSize = blockSize; ++ p->bufferBase = (Byte *)alloc->Alloc(alloc, (size_t)blockSize); ++ } ++ return (p->bufferBase != 0); ++} ++ ++Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; } ++static Byte MatchFinder_GetIndexByte(CMatchFinder *p, Int32 index) { return p->buffer[index]; } ++ ++static UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; } ++ ++void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue) ++{ ++ p->posLimit -= subValue; ++ p->pos -= subValue; ++ p->streamPos -= subValue; ++} ++ ++static void MatchFinder_ReadBlock(CMatchFinder *p) ++{ ++ if (p->streamEndWasReached || p->result != SZ_OK) ++ return; ++ if (p->directInput) ++ { ++ UInt32 curSize = 0xFFFFFFFF - p->streamPos; ++ if (curSize > p->directInputRem) ++ curSize = (UInt32)p->directInputRem; ++ p->directInputRem -= curSize; ++ p->streamPos += curSize; ++ if (p->directInputRem == 0) ++ p->streamEndWasReached = 1; ++ return; ++ } ++ for (;;) ++ { ++ Byte *dest = p->buffer + (p->streamPos - p->pos); ++ size_t size = (p->bufferBase + p->blockSize - dest); ++ if (size == 0) ++ return; ++ p->result = p->stream->Read(p->stream, dest, &size); ++ if (p->result != SZ_OK) ++ return; ++ if (size == 0) ++ { ++ p->streamEndWasReached = 1; ++ return; ++ } ++ p->streamPos += (UInt32)size; ++ if (p->streamPos - p->pos > p->keepSizeAfter) ++ return; ++ } ++} ++ ++void MatchFinder_MoveBlock(CMatchFinder *p) ++{ ++ memmove(p->bufferBase, ++ p->buffer - p->keepSizeBefore, ++ (size_t)(p->streamPos - p->pos + p->keepSizeBefore)); ++ p->buffer = p->bufferBase + p->keepSizeBefore; ++} ++ ++int MatchFinder_NeedMove(CMatchFinder *p) ++{ ++ if (p->directInput) ++ return 0; ++ /* if (p->streamEndWasReached) return 0; */ ++ return ((size_t)(p->bufferBase + p->blockSize - p->buffer) <= p->keepSizeAfter); ++} ++ ++void MatchFinder_ReadIfRequired(CMatchFinder *p) ++{ ++ if (p->streamEndWasReached) ++ return; ++ if (p->keepSizeAfter >= p->streamPos - p->pos) ++ MatchFinder_ReadBlock(p); ++} ++ ++static void MatchFinder_CheckAndMoveAndRead(CMatchFinder *p) ++{ ++ if (MatchFinder_NeedMove(p)) ++ MatchFinder_MoveBlock(p); ++ MatchFinder_ReadBlock(p); ++} ++ ++static void MatchFinder_SetDefaultSettings(CMatchFinder *p) ++{ ++ p->cutValue = 32; ++ p->btMode = 1; ++ p->numHashBytes = 4; ++ p->bigHash = 0; ++} ++ ++#define kCrcPoly 0xEDB88320 ++ ++void MatchFinder_Construct(CMatchFinder *p) ++{ ++ UInt32 i; ++ p->bufferBase = 0; ++ p->directInput = 0; ++ p->hash = 0; ++ MatchFinder_SetDefaultSettings(p); ++ ++ for (i = 0; i < 256; i++) ++ { ++ UInt32 r = i; ++ int j; ++ for (j = 0; j < 8; j++) ++ r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1)); ++ p->crc[i] = r; ++ } ++} ++ ++static void MatchFinder_FreeThisClassMemory(CMatchFinder *p, ISzAlloc *alloc) ++{ ++ alloc->Free(alloc, p->hash); ++ p->hash = 0; ++} ++ ++void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc) ++{ ++ MatchFinder_FreeThisClassMemory(p, alloc); ++ LzInWindow_Free(p, alloc); ++} ++ ++static CLzRef* AllocRefs(UInt32 num, ISzAlloc *alloc) ++{ ++ size_t sizeInBytes = (size_t)num * sizeof(CLzRef); ++ if (sizeInBytes / sizeof(CLzRef) != num) ++ return 0; ++ return (CLzRef *)alloc->Alloc(alloc, sizeInBytes); ++} ++ ++int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, ++ UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ++ ISzAlloc *alloc) ++{ ++ UInt32 sizeReserv; ++ if (historySize > kMaxHistorySize) ++ { ++ MatchFinder_Free(p, alloc); ++ return 0; ++ } ++ sizeReserv = historySize >> 1; ++ if (historySize > ((UInt32)2 << 30)) ++ sizeReserv = historySize >> 2; ++ sizeReserv += (keepAddBufferBefore + matchMaxLen + keepAddBufferAfter) / 2 + (1 << 19); ++ ++ p->keepSizeBefore = historySize + keepAddBufferBefore + 1; ++ p->keepSizeAfter = matchMaxLen + keepAddBufferAfter; ++ /* we need one additional byte, since we use MoveBlock after pos++ and before dictionary using */ ++ if (LzInWindow_Create(p, sizeReserv, alloc)) ++ { ++ UInt32 newCyclicBufferSize = historySize + 1; ++ UInt32 hs; ++ p->matchMaxLen = matchMaxLen; ++ { ++ p->fixedHashSize = 0; ++ if (p->numHashBytes == 2) ++ hs = (1 << 16) - 1; ++ else ++ { ++ hs = historySize - 1; ++ hs |= (hs >> 1); ++ hs |= (hs >> 2); ++ hs |= (hs >> 4); ++ hs |= (hs >> 8); ++ hs >>= 1; ++ hs |= 0xFFFF; /* don't change it! It's required for Deflate */ ++ if (hs > (1 << 24)) ++ { ++ if (p->numHashBytes == 3) ++ hs = (1 << 24) - 1; ++ else ++ hs >>= 1; ++ } ++ } ++ p->hashMask = hs; ++ hs++; ++ if (p->numHashBytes > 2) p->fixedHashSize += kHash2Size; ++ if (p->numHashBytes > 3) p->fixedHashSize += kHash3Size; ++ if (p->numHashBytes > 4) p->fixedHashSize += kHash4Size; ++ hs += p->fixedHashSize; ++ } ++ ++ { ++ UInt32 prevSize = p->hashSizeSum + p->numSons; ++ UInt32 newSize; ++ p->historySize = historySize; ++ p->hashSizeSum = hs; ++ p->cyclicBufferSize = newCyclicBufferSize; ++ p->numSons = (p->btMode ? newCyclicBufferSize * 2 : newCyclicBufferSize); ++ newSize = p->hashSizeSum + p->numSons; ++ if (p->hash != 0 && prevSize == newSize) ++ return 1; ++ MatchFinder_FreeThisClassMemory(p, alloc); ++ p->hash = AllocRefs(newSize, alloc); ++ if (p->hash != 0) ++ { ++ p->son = p->hash + p->hashSizeSum; ++ return 1; ++ } ++ } ++ } ++ MatchFinder_Free(p, alloc); ++ return 0; ++} ++ ++static void MatchFinder_SetLimits(CMatchFinder *p) ++{ ++ UInt32 limit = kMaxValForNormalize - p->pos; ++ UInt32 limit2 = p->cyclicBufferSize - p->cyclicBufferPos; ++ if (limit2 < limit) ++ limit = limit2; ++ limit2 = p->streamPos - p->pos; ++ if (limit2 <= p->keepSizeAfter) ++ { ++ if (limit2 > 0) ++ limit2 = 1; ++ } ++ else ++ limit2 -= p->keepSizeAfter; ++ if (limit2 < limit) ++ limit = limit2; ++ { ++ UInt32 lenLimit = p->streamPos - p->pos; ++ if (lenLimit > p->matchMaxLen) ++ lenLimit = p->matchMaxLen; ++ p->lenLimit = lenLimit; ++ } ++ p->posLimit = p->pos + limit; ++} ++ ++void MatchFinder_Init(CMatchFinder *p) ++{ ++ UInt32 i; ++ for (i = 0; i < p->hashSizeSum; i++) ++ p->hash[i] = kEmptyHashValue; ++ p->cyclicBufferPos = 0; ++ p->buffer = p->bufferBase; ++ p->pos = p->streamPos = p->cyclicBufferSize; ++ p->result = SZ_OK; ++ p->streamEndWasReached = 0; ++ MatchFinder_ReadBlock(p); ++ MatchFinder_SetLimits(p); ++} ++ ++static UInt32 MatchFinder_GetSubValue(CMatchFinder *p) ++{ ++ return (p->pos - p->historySize - 1) & kNormalizeMask; ++} ++ ++void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems) ++{ ++ UInt32 i; ++ for (i = 0; i < numItems; i++) ++ { ++ UInt32 value = items[i]; ++ if (value <= subValue) ++ value = kEmptyHashValue; ++ else ++ value -= subValue; ++ items[i] = value; ++ } ++} ++ ++static void MatchFinder_Normalize(CMatchFinder *p) ++{ ++ UInt32 subValue = MatchFinder_GetSubValue(p); ++ MatchFinder_Normalize3(subValue, p->hash, p->hashSizeSum + p->numSons); ++ MatchFinder_ReduceOffsets(p, subValue); ++} ++ ++static void MatchFinder_CheckLimits(CMatchFinder *p) ++{ ++ if (p->pos == kMaxValForNormalize) ++ MatchFinder_Normalize(p); ++ if (!p->streamEndWasReached && p->keepSizeAfter == p->streamPos - p->pos) ++ MatchFinder_CheckAndMoveAndRead(p); ++ if (p->cyclicBufferPos == p->cyclicBufferSize) ++ p->cyclicBufferPos = 0; ++ MatchFinder_SetLimits(p); ++} ++ ++static UInt32 * Hc_GetMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, ++ UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, ++ UInt32 *distances, UInt32 maxLen) ++{ ++ son[_cyclicBufferPos] = curMatch; ++ for (;;) ++ { ++ UInt32 delta = pos - curMatch; ++ if (cutValue-- == 0 || delta >= _cyclicBufferSize) ++ return distances; ++ { ++ const Byte *pb = cur - delta; ++ curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)]; ++ if (pb[maxLen] == cur[maxLen] && *pb == *cur) ++ { ++ UInt32 len = 0; ++ while (++len != lenLimit) ++ if (pb[len] != cur[len]) ++ break; ++ if (maxLen < len) ++ { ++ *distances++ = maxLen = len; ++ *distances++ = delta - 1; ++ if (len == lenLimit) ++ return distances; ++ } ++ } ++ } ++ } ++} ++ ++UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, ++ UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, ++ UInt32 *distances, UInt32 maxLen) ++{ ++ CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1; ++ CLzRef *ptr1 = son + (_cyclicBufferPos << 1); ++ UInt32 len0 = 0, len1 = 0; ++ for (;;) ++ { ++ UInt32 delta = pos - curMatch; ++ if (cutValue-- == 0 || delta >= _cyclicBufferSize) ++ { ++ *ptr0 = *ptr1 = kEmptyHashValue; ++ return distances; ++ } ++ { ++ CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1); ++ const Byte *pb = cur - delta; ++ UInt32 len = (len0 < len1 ? len0 : len1); ++ if (pb[len] == cur[len]) ++ { ++ if (++len != lenLimit && pb[len] == cur[len]) ++ while (++len != lenLimit) ++ if (pb[len] != cur[len]) ++ break; ++ if (maxLen < len) ++ { ++ *distances++ = maxLen = len; ++ *distances++ = delta - 1; ++ if (len == lenLimit) ++ { ++ *ptr1 = pair[0]; ++ *ptr0 = pair[1]; ++ return distances; ++ } ++ } ++ } ++ if (pb[len] < cur[len]) ++ { ++ *ptr1 = curMatch; ++ ptr1 = pair + 1; ++ curMatch = *ptr1; ++ len1 = len; ++ } ++ else ++ { ++ *ptr0 = curMatch; ++ ptr0 = pair; ++ curMatch = *ptr0; ++ len0 = len; ++ } ++ } ++ } ++} ++ ++static void SkipMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, ++ UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue) ++{ ++ CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1; ++ CLzRef *ptr1 = son + (_cyclicBufferPos << 1); ++ UInt32 len0 = 0, len1 = 0; ++ for (;;) ++ { ++ UInt32 delta = pos - curMatch; ++ if (cutValue-- == 0 || delta >= _cyclicBufferSize) ++ { ++ *ptr0 = *ptr1 = kEmptyHashValue; ++ return; ++ } ++ { ++ CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1); ++ const Byte *pb = cur - delta; ++ UInt32 len = (len0 < len1 ? len0 : len1); ++ if (pb[len] == cur[len]) ++ { ++ while (++len != lenLimit) ++ if (pb[len] != cur[len]) ++ break; ++ { ++ if (len == lenLimit) ++ { ++ *ptr1 = pair[0]; ++ *ptr0 = pair[1]; ++ return; ++ } ++ } ++ } ++ if (pb[len] < cur[len]) ++ { ++ *ptr1 = curMatch; ++ ptr1 = pair + 1; ++ curMatch = *ptr1; ++ len1 = len; ++ } ++ else ++ { ++ *ptr0 = curMatch; ++ ptr0 = pair; ++ curMatch = *ptr0; ++ len0 = len; ++ } ++ } ++ } ++} ++ ++#define MOVE_POS \ ++ ++p->cyclicBufferPos; \ ++ p->buffer++; \ ++ if (++p->pos == p->posLimit) MatchFinder_CheckLimits(p); ++ ++#define MOVE_POS_RET MOVE_POS return offset; ++ ++static void MatchFinder_MovePos(CMatchFinder *p) { MOVE_POS; } ++ ++#define GET_MATCHES_HEADER2(minLen, ret_op) \ ++ UInt32 lenLimit; UInt32 hashValue; const Byte *cur; UInt32 curMatch; \ ++ lenLimit = p->lenLimit; { if (lenLimit < minLen) { MatchFinder_MovePos(p); ret_op; }} \ ++ cur = p->buffer; ++ ++#define GET_MATCHES_HEADER(minLen) GET_MATCHES_HEADER2(minLen, return 0) ++#define SKIP_HEADER(minLen) GET_MATCHES_HEADER2(minLen, continue) ++ ++#define MF_PARAMS(p) p->pos, p->buffer, p->son, p->cyclicBufferPos, p->cyclicBufferSize, p->cutValue ++ ++#define GET_MATCHES_FOOTER(offset, maxLen) \ ++ offset = (UInt32)(GetMatchesSpec1(lenLimit, curMatch, MF_PARAMS(p), \ ++ distances + offset, maxLen) - distances); MOVE_POS_RET; ++ ++#define SKIP_FOOTER \ ++ SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS; ++ ++static UInt32 Bt2_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) ++{ ++ UInt32 offset; ++ GET_MATCHES_HEADER(2) ++ HASH2_CALC; ++ curMatch = p->hash[hashValue]; ++ p->hash[hashValue] = p->pos; ++ offset = 0; ++ GET_MATCHES_FOOTER(offset, 1) ++} ++ ++UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) ++{ ++ UInt32 offset; ++ GET_MATCHES_HEADER(3) ++ HASH_ZIP_CALC; ++ curMatch = p->hash[hashValue]; ++ p->hash[hashValue] = p->pos; ++ offset = 0; ++ GET_MATCHES_FOOTER(offset, 2) ++} ++ ++static UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) ++{ ++ UInt32 hash2Value, delta2, maxLen, offset; ++ GET_MATCHES_HEADER(3) ++ ++ HASH3_CALC; ++ ++ delta2 = p->pos - p->hash[hash2Value]; ++ curMatch = p->hash[kFix3HashSize + hashValue]; ++ ++ p->hash[hash2Value] = ++ p->hash[kFix3HashSize + hashValue] = p->pos; ++ ++ ++ maxLen = 2; ++ offset = 0; ++ if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur) ++ { ++ for (; maxLen != lenLimit; maxLen++) ++ if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen]) ++ break; ++ distances[0] = maxLen; ++ distances[1] = delta2 - 1; ++ offset = 2; ++ if (maxLen == lenLimit) ++ { ++ SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); ++ MOVE_POS_RET; ++ } ++ } ++ GET_MATCHES_FOOTER(offset, maxLen) ++} ++ ++static UInt32 Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) ++{ ++ UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset; ++ GET_MATCHES_HEADER(4) ++ ++ HASH4_CALC; ++ ++ delta2 = p->pos - p->hash[ hash2Value]; ++ delta3 = p->pos - p->hash[kFix3HashSize + hash3Value]; ++ curMatch = p->hash[kFix4HashSize + hashValue]; ++ ++ p->hash[ hash2Value] = ++ p->hash[kFix3HashSize + hash3Value] = ++ p->hash[kFix4HashSize + hashValue] = p->pos; ++ ++ maxLen = 1; ++ offset = 0; ++ if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur) ++ { ++ distances[0] = maxLen = 2; ++ distances[1] = delta2 - 1; ++ offset = 2; ++ } ++ if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur) ++ { ++ maxLen = 3; ++ distances[offset + 1] = delta3 - 1; ++ offset += 2; ++ delta2 = delta3; ++ } ++ if (offset != 0) ++ { ++ for (; maxLen != lenLimit; maxLen++) ++ if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen]) ++ break; ++ distances[offset - 2] = maxLen; ++ if (maxLen == lenLimit) ++ { ++ SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); ++ MOVE_POS_RET; ++ } ++ } ++ if (maxLen < 3) ++ maxLen = 3; ++ GET_MATCHES_FOOTER(offset, maxLen) ++} ++ ++static UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) ++{ ++ UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset; ++ GET_MATCHES_HEADER(4) ++ ++ HASH4_CALC; ++ ++ delta2 = p->pos - p->hash[ hash2Value]; ++ delta3 = p->pos - p->hash[kFix3HashSize + hash3Value]; ++ curMatch = p->hash[kFix4HashSize + hashValue]; ++ ++ p->hash[ hash2Value] = ++ p->hash[kFix3HashSize + hash3Value] = ++ p->hash[kFix4HashSize + hashValue] = p->pos; ++ ++ maxLen = 1; ++ offset = 0; ++ if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur) ++ { ++ distances[0] = maxLen = 2; ++ distances[1] = delta2 - 1; ++ offset = 2; ++ } ++ if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur) ++ { ++ maxLen = 3; ++ distances[offset + 1] = delta3 - 1; ++ offset += 2; ++ delta2 = delta3; ++ } ++ if (offset != 0) ++ { ++ for (; maxLen != lenLimit; maxLen++) ++ if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen]) ++ break; ++ distances[offset - 2] = maxLen; ++ if (maxLen == lenLimit) ++ { ++ p->son[p->cyclicBufferPos] = curMatch; ++ MOVE_POS_RET; ++ } ++ } ++ if (maxLen < 3) ++ maxLen = 3; ++ offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p), ++ distances + offset, maxLen) - (distances)); ++ MOVE_POS_RET ++} ++ ++UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) ++{ ++ UInt32 offset; ++ GET_MATCHES_HEADER(3) ++ HASH_ZIP_CALC; ++ curMatch = p->hash[hashValue]; ++ p->hash[hashValue] = p->pos; ++ offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p), ++ distances, 2) - (distances)); ++ MOVE_POS_RET ++} ++ ++static void Bt2_MatchFinder_Skip(CMatchFinder *p, UInt32 num) ++{ ++ do ++ { ++ SKIP_HEADER(2) ++ HASH2_CALC; ++ curMatch = p->hash[hashValue]; ++ p->hash[hashValue] = p->pos; ++ SKIP_FOOTER ++ } ++ while (--num != 0); ++} ++ ++void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num) ++{ ++ do ++ { ++ SKIP_HEADER(3) ++ HASH_ZIP_CALC; ++ curMatch = p->hash[hashValue]; ++ p->hash[hashValue] = p->pos; ++ SKIP_FOOTER ++ } ++ while (--num != 0); ++} ++ ++static void Bt3_MatchFinder_Skip(CMatchFinder *p, UInt32 num) ++{ ++ do ++ { ++ UInt32 hash2Value; ++ SKIP_HEADER(3) ++ HASH3_CALC; ++ curMatch = p->hash[kFix3HashSize + hashValue]; ++ p->hash[hash2Value] = ++ p->hash[kFix3HashSize + hashValue] = p->pos; ++ SKIP_FOOTER ++ } ++ while (--num != 0); ++} ++ ++static void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num) ++{ ++ do ++ { ++ UInt32 hash2Value, hash3Value; ++ SKIP_HEADER(4) ++ HASH4_CALC; ++ curMatch = p->hash[kFix4HashSize + hashValue]; ++ p->hash[ hash2Value] = ++ p->hash[kFix3HashSize + hash3Value] = p->pos; ++ p->hash[kFix4HashSize + hashValue] = p->pos; ++ SKIP_FOOTER ++ } ++ while (--num != 0); ++} ++ ++static void Hc4_MatchFinder_Skip(CMatchFinder *p, UInt32 num) ++{ ++ do ++ { ++ UInt32 hash2Value, hash3Value; ++ SKIP_HEADER(4) ++ HASH4_CALC; ++ curMatch = p->hash[kFix4HashSize + hashValue]; ++ p->hash[ hash2Value] = ++ p->hash[kFix3HashSize + hash3Value] = ++ p->hash[kFix4HashSize + hashValue] = p->pos; ++ p->son[p->cyclicBufferPos] = curMatch; ++ MOVE_POS ++ } ++ while (--num != 0); ++} ++ ++void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num) ++{ ++ do ++ { ++ SKIP_HEADER(3) ++ HASH_ZIP_CALC; ++ curMatch = p->hash[hashValue]; ++ p->hash[hashValue] = p->pos; ++ p->son[p->cyclicBufferPos] = curMatch; ++ MOVE_POS ++ } ++ while (--num != 0); ++} ++ ++void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable) ++{ ++ vTable->Init = (Mf_Init_Func)MatchFinder_Init; ++ vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinder_GetIndexByte; ++ vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes; ++ vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos; ++ if (!p->btMode) ++ { ++ vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches; ++ vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip; ++ } ++ else if (p->numHashBytes == 2) ++ { ++ vTable->GetMatches = (Mf_GetMatches_Func)Bt2_MatchFinder_GetMatches; ++ vTable->Skip = (Mf_Skip_Func)Bt2_MatchFinder_Skip; ++ } ++ else if (p->numHashBytes == 3) ++ { ++ vTable->GetMatches = (Mf_GetMatches_Func)Bt3_MatchFinder_GetMatches; ++ vTable->Skip = (Mf_Skip_Func)Bt3_MatchFinder_Skip; ++ } ++ else ++ { ++ vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches; ++ vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip; ++ } ++} +diff --git a/lib/lzma/LzmaDec.c b/lib/lzma/LzmaDec.c +new file mode 100644 +index 000000000000..7bc3ce91a6a0 +--- /dev/null ++++ b/lib/lzma/LzmaDec.c +@@ -0,0 +1,999 @@ ++/* LzmaDec.c -- LZMA Decoder ++2009-09-20 : Igor Pavlov : Public domain */ ++ ++#include "LzmaDec.h" ++ ++#include ++ ++#define kNumTopBits 24 ++#define kTopValue ((UInt32)1 << kNumTopBits) ++ ++#define kNumBitModelTotalBits 11 ++#define kBitModelTotal (1 << kNumBitModelTotalBits) ++#define kNumMoveBits 5 ++ ++#define RC_INIT_SIZE 5 ++ ++#define NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); } ++ ++#define IF_BIT_0(p) ttt = *(p); NORMALIZE; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) ++#define UPDATE_0(p) range = bound; *(p) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); ++#define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits)); ++#define GET_BIT2(p, i, A0, A1) IF_BIT_0(p) \ ++ { UPDATE_0(p); i = (i + i); A0; } else \ ++ { UPDATE_1(p); i = (i + i) + 1; A1; } ++#define GET_BIT(p, i) GET_BIT2(p, i, ; , ;) ++ ++#define TREE_GET_BIT(probs, i) { GET_BIT((probs + i), i); } ++#define TREE_DECODE(probs, limit, i) \ ++ { i = 1; do { TREE_GET_BIT(probs, i); } while (i < limit); i -= limit; } ++ ++/* #define _LZMA_SIZE_OPT */ ++ ++#ifdef _LZMA_SIZE_OPT ++#define TREE_6_DECODE(probs, i) TREE_DECODE(probs, (1 << 6), i) ++#else ++#define TREE_6_DECODE(probs, i) \ ++ { i = 1; \ ++ TREE_GET_BIT(probs, i); \ ++ TREE_GET_BIT(probs, i); \ ++ TREE_GET_BIT(probs, i); \ ++ TREE_GET_BIT(probs, i); \ ++ TREE_GET_BIT(probs, i); \ ++ TREE_GET_BIT(probs, i); \ ++ i -= 0x40; } ++#endif ++ ++#define NORMALIZE_CHECK if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); } ++ ++#define IF_BIT_0_CHECK(p) ttt = *(p); NORMALIZE_CHECK; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) ++#define UPDATE_0_CHECK range = bound; ++#define UPDATE_1_CHECK range -= bound; code -= bound; ++#define GET_BIT2_CHECK(p, i, A0, A1) IF_BIT_0_CHECK(p) \ ++ { UPDATE_0_CHECK; i = (i + i); A0; } else \ ++ { UPDATE_1_CHECK; i = (i + i) + 1; A1; } ++#define GET_BIT_CHECK(p, i) GET_BIT2_CHECK(p, i, ; , ;) ++#define TREE_DECODE_CHECK(probs, limit, i) \ ++ { i = 1; do { GET_BIT_CHECK(probs + i, i) } while (i < limit); i -= limit; } ++ ++ ++#define kNumPosBitsMax 4 ++#define kNumPosStatesMax (1 << kNumPosBitsMax) ++ ++#define kLenNumLowBits 3 ++#define kLenNumLowSymbols (1 << kLenNumLowBits) ++#define kLenNumMidBits 3 ++#define kLenNumMidSymbols (1 << kLenNumMidBits) ++#define kLenNumHighBits 8 ++#define kLenNumHighSymbols (1 << kLenNumHighBits) ++ ++#define LenChoice 0 ++#define LenChoice2 (LenChoice + 1) ++#define LenLow (LenChoice2 + 1) ++#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits)) ++#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits)) ++#define kNumLenProbs (LenHigh + kLenNumHighSymbols) ++ ++ ++#define kNumStates 12 ++#define kNumLitStates 7 ++ ++#define kStartPosModelIndex 4 ++#define kEndPosModelIndex 14 ++#define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) ++ ++#define kNumPosSlotBits 6 ++#define kNumLenToPosStates 4 ++ ++#define kNumAlignBits 4 ++#define kAlignTableSize (1 << kNumAlignBits) ++ ++#define kMatchMinLen 2 ++#define kMatchSpecLenStart (kMatchMinLen + kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols) ++ ++#define IsMatch 0 ++#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax)) ++#define IsRepG0 (IsRep + kNumStates) ++#define IsRepG1 (IsRepG0 + kNumStates) ++#define IsRepG2 (IsRepG1 + kNumStates) ++#define IsRep0Long (IsRepG2 + kNumStates) ++#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax)) ++#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits)) ++#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex) ++#define LenCoder (Align + kAlignTableSize) ++#define RepLenCoder (LenCoder + kNumLenProbs) ++#define Literal (RepLenCoder + kNumLenProbs) ++ ++#define LZMA_BASE_SIZE 1846 ++#define LZMA_LIT_SIZE 768 ++ ++#define LzmaProps_GetNumProbs(p) ((UInt32)LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((p)->lc + (p)->lp))) ++ ++#if Literal != LZMA_BASE_SIZE ++StopCompilingDueBUG ++#endif ++ ++#define LZMA_DIC_MIN (1 << 12) ++ ++/* First LZMA-symbol is always decoded. ++And it decodes new LZMA-symbols while (buf < bufLimit), but "buf" is without last normalization ++Out: ++ Result: ++ SZ_OK - OK ++ SZ_ERROR_DATA - Error ++ p->remainLen: ++ < kMatchSpecLenStart : normal remain ++ = kMatchSpecLenStart : finished ++ = kMatchSpecLenStart + 1 : Flush marker ++ = kMatchSpecLenStart + 2 : State Init Marker ++*/ ++ ++static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte *bufLimit) ++{ ++ CLzmaProb *probs = p->probs; ++ ++ unsigned state = p->state; ++ UInt32 rep0 = p->reps[0], rep1 = p->reps[1], rep2 = p->reps[2], rep3 = p->reps[3]; ++ unsigned pbMask = ((unsigned)1 << (p->prop.pb)) - 1; ++ unsigned lpMask = ((unsigned)1 << (p->prop.lp)) - 1; ++ unsigned lc = p->prop.lc; ++ ++ Byte *dic = p->dic; ++ SizeT dicBufSize = p->dicBufSize; ++ SizeT dicPos = p->dicPos; ++ ++ UInt32 processedPos = p->processedPos; ++ UInt32 checkDicSize = p->checkDicSize; ++ unsigned len = 0; ++ ++ const Byte *buf = p->buf; ++ UInt32 range = p->range; ++ UInt32 code = p->code; ++ ++ do ++ { ++ CLzmaProb *prob; ++ UInt32 bound; ++ unsigned ttt; ++ unsigned posState = processedPos & pbMask; ++ ++ prob = probs + IsMatch + (state << kNumPosBitsMax) + posState; ++ IF_BIT_0(prob) ++ { ++ unsigned symbol; ++ UPDATE_0(prob); ++ prob = probs + Literal; ++ if (checkDicSize != 0 || processedPos != 0) ++ prob += (LZMA_LIT_SIZE * (((processedPos & lpMask) << lc) + ++ (dic[(dicPos == 0 ? dicBufSize : dicPos) - 1] >> (8 - lc)))); ++ ++ if (state < kNumLitStates) ++ { ++ state -= (state < 4) ? state : 3; ++ symbol = 1; ++ do { GET_BIT(prob + symbol, symbol) } while (symbol < 0x100); ++ } ++ else ++ { ++ unsigned matchByte = p->dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; ++ unsigned offs = 0x100; ++ state -= (state < 10) ? 3 : 6; ++ symbol = 1; ++ do ++ { ++ unsigned bit; ++ CLzmaProb *probLit; ++ matchByte <<= 1; ++ bit = (matchByte & offs); ++ probLit = prob + offs + bit + symbol; ++ GET_BIT2(probLit, symbol, offs &= ~bit, offs &= bit) ++ } ++ while (symbol < 0x100); ++ } ++ dic[dicPos++] = (Byte)symbol; ++ processedPos++; ++ continue; ++ } ++ else ++ { ++ UPDATE_1(prob); ++ prob = probs + IsRep + state; ++ IF_BIT_0(prob) ++ { ++ UPDATE_0(prob); ++ state += kNumStates; ++ prob = probs + LenCoder; ++ } ++ else ++ { ++ UPDATE_1(prob); ++ if (checkDicSize == 0 && processedPos == 0) ++ return SZ_ERROR_DATA; ++ prob = probs + IsRepG0 + state; ++ IF_BIT_0(prob) ++ { ++ UPDATE_0(prob); ++ prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState; ++ IF_BIT_0(prob) ++ { ++ UPDATE_0(prob); ++ dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; ++ dicPos++; ++ processedPos++; ++ state = state < kNumLitStates ? 9 : 11; ++ continue; ++ } ++ UPDATE_1(prob); ++ } ++ else ++ { ++ UInt32 distance; ++ UPDATE_1(prob); ++ prob = probs + IsRepG1 + state; ++ IF_BIT_0(prob) ++ { ++ UPDATE_0(prob); ++ distance = rep1; ++ } ++ else ++ { ++ UPDATE_1(prob); ++ prob = probs + IsRepG2 + state; ++ IF_BIT_0(prob) ++ { ++ UPDATE_0(prob); ++ distance = rep2; ++ } ++ else ++ { ++ UPDATE_1(prob); ++ distance = rep3; ++ rep3 = rep2; ++ } ++ rep2 = rep1; ++ } ++ rep1 = rep0; ++ rep0 = distance; ++ } ++ state = state < kNumLitStates ? 8 : 11; ++ prob = probs + RepLenCoder; ++ } ++ { ++ unsigned limit, offset; ++ CLzmaProb *probLen = prob + LenChoice; ++ IF_BIT_0(probLen) ++ { ++ UPDATE_0(probLen); ++ probLen = prob + LenLow + (posState << kLenNumLowBits); ++ offset = 0; ++ limit = (1 << kLenNumLowBits); ++ } ++ else ++ { ++ UPDATE_1(probLen); ++ probLen = prob + LenChoice2; ++ IF_BIT_0(probLen) ++ { ++ UPDATE_0(probLen); ++ probLen = prob + LenMid + (posState << kLenNumMidBits); ++ offset = kLenNumLowSymbols; ++ limit = (1 << kLenNumMidBits); ++ } ++ else ++ { ++ UPDATE_1(probLen); ++ probLen = prob + LenHigh; ++ offset = kLenNumLowSymbols + kLenNumMidSymbols; ++ limit = (1 << kLenNumHighBits); ++ } ++ } ++ TREE_DECODE(probLen, limit, len); ++ len += offset; ++ } ++ ++ if (state >= kNumStates) ++ { ++ UInt32 distance; ++ prob = probs + PosSlot + ++ ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits); ++ TREE_6_DECODE(prob, distance); ++ if (distance >= kStartPosModelIndex) ++ { ++ unsigned posSlot = (unsigned)distance; ++ int numDirectBits = (int)(((distance >> 1) - 1)); ++ distance = (2 | (distance & 1)); ++ if (posSlot < kEndPosModelIndex) ++ { ++ distance <<= numDirectBits; ++ prob = probs + SpecPos + distance - posSlot - 1; ++ { ++ UInt32 mask = 1; ++ unsigned i = 1; ++ do ++ { ++ GET_BIT2(prob + i, i, ; , distance |= mask); ++ mask <<= 1; ++ } ++ while (--numDirectBits != 0); ++ } ++ } ++ else ++ { ++ numDirectBits -= kNumAlignBits; ++ do ++ { ++ NORMALIZE ++ range >>= 1; ++ ++ { ++ UInt32 t; ++ code -= range; ++ t = (0 - ((UInt32)code >> 31)); /* (UInt32)((Int32)code >> 31) */ ++ distance = (distance << 1) + (t + 1); ++ code += range & t; ++ } ++ /* ++ distance <<= 1; ++ if (code >= range) ++ { ++ code -= range; ++ distance |= 1; ++ } ++ */ ++ } ++ while (--numDirectBits != 0); ++ prob = probs + Align; ++ distance <<= kNumAlignBits; ++ { ++ unsigned i = 1; ++ GET_BIT2(prob + i, i, ; , distance |= 1); ++ GET_BIT2(prob + i, i, ; , distance |= 2); ++ GET_BIT2(prob + i, i, ; , distance |= 4); ++ GET_BIT2(prob + i, i, ; , distance |= 8); ++ } ++ if (distance == (UInt32)0xFFFFFFFF) ++ { ++ len += kMatchSpecLenStart; ++ state -= kNumStates; ++ break; ++ } ++ } ++ } ++ rep3 = rep2; ++ rep2 = rep1; ++ rep1 = rep0; ++ rep0 = distance + 1; ++ if (checkDicSize == 0) ++ { ++ if (distance >= processedPos) ++ return SZ_ERROR_DATA; ++ } ++ else if (distance >= checkDicSize) ++ return SZ_ERROR_DATA; ++ state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3; ++ } ++ ++ len += kMatchMinLen; ++ ++ if (limit == dicPos) ++ return SZ_ERROR_DATA; ++ { ++ SizeT rem = limit - dicPos; ++ unsigned curLen = ((rem < len) ? (unsigned)rem : len); ++ SizeT pos = (dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0); ++ ++ processedPos += curLen; ++ ++ len -= curLen; ++ if (pos + curLen <= dicBufSize) ++ { ++ Byte *dest = dic + dicPos; ++ ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos; ++ const Byte *lim = dest + curLen; ++ dicPos += curLen; ++ do ++ *(dest) = (Byte)*(dest + src); ++ while (++dest != lim); ++ } ++ else ++ { ++ do ++ { ++ dic[dicPos++] = dic[pos]; ++ if (++pos == dicBufSize) ++ pos = 0; ++ } ++ while (--curLen != 0); ++ } ++ } ++ } ++ } ++ while (dicPos < limit && buf < bufLimit); ++ NORMALIZE; ++ p->buf = buf; ++ p->range = range; ++ p->code = code; ++ p->remainLen = len; ++ p->dicPos = dicPos; ++ p->processedPos = processedPos; ++ p->reps[0] = rep0; ++ p->reps[1] = rep1; ++ p->reps[2] = rep2; ++ p->reps[3] = rep3; ++ p->state = state; ++ ++ return SZ_OK; ++} ++ ++static void MY_FAST_CALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit) ++{ ++ if (p->remainLen != 0 && p->remainLen < kMatchSpecLenStart) ++ { ++ Byte *dic = p->dic; ++ SizeT dicPos = p->dicPos; ++ SizeT dicBufSize = p->dicBufSize; ++ unsigned len = p->remainLen; ++ UInt32 rep0 = p->reps[0]; ++ if (limit - dicPos < len) ++ len = (unsigned)(limit - dicPos); ++ ++ if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len) ++ p->checkDicSize = p->prop.dicSize; ++ ++ p->processedPos += len; ++ p->remainLen -= len; ++ while (len-- != 0) ++ { ++ dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; ++ dicPos++; ++ } ++ p->dicPos = dicPos; ++ } ++} ++ ++static int MY_FAST_CALL LzmaDec_DecodeReal2(CLzmaDec *p, SizeT limit, const Byte *bufLimit) ++{ ++ do ++ { ++ SizeT limit2 = limit; ++ if (p->checkDicSize == 0) ++ { ++ UInt32 rem = p->prop.dicSize - p->processedPos; ++ if (limit - p->dicPos > rem) ++ limit2 = p->dicPos + rem; ++ } ++ RINOK(LzmaDec_DecodeReal(p, limit2, bufLimit)); ++ if (p->processedPos >= p->prop.dicSize) ++ p->checkDicSize = p->prop.dicSize; ++ LzmaDec_WriteRem(p, limit); ++ } ++ while (p->dicPos < limit && p->buf < bufLimit && p->remainLen < kMatchSpecLenStart); ++ ++ if (p->remainLen > kMatchSpecLenStart) ++ { ++ p->remainLen = kMatchSpecLenStart; ++ } ++ return 0; ++} ++ ++typedef enum ++{ ++ DUMMY_ERROR, /* unexpected end of input stream */ ++ DUMMY_LIT, ++ DUMMY_MATCH, ++ DUMMY_REP ++} ELzmaDummy; ++ ++static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inSize) ++{ ++ UInt32 range = p->range; ++ UInt32 code = p->code; ++ const Byte *bufLimit = buf + inSize; ++ CLzmaProb *probs = p->probs; ++ unsigned state = p->state; ++ ELzmaDummy res; ++ ++ { ++ CLzmaProb *prob; ++ UInt32 bound; ++ unsigned ttt; ++ unsigned posState = (p->processedPos) & ((1 << p->prop.pb) - 1); ++ ++ prob = probs + IsMatch + (state << kNumPosBitsMax) + posState; ++ IF_BIT_0_CHECK(prob) ++ { ++ UPDATE_0_CHECK ++ ++ /* if (bufLimit - buf >= 7) return DUMMY_LIT; */ ++ ++ prob = probs + Literal; ++ if (p->checkDicSize != 0 || p->processedPos != 0) ++ prob += (LZMA_LIT_SIZE * ++ ((((p->processedPos) & ((1 << (p->prop.lp)) - 1)) << p->prop.lc) + ++ (p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc)))); ++ ++ if (state < kNumLitStates) ++ { ++ unsigned symbol = 1; ++ do { GET_BIT_CHECK(prob + symbol, symbol) } while (symbol < 0x100); ++ } ++ else ++ { ++ unsigned matchByte = p->dic[p->dicPos - p->reps[0] + ++ ((p->dicPos < p->reps[0]) ? p->dicBufSize : 0)]; ++ unsigned offs = 0x100; ++ unsigned symbol = 1; ++ do ++ { ++ unsigned bit; ++ CLzmaProb *probLit; ++ matchByte <<= 1; ++ bit = (matchByte & offs); ++ probLit = prob + offs + bit + symbol; ++ GET_BIT2_CHECK(probLit, symbol, offs &= ~bit, offs &= bit) ++ } ++ while (symbol < 0x100); ++ } ++ res = DUMMY_LIT; ++ } ++ else ++ { ++ unsigned len; ++ UPDATE_1_CHECK; ++ ++ prob = probs + IsRep + state; ++ IF_BIT_0_CHECK(prob) ++ { ++ UPDATE_0_CHECK; ++ state = 0; ++ prob = probs + LenCoder; ++ res = DUMMY_MATCH; ++ } ++ else ++ { ++ UPDATE_1_CHECK; ++ res = DUMMY_REP; ++ prob = probs + IsRepG0 + state; ++ IF_BIT_0_CHECK(prob) ++ { ++ UPDATE_0_CHECK; ++ prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState; ++ IF_BIT_0_CHECK(prob) ++ { ++ UPDATE_0_CHECK; ++ NORMALIZE_CHECK; ++ return DUMMY_REP; ++ } ++ else ++ { ++ UPDATE_1_CHECK; ++ } ++ } ++ else ++ { ++ UPDATE_1_CHECK; ++ prob = probs + IsRepG1 + state; ++ IF_BIT_0_CHECK(prob) ++ { ++ UPDATE_0_CHECK; ++ } ++ else ++ { ++ UPDATE_1_CHECK; ++ prob = probs + IsRepG2 + state; ++ IF_BIT_0_CHECK(prob) ++ { ++ UPDATE_0_CHECK; ++ } ++ else ++ { ++ UPDATE_1_CHECK; ++ } ++ } ++ } ++ state = kNumStates; ++ prob = probs + RepLenCoder; ++ } ++ { ++ unsigned limit, offset; ++ CLzmaProb *probLen = prob + LenChoice; ++ IF_BIT_0_CHECK(probLen) ++ { ++ UPDATE_0_CHECK; ++ probLen = prob + LenLow + (posState << kLenNumLowBits); ++ offset = 0; ++ limit = 1 << kLenNumLowBits; ++ } ++ else ++ { ++ UPDATE_1_CHECK; ++ probLen = prob + LenChoice2; ++ IF_BIT_0_CHECK(probLen) ++ { ++ UPDATE_0_CHECK; ++ probLen = prob + LenMid + (posState << kLenNumMidBits); ++ offset = kLenNumLowSymbols; ++ limit = 1 << kLenNumMidBits; ++ } ++ else ++ { ++ UPDATE_1_CHECK; ++ probLen = prob + LenHigh; ++ offset = kLenNumLowSymbols + kLenNumMidSymbols; ++ limit = 1 << kLenNumHighBits; ++ } ++ } ++ TREE_DECODE_CHECK(probLen, limit, len); ++ len += offset; ++ } ++ ++ if (state < 4) ++ { ++ unsigned posSlot; ++ prob = probs + PosSlot + ++ ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << ++ kNumPosSlotBits); ++ TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot); ++ if (posSlot >= kStartPosModelIndex) ++ { ++ int numDirectBits = ((posSlot >> 1) - 1); ++ ++ /* if (bufLimit - buf >= 8) return DUMMY_MATCH; */ ++ ++ if (posSlot < kEndPosModelIndex) ++ { ++ prob = probs + SpecPos + ((2 | (posSlot & 1)) << numDirectBits) - posSlot - 1; ++ } ++ else ++ { ++ numDirectBits -= kNumAlignBits; ++ do ++ { ++ NORMALIZE_CHECK ++ range >>= 1; ++ code -= range & (((code - range) >> 31) - 1); ++ /* if (code >= range) code -= range; */ ++ } ++ while (--numDirectBits != 0); ++ prob = probs + Align; ++ numDirectBits = kNumAlignBits; ++ } ++ { ++ unsigned i = 1; ++ do ++ { ++ GET_BIT_CHECK(prob + i, i); ++ } ++ while (--numDirectBits != 0); ++ } ++ } ++ } ++ } ++ } ++ NORMALIZE_CHECK; ++ return res; ++} ++ ++ ++static void LzmaDec_InitRc(CLzmaDec *p, const Byte *data) ++{ ++ p->code = ((UInt32)data[1] << 24) | ((UInt32)data[2] << 16) | ((UInt32)data[3] << 8) | ((UInt32)data[4]); ++ p->range = 0xFFFFFFFF; ++ p->needFlush = 0; ++} ++ ++static void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState) ++{ ++ p->needFlush = 1; ++ p->remainLen = 0; ++ p->tempBufSize = 0; ++ ++ if (initDic) ++ { ++ p->processedPos = 0; ++ p->checkDicSize = 0; ++ p->needInitState = 1; ++ } ++ if (initState) ++ p->needInitState = 1; ++} ++ ++void LzmaDec_Init(CLzmaDec *p) ++{ ++ p->dicPos = 0; ++ LzmaDec_InitDicAndState(p, True, True); ++} ++ ++static void LzmaDec_InitStateReal(CLzmaDec *p) ++{ ++ UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (p->prop.lc + p->prop.lp)); ++ UInt32 i; ++ CLzmaProb *probs = p->probs; ++ for (i = 0; i < numProbs; i++) ++ probs[i] = kBitModelTotal >> 1; ++ p->reps[0] = p->reps[1] = p->reps[2] = p->reps[3] = 1; ++ p->state = 0; ++ p->needInitState = 0; ++} ++ ++SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen, ++ ELzmaFinishMode finishMode, ELzmaStatus *status) ++{ ++ SizeT inSize = *srcLen; ++ (*srcLen) = 0; ++ LzmaDec_WriteRem(p, dicLimit); ++ ++ *status = LZMA_STATUS_NOT_SPECIFIED; ++ ++ while (p->remainLen != kMatchSpecLenStart) ++ { ++ int checkEndMarkNow; ++ ++ if (p->needFlush != 0) ++ { ++ for (; inSize > 0 && p->tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--) ++ p->tempBuf[p->tempBufSize++] = *src++; ++ if (p->tempBufSize < RC_INIT_SIZE) ++ { ++ *status = LZMA_STATUS_NEEDS_MORE_INPUT; ++ return SZ_OK; ++ } ++ if (p->tempBuf[0] != 0) ++ return SZ_ERROR_DATA; ++ ++ LzmaDec_InitRc(p, p->tempBuf); ++ p->tempBufSize = 0; ++ } ++ ++ checkEndMarkNow = 0; ++ if (p->dicPos >= dicLimit) ++ { ++ if (p->remainLen == 0 && p->code == 0) ++ { ++ *status = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK; ++ return SZ_OK; ++ } ++ if (finishMode == LZMA_FINISH_ANY) ++ { ++ *status = LZMA_STATUS_NOT_FINISHED; ++ return SZ_OK; ++ } ++ if (p->remainLen != 0) ++ { ++ *status = LZMA_STATUS_NOT_FINISHED; ++ return SZ_ERROR_DATA; ++ } ++ checkEndMarkNow = 1; ++ } ++ ++ if (p->needInitState) ++ LzmaDec_InitStateReal(p); ++ ++ if (p->tempBufSize == 0) ++ { ++ SizeT processed; ++ const Byte *bufLimit; ++ if (inSize < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) ++ { ++ int dummyRes = LzmaDec_TryDummy(p, src, inSize); ++ if (dummyRes == DUMMY_ERROR) ++ { ++ memcpy(p->tempBuf, src, inSize); ++ p->tempBufSize = (unsigned)inSize; ++ (*srcLen) += inSize; ++ *status = LZMA_STATUS_NEEDS_MORE_INPUT; ++ return SZ_OK; ++ } ++ if (checkEndMarkNow && dummyRes != DUMMY_MATCH) ++ { ++ *status = LZMA_STATUS_NOT_FINISHED; ++ return SZ_ERROR_DATA; ++ } ++ bufLimit = src; ++ } ++ else ++ bufLimit = src + inSize - LZMA_REQUIRED_INPUT_MAX; ++ p->buf = src; ++ if (LzmaDec_DecodeReal2(p, dicLimit, bufLimit) != 0) ++ return SZ_ERROR_DATA; ++ processed = (SizeT)(p->buf - src); ++ (*srcLen) += processed; ++ src += processed; ++ inSize -= processed; ++ } ++ else ++ { ++ unsigned rem = p->tempBufSize, lookAhead = 0; ++ while (rem < LZMA_REQUIRED_INPUT_MAX && lookAhead < inSize) ++ p->tempBuf[rem++] = src[lookAhead++]; ++ p->tempBufSize = rem; ++ if (rem < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) ++ { ++ int dummyRes = LzmaDec_TryDummy(p, p->tempBuf, rem); ++ if (dummyRes == DUMMY_ERROR) ++ { ++ (*srcLen) += lookAhead; ++ *status = LZMA_STATUS_NEEDS_MORE_INPUT; ++ return SZ_OK; ++ } ++ if (checkEndMarkNow && dummyRes != DUMMY_MATCH) ++ { ++ *status = LZMA_STATUS_NOT_FINISHED; ++ return SZ_ERROR_DATA; ++ } ++ } ++ p->buf = p->tempBuf; ++ if (LzmaDec_DecodeReal2(p, dicLimit, p->buf) != 0) ++ return SZ_ERROR_DATA; ++ lookAhead -= (rem - (unsigned)(p->buf - p->tempBuf)); ++ (*srcLen) += lookAhead; ++ src += lookAhead; ++ inSize -= lookAhead; ++ p->tempBufSize = 0; ++ } ++ } ++ if (p->code == 0) ++ *status = LZMA_STATUS_FINISHED_WITH_MARK; ++ return (p->code == 0) ? SZ_OK : SZ_ERROR_DATA; ++} ++ ++SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) ++{ ++ SizeT outSize = *destLen; ++ SizeT inSize = *srcLen; ++ *srcLen = *destLen = 0; ++ for (;;) ++ { ++ SizeT inSizeCur = inSize, outSizeCur, dicPos; ++ ELzmaFinishMode curFinishMode; ++ SRes res; ++ if (p->dicPos == p->dicBufSize) ++ p->dicPos = 0; ++ dicPos = p->dicPos; ++ if (outSize > p->dicBufSize - dicPos) ++ { ++ outSizeCur = p->dicBufSize; ++ curFinishMode = LZMA_FINISH_ANY; ++ } ++ else ++ { ++ outSizeCur = dicPos + outSize; ++ curFinishMode = finishMode; ++ } ++ ++ res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status); ++ src += inSizeCur; ++ inSize -= inSizeCur; ++ *srcLen += inSizeCur; ++ outSizeCur = p->dicPos - dicPos; ++ memcpy(dest, p->dic + dicPos, outSizeCur); ++ dest += outSizeCur; ++ outSize -= outSizeCur; ++ *destLen += outSizeCur; ++ if (res != 0) ++ return res; ++ if (outSizeCur == 0 || outSize == 0) ++ return SZ_OK; ++ } ++} ++ ++void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc) ++{ ++ alloc->Free(alloc, p->probs); ++ p->probs = 0; ++} ++ ++static void LzmaDec_FreeDict(CLzmaDec *p, ISzAlloc *alloc) ++{ ++ alloc->Free(alloc, p->dic); ++ p->dic = 0; ++} ++ ++void LzmaDec_Free(CLzmaDec *p, ISzAlloc *alloc) ++{ ++ LzmaDec_FreeProbs(p, alloc); ++ LzmaDec_FreeDict(p, alloc); ++} ++ ++SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size) ++{ ++ UInt32 dicSize; ++ Byte d; ++ ++ if (size < LZMA_PROPS_SIZE) ++ return SZ_ERROR_UNSUPPORTED; ++ else ++ dicSize = data[1] | ((UInt32)data[2] << 8) | ((UInt32)data[3] << 16) | ((UInt32)data[4] << 24); ++ ++ if (dicSize < LZMA_DIC_MIN) ++ dicSize = LZMA_DIC_MIN; ++ p->dicSize = dicSize; ++ ++ d = data[0]; ++ if (d >= (9 * 5 * 5)) ++ return SZ_ERROR_UNSUPPORTED; ++ ++ p->lc = d % 9; ++ d /= 9; ++ p->pb = d / 5; ++ p->lp = d % 5; ++ ++ return SZ_OK; ++} ++ ++static SRes LzmaDec_AllocateProbs2(CLzmaDec *p, const CLzmaProps *propNew, ISzAlloc *alloc) ++{ ++ UInt32 numProbs = LzmaProps_GetNumProbs(propNew); ++ if (p->probs == 0 || numProbs != p->numProbs) ++ { ++ LzmaDec_FreeProbs(p, alloc); ++ p->probs = (CLzmaProb *)alloc->Alloc(alloc, numProbs * sizeof(CLzmaProb)); ++ p->numProbs = numProbs; ++ if (p->probs == 0) ++ return SZ_ERROR_MEM; ++ } ++ return SZ_OK; ++} ++ ++SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) ++{ ++ CLzmaProps propNew; ++ RINOK(LzmaProps_Decode(&propNew, props, propsSize)); ++ RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); ++ p->prop = propNew; ++ return SZ_OK; ++} ++ ++SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) ++{ ++ CLzmaProps propNew; ++ SizeT dicBufSize; ++ RINOK(LzmaProps_Decode(&propNew, props, propsSize)); ++ RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); ++ dicBufSize = propNew.dicSize; ++ if (p->dic == 0 || dicBufSize != p->dicBufSize) ++ { ++ LzmaDec_FreeDict(p, alloc); ++ p->dic = (Byte *)alloc->Alloc(alloc, dicBufSize); ++ if (p->dic == 0) ++ { ++ LzmaDec_FreeProbs(p, alloc); ++ return SZ_ERROR_MEM; ++ } ++ } ++ p->dicBufSize = dicBufSize; ++ p->prop = propNew; ++ return SZ_OK; ++} ++ ++SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ++ const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, ++ ELzmaStatus *status, ISzAlloc *alloc) ++{ ++ CLzmaDec p; ++ SRes res; ++ SizeT inSize = *srcLen; ++ SizeT outSize = *destLen; ++ *srcLen = *destLen = 0; ++ if (inSize < RC_INIT_SIZE) ++ return SZ_ERROR_INPUT_EOF; ++ ++ LzmaDec_Construct(&p); ++ res = LzmaDec_AllocateProbs(&p, propData, propSize, alloc); ++ if (res != 0) ++ return res; ++ p.dic = dest; ++ p.dicBufSize = outSize; ++ ++ LzmaDec_Init(&p); ++ ++ *srcLen = inSize; ++ res = LzmaDec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status); ++ ++ if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT) ++ res = SZ_ERROR_INPUT_EOF; ++ ++ (*destLen) = p.dicPos; ++ LzmaDec_FreeProbs(&p, alloc); ++ return res; ++} +diff --git a/lib/lzma/LzmaEnc.c b/lib/lzma/LzmaEnc.c +new file mode 100644 +index 000000000000..b81f0863f7d8 +--- /dev/null ++++ b/lib/lzma/LzmaEnc.c +@@ -0,0 +1,2271 @@ ++/* LzmaEnc.c -- LZMA Encoder ++2009-11-24 : Igor Pavlov : Public domain */ ++ ++#include ++ ++/* #define SHOW_STAT */ ++/* #define SHOW_STAT2 */ ++ ++#if defined(SHOW_STAT) || defined(SHOW_STAT2) ++#include ++#endif ++ ++#include "LzmaEnc.h" ++ ++/* disable MT */ ++#define _7ZIP_ST ++ ++#include "LzFind.h" ++#ifndef _7ZIP_ST ++#include "LzFindMt.h" ++#endif ++ ++#ifdef SHOW_STAT ++static int ttt = 0; ++#endif ++ ++#define kBlockSizeMax ((1 << LZMA_NUM_BLOCK_SIZE_BITS) - 1) ++ ++#define kBlockSize (9 << 10) ++#define kUnpackBlockSize (1 << 18) ++#define kMatchArraySize (1 << 21) ++#define kMatchRecordMaxSize ((LZMA_MATCH_LEN_MAX * 2 + 3) * LZMA_MATCH_LEN_MAX) ++ ++#define kNumMaxDirectBits (31) ++ ++#define kNumTopBits 24 ++#define kTopValue ((UInt32)1 << kNumTopBits) ++ ++#define kNumBitModelTotalBits 11 ++#define kBitModelTotal (1 << kNumBitModelTotalBits) ++#define kNumMoveBits 5 ++#define kProbInitValue (kBitModelTotal >> 1) ++ ++#define kNumMoveReducingBits 4 ++#define kNumBitPriceShiftBits 4 ++#define kBitPrice (1 << kNumBitPriceShiftBits) ++ ++void LzmaEncProps_Init(CLzmaEncProps *p) ++{ ++ p->level = 5; ++ p->dictSize = p->mc = 0; ++ p->lc = p->lp = p->pb = p->algo = p->fb = p->btMode = p->numHashBytes = p->numThreads = -1; ++ p->writeEndMark = 0; ++} ++ ++void LzmaEncProps_Normalize(CLzmaEncProps *p) ++{ ++ int level = p->level; ++ if (level < 0) level = 5; ++ p->level = level; ++ if (p->dictSize == 0) p->dictSize = (level <= 5 ? (1 << (level * 2 + 14)) : (level == 6 ? (1 << 25) : (1 << 26))); ++ if (p->lc < 0) p->lc = 3; ++ if (p->lp < 0) p->lp = 0; ++ if (p->pb < 0) p->pb = 2; ++ if (p->algo < 0) p->algo = (level < 5 ? 0 : 1); ++ if (p->fb < 0) p->fb = (level < 7 ? 32 : 64); ++ if (p->btMode < 0) p->btMode = (p->algo == 0 ? 0 : 1); ++ if (p->numHashBytes < 0) p->numHashBytes = 4; ++ if (p->mc == 0) p->mc = (16 + (p->fb >> 1)) >> (p->btMode ? 0 : 1); ++ if (p->numThreads < 0) ++ p->numThreads = ++ #ifndef _7ZIP_ST ++ ((p->btMode && p->algo) ? 2 : 1); ++ #else ++ 1; ++ #endif ++} ++ ++UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2) ++{ ++ CLzmaEncProps props = *props2; ++ LzmaEncProps_Normalize(&props); ++ return props.dictSize; ++} ++ ++/* #define LZMA_LOG_BSR */ ++/* Define it for Intel's CPU */ ++ ++ ++#ifdef LZMA_LOG_BSR ++ ++#define kDicLogSizeMaxCompress 30 ++ ++#define BSR2_RET(pos, res) { unsigned long i; _BitScanReverse(&i, (pos)); res = (i + i) + ((pos >> (i - 1)) & 1); } ++ ++UInt32 GetPosSlot1(UInt32 pos) ++{ ++ UInt32 res; ++ BSR2_RET(pos, res); ++ return res; ++} ++#define GetPosSlot2(pos, res) { BSR2_RET(pos, res); } ++#define GetPosSlot(pos, res) { if (pos < 2) res = pos; else BSR2_RET(pos, res); } ++ ++#else ++ ++#define kNumLogBits (9 + (int)sizeof(size_t) / 2) ++#define kDicLogSizeMaxCompress ((kNumLogBits - 1) * 2 + 7) ++ ++static void LzmaEnc_FastPosInit(Byte *g_FastPos) ++{ ++ int c = 2, slotFast; ++ g_FastPos[0] = 0; ++ g_FastPos[1] = 1; ++ ++ for (slotFast = 2; slotFast < kNumLogBits * 2; slotFast++) ++ { ++ UInt32 k = (1 << ((slotFast >> 1) - 1)); ++ UInt32 j; ++ for (j = 0; j < k; j++, c++) ++ g_FastPos[c] = (Byte)slotFast; ++ } ++} ++ ++#define BSR2_RET(pos, res) { UInt32 i = 6 + ((kNumLogBits - 1) & \ ++ (0 - (((((UInt32)1 << (kNumLogBits + 6)) - 1) - pos) >> 31))); \ ++ res = p->g_FastPos[pos >> i] + (i * 2); } ++/* ++#define BSR2_RET(pos, res) { res = (pos < (1 << (kNumLogBits + 6))) ? \ ++ p->g_FastPos[pos >> 6] + 12 : \ ++ p->g_FastPos[pos >> (6 + kNumLogBits - 1)] + (6 + (kNumLogBits - 1)) * 2; } ++*/ ++ ++#define GetPosSlot1(pos) p->g_FastPos[pos] ++#define GetPosSlot2(pos, res) { BSR2_RET(pos, res); } ++#define GetPosSlot(pos, res) { if (pos < kNumFullDistances) res = p->g_FastPos[pos]; else BSR2_RET(pos, res); } ++ ++#endif ++ ++ ++#define LZMA_NUM_REPS 4 ++ ++typedef unsigned CState; ++ ++typedef struct ++{ ++ UInt32 price; ++ ++ CState state; ++ int prev1IsChar; ++ int prev2; ++ ++ UInt32 posPrev2; ++ UInt32 backPrev2; ++ ++ UInt32 posPrev; ++ UInt32 backPrev; ++ UInt32 backs[LZMA_NUM_REPS]; ++} COptimal; ++ ++#define kNumOpts (1 << 12) ++ ++#define kNumLenToPosStates 4 ++#define kNumPosSlotBits 6 ++#define kDicLogSizeMin 0 ++#define kDicLogSizeMax 32 ++#define kDistTableSizeMax (kDicLogSizeMax * 2) ++ ++ ++#define kNumAlignBits 4 ++#define kAlignTableSize (1 << kNumAlignBits) ++#define kAlignMask (kAlignTableSize - 1) ++ ++#define kStartPosModelIndex 4 ++#define kEndPosModelIndex 14 ++#define kNumPosModels (kEndPosModelIndex - kStartPosModelIndex) ++ ++#define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) ++ ++#ifdef _LZMA_PROB32 ++#define CLzmaProb UInt32 ++#else ++#define CLzmaProb UInt16 ++#endif ++ ++#define LZMA_PB_MAX 4 ++#define LZMA_LC_MAX 8 ++#define LZMA_LP_MAX 4 ++ ++#define LZMA_NUM_PB_STATES_MAX (1 << LZMA_PB_MAX) ++ ++ ++#define kLenNumLowBits 3 ++#define kLenNumLowSymbols (1 << kLenNumLowBits) ++#define kLenNumMidBits 3 ++#define kLenNumMidSymbols (1 << kLenNumMidBits) ++#define kLenNumHighBits 8 ++#define kLenNumHighSymbols (1 << kLenNumHighBits) ++ ++#define kLenNumSymbolsTotal (kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols) ++ ++#define LZMA_MATCH_LEN_MIN 2 ++#define LZMA_MATCH_LEN_MAX (LZMA_MATCH_LEN_MIN + kLenNumSymbolsTotal - 1) ++ ++#define kNumStates 12 ++ ++typedef struct ++{ ++ CLzmaProb choice; ++ CLzmaProb choice2; ++ CLzmaProb low[LZMA_NUM_PB_STATES_MAX << kLenNumLowBits]; ++ CLzmaProb mid[LZMA_NUM_PB_STATES_MAX << kLenNumMidBits]; ++ CLzmaProb high[kLenNumHighSymbols]; ++} CLenEnc; ++ ++typedef struct ++{ ++ CLenEnc p; ++ UInt32 prices[LZMA_NUM_PB_STATES_MAX][kLenNumSymbolsTotal]; ++ UInt32 tableSize; ++ UInt32 counters[LZMA_NUM_PB_STATES_MAX]; ++} CLenPriceEnc; ++ ++typedef struct ++{ ++ UInt32 range; ++ Byte cache; ++ UInt64 low; ++ UInt64 cacheSize; ++ Byte *buf; ++ Byte *bufLim; ++ Byte *bufBase; ++ ISeqOutStream *outStream; ++ UInt64 processed; ++ SRes res; ++} CRangeEnc; ++ ++typedef struct ++{ ++ CLzmaProb *litProbs; ++ ++ CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX]; ++ CLzmaProb isRep[kNumStates]; ++ CLzmaProb isRepG0[kNumStates]; ++ CLzmaProb isRepG1[kNumStates]; ++ CLzmaProb isRepG2[kNumStates]; ++ CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX]; ++ ++ CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits]; ++ CLzmaProb posEncoders[kNumFullDistances - kEndPosModelIndex]; ++ CLzmaProb posAlignEncoder[1 << kNumAlignBits]; ++ ++ CLenPriceEnc lenEnc; ++ CLenPriceEnc repLenEnc; ++ ++ UInt32 reps[LZMA_NUM_REPS]; ++ UInt32 state; ++} CSaveState; ++ ++typedef struct ++{ ++ IMatchFinder matchFinder; ++ void *matchFinderObj; ++ ++ #ifndef _7ZIP_ST ++ Bool mtMode; ++ CMatchFinderMt matchFinderMt; ++ #endif ++ ++ CMatchFinder matchFinderBase; ++ ++ #ifndef _7ZIP_ST ++ Byte pad[128]; ++ #endif ++ ++ UInt32 optimumEndIndex; ++ UInt32 optimumCurrentIndex; ++ ++ UInt32 longestMatchLength; ++ UInt32 numPairs; ++ UInt32 numAvail; ++ COptimal opt[kNumOpts]; ++ ++ #ifndef LZMA_LOG_BSR ++ Byte g_FastPos[1 << kNumLogBits]; ++ #endif ++ ++ UInt32 ProbPrices[kBitModelTotal >> kNumMoveReducingBits]; ++ UInt32 matches[LZMA_MATCH_LEN_MAX * 2 + 2 + 1]; ++ UInt32 numFastBytes; ++ UInt32 additionalOffset; ++ UInt32 reps[LZMA_NUM_REPS]; ++ UInt32 state; ++ ++ UInt32 posSlotPrices[kNumLenToPosStates][kDistTableSizeMax]; ++ UInt32 distancesPrices[kNumLenToPosStates][kNumFullDistances]; ++ UInt32 alignPrices[kAlignTableSize]; ++ UInt32 alignPriceCount; ++ ++ UInt32 distTableSize; ++ ++ unsigned lc, lp, pb; ++ unsigned lpMask, pbMask; ++ ++ CLzmaProb *litProbs; ++ ++ CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX]; ++ CLzmaProb isRep[kNumStates]; ++ CLzmaProb isRepG0[kNumStates]; ++ CLzmaProb isRepG1[kNumStates]; ++ CLzmaProb isRepG2[kNumStates]; ++ CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX]; ++ ++ CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits]; ++ CLzmaProb posEncoders[kNumFullDistances - kEndPosModelIndex]; ++ CLzmaProb posAlignEncoder[1 << kNumAlignBits]; ++ ++ CLenPriceEnc lenEnc; ++ CLenPriceEnc repLenEnc; ++ ++ unsigned lclp; ++ ++ Bool fastMode; ++ ++ CRangeEnc rc; ++ ++ Bool writeEndMark; ++ UInt64 nowPos64; ++ UInt32 matchPriceCount; ++ Bool finished; ++ Bool multiThread; ++ ++ SRes result; ++ UInt32 dictSize; ++ UInt32 matchFinderCycles; ++ ++ int needInit; ++ ++ CSaveState saveState; ++} CLzmaEnc; ++ ++/*void LzmaEnc_SaveState(CLzmaEncHandle pp) ++{ ++ CLzmaEnc *p = (CLzmaEnc *)pp; ++ CSaveState *dest = &p->saveState; ++ int i; ++ dest->lenEnc = p->lenEnc; ++ dest->repLenEnc = p->repLenEnc; ++ dest->state = p->state; ++ ++ for (i = 0; i < kNumStates; i++) ++ { ++ memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i])); ++ memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i])); ++ } ++ for (i = 0; i < kNumLenToPosStates; i++) ++ memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i])); ++ memcpy(dest->isRep, p->isRep, sizeof(p->isRep)); ++ memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0)); ++ memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1)); ++ memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2)); ++ memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders)); ++ memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder)); ++ memcpy(dest->reps, p->reps, sizeof(p->reps)); ++ memcpy(dest->litProbs, p->litProbs, (0x300 << p->lclp) * sizeof(CLzmaProb)); ++}*/ ++ ++/*void LzmaEnc_RestoreState(CLzmaEncHandle pp) ++{ ++ CLzmaEnc *dest = (CLzmaEnc *)pp; ++ const CSaveState *p = &dest->saveState; ++ int i; ++ dest->lenEnc = p->lenEnc; ++ dest->repLenEnc = p->repLenEnc; ++ dest->state = p->state; ++ ++ for (i = 0; i < kNumStates; i++) ++ { ++ memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i])); ++ memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i])); ++ } ++ for (i = 0; i < kNumLenToPosStates; i++) ++ memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i])); ++ memcpy(dest->isRep, p->isRep, sizeof(p->isRep)); ++ memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0)); ++ memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1)); ++ memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2)); ++ memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders)); ++ memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder)); ++ memcpy(dest->reps, p->reps, sizeof(p->reps)); ++ memcpy(dest->litProbs, p->litProbs, (0x300 << dest->lclp) * sizeof(CLzmaProb)); ++}*/ ++ ++SRes LzmaEnc_SetProps(CLzmaEncHandle pp, const CLzmaEncProps *props2) ++{ ++ CLzmaEnc *p = (CLzmaEnc *)pp; ++ CLzmaEncProps props = *props2; ++ LzmaEncProps_Normalize(&props); ++ ++ if (props.lc > LZMA_LC_MAX || props.lp > LZMA_LP_MAX || props.pb > LZMA_PB_MAX || ++ props.dictSize > (1 << kDicLogSizeMaxCompress) || props.dictSize > (1 << 30)) ++ return SZ_ERROR_PARAM; ++ p->dictSize = props.dictSize; ++ p->matchFinderCycles = props.mc; ++ { ++ unsigned fb = props.fb; ++ if (fb < 5) ++ fb = 5; ++ if (fb > LZMA_MATCH_LEN_MAX) ++ fb = LZMA_MATCH_LEN_MAX; ++ p->numFastBytes = fb; ++ } ++ p->lc = props.lc; ++ p->lp = props.lp; ++ p->pb = props.pb; ++ p->fastMode = (props.algo == 0); ++ p->matchFinderBase.btMode = props.btMode; ++ { ++ UInt32 numHashBytes = 4; ++ if (props.btMode) ++ { ++ if (props.numHashBytes < 2) ++ numHashBytes = 2; ++ else if (props.numHashBytes < 4) ++ numHashBytes = props.numHashBytes; ++ } ++ p->matchFinderBase.numHashBytes = numHashBytes; ++ } ++ ++ p->matchFinderBase.cutValue = props.mc; ++ ++ p->writeEndMark = props.writeEndMark; ++ ++ #ifndef _7ZIP_ST ++ /* ++ if (newMultiThread != _multiThread) ++ { ++ ReleaseMatchFinder(); ++ _multiThread = newMultiThread; ++ } ++ */ ++ p->multiThread = (props.numThreads > 1); ++ #endif ++ ++ return SZ_OK; ++} ++ ++static const int kLiteralNextStates[kNumStates] = {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5}; ++static const int kMatchNextStates[kNumStates] = {7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10}; ++static const int kRepNextStates[kNumStates] = {8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11}; ++static const int kShortRepNextStates[kNumStates]= {9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11}; ++ ++#define IsCharState(s) ((s) < 7) ++ ++#define GetLenToPosState(len) (((len) < kNumLenToPosStates + 1) ? (len) - 2 : kNumLenToPosStates - 1) ++ ++#define kInfinityPrice (1 << 30) ++ ++static void RangeEnc_Construct(CRangeEnc *p) ++{ ++ p->outStream = 0; ++ p->bufBase = 0; ++} ++ ++#define RangeEnc_GetProcessed(p) ((p)->processed + ((p)->buf - (p)->bufBase) + (p)->cacheSize) ++ ++#define RC_BUF_SIZE (1 << 16) ++static int RangeEnc_Alloc(CRangeEnc *p, ISzAlloc *alloc) ++{ ++ if (p->bufBase == 0) ++ { ++ p->bufBase = (Byte *)alloc->Alloc(alloc, RC_BUF_SIZE); ++ if (p->bufBase == 0) ++ return 0; ++ p->bufLim = p->bufBase + RC_BUF_SIZE; ++ } ++ return 1; ++} ++ ++static void RangeEnc_Free(CRangeEnc *p, ISzAlloc *alloc) ++{ ++ alloc->Free(alloc, p->bufBase); ++ p->bufBase = 0; ++} ++ ++static void RangeEnc_Init(CRangeEnc *p) ++{ ++ /* Stream.Init(); */ ++ p->low = 0; ++ p->range = 0xFFFFFFFF; ++ p->cacheSize = 1; ++ p->cache = 0; ++ ++ p->buf = p->bufBase; ++ ++ p->processed = 0; ++ p->res = SZ_OK; ++} ++ ++static void RangeEnc_FlushStream(CRangeEnc *p) ++{ ++ size_t num; ++ if (p->res != SZ_OK) ++ return; ++ num = p->buf - p->bufBase; ++ if (num != p->outStream->Write(p->outStream, p->bufBase, num)) ++ p->res = SZ_ERROR_WRITE; ++ p->processed += num; ++ p->buf = p->bufBase; ++} ++ ++static void MY_FAST_CALL RangeEnc_ShiftLow(CRangeEnc *p) ++{ ++ if ((UInt32)p->low < (UInt32)0xFF000000 || (int)(p->low >> 32) != 0) ++ { ++ Byte temp = p->cache; ++ do ++ { ++ Byte *buf = p->buf; ++ *buf++ = (Byte)(temp + (Byte)(p->low >> 32)); ++ p->buf = buf; ++ if (buf == p->bufLim) ++ RangeEnc_FlushStream(p); ++ temp = 0xFF; ++ } ++ while (--p->cacheSize != 0); ++ p->cache = (Byte)((UInt32)p->low >> 24); ++ } ++ p->cacheSize++; ++ p->low = (UInt32)p->low << 8; ++} ++ ++static void RangeEnc_FlushData(CRangeEnc *p) ++{ ++ int i; ++ for (i = 0; i < 5; i++) ++ RangeEnc_ShiftLow(p); ++} ++ ++static void RangeEnc_EncodeDirectBits(CRangeEnc *p, UInt32 value, int numBits) ++{ ++ do ++ { ++ p->range >>= 1; ++ p->low += p->range & (0 - ((value >> --numBits) & 1)); ++ if (p->range < kTopValue) ++ { ++ p->range <<= 8; ++ RangeEnc_ShiftLow(p); ++ } ++ } ++ while (numBits != 0); ++} ++ ++static void RangeEnc_EncodeBit(CRangeEnc *p, CLzmaProb *prob, UInt32 symbol) ++{ ++ UInt32 ttt = *prob; ++ UInt32 newBound = (p->range >> kNumBitModelTotalBits) * ttt; ++ if (symbol == 0) ++ { ++ p->range = newBound; ++ ttt += (kBitModelTotal - ttt) >> kNumMoveBits; ++ } ++ else ++ { ++ p->low += newBound; ++ p->range -= newBound; ++ ttt -= ttt >> kNumMoveBits; ++ } ++ *prob = (CLzmaProb)ttt; ++ if (p->range < kTopValue) ++ { ++ p->range <<= 8; ++ RangeEnc_ShiftLow(p); ++ } ++} ++ ++static void LitEnc_Encode(CRangeEnc *p, CLzmaProb *probs, UInt32 symbol) ++{ ++ symbol |= 0x100; ++ do ++ { ++ RangeEnc_EncodeBit(p, probs + (symbol >> 8), (symbol >> 7) & 1); ++ symbol <<= 1; ++ } ++ while (symbol < 0x10000); ++} ++ ++static void LitEnc_EncodeMatched(CRangeEnc *p, CLzmaProb *probs, UInt32 symbol, UInt32 matchByte) ++{ ++ UInt32 offs = 0x100; ++ symbol |= 0x100; ++ do ++ { ++ matchByte <<= 1; ++ RangeEnc_EncodeBit(p, probs + (offs + (matchByte & offs) + (symbol >> 8)), (symbol >> 7) & 1); ++ symbol <<= 1; ++ offs &= ~(matchByte ^ symbol); ++ } ++ while (symbol < 0x10000); ++} ++ ++static void LzmaEnc_InitPriceTables(UInt32 *ProbPrices) ++{ ++ UInt32 i; ++ for (i = (1 << kNumMoveReducingBits) / 2; i < kBitModelTotal; i += (1 << kNumMoveReducingBits)) ++ { ++ const int kCyclesBits = kNumBitPriceShiftBits; ++ UInt32 w = i; ++ UInt32 bitCount = 0; ++ int j; ++ for (j = 0; j < kCyclesBits; j++) ++ { ++ w = w * w; ++ bitCount <<= 1; ++ while (w >= ((UInt32)1 << 16)) ++ { ++ w >>= 1; ++ bitCount++; ++ } ++ } ++ ProbPrices[i >> kNumMoveReducingBits] = ((kNumBitModelTotalBits << kCyclesBits) - 15 - bitCount); ++ } ++} ++ ++ ++#define GET_PRICE(prob, symbol) \ ++ p->ProbPrices[((prob) ^ (((-(int)(symbol))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits]; ++ ++#define GET_PRICEa(prob, symbol) \ ++ ProbPrices[((prob) ^ ((-((int)(symbol))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits]; ++ ++#define GET_PRICE_0(prob) p->ProbPrices[(prob) >> kNumMoveReducingBits] ++#define GET_PRICE_1(prob) p->ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits] ++ ++#define GET_PRICE_0a(prob) ProbPrices[(prob) >> kNumMoveReducingBits] ++#define GET_PRICE_1a(prob) ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits] ++ ++static UInt32 LitEnc_GetPrice(const CLzmaProb *probs, UInt32 symbol, UInt32 *ProbPrices) ++{ ++ UInt32 price = 0; ++ symbol |= 0x100; ++ do ++ { ++ price += GET_PRICEa(probs[symbol >> 8], (symbol >> 7) & 1); ++ symbol <<= 1; ++ } ++ while (symbol < 0x10000); ++ return price; ++} ++ ++static UInt32 LitEnc_GetPriceMatched(const CLzmaProb *probs, UInt32 symbol, UInt32 matchByte, UInt32 *ProbPrices) ++{ ++ UInt32 price = 0; ++ UInt32 offs = 0x100; ++ symbol |= 0x100; ++ do ++ { ++ matchByte <<= 1; ++ price += GET_PRICEa(probs[offs + (matchByte & offs) + (symbol >> 8)], (symbol >> 7) & 1); ++ symbol <<= 1; ++ offs &= ~(matchByte ^ symbol); ++ } ++ while (symbol < 0x10000); ++ return price; ++} ++ ++ ++static void RcTree_Encode(CRangeEnc *rc, CLzmaProb *probs, int numBitLevels, UInt32 symbol) ++{ ++ UInt32 m = 1; ++ int i; ++ for (i = numBitLevels; i != 0;) ++ { ++ UInt32 bit; ++ i--; ++ bit = (symbol >> i) & 1; ++ RangeEnc_EncodeBit(rc, probs + m, bit); ++ m = (m << 1) | bit; ++ } ++} ++ ++static void RcTree_ReverseEncode(CRangeEnc *rc, CLzmaProb *probs, int numBitLevels, UInt32 symbol) ++{ ++ UInt32 m = 1; ++ int i; ++ for (i = 0; i < numBitLevels; i++) ++ { ++ UInt32 bit = symbol & 1; ++ RangeEnc_EncodeBit(rc, probs + m, bit); ++ m = (m << 1) | bit; ++ symbol >>= 1; ++ } ++} ++ ++static UInt32 RcTree_GetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, UInt32 *ProbPrices) ++{ ++ UInt32 price = 0; ++ symbol |= (1 << numBitLevels); ++ while (symbol != 1) ++ { ++ price += GET_PRICEa(probs[symbol >> 1], symbol & 1); ++ symbol >>= 1; ++ } ++ return price; ++} ++ ++static UInt32 RcTree_ReverseGetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, UInt32 *ProbPrices) ++{ ++ UInt32 price = 0; ++ UInt32 m = 1; ++ int i; ++ for (i = numBitLevels; i != 0; i--) ++ { ++ UInt32 bit = symbol & 1; ++ symbol >>= 1; ++ price += GET_PRICEa(probs[m], bit); ++ m = (m << 1) | bit; ++ } ++ return price; ++} ++ ++ ++static void LenEnc_Init(CLenEnc *p) ++{ ++ unsigned i; ++ p->choice = p->choice2 = kProbInitValue; ++ for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << kLenNumLowBits); i++) ++ p->low[i] = kProbInitValue; ++ for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << kLenNumMidBits); i++) ++ p->mid[i] = kProbInitValue; ++ for (i = 0; i < kLenNumHighSymbols; i++) ++ p->high[i] = kProbInitValue; ++} ++ ++static void LenEnc_Encode(CLenEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posState) ++{ ++ if (symbol < kLenNumLowSymbols) ++ { ++ RangeEnc_EncodeBit(rc, &p->choice, 0); ++ RcTree_Encode(rc, p->low + (posState << kLenNumLowBits), kLenNumLowBits, symbol); ++ } ++ else ++ { ++ RangeEnc_EncodeBit(rc, &p->choice, 1); ++ if (symbol < kLenNumLowSymbols + kLenNumMidSymbols) ++ { ++ RangeEnc_EncodeBit(rc, &p->choice2, 0); ++ RcTree_Encode(rc, p->mid + (posState << kLenNumMidBits), kLenNumMidBits, symbol - kLenNumLowSymbols); ++ } ++ else ++ { ++ RangeEnc_EncodeBit(rc, &p->choice2, 1); ++ RcTree_Encode(rc, p->high, kLenNumHighBits, symbol - kLenNumLowSymbols - kLenNumMidSymbols); ++ } ++ } ++} ++ ++static void LenEnc_SetPrices(CLenEnc *p, UInt32 posState, UInt32 numSymbols, UInt32 *prices, UInt32 *ProbPrices) ++{ ++ UInt32 a0 = GET_PRICE_0a(p->choice); ++ UInt32 a1 = GET_PRICE_1a(p->choice); ++ UInt32 b0 = a1 + GET_PRICE_0a(p->choice2); ++ UInt32 b1 = a1 + GET_PRICE_1a(p->choice2); ++ UInt32 i = 0; ++ for (i = 0; i < kLenNumLowSymbols; i++) ++ { ++ if (i >= numSymbols) ++ return; ++ prices[i] = a0 + RcTree_GetPrice(p->low + (posState << kLenNumLowBits), kLenNumLowBits, i, ProbPrices); ++ } ++ for (; i < kLenNumLowSymbols + kLenNumMidSymbols; i++) ++ { ++ if (i >= numSymbols) ++ return; ++ prices[i] = b0 + RcTree_GetPrice(p->mid + (posState << kLenNumMidBits), kLenNumMidBits, i - kLenNumLowSymbols, ProbPrices); ++ } ++ for (; i < numSymbols; i++) ++ prices[i] = b1 + RcTree_GetPrice(p->high, kLenNumHighBits, i - kLenNumLowSymbols - kLenNumMidSymbols, ProbPrices); ++} ++ ++static void MY_FAST_CALL LenPriceEnc_UpdateTable(CLenPriceEnc *p, UInt32 posState, UInt32 *ProbPrices) ++{ ++ LenEnc_SetPrices(&p->p, posState, p->tableSize, p->prices[posState], ProbPrices); ++ p->counters[posState] = p->tableSize; ++} ++ ++static void LenPriceEnc_UpdateTables(CLenPriceEnc *p, UInt32 numPosStates, UInt32 *ProbPrices) ++{ ++ UInt32 posState; ++ for (posState = 0; posState < numPosStates; posState++) ++ LenPriceEnc_UpdateTable(p, posState, ProbPrices); ++} ++ ++static void LenEnc_Encode2(CLenPriceEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posState, Bool updatePrice, UInt32 *ProbPrices) ++{ ++ LenEnc_Encode(&p->p, rc, symbol, posState); ++ if (updatePrice) ++ if (--p->counters[posState] == 0) ++ LenPriceEnc_UpdateTable(p, posState, ProbPrices); ++} ++ ++ ++ ++ ++static void MovePos(CLzmaEnc *p, UInt32 num) ++{ ++ #ifdef SHOW_STAT ++ ttt += num; ++ printf("\n MovePos %d", num); ++ #endif ++ if (num != 0) ++ { ++ p->additionalOffset += num; ++ p->matchFinder.Skip(p->matchFinderObj, num); ++ } ++} ++ ++static UInt32 ReadMatchDistances(CLzmaEnc *p, UInt32 *numDistancePairsRes) ++{ ++ UInt32 lenRes = 0, numPairs; ++ p->numAvail = p->matchFinder.GetNumAvailableBytes(p->matchFinderObj); ++ numPairs = p->matchFinder.GetMatches(p->matchFinderObj, p->matches); ++ #ifdef SHOW_STAT ++ printf("\n i = %d numPairs = %d ", ttt, numPairs / 2); ++ ttt++; ++ { ++ UInt32 i; ++ for (i = 0; i < numPairs; i += 2) ++ printf("%2d %6d | ", p->matches[i], p->matches[i + 1]); ++ } ++ #endif ++ if (numPairs > 0) ++ { ++ lenRes = p->matches[numPairs - 2]; ++ if (lenRes == p->numFastBytes) ++ { ++ const Byte *pby = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; ++ UInt32 distance = p->matches[numPairs - 1] + 1; ++ UInt32 numAvail = p->numAvail; ++ if (numAvail > LZMA_MATCH_LEN_MAX) ++ numAvail = LZMA_MATCH_LEN_MAX; ++ { ++ const Byte *pby2 = pby - distance; ++ for (; lenRes < numAvail && pby[lenRes] == pby2[lenRes]; lenRes++); ++ } ++ } ++ } ++ p->additionalOffset++; ++ *numDistancePairsRes = numPairs; ++ return lenRes; ++} ++ ++ ++#define MakeAsChar(p) (p)->backPrev = (UInt32)(-1); (p)->prev1IsChar = False; ++#define MakeAsShortRep(p) (p)->backPrev = 0; (p)->prev1IsChar = False; ++#define IsShortRep(p) ((p)->backPrev == 0) ++ ++static UInt32 GetRepLen1Price(CLzmaEnc *p, UInt32 state, UInt32 posState) ++{ ++ return ++ GET_PRICE_0(p->isRepG0[state]) + ++ GET_PRICE_0(p->isRep0Long[state][posState]); ++} ++ ++static UInt32 GetPureRepPrice(CLzmaEnc *p, UInt32 repIndex, UInt32 state, UInt32 posState) ++{ ++ UInt32 price; ++ if (repIndex == 0) ++ { ++ price = GET_PRICE_0(p->isRepG0[state]); ++ price += GET_PRICE_1(p->isRep0Long[state][posState]); ++ } ++ else ++ { ++ price = GET_PRICE_1(p->isRepG0[state]); ++ if (repIndex == 1) ++ price += GET_PRICE_0(p->isRepG1[state]); ++ else ++ { ++ price += GET_PRICE_1(p->isRepG1[state]); ++ price += GET_PRICE(p->isRepG2[state], repIndex - 2); ++ } ++ } ++ return price; ++} ++ ++static UInt32 GetRepPrice(CLzmaEnc *p, UInt32 repIndex, UInt32 len, UInt32 state, UInt32 posState) ++{ ++ return p->repLenEnc.prices[posState][len - LZMA_MATCH_LEN_MIN] + ++ GetPureRepPrice(p, repIndex, state, posState); ++} ++ ++static UInt32 Backward(CLzmaEnc *p, UInt32 *backRes, UInt32 cur) ++{ ++ UInt32 posMem = p->opt[cur].posPrev; ++ UInt32 backMem = p->opt[cur].backPrev; ++ p->optimumEndIndex = cur; ++ do ++ { ++ if (p->opt[cur].prev1IsChar) ++ { ++ MakeAsChar(&p->opt[posMem]) ++ p->opt[posMem].posPrev = posMem - 1; ++ if (p->opt[cur].prev2) ++ { ++ p->opt[posMem - 1].prev1IsChar = False; ++ p->opt[posMem - 1].posPrev = p->opt[cur].posPrev2; ++ p->opt[posMem - 1].backPrev = p->opt[cur].backPrev2; ++ } ++ } ++ { ++ UInt32 posPrev = posMem; ++ UInt32 backCur = backMem; ++ ++ backMem = p->opt[posPrev].backPrev; ++ posMem = p->opt[posPrev].posPrev; ++ ++ p->opt[posPrev].backPrev = backCur; ++ p->opt[posPrev].posPrev = cur; ++ cur = posPrev; ++ } ++ } ++ while (cur != 0); ++ *backRes = p->opt[0].backPrev; ++ p->optimumCurrentIndex = p->opt[0].posPrev; ++ return p->optimumCurrentIndex; ++} ++ ++#define LIT_PROBS(pos, prevByte) (p->litProbs + ((((pos) & p->lpMask) << p->lc) + ((prevByte) >> (8 - p->lc))) * 0x300) ++ ++static UInt32 GetOptimum(CLzmaEnc *p, UInt32 position, UInt32 *backRes) ++{ ++ UInt32 numAvail, mainLen, numPairs, repMaxIndex, i, posState, lenEnd, len, cur; ++ UInt32 matchPrice, repMatchPrice, normalMatchPrice; ++ UInt32 reps[LZMA_NUM_REPS], repLens[LZMA_NUM_REPS]; ++ UInt32 *matches; ++ const Byte *data; ++ Byte curByte, matchByte; ++ if (p->optimumEndIndex != p->optimumCurrentIndex) ++ { ++ const COptimal *opt = &p->opt[p->optimumCurrentIndex]; ++ UInt32 lenRes = opt->posPrev - p->optimumCurrentIndex; ++ *backRes = opt->backPrev; ++ p->optimumCurrentIndex = opt->posPrev; ++ return lenRes; ++ } ++ p->optimumCurrentIndex = p->optimumEndIndex = 0; ++ ++ if (p->additionalOffset == 0) ++ mainLen = ReadMatchDistances(p, &numPairs); ++ else ++ { ++ mainLen = p->longestMatchLength; ++ numPairs = p->numPairs; ++ } ++ ++ numAvail = p->numAvail; ++ if (numAvail < 2) ++ { ++ *backRes = (UInt32)(-1); ++ return 1; ++ } ++ if (numAvail > LZMA_MATCH_LEN_MAX) ++ numAvail = LZMA_MATCH_LEN_MAX; ++ ++ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; ++ repMaxIndex = 0; ++ for (i = 0; i < LZMA_NUM_REPS; i++) ++ { ++ UInt32 lenTest; ++ const Byte *data2; ++ reps[i] = p->reps[i]; ++ data2 = data - (reps[i] + 1); ++ if (data[0] != data2[0] || data[1] != data2[1]) ++ { ++ repLens[i] = 0; ++ continue; ++ } ++ for (lenTest = 2; lenTest < numAvail && data[lenTest] == data2[lenTest]; lenTest++); ++ repLens[i] = lenTest; ++ if (lenTest > repLens[repMaxIndex]) ++ repMaxIndex = i; ++ } ++ if (repLens[repMaxIndex] >= p->numFastBytes) ++ { ++ UInt32 lenRes; ++ *backRes = repMaxIndex; ++ lenRes = repLens[repMaxIndex]; ++ MovePos(p, lenRes - 1); ++ return lenRes; ++ } ++ ++ matches = p->matches; ++ if (mainLen >= p->numFastBytes) ++ { ++ *backRes = matches[numPairs - 1] + LZMA_NUM_REPS; ++ MovePos(p, mainLen - 1); ++ return mainLen; ++ } ++ curByte = *data; ++ matchByte = *(data - (reps[0] + 1)); ++ ++ if (mainLen < 2 && curByte != matchByte && repLens[repMaxIndex] < 2) ++ { ++ *backRes = (UInt32)-1; ++ return 1; ++ } ++ ++ p->opt[0].state = (CState)p->state; ++ ++ posState = (position & p->pbMask); ++ ++ { ++ const CLzmaProb *probs = LIT_PROBS(position, *(data - 1)); ++ p->opt[1].price = GET_PRICE_0(p->isMatch[p->state][posState]) + ++ (!IsCharState(p->state) ? ++ LitEnc_GetPriceMatched(probs, curByte, matchByte, p->ProbPrices) : ++ LitEnc_GetPrice(probs, curByte, p->ProbPrices)); ++ } ++ ++ MakeAsChar(&p->opt[1]); ++ ++ matchPrice = GET_PRICE_1(p->isMatch[p->state][posState]); ++ repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[p->state]); ++ ++ if (matchByte == curByte) ++ { ++ UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(p, p->state, posState); ++ if (shortRepPrice < p->opt[1].price) ++ { ++ p->opt[1].price = shortRepPrice; ++ MakeAsShortRep(&p->opt[1]); ++ } ++ } ++ lenEnd = ((mainLen >= repLens[repMaxIndex]) ? mainLen : repLens[repMaxIndex]); ++ ++ if (lenEnd < 2) ++ { ++ *backRes = p->opt[1].backPrev; ++ return 1; ++ } ++ ++ p->opt[1].posPrev = 0; ++ for (i = 0; i < LZMA_NUM_REPS; i++) ++ p->opt[0].backs[i] = reps[i]; ++ ++ len = lenEnd; ++ do ++ p->opt[len--].price = kInfinityPrice; ++ while (len >= 2); ++ ++ for (i = 0; i < LZMA_NUM_REPS; i++) ++ { ++ UInt32 repLen = repLens[i]; ++ UInt32 price; ++ if (repLen < 2) ++ continue; ++ price = repMatchPrice + GetPureRepPrice(p, i, p->state, posState); ++ do ++ { ++ UInt32 curAndLenPrice = price + p->repLenEnc.prices[posState][repLen - 2]; ++ COptimal *opt = &p->opt[repLen]; ++ if (curAndLenPrice < opt->price) ++ { ++ opt->price = curAndLenPrice; ++ opt->posPrev = 0; ++ opt->backPrev = i; ++ opt->prev1IsChar = False; ++ } ++ } ++ while (--repLen >= 2); ++ } ++ ++ normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[p->state]); ++ ++ len = ((repLens[0] >= 2) ? repLens[0] + 1 : 2); ++ if (len <= mainLen) ++ { ++ UInt32 offs = 0; ++ while (len > matches[offs]) ++ offs += 2; ++ for (; ; len++) ++ { ++ COptimal *opt; ++ UInt32 distance = matches[offs + 1]; ++ ++ UInt32 curAndLenPrice = normalMatchPrice + p->lenEnc.prices[posState][len - LZMA_MATCH_LEN_MIN]; ++ UInt32 lenToPosState = GetLenToPosState(len); ++ if (distance < kNumFullDistances) ++ curAndLenPrice += p->distancesPrices[lenToPosState][distance]; ++ else ++ { ++ UInt32 slot; ++ GetPosSlot2(distance, slot); ++ curAndLenPrice += p->alignPrices[distance & kAlignMask] + p->posSlotPrices[lenToPosState][slot]; ++ } ++ opt = &p->opt[len]; ++ if (curAndLenPrice < opt->price) ++ { ++ opt->price = curAndLenPrice; ++ opt->posPrev = 0; ++ opt->backPrev = distance + LZMA_NUM_REPS; ++ opt->prev1IsChar = False; ++ } ++ if (len == matches[offs]) ++ { ++ offs += 2; ++ if (offs == numPairs) ++ break; ++ } ++ } ++ } ++ ++ cur = 0; ++ ++ #ifdef SHOW_STAT2 ++ if (position >= 0) ++ { ++ unsigned i; ++ printf("\n pos = %4X", position); ++ for (i = cur; i <= lenEnd; i++) ++ printf("\nprice[%4X] = %d", position - cur + i, p->opt[i].price); ++ } ++ #endif ++ ++ for (;;) ++ { ++ UInt32 numAvailFull, newLen, numPairs, posPrev, state, posState, startLen; ++ UInt32 curPrice, curAnd1Price, matchPrice, repMatchPrice; ++ Bool nextIsChar; ++ Byte curByte, matchByte; ++ const Byte *data; ++ COptimal *curOpt; ++ COptimal *nextOpt; ++ ++ cur++; ++ if (cur == lenEnd) ++ return Backward(p, backRes, cur); ++ ++ newLen = ReadMatchDistances(p, &numPairs); ++ if (newLen >= p->numFastBytes) ++ { ++ p->numPairs = numPairs; ++ p->longestMatchLength = newLen; ++ return Backward(p, backRes, cur); ++ } ++ position++; ++ curOpt = &p->opt[cur]; ++ posPrev = curOpt->posPrev; ++ if (curOpt->prev1IsChar) ++ { ++ posPrev--; ++ if (curOpt->prev2) ++ { ++ state = p->opt[curOpt->posPrev2].state; ++ if (curOpt->backPrev2 < LZMA_NUM_REPS) ++ state = kRepNextStates[state]; ++ else ++ state = kMatchNextStates[state]; ++ } ++ else ++ state = p->opt[posPrev].state; ++ state = kLiteralNextStates[state]; ++ } ++ else ++ state = p->opt[posPrev].state; ++ if (posPrev == cur - 1) ++ { ++ if (IsShortRep(curOpt)) ++ state = kShortRepNextStates[state]; ++ else ++ state = kLiteralNextStates[state]; ++ } ++ else ++ { ++ UInt32 pos; ++ const COptimal *prevOpt; ++ if (curOpt->prev1IsChar && curOpt->prev2) ++ { ++ posPrev = curOpt->posPrev2; ++ pos = curOpt->backPrev2; ++ state = kRepNextStates[state]; ++ } ++ else ++ { ++ pos = curOpt->backPrev; ++ if (pos < LZMA_NUM_REPS) ++ state = kRepNextStates[state]; ++ else ++ state = kMatchNextStates[state]; ++ } ++ prevOpt = &p->opt[posPrev]; ++ if (pos < LZMA_NUM_REPS) ++ { ++ UInt32 i; ++ reps[0] = prevOpt->backs[pos]; ++ for (i = 1; i <= pos; i++) ++ reps[i] = prevOpt->backs[i - 1]; ++ for (; i < LZMA_NUM_REPS; i++) ++ reps[i] = prevOpt->backs[i]; ++ } ++ else ++ { ++ UInt32 i; ++ reps[0] = (pos - LZMA_NUM_REPS); ++ for (i = 1; i < LZMA_NUM_REPS; i++) ++ reps[i] = prevOpt->backs[i - 1]; ++ } ++ } ++ curOpt->state = (CState)state; ++ ++ curOpt->backs[0] = reps[0]; ++ curOpt->backs[1] = reps[1]; ++ curOpt->backs[2] = reps[2]; ++ curOpt->backs[3] = reps[3]; ++ ++ curPrice = curOpt->price; ++ nextIsChar = False; ++ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; ++ curByte = *data; ++ matchByte = *(data - (reps[0] + 1)); ++ ++ posState = (position & p->pbMask); ++ ++ curAnd1Price = curPrice + GET_PRICE_0(p->isMatch[state][posState]); ++ { ++ const CLzmaProb *probs = LIT_PROBS(position, *(data - 1)); ++ curAnd1Price += ++ (!IsCharState(state) ? ++ LitEnc_GetPriceMatched(probs, curByte, matchByte, p->ProbPrices) : ++ LitEnc_GetPrice(probs, curByte, p->ProbPrices)); ++ } ++ ++ nextOpt = &p->opt[cur + 1]; ++ ++ if (curAnd1Price < nextOpt->price) ++ { ++ nextOpt->price = curAnd1Price; ++ nextOpt->posPrev = cur; ++ MakeAsChar(nextOpt); ++ nextIsChar = True; ++ } ++ ++ matchPrice = curPrice + GET_PRICE_1(p->isMatch[state][posState]); ++ repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[state]); ++ ++ if (matchByte == curByte && !(nextOpt->posPrev < cur && nextOpt->backPrev == 0)) ++ { ++ UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(p, state, posState); ++ if (shortRepPrice <= nextOpt->price) ++ { ++ nextOpt->price = shortRepPrice; ++ nextOpt->posPrev = cur; ++ MakeAsShortRep(nextOpt); ++ nextIsChar = True; ++ } ++ } ++ numAvailFull = p->numAvail; ++ { ++ UInt32 temp = kNumOpts - 1 - cur; ++ if (temp < numAvailFull) ++ numAvailFull = temp; ++ } ++ ++ if (numAvailFull < 2) ++ continue; ++ numAvail = (numAvailFull <= p->numFastBytes ? numAvailFull : p->numFastBytes); ++ ++ if (!nextIsChar && matchByte != curByte) /* speed optimization */ ++ { ++ /* try Literal + rep0 */ ++ UInt32 temp; ++ UInt32 lenTest2; ++ const Byte *data2 = data - (reps[0] + 1); ++ UInt32 limit = p->numFastBytes + 1; ++ if (limit > numAvailFull) ++ limit = numAvailFull; ++ ++ for (temp = 1; temp < limit && data[temp] == data2[temp]; temp++); ++ lenTest2 = temp - 1; ++ if (lenTest2 >= 2) ++ { ++ UInt32 state2 = kLiteralNextStates[state]; ++ UInt32 posStateNext = (position + 1) & p->pbMask; ++ UInt32 nextRepMatchPrice = curAnd1Price + ++ GET_PRICE_1(p->isMatch[state2][posStateNext]) + ++ GET_PRICE_1(p->isRep[state2]); ++ /* for (; lenTest2 >= 2; lenTest2--) */ ++ { ++ UInt32 curAndLenPrice; ++ COptimal *opt; ++ UInt32 offset = cur + 1 + lenTest2; ++ while (lenEnd < offset) ++ p->opt[++lenEnd].price = kInfinityPrice; ++ curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext); ++ opt = &p->opt[offset]; ++ if (curAndLenPrice < opt->price) ++ { ++ opt->price = curAndLenPrice; ++ opt->posPrev = cur + 1; ++ opt->backPrev = 0; ++ opt->prev1IsChar = True; ++ opt->prev2 = False; ++ } ++ } ++ } ++ } ++ ++ startLen = 2; /* speed optimization */ ++ { ++ UInt32 repIndex; ++ for (repIndex = 0; repIndex < LZMA_NUM_REPS; repIndex++) ++ { ++ UInt32 lenTest; ++ UInt32 lenTestTemp; ++ UInt32 price; ++ const Byte *data2 = data - (reps[repIndex] + 1); ++ if (data[0] != data2[0] || data[1] != data2[1]) ++ continue; ++ for (lenTest = 2; lenTest < numAvail && data[lenTest] == data2[lenTest]; lenTest++); ++ while (lenEnd < cur + lenTest) ++ p->opt[++lenEnd].price = kInfinityPrice; ++ lenTestTemp = lenTest; ++ price = repMatchPrice + GetPureRepPrice(p, repIndex, state, posState); ++ do ++ { ++ UInt32 curAndLenPrice = price + p->repLenEnc.prices[posState][lenTest - 2]; ++ COptimal *opt = &p->opt[cur + lenTest]; ++ if (curAndLenPrice < opt->price) ++ { ++ opt->price = curAndLenPrice; ++ opt->posPrev = cur; ++ opt->backPrev = repIndex; ++ opt->prev1IsChar = False; ++ } ++ } ++ while (--lenTest >= 2); ++ lenTest = lenTestTemp; ++ ++ if (repIndex == 0) ++ startLen = lenTest + 1; ++ ++ /* if (_maxMode) */ ++ { ++ UInt32 lenTest2 = lenTest + 1; ++ UInt32 limit = lenTest2 + p->numFastBytes; ++ UInt32 nextRepMatchPrice; ++ if (limit > numAvailFull) ++ limit = numAvailFull; ++ for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++); ++ lenTest2 -= lenTest + 1; ++ if (lenTest2 >= 2) ++ { ++ UInt32 state2 = kRepNextStates[state]; ++ UInt32 posStateNext = (position + lenTest) & p->pbMask; ++ UInt32 curAndLenCharPrice = ++ price + p->repLenEnc.prices[posState][lenTest - 2] + ++ GET_PRICE_0(p->isMatch[state2][posStateNext]) + ++ LitEnc_GetPriceMatched(LIT_PROBS(position + lenTest, data[lenTest - 1]), ++ data[lenTest], data2[lenTest], p->ProbPrices); ++ state2 = kLiteralNextStates[state2]; ++ posStateNext = (position + lenTest + 1) & p->pbMask; ++ nextRepMatchPrice = curAndLenCharPrice + ++ GET_PRICE_1(p->isMatch[state2][posStateNext]) + ++ GET_PRICE_1(p->isRep[state2]); ++ ++ /* for (; lenTest2 >= 2; lenTest2--) */ ++ { ++ UInt32 curAndLenPrice; ++ COptimal *opt; ++ UInt32 offset = cur + lenTest + 1 + lenTest2; ++ while (lenEnd < offset) ++ p->opt[++lenEnd].price = kInfinityPrice; ++ curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext); ++ opt = &p->opt[offset]; ++ if (curAndLenPrice < opt->price) ++ { ++ opt->price = curAndLenPrice; ++ opt->posPrev = cur + lenTest + 1; ++ opt->backPrev = 0; ++ opt->prev1IsChar = True; ++ opt->prev2 = True; ++ opt->posPrev2 = cur; ++ opt->backPrev2 = repIndex; ++ } ++ } ++ } ++ } ++ } ++ } ++ /* for (UInt32 lenTest = 2; lenTest <= newLen; lenTest++) */ ++ if (newLen > numAvail) ++ { ++ newLen = numAvail; ++ for (numPairs = 0; newLen > matches[numPairs]; numPairs += 2); ++ matches[numPairs] = newLen; ++ numPairs += 2; ++ } ++ if (newLen >= startLen) ++ { ++ UInt32 normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[state]); ++ UInt32 offs, curBack, posSlot; ++ UInt32 lenTest; ++ while (lenEnd < cur + newLen) ++ p->opt[++lenEnd].price = kInfinityPrice; ++ ++ offs = 0; ++ while (startLen > matches[offs]) ++ offs += 2; ++ curBack = matches[offs + 1]; ++ GetPosSlot2(curBack, posSlot); ++ for (lenTest = /*2*/ startLen; ; lenTest++) ++ { ++ UInt32 curAndLenPrice = normalMatchPrice + p->lenEnc.prices[posState][lenTest - LZMA_MATCH_LEN_MIN]; ++ UInt32 lenToPosState = GetLenToPosState(lenTest); ++ COptimal *opt; ++ if (curBack < kNumFullDistances) ++ curAndLenPrice += p->distancesPrices[lenToPosState][curBack]; ++ else ++ curAndLenPrice += p->posSlotPrices[lenToPosState][posSlot] + p->alignPrices[curBack & kAlignMask]; ++ ++ opt = &p->opt[cur + lenTest]; ++ if (curAndLenPrice < opt->price) ++ { ++ opt->price = curAndLenPrice; ++ opt->posPrev = cur; ++ opt->backPrev = curBack + LZMA_NUM_REPS; ++ opt->prev1IsChar = False; ++ } ++ ++ if (/*_maxMode && */lenTest == matches[offs]) ++ { ++ /* Try Match + Literal + Rep0 */ ++ const Byte *data2 = data - (curBack + 1); ++ UInt32 lenTest2 = lenTest + 1; ++ UInt32 limit = lenTest2 + p->numFastBytes; ++ UInt32 nextRepMatchPrice; ++ if (limit > numAvailFull) ++ limit = numAvailFull; ++ for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++); ++ lenTest2 -= lenTest + 1; ++ if (lenTest2 >= 2) ++ { ++ UInt32 state2 = kMatchNextStates[state]; ++ UInt32 posStateNext = (position + lenTest) & p->pbMask; ++ UInt32 curAndLenCharPrice = curAndLenPrice + ++ GET_PRICE_0(p->isMatch[state2][posStateNext]) + ++ LitEnc_GetPriceMatched(LIT_PROBS(position + lenTest, data[lenTest - 1]), ++ data[lenTest], data2[lenTest], p->ProbPrices); ++ state2 = kLiteralNextStates[state2]; ++ posStateNext = (posStateNext + 1) & p->pbMask; ++ nextRepMatchPrice = curAndLenCharPrice + ++ GET_PRICE_1(p->isMatch[state2][posStateNext]) + ++ GET_PRICE_1(p->isRep[state2]); ++ ++ /* for (; lenTest2 >= 2; lenTest2--) */ ++ { ++ UInt32 offset = cur + lenTest + 1 + lenTest2; ++ UInt32 curAndLenPrice; ++ COptimal *opt; ++ while (lenEnd < offset) ++ p->opt[++lenEnd].price = kInfinityPrice; ++ curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext); ++ opt = &p->opt[offset]; ++ if (curAndLenPrice < opt->price) ++ { ++ opt->price = curAndLenPrice; ++ opt->posPrev = cur + lenTest + 1; ++ opt->backPrev = 0; ++ opt->prev1IsChar = True; ++ opt->prev2 = True; ++ opt->posPrev2 = cur; ++ opt->backPrev2 = curBack + LZMA_NUM_REPS; ++ } ++ } ++ } ++ offs += 2; ++ if (offs == numPairs) ++ break; ++ curBack = matches[offs + 1]; ++ if (curBack >= kNumFullDistances) ++ GetPosSlot2(curBack, posSlot); ++ } ++ } ++ } ++ } ++} ++ ++#define ChangePair(smallDist, bigDist) (((bigDist) >> 7) > (smallDist)) ++ ++static UInt32 GetOptimumFast(CLzmaEnc *p, UInt32 *backRes) ++{ ++ UInt32 numAvail, mainLen, mainDist, numPairs, repIndex, repLen, i; ++ const Byte *data; ++ const UInt32 *matches; ++ ++ if (p->additionalOffset == 0) ++ mainLen = ReadMatchDistances(p, &numPairs); ++ else ++ { ++ mainLen = p->longestMatchLength; ++ numPairs = p->numPairs; ++ } ++ ++ numAvail = p->numAvail; ++ *backRes = (UInt32)-1; ++ if (numAvail < 2) ++ return 1; ++ if (numAvail > LZMA_MATCH_LEN_MAX) ++ numAvail = LZMA_MATCH_LEN_MAX; ++ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; ++ ++ repLen = repIndex = 0; ++ for (i = 0; i < LZMA_NUM_REPS; i++) ++ { ++ UInt32 len; ++ const Byte *data2 = data - (p->reps[i] + 1); ++ if (data[0] != data2[0] || data[1] != data2[1]) ++ continue; ++ for (len = 2; len < numAvail && data[len] == data2[len]; len++); ++ if (len >= p->numFastBytes) ++ { ++ *backRes = i; ++ MovePos(p, len - 1); ++ return len; ++ } ++ if (len > repLen) ++ { ++ repIndex = i; ++ repLen = len; ++ } ++ } ++ ++ matches = p->matches; ++ if (mainLen >= p->numFastBytes) ++ { ++ *backRes = matches[numPairs - 1] + LZMA_NUM_REPS; ++ MovePos(p, mainLen - 1); ++ return mainLen; ++ } ++ ++ mainDist = 0; /* for GCC */ ++ if (mainLen >= 2) ++ { ++ mainDist = matches[numPairs - 1]; ++ while (numPairs > 2 && mainLen == matches[numPairs - 4] + 1) ++ { ++ if (!ChangePair(matches[numPairs - 3], mainDist)) ++ break; ++ numPairs -= 2; ++ mainLen = matches[numPairs - 2]; ++ mainDist = matches[numPairs - 1]; ++ } ++ if (mainLen == 2 && mainDist >= 0x80) ++ mainLen = 1; ++ } ++ ++ if (repLen >= 2 && ( ++ (repLen + 1 >= mainLen) || ++ (repLen + 2 >= mainLen && mainDist >= (1 << 9)) || ++ (repLen + 3 >= mainLen && mainDist >= (1 << 15)))) ++ { ++ *backRes = repIndex; ++ MovePos(p, repLen - 1); ++ return repLen; ++ } ++ ++ if (mainLen < 2 || numAvail <= 2) ++ return 1; ++ ++ p->longestMatchLength = ReadMatchDistances(p, &p->numPairs); ++ if (p->longestMatchLength >= 2) ++ { ++ UInt32 newDistance = matches[p->numPairs - 1]; ++ if ((p->longestMatchLength >= mainLen && newDistance < mainDist) || ++ (p->longestMatchLength == mainLen + 1 && !ChangePair(mainDist, newDistance)) || ++ (p->longestMatchLength > mainLen + 1) || ++ (p->longestMatchLength + 1 >= mainLen && mainLen >= 3 && ChangePair(newDistance, mainDist))) ++ return 1; ++ } ++ ++ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; ++ for (i = 0; i < LZMA_NUM_REPS; i++) ++ { ++ UInt32 len, limit; ++ const Byte *data2 = data - (p->reps[i] + 1); ++ if (data[0] != data2[0] || data[1] != data2[1]) ++ continue; ++ limit = mainLen - 1; ++ for (len = 2; len < limit && data[len] == data2[len]; len++); ++ if (len >= limit) ++ return 1; ++ } ++ *backRes = mainDist + LZMA_NUM_REPS; ++ MovePos(p, mainLen - 2); ++ return mainLen; ++} ++ ++static void WriteEndMarker(CLzmaEnc *p, UInt32 posState) ++{ ++ UInt32 len; ++ RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 1); ++ RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 0); ++ p->state = kMatchNextStates[p->state]; ++ len = LZMA_MATCH_LEN_MIN; ++ LenEnc_Encode2(&p->lenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices); ++ RcTree_Encode(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], kNumPosSlotBits, (1 << kNumPosSlotBits) - 1); ++ RangeEnc_EncodeDirectBits(&p->rc, (((UInt32)1 << 30) - 1) >> kNumAlignBits, 30 - kNumAlignBits); ++ RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, kAlignMask); ++} ++ ++static SRes CheckErrors(CLzmaEnc *p) ++{ ++ if (p->result != SZ_OK) ++ return p->result; ++ if (p->rc.res != SZ_OK) ++ p->result = SZ_ERROR_WRITE; ++ if (p->matchFinderBase.result != SZ_OK) ++ p->result = SZ_ERROR_READ; ++ if (p->result != SZ_OK) ++ p->finished = True; ++ return p->result; ++} ++ ++static SRes Flush(CLzmaEnc *p, UInt32 nowPos) ++{ ++ /* ReleaseMFStream(); */ ++ p->finished = True; ++ if (p->writeEndMark) ++ WriteEndMarker(p, nowPos & p->pbMask); ++ RangeEnc_FlushData(&p->rc); ++ RangeEnc_FlushStream(&p->rc); ++ return CheckErrors(p); ++} ++ ++static void FillAlignPrices(CLzmaEnc *p) ++{ ++ UInt32 i; ++ for (i = 0; i < kAlignTableSize; i++) ++ p->alignPrices[i] = RcTree_ReverseGetPrice(p->posAlignEncoder, kNumAlignBits, i, p->ProbPrices); ++ p->alignPriceCount = 0; ++} ++ ++static void FillDistancesPrices(CLzmaEnc *p) ++{ ++ UInt32 tempPrices[kNumFullDistances]; ++ UInt32 i, lenToPosState; ++ for (i = kStartPosModelIndex; i < kNumFullDistances; i++) ++ { ++ UInt32 posSlot = GetPosSlot1(i); ++ UInt32 footerBits = ((posSlot >> 1) - 1); ++ UInt32 base = ((2 | (posSlot & 1)) << footerBits); ++ tempPrices[i] = RcTree_ReverseGetPrice(p->posEncoders + base - posSlot - 1, footerBits, i - base, p->ProbPrices); ++ } ++ ++ for (lenToPosState = 0; lenToPosState < kNumLenToPosStates; lenToPosState++) ++ { ++ UInt32 posSlot; ++ const CLzmaProb *encoder = p->posSlotEncoder[lenToPosState]; ++ UInt32 *posSlotPrices = p->posSlotPrices[lenToPosState]; ++ for (posSlot = 0; posSlot < p->distTableSize; posSlot++) ++ posSlotPrices[posSlot] = RcTree_GetPrice(encoder, kNumPosSlotBits, posSlot, p->ProbPrices); ++ for (posSlot = kEndPosModelIndex; posSlot < p->distTableSize; posSlot++) ++ posSlotPrices[posSlot] += ((((posSlot >> 1) - 1) - kNumAlignBits) << kNumBitPriceShiftBits); ++ ++ { ++ UInt32 *distancesPrices = p->distancesPrices[lenToPosState]; ++ UInt32 i; ++ for (i = 0; i < kStartPosModelIndex; i++) ++ distancesPrices[i] = posSlotPrices[i]; ++ for (; i < kNumFullDistances; i++) ++ distancesPrices[i] = posSlotPrices[GetPosSlot1(i)] + tempPrices[i]; ++ } ++ } ++ p->matchPriceCount = 0; ++} ++ ++static void LzmaEnc_Construct(CLzmaEnc *p) ++{ ++ RangeEnc_Construct(&p->rc); ++ MatchFinder_Construct(&p->matchFinderBase); ++ #ifndef _7ZIP_ST ++ MatchFinderMt_Construct(&p->matchFinderMt); ++ p->matchFinderMt.MatchFinder = &p->matchFinderBase; ++ #endif ++ ++ { ++ CLzmaEncProps props; ++ LzmaEncProps_Init(&props); ++ LzmaEnc_SetProps(p, &props); ++ } ++ ++ #ifndef LZMA_LOG_BSR ++ LzmaEnc_FastPosInit(p->g_FastPos); ++ #endif ++ ++ LzmaEnc_InitPriceTables(p->ProbPrices); ++ p->litProbs = 0; ++ p->saveState.litProbs = 0; ++} ++ ++CLzmaEncHandle LzmaEnc_Create(ISzAlloc *alloc) ++{ ++ void *p; ++ p = alloc->Alloc(alloc, sizeof(CLzmaEnc)); ++ if (p != 0) ++ LzmaEnc_Construct((CLzmaEnc *)p); ++ return p; ++} ++ ++static void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAlloc *alloc) ++{ ++ alloc->Free(alloc, p->litProbs); ++ alloc->Free(alloc, p->saveState.litProbs); ++ p->litProbs = 0; ++ p->saveState.litProbs = 0; ++} ++ ++static void LzmaEnc_Destruct(CLzmaEnc *p, ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ #ifndef _7ZIP_ST ++ MatchFinderMt_Destruct(&p->matchFinderMt, allocBig); ++ #endif ++ MatchFinder_Free(&p->matchFinderBase, allocBig); ++ LzmaEnc_FreeLits(p, alloc); ++ RangeEnc_Free(&p->rc, alloc); ++} ++ ++void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ LzmaEnc_Destruct((CLzmaEnc *)p, alloc, allocBig); ++ alloc->Free(alloc, p); ++} ++ ++static SRes LzmaEnc_CodeOneBlock(CLzmaEnc *p, Bool useLimits, UInt32 maxPackSize, UInt32 maxUnpackSize) ++{ ++ UInt32 nowPos32, startPos32; ++ if (p->needInit) ++ { ++ p->matchFinder.Init(p->matchFinderObj); ++ p->needInit = 0; ++ } ++ ++ if (p->finished) ++ return p->result; ++ RINOK(CheckErrors(p)); ++ ++ nowPos32 = (UInt32)p->nowPos64; ++ startPos32 = nowPos32; ++ ++ if (p->nowPos64 == 0) ++ { ++ UInt32 numPairs; ++ Byte curByte; ++ if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0) ++ return Flush(p, nowPos32); ++ ReadMatchDistances(p, &numPairs); ++ RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][0], 0); ++ p->state = kLiteralNextStates[p->state]; ++ curByte = p->matchFinder.GetIndexByte(p->matchFinderObj, 0 - p->additionalOffset); ++ LitEnc_Encode(&p->rc, p->litProbs, curByte); ++ p->additionalOffset--; ++ nowPos32++; ++ } ++ ++ if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) != 0) ++ for (;;) ++ { ++ UInt32 pos, len, posState; ++ ++ if (p->fastMode) ++ len = GetOptimumFast(p, &pos); ++ else ++ len = GetOptimum(p, nowPos32, &pos); ++ ++ #ifdef SHOW_STAT2 ++ printf("\n pos = %4X, len = %d pos = %d", nowPos32, len, pos); ++ #endif ++ ++ posState = nowPos32 & p->pbMask; ++ if (len == 1 && pos == (UInt32)-1) ++ { ++ Byte curByte; ++ CLzmaProb *probs; ++ const Byte *data; ++ ++ RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 0); ++ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset; ++ curByte = *data; ++ probs = LIT_PROBS(nowPos32, *(data - 1)); ++ if (IsCharState(p->state)) ++ LitEnc_Encode(&p->rc, probs, curByte); ++ else ++ LitEnc_EncodeMatched(&p->rc, probs, curByte, *(data - p->reps[0] - 1)); ++ p->state = kLiteralNextStates[p->state]; ++ } ++ else ++ { ++ RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 1); ++ if (pos < LZMA_NUM_REPS) ++ { ++ RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 1); ++ if (pos == 0) ++ { ++ RangeEnc_EncodeBit(&p->rc, &p->isRepG0[p->state], 0); ++ RangeEnc_EncodeBit(&p->rc, &p->isRep0Long[p->state][posState], ((len == 1) ? 0 : 1)); ++ } ++ else ++ { ++ UInt32 distance = p->reps[pos]; ++ RangeEnc_EncodeBit(&p->rc, &p->isRepG0[p->state], 1); ++ if (pos == 1) ++ RangeEnc_EncodeBit(&p->rc, &p->isRepG1[p->state], 0); ++ else ++ { ++ RangeEnc_EncodeBit(&p->rc, &p->isRepG1[p->state], 1); ++ RangeEnc_EncodeBit(&p->rc, &p->isRepG2[p->state], pos - 2); ++ if (pos == 3) ++ p->reps[3] = p->reps[2]; ++ p->reps[2] = p->reps[1]; ++ } ++ p->reps[1] = p->reps[0]; ++ p->reps[0] = distance; ++ } ++ if (len == 1) ++ p->state = kShortRepNextStates[p->state]; ++ else ++ { ++ LenEnc_Encode2(&p->repLenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices); ++ p->state = kRepNextStates[p->state]; ++ } ++ } ++ else ++ { ++ UInt32 posSlot; ++ RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 0); ++ p->state = kMatchNextStates[p->state]; ++ LenEnc_Encode2(&p->lenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices); ++ pos -= LZMA_NUM_REPS; ++ GetPosSlot(pos, posSlot); ++ RcTree_Encode(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], kNumPosSlotBits, posSlot); ++ ++ if (posSlot >= kStartPosModelIndex) ++ { ++ UInt32 footerBits = ((posSlot >> 1) - 1); ++ UInt32 base = ((2 | (posSlot & 1)) << footerBits); ++ UInt32 posReduced = pos - base; ++ ++ if (posSlot < kEndPosModelIndex) ++ RcTree_ReverseEncode(&p->rc, p->posEncoders + base - posSlot - 1, footerBits, posReduced); ++ else ++ { ++ RangeEnc_EncodeDirectBits(&p->rc, posReduced >> kNumAlignBits, footerBits - kNumAlignBits); ++ RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, posReduced & kAlignMask); ++ p->alignPriceCount++; ++ } ++ } ++ p->reps[3] = p->reps[2]; ++ p->reps[2] = p->reps[1]; ++ p->reps[1] = p->reps[0]; ++ p->reps[0] = pos; ++ p->matchPriceCount++; ++ } ++ } ++ p->additionalOffset -= len; ++ nowPos32 += len; ++ if (p->additionalOffset == 0) ++ { ++ UInt32 processed; ++ if (!p->fastMode) ++ { ++ if (p->matchPriceCount >= (1 << 7)) ++ FillDistancesPrices(p); ++ if (p->alignPriceCount >= kAlignTableSize) ++ FillAlignPrices(p); ++ } ++ if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0) ++ break; ++ processed = nowPos32 - startPos32; ++ if (useLimits) ++ { ++ if (processed + kNumOpts + 300 >= maxUnpackSize || ++ RangeEnc_GetProcessed(&p->rc) + kNumOpts * 2 >= maxPackSize) ++ break; ++ } ++ else if (processed >= (1 << 15)) ++ { ++ p->nowPos64 += nowPos32 - startPos32; ++ return CheckErrors(p); ++ } ++ } ++ } ++ p->nowPos64 += nowPos32 - startPos32; ++ return Flush(p, nowPos32); ++} ++ ++#define kBigHashDicLimit ((UInt32)1 << 24) ++ ++static SRes LzmaEnc_Alloc(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ UInt32 beforeSize = kNumOpts; ++ Bool btMode; ++ if (!RangeEnc_Alloc(&p->rc, alloc)) ++ return SZ_ERROR_MEM; ++ btMode = (p->matchFinderBase.btMode != 0); ++ #ifndef _7ZIP_ST ++ p->mtMode = (p->multiThread && !p->fastMode && btMode); ++ #endif ++ ++ { ++ unsigned lclp = p->lc + p->lp; ++ if (p->litProbs == 0 || p->saveState.litProbs == 0 || p->lclp != lclp) ++ { ++ LzmaEnc_FreeLits(p, alloc); ++ p->litProbs = (CLzmaProb *)alloc->Alloc(alloc, (0x300 << lclp) * sizeof(CLzmaProb)); ++ p->saveState.litProbs = (CLzmaProb *)alloc->Alloc(alloc, (0x300 << lclp) * sizeof(CLzmaProb)); ++ if (p->litProbs == 0 || p->saveState.litProbs == 0) ++ { ++ LzmaEnc_FreeLits(p, alloc); ++ return SZ_ERROR_MEM; ++ } ++ p->lclp = lclp; ++ } ++ } ++ ++ p->matchFinderBase.bigHash = (p->dictSize > kBigHashDicLimit); ++ ++ if (beforeSize + p->dictSize < keepWindowSize) ++ beforeSize = keepWindowSize - p->dictSize; ++ ++ #ifndef _7ZIP_ST ++ if (p->mtMode) ++ { ++ RINOK(MatchFinderMt_Create(&p->matchFinderMt, p->dictSize, beforeSize, p->numFastBytes, LZMA_MATCH_LEN_MAX, allocBig)); ++ p->matchFinderObj = &p->matchFinderMt; ++ MatchFinderMt_CreateVTable(&p->matchFinderMt, &p->matchFinder); ++ } ++ else ++ #endif ++ { ++ if (!MatchFinder_Create(&p->matchFinderBase, p->dictSize, beforeSize, p->numFastBytes, LZMA_MATCH_LEN_MAX, allocBig)) ++ return SZ_ERROR_MEM; ++ p->matchFinderObj = &p->matchFinderBase; ++ MatchFinder_CreateVTable(&p->matchFinderBase, &p->matchFinder); ++ } ++ return SZ_OK; ++} ++ ++static void LzmaEnc_Init(CLzmaEnc *p) ++{ ++ UInt32 i; ++ p->state = 0; ++ for (i = 0 ; i < LZMA_NUM_REPS; i++) ++ p->reps[i] = 0; ++ ++ RangeEnc_Init(&p->rc); ++ ++ ++ for (i = 0; i < kNumStates; i++) ++ { ++ UInt32 j; ++ for (j = 0; j < LZMA_NUM_PB_STATES_MAX; j++) ++ { ++ p->isMatch[i][j] = kProbInitValue; ++ p->isRep0Long[i][j] = kProbInitValue; ++ } ++ p->isRep[i] = kProbInitValue; ++ p->isRepG0[i] = kProbInitValue; ++ p->isRepG1[i] = kProbInitValue; ++ p->isRepG2[i] = kProbInitValue; ++ } ++ ++ { ++ UInt32 num = 0x300 << (p->lp + p->lc); ++ for (i = 0; i < num; i++) ++ p->litProbs[i] = kProbInitValue; ++ } ++ ++ { ++ for (i = 0; i < kNumLenToPosStates; i++) ++ { ++ CLzmaProb *probs = p->posSlotEncoder[i]; ++ UInt32 j; ++ for (j = 0; j < (1 << kNumPosSlotBits); j++) ++ probs[j] = kProbInitValue; ++ } ++ } ++ { ++ for (i = 0; i < kNumFullDistances - kEndPosModelIndex; i++) ++ p->posEncoders[i] = kProbInitValue; ++ } ++ ++ LenEnc_Init(&p->lenEnc.p); ++ LenEnc_Init(&p->repLenEnc.p); ++ ++ for (i = 0; i < (1 << kNumAlignBits); i++) ++ p->posAlignEncoder[i] = kProbInitValue; ++ ++ p->optimumEndIndex = 0; ++ p->optimumCurrentIndex = 0; ++ p->additionalOffset = 0; ++ ++ p->pbMask = (1 << p->pb) - 1; ++ p->lpMask = (1 << p->lp) - 1; ++} ++ ++static void LzmaEnc_InitPrices(CLzmaEnc *p) ++{ ++ if (!p->fastMode) ++ { ++ FillDistancesPrices(p); ++ FillAlignPrices(p); ++ } ++ ++ p->lenEnc.tableSize = ++ p->repLenEnc.tableSize = ++ p->numFastBytes + 1 - LZMA_MATCH_LEN_MIN; ++ LenPriceEnc_UpdateTables(&p->lenEnc, 1 << p->pb, p->ProbPrices); ++ LenPriceEnc_UpdateTables(&p->repLenEnc, 1 << p->pb, p->ProbPrices); ++} ++ ++static SRes LzmaEnc_AllocAndInit(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ UInt32 i; ++ for (i = 0; i < (UInt32)kDicLogSizeMaxCompress; i++) ++ if (p->dictSize <= ((UInt32)1 << i)) ++ break; ++ p->distTableSize = i * 2; ++ ++ p->finished = False; ++ p->result = SZ_OK; ++ RINOK(LzmaEnc_Alloc(p, keepWindowSize, alloc, allocBig)); ++ LzmaEnc_Init(p); ++ LzmaEnc_InitPrices(p); ++ p->nowPos64 = 0; ++ return SZ_OK; ++} ++ ++static SRes LzmaEnc_Prepare(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ++ ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ CLzmaEnc *p = (CLzmaEnc *)pp; ++ p->matchFinderBase.stream = inStream; ++ p->needInit = 1; ++ p->rc.outStream = outStream; ++ return LzmaEnc_AllocAndInit(p, 0, alloc, allocBig); ++} ++ ++/*SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle pp, ++ ISeqInStream *inStream, UInt32 keepWindowSize, ++ ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ CLzmaEnc *p = (CLzmaEnc *)pp; ++ p->matchFinderBase.stream = inStream; ++ p->needInit = 1; ++ return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig); ++}*/ ++ ++static void LzmaEnc_SetInputBuf(CLzmaEnc *p, const Byte *src, SizeT srcLen) ++{ ++ p->matchFinderBase.directInput = 1; ++ p->matchFinderBase.bufferBase = (Byte *)src; ++ p->matchFinderBase.directInputRem = srcLen; ++} ++ ++static SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen, ++ UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ CLzmaEnc *p = (CLzmaEnc *)pp; ++ LzmaEnc_SetInputBuf(p, src, srcLen); ++ p->needInit = 1; ++ ++ return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig); ++} ++ ++static void LzmaEnc_Finish(CLzmaEncHandle pp) ++{ ++ #ifndef _7ZIP_ST ++ CLzmaEnc *p = (CLzmaEnc *)pp; ++ if (p->mtMode) ++ MatchFinderMt_ReleaseStream(&p->matchFinderMt); ++ #else ++ pp = pp; ++ #endif ++} ++ ++typedef struct ++{ ++ ISeqOutStream funcTable; ++ Byte *data; ++ SizeT rem; ++ Bool overflow; ++} CSeqOutStreamBuf; ++ ++static size_t MyWrite(void *pp, const void *data, size_t size) ++{ ++ CSeqOutStreamBuf *p = (CSeqOutStreamBuf *)pp; ++ if (p->rem < size) ++ { ++ size = p->rem; ++ p->overflow = True; ++ } ++ memcpy(p->data, data, size); ++ p->rem -= size; ++ p->data += size; ++ return size; ++} ++ ++ ++/*UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle pp) ++{ ++ const CLzmaEnc *p = (CLzmaEnc *)pp; ++ return p->matchFinder.GetNumAvailableBytes(p->matchFinderObj); ++}*/ ++ ++/*const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp) ++{ ++ const CLzmaEnc *p = (CLzmaEnc *)pp; ++ return p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset; ++}*/ ++ ++/* SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, Bool reInit, ++ Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize) ++{ ++ CLzmaEnc *p = (CLzmaEnc *)pp; ++ UInt64 nowPos64; ++ SRes res; ++ CSeqOutStreamBuf outStream; ++ ++ outStream.funcTable.Write = MyWrite; ++ outStream.data = dest; ++ outStream.rem = *destLen; ++ outStream.overflow = False; ++ ++ p->writeEndMark = False; ++ p->finished = False; ++ p->result = SZ_OK; ++ ++ if (reInit) ++ LzmaEnc_Init(p); ++ LzmaEnc_InitPrices(p); ++ nowPos64 = p->nowPos64; ++ RangeEnc_Init(&p->rc); ++ p->rc.outStream = &outStream.funcTable; ++ ++ res = LzmaEnc_CodeOneBlock(p, True, desiredPackSize, *unpackSize); ++ ++ *unpackSize = (UInt32)(p->nowPos64 - nowPos64); ++ *destLen -= outStream.rem; ++ if (outStream.overflow) ++ return SZ_ERROR_OUTPUT_EOF; ++ ++ return res; ++}*/ ++ ++static SRes LzmaEnc_Encode2(CLzmaEnc *p, ICompressProgress *progress) ++{ ++ SRes res = SZ_OK; ++ ++ #ifndef _7ZIP_ST ++ Byte allocaDummy[0x300]; ++ int i = 0; ++ for (i = 0; i < 16; i++) ++ allocaDummy[i] = (Byte)i; ++ #endif ++ ++ for (;;) ++ { ++ res = LzmaEnc_CodeOneBlock(p, False, 0, 0); ++ if (res != SZ_OK || p->finished != 0) ++ break; ++ if (progress != 0) ++ { ++ res = progress->Progress(progress, p->nowPos64, RangeEnc_GetProcessed(&p->rc)); ++ if (res != SZ_OK) ++ { ++ res = SZ_ERROR_PROGRESS; ++ break; ++ } ++ } ++ } ++ LzmaEnc_Finish(p); ++ return res; ++} ++ ++SRes LzmaEnc_Encode(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress, ++ ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ RINOK(LzmaEnc_Prepare(pp, outStream, inStream, alloc, allocBig)); ++ return LzmaEnc_Encode2((CLzmaEnc *)pp, progress); ++} ++ ++SRes LzmaEnc_WriteProperties(CLzmaEncHandle pp, Byte *props, SizeT *size) ++{ ++ CLzmaEnc *p = (CLzmaEnc *)pp; ++ int i; ++ UInt32 dictSize = p->dictSize; ++ if (*size < LZMA_PROPS_SIZE) ++ return SZ_ERROR_PARAM; ++ *size = LZMA_PROPS_SIZE; ++ props[0] = (Byte)((p->pb * 5 + p->lp) * 9 + p->lc); ++ ++ for (i = 11; i <= 30; i++) ++ { ++ if (dictSize <= ((UInt32)2 << i)) ++ { ++ dictSize = (2 << i); ++ break; ++ } ++ if (dictSize <= ((UInt32)3 << i)) ++ { ++ dictSize = (3 << i); ++ break; ++ } ++ } ++ ++ for (i = 0; i < 4; i++) ++ props[1 + i] = (Byte)(dictSize >> (8 * i)); ++ return SZ_OK; ++} ++ ++SRes LzmaEnc_MemEncode(CLzmaEncHandle pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, ++ int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ SRes res; ++ CLzmaEnc *p = (CLzmaEnc *)pp; ++ ++ CSeqOutStreamBuf outStream; ++ ++ LzmaEnc_SetInputBuf(p, src, srcLen); ++ ++ outStream.funcTable.Write = MyWrite; ++ outStream.data = dest; ++ outStream.rem = *destLen; ++ outStream.overflow = False; ++ ++ p->writeEndMark = writeEndMark; ++ ++ p->rc.outStream = &outStream.funcTable; ++ res = LzmaEnc_MemPrepare(pp, src, srcLen, 0, alloc, allocBig); ++ if (res == SZ_OK) ++ res = LzmaEnc_Encode2(p, progress); ++ ++ *destLen -= outStream.rem; ++ if (outStream.overflow) ++ return SZ_ERROR_OUTPUT_EOF; ++ return res; ++} ++ ++SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, ++ const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, ++ ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ CLzmaEnc *p = (CLzmaEnc *)LzmaEnc_Create(alloc); ++ SRes res; ++ if (p == 0) ++ return SZ_ERROR_MEM; ++ ++ res = LzmaEnc_SetProps(p, props); ++ if (res == SZ_OK) ++ { ++ res = LzmaEnc_WriteProperties(p, propsEncoded, propsSize); ++ if (res == SZ_OK) ++ res = LzmaEnc_MemEncode(p, dest, destLen, src, srcLen, ++ writeEndMark, progress, alloc, allocBig); ++ } ++ ++ LzmaEnc_Destroy(p, alloc, allocBig); ++ return res; ++} +diff --git a/lib/lzma/Makefile b/lib/lzma/Makefile +new file mode 100644 +index 000000000000..02e799c99381 +--- /dev/null ++++ b/lib/lzma/Makefile +@@ -0,0 +1,7 @@ ++lzma_compress-objs := LzFind.o LzmaEnc.o ++lzma_decompress-objs := LzmaDec.o ++ ++obj-$(CONFIG_LZMA_COMPRESS) += lzma_compress.o ++obj-$(CONFIG_LZMA_DECOMPRESS) += lzma_decompress.o ++ ++EXTRA_CFLAGS += -Iinclude/linux -Iinclude/linux/lzma -include types.h +-- +2.51.0 + + +From 0749420ddd81391f698d65098ee2e56e19f4cf16 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Mon, 3 Nov 2025 15:49:52 +0100 +Subject: [PATCH 253/517] fs: jffs2: EOF marker + +Signed-off-by: Felix Fietkau +--- + fs/jffs2/build.c | 10 ++++++++++ + fs/jffs2/scan.c | 21 +++++++++++++++++++-- + 2 files changed, 29 insertions(+), 2 deletions(-) + +diff --git a/fs/jffs2/build.c b/fs/jffs2/build.c +index 6ae9d6fefb86..d21a7ecec6ee 100644 +--- a/fs/jffs2/build.c ++++ b/fs/jffs2/build.c +@@ -117,6 +117,16 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c) + dbg_fsbuild("scanned flash completely\n"); + jffs2_dbg_dump_block_lists_nolock(c); + ++ if (c->flags & (1 << 7)) { ++ printk("%s(): unlocking the mtd device... ", __func__); ++ mtd_unlock(c->mtd, 0, c->mtd->size); ++ printk("done.\n"); ++ ++ printk("%s(): erasing all blocks after the end marker... ", __func__); ++ jffs2_erase_pending_blocks(c, -1); ++ printk("done.\n"); ++ } ++ + dbg_fsbuild("pass 1 starting\n"); + c->flags |= JFFS2_SB_FLAG_BUILDING; + /* Now scan the directory tree, increasing nlink according to every dirent found. */ +diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c +index 62879c218d4b..cb928d2414ed 100644 +--- a/fs/jffs2/scan.c ++++ b/fs/jffs2/scan.c +@@ -148,8 +148,14 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) + /* reset summary info for next eraseblock scan */ + jffs2_sum_reset_collected(s); + +- ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset), +- buf_size, s); ++ if (c->flags & (1 << 7)) { ++ if (mtd_block_isbad(c->mtd, jeb->offset)) ++ ret = BLK_STATE_BADBLOCK; ++ else ++ ret = BLK_STATE_ALLFF; ++ } else ++ ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset), ++ buf_size, s); + + if (ret < 0) + goto out; +@@ -569,6 +575,17 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo + return err; + } + ++ if ((buf[0] == 0xde) && ++ (buf[1] == 0xad) && ++ (buf[2] == 0xc0) && ++ (buf[3] == 0xde)) { ++ /* end of filesystem. erase everything after this point */ ++ printk("%s(): End of filesystem marker found at 0x%x\n", __func__, jeb->offset); ++ c->flags |= (1 << 7); ++ ++ return BLK_STATE_ALLFF; ++ } ++ + /* We temporarily use 'ofs' as a pointer into the buffer/jeb */ + ofs = 0; + max_ofs = EMPTY_SCAN_SIZE(c->sector_size); +-- +2.51.0 + + +From a62f2a7232e826e000cc8364899b074427f3ca34 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Mon, 3 Nov 2025 15:49:52 +0100 +Subject: [PATCH 254/517] netfilter: add support for flushing conntrack via + /proc + +lede-commit 8193bbe59a74d34d6a26d4a8cb857b1952905314 +Signed-off-by: Felix Fietkau +--- + net/netfilter/nf_conntrack_standalone.c | 58 ++++++++++++++++++++++++- + 1 file changed, 56 insertions(+), 2 deletions(-) + +diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c +index 3ea60ff7a6a4..39fd99016360 100644 +--- a/net/netfilter/nf_conntrack_standalone.c ++++ b/net/netfilter/nf_conntrack_standalone.c +@@ -9,6 +9,7 @@ + #include + #include + #include ++#include + #include + #ifdef CONFIG_SYSCTL + #include +@@ -458,6 +459,58 @@ static int ct_cpu_seq_show(struct seq_file *seq, void *v) + return 0; + } + ++struct kill_request { ++ u16 family; ++ union nf_inet_addr addr; ++}; ++ ++static int kill_matching(struct nf_conn *i, void *data) ++{ ++ struct kill_request *kr = data; ++ struct nf_conntrack_tuple *t1 = &i->tuplehash[IP_CT_DIR_ORIGINAL].tuple; ++ struct nf_conntrack_tuple *t2 = &i->tuplehash[IP_CT_DIR_REPLY].tuple; ++ ++ if (!kr->family) ++ return 1; ++ ++ if (t1->src.l3num != kr->family) ++ return 0; ++ ++ return (nf_inet_addr_cmp(&kr->addr, &t1->src.u3) || ++ nf_inet_addr_cmp(&kr->addr, &t1->dst.u3) || ++ nf_inet_addr_cmp(&kr->addr, &t2->src.u3) || ++ nf_inet_addr_cmp(&kr->addr, &t2->dst.u3)); ++} ++ ++static int ct_file_write(struct file *file, char *buf, size_t count) ++{ ++ struct seq_file *seq = file->private_data; ++ struct nf_ct_iter_data iter_data; ++ struct kill_request kr = { }; ++ ++ if (count == 0) ++ return 0; ++ ++ if (count >= INET6_ADDRSTRLEN) ++ count = INET6_ADDRSTRLEN - 1; ++ ++ if (strnchr(buf, count, ':')) { ++ kr.family = AF_INET6; ++ if (!in6_pton(buf, count, (void *)&kr.addr, '\n', NULL)) ++ return -EINVAL; ++ } else if (strnchr(buf, count, '.')) { ++ kr.family = AF_INET; ++ if (!in4_pton(buf, count, (void *)&kr.addr, '\n', NULL)) ++ return -EINVAL; ++ } ++ ++ iter_data.net = seq_file_net(seq); ++ iter_data.data = &kr; ++ nf_ct_iterate_cleanup_net(kill_matching, &iter_data); ++ ++ return 0; ++} ++ + static const struct seq_operations ct_cpu_seq_ops = { + .start = ct_cpu_seq_start, + .next = ct_cpu_seq_next, +@@ -471,8 +524,9 @@ static int nf_conntrack_standalone_init_proc(struct net *net) + kuid_t root_uid; + kgid_t root_gid; + +- pde = proc_create_net("nf_conntrack", 0440, net->proc_net, &ct_seq_ops, +- sizeof(struct ct_iter_state)); ++ pde = proc_create_net_data_write("nf_conntrack", 0440, net->proc_net, ++ &ct_seq_ops, &ct_file_write, ++ sizeof(struct ct_iter_state), NULL); + if (!pde) + goto out_nf_conntrack; + +-- +2.51.0 + + +From 92d7c8f5e0513a7b12c993c38792ba7edc72dee9 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Mon, 3 Nov 2025 15:49:53 +0100 +Subject: [PATCH 255/517] kernel: add a new version of my netfilter speedup + patches for linux 2.6.39 and 3.0 + +Signed-off-by: Felix Fietkau +--- + include/uapi/linux/netfilter_ipv4/ip_tables.h | 1 + + net/ipv4/netfilter/ip_tables.c | 42 ++++++++++++++++++- + 2 files changed, 42 insertions(+), 1 deletion(-) + +diff --git a/include/uapi/linux/netfilter_ipv4/ip_tables.h b/include/uapi/linux/netfilter_ipv4/ip_tables.h +index 1485df28b239..250350c37ef5 100644 +--- a/include/uapi/linux/netfilter_ipv4/ip_tables.h ++++ b/include/uapi/linux/netfilter_ipv4/ip_tables.h +@@ -89,6 +89,7 @@ struct ipt_ip { + #define IPT_F_FRAG 0x01 /* Set if rule is a fragment rule */ + #define IPT_F_GOTO 0x02 /* Set if jump is a goto */ + #define IPT_F_MASK 0x03 /* All possible flag bits mask. */ ++#define IPT_F_NO_DEF_MATCH 0x80 /* Internal: no default match rules present */ + + /* Values for "inv" field in struct ipt_ip. */ + #define IPT_INV_VIA_IN 0x01 /* Invert the sense of IN IFACE. */ +diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c +index 3d101613f27f..43ee82554011 100644 +--- a/net/ipv4/netfilter/ip_tables.c ++++ b/net/ipv4/netfilter/ip_tables.c +@@ -48,6 +48,9 @@ ip_packet_match(const struct iphdr *ip, + { + unsigned long ret; + ++ if (ipinfo->flags & IPT_F_NO_DEF_MATCH) ++ return true; ++ + if (NF_INVF(ipinfo, IPT_INV_SRCIP, + (ip->saddr & ipinfo->smsk.s_addr) != ipinfo->src.s_addr) || + NF_INVF(ipinfo, IPT_INV_DSTIP, +@@ -78,6 +81,29 @@ ip_packet_match(const struct iphdr *ip, + return true; + } + ++static void ++ip_checkdefault(struct ipt_ip *ip) ++{ ++ static const char iface_mask[IFNAMSIZ] = {}; ++ ++ if (ip->invflags || ip->flags & IPT_F_FRAG) ++ return; ++ ++ if (memcmp(ip->iniface_mask, iface_mask, IFNAMSIZ) != 0) ++ return; ++ ++ if (memcmp(ip->outiface_mask, iface_mask, IFNAMSIZ) != 0) ++ return; ++ ++ if (ip->smsk.s_addr || ip->dmsk.s_addr) ++ return; ++ ++ if (ip->proto) ++ return; ++ ++ ip->flags |= IPT_F_NO_DEF_MATCH; ++} ++ + static bool + ip_checkentry(const struct ipt_ip *ip) + { +@@ -523,6 +549,8 @@ find_check_entry(struct ipt_entry *e, struct net *net, const char *name, + struct xt_mtchk_param mtpar; + struct xt_entry_match *ematch; + ++ ip_checkdefault(&e->ip); ++ + if (!xt_percpu_counter_alloc(alloc_state, &e->counters)) + return -ENOMEM; + +@@ -817,6 +845,7 @@ copy_entries_to_user(unsigned int total_size, + const struct xt_table_info *private = table->private; + int ret = 0; + const void *loc_cpu_entry; ++ u8 flags; + + counters = alloc_counters(table); + if (IS_ERR(counters)) +@@ -844,6 +873,14 @@ copy_entries_to_user(unsigned int total_size, + goto free_counters; + } + ++ flags = e->ip.flags & IPT_F_MASK; ++ if (copy_to_user(userptr + off ++ + offsetof(struct ipt_entry, ip.flags), ++ &flags, sizeof(flags)) != 0) { ++ ret = -EFAULT; ++ goto free_counters; ++ } ++ + for (i = sizeof(struct ipt_entry); + i < e->target_offset; + i += m->u.match_size) { +@@ -1225,12 +1262,15 @@ compat_copy_entry_to_user(struct ipt_entry *e, void __user **dstptr, + compat_uint_t origsize; + const struct xt_entry_match *ematch; + int ret = 0; ++ u8 flags = e->ip.flags & IPT_F_MASK; + + origsize = *size; + ce = *dstptr; + if (copy_to_user(ce, e, sizeof(struct ipt_entry)) != 0 || + copy_to_user(&ce->counters, &counters[i], +- sizeof(counters[i])) != 0) ++ sizeof(counters[i])) != 0 || ++ copy_to_user(&ce->ip.flags, &flags, ++ sizeof(flags)) != 0) + return -EFAULT; + + *dstptr += sizeof(struct compat_ipt_entry); +-- +2.51.0 + + +From 12cf7d07371762ca70888fb3b9511a3250211a88 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Mon, 3 Nov 2025 15:49:53 +0100 +Subject: [PATCH 256/517] netfilter: match bypass default table + +Signed-off-by: Felix Fietkau +--- + net/ipv4/netfilter/ip_tables.c | 69 ++++++++++++++++++++++++++-------- + 1 file changed, 53 insertions(+), 16 deletions(-) + +diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c +index 43ee82554011..8325e81b9827 100644 +--- a/net/ipv4/netfilter/ip_tables.c ++++ b/net/ipv4/netfilter/ip_tables.c +@@ -244,6 +244,33 @@ struct ipt_entry *ipt_next_entry(const struct ipt_entry *entry) + return (void *)entry + entry->next_offset; + } + ++static bool ++ipt_handle_default_rule(struct ipt_entry *e, unsigned int *verdict) ++{ ++ struct xt_entry_target *t; ++ struct xt_standard_target *st; ++ ++ if (e->target_offset != sizeof(struct ipt_entry)) ++ return false; ++ ++ if (!(e->ip.flags & IPT_F_NO_DEF_MATCH)) ++ return false; ++ ++ t = ipt_get_target(e); ++ if (t->u.kernel.target->target) ++ return false; ++ ++ st = (struct xt_standard_target *) t; ++ if (st->verdict == XT_RETURN) ++ return false; ++ ++ if (st->verdict >= 0) ++ return false; ++ ++ *verdict = (unsigned)(-st->verdict) - 1; ++ return true; ++} ++ + /* Returns one of the generic firewall policies, like NF_ACCEPT. */ + unsigned int + ipt_do_table(void *priv, +@@ -265,27 +292,28 @@ ipt_do_table(void *priv, + unsigned int addend; + + /* Initialization */ ++ WARN_ON(!(table->valid_hooks & (1 << hook))); ++ local_bh_disable(); ++ private = READ_ONCE(table->private); /* Address dependency. */ ++ cpu = smp_processor_id(); ++ table_base = private->entries; ++ ++ e = get_entry(table_base, private->hook_entry[hook]); ++ if (ipt_handle_default_rule(e, &verdict)) { ++ struct xt_counters *counter; ++ ++ counter = xt_get_this_cpu_counter(&e->counters); ++ ADD_COUNTER(*counter, skb->len, 1); ++ local_bh_enable(); ++ return verdict; ++ } ++ + stackidx = 0; + ip = ip_hdr(skb); + indev = state->in ? state->in->name : nulldevname; + outdev = state->out ? state->out->name : nulldevname; +- /* We handle fragments by dealing with the first fragment as +- * if it was a normal packet. All other fragments are treated +- * normally, except that they will NEVER match rules that ask +- * things we don't know, ie. tcp syn flag or ports). If the +- * rule is also a fragment-specific rule, non-fragments won't +- * match it. */ +- acpar.fragoff = ntohs(ip->frag_off) & IP_OFFSET; +- acpar.thoff = ip_hdrlen(skb); +- acpar.hotdrop = false; +- acpar.state = state; + +- WARN_ON(!(table->valid_hooks & (1 << hook))); +- local_bh_disable(); + addend = xt_write_recseq_begin(); +- private = READ_ONCE(table->private); /* Address dependency. */ +- cpu = smp_processor_id(); +- table_base = private->entries; + jumpstack = (struct ipt_entry **)private->jumpstack[cpu]; + + /* Switch to alternate jumpstack if we're being invoked via TEE. +@@ -298,7 +326,16 @@ ipt_do_table(void *priv, + if (static_key_false(&xt_tee_enabled)) + jumpstack += private->stacksize * __this_cpu_read(nf_skb_duplicated); + +- e = get_entry(table_base, private->hook_entry[hook]); ++ /* We handle fragments by dealing with the first fragment as ++ * if it was a normal packet. All other fragments are treated ++ * normally, except that they will NEVER match rules that ask ++ * things we don't know, ie. tcp syn flag or ports). If the ++ * rule is also a fragment-specific rule, non-fragments won't ++ * match it. */ ++ acpar.fragoff = ntohs(ip->frag_off) & IP_OFFSET; ++ acpar.thoff = ip_hdrlen(skb); ++ acpar.hotdrop = false; ++ acpar.state = state; + + do { + const struct xt_entry_target *t; +-- +2.51.0 + + +From 34ea6fee7df6d495f35ff6fd7045b334c50325ba Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Mon, 3 Nov 2025 15:49:53 +0100 +Subject: [PATCH 257/517] netfilter: reduce match memory access + +Signed-off-by: Felix Fietkau +--- + net/ipv4/netfilter/ip_tables.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c +index 8325e81b9827..d03e2121810b 100644 +--- a/net/ipv4/netfilter/ip_tables.c ++++ b/net/ipv4/netfilter/ip_tables.c +@@ -51,9 +51,9 @@ ip_packet_match(const struct iphdr *ip, + if (ipinfo->flags & IPT_F_NO_DEF_MATCH) + return true; + +- if (NF_INVF(ipinfo, IPT_INV_SRCIP, ++ if (NF_INVF(ipinfo, IPT_INV_SRCIP, ipinfo->smsk.s_addr && + (ip->saddr & ipinfo->smsk.s_addr) != ipinfo->src.s_addr) || +- NF_INVF(ipinfo, IPT_INV_DSTIP, ++ NF_INVF(ipinfo, IPT_INV_DSTIP, ipinfo->dmsk.s_addr && + (ip->daddr & ipinfo->dmsk.s_addr) != ipinfo->dst.s_addr)) + return false; + +-- +2.51.0 + + +From db287f2364f5f532223610146e83950c43e89a11 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Mon, 3 Nov 2025 15:49:53 +0100 +Subject: [PATCH 258/517] net: add an optimization for dealing with raw sockets + +lede-commit: 4898039703d7315f0f3431c860123338ec3be0f6 +Signed-off-by: Felix Fietkau +--- + include/uapi/linux/if_packet.h | 3 +++ + net/packet/af_packet.c | 34 +++++++++++++++++++++++++++------- + net/packet/internal.h | 1 + + 3 files changed, 31 insertions(+), 7 deletions(-) + +diff --git a/include/uapi/linux/if_packet.h b/include/uapi/linux/if_packet.h +index 1d2718dd9647..a52deea9d653 100644 +--- a/include/uapi/linux/if_packet.h ++++ b/include/uapi/linux/if_packet.h +@@ -33,6 +33,8 @@ struct sockaddr_ll { + #define PACKET_KERNEL 7 /* To kernel space */ + /* Unused, PACKET_FASTROUTE and PACKET_LOOPBACK are invisible to user space */ + #define PACKET_FASTROUTE 6 /* Fastrouted frame */ ++#define PACKET_MASK_ANY 0xffffffff /* mask for packet type bits */ ++ + + /* Packet socket options */ + +@@ -60,6 +62,7 @@ struct sockaddr_ll { + #define PACKET_FANOUT_DATA 22 + #define PACKET_IGNORE_OUTGOING 23 + #define PACKET_VNET_HDR_SZ 24 ++#define PACKET_RECV_TYPE 25 + + #define PACKET_FANOUT_HASH 0 + #define PACKET_FANOUT_LB 1 +diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c +index e8589fede4d4..e2c5b44c0e60 100644 +--- a/net/packet/af_packet.c ++++ b/net/packet/af_packet.c +@@ -1911,6 +1911,7 @@ static int packet_rcv_spkt(struct sk_buff *skb, struct net_device *dev, + { + struct sock *sk; + struct sockaddr_pkt *spkt; ++ struct packet_sock *po; + + /* + * When we registered the protocol we saved the socket in the data +@@ -1918,6 +1919,7 @@ static int packet_rcv_spkt(struct sk_buff *skb, struct net_device *dev, + */ + + sk = pt->af_packet_priv; ++ po = pkt_sk(sk); + + /* + * Yank back the headers [hope the device set this +@@ -1930,7 +1932,7 @@ static int packet_rcv_spkt(struct sk_buff *skb, struct net_device *dev, + * so that this procedure is noop. + */ + +- if (skb->pkt_type == PACKET_LOOPBACK) ++ if (!(po->pkt_type & (1 << skb->pkt_type))) + goto out; + + if (!net_eq(dev_net(dev), sock_net(sk))) +@@ -2175,12 +2177,12 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, + int skb_len = skb->len; + unsigned int snaplen, res; + +- if (skb->pkt_type == PACKET_LOOPBACK) +- goto drop; +- + sk = pt->af_packet_priv; + po = pkt_sk(sk); + ++ if (!(po->pkt_type & (1 << skb->pkt_type))) ++ goto drop; ++ + if (!net_eq(dev_net(dev), sock_net(sk))) + goto drop; + +@@ -2304,12 +2306,12 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, + BUILD_BUG_ON(TPACKET_ALIGN(sizeof(*h.h2)) != 32); + BUILD_BUG_ON(TPACKET_ALIGN(sizeof(*h.h3)) != 48); + +- if (skb->pkt_type == PACKET_LOOPBACK) +- goto drop; +- + sk = pt->af_packet_priv; + po = pkt_sk(sk); + ++ if (!(po->pkt_type & (1 << skb->pkt_type))) ++ goto drop; ++ + if (!net_eq(dev_net(dev), sock_net(sk))) + goto drop; + +@@ -3429,6 +3431,7 @@ static int packet_create(struct net *net, struct socket *sock, int protocol, + mutex_init(&po->pg_vec_lock); + po->rollover = NULL; + po->prot_hook.func = packet_rcv; ++ po->pkt_type = PACKET_MASK_ANY & ~(1 << PACKET_LOOPBACK); + + if (sock->type == SOCK_PACKET) + po->prot_hook.func = packet_rcv_spkt; +@@ -4096,6 +4099,16 @@ packet_setsockopt(struct socket *sock, int level, int optname, sockptr_t optval, + packet_sock_flag_set(po, PACKET_SOCK_QDISC_BYPASS, val); + return 0; + } ++ case PACKET_RECV_TYPE: ++ { ++ unsigned int val; ++ if (optlen != sizeof(val)) ++ return -EINVAL; ++ if (copy_from_sockptr(&val, optval, sizeof(val))) ++ return -EFAULT; ++ po->pkt_type = val & ~BIT(PACKET_LOOPBACK); ++ return 0; ++ } + default: + return -ENOPROTOOPT; + } +@@ -4158,6 +4171,13 @@ static int packet_getsockopt(struct socket *sock, int level, int optname, + case PACKET_COPY_THRESH: + val = READ_ONCE(pkt_sk(sk)->copy_thresh); + break; ++ case PACKET_RECV_TYPE: ++ if (len > sizeof(unsigned int)) ++ len = sizeof(unsigned int); ++ val = po->pkt_type; ++ ++ data = &val; ++ break; + case PACKET_VERSION: + val = po->tp_version; + break; +diff --git a/net/packet/internal.h b/net/packet/internal.h +index d5d70712007a..891df18a6947 100644 +--- a/net/packet/internal.h ++++ b/net/packet/internal.h +@@ -131,6 +131,7 @@ struct packet_sock { + struct net_device __rcu *cached_dev; + struct packet_type prot_hook ____cacheline_aligned_in_smp; + atomic_t tp_drops ____cacheline_aligned_in_smp; ++ unsigned int pkt_type; + }; + + #define pkt_sk(ptr) container_of_const(ptr, struct packet_sock, sk) +-- +2.51.0 + + +From d187d050110d76efe46d7d7eb669a335ec25e330 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Thu, 22 Aug 2024 18:02:17 +0200 +Subject: [PATCH 259/517] net: bridge: fix switchdev host mdb entry updates + +When a mdb entry is removed, the bridge switchdev code can issue a +switchdev_port_obj_del call for a port that was not offloaded. + +This leads to an imbalance in switchdev_port_obj_add/del calls, since +br_switchdev_mdb_replay has not been called for the port before. + +This can lead to potential multicast forwarding issues and messages such as: +mt7915e 0000:01:00.0 wl1-ap0: Failed to del Host Multicast Database entry + (object id=3) with error: -ENOENT (-2). + +Fix this issue by checking the port offload status when iterating over +lower devs. + +Signed-off-by: Felix Fietkau +--- + net/bridge/br_switchdev.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/net/bridge/br_switchdev.c b/net/bridge/br_switchdev.c +index f10bd6a233dc..6dffac613768 100644 +--- a/net/bridge/br_switchdev.c ++++ b/net/bridge/br_switchdev.c +@@ -571,10 +571,18 @@ static void br_switchdev_host_mdb(struct net_device *dev, + struct net_bridge_mdb_entry *mp, int type) + { + struct net_device *lower_dev; ++ struct net_bridge_port *port; + struct list_head *iter; + +- netdev_for_each_lower_dev(dev, lower_dev, iter) ++ rcu_read_lock(); ++ netdev_for_each_lower_dev(dev, lower_dev, iter) { ++ port = br_port_get_rcu(lower_dev); ++ if (!port || !port->offload_count) ++ continue; ++ + br_switchdev_host_mdb_one(dev, lower_dev, mp, type); ++ } ++ rcu_read_unlock(); + } + + static int +-- +2.51.0 + + +From ee69dd931652725a53e666564b5e9f405be3a770 Mon Sep 17 00:00:00 2001 +From: "Leon M. Busch-George" +Date: Sun, 20 Oct 2024 18:20:14 +0200 +Subject: [PATCH 260/517] net: bridge: switchdev: Don't drop packets between + ports with no hwdom + +nbp_switchdev_allowed_egress uses hwdom to determine whether or not a +packet has already been forwarded to a hardware domain. For +net_bridge_ports that aren't set up to use forward offloading, hwdom is +set to 0. When both ingress and egress port have no hwdom, +'cb->src_hwdom != p->hwdom' indicates that the packet is already known in +the target domain - which it isn't - and the packet is wrongly dropped. + +The error was found on a bridge containing a wifi device and a VLAN +tagging device (e.g. eth0.12). With VLAN filtering, this shouldn't happen. + +This patch adds a check for p->hwdom != 0 before comparing hardware +domains to restore forwarding between ports with hwdom = 0. + +fwd_hwdoms are only set for ports with offloading enabled, which also +implies a valid hwdom, so the check '!test_bit(p->hwdom, &cb->fwd_hwdoms)' +doesn't fail in this way (yet - fingers crossed..) and it is left in place. + +Co-developed-by: Felix Fietkau +Signed-off-by: Felix Fietkau +Signed-off-by: Leon M. Busch-George +--- + net/bridge/br_switchdev.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/bridge/br_switchdev.c b/net/bridge/br_switchdev.c +index 6dffac613768..98ef0642dda4 100644 +--- a/net/bridge/br_switchdev.c ++++ b/net/bridge/br_switchdev.c +@@ -70,7 +70,7 @@ bool nbp_switchdev_allowed_egress(const struct net_bridge_port *p, + struct br_input_skb_cb *cb = BR_INPUT_SKB_CB(skb); + + return !test_bit(p->hwdom, &cb->fwd_hwdoms) && +- (!skb->offload_fwd_mark || cb->src_hwdom != p->hwdom); ++ (!skb->offload_fwd_mark || !p->hwdom || cb->src_hwdom != p->hwdom); + } + + /* Flags that can be offloaded to hardware */ +-- +2.51.0 + + +From c2a69cffa26902e6c10ea558dd5d6dc305f1dd48 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Tue, 15 Jul 2025 12:37:45 +0200 +Subject: [PATCH 261/517] net: pppoe: implement GRO support + +Only handles packets where the pppoe header length field matches the exact +packet length. Significantly improves rx throughput. + +When running NAT traffic through a MediaTek MT7621 devices from a host +behind PPPoE to a host directly connected via ethernet, the TCP throughput +that the device is able to handle improves from ~130 Mbit/s to ~630 Mbit/s, +using fraglist GRO. + +Signed-off-by: Felix Fietkau +--- + drivers/net/ppp/pppoe.c | 160 +++++++++++++++++++++++++++++++++++++++- + net/ipv4/af_inet.c | 2 + + net/ipv6/ip6_offload.c | 2 + + 3 files changed, 163 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c +index 68e631718ab0..3d145fb7a6ab 100644 +--- a/drivers/net/ppp/pppoe.c ++++ b/drivers/net/ppp/pppoe.c +@@ -77,6 +77,7 @@ + #include + #include + #include ++#include + + #include + +@@ -435,7 +436,7 @@ static int pppoe_rcv(struct sk_buff *skb, struct net_device *dev, + if (skb->len < len) + goto drop; + +- if (pskb_trim_rcsum(skb, len)) ++ if (!skb_is_gso(skb) && pskb_trim_rcsum(skb, len)) + goto drop; + + ph = pppoe_hdr(skb); +@@ -1173,6 +1174,161 @@ static struct pernet_operations pppoe_net_ops = { + .size = sizeof(struct pppoe_net), + }; + ++static u16 ++compare_pppoe_header(struct pppoe_hdr *phdr, struct pppoe_hdr *phdr2) ++{ ++ return (__force __u16)((phdr->sid ^ phdr2->sid) | ++ (phdr->tag[0].tag_type ^ phdr2->tag[0].tag_type)); ++} ++ ++static __be16 pppoe_hdr_proto(struct pppoe_hdr *phdr) ++{ ++ switch (phdr->tag[0].tag_type) { ++ case cpu_to_be16(PPP_IP): ++ return cpu_to_be16(ETH_P_IP); ++ case cpu_to_be16(PPP_IPV6): ++ return cpu_to_be16(ETH_P_IPV6); ++ default: ++ return 0; ++ } ++ ++} ++ ++static struct sk_buff *pppoe_gro_receive(struct list_head *head, ++ struct sk_buff *skb) ++{ ++ const struct packet_offload *ptype; ++ unsigned int hlen, off_pppoe; ++ struct sk_buff *pp = NULL; ++ struct pppoe_hdr *phdr; ++ struct sk_buff *p; ++ int flush = 1; ++ __be16 type; ++ ++ off_pppoe = skb_gro_offset(skb); ++ hlen = off_pppoe + sizeof(*phdr); ++ phdr = skb_gro_header(skb, hlen + 2, off_pppoe); ++ if (unlikely(!phdr)) ++ goto out; ++ ++ /* ignore packets with padding or invalid length */ ++ if (skb_gro_len(skb) != be16_to_cpu(phdr->length) + hlen) ++ goto out; ++ ++ type = pppoe_hdr_proto(phdr); ++ if (!type) ++ goto out; ++ ++ ptype = gro_find_receive_by_type(type); ++ if (!ptype) ++ goto out; ++ ++ flush = 0; ++ ++ list_for_each_entry(p, head, list) { ++ struct pppoe_hdr *phdr2; ++ ++ if (!NAPI_GRO_CB(p)->same_flow) ++ continue; ++ ++ phdr2 = (struct pppoe_hdr *)(p->data + off_pppoe); ++ if (compare_pppoe_header(phdr, phdr2)) ++ NAPI_GRO_CB(p)->same_flow = 0; ++ } ++ ++ skb_gro_pull(skb, sizeof(*phdr) + 2); ++ skb_gro_postpull_rcsum(skb, phdr, sizeof(*phdr) + 2); ++ ++ pp = indirect_call_gro_receive_inet(ptype->callbacks.gro_receive, ++ ipv6_gro_receive, inet_gro_receive, ++ head, skb); ++ ++out: ++ skb_gro_flush_final(skb, pp, flush); ++ ++ return pp; ++} ++ ++static int pppoe_gro_complete(struct sk_buff *skb, int nhoff) ++{ ++ struct pppoe_hdr *phdr = (struct pppoe_hdr *)(skb->data + nhoff); ++ __be16 type = pppoe_hdr_proto(phdr); ++ struct packet_offload *ptype; ++ int len, err; ++ ++ ptype = gro_find_complete_by_type(type); ++ if (!ptype) ++ return -ENOENT; ++ ++ err = INDIRECT_CALL_INET(ptype->callbacks.gro_complete, ++ ipv6_gro_complete, inet_gro_complete, ++ skb, nhoff + sizeof(*phdr) + 2); ++ if (err) ++ return err; ++ ++ len = skb->len - (nhoff + sizeof(*phdr)); ++ phdr->length = cpu_to_be16(len); ++ ++ return 0; ++} ++ ++static struct sk_buff *pppoe_gso_segment(struct sk_buff *skb, ++ netdev_features_t features) ++{ ++ unsigned int pppoe_hlen = sizeof(struct pppoe_hdr) + 2; ++ struct sk_buff *segs = ERR_PTR(-EINVAL); ++ u16 mac_offset = skb->mac_header; ++ struct packet_offload *ptype; ++ u16 mac_len = skb->mac_len; ++ struct pppoe_hdr *phdr; ++ __be16 orig_type, type; ++ int len, nhoff; ++ ++ skb_reset_network_header(skb); ++ nhoff = skb_network_header(skb) - skb_mac_header(skb); ++ ++ if (unlikely(!pskb_may_pull(skb, pppoe_hlen))) ++ goto out; ++ ++ phdr = (struct pppoe_hdr *)skb_network_header(skb); ++ type = pppoe_hdr_proto(phdr); ++ ptype = gro_find_complete_by_type(type); ++ if (!ptype) ++ goto out; ++ ++ orig_type = skb->protocol; ++ __skb_pull(skb, pppoe_hlen); ++ segs = ptype->callbacks.gso_segment(skb, features); ++ if (IS_ERR_OR_NULL(segs)) { ++ skb_gso_error_unwind(skb, orig_type, pppoe_hlen, mac_offset, ++ mac_len); ++ goto out; ++ } ++ ++ skb = segs; ++ do { ++ phdr = (struct pppoe_hdr *)(skb_mac_header(skb) + nhoff); ++ len = skb->len - (nhoff + sizeof(*phdr)); ++ phdr->length = cpu_to_be16(len); ++ skb->network_header = (u8 *)phdr - skb->head; ++ skb->protocol = orig_type; ++ skb_reset_mac_len(skb); ++ } while ((skb = skb->next)); ++ ++out: ++ return segs; ++} ++ ++static struct packet_offload pppoe_packet_offload __read_mostly = { ++ .type = cpu_to_be16(ETH_P_PPP_SES), ++ .priority = 20, ++ .callbacks = { ++ .gro_receive = pppoe_gro_receive, ++ .gro_complete = pppoe_gro_complete, ++ .gso_segment = pppoe_gso_segment, ++ }, ++}; ++ + static int __init pppoe_init(void) + { + int err; +@@ -1189,6 +1345,7 @@ static int __init pppoe_init(void) + if (err) + goto out_unregister_pppoe_proto; + ++ dev_add_offload(&pppoe_packet_offload); + dev_add_pack(&pppoes_ptype); + dev_add_pack(&pppoed_ptype); + register_netdevice_notifier(&pppoe_notifier); +@@ -1208,6 +1365,7 @@ static void __exit pppoe_exit(void) + unregister_netdevice_notifier(&pppoe_notifier); + dev_remove_pack(&pppoed_ptype); + dev_remove_pack(&pppoes_ptype); ++ dev_remove_offload(&pppoe_packet_offload); + unregister_pppox_proto(PX_PROTO_OE); + proto_unregister(&pppoe_sk_proto); + unregister_pernet_device(&pppoe_net_ops); +diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c +index 8095e82de808..a1a7d91c42f6 100644 +--- a/net/ipv4/af_inet.c ++++ b/net/ipv4/af_inet.c +@@ -1546,6 +1546,7 @@ struct sk_buff *inet_gro_receive(struct list_head *head, struct sk_buff *skb) + + return pp; + } ++EXPORT_INDIRECT_CALLABLE(inet_gro_receive); + + static struct sk_buff *ipip_gro_receive(struct list_head *head, + struct sk_buff *skb) +@@ -1631,6 +1632,7 @@ int inet_gro_complete(struct sk_buff *skb, int nhoff) + out: + return err; + } ++EXPORT_INDIRECT_CALLABLE(inet_gro_complete); + + static int ipip_gro_complete(struct sk_buff *skb, int nhoff) + { +diff --git a/net/ipv6/ip6_offload.c b/net/ipv6/ip6_offload.c +index fce91183797a..9e3640b018a4 100644 +--- a/net/ipv6/ip6_offload.c ++++ b/net/ipv6/ip6_offload.c +@@ -306,6 +306,7 @@ INDIRECT_CALLABLE_SCOPE struct sk_buff *ipv6_gro_receive(struct list_head *head, + + return pp; + } ++EXPORT_INDIRECT_CALLABLE(ipv6_gro_receive); + + static struct sk_buff *sit_ip6ip6_gro_receive(struct list_head *head, + struct sk_buff *skb) +@@ -388,6 +389,7 @@ INDIRECT_CALLABLE_SCOPE int ipv6_gro_complete(struct sk_buff *skb, int nhoff) + out: + return err; + } ++EXPORT_INDIRECT_CALLABLE(ipv6_gro_complete); + + static int sit_gro_complete(struct sk_buff *skb, int nhoff) + { +-- +2.51.0 + + +From 2e462085b5c2cff943dd6a5620e0f541be7acaeb Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Mon, 3 Nov 2025 15:49:54 +0100 +Subject: [PATCH 262/517] kernel: add a few patches for avoiding unnecessary + skb reallocations - significantly improves ethernet<->wireless performance + +lede-commit: 6f89cffc9add6939d44a6b54cf9a5e77849aa7fd +Signed-off-by: Felix Fietkau +--- + include/linux/skbuff.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h +index 314328ab0b84..eb7b94939f46 100644 +--- a/include/linux/skbuff.h ++++ b/include/linux/skbuff.h +@@ -3209,7 +3209,7 @@ static inline int pskb_network_may_pull(struct sk_buff *skb, unsigned int len) + * NET_IP_ALIGN(2) + ethernet_header(14) + IP_header(20/40) + ports(8) + */ + #ifndef NET_SKB_PAD +-#define NET_SKB_PAD max(32, L1_CACHE_BYTES) ++#define NET_SKB_PAD max(64, L1_CACHE_BYTES) + #endif + + int ___pskb_trim(struct sk_buff *skb, unsigned int len); +-- +2.51.0 + + +From 7c39dc46af4ecff37c87b8ed7e9061f44e1401ce Mon Sep 17 00:00:00 2001 +From: Steven Barth +Date: Mon, 3 Nov 2025 15:49:55 +0100 +Subject: [PATCH 263/517] Add support for MAP-E FMRs (mesh mode) + +MAP-E FMRs (draft-ietf-softwire-map-10) are rules for IPv4-communication +between MAP CEs (mesh mode) without the need to forward such data to a +border relay. This is similar to how 6rd works but for IPv4 over IPv6. + +Signed-off-by: Steven Barth +--- + include/net/ip6_tunnel.h | 13 ++ + include/uapi/linux/if_tunnel.h | 13 ++ + net/ipv6/ip6_tunnel.c | 281 ++++++++++++++++++++++++++++++++- + 3 files changed, 299 insertions(+), 8 deletions(-) + +diff --git a/include/net/ip6_tunnel.h b/include/net/ip6_tunnel.h +index 399592405c72..79b066a4d13b 100644 +--- a/include/net/ip6_tunnel.h ++++ b/include/net/ip6_tunnel.h +@@ -18,6 +18,18 @@ + /* determine capability on a per-packet basis */ + #define IP6_TNL_F_CAP_PER_PACKET 0x40000 + ++/* IPv6 tunnel FMR */ ++struct __ip6_tnl_fmr { ++ struct __ip6_tnl_fmr *next; /* next fmr in list */ ++ struct in6_addr ip6_prefix; ++ struct in_addr ip4_prefix; ++ ++ __u8 ip6_prefix_len; ++ __u8 ip4_prefix_len; ++ __u8 ea_len; ++ __u8 offset; ++}; ++ + struct __ip6_tnl_parm { + char name[IFNAMSIZ]; /* name of tunnel device */ + int link; /* ifindex of underlying L2 interface */ +@@ -29,6 +41,7 @@ struct __ip6_tnl_parm { + __u32 flags; /* tunnel flags */ + struct in6_addr laddr; /* local tunnel end-point address */ + struct in6_addr raddr; /* remote tunnel end-point address */ ++ struct __ip6_tnl_fmr *fmrs; /* FMRs */ + + IP_TUNNEL_DECLARE_FLAGS(i_flags); + IP_TUNNEL_DECLARE_FLAGS(o_flags); +diff --git a/include/uapi/linux/if_tunnel.h b/include/uapi/linux/if_tunnel.h +index e1a246dd8c62..fda447945078 100644 +--- a/include/uapi/linux/if_tunnel.h ++++ b/include/uapi/linux/if_tunnel.h +@@ -77,10 +77,23 @@ enum { + IFLA_IPTUN_ENCAP_DPORT, + IFLA_IPTUN_COLLECT_METADATA, + IFLA_IPTUN_FWMARK, ++ IFLA_IPTUN_FMRS, + __IFLA_IPTUN_MAX, + }; + #define IFLA_IPTUN_MAX (__IFLA_IPTUN_MAX - 1) + ++enum { ++ IFLA_IPTUN_FMR_UNSPEC, ++ IFLA_IPTUN_FMR_IP6_PREFIX, ++ IFLA_IPTUN_FMR_IP4_PREFIX, ++ IFLA_IPTUN_FMR_IP6_PREFIX_LEN, ++ IFLA_IPTUN_FMR_IP4_PREFIX_LEN, ++ IFLA_IPTUN_FMR_EA_LEN, ++ IFLA_IPTUN_FMR_OFFSET, ++ __IFLA_IPTUN_FMR_MAX, ++}; ++#define IFLA_IPTUN_FMR_MAX (__IFLA_IPTUN_FMR_MAX - 1) ++ + enum tunnel_encap_types { + TUNNEL_ENCAP_NONE, + TUNNEL_ENCAP_FOU, +diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c +index b72ca1034906..ff58b562758e 100644 +--- a/net/ipv6/ip6_tunnel.c ++++ b/net/ipv6/ip6_tunnel.c +@@ -11,6 +11,9 @@ + * linux/net/ipv6/sit.c and linux/net/ipv4/ipip.c + * + * RFC 2473 ++ * ++ * Changes: ++ * Steven Barth : MAP-E FMR support + */ + + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +@@ -68,9 +71,9 @@ static bool log_ecn_error = true; + module_param(log_ecn_error, bool, 0644); + MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN"); + +-static u32 HASH(const struct in6_addr *addr1, const struct in6_addr *addr2) ++static u32 HASH(const struct in6_addr *addr) + { +- u32 hash = ipv6_addr_hash(addr1) ^ ipv6_addr_hash(addr2); ++ u32 hash = ipv6_addr_hash(addr); + + return hash_32(hash, IP6_TUNNEL_HASH_SIZE_SHIFT); + } +@@ -115,17 +118,33 @@ static struct ip6_tnl * + ip6_tnl_lookup(struct net *net, int link, + const struct in6_addr *remote, const struct in6_addr *local) + { +- unsigned int hash = HASH(remote, local); ++ unsigned int hash = HASH(local); + struct ip6_tnl *t, *cand = NULL; + struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); + struct in6_addr any; + + for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) { + if (!ipv6_addr_equal(local, &t->parms.laddr) || +- !ipv6_addr_equal(remote, &t->parms.raddr) || + !(t->dev->flags & IFF_UP)) + continue; + ++ if (!ipv6_addr_equal(remote, &t->parms.raddr)) { ++ struct __ip6_tnl_fmr *fmr; ++ bool found = false; ++ ++ for (fmr = t->parms.fmrs; fmr; fmr = fmr->next) { ++ if (!ipv6_prefix_equal(remote, &fmr->ip6_prefix, ++ fmr->ip6_prefix_len)) ++ continue; ++ ++ found = true; ++ break; ++ } ++ ++ if (!found) ++ continue; ++ } ++ + if (link == t->parms.link) + return t; + else +@@ -133,7 +152,7 @@ ip6_tnl_lookup(struct net *net, int link, + } + + memset(&any, 0, sizeof(any)); +- hash = HASH(&any, local); ++ hash = HASH(local); + for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) { + if (!ipv6_addr_equal(local, &t->parms.laddr) || + !ipv6_addr_any(&t->parms.raddr) || +@@ -146,7 +165,7 @@ ip6_tnl_lookup(struct net *net, int link, + cand = t; + } + +- hash = HASH(remote, &any); ++ hash = HASH(&any); + for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) { + if (!ipv6_addr_equal(remote, &t->parms.raddr) || + !ipv6_addr_any(&t->parms.laddr) || +@@ -195,7 +214,7 @@ ip6_tnl_bucket(struct ip6_tnl_net *ip6n, const struct __ip6_tnl_parm *p) + + if (!ipv6_addr_any(remote) || !ipv6_addr_any(local)) { + prio = 1; +- h = HASH(remote, local); ++ h = HASH(local); + } + return &ip6n->tnls[prio][h]; + } +@@ -376,6 +395,12 @@ ip6_tnl_dev_uninit(struct net_device *dev) + struct net *net = t->net; + struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); + ++ while (t->parms.fmrs) { ++ struct __ip6_tnl_fmr *next = t->parms.fmrs->next; ++ kfree(t->parms.fmrs); ++ t->parms.fmrs = next; ++ } ++ + if (dev == ip6n->fb_tnl_dev) + RCU_INIT_POINTER(ip6n->tnls_wc[0], NULL); + else +@@ -790,6 +815,107 @@ int ip6_tnl_rcv_ctl(struct ip6_tnl *t, + } + EXPORT_SYMBOL_GPL(ip6_tnl_rcv_ctl); + ++/** ++ * ip4ip6_fmr_calc - calculate target / source IPv6-address based on FMR ++ * @dest: destination IPv6 address buffer ++ * @skb: received socket buffer ++ * @fmr: MAP FMR ++ * @xmit: Calculate for xmit or rcv ++ **/ ++static void ip4ip6_fmr_calc(struct in6_addr *dest, ++ const struct iphdr *iph, const uint8_t *end, ++ const struct __ip6_tnl_fmr *fmr, bool xmit) ++{ ++ int psidlen = fmr->ea_len - (32 - fmr->ip4_prefix_len); ++ u8 *portp = NULL; ++ bool use_dest_addr; ++ const struct iphdr *dsth = iph; ++ ++ if ((u8*)dsth >= end) ++ return; ++ ++ /* find significant IP header */ ++ if (iph->protocol == IPPROTO_ICMP) { ++ struct icmphdr *ih = (struct icmphdr*)(((u8*)dsth) + dsth->ihl * 4); ++ if (ih && ((u8*)&ih[1]) <= end && ( ++ ih->type == ICMP_DEST_UNREACH || ++ ih->type == ICMP_SOURCE_QUENCH || ++ ih->type == ICMP_TIME_EXCEEDED || ++ ih->type == ICMP_PARAMETERPROB || ++ ih->type == ICMP_REDIRECT)) ++ dsth = (const struct iphdr*)&ih[1]; ++ } ++ ++ /* in xmit-path use dest port by default and source port only if ++ this is an ICMP reply to something else; vice versa in rcv-path */ ++ use_dest_addr = (xmit && dsth == iph) || (!xmit && dsth != iph); ++ ++ /* get dst port */ ++ if (((u8*)&dsth[1]) <= end && ( ++ dsth->protocol == IPPROTO_UDP || ++ dsth->protocol == IPPROTO_TCP || ++ dsth->protocol == IPPROTO_SCTP || ++ dsth->protocol == IPPROTO_DCCP)) { ++ /* for UDP, TCP, SCTP and DCCP source and dest port ++ follow IPv4 header directly */ ++ portp = ((u8*)dsth) + dsth->ihl * 4; ++ ++ if (use_dest_addr) ++ portp += sizeof(u16); ++ } else if (iph->protocol == IPPROTO_ICMP) { ++ struct icmphdr *ih = (struct icmphdr*)(((u8*)dsth) + dsth->ihl * 4); ++ ++ /* use icmp identifier as port */ ++ if (((u8*)&ih) <= end && ( ++ (use_dest_addr && ( ++ ih->type == ICMP_ECHOREPLY || ++ ih->type == ICMP_TIMESTAMPREPLY || ++ ih->type == ICMP_INFO_REPLY || ++ ih->type == ICMP_ADDRESSREPLY)) || ++ (!use_dest_addr && ( ++ ih->type == ICMP_ECHO || ++ ih->type == ICMP_TIMESTAMP || ++ ih->type == ICMP_INFO_REQUEST || ++ ih->type == ICMP_ADDRESS) ++ ))) ++ portp = (u8*)&ih->un.echo.id; ++ } ++ ++ if ((portp && &portp[2] <= end) || psidlen == 0) { ++ int frombyte = fmr->ip6_prefix_len / 8; ++ int fromrem = fmr->ip6_prefix_len % 8; ++ int bytes = sizeof(struct in6_addr) - frombyte; ++ const u32 *addr = (use_dest_addr) ? &iph->daddr : &iph->saddr; ++ u64 eabits = ((u64)ntohl(*addr)) << (32 + fmr->ip4_prefix_len); ++ u64 t = 0; ++ ++ /* extract PSID from port and add it to eabits */ ++ u16 psidbits = 0; ++ if (psidlen > 0) { ++ psidbits = ((u16)portp[0]) << 8 | ((u16)portp[1]); ++ psidbits >>= 16 - psidlen - fmr->offset; ++ psidbits = (u16)(psidbits << (16 - psidlen)); ++ eabits |= ((u64)psidbits) << (48 - (fmr->ea_len - psidlen)); ++ } ++ ++ /* rewrite destination address */ ++ *dest = fmr->ip6_prefix; ++ memcpy(&dest->s6_addr[10], addr, sizeof(*addr)); ++ dest->s6_addr16[7] = htons(psidbits >> (16 - psidlen)); ++ ++ if (bytes > sizeof(u64)) ++ bytes = sizeof(u64); ++ ++ /* insert eabits */ ++ memcpy(&t, &dest->s6_addr[frombyte], bytes); ++ t = be64_to_cpu(t) & ~(((((u64)1) << fmr->ea_len) - 1) ++ << (64 - fmr->ea_len - fromrem)); ++ t = cpu_to_be64(t | (eabits >> fromrem)); ++ memcpy(&dest->s6_addr[frombyte], &t, bytes); ++ } ++} ++ ++ + static int __ip6_tnl_rcv(struct ip6_tnl *tunnel, struct sk_buff *skb, + const struct tnl_ptk_info *tpi, + struct metadata_dst *tun_dst, +@@ -855,6 +981,27 @@ static int __ip6_tnl_rcv(struct ip6_tnl *tunnel, struct sk_buff *skb, + + memset(skb->cb, 0, sizeof(struct inet6_skb_parm)); + ++ if (tpi->proto == htons(ETH_P_IP) && tunnel->parms.fmrs && ++ !ipv6_addr_equal(&ipv6h->saddr, &tunnel->parms.raddr)) { ++ /* Packet didn't come from BR, so lookup FMR */ ++ struct __ip6_tnl_fmr *fmr; ++ struct in6_addr expected = tunnel->parms.raddr; ++ for (fmr = tunnel->parms.fmrs; fmr; fmr = fmr->next) ++ if (ipv6_prefix_equal(&ipv6h->saddr, ++ &fmr->ip6_prefix, fmr->ip6_prefix_len)) ++ break; ++ ++ /* Check that IPv6 matches IPv4 source to prevent spoofing */ ++ if (fmr) ++ ip4ip6_fmr_calc(&expected, ip_hdr(skb), ++ skb_tail_pointer(skb), fmr, false); ++ ++ if (!ipv6_addr_equal(&ipv6h->saddr, &expected)) { ++ rcu_read_unlock(); ++ goto drop; ++ } ++ } ++ + __skb_tunnel_rx(skb, tunnel->dev, tunnel->net); + + err = dscp_ecn_decapsulate(tunnel, ipv6h, skb); +@@ -1004,6 +1151,7 @@ static void init_tel_txopt(struct ipv6_tel_txoption *opt, __u8 encap_limit) + opt->ops.opt_nflen = 8; + } + ++ + /** + * ip6_tnl_addr_conflict - compare packet addresses to tunnel's own + * @t: the outgoing tunnel device +@@ -1293,6 +1441,7 @@ ipxip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev, + u8 protocol) + { + struct ip6_tnl *t = netdev_priv(dev); ++ struct __ip6_tnl_fmr *fmr; + struct ipv6hdr *ipv6h; + const struct iphdr *iph; + int encap_limit = -1; +@@ -1392,6 +1541,18 @@ ipxip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev, + fl6.flowi6_uid = sock_net_uid(dev_net(dev), NULL); + dsfield = INET_ECN_encapsulate(dsfield, orig_dsfield); + ++ /* try to find matching FMR */ ++ for (fmr = t->parms.fmrs; fmr; fmr = fmr->next) { ++ unsigned mshift = 32 - fmr->ip4_prefix_len; ++ if (ntohl(fmr->ip4_prefix.s_addr) >> mshift == ++ ntohl(ip_hdr(skb)->daddr) >> mshift) ++ break; ++ } ++ ++ /* change dstaddr according to FMR */ ++ if (fmr) ++ ip4ip6_fmr_calc(&fl6.daddr, ip_hdr(skb), skb_tail_pointer(skb), fmr, true); ++ + if (iptunnel_handle_offloads(skb, SKB_GSO_IPXIP6)) + return -1; + +@@ -1545,6 +1706,14 @@ ip6_tnl_change(struct ip6_tnl *t, const struct __ip6_tnl_parm *p) + t->parms.link = p->link; + t->parms.proto = p->proto; + t->parms.fwmark = p->fwmark; ++ ++ while (t->parms.fmrs) { ++ struct __ip6_tnl_fmr *next = t->parms.fmrs->next; ++ kfree(t->parms.fmrs); ++ t->parms.fmrs = next; ++ } ++ t->parms.fmrs = p->fmrs; ++ + dst_cache_reset(&t->dst_cache); + ip6_tnl_link_config(t); + } +@@ -1579,6 +1748,7 @@ ip6_tnl_parm_from_user(struct __ip6_tnl_parm *p, const struct ip6_tnl_parm *u) + p->flowinfo = u->flowinfo; + p->link = u->link; + p->proto = u->proto; ++ p->fmrs = NULL; + memcpy(p->name, u->name, sizeof(u->name)); + } + +@@ -1962,6 +2132,15 @@ static int ip6_tnl_validate(struct nlattr *tb[], struct nlattr *data[], + return 0; + } + ++static const struct nla_policy ip6_tnl_fmr_policy[IFLA_IPTUN_FMR_MAX + 1] = { ++ [IFLA_IPTUN_FMR_IP6_PREFIX] = { .len = sizeof(struct in6_addr) }, ++ [IFLA_IPTUN_FMR_IP4_PREFIX] = { .len = sizeof(struct in_addr) }, ++ [IFLA_IPTUN_FMR_IP6_PREFIX_LEN] = { .type = NLA_U8 }, ++ [IFLA_IPTUN_FMR_IP4_PREFIX_LEN] = { .type = NLA_U8 }, ++ [IFLA_IPTUN_FMR_EA_LEN] = { .type = NLA_U8 }, ++ [IFLA_IPTUN_FMR_OFFSET] = { .type = NLA_U8 } ++}; ++ + static void ip6_tnl_netlink_parms(struct nlattr *data[], + struct __ip6_tnl_parm *parms) + { +@@ -1999,6 +2178,46 @@ static void ip6_tnl_netlink_parms(struct nlattr *data[], + + if (data[IFLA_IPTUN_FWMARK]) + parms->fwmark = nla_get_u32(data[IFLA_IPTUN_FWMARK]); ++ ++ if (data[IFLA_IPTUN_FMRS]) { ++ unsigned rem; ++ struct nlattr *fmr; ++ nla_for_each_nested(fmr, data[IFLA_IPTUN_FMRS], rem) { ++ struct nlattr *fmrd[IFLA_IPTUN_FMR_MAX + 1], *c; ++ struct __ip6_tnl_fmr *nfmr; ++ ++ nla_parse_nested(fmrd, IFLA_IPTUN_FMR_MAX, ++ fmr, ip6_tnl_fmr_policy, NULL); ++ ++ if (!(nfmr = kzalloc(sizeof(*nfmr), GFP_KERNEL))) ++ continue; ++ ++ nfmr->offset = 6; ++ ++ if ((c = fmrd[IFLA_IPTUN_FMR_IP6_PREFIX])) ++ nla_memcpy(&nfmr->ip6_prefix, fmrd[IFLA_IPTUN_FMR_IP6_PREFIX], ++ sizeof(nfmr->ip6_prefix)); ++ ++ if ((c = fmrd[IFLA_IPTUN_FMR_IP4_PREFIX])) ++ nla_memcpy(&nfmr->ip4_prefix, fmrd[IFLA_IPTUN_FMR_IP4_PREFIX], ++ sizeof(nfmr->ip4_prefix)); ++ ++ if ((c = fmrd[IFLA_IPTUN_FMR_IP6_PREFIX_LEN])) ++ nfmr->ip6_prefix_len = nla_get_u8(c); ++ ++ if ((c = fmrd[IFLA_IPTUN_FMR_IP4_PREFIX_LEN])) ++ nfmr->ip4_prefix_len = nla_get_u8(c); ++ ++ if ((c = fmrd[IFLA_IPTUN_FMR_EA_LEN])) ++ nfmr->ea_len = nla_get_u8(c); ++ ++ if ((c = fmrd[IFLA_IPTUN_FMR_OFFSET])) ++ nfmr->offset = nla_get_u8(c); ++ ++ nfmr->next = parms->fmrs; ++ parms->fmrs = nfmr; ++ } ++ } + } + + static int ip6_tnl_newlink(struct net *src_net, struct net_device *dev, +@@ -2083,6 +2302,12 @@ static void ip6_tnl_dellink(struct net_device *dev, struct list_head *head) + + static size_t ip6_tnl_get_size(const struct net_device *dev) + { ++ const struct ip6_tnl *t = netdev_priv(dev); ++ struct __ip6_tnl_fmr *c; ++ int fmrs = 0; ++ for (c = t->parms.fmrs; c; c = c->next) ++ ++fmrs; ++ + return + /* IFLA_IPTUN_LINK */ + nla_total_size(4) + +@@ -2112,6 +2337,24 @@ static size_t ip6_tnl_get_size(const struct net_device *dev) + nla_total_size(0) + + /* IFLA_IPTUN_FWMARK */ + nla_total_size(4) + ++ /* IFLA_IPTUN_FMRS */ ++ nla_total_size(0) + ++ ( ++ /* nest */ ++ nla_total_size(0) + ++ /* IFLA_IPTUN_FMR_IP6_PREFIX */ ++ nla_total_size(sizeof(struct in6_addr)) + ++ /* IFLA_IPTUN_FMR_IP4_PREFIX */ ++ nla_total_size(sizeof(struct in_addr)) + ++ /* IFLA_IPTUN_FMR_EA_LEN */ ++ nla_total_size(1) + ++ /* IFLA_IPTUN_FMR_IP6_PREFIX_LEN */ ++ nla_total_size(1) + ++ /* IFLA_IPTUN_FMR_IP4_PREFIX_LEN */ ++ nla_total_size(1) + ++ /* IFLA_IPTUN_FMR_OFFSET */ ++ nla_total_size(1) ++ ) * fmrs + + 0; + } + +@@ -2119,6 +2362,9 @@ static int ip6_tnl_fill_info(struct sk_buff *skb, const struct net_device *dev) + { + struct ip6_tnl *tunnel = netdev_priv(dev); + struct __ip6_tnl_parm *parm = &tunnel->parms; ++ struct __ip6_tnl_fmr *c; ++ int fmrcnt = 0; ++ struct nlattr *fmrs; + + if (nla_put_u32(skb, IFLA_IPTUN_LINK, parm->link) || + nla_put_in6_addr(skb, IFLA_IPTUN_LOCAL, &parm->laddr) || +@@ -2128,9 +2374,27 @@ static int ip6_tnl_fill_info(struct sk_buff *skb, const struct net_device *dev) + nla_put_be32(skb, IFLA_IPTUN_FLOWINFO, parm->flowinfo) || + nla_put_u32(skb, IFLA_IPTUN_FLAGS, parm->flags) || + nla_put_u8(skb, IFLA_IPTUN_PROTO, parm->proto) || +- nla_put_u32(skb, IFLA_IPTUN_FWMARK, parm->fwmark)) ++ nla_put_u32(skb, IFLA_IPTUN_FWMARK, parm->fwmark) || ++ !(fmrs = nla_nest_start(skb, IFLA_IPTUN_FMRS))) + goto nla_put_failure; + ++ for (c = parm->fmrs; c; c = c->next) { ++ struct nlattr *fmr = nla_nest_start(skb, ++fmrcnt); ++ if (!fmr || ++ nla_put(skb, IFLA_IPTUN_FMR_IP6_PREFIX, ++ sizeof(c->ip6_prefix), &c->ip6_prefix) || ++ nla_put(skb, IFLA_IPTUN_FMR_IP4_PREFIX, ++ sizeof(c->ip4_prefix), &c->ip4_prefix) || ++ nla_put_u8(skb, IFLA_IPTUN_FMR_IP6_PREFIX_LEN, c->ip6_prefix_len) || ++ nla_put_u8(skb, IFLA_IPTUN_FMR_IP4_PREFIX_LEN, c->ip4_prefix_len) || ++ nla_put_u8(skb, IFLA_IPTUN_FMR_EA_LEN, c->ea_len) || ++ nla_put_u8(skb, IFLA_IPTUN_FMR_OFFSET, c->offset)) ++ goto nla_put_failure; ++ ++ nla_nest_end(skb, fmr); ++ } ++ nla_nest_end(skb, fmrs); ++ + if (nla_put_u16(skb, IFLA_IPTUN_ENCAP_TYPE, tunnel->encap.type) || + nla_put_be16(skb, IFLA_IPTUN_ENCAP_SPORT, tunnel->encap.sport) || + nla_put_be16(skb, IFLA_IPTUN_ENCAP_DPORT, tunnel->encap.dport) || +@@ -2170,6 +2434,7 @@ static const struct nla_policy ip6_tnl_policy[IFLA_IPTUN_MAX + 1] = { + [IFLA_IPTUN_ENCAP_DPORT] = { .type = NLA_U16 }, + [IFLA_IPTUN_COLLECT_METADATA] = { .type = NLA_FLAG }, + [IFLA_IPTUN_FWMARK] = { .type = NLA_U32 }, ++ [IFLA_IPTUN_FMRS] = { .type = NLA_NESTED }, + }; + + static struct rtnl_link_ops ip6_link_ops __read_mostly = { +-- +2.51.0 + + +From 3878b9edc9d3b56abb5439d09dc4f05403518e35 Mon Sep 17 00:00:00 2001 +From: Jonas Gorski +Date: Mon, 3 Nov 2025 15:49:55 +0100 +Subject: [PATCH 264/517] ipv6: allow rejecting with "source address failed + policy" + +RFC6204 L-14 requires rejecting traffic from invalid addresses with +ICMPv6 Destination Unreachable, Code 5 (Source address failed ingress/ +egress policy) on the LAN side, so add an appropriate rule for that. + +Signed-off-by: Jonas Gorski +--- + include/net/netns/ipv6.h | 1 + + include/uapi/linux/fib_rules.h | 4 +++ + include/uapi/linux/rtnetlink.h | 1 + + net/ipv4/fib_semantics.c | 4 +++ + net/ipv4/fib_trie.c | 1 + + net/ipv4/ipmr.c | 1 + + net/ipv6/fib6_rules.c | 4 +++ + net/ipv6/ip6mr.c | 2 ++ + net/ipv6/route.c | 56 ++++++++++++++++++++++++++++++++-- + 9 files changed, 72 insertions(+), 2 deletions(-) + +diff --git a/include/net/netns/ipv6.h b/include/net/netns/ipv6.h +index 5f2cfd84570a..c56a4b0e9636 100644 +--- a/include/net/netns/ipv6.h ++++ b/include/net/netns/ipv6.h +@@ -86,6 +86,7 @@ struct netns_ipv6 { + unsigned int fib6_routes_require_src; + #endif + struct rt6_info *ip6_prohibit_entry; ++ struct rt6_info *ip6_policy_failed_entry; + struct rt6_info *ip6_blk_hole_entry; + struct fib6_table *fib6_local_tbl; + struct fib_rules_ops *fib6_rules_ops; +diff --git a/include/uapi/linux/fib_rules.h b/include/uapi/linux/fib_rules.h +index a6924dd3aff1..4b3e1d99a654 100644 +--- a/include/uapi/linux/fib_rules.h ++++ b/include/uapi/linux/fib_rules.h +@@ -83,6 +83,10 @@ enum { + FR_ACT_BLACKHOLE, /* Drop without notification */ + FR_ACT_UNREACHABLE, /* Drop with ENETUNREACH */ + FR_ACT_PROHIBIT, /* Drop with EACCES */ ++ FR_ACT_RES9, ++ FR_ACT_RES10, ++ FR_ACT_RES11, ++ FR_ACT_POLICY_FAILED, /* Drop with EACCES */ + __FR_ACT_MAX, + }; + +diff --git a/include/uapi/linux/rtnetlink.h b/include/uapi/linux/rtnetlink.h +index db7254d52d93..d49560d2bd71 100644 +--- a/include/uapi/linux/rtnetlink.h ++++ b/include/uapi/linux/rtnetlink.h +@@ -265,6 +265,7 @@ enum { + RTN_THROW, /* Not in this table */ + RTN_NAT, /* Translate this address */ + RTN_XRESOLVE, /* Use external resolver */ ++ RTN_POLICY_FAILED, /* Failed ingress/egress policy */ + __RTN_MAX + }; + +diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c +index ba2df3d2ac15..f70f87839faa 100644 +--- a/net/ipv4/fib_semantics.c ++++ b/net/ipv4/fib_semantics.c +@@ -145,6 +145,10 @@ const struct fib_prop fib_props[RTN_MAX + 1] = { + .error = -EINVAL, + .scope = RT_SCOPE_NOWHERE, + }, ++ [RTN_POLICY_FAILED] = { ++ .error = -EACCES, ++ .scope = RT_SCOPE_UNIVERSE, ++ }, + }; + + static void rt_fibinfo_free(struct rtable __rcu **rtp) +diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c +index cc86031d2050..b7440806041b 100644 +--- a/net/ipv4/fib_trie.c ++++ b/net/ipv4/fib_trie.c +@@ -2762,6 +2762,7 @@ static const char *const rtn_type_names[__RTN_MAX] = { + [RTN_THROW] = "THROW", + [RTN_NAT] = "NAT", + [RTN_XRESOLVE] = "XRESOLVE", ++ [RTN_POLICY_FAILED] = "POLICY_FAILED", + }; + + static inline const char *rtn_type(char *buf, size_t len, unsigned int t) +diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c +index de0d9cc7806a..bef0f63f4fd4 100644 +--- a/net/ipv4/ipmr.c ++++ b/net/ipv4/ipmr.c +@@ -191,6 +191,7 @@ static int ipmr_rule_action(struct fib_rule *rule, struct flowi *flp, + case FR_ACT_UNREACHABLE: + return -ENETUNREACH; + case FR_ACT_PROHIBIT: ++ case FR_ACT_POLICY_FAILED: + return -EACCES; + case FR_ACT_BLACKHOLE: + default: +diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c +index 29185c9ebd02..369fcdcfd0f0 100644 +--- a/net/ipv6/fib6_rules.c ++++ b/net/ipv6/fib6_rules.c +@@ -222,6 +222,10 @@ static int __fib6_rule_action(struct fib_rule *rule, struct flowi *flp, + err = -EACCES; + rt = net->ipv6.ip6_prohibit_entry; + goto discard_pkt; ++ case FR_ACT_POLICY_FAILED: ++ err = -EACCES; ++ rt = net->ipv6.ip6_policy_failed_entry; ++ goto discard_pkt; + } + + tb_id = fib_rule_get_table(rule, arg); +diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c +index 68bc518500f9..685d4c37b6ed 100644 +--- a/net/ipv6/ip6mr.c ++++ b/net/ipv6/ip6mr.c +@@ -180,6 +180,8 @@ static int ip6mr_rule_action(struct fib_rule *rule, struct flowi *flp, + return -ENETUNREACH; + case FR_ACT_PROHIBIT: + return -EACCES; ++ case FR_ACT_POLICY_FAILED: ++ return -EACCES; + case FR_ACT_BLACKHOLE: + default: + return -EINVAL; +diff --git a/net/ipv6/route.c b/net/ipv6/route.c +index 22866444efc0..33cfc2dc9aaf 100644 +--- a/net/ipv6/route.c ++++ b/net/ipv6/route.c +@@ -98,6 +98,8 @@ static int ip6_pkt_discard(struct sk_buff *skb); + static int ip6_pkt_discard_out(struct net *net, struct sock *sk, struct sk_buff *skb); + static int ip6_pkt_prohibit(struct sk_buff *skb); + static int ip6_pkt_prohibit_out(struct net *net, struct sock *sk, struct sk_buff *skb); ++static int ip6_pkt_policy_failed(struct sk_buff *skb); ++static int ip6_pkt_policy_failed_out(struct net *net, struct sock *sk, struct sk_buff *skb); + static void ip6_link_failure(struct sk_buff *skb); + static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk, + struct sk_buff *skb, u32 mtu, +@@ -316,6 +318,18 @@ static const struct rt6_info ip6_prohibit_entry_template = { + .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP), + }; + ++static const struct rt6_info ip6_policy_failed_entry_template = { ++ .dst = { ++ .__rcuref = RCUREF_INIT(1), ++ .__use = 1, ++ .obsolete = DST_OBSOLETE_FORCE_CHK, ++ .error = -EACCES, ++ .input = ip6_pkt_policy_failed, ++ .output = ip6_pkt_policy_failed_out, ++ }, ++ .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP), ++}; ++ + static const struct rt6_info ip6_blk_hole_entry_template = { + .dst = { + .__rcuref = RCUREF_INIT(1), +@@ -1085,6 +1099,7 @@ static const int fib6_prop[RTN_MAX + 1] = { + [RTN_BLACKHOLE] = -EINVAL, + [RTN_UNREACHABLE] = -EHOSTUNREACH, + [RTN_PROHIBIT] = -EACCES, ++ [RTN_POLICY_FAILED] = -EACCES, + [RTN_THROW] = -EAGAIN, + [RTN_NAT] = -EINVAL, + [RTN_XRESOLVE] = -EINVAL, +@@ -1120,6 +1135,10 @@ static void ip6_rt_init_dst_reject(struct rt6_info *rt, u8 fib6_type) + rt->dst.output = ip6_pkt_prohibit_out; + rt->dst.input = ip6_pkt_prohibit; + break; ++ case RTN_POLICY_FAILED: ++ rt->dst.output = ip6_pkt_policy_failed_out; ++ rt->dst.input = ip6_pkt_policy_failed; ++ break; + case RTN_THROW: + case RTN_UNREACHABLE: + default: +@@ -4598,6 +4617,17 @@ static int ip6_pkt_prohibit_out(struct net *net, struct sock *sk, struct sk_buff + return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES); + } + ++static int ip6_pkt_policy_failed(struct sk_buff *skb) ++{ ++ return ip6_pkt_drop(skb, ICMPV6_POLICY_FAIL, IPSTATS_MIB_INNOROUTES); ++} ++ ++static int ip6_pkt_policy_failed_out(struct net *net, struct sock *sk, struct sk_buff *skb) ++{ ++ skb->dev = skb_dst(skb)->dev; ++ return ip6_pkt_drop(skb, ICMPV6_POLICY_FAIL, IPSTATS_MIB_OUTNOROUTES); ++} ++ + /* + * Allocate a dst for local (unicast / anycast) address. + */ +@@ -5089,7 +5119,8 @@ static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh, + if (rtm->rtm_type == RTN_UNREACHABLE || + rtm->rtm_type == RTN_BLACKHOLE || + rtm->rtm_type == RTN_PROHIBIT || +- rtm->rtm_type == RTN_THROW) ++ rtm->rtm_type == RTN_THROW || ++ rtm->rtm_type == RTN_POLICY_FAILED) + cfg->fc_flags |= RTF_REJECT; + + if (rtm->rtm_type == RTN_LOCAL) +@@ -6357,6 +6388,8 @@ static int ip6_route_dev_notify(struct notifier_block *this, + #ifdef CONFIG_IPV6_MULTIPLE_TABLES + net->ipv6.ip6_prohibit_entry->dst.dev = dev; + net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev); ++ net->ipv6.ip6_policy_failed_entry->dst.dev = dev; ++ net->ipv6.ip6_policy_failed_entry->rt6i_idev = in6_dev_get(dev); + net->ipv6.ip6_blk_hole_entry->dst.dev = dev; + net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev); + #endif +@@ -6368,6 +6401,7 @@ static int ip6_route_dev_notify(struct notifier_block *this, + in6_dev_put_clear(&net->ipv6.ip6_null_entry->rt6i_idev); + #ifdef CONFIG_IPV6_MULTIPLE_TABLES + in6_dev_put_clear(&net->ipv6.ip6_prohibit_entry->rt6i_idev); ++ in6_dev_put_clear(&net->ipv6.ip6_policy_failed_entry->rt6i_idev); + in6_dev_put_clear(&net->ipv6.ip6_blk_hole_entry->rt6i_idev); + #endif + } +@@ -6563,6 +6597,8 @@ static int __net_init ip6_route_net_init(struct net *net) + + #ifdef CONFIG_IPV6_MULTIPLE_TABLES + net->ipv6.fib6_has_custom_rules = false; ++ ++ + net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template, + sizeof(*net->ipv6.ip6_prohibit_entry), + GFP_KERNEL); +@@ -6573,11 +6609,21 @@ static int __net_init ip6_route_net_init(struct net *net) + ip6_template_metrics, true); + INIT_LIST_HEAD(&net->ipv6.ip6_prohibit_entry->dst.rt_uncached); + ++ net->ipv6.ip6_policy_failed_entry = ++ kmemdup(&ip6_policy_failed_entry_template, ++ sizeof(*net->ipv6.ip6_policy_failed_entry), GFP_KERNEL); ++ if (!net->ipv6.ip6_policy_failed_entry) ++ goto out_ip6_prohibit_entry; ++ net->ipv6.ip6_policy_failed_entry->dst.ops = &net->ipv6.ip6_dst_ops; ++ dst_init_metrics(&net->ipv6.ip6_policy_failed_entry->dst, ++ ip6_template_metrics, true); ++ INIT_LIST_HEAD(&net->ipv6.ip6_policy_failed_entry->dst.rt_uncached); ++ + net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template, + sizeof(*net->ipv6.ip6_blk_hole_entry), + GFP_KERNEL); + if (!net->ipv6.ip6_blk_hole_entry) +- goto out_ip6_prohibit_entry; ++ goto out_ip6_policy_failed_entry; + net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops; + dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst, + ip6_template_metrics, true); +@@ -6604,6 +6650,8 @@ static int __net_init ip6_route_net_init(struct net *net) + return ret; + + #ifdef CONFIG_IPV6_MULTIPLE_TABLES ++out_ip6_policy_failed_entry: ++ kfree(net->ipv6.ip6_policy_failed_entry); + out_ip6_prohibit_entry: + kfree(net->ipv6.ip6_prohibit_entry); + out_ip6_null_entry: +@@ -6623,6 +6671,7 @@ static void __net_exit ip6_route_net_exit(struct net *net) + kfree(net->ipv6.ip6_null_entry); + #ifdef CONFIG_IPV6_MULTIPLE_TABLES + kfree(net->ipv6.ip6_prohibit_entry); ++ kfree(net->ipv6.ip6_policy_failed_entry); + kfree(net->ipv6.ip6_blk_hole_entry); + #endif + dst_entries_destroy(&net->ipv6.ip6_dst_ops); +@@ -6706,6 +6755,9 @@ void __init ip6_route_init_special_entries(void) + init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); + init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev; + init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); ++ init_net.ipv6.ip6_policy_failed_entry->dst.dev = init_net.loopback_dev; ++ init_net.ipv6.ip6_policy_failed_entry->rt6i_idev = ++ in6_dev_get(init_net.loopback_dev); + #endif + } + +-- +2.51.0 + + +From afd618b85af8f8aac217bd64b5626dd6062caf19 Mon Sep 17 00:00:00 2001 +From: Jonas Gorski +Date: Mon, 3 Nov 2025 15:49:55 +0100 +Subject: [PATCH 265/517] net: provide defines for _POLICY_FAILED until all + code is updated + +Upstream introduced ICMPV6_POLICY_FAIL for code 5 of destination +unreachable, conflicting with our name. + +Add appropriate defines to allow our code to build with the new +name until we have updated our local patches for older kernels +and userspace packages. + +Signed-off-by: Jonas Gorski +--- + include/uapi/linux/fib_rules.h | 2 ++ + include/uapi/linux/icmpv6.h | 2 ++ + include/uapi/linux/rtnetlink.h | 2 ++ + 3 files changed, 6 insertions(+) + +diff --git a/include/uapi/linux/fib_rules.h b/include/uapi/linux/fib_rules.h +index 4b3e1d99a654..598fe9d0f409 100644 +--- a/include/uapi/linux/fib_rules.h ++++ b/include/uapi/linux/fib_rules.h +@@ -90,6 +90,8 @@ enum { + __FR_ACT_MAX, + }; + ++#define FR_ACT_FAILED_POLICY FR_ACT_POLICY_FAILED ++ + #define FR_ACT_MAX (__FR_ACT_MAX - 1) + + #endif +diff --git a/include/uapi/linux/icmpv6.h b/include/uapi/linux/icmpv6.h +index 4eaab89e2856..1d7e12b488ac 100644 +--- a/include/uapi/linux/icmpv6.h ++++ b/include/uapi/linux/icmpv6.h +@@ -127,6 +127,8 @@ struct icmp6hdr { + #define ICMPV6_POLICY_FAIL 5 + #define ICMPV6_REJECT_ROUTE 6 + ++#define ICMPV6_FAILED_POLICY ICMPV6_POLICY_FAIL ++ + /* + * Codes for Time Exceeded + */ +diff --git a/include/uapi/linux/rtnetlink.h b/include/uapi/linux/rtnetlink.h +index d49560d2bd71..795736ef4217 100644 +--- a/include/uapi/linux/rtnetlink.h ++++ b/include/uapi/linux/rtnetlink.h +@@ -269,6 +269,8 @@ enum { + __RTN_MAX + }; + ++#define RTN_FAILED_POLICY RTN_POLICY_FAILED ++ + #define RTN_MAX (__RTN_MAX - 1) + + +-- +2.51.0 + + +From d1e0e08702e53d8608d0464cace36a3e1ef428b3 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Thu, 15 Aug 2024 21:15:13 +0200 +Subject: [PATCH 266/517] net: remove NETIF_F_GSO_FRAGLIST from + NETIF_F_GSO_SOFTWARE + +Several drivers set NETIF_F_GSO_SOFTWARE, but mangle fraglist GRO packets +in a way that they can't be properly segmented anymore. +In order to properly deal with this, remove fraglist GSO from +NETIF_F_GSO_SOFTWARE and switch to NETIF_F_GSO_SOFTWARE_ALL (which includes +fraglist GSO) in places where it's safe to add. + +Signed-off-by: Felix Fietkau +--- + drivers/net/dummy.c | 2 +- + drivers/net/loopback.c | 2 +- + drivers/net/macvlan.c | 2 +- + include/linux/netdev_features.h | 5 +++-- + net/8021q/vlan.h | 2 +- + net/8021q/vlan_dev.c | 4 ++-- + net/core/sock.c | 2 +- + net/mac80211/ieee80211_i.h | 2 +- + net/openvswitch/vport-internal_dev.c | 2 +- + 9 files changed, 12 insertions(+), 11 deletions(-) + +diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c +index e9c5e1e11fa0..d32b6190bde1 100644 +--- a/drivers/net/dummy.c ++++ b/drivers/net/dummy.c +@@ -111,7 +111,7 @@ static void dummy_setup(struct net_device *dev) + dev->priv_flags |= IFF_LIVE_ADDR_CHANGE | IFF_NO_QUEUE; + dev->lltx = true; + dev->features |= NETIF_F_SG | NETIF_F_FRAGLIST; +- dev->features |= NETIF_F_GSO_SOFTWARE; ++ dev->features |= NETIF_F_GSO_SOFTWARE_ALL; + dev->features |= NETIF_F_HW_CSUM | NETIF_F_HIGHDMA; + dev->features |= NETIF_F_GSO_ENCAP_ALL; + dev->hw_features |= dev->features; +diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c +index 491e56b3263f..602396bec287 100644 +--- a/drivers/net/loopback.c ++++ b/drivers/net/loopback.c +@@ -174,7 +174,7 @@ static void gen_lo_setup(struct net_device *dev, + dev->lltx = true; + dev->netns_local = true; + netif_keep_dst(dev); +- dev->hw_features = NETIF_F_GSO_SOFTWARE; ++ dev->hw_features = NETIF_F_GSO_SOFTWARE_ALL; + dev->features = NETIF_F_SG | NETIF_F_FRAGLIST + | NETIF_F_GSO_SOFTWARE + | NETIF_F_HW_CSUM +diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c +index cf18e66de142..e1a501061d21 100644 +--- a/drivers/net/macvlan.c ++++ b/drivers/net/macvlan.c +@@ -897,7 +897,7 @@ static int macvlan_hwtstamp_set(struct net_device *dev, + static struct lock_class_key macvlan_netdev_addr_lock_key; + + #define ALWAYS_ON_OFFLOADS \ +- (NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_GSO_SOFTWARE | \ ++ (NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_GSO_SOFTWARE_ALL | \ + NETIF_F_GSO_ROBUST | NETIF_F_GSO_ENCAP_ALL) + + #define ALWAYS_ON_FEATURES ALWAYS_ON_OFFLOADS +diff --git a/include/linux/netdev_features.h b/include/linux/netdev_features.h +index 11be70a7929f..e2e3dd919068 100644 +--- a/include/linux/netdev_features.h ++++ b/include/linux/netdev_features.h +@@ -211,13 +211,14 @@ static inline int find_next_netdev_feature(u64 feature, unsigned long start) + + /* List of features with software fallbacks. */ + #define NETIF_F_GSO_SOFTWARE (NETIF_F_ALL_TSO | NETIF_F_GSO_SCTP | \ +- NETIF_F_GSO_UDP_L4 | NETIF_F_GSO_FRAGLIST) ++ NETIF_F_GSO_UDP_L4) ++#define NETIF_F_GSO_SOFTWARE_ALL (NETIF_F_GSO_SOFTWARE | NETIF_F_GSO_FRAGLIST) + + /* + * If one device supports one of these features, then enable them + * for all in netdev_increment_features. + */ +-#define NETIF_F_ONE_FOR_ALL (NETIF_F_GSO_SOFTWARE | NETIF_F_GSO_ROBUST | \ ++#define NETIF_F_ONE_FOR_ALL (NETIF_F_GSO_SOFTWARE_ALL | NETIF_F_GSO_ROBUST | \ + NETIF_F_SG | NETIF_F_HIGHDMA | \ + NETIF_F_FRAGLIST | NETIF_F_VLAN_CHALLENGED) + +diff --git a/net/8021q/vlan.h b/net/8021q/vlan.h +index c7ffe591d593..8a446f996172 100644 +--- a/net/8021q/vlan.h ++++ b/net/8021q/vlan.h +@@ -109,7 +109,7 @@ static inline netdev_features_t vlan_tnl_features(struct net_device *real_dev) + netdev_features_t ret; + + ret = real_dev->hw_enc_features & +- (NETIF_F_CSUM_MASK | NETIF_F_GSO_SOFTWARE | ++ (NETIF_F_CSUM_MASK | NETIF_F_GSO_SOFTWARE_ALL | + NETIF_F_GSO_ENCAP_ALL); + + if ((ret & NETIF_F_GSO_ENCAP_ALL) && (ret & NETIF_F_CSUM_MASK)) +diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c +index 9184cf7eb128..3cecafc13a3e 100644 +--- a/net/8021q/vlan_dev.c ++++ b/net/8021q/vlan_dev.c +@@ -538,7 +538,7 @@ static int vlan_dev_init(struct net_device *dev) + dev->state |= (1 << __LINK_STATE_NOCARRIER); + + dev->hw_features = NETIF_F_HW_CSUM | NETIF_F_SG | +- NETIF_F_FRAGLIST | NETIF_F_GSO_SOFTWARE | ++ NETIF_F_FRAGLIST | NETIF_F_GSO_SOFTWARE_ALL | + NETIF_F_GSO_ENCAP_ALL | + NETIF_F_HIGHDMA | NETIF_F_SCTP_CRC | + NETIF_F_FCOE_CRC | NETIF_F_FSO; +@@ -634,7 +634,7 @@ static netdev_features_t vlan_dev_fix_features(struct net_device *dev, + if (lower_features & (NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM)) + lower_features |= NETIF_F_HW_CSUM; + features = netdev_intersect_features(features, lower_features); +- features |= old_features & (NETIF_F_SOFT_FEATURES | NETIF_F_GSO_SOFTWARE); ++ features |= old_features & (NETIF_F_SOFT_FEATURES | NETIF_F_GSO_SOFTWARE_ALL); + + return features; + } +diff --git a/net/core/sock.c b/net/core/sock.c +index a5f248a91404..57fafa7cb47b 100644 +--- a/net/core/sock.c ++++ b/net/core/sock.c +@@ -2554,7 +2554,7 @@ void sk_setup_caps(struct sock *sk, struct dst_entry *dst) + icsk->icsk_ack.dst_quick_ack = dst_metric(dst, RTAX_QUICKACK); + } + if (sk->sk_route_caps & NETIF_F_GSO) +- sk->sk_route_caps |= NETIF_F_GSO_SOFTWARE; ++ sk->sk_route_caps |= NETIF_F_GSO_SOFTWARE_ALL; + if (unlikely(sk->sk_gso_disabled)) + sk->sk_route_caps &= ~NETIF_F_GSO_MASK; + if (sk_can_gso(sk)) { +diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h +index 2f017dbbcb97..6289ba270e23 100644 +--- a/net/mac80211/ieee80211_i.h ++++ b/net/mac80211/ieee80211_i.h +@@ -2021,7 +2021,7 @@ void ieee80211_color_collision_detection_work(struct wiphy *wiphy, + /* interface handling */ + #define MAC80211_SUPPORTED_FEATURES_TX (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | \ + NETIF_F_HW_CSUM | NETIF_F_SG | \ +- NETIF_F_HIGHDMA | NETIF_F_GSO_SOFTWARE | \ ++ NETIF_F_HIGHDMA | NETIF_F_GSO_SOFTWARE_ALL | \ + NETIF_F_HW_TC) + #define MAC80211_SUPPORTED_FEATURES_RX (NETIF_F_RXCSUM) + #define MAC80211_SUPPORTED_FEATURES (MAC80211_SUPPORTED_FEATURES_TX | \ +diff --git a/net/openvswitch/vport-internal_dev.c b/net/openvswitch/vport-internal_dev.c +index 5858d65ea1a9..2bc32affb98a 100644 +--- a/net/openvswitch/vport-internal_dev.c ++++ b/net/openvswitch/vport-internal_dev.c +@@ -109,7 +109,7 @@ static void do_setup(struct net_device *netdev) + netdev->rtnl_link_ops = &internal_dev_link_ops; + + netdev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA | +- NETIF_F_HW_CSUM | NETIF_F_GSO_SOFTWARE | ++ NETIF_F_HW_CSUM | NETIF_F_GSO_SOFTWARE_ALL | + NETIF_F_GSO_ENCAP_ALL; + + netdev->vlan_features = netdev->features; +-- +2.51.0 + + +From 1d33d41f90da611376b78c3db81b12643fd330da Mon Sep 17 00:00:00 2001 +From: OpenWrt community +Date: Wed, 13 Jul 2022 12:22:48 +0200 +Subject: [PATCH 267/517] of/of_net: write back netdev MAC-address to + device-tree + +The label-mac logic relies on the mac-address property of a netdev +devices of-node. However, the mac address can also be stored as a +different property or read from e.g. an mtd device. + +Create this node when reading a mac-address from OF if it does not +already exist and copy the mac-address used for the device to this +property. This way, the MAC address can be accessed using procfs. +--- + net/core/of_net.c | 35 +++++++++++++++++++++++++++++++---- + 1 file changed, 31 insertions(+), 4 deletions(-) + +diff --git a/net/core/of_net.c b/net/core/of_net.c +index 93ea425b9248..2497ae67dad5 100644 +--- a/net/core/of_net.c ++++ b/net/core/of_net.c +@@ -97,6 +97,27 @@ int of_get_mac_address_nvmem(struct device_node *np, u8 *addr) + } + EXPORT_SYMBOL(of_get_mac_address_nvmem); + ++static int of_add_mac_address(struct device_node *np, u8* addr) ++{ ++ struct property *prop; ++ ++ prop = kzalloc(sizeof(*prop), GFP_KERNEL); ++ if (!prop) ++ return -ENOMEM; ++ ++ prop->name = "mac-address"; ++ prop->length = ETH_ALEN; ++ prop->value = kmemdup(addr, ETH_ALEN, GFP_KERNEL); ++ if (!prop->value || of_update_property(np, prop)) ++ goto free; ++ ++ return 0; ++free: ++ kfree(prop->value); ++ kfree(prop); ++ return -ENOMEM; ++} ++ + /** + * of_get_mac_address() + * @np: Caller's Device Node +@@ -132,17 +153,23 @@ int of_get_mac_address(struct device_node *np, u8 *addr) + + ret = of_get_mac_addr(np, "mac-address", addr); + if (!ret) +- return 0; ++ goto found; + + ret = of_get_mac_addr(np, "local-mac-address", addr); + if (!ret) +- return 0; ++ goto found; + + ret = of_get_mac_addr(np, "address", addr); + if (!ret) +- return 0; ++ goto found; + +- return of_get_mac_address_nvmem(np, addr); ++ ret = of_get_mac_address_nvmem(np, addr); ++ if (ret) ++ return ret; ++ ++found: ++ ret = of_add_mac_address(np, addr); ++ return ret; + } + EXPORT_SYMBOL(of_get_mac_address); + +-- +2.51.0 + + +From f601c2883cdc25ee169350d3477da082fe5c5779 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Tue, 7 May 2024 11:24:50 +0200 +Subject: [PATCH 268/517] net: add missing check for TCP fraglist GRO + +It turns out that the existing checks do not guarantee that the skb can be +pulled up to the GRO offset. When using the usb r8152 network driver with +GRO fraglist, the BUG() in __skb_pull is often triggered. +Fix the crash by adding the missing check. + +Fixes: 8d95dc474f85 ("net: add code for TCP fraglist GRO") +Signed-off-by: Felix Fietkau +--- + net/ipv4/tcp_offload.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/ipv4/tcp_offload.c b/net/ipv4/tcp_offload.c +index 3a9c5c14c310..eaf92be2d7fe 100644 +--- a/net/ipv4/tcp_offload.c ++++ b/net/ipv4/tcp_offload.c +@@ -354,6 +354,7 @@ struct sk_buff *tcp_gro_receive(struct list_head *head, struct sk_buff *skb, + flush |= (__force int)(flags ^ tcp_flag_word(th2)); + flush |= skb->ip_summed != p->ip_summed; + flush |= skb->csum_level != p->csum_level; ++ flush |= !pskb_may_pull(skb, skb_gro_offset(skb)); + flush |= NAPI_GRO_CB(p)->count >= 64; + skb_set_network_header(skb, skb_gro_receive_network_offset(skb)); + +-- +2.51.0 + + +From 7cdbd6508ee5fe893169c25d43598829a6fecc1d Mon Sep 17 00:00:00 2001 +From: Pablo Neira Ayuso +Date: Thu, 25 Jan 2018 12:58:55 +0100 +Subject: [PATCH 269/517] netfilter: nft_flow_offload: handle netdevice events + from nf_flow_table + +Move the code that deals with device events to the core. + +Signed-off-by: Pablo Neira Ayuso +--- + net/netfilter/nf_flow_table_core.c | 22 +++++++++++++++++++ + net/netfilter/nft_flow_offload.c | 35 +----------------------------- + 2 files changed, 23 insertions(+), 34 deletions(-) + +diff --git a/net/netfilter/nf_flow_table_core.c b/net/netfilter/nf_flow_table_core.c +index df72b0376970..54881f0e878a 100644 +--- a/net/netfilter/nf_flow_table_core.c ++++ b/net/netfilter/nf_flow_table_core.c +@@ -658,6 +658,23 @@ static struct pernet_operations nf_flow_table_net_ops = { + .exit_batch = nf_flow_table_pernet_exit, + }; + ++static int nf_flow_table_netdev_event(struct notifier_block *this, ++ unsigned long event, void *ptr) ++{ ++ struct net_device *dev = netdev_notifier_info_to_dev(ptr); ++ ++ if (event != NETDEV_DOWN) ++ return NOTIFY_DONE; ++ ++ nf_flow_table_cleanup(dev); ++ ++ return NOTIFY_DONE; ++} ++ ++static struct notifier_block flow_offload_netdev_notifier = { ++ .notifier_call = nf_flow_table_netdev_event, ++}; ++ + static int __init nf_flow_table_module_init(void) + { + int ret; +@@ -674,6 +691,10 @@ static int __init nf_flow_table_module_init(void) + if (ret) + goto out_bpf; + ++ ret = register_netdevice_notifier(&flow_offload_netdev_notifier); ++ if (ret) ++ goto out_bpf; ++ + return 0; + + out_bpf: +@@ -685,6 +706,7 @@ static int __init nf_flow_table_module_init(void) + + static void __exit nf_flow_table_module_exit(void) + { ++ unregister_netdevice_notifier(&flow_offload_netdev_notifier); + nf_flow_table_offload_exit(); + unregister_pernet_subsys(&nf_flow_table_net_ops); + } +diff --git a/net/netfilter/nft_flow_offload.c b/net/netfilter/nft_flow_offload.c +index da9ebd00b198..a7611b8a7ca2 100644 +--- a/net/netfilter/nft_flow_offload.c ++++ b/net/netfilter/nft_flow_offload.c +@@ -487,47 +487,14 @@ static struct nft_expr_type nft_flow_offload_type __read_mostly = { + .owner = THIS_MODULE, + }; + +-static int flow_offload_netdev_event(struct notifier_block *this, +- unsigned long event, void *ptr) +-{ +- struct net_device *dev = netdev_notifier_info_to_dev(ptr); +- +- if (event != NETDEV_DOWN) +- return NOTIFY_DONE; +- +- nf_flow_table_cleanup(dev); +- +- return NOTIFY_DONE; +-} +- +-static struct notifier_block flow_offload_netdev_notifier = { +- .notifier_call = flow_offload_netdev_event, +-}; +- + static int __init nft_flow_offload_module_init(void) + { +- int err; +- +- err = register_netdevice_notifier(&flow_offload_netdev_notifier); +- if (err) +- goto err; +- +- err = nft_register_expr(&nft_flow_offload_type); +- if (err < 0) +- goto register_expr; +- +- return 0; +- +-register_expr: +- unregister_netdevice_notifier(&flow_offload_netdev_notifier); +-err: +- return err; ++ return nft_register_expr(&nft_flow_offload_type); + } + + static void __exit nft_flow_offload_module_exit(void) + { + nft_unregister_expr(&nft_flow_offload_type); +- unregister_netdevice_notifier(&flow_offload_netdev_notifier); + } + + module_init(nft_flow_offload_module_init); +-- +2.51.0 + + +From 508c09b7af27f9d86d0dd3621932d17b40731195 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Thu, 31 Aug 2023 21:48:38 +0200 +Subject: [PATCH 270/517] netfilter: nf_tables: ignore -EOPNOTSUPP on flowtable + device offload setup + +On many embedded devices, it is common to configure flowtable offloading for +a mix of different devices, some of which have hardware offload support and +some of which don't. +The current code limits the ability of user space to properly set up such a +configuration by only allowing adding devices with hardware offload support to +a offload-enabled flowtable. +Given that offload-enabled flowtables also imply fallback to pure software +offloading, this limitation makes little sense. +Fix it by not bailing out when the offload setup returns -EOPNOTSUPP + +Signed-off-by: Felix Fietkau +--- + net/netfilter/nf_tables_api.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c +index 3028d388b293..3b94f0d3995c 100644 +--- a/net/netfilter/nf_tables_api.c ++++ b/net/netfilter/nf_tables_api.c +@@ -8666,7 +8666,7 @@ static int nft_register_flowtable_net_hooks(struct net *net, + err = flowtable->data.type->setup(&flowtable->data, + hook->ops.dev, + FLOW_BLOCK_BIND); +- if (err < 0) ++ if (err < 0 && err != -EOPNOTSUPP) + goto err_unregister_net_hooks; + + err = nf_register_net_hook(net, &hook->ops); +-- +2.51.0 + + +From 7c144c4befb80c567d4225bbd64484bbcaece728 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Mon, 21 Mar 2022 20:39:59 +0100 +Subject: [PATCH 271/517] net: ethernet: mtk_eth_soc: enable threaded NAPI + +This can improve performance under load by ensuring that NAPI processing is +not pinned on CPU 0. + +Signed-off-by: Felix Fietkau +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +index 2a0be107b3d7..e51ca80b4f15 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -5148,6 +5148,8 @@ static int mtk_probe(struct platform_device *pdev) + dev_err(eth->dev, "failed to allocated dummy device\n"); + goto err_unreg_netdev; + } ++ eth->dummy_dev->threaded = 1; ++ strcpy(eth->dummy_dev->name, "mtk_eth"); + netif_napi_add(eth->dummy_dev, ð->tx_napi, mtk_napi_tx); + netif_napi_add(eth->dummy_dev, ð->rx_napi, mtk_napi_rx); + +-- +2.51.0 + + +From 6fce75728838d9ed2cea822d5558eb619d3fd80a Mon Sep 17 00:00:00 2001 +From: Gabor Juhos +Date: Mon, 3 Nov 2025 15:49:57 +0100 +Subject: [PATCH 272/517] generic: add detach callback to struct phy_driver + +lede-commit: fe61fc2d7d0b3fb348b502f68f98243b3ddf5867 + +Signed-off-by: Gabor Juhos +--- + drivers/net/phy/phy_device.c | 3 +++ + include/linux/phy.h | 6 ++++++ + 2 files changed, 9 insertions(+) + +diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c +index 2e08d20a3cfb..6e81501e5687 100644 +--- a/drivers/net/phy/phy_device.c ++++ b/drivers/net/phy/phy_device.c +@@ -2037,6 +2037,9 @@ void phy_detach(struct phy_device *phydev) + phydev->devlink = NULL; + } + ++ if (phydev->drv && phydev->drv->detach) ++ phydev->drv->detach(phydev); ++ + if (phydev->sysfs_links) { + if (dev) + sysfs_remove_link(&dev->dev.kobj, "phydev"); +diff --git a/include/linux/phy.h b/include/linux/phy.h +index 85217937e489..b6c372ea4e2d 100644 +--- a/include/linux/phy.h ++++ b/include/linux/phy.h +@@ -1027,6 +1027,12 @@ struct phy_driver { + /** @handle_interrupt: Override default interrupt handling */ + irqreturn_t (*handle_interrupt)(struct phy_device *phydev); + ++ /* ++ * Called before an ethernet device is detached ++ * from the PHY. ++ */ ++ void (*detach)(struct phy_device *phydev); ++ + /** @remove: Clears up any memory if needed */ + void (*remove)(struct phy_device *phydev); + +-- +2.51.0 + + +From b164fe2b20f203a4b1456889693c9855179251c5 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Fri, 6 May 2022 21:38:42 +0200 +Subject: [PATCH 273/517] net: dsa: tag_mtk: add padding for tx packets + +Padding for transmitted packets needs to account for the special tag. +With not enough padding, garbage bytes are inserted by the switch at the +end of small packets. + +Fixes: 5cd8985a1909 ("net-next: dsa: add Mediatek tag RX/TX handler") +Signed-off-by: Felix Fietkau +--- + net/dsa/tag_mtk.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/net/dsa/tag_mtk.c b/net/dsa/tag_mtk.c +index b670e3c53e91..791f87349ba6 100644 +--- a/net/dsa/tag_mtk.c ++++ b/net/dsa/tag_mtk.c +@@ -29,6 +29,13 @@ static struct sk_buff *mtk_tag_xmit(struct sk_buff *skb, + + skb_set_queue_mapping(skb, dp->index); + ++ /* The Ethernet switch we are interfaced with needs packets to be at ++ * least 64 bytes (including FCS) otherwise their padding might be ++ * corrupted. With tags enabled, we need to make sure that packets are ++ * at least 68 bytes (including FCS and tag). ++ */ ++ eth_skb_pad(skb); ++ + /* Build the special tag after the MAC Source Address. If VLAN header + * is present, it's required that VLAN header and special tag is + * being combined. Only in this way we can allow the switch can parse +-- +2.51.0 + + +From 3d059952a5f51a3ee562b27a845b860bdeba7869 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Tue, 8 Oct 2024 23:58:41 +0100 +Subject: [PATCH 274/517] net: phy: populate host_interfaces when attaching PHY + +Use bitmask of interfaces supported by the MAC for the PHY to choose +from if the declared interface mode is among those using a single pair +of SerDes lanes. +This will allow 2500Base-T PHYs to switch to SGMII on most hosts, which +results in half-duplex being supported in case the MAC supports them. +Without this change, 2500Base-T PHYs will always operate in 2500Base-X +mode with rate-matching, which is not only wasteful in terms of energy +consumption, but also limits the supported interface modes to +full-duplex only. + +Signed-off-by: Daniel Golle +--- + drivers/net/phy/phylink.c | 21 ++++++++++++++++++++- + 1 file changed, 20 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c +index ede93109f9c5..e168766e465e 100644 +--- a/drivers/net/phy/phylink.c ++++ b/drivers/net/phy/phylink.c +@@ -2264,7 +2264,7 @@ int phylink_fwnode_phy_connect(struct phylink *pl, + { + struct fwnode_handle *phy_fwnode; + struct phy_device *phy_dev; +- int ret; ++ int i, ret; + + /* Fixed links and 802.3z are handled without needing a PHY */ + if (pl->cfg_link_an_mode == MLO_AN_FIXED || +@@ -2294,6 +2294,25 @@ int phylink_fwnode_phy_connect(struct phylink *pl, + if (pl->config->mac_requires_rxc) + flags |= PHY_F_RXC_ALWAYS_ON; + ++ /* Assume single-lane SerDes interface modes share the same ++ * lanes and allow the PHY to switch to slower also supported modes ++ */ ++ for (i = ARRAY_SIZE(phylink_sfp_interface_preference) - 1; i >= 0; i--) { ++ /* skip unsupported modes */ ++ if (!test_bit(phylink_sfp_interface_preference[i], pl->config->supported_interfaces)) ++ continue; ++ ++ __set_bit(phylink_sfp_interface_preference[i], phy_dev->host_interfaces); ++ ++ /* skip all faster modes */ ++ if (phylink_sfp_interface_preference[i] == pl->link_interface) ++ break; ++ } ++ ++ if (test_bit(pl->link_interface, phylink_sfp_interfaces)) ++ phy_interface_and(phy_dev->host_interfaces, phylink_sfp_interfaces, ++ pl->config->supported_interfaces); ++ + ret = phy_attach_direct(pl->netdev, phy_dev, flags, + pl->link_interface); + phy_device_free(phy_dev); +-- +2.51.0 + + +From 71873c04d3b023c84d1292d6ac910270998aece5 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Fri, 27 Aug 2021 12:22:32 +0200 +Subject: [PATCH 275/517] bridge: add knob for filtering rx/tx BPDU packets on + a port + +Some devices (e.g. wireless APs) can't have devices behind them be part of +a bridge topology with redundant links, due to address limitations. +Additionally, broadcast traffic on these devices is somewhat expensive, due to +the low data rate and wakeups of clients in powersave mode. +This knob can be used to ensure that BPDU packets are never sent or forwarded +to/from these devices + +Signed-off-by: Felix Fietkau +--- + include/linux/if_bridge.h | 1 + + include/uapi/linux/if_link.h | 1 + + net/bridge/br_forward.c | 5 +++++ + net/bridge/br_input.c | 2 ++ + net/bridge/br_netlink.c | 6 +++++- + net/bridge/br_stp_bpdu.c | 9 +++++++-- + net/bridge/br_sysfs_if.c | 2 ++ + net/core/rtnetlink.c | 6 ++++-- + 8 files changed, 27 insertions(+), 5 deletions(-) + +diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h +index 3ff96ae31bf6..cff03a1dfd68 100644 +--- a/include/linux/if_bridge.h ++++ b/include/linux/if_bridge.h +@@ -61,6 +61,7 @@ struct br_ip_list { + #define BR_PORT_LOCKED BIT(21) + #define BR_PORT_MAB BIT(22) + #define BR_NEIGH_VLAN_SUPPRESS BIT(23) ++#define BR_BPDU_FILTER BIT(24) + + #define BR_DEFAULT_AGEING_TIME (300 * HZ) + +diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h +index 2acc7687e017..493ca8617d33 100644 +--- a/include/uapi/linux/if_link.h ++++ b/include/uapi/linux/if_link.h +@@ -1094,6 +1094,7 @@ enum { + IFLA_BRPORT_MCAST_MAX_GROUPS, + IFLA_BRPORT_NEIGH_VLAN_SUPPRESS, + IFLA_BRPORT_BACKUP_NHID, ++ IFLA_BRPORT_BPDU_FILTER, + __IFLA_BRPORT_MAX + }; + #define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1) +diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c +index e19b583ff2c6..20925747f36e 100644 +--- a/net/bridge/br_forward.c ++++ b/net/bridge/br_forward.c +@@ -201,6 +201,7 @@ void br_flood(struct net_bridge *br, struct sk_buff *skb, + enum br_pkt_type pkt_type, bool local_rcv, bool local_orig, + u16 vid) + { ++ const unsigned char *dest = eth_hdr(skb)->h_dest; + struct net_bridge_port *prev = NULL; + struct net_bridge_port *p; + +@@ -218,6 +219,10 @@ void br_flood(struct net_bridge *br, struct sk_buff *skb, + case BR_PKT_MULTICAST: + if (!(p->flags & BR_MCAST_FLOOD) && skb->dev != br->dev) + continue; ++ if ((p->flags & BR_BPDU_FILTER) && ++ unlikely(is_link_local_ether_addr(dest) && ++ dest[5] == 0)) ++ continue; + break; + case BR_PKT_BROADCAST: + if (!(p->flags & BR_BCAST_FLOOD) && skb->dev != br->dev) +diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c +index 0332371d19ab..da0ccd6b0034 100644 +--- a/net/bridge/br_input.c ++++ b/net/bridge/br_input.c +@@ -368,6 +368,8 @@ static rx_handler_result_t br_handle_frame(struct sk_buff **pskb) + fwd_mask |= p->group_fwd_mask; + switch (dest[5]) { + case 0x00: /* Bridge Group Address */ ++ if (p->flags & BR_BPDU_FILTER) ++ goto drop; + /* If STP is turned off, + then must forward to keep loop detection */ + if (p->br->stp_enabled == BR_NO_STP || +diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c +index 6b97ae47f855..5a6fdf3f9c86 100644 +--- a/net/bridge/br_netlink.c ++++ b/net/bridge/br_netlink.c +@@ -190,6 +190,7 @@ static inline size_t br_port_info_size(void) + + nla_total_size(1) /* IFLA_BRPORT_LOCKED */ + + nla_total_size(1) /* IFLA_BRPORT_MAB */ + + nla_total_size(1) /* IFLA_BRPORT_NEIGH_VLAN_SUPPRESS */ ++ + nla_total_size(1) /* IFLA_BRPORT_BPDU_FILTER */ + + nla_total_size(sizeof(struct ifla_bridge_id)) /* IFLA_BRPORT_ROOT_ID */ + + nla_total_size(sizeof(struct ifla_bridge_id)) /* IFLA_BRPORT_BRIDGE_ID */ + + nla_total_size(sizeof(u16)) /* IFLA_BRPORT_DESIGNATED_PORT */ +@@ -282,7 +283,8 @@ static int br_port_fill_attrs(struct sk_buff *skb, + nla_put_u8(skb, IFLA_BRPORT_LOCKED, !!(p->flags & BR_PORT_LOCKED)) || + nla_put_u8(skb, IFLA_BRPORT_MAB, !!(p->flags & BR_PORT_MAB)) || + nla_put_u8(skb, IFLA_BRPORT_NEIGH_VLAN_SUPPRESS, +- !!(p->flags & BR_NEIGH_VLAN_SUPPRESS))) ++ !!(p->flags & BR_NEIGH_VLAN_SUPPRESS)) || ++ nla_put_u8(skb, IFLA_BRPORT_BPDU_FILTER, !!(p->flags & BR_BPDU_FILTER))) + return -EMSGSIZE; + + timerval = br_timer_value(&p->message_age_timer); +@@ -902,6 +904,7 @@ static const struct nla_policy br_port_policy[IFLA_BRPORT_MAX + 1] = { + [IFLA_BRPORT_MCAST_MAX_GROUPS] = { .type = NLA_U32 }, + [IFLA_BRPORT_NEIGH_VLAN_SUPPRESS] = NLA_POLICY_MAX(NLA_U8, 1), + [IFLA_BRPORT_BACKUP_NHID] = { .type = NLA_U32 }, ++ [IFLA_BRPORT_BPDU_FILTER] = { .type = NLA_U8 }, + }; + + /* Change the state of the port and notify spanning tree */ +@@ -970,6 +973,7 @@ static int br_setport(struct net_bridge_port *p, struct nlattr *tb[], + br_set_port_flag(p, tb, IFLA_BRPORT_MAB, BR_PORT_MAB); + br_set_port_flag(p, tb, IFLA_BRPORT_NEIGH_VLAN_SUPPRESS, + BR_NEIGH_VLAN_SUPPRESS); ++ br_set_port_flag(p, tb, IFLA_BRPORT_BPDU_FILTER, BR_BPDU_FILTER); + + if ((p->flags & BR_PORT_MAB) && + (!(p->flags & BR_PORT_LOCKED) || !(p->flags & BR_LEARNING))) { +diff --git a/net/bridge/br_stp_bpdu.c b/net/bridge/br_stp_bpdu.c +index 7895489ac6fe..34c7ae7c9d63 100644 +--- a/net/bridge/br_stp_bpdu.c ++++ b/net/bridge/br_stp_bpdu.c +@@ -80,7 +80,8 @@ void br_send_config_bpdu(struct net_bridge_port *p, struct br_config_bpdu *bpdu) + { + unsigned char buf[35]; + +- if (p->br->stp_enabled != BR_KERNEL_STP) ++ if (p->br->stp_enabled != BR_KERNEL_STP || ++ (p->flags & BR_BPDU_FILTER)) + return; + + buf[0] = 0; +@@ -127,7 +128,8 @@ void br_send_tcn_bpdu(struct net_bridge_port *p) + { + unsigned char buf[4]; + +- if (p->br->stp_enabled != BR_KERNEL_STP) ++ if (p->br->stp_enabled != BR_KERNEL_STP || ++ (p->flags & BR_BPDU_FILTER)) + return; + + buf[0] = 0; +@@ -172,6 +174,9 @@ void br_stp_rcv(const struct stp_proto *proto, struct sk_buff *skb, + if (!(br->dev->flags & IFF_UP)) + goto out; + ++ if (p->flags & BR_BPDU_FILTER) ++ goto out; ++ + if (p->state == BR_STATE_DISABLED) + goto out; + +diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c +index 74fdd8105dca..aee7c5902206 100644 +--- a/net/bridge/br_sysfs_if.c ++++ b/net/bridge/br_sysfs_if.c +@@ -240,6 +240,7 @@ BRPORT_ATTR_FLAG(multicast_flood, BR_MCAST_FLOOD); + BRPORT_ATTR_FLAG(broadcast_flood, BR_BCAST_FLOOD); + BRPORT_ATTR_FLAG(neigh_suppress, BR_NEIGH_SUPPRESS); + BRPORT_ATTR_FLAG(isolated, BR_ISOLATED); ++BRPORT_ATTR_FLAG(bpdu_filter, BR_BPDU_FILTER); + + #ifdef CONFIG_BRIDGE_IGMP_SNOOPING + static ssize_t show_multicast_router(struct net_bridge_port *p, char *buf) +@@ -292,6 +293,7 @@ static const struct brport_attribute *brport_attrs[] = { + &brport_attr_group_fwd_mask, + &brport_attr_neigh_suppress, + &brport_attr_isolated, ++ &brport_attr_bpdu_filter, + &brport_attr_backup_port, + NULL + }; +diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c +index 4d0ee1c9002a..e88f76b7ff00 100644 +--- a/net/core/rtnetlink.c ++++ b/net/core/rtnetlink.c +@@ -62,7 +62,7 @@ + #include "dev.h" + + #define RTNL_MAX_TYPE 50 +-#define RTNL_SLAVE_MAX_TYPE 44 ++#define RTNL_SLAVE_MAX_TYPE 45 + + struct rtnl_link { + rtnl_doit_func doit; +@@ -5012,7 +5012,9 @@ int ndo_dflt_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, + brport_nla_put_flag(skb, flags, mask, + IFLA_BRPORT_MCAST_FLOOD, BR_MCAST_FLOOD) || + brport_nla_put_flag(skb, flags, mask, +- IFLA_BRPORT_BCAST_FLOOD, BR_BCAST_FLOOD)) { ++ IFLA_BRPORT_BCAST_FLOOD, BR_BCAST_FLOOD) || ++ brport_nla_put_flag(skb, flags, mask, ++ IFLA_BRPORT_BPDU_FILTER, BR_BPDU_FILTER)) { + nla_nest_cancel(skb, protinfo); + goto nla_put_failure; + } +-- +2.51.0 + + +From a76fd2c1b182f24e3594eb106794b778f7287f1d Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Tue, 4 Jul 2023 22:50:12 +0200 +Subject: [PATCH 276/517] net: dsa: qca8k: implement lag_fdb_add/del ops + +Implement lag_fdb_add/del ops to correctly support using LAG interface. +Qca8k switch supports declaring fdb entry for link aggregation by simply +setting the DES_PORT bits to all the LAG member. + +Signed-off-by: Christian Marangi +--- + drivers/net/dsa/qca/qca8k-8xxx.c | 2 ++ + drivers/net/dsa/qca/qca8k-common.c | 36 ++++++++++++++++++++++++++++++ + drivers/net/dsa/qca/qca8k.h | 6 +++++ + 3 files changed, 44 insertions(+) + +diff --git a/drivers/net/dsa/qca/qca8k-8xxx.c b/drivers/net/dsa/qca/qca8k-8xxx.c +index 59b4a7240b58..de3d1227d1ae 100644 +--- a/drivers/net/dsa/qca/qca8k-8xxx.c ++++ b/drivers/net/dsa/qca/qca8k-8xxx.c +@@ -2031,6 +2031,8 @@ static const struct dsa_switch_ops qca8k_switch_ops = { + .port_fdb_add = qca8k_port_fdb_add, + .port_fdb_del = qca8k_port_fdb_del, + .port_fdb_dump = qca8k_port_fdb_dump, ++ .lag_fdb_add = qca8k_lag_fdb_add, ++ .lag_fdb_del = qca8k_lag_fdb_del, + .port_mdb_add = qca8k_port_mdb_add, + .port_mdb_del = qca8k_port_mdb_del, + .port_mirror_add = qca8k_port_mirror_add, +diff --git a/drivers/net/dsa/qca/qca8k-common.c b/drivers/net/dsa/qca/qca8k-common.c +index 560c74c4ac3d..2194f706aed5 100644 +--- a/drivers/net/dsa/qca/qca8k-common.c ++++ b/drivers/net/dsa/qca/qca8k-common.c +@@ -1234,6 +1234,42 @@ int qca8k_port_lag_leave(struct dsa_switch *ds, int port, + return qca8k_lag_refresh_portmap(ds, port, lag, true); + } + ++int qca8k_lag_fdb_add(struct dsa_switch *ds, struct dsa_lag lag, ++ const unsigned char *addr, u16 vid, ++ struct dsa_db db) ++{ ++ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; ++ struct dsa_port *dp; ++ u16 port_mask = 0; ++ ++ /* Set the vid to the port vlan id if no vid is set */ ++ if (!vid) ++ vid = QCA8K_PORT_VID_DEF; ++ ++ dsa_lag_foreach_port(dp, ds->dst, &lag) ++ port_mask |= BIT(dp->index); ++ ++ return qca8k_port_fdb_insert(priv, addr, port_mask, vid); ++} ++ ++int qca8k_lag_fdb_del(struct dsa_switch *ds, struct dsa_lag lag, ++ const unsigned char *addr, u16 vid, ++ struct dsa_db db) ++{ ++ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; ++ struct dsa_port *dp; ++ u16 port_mask = 0; ++ ++ /* Set the vid to the port vlan id if no vid is set */ ++ if (!vid) ++ vid = QCA8K_PORT_VID_DEF; ++ ++ dsa_lag_foreach_port(dp, ds->dst, &lag) ++ port_mask |= BIT(dp->index); ++ ++ return qca8k_fdb_del(priv, addr, port_mask, vid); ++} ++ + int qca8k_read_switch_id(struct qca8k_priv *priv) + { + u32 val; +diff --git a/drivers/net/dsa/qca/qca8k.h b/drivers/net/dsa/qca/qca8k.h +index 3664a2e2f1f6..894bd1f1e123 100644 +--- a/drivers/net/dsa/qca/qca8k.h ++++ b/drivers/net/dsa/qca/qca8k.h +@@ -592,5 +592,11 @@ int qca8k_port_lag_join(struct dsa_switch *ds, int port, struct dsa_lag lag, + struct netlink_ext_ack *extack); + int qca8k_port_lag_leave(struct dsa_switch *ds, int port, + struct dsa_lag lag); ++int qca8k_lag_fdb_add(struct dsa_switch *ds, struct dsa_lag lag, ++ const unsigned char *addr, u16 vid, ++ struct dsa_db db); ++int qca8k_lag_fdb_del(struct dsa_switch *ds, struct dsa_lag lag, ++ const unsigned char *addr, u16 vid, ++ struct dsa_db db); + + #endif /* __QCA8K_H */ +-- +2.51.0 + + +From 1ab637936c9a5b4385ad741d2228accb5d12580e Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Tue, 20 Jun 2023 21:48:24 +0200 +Subject: [PATCH 277/517] net: dsa: qca8k: enable flooding to both CPU port + +To permit a multi-CPU setup, flood all unknown frames to all CPU ports. +Each CPU port should have correct LOOKUP MEMBER configuration to +prevent receiving duplicate packets from user ports. + +Signed-off-by: Christian Marangi +--- + drivers/net/dsa/qca/qca8k-8xxx.c | 13 +++++-------- + 1 file changed, 5 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/dsa/qca/qca8k-8xxx.c b/drivers/net/dsa/qca/qca8k-8xxx.c +index de3d1227d1ae..552feb99d33c 100644 +--- a/drivers/net/dsa/qca/qca8k-8xxx.c ++++ b/drivers/net/dsa/qca/qca8k-8xxx.c +@@ -1913,15 +1913,12 @@ qca8k_setup(struct dsa_switch *ds) + } + } + +- /* Forward all unknown frames to CPU port for Linux processing +- * Notice that in multi-cpu config only one port should be set +- * for igmp, unknown, multicast and broadcast packet +- */ ++ /* Forward all unknown frames to CPU port for Linux processing */ + ret = qca8k_write(priv, QCA8K_REG_GLOBAL_FW_CTRL1, +- FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_MASK, BIT(cpu_port)) | +- FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_BC_DP_MASK, BIT(cpu_port)) | +- FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_MC_DP_MASK, BIT(cpu_port)) | +- FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_UC_DP_MASK, BIT(cpu_port))); ++ FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_MASK, dsa_cpu_ports(ds)) | ++ FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_BC_DP_MASK, dsa_cpu_ports(ds)) | ++ FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_MC_DP_MASK, dsa_cpu_ports(ds)) | ++ FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_UC_DP_MASK, dsa_cpu_ports(ds))); + if (ret) + return ret; + +-- +2.51.0 + + +From 5b32eeb255186bab8c0dc100a1b31b671bb89b69 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Tue, 20 Jun 2023 07:57:38 +0200 +Subject: [PATCH 278/517] net: dsa: qca8k: add support for port_change_master + +Add support for port_change_master to permit assigning an alternative +CPU port if the switch have both CPU port connected or create a LAG on +both CPU port and assign the LAG as DSA master. + +On port change master request, we check if the master is a LAG. +With LAG we compose the cpu_port_mask with the CPU port in the LAG, if +master is a simple dsa_port, we derive the index. + +Finally we apply the new cpu_port_mask to the LOOKUP MEMBER to permit +the port to receive packet by the new CPU port setup for the port and we +refresh the CPU ports LOOKUP MEMBER configuration to reflect the new +user port state. + +port_lag_join/leave is updated to refresh the user ports if we detect +that the LAG is a DSA master and we have user port using it as a master. + +Signed-off-by: Christian Marangi +--- + drivers/net/dsa/qca/qca8k-8xxx.c | 116 ++++++++++++++++++++++++++++++- + 1 file changed, 114 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/dsa/qca/qca8k-8xxx.c b/drivers/net/dsa/qca/qca8k-8xxx.c +index 552feb99d33c..aad8a20e72c7 100644 +--- a/drivers/net/dsa/qca/qca8k-8xxx.c ++++ b/drivers/net/dsa/qca/qca8k-8xxx.c +@@ -1750,6 +1750,117 @@ qca8k_get_tag_protocol(struct dsa_switch *ds, int port, + return DSA_TAG_PROTO_QCA; + } + ++static int qca8k_port_change_master(struct dsa_switch *ds, int port, ++ struct net_device *master, ++ struct netlink_ext_ack *extack) ++{ ++ struct dsa_switch_tree *dst = ds->dst; ++ struct qca8k_priv *priv = ds->priv; ++ u8 cpu_port_mask = 0; ++ struct dsa_port *dp; ++ u32 val; ++ int ret; ++ ++ /* With LAG of CPU port, compose the mask for port LOOKUP MEMBER */ ++ if (netif_is_lag_master(master)) { ++ struct dsa_lag *lag; ++ int id; ++ ++ id = dsa_lag_id(dst, master); ++ lag = dsa_lag_by_id(dst, id); ++ ++ dsa_lag_foreach_port(dp, dst, lag) ++ if (dsa_port_is_cpu(dp)) ++ cpu_port_mask |= BIT(dp->index); ++ } else { ++ dp = master->dsa_ptr; ++ cpu_port_mask |= BIT(dp->index); ++ } ++ ++ /* Connect port to new cpu port */ ++ ret = regmap_read(priv->regmap, QCA8K_PORT_LOOKUP_CTRL(port), &val); ++ if (ret) ++ return ret; ++ ++ /* Reset connected CPU port in port LOOKUP MEMBER */ ++ val &= ~dsa_cpu_ports(ds); ++ /* Assign the new CPU port in port LOOKUP MEMBER */ ++ val |= cpu_port_mask; ++ ++ ret = regmap_update_bits(priv->regmap, QCA8K_PORT_LOOKUP_CTRL(port), ++ QCA8K_PORT_LOOKUP_MEMBER, ++ val); ++ if (ret) ++ return ret; ++ ++ /* Refresh CPU port LOOKUP MEMBER with new port */ ++ dsa_tree_for_each_cpu_port(dp, ds->dst) { ++ u32 reg = QCA8K_PORT_LOOKUP_CTRL(dp->index); ++ ++ /* If CPU port in mask assign port, else remove port */ ++ if (BIT(dp->index) & cpu_port_mask) ++ ret = regmap_set_bits(priv->regmap, reg, BIT(port)); ++ else ++ ret = regmap_clear_bits(priv->regmap, reg, BIT(port)); ++ ++ if (ret) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int qca8k_port_lag_refresh_user_ports(struct dsa_switch *ds, ++ struct dsa_lag lag) ++{ ++ struct net_device *lag_dev = lag.dev; ++ struct dsa_port *dp; ++ int ret; ++ ++ /* Ignore if LAG is not a DSA master */ ++ if (!netif_is_lag_master(lag_dev)) ++ return 0; ++ ++ dsa_switch_for_each_user_port(dp, ds) { ++ /* Skip if assigned master is not the LAG */ ++ if (dsa_port_to_conduit(dp) != lag_dev) ++ continue; ++ ++ ret = qca8k_port_change_master(ds, dp->index, ++ lag_dev, NULL); ++ if (ret) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int qca8xxx_port_lag_join(struct dsa_switch *ds, int port, ++ struct dsa_lag lag, ++ struct netdev_lag_upper_info *info, ++ struct netlink_ext_ack *extack) ++{ ++ int ret; ++ ++ ret = qca8k_port_lag_join(ds, port, lag, info, extack); ++ if (ret) ++ return ret; ++ ++ return qca8k_port_lag_refresh_user_ports(ds, lag); ++} ++ ++static int qca8xxx_port_lag_leave(struct dsa_switch *ds, int port, ++ struct dsa_lag lag) ++{ ++ int ret; ++ ++ ret = qca8k_port_lag_leave(ds, port, lag); ++ if (ret) ++ return ret; ++ ++ return qca8k_port_lag_refresh_user_ports(ds, lag); ++} ++ + static void + qca8k_conduit_change(struct dsa_switch *ds, const struct net_device *conduit, + bool operational) +@@ -2039,8 +2150,9 @@ static const struct dsa_switch_ops qca8k_switch_ops = { + .port_vlan_del = qca8k_port_vlan_del, + .phylink_get_caps = qca8k_phylink_get_caps, + .get_phy_flags = qca8k_get_phy_flags, +- .port_lag_join = qca8k_port_lag_join, +- .port_lag_leave = qca8k_port_lag_leave, ++ .port_lag_join = qca8xxx_port_lag_join, ++ .port_lag_leave = qca8xxx_port_lag_leave, ++ .port_change_conduit = qca8k_port_change_master, + .conduit_state_change = qca8k_conduit_change, + .connect_tag_protocol = qca8k_connect_tag_protocol, + }; +-- +2.51.0 + + +From d4996d68368205d76f6d715a69bf755bc441e721 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Fri, 6 Oct 2023 12:44:00 +0200 +Subject: [PATCH 279/517] net: dsa: qca8k: enable assisted learning on CPU port + +Enable assisted learning on CPU port. + +It has been verified that there is a problem in packet roaming +from one BSS to another in the same security settings from one +physical R7800 to another physical R7800 where they are in the +same L2 broadcast domain backhauled/linked together via one +of the ethernet ports. +DHCP will fail to complete and traffic cannot flow for around 300 +seconds. + +Signed-off-by: Christian Marangi +--- + drivers/net/dsa/qca/qca8k-8xxx.c | 14 +++++++++----- + 1 file changed, 9 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/dsa/qca/qca8k-8xxx.c b/drivers/net/dsa/qca/qca8k-8xxx.c +index aad8a20e72c7..de56bbc09cf9 100644 +--- a/drivers/net/dsa/qca/qca8k-8xxx.c ++++ b/drivers/net/dsa/qca/qca8k-8xxx.c +@@ -2022,6 +2022,12 @@ qca8k_setup(struct dsa_switch *ds) + dev_err(priv->dev, "failed enabling QCA header mode on port %d", dp->index); + return ret; + } ++ ++ /* Disable learning by default on all ports */ ++ ret = regmap_clear_bits(priv->regmap, QCA8K_PORT_LOOKUP_CTRL(dp->index), ++ QCA8K_PORT_LOOKUP_LEARN); ++ if (ret) ++ return ret; + } + + /* Forward all unknown frames to CPU port for Linux processing */ +@@ -2051,11 +2057,6 @@ qca8k_setup(struct dsa_switch *ds) + if (ret) + return ret; + +- ret = regmap_clear_bits(priv->regmap, QCA8K_PORT_LOOKUP_CTRL(port), +- QCA8K_PORT_LOOKUP_LEARN); +- if (ret) +- return ret; +- + /* For port based vlans to work we need to set the + * default egress vid + */ +@@ -2107,6 +2108,9 @@ qca8k_setup(struct dsa_switch *ds) + /* Set max number of LAGs supported */ + ds->num_lag_ids = QCA8K_NUM_LAGS; + ++ /* HW learn on CPU port is limited and require manual setting */ ++ ds->assisted_learning_on_cpu_port = true; ++ + return 0; + } + +-- +2.51.0 + + +From cf6f77006d285fcf40f251a7988911316d99c134 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Sun, 2 Apr 2023 23:56:16 +0100 +Subject: [PATCH 280/517] net: phy: realtek: use genphy_soft_reset for 2.5G + PHYs + +Some vendor bootloaders do weird things with those PHYs which result in +link modes being reported wrongly. Start from a clean sheet by resetting +the PHY. + +Reported-by: Yevhen Kolomeiko +Signed-off-by: Daniel Golle +--- + drivers/net/phy/realtek/realtek_main.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c +index 114d219562f1..2d2ed0a9d360 100644 +--- a/drivers/net/phy/realtek/realtek_main.c ++++ b/drivers/net/phy/realtek/realtek_main.c +@@ -1675,6 +1675,7 @@ static struct phy_driver realtek_drvs[] = { + }, { + .name = "RTL8226 2.5Gbps PHY", + .match_phy_device = rtl8226_match_phy_device, ++ .soft_reset = genphy_soft_reset, + .get_features = rtl822x_get_features, + .config_aneg = rtl822x_config_aneg, + .read_status = rtl822x_read_status, +@@ -1685,6 +1686,7 @@ static struct phy_driver realtek_drvs[] = { + }, { + .match_phy_device = rtl8221b_match_phy_device, + .name = "RTL8226B_RTL8221B 2.5Gbps PHY", ++ .soft_reset = genphy_soft_reset, + .get_features = rtl822x_get_features, + .config_aneg = rtl822x_config_aneg, + .config_init = rtl822xb_config_init, +@@ -1707,6 +1709,7 @@ static struct phy_driver realtek_drvs[] = { + }, { + PHY_ID_MATCH_EXACT(0x001cc848), + .name = "RTL8226B-CG_RTL8221B-CG 2.5Gbps PHY", ++ .soft_reset = genphy_soft_reset, + .get_features = rtl822x_get_features, + .config_aneg = rtl822x_config_aneg, + .config_init = rtl822xb_config_init, +@@ -1719,6 +1722,7 @@ static struct phy_driver realtek_drvs[] = { + }, { + .match_phy_device = rtl8221b_vb_cg_c22_match_phy_device, + .name = "RTL8221B-VB-CG 2.5Gbps PHY (C22)", ++ .soft_reset = genphy_soft_reset, + .probe = rtl822x_probe, + .get_features = rtl822x_get_features, + .config_aneg = rtl822x_config_aneg, +@@ -1732,6 +1736,7 @@ static struct phy_driver realtek_drvs[] = { + }, { + .match_phy_device = rtl8221b_vb_cg_c45_match_phy_device, + .name = "RTL8221B-VB-CG 2.5Gbps PHY (C45)", ++ .soft_reset = rtl822x_c45_soft_reset, + .probe = rtl822x_probe, + .config_init = rtl822xb_config_init, + .get_rate_matching = rtl822xb_get_rate_matching, +@@ -1743,6 +1748,7 @@ static struct phy_driver realtek_drvs[] = { + }, { + .match_phy_device = rtl8221b_vn_cg_c22_match_phy_device, + .name = "RTL8221B-VM-CG 2.5Gbps PHY (C22)", ++ .soft_reset = genphy_soft_reset, + .probe = rtl822x_probe, + .get_features = rtl822x_get_features, + .config_aneg = rtl822x_config_aneg, +@@ -1756,6 +1762,7 @@ static struct phy_driver realtek_drvs[] = { + }, { + .match_phy_device = rtl8221b_vn_cg_c45_match_phy_device, + .name = "RTL8221B-VN-CG 2.5Gbps PHY (C45)", ++ .soft_reset = rtl822x_c45_soft_reset, + .probe = rtl822x_probe, + .config_init = rtl822xb_config_init, + .get_rate_matching = rtl822xb_get_rate_matching, +-- +2.51.0 + + +From d1c87314cf69950550a4c6e3a64c4c194006f502 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Mon, 3 Apr 2023 01:21:57 +0300 +Subject: [PATCH 281/517] net: phy: realtek: disable SGMII in-band AN for 2.5G + PHYs + +MAC drivers don't use SGMII in-band autonegotiation unless told to do so +in device tree using 'managed = "in-band-status"'. When using MDIO to +access a PHY, in-band-status is unneeded as we have link-status via +MDIO. Switch off SGMII in-band autonegotiation using magic values. + +Reported-by: Chen Minqiang +Reported-by: Chukun Pan +Reported-by: Yevhen Kolomeiko +Tested-by: Yevhen Kolomeiko +Signed-off-by: Daniel Golle +--- + drivers/net/phy/realtek/realtek_main.c | 34 ++++++++++++++++++++++---- + 1 file changed, 29 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c +index 2d2ed0a9d360..0b2ec2ee0cf3 100644 +--- a/drivers/net/phy/realtek/realtek_main.c ++++ b/drivers/net/phy/realtek/realtek_main.c +@@ -1035,8 +1035,8 @@ static int rtl822x_probe(struct phy_device *phydev) + static int rtl822x_set_serdes_option_mode(struct phy_device *phydev, bool gen1) + { + bool has_2500, has_sgmii; ++ int ret, val; + u16 mode; +- int ret; + + has_2500 = test_bit(PHY_INTERFACE_MODE_2500BASEX, + phydev->host_interfaces) || +@@ -1078,18 +1078,42 @@ static int rtl822x_set_serdes_option_mode(struct phy_device *phydev, bool gen1) + RTL822X_VND1_SERDES_OPTION, + RTL822X_VND1_SERDES_OPTION_MODE_MASK, + mode); +- if (gen1 || ret < 0) ++ if (ret < 0) + return ret; + +- ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6a04, 0x0503); ++ if (!gen1) { ++ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6a04, 0x0503); ++ if (ret < 0) ++ return ret; ++ ++ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6f10, 0xd455); ++ if (ret < 0) ++ return ret; ++ ++ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6f11, 0x8020); ++ if (ret < 0) ++ return ret; ++ } ++ ++ /* Disable SGMII AN */ ++ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x7588, 0x2); ++ if (ret < 0) ++ return ret; ++ ++ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x7589, 0x71d0); + if (ret < 0) + return ret; + +- ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6f10, 0xd455); ++ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x7587, 0x3); + if (ret < 0) + return ret; + +- return phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6f11, 0x8020); ++ ret = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1, 0x7587, ++ val, !(val & BIT(0)), 500, 100000, false); ++ if (ret < 0) ++ return ret; ++ ++ return 0; + } + + static int rtl822x_config_init(struct phy_device *phydev) +-- +2.51.0 + + +From 1b0e9bd766fd803b1df1b13ed2d6e4ac159f20d5 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Sat, 22 Apr 2023 01:21:14 +0100 +Subject: [PATCH 282/517] net: phy: realtek: make sure paged read is protected + by mutex + +As we cannot rely on phy_read_paged function before the PHY is +identified, the paged read in rtlgen_supports_2_5gbps needs to be open +coded as it is being called by the match_phy_device function, ie. before +.read_page and .write_page have been populated. + +Make sure it is also protected by the MDIO bus mutex and use +rtl821x_write_page instead of 3 individually locked MDIO bus operations. + +Signed-off-by: Daniel Golle +--- + drivers/net/phy/realtek/realtek_main.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c +index 0b2ec2ee0cf3..3bd9d52ce109 100644 +--- a/drivers/net/phy/realtek/realtek_main.c ++++ b/drivers/net/phy/realtek/realtek_main.c +@@ -1343,9 +1343,11 @@ static bool rtlgen_supports_2_5gbps(struct phy_device *phydev) + { + int val; + +- phy_write(phydev, RTL821x_PAGE_SELECT, 0xa61); +- val = phy_read(phydev, 0x13); +- phy_write(phydev, RTL821x_PAGE_SELECT, 0); ++ mutex_lock(&phydev->mdio.bus->mdio_lock); ++ rtl821x_write_page(phydev, 0xa61); ++ val = __phy_read(phydev, 0x13); ++ rtl821x_write_page(phydev, 0); ++ mutex_unlock(&phydev->mdio.bus->mdio_lock); + + return val >= 0 && val & MDIO_PMA_SPEED_2_5G; + } +-- +2.51.0 + + +From 6b913911a8983435f5435892606fe4e418b94f39 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Sat, 22 Apr 2023 03:26:01 +0100 +Subject: [PATCH 283/517] net: phy: realtek: setup ALDPS on RTL822x + +Setup Link Down Power Saving Mode according the DTS property +just like for RTL821x 1GE PHYs. + +Signed-off-by: Daniel Golle +--- + drivers/net/phy/realtek/realtek_main.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c +index 3bd9d52ce109..036b27ab244e 100644 +--- a/drivers/net/phy/realtek/realtek_main.c ++++ b/drivers/net/phy/realtek/realtek_main.c +@@ -129,6 +129,10 @@ + */ + #define RTL822X_VND2_C22_REG(reg) (0xa400 + 2 * (reg)) + ++#define RTL8221B_PHYCR1 0xa430 ++#define RTL8221B_PHYCR1_ALDPS_EN BIT(2) ++#define RTL8221B_PHYCR1_ALDPS_XTAL_OFF_EN BIT(12) ++ + #define RTL8366RB_POWER_SAVE 0x15 + #define RTL8366RB_POWER_SAVE_ON BIT(12) + +@@ -1095,6 +1099,15 @@ static int rtl822x_set_serdes_option_mode(struct phy_device *phydev, bool gen1) + return ret; + } + ++ if (of_property_read_bool(phydev->mdio.dev.of_node, "realtek,aldps-enable")) ++ ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, RTL8221B_PHYCR1, ++ RTL8221B_PHYCR1_ALDPS_EN | RTL8221B_PHYCR1_ALDPS_XTAL_OFF_EN); ++ else ++ ret = phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, RTL8221B_PHYCR1, ++ RTL8221B_PHYCR1_ALDPS_EN | RTL8221B_PHYCR1_ALDPS_XTAL_OFF_EN); ++ if (ret < 0) ++ return ret; ++ + /* Disable SGMII AN */ + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x7588, 0x2); + if (ret < 0) +-- +2.51.0 + + +From 4bc0f42ffef605a9a323a18105c572a0f26b7cdd Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Sun, 30 Apr 2023 00:15:41 +0100 +Subject: [PATCH 284/517] net: phy: realtek: detect early version of RTL8221B + +Early versions (?) of the RTL8221B PHY cannot be identified in a regular +Clause-45 bus scan as the PHY doesn't report the implemented MMDs +correctly but returns 0 instead. +Implement custom identify function using the PKGID instead of iterating +over the implemented MMDs. + +Signed-off-by: Daniel Golle +[forward-port by @namiltd] +Signed-off-by: Mieczyslaw Nalewaj +--- + drivers/net/phy/realtek/realtek_main.c | 28 +++++++++++++++++++++++--- + 1 file changed, 25 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c +index 036b27ab244e..88beb4c5c9db 100644 +--- a/drivers/net/phy/realtek/realtek_main.c ++++ b/drivers/net/phy/realtek/realtek_main.c +@@ -1400,10 +1400,32 @@ static int rtl8226_match_phy_device(struct phy_device *phydev, + static int rtlgen_is_c45_match(struct phy_device *phydev, unsigned int id, + bool is_c45) + { +- if (phydev->is_c45) +- return is_c45 && (id == phydev->c45_ids.device_ids[1]); +- else ++ if (phydev->is_c45) { ++ u32 rid; ++ ++ if (!is_c45) ++ return 0; ++ ++ rid = phydev->c45_ids.device_ids[1]; ++ if ((rid == 0xffffffff) && phydev->mdio.bus->read_c45) { ++ int val; ++ ++ val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PKGID1); ++ if (val < 0) ++ return 0; ++ ++ rid = val << 16; ++ val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PKGID2); ++ if (val < 0) ++ return 0; ++ ++ rid |= val; ++ } ++ ++ return (id == rid); ++ } else { + return !is_c45 && (id == phydev->phy_id); ++ } + } + + static int rtl8221b_match_phy_device(struct phy_device *phydev, +-- +2.51.0 + + +From d501f6a78763e0dfdce00fed1842bdb93f06b306 Mon Sep 17 00:00:00 2001 +From: Jianhui Zhao +Date: Sun, 24 Sep 2023 22:15:00 +0800 +Subject: [PATCH 285/517] net: phy: realtek: add interrupt support for RTL8221B + +This commit introduces interrupt support for RTL8221B. + +Signed-off-by: Jianhui Zhao +--- + drivers/net/phy/realtek/realtek_main.c | 53 ++++++++++++++++++++++++++ + 1 file changed, 53 insertions(+) + +diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c +index 88beb4c5c9db..c4cd0df5f971 100644 +--- a/drivers/net/phy/realtek/realtek_main.c ++++ b/drivers/net/phy/realtek/realtek_main.c +@@ -1619,6 +1619,51 @@ static irqreturn_t rtl9000a_handle_interrupt(struct phy_device *phydev) + return IRQ_HANDLED; + } + ++static int rtl8221b_ack_interrupt(struct phy_device *phydev) ++{ ++ int err; ++ ++ err = phy_read_mmd(phydev, MDIO_MMD_VEND2, 0xa4d4); ++ ++ return (err < 0) ? err : 0; ++} ++ ++static int rtl8221b_config_intr(struct phy_device *phydev) ++{ ++ int err; ++ ++ if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { ++ err = rtl8221b_ack_interrupt(phydev); ++ if (err) ++ return err; ++ ++ err = phy_write_mmd(phydev, MDIO_MMD_VEND2, 0xa4d2, 0x7ff); ++ } else { ++ err = phy_write_mmd(phydev, MDIO_MMD_VEND2, 0xa4d2, 0x0); ++ if (err) ++ return err; ++ ++ err = rtl8221b_ack_interrupt(phydev); ++ } ++ ++ return err; ++} ++ ++static irqreturn_t rtl8221b_handle_interrupt(struct phy_device *phydev) ++{ ++ int err; ++ ++ err = rtl8221b_ack_interrupt(phydev); ++ if (err) { ++ phy_error(phydev); ++ return IRQ_NONE; ++ } ++ ++ phy_trigger_machine(phydev); ++ ++ return IRQ_HANDLED; ++} ++ + static struct phy_driver realtek_drvs[] = { + { + PHY_ID_MATCH_EXACT(0x00008201), +@@ -1783,6 +1828,8 @@ static struct phy_driver realtek_drvs[] = { + }, { + .match_phy_device = rtl8221b_vb_cg_c22_match_phy_device, + .name = "RTL8221B-VB-CG 2.5Gbps PHY (C22)", ++ .config_intr = rtl8221b_config_intr, ++ .handle_interrupt = rtl8221b_handle_interrupt, + .soft_reset = genphy_soft_reset, + .probe = rtl822x_probe, + .get_features = rtl822x_get_features, +@@ -1797,6 +1844,8 @@ static struct phy_driver realtek_drvs[] = { + }, { + .match_phy_device = rtl8221b_vb_cg_c45_match_phy_device, + .name = "RTL8221B-VB-CG 2.5Gbps PHY (C45)", ++ .config_intr = rtl8221b_config_intr, ++ .handle_interrupt = rtl8221b_handle_interrupt, + .soft_reset = rtl822x_c45_soft_reset, + .probe = rtl822x_probe, + .config_init = rtl822xb_config_init, +@@ -1809,6 +1858,8 @@ static struct phy_driver realtek_drvs[] = { + }, { + .match_phy_device = rtl8221b_vn_cg_c22_match_phy_device, + .name = "RTL8221B-VM-CG 2.5Gbps PHY (C22)", ++ .config_intr = rtl8221b_config_intr, ++ .handle_interrupt = rtl8221b_handle_interrupt, + .soft_reset = genphy_soft_reset, + .probe = rtl822x_probe, + .get_features = rtl822x_get_features, +@@ -1823,6 +1874,8 @@ static struct phy_driver realtek_drvs[] = { + }, { + .match_phy_device = rtl8221b_vn_cg_c45_match_phy_device, + .name = "RTL8221B-VN-CG 2.5Gbps PHY (C45)", ++ .config_intr = rtl8221b_config_intr, ++ .handle_interrupt = rtl8221b_handle_interrupt, + .soft_reset = rtl822x_c45_soft_reset, + .probe = rtl822x_probe, + .config_init = rtl822xb_config_init, +-- +2.51.0 + + +From 9715b901b205b49e6d1a24c5915ffef7936afd23 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Thu, 23 Jan 2025 03:25:29 +0000 +Subject: [PATCH 286/517] net: phy: realtek: mark existing MMDs as present + +When using Clause-45 mode to access RealTek RTL8221B 2.5G PHYs some +versions of the PHY fail to report the MMDs present on the PHY. +Mark MMDs PMAPMD, PCS and AN which are always existing according to +the datasheet as present to fix that. + +Signed-off-by: Daniel Golle +--- + drivers/net/phy/realtek/realtek_main.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c +index c4cd0df5f971..cd4c452508ae 100644 +--- a/drivers/net/phy/realtek/realtek_main.c ++++ b/drivers/net/phy/realtek/realtek_main.c +@@ -1259,6 +1259,9 @@ static int rtl822x_c45_get_features(struct phy_device *phydev) + linkmode_set_bit(ETHTOOL_LINK_MODE_TP_BIT, + phydev->supported); + ++ phydev->c45_ids.mmds_present |= MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | ++ MDIO_DEVS_AN; ++ + return genphy_c45_pma_read_abilities(phydev); + } + +-- +2.51.0 + + +From 5348f3256a254426ca1fd4c6e828e2b5bd1913d9 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Thu, 30 Jan 2025 05:33:12 +0000 +Subject: [PATCH 287/517] net: phy: realtek: work around broken SerDes + +For still unknown reasons the SerDes init sequence may sometimes +time out because a self-clearing bit never clears, indicating the +PHY has entered an unrecoverable error state. + +Work-around the issue by triggering a hardware reset and retry the +setup sequence while warning the user that this has happened. +This is really more of a work-around than a fix, and should be +replaced by a better actual fix in future (hopefully). + +Signed-off-by: Daniel Golle +--- + drivers/net/phy/realtek/realtek_main.c | 20 ++++++++++++++++++-- + 1 file changed, 18 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c +index cd4c452508ae..7620935988ce 100644 +--- a/drivers/net/phy/realtek/realtek_main.c ++++ b/drivers/net/phy/realtek/realtek_main.c +@@ -1139,6 +1139,22 @@ static int rtl822xb_config_init(struct phy_device *phydev) + return rtl822x_set_serdes_option_mode(phydev, false); + } + ++static int rtl822xb_config_init_war(struct phy_device *phydev) ++{ ++ int ret; ++ ++ ret = rtl822xb_config_init(phydev); ++ ++ if (ret == -ETIMEDOUT) { ++ phydev_warn(phydev, "SerDes setup timed out, retrying\n"); ++ phy_device_reset(phydev, 1); ++ phy_device_reset(phydev, 0); ++ ret = rtl822xb_config_init(phydev); ++ } ++ ++ return ret; ++} ++ + static int rtl822xb_get_rate_matching(struct phy_device *phydev, + phy_interface_t iface) + { +@@ -1851,7 +1867,7 @@ static struct phy_driver realtek_drvs[] = { + .handle_interrupt = rtl8221b_handle_interrupt, + .soft_reset = rtl822x_c45_soft_reset, + .probe = rtl822x_probe, +- .config_init = rtl822xb_config_init, ++ .config_init = rtl822xb_config_init_war, + .get_rate_matching = rtl822xb_get_rate_matching, + .get_features = rtl822x_c45_get_features, + .config_aneg = rtl822x_c45_config_aneg, +@@ -1881,7 +1897,7 @@ static struct phy_driver realtek_drvs[] = { + .handle_interrupt = rtl8221b_handle_interrupt, + .soft_reset = rtl822x_c45_soft_reset, + .probe = rtl822x_probe, +- .config_init = rtl822xb_config_init, ++ .config_init = rtl822xb_config_init_war, + .get_rate_matching = rtl822xb_get_rate_matching, + .get_features = rtl822x_c45_get_features, + .config_aneg = rtl822x_c45_config_aneg, +-- +2.51.0 + + +From 90d35efb01b9a152f1409a9029eae2e344115750 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Thu, 30 Jan 2025 05:38:31 +0000 +Subject: [PATCH 288/517] net: phy: realtek: disable MDIO broadcast + +RealTek's PHYs by default also listen on MDIO address 0 which is defined +as broadcast address. This can lead to problems if there is an actual PHY +(such as MT7981 built-in PHY) present at this address, as accessing that +PHY may then confuse the RealTek PHY. + +Disabled listening on the MDIO broadcast address to avoid such problems. + +Signed-off-by: Daniel Golle +--- + drivers/net/phy/realtek/realtek_main.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c +index 7620935988ce..d9455b8a3db7 100644 +--- a/drivers/net/phy/realtek/realtek_main.c ++++ b/drivers/net/phy/realtek/realtek_main.c +@@ -1050,6 +1050,11 @@ static int rtl822x_set_serdes_option_mode(struct phy_device *phydev, bool gen1) + phydev->host_interfaces) || + phydev->interface == PHY_INTERFACE_MODE_SGMII; + ++ /* disable listening on MDIO broadcast address (0) */ ++ ret = phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, 0xa430, BIT(13)); ++ if (ret < 0) ++ return ret; ++ + /* fill in possible interfaces */ + __assign_bit(PHY_INTERFACE_MODE_2500BASEX, phydev->possible_interfaces, + has_2500); +-- +2.51.0 + + +From f90b4d719f26a1089016a54d8a675d44654649e1 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Thu, 20 Oct 2022 03:34:43 +0200 +Subject: [PATCH 289/517] net: permit ieee80211_ptr even with no CFG82111 + support + +Introduce a new flag CONFIG_CFG80211_HEADERS to compile in ieee80211_ptr +even if CFG80211 support is not compiled in. This is needed for the +backports project and for any downstream wireless driver that loads in +the kernel dynamically. + +Signed-off-by: Christian Marangi +--- + include/linux/netdevice.h | 2 +- + net/batman-adv/hard-interface.c | 2 +- + net/wireless/Kconfig | 4 ++++ + 3 files changed, 6 insertions(+), 2 deletions(-) + +diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h +index 35b886385f32..c0a26b22f590 100644 +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -2224,7 +2224,7 @@ struct net_device { + #if IS_ENABLED(CONFIG_AX25) + struct ax25_dev __rcu *ax25_ptr; + #endif +-#if IS_ENABLED(CONFIG_CFG80211) ++#if IS_ENABLED(CONFIG_CFG80211_HEADERS) + struct wireless_dev *ieee80211_ptr; + #endif + #if IS_ENABLED(CONFIG_IEEE802154) || IS_ENABLED(CONFIG_6LOWPAN) +diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c +index 96a412beab2d..abfa4dc9e050 100644 +--- a/net/batman-adv/hard-interface.c ++++ b/net/batman-adv/hard-interface.c +@@ -309,7 +309,7 @@ static bool batadv_is_cfg80211_netdev(struct net_device *net_device) + if (!net_device) + return false; + +-#if IS_ENABLED(CONFIG_CFG80211) ++#if IS_ENABLED(CONFIG_CFG80211_HEADERS) + /* cfg80211 drivers have to set ieee80211_ptr */ + if (net_device->ieee80211_ptr) + return true; +diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig +index 10345388ad13..c141a1b74240 100644 +--- a/net/wireless/Kconfig ++++ b/net/wireless/Kconfig +@@ -26,6 +26,7 @@ config CFG80211 + # using a different algorithm, though right now they shouldn't + # (this is here rather than below to allow it to be a module) + select CRYPTO_SHA256 if CFG80211_USE_KERNEL_REGDB_KEYS ++ select CFG80211_HEADERS + help + cfg80211 is the Linux wireless LAN (802.11) configuration API. + Enable this if you have a wireless device. +@@ -36,6 +37,9 @@ config CFG80211 + + When built as a module it will be called cfg80211. + ++config CFG80211_HEADERS ++ bool "cfg80211 - headers support" ++ + if CFG80211 + + config NL80211_TESTMODE +-- +2.51.0 + + +From adbd719bddb099f80db240cd3d80788d7d76096a Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Thu, 27 Oct 2022 23:39:52 +0200 +Subject: [PATCH 290/517] net: ethernet: mtk_eth_soc: compile out netsys v2 + code on mt7621 + +Avoid some branches in the hot path on low-end devices with limited CPU power, +and reduce code size + +Signed-off-by: Felix Fietkau +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +index 723475570ff7..232659c596c4 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -1344,6 +1344,22 @@ struct mtk_mac { + /* the struct describing the SoC. these are declared in the soc_xyz.c files */ + extern const struct of_device_id of_mtk_match[]; + ++#ifdef CONFIG_SOC_MT7621 ++static inline bool mtk_is_netsys_v1(struct mtk_eth *eth) ++{ ++ return true; ++} ++ ++static inline bool mtk_is_netsys_v2_or_greater(struct mtk_eth *eth) ++{ ++ return false; ++} ++ ++static inline bool mtk_is_netsys_v3_or_greater(struct mtk_eth *eth) ++{ ++ return false; ++} ++#else + static inline bool mtk_is_netsys_v1(struct mtk_eth *eth) + { + return eth->soc->version == 1; +@@ -1358,6 +1374,7 @@ static inline bool mtk_is_netsys_v3_or_greater(struct mtk_eth *eth) + { + return eth->soc->version > 2; + } ++#endif + + static inline struct mtk_foe_entry * + mtk_foe_get_entry(struct mtk_ppe *ppe, u16 hash) +-- +2.51.0 + + +From 8586fb600da61306b61d7a714af292fbf5e1ce43 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Thu, 3 Nov 2022 12:38:49 +0100 +Subject: [PATCH 291/517] net: ethernet: mtk_eth_soc: work around issue with + sending small fragments + +When lots of frames are sent with a number of very small fragments, an +internal FIFO can overflow, causing the DMA engine to lock up lock up and +transmit attempts time out. + +Fix this on MT7986 by increasing the reserved FIFO space. +Fix this on older chips by detecting the presence of small fragments and use +skb_gso_segment + skb_linearize to deal with them. + +Signed-off-by: Felix Fietkau +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 39 +++++++++++++++++++-- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 2 +- + 2 files changed, 38 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +index e51ca80b4f15..0ab06e1ce084 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + #include + + #include "mtk_eth_soc.h" +@@ -1607,12 +1608,28 @@ static void mtk_wake_queue(struct mtk_eth *eth) + } + } + ++static bool mtk_skb_has_small_frag(struct sk_buff *skb) ++{ ++ int min_size = 16; ++ int i; ++ ++ if (skb_headlen(skb) < min_size) ++ return true; ++ ++ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) ++ if (skb_frag_size(&skb_shinfo(skb)->frags[i]) < min_size) ++ return true; ++ ++ return false; ++} ++ + static netdev_tx_t mtk_start_xmit(struct sk_buff *skb, struct net_device *dev) + { + struct mtk_mac *mac = netdev_priv(dev); + struct mtk_eth *eth = mac->hw; + struct mtk_tx_ring *ring = ð->tx_ring; + struct net_device_stats *stats = &dev->stats; ++ struct sk_buff *segs, *next; + bool gso = false; + int tx_num; + +@@ -1641,6 +1658,18 @@ static netdev_tx_t mtk_start_xmit(struct sk_buff *skb, struct net_device *dev) + return NETDEV_TX_BUSY; + } + ++ if (mtk_is_netsys_v1(eth) && ++ skb_is_gso(skb) && mtk_skb_has_small_frag(skb)) { ++ segs = skb_gso_segment(skb, dev->features & ~NETIF_F_ALL_TSO); ++ if (IS_ERR(segs)) ++ goto drop; ++ ++ if (segs) { ++ consume_skb(skb); ++ skb = segs; ++ } ++ } ++ + /* TSO: fill MSS info in tcp checksum field */ + if (skb_is_gso(skb)) { + if (skb_cow_head(skb, 0)) { +@@ -1656,8 +1685,14 @@ static netdev_tx_t mtk_start_xmit(struct sk_buff *skb, struct net_device *dev) + } + } + +- if (mtk_tx_map(skb, dev, tx_num, ring, gso) < 0) +- goto drop; ++ skb_list_walk_safe(skb, skb, next) { ++ if ((mtk_is_netsys_v1(eth) && ++ mtk_skb_has_small_frag(skb) && skb_linearize(skb)) || ++ mtk_tx_map(skb, dev, tx_num, ring, gso) < 0) { ++ stats->tx_dropped++; ++ dev_kfree_skb_any(skb); ++ } ++ } + + if (unlikely(atomic_read(&ring->free_count) <= ring->thresh)) + netif_tx_stop_all_queues(dev); +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +index 232659c596c4..45ca9c17683a 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -278,7 +278,7 @@ + #define MTK_CHK_DDONE_EN BIT(28) + #define MTK_DMAD_WR_WDONE BIT(26) + #define MTK_WCOMP_EN BIT(24) +-#define MTK_RESV_BUF (0x40 << 16) ++#define MTK_RESV_BUF (0x80 << 16) + #define MTK_MUTLI_CNT (0x4 << 12) + #define MTK_LEAKY_BUCKET_EN BIT(11) + +-- +2.51.0 + + +From badd05196d60a325cb7fc144c802fb6354b219aa Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Tue, 15 Oct 2024 12:52:56 +0200 +Subject: [PATCH 292/517] net: ethernet: mtk_eth_soc: optimize dma ring + address/index calculation + +Since DMA descriptor sizes are all power of 2, we can avoid costly integer +division in favor or simple shifts. + +Signed-off-by: Felix Fietkau +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 112 +++++++++++--------- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 6 +- + 2 files changed, 62 insertions(+), 56 deletions(-) + +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +index 0ab06e1ce084..ff25dba46922 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -43,6 +43,11 @@ MODULE_PARM_DESC(msg_level, "Message level (-1=defaults,0=none,...,16=all)"); + offsetof(struct mtk_hw_stats, xdp_stats.x) / \ + sizeof(u64) } + ++#define RX_DESC_OFS(eth, i) \ ++ ((i) << (eth)->soc->rx.desc_shift) ++#define TX_DESC_OFS(eth, i) \ ++ ((i) << (eth)->soc->tx.desc_shift) ++ + static const struct mtk_reg_map mtk_reg_map = { + .tx_irq_mask = 0x1a1c, + .tx_irq_status = 0x1a18, +@@ -1160,14 +1165,14 @@ static int mtk_init_fq_dma(struct mtk_eth *eth) + eth->scratch_ring = eth->sram_base; + else + eth->scratch_ring = dma_alloc_coherent(eth->dma_dev, +- cnt * soc->tx.desc_size, ++ TX_DESC_OFS(eth, cnt), + ð->phy_scratch_ring, + GFP_KERNEL); + + if (unlikely(!eth->scratch_ring)) + return -ENOMEM; + +- phy_ring_tail = eth->phy_scratch_ring + soc->tx.desc_size * (cnt - 1); ++ phy_ring_tail = eth->phy_scratch_ring + TX_DESC_OFS(eth, cnt - 1); + + for (j = 0; j < DIV_ROUND_UP(soc->tx.fq_dma_size, MTK_FQ_DMA_LENGTH); j++) { + len = min_t(int, cnt - j * MTK_FQ_DMA_LENGTH, MTK_FQ_DMA_LENGTH); +@@ -1186,11 +1191,11 @@ static int mtk_init_fq_dma(struct mtk_eth *eth) + for (i = 0; i < len; i++) { + struct mtk_tx_dma_v2 *txd; + +- txd = eth->scratch_ring + (j * MTK_FQ_DMA_LENGTH + i) * soc->tx.desc_size; ++ txd = eth->scratch_ring + TX_DESC_OFS(eth, j * MTK_FQ_DMA_LENGTH + i); + txd->txd1 = dma_addr + i * MTK_QDMA_PAGE_SIZE; + if (j * MTK_FQ_DMA_LENGTH + i < cnt) + txd->txd2 = eth->phy_scratch_ring + +- (j * MTK_FQ_DMA_LENGTH + i + 1) * soc->tx.desc_size; ++ TX_DESC_OFS(eth, j * MTK_FQ_DMA_LENGTH + i + 1); + + txd->txd3 = TX_DMA_PLEN0(MTK_QDMA_PAGE_SIZE); + if (MTK_HAS_CAPS(soc->caps, MTK_36BIT_DMA)) +@@ -1220,9 +1225,9 @@ static void *mtk_qdma_phys_to_virt(struct mtk_tx_ring *ring, u32 desc) + } + + static struct mtk_tx_buf *mtk_desc_to_tx_buf(struct mtk_tx_ring *ring, +- void *txd, u32 txd_size) ++ void *txd, u32 txd_shift) + { +- int idx = (txd - ring->dma) / txd_size; ++ int idx = (txd - ring->dma) >> txd_shift; + + return &ring->buf[idx]; + } +@@ -1233,9 +1238,9 @@ static struct mtk_tx_dma *qdma_to_pdma(struct mtk_tx_ring *ring, + return ring->dma_pdma - (struct mtk_tx_dma *)ring->dma + dma; + } + +-static int txd_to_idx(struct mtk_tx_ring *ring, void *dma, u32 txd_size) ++static int txd_to_idx(struct mtk_tx_ring *ring, void *dma, u32 txd_shift) + { +- return (dma - ring->dma) / txd_size; ++ return (dma - ring->dma) >> txd_shift; + } + + static void mtk_tx_unmap(struct mtk_eth *eth, struct mtk_tx_buf *tx_buf, +@@ -1443,7 +1448,7 @@ static int mtk_tx_map(struct sk_buff *skb, struct net_device *dev, + if (itxd == ring->last_free) + return -ENOMEM; + +- itx_buf = mtk_desc_to_tx_buf(ring, itxd, soc->tx.desc_size); ++ itx_buf = mtk_desc_to_tx_buf(ring, itxd, soc->tx.desc_shift); + memset(itx_buf, 0, sizeof(*itx_buf)); + + txd_info.addr = dma_map_single(eth->dma_dev, skb->data, txd_info.size, +@@ -1497,7 +1502,7 @@ static int mtk_tx_map(struct sk_buff *skb, struct net_device *dev, + mtk_tx_set_dma_desc(dev, txd, &txd_info); + + tx_buf = mtk_desc_to_tx_buf(ring, txd, +- soc->tx.desc_size); ++ soc->tx.desc_shift); + if (new_desc) + memset(tx_buf, 0, sizeof(*tx_buf)); + tx_buf->data = (void *)MTK_DMA_DUMMY_DESC; +@@ -1540,7 +1545,7 @@ static int mtk_tx_map(struct sk_buff *skb, struct net_device *dev, + } else { + int next_idx; + +- next_idx = NEXT_DESP_IDX(txd_to_idx(ring, txd, soc->tx.desc_size), ++ next_idx = NEXT_DESP_IDX(txd_to_idx(ring, txd, soc->tx.desc_shift), + ring->dma_size); + mtk_w32(eth, next_idx, MT7628_TX_CTX_IDX0); + } +@@ -1549,7 +1554,7 @@ static int mtk_tx_map(struct sk_buff *skb, struct net_device *dev, + + err_dma: + do { +- tx_buf = mtk_desc_to_tx_buf(ring, itxd, soc->tx.desc_size); ++ tx_buf = mtk_desc_to_tx_buf(ring, itxd, soc->tx.desc_shift); + + /* unmap dma */ + mtk_tx_unmap(eth, tx_buf, NULL, false); +@@ -1723,7 +1728,7 @@ static struct mtk_rx_ring *mtk_get_rx_ring(struct mtk_eth *eth) + + ring = ð->rx_ring[i]; + idx = NEXT_DESP_IDX(ring->calc_idx, ring->dma_size); +- rxd = ring->dma + idx * eth->soc->rx.desc_size; ++ rxd = ring->dma + RX_DESC_OFS(eth, idx); + if (rxd->rxd2 & RX_DMA_DONE) { + ring->calc_idx_update = true; + return ring; +@@ -1891,7 +1896,7 @@ static int mtk_xdp_submit_frame(struct mtk_eth *eth, struct xdp_frame *xdpf, + } + htxd = txd; + +- tx_buf = mtk_desc_to_tx_buf(ring, txd, soc->tx.desc_size); ++ tx_buf = mtk_desc_to_tx_buf(ring, txd, soc->tx.desc_shift); + memset(tx_buf, 0, sizeof(*tx_buf)); + htx_buf = tx_buf; + +@@ -1910,7 +1915,7 @@ static int mtk_xdp_submit_frame(struct mtk_eth *eth, struct xdp_frame *xdpf, + goto unmap; + + tx_buf = mtk_desc_to_tx_buf(ring, txd, +- soc->tx.desc_size); ++ soc->tx.desc_shift); + memset(tx_buf, 0, sizeof(*tx_buf)); + n_desc++; + } +@@ -1948,7 +1953,7 @@ static int mtk_xdp_submit_frame(struct mtk_eth *eth, struct xdp_frame *xdpf, + } else { + int idx; + +- idx = txd_to_idx(ring, txd, soc->tx.desc_size); ++ idx = txd_to_idx(ring, txd, soc->tx.desc_shift); + mtk_w32(eth, NEXT_DESP_IDX(idx, ring->dma_size), + MT7628_TX_CTX_IDX0); + } +@@ -1959,7 +1964,7 @@ static int mtk_xdp_submit_frame(struct mtk_eth *eth, struct xdp_frame *xdpf, + + unmap: + while (htxd != txd) { +- tx_buf = mtk_desc_to_tx_buf(ring, htxd, soc->tx.desc_size); ++ tx_buf = mtk_desc_to_tx_buf(ring, htxd, soc->tx.desc_shift); + mtk_tx_unmap(eth, tx_buf, NULL, false); + + htxd->txd3 = TX_DMA_LS0 | TX_DMA_OWNER_CPU; +@@ -2091,7 +2096,7 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget, + goto rx_done; + + idx = NEXT_DESP_IDX(ring->calc_idx, ring->dma_size); +- rxd = ring->dma + idx * eth->soc->rx.desc_size; ++ rxd = ring->dma + RX_DESC_OFS(eth, idx); + data = ring->data[idx]; + + if (!mtk_rx_get_desc(eth, &trxd, rxd)) +@@ -2355,7 +2360,7 @@ static int mtk_poll_tx_qdma(struct mtk_eth *eth, int budget, + break; + + tx_buf = mtk_desc_to_tx_buf(ring, desc, +- eth->soc->tx.desc_size); ++ eth->soc->tx.desc_shift); + if (!tx_buf->data) + break; + +@@ -2406,7 +2411,7 @@ static int mtk_poll_tx_pdma(struct mtk_eth *eth, int budget, + } + mtk_tx_unmap(eth, tx_buf, &bq, true); + +- desc = ring->dma + cpu * eth->soc->tx.desc_size; ++ desc = ring->dma + TX_DESC_OFS(eth, cpu); + ring->last_free = desc; + atomic_inc(&ring->free_count); + +@@ -2524,7 +2529,7 @@ static int mtk_tx_alloc(struct mtk_eth *eth) + { + const struct mtk_soc_data *soc = eth->soc; + struct mtk_tx_ring *ring = ð->tx_ring; +- int i, sz = soc->tx.desc_size; ++ int i, sz = TX_DESC_OFS(eth, 1); + struct mtk_tx_dma_v2 *txd; + int ring_size; + u32 ofs, val; +@@ -2571,7 +2576,7 @@ static int mtk_tx_alloc(struct mtk_eth *eth) + * descriptors in ring->dma_pdma. + */ + if (!MTK_HAS_CAPS(soc->caps, MTK_QDMA)) { +- ring->dma_pdma = dma_alloc_coherent(eth->dma_dev, ring_size * sz, ++ ring->dma_pdma = dma_alloc_coherent(eth->dma_dev, TX_DESC_OFS(eth, ring_size), + &ring->phys_pdma, GFP_KERNEL); + if (!ring->dma_pdma) + goto no_tx_mem; +@@ -2586,7 +2591,7 @@ static int mtk_tx_alloc(struct mtk_eth *eth) + atomic_set(&ring->free_count, ring_size - 2); + ring->next_free = ring->dma; + ring->last_free = (void *)txd; +- ring->last_free_ptr = (u32)(ring->phys + ((ring_size - 1) * sz)); ++ ring->last_free_ptr = (u32)(ring->phys + TX_DESC_OFS(eth, ring_size - 1)); + ring->thresh = MAX_SKB_FRAGS; + + /* make sure that all changes to the dma ring are flushed before we +@@ -2598,7 +2603,7 @@ static int mtk_tx_alloc(struct mtk_eth *eth) + mtk_w32(eth, ring->phys, soc->reg_map->qdma.ctx_ptr); + mtk_w32(eth, ring->phys, soc->reg_map->qdma.dtx_ptr); + mtk_w32(eth, +- ring->phys + ((ring_size - 1) * sz), ++ ring->phys + TX_DESC_OFS(eth, ring_size - 1), + soc->reg_map->qdma.crx_ptr); + mtk_w32(eth, ring->last_free_ptr, soc->reg_map->qdma.drx_ptr); + +@@ -2647,14 +2652,14 @@ static void mtk_tx_clean(struct mtk_eth *eth) + } + if (!MTK_HAS_CAPS(soc->caps, MTK_SRAM) && ring->dma) { + dma_free_coherent(eth->dma_dev, +- ring->dma_size * soc->tx.desc_size, ++ TX_DESC_OFS(eth, ring->dma_size), + ring->dma, ring->phys); + ring->dma = NULL; + } + + if (ring->dma_pdma) { + dma_free_coherent(eth->dma_dev, +- ring->dma_size * soc->tx.desc_size, ++ TX_DESC_OFS(eth, ring->dma_size), + ring->dma_pdma, ring->phys_pdma); + ring->dma_pdma = NULL; + } +@@ -2710,15 +2715,13 @@ static int mtk_rx_alloc(struct mtk_eth *eth, int ring_no, int rx_flag) + if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SRAM) || + rx_flag != MTK_RX_FLAGS_NORMAL) { + ring->dma = dma_alloc_coherent(eth->dma_dev, +- rx_dma_size * eth->soc->rx.desc_size, ++ RX_DESC_OFS(eth, rx_dma_size), + &ring->phys, GFP_KERNEL); + } else { + struct mtk_tx_ring *tx_ring = ð->tx_ring; + +- ring->dma = tx_ring->dma + tx_ring_size * +- eth->soc->tx.desc_size * (ring_no + 1); +- ring->phys = tx_ring->phys + tx_ring_size * +- eth->soc->tx.desc_size * (ring_no + 1); ++ ring->dma = tx_ring->dma + TX_DESC_OFS(eth, tx_ring_size * (ring_no + 1)); ++ ring->phys = tx_ring->phys + TX_DESC_OFS(eth, tx_ring_size * (ring_no + 1)); + } + + if (!ring->dma) +@@ -2729,7 +2732,7 @@ static int mtk_rx_alloc(struct mtk_eth *eth, int ring_no, int rx_flag) + dma_addr_t dma_addr; + void *data; + +- rxd = ring->dma + i * eth->soc->rx.desc_size; ++ rxd = ring->dma + RX_DESC_OFS(eth, i); + if (ring->page_pool) { + data = mtk_page_pool_get_buff(ring->page_pool, + &dma_addr, GFP_KERNEL); +@@ -2820,7 +2823,7 @@ static void mtk_rx_clean(struct mtk_eth *eth, struct mtk_rx_ring *ring, bool in_ + if (!ring->data[i]) + continue; + +- rxd = ring->dma + i * eth->soc->rx.desc_size; ++ rxd = ring->dma + RX_DESC_OFS(eth, i); + if (!rxd->rxd1) + continue; + +@@ -2837,7 +2840,7 @@ static void mtk_rx_clean(struct mtk_eth *eth, struct mtk_rx_ring *ring, bool in_ + + if (!in_sram && ring->dma) { + dma_free_coherent(eth->dma_dev, +- ring->dma_size * eth->soc->rx.desc_size, ++ RX_DESC_OFS(eth, ring->dma_size), + ring->dma, ring->phys); + ring->dma = NULL; + } +@@ -3208,7 +3211,7 @@ static void mtk_dma_free(struct mtk_eth *eth) + + if (!MTK_HAS_CAPS(soc->caps, MTK_SRAM) && eth->scratch_ring) { + dma_free_coherent(eth->dma_dev, +- MTK_QDMA_RING_SIZE * soc->tx.desc_size, ++ TX_DESC_OFS(eth, MTK_QDMA_RING_SIZE), + eth->scratch_ring, eth->phy_scratch_ring); + eth->scratch_ring = NULL; + eth->phy_scratch_ring = 0; +@@ -5236,6 +5239,9 @@ static void mtk_remove(struct platform_device *pdev) + mtk_mdio_cleanup(eth); + } + ++#define DESC_SIZE(struct_name) \ ++ .desc_shift = const_ilog2(sizeof(struct_name)) ++ + static const struct mtk_soc_data mt2701_data = { + .reg_map = &mtk_reg_map, + .caps = MT7623_CAPS | MTK_HWLRO, +@@ -5244,14 +5250,14 @@ static const struct mtk_soc_data mt2701_data = { + .required_pctl = true, + .version = 1, + .tx = { +- .desc_size = sizeof(struct mtk_tx_dma), ++ DESC_SIZE(struct mtk_tx_dma), + .dma_max_len = MTK_TX_DMA_BUF_LEN, + .dma_len_offset = 16, + .dma_size = MTK_DMA_SIZE(2K), + .fq_dma_size = MTK_DMA_SIZE(2K), + }, + .rx = { +- .desc_size = sizeof(struct mtk_rx_dma), ++ DESC_SIZE(struct mtk_rx_dma), + .irq_done_mask = MTK_RX_DONE_INT, + .dma_l4_valid = RX_DMA_L4_VALID, + .dma_size = MTK_DMA_SIZE(2K), +@@ -5272,14 +5278,14 @@ static const struct mtk_soc_data mt7621_data = { + .hash_offset = 2, + .foe_entry_size = MTK_FOE_ENTRY_V1_SIZE, + .tx = { +- .desc_size = sizeof(struct mtk_tx_dma), ++ DESC_SIZE(struct mtk_tx_dma), + .dma_max_len = MTK_TX_DMA_BUF_LEN, + .dma_len_offset = 16, + .dma_size = MTK_DMA_SIZE(2K), + .fq_dma_size = MTK_DMA_SIZE(2K), + }, + .rx = { +- .desc_size = sizeof(struct mtk_rx_dma), ++ DESC_SIZE(struct mtk_rx_dma), + .irq_done_mask = MTK_RX_DONE_INT, + .dma_l4_valid = RX_DMA_L4_VALID, + .dma_size = MTK_DMA_SIZE(2K), +@@ -5302,14 +5308,14 @@ static const struct mtk_soc_data mt7622_data = { + .has_accounting = true, + .foe_entry_size = MTK_FOE_ENTRY_V1_SIZE, + .tx = { +- .desc_size = sizeof(struct mtk_tx_dma), ++ DESC_SIZE(struct mtk_tx_dma), + .dma_max_len = MTK_TX_DMA_BUF_LEN, + .dma_len_offset = 16, + .dma_size = MTK_DMA_SIZE(2K), + .fq_dma_size = MTK_DMA_SIZE(2K), + }, + .rx = { +- .desc_size = sizeof(struct mtk_rx_dma), ++ DESC_SIZE(struct mtk_rx_dma), + .irq_done_mask = MTK_RX_DONE_INT, + .dma_l4_valid = RX_DMA_L4_VALID, + .dma_size = MTK_DMA_SIZE(2K), +@@ -5331,14 +5337,14 @@ static const struct mtk_soc_data mt7623_data = { + .foe_entry_size = MTK_FOE_ENTRY_V1_SIZE, + .disable_pll_modes = true, + .tx = { +- .desc_size = sizeof(struct mtk_tx_dma), ++ DESC_SIZE(struct mtk_tx_dma), + .dma_max_len = MTK_TX_DMA_BUF_LEN, + .dma_len_offset = 16, + .dma_size = MTK_DMA_SIZE(2K), + .fq_dma_size = MTK_DMA_SIZE(2K), + }, + .rx = { +- .desc_size = sizeof(struct mtk_rx_dma), ++ DESC_SIZE(struct mtk_rx_dma), + .irq_done_mask = MTK_RX_DONE_INT, + .dma_l4_valid = RX_DMA_L4_VALID, + .dma_size = MTK_DMA_SIZE(2K), +@@ -5357,14 +5363,14 @@ static const struct mtk_soc_data mt7629_data = { + .has_accounting = true, + .version = 1, + .tx = { +- .desc_size = sizeof(struct mtk_tx_dma), ++ DESC_SIZE(struct mtk_tx_dma), + .dma_max_len = MTK_TX_DMA_BUF_LEN, + .dma_len_offset = 16, + .dma_size = MTK_DMA_SIZE(2K), + .fq_dma_size = MTK_DMA_SIZE(2K), + }, + .rx = { +- .desc_size = sizeof(struct mtk_rx_dma), ++ DESC_SIZE(struct mtk_rx_dma), + .irq_done_mask = MTK_RX_DONE_INT, + .dma_l4_valid = RX_DMA_L4_VALID, + .dma_size = MTK_DMA_SIZE(2K), +@@ -5387,14 +5393,14 @@ static const struct mtk_soc_data mt7981_data = { + .has_accounting = true, + .foe_entry_size = MTK_FOE_ENTRY_V2_SIZE, + .tx = { +- .desc_size = sizeof(struct mtk_tx_dma_v2), ++ DESC_SIZE(struct mtk_tx_dma_v2), + .dma_max_len = MTK_TX_DMA_BUF_LEN_V2, + .dma_len_offset = 8, + .dma_size = MTK_DMA_SIZE(2K), + .fq_dma_size = MTK_DMA_SIZE(2K), + }, + .rx = { +- .desc_size = sizeof(struct mtk_rx_dma), ++ DESC_SIZE(struct mtk_rx_dma), + .irq_done_mask = MTK_RX_DONE_INT, + .dma_l4_valid = RX_DMA_L4_VALID_V2, + .dma_max_len = MTK_TX_DMA_BUF_LEN, +@@ -5417,14 +5423,14 @@ static const struct mtk_soc_data mt7986_data = { + .has_accounting = true, + .foe_entry_size = MTK_FOE_ENTRY_V2_SIZE, + .tx = { +- .desc_size = sizeof(struct mtk_tx_dma_v2), ++ DESC_SIZE(struct mtk_tx_dma_v2), + .dma_max_len = MTK_TX_DMA_BUF_LEN_V2, + .dma_len_offset = 8, + .dma_size = MTK_DMA_SIZE(2K), + .fq_dma_size = MTK_DMA_SIZE(2K), + }, + .rx = { +- .desc_size = sizeof(struct mtk_rx_dma), ++ DESC_SIZE(struct mtk_rx_dma), + .irq_done_mask = MTK_RX_DONE_INT, + .dma_l4_valid = RX_DMA_L4_VALID_V2, + .dma_max_len = MTK_TX_DMA_BUF_LEN, +@@ -5447,14 +5453,14 @@ static const struct mtk_soc_data mt7988_data = { + .has_accounting = true, + .foe_entry_size = MTK_FOE_ENTRY_V3_SIZE, + .tx = { +- .desc_size = sizeof(struct mtk_tx_dma_v2), ++ DESC_SIZE(struct mtk_tx_dma_v2), + .dma_max_len = MTK_TX_DMA_BUF_LEN_V2, + .dma_len_offset = 8, + .dma_size = MTK_DMA_SIZE(2K), + .fq_dma_size = MTK_DMA_SIZE(4K), + }, + .rx = { +- .desc_size = sizeof(struct mtk_rx_dma_v2), ++ DESC_SIZE(struct mtk_rx_dma_v2), + .irq_done_mask = MTK_RX_DONE_INT_V2, + .dma_l4_valid = RX_DMA_L4_VALID_V2, + .dma_max_len = MTK_TX_DMA_BUF_LEN_V2, +@@ -5471,13 +5477,13 @@ static const struct mtk_soc_data rt5350_data = { + .required_pctl = false, + .version = 1, + .tx = { +- .desc_size = sizeof(struct mtk_tx_dma), ++ DESC_SIZE(struct mtk_tx_dma), + .dma_max_len = MTK_TX_DMA_BUF_LEN, + .dma_len_offset = 16, + .dma_size = MTK_DMA_SIZE(2K), + }, + .rx = { +- .desc_size = sizeof(struct mtk_rx_dma), ++ DESC_SIZE(struct mtk_rx_dma), + .irq_done_mask = MTK_RX_DONE_INT, + .dma_l4_valid = RX_DMA_L4_VALID_PDMA, + .dma_max_len = MTK_TX_DMA_BUF_LEN, +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +index 45ca9c17683a..b4699cdd65fa 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -1160,7 +1160,7 @@ struct mtk_reg_map { + * @foe_entry_size Foe table entry size. + * @has_accounting Bool indicating support for accounting of + * offloaded flows. +- * @desc_size Tx/Rx DMA descriptor size. ++ * @desc_shift Tx/Rx DMA descriptor size (in power-of-2). + * @irq_done_mask Rx irq done register mask. + * @dma_l4_valid Rx DMA valid register mask. + * @dma_max_len Max DMA tx/rx buffer length. +@@ -1181,14 +1181,14 @@ struct mtk_soc_data { + bool has_accounting; + bool disable_pll_modes; + struct { +- u32 desc_size; ++ u32 desc_shift; + u32 dma_max_len; + u32 dma_len_offset; + u32 dma_size; + u32 fq_dma_size; + } tx; + struct { +- u32 desc_size; ++ u32 desc_shift; + u32 irq_done_mask; + u32 dma_l4_valid; + u32 dma_max_len; +-- +2.51.0 + + +From 83c9e69493e9c550f16796ba7ca7859d07e50159 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Mon, 14 Jul 2025 10:52:59 +0200 +Subject: [PATCH 293/517] net: ethernet: mtk_eth_soc: shrink struct mtk_tx_buf + +There is no need to track the difference between dma_map_page +and dma_map_single, since they're unmapped in exactly the same way. +Also reorder fields in order to avoid padding. + +Signed-off-by: Felix Fietkau +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 42 ++++++--------------- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 13 +------ + 2 files changed, 14 insertions(+), 41 deletions(-) + +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +index ff25dba46922..1d64979195c1 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -1246,32 +1246,19 @@ static int txd_to_idx(struct mtk_tx_ring *ring, void *dma, u32 txd_shift) + static void mtk_tx_unmap(struct mtk_eth *eth, struct mtk_tx_buf *tx_buf, + struct xdp_frame_bulk *bq, bool napi) + { +- if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) { +- if (tx_buf->flags & MTK_TX_FLAGS_SINGLE0) { +- dma_unmap_single(eth->dma_dev, +- dma_unmap_addr(tx_buf, dma_addr0), +- dma_unmap_len(tx_buf, dma_len0), +- DMA_TO_DEVICE); +- } else if (tx_buf->flags & MTK_TX_FLAGS_PAGE0) { +- dma_unmap_page(eth->dma_dev, +- dma_unmap_addr(tx_buf, dma_addr0), +- dma_unmap_len(tx_buf, dma_len0), +- DMA_TO_DEVICE); +- } +- } else { +- if (dma_unmap_len(tx_buf, dma_len0)) { +- dma_unmap_page(eth->dma_dev, +- dma_unmap_addr(tx_buf, dma_addr0), +- dma_unmap_len(tx_buf, dma_len0), +- DMA_TO_DEVICE); +- } ++ if (dma_unmap_len(tx_buf, dma_len0)) { ++ dma_unmap_page(eth->dma_dev, ++ dma_unmap_addr(tx_buf, dma_addr0), ++ dma_unmap_len(tx_buf, dma_len0), ++ DMA_TO_DEVICE); ++ } + +- if (dma_unmap_len(tx_buf, dma_len1)) { +- dma_unmap_page(eth->dma_dev, +- dma_unmap_addr(tx_buf, dma_addr1), +- dma_unmap_len(tx_buf, dma_len1), +- DMA_TO_DEVICE); +- } ++ if (!MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA) && ++ dma_unmap_len(tx_buf, dma_len1)) { ++ dma_unmap_page(eth->dma_dev, ++ dma_unmap_addr(tx_buf, dma_addr1), ++ dma_unmap_len(tx_buf, dma_len1), ++ DMA_TO_DEVICE); + } + + if (tx_buf->data && tx_buf->data != (void *)MTK_DMA_DUMMY_DESC) { +@@ -1293,7 +1280,6 @@ static void mtk_tx_unmap(struct mtk_eth *eth, struct mtk_tx_buf *tx_buf, + xdp_return_frame(xdpf); + } + } +- tx_buf->flags = 0; + tx_buf->data = NULL; + } + +@@ -1458,7 +1444,6 @@ static int mtk_tx_map(struct sk_buff *skb, struct net_device *dev, + + mtk_tx_set_dma_desc(dev, itxd, &txd_info); + +- itx_buf->flags |= MTK_TX_FLAGS_SINGLE0; + itx_buf->mac_id = mac->id; + setup_tx_buf(eth, itx_buf, itxd_pdma, txd_info.addr, txd_info.size, + k++); +@@ -1506,7 +1491,6 @@ static int mtk_tx_map(struct sk_buff *skb, struct net_device *dev, + if (new_desc) + memset(tx_buf, 0, sizeof(*tx_buf)); + tx_buf->data = (void *)MTK_DMA_DUMMY_DESC; +- tx_buf->flags |= MTK_TX_FLAGS_PAGE0; + tx_buf->mac_id = mac->id; + + setup_tx_buf(eth, tx_buf, txd_pdma, txd_info.addr, +@@ -1839,8 +1823,6 @@ static int mtk_xdp_frame_map(struct mtk_eth *eth, struct net_device *dev, + txd_info->size, DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(eth->dma_dev, txd_info->addr))) + return -ENOMEM; +- +- tx_buf->flags |= MTK_TX_FLAGS_SINGLE0; + } else { + struct page *page = virt_to_head_page(data); + +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +index b4699cdd65fa..b5aad9a7360c 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -701,14 +701,6 @@ struct mtk_hw_stats { + struct u64_stats_sync syncp; + }; + +-enum mtk_tx_flags { +- /* PDMA descriptor can point at 1-2 segments. This enum allows us to +- * track how memory was allocated so that it can be freed properly. +- */ +- MTK_TX_FLAGS_SINGLE0 = 0x01, +- MTK_TX_FLAGS_PAGE0 = 0x02, +-}; +- + /* This enum allows us to identify how the clock is defined on the array of the + * clock in the order + */ +@@ -881,13 +873,12 @@ enum mtk_tx_buf_type { + */ + struct mtk_tx_buf { + enum mtk_tx_buf_type type; ++ u16 mac_id; + void *data; + +- u16 mac_id; +- u16 flags; + DEFINE_DMA_UNMAP_ADDR(dma_addr0); +- DEFINE_DMA_UNMAP_LEN(dma_len0); + DEFINE_DMA_UNMAP_ADDR(dma_addr1); ++ DEFINE_DMA_UNMAP_LEN(dma_len0); + DEFINE_DMA_UNMAP_LEN(dma_len1); + }; + +-- +2.51.0 + + +From 930617345e8d124cf3ae225a46476dc20d03b264 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Mon, 14 Jul 2025 10:41:27 +0200 +Subject: [PATCH 294/517] net: ethernet: mtk_eth_soc: add support for sending + fraglist GSO packets + +When primarily forwarding traffic, TCP fraglist GRO can be noticeably more +efficient than regular TCP GRO. In order to avoid the overhead of +unnecessary segmentation on ethernet tx, add support for sending fraglist +GRO packets. + +Signed-off-by: Felix Fietkau +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 355 ++++++++++++++------ + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 2 + + 2 files changed, 259 insertions(+), 98 deletions(-) + +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +index 1d64979195c1..98266707bc22 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -18,6 +18,8 @@ + #include + #include + #include ++#include ++#include + #include + #include + #include +@@ -27,6 +29,7 @@ + #include + #include + #include ++#include + #include + + #include "mtk_eth_soc.h" +@@ -1404,119 +1407,244 @@ static void mtk_tx_set_dma_desc(struct net_device *dev, void *txd, + mtk_tx_set_dma_desc_v1(dev, txd, info); + } + ++struct mtk_tx_map_state { ++ struct mtk_tx_dma *txd, *txd_pdma; ++ struct mtk_tx_buf *tx_buf; ++ int nbuf; ++ int ndesc; ++}; ++ ++static void ++mtk_tx_map_set_txd(struct mtk_tx_map_state *state, struct mtk_tx_ring *ring, ++ const struct mtk_soc_data *soc, struct mtk_tx_dma *txd) ++{ ++ state->txd = txd; ++ state->txd_pdma = qdma_to_pdma(ring, txd); ++ state->tx_buf = mtk_desc_to_tx_buf(ring, txd, soc->tx.desc_shift); ++ memset(state->tx_buf, 0, sizeof(*state->tx_buf)); ++} ++ ++static int ++mtk_tx_map_info(struct mtk_eth *eth, struct mtk_tx_ring *ring, ++ struct net_device *dev, struct mtk_tx_map_state *state, ++ struct mtk_tx_dma_desc_info *txd_info) ++{ ++ const struct mtk_soc_data *soc = eth->soc; ++ struct mtk_tx_buf *tx_buf = state->tx_buf; ++ struct mtk_tx_dma *txd = state->txd; ++ struct mtk_mac *mac = netdev_priv(dev); ++ ++ if (state->nbuf && ++ (MTK_HAS_CAPS(soc->caps, MTK_QDMA) || (state->nbuf & 1) == 0)) { ++ txd = mtk_qdma_phys_to_virt(ring, txd->txd2); ++ if (txd == ring->last_free) ++ return -1; ++ ++ mtk_tx_map_set_txd(state, ring, soc, txd); ++ state->ndesc++; ++ } ++ ++ mtk_tx_set_dma_desc(dev, txd, txd_info); ++ tx_buf = state->tx_buf; ++ tx_buf->data = (void *)MTK_DMA_DUMMY_DESC; ++ tx_buf->mac_id = mac->id; ++ ++ setup_tx_buf(eth, tx_buf, state->txd_pdma, txd_info->addr, ++ txd_info->size, state->nbuf++); ++ return 0; ++} ++ ++static void ++mtk_tx_update_ipaddr(struct sk_buff *skb, ++ struct iphdr *iph, struct tcphdr *th, ++ __be32 *old_ip, __be32 new_ip) ++{ ++ if (*old_ip == new_ip) ++ return; ++ ++ inet_proto_csum_replace4(&th->check, skb, *old_ip, new_ip, true); ++ csum_replace4(&iph->check, *old_ip, new_ip); ++ *old_ip = new_ip; ++} ++ ++static void ++mtk_tx_update_ip6addr(struct sk_buff *skb, struct ipv6hdr *iph, ++ struct tcphdr *th, struct in6_addr *old_ip, ++ const struct in6_addr *new_ip) ++{ ++ if (ipv6_addr_equal(old_ip, new_ip)) ++ return; ++ ++ inet_proto_csum_replace16(&th->check, skb, old_ip->s6_addr32, ++ new_ip->s6_addr32, true); ++ *old_ip = *new_ip; ++} ++ ++static void ++mtk_tx_update_port(struct sk_buff *skb, struct tcphdr *th, ++ __be16 *old_port, __be16 new_port) ++{ ++ if (*old_port == new_port) ++ return; ++ ++ inet_proto_csum_replace2(&th->check, skb, *old_port, new_port, false); ++ *old_port = new_port; ++} ++ + static int mtk_tx_map(struct sk_buff *skb, struct net_device *dev, +- int tx_num, struct mtk_tx_ring *ring, bool gso) ++ int tx_num, struct mtk_tx_ring *ring, bool gso, ++ unsigned int header_len) + { +- struct mtk_tx_dma_desc_info txd_info = { +- .size = skb_headlen(skb), +- .gso = gso, +- .csum = skb->ip_summed == CHECKSUM_PARTIAL, +- .vlan = skb_vlan_tag_present(skb), +- .qid = skb_get_queue_mapping(skb), +- .vlan_tci = skb_vlan_tag_get(skb), +- .first = true, +- .last = !skb_is_nonlinear(skb), ++ struct mtk_tx_dma_desc_info txd_info; ++ struct mtk_tx_map_state state = { ++ .ndesc = 1, + }; + struct netdev_queue *txq; + struct mtk_mac *mac = netdev_priv(dev); + struct mtk_eth *eth = mac->hw; + const struct mtk_soc_data *soc = eth->soc; +- struct mtk_tx_dma *itxd, *txd; +- struct mtk_tx_dma *itxd_pdma, *txd_pdma; +- struct mtk_tx_buf *itx_buf, *tx_buf; +- int i, n_desc = 1; ++ struct mtk_tx_dma *itxd; ++ struct sk_buff *cur_skb, *next_skb; + int queue = skb_get_queue_mapping(skb); +- int k = 0; ++ int offset = 0; ++ int i, frag_size; ++ bool gso_v4; + + txq = netdev_get_tx_queue(dev, queue); + itxd = ring->next_free; +- itxd_pdma = qdma_to_pdma(ring, itxd); + if (itxd == ring->last_free) + return -ENOMEM; + +- itx_buf = mtk_desc_to_tx_buf(ring, itxd, soc->tx.desc_shift); +- memset(itx_buf, 0, sizeof(*itx_buf)); ++ cur_skb = skb; ++ next_skb = skb_shinfo(skb)->frag_list; ++ mtk_tx_map_set_txd(&state, ring, soc, itxd); ++ gso_v4 = skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4; + +- txd_info.addr = dma_map_single(eth->dma_dev, skb->data, txd_info.size, +- DMA_TO_DEVICE); +- if (unlikely(dma_mapping_error(eth->dma_dev, txd_info.addr))) +- return -ENOMEM; ++next: ++ txd_info = (struct mtk_tx_dma_desc_info){ ++ .gso = gso, ++ .qid = queue, ++ .csum = cur_skb->ip_summed == CHECKSUM_PARTIAL || gso, ++ .vlan = skb_vlan_tag_present(skb), ++ .vlan_tci = skb_vlan_tag_get(skb), ++ .first = true, ++ }; + +- mtk_tx_set_dma_desc(dev, itxd, &txd_info); ++ offset = 0; ++ frag_size = skb_headlen(cur_skb); ++ if (cur_skb != skb) { ++ struct tcphdr *th, *th2; + +- itx_buf->mac_id = mac->id; +- setup_tx_buf(eth, itx_buf, itxd_pdma, txd_info.addr, txd_info.size, +- k++); ++ if (skb_cow_head(cur_skb, header_len)) ++ goto err_dma; + +- /* TX SG offload */ +- txd = itxd; +- txd_pdma = qdma_to_pdma(ring, txd); ++ memcpy(cur_skb->data - header_len, skb->data, ++ skb_network_offset(skb)); + +- for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { +- skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; +- unsigned int offset = 0; +- int frag_size = skb_frag_size(frag); ++ th = tcp_hdr(cur_skb); ++ th2 = tcp_hdr(skb); ++ if (gso_v4) { ++ struct iphdr *iph = ip_hdr(cur_skb); ++ struct iphdr *iph2 = ip_hdr(skb); + +- while (frag_size) { +- bool new_desc = true; ++ mtk_tx_update_ipaddr(skb, iph, th, &iph->saddr, ++ iph2->saddr); ++ mtk_tx_update_ipaddr(skb, iph, th, &iph->daddr, ++ iph2->daddr); ++ } else { ++ struct ipv6hdr *iph = ipv6_hdr(cur_skb); ++ struct ipv6hdr *iph2 = ipv6_hdr(skb); + +- if (MTK_HAS_CAPS(soc->caps, MTK_QDMA) || +- (i & 0x1)) { +- txd = mtk_qdma_phys_to_virt(ring, txd->txd2); +- txd_pdma = qdma_to_pdma(ring, txd); +- if (txd == ring->last_free) +- goto err_dma; ++ mtk_tx_update_ip6addr(skb, iph, th, &iph->saddr, ++ &iph2->saddr); ++ mtk_tx_update_ip6addr(skb, iph, th, &iph->daddr, ++ &iph2->daddr); ++ } + +- n_desc++; +- } else { +- new_desc = false; +- } ++ mtk_tx_update_port(skb, th, &th->source, th2->source); ++ mtk_tx_update_port(skb, th, &th->dest, th2->dest); + +- memset(&txd_info, 0, sizeof(struct mtk_tx_dma_desc_info)); ++ offset = -header_len; ++ frag_size += header_len; ++ } else if (next_skb) { ++ unsigned int ip_len = skb_pagelen(skb) - skb_network_offset(skb); ++ if (gso_v4) { ++ struct iphdr *iph = ip_hdr(cur_skb); ++ __be16 ip_len_val = cpu_to_be16(ip_len); ++ ++ csum_replace2(&iph->check, iph->tot_len, ip_len_val); ++ iph->tot_len = ip_len_val; ++ } else { ++ struct ipv6hdr *iph = ipv6_hdr(cur_skb); ++ __be16 ip_len_val = cpu_to_be16(ip_len - sizeof(*iph)); ++ ++ iph->payload_len = ip_len_val; ++ } ++ } ++ ++ while (frag_size) { ++ txd_info.size = min_t(unsigned int, frag_size, ++ soc->tx.dma_max_len); ++ txd_info.addr = dma_map_single(eth->dma_dev, cur_skb->data + offset, ++ txd_info.size, DMA_TO_DEVICE); ++ if (unlikely(dma_mapping_error(eth->dma_dev, txd_info.addr))) ++ goto err_dma; ++ ++ frag_size -= txd_info.size; ++ offset += txd_info.size; ++ txd_info.last = !frag_size && !skb_shinfo(cur_skb)->nr_frags; ++ if (mtk_tx_map_info(eth, ring, dev, &state, &txd_info) < 0) ++ goto err_dma; ++ } ++ ++ for (i = 0; i < skb_shinfo(cur_skb)->nr_frags; i++) { ++ skb_frag_t *frag = &skb_shinfo(cur_skb)->frags[i]; ++ ++ frag_size = skb_frag_size(frag); ++ memset(&txd_info, 0, sizeof(struct mtk_tx_dma_desc_info)); ++ txd_info.qid = queue; ++ offset = 0; ++ while (frag_size) { + txd_info.size = min_t(unsigned int, frag_size, + soc->tx.dma_max_len); +- txd_info.qid = queue; +- txd_info.last = i == skb_shinfo(skb)->nr_frags - 1 && +- !(frag_size - txd_info.size); +- txd_info.addr = skb_frag_dma_map(eth->dma_dev, frag, +- offset, txd_info.size, +- DMA_TO_DEVICE); ++ txd_info.addr = skb_frag_dma_map(eth->dma_dev, frag, offset, ++ txd_info.size, DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(eth->dma_dev, txd_info.addr))) + goto err_dma; + +- mtk_tx_set_dma_desc(dev, txd, &txd_info); +- +- tx_buf = mtk_desc_to_tx_buf(ring, txd, +- soc->tx.desc_shift); +- if (new_desc) +- memset(tx_buf, 0, sizeof(*tx_buf)); +- tx_buf->data = (void *)MTK_DMA_DUMMY_DESC; +- tx_buf->mac_id = mac->id; +- +- setup_tx_buf(eth, tx_buf, txd_pdma, txd_info.addr, +- txd_info.size, k++); +- + frag_size -= txd_info.size; + offset += txd_info.size; ++ txd_info.last = i == skb_shinfo(cur_skb)->nr_frags - 1 && ++ !frag_size; ++ if (mtk_tx_map_info(eth, ring, dev, &state, &txd_info) < 0) ++ goto err_dma; + } + } + +- /* store skb to cleanup */ +- itx_buf->type = MTK_TYPE_SKB; +- itx_buf->data = skb; +- + if (!MTK_HAS_CAPS(soc->caps, MTK_QDMA)) { +- if (k & 0x1) +- txd_pdma->txd2 |= TX_DMA_LS0; +- else +- txd_pdma->txd2 |= TX_DMA_LS1; ++ if (state.nbuf & 0x1) { ++ state.txd_pdma->txd2 |= TX_DMA_LS0; ++ state.nbuf++; ++ } else { ++ state.txd_pdma->txd2 |= TX_DMA_LS1; ++ } ++ } ++ ++ if (next_skb) { ++ cur_skb = next_skb; ++ next_skb = cur_skb->next; ++ goto next; + } + ++ /* store skb to cleanup */ ++ state.tx_buf->type = MTK_TYPE_SKB; ++ state.tx_buf->data = skb; ++ + netdev_tx_sent_queue(txq, skb->len); + skb_tx_timestamp(skb); + +- ring->next_free = mtk_qdma_phys_to_virt(ring, txd->txd2); +- atomic_sub(n_desc, &ring->free_count); ++ ring->next_free = mtk_qdma_phys_to_virt(ring, state.txd->txd2); ++ atomic_sub(state.ndesc, &ring->free_count); + + /* make sure that all changes to the dma ring are flushed before we + * continue +@@ -1525,11 +1653,11 @@ static int mtk_tx_map(struct sk_buff *skb, struct net_device *dev, + + if (MTK_HAS_CAPS(soc->caps, MTK_QDMA)) { + if (netif_xmit_stopped(txq) || !netdev_xmit_more()) +- mtk_w32(eth, txd->txd2, soc->reg_map->qdma.ctx_ptr); ++ mtk_w32(eth, state.txd->txd2, soc->reg_map->qdma.ctx_ptr); + } else { + int next_idx; + +- next_idx = NEXT_DESP_IDX(txd_to_idx(ring, txd, soc->tx.desc_shift), ++ next_idx = NEXT_DESP_IDX(txd_to_idx(ring, state.txd, soc->tx.desc_shift), + ring->dma_size); + mtk_w32(eth, next_idx, MT7628_TX_CTX_IDX0); + } +@@ -1538,18 +1666,20 @@ static int mtk_tx_map(struct sk_buff *skb, struct net_device *dev, + + err_dma: + do { +- tx_buf = mtk_desc_to_tx_buf(ring, itxd, soc->tx.desc_shift); ++ struct mtk_tx_dma *itxd_pdma = qdma_to_pdma(ring, itxd); ++ struct mtk_tx_buf *itx_buf; ++ ++ itx_buf = mtk_desc_to_tx_buf(ring, itxd, soc->tx.desc_shift); + + /* unmap dma */ +- mtk_tx_unmap(eth, tx_buf, NULL, false); ++ mtk_tx_unmap(eth, itx_buf, NULL, false); + + itxd->txd3 = TX_DMA_LS0 | TX_DMA_OWNER_CPU; + if (!MTK_HAS_CAPS(soc->caps, MTK_QDMA)) + itxd_pdma->txd2 = TX_DMA_DESP2_DEF; + + itxd = mtk_qdma_phys_to_virt(ring, itxd->txd2); +- itxd_pdma = qdma_to_pdma(ring, itxd); +- } while (itxd != txd); ++ } while (itxd != state.txd); + + return -ENOMEM; + } +@@ -1569,6 +1699,9 @@ static int mtk_cal_txd_req(struct mtk_eth *eth, struct sk_buff *skb) + nfrags += skb_shinfo(skb)->nr_frags; + } + ++ for (skb = skb_shinfo(skb)->frag_list; skb; skb = skb->next) ++ nfrags += mtk_cal_txd_req(eth, skb) + 1; ++ + return nfrags; + } + +@@ -1609,9 +1742,29 @@ static bool mtk_skb_has_small_frag(struct sk_buff *skb) + if (skb_frag_size(&skb_shinfo(skb)->frags[i]) < min_size) + return true; + ++ for (skb = skb_shinfo(skb)->frag_list; skb; skb = skb->next) ++ if (mtk_skb_has_small_frag(skb)) ++ return true; ++ + return false; + } + ++static bool mtk_skb_valid_gso(struct mtk_eth *eth, struct sk_buff *skb, ++ unsigned int header_len) ++{ ++ if (mtk_is_netsys_v1(eth) && mtk_skb_has_small_frag(skb)) ++ return false; ++ ++ if (!(skb_shinfo(skb)->gso_type & SKB_GSO_FRAGLIST)) ++ return true; ++ ++ if (skb_tnl_header_len(skb)) ++ return false; ++ ++ return skb_pagelen(skb) - header_len == skb_shinfo(skb)->gso_size && ++ skb_headlen(skb) > header_len; ++} ++ + static netdev_tx_t mtk_start_xmit(struct sk_buff *skb, struct net_device *dev) + { + struct mtk_mac *mac = netdev_priv(dev); +@@ -1619,6 +1772,7 @@ static netdev_tx_t mtk_start_xmit(struct sk_buff *skb, struct net_device *dev) + struct mtk_tx_ring *ring = ð->tx_ring; + struct net_device_stats *stats = &dev->stats; + struct sk_buff *segs, *next; ++ unsigned int header_len = 0; + bool gso = false; + int tx_num; + +@@ -1647,37 +1801,42 @@ static netdev_tx_t mtk_start_xmit(struct sk_buff *skb, struct net_device *dev) + return NETDEV_TX_BUSY; + } + +- if (mtk_is_netsys_v1(eth) && +- skb_is_gso(skb) && mtk_skb_has_small_frag(skb)) { +- segs = skb_gso_segment(skb, dev->features & ~NETIF_F_ALL_TSO); +- if (IS_ERR(segs)) +- goto drop; +- +- if (segs) { +- consume_skb(skb); +- skb = segs; +- } +- } +- +- /* TSO: fill MSS info in tcp checksum field */ + if (skb_is_gso(skb)) { +- if (skb_cow_head(skb, 0)) { +- netif_warn(eth, tx_err, dev, +- "GSO expand head fail.\n"); +- goto drop; ++ header_len = skb_tcp_all_headers(skb); ++ if (!mtk_skb_valid_gso(eth, skb, header_len)) { ++ segs = skb_gso_segment(skb, dev->features & ~NETIF_F_ALL_TSO); ++ if (IS_ERR(segs)) ++ goto drop; ++ ++ if (segs) { ++ consume_skb(skb); ++ skb = segs; ++ } ++ goto send; + } + ++ if ((skb_shinfo(skb)->gso_type & SKB_GSO_FRAGLIST)) ++ goto send; ++ + if (skb_shinfo(skb)->gso_type & + (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)) { ++ /* TSO: fill MSS info in tcp checksum field */ + gso = true; ++ if (skb_cow_head(skb, 0)) { ++ netif_warn(eth, tx_err, dev, ++ "GSO expand head fail.\n"); ++ goto drop; ++ } ++ + tcp_hdr(skb)->check = htons(skb_shinfo(skb)->gso_size); + } + } + ++send: + skb_list_walk_safe(skb, skb, next) { + if ((mtk_is_netsys_v1(eth) && + mtk_skb_has_small_frag(skb) && skb_linearize(skb)) || +- mtk_tx_map(skb, dev, tx_num, ring, gso) < 0) { ++ mtk_tx_map(skb, dev, tx_num, ring, gso, header_len) < 0) { + stats->tx_dropped++; + dev_kfree_skb_any(skb); + } +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +index b5aad9a7360c..1cf701b4126c 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -51,6 +51,8 @@ + NETIF_F_HW_VLAN_CTAG_TX | \ + NETIF_F_SG | NETIF_F_TSO | \ + NETIF_F_TSO6 | \ ++ NETIF_F_FRAGLIST | \ ++ NETIF_F_GSO_FRAGLIST | \ + NETIF_F_IPV6_CSUM |\ + NETIF_F_HW_TC) + #define MTK_HW_FEATURES_MT7628 (NETIF_F_SG | NETIF_F_RXCSUM) +-- +2.51.0 + + +From 878fe32f74d05f5e8b1ab976b2ac1b6caec2e6c7 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Mon, 20 May 2024 14:29:58 +0200 +Subject: [PATCH 295/517] net: ethernet: mtk_eth_soc: use napi_build_skb() + +The napi_build_skb() can reuse the skb in skb cache per CPU or +can allocate skbs in bulk, which helps improve the performance. + +Signed-off-by: Felix Fietkau +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +index 98266707bc22..4f7fdb29ad5b 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -2305,7 +2305,7 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget, + if (ret != XDP_PASS) + goto skip_rx; + +- skb = build_skb(data, PAGE_SIZE); ++ skb = napi_build_skb(data, PAGE_SIZE); + if (unlikely(!skb)) { + page_pool_put_full_page(ring->page_pool, + page, true); +@@ -2343,7 +2343,7 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget, + dma_unmap_single(eth->dma_dev, ((u64)trxd.rxd1 | addr64), + ring->buf_size, DMA_FROM_DEVICE); + +- skb = build_skb(data, ring->frag_size); ++ skb = napi_build_skb(data, ring->frag_size); + if (unlikely(!skb)) { + netdev->stats.rx_dropped++; + skb_free_frag(data); +-- +2.51.0 + + +From c29fb4a652ba3554f49264320bea3f3355480ee3 Mon Sep 17 00:00:00 2001 +From: Chad Monroe +Date: Mon, 16 Sep 2024 19:29:03 -0700 +Subject: [PATCH 296/517] net: ethernet: mediatek: increase QDMA RESV_BUF size + +Increase QDMA RESV_BUF from 2K to 3K for netsys v2 to match Mediatek SDK[1]. +This helps reduce the possibility of Ethernet transmit timeouts. + +[1]: https://git01.mediatek.com/plugins/gitiles/openwrt/feeds/mtk-openwrt-feeds/+/19d8456c3051e5f6dabf42fa770916a2126ea4bf + +Signed-off-by: Chad Monroe +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 6 ++++-- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 1 + + 2 files changed, 5 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +index 4f7fdb29ad5b..ba9b3d6be8b2 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -3476,12 +3476,14 @@ static int mtk_start_dma(struct mtk_eth *eth) + MTK_TX_BT_32DWORDS | MTK_NDP_CO_PRO | + MTK_RX_2B_OFFSET | MTK_TX_WB_DDONE; + +- if (mtk_is_netsys_v2_or_greater(eth)) ++ if (mtk_is_netsys_v2_or_greater(eth)) { ++ val &= ~MTK_RESV_BUF_MASK; + val |= MTK_MUTLI_CNT | MTK_RESV_BUF | + MTK_WCOMP_EN | MTK_DMAD_WR_WDONE | + MTK_CHK_DDONE_EN; +- else ++ } else { + val |= MTK_RX_BT_32DWORDS; ++ } + mtk_w32(eth, val, reg_map->qdma.glo_cfg); + + mtk_w32(eth, +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +index 1cf701b4126c..88dee7983642 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -282,6 +282,7 @@ + #define MTK_WCOMP_EN BIT(24) + #define MTK_RESV_BUF (0x80 << 16) + #define MTK_MUTLI_CNT (0x4 << 12) ++#define MTK_RESV_BUF_MASK (0xff << 16) + #define MTK_LEAKY_BUCKET_EN BIT(11) + + /* QDMA Flow Control Register */ +-- +2.51.0 + + +From 39e91a55c5696f31f8afd9d764863578695c3028 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Thu, 23 Mar 2023 10:24:11 +0100 +Subject: [PATCH 297/517] net: ethernet: mtk_eth_soc: improve keeping track of + offloaded flows + +Unify tracking of L2 and L3 flows. Use the generic list field in struct +mtk_foe_entry for tracking L2 subflows. Preparation for improving +flow accounting support. + +Signed-off-by: Felix Fietkau +--- + drivers/net/ethernet/mediatek/mtk_ppe.c | 162 ++++++++++++------------ + drivers/net/ethernet/mediatek/mtk_ppe.h | 15 +-- + 2 files changed, 86 insertions(+), 91 deletions(-) + +diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.c b/drivers/net/ethernet/mediatek/mtk_ppe.c +index ada852adc5f7..5b352ab64ef7 100644 +--- a/drivers/net/ethernet/mediatek/mtk_ppe.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.c +@@ -479,42 +479,43 @@ int mtk_foe_entry_set_queue(struct mtk_eth *eth, struct mtk_foe_entry *entry, + return 0; + } + ++static int ++mtk_flow_entry_match_len(struct mtk_eth *eth, struct mtk_foe_entry *entry) ++{ ++ int type = mtk_get_ib1_pkt_type(eth, entry->ib1); ++ ++ if (type > MTK_PPE_PKT_TYPE_IPV4_DSLITE) ++ return offsetof(struct mtk_foe_entry, ipv6._rsv); ++ else ++ return offsetof(struct mtk_foe_entry, ipv4.ib2); ++} ++ + static bool + mtk_flow_entry_match(struct mtk_eth *eth, struct mtk_flow_entry *entry, +- struct mtk_foe_entry *data) ++ struct mtk_foe_entry *data, int len) + { +- int type, len; +- + if ((data->ib1 ^ entry->data.ib1) & MTK_FOE_IB1_UDP) + return false; + +- type = mtk_get_ib1_pkt_type(eth, entry->data.ib1); +- if (type > MTK_PPE_PKT_TYPE_IPV4_DSLITE) +- len = offsetof(struct mtk_foe_entry, ipv6._rsv); +- else +- len = offsetof(struct mtk_foe_entry, ipv4.ib2); +- + return !memcmp(&entry->data.data, &data->data, len - 4); + } + + static void +-__mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) ++__mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry, ++ bool set_state) + { +- struct hlist_head *head; + struct hlist_node *tmp; + + if (entry->type == MTK_FLOW_TYPE_L2) { + rhashtable_remove_fast(&ppe->l2_flows, &entry->l2_node, + mtk_flow_l2_ht_params); + +- head = &entry->l2_flows; +- hlist_for_each_entry_safe(entry, tmp, head, l2_data.list) +- __mtk_foe_entry_clear(ppe, entry); ++ hlist_for_each_entry_safe(entry, tmp, &entry->l2_flows, l2_list) ++ __mtk_foe_entry_clear(ppe, entry, set_state); + return; + } + +- hlist_del_init(&entry->list); +- if (entry->hash != 0xffff) { ++ if (entry->hash != 0xffff && set_state) { + struct mtk_foe_entry *hwe = mtk_foe_get_entry(ppe, entry->hash); + + hwe->ib1 &= ~MTK_FOE_IB1_STATE; +@@ -535,7 +536,8 @@ __mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) + if (entry->type != MTK_FLOW_TYPE_L2_SUBFLOW) + return; + +- hlist_del_init(&entry->l2_data.list); ++ hlist_del_init(&entry->l2_list); ++ hlist_del_init(&entry->list); + kfree(entry); + } + +@@ -551,68 +553,57 @@ static int __mtk_foe_entry_idle_time(struct mtk_ppe *ppe, u32 ib1) + return now - timestamp; + } + ++static bool ++mtk_flow_entry_update(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) ++{ ++ struct mtk_foe_entry foe = {}; ++ struct mtk_foe_entry *hwe; ++ u16 hash = entry->hash; ++ int len; ++ ++ if (hash == 0xffff) ++ return false; ++ ++ hwe = mtk_foe_get_entry(ppe, hash); ++ len = mtk_flow_entry_match_len(ppe->eth, &entry->data); ++ memcpy(&foe, hwe, len); ++ ++ if (!mtk_flow_entry_match(ppe->eth, entry, &foe, len) || ++ FIELD_GET(MTK_FOE_IB1_STATE, foe.ib1) != MTK_FOE_STATE_BIND) ++ return false; ++ ++ entry->data.ib1 = foe.ib1; ++ ++ return true; ++} ++ + static void + mtk_flow_entry_update_l2(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) + { + u32 ib1_ts_mask = mtk_get_ib1_ts_mask(ppe->eth); + struct mtk_flow_entry *cur; +- struct mtk_foe_entry *hwe; + struct hlist_node *tmp; + int idle; + + idle = __mtk_foe_entry_idle_time(ppe, entry->data.ib1); +- hlist_for_each_entry_safe(cur, tmp, &entry->l2_flows, l2_data.list) { ++ hlist_for_each_entry_safe(cur, tmp, &entry->l2_flows, l2_list) { + int cur_idle; +- u32 ib1; +- +- hwe = mtk_foe_get_entry(ppe, cur->hash); +- ib1 = READ_ONCE(hwe->ib1); + +- if (FIELD_GET(MTK_FOE_IB1_STATE, ib1) != MTK_FOE_STATE_BIND) { +- cur->hash = 0xffff; +- __mtk_foe_entry_clear(ppe, cur); ++ if (!mtk_flow_entry_update(ppe, cur)) { ++ __mtk_foe_entry_clear(ppe, entry, false); + continue; + } + +- cur_idle = __mtk_foe_entry_idle_time(ppe, ib1); ++ cur_idle = __mtk_foe_entry_idle_time(ppe, cur->data.ib1); + if (cur_idle >= idle) + continue; + + idle = cur_idle; + entry->data.ib1 &= ~ib1_ts_mask; +- entry->data.ib1 |= ib1 & ib1_ts_mask; ++ entry->data.ib1 |= cur->data.ib1 & ib1_ts_mask; + } + } + +-static void +-mtk_flow_entry_update(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) +-{ +- struct mtk_foe_entry foe = {}; +- struct mtk_foe_entry *hwe; +- +- spin_lock_bh(&ppe_lock); +- +- if (entry->type == MTK_FLOW_TYPE_L2) { +- mtk_flow_entry_update_l2(ppe, entry); +- goto out; +- } +- +- if (entry->hash == 0xffff) +- goto out; +- +- hwe = mtk_foe_get_entry(ppe, entry->hash); +- memcpy(&foe, hwe, ppe->eth->soc->foe_entry_size); +- if (!mtk_flow_entry_match(ppe->eth, entry, &foe)) { +- entry->hash = 0xffff; +- goto out; +- } +- +- entry->data.ib1 = foe.ib1; +- +-out: +- spin_unlock_bh(&ppe_lock); +-} +- + static void + __mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_foe_entry *entry, + u16 hash) +@@ -653,7 +644,8 @@ __mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_foe_entry *entry, + void mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) + { + spin_lock_bh(&ppe_lock); +- __mtk_foe_entry_clear(ppe, entry); ++ __mtk_foe_entry_clear(ppe, entry, true); ++ hlist_del_init(&entry->list); + spin_unlock_bh(&ppe_lock); + } + +@@ -700,8 +692,8 @@ mtk_foe_entry_commit_subflow(struct mtk_ppe *ppe, struct mtk_flow_entry *entry, + { + const struct mtk_soc_data *soc = ppe->eth->soc; + struct mtk_flow_entry *flow_info; +- struct mtk_foe_entry foe = {}, *hwe; + struct mtk_foe_mac_info *l2; ++ struct mtk_foe_entry *hwe; + u32 ib1_mask = mtk_get_ib1_pkt_type_mask(ppe->eth) | MTK_FOE_IB1_UDP; + int type; + +@@ -709,30 +701,30 @@ mtk_foe_entry_commit_subflow(struct mtk_ppe *ppe, struct mtk_flow_entry *entry, + if (!flow_info) + return; + +- flow_info->l2_data.base_flow = entry; + flow_info->type = MTK_FLOW_TYPE_L2_SUBFLOW; + flow_info->hash = hash; + hlist_add_head(&flow_info->list, + &ppe->foe_flow[hash / soc->hash_offset]); +- hlist_add_head(&flow_info->l2_data.list, &entry->l2_flows); ++ hlist_add_head(&flow_info->l2_list, &entry->l2_flows); + + hwe = mtk_foe_get_entry(ppe, hash); +- memcpy(&foe, hwe, soc->foe_entry_size); +- foe.ib1 &= ib1_mask; +- foe.ib1 |= entry->data.ib1 & ~ib1_mask; ++ memcpy(&flow_info->data, hwe, soc->foe_entry_size); ++ flow_info->data.ib1 &= ib1_mask; ++ flow_info->data.ib1 |= entry->data.ib1 & ~ib1_mask; + +- l2 = mtk_foe_entry_l2(ppe->eth, &foe); ++ l2 = mtk_foe_entry_l2(ppe->eth, &flow_info->data); + memcpy(l2, &entry->data.bridge.l2, sizeof(*l2)); + +- type = mtk_get_ib1_pkt_type(ppe->eth, foe.ib1); ++ type = mtk_get_ib1_pkt_type(ppe->eth, flow_info->data.ib1); + if (type == MTK_PPE_PKT_TYPE_IPV4_HNAPT) +- memcpy(&foe.ipv4.new, &foe.ipv4.orig, sizeof(foe.ipv4.new)); ++ memcpy(&flow_info->data.ipv4.new, &flow_info->data.ipv4.orig, ++ sizeof(flow_info->data.ipv4.new)); + else if (type >= MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T && l2->etype == ETH_P_IP) + l2->etype = ETH_P_IPV6; + +- *mtk_foe_entry_ib2(ppe->eth, &foe) = entry->data.bridge.ib2; ++ *mtk_foe_entry_ib2(ppe->eth, &flow_info->data) = entry->data.bridge.ib2; + +- __mtk_foe_entry_commit(ppe, &foe, hash); ++ __mtk_foe_entry_commit(ppe, &flow_info->data, hash); + } + + void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash) +@@ -742,9 +734,11 @@ void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash) + struct mtk_foe_entry *hwe = mtk_foe_get_entry(ppe, hash); + struct mtk_flow_entry *entry; + struct mtk_foe_bridge key = {}; ++ struct mtk_foe_entry foe = {}; + struct hlist_node *n; + struct ethhdr *eh; + bool found = false; ++ int entry_len; + u8 *tag; + + spin_lock_bh(&ppe_lock); +@@ -752,20 +746,14 @@ void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash) + if (FIELD_GET(MTK_FOE_IB1_STATE, hwe->ib1) == MTK_FOE_STATE_BIND) + goto out; + +- hlist_for_each_entry_safe(entry, n, head, list) { +- if (entry->type == MTK_FLOW_TYPE_L2_SUBFLOW) { +- if (unlikely(FIELD_GET(MTK_FOE_IB1_STATE, hwe->ib1) == +- MTK_FOE_STATE_BIND)) +- continue; +- +- entry->hash = 0xffff; +- __mtk_foe_entry_clear(ppe, entry); +- continue; +- } ++ entry_len = mtk_flow_entry_match_len(ppe->eth, hwe); ++ memcpy(&foe, hwe, entry_len); + +- if (found || !mtk_flow_entry_match(ppe->eth, entry, hwe)) { ++ hlist_for_each_entry_safe(entry, n, head, list) { ++ if (found || ++ !mtk_flow_entry_match(ppe->eth, entry, &foe, entry_len)) { + if (entry->hash != 0xffff) +- entry->hash = 0xffff; ++ __mtk_foe_entry_clear(ppe, entry, false); + continue; + } + +@@ -816,9 +804,17 @@ void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash) + + int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) + { +- mtk_flow_entry_update(ppe, entry); ++ int idle; ++ ++ spin_lock_bh(&ppe_lock); ++ if (entry->type == MTK_FLOW_TYPE_L2) ++ mtk_flow_entry_update_l2(ppe, entry); ++ else ++ mtk_flow_entry_update(ppe, entry); ++ idle = __mtk_foe_entry_idle_time(ppe, entry->data.ib1); ++ spin_unlock_bh(&ppe_lock); + +- return __mtk_foe_entry_idle_time(ppe, entry->data.ib1); ++ return idle; + } + + int mtk_ppe_prepare_reset(struct mtk_ppe *ppe) +diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.h b/drivers/net/ethernet/mediatek/mtk_ppe.h +index 223f709e2704..aa0799c1ce95 100644 +--- a/drivers/net/ethernet/mediatek/mtk_ppe.h ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.h +@@ -286,7 +286,12 @@ enum { + + struct mtk_flow_entry { + union { +- struct hlist_node list; ++ /* regular flows + L2 subflows */ ++ struct { ++ struct hlist_node list; ++ struct hlist_node l2_list; ++ }; ++ /* L2 flows */ + struct { + struct rhash_head l2_node; + struct hlist_head l2_flows; +@@ -296,13 +301,7 @@ struct mtk_flow_entry { + s8 wed_index; + u8 ppe_index; + u16 hash; +- union { +- struct mtk_foe_entry data; +- struct { +- struct mtk_flow_entry *base_flow; +- struct hlist_node list; +- } l2_data; +- }; ++ struct mtk_foe_entry data; + struct rhash_head node; + unsigned long cookie; + }; +-- +2.51.0 + + +From 5fc20c1af300b58d2ee1f802ae8d630ef24f3573 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Thu, 23 Mar 2023 11:05:22 +0100 +Subject: [PATCH 298/517] net: ethernet: mediatek: fix ppe flow accounting for + L2 flows + +For L2 flows, the packet/byte counters should report the sum of the +counters of their subflows, both current and expired. +In order to make this work, change the way that accounting data is tracked. +Reset counters when a flow enters bind. Once it expires (or enters unbind), +store the last counter value in struct mtk_flow_entry. + +Signed-off-by: Felix Fietkau +--- + drivers/net/ethernet/mediatek/mtk_ppe.c | 140 ++++++++++-------- + drivers/net/ethernet/mediatek/mtk_ppe.h | 8 +- + .../net/ethernet/mediatek/mtk_ppe_debugfs.c | 2 +- + .../net/ethernet/mediatek/mtk_ppe_offload.c | 17 +-- + 4 files changed, 89 insertions(+), 78 deletions(-) + +diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.c b/drivers/net/ethernet/mediatek/mtk_ppe.c +index 5b352ab64ef7..96365a75b198 100644 +--- a/drivers/net/ethernet/mediatek/mtk_ppe.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.c +@@ -83,9 +83,9 @@ static int mtk_ppe_mib_wait_busy(struct mtk_ppe *ppe) + int ret; + u32 val; + +- ret = readl_poll_timeout(ppe->base + MTK_PPE_MIB_SER_CR, val, +- !(val & MTK_PPE_MIB_SER_CR_ST), +- 20, MTK_PPE_WAIT_TIMEOUT_US); ++ ret = readl_poll_timeout_atomic(ppe->base + MTK_PPE_MIB_SER_CR, val, ++ !(val & MTK_PPE_MIB_SER_CR_ST), ++ 20, MTK_PPE_WAIT_TIMEOUT_US); + + if (ret) + dev_err(ppe->dev, "MIB table busy"); +@@ -93,17 +93,31 @@ static int mtk_ppe_mib_wait_busy(struct mtk_ppe *ppe) + return ret; + } + +-static int mtk_mib_entry_read(struct mtk_ppe *ppe, u16 index, u64 *bytes, u64 *packets) ++static inline struct mtk_foe_accounting * ++mtk_ppe_acct_data(struct mtk_ppe *ppe, u16 index) ++{ ++ if (!ppe->acct_table) ++ return NULL; ++ ++ return ppe->acct_table + index * sizeof(struct mtk_foe_accounting); ++} ++ ++struct mtk_foe_accounting *mtk_ppe_mib_entry_read(struct mtk_ppe *ppe, u16 index) + { + u32 val, cnt_r0, cnt_r1, cnt_r2; ++ struct mtk_foe_accounting *acct; + int ret; + + val = FIELD_PREP(MTK_PPE_MIB_SER_CR_ADDR, index) | MTK_PPE_MIB_SER_CR_ST; + ppe_w32(ppe, MTK_PPE_MIB_SER_CR, val); + ++ acct = mtk_ppe_acct_data(ppe, index); ++ if (!acct) ++ return NULL; ++ + ret = mtk_ppe_mib_wait_busy(ppe); + if (ret) +- return ret; ++ return acct; + + cnt_r0 = readl(ppe->base + MTK_PPE_MIB_SER_R0); + cnt_r1 = readl(ppe->base + MTK_PPE_MIB_SER_R1); +@@ -112,19 +126,19 @@ static int mtk_mib_entry_read(struct mtk_ppe *ppe, u16 index, u64 *bytes, u64 *p + if (mtk_is_netsys_v3_or_greater(ppe->eth)) { + /* 64 bit for each counter */ + u32 cnt_r3 = readl(ppe->base + MTK_PPE_MIB_SER_R3); +- *bytes = ((u64)cnt_r1 << 32) | cnt_r0; +- *packets = ((u64)cnt_r3 << 32) | cnt_r2; ++ acct->bytes += ((u64)cnt_r1 << 32) | cnt_r0; ++ acct->packets += ((u64)cnt_r3 << 32) | cnt_r2; + } else { + /* 48 bit byte counter, 40 bit packet counter */ + u32 byte_cnt_low = FIELD_GET(MTK_PPE_MIB_SER_R0_BYTE_CNT_LOW, cnt_r0); + u32 byte_cnt_high = FIELD_GET(MTK_PPE_MIB_SER_R1_BYTE_CNT_HIGH, cnt_r1); + u32 pkt_cnt_low = FIELD_GET(MTK_PPE_MIB_SER_R1_PKT_CNT_LOW, cnt_r1); + u32 pkt_cnt_high = FIELD_GET(MTK_PPE_MIB_SER_R2_PKT_CNT_HIGH, cnt_r2); +- *bytes = ((u64)byte_cnt_high << 32) | byte_cnt_low; +- *packets = ((u64)pkt_cnt_high << 16) | pkt_cnt_low; ++ acct->bytes += ((u64)byte_cnt_high << 32) | byte_cnt_low; ++ acct->packets += ((u64)pkt_cnt_high << 16) | pkt_cnt_low; + } + +- return 0; ++ return acct; + } + + static void mtk_ppe_cache_clear(struct mtk_ppe *ppe) +@@ -522,14 +536,6 @@ __mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry, + hwe->ib1 |= FIELD_PREP(MTK_FOE_IB1_STATE, MTK_FOE_STATE_INVALID); + dma_wmb(); + mtk_ppe_cache_clear(ppe); +- +- if (ppe->accounting) { +- struct mtk_foe_accounting *acct; +- +- acct = ppe->acct_table + entry->hash * sizeof(*acct); +- acct->packets = 0; +- acct->bytes = 0; +- } + } + entry->hash = 0xffff; + +@@ -554,11 +560,14 @@ static int __mtk_foe_entry_idle_time(struct mtk_ppe *ppe, u32 ib1) + } + + static bool +-mtk_flow_entry_update(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) ++mtk_flow_entry_update(struct mtk_ppe *ppe, struct mtk_flow_entry *entry, ++ u64 *packets, u64 *bytes) + { ++ struct mtk_foe_accounting *acct; + struct mtk_foe_entry foe = {}; + struct mtk_foe_entry *hwe; + u16 hash = entry->hash; ++ bool ret = false; + int len; + + if (hash == 0xffff) +@@ -569,18 +578,35 @@ mtk_flow_entry_update(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) + memcpy(&foe, hwe, len); + + if (!mtk_flow_entry_match(ppe->eth, entry, &foe, len) || +- FIELD_GET(MTK_FOE_IB1_STATE, foe.ib1) != MTK_FOE_STATE_BIND) +- return false; ++ FIELD_GET(MTK_FOE_IB1_STATE, foe.ib1) != MTK_FOE_STATE_BIND) { ++ acct = mtk_ppe_acct_data(ppe, hash); ++ if (acct) { ++ entry->prev_packets += acct->packets; ++ entry->prev_bytes += acct->bytes; ++ } ++ ++ goto out; ++ } + + entry->data.ib1 = foe.ib1; ++ acct = mtk_ppe_mib_entry_read(ppe, hash); ++ ret = true; ++ ++out: ++ if (acct) { ++ *packets += acct->packets; ++ *bytes += acct->bytes; ++ } + +- return true; ++ return ret; + } + + static void + mtk_flow_entry_update_l2(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) + { + u32 ib1_ts_mask = mtk_get_ib1_ts_mask(ppe->eth); ++ u64 *packets = &entry->packets; ++ u64 *bytes = &entry->bytes; + struct mtk_flow_entry *cur; + struct hlist_node *tmp; + int idle; +@@ -589,7 +615,9 @@ mtk_flow_entry_update_l2(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) + hlist_for_each_entry_safe(cur, tmp, &entry->l2_flows, l2_list) { + int cur_idle; + +- if (!mtk_flow_entry_update(ppe, cur)) { ++ if (!mtk_flow_entry_update(ppe, cur, packets, bytes)) { ++ entry->prev_packets += cur->prev_packets; ++ entry->prev_bytes += cur->prev_bytes; + __mtk_foe_entry_clear(ppe, entry, false); + continue; + } +@@ -604,10 +632,29 @@ mtk_flow_entry_update_l2(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) + } + } + ++void mtk_foe_entry_get_stats(struct mtk_ppe *ppe, struct mtk_flow_entry *entry, ++ int *idle) ++{ ++ entry->packets = entry->prev_packets; ++ entry->bytes = entry->prev_bytes; ++ ++ spin_lock_bh(&ppe_lock); ++ ++ if (entry->type == MTK_FLOW_TYPE_L2) ++ mtk_flow_entry_update_l2(ppe, entry); ++ else ++ mtk_flow_entry_update(ppe, entry, &entry->packets, &entry->bytes); ++ ++ *idle = __mtk_foe_entry_idle_time(ppe, entry->data.ib1); ++ ++ spin_unlock_bh(&ppe_lock); ++} ++ + static void + __mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_foe_entry *entry, + u16 hash) + { ++ struct mtk_foe_accounting *acct; + struct mtk_eth *eth = ppe->eth; + u16 timestamp = mtk_eth_timestamp(eth); + struct mtk_foe_entry *hwe; +@@ -638,6 +685,12 @@ __mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_foe_entry *entry, + + dma_wmb(); + ++ acct = mtk_ppe_mib_entry_read(ppe, hash); ++ if (acct) { ++ acct->packets = 0; ++ acct->bytes = 0; ++ } ++ + mtk_ppe_cache_clear(ppe); + } + +@@ -802,21 +855,6 @@ void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash) + spin_unlock_bh(&ppe_lock); + } + +-int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) +-{ +- int idle; +- +- spin_lock_bh(&ppe_lock); +- if (entry->type == MTK_FLOW_TYPE_L2) +- mtk_flow_entry_update_l2(ppe, entry); +- else +- mtk_flow_entry_update(ppe, entry); +- idle = __mtk_foe_entry_idle_time(ppe, entry->data.ib1); +- spin_unlock_bh(&ppe_lock); +- +- return idle; +-} +- + int mtk_ppe_prepare_reset(struct mtk_ppe *ppe) + { + if (!ppe) +@@ -844,32 +882,6 @@ int mtk_ppe_prepare_reset(struct mtk_ppe *ppe) + return mtk_ppe_wait_busy(ppe); + } + +-struct mtk_foe_accounting *mtk_foe_entry_get_mib(struct mtk_ppe *ppe, u32 index, +- struct mtk_foe_accounting *diff) +-{ +- struct mtk_foe_accounting *acct; +- int size = sizeof(struct mtk_foe_accounting); +- u64 bytes, packets; +- +- if (!ppe->accounting) +- return NULL; +- +- if (mtk_mib_entry_read(ppe, index, &bytes, &packets)) +- return NULL; +- +- acct = ppe->acct_table + index * size; +- +- acct->bytes += bytes; +- acct->packets += packets; +- +- if (diff) { +- diff->bytes = bytes; +- diff->packets = packets; +- } +- +- return acct; +-} +- + struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, int index) + { + bool accounting = eth->soc->has_accounting; +diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.h b/drivers/net/ethernet/mediatek/mtk_ppe.h +index aa0799c1ce95..9a4990aa5fa5 100644 +--- a/drivers/net/ethernet/mediatek/mtk_ppe.h ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.h +@@ -304,6 +304,8 @@ struct mtk_flow_entry { + struct mtk_foe_entry data; + struct rhash_head node; + unsigned long cookie; ++ u64 prev_packets, prev_bytes; ++ u64 packets, bytes; + }; + + struct mtk_mib_entry { +@@ -348,6 +350,7 @@ void mtk_ppe_deinit(struct mtk_eth *eth); + void mtk_ppe_start(struct mtk_ppe *ppe); + int mtk_ppe_stop(struct mtk_ppe *ppe); + int mtk_ppe_prepare_reset(struct mtk_ppe *ppe); ++struct mtk_foe_accounting *mtk_ppe_mib_entry_read(struct mtk_ppe *ppe, u16 index); + + void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash); + +@@ -397,9 +400,8 @@ int mtk_foe_entry_set_queue(struct mtk_eth *eth, struct mtk_foe_entry *entry, + unsigned int queue); + int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_flow_entry *entry); + void mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry); +-int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry); + int mtk_ppe_debugfs_init(struct mtk_ppe *ppe, int index); +-struct mtk_foe_accounting *mtk_foe_entry_get_mib(struct mtk_ppe *ppe, u32 index, +- struct mtk_foe_accounting *diff); ++void mtk_foe_entry_get_stats(struct mtk_ppe *ppe, struct mtk_flow_entry *entry, ++ int *idle); + + #endif +diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c b/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c +index 570ebf91f693..9259d0925b88 100644 +--- a/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c +@@ -97,7 +97,7 @@ mtk_ppe_debugfs_foe_show(struct seq_file *m, void *private, bool bind) + if (bind && state != MTK_FOE_STATE_BIND) + continue; + +- acct = mtk_foe_entry_get_mib(ppe, i, NULL); ++ acct = mtk_ppe_mib_entry_read(ppe, i); + + type = mtk_get_ib1_pkt_type(ppe->eth, entry->ib1); + seq_printf(m, "%05x %s %7s", i, +diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c +index e9bd32741983..af8e0107fb93 100644 +--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c +@@ -522,24 +522,21 @@ static int + mtk_flow_offload_stats(struct mtk_eth *eth, struct flow_cls_offload *f) + { + struct mtk_flow_entry *entry; +- struct mtk_foe_accounting diff; +- u32 idle; ++ u64 packets, bytes; ++ int idle; + + entry = rhashtable_lookup(ð->flow_table, &f->cookie, + mtk_flow_ht_params); + if (!entry) + return -ENOENT; + +- idle = mtk_foe_entry_idle_time(eth->ppe[entry->ppe_index], entry); ++ packets = entry->packets; ++ bytes = entry->bytes; ++ mtk_foe_entry_get_stats(eth->ppe[entry->ppe_index], entry, &idle); ++ f->stats.pkts += entry->packets - packets; ++ f->stats.bytes += entry->bytes - bytes; + f->stats.lastused = jiffies - idle * HZ; + +- if (entry->hash != 0xFFFF && +- mtk_foe_entry_get_mib(eth->ppe[entry->ppe_index], entry->hash, +- &diff)) { +- f->stats.pkts += diff.packets; +- f->stats.bytes += diff.bytes; +- } +- + return 0; + } + +-- +2.51.0 + + +From 6ece59fe862195dec63a973bd2a6099bee78859d Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Fri, 12 Sep 2025 14:18:14 +0200 +Subject: [PATCH 299/517] net: ethernet: mtk_eth_soc: zero initialize PPE flow + table + +Avoid picking up flows from last boot or other invalid data + +Signed-off-by: Felix Fietkau +--- + drivers/net/ethernet/mediatek/mtk_ppe.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.c b/drivers/net/ethernet/mediatek/mtk_ppe.c +index 96365a75b198..cb08d132bad9 100644 +--- a/drivers/net/ethernet/mediatek/mtk_ppe.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.c +@@ -914,6 +914,7 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, int index) + if (!foe) + goto err_free_l2_flows; + ++ memset(foe, 0, MTK_PPE_ENTRIES * soc->foe_entry_size); + ppe->foe_table = foe; + + foe_flow_size = (MTK_PPE_ENTRIES / soc->hash_offset) * +@@ -928,6 +929,7 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, int index) + if (!mib) + return NULL; + ++ memset(mib, 0, MTK_PPE_ENTRIES * sizeof(*mib)); + ppe->mib_table = mib; + + acct = devm_kzalloc(dev, MTK_PPE_ENTRIES * sizeof(*acct), +-- +2.51.0 + + +From a6edd3042d35a2553e33b9d880226c6187bc6579 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Tue, 12 Dec 2023 03:51:14 +0000 +Subject: [PATCH 300/517] net: ethernet: mtk_eth_soc: add paths and SerDes + modes for MT7988 + +MT7988 comes with a built-in 2.5G PHY as well as SerDes lanes to +connect external PHYs or transceivers in USXGMII, 10GBase-R, 5GBase-R, +2500Base-X, 1000Base-X and Cisco SGMII interface modes. + +Implement support for configuring for the new paths to SerDes interfaces +and the internal 2.5G PHY. + +Add USXGMII PCS driver for 10GBase-R, 5GBase-R and USXGMII mode, and +setup the new PHYA on MT7988 to access the also still existing old +LynxI PCS for 1000Base-X, 2500Base-X and Cisco SGMII PCS interface +modes. + +Signed-off-by: Daniel Golle +--- + drivers/net/ethernet/mediatek/mtk_eth_path.c | 122 +++++++- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 288 +++++++++++++++++-- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 93 +++++- + 3 files changed, 470 insertions(+), 33 deletions(-) + +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_path.c b/drivers/net/ethernet/mediatek/mtk_eth_path.c +index 7c27a19c4d8f..3f4f4cfe6a23 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_path.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_path.c +@@ -31,10 +31,20 @@ static const char *mtk_eth_path_name(u64 path) + return "gmac2_rgmii"; + case MTK_ETH_PATH_GMAC2_SGMII: + return "gmac2_sgmii"; ++ case MTK_ETH_PATH_GMAC2_2P5GPHY: ++ return "gmac2_2p5gphy"; + case MTK_ETH_PATH_GMAC2_GEPHY: + return "gmac2_gephy"; ++ case MTK_ETH_PATH_GMAC3_SGMII: ++ return "gmac3_sgmii"; + case MTK_ETH_PATH_GDM1_ESW: + return "gdm1_esw"; ++ case MTK_ETH_PATH_GMAC1_USXGMII: ++ return "gmac1_usxgmii"; ++ case MTK_ETH_PATH_GMAC2_USXGMII: ++ return "gmac2_usxgmii"; ++ case MTK_ETH_PATH_GMAC3_USXGMII: ++ return "gmac3_usxgmii"; + default: + return "unknown path"; + } +@@ -127,6 +137,27 @@ static int set_mux_u3_gmac2_to_qphy(struct mtk_eth *eth, u64 path) + return 0; + } + ++static int set_mux_gmac2_to_2p5gphy(struct mtk_eth *eth, u64 path) ++{ ++ int ret; ++ ++ if (path == MTK_ETH_PATH_GMAC2_2P5GPHY) { ++ ret = regmap_clear_bits(eth->ethsys, ETHSYS_SYSCFG0, SYSCFG0_SGMII_GMAC2_V2); ++ if (ret) ++ return ret; ++ ++ /* Setup mux to 2p5g PHY */ ++ ret = regmap_clear_bits(eth->infra, TOP_MISC_NETSYS_PCS_MUX, MUX_G2_USXGMII_SEL); ++ if (ret) ++ return ret; ++ ++ dev_dbg(eth->dev, "path %s in %s updated\n", ++ mtk_eth_path_name(path), __func__); ++ } ++ ++ return 0; ++} ++ + static int set_mux_gmac1_gmac2_to_sgmii_rgmii(struct mtk_eth *eth, u64 path) + { + unsigned int val = 0; +@@ -165,7 +196,48 @@ static int set_mux_gmac1_gmac2_to_sgmii_rgmii(struct mtk_eth *eth, u64 path) + return 0; + } + +-static int set_mux_gmac12_to_gephy_sgmii(struct mtk_eth *eth, u64 path) ++static int set_mux_gmac123_to_usxgmii(struct mtk_eth *eth, u64 path) ++{ ++ unsigned int val = 0; ++ bool updated = true; ++ int mac_id = 0; ++ ++ /* Disable SYSCFG1 SGMII */ ++ regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val); ++ ++ switch (path) { ++ case MTK_ETH_PATH_GMAC1_USXGMII: ++ val &= ~(u32)SYSCFG0_SGMII_GMAC1_V2; ++ mac_id = MTK_GMAC1_ID; ++ break; ++ case MTK_ETH_PATH_GMAC2_USXGMII: ++ val &= ~(u32)SYSCFG0_SGMII_GMAC2_V2; ++ mac_id = MTK_GMAC2_ID; ++ break; ++ case MTK_ETH_PATH_GMAC3_USXGMII: ++ val &= ~(u32)SYSCFG0_SGMII_GMAC3_V2; ++ mac_id = MTK_GMAC3_ID; ++ break; ++ default: ++ updated = false; ++ }; ++ ++ if (updated) { ++ regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0, ++ SYSCFG0_SGMII_MASK, val); ++ ++ if (mac_id == MTK_GMAC2_ID) ++ regmap_set_bits(eth->infra, TOP_MISC_NETSYS_PCS_MUX, ++ MUX_G2_USXGMII_SEL); ++ } ++ ++ dev_dbg(eth->dev, "path %s in %s updated = %d\n", ++ mtk_eth_path_name(path), __func__, updated); ++ ++ return 0; ++} ++ ++static int set_mux_gmac123_to_gephy_sgmii(struct mtk_eth *eth, u64 path) + { + unsigned int val = 0; + bool updated = true; +@@ -182,6 +254,9 @@ static int set_mux_gmac12_to_gephy_sgmii(struct mtk_eth *eth, u64 path) + case MTK_ETH_PATH_GMAC2_SGMII: + val |= SYSCFG0_SGMII_GMAC2_V2; + break; ++ case MTK_ETH_PATH_GMAC3_SGMII: ++ val |= SYSCFG0_SGMII_GMAC3_V2; ++ break; + default: + updated = false; + } +@@ -209,6 +284,10 @@ static const struct mtk_eth_muxc mtk_eth_muxc[] = { + .name = "mux_u3_gmac2_to_qphy", + .cap_bit = MTK_ETH_MUX_U3_GMAC2_TO_QPHY, + .set_path = set_mux_u3_gmac2_to_qphy, ++ }, { ++ .name = "mux_gmac2_to_2p5gphy", ++ .cap_bit = MTK_ETH_MUX_GMAC2_TO_2P5GPHY, ++ .set_path = set_mux_gmac2_to_2p5gphy, + }, { + .name = "mux_gmac1_gmac2_to_sgmii_rgmii", + .cap_bit = MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII, +@@ -216,7 +295,15 @@ static const struct mtk_eth_muxc mtk_eth_muxc[] = { + }, { + .name = "mux_gmac12_to_gephy_sgmii", + .cap_bit = MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII, +- .set_path = set_mux_gmac12_to_gephy_sgmii, ++ .set_path = set_mux_gmac123_to_gephy_sgmii, ++ }, { ++ .name = "mux_gmac123_to_gephy_sgmii", ++ .cap_bit = MTK_ETH_MUX_GMAC123_TO_GEPHY_SGMII, ++ .set_path = set_mux_gmac123_to_gephy_sgmii, ++ }, { ++ .name = "mux_gmac123_to_usxgmii", ++ .cap_bit = MTK_ETH_MUX_GMAC123_TO_USXGMII, ++ .set_path = set_mux_gmac123_to_usxgmii, + }, + }; + +@@ -249,12 +336,39 @@ static int mtk_eth_mux_setup(struct mtk_eth *eth, u64 path) + return err; + } + ++int mtk_gmac_usxgmii_path_setup(struct mtk_eth *eth, int mac_id) ++{ ++ u64 path; ++ ++ path = (mac_id == MTK_GMAC1_ID) ? MTK_ETH_PATH_GMAC1_USXGMII : ++ (mac_id == MTK_GMAC2_ID) ? MTK_ETH_PATH_GMAC2_USXGMII : ++ MTK_ETH_PATH_GMAC3_USXGMII; ++ ++ /* Setup proper MUXes along the path */ ++ return mtk_eth_mux_setup(eth, path); ++} ++ + int mtk_gmac_sgmii_path_setup(struct mtk_eth *eth, int mac_id) + { + u64 path; + +- path = (mac_id == 0) ? MTK_ETH_PATH_GMAC1_SGMII : +- MTK_ETH_PATH_GMAC2_SGMII; ++ path = (mac_id == MTK_GMAC1_ID) ? MTK_ETH_PATH_GMAC1_SGMII : ++ (mac_id == MTK_GMAC2_ID) ? MTK_ETH_PATH_GMAC2_SGMII : ++ MTK_ETH_PATH_GMAC3_SGMII; ++ ++ /* Setup proper MUXes along the path */ ++ return mtk_eth_mux_setup(eth, path); ++} ++ ++int mtk_gmac_2p5gphy_path_setup(struct mtk_eth *eth, int mac_id) ++{ ++ u64 path = 0; ++ ++ if (mac_id == MTK_GMAC2_ID) ++ path = MTK_ETH_PATH_GMAC2_2P5GPHY; ++ ++ if (!path) ++ return -EINVAL; + + /* Setup proper MUXes along the path */ + return mtk_eth_mux_setup(eth, path); +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +index ba9b3d6be8b2..2883f53c016a 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -24,6 +24,8 @@ + #include + #include + #include ++#include ++#include + #include + #include + #include +@@ -522,6 +524,30 @@ static void mtk_setup_bridge_switch(struct mtk_eth *eth) + MTK_GSW_CFG); + } + ++static bool mtk_check_gmac23_idle(struct mtk_mac *mac) ++{ ++ u32 mac_fsm, gdm_fsm; ++ ++ mac_fsm = mtk_r32(mac->hw, MTK_MAC_FSM(mac->id)); ++ ++ switch (mac->id) { ++ case MTK_GMAC2_ID: ++ gdm_fsm = mtk_r32(mac->hw, MTK_FE_GDM2_FSM); ++ break; ++ case MTK_GMAC3_ID: ++ gdm_fsm = mtk_r32(mac->hw, MTK_FE_GDM3_FSM); ++ break; ++ default: ++ return true; ++ }; ++ ++ if ((mac_fsm & 0xFFFF0000) == 0x01010000 && ++ (gdm_fsm & 0xFFFF0000) == 0x00000000) ++ return true; ++ ++ return false; ++} ++ + static struct phylink_pcs *mtk_mac_select_pcs(struct phylink_config *config, + phy_interface_t interface) + { +@@ -530,6 +556,21 @@ static struct phylink_pcs *mtk_mac_select_pcs(struct phylink_config *config, + struct mtk_eth *eth = mac->hw; + unsigned int sid; + ++ if (mtk_is_netsys_v3_or_greater(eth)) { ++ switch (interface) { ++ case PHY_INTERFACE_MODE_1000BASEX: ++ case PHY_INTERFACE_MODE_2500BASEX: ++ case PHY_INTERFACE_MODE_SGMII: ++ return mac->sgmii_pcs; ++ case PHY_INTERFACE_MODE_5GBASER: ++ case PHY_INTERFACE_MODE_10GBASER: ++ case PHY_INTERFACE_MODE_USXGMII: ++ return mac->usxgmii_pcs; ++ default: ++ return NULL; ++ } ++ } ++ + if (interface == PHY_INTERFACE_MODE_SGMII || + phy_interface_mode_is_8023z(interface)) { + sid = (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_SGMII)) ? +@@ -581,7 +622,22 @@ static void mtk_mac_config(struct phylink_config *config, unsigned int mode, + goto init_err; + } + break; ++ case PHY_INTERFACE_MODE_USXGMII: ++ case PHY_INTERFACE_MODE_10GBASER: ++ case PHY_INTERFACE_MODE_5GBASER: ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_USXGMII)) { ++ err = mtk_gmac_usxgmii_path_setup(eth, mac->id); ++ if (err) ++ goto init_err; ++ } ++ break; + case PHY_INTERFACE_MODE_INTERNAL: ++ if (mac->id == MTK_GMAC2_ID && ++ MTK_HAS_CAPS(eth->soc->caps, MTK_2P5GPHY)) { ++ err = mtk_gmac_2p5gphy_path_setup(eth, mac->id); ++ if (err) ++ goto init_err; ++ } + break; + default: + goto err_phy; +@@ -628,8 +684,6 @@ static void mtk_mac_config(struct phylink_config *config, unsigned int mode, + val &= ~SYSCFG0_GE_MODE(SYSCFG0_GE_MASK, mac->id); + val |= SYSCFG0_GE_MODE(ge_mode, mac->id); + regmap_write(eth->ethsys, ETHSYS_SYSCFG0, val); +- +- mac->interface = state->interface; + } + + /* SGMII */ +@@ -646,21 +700,40 @@ static void mtk_mac_config(struct phylink_config *config, unsigned int mode, + + /* Save the syscfg0 value for mac_finish */ + mac->syscfg0 = val; +- } else if (phylink_autoneg_inband(mode)) { ++ } else if (state->interface != PHY_INTERFACE_MODE_USXGMII && ++ state->interface != PHY_INTERFACE_MODE_10GBASER && ++ state->interface != PHY_INTERFACE_MODE_5GBASER && ++ phylink_autoneg_inband(mode)) { + dev_err(eth->dev, +- "In-band mode not supported in non SGMII mode!\n"); ++ "In-band mode not supported in non-SerDes modes!\n"); + return; + } + + /* Setup gmac */ +- if (mtk_is_netsys_v3_or_greater(eth) && +- mac->interface == PHY_INTERFACE_MODE_INTERNAL) { +- mtk_w32(mac->hw, MTK_GDMA_XGDM_SEL, MTK_GDMA_EG_CTRL(mac->id)); +- mtk_w32(mac->hw, MAC_MCR_FORCE_LINK_DOWN, MTK_MAC_MCR(mac->id)); ++ if (mtk_is_netsys_v3_or_greater(eth)) { ++ if (mtk_interface_mode_is_xgmii(state->interface)) { ++ mtk_w32(mac->hw, MTK_GDMA_XGDM_SEL, MTK_GDMA_EG_CTRL(mac->id)); ++ mtk_w32(mac->hw, MAC_MCR_FORCE_LINK_DOWN, MTK_MAC_MCR(mac->id)); + +- mtk_setup_bridge_switch(eth); ++ if (mac->id == MTK_GMAC1_ID) ++ mtk_setup_bridge_switch(eth); ++ } else { ++ mtk_w32(eth, 0, MTK_GDMA_EG_CTRL(mac->id)); ++ ++ /* FIXME: In current hardware design, we have to reset FE ++ * when swtiching XGDM to GDM. Therefore, here trigger an SER ++ * to let GDM go back to the initial state. ++ */ ++ if ((mtk_interface_mode_is_xgmii(mac->interface) || ++ mac->interface == PHY_INTERFACE_MODE_NA) && ++ !mtk_check_gmac23_idle(mac) && ++ !test_bit(MTK_RESETTING, ð->state)) ++ schedule_work(ð->pending_work); ++ } + } + ++ mac->interface = state->interface; ++ + return; + + err_phy: +@@ -673,6 +746,18 @@ static void mtk_mac_config(struct phylink_config *config, unsigned int mode, + mac->id, phy_modes(state->interface), err); + } + ++static int mtk_mac_prepare(struct phylink_config *config, unsigned int mode, ++ phy_interface_t interface) ++{ ++ struct mtk_mac *mac = container_of(config, struct mtk_mac, ++ phylink_config); ++ ++ if (mac->pextp && mac->interface != interface) ++ phy_reset(mac->pextp); ++ ++ return 0; ++} ++ + static int mtk_mac_finish(struct phylink_config *config, unsigned int mode, + phy_interface_t interface) + { +@@ -681,6 +766,10 @@ static int mtk_mac_finish(struct phylink_config *config, unsigned int mode, + struct mtk_eth *eth = mac->hw; + u32 mcr_cur, mcr_new; + ++ /* Setup PMA/PMD */ ++ if (mac->pextp) ++ phy_set_mode_ext(mac->pextp, PHY_MODE_ETHERNET, interface); ++ + /* Enable SGMII */ + if (interface == PHY_INTERFACE_MODE_SGMII || + phy_interface_mode_is_8023z(interface)) +@@ -705,10 +794,14 @@ static void mtk_mac_link_down(struct phylink_config *config, unsigned int mode, + { + struct mtk_mac *mac = container_of(config, struct mtk_mac, + phylink_config); +- u32 mcr = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id)); + +- mcr &= ~(MAC_MCR_TX_EN | MAC_MCR_RX_EN | MAC_MCR_FORCE_LINK); +- mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id)); ++ if (!mtk_interface_mode_is_xgmii(interface)) { ++ mtk_m32(mac->hw, MAC_MCR_TX_EN | MAC_MCR_RX_EN | MAC_MCR_FORCE_LINK, 0, MTK_MAC_MCR(mac->id)); ++ if (mtk_is_netsys_v3_or_greater(mac->hw)) ++ mtk_m32(mac->hw, MTK_XGMAC_FORCE_LINK(mac->id), 0, MTK_XGMAC_STS(mac->id)); ++ } else if (mtk_is_netsys_v3_or_greater(mac->hw) && mac->id != MTK_GMAC1_ID) { ++ mtk_m32(mac->hw, XMAC_MCR_TRX_DISABLE, XMAC_MCR_TRX_DISABLE, MTK_XMAC_MCR(mac->id)); ++ } + } + + static void mtk_set_queue_speed(struct mtk_eth *eth, unsigned int idx, +@@ -780,13 +873,11 @@ static void mtk_set_queue_speed(struct mtk_eth *eth, unsigned int idx, + mtk_w32(eth, val, soc->reg_map->qdma.qtx_sch + ofs); + } + +-static void mtk_mac_link_up(struct phylink_config *config, +- struct phy_device *phy, +- unsigned int mode, phy_interface_t interface, +- int speed, int duplex, bool tx_pause, bool rx_pause) ++static void mtk_gdm_mac_link_up(struct mtk_mac *mac, ++ struct phy_device *phy, ++ unsigned int mode, phy_interface_t interface, ++ int speed, int duplex, bool tx_pause, bool rx_pause) + { +- struct mtk_mac *mac = container_of(config, struct mtk_mac, +- phylink_config); + u32 mcr; + + mcr = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id)); +@@ -830,9 +921,63 @@ static void mtk_mac_link_up(struct phylink_config *config, + mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id)); + } + ++static void mtk_xgdm_mac_link_up(struct mtk_mac *mac, ++ struct phy_device *phy, ++ unsigned int mode, phy_interface_t interface, ++ int speed, int duplex, bool tx_pause, bool rx_pause) ++{ ++ u32 mcr, force_link = 0; ++ ++ if (mac->id == MTK_GMAC1_ID) ++ return; ++ ++ /* Eliminate the interference(before link-up) caused by PHY noise */ ++ mtk_m32(mac->hw, XMAC_LOGIC_RST, 0, MTK_XMAC_LOGIC_RST(mac->id)); ++ mdelay(20); ++ mtk_m32(mac->hw, XMAC_GLB_CNTCLR, XMAC_GLB_CNTCLR, MTK_XMAC_CNT_CTRL(mac->id)); ++ ++ if (mac->interface == PHY_INTERFACE_MODE_INTERNAL || mac->id == MTK_GMAC3_ID) ++ force_link = MTK_XGMAC_FORCE_LINK(mac->id); ++ ++ mtk_m32(mac->hw, MTK_XGMAC_FORCE_LINK(mac->id), force_link, MTK_XGMAC_STS(mac->id)); ++ ++ mcr = mtk_r32(mac->hw, MTK_XMAC_MCR(mac->id)); ++ mcr &= ~(XMAC_MCR_FORCE_TX_FC | XMAC_MCR_FORCE_RX_FC | XMAC_MCR_TRX_DISABLE); ++ /* Configure pause modes - ++ * phylink will avoid these for half duplex ++ */ ++ if (tx_pause) ++ mcr |= XMAC_MCR_FORCE_TX_FC; ++ if (rx_pause) ++ mcr |= XMAC_MCR_FORCE_RX_FC; ++ ++ mtk_w32(mac->hw, mcr, MTK_XMAC_MCR(mac->id)); ++} ++ ++static void mtk_mac_link_up(struct phylink_config *config, ++ struct phy_device *phy, ++ unsigned int mode, phy_interface_t interface, ++ int speed, int duplex, bool tx_pause, bool rx_pause) ++{ ++ struct mtk_mac *mac = container_of(config, struct mtk_mac, ++ phylink_config); ++ ++ if (mtk_is_netsys_v3_or_greater(mac->hw) && mtk_interface_mode_is_xgmii(interface)) ++ mtk_xgdm_mac_link_up(mac, phy, mode, interface, speed, duplex, ++ tx_pause, rx_pause); ++ else ++ mtk_gdm_mac_link_up(mac, phy, mode, interface, speed, duplex, ++ tx_pause, rx_pause); ++ ++ /* Repeat pextp setup to tune link */ ++ if (mac->pextp) ++ phy_set_mode_ext(mac->pextp, PHY_MODE_ETHERNET, interface); ++} ++ + static const struct phylink_mac_ops mtk_phylink_ops = { + .mac_select_pcs = mtk_mac_select_pcs, + .mac_config = mtk_mac_config, ++ .mac_prepare = mtk_mac_prepare, + .mac_finish = mtk_mac_finish, + .mac_link_down = mtk_mac_link_down, + .mac_link_up = mtk_mac_link_up, +@@ -3584,6 +3729,9 @@ static int mtk_open(struct net_device *dev) + + ppe_num = eth->soc->ppe_num; + ++ if (mac->pextp) ++ phy_power_on(mac->pextp); ++ + err = phylink_of_phy_connect(mac->phylink, mac->of_node, 0); + if (err) { + netdev_err(dev, "%s: could not attach PHY: %d\n", __func__, +@@ -3731,6 +3879,9 @@ static int mtk_stop(struct net_device *dev) + for (i = 0; i < ARRAY_SIZE(eth->ppe); i++) + mtk_ppe_stop(eth->ppe[i]); + ++ if (mac->pextp) ++ phy_power_off(mac->pextp); ++ + return 0; + } + +@@ -4821,6 +4972,7 @@ static const struct net_device_ops mtk_netdev_ops = { + static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) + { + const __be32 *_id = of_get_property(np, "reg", NULL); ++ struct device_node *pcs_np; + phy_interface_t phy_mode; + struct phylink *phylink; + struct mtk_mac *mac; +@@ -4859,16 +5011,41 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) + mac->id = id; + mac->hw = eth; + mac->of_node = np; ++ pcs_np = of_parse_phandle(mac->of_node, "pcs-handle", 0); ++ if (pcs_np) { ++ mac->sgmii_pcs = mtk_pcs_lynxi_get(eth->dev, pcs_np); ++ if (IS_ERR(mac->sgmii_pcs)) { ++ if (PTR_ERR(mac->sgmii_pcs) == -EPROBE_DEFER) ++ return -EPROBE_DEFER; ++ ++ dev_err(eth->dev, "cannot select SGMII PCS, error %ld\n", ++ PTR_ERR(mac->sgmii_pcs)); ++ return PTR_ERR(mac->sgmii_pcs); ++ } ++ } + +- err = of_get_ethdev_address(mac->of_node, eth->netdev[id]); +- if (err == -EPROBE_DEFER) +- return err; ++ pcs_np = of_parse_phandle(mac->of_node, "pcs-handle", 1); ++ if (pcs_np) { ++ mac->usxgmii_pcs = mtk_usxgmii_pcs_get(eth->dev, pcs_np); ++ if (IS_ERR(mac->usxgmii_pcs)) { ++ if (PTR_ERR(mac->usxgmii_pcs) == -EPROBE_DEFER) ++ return -EPROBE_DEFER; + +- if (err) { +- /* If the mac address is invalid, use random mac address */ +- eth_hw_addr_random(eth->netdev[id]); +- dev_err(eth->dev, "generated random MAC address %pM\n", +- eth->netdev[id]->dev_addr); ++ dev_err(eth->dev, "cannot select USXGMII PCS, error %ld\n", ++ PTR_ERR(mac->usxgmii_pcs)); ++ return PTR_ERR(mac->usxgmii_pcs); ++ } ++ } ++ ++ if (mtk_is_netsys_v3_or_greater(eth) && (mac->sgmii_pcs || mac->usxgmii_pcs)) { ++ mac->pextp = devm_of_phy_get(eth->dev, mac->of_node, NULL); ++ if (IS_ERR(mac->pextp)) { ++ if (PTR_ERR(mac->pextp) != -EPROBE_DEFER) ++ dev_err(eth->dev, "cannot get PHY, error %ld\n", ++ PTR_ERR(mac->pextp)); ++ ++ return PTR_ERR(mac->pextp); ++ } + } + + memset(mac->hwlro_ip, 0, sizeof(mac->hwlro_ip)); +@@ -4951,8 +5128,21 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) + phy_interface_zero(mac->phylink_config.supported_interfaces); + __set_bit(PHY_INTERFACE_MODE_INTERNAL, + mac->phylink_config.supported_interfaces); ++ } else if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_USXGMII)) { ++ mac->phylink_config.mac_capabilities |= MAC_5000FD | MAC_10000FD; ++ __set_bit(PHY_INTERFACE_MODE_5GBASER, ++ mac->phylink_config.supported_interfaces); ++ __set_bit(PHY_INTERFACE_MODE_10GBASER, ++ mac->phylink_config.supported_interfaces); ++ __set_bit(PHY_INTERFACE_MODE_USXGMII, ++ mac->phylink_config.supported_interfaces); + } + ++ if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_2P5GPHY) && ++ id == MTK_GMAC2_ID) ++ __set_bit(PHY_INTERFACE_MODE_INTERNAL, ++ mac->phylink_config.supported_interfaces); ++ + phylink = phylink_create(&mac->phylink_config, + of_fwnode_handle(mac->of_node), + phy_mode, &mtk_phylink_ops); +@@ -5003,6 +5193,26 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) + return err; + } + ++static int mtk_mac_assign_address(struct mtk_eth *eth, int i, bool test_defer_only) ++{ ++ int err = of_get_ethdev_address(eth->mac[i]->of_node, eth->netdev[i]); ++ ++ if (err == -EPROBE_DEFER) ++ return err; ++ ++ if (test_defer_only) ++ return 0; ++ ++ if (err) { ++ /* If the mac address is invalid, use random mac address */ ++ eth_hw_addr_random(eth->netdev[i]); ++ dev_err(eth->dev, "generated random MAC address %pM\n", ++ eth->netdev[i]); ++ } ++ ++ return 0; ++} ++ + void mtk_eth_set_dma_device(struct mtk_eth *eth, struct device *dma_dev) + { + struct net_device *dev, *tmp; +@@ -5149,7 +5359,8 @@ static int mtk_probe(struct platform_device *pdev) + regmap_write(cci, 0, 3); + } + +- if (MTK_HAS_CAPS(eth->soc->caps, MTK_SGMII)) { ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_SGMII) && ++ !mtk_is_netsys_v3_or_greater(eth)) { + err = mtk_sgmii_init(eth); + + if (err) +@@ -5260,6 +5471,24 @@ static int mtk_probe(struct platform_device *pdev) + } + } + ++ for (i = 0; i < MTK_MAX_DEVS; i++) { ++ if (!eth->netdev[i]) ++ continue; ++ ++ err = mtk_mac_assign_address(eth, i, true); ++ if (err) ++ goto err_deinit_hw; ++ } ++ ++ for (i = 0; i < MTK_MAX_DEVS; i++) { ++ if (!eth->netdev[i]) ++ continue; ++ ++ err = mtk_mac_assign_address(eth, i, false); ++ if (err) ++ goto err_deinit_hw; ++ } ++ + if (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_INT)) { + err = devm_request_irq(eth->dev, eth->irq[0], + mtk_handle_irq, 0, +@@ -5370,6 +5599,11 @@ static void mtk_remove(struct platform_device *pdev) + mtk_stop(eth->netdev[i]); + mac = netdev_priv(eth->netdev[i]); + phylink_disconnect_phy(mac->phylink); ++ if (mac->sgmii_pcs) ++ mtk_pcs_lynxi_put(mac->sgmii_pcs); ++ ++ if (mac->usxgmii_pcs) ++ mtk_usxgmii_pcs_put(mac->usxgmii_pcs); + } + + mtk_wed_exit(); +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +index 88dee7983642..c7ad88351a1b 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -15,6 +15,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -527,6 +528,21 @@ + #define INTF_MODE_RGMII_1000 (TRGMII_MODE | TRGMII_CENTRAL_ALIGNED) + #define INTF_MODE_RGMII_10_100 0 + ++/* XFI Mac control registers */ ++#define MTK_XMAC_BASE(x) (0x12000 + (((x) - 1) * 0x1000)) ++#define MTK_XMAC_MCR(x) (MTK_XMAC_BASE(x)) ++#define XMAC_MCR_TRX_DISABLE 0xf ++#define XMAC_MCR_FORCE_TX_FC BIT(5) ++#define XMAC_MCR_FORCE_RX_FC BIT(4) ++ ++/* XFI Mac logic reset registers */ ++#define MTK_XMAC_LOGIC_RST(x) (MTK_XMAC_BASE(x) + 0x10) ++#define XMAC_LOGIC_RST BIT(0) ++ ++/* XFI Mac count global control */ ++#define MTK_XMAC_CNT_CTRL(x) (MTK_XMAC_BASE(x) + 0x100) ++#define XMAC_GLB_CNTCLR BIT(0) ++ + /* GPIO port control registers for GMAC 2*/ + #define GPIO_OD33_CTRL8 0x4c0 + #define GPIO_BIAS_CTRL 0xed0 +@@ -552,6 +568,7 @@ + #define SYSCFG0_SGMII_GMAC2 ((3 << 8) & SYSCFG0_SGMII_MASK) + #define SYSCFG0_SGMII_GMAC1_V2 BIT(9) + #define SYSCFG0_SGMII_GMAC2_V2 BIT(8) ++#define SYSCFG0_SGMII_GMAC3_V2 BIT(7) + + + /* ethernet subsystem clock register */ +@@ -590,6 +607,11 @@ + #define GEPHY_MAC_SEL BIT(1) + + /* Top misc registers */ ++#define TOP_MISC_NETSYS_PCS_MUX 0x0 ++#define NETSYS_PCS_MUX_MASK GENMASK(1, 0) ++#define MUX_G2_USXGMII_SEL BIT(1) ++#define MUX_HSGMII1_G1_SEL BIT(0) ++ + #define USB_PHY_SWITCH_REG 0x218 + #define QPHY_SEL_MASK GENMASK(1, 0) + #define SGMII_QPHY_SEL 0x2 +@@ -614,6 +636,8 @@ + #define MT7628_SDM_RBCNT (MT7628_SDM_OFFSET + 0x10c) + #define MT7628_SDM_CS_ERR (MT7628_SDM_OFFSET + 0x110) + ++/* Debug Purpose Register */ ++#define MTK_PSE_FQFC_CFG 0x100 + #define MTK_FE_CDM1_FSM 0x220 + #define MTK_FE_CDM2_FSM 0x224 + #define MTK_FE_CDM3_FSM 0x238 +@@ -622,6 +646,11 @@ + #define MTK_FE_CDM6_FSM 0x328 + #define MTK_FE_GDM1_FSM 0x228 + #define MTK_FE_GDM2_FSM 0x22C ++#define MTK_FE_GDM3_FSM 0x23C ++#define MTK_FE_PSE_FREE 0x240 ++#define MTK_FE_DROP_FQ 0x244 ++#define MTK_FE_DROP_FC 0x248 ++#define MTK_FE_DROP_PPE 0x24C + + #define MTK_MAC_FSM(x) (0x1010C + ((x) * 0x100)) + +@@ -945,6 +974,8 @@ enum mkt_eth_capabilities { + MTK_RGMII_BIT = 0, + MTK_TRGMII_BIT, + MTK_SGMII_BIT, ++ MTK_USXGMII_BIT, ++ MTK_2P5GPHY_BIT, + MTK_ESW_BIT, + MTK_GEPHY_BIT, + MTK_MUX_BIT, +@@ -965,8 +996,11 @@ enum mkt_eth_capabilities { + MTK_ETH_MUX_GDM1_TO_GMAC1_ESW_BIT, + MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY_BIT, + MTK_ETH_MUX_U3_GMAC2_TO_QPHY_BIT, ++ MTK_ETH_MUX_GMAC2_TO_2P5GPHY_BIT, + MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII_BIT, + MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII_BIT, ++ MTK_ETH_MUX_GMAC123_TO_GEPHY_SGMII_BIT, ++ MTK_ETH_MUX_GMAC123_TO_USXGMII_BIT, + + /* PATH BITS */ + MTK_ETH_PATH_GMAC1_RGMII_BIT, +@@ -974,14 +1008,21 @@ enum mkt_eth_capabilities { + MTK_ETH_PATH_GMAC1_SGMII_BIT, + MTK_ETH_PATH_GMAC2_RGMII_BIT, + MTK_ETH_PATH_GMAC2_SGMII_BIT, ++ MTK_ETH_PATH_GMAC2_2P5GPHY_BIT, + MTK_ETH_PATH_GMAC2_GEPHY_BIT, ++ MTK_ETH_PATH_GMAC3_SGMII_BIT, + MTK_ETH_PATH_GDM1_ESW_BIT, ++ MTK_ETH_PATH_GMAC1_USXGMII_BIT, ++ MTK_ETH_PATH_GMAC2_USXGMII_BIT, ++ MTK_ETH_PATH_GMAC3_USXGMII_BIT, + }; + + /* Supported hardware group on SoCs */ + #define MTK_RGMII BIT_ULL(MTK_RGMII_BIT) + #define MTK_TRGMII BIT_ULL(MTK_TRGMII_BIT) + #define MTK_SGMII BIT_ULL(MTK_SGMII_BIT) ++#define MTK_USXGMII BIT_ULL(MTK_USXGMII_BIT) ++#define MTK_2P5GPHY BIT_ULL(MTK_2P5GPHY_BIT) + #define MTK_ESW BIT_ULL(MTK_ESW_BIT) + #define MTK_GEPHY BIT_ULL(MTK_GEPHY_BIT) + #define MTK_MUX BIT_ULL(MTK_MUX_BIT) +@@ -1004,10 +1045,16 @@ enum mkt_eth_capabilities { + BIT_ULL(MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY_BIT) + #define MTK_ETH_MUX_U3_GMAC2_TO_QPHY \ + BIT_ULL(MTK_ETH_MUX_U3_GMAC2_TO_QPHY_BIT) ++#define MTK_ETH_MUX_GMAC2_TO_2P5GPHY \ ++ BIT_ULL(MTK_ETH_MUX_GMAC2_TO_2P5GPHY_BIT) + #define MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII \ + BIT_ULL(MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII_BIT) + #define MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII \ + BIT_ULL(MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII_BIT) ++#define MTK_ETH_MUX_GMAC123_TO_GEPHY_SGMII \ ++ BIT_ULL(MTK_ETH_MUX_GMAC123_TO_GEPHY_SGMII_BIT) ++#define MTK_ETH_MUX_GMAC123_TO_USXGMII \ ++ BIT_ULL(MTK_ETH_MUX_GMAC123_TO_USXGMII_BIT) + + /* Supported path present on SoCs */ + #define MTK_ETH_PATH_GMAC1_RGMII BIT_ULL(MTK_ETH_PATH_GMAC1_RGMII_BIT) +@@ -1015,8 +1062,13 @@ enum mkt_eth_capabilities { + #define MTK_ETH_PATH_GMAC1_SGMII BIT_ULL(MTK_ETH_PATH_GMAC1_SGMII_BIT) + #define MTK_ETH_PATH_GMAC2_RGMII BIT_ULL(MTK_ETH_PATH_GMAC2_RGMII_BIT) + #define MTK_ETH_PATH_GMAC2_SGMII BIT_ULL(MTK_ETH_PATH_GMAC2_SGMII_BIT) ++#define MTK_ETH_PATH_GMAC2_2P5GPHY BIT_ULL(MTK_ETH_PATH_GMAC2_2P5GPHY_BIT) + #define MTK_ETH_PATH_GMAC2_GEPHY BIT_ULL(MTK_ETH_PATH_GMAC2_GEPHY_BIT) ++#define MTK_ETH_PATH_GMAC3_SGMII BIT_ULL(MTK_ETH_PATH_GMAC3_SGMII_BIT) + #define MTK_ETH_PATH_GDM1_ESW BIT_ULL(MTK_ETH_PATH_GDM1_ESW_BIT) ++#define MTK_ETH_PATH_GMAC1_USXGMII BIT_ULL(MTK_ETH_PATH_GMAC1_USXGMII_BIT) ++#define MTK_ETH_PATH_GMAC2_USXGMII BIT_ULL(MTK_ETH_PATH_GMAC2_USXGMII_BIT) ++#define MTK_ETH_PATH_GMAC3_USXGMII BIT_ULL(MTK_ETH_PATH_GMAC3_USXGMII_BIT) + + #define MTK_GMAC1_RGMII (MTK_ETH_PATH_GMAC1_RGMII | MTK_RGMII) + #define MTK_GMAC1_TRGMII (MTK_ETH_PATH_GMAC1_TRGMII | MTK_TRGMII) +@@ -1024,7 +1076,12 @@ enum mkt_eth_capabilities { + #define MTK_GMAC2_RGMII (MTK_ETH_PATH_GMAC2_RGMII | MTK_RGMII) + #define MTK_GMAC2_SGMII (MTK_ETH_PATH_GMAC2_SGMII | MTK_SGMII) + #define MTK_GMAC2_GEPHY (MTK_ETH_PATH_GMAC2_GEPHY | MTK_GEPHY) ++#define MTK_GMAC2_2P5GPHY (MTK_ETH_PATH_GMAC2_2P5GPHY | MTK_2P5GPHY) ++#define MTK_GMAC3_SGMII (MTK_ETH_PATH_GMAC3_SGMII | MTK_SGMII) + #define MTK_GDM1_ESW (MTK_ETH_PATH_GDM1_ESW | MTK_ESW) ++#define MTK_GMAC1_USXGMII (MTK_ETH_PATH_GMAC1_USXGMII | MTK_USXGMII) ++#define MTK_GMAC2_USXGMII (MTK_ETH_PATH_GMAC2_USXGMII | MTK_USXGMII) ++#define MTK_GMAC3_USXGMII (MTK_ETH_PATH_GMAC3_USXGMII | MTK_USXGMII) + + /* MUXes present on SoCs */ + /* 0: GDM1 -> GMAC1, 1: GDM1 -> ESW */ +@@ -1043,10 +1100,20 @@ enum mkt_eth_capabilities { + (MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII | MTK_MUX | \ + MTK_SHARED_SGMII) + ++/* 2: GMAC2 -> XGMII */ ++#define MTK_MUX_GMAC2_TO_2P5GPHY \ ++ (MTK_ETH_MUX_GMAC2_TO_2P5GPHY | MTK_MUX | MTK_INFRA) ++ + /* 0: GMACx -> GEPHY, 1: GMACx -> SGMII where x is 1 or 2 */ + #define MTK_MUX_GMAC12_TO_GEPHY_SGMII \ + (MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII | MTK_MUX) + ++#define MTK_MUX_GMAC123_TO_GEPHY_SGMII \ ++ (MTK_ETH_MUX_GMAC123_TO_GEPHY_SGMII | MTK_MUX) ++ ++#define MTK_MUX_GMAC123_TO_USXGMII \ ++ (MTK_ETH_MUX_GMAC123_TO_USXGMII | MTK_MUX | MTK_INFRA) ++ + #define MTK_HAS_CAPS(caps, _x) (((caps) & (_x)) == (_x)) + + #define MT7621_CAPS (MTK_GMAC1_RGMII | MTK_GMAC1_TRGMII | \ +@@ -1078,8 +1145,12 @@ enum mkt_eth_capabilities { + MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA | \ + MTK_RSTCTRL_PPE1 | MTK_SRAM) + +-#define MT7988_CAPS (MTK_36BIT_DMA | MTK_GDM1_ESW | MTK_QDMA | \ +- MTK_RSTCTRL_PPE1 | MTK_RSTCTRL_PPE2 | MTK_SRAM) ++#define MT7988_CAPS (MTK_36BIT_DMA | MTK_GDM1_ESW | MTK_GMAC1_SGMII | \ ++ MTK_GMAC2_2P5GPHY | MTK_GMAC2_SGMII | MTK_GMAC2_USXGMII | \ ++ MTK_GMAC3_SGMII | MTK_GMAC3_USXGMII | \ ++ MTK_MUX_GMAC123_TO_GEPHY_SGMII | \ ++ MTK_MUX_GMAC123_TO_USXGMII | MTK_MUX_GMAC2_TO_2P5GPHY | \ ++ MTK_QDMA | MTK_RSTCTRL_PPE1 | MTK_RSTCTRL_PPE2 | MTK_SRAM) + + struct mtk_tx_dma_desc_info { + dma_addr_t addr; +@@ -1327,6 +1398,9 @@ struct mtk_mac { + struct device_node *of_node; + struct phylink *phylink; + struct phylink_config phylink_config; ++ struct phylink_pcs *sgmii_pcs; ++ struct phylink_pcs *usxgmii_pcs; ++ struct phy *pextp; + struct mtk_eth *hw; + struct mtk_hw_stats *hw_stats; + __be32 hwlro_ip[MTK_MAX_LRO_IP_CNT]; +@@ -1450,6 +1524,19 @@ static inline u32 mtk_get_ib2_multicast_mask(struct mtk_eth *eth) + return MTK_FOE_IB2_MULTICAST; + } + ++static inline bool mtk_interface_mode_is_xgmii(phy_interface_t interface) ++{ ++ switch (interface) { ++ case PHY_INTERFACE_MODE_INTERNAL: ++ case PHY_INTERFACE_MODE_USXGMII: ++ case PHY_INTERFACE_MODE_10GBASER: ++ case PHY_INTERFACE_MODE_5GBASER: ++ return true; ++ default: ++ return false; ++ } ++} ++ + /* read the hardware status register */ + void mtk_stats_update_mac(struct mtk_mac *mac); + +@@ -1458,8 +1545,10 @@ u32 mtk_r32(struct mtk_eth *eth, unsigned reg); + u32 mtk_m32(struct mtk_eth *eth, u32 mask, u32 set, unsigned int reg); + + int mtk_gmac_sgmii_path_setup(struct mtk_eth *eth, int mac_id); ++int mtk_gmac_2p5gphy_path_setup(struct mtk_eth *eth, int mac_id); + int mtk_gmac_gephy_path_setup(struct mtk_eth *eth, int mac_id); + int mtk_gmac_rgmii_path_setup(struct mtk_eth *eth, int mac_id); ++int mtk_gmac_usxgmii_path_setup(struct mtk_eth *eth, int mac_id); + + int mtk_eth_offload_init(struct mtk_eth *eth, u8 id); + int mtk_eth_setup_tc(struct net_device *dev, enum tc_setup_type type, +-- +2.51.0 + + +From f45eeb706a8d64bfc50fd9b3b667530ff0625232 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Tue, 15 Oct 2024 13:09:37 +0200 +Subject: [PATCH 301/517] net: ethernet: mtk_eth_soc: reduce rx ring size for + older chipsets + +Commit c57e55819443 ("net: ethernet: mtk_eth_soc: handle dma buffer +size soc specific") resolved some tx timeout issues by bumping FQ and +tx ring sizes from 512 to 2048 entries (the value used in the MediaTek +SDK), however it also changed the rx ring size for all chipsets in the +same way. + +Based on a few tests, it seems that a symmetric rx/tx ring size of 2048 +really only makes sense on MT7988, which is capable of 10G ethernet links. + +Older chipsets are typically deployed in systems that are more memory +constrained and don't actually need the larger rings to handle received +packets. + +In order to reduce wasted memory set the ring size based on the SoC to +the following values: +- 2048 on MT7988 +- 1024 on MT7986 +- 512 (previous value) on everything else, except: +- 256 on RT5350 (the oldest supported chipset) + +Fixes: c57e55819443 ("net: ethernet: mtk_eth_soc: handle dma buffer size soc specific") +Signed-off-by: Felix Fietkau +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +index 2883f53c016a..18a31e6ed350 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -5637,7 +5637,7 @@ static const struct mtk_soc_data mt2701_data = { + DESC_SIZE(struct mtk_rx_dma), + .irq_done_mask = MTK_RX_DONE_INT, + .dma_l4_valid = RX_DMA_L4_VALID, +- .dma_size = MTK_DMA_SIZE(2K), ++ .dma_size = MTK_DMA_SIZE(512), + .dma_max_len = MTK_TX_DMA_BUF_LEN, + .dma_len_offset = 16, + }, +@@ -5665,7 +5665,7 @@ static const struct mtk_soc_data mt7621_data = { + DESC_SIZE(struct mtk_rx_dma), + .irq_done_mask = MTK_RX_DONE_INT, + .dma_l4_valid = RX_DMA_L4_VALID, +- .dma_size = MTK_DMA_SIZE(2K), ++ .dma_size = MTK_DMA_SIZE(512), + .dma_max_len = MTK_TX_DMA_BUF_LEN, + .dma_len_offset = 16, + }, +@@ -5695,7 +5695,7 @@ static const struct mtk_soc_data mt7622_data = { + DESC_SIZE(struct mtk_rx_dma), + .irq_done_mask = MTK_RX_DONE_INT, + .dma_l4_valid = RX_DMA_L4_VALID, +- .dma_size = MTK_DMA_SIZE(2K), ++ .dma_size = MTK_DMA_SIZE(512), + .dma_max_len = MTK_TX_DMA_BUF_LEN, + .dma_len_offset = 16, + }, +@@ -5724,7 +5724,7 @@ static const struct mtk_soc_data mt7623_data = { + DESC_SIZE(struct mtk_rx_dma), + .irq_done_mask = MTK_RX_DONE_INT, + .dma_l4_valid = RX_DMA_L4_VALID, +- .dma_size = MTK_DMA_SIZE(2K), ++ .dma_size = MTK_DMA_SIZE(512), + .dma_max_len = MTK_TX_DMA_BUF_LEN, + .dma_len_offset = 16, + }, +@@ -5750,7 +5750,7 @@ static const struct mtk_soc_data mt7629_data = { + DESC_SIZE(struct mtk_rx_dma), + .irq_done_mask = MTK_RX_DONE_INT, + .dma_l4_valid = RX_DMA_L4_VALID, +- .dma_size = MTK_DMA_SIZE(2K), ++ .dma_size = MTK_DMA_SIZE(512), + .dma_max_len = MTK_TX_DMA_BUF_LEN, + .dma_len_offset = 16, + }, +@@ -5782,7 +5782,7 @@ static const struct mtk_soc_data mt7981_data = { + .dma_l4_valid = RX_DMA_L4_VALID_V2, + .dma_max_len = MTK_TX_DMA_BUF_LEN, + .dma_len_offset = 16, +- .dma_size = MTK_DMA_SIZE(2K), ++ .dma_size = MTK_DMA_SIZE(512), + }, + }; + +@@ -5812,7 +5812,7 @@ static const struct mtk_soc_data mt7986_data = { + .dma_l4_valid = RX_DMA_L4_VALID_V2, + .dma_max_len = MTK_TX_DMA_BUF_LEN, + .dma_len_offset = 16, +- .dma_size = MTK_DMA_SIZE(2K), ++ .dma_size = MTK_DMA_SIZE(1K), + }, + }; + +@@ -5865,7 +5865,7 @@ static const struct mtk_soc_data rt5350_data = { + .dma_l4_valid = RX_DMA_L4_VALID_PDMA, + .dma_max_len = MTK_TX_DMA_BUF_LEN, + .dma_len_offset = 16, +- .dma_size = MTK_DMA_SIZE(2K), ++ .dma_size = MTK_DMA_SIZE(256), + }, + }; + +-- +2.51.0 + + +From 7fa390446c8e232a3663e8ed59c0efbb9a3978f3 Mon Sep 17 00:00:00 2001 +From: Danila Romanov +Date: Wed, 22 Jan 2025 06:48:45 +0100 +Subject: [PATCH 302/517] net: ethernet: mtk_eth_soc: do not enable page pool + stats by default + +There is no reason for it to be enabled by default. +Align mtk_eth_soc driver to mt76 driver. + +This option incurs additional CPU cost in allocation and recycle paths +and additional memory cost to store the statistics. + +Signed-off-by: Danila Romanov +Signed-off-by: Felix Fietkau +--- + drivers/net/ethernet/mediatek/Kconfig | 1 - + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 2 ++ + 2 files changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/mediatek/Kconfig b/drivers/net/ethernet/mediatek/Kconfig +index 95c4405b7d7b..d97431682c3a 100644 +--- a/drivers/net/ethernet/mediatek/Kconfig ++++ b/drivers/net/ethernet/mediatek/Kconfig +@@ -26,7 +26,6 @@ config NET_MEDIATEK_SOC + select PHYLINK + select DIMLIB + select PAGE_POOL +- select PAGE_POOL_STATS + select PCS_MTK_LYNXI + select REGMAP_MMIO + help +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +index 18a31e6ed350..bc217da6ffc7 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -4740,6 +4740,7 @@ static int mtk_get_sset_count(struct net_device *dev, int sset) + + static void mtk_ethtool_pp_stats(struct mtk_eth *eth, u64 *data) + { ++#ifdef CONFIG_PAGE_POOL_STATS + struct page_pool_stats stats = {}; + int i; + +@@ -4752,6 +4753,7 @@ static void mtk_ethtool_pp_stats(struct mtk_eth *eth, u64 *data) + page_pool_get_stats(ring->page_pool, &stats); + } + page_pool_ethtool_stats_get(data, &stats); ++#endif + } + + static void mtk_get_ethtool_stats(struct net_device *dev, +-- +2.51.0 + + +From 9e1ea8c49deab1c1c5681faf44991ca8ad03de1c Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Thu, 1 Feb 2024 21:52:20 +0000 +Subject: [PATCH 303/517] dt-bindings: phy: mediatek,xfi-tphy: add new bindings + +Add bindings for the MediaTek XFI T-PHY Ethernet SerDes PHY found in the +MediaTek MT7988 SoC which can operate at various interfaces modes: + +via USXGMII PCS: + * USXGMII + * 10GBase-R + * 5GBase-R + +via LynxI SGMII PCS: + * 2500Base-X + * 1000Base-X + * Cisco SGMII (MAC side) + +Signed-off-by: Daniel Golle +--- + .../bindings/phy/mediatek,xfi-tphy.yaml | 80 +++++++++++++++++++ + 1 file changed, 80 insertions(+) + create mode 100644 Documentation/devicetree/bindings/phy/mediatek,xfi-tphy.yaml + +diff --git a/Documentation/devicetree/bindings/phy/mediatek,xfi-tphy.yaml b/Documentation/devicetree/bindings/phy/mediatek,xfi-tphy.yaml +new file mode 100644 +index 000000000000..e897118dcf7e +--- /dev/null ++++ b/Documentation/devicetree/bindings/phy/mediatek,xfi-tphy.yaml +@@ -0,0 +1,80 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/phy/mediatek,xfi-tphy.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: MediaTek XFI T-PHY ++ ++maintainers: ++ - Daniel Golle ++ ++description: ++ The MediaTek XFI SerDes T-PHY provides the physical SerDes lanes ++ used by the (10G/5G) USXGMII PCS and (1G/2.5G) LynxI PCS found in ++ MediaTek's 10G-capabale SoCs. ++ ++properties: ++ $nodename: ++ pattern: "^phy@[0-9a-f]+$" ++ ++ compatible: ++ const: mediatek,mt7988-xfi-tphy ++ ++ reg: ++ maxItems: 1 ++ ++ clocks: ++ items: ++ - description: XFI PHY clock ++ - description: XFI register clock ++ ++ clock-names: ++ items: ++ - const: xfipll ++ - const: topxtal ++ ++ resets: ++ items: ++ - description: PEXTP reset ++ ++ mediatek,usxgmii-performance-errata: ++ $ref: /schemas/types.yaml#/definitions/flag ++ description: ++ One instance of the T-PHY on MT7988 suffers from a performance ++ problem in 10GBase-R mode which needs a work-around in the driver. ++ The work-around is enabled using this flag. ++ ++ "#phy-cells": ++ const: 0 ++ ++required: ++ - compatible ++ - reg ++ - clocks ++ - clock-names ++ - resets ++ - "#phy-cells" ++ ++additionalProperties: false ++ ++examples: ++ - | ++ #include ++ soc { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ++ phy@11f20000 { ++ compatible = "mediatek,mt7988-xfi-tphy"; ++ reg = <0 0x11f20000 0 0x10000>; ++ clocks = <&xfi_pll CLK_XFIPLL_PLL_EN>, ++ <&topckgen CLK_TOP_XFI_PHY_0_XTAL_SEL>; ++ clock-names = "xfipll", "topxtal"; ++ resets = <&watchdog 14>; ++ mediatek,usxgmii-performance-errata; ++ #phy-cells = <0>; ++ }; ++ }; ++ ++... +-- +2.51.0 + + +From 6521c70d317c1145ac508e6d30bf15238af9c73f Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Tue, 12 Dec 2023 03:47:18 +0000 +Subject: [PATCH 304/517] net: pcs: pcs-mtk-lynxi: add platform driver for + MT7988 + +Introduce a proper platform MFD driver for the LynxI (H)SGMII PCS which +is going to initially be used for the MT7988 SoC. + +Signed-off-by: Daniel Golle +--- + drivers/net/pcs/pcs-mtk-lynxi.c | 224 ++++++++++++++++++++++++++++-- + include/linux/pcs/pcs-mtk-lynxi.h | 11 ++ + 2 files changed, 224 insertions(+), 11 deletions(-) + +diff --git a/drivers/net/pcs/pcs-mtk-lynxi.c b/drivers/net/pcs/pcs-mtk-lynxi.c +index 7de804535229..9f32540bba9c 100644 +--- a/drivers/net/pcs/pcs-mtk-lynxi.c ++++ b/drivers/net/pcs/pcs-mtk-lynxi.c +@@ -1,6 +1,6 @@ + // SPDX-License-Identifier: GPL-2.0 + // Copyright (c) 2018-2019 MediaTek Inc. +-/* A library for MediaTek SGMII circuit ++/* A library and platform driver for the MediaTek LynxI SGMII circuit + * + * Author: Sean Wang + * Author: Alexander Couzens +@@ -8,11 +8,17 @@ + * + */ + ++#include + #include ++#include ++#include + #include ++#include + #include + #include ++#include + #include ++#include + + /* SGMII subsystem config registers */ + /* BMCR (low 16) BMSR (high 16) */ +@@ -65,6 +71,8 @@ + #define SGMII_PN_SWAP_MASK GENMASK(1, 0) + #define SGMII_PN_SWAP_TX_RX (BIT(0) | BIT(1)) + ++#define MTK_NETSYS_V3_AMA_RGC3 0x128 ++ + /* struct mtk_pcs_lynxi - This structure holds each sgmii regmap andassociated + * data + * @regmap: The register map pointing at the range used to setup +@@ -74,15 +82,29 @@ + * @interface: Currently configured interface mode + * @pcs: Phylink PCS structure + * @flags: Flags indicating hardware properties ++ * @rstc: Reset controller ++ * @sgmii_sel: SGMII Register Clock ++ * @sgmii_rx: SGMII RX Clock ++ * @sgmii_tx: SGMII TX Clock ++ * @node: List node + */ + struct mtk_pcs_lynxi { + struct regmap *regmap; ++ struct device *dev; + u32 ana_rgc3; + phy_interface_t interface; + struct phylink_pcs pcs; + u32 flags; ++ struct reset_control *rstc; ++ struct clk *sgmii_sel; ++ struct clk *sgmii_rx; ++ struct clk *sgmii_tx; ++ struct list_head node; + }; + ++static LIST_HEAD(mtk_pcs_lynxi_instances); ++static DEFINE_MUTEX(instance_mutex); ++ + static struct mtk_pcs_lynxi *pcs_to_mtk_pcs_lynxi(struct phylink_pcs *pcs) + { + return container_of(pcs, struct mtk_pcs_lynxi, pcs); +@@ -117,6 +139,17 @@ static void mtk_pcs_lynxi_get_state(struct phylink_pcs *pcs, + FIELD_GET(SGMII_LPA, adv)); + } + ++static void mtk_sgmii_reset(struct mtk_pcs_lynxi *mpcs) ++{ ++ if (!mpcs->rstc) ++ return; ++ ++ reset_control_assert(mpcs->rstc); ++ udelay(100); ++ reset_control_deassert(mpcs->rstc); ++ mdelay(1); ++} ++ + static int mtk_pcs_lynxi_config(struct phylink_pcs *pcs, unsigned int neg_mode, + phy_interface_t interface, + const unsigned long *advertising, +@@ -162,6 +195,7 @@ static int mtk_pcs_lynxi_config(struct phylink_pcs *pcs, unsigned int neg_mode, + SGMII_PHYA_PWD); + + /* Reset SGMII PCS state */ ++ mtk_sgmii_reset(mpcs); + regmap_set_bits(mpcs->regmap, SGMSYS_RESERVED_0, + SGMII_SW_RESET); + +@@ -248,10 +282,29 @@ static void mtk_pcs_lynxi_link_up(struct phylink_pcs *pcs, + } + } + ++static int mtk_pcs_lynxi_enable(struct phylink_pcs *pcs) ++{ ++ struct mtk_pcs_lynxi *mpcs = pcs_to_mtk_pcs_lynxi(pcs); ++ ++ if (mpcs->sgmii_tx && mpcs->sgmii_rx) { ++ clk_prepare_enable(mpcs->sgmii_rx); ++ clk_prepare_enable(mpcs->sgmii_tx); ++ } ++ ++ return 0; ++} ++ + static void mtk_pcs_lynxi_disable(struct phylink_pcs *pcs) + { + struct mtk_pcs_lynxi *mpcs = pcs_to_mtk_pcs_lynxi(pcs); + ++ regmap_set_bits(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, SGMII_PHYA_PWD); ++ ++ if (mpcs->sgmii_tx && mpcs->sgmii_rx) { ++ clk_disable_unprepare(mpcs->sgmii_tx); ++ clk_disable_unprepare(mpcs->sgmii_rx); ++ } ++ + mpcs->interface = PHY_INTERFACE_MODE_NA; + } + +@@ -262,11 +315,12 @@ static const struct phylink_pcs_ops mtk_pcs_lynxi_ops = { + .pcs_an_restart = mtk_pcs_lynxi_restart_an, + .pcs_link_up = mtk_pcs_lynxi_link_up, + .pcs_disable = mtk_pcs_lynxi_disable, ++ .pcs_enable = mtk_pcs_lynxi_enable, + }; + +-struct phylink_pcs *mtk_pcs_lynxi_create(struct device *dev, +- struct regmap *regmap, u32 ana_rgc3, +- u32 flags) ++static struct phylink_pcs *mtk_pcs_lynxi_init(struct device *dev, struct regmap *regmap, ++ u32 ana_rgc3, u32 flags, ++ struct mtk_pcs_lynxi *prealloc) + { + struct mtk_pcs_lynxi *mpcs; + u32 id, ver; +@@ -274,29 +328,33 @@ struct phylink_pcs *mtk_pcs_lynxi_create(struct device *dev, + + ret = regmap_read(regmap, SGMSYS_PCS_DEVICE_ID, &id); + if (ret < 0) +- return NULL; ++ return ERR_PTR(ret); + + if (id != SGMII_LYNXI_DEV_ID) { + dev_err(dev, "unknown PCS device id %08x\n", id); +- return NULL; ++ return ERR_PTR(-ENODEV); + } + + ret = regmap_read(regmap, SGMSYS_PCS_SCRATCH, &ver); + if (ret < 0) +- return NULL; ++ return ERR_PTR(ret); + + ver = FIELD_GET(SGMII_DEV_VERSION, ver); + if (ver != 0x1) { + dev_err(dev, "unknown PCS device version %04x\n", ver); +- return NULL; ++ return ERR_PTR(-ENODEV); + } + + dev_dbg(dev, "MediaTek LynxI SGMII PCS (id 0x%08x, ver 0x%04x)\n", id, + ver); + +- mpcs = kzalloc(sizeof(*mpcs), GFP_KERNEL); +- if (!mpcs) +- return NULL; ++ if (prealloc) { ++ mpcs = prealloc; ++ } else { ++ mpcs = kzalloc(sizeof(*mpcs), GFP_KERNEL); ++ if (!mpcs) ++ return ERR_PTR(-ENOMEM); ++ }; + + mpcs->ana_rgc3 = ana_rgc3; + mpcs->regmap = regmap; +@@ -307,6 +365,13 @@ struct phylink_pcs *mtk_pcs_lynxi_create(struct device *dev, + mpcs->interface = PHY_INTERFACE_MODE_NA; + + return &mpcs->pcs; ++}; ++ ++struct phylink_pcs *mtk_pcs_lynxi_create(struct device *dev, ++ struct regmap *regmap, u32 ana_rgc3, ++ u32 flags) ++{ ++ return mtk_pcs_lynxi_init(dev, regmap, ana_rgc3, flags, NULL); + } + EXPORT_SYMBOL(mtk_pcs_lynxi_create); + +@@ -319,5 +384,142 @@ void mtk_pcs_lynxi_destroy(struct phylink_pcs *pcs) + } + EXPORT_SYMBOL(mtk_pcs_lynxi_destroy); + ++static int mtk_pcs_lynxi_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct device_node *np = dev->of_node; ++ struct mtk_pcs_lynxi *mpcs; ++ struct phylink_pcs *pcs; ++ struct regmap *regmap; ++ u32 flags = 0; ++ ++ mpcs = devm_kzalloc(dev, sizeof(*mpcs), GFP_KERNEL); ++ if (!mpcs) ++ return -ENOMEM; ++ ++ mpcs->dev = dev; ++ regmap = syscon_node_to_regmap(np->parent); ++ if (IS_ERR(regmap)) ++ return PTR_ERR(regmap); ++ ++ if (of_property_read_bool(np->parent, "mediatek,pnswap")) ++ flags |= MTK_SGMII_FLAG_PN_SWAP; ++ ++ mpcs->rstc = of_reset_control_get_shared(np->parent, NULL); ++ if (IS_ERR(mpcs->rstc)) ++ return PTR_ERR(mpcs->rstc); ++ ++ reset_control_deassert(mpcs->rstc); ++ mpcs->sgmii_sel = devm_clk_get_enabled(dev, "sgmii_sel"); ++ if (IS_ERR(mpcs->sgmii_sel)) ++ return PTR_ERR(mpcs->sgmii_sel); ++ ++ mpcs->sgmii_rx = devm_clk_get(dev, "sgmii_rx"); ++ if (IS_ERR(mpcs->sgmii_rx)) ++ return PTR_ERR(mpcs->sgmii_rx); ++ ++ mpcs->sgmii_tx = devm_clk_get(dev, "sgmii_tx"); ++ if (IS_ERR(mpcs->sgmii_tx)) ++ return PTR_ERR(mpcs->sgmii_tx); ++ ++ pcs = mtk_pcs_lynxi_init(dev, regmap, (uintptr_t)of_device_get_match_data(dev), ++ flags, mpcs); ++ if (IS_ERR(pcs)) ++ return PTR_ERR(pcs); ++ ++ regmap_set_bits(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, SGMII_PHYA_PWD); ++ ++ platform_set_drvdata(pdev, mpcs); ++ ++ mutex_lock(&instance_mutex); ++ list_add_tail(&mpcs->node, &mtk_pcs_lynxi_instances); ++ mutex_unlock(&instance_mutex); ++ ++ return 0; ++} ++ ++static void mtk_pcs_lynxi_remove(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct mtk_pcs_lynxi *cur, *tmp; ++ ++ mutex_lock(&instance_mutex); ++ list_for_each_entry_safe(cur, tmp, &mtk_pcs_lynxi_instances, node) ++ if (cur->dev == dev) { ++ list_del(&cur->node); ++ kfree(cur); ++ break; ++ } ++ mutex_unlock(&instance_mutex); ++} ++ ++static const struct of_device_id mtk_pcs_lynxi_of_match[] = { ++ { .compatible = "mediatek,mt7988-sgmii", .data = (void *)MTK_NETSYS_V3_AMA_RGC3 }, ++ { /* sentinel */ }, ++}; ++MODULE_DEVICE_TABLE(of, mtk_pcs_lynxi_of_match); ++ ++struct phylink_pcs *mtk_pcs_lynxi_get(struct device *dev, struct device_node *np) ++{ ++ struct platform_device *pdev; ++ struct mtk_pcs_lynxi *mpcs; ++ ++ if (!np) ++ return NULL; ++ ++ if (!of_device_is_available(np)) ++ return ERR_PTR(-ENODEV); ++ ++ if (!of_match_node(mtk_pcs_lynxi_of_match, np)) ++ return ERR_PTR(-EINVAL); ++ ++ pdev = of_find_device_by_node(np); ++ if (!pdev || !platform_get_drvdata(pdev)) { ++ if (pdev) ++ put_device(&pdev->dev); ++ return ERR_PTR(-EPROBE_DEFER); ++ } ++ ++ mpcs = platform_get_drvdata(pdev); ++ device_link_add(dev, mpcs->dev, DL_FLAG_AUTOREMOVE_CONSUMER); ++ ++ return &mpcs->pcs; ++} ++EXPORT_SYMBOL(mtk_pcs_lynxi_get); ++ ++void mtk_pcs_lynxi_put(struct phylink_pcs *pcs) ++{ ++ struct mtk_pcs_lynxi *cur, *mpcs = NULL; ++ ++ if (!pcs) ++ return; ++ ++ mutex_lock(&instance_mutex); ++ list_for_each_entry(cur, &mtk_pcs_lynxi_instances, node) ++ if (pcs == &cur->pcs) { ++ mpcs = cur; ++ break; ++ } ++ mutex_unlock(&instance_mutex); ++ ++ if (WARN_ON(!mpcs)) ++ return; ++ ++ put_device(mpcs->dev); ++} ++EXPORT_SYMBOL(mtk_pcs_lynxi_put); ++ ++static struct platform_driver mtk_pcs_lynxi_driver = { ++ .driver = { ++ .name = "mtk-pcs-lynxi", ++ .suppress_bind_attrs = true, ++ .of_match_table = mtk_pcs_lynxi_of_match, ++ }, ++ .probe = mtk_pcs_lynxi_probe, ++ .remove_new = mtk_pcs_lynxi_remove, ++}; ++module_platform_driver(mtk_pcs_lynxi_driver); ++ ++MODULE_AUTHOR("Daniel Golle "); + MODULE_DESCRIPTION("MediaTek SGMII library for LynxI"); + MODULE_LICENSE("GPL"); +diff --git a/include/linux/pcs/pcs-mtk-lynxi.h b/include/linux/pcs/pcs-mtk-lynxi.h +index be3b4ab32f4a..2d44e951229c 100644 +--- a/include/linux/pcs/pcs-mtk-lynxi.h ++++ b/include/linux/pcs/pcs-mtk-lynxi.h +@@ -10,4 +10,15 @@ struct phylink_pcs *mtk_pcs_lynxi_create(struct device *dev, + struct regmap *regmap, + u32 ana_rgc3, u32 flags); + void mtk_pcs_lynxi_destroy(struct phylink_pcs *pcs); ++ ++#if IS_ENABLED(CONFIG_PCS_MTK_LYNXI) ++struct phylink_pcs *mtk_pcs_lynxi_get(struct device *dev, struct device_node *np); ++void mtk_pcs_lynxi_put(struct phylink_pcs *pcs); ++#else ++static inline struct phylink_pcs *mtk_pcs_lynxi_get(struct device *dev, struct device_node *np) ++{ ++ return NULL; ++} ++static inline void mtk_pcs_lynxi_put(struct phylink_pcs *pcs) { } ++#endif /* IS_ENABLED(CONFIG_PCS_MTK_LYNXI) */ + #endif +-- +2.51.0 + + +From a09eaf2a559be259da7878179db062e574fcf9ad Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Tue, 12 Dec 2023 03:47:31 +0000 +Subject: [PATCH 305/517] dt-bindings: net: pcs: add bindings for MediaTek + USXGMII PCS + +MediaTek's USXGMII can be found in the MT7988 SoC. We need to access +it in order to configure and monitor the Ethernet SerDes link in +USXGMII, 10GBase-R and 5GBase-R mode. By including a wrapped +legacy 1000Base-X/2500Base-X/Cisco SGMII LynxI PCS as well, those +interface modes are also available. + +Signed-off-by: Daniel Golle +--- + .../bindings/net/pcs/mediatek,usxgmii.yaml | 60 +++++++++++++++++++ + 1 file changed, 60 insertions(+) + create mode 100644 Documentation/devicetree/bindings/net/pcs/mediatek,usxgmii.yaml + +diff --git a/Documentation/devicetree/bindings/net/pcs/mediatek,usxgmii.yaml b/Documentation/devicetree/bindings/net/pcs/mediatek,usxgmii.yaml +new file mode 100644 +index 000000000000..0cdaa3545edb +--- /dev/null ++++ b/Documentation/devicetree/bindings/net/pcs/mediatek,usxgmii.yaml +@@ -0,0 +1,60 @@ ++# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/net/pcs/mediatek,usxgmii.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: MediaTek USXGMII PCS ++ ++maintainers: ++ - Daniel Golle ++ ++description: ++ The MediaTek USXGMII PCS provides physical link control and status ++ for USXGMII, 10GBase-R and 5GBase-R links on the SerDes interfaces ++ provided by the PEXTP PHY. ++ In order to also support legacy 2500Base-X, 1000Base-X and Cisco ++ SGMII an existing mediatek,*-sgmiisys LynxI PCS is wrapped to ++ provide those interfaces modes on the same SerDes interfaces shared ++ with the USXGMII PCS. ++ ++properties: ++ $nodename: ++ pattern: "^pcs@[0-9a-f]+$" ++ ++ compatible: ++ const: mediatek,mt7988-usxgmiisys ++ ++ reg: ++ maxItems: 1 ++ ++ clocks: ++ items: ++ - description: USXGMII top-level clock ++ ++ resets: ++ items: ++ - description: XFI reset ++ ++required: ++ - compatible ++ - reg ++ - clocks ++ - resets ++ ++additionalProperties: false ++ ++examples: ++ - | ++ #include ++ #define MT7988_TOPRGU_XFI0_GRST 12 ++ soc { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ usxgmiisys0: pcs@10080000 { ++ compatible = "mediatek,mt7988-usxgmiisys"; ++ reg = <0 0x10080000 0 0x1000>; ++ clocks = <&topckgen CLK_TOP_USXGMII_SBUS_0_SEL>; ++ resets = <&watchdog MT7988_TOPRGU_XFI0_GRST>; ++ }; ++ }; +-- +2.51.0 + + +From 0005a0d86158863f4dd392dae5faca22f13d5f0e Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Tue, 12 Dec 2023 03:47:47 +0000 +Subject: [PATCH 306/517] net: pcs: add driver for MediaTek USXGMII PCS + +Add driver for USXGMII PCS found in the MediaTek MT7988 SoC and supporting +USXGMII, 10GBase-R and 5GBase-R interface modes. + +Signed-off-by: Daniel Golle +--- + MAINTAINERS | 2 + + drivers/net/pcs/Kconfig | 11 + + drivers/net/pcs/Makefile | 1 + + drivers/net/pcs/pcs-mtk-usxgmii.c | 454 ++++++++++++++++++++++++++++ + include/linux/pcs/pcs-mtk-usxgmii.h | 27 ++ + 5 files changed, 495 insertions(+) + create mode 100644 drivers/net/pcs/pcs-mtk-usxgmii.c + create mode 100644 include/linux/pcs/pcs-mtk-usxgmii.h + +diff --git a/MAINTAINERS b/MAINTAINERS +index dcb5c71bc204..3a22c29b35a6 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -14419,7 +14419,9 @@ M: Daniel Golle + L: netdev@vger.kernel.org + S: Maintained + F: drivers/net/pcs/pcs-mtk-lynxi.c ++F: drivers/net/pcs/pcs-mtk-usxgmii.c + F: include/linux/pcs/pcs-mtk-lynxi.h ++F: include/linux/pcs/pcs-mtk-usxgmii.h + + MEDIATEK ETHERNET PHY DRIVERS + M: Daniel Golle +diff --git a/drivers/net/pcs/Kconfig b/drivers/net/pcs/Kconfig +index f6aa437473de..8c642da2c6e0 100644 +--- a/drivers/net/pcs/Kconfig ++++ b/drivers/net/pcs/Kconfig +@@ -25,6 +25,17 @@ config PCS_MTK_LYNXI + This module provides helpers to phylink for managing the LynxI PCS + which is part of MediaTek's SoC and Ethernet switch ICs. + ++config PCS_MTK_USXGMII ++ tristate "MediaTek USXGMII PCS" ++ select PCS_MTK_LYNXI ++ select PHY_MTK_PEXTP ++ select PHYLINK ++ help ++ This module provides a driver for MediaTek's USXGMII PCS supporting ++ 10GBase-R, 5GBase-R and USXGMII interface modes. ++ 1000Base-X, 2500Base-X and Cisco SGMII are supported on the same ++ differential pairs via an embedded LynxI PHY. ++ + config PCS_RZN1_MIIC + tristate "Renesas RZ/N1 MII converter" + depends on OF && (ARCH_RZN1 || COMPILE_TEST) +diff --git a/drivers/net/pcs/Makefile b/drivers/net/pcs/Makefile +index 4f7920618b90..20647ac375d5 100644 +--- a/drivers/net/pcs/Makefile ++++ b/drivers/net/pcs/Makefile +@@ -8,3 +8,4 @@ obj-$(CONFIG_PCS_XPCS) += pcs_xpcs.o + obj-$(CONFIG_PCS_LYNX) += pcs-lynx.o + obj-$(CONFIG_PCS_MTK_LYNXI) += pcs-mtk-lynxi.o + obj-$(CONFIG_PCS_RZN1_MIIC) += pcs-rzn1-miic.o ++obj-$(CONFIG_PCS_MTK_USXGMII) += pcs-mtk-usxgmii.o +diff --git a/drivers/net/pcs/pcs-mtk-usxgmii.c b/drivers/net/pcs/pcs-mtk-usxgmii.c +new file mode 100644 +index 000000000000..9691d9e73790 +--- /dev/null ++++ b/drivers/net/pcs/pcs-mtk-usxgmii.c +@@ -0,0 +1,454 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (c) 2023 MediaTek Inc. ++ * Author: Henry Yen ++ * Daniel Golle ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* USXGMII subsystem config registers */ ++/* Register to control speed */ ++#define RG_PHY_TOP_SPEED_CTRL1 0x80c ++#define USXGMII_RATE_UPDATE_MODE BIT(31) ++#define USXGMII_MAC_CK_GATED BIT(29) ++#define USXGMII_IF_FORCE_EN BIT(28) ++#define USXGMII_RATE_ADAPT_MODE GENMASK(10, 8) ++#define USXGMII_RATE_ADAPT_MODE_X1 0 ++#define USXGMII_RATE_ADAPT_MODE_X2 1 ++#define USXGMII_RATE_ADAPT_MODE_X4 2 ++#define USXGMII_RATE_ADAPT_MODE_X10 3 ++#define USXGMII_RATE_ADAPT_MODE_X100 4 ++#define USXGMII_RATE_ADAPT_MODE_X5 5 ++#define USXGMII_RATE_ADAPT_MODE_X50 6 ++#define USXGMII_XFI_RX_MODE GENMASK(6, 4) ++#define USXGMII_XFI_TX_MODE GENMASK(2, 0) ++#define USXGMII_XFI_MODE_10G 0 ++#define USXGMII_XFI_MODE_5G 1 ++#define USXGMII_XFI_MODE_2P5G 3 ++ ++/* Register to control PCS AN */ ++#define RG_PCS_AN_CTRL0 0x810 ++#define USXGMII_AN_RESTART BIT(31) ++#define USXGMII_AN_SYNC_CNT GENMASK(30, 11) ++#define USXGMII_AN_ENABLE BIT(0) ++ ++#define RG_PCS_AN_CTRL2 0x818 ++#define USXGMII_LINK_TIMER_IDLE_DETECT GENMASK(29, 20) ++#define USXGMII_LINK_TIMER_COMP_ACK_DETECT GENMASK(19, 10) ++#define USXGMII_LINK_TIMER_AN_RESTART GENMASK(9, 0) ++ ++/* Register to read PCS AN status */ ++#define RG_PCS_AN_STS0 0x81c ++#define USXGMII_LPA GENMASK(15, 0) ++#define USXGMII_LPA_LATCH BIT(31) ++ ++/* Register to read PCS link status */ ++#define RG_PCS_RX_STATUS0 0x904 ++#define RG_PCS_RX_STATUS_UPDATE BIT(16) ++#define RG_PCS_RX_LINK_STATUS BIT(2) ++ ++/* struct mtk_usxgmii_pcs - This structure holds each usxgmii PCS ++ * @pcs: Phylink PCS structure ++ * @dev: Pointer to device structure ++ * @base: IO memory to access PCS hardware ++ * @clk: Pointer to USXGMII clk ++ * @reset: Pointer to USXGMII reset control ++ * @interface: Currently selected interface mode ++ * @neg_mode: Currently used phylink neg_mode ++ * @node: List node ++ */ ++struct mtk_usxgmii_pcs { ++ struct phylink_pcs pcs; ++ struct device *dev; ++ void __iomem *base; ++ struct clk *clk; ++ struct reset_control *reset; ++ phy_interface_t interface; ++ unsigned int neg_mode; ++ struct list_head node; ++}; ++ ++static LIST_HEAD(mtk_usxgmii_pcs_instances); ++static DEFINE_MUTEX(instance_mutex); ++ ++static u32 mtk_r32(struct mtk_usxgmii_pcs *mpcs, unsigned int reg) ++{ ++ return ioread32(mpcs->base + reg); ++} ++ ++static void mtk_m32(struct mtk_usxgmii_pcs *mpcs, unsigned int reg, u32 mask, u32 set) ++{ ++ u32 val; ++ ++ val = ioread32(mpcs->base + reg); ++ val &= ~mask; ++ val |= set; ++ iowrite32(val, mpcs->base + reg); ++} ++ ++static struct mtk_usxgmii_pcs *pcs_to_mtk_usxgmii_pcs(struct phylink_pcs *pcs) ++{ ++ return container_of(pcs, struct mtk_usxgmii_pcs, pcs); ++} ++ ++static void mtk_usxgmii_reset(struct mtk_usxgmii_pcs *mpcs) ++{ ++ reset_control_assert(mpcs->reset); ++ udelay(100); ++ reset_control_deassert(mpcs->reset); ++ ++ mdelay(10); ++} ++ ++static int mtk_usxgmii_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode, ++ phy_interface_t interface, ++ const unsigned long *advertising, ++ bool permit_pause_to_mac) ++{ ++ struct mtk_usxgmii_pcs *mpcs = pcs_to_mtk_usxgmii_pcs(pcs); ++ unsigned int an_ctrl = 0, link_timer = 0, xfi_mode = 0, adapt_mode = 0; ++ bool mode_changed = false; ++ ++ if (interface == PHY_INTERFACE_MODE_USXGMII) { ++ an_ctrl = FIELD_PREP(USXGMII_AN_SYNC_CNT, 0x1FF) | USXGMII_AN_ENABLE; ++ link_timer = FIELD_PREP(USXGMII_LINK_TIMER_IDLE_DETECT, 0x7B) | ++ FIELD_PREP(USXGMII_LINK_TIMER_COMP_ACK_DETECT, 0x7B) | ++ FIELD_PREP(USXGMII_LINK_TIMER_AN_RESTART, 0x7B); ++ xfi_mode = FIELD_PREP(USXGMII_XFI_RX_MODE, USXGMII_XFI_MODE_10G) | ++ FIELD_PREP(USXGMII_XFI_TX_MODE, USXGMII_XFI_MODE_10G); ++ } else if (interface == PHY_INTERFACE_MODE_10GBASER) { ++ an_ctrl = FIELD_PREP(USXGMII_AN_SYNC_CNT, 0x1FF); ++ link_timer = FIELD_PREP(USXGMII_LINK_TIMER_IDLE_DETECT, 0x7B) | ++ FIELD_PREP(USXGMII_LINK_TIMER_COMP_ACK_DETECT, 0x7B) | ++ FIELD_PREP(USXGMII_LINK_TIMER_AN_RESTART, 0x7B); ++ xfi_mode = FIELD_PREP(USXGMII_XFI_RX_MODE, USXGMII_XFI_MODE_10G) | ++ FIELD_PREP(USXGMII_XFI_TX_MODE, USXGMII_XFI_MODE_10G); ++ adapt_mode = USXGMII_RATE_UPDATE_MODE; ++ } else if (interface == PHY_INTERFACE_MODE_5GBASER) { ++ an_ctrl = FIELD_PREP(USXGMII_AN_SYNC_CNT, 0xFF); ++ link_timer = FIELD_PREP(USXGMII_LINK_TIMER_IDLE_DETECT, 0x3D) | ++ FIELD_PREP(USXGMII_LINK_TIMER_COMP_ACK_DETECT, 0x3D) | ++ FIELD_PREP(USXGMII_LINK_TIMER_AN_RESTART, 0x3D); ++ xfi_mode = FIELD_PREP(USXGMII_XFI_RX_MODE, USXGMII_XFI_MODE_5G) | ++ FIELD_PREP(USXGMII_XFI_TX_MODE, USXGMII_XFI_MODE_5G); ++ adapt_mode = USXGMII_RATE_UPDATE_MODE; ++ } else { ++ return -EINVAL; ++ } ++ ++ adapt_mode |= FIELD_PREP(USXGMII_RATE_ADAPT_MODE, USXGMII_RATE_ADAPT_MODE_X1); ++ ++ if (mpcs->interface != interface) { ++ mpcs->interface = interface; ++ mode_changed = true; ++ } ++ ++ mtk_usxgmii_reset(mpcs); ++ ++ /* Setup USXGMII AN ctrl */ ++ mtk_m32(mpcs, RG_PCS_AN_CTRL0, ++ USXGMII_AN_SYNC_CNT | USXGMII_AN_ENABLE, ++ an_ctrl); ++ ++ mtk_m32(mpcs, RG_PCS_AN_CTRL2, ++ USXGMII_LINK_TIMER_IDLE_DETECT | ++ USXGMII_LINK_TIMER_COMP_ACK_DETECT | ++ USXGMII_LINK_TIMER_AN_RESTART, ++ link_timer); ++ ++ mpcs->neg_mode = neg_mode; ++ ++ /* Gated MAC CK */ ++ mtk_m32(mpcs, RG_PHY_TOP_SPEED_CTRL1, ++ USXGMII_MAC_CK_GATED, USXGMII_MAC_CK_GATED); ++ ++ /* Enable interface force mode */ ++ mtk_m32(mpcs, RG_PHY_TOP_SPEED_CTRL1, ++ USXGMII_IF_FORCE_EN, USXGMII_IF_FORCE_EN); ++ ++ /* Setup USXGMII adapt mode */ ++ mtk_m32(mpcs, RG_PHY_TOP_SPEED_CTRL1, ++ USXGMII_RATE_UPDATE_MODE | USXGMII_RATE_ADAPT_MODE, ++ adapt_mode); ++ ++ /* Setup USXGMII speed */ ++ mtk_m32(mpcs, RG_PHY_TOP_SPEED_CTRL1, ++ USXGMII_XFI_RX_MODE | USXGMII_XFI_TX_MODE, ++ xfi_mode); ++ ++ usleep_range(1, 10); ++ ++ /* Un-gated MAC CK */ ++ mtk_m32(mpcs, RG_PHY_TOP_SPEED_CTRL1, USXGMII_MAC_CK_GATED, 0); ++ ++ usleep_range(1, 10); ++ ++ /* Disable interface force mode for the AN mode */ ++ if (an_ctrl & USXGMII_AN_ENABLE) ++ mtk_m32(mpcs, RG_PHY_TOP_SPEED_CTRL1, USXGMII_IF_FORCE_EN, 0); ++ ++ return mode_changed; ++} ++ ++static void mtk_usxgmii_pcs_get_fixed_speed(struct mtk_usxgmii_pcs *mpcs, ++ struct phylink_link_state *state) ++{ ++ u32 val = mtk_r32(mpcs, RG_PHY_TOP_SPEED_CTRL1); ++ int speed; ++ ++ /* Calculate speed from interface speed and rate adapt mode */ ++ switch (FIELD_GET(USXGMII_XFI_RX_MODE, val)) { ++ case USXGMII_XFI_MODE_10G: ++ speed = 10000; ++ break; ++ case USXGMII_XFI_MODE_5G: ++ speed = 5000; ++ break; ++ case USXGMII_XFI_MODE_2P5G: ++ speed = 2500; ++ break; ++ default: ++ state->speed = SPEED_UNKNOWN; ++ return; ++ } ++ ++ switch (FIELD_GET(USXGMII_RATE_ADAPT_MODE, val)) { ++ case USXGMII_RATE_ADAPT_MODE_X100: ++ speed /= 100; ++ break; ++ case USXGMII_RATE_ADAPT_MODE_X50: ++ speed /= 50; ++ break; ++ case USXGMII_RATE_ADAPT_MODE_X10: ++ speed /= 10; ++ break; ++ case USXGMII_RATE_ADAPT_MODE_X5: ++ speed /= 5; ++ break; ++ case USXGMII_RATE_ADAPT_MODE_X4: ++ speed /= 4; ++ break; ++ case USXGMII_RATE_ADAPT_MODE_X2: ++ speed /= 2; ++ break; ++ case USXGMII_RATE_ADAPT_MODE_X1: ++ break; ++ default: ++ state->speed = SPEED_UNKNOWN; ++ return; ++ } ++ ++ state->speed = speed; ++ state->duplex = DUPLEX_FULL; ++} ++ ++static void mtk_usxgmii_pcs_get_an_state(struct mtk_usxgmii_pcs *mpcs, ++ struct phylink_link_state *state) ++{ ++ u16 lpa; ++ ++ /* Refresh LPA by toggling LPA_LATCH */ ++ mtk_m32(mpcs, RG_PCS_AN_STS0, USXGMII_LPA_LATCH, USXGMII_LPA_LATCH); ++ ndelay(1020); ++ mtk_m32(mpcs, RG_PCS_AN_STS0, USXGMII_LPA_LATCH, 0); ++ ndelay(1020); ++ lpa = FIELD_GET(USXGMII_LPA, mtk_r32(mpcs, RG_PCS_AN_STS0)); ++ ++ phylink_decode_usxgmii_word(state, lpa); ++} ++ ++static void mtk_usxgmii_pcs_get_state(struct phylink_pcs *pcs, ++ struct phylink_link_state *state) ++{ ++ struct mtk_usxgmii_pcs *mpcs = pcs_to_mtk_usxgmii_pcs(pcs); ++ ++ /* Refresh USXGMII link status by toggling RG_PCS_AN_STATUS_UPDATE */ ++ mtk_m32(mpcs, RG_PCS_RX_STATUS0, RG_PCS_RX_STATUS_UPDATE, ++ RG_PCS_RX_STATUS_UPDATE); ++ ndelay(1020); ++ mtk_m32(mpcs, RG_PCS_RX_STATUS0, RG_PCS_RX_STATUS_UPDATE, 0); ++ ndelay(1020); ++ ++ /* Read USXGMII link status */ ++ state->link = FIELD_GET(RG_PCS_RX_LINK_STATUS, ++ mtk_r32(mpcs, RG_PCS_RX_STATUS0)); ++ ++ /* Continuously repeat re-configuration sequence until link comes up */ ++ if (!state->link) { ++ mtk_usxgmii_pcs_config(pcs, mpcs->neg_mode, ++ state->interface, NULL, false); ++ return; ++ } ++ ++ if (FIELD_GET(USXGMII_AN_ENABLE, mtk_r32(mpcs, RG_PCS_AN_CTRL0))) ++ mtk_usxgmii_pcs_get_an_state(mpcs, state); ++ else ++ mtk_usxgmii_pcs_get_fixed_speed(mpcs, state); ++} ++ ++static void mtk_usxgmii_pcs_restart_an(struct phylink_pcs *pcs) ++{ ++ struct mtk_usxgmii_pcs *mpcs = pcs_to_mtk_usxgmii_pcs(pcs); ++ ++ mtk_m32(mpcs, RG_PCS_AN_CTRL0, USXGMII_AN_RESTART, USXGMII_AN_RESTART); ++} ++ ++static void mtk_usxgmii_pcs_link_up(struct phylink_pcs *pcs, unsigned int neg_mode, ++ phy_interface_t interface, ++ int speed, int duplex) ++{ ++ /* Reconfiguring USXGMII to ensure the quality of the RX signal ++ * after the line side link up. ++ */ ++ mtk_usxgmii_pcs_config(pcs, neg_mode, interface, NULL, false); ++} ++ ++static void mtk_usxgmii_pcs_disable(struct phylink_pcs *pcs) ++{ ++ struct mtk_usxgmii_pcs *mpcs = pcs_to_mtk_usxgmii_pcs(pcs); ++ ++ mpcs->interface = PHY_INTERFACE_MODE_NA; ++ mpcs->neg_mode = -1; ++} ++ ++static const struct phylink_pcs_ops mtk_usxgmii_pcs_ops = { ++ .pcs_config = mtk_usxgmii_pcs_config, ++ .pcs_get_state = mtk_usxgmii_pcs_get_state, ++ .pcs_an_restart = mtk_usxgmii_pcs_restart_an, ++ .pcs_link_up = mtk_usxgmii_pcs_link_up, ++ .pcs_disable = mtk_usxgmii_pcs_disable, ++}; ++ ++static int mtk_usxgmii_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct mtk_usxgmii_pcs *mpcs; ++ ++ mpcs = devm_kzalloc(dev, sizeof(*mpcs), GFP_KERNEL); ++ if (!mpcs) ++ return -ENOMEM; ++ ++ mpcs->base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(mpcs->base)) ++ return PTR_ERR(mpcs->base); ++ ++ mpcs->dev = dev; ++ mpcs->pcs.ops = &mtk_usxgmii_pcs_ops; ++ mpcs->pcs.poll = true; ++ mpcs->pcs.neg_mode = true; ++ mpcs->interface = PHY_INTERFACE_MODE_NA; ++ mpcs->neg_mode = -1; ++ ++ mpcs->clk = devm_clk_get_enabled(mpcs->dev, NULL); ++ if (IS_ERR(mpcs->clk)) ++ return PTR_ERR(mpcs->clk); ++ ++ mpcs->reset = devm_reset_control_get_shared(dev, NULL); ++ if (IS_ERR(mpcs->reset)) ++ return PTR_ERR(mpcs->reset); ++ ++ reset_control_deassert(mpcs->reset); ++ ++ platform_set_drvdata(pdev, mpcs); ++ ++ mutex_lock(&instance_mutex); ++ list_add_tail(&mpcs->node, &mtk_usxgmii_pcs_instances); ++ mutex_unlock(&instance_mutex); ++ ++ return 0; ++} ++ ++static void mtk_usxgmii_remove(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct mtk_usxgmii_pcs *cur, *tmp; ++ ++ mutex_lock(&instance_mutex); ++ list_for_each_entry_safe(cur, tmp, &mtk_usxgmii_pcs_instances, node) ++ if (cur->dev == dev) { ++ list_del(&cur->node); ++ break; ++ } ++ mutex_unlock(&instance_mutex); ++} ++ ++static const struct of_device_id mtk_usxgmii_of_mtable[] = { ++ { .compatible = "mediatek,mt7988-usxgmiisys" }, ++ { /* sentinel */ }, ++}; ++MODULE_DEVICE_TABLE(of, mtk_usxgmii_of_mtable); ++ ++struct phylink_pcs *mtk_usxgmii_pcs_get(struct device *dev, struct device_node *np) ++{ ++ struct platform_device *pdev; ++ struct mtk_usxgmii_pcs *mpcs; ++ ++ if (!np) ++ return NULL; ++ ++ if (!of_device_is_available(np)) ++ return ERR_PTR(-ENODEV); ++ ++ if (!of_match_node(mtk_usxgmii_of_mtable, np)) ++ return ERR_PTR(-EINVAL); ++ ++ pdev = of_find_device_by_node(np); ++ if (!pdev || !platform_get_drvdata(pdev)) { ++ if (pdev) ++ put_device(&pdev->dev); ++ return ERR_PTR(-EPROBE_DEFER); ++ } ++ ++ mpcs = platform_get_drvdata(pdev); ++ device_link_add(dev, mpcs->dev, DL_FLAG_AUTOREMOVE_CONSUMER); ++ ++ return &mpcs->pcs; ++} ++EXPORT_SYMBOL(mtk_usxgmii_pcs_get); ++ ++void mtk_usxgmii_pcs_put(struct phylink_pcs *pcs) ++{ ++ struct mtk_usxgmii_pcs *cur, *mpcs = NULL; ++ ++ if (!pcs) ++ return; ++ ++ mutex_lock(&instance_mutex); ++ list_for_each_entry(cur, &mtk_usxgmii_pcs_instances, node) ++ if (pcs == &cur->pcs) { ++ mpcs = cur; ++ break; ++ } ++ mutex_unlock(&instance_mutex); ++ ++ if (WARN_ON(!mpcs)) ++ return; ++ ++ put_device(mpcs->dev); ++} ++EXPORT_SYMBOL(mtk_usxgmii_pcs_put); ++ ++static struct platform_driver mtk_usxgmii_driver = { ++ .driver = { ++ .name = "mtk_usxgmii", ++ .suppress_bind_attrs = true, ++ .of_match_table = mtk_usxgmii_of_mtable, ++ }, ++ .probe = mtk_usxgmii_probe, ++ .remove_new = mtk_usxgmii_remove, ++}; ++module_platform_driver(mtk_usxgmii_driver); ++ ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("MediaTek USXGMII PCS driver"); ++MODULE_AUTHOR("Daniel Golle "); +diff --git a/include/linux/pcs/pcs-mtk-usxgmii.h b/include/linux/pcs/pcs-mtk-usxgmii.h +new file mode 100644 +index 000000000000..ef936d9c5f11 +--- /dev/null ++++ b/include/linux/pcs/pcs-mtk-usxgmii.h +@@ -0,0 +1,27 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++#ifndef __LINUX_PCS_MTK_USXGMII_H ++#define __LINUX_PCS_MTK_USXGMII_H ++ ++#include ++ ++/** ++ * mtk_usxgmii_select_pcs() - Get MediaTek PCS instance ++ * @np: Pointer to device node indentifying a MediaTek USXGMII PCS ++ * @mode: Ethernet PHY interface mode ++ * ++ * Return PCS identified by a device node and the PHY interface mode in use ++ * ++ * Return: Pointer to phylink PCS instance of NULL ++ */ ++#if IS_ENABLED(CONFIG_PCS_MTK_USXGMII) ++struct phylink_pcs *mtk_usxgmii_pcs_get(struct device *dev, struct device_node *np); ++void mtk_usxgmii_pcs_put(struct phylink_pcs *pcs); ++#else ++static inline struct phylink_pcs *mtk_usxgmii_pcs_get(struct device *dev, struct device_node *np) ++{ ++ return NULL; ++} ++static inline void mtk_usxgmii_pcs_put(struct phylink_pcs *pcs) { } ++#endif /* IS_ENABLED(CONFIG_PCS_MTK_USXGMII) */ ++ ++#endif /* __LINUX_PCS_MTK_USXGMII_H */ +-- +2.51.0 + + +From 8d0a817f11fff5555100d757f73aa7d702774a83 Mon Sep 17 00:00:00 2001 +From: Hauke Mehrtens +Date: Sun, 21 May 2023 22:24:56 +0200 +Subject: [PATCH 307/517] net: phy: motorcomm: Add missing include + +Directly include linux/bitfield.h which provides FIELD_PREP. + +Signed-off-by: Hauke Mehrtens +--- + drivers/net/phy/motorcomm.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/phy/motorcomm.c b/drivers/net/phy/motorcomm.c +index 0e91f5d1a4fd..cb57ebb87237 100644 +--- a/drivers/net/phy/motorcomm.c ++++ b/drivers/net/phy/motorcomm.c +@@ -6,6 +6,7 @@ + * Author: Frank + */ + ++#include + #include + #include + #include +-- +2.51.0 + + +From 64c6f86708f9e4ccf5e70f38508f88be90d095c9 Mon Sep 17 00:00:00 2001 +From: David Bauer +Date: Sat, 16 Nov 2024 22:36:15 +0100 +Subject: [PATCH 308/517] net: phy: broadcom: update dependency condition + +The broadcom PHY driver only has to depend upon PTP_1588_CLOCK_OPTIONAL +if NETWORK_PHY_TIMESTAMPING is enabled. The PTP functionality is stubbed +in this case. + +Reflect this circumstance in the dependence condition. This allows to +build the driver as a built-in module even if PTP is built as a module. + +This is required to include the broadcom PHY module regardless of the +built-setting of the PTP subsystem. On ath79 (and probably more) +targets with Broadcom PHY, Gigabit operation is currently broken as the +PHY driver is only built as a module in case all kernel-packages are +built. Due to this circumstance, affected devices fall back to using the +generic PHY driver. + +Signed-off-by: David Bauer +--- + drivers/net/phy/Kconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig +index bf7c34402e74..8c92405b84d4 100644 +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -151,7 +151,7 @@ config BROADCOM_PHY + tristate "Broadcom 54XX PHYs" + select BCM_NET_PHYLIB + select BCM_NET_PHYPTP if NETWORK_PHY_TIMESTAMPING +- depends on PTP_1588_CLOCK_OPTIONAL ++ depends on NETWORK_PHY_TIMESTAMPING=n || PTP_1588_CLOCK_OPTIONAL + help + Currently supports the BCM5411, BCM5421, BCM5461, BCM54616S, BCM5464, + BCM5481, BCM54810 and BCM5482 PHYs. +-- +2.51.0 + + +From e3a83bc28d2d129742cc38dbb1e652c9839c110b Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Thu, 5 Aug 2021 23:23:30 +0100 +Subject: [PATCH 309/517] ARM: kirkwood: add missing for + ETH_ALEN + +After commit 83216e3988cd1 ("of: net: pass the dst buffer to +of_get_mac_address()") build fails for kirkwood as ETH_ALEN is not +defined. + +arch/arm/mach-mvebu/kirkwood.c: In function 'kirkwood_dt_eth_fixup': +arch/arm/mach-mvebu/kirkwood.c:87:13: error: 'ETH_ALEN' undeclared (first use in this function); did you mean 'ESTALE'? + u8 tmpmac[ETH_ALEN]; + ^~~~~~~~ + ESTALE +arch/arm/mach-mvebu/kirkwood.c:87:13: note: each undeclared identifier is reported only once for each function it appears in +arch/arm/mach-mvebu/kirkwood.c:87:6: warning: unused variable 'tmpmac' [-Wunused-variable] + u8 tmpmac[ETH_ALEN]; + ^~~~~~ +make[5]: *** [scripts/Makefile.build:262: arch/arm/mach-mvebu/kirkwood.o] Error 1 +make[5]: *** Waiting for unfinished jobs.... + +Add missing #include to fix this. + +Cc: David S. Miller +Cc: Andrew Lunn +Cc: Michael Walle +Reported-by: https://buildbot.openwrt.org/master/images/#/builders/56/builds/220/steps/44/logs/stdio +Fixes: 83216e3988cd1 ("of: net: pass the dst buffer to of_get_mac_address()") +Signed-off-by: Daniel Golle +--- + arch/arm/mach-mvebu/kirkwood.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm/mach-mvebu/kirkwood.c b/arch/arm/mach-mvebu/kirkwood.c +index 73b2a86d6489..b375df4010c2 100644 +--- a/arch/arm/mach-mvebu/kirkwood.c ++++ b/arch/arm/mach-mvebu/kirkwood.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + #include + #include + #include +-- +2.51.0 + + +From 47f8ae989e1a237b33f2e91babea618444b71d42 Mon Sep 17 00:00:00 2001 +From: Robert Marko +Date: Sat, 5 Nov 2022 20:02:56 +0100 +Subject: [PATCH 310/517] bus: mhi: core: add SBL state callback + +Add support for SBL state callback in MHI core. + +It is required for ath11k MHI devices in order to be able to set QRTR +instance ID in the SBL state so that QRTR instance ID-s dont conflict in +case of multiple PCI/MHI cards or AHB + PCI/MHI card. +Setting QRTR instance ID is only possible in SBL state and there is +currently no way to ensure that we are in that state, so provide a +callback that the controller can trigger off. + +Signed-off-by: Robert Marko +--- + drivers/bus/mhi/host/main.c | 1 + + include/linux/mhi.h | 2 ++ + 2 files changed, 3 insertions(+) + +diff --git a/drivers/bus/mhi/host/main.c b/drivers/bus/mhi/host/main.c +index 45ec1b585577..45b28cd4f9b8 100644 +--- a/drivers/bus/mhi/host/main.c ++++ b/drivers/bus/mhi/host/main.c +@@ -916,6 +916,7 @@ int mhi_process_ctrl_ev_ring(struct mhi_controller *mhi_cntrl, + switch (event) { + case MHI_EE_SBL: + st = DEV_ST_TRANSITION_SBL; ++ mhi_cntrl->status_cb(mhi_cntrl, MHI_CB_EE_SBL_MODE); + break; + case MHI_EE_WFW: + case MHI_EE_AMSS: +diff --git a/include/linux/mhi.h b/include/linux/mhi.h +index 059dc94d20bb..b2f1cf400065 100644 +--- a/include/linux/mhi.h ++++ b/include/linux/mhi.h +@@ -34,6 +34,7 @@ struct mhi_buf_info; + * @MHI_CB_SYS_ERROR: MHI device entered error state (may recover) + * @MHI_CB_FATAL_ERROR: MHI device entered fatal error state + * @MHI_CB_BW_REQ: Received a bandwidth switch request from device ++ * @MHI_CB_EE_SBL_MODE: MHI device entered SBL mode + */ + enum mhi_callback { + MHI_CB_IDLE, +@@ -45,6 +46,7 @@ enum mhi_callback { + MHI_CB_SYS_ERROR, + MHI_CB_FATAL_ERROR, + MHI_CB_BW_REQ, ++ MHI_CB_EE_SBL_MODE, + }; + + /** +-- +2.51.0 + + +From e75c28fcf09e756a41d0be9abc31eaa86b8f5ca3 Mon Sep 17 00:00:00 2001 +From: Pavan Chebbi +Date: Tue, 10 Dec 2024 03:28:31 -0800 +Subject: [PATCH 311/517] tg3: Fix DMA allocations on 57766 devices + +The coherent DMA mask of 31b may not be accepted if +the DMA mask is configured to use higher memories of +64b. Set the DMA mask also to lower 32b for 57766 +devices. + +Fixes: 614f4d166eee ("tg3: Set coherent DMA mask bits to 31 for BCM57766 chipsets") +Reported-By: Rui Salvaterra +Signed-off-by: Pavan Chebbi +--- + drivers/net/ethernet/broadcom/tg3.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c +index dc170feee8ad..cf61cb311f23 100644 +--- a/drivers/net/ethernet/broadcom/tg3.c ++++ b/drivers/net/ethernet/broadcom/tg3.c +@@ -17799,8 +17799,10 @@ static int tg3_init_one(struct pci_dev *pdev, + } else + persist_dma_mask = dma_mask = DMA_BIT_MASK(64); + +- if (tg3_asic_rev(tp) == ASIC_REV_57766) ++ if (tg3_asic_rev(tp) == ASIC_REV_57766) { ++ dma_mask = DMA_BIT_MASK(32); + persist_dma_mask = DMA_BIT_MASK(31); ++ } + + /* Configure DMA attributes. */ + if (dma_mask > DMA_BIT_MASK(32)) { +-- +2.51.0 + + +From 672489ca59270bcbe18cf959c77b9401292371e4 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Mon, 3 Nov 2025 15:50:09 +0100 +Subject: [PATCH 312/517] bcma: get SoC device struct & copy its DMA params to + the subdevices +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +For bus devices to be fully usable it's required to set their DMA +parameters. + +For years it has been missing and remained unnoticed because of +mips_dma_alloc_coherent() silently handling the empty coherent_dma_mask. +Kernel 4.19 came with a lot of DMA changes and caused a regression on +the bcm47xx. Starting with the commit f8c55dc6e828 ("MIPS: use generic +dma noncoherent ops for simple noncoherent platforms") DMA coherent +allocations just fail. Example: +[ 1.114914] bgmac_bcma bcma0:2: Allocation of TX ring 0x200 failed +[ 1.121215] bgmac_bcma bcma0:2: Unable to alloc memory for DMA +[ 1.127626] bgmac_bcma: probe of bcma0:2 failed with error -12 +[ 1.133838] bgmac_bcma: Broadcom 47xx GBit MAC driver loaded + +This change fixes above regression in addition to the MIPS bcm47xx +commit 321c46b91550 ("MIPS: BCM47XX: Setup struct device for the SoC"). + +It also fixes another *old* GPIO regression caused by a parent pointing +to the NULL: +[ 0.157054] missing gpiochip .dev parent pointer +[ 0.157287] bcma: bus0: Error registering GPIO driver: -22 +introduced by the commit 74f4e0cc6108 ("bcma: switch GPIO portions to +use GPIOLIB_IRQCHIP"). + +Fixes: f8c55dc6e828 ("MIPS: use generic dma noncoherent ops for simple noncoherent platforms") +Fixes: 74f4e0cc6108 ("bcma: switch GPIO portions to use GPIOLIB_IRQCHIP") +Cc: linux-mips@linux-mips.org +Cc: Christoph Hellwig +Cc: Linus Walleij +Signed-off-by: RafaÅ‚ MiÅ‚ecki +--- + drivers/bcma/host_soc.c | 2 ++ + drivers/bcma/main.c | 10 +++++++--- + 2 files changed, 9 insertions(+), 3 deletions(-) + +diff --git a/drivers/bcma/host_soc.c b/drivers/bcma/host_soc.c +index 8ae0b918e740..280c2caeaf86 100644 +--- a/drivers/bcma/host_soc.c ++++ b/drivers/bcma/host_soc.c +@@ -191,6 +191,8 @@ int __init bcma_host_soc_init(struct bcma_soc *soc) + struct bcma_bus *bus = &soc->bus; + int err; + ++ bus->dev = soc->dev; ++ + /* Scan bus and initialize it */ + err = bcma_bus_early_register(bus); + if (err) +diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c +index 6ecfc821cf83..6842fe781eef 100644 +--- a/drivers/bcma/main.c ++++ b/drivers/bcma/main.c +@@ -237,13 +237,17 @@ EXPORT_SYMBOL(bcma_core_irq); + + void bcma_prepare_core(struct bcma_bus *bus, struct bcma_device *core) + { +- device_initialize(&core->dev); ++ struct device *dev = &core->dev; ++ ++ device_initialize(dev); + core->dev.release = bcma_release_core_dev; + core->dev.bus = &bcma_bus_type; +- dev_set_name(&core->dev, "bcma%d:%d", bus->num, core->core_index); ++ dev_set_name(dev, "bcma%d:%d", bus->num, core->core_index); + core->dev.parent = bus->dev; +- if (bus->dev) ++ if (bus->dev) { + bcma_of_fill_device(bus->dev, core); ++ dma_coerce_mask_and_coherent(dev, bus->dev->coherent_dma_mask); ++ } + + switch (bus->hosttype) { + case BCMA_HOSTTYPE_PCI: +-- +2.51.0 + + +From cf2b01ee5a6c91e55e54d40ebc0382ba875b19d5 Mon Sep 17 00:00:00 2001 +From: Mauri Sandberg +Date: Thu, 25 Mar 2021 11:48:05 +0200 +Subject: [PATCH 313/517] gpio: gpio-cascade: add generic GPIO cascade + +Adds support for building cascades of GPIO lines. That is, it allows +setups when there is one upstream line and multiple cascaded lines, out +of which one can be chosen at a time. The status of the upstream line +can be conveyed to the selected cascaded line or, vice versa, the status +of the cascaded line can be conveyed to the upstream line. + +A multiplexer is being used to select, which cascaded GPIO line is being +used at any given time. + +At the moment only input direction is supported. In future it should be +possible to add support for output direction, too. + +Signed-off-by: Mauri Sandberg +Reviewed-by: Linus Walleij +Reviewed-by: Andy Shevchenko +--- + drivers/gpio/Kconfig | 15 +++++ + drivers/gpio/Makefile | 1 + + drivers/gpio/gpio-cascade.c | 112 ++++++++++++++++++++++++++++++++++++ + 3 files changed, 128 insertions(+) + create mode 100644 drivers/gpio/gpio-cascade.c + +diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig +index d93cd4f722b4..6c74cafa987e 100644 +--- a/drivers/gpio/Kconfig ++++ b/drivers/gpio/Kconfig +@@ -1929,4 +1929,19 @@ config GPIO_VIRTUSER + + endmenu + ++comment "Other GPIO expanders" ++ ++config GPIO_CASCADE ++ tristate "General GPIO cascade" ++ select MULTIPLEXER ++ help ++ Say yes here to enable support for generic GPIO cascade. ++ ++ This allows building one-to-many cascades of GPIO lines using ++ different types of multiplexers readily available. At the ++ moment only input lines are supported. ++ ++ To build the driver as a module choose 'm' and the resulting module ++ will be called 'gpio-cascade'. ++ + endif +diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile +index 1429e8c0229b..b0c5979fd84e 100644 +--- a/drivers/gpio/Makefile ++++ b/drivers/gpio/Makefile +@@ -45,6 +45,7 @@ obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd9571mwv.o + obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o + obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o + obj-$(CONFIG_GPIO_CADENCE) += gpio-cadence.o ++obj-$(CONFIG_GPIO_CASCADE) += gpio-cascade.o + obj-$(CONFIG_GPIO_CLPS711X) += gpio-clps711x.o + obj-$(CONFIG_GPIO_SNPS_CREG) += gpio-creg-snps.o + obj-$(CONFIG_GPIO_CROS_EC) += gpio-cros-ec.o +diff --git a/drivers/gpio/gpio-cascade.c b/drivers/gpio/gpio-cascade.c +new file mode 100644 +index 000000000000..5fae4f46ecf3 +--- /dev/null ++++ b/drivers/gpio/gpio-cascade.c +@@ -0,0 +1,112 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * A generic GPIO cascade driver ++ * ++ * Copyright (C) 2021 Mauri Sandberg ++ * ++ * This allows building cascades of GPIO lines in a manner illustrated ++ * below: ++ * ++ * /|---- Cascaded GPIO line 0 ++ * Upstream | |---- Cascaded GPIO line 1 ++ * GPIO line ----+ | . ++ * | | . ++ * \|---- Cascaded GPIO line n ++ * ++ * A multiplexer is being used to select, which cascaded line is being ++ * addressed at any given time. ++ * ++ * At the moment only input mode is supported due to lack of means for ++ * testing output functionality. At least theoretically output should be ++ * possible with open drain constructions. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++struct gpio_cascade { ++ struct gpio_chip gpio_chip; ++ struct device *parent; ++ struct mux_control *mux_control; ++ struct gpio_desc *upstream_line; ++}; ++ ++static int gpio_cascade_get_direction(struct gpio_chip *gc, unsigned int offset) ++{ ++ return GPIO_LINE_DIRECTION_IN; ++} ++ ++static int gpio_cascade_get_value(struct gpio_chip *gc, unsigned int offset) ++{ ++ struct gpio_cascade *cas = gpiochip_get_data(gc); ++ int ret; ++ ++ ret = mux_control_select(cas->mux_control, offset); ++ if (ret) ++ return ret; ++ ++ ret = gpiod_get_value(cas->upstream_line); ++ mux_control_deselect(cas->mux_control); ++ return ret; ++} ++ ++static int gpio_cascade_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct gpio_cascade *cas; ++ struct mux_control *mc; ++ struct gpio_desc *upstream; ++ struct gpio_chip *gc; ++ ++ cas = devm_kzalloc(dev, sizeof(*cas), GFP_KERNEL); ++ if (!cas) ++ return -ENOMEM; ++ ++ mc = devm_mux_control_get(dev, NULL); ++ if (IS_ERR(mc)) ++ return dev_err_probe(dev, PTR_ERR(mc), "unable to get mux-control\n"); ++ ++ cas->mux_control = mc; ++ upstream = devm_gpiod_get(dev, "upstream", GPIOD_IN); ++ if (IS_ERR(upstream)) ++ return dev_err_probe(dev, PTR_ERR(upstream), "unable to claim upstream GPIO line\n"); ++ ++ cas->upstream_line = upstream; ++ cas->parent = dev; ++ ++ gc = &cas->gpio_chip; ++ gc->get = gpio_cascade_get_value; ++ gc->get_direction = gpio_cascade_get_direction; ++ gc->base = -1; ++ gc->ngpio = mux_control_states(mc); ++ gc->label = dev_name(cas->parent); ++ gc->parent = cas->parent; ++ gc->owner = THIS_MODULE; ++ ++ platform_set_drvdata(pdev, cas); ++ return devm_gpiochip_add_data(dev, &cas->gpio_chip, cas); ++} ++ ++static const struct of_device_id gpio_cascade_id[] = { ++ { .compatible = "gpio-cascade" }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, gpio_cascade_id); ++ ++static struct platform_driver gpio_cascade_driver = { ++ .driver = { ++ .name = "gpio-cascade", ++ .of_match_table = gpio_cascade_id, ++ }, ++ .probe = gpio_cascade_probe, ++}; ++module_platform_driver(gpio_cascade_driver); ++ ++MODULE_AUTHOR("Mauri Sandberg "); ++MODULE_DESCRIPTION("Generic GPIO cascade"); ++MODULE_LICENSE("GPL"); +-- +2.51.0 + + +From 1e797580d94af360372d4ee9b0287b4add407be4 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Thu, 15 Sep 2022 18:49:43 +0200 +Subject: [PATCH 314/517] OPP: Provide old opp to config_clks on _set_opp + +With the target opp, also pass the old opp to config_clks function. +This can be useful when a driver needs to take decision on what fequency +to set based on what is the current frequency without using a +clk_get_freq call. +Update the only user of custom config_clks (tegra30 devfreq driver) to +this new implementation. + +Signed-off-by: Christian Marangi +--- + drivers/devfreq/tegra30-devfreq.c | 5 +++-- + drivers/opp/core.c | 11 ++++++----- + drivers/ufs/core/ufshcd.c | 4 ++-- + include/linux/pm_opp.h | 11 ++++++----- + include/ufs/ufshcd.h | 4 ++-- + 5 files changed, 19 insertions(+), 16 deletions(-) + +diff --git a/drivers/devfreq/tegra30-devfreq.c b/drivers/devfreq/tegra30-devfreq.c +index 4a4f0106ab9d..82616eeca6c3 100644 +--- a/drivers/devfreq/tegra30-devfreq.c ++++ b/drivers/devfreq/tegra30-devfreq.c +@@ -823,8 +823,9 @@ static int devm_tegra_devfreq_init_hw(struct device *dev, + + static int tegra_devfreq_config_clks_nop(struct device *dev, + struct opp_table *opp_table, +- struct dev_pm_opp *opp, void *data, +- bool scaling_down) ++ struct dev_pm_opp *old_opp, ++ struct dev_pm_opp *opp, ++ void *data, bool scaling_down) + { + /* We want to skip clk configuration via dev_pm_opp_set_opp() */ + return 0; +diff --git a/drivers/opp/core.c b/drivers/opp/core.c +index 5ac209472c0c..07cfde8119bf 100644 +--- a/drivers/opp/core.c ++++ b/drivers/opp/core.c +@@ -965,7 +965,8 @@ static int _set_opp_voltage(struct device *dev, struct regulator *reg, + + static int + _opp_config_clk_single(struct device *dev, struct opp_table *opp_table, +- struct dev_pm_opp *opp, void *data, bool scaling_down) ++ struct dev_pm_opp *old_opp, struct dev_pm_opp *opp, ++ void *data, bool scaling_down) + { + unsigned long *target = data; + unsigned long freq; +@@ -997,8 +998,8 @@ _opp_config_clk_single(struct device *dev, struct opp_table *opp_table, + * the order in which they are present in the array while scaling up. + */ + int dev_pm_opp_config_clks_simple(struct device *dev, +- struct opp_table *opp_table, struct dev_pm_opp *opp, void *data, +- bool scaling_down) ++ struct opp_table *opp_table, struct dev_pm_opp *old_opp, ++ struct dev_pm_opp *opp, void *data, bool scaling_down) + { + int ret, i; + +@@ -1265,7 +1266,7 @@ static int _set_opp(struct device *dev, struct opp_table *opp_table, + } + + if (opp_table->config_clks) { +- ret = opp_table->config_clks(dev, opp_table, opp, clk_data, scaling_down); ++ ret = opp_table->config_clks(dev, opp_table, old_opp, opp, clk_data, scaling_down); + if (ret) + return ret; + } +@@ -1344,7 +1345,7 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq) + * equivalent to a clk_set_rate() + */ + if (!_get_opp_count(opp_table)) { +- ret = opp_table->config_clks(dev, opp_table, NULL, ++ ret = opp_table->config_clks(dev, opp_table, NULL, NULL, + &target_freq, false); + goto put_opp_table; + } +diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c +index e079cb5d9ec6..a700da1d03e5 100644 +--- a/drivers/ufs/core/ufshcd.c ++++ b/drivers/ufs/core/ufshcd.c +@@ -1119,8 +1119,8 @@ static int ufshcd_set_clk_freq(struct ufs_hba *hba, bool scale_up) + } + + int ufshcd_opp_config_clks(struct device *dev, struct opp_table *opp_table, +- struct dev_pm_opp *opp, void *data, +- bool scaling_down) ++ struct dev_pm_opp *old_opp, struct dev_pm_opp *opp, ++ void *data, bool scaling_down) + { + struct ufs_hba *hba = dev_get_drvdata(dev); + struct list_head *head = &hba->clk_list_head; +diff --git a/include/linux/pm_opp.h b/include/linux/pm_opp.h +index 6424692c30b7..44b50cf91e93 100644 +--- a/include/linux/pm_opp.h ++++ b/include/linux/pm_opp.h +@@ -50,7 +50,8 @@ typedef int (*config_regulators_t)(struct device *dev, + struct dev_pm_opp *old_opp, struct dev_pm_opp *new_opp, + struct regulator **regulators, unsigned int count); + +-typedef int (*config_clks_t)(struct device *dev, struct opp_table *opp_table, ++typedef int (*config_clks_t)(struct device *dev, ++ struct opp_table *opp_table, struct dev_pm_opp *old_opp, + struct dev_pm_opp *opp, void *data, bool scaling_down); + + /** +@@ -184,8 +185,8 @@ int dev_pm_opp_set_config(struct device *dev, struct dev_pm_opp_config *config); + int devm_pm_opp_set_config(struct device *dev, struct dev_pm_opp_config *config); + void dev_pm_opp_clear_config(int token); + int dev_pm_opp_config_clks_simple(struct device *dev, +- struct opp_table *opp_table, struct dev_pm_opp *opp, void *data, +- bool scaling_down); ++ struct opp_table *opp_table, struct dev_pm_opp *old_opp, ++ struct dev_pm_opp *opp, void *data, bool scaling_down); + + struct dev_pm_opp *dev_pm_opp_xlate_required_opp(struct opp_table *src_table, struct opp_table *dst_table, struct dev_pm_opp *src_opp); + int dev_pm_opp_xlate_performance_state(struct opp_table *src_table, struct opp_table *dst_table, unsigned int pstate); +@@ -395,8 +396,8 @@ static inline int devm_pm_opp_set_config(struct device *dev, struct dev_pm_opp_c + static inline void dev_pm_opp_clear_config(int token) {} + + static inline int dev_pm_opp_config_clks_simple(struct device *dev, +- struct opp_table *opp_table, struct dev_pm_opp *opp, void *data, +- bool scaling_down) ++ struct opp_table *opp_table, struct dev_pm_opp *old_opp, ++ struct dev_pm_opp *opp, void *data, bool scaling_down) + { + return -EOPNOTSUPP; + } +diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h +index 47cba116f87b..a303f853acf0 100644 +--- a/include/ufs/ufshcd.h ++++ b/include/ufs/ufshcd.h +@@ -1326,8 +1326,8 @@ void ufshcd_mcq_enable(struct ufs_hba *hba); + void ufshcd_mcq_config_esi(struct ufs_hba *hba, struct msi_msg *msg); + + int ufshcd_opp_config_clks(struct device *dev, struct opp_table *opp_table, +- struct dev_pm_opp *opp, void *data, +- bool scaling_down); ++ struct dev_pm_opp *old_opp, struct dev_pm_opp *opp, ++ void *data, bool scaling_down); + /** + * ufshcd_set_variant - set variant specific data to the hba + * @hba: per adapter instance +-- +2.51.0 + + +From af475ef6d3d0d36054adbf764810eafc2d0e3ef7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Thu, 13 Jul 2023 18:29:19 +0200 +Subject: [PATCH 315/517] nvmem: core: support "mac-base" fixed layout cells + +Fixed layout binding allows specifying "mac-base" NVMEM cells. It's used +for base MAC address (that can be used for calculating relative +addresses). It can be stored in a raw binary format or as an ASCII +string. +--- + drivers/nvmem/Kconfig | 1 + + drivers/nvmem/core.c | 78 +++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 79 insertions(+) + +diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig +index 40b5fd1bfde4..51257aa2cd3e 100644 +--- a/drivers/nvmem/Kconfig ++++ b/drivers/nvmem/Kconfig +@@ -2,6 +2,7 @@ + menuconfig NVMEM + bool "NVMEM Support" + imply NVMEM_LAYOUTS ++ select GENERIC_NET_UTILS + help + Support for NVMEM(Non Volatile Memory) devices like EEPROM, EFUSES... + +diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c +index d1869e6de384..f978adbc5fff 100644 +--- a/drivers/nvmem/core.c ++++ b/drivers/nvmem/core.c +@@ -7,9 +7,12 @@ + */ + + #include ++#include ++#include + #include + #include + #include ++#include + #include + #include + #include +@@ -811,6 +814,62 @@ static int nvmem_validate_keepouts(struct nvmem_device *nvmem) + return 0; + } + ++static int nvmem_mac_base_raw_read(void *context, const char *id, int index, unsigned int offset, ++ void *buf, size_t bytes) ++{ ++ if (WARN_ON(bytes != ETH_ALEN)) ++ return -EINVAL; ++ ++ if (index) ++ eth_addr_add(buf, index); ++ ++ return 0; ++} ++ ++static int nvmem_mac_base_ascii_read(void *context, const char *id, int index, unsigned int offset, ++ void *buf, size_t bytes) ++{ ++ u8 mac[ETH_ALEN]; ++ ++ if (WARN_ON(bytes != 3 * ETH_ALEN - 1)) ++ return -EINVAL; ++ ++ if (!mac_pton(buf, mac)) ++ return -EINVAL; ++ ++ if (index) ++ eth_addr_add(mac, index); ++ ++ ether_addr_copy(buf, mac); ++ ++ return 0; ++} ++ ++static int nvmem_mac_base_hex_read(void *context, const char *id, int index, unsigned int offset, ++ void *buf, size_t bytes) ++{ ++ u8 mac[ETH_ALEN], *hexstr; ++ int i; ++ ++ if (WARN_ON(bytes != 2 * ETH_ALEN)) ++ return -EINVAL; ++ ++ hexstr = (u8 *)buf; ++ for (i = 0; i < ETH_ALEN; i++) { ++ if (!isxdigit(hexstr[i * 2]) || !isxdigit(hexstr[i * 2 + 1])) ++ return -EINVAL; ++ ++ mac[i] = (hex_to_bin(hexstr[i * 2]) << 4) | hex_to_bin(hexstr[i * 2 + 1]); ++ } ++ ++ if (index) ++ eth_addr_add(mac, index); ++ ++ ether_addr_copy(buf, mac); ++ ++ return 0; ++} ++ + static int nvmem_add_cells_from_dt(struct nvmem_device *nvmem, struct device_node *np) + { + struct device *dev = &nvmem->dev; +@@ -852,6 +911,25 @@ static int nvmem_add_cells_from_dt(struct nvmem_device *nvmem, struct device_nod + if (nvmem->fixup_dt_cell_info) + nvmem->fixup_dt_cell_info(nvmem, &info); + ++ if (of_device_is_compatible(np, "fixed-layout")) { ++ if (of_device_is_compatible(child, "mac-base")) { ++ if (info.bytes == ETH_ALEN) { ++ info.raw_len = info.bytes; ++ info.bytes = ETH_ALEN; ++ info.read_post_process = nvmem_mac_base_raw_read; ++ } else if (info.bytes == 2 * ETH_ALEN) { ++ info.raw_len = info.bytes; ++ info.bytes = ETH_ALEN; ++ info.read_post_process = nvmem_mac_base_hex_read; ++ } else if (info.bytes == 3 * ETH_ALEN - 1) { ++ info.raw_len = info.bytes; ++ info.bytes = ETH_ALEN; ++ info.read_post_process = nvmem_mac_base_ascii_read; ++ } ++ ++ } ++ } ++ + ret = nvmem_add_one_cell(nvmem, &info); + kfree(info.name); + if (ret) { +-- +2.51.0 + + +From 38d604ad64b2a28e0d8560c01e741c2aada79bc8 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Mon, 3 Feb 2025 00:10:18 +0100 +Subject: [PATCH 316/517] nvmem: core: generalize "mac-base" cells handling + +Generalize support of "mac-base" nvmem cells and provide a GPL symbol to +permit also other NVMEM layout driver to parse mac-base cells. + +It's VERY COMMON for some specially formatted NVMEM to expose a mac +address in ASCII format or HEX format hence prevent code duplication by +exposing a common helper. + +Such helper will change the nvmem_info_cell and apply the correct post +process function to correctly parse the mac address. + +Since the API requires OF and is only related to layout, move the +function in layouts.c to correctly handle non-OF NVMEM. + +Signed-off-by: Christian Marangi +--- + drivers/nvmem/core.c | 79 +-------------------------------- + drivers/nvmem/layouts.c | 80 ++++++++++++++++++++++++++++++++++ + include/linux/nvmem-provider.h | 4 ++ + 3 files changed, 86 insertions(+), 77 deletions(-) + +diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c +index f978adbc5fff..9b9177e28706 100644 +--- a/drivers/nvmem/core.c ++++ b/drivers/nvmem/core.c +@@ -7,12 +7,9 @@ + */ + + #include +-#include +-#include + #include + #include + #include +-#include + #include + #include + #include +@@ -814,62 +811,6 @@ static int nvmem_validate_keepouts(struct nvmem_device *nvmem) + return 0; + } + +-static int nvmem_mac_base_raw_read(void *context, const char *id, int index, unsigned int offset, +- void *buf, size_t bytes) +-{ +- if (WARN_ON(bytes != ETH_ALEN)) +- return -EINVAL; +- +- if (index) +- eth_addr_add(buf, index); +- +- return 0; +-} +- +-static int nvmem_mac_base_ascii_read(void *context, const char *id, int index, unsigned int offset, +- void *buf, size_t bytes) +-{ +- u8 mac[ETH_ALEN]; +- +- if (WARN_ON(bytes != 3 * ETH_ALEN - 1)) +- return -EINVAL; +- +- if (!mac_pton(buf, mac)) +- return -EINVAL; +- +- if (index) +- eth_addr_add(mac, index); +- +- ether_addr_copy(buf, mac); +- +- return 0; +-} +- +-static int nvmem_mac_base_hex_read(void *context, const char *id, int index, unsigned int offset, +- void *buf, size_t bytes) +-{ +- u8 mac[ETH_ALEN], *hexstr; +- int i; +- +- if (WARN_ON(bytes != 2 * ETH_ALEN)) +- return -EINVAL; +- +- hexstr = (u8 *)buf; +- for (i = 0; i < ETH_ALEN; i++) { +- if (!isxdigit(hexstr[i * 2]) || !isxdigit(hexstr[i * 2 + 1])) +- return -EINVAL; +- +- mac[i] = (hex_to_bin(hexstr[i * 2]) << 4) | hex_to_bin(hexstr[i * 2 + 1]); +- } +- +- if (index) +- eth_addr_add(mac, index); +- +- ether_addr_copy(buf, mac); +- +- return 0; +-} +- + static int nvmem_add_cells_from_dt(struct nvmem_device *nvmem, struct device_node *np) + { + struct device *dev = &nvmem->dev; +@@ -911,24 +852,8 @@ static int nvmem_add_cells_from_dt(struct nvmem_device *nvmem, struct device_nod + if (nvmem->fixup_dt_cell_info) + nvmem->fixup_dt_cell_info(nvmem, &info); + +- if (of_device_is_compatible(np, "fixed-layout")) { +- if (of_device_is_compatible(child, "mac-base")) { +- if (info.bytes == ETH_ALEN) { +- info.raw_len = info.bytes; +- info.bytes = ETH_ALEN; +- info.read_post_process = nvmem_mac_base_raw_read; +- } else if (info.bytes == 2 * ETH_ALEN) { +- info.raw_len = info.bytes; +- info.bytes = ETH_ALEN; +- info.read_post_process = nvmem_mac_base_hex_read; +- } else if (info.bytes == 3 * ETH_ALEN - 1) { +- info.raw_len = info.bytes; +- info.bytes = ETH_ALEN; +- info.read_post_process = nvmem_mac_base_ascii_read; +- } +- +- } +- } ++ if (of_device_is_compatible(np, "fixed-layout")) ++ nvmem_layout_parse_mac_base(&info); + + ret = nvmem_add_one_cell(nvmem, &info); + kfree(info.name); +diff --git a/drivers/nvmem/layouts.c b/drivers/nvmem/layouts.c +index f381ce1e84bd..3220cd20c33a 100644 +--- a/drivers/nvmem/layouts.c ++++ b/drivers/nvmem/layouts.c +@@ -6,8 +6,11 @@ + * Author: Miquel Raynal + #include + #include ++#include ++#include + #include + #include + #include +@@ -21,6 +24,83 @@ + #define to_nvmem_layout_device(_dev) \ + container_of((_dev), struct nvmem_layout, dev) + ++static int nvmem_mac_base_raw_read(void *context, const char *id, int index, unsigned int offset, ++ void *buf, size_t bytes) ++{ ++ if (WARN_ON(bytes != ETH_ALEN)) ++ return -EINVAL; ++ ++ if (index) ++ eth_addr_add(buf, index); ++ ++ return 0; ++} ++ ++static int nvmem_mac_base_ascii_read(void *context, const char *id, int index, unsigned int offset, ++ void *buf, size_t bytes) ++{ ++ u8 mac[ETH_ALEN]; ++ ++ if (WARN_ON(bytes != 3 * ETH_ALEN - 1)) ++ return -EINVAL; ++ ++ if (!mac_pton(buf, mac)) ++ return -EINVAL; ++ ++ if (index) ++ eth_addr_add(mac, index); ++ ++ ether_addr_copy(buf, mac); ++ ++ return 0; ++} ++ ++static int nvmem_mac_base_hex_read(void *context, const char *id, int index, unsigned int offset, ++ void *buf, size_t bytes) ++{ ++ u8 mac[ETH_ALEN], *hexstr; ++ int i; ++ ++ if (WARN_ON(bytes != 2 * ETH_ALEN)) ++ return -EINVAL; ++ ++ hexstr = (u8 *)buf; ++ for (i = 0; i < ETH_ALEN; i++) { ++ if (!isxdigit(hexstr[i * 2]) || !isxdigit(hexstr[i * 2 + 1])) ++ return -EINVAL; ++ ++ mac[i] = (hex_to_bin(hexstr[i * 2]) << 4) | hex_to_bin(hexstr[i * 2 + 1]); ++ } ++ ++ if (index) ++ eth_addr_add(mac, index); ++ ++ ether_addr_copy(buf, mac); ++ ++ return 0; ++} ++ ++void nvmem_layout_parse_mac_base(struct nvmem_cell_info *info) ++{ ++ if (!of_device_is_compatible(info->np, "mac-base")) ++ return; ++ ++ if (info->bytes == ETH_ALEN) { ++ info->raw_len = info->bytes; ++ info->bytes = ETH_ALEN; ++ info->read_post_process = nvmem_mac_base_raw_read; ++ } else if (info->bytes == 2 * ETH_ALEN) { ++ info->raw_len = info->bytes; ++ info->bytes = ETH_ALEN; ++ info->read_post_process = nvmem_mac_base_hex_read; ++ } else if (info->bytes == 3 * ETH_ALEN - 1) { ++ info->raw_len = info->bytes; ++ info->bytes = ETH_ALEN; ++ info->read_post_process = nvmem_mac_base_ascii_read; ++ } ++} ++EXPORT_SYMBOL_GPL(nvmem_layout_parse_mac_base); ++ + static int nvmem_layout_bus_match(struct device *dev, const struct device_driver *drv) + { + return of_driver_match_device(dev, drv); +diff --git a/include/linux/nvmem-provider.h b/include/linux/nvmem-provider.h +index 3ebeaa0ded00..97698b898dcf 100644 +--- a/include/linux/nvmem-provider.h ++++ b/include/linux/nvmem-provider.h +@@ -242,6 +242,8 @@ static inline void nvmem_layout_unregister(struct nvmem_layout *layout) {} + + #if IS_ENABLED(CONFIG_NVMEM) && IS_ENABLED(CONFIG_OF) + ++void nvmem_layout_parse_mac_base(struct nvmem_cell_info *info); ++ + /** + * of_nvmem_layout_get_container() - Get OF node of layout container + * +@@ -254,6 +256,8 @@ struct device_node *of_nvmem_layout_get_container(struct nvmem_device *nvmem); + + #else /* CONFIG_NVMEM && CONFIG_OF */ + ++static inline void nvmem_layout_parse_mac_base(struct nvmem_cell_info *info) {} ++ + static inline struct device_node *of_nvmem_layout_get_container(struct nvmem_device *nvmem) + { + return NULL; +-- +2.51.0 + + +From c7d5b37e95ce1865a1c04a2d863966379f13b7fb Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Mon, 3 Feb 2025 00:36:12 +0100 +Subject: [PATCH 317/517] nvmem: layouts: add support for ascii-env driver + +Add support for simple ASCII envirorment driver for NVMEM layouts. + +It's very common for devices to store simple text file format in +partition for environment varibles. The most common pattern is variable +name, a delimiter and variable value all separated by a new line +character (\n). + +This driver adds support for exporting such data and expose NVMEM cells +so they can be referenced by other drivers. This driver also supports +parsing mac-base NVMEM cells to parse ASCII or HEX mac address. + +Signed-off-by: Christian Marangi +--- + drivers/nvmem/layouts/Kconfig | 13 +++ + drivers/nvmem/layouts/Makefile | 1 + + drivers/nvmem/layouts/ascii-env.c | 148 ++++++++++++++++++++++++++++++ + 3 files changed, 162 insertions(+) + create mode 100644 drivers/nvmem/layouts/ascii-env.c + +diff --git a/drivers/nvmem/layouts/Kconfig b/drivers/nvmem/layouts/Kconfig +index 5e586dfebe47..58df4ad61e13 100644 +--- a/drivers/nvmem/layouts/Kconfig ++++ b/drivers/nvmem/layouts/Kconfig +@@ -37,6 +37,19 @@ config NVMEM_LAYOUT_U_BOOT_ENV + + If unsure, say N. + ++config NVMEM_LAYOUT_ASCII_ENV ++ tristate "ASCII environment variables layout" ++ help ++ It's very common for devices to store simple text file format in ++ partition for environment varibles. The most common pattern is variable ++ name, a delimiter and variable value all separated by a new line ++ character (\n). ++ This driver adds support for exporting such data and expose NVMEM cells ++ so they can be referenced by other drivers. This driver also supports ++ parsing mac-base NVMEM cells to parse ASCII or HEX mac address. ++ ++ If unsure, say N. ++ + endmenu + + endif +diff --git a/drivers/nvmem/layouts/Makefile b/drivers/nvmem/layouts/Makefile +index 4940c9db0665..060ddf18d05a 100644 +--- a/drivers/nvmem/layouts/Makefile ++++ b/drivers/nvmem/layouts/Makefile +@@ -6,3 +6,4 @@ + obj-$(CONFIG_NVMEM_LAYOUT_SL28_VPD) += sl28vpd.o + obj-$(CONFIG_NVMEM_LAYOUT_ONIE_TLV) += onie-tlv.o + obj-$(CONFIG_NVMEM_LAYOUT_U_BOOT_ENV) += u-boot-env.o ++obj-$(CONFIG_NVMEM_LAYOUT_ASCII_ENV) += ascii-env.o +diff --git a/drivers/nvmem/layouts/ascii-env.c b/drivers/nvmem/layouts/ascii-env.c +new file mode 100644 +index 000000000000..491fcfd3a501 +--- /dev/null ++++ b/drivers/nvmem/layouts/ascii-env.c +@@ -0,0 +1,148 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Copyright (C) 2024 Christian Marangi ++ * ++ * This borrow some parse logic from u-boot-env. ++ */ ++#include ++#include ++#include ++#include ++ ++struct ascii_env_match_data { ++ const char delim; ++}; ++ ++/* ++ * Parse a buffer as an ASCII text with name delimiter value and each pattern separated ++ * with a new line char '\n' ++ * Example: (delimiter '=') ++ * name=value\nname2=value2\n ++ * 2 Cell: ++ * - name: value ++ * - name2: value2 ++ */ ++static int ascii_env_parse_cells(struct device *dev, struct nvmem_device *nvmem, uint8_t *buf, ++ size_t data_len, const char delim) ++{ ++ char *var, *value, *eq, *lf; ++ char *data = buf; ++ ++ /* ++ * Warning the inner loop take care of replacing '\n' ++ * with '\0', hence we can use strlen on value. ++ */ ++ for (var = data; var < data + data_len && *var; ++ var = value + strlen(value) + 1) { ++ struct nvmem_cell_info info = {}; ++ struct device_node *child; ++ const char *label; ++ ++ eq = strchr(var, delim); ++ if (!eq) ++ break; ++ *eq = '\0'; ++ value = eq + 1; ++ ++ /* Replace '\n' with '\0' to use strlen for value */ ++ lf = strchr(value, '\n'); ++ if (!lf) ++ break; ++ *lf = '\0'; ++ ++ info.name = devm_kstrdup(dev, var, GFP_KERNEL); ++ if (!info.name) ++ return -ENOMEM; ++ info.offset = value - data; ++ info.bytes = strlen(value); ++ info.np = of_get_child_by_name(dev->of_node, info.name); ++ for_each_child_of_node(dev->of_node, child) { ++ if (!of_property_read_string(child, "label", &label) && ++ !strncmp(info.name, label, info.bytes)) ++ info.np = child; ++ else if (of_node_name_eq(child, info.name)) ++ info.np = child; ++ } ++ ++ nvmem_layout_parse_mac_base(&info); ++ ++ nvmem_add_one_cell(nvmem, &info); ++ } ++ ++ return 0; ++} ++ ++static int ascii_env_add_cells(struct nvmem_layout *layout) ++{ ++ struct nvmem_device *nvmem = layout->nvmem; ++ const struct ascii_env_match_data *data; ++ struct device *dev = &layout->dev; ++ size_t dev_size; ++ uint8_t *buf; ++ int bytes; ++ int ret; ++ ++ /* Get the delimiter for name value pattern */ ++ data = device_get_match_data(dev); ++ ++ dev_size = nvmem_dev_size(nvmem); ++ ++ buf = kzalloc(dev_size, GFP_KERNEL); ++ if (!buf) { ++ ret = -ENOMEM; ++ goto err_out; ++ } ++ ++ bytes = nvmem_device_read(nvmem, 0, dev_size, buf); ++ if (bytes < 0) { ++ ret = bytes; ++ goto err_kfree; ++ } else if (bytes != dev_size) { ++ ret = -EIO; ++ goto err_kfree; ++ } ++ ++ buf[dev_size - 1] = '\0'; ++ ret = ascii_env_parse_cells(dev, nvmem, buf, dev_size, data->delim); ++ ++err_kfree: ++ kfree(buf); ++err_out: ++ return ret; ++} ++ ++static int ascii_env_probe(struct nvmem_layout *layout) ++{ ++ layout->add_cells = ascii_env_add_cells; ++ ++ return nvmem_layout_register(layout); ++} ++ ++static void ascii_env_remove(struct nvmem_layout *layout) ++{ ++ nvmem_layout_unregister(layout); ++} ++ ++static const struct ascii_env_match_data ascii_env_eq = { ++ .delim = '=', ++}; ++ ++static const struct of_device_id ascii_env_of_match_table[] = { ++ { .compatible = "ascii-eq-delim-env", .data = &ascii_env_eq, }, ++ {}, ++}; ++ ++static struct nvmem_layout_driver ascii_env_layout = { ++ .driver = { ++ .name = "ascii-env-layout", ++ .of_match_table = ascii_env_of_match_table, ++ }, ++ .probe = ascii_env_probe, ++ .remove = ascii_env_remove, ++}; ++module_nvmem_layout_driver(ascii_env_layout); ++ ++MODULE_AUTHOR("Christian Marangi "); ++MODULE_LICENSE("GPL"); ++MODULE_DEVICE_TABLE(of, ascii_env_of_match_table); ++MODULE_DESCRIPTION("NVMEM layout driver for ASCII environment variables"); +-- +2.51.0 + + +From 773d9fc4bc823e602c25cb93786fd38bc9bfd9ac Mon Sep 17 00:00:00 2001 +From: George Moussalem +Date: Thu, 6 Feb 2025 21:55:28 +0400 +Subject: [PATCH 318/517] nvmem: layouts: ascii-env handle CRLF while parsing + +The current driver supports LF line endings only. + +For CRLF-based line endings in the ASCII env, the length of the value of +the variable passed to nvmem_layout_parse_mac_base is 18 bytes instead +of an expected length of 17 causing the parsing to fail. +So, let's add the ability to handle CRLF line endings by adding a +condition to check if the value ends with a '\r' character and replace it +with '\0' to properly parse the mac address. + +Tested on Linksys MX2000, MX5500, and SPNMX56. + +Signed-off-by: George Moussalem +--- + drivers/nvmem/layouts/ascii-env.c | 15 +++++++++++++-- + 1 file changed, 13 insertions(+), 2 deletions(-) + +diff --git a/drivers/nvmem/layouts/ascii-env.c b/drivers/nvmem/layouts/ascii-env.c +index 491fcfd3a501..119bfc2b26f7 100644 +--- a/drivers/nvmem/layouts/ascii-env.c ++++ b/drivers/nvmem/layouts/ascii-env.c +@@ -25,18 +25,20 @@ struct ascii_env_match_data { + static int ascii_env_parse_cells(struct device *dev, struct nvmem_device *nvmem, uint8_t *buf, + size_t data_len, const char delim) + { +- char *var, *value, *eq, *lf; ++ char *var, *value, *eq, *lf, *cr; + char *data = buf; ++ uint incr = 0; + + /* + * Warning the inner loop take care of replacing '\n' + * with '\0', hence we can use strlen on value. + */ + for (var = data; var < data + data_len && *var; +- var = value + strlen(value) + 1) { ++ var = value + strlen(value) + incr) { + struct nvmem_cell_info info = {}; + struct device_node *child; + const char *label; ++ incr = 0; + + eq = strchr(var, delim); + if (!eq) +@@ -49,6 +51,15 @@ static int ascii_env_parse_cells(struct device *dev, struct nvmem_device *nvmem, + if (!lf) + break; + *lf = '\0'; ++ incr++; ++ ++ /* For CRLF based env, replace '\r' with '\0' too to use strlen ++ * for value, and increment var by one in loop for next variable */ ++ cr = strchr(value, '\r'); ++ if (cr) { ++ *cr = '\0'; ++ incr++; ++ } + + info.name = devm_kstrdup(dev, var, GFP_KERNEL); + if (!info.name) +-- +2.51.0 + + +From baede361c7b81acf63a533c25fe10c05b5116cf4 Mon Sep 17 00:00:00 2001 +From: Gabor Juhos +Date: Mon, 3 Nov 2025 15:50:11 +0100 +Subject: [PATCH 319/517] debloat: add kernel config option to disabling common + PCI quirks + +Signed-off-by: Gabor Juhos +--- + drivers/pci/Kconfig | 7 +++++++ + drivers/pci/quirks.c | 7 +++++++ + 2 files changed, 14 insertions(+) + +diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig +index 7cef00d9d7ab..6b458cba5c2f 100644 +--- a/drivers/pci/Kconfig ++++ b/drivers/pci/Kconfig +@@ -118,6 +118,13 @@ config XEN_PCIDEV_FRONTEND + The PCI device frontend driver allows the kernel to import arbitrary + PCI devices from a PCI backend to support PCI driver domains. + ++config PCI_DISABLE_COMMON_QUIRKS ++ bool "PCI disable common quirks" ++ depends on PCI ++ help ++ If you don't know what to do here, say N. ++ ++ + config PCI_ATS + bool + +diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c +index db609d26811b..26e7a21a5ee7 100644 +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -313,6 +313,7 @@ static void quirk_mmio_always_on(struct pci_dev *dev) + DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_BRIDGE_HOST, 8, quirk_mmio_always_on); + ++#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS + /* + * The Mellanox Tavor device gives false positive parity errors. Disable + * parity error reporting. +@@ -3508,6 +3509,8 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x65f8, quirk_intel_mc_errata); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x65f9, quirk_intel_mc_errata); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x65fa, quirk_intel_mc_errata); + ++#endif /* !CONFIG_PCI_DISABLE_COMMON_QUIRKS */ ++ + /* + * Ivytown NTB BAR sizes are misreported by the hardware due to an erratum. + * To work around this, query the size it should be configured to by the +@@ -3533,6 +3536,8 @@ static void quirk_intel_ntb(struct pci_dev *dev) + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0e08, quirk_intel_ntb); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0e0d, quirk_intel_ntb); + ++#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS ++ + /* + * Some BIOS implementations leave the Intel GPU interrupts enabled, even + * though no one is handling them (e.g., if the i915 driver is never +@@ -3571,6 +3576,8 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0106, disable_igfx_irq); + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x010a, disable_igfx_irq); + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0152, disable_igfx_irq); + ++#endif /* !CONFIG_PCI_DISABLE_COMMON_QUIRKS */ ++ + /* + * PCI devices which are on Intel chips can skip the 10ms delay + * before entering D3 mode. +-- +2.51.0 + + +From 5ba95a2dade8bae2429b2e6de0d7eed0e7819c7d Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Sat, 26 Apr 2025 21:10:40 +0200 +Subject: [PATCH 320/517] debloat: disable common USB quirks + +Signed-off-by: Felix Fietkau +--- + drivers/usb/host/pci-quirks.c | 7 +++++++ + drivers/usb/host/pci-quirks.h | 4 ++++ + 2 files changed, 11 insertions(+) + +diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c +index 0404489c2f6a..362d347b5982 100644 +--- a/drivers/usb/host/pci-quirks.c ++++ b/drivers/usb/host/pci-quirks.c +@@ -590,6 +590,7 @@ bool usb_amd_pt_check_port(struct device *device, int port) + EXPORT_SYMBOL_GPL(usb_amd_pt_check_port); + #endif /* CONFIG_USB_PCI_AMD */ + ++#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS + static int usb_asmedia_wait_write(struct pci_dev *pdev) + { + unsigned long retry_count; +@@ -642,6 +643,7 @@ static inline int io_type_enabled(struct pci_dev *pdev, unsigned int mask) + } + + #define mmio_enabled(dev) io_type_enabled(dev, PCI_COMMAND_MEMORY) ++#endif /* !CONFIG_PCI_DISABLE_COMMON_QUIRKS */ + + #if defined(CONFIG_HAS_IOPORT) && IS_ENABLED(CONFIG_USB_UHCI_HCD) + /* +@@ -724,6 +726,10 @@ int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base) + return 1; + } + EXPORT_SYMBOL_GPL(uhci_check_and_reset_hc); ++#endif ++ ++#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS ++#if defined(CONFIG_HAS_IOPORT) && IS_ENABLED(CONFIG_USB_UHCI_HCD) + + #define pio_enabled(dev) io_type_enabled(dev, PCI_COMMAND_IO) + +@@ -1304,3 +1310,4 @@ static void quirk_usb_early_handoff(struct pci_dev *pdev) + } + DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_SERIAL_USB, 8, quirk_usb_early_handoff); ++#endif /* !CONFIG_PCI_DISABLE_COMMON_QUIRKS */ +diff --git a/drivers/usb/host/pci-quirks.h b/drivers/usb/host/pci-quirks.h +index a5230b0b9e91..9cc969a3b352 100644 +--- a/drivers/usb/host/pci-quirks.h ++++ b/drivers/usb/host/pci-quirks.h +@@ -38,12 +38,16 @@ static inline bool usb_amd_pt_check_port(struct device *device, int port) + #ifdef CONFIG_USB_PCI + void uhci_reset_hc(struct pci_dev *pdev, unsigned long base); + int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base); ++#endif ++ ++#if defined(CONFIG_USB_PCI) && !defined(CONFIG_PCI_DISABLE_COMMON_QUIRKS) + void usb_asmedia_modifyflowcontrol(struct pci_dev *pdev); + void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev); + void usb_disable_xhci_ports(struct pci_dev *xhci_pdev); + #else + struct pci_dev; + static inline void usb_asmedia_modifyflowcontrol(struct pci_dev *pdev) {} ++static inline void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev) {} + static inline void usb_disable_xhci_ports(struct pci_dev *xhci_pdev) {} + #endif /* CONFIG_USB_PCI */ + +-- +2.51.0 + + +From 922d037dad402d02ba7937afa88740db3487d89b Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Mon, 13 Oct 2025 20:45:25 +0200 +Subject: [PATCH 321/517] PCI/sysfs: enforce single creation of sysfs entry for + pdev +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +In some specific scenario it's possible that the +pci_create_resource_files() gets called multiple times and the created +entry actually gets wrongly deleted with extreme case of having a NULL +pointer dereference when the PCI is removed. + +This mainly happen due to bad timing where the PCI bus is adding PCI +devices and at the same time the sysfs code is adding the entry causing +double execution of the pci_create_resource_files function and kernel +WARNING. + +To be more precise there is a race between the late_initcall of +pci-sysfs with pci_sysfs_init and PCI bus.c pci_bus_add_device that also +call pci_create_sysfs_dev_files. + +With correct amount of ""luck"" (or better say bad luck) +pci_create_sysfs_dev_files in bus.c might be called with pci_sysfs_init +is executing the loop. + +This has been reported multiple times and on multiple system, like imx6 +system, ipq806x systems... + +To address this, imlement multiple improvement to the implementation: +1. Add a bool to pci_dev to flag when sysfs entry are created + (sysfs_init) +2. Implement a simple completion to wait pci_sysfs_init execution. +3. Permit additional call of pci_create_sysfs_dev_files only after + pci_sysfs_init has finished. + +With such logic in place, we address al kind of timing problem with +minimal change to any driver. + +A notice worth to mention is that the remove function are not affected +by this as the pci_remove_resource_files have enough check in place to +always work and it's always called by pci_stop_dev. + +Cc: stable@vger.kernel.org +Reported-by: Krzysztof HaÅ‚asa +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=215515 +Signed-off-by: Christian Marangi +--- + drivers/pci/pci-sysfs.c | 34 +++++++++++++++++++++++++++++----- + include/linux/pci.h | 1 + + 2 files changed, 30 insertions(+), 5 deletions(-) + +diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c +index 96f9cf9f8d64..85440b4312e5 100644 +--- a/drivers/pci/pci-sysfs.c ++++ b/drivers/pci/pci-sysfs.c +@@ -13,6 +13,7 @@ + */ + + #include ++#include + #include + #include + #include +@@ -36,6 +37,7 @@ + #endif + + static int sysfs_initialized; /* = 0 */ ++static DECLARE_COMPLETION(sysfs_init_completion); + + /* show configuration fields */ + #define pci_config_attr(field, format_string) \ +@@ -1551,12 +1553,32 @@ static const struct attribute_group pci_dev_resource_resize_group = { + .is_visible = resource_resize_is_visible, + }; + ++static int __pci_create_sysfs_dev_files(struct pci_dev *pdev) ++{ ++ int ret; ++ ++ ret = pci_create_resource_files(pdev); ++ if (ret) ++ return ret; ++ ++ /* on success set sysfs correctly created */ ++ pdev->sysfs_init = true; ++ return 0; ++} ++ + int __must_check pci_create_sysfs_dev_files(struct pci_dev *pdev) + { + if (!sysfs_initialized) + return -EACCES; + +- return pci_create_resource_files(pdev); ++ /* sysfs entry already created */ ++ if (pdev->sysfs_init) ++ return 0; ++ ++ /* wait for pci_sysfs_init */ ++ wait_for_completion(&sysfs_init_completion); ++ ++ return __pci_create_sysfs_dev_files(pdev); + } + + /** +@@ -1577,21 +1599,23 @@ static int __init pci_sysfs_init(void) + { + struct pci_dev *pdev = NULL; + struct pci_bus *pbus = NULL; +- int retval; ++ int retval = 0; + + sysfs_initialized = 1; + for_each_pci_dev(pdev) { +- retval = pci_create_sysfs_dev_files(pdev); ++ retval = __pci_create_sysfs_dev_files(pdev); + if (retval) { + pci_dev_put(pdev); +- return retval; ++ goto exit; + } + } + + while ((pbus = pci_find_next_bus(pbus))) + pci_create_legacy_files(pbus); + +- return 0; ++exit: ++ complete_all(&sysfs_init_completion); ++ return retval; + } + late_initcall(pci_sysfs_init); + +diff --git a/include/linux/pci.h b/include/linux/pci.h +index 452a3dca28ea..2c3758975d35 100644 +--- a/include/linux/pci.h ++++ b/include/linux/pci.h +@@ -484,6 +484,7 @@ struct pci_dev { + unsigned int rom_attr_enabled:1; /* Display of ROM attribute enabled? */ + pci_dev_flags_t dev_flags; + atomic_t enable_cnt; /* pci_enable_device has been called */ ++ bool sysfs_init; /* sysfs entry has been created */ + + spinlock_t pcie_cap_lock; /* Protects RMW ops in capability accessors */ + u32 saved_config_space[16]; /* Config space saved at suspend time */ +-- +2.51.0 + + +From ddc0f7fa795c53ea0c7728a6fabf718eead7aedd Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Mon, 3 Nov 2025 15:50:12 +0100 +Subject: [PATCH 322/517] libata: add ledtrig support + +This adds a LED trigger for each ATA port indicating disk activity. + +As this is needed only on specific platforms (NAS SoCs and such), +these platforms should define ARCH_WANTS_LIBATA_LEDS if there +are boards with LED(s) intended to indicate ATA disk activity and +need the OS to take care of that. +In that way, if not selected, LED trigger support not will be +included in libata-core and both, codepaths and structures remain +untouched. + +Signed-off-by: Daniel Golle +--- + drivers/ata/Kconfig | 16 ++++++++++++++++ + drivers/ata/libata-core.c | 39 +++++++++++++++++++++++++++++++++++++++ + include/linux/libata.h | 7 +++++++ + 3 files changed, 62 insertions(+) + +diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig +index 120a2b7067fc..9f7d5609a577 100644 +--- a/drivers/ata/Kconfig ++++ b/drivers/ata/Kconfig +@@ -67,6 +67,22 @@ config ATA_FORCE + + If unsure, say Y. + ++config ARCH_WANT_LIBATA_LEDS ++ bool ++ ++config ATA_LEDS ++ bool "support ATA port LED triggers" ++ depends on ARCH_WANT_LIBATA_LEDS ++ select NEW_LEDS ++ select LEDS_CLASS ++ select LEDS_TRIGGERS ++ default y ++ help ++ This option adds a LED trigger for each registered ATA port. ++ It is used to drive disk activity leds connected via GPIO. ++ ++ If unsure, say N. ++ + config ATA_ACPI + bool "ATA ACPI Support" + depends on ACPI +diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c +index 0cb97181d10a..faf86008348c 100644 +--- a/drivers/ata/libata-core.c ++++ b/drivers/ata/libata-core.c +@@ -703,6 +703,17 @@ static inline void ata_set_tf_cdl(struct ata_queued_cmd *qc, int cdl) + qc->flags |= ATA_QCFLAG_HAS_CDL | ATA_QCFLAG_RESULT_TF; + } + ++#ifdef CONFIG_ATA_LEDS ++#define LIBATA_BLINK_DELAY 20 /* ms */ ++static inline void ata_led_act(struct ata_port *ap) ++{ ++ if (unlikely(!ap->ledtrig)) ++ return; ++ ++ led_trigger_blink_oneshot(ap->ledtrig, LIBATA_BLINK_DELAY, LIBATA_BLINK_DELAY, 0); ++} ++#endif ++ + /** + * ata_build_rw_tf - Build ATA taskfile for given read/write request + * @qc: Metadata associated with the taskfile to build +@@ -4767,6 +4778,9 @@ void __ata_qc_complete(struct ata_queued_cmd *qc) + link->active_tag = ATA_TAG_POISON; + ap->nr_active_links--; + } ++#ifdef CONFIG_ATA_LEDS ++ ata_led_act(ap); ++#endif + + /* clear exclusive status */ + if (unlikely(qc->flags & ATA_QCFLAG_CLEAR_EXCL && +@@ -5488,6 +5502,9 @@ struct ata_port *ata_port_alloc(struct ata_host *host) + #ifdef ATA_IRQ_TRAP + ap->stats.unhandled_irq = 1; + ap->stats.idle_irq = 1; ++#endif ++#ifdef CONFIG_ATA_LEDS ++ ap->ledtrig = kzalloc(sizeof(struct led_trigger), GFP_KERNEL); + #endif + ata_sff_port_init(ap); + +@@ -5505,6 +5522,12 @@ void ata_port_free(struct ata_port *ap) + kfree(ap->pmp_link); + kfree(ap->slave_link); + ida_free(&ata_ida, ap->print_id); ++#ifdef CONFIG_ATA_LEDS ++ if (ap->ledtrig) { ++ led_trigger_unregister(ap->ledtrig); ++ kfree(ap->ledtrig); ++ }; ++#endif + kfree(ap); + } + EXPORT_SYMBOL_GPL(ata_port_free); +@@ -5909,7 +5932,23 @@ int ata_host_register(struct ata_host *host, const struct scsi_host_template *sh + WARN_ON(1); + return -EINVAL; + } ++#ifdef CONFIG_ATA_LEDS ++ for (i = 0; i < host->n_ports; i++) { ++ if (unlikely(!host->ports[i]->ledtrig)) ++ continue; ++ ++ snprintf(host->ports[i]->ledtrig_name, ++ sizeof(host->ports[i]->ledtrig_name), "ata%u", ++ host->ports[i]->print_id); + ++ host->ports[i]->ledtrig->name = host->ports[i]->ledtrig_name; ++ ++ if (led_trigger_register(host->ports[i]->ledtrig)) { ++ kfree(host->ports[i]->ledtrig); ++ host->ports[i]->ledtrig = NULL; ++ } ++ } ++#endif + /* Create associated sysfs transport objects */ + for (i = 0; i < host->n_ports; i++) { + rc = ata_tport_add(host->dev,host->ports[i]); +diff --git a/include/linux/libata.h b/include/linux/libata.h +index 1983a98e3d67..4b9a57cfb801 100644 +--- a/include/linux/libata.h ++++ b/include/linux/libata.h +@@ -23,6 +23,9 @@ + #include + #include + #include ++#ifdef CONFIG_ATA_LEDS ++#include ++#endif + + /* + * Define if arch has non-standard setup. This is a _PCI_ standard +@@ -935,6 +938,10 @@ struct ata_port { + #ifdef CONFIG_ATA_ACPI + struct ata_acpi_gtm __acpi_init_gtm; /* use ata_acpi_init_gtm() */ + #endif ++#ifdef CONFIG_ATA_LEDS ++ struct led_trigger *ledtrig; ++ char ledtrig_name[8]; ++#endif + }; + + /* The following initializer overrides a method to NULL whether one of +-- +2.51.0 + + +From e21a9da306cb81ea815c95e7222b4a5cf31c1f8a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= +Date: Sat, 20 Feb 2021 18:36:38 +0100 +Subject: [PATCH 323/517] hwrng: bcm2835: set quality to 1000 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This allows devices without a high precission timer to reduce boot from >100s +to <30s. + +Signed-off-by: Ãlvaro Fernández Rojas +--- + drivers/char/hw_random/bcm2835-rng.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/char/hw_random/bcm2835-rng.c b/drivers/char/hw_random/bcm2835-rng.c +index aa2b135e3ee2..1a7b3fcd5eb8 100644 +--- a/drivers/char/hw_random/bcm2835-rng.c ++++ b/drivers/char/hw_random/bcm2835-rng.c +@@ -169,6 +169,7 @@ static int bcm2835_rng_probe(struct platform_device *pdev) + priv->rng.init = bcm2835_rng_init; + priv->rng.read = bcm2835_rng_read; + priv->rng.cleanup = bcm2835_rng_cleanup; ++ priv->rng.quality = 1000; + + if (dev_of_node(dev)) { + rng_id = of_match_node(bcm2835_rng_of_match, dev->of_node); +-- +2.51.0 + + +From f207db8602135a5efdbdb5d9be0464162dc43531 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marek=20Beh=C3=BAn?= +Date: Mon, 10 Jan 2022 02:02:00 +0100 +Subject: [PATCH 324/517] PCI: aardvark: Make main irq_chip structure a static + driver structure +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Marc Zyngier says [1] that we should use struct irq_chip as a global +static struct in the driver. Even though the structure currently +contains a dynamic member (parent_device), Marc says [2] that he plans +to kill it and make the structure completely static. + +We have already converted others irq_chip structures in this driver in +this way, but we omitted this one because the .name member is +dynamically created from device's name, and the name is displayed in +sysfs, so changing it would break sysfs ABI. + +The rationale for changing the name (to "advk-INT") in spite of sysfs +ABI, and thus allowing to convert to a static structure, is that after +the other changes we made in this series, the IRQ chip is basically +something different: it no logner generates ERR and PME interrupts (they +are generated by emulated bridge's rp_irq_chip). + +[1] https://lore.kernel.org/linux-pci/877dbcvngf.wl-maz@kernel.org/ +[2] https://lore.kernel.org/linux-pci/874k6gvkhz.wl-maz@kernel.org/ + +Signed-off-by: Marek Behún +--- + drivers/pci/controller/pci-aardvark.c | 25 +++++++------------------ + 1 file changed, 7 insertions(+), 18 deletions(-) + +diff --git a/drivers/pci/controller/pci-aardvark.c b/drivers/pci/controller/pci-aardvark.c +index a598a98247ce..b2acf14fe414 100644 +--- a/drivers/pci/controller/pci-aardvark.c ++++ b/drivers/pci/controller/pci-aardvark.c +@@ -276,7 +276,6 @@ struct advk_pcie { + u8 wins_count; + struct irq_domain *rp_irq_domain; + struct irq_domain *irq_domain; +- struct irq_chip irq_chip; + raw_spinlock_t irq_lock; + struct irq_domain *msi_domain; + struct irq_domain *msi_inner_domain; +@@ -1418,14 +1417,19 @@ static void advk_pcie_irq_unmask(struct irq_data *d) + raw_spin_unlock_irqrestore(&pcie->irq_lock, flags); + } + ++static struct irq_chip advk_irq_chip = { ++ .name = "advk-INT", ++ .irq_mask = advk_pcie_irq_mask, ++ .irq_unmask = advk_pcie_irq_unmask, ++}; ++ + static int advk_pcie_irq_map(struct irq_domain *h, + unsigned int virq, irq_hw_number_t hwirq) + { + struct advk_pcie *pcie = h->host_data; + + irq_set_status_flags(virq, IRQ_LEVEL); +- irq_set_chip_and_handler(virq, &pcie->irq_chip, +- handle_level_irq); ++ irq_set_chip_and_handler(virq, &advk_irq_chip, handle_level_irq); + irq_set_chip_data(virq, pcie); + + return 0; +@@ -1485,7 +1489,6 @@ static int advk_pcie_init_irq_domain(struct advk_pcie *pcie) + struct device *dev = &pcie->pdev->dev; + struct device_node *node = dev->of_node; + struct device_node *pcie_intc_node; +- struct irq_chip *irq_chip; + int ret = 0; + + raw_spin_lock_init(&pcie->irq_lock); +@@ -1496,28 +1499,14 @@ static int advk_pcie_init_irq_domain(struct advk_pcie *pcie) + return -ENODEV; + } + +- irq_chip = &pcie->irq_chip; +- +- irq_chip->name = devm_kasprintf(dev, GFP_KERNEL, "%s-irq", +- dev_name(dev)); +- if (!irq_chip->name) { +- ret = -ENOMEM; +- goto out_put_node; +- } +- +- irq_chip->irq_mask = advk_pcie_irq_mask; +- irq_chip->irq_unmask = advk_pcie_irq_unmask; +- + pcie->irq_domain = + irq_domain_add_linear(pcie_intc_node, PCI_NUM_INTX, + &advk_pcie_irq_domain_ops, pcie); + if (!pcie->irq_domain) { + dev_err(dev, "Failed to get a INTx IRQ domain\n"); + ret = -ENOMEM; +- goto out_put_node; + } + +-out_put_node: + of_node_put(pcie_intc_node); + return ret; + } +-- +2.51.0 + + +From 772fcedd8d860ca53e1f543962c11f4dcad5c3ba Mon Sep 17 00:00:00 2001 +From: Corentin Labbe +Date: Tue, 7 May 2024 13:15:22 +0000 +Subject: [PATCH 325/517] usb: serial: add support for CH348 + +The CH348 is an USB octo port serial adapter. +The device multiplexes all 8 ports in the same pair of Bulk endpoints. +Since there is no public datasheet, unfortunately it remains some magic values + +Signed-off-by: Corentin Labbe +Tested-by: Martin Blumenstingl +--- + drivers/usb/serial/Kconfig | 9 + + drivers/usb/serial/Makefile | 1 + + drivers/usb/serial/ch348.c | 725 ++++++++++++++++++++++++++++++++++++ + 3 files changed, 735 insertions(+) + create mode 100644 drivers/usb/serial/ch348.c + +diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig +index ef8d1c73c754..1e1842656b54 100644 +--- a/drivers/usb/serial/Kconfig ++++ b/drivers/usb/serial/Kconfig +@@ -112,6 +112,15 @@ config USB_SERIAL_CH341 + To compile this driver as a module, choose M here: the + module will be called ch341. + ++config USB_SERIAL_CH348 ++ tristate "USB Winchiphead CH348 Octo Port Serial Driver" ++ help ++ Say Y here if you want to use a Winchiphead CH348 octo port ++ USB to serial adapter. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called ch348. ++ + config USB_SERIAL_WHITEHEAT + tristate "USB ConnectTech WhiteHEAT Serial Driver" + select USB_EZUSB_FX2 +diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile +index c7bb1a88173e..d16ff59fde68 100644 +--- a/drivers/usb/serial/Makefile ++++ b/drivers/usb/serial/Makefile +@@ -15,6 +15,7 @@ obj-$(CONFIG_USB_SERIAL_AIRCABLE) += aircable.o + obj-$(CONFIG_USB_SERIAL_ARK3116) += ark3116.o + obj-$(CONFIG_USB_SERIAL_BELKIN) += belkin_sa.o + obj-$(CONFIG_USB_SERIAL_CH341) += ch341.o ++obj-$(CONFIG_USB_SERIAL_CH348) += ch348.o + obj-$(CONFIG_USB_SERIAL_CP210X) += cp210x.o + obj-$(CONFIG_USB_SERIAL_CYBERJACK) += cyberjack.o + obj-$(CONFIG_USB_SERIAL_CYPRESS_M8) += cypress_m8.o +diff --git a/drivers/usb/serial/ch348.c b/drivers/usb/serial/ch348.c +new file mode 100644 +index 000000000000..e437ba36bb5e +--- /dev/null ++++ b/drivers/usb/serial/ch348.c +@@ -0,0 +1,725 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * USB serial driver for USB to Octal UARTs chip ch348. ++ * ++ * Copyright (C) 2022 Corentin Labbe ++ * With the help of Neil Armstrong ++ * and the help of Martin Blumenstingl ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define CH348_CMD_TIMEOUT 2000 ++ ++#define CH348_CTO_D 0x01 ++#define CH348_CTO_R 0x02 ++ ++#define CH348_CTI_C 0x10 ++#define CH348_CTI_DSR 0x20 ++#define CH348_CTI_R 0x40 ++#define CH348_CTI_DCD 0x80 ++ ++#define CH348_LO 0x02 ++#define CH348_LP 0x04 ++#define CH348_LF 0x08 ++#define CH348_LB 0x10 ++ ++#define CMD_W_R 0xC0 ++#define CMD_W_BR 0x80 ++ ++#define CMD_WB_E 0x90 ++#define CMD_RB_E 0xC0 ++ ++#define M_NOR 0x00 ++#define M_HF 0x03 ++ ++#define R_MOD 0x97 ++#define R_IO_D 0x98 ++#define R_IO_O 0x99 ++#define R_IO_I 0x9b ++#define R_TM_O 0x9c ++#define R_INIT 0xa1 ++ ++#define R_C1 0x01 ++#define R_C2 0x02 ++#define R_C4 0x04 ++#define R_C5 0x06 ++ ++#define R_II_B1 0x06 ++#define R_II_B2 0x02 ++#define R_II_B3 0x00 ++ ++#define CMD_VER 0x96 ++ ++#define CH348_RX_PORT_CHUNK_LENGTH 32 ++#define CH348_RX_PORT_MAX_LENGTH 30 ++ ++struct ch348_rxbuf { ++ u8 port; ++ u8 length; ++ u8 data[CH348_RX_PORT_MAX_LENGTH]; ++} __packed; ++ ++struct ch348_txbuf { ++ u8 port; ++ __le16 length; ++ u8 data[]; ++} __packed; ++ ++#define CH348_TX_HDRSIZE offsetof(struct ch348_txbuf, data) ++ ++struct ch348_initbuf { ++ u8 cmd; ++ u8 reg; ++ u8 port; ++ __be32 baudrate; ++ u8 format; ++ u8 paritytype; ++ u8 databits; ++ u8 rate; ++ u8 unknown; ++} __packed; ++ ++#define CH348_MAXPORT 8 ++ ++/* ++ * The CH348 multiplexes rx & tx into a pair of Bulk USB endpoints for ++ * the 8 serial ports, and another pair of Bulk USB endpoints to ++ * set port settings and receive port status events. ++ * ++ * The USB serial cores ties every Bulk endpoints pairs to each ports, ++ * but in our case it will set port 0 with the rx/tx endpoints ++ * and port 1 with the setup/status endpoints. ++ * ++ * To still take advantage of the generic code, we (re-)initialize ++ * the USB serial port structure with the correct USB endpoint ++ * for read and write, and write proper process_read_urb() ++ * and prepare_write_buffer() to correctly (de-)multiplex data. ++ * Also we use a custom write() implementation to wait until the buffer ++ * has been fully transmitted to prevent TX buffer overruns. ++ */ ++ ++/* ++ * struct ch348_port - per-port information ++ * @uartmode: UART port current mode ++ * @write_completion: completion event when the TX buffer has been written out ++ */ ++struct ch348_port { ++ u8 uartmode; ++ struct completion write_completion; ++}; ++ ++/* ++ * struct ch348 - main container for all this driver information ++ * @udev: pointer to the CH348 USB device ++ * @ports: List of per-port information ++ * @serial: pointer to the serial structure ++ * @write_lock: protect against concurrent writes so we don't lose data ++ * @cmd_ep: endpoint number for configure operations ++ * @status_urb: URB for status ++ * @status_buffer: buffer used by status_urb ++ */ ++struct ch348 { ++ struct usb_device *udev; ++ struct ch348_port ports[CH348_MAXPORT]; ++ struct usb_serial *serial; ++ ++ struct mutex write_lock; ++ ++ int cmd_ep; ++ ++ struct urb *status_urb; ++ u8 status_buffer[]; ++}; ++ ++struct ch348_magic { ++ u8 action; ++ u8 reg; ++ u8 control; ++} __packed; ++ ++struct ch348_status_entry { ++ u8 portnum:4; ++ u8 unused:4; ++ u8 reg_iir; ++ union { ++ u8 lsr_signal; ++ u8 modem_signal; ++ u8 init_data[10]; ++ }; ++} __packed; ++ ++static void ch348_process_status_urb(struct urb *urb) ++{ ++ struct ch348_status_entry *status_entry; ++ struct ch348 *ch348 = urb->context; ++ int ret, status = urb->status; ++ struct usb_serial_port *port; ++ unsigned int i, status_len; ++ ++ switch (status) { ++ case 0: ++ /* success */ ++ break; ++ case -ECONNRESET: ++ case -ENOENT: ++ case -ESHUTDOWN: ++ /* this urb is terminated, clean up */ ++ dev_dbg(&urb->dev->dev, "%s - urb shutting down with status: %d\n", ++ __func__, status); ++ return; ++ default: ++ dev_err(&urb->dev->dev, "%s - nonzero urb status received: %d\n", ++ __func__, status); ++ goto exit; ++ } ++ ++ if (urb->actual_length < 3) { ++ dev_warn(&ch348->udev->dev, ++ "Received too short status buffer with %u bytes\n", ++ urb->actual_length); ++ goto exit; ++ } ++ ++ for (i = 0; i < urb->actual_length;) { ++ status_entry = urb->transfer_buffer + i; ++ ++ if (status_entry->portnum >= CH348_MAXPORT) { ++ dev_warn(&ch348->udev->dev, ++ "Invalid port %d in status entry\n", ++ status_entry->portnum); ++ break; ++ } ++ ++ port = ch348->serial->port[status_entry->portnum]; ++ status_len = 3; ++ ++ if (!status_entry->reg_iir) { ++ dev_dbg(&port->dev, "Ignoring status with zero reg_iir\n"); ++ } else if (status_entry->reg_iir == R_INIT) { ++ status_len = 12; ++ } else if ((status_entry->reg_iir & 0x0f) == R_II_B1) { ++ if (status_entry->lsr_signal & CH348_LO) ++ port->icount.overrun++; ++ if (status_entry->lsr_signal & CH348_LP) ++ port->icount.parity++; ++ if (status_entry->lsr_signal & CH348_LF) ++ port->icount.frame++; ++ if (status_entry->lsr_signal & CH348_LF) ++ port->icount.brk++; ++ } else if ((status_entry->reg_iir & 0x0f) == R_II_B2) { ++ complete_all(&ch348->ports[status_entry->portnum].write_completion); ++ } else { ++ dev_warn(&port->dev, ++ "Unsupported status with reg_iir 0x%02x\n", ++ status_entry->reg_iir); ++ } ++ ++ usb_serial_debug_data(&port->dev, __func__, status_len, ++ urb->transfer_buffer + i); ++ ++ i += status_len; ++ } ++ ++exit: ++ ret = usb_submit_urb(urb, GFP_ATOMIC); ++ if (ret) ++ dev_err(&urb->dev->dev, "%s - usb_submit_urb failed; %d\n", ++ __func__, ret); ++} ++ ++/* ++ * Some values came from vendor tree, and we have no meaning for them, this ++ * function simply use them. ++ */ ++static int ch348_do_magic(struct ch348 *ch348, int portnum, u8 action, u8 reg, u8 control) ++{ ++ struct ch348_magic *buffer; ++ int ret, len; ++ ++ buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); ++ if (!buffer) ++ return -ENOMEM; ++ ++ if (portnum < 4) ++ reg += 0x10 * portnum; ++ else ++ reg += 0x10 * (portnum - 4) + 0x08; ++ ++ buffer->action = action; ++ buffer->reg = reg; ++ buffer->control = control; ++ ++ ret = usb_bulk_msg(ch348->udev, ch348->cmd_ep, buffer, 3, &len, ++ CH348_CMD_TIMEOUT); ++ if (ret) ++ dev_err(&ch348->udev->dev, "Failed to write magic err=%d\n", ret); ++ ++ kfree(buffer); ++ ++ return ret; ++} ++ ++static int ch348_configure(struct ch348 *ch348, int portnum) ++{ ++ int ret; ++ ++ ret = ch348_do_magic(ch348, portnum, CMD_W_R, R_C2, 0x87); ++ if (ret) ++ return ret; ++ ++ return ch348_do_magic(ch348, portnum, CMD_W_R, R_C4, 0x08); ++} ++ ++static void ch348_process_read_urb(struct urb *urb) ++{ ++ struct usb_serial_port *port = urb->context; ++ struct ch348 *ch348 = usb_get_serial_data(port->serial); ++ unsigned int portnum, usblen, i; ++ struct ch348_rxbuf *rxb; ++ ++ if (urb->actual_length < 2) { ++ dev_dbg(&ch348->udev->dev, "Empty rx buffer\n"); ++ return; ++ } ++ ++ for (i = 0; i < urb->actual_length; i += CH348_RX_PORT_CHUNK_LENGTH) { ++ rxb = urb->transfer_buffer + i; ++ portnum = rxb->port; ++ if (portnum >= CH348_MAXPORT) { ++ dev_dbg(&ch348->udev->dev, "Invalid port %d\n", portnum); ++ break; ++ } ++ ++ port = ch348->serial->port[portnum]; ++ ++ usblen = rxb->length; ++ if (usblen > CH348_RX_PORT_MAX_LENGTH) { ++ dev_dbg(&port->dev, "Invalid length %d for port %d\n", ++ usblen, portnum); ++ break; ++ } ++ ++ tty_insert_flip_string(&port->port, rxb->data, usblen); ++ tty_flip_buffer_push(&port->port); ++ port->icount.rx += usblen; ++ usb_serial_debug_data(&port->dev, __func__, usblen, rxb->data); ++ } ++} ++ ++static int ch348_prepare_write_buffer(struct usb_serial_port *port, void *dest, size_t size) ++{ ++ struct ch348_txbuf *rxt = dest; ++ int count; ++ ++ count = kfifo_out_locked(&port->write_fifo, rxt->data, ++ size - CH348_TX_HDRSIZE, &port->lock); ++ ++ rxt->port = port->port_number; ++ rxt->length = cpu_to_le16(count); ++ ++ return count + CH348_TX_HDRSIZE; ++} ++ ++static int ch348_write(struct tty_struct *tty, struct usb_serial_port *port, ++ const unsigned char *buf, int count) ++{ ++ struct ch348 *ch348 = usb_get_serial_data(port->serial); ++ struct ch348_port *ch348_port = &ch348->ports[port->port_number]; ++ int ret, max_tx_size; ++ ++ if (tty_get_baud_rate(tty) < 9600 && count >= 128) ++ /* ++ * Writing larger buffers can take longer than the hardware ++ * allows before discarding the write buffer. Limit the ++ * transfer size in such cases. ++ * These values have been found by empirical testing. ++ */ ++ max_tx_size = 128; ++ else ++ /* ++ * Only ingest as many bytes as we can transfer with one URB at ++ * a time. Once an URB has been written we need to wait for the ++ * R_II_B2 status event before we are allowed to send more data. ++ * If we ingest more data then usb_serial_generic_write() will ++ * internally try to process as much data as possible with any ++ * number of URBs without giving us the chance to wait in ++ * between transfers. ++ */ ++ max_tx_size = port->bulk_out_size - CH348_TX_HDRSIZE; ++ ++ reinit_completion(&ch348_port->write_completion); ++ ++ mutex_lock(&ch348->write_lock); ++ ++ /* ++ * For any (remaining) bytes that we did not transfer TTY core will ++ * call us again, with the buffer and count adjusted to the remaining ++ * data. ++ */ ++ ret = usb_serial_generic_write(tty, port, buf, min(count, max_tx_size)); ++ ++ mutex_unlock(&ch348->write_lock); ++ ++ if (ret <= 0) ++ return ret; ++ ++ if (!wait_for_completion_interruptible_timeout(&ch348_port->write_completion, ++ msecs_to_jiffies(CH348_CMD_TIMEOUT))) { ++ dev_err_console(port, "Failed to wait for TX buffer flush\n"); ++ return -ETIMEDOUT; ++ } ++ ++ return ret; ++} ++ ++static int ch348_set_uartmode(struct ch348 *ch348, int portnum, u8 mode) ++{ ++ int ret; ++ ++ if (ch348->ports[portnum].uartmode == M_NOR && mode == M_HF) { ++ ret = ch348_do_magic(ch348, portnum, CMD_W_BR, R_C4, 0x51); ++ if (ret) ++ return ret; ++ ch348->ports[portnum].uartmode = M_HF; ++ } ++ ++ if (ch348->ports[portnum].uartmode == M_HF && mode == M_NOR) { ++ ret = ch348_do_magic(ch348, portnum, CMD_W_BR, R_C4, 0x50); ++ if (ret) ++ return ret; ++ ch348->ports[portnum].uartmode = M_NOR; ++ } ++ return 0; ++} ++ ++static void ch348_set_termios(struct tty_struct *tty, struct usb_serial_port *port, ++ const struct ktermios *termios_old) ++{ ++ struct ch348 *ch348 = usb_get_serial_data(port->serial); ++ struct ktermios *termios = &tty->termios; ++ int ret, portnum = port->port_number; ++ struct ch348_initbuf *buffer; ++ speed_t baudrate; ++ u8 format; ++ ++ if (termios_old && !tty_termios_hw_change(&tty->termios, termios_old)) ++ return; ++ ++ buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); ++ if (!buffer) { ++ if (termios_old) ++ tty->termios = *termios_old; ++ return; ++ } ++ ++ /* ++ * The datasheet states that only baud rates in range of 1200..6000000 ++ * are supported. Tests however show that even baud rates as low as 50 ++ * and as high as 12000000 are working in practice. ++ */ ++ baudrate = clamp(tty_get_baud_rate(tty), 50, 12000000); ++ ++ format = termios->c_cflag & CSTOPB ? 2 : 1; ++ ++ buffer->paritytype = 0; ++ if (termios->c_cflag & PARENB) { ++ if (termios->c_cflag & PARODD) ++ buffer->paritytype += 1; ++ else ++ buffer->paritytype += 2; ++ if (termios->c_cflag & CMSPAR) ++ buffer->paritytype += 2; ++ } ++ ++ switch (C_CSIZE(tty)) { ++ case CS5: ++ buffer->databits = 5; ++ break; ++ case CS6: ++ buffer->databits = 6; ++ break; ++ case CS7: ++ buffer->databits = 7; ++ break; ++ case CS8: ++ default: ++ buffer->databits = 8; ++ break; ++ } ++ buffer->cmd = CMD_WB_E | (portnum & 0x0F); ++ buffer->reg = R_INIT; ++ buffer->port = portnum; ++ buffer->baudrate = cpu_to_be32(baudrate); ++ ++ if (format == 2) ++ buffer->format = 0x02; ++ else if (format == 1) ++ buffer->format = 0x00; ++ ++ buffer->rate = max_t(speed_t, 5, (10000 * 15 / baudrate) + 1); ++ ++ ret = usb_bulk_msg(ch348->udev, ch348->cmd_ep, buffer, ++ sizeof(*buffer), NULL, CH348_CMD_TIMEOUT); ++ if (ret < 0) { ++ dev_err(&ch348->udev->dev, "Failed to change line settings: err=%d\n", ++ ret); ++ goto out; ++ } ++ ++ ret = ch348_do_magic(ch348, portnum, CMD_W_R, R_C1, 0x0F); ++ if (ret < 0) ++ goto out; ++ ++ if (C_CRTSCTS(tty)) ++ ret = ch348_set_uartmode(ch348, portnum, M_HF); ++ else ++ ret = ch348_set_uartmode(ch348, portnum, M_NOR); ++ ++out: ++ kfree(buffer); ++} ++ ++static int ch348_open(struct tty_struct *tty, struct usb_serial_port *port) ++{ ++ struct ch348 *ch348 = usb_get_serial_data(port->serial); ++ int ret; ++ ++ if (tty) ++ ch348_set_termios(tty, port, NULL); ++ ++ ret = ch348_configure(ch348, port->port_number); ++ if (ret) { ++ dev_err(&ch348->udev->dev, "Fail to configure err=%d\n", ret); ++ return ret; ++ } ++ ++ return usb_serial_generic_open(tty, port); ++} ++ ++static int ch348_attach(struct usb_serial *serial) ++{ ++ struct usb_endpoint_descriptor *epcmd, *epstatus; ++ struct usb_serial_port *port0 = serial->port[1]; ++ struct usb_device *usb_dev = serial->dev; ++ int status_buffer_size, i, ret; ++ struct usb_interface *intf; ++ struct ch348 *ch348; ++ ++ intf = usb_ifnum_to_if(usb_dev, 0); ++ epstatus = &intf->cur_altsetting->endpoint[2].desc; ++ epcmd = &intf->cur_altsetting->endpoint[3].desc; ++ ++ status_buffer_size = usb_endpoint_maxp(epstatus); ++ ++ ch348 = kzalloc(struct_size(ch348, status_buffer, status_buffer_size), ++ GFP_KERNEL); ++ if (!ch348) ++ return -ENOMEM; ++ ++ usb_set_serial_data(serial, ch348); ++ ++ ch348->udev = serial->dev; ++ ch348->serial = serial; ++ mutex_init(&ch348->write_lock); ++ ++ for (i = 0; i < CH348_MAXPORT; i++) ++ init_completion(&ch348->ports[i].write_completion); ++ ++ ch348->status_urb = usb_alloc_urb(0, GFP_KERNEL); ++ if (!ch348->status_urb) { ++ ret = -ENOMEM; ++ goto err_free_ch348; ++ } ++ ++ usb_fill_bulk_urb(ch348->status_urb, ch348->udev, ++ usb_rcvbulkpipe(ch348->udev, epstatus->bEndpointAddress), ++ ch348->status_buffer, status_buffer_size, ++ ch348_process_status_urb, ch348); ++ ++ ret = usb_submit_urb(ch348->status_urb, GFP_KERNEL); ++ if (ret) { ++ dev_err(&ch348->udev->dev, ++ "%s - failed to submit status/interrupt urb %i\n", ++ __func__, ret); ++ goto err_free_status_urb; ++ } ++ ++ ret = usb_serial_generic_submit_read_urbs(port0, GFP_KERNEL); ++ if (ret) ++ goto err_kill_status_urb; ++ ++ ch348->cmd_ep = usb_sndbulkpipe(usb_dev, epcmd->bEndpointAddress); ++ ++ return 0; ++ ++err_kill_status_urb: ++ usb_kill_urb(ch348->status_urb); ++err_free_status_urb: ++ usb_free_urb(ch348->status_urb); ++err_free_ch348: ++ kfree(ch348); ++ return ret; ++} ++ ++static void ch348_release(struct usb_serial *serial) ++{ ++ struct ch348 *ch348 = usb_get_serial_data(serial); ++ ++ usb_kill_urb(ch348->status_urb); ++ usb_free_urb(ch348->status_urb); ++ ++ kfree(ch348); ++} ++ ++static void ch348_print_version(struct usb_serial *serial) ++{ ++ u8 *version_buf; ++ int ret; ++ ++ version_buf = kzalloc(4, GFP_KERNEL); ++ if (!version_buf) ++ return; ++ ++ ret = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), ++ CMD_VER, ++ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, ++ 0, 0, version_buf, 4, CH348_CMD_TIMEOUT); ++ if (ret < 0) ++ dev_dbg(&serial->dev->dev, "Failed to read CMD_VER: %d\n", ret); ++ else ++ dev_info(&serial->dev->dev, "Found WCH CH348%s\n", ++ (version_buf[1] & 0x80) ? "Q" : "L"); ++ ++ kfree(version_buf); ++} ++ ++static int ch348_probe(struct usb_serial *serial, const struct usb_device_id *id) ++{ ++ struct usb_endpoint_descriptor *epread, *epwrite, *epstatus, *epcmd; ++ struct usb_device *usb_dev = serial->dev; ++ struct usb_interface *intf; ++ int ret; ++ ++ intf = usb_ifnum_to_if(usb_dev, 0); ++ ++ ret = usb_find_common_endpoints(intf->cur_altsetting, &epread, &epwrite, ++ NULL, NULL); ++ if (ret) { ++ dev_err(&serial->dev->dev, "Failed to find basic endpoints ret=%d\n", ret); ++ return ret; ++ } ++ ++ epstatus = &intf->cur_altsetting->endpoint[2].desc; ++ if (!usb_endpoint_is_bulk_in(epstatus)) { ++ dev_err(&serial->dev->dev, "Missing second bulk in (STATUS/INT)\n"); ++ return -ENODEV; ++ } ++ ++ epcmd = &intf->cur_altsetting->endpoint[3].desc; ++ if (!usb_endpoint_is_bulk_out(epcmd)) { ++ dev_err(&serial->dev->dev, "Missing second bulk out (CMD)\n"); ++ return -ENODEV; ++ } ++ ++ ch348_print_version(serial); ++ ++ return 0; ++} ++ ++static int ch348_calc_num_ports(struct usb_serial *serial, ++ struct usb_serial_endpoints *epds) ++{ ++ int i; ++ ++ for (i = 1; i < CH348_MAXPORT; ++i) { ++ epds->bulk_out[i] = epds->bulk_out[0]; ++ epds->bulk_in[i] = epds->bulk_in[0]; ++ } ++ ++ epds->num_bulk_out = CH348_MAXPORT; ++ epds->num_bulk_in = CH348_MAXPORT; ++ ++ return CH348_MAXPORT; ++} ++ ++static int ch348_suspend(struct usb_serial *serial, pm_message_t message) ++{ ++ struct ch348 *ch348 = usb_get_serial_data(serial); ++ ++ usb_kill_urb(ch348->status_urb); ++ ++ return 0; ++} ++ ++static int ch348_resume(struct usb_serial *serial) ++{ ++ struct ch348 *ch348 = usb_get_serial_data(serial); ++ int ret; ++ ++ ret = usb_submit_urb(ch348->status_urb, GFP_KERNEL); ++ if (ret) { ++ dev_err(&ch348->udev->dev, ++ "%s - failed to submit status/interrupt urb %i\n", ++ __func__, ret); ++ return ret; ++ } ++ ++ ret = usb_serial_generic_resume(serial); ++ if (ret) ++ usb_kill_urb(ch348->status_urb); ++ ++ return ret; ++} ++ ++static const struct usb_device_id ch348_ids[] = { ++ { USB_DEVICE(0x1a86, 0x55d9), }, ++ { /* sentinel */ } ++}; ++ ++MODULE_DEVICE_TABLE(usb, ch348_ids); ++ ++static struct usb_serial_driver ch348_device = { ++ .driver = { ++ .owner = THIS_MODULE, ++ .name = "ch348", ++ }, ++ .id_table = ch348_ids, ++ .num_ports = CH348_MAXPORT, ++ .num_bulk_in = 1, ++ .num_bulk_out = 1, ++ .open = ch348_open, ++ .set_termios = ch348_set_termios, ++ .process_read_urb = ch348_process_read_urb, ++ .prepare_write_buffer = ch348_prepare_write_buffer, ++ .write = ch348_write, ++ .probe = ch348_probe, ++ .calc_num_ports = ch348_calc_num_ports, ++ .attach = ch348_attach, ++ .release = ch348_release, ++ .suspend = ch348_suspend, ++ .resume = ch348_resume, ++}; ++ ++static struct usb_serial_driver * const serial_drivers[] = { ++ &ch348_device, NULL ++}; ++ ++module_usb_serial_driver(serial_drivers, ch348_ids); ++ ++MODULE_AUTHOR("Corentin Labbe "); ++MODULE_DESCRIPTION("USB CH348 Octo port serial converter driver"); ++MODULE_LICENSE("GPL"); +-- +2.51.0 + + +From 7425a0d41434f00f9190aeee0fbbe6c94315589b Mon Sep 17 00:00:00 2001 +From: Vicentiu Galanopulo +Date: Wed, 18 Dec 2024 18:33:58 +0000 +Subject: [PATCH 326/517] dt-bindings: leds: Add LED1202 LED Controller + +The LED1202 is a 12-channel low quiescent current LED driver with: + * Supply range from 2.6 V to 5 V + * 20 mA current capability per channel + * 1.8 V compatible I2C control interface + * 8-bit analog dimming individual control + * 12-bit local PWM resolution + * 8 programmable patterns + +If the led node is present in the controller then the channel is +set to active. + +Signed-off-by: Vicentiu Galanopulo +Reviewed-by: Krzysztof Kozlowski +--- + .../devicetree/bindings/leds/st,led1202.yaml | 132 ++++++++++++++++++ + 1 file changed, 132 insertions(+) + create mode 100644 Documentation/devicetree/bindings/leds/st,led1202.yaml + +diff --git a/Documentation/devicetree/bindings/leds/st,led1202.yaml b/Documentation/devicetree/bindings/leds/st,led1202.yaml +new file mode 100644 +index 000000000000..f1e5e4efaa3a +--- /dev/null ++++ b/Documentation/devicetree/bindings/leds/st,led1202.yaml +@@ -0,0 +1,132 @@ ++# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/leds/st,led1202.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: ST LED1202 LED controllers ++ ++maintainers: ++ - Vicentiu Galanopulo ++ ++description: | ++ The LED1202 is a 12-channel low quiescent current LED controller ++ programmable via I2C; The output current can be adjusted separately ++ for each channel by 8-bit analog and 12-bit digital dimming control. ++ Datasheet available at ++ https://www.st.com/en/power-management/led1202.html ++ ++properties: ++ compatible: ++ const: st,led1202 ++ ++ reg: ++ maxItems: 1 ++ ++ "#address-cells": ++ const: 1 ++ ++ "#size-cells": ++ const: 0 ++ ++patternProperties: ++ "^led@[0-9a-f]$": ++ type: object ++ $ref: common.yaml# ++ unevaluatedProperties: false ++ ++ properties: ++ reg: ++ minimum: 0 ++ maximum: 11 ++ ++ required: ++ - reg ++ ++required: ++ - compatible ++ - reg ++ - "#address-cells" ++ - "#size-cells" ++ ++additionalProperties: false ++ ++examples: ++ - | ++ #include ++ ++ i2c { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ led-controller@58 { ++ compatible = "st,led1202"; ++ reg = <0x58>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ led@0 { ++ reg = <0x0>; ++ function = LED_FUNCTION_STATUS; ++ color = ; ++ function-enumerator = <1>; ++ }; ++ ++ led@1 { ++ reg = <0x1>; ++ function = LED_FUNCTION_STATUS; ++ color = ; ++ function-enumerator = <2>; ++ }; ++ ++ led@2 { ++ reg = <0x2>; ++ function = LED_FUNCTION_STATUS; ++ color = ; ++ function-enumerator = <3>; ++ }; ++ ++ led@3 { ++ reg = <0x3>; ++ function = LED_FUNCTION_STATUS; ++ color = ; ++ function-enumerator = <4>; ++ }; ++ ++ led@4 { ++ reg = <0x4>; ++ function = LED_FUNCTION_STATUS; ++ color = ; ++ function-enumerator = <5>; ++ }; ++ ++ led@5 { ++ reg = <0x5>; ++ function = LED_FUNCTION_STATUS; ++ color = ; ++ function-enumerator = <6>; ++ }; ++ ++ led@6 { ++ reg = <0x6>; ++ function = LED_FUNCTION_STATUS; ++ color = ; ++ function-enumerator = <7>; ++ }; ++ ++ led@7 { ++ reg = <0x7>; ++ function = LED_FUNCTION_STATUS; ++ color = ; ++ function-enumerator = <8>; ++ }; ++ ++ led@8 { ++ reg = <0x8>; ++ function = LED_FUNCTION_STATUS; ++ color = ; ++ function-enumerator = <9>; ++ }; ++ }; ++ }; ++... +-- +2.51.0 + + +From 266622ae5a057e31d2539cf532af4287df3aa656 Mon Sep 17 00:00:00 2001 +From: Vicentiu Galanopulo +Date: Wed, 18 Dec 2024 18:33:59 +0000 +Subject: [PATCH 327/517] leds: Add LED1202 I2C driver + +The output current can be adjusted separately for each channel by 8-bit +analog (current sink input) and 12-bit digital (PWM) dimming control. The +LED1202 implements 12 low-side current generators with independent dimming +control. +Internal volatile memory allows the user to store up to 8 different patterns, +each pattern is a particular output configuration in terms of PWM +duty-cycle (on 4096 steps). Analog dimming (on 256 steps) is per channel but +common to all patterns. Each device tree LED node will have a corresponding +entry in /sys/class/leds with the label name. The brightness property +corresponds to the per channel analog dimming, while the patterns[1-8] to the +PWM dimming control. + +Signed-off-by: Vicentiu Galanopulo +--- + drivers/leds/Kconfig | 10 + + drivers/leds/Makefile | 1 + + drivers/leds/leds-st1202.c | 416 +++++++++++++++++++++++++++++++++++++ + 3 files changed, 427 insertions(+) + create mode 100644 drivers/leds/leds-st1202.c + +diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig +index b784bb74a837..c275963c498c 100644 +--- a/drivers/leds/Kconfig ++++ b/drivers/leds/Kconfig +@@ -931,6 +931,16 @@ config LEDS_LM36274 + Say Y to enable the LM36274 LED driver for TI LMU devices. + This supports the LED device LM36274. + ++config LEDS_ST1202 ++ tristate "LED Support for STMicroelectronics LED1202 I2C chips" ++ depends on LEDS_CLASS ++ depends on I2C ++ depends on OF ++ select LEDS_TRIGGERS ++ help ++ Say Y to enable support for LEDs connected to LED1202 ++ LED driver chips accessed via the I2C bus. ++ + config LEDS_TPS6105X + tristate "LED support for TI TPS6105X" + depends on LEDS_CLASS +diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile +index 18afbb5a23ee..32241451b805 100644 +--- a/drivers/leds/Makefile ++++ b/drivers/leds/Makefile +@@ -82,6 +82,7 @@ obj-$(CONFIG_LEDS_PWM) += leds-pwm.o + obj-$(CONFIG_LEDS_REGULATOR) += leds-regulator.o + obj-$(CONFIG_LEDS_SC27XX_BLTC) += leds-sc27xx-bltc.o + obj-$(CONFIG_LEDS_SUN50I_A100) += leds-sun50i-a100.o ++obj-$(CONFIG_LEDS_ST1202) += leds-st1202.o + obj-$(CONFIG_LEDS_SUNFIRE) += leds-sunfire.o + obj-$(CONFIG_LEDS_SYSCON) += leds-syscon.o + obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o +diff --git a/drivers/leds/leds-st1202.c b/drivers/leds/leds-st1202.c +new file mode 100644 +index 000000000000..b691c4886993 +--- /dev/null ++++ b/drivers/leds/leds-st1202.c +@@ -0,0 +1,416 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * LED driver for STMicroelectronics LED1202 chip ++ * ++ * Copyright (C) 2024 Remote-Tech Ltd. UK ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define ST1202_CHAN_DISABLE_ALL 0x00 ++#define ST1202_CHAN_ENABLE_HIGH 0x03 ++#define ST1202_CHAN_ENABLE_LOW 0x02 ++#define ST1202_CONFIG_REG 0x04 ++/* PATS: Pattern sequence feature enable */ ++#define ST1202_CONFIG_REG_PATS BIT(7) ++/* PATSR: Pattern sequence runs (self-clear when sequence is finished) */ ++#define ST1202_CONFIG_REG_PATSR BIT(6) ++#define ST1202_CONFIG_REG_SHFT BIT(3) ++#define ST1202_DEV_ENABLE 0x01 ++#define ST1202_DEV_ENABLE_ON BIT(0) ++#define ST1202_DEV_ENABLE_RESET BIT(7) ++#define ST1202_DEVICE_ID 0x00 ++#define ST1202_ILED_REG0 0x09 ++#define ST1202_MAX_LEDS 12 ++#define ST1202_MAX_PATTERNS 8 ++#define ST1202_MILLIS_PATTERN_DUR_MAX 5660 ++#define ST1202_MILLIS_PATTERN_DUR_MIN 22 ++#define ST1202_PATTERN_DUR 0x16 ++#define ST1202_PATTERN_PWM 0x1E ++#define ST1202_PATTERN_REP 0x15 ++ ++struct st1202_led { ++ struct fwnode_handle *fwnode; ++ struct led_classdev led_cdev; ++ struct st1202_chip *chip; ++ bool is_active; ++ int led_num; ++}; ++ ++struct st1202_chip { ++ struct i2c_client *client; ++ struct mutex lock; ++ struct st1202_led leds[ST1202_MAX_LEDS]; ++}; ++ ++static struct st1202_led *cdev_to_st1202_led(struct led_classdev *cdev) ++{ ++ return container_of(cdev, struct st1202_led, led_cdev); ++} ++ ++static int st1202_read_reg(struct st1202_chip *chip, int reg, uint8_t *val) ++{ ++ struct device *dev = &chip->client->dev; ++ int ret; ++ ++ ret = i2c_smbus_read_byte_data(chip->client, reg); ++ if (ret < 0) { ++ dev_err(dev, "Failed to read register [0x%x]: %d\n", reg, ret); ++ return ret; ++ } ++ ++ *val = (uint8_t)ret; ++ return 0; ++} ++ ++static int st1202_write_reg(struct st1202_chip *chip, int reg, uint8_t val) ++{ ++ struct device *dev = &chip->client->dev; ++ int ret; ++ ++ ret = i2c_smbus_write_byte_data(chip->client, reg, val); ++ if (ret != 0) ++ dev_err(dev, "Failed to write %d to register [0x%x]: %d\n", val, reg, ret); ++ ++ return ret; ++} ++ ++static uint8_t st1202_prescalar_to_miliseconds(unsigned int value) ++{ ++ return value / ST1202_MILLIS_PATTERN_DUR_MIN - 1; ++} ++ ++static int st1202_pwm_pattern_write(struct st1202_chip *chip, int led_num, ++ int pattern, unsigned int value) ++{ ++ u8 value_l, value_h; ++ int ret; ++ ++ value_l = (u8)value; ++ value_h = (u8)(value >> 8); ++ ++ /* ++ * Datasheet: Register address low = 1Eh + 2*(xh) + 18h*(yh), ++ * where x is the channel number (led number) in hexadecimal (x = 00h .. 0Bh) ++ * and y is the pattern number in hexadecimal (y = 00h .. 07h) ++ */ ++ ret = st1202_write_reg(chip, (ST1202_PATTERN_PWM + (led_num * 2) + 0x18 * pattern), ++ value_l); ++ if (ret != 0) ++ return ret; ++ ++ /* ++ * Datasheet: Register address high = 1Eh + 01h + 2(xh) +18h*(yh), ++ * where x is the channel number in hexadecimal (x = 00h .. 0Bh) ++ * and y is the pattern number in hexadecimal (y = 00h .. 07h) ++ */ ++ ret = st1202_write_reg(chip, (ST1202_PATTERN_PWM + 0x1 + (led_num * 2) + 0x18 * pattern), ++ value_h); ++ if (ret != 0) ++ return ret; ++ ++ return 0; ++} ++ ++static int st1202_duration_pattern_write(struct st1202_chip *chip, int pattern, ++ unsigned int value) ++{ ++ return st1202_write_reg(chip, (ST1202_PATTERN_DUR + pattern), ++ st1202_prescalar_to_miliseconds(value)); ++} ++ ++static void st1202_brightness_set(struct led_classdev *led_cdev, ++ enum led_brightness value) ++{ ++ struct st1202_led *led = cdev_to_st1202_led(led_cdev); ++ struct st1202_chip *chip = led->chip; ++ ++ guard(mutex)(&chip->lock); ++ ++ st1202_write_reg(chip, ST1202_ILED_REG0 + led->led_num, value); ++} ++ ++static enum led_brightness st1202_brightness_get(struct led_classdev *led_cdev) ++{ ++ struct st1202_led *led = cdev_to_st1202_led(led_cdev); ++ struct st1202_chip *chip = led->chip; ++ u8 value = 0; ++ ++ guard(mutex)(&chip->lock); ++ ++ st1202_read_reg(chip, ST1202_ILED_REG0 + led->led_num, &value); ++ ++ return value; ++} ++ ++static int st1202_channel_set(struct st1202_chip *chip, int led_num, bool active) ++{ ++ u8 chan_low, chan_high; ++ int ret; ++ ++ guard(mutex)(&chip->lock); ++ ++ if (led_num <= 7) { ++ ret = st1202_read_reg(chip, ST1202_CHAN_ENABLE_LOW, &chan_low); ++ if (ret < 0) ++ return ret; ++ ++ chan_low = active ? chan_low | BIT(led_num) : chan_low & ~BIT(led_num); ++ ++ ret = st1202_write_reg(chip, ST1202_CHAN_ENABLE_LOW, chan_low); ++ if (ret < 0) ++ return ret; ++ ++ } else { ++ ret = st1202_read_reg(chip, ST1202_CHAN_ENABLE_HIGH, &chan_high); ++ if (ret < 0) ++ return ret; ++ ++ chan_high = active ? chan_high | (BIT(led_num) >> 8) : ++ chan_high & ~(BIT(led_num) >> 8); ++ ++ ret = st1202_write_reg(chip, ST1202_CHAN_ENABLE_HIGH, chan_high); ++ if (ret < 0) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int st1202_led_set(struct led_classdev *ldev, enum led_brightness value) ++{ ++ struct st1202_led *led = cdev_to_st1202_led(ldev); ++ struct st1202_chip *chip = led->chip; ++ ++ return st1202_channel_set(chip, led->led_num, value == LED_OFF ? false : true); ++} ++ ++static int st1202_led_pattern_clear(struct led_classdev *ldev) ++{ ++ struct st1202_led *led = cdev_to_st1202_led(ldev); ++ struct st1202_chip *chip = led->chip; ++ int ret; ++ ++ guard(mutex)(&chip->lock); ++ ++ for (int patt = 0; patt < ST1202_MAX_PATTERNS; patt++) { ++ ret = st1202_pwm_pattern_write(chip, led->led_num, patt, LED_OFF); ++ if (ret != 0) ++ return ret; ++ ++ ret = st1202_duration_pattern_write(chip, patt, ST1202_MILLIS_PATTERN_DUR_MIN); ++ if (ret != 0) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int st1202_led_pattern_set(struct led_classdev *ldev, ++ struct led_pattern *pattern, ++ u32 len, int repeat) ++{ ++ struct st1202_led *led = cdev_to_st1202_led(ldev); ++ struct st1202_chip *chip = led->chip; ++ int ret; ++ ++ if (len > ST1202_MAX_PATTERNS) ++ return -EINVAL; ++ ++ guard(mutex)(&chip->lock); ++ ++ for (int patt = 0; patt < len; patt++) { ++ if (pattern[patt].delta_t < ST1202_MILLIS_PATTERN_DUR_MIN || ++ pattern[patt].delta_t > ST1202_MILLIS_PATTERN_DUR_MAX) ++ return -EINVAL; ++ ++ ret = st1202_pwm_pattern_write(chip, led->led_num, patt, pattern[patt].brightness); ++ if (ret != 0) ++ return ret; ++ ++ ret = st1202_duration_pattern_write(chip, patt, pattern[patt].delta_t); ++ if (ret != 0) ++ return ret; ++ } ++ ++ ret = st1202_write_reg(chip, ST1202_PATTERN_REP, repeat); ++ if (ret != 0) ++ return ret; ++ ++ ret = st1202_write_reg(chip, ST1202_CONFIG_REG, (ST1202_CONFIG_REG_PATSR | ++ ST1202_CONFIG_REG_PATS | ST1202_CONFIG_REG_SHFT)); ++ if (ret != 0) ++ return ret; ++ ++ return 0; ++} ++ ++static int st1202_dt_init(struct st1202_chip *chip) ++{ ++ struct device *dev = &chip->client->dev; ++ struct st1202_led *led; ++ int err, reg; ++ ++ for_each_available_child_of_node_scoped(dev_of_node(dev), child) { ++ struct led_init_data init_data = {}; ++ ++ err = of_property_read_u32(child, "reg", ®); ++ if (err) ++ return dev_err_probe(dev, err, "Invalid register\n"); ++ ++ led = &chip->leds[reg]; ++ led->is_active = true; ++ led->fwnode = of_fwnode_handle(child); ++ ++ led->led_cdev.max_brightness = U8_MAX; ++ led->led_cdev.brightness_set_blocking = st1202_led_set; ++ led->led_cdev.pattern_set = st1202_led_pattern_set; ++ led->led_cdev.pattern_clear = st1202_led_pattern_clear; ++ led->led_cdev.default_trigger = "pattern"; ++ ++ init_data.fwnode = led->fwnode; ++ init_data.devicename = "st1202"; ++ init_data.default_label = ":"; ++ ++ err = devm_led_classdev_register_ext(dev, &led->led_cdev, &init_data); ++ if (err < 0) ++ return dev_err_probe(dev, err, "Failed to register LED class device\n"); ++ ++ led->led_cdev.brightness_set = st1202_brightness_set; ++ led->led_cdev.brightness_get = st1202_brightness_get; ++ } ++ ++ return 0; ++} ++ ++static int st1202_setup(struct st1202_chip *chip) ++{ ++ int ret; ++ ++ guard(mutex)(&chip->lock); ++ ++ /* ++ * Once the supply voltage is applied, the LED1202 executes some internal checks, ++ * afterwords it stops the oscillator and puts the internal LDO in quiescent mode. ++ * To start the device, EN bit must be set inside the “Device Enable†register at ++ * address 01h. As soon as EN is set, the LED1202 loads the adjustment parameters ++ * from the internal non-volatile memory and performs an auto-calibration procedure ++ * in order to increase the output current precision. ++ * Such initialization lasts about 6.5 ms. ++ */ ++ ++ /* Reset the chip during setup */ ++ ret = st1202_write_reg(chip, ST1202_DEV_ENABLE, ST1202_DEV_ENABLE_RESET); ++ if (ret < 0) ++ return ret; ++ ++ /* Enable phase-shift delay feature */ ++ ret = st1202_write_reg(chip, ST1202_CONFIG_REG, ST1202_CONFIG_REG_SHFT); ++ if (ret < 0) ++ return ret; ++ ++ /* Enable the device */ ++ ret = st1202_write_reg(chip, ST1202_DEV_ENABLE, ST1202_DEV_ENABLE_ON); ++ if (ret < 0) ++ return ret; ++ ++ /* Duration of initialization */ ++ usleep_range(6500, 10000); ++ ++ /* Deactivate all LEDS (channels) and activate only the ones found in Device Tree */ ++ ret = st1202_write_reg(chip, ST1202_CHAN_ENABLE_LOW, ST1202_CHAN_DISABLE_ALL); ++ if (ret < 0) ++ return ret; ++ ++ ret = st1202_write_reg(chip, ST1202_CHAN_ENABLE_HIGH, ST1202_CHAN_DISABLE_ALL); ++ if (ret < 0) ++ return ret; ++ ++ ret = st1202_write_reg(chip, ST1202_CONFIG_REG, ++ ST1202_CONFIG_REG_PATS | ST1202_CONFIG_REG_PATSR); ++ if (ret < 0) ++ return ret; ++ ++ return 0; ++} ++ ++static int st1202_probe(struct i2c_client *client) ++{ ++ struct st1202_chip *chip; ++ struct st1202_led *led; ++ int ret; ++ ++ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) ++ return dev_err_probe(&client->dev, -EIO, "SMBUS Byte Data not Supported\n"); ++ ++ chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); ++ if (!chip) ++ return -ENOMEM; ++ ++ devm_mutex_init(&client->dev, &chip->lock); ++ chip->client = client; ++ ++ ret = st1202_dt_init(chip); ++ if (ret < 0) ++ return ret; ++ ++ ret = st1202_setup(chip); ++ if (ret < 0) ++ return ret; ++ ++ for (int i = 0; i < ST1202_MAX_LEDS; i++) { ++ led = &chip->leds[i]; ++ led->chip = chip; ++ led->led_num = i; ++ ++ if (!led->is_active) ++ continue; ++ ++ ret = st1202_channel_set(led->chip, led->led_num, true); ++ if (ret < 0) ++ return dev_err_probe(&client->dev, ret, ++ "Failed to activate LED channel\n"); ++ ++ ret = st1202_led_pattern_clear(&led->led_cdev); ++ if (ret < 0) ++ return dev_err_probe(&client->dev, ret, ++ "Failed to clear LED pattern\n"); ++ } ++ ++ return 0; ++} ++ ++static const struct i2c_device_id st1202_id[] = { ++ { "st1202-i2c" }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(i2c, st1202_id); ++ ++static const struct of_device_id st1202_dt_ids[] = { ++ { .compatible = "st,led1202" }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, st1202_dt_ids); ++ ++static struct i2c_driver st1202_driver = { ++ .driver = { ++ .name = "leds-st1202", ++ .of_match_table = of_match_ptr(st1202_dt_ids), ++ }, ++ .probe = st1202_probe, ++ .id_table = st1202_id, ++}; ++module_i2c_driver(st1202_driver); ++ ++MODULE_AUTHOR("Remote Tech LTD"); ++MODULE_DESCRIPTION("STMicroelectronics LED1202 : 12-channel constant current LED driver"); ++MODULE_LICENSE("GPL"); +-- +2.51.0 + + +From d379a1ad8f3ca2546f188f019764f46e06fdf24e Mon Sep 17 00:00:00 2001 +From: Manuel Fombuena +Date: Fri, 17 Jan 2025 12:31:49 +0000 +Subject: [PATCH 328/517] leds: leds-st1202: fix NULL pointer access on race + condition + +st1202_dt_init() calls devm_led_classdev_register_ext() before the +internal data structures are properly setup, so the leds become visible +to user space while being partially initialized, leading to a window +where trying to access them causes a NULL pointer access. + +This change moves devm_led_classdev_register_ext() to the last thing to +happen during initialization to eliminate it. + +Signed-off-by: Manuel Fombuena +--- + drivers/leds/leds-st1202.c | 21 ++++++++++----------- + 1 file changed, 10 insertions(+), 11 deletions(-) + +diff --git a/drivers/leds/leds-st1202.c b/drivers/leds/leds-st1202.c +index b691c4886993..e894b3f9a0f4 100644 +--- a/drivers/leds/leds-st1202.c ++++ b/drivers/leds/leds-st1202.c +@@ -261,8 +261,6 @@ static int st1202_dt_init(struct st1202_chip *chip) + int err, reg; + + for_each_available_child_of_node_scoped(dev_of_node(dev), child) { +- struct led_init_data init_data = {}; +- + err = of_property_read_u32(child, "reg", ®); + if (err) + return dev_err_probe(dev, err, "Invalid register\n"); +@@ -276,15 +274,6 @@ static int st1202_dt_init(struct st1202_chip *chip) + led->led_cdev.pattern_set = st1202_led_pattern_set; + led->led_cdev.pattern_clear = st1202_led_pattern_clear; + led->led_cdev.default_trigger = "pattern"; +- +- init_data.fwnode = led->fwnode; +- init_data.devicename = "st1202"; +- init_data.default_label = ":"; +- +- err = devm_led_classdev_register_ext(dev, &led->led_cdev, &init_data); +- if (err < 0) +- return dev_err_probe(dev, err, "Failed to register LED class device\n"); +- + led->led_cdev.brightness_set = st1202_brightness_set; + led->led_cdev.brightness_get = st1202_brightness_get; + } +@@ -368,6 +357,7 @@ static int st1202_probe(struct i2c_client *client) + return ret; + + for (int i = 0; i < ST1202_MAX_LEDS; i++) { ++ struct led_init_data init_data = {}; + led = &chip->leds[i]; + led->chip = chip; + led->led_num = i; +@@ -384,6 +374,15 @@ static int st1202_probe(struct i2c_client *client) + if (ret < 0) + return dev_err_probe(&client->dev, ret, + "Failed to clear LED pattern\n"); ++ ++ init_data.fwnode = led->fwnode; ++ init_data.devicename = "st1202"; ++ init_data.default_label = ":"; ++ ++ ret = devm_led_classdev_register_ext(&client->dev, &led->led_cdev, &init_data); ++ if (ret < 0) ++ return dev_err_probe(&client->dev, ret, ++ "Failed to register LED class device\n"); + } + + return 0; +-- +2.51.0 + + +From 563309444342b92bf2a677a057a3ed0753c5a2d6 Mon Sep 17 00:00:00 2001 +From: Oskari Lemmela +Date: Sat, 13 Jul 2024 18:56:59 +0300 +Subject: [PATCH 329/517] net: ag71xx: fix qca9530 and qca9550 mdio probe + +Newer QCA9530 and QCA9550 devices should use same div table as AR933X. + +Fixes: d51b6ce441d3 ("net: ethernet: add ag71xx driver") +Signed-off-by: Oskari Lemmela +--- + drivers/net/ethernet/atheros/ag71xx.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/atheros/ag71xx.c b/drivers/net/ethernet/atheros/ag71xx.c +index bccc7e7b2a84..adac0a9e0ceb 100644 +--- a/drivers/net/ethernet/atheros/ag71xx.c ++++ b/drivers/net/ethernet/atheros/ag71xx.c +@@ -641,7 +641,8 @@ static int ag71xx_mdio_get_divider(struct ag71xx *ag, u32 *div) + if (!ref_clock) + return -EINVAL; + +- if (ag71xx_is(ag, AR9330) || ag71xx_is(ag, AR9340)) { ++ if (ag71xx_is(ag, AR9330) || ag71xx_is(ag, AR9340) || ++ ag71xx_is(ag, QCA9530) || ag71xx_is(ag, QCA9550)) { + table = ar933x_mdio_div_table; + ndivs = ARRAY_SIZE(ar933x_mdio_div_table); + } else if (ag71xx_is(ag, AR7240)) { +-- +2.51.0 + + +From d35ab9470d3d007cfbae608b5c50dabc29299843 Mon Sep 17 00:00:00 2001 +From: Imre Kaloz +Date: Mon, 3 Nov 2025 15:50:14 +0100 +Subject: [PATCH 330/517] init: add CONFIG_MANGLE_BOOTARGS and disable it by + default + +Enabling this option renames the bootloader supplied root= +and rootfstype= variables, which might have to be know but +would break the automatisms OpenWrt uses. + +Signed-off-by: Imre Kaloz +--- + init/Kconfig | 9 +++++++++ + init/main.c | 24 ++++++++++++++++++++++++ + 2 files changed, 33 insertions(+) + +diff --git a/init/Kconfig b/init/Kconfig +index 9b04e413be82..0de264f33b49 100644 +--- a/init/Kconfig ++++ b/init/Kconfig +@@ -1888,6 +1888,15 @@ config ARCH_HAS_MEMBARRIER_CALLBACKS + config ARCH_HAS_MEMBARRIER_SYNC_CORE + bool + ++config MANGLE_BOOTARGS ++ bool "Rename offending bootargs" ++ depends on EXPERT ++ help ++ Sometimes the bootloader passed bogus root= and rootfstype= ++ parameters to the kernel, and while you want to ignore them, ++ you need to know the values f.e. to support dual firmware ++ layouts on the flash. ++ + config HAVE_PERF_EVENTS + bool + help +diff --git a/init/main.c b/init/main.c +index 821df1f05e9c..13fdc3236647 100644 +--- a/init/main.c ++++ b/init/main.c +@@ -633,6 +633,29 @@ static inline void setup_nr_cpu_ids(void) { } + static inline void smp_prepare_cpus(unsigned int maxcpus) { } + #endif + ++#ifdef CONFIG_MANGLE_BOOTARGS ++static void __init mangle_bootargs(char *command_line) ++{ ++ char *rootdev; ++ char *rootfs; ++ ++ rootdev = strstr(command_line, "root=/dev/mtdblock"); ++ ++ if (rootdev) ++ strncpy(rootdev, "mangled_rootblock=", 18); ++ ++ rootfs = strstr(command_line, "rootfstype"); ++ ++ if (rootfs) ++ strncpy(rootfs, "mangled_fs", 10); ++ ++} ++#else ++static void __init mangle_bootargs(char *command_line) ++{ ++} ++#endif ++ + /* + * We need to store the untouched command line for future reference. + * We also need to store the touched command line since the parameter +@@ -939,6 +962,7 @@ void start_kernel(void) + jump_label_init(); + static_call_init(); + early_security_init(); ++ mangle_bootargs(command_line); + setup_boot_config(); + setup_command_line(command_line); + setup_nr_cpu_ids(); +-- +2.51.0 + + +From 8ffc66f125f867d5a7b40ab3b1e0735ec30b7e2f Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Tue, 7 May 2024 12:22:15 +0200 +Subject: [PATCH 331/517] kernel: fix tools build breakage on macos with x86 + +Signed-off-by: Felix Fietkau +--- + tools/arch/x86/include/asm/insn.h | 2 +- + tools/arch/x86/include/asm/orc_types.h | 10 ++++++++++ + tools/arch/x86/lib/insn.c | 4 ++++ + tools/include/asm-generic/bitops/fls.h | 3 +++ + tools/include/linux/rbtree.h | 1 - + tools/include/linux/types.h | 1 + + tools/lib/string.c | 2 ++ + tools/lib/subcmd/exec-cmd.c | 3 +++ + tools/objtool/Makefile | 2 ++ + tools/objtool/include/objtool/objtool.h | 1 + + tools/scripts/Makefile.include | 10 ++++++---- + 11 files changed, 33 insertions(+), 6 deletions(-) + +diff --git a/tools/arch/x86/include/asm/insn.h b/tools/arch/x86/include/asm/insn.h +index 0e5abd896ad4..f65f0f2a5466 100644 +--- a/tools/arch/x86/include/asm/insn.h ++++ b/tools/arch/x86/include/asm/insn.h +@@ -7,7 +7,7 @@ + * Copyright (C) IBM Corporation, 2009 + */ + +-#include ++#include + /* insn_attr_t is defined in inat.h */ + #include "inat.h" /* __ignore_sync_check__ */ + +diff --git a/tools/arch/x86/include/asm/orc_types.h b/tools/arch/x86/include/asm/orc_types.h +index 46d7e06763c9..6e4afd2ec247 100644 +--- a/tools/arch/x86/include/asm/orc_types.h ++++ b/tools/arch/x86/include/asm/orc_types.h +@@ -46,7 +46,17 @@ + #define ORC_TYPE_REGS_PARTIAL 4 + + #ifndef __ASSEMBLY__ ++#ifdef __APPLE__ ++#include ++ ++#if __BYTE_ORDER == __LITTLE_ENDIAN ++#define __LITTLE_ENDIAN_BITFIELD ++#elif __BYTE_ORDER == __BIG_ENDIAN ++#define __BIG_ENDIAN_BITFIELD ++#endif ++#else + #include ++#endif + + /* + * This struct is more or less a vastly simplified version of the DWARF Call +diff --git a/tools/arch/x86/lib/insn.c b/tools/arch/x86/lib/insn.c +index e91d4c4e1c16..613539c3b015 100644 +--- a/tools/arch/x86/lib/insn.c ++++ b/tools/arch/x86/lib/insn.c +@@ -15,7 +15,11 @@ + #include "../include/asm/insn.h" /* __ignore_sync_check__ */ + #include /* __ignore_sync_check__ */ + ++#ifdef __KERNEL__ + #include ++#else ++#include ++#endif + #include + + #include "../include/asm/emulate_prefix.h" /* __ignore_sync_check__ */ +diff --git a/tools/include/asm-generic/bitops/fls.h b/tools/include/asm-generic/bitops/fls.h +index 26f3ce1dd6e4..d028c2eab89b 100644 +--- a/tools/include/asm-generic/bitops/fls.h ++++ b/tools/include/asm-generic/bitops/fls.h +@@ -2,6 +2,8 @@ + #ifndef _ASM_GENERIC_BITOPS_FLS_H_ + #define _ASM_GENERIC_BITOPS_FLS_H_ + ++#include ++ + /** + * generic_fls - find last (most-significant) bit set + * @x: the word to search +@@ -10,6 +12,7 @@ + * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32. + */ + ++#define generic_fls __linux_fls + static __always_inline int generic_fls(unsigned int x) + { + int r = 32; +diff --git a/tools/include/linux/rbtree.h b/tools/include/linux/rbtree.h +index 2680f2edb837..656890130ffd 100644 +--- a/tools/include/linux/rbtree.h ++++ b/tools/include/linux/rbtree.h +@@ -18,7 +18,6 @@ + #define __TOOLS_LINUX_PERF_RBTREE_H + + #include +-#include + + struct rb_node { + unsigned long __rb_parent_color; +diff --git a/tools/include/linux/types.h b/tools/include/linux/types.h +index 8519386acd23..be6804eb9f82 100644 +--- a/tools/include/linux/types.h ++++ b/tools/include/linux/types.h +@@ -56,6 +56,7 @@ typedef __s8 s8; + #define __user + #endif + #define __must_check ++#undef __cold + #define __cold + + typedef __u16 __bitwise __le16; +diff --git a/tools/lib/string.c b/tools/lib/string.c +index 3126d2cff716..5016d4ccae24 100644 +--- a/tools/lib/string.c ++++ b/tools/lib/string.c +@@ -96,6 +96,7 @@ int strtobool(const char *s, bool *res) + * If libc has strlcpy() then that version will override this + * implementation: + */ ++#ifndef __APPLE__ + #ifdef __clang__ + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wignored-attributes" +@@ -114,6 +115,7 @@ size_t __weak strlcpy(char *dest, const char *src, size_t size) + #ifdef __clang__ + #pragma clang diagnostic pop + #endif ++#endif + + /** + * skip_spaces - Removes leading whitespace from @str. +diff --git a/tools/lib/subcmd/exec-cmd.c b/tools/lib/subcmd/exec-cmd.c +index 7739b5217cf6..dc82cacd82cb 100644 +--- a/tools/lib/subcmd/exec-cmd.c ++++ b/tools/lib/subcmd/exec-cmd.c +@@ -12,7 +12,10 @@ + #include "subcmd-config.h" + + #define MAX_ARGS 32 ++ ++#ifndef PATH_MAX + #define PATH_MAX 4096 ++#endif + + static const char *argv_exec_path; + static const char *argv0_path; +diff --git a/tools/objtool/Makefile b/tools/objtool/Makefile +index bf7f7f84ac62..aa6deced92d2 100644 +--- a/tools/objtool/Makefile ++++ b/tools/objtool/Makefile +@@ -39,6 +39,8 @@ OBJTOOL_LDFLAGS := $(LIBELF_LIBS) $(LIBSUBCMD) $(KBUILD_HOSTLDFLAGS) + elfshdr := $(shell echo '$(pound)include ' | $(HOSTCC) $(OBJTOOL_CFLAGS) -x c -E - | grep elf_getshdr) + OBJTOOL_CFLAGS += $(if $(elfshdr),,-DLIBELF_USE_DEPRECATED) + ++OBJTOOL_CFLAGS += $(HOST_EXTRACFLAGS) ++ + # Always want host compilation. + HOST_OVERRIDES := CC="$(HOSTCC)" LD="$(HOSTLD)" AR="$(HOSTAR)" + +diff --git a/tools/objtool/include/objtool/objtool.h b/tools/objtool/include/objtool/objtool.h +index 94a33ee7b363..f34332e00155 100644 +--- a/tools/objtool/include/objtool/objtool.h ++++ b/tools/objtool/include/objtool/objtool.h +@@ -12,6 +12,7 @@ + + #include + ++#undef __weak + #define __weak __attribute__((weak)) + + struct pv_state { +diff --git a/tools/scripts/Makefile.include b/tools/scripts/Makefile.include +index 5f2afd95de43..dd3369624bdb 100644 +--- a/tools/scripts/Makefile.include ++++ b/tools/scripts/Makefile.include +@@ -72,8 +72,6 @@ $(call allow-override,CXX,$(CROSS_COMPILE)g++) + $(call allow-override,STRIP,$(CROSS_COMPILE)strip) + endif + +-CC_NO_CLANG := $(shell $(CC) -dM -E -x c /dev/null | grep -Fq "__clang__"; echo $$?) +- + ifneq ($(LLVM),) + HOSTAR ?= $(LLVM_PREFIX)llvm-ar$(LLVM_SUFFIX) + HOSTCC ?= $(LLVM_PREFIX)clang$(LLVM_SUFFIX) +@@ -84,6 +82,9 @@ HOSTCC ?= gcc + HOSTLD ?= ld + endif + ++CC_NO_CLANG := $(shell $(CC) -dM -E -x c /dev/null | grep -Fq "__clang__"; echo $$?) ++HOSTCC_NO_CLANG := $(shell $(HOSTCC) -dM -E -x c /dev/null | grep -Fq "__clang__"; echo $$?) ++ + # Some tools require Clang, LLC and/or LLVM utils + CLANG ?= clang + LLC ?= llc +@@ -92,8 +93,9 @@ LLVM_OBJCOPY ?= llvm-objcopy + LLVM_STRIP ?= llvm-strip + + ifeq ($(CC_NO_CLANG), 1) +-EXTRA_WARNINGS += -Wstrict-aliasing=3 +- ++ ifeq ($(HOSTCC_NO_CLANG), 1) ++ EXTRA_WARNINGS += -Wstrict-aliasing=3 ++ endif + else ifneq ($(CROSS_COMPILE),) + # Allow userspace to override CLANG_CROSS_FLAGS to specify their own + # sysroots and flags or to avoid the GCC call in pure Clang builds. +-- +2.51.0 + + +From c9d439a6002e088e00dda40c83df1e5fcd956ae4 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Fri, 7 Jul 2017 16:56:48 +0200 +Subject: [PATCH 332/517] build: add a hack for removing non-essential module + info + +Signed-off-by: Felix Fietkau +--- + include/linux/module.h | 13 ++++++++----- + include/linux/moduleparam.h | 12 +++++++++++- + kernel/module/Kconfig | 7 +++++++ + kernel/module/main.c | 7 ++++++- + scripts/mod/modpost.c | 10 ++++++++++ + 5 files changed, 42 insertions(+), 7 deletions(-) + +diff --git a/include/linux/module.h b/include/linux/module.h +index 7886217c9988..22566f9aa0ee 100644 +--- a/include/linux/module.h ++++ b/include/linux/module.h +@@ -166,6 +166,7 @@ struct module_kobject *lookup_or_create_module_kobject(const char *name); + + /* Generic info of form tag = "info" */ + #define MODULE_INFO(tag, info) __MODULE_INFO(tag, tag, info) ++#define MODULE_INFO_STRIP(tag, info) __MODULE_INFO_STRIP(tag, tag, info) + + /* For userspace: you can also call me... */ + #define MODULE_ALIAS(_alias) MODULE_INFO(alias, _alias) +@@ -241,12 +242,12 @@ struct module_kobject *lookup_or_create_module_kobject(const char *name); + * Author(s), use "Name " or just "Name", for multiple + * authors use multiple MODULE_AUTHOR() statements/lines. + */ +-#define MODULE_AUTHOR(_author) MODULE_INFO(author, _author) ++#define MODULE_AUTHOR(_author) MODULE_INFO_STRIP(author, _author) + + /* What your module does. */ +-#define MODULE_DESCRIPTION(_description) MODULE_INFO(description, _description) ++#define MODULE_DESCRIPTION(_description) MODULE_INFO_STRIP(description, _description) + +-#ifdef MODULE ++#if defined(MODULE) && !defined(CONFIG_MODULE_STRIPPED) + /* Creates an alias so file2alias.c can find device table. */ + #define MODULE_DEVICE_TABLE(type, name) \ + extern typeof(name) __mod_##type##__##name##_device_table \ +@@ -273,7 +274,9 @@ extern typeof(name) __mod_##type##__##name##_device_table \ + */ + + #if defined(MODULE) || !defined(CONFIG_SYSFS) +-#define MODULE_VERSION(_version) MODULE_INFO(version, _version) ++#define MODULE_VERSION(_version) MODULE_INFO_STRIP(version, _version) ++#elif defined(CONFIG_MODULE_STRIPPED) ++#define MODULE_VERSION(_version) __MODULE_INFO_DISABLED(version) + #else + #define MODULE_VERSION(_version) \ + MODULE_INFO(version, _version); \ +@@ -296,7 +299,7 @@ extern typeof(name) __mod_##type##__##name##_device_table \ + /* Optional firmware file (or files) needed by the module + * format is simply firmware file name. Multiple firmware + * files require multiple MODULE_FIRMWARE() specifiers */ +-#define MODULE_FIRMWARE(_firmware) MODULE_INFO(firmware, _firmware) ++#define MODULE_FIRMWARE(_firmware) MODULE_INFO_STRIP(firmware, _firmware) + + #define MODULE_IMPORT_NS(ns) MODULE_INFO(import_ns, __stringify(ns)) + +diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h +index 110e9d09de24..198f715e7bcc 100644 +--- a/include/linux/moduleparam.h ++++ b/include/linux/moduleparam.h +@@ -20,6 +20,16 @@ + /* Chosen so that structs with an unsigned long line up. */ + #define MAX_PARAM_PREFIX_LEN (64 - sizeof(unsigned long)) + ++/* This struct is here for syntactic coherency, it is not used */ ++#define __MODULE_INFO_DISABLED(name) \ ++ struct __UNIQUE_ID(name) {} ++ ++#ifdef CONFIG_MODULE_STRIPPED ++#define __MODULE_INFO_STRIP(tag, name, info) __MODULE_INFO_DISABLED(name) ++#else ++#define __MODULE_INFO_STRIP(tag, name, info) __MODULE_INFO(tag, name, info) ++#endif ++ + #define __MODULE_INFO(tag, name, info) \ + static const char __UNIQUE_ID(name)[] \ + __used __section(".modinfo") __aligned(1) \ +@@ -31,7 +41,7 @@ + /* One for each parameter, describing how to use it. Some files do + multiple of these per line, so can't just use MODULE_INFO. */ + #define MODULE_PARM_DESC(_parm, desc) \ +- __MODULE_INFO(parm, _parm, #_parm ":" desc) ++ __MODULE_INFO_STRIP(parm, _parm, #_parm ":" desc) + + struct kernel_param; + +diff --git a/kernel/module/Kconfig b/kernel/module/Kconfig +index 0c746a150e34..ccc20082d0f0 100644 +--- a/kernel/module/Kconfig ++++ b/kernel/module/Kconfig +@@ -402,4 +402,11 @@ config MODULES_TREE_LOOKUP + def_bool y + depends on PERF_EVENTS || TRACING || CFI_CLANG + ++config MODULE_STRIPPED ++ bool "Reduce module size" ++ depends on MODULES ++ help ++ Remove module parameter descriptions, author info, version, aliases, ++ device tables, etc. ++ + endif # MODULES +diff --git a/kernel/module/main.c b/kernel/module/main.c +index 4511d0a4762a..2122fab827f1 100644 +--- a/kernel/module/main.c ++++ b/kernel/module/main.c +@@ -1001,6 +1001,7 @@ size_t modinfo_attrs_count = ARRAY_SIZE(modinfo_attrs); + + static const char vermagic[] = VERMAGIC_STRING; + ++#if defined(CONFIG_MODVERSIONS) || !defined(CONFIG_MODULE_STRIPPED) + int try_to_force_load(struct module *mod, const char *reason) + { + #ifdef CONFIG_MODULE_FORCE_LOAD +@@ -1012,6 +1013,7 @@ int try_to_force_load(struct module *mod, const char *reason) + return -ENOEXEC; + #endif + } ++#endif + + /* Parse tag=value strings from .modinfo section */ + char *module_next_tag_pair(char *string, unsigned long *secsize) +@@ -2095,9 +2097,11 @@ static void module_augment_kernel_taints(struct module *mod, struct load_info *i + + static int check_modinfo(struct module *mod, struct load_info *info, int flags) + { +- const char *modmagic = get_modinfo(info, "vermagic"); + int err; + ++#ifndef CONFIG_MODULE_STRIPPED ++ const char *modmagic = get_modinfo(info, "vermagic"); ++ + if (flags & MODULE_INIT_IGNORE_VERMAGIC) + modmagic = NULL; + +@@ -2111,6 +2115,7 @@ static int check_modinfo(struct module *mod, struct load_info *info, int flags) + info->name, modmagic, vermagic); + return -ENOEXEC; + } ++#endif + + err = check_modinfo_livepatch(mod, info); + if (err) +diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c +index 971eda0c6ba7..f90320fdea74 100644 +--- a/scripts/mod/modpost.c ++++ b/scripts/mod/modpost.c +@@ -1601,7 +1601,9 @@ static void read_symbols(const char *modname) + symname = remove_dot(info.strtab + sym->st_name); + + handle_symbol(mod, &info, sym, symname); ++#ifndef CONFIG_MODULE_STRIPPED + handle_moddevtable(mod, &info, sym, symname); ++#endif + } + + check_sec_ref(mod, &info); +@@ -1758,7 +1760,9 @@ static void add_header(struct buffer *b, struct module *mod) + buf_printf(b, "#include \n"); + buf_printf(b, "#include \n"); + buf_printf(b, "\n"); ++#ifndef CONFIG_MODULE_STRIPPED + buf_printf(b, "MODULE_INFO(name, KBUILD_MODNAME);\n"); ++#endif + buf_printf(b, "\n"); + buf_printf(b, "__visible struct module __this_module\n"); + buf_printf(b, "__section(\".gnu.linkonce.this_module\") = {\n"); +@@ -1772,11 +1776,13 @@ static void add_header(struct buffer *b, struct module *mod) + buf_printf(b, "\t.arch = MODULE_ARCH_INIT,\n"); + buf_printf(b, "};\n"); + ++#ifndef CONFIG_MODULE_STRIPPED + if (!external_module) + buf_printf(b, "\nMODULE_INFO(intree, \"Y\");\n"); + + if (strstarts(mod->name, "drivers/staging")) + buf_printf(b, "\nMODULE_INFO(staging, \"Y\");\n"); ++#endif + + if (strstarts(mod->name, "tools/testing")) + buf_printf(b, "\nMODULE_INFO(test, \"Y\");\n"); +@@ -1886,11 +1892,13 @@ static void add_depends(struct buffer *b, struct module *mod) + + static void add_srcversion(struct buffer *b, struct module *mod) + { ++#ifndef CONFIG_MODULE_STRIPPED + if (mod->srcversion[0]) { + buf_printf(b, "\n"); + buf_printf(b, "MODULE_INFO(srcversion, \"%s\");\n", + mod->srcversion); + } ++#endif + } + + static void write_buf(struct buffer *b, const char *fname) +@@ -1973,7 +1981,9 @@ static void write_mod_c_file(struct module *mod) + add_exported_symbols(&buf, mod); + add_versions(&buf, mod); + add_depends(&buf, mod); ++#ifndef CONFIG_MODULE_STRIPPED + add_moddevtable(&buf, mod); ++#endif + add_srcversion(&buf, mod); + + ret = snprintf(fname, sizeof(fname), "%s.mod.c", mod->name); +-- +2.51.0 + + +From b3b18ef0e01eaa79077ae5c4f669df7d62d59695 Mon Sep 17 00:00:00 2001 +From: David Bauer +Date: Fri, 11 Nov 2022 13:33:44 +0100 +Subject: [PATCH 333/517] kconfig: abort configuration on unset symbol + +When a target configuration has unset Kconfig symbols, the build will +fail when OpenWrt is compiled with V=s and stdin is connected to a tty. + +In case OpenWrt is compiled without either of these preconditions, the +build will succeed with the symbols in question being unset. + +Modify the kernel configuration in a way it fails on unset symbols +regardless of the aforementioned preconditions. + +Signed-off-by: David Bauer +--- + scripts/kconfig/conf.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c +index 3d7d454c54da..d260f1519722 100644 +--- a/scripts/kconfig/conf.c ++++ b/scripts/kconfig/conf.c +@@ -312,6 +312,9 @@ static int conf_askvalue(struct symbol *sym, const char *def) + } + /* fall through */ + default: ++ if (!tty_stdio && getenv("FAIL_ON_UNCONFIGURED")) { ++ exit(1); ++ } + fflush(stdout); + xfgets(line, sizeof(line), stdin); + break; +@@ -470,6 +473,9 @@ static void conf_choice(struct menu *menu) + } + /* fall through */ + case oldaskconfig: ++ if (!tty_stdio && getenv("FAIL_ON_UNCONFIGURED")) { ++ exit(1); ++ } + fflush(stdout); + xfgets(line, sizeof(line), stdin); + strip(line); +-- +2.51.0 + + +From e94565caa2778a2c0a56e359b47169cea8111d3f Mon Sep 17 00:00:00 2001 +From: Florian Fainelli +Date: Fri, 7 Jul 2017 17:00:49 +0200 +Subject: [PATCH 334/517] Add an OSX specific patch to make the kernel be + compiled + +lede-commit: 3fc2a24f0422b2f55f9ed43f116db3111f700526 +Signed-off-by: Florian Fainelli +--- + scripts/mod/elf.h | 3007 ++++++++++++++++++++++++++++++++++++ + scripts/mod/mk_elfconfig.c | 4 + + scripts/mod/modpost.h | 4 + + 3 files changed, 3015 insertions(+) + create mode 100644 scripts/mod/elf.h + +diff --git a/scripts/mod/elf.h b/scripts/mod/elf.h +new file mode 100644 +index 000000000000..036a176345eb +--- /dev/null ++++ b/scripts/mod/elf.h +@@ -0,0 +1,3007 @@ ++/* This file defines standard ELF types, structures, and macros. ++ Copyright (C) 1995-2012 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#ifndef _ELF_H ++#define _ELF_H 1 ++ ++/* Standard ELF types. */ ++ ++#include ++ ++/* Type for a 16-bit quantity. */ ++typedef uint16_t Elf32_Half; ++typedef uint16_t Elf64_Half; ++ ++/* Types for signed and unsigned 32-bit quantities. */ ++typedef uint32_t Elf32_Word; ++typedef int32_t Elf32_Sword; ++typedef uint32_t Elf64_Word; ++typedef int32_t Elf64_Sword; ++ ++/* Types for signed and unsigned 64-bit quantities. */ ++typedef uint64_t Elf32_Xword; ++typedef int64_t Elf32_Sxword; ++typedef uint64_t Elf64_Xword; ++typedef int64_t Elf64_Sxword; ++ ++/* Type of addresses. */ ++typedef uint32_t Elf32_Addr; ++typedef uint64_t Elf64_Addr; ++ ++/* Type of file offsets. */ ++typedef uint32_t Elf32_Off; ++typedef uint64_t Elf64_Off; ++ ++/* Type for section indices, which are 16-bit quantities. */ ++typedef uint16_t Elf32_Section; ++typedef uint16_t Elf64_Section; ++ ++/* Type for version symbol information. */ ++typedef Elf32_Half Elf32_Versym; ++typedef Elf64_Half Elf64_Versym; ++ ++ ++/* The ELF file header. This appears at the start of every ELF file. */ ++ ++#define EI_NIDENT (16) ++ ++typedef struct ++{ ++ unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ ++ Elf32_Half e_type; /* Object file type */ ++ Elf32_Half e_machine; /* Architecture */ ++ Elf32_Word e_version; /* Object file version */ ++ Elf32_Addr e_entry; /* Entry point virtual address */ ++ Elf32_Off e_phoff; /* Program header table file offset */ ++ Elf32_Off e_shoff; /* Section header table file offset */ ++ Elf32_Word e_flags; /* Processor-specific flags */ ++ Elf32_Half e_ehsize; /* ELF header size in bytes */ ++ Elf32_Half e_phentsize; /* Program header table entry size */ ++ Elf32_Half e_phnum; /* Program header table entry count */ ++ Elf32_Half e_shentsize; /* Section header table entry size */ ++ Elf32_Half e_shnum; /* Section header table entry count */ ++ Elf32_Half e_shstrndx; /* Section header string table index */ ++} Elf32_Ehdr; ++ ++typedef struct ++{ ++ unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ ++ Elf64_Half e_type; /* Object file type */ ++ Elf64_Half e_machine; /* Architecture */ ++ Elf64_Word e_version; /* Object file version */ ++ Elf64_Addr e_entry; /* Entry point virtual address */ ++ Elf64_Off e_phoff; /* Program header table file offset */ ++ Elf64_Off e_shoff; /* Section header table file offset */ ++ Elf64_Word e_flags; /* Processor-specific flags */ ++ Elf64_Half e_ehsize; /* ELF header size in bytes */ ++ Elf64_Half e_phentsize; /* Program header table entry size */ ++ Elf64_Half e_phnum; /* Program header table entry count */ ++ Elf64_Half e_shentsize; /* Section header table entry size */ ++ Elf64_Half e_shnum; /* Section header table entry count */ ++ Elf64_Half e_shstrndx; /* Section header string table index */ ++} Elf64_Ehdr; ++ ++/* Fields in the e_ident array. The EI_* macros are indices into the ++ array. The macros under each EI_* macro are the values the byte ++ may have. */ ++ ++#define EI_MAG0 0 /* File identification byte 0 index */ ++#define ELFMAG0 0x7f /* Magic number byte 0 */ ++ ++#define EI_MAG1 1 /* File identification byte 1 index */ ++#define ELFMAG1 'E' /* Magic number byte 1 */ ++ ++#define EI_MAG2 2 /* File identification byte 2 index */ ++#define ELFMAG2 'L' /* Magic number byte 2 */ ++ ++#define EI_MAG3 3 /* File identification byte 3 index */ ++#define ELFMAG3 'F' /* Magic number byte 3 */ ++ ++/* Conglomeration of the identification bytes, for easy testing as a word. */ ++#define ELFMAG "\177ELF" ++#define SELFMAG 4 ++ ++#define EI_CLASS 4 /* File class byte index */ ++#define ELFCLASSNONE 0 /* Invalid class */ ++#define ELFCLASS32 1 /* 32-bit objects */ ++#define ELFCLASS64 2 /* 64-bit objects */ ++#define ELFCLASSNUM 3 ++ ++#define EI_DATA 5 /* Data encoding byte index */ ++#define ELFDATANONE 0 /* Invalid data encoding */ ++#define ELFDATA2LSB 1 /* 2's complement, little endian */ ++#define ELFDATA2MSB 2 /* 2's complement, big endian */ ++#define ELFDATANUM 3 ++ ++#define EI_VERSION 6 /* File version byte index */ ++ /* Value must be EV_CURRENT */ ++ ++#define EI_OSABI 7 /* OS ABI identification */ ++#define ELFOSABI_NONE 0 /* UNIX System V ABI */ ++#define ELFOSABI_SYSV 0 /* Alias. */ ++#define ELFOSABI_HPUX 1 /* HP-UX */ ++#define ELFOSABI_NETBSD 2 /* NetBSD. */ ++#define ELFOSABI_GNU 3 /* Object uses GNU ELF extensions. */ ++#define ELFOSABI_LINUX ELFOSABI_GNU /* Compatibility alias. */ ++#define ELFOSABI_SOLARIS 6 /* Sun Solaris. */ ++#define ELFOSABI_AIX 7 /* IBM AIX. */ ++#define ELFOSABI_IRIX 8 /* SGI Irix. */ ++#define ELFOSABI_FREEBSD 9 /* FreeBSD. */ ++#define ELFOSABI_TRU64 10 /* Compaq TRU64 UNIX. */ ++#define ELFOSABI_MODESTO 11 /* Novell Modesto. */ ++#define ELFOSABI_OPENBSD 12 /* OpenBSD. */ ++#define ELFOSABI_ARM_AEABI 64 /* ARM EABI */ ++#define ELFOSABI_ARM 97 /* ARM */ ++#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ ++ ++#define EI_ABIVERSION 8 /* ABI version */ ++ ++#define EI_PAD 9 /* Byte index of padding bytes */ ++ ++/* Legal values for e_type (object file type). */ ++ ++#define ET_NONE 0 /* No file type */ ++#define ET_REL 1 /* Relocatable file */ ++#define ET_EXEC 2 /* Executable file */ ++#define ET_DYN 3 /* Shared object file */ ++#define ET_CORE 4 /* Core file */ ++#define ET_NUM 5 /* Number of defined types */ ++#define ET_LOOS 0xfe00 /* OS-specific range start */ ++#define ET_HIOS 0xfeff /* OS-specific range end */ ++#define ET_LOPROC 0xff00 /* Processor-specific range start */ ++#define ET_HIPROC 0xffff /* Processor-specific range end */ ++ ++/* Legal values for e_machine (architecture). */ ++ ++#define EM_NONE 0 /* No machine */ ++#define EM_M32 1 /* AT&T WE 32100 */ ++#define EM_SPARC 2 /* SUN SPARC */ ++#define EM_386 3 /* Intel 80386 */ ++#define EM_68K 4 /* Motorola m68k family */ ++#define EM_88K 5 /* Motorola m88k family */ ++#define EM_860 7 /* Intel 80860 */ ++#define EM_MIPS 8 /* MIPS R3000 big-endian */ ++#define EM_S370 9 /* IBM System/370 */ ++#define EM_MIPS_RS3_LE 10 /* MIPS R3000 little-endian */ ++ ++#define EM_PARISC 15 /* HPPA */ ++#define EM_VPP500 17 /* Fujitsu VPP500 */ ++#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */ ++#define EM_960 19 /* Intel 80960 */ ++#define EM_PPC 20 /* PowerPC */ ++#define EM_PPC64 21 /* PowerPC 64-bit */ ++#define EM_S390 22 /* IBM S390 */ ++ ++#define EM_V800 36 /* NEC V800 series */ ++#define EM_FR20 37 /* Fujitsu FR20 */ ++#define EM_RH32 38 /* TRW RH-32 */ ++#define EM_RCE 39 /* Motorola RCE */ ++#define EM_ARM 40 /* ARM */ ++#define EM_FAKE_ALPHA 41 /* Digital Alpha */ ++#define EM_SH 42 /* Hitachi SH */ ++#define EM_SPARCV9 43 /* SPARC v9 64-bit */ ++#define EM_TRICORE 44 /* Siemens Tricore */ ++#define EM_ARC 45 /* Argonaut RISC Core */ ++#define EM_H8_300 46 /* Hitachi H8/300 */ ++#define EM_H8_300H 47 /* Hitachi H8/300H */ ++#define EM_H8S 48 /* Hitachi H8S */ ++#define EM_H8_500 49 /* Hitachi H8/500 */ ++#define EM_IA_64 50 /* Intel Merced */ ++#define EM_MIPS_X 51 /* Stanford MIPS-X */ ++#define EM_COLDFIRE 52 /* Motorola Coldfire */ ++#define EM_68HC12 53 /* Motorola M68HC12 */ ++#define EM_MMA 54 /* Fujitsu MMA Multimedia Accelerator*/ ++#define EM_PCP 55 /* Siemens PCP */ ++#define EM_NCPU 56 /* Sony nCPU embeeded RISC */ ++#define EM_NDR1 57 /* Denso NDR1 microprocessor */ ++#define EM_STARCORE 58 /* Motorola Start*Core processor */ ++#define EM_ME16 59 /* Toyota ME16 processor */ ++#define EM_ST100 60 /* STMicroelectronic ST100 processor */ ++#define EM_TINYJ 61 /* Advanced Logic Corp. Tinyj emb.fam*/ ++#define EM_X86_64 62 /* AMD x86-64 architecture */ ++#define EM_PDSP 63 /* Sony DSP Processor */ ++ ++#define EM_FX66 66 /* Siemens FX66 microcontroller */ ++#define EM_ST9PLUS 67 /* STMicroelectronics ST9+ 8/16 mc */ ++#define EM_ST7 68 /* STmicroelectronics ST7 8 bit mc */ ++#define EM_68HC16 69 /* Motorola MC68HC16 microcontroller */ ++#define EM_68HC11 70 /* Motorola MC68HC11 microcontroller */ ++#define EM_68HC08 71 /* Motorola MC68HC08 microcontroller */ ++#define EM_68HC05 72 /* Motorola MC68HC05 microcontroller */ ++#define EM_SVX 73 /* Silicon Graphics SVx */ ++#define EM_ST19 74 /* STMicroelectronics ST19 8 bit mc */ ++#define EM_VAX 75 /* Digital VAX */ ++#define EM_CRIS 76 /* Axis Communications 32-bit embedded processor */ ++#define EM_JAVELIN 77 /* Infineon Technologies 32-bit embedded processor */ ++#define EM_FIREPATH 78 /* Element 14 64-bit DSP Processor */ ++#define EM_ZSP 79 /* LSI Logic 16-bit DSP Processor */ ++#define EM_MMIX 80 /* Donald Knuth's educational 64-bit processor */ ++#define EM_HUANY 81 /* Harvard University machine-independent object files */ ++#define EM_PRISM 82 /* SiTera Prism */ ++#define EM_AVR 83 /* Atmel AVR 8-bit microcontroller */ ++#define EM_FR30 84 /* Fujitsu FR30 */ ++#define EM_D10V 85 /* Mitsubishi D10V */ ++#define EM_D30V 86 /* Mitsubishi D30V */ ++#define EM_V850 87 /* NEC v850 */ ++#define EM_M32R 88 /* Mitsubishi M32R */ ++#define EM_MN10300 89 /* Matsushita MN10300 */ ++#define EM_MN10200 90 /* Matsushita MN10200 */ ++#define EM_PJ 91 /* picoJava */ ++#define EM_OPENRISC 92 /* OpenRISC 32-bit embedded processor */ ++#define EM_ARC_A5 93 /* ARC Cores Tangent-A5 */ ++#define EM_XTENSA 94 /* Tensilica Xtensa Architecture */ ++#define EM_TILEPRO 188 /* Tilera TILEPro */ ++#define EM_TILEGX 191 /* Tilera TILE-Gx */ ++#define EM_NUM 192 ++ ++/* If it is necessary to assign new unofficial EM_* values, please ++ pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the ++ chances of collision with official or non-GNU unofficial values. */ ++ ++#define EM_ALPHA 0x9026 ++ ++/* Legal values for e_version (version). */ ++ ++#define EV_NONE 0 /* Invalid ELF version */ ++#define EV_CURRENT 1 /* Current version */ ++#define EV_NUM 2 ++ ++/* Section header. */ ++ ++typedef struct ++{ ++ Elf32_Word sh_name; /* Section name (string tbl index) */ ++ Elf32_Word sh_type; /* Section type */ ++ Elf32_Word sh_flags; /* Section flags */ ++ Elf32_Addr sh_addr; /* Section virtual addr at execution */ ++ Elf32_Off sh_offset; /* Section file offset */ ++ Elf32_Word sh_size; /* Section size in bytes */ ++ Elf32_Word sh_link; /* Link to another section */ ++ Elf32_Word sh_info; /* Additional section information */ ++ Elf32_Word sh_addralign; /* Section alignment */ ++ Elf32_Word sh_entsize; /* Entry size if section holds table */ ++} Elf32_Shdr; ++ ++typedef struct ++{ ++ Elf64_Word sh_name; /* Section name (string tbl index) */ ++ Elf64_Word sh_type; /* Section type */ ++ Elf64_Xword sh_flags; /* Section flags */ ++ Elf64_Addr sh_addr; /* Section virtual addr at execution */ ++ Elf64_Off sh_offset; /* Section file offset */ ++ Elf64_Xword sh_size; /* Section size in bytes */ ++ Elf64_Word sh_link; /* Link to another section */ ++ Elf64_Word sh_info; /* Additional section information */ ++ Elf64_Xword sh_addralign; /* Section alignment */ ++ Elf64_Xword sh_entsize; /* Entry size if section holds table */ ++} Elf64_Shdr; ++ ++/* Special section indices. */ ++ ++#define SHN_UNDEF 0 /* Undefined section */ ++#define SHN_LORESERVE 0xff00 /* Start of reserved indices */ ++#define SHN_LOPROC 0xff00 /* Start of processor-specific */ ++#define SHN_BEFORE 0xff00 /* Order section before all others ++ (Solaris). */ ++#define SHN_AFTER 0xff01 /* Order section after all others ++ (Solaris). */ ++#define SHN_HIPROC 0xff1f /* End of processor-specific */ ++#define SHN_LOOS 0xff20 /* Start of OS-specific */ ++#define SHN_HIOS 0xff3f /* End of OS-specific */ ++#define SHN_ABS 0xfff1 /* Associated symbol is absolute */ ++#define SHN_COMMON 0xfff2 /* Associated symbol is common */ ++#define SHN_XINDEX 0xffff /* Index is in extra table. */ ++#define SHN_HIRESERVE 0xffff /* End of reserved indices */ ++ ++/* Legal values for sh_type (section type). */ ++ ++#define SHT_NULL 0 /* Section header table entry unused */ ++#define SHT_PROGBITS 1 /* Program data */ ++#define SHT_SYMTAB 2 /* Symbol table */ ++#define SHT_STRTAB 3 /* String table */ ++#define SHT_RELA 4 /* Relocation entries with addends */ ++#define SHT_HASH 5 /* Symbol hash table */ ++#define SHT_DYNAMIC 6 /* Dynamic linking information */ ++#define SHT_NOTE 7 /* Notes */ ++#define SHT_NOBITS 8 /* Program space with no data (bss) */ ++#define SHT_REL 9 /* Relocation entries, no addends */ ++#define SHT_SHLIB 10 /* Reserved */ ++#define SHT_DYNSYM 11 /* Dynamic linker symbol table */ ++#define SHT_INIT_ARRAY 14 /* Array of constructors */ ++#define SHT_FINI_ARRAY 15 /* Array of destructors */ ++#define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */ ++#define SHT_GROUP 17 /* Section group */ ++#define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */ ++#define SHT_NUM 19 /* Number of defined types. */ ++#define SHT_LOOS 0x60000000 /* Start OS-specific. */ ++#define SHT_GNU_ATTRIBUTES 0x6ffffff5 /* Object attributes. */ ++#define SHT_GNU_HASH 0x6ffffff6 /* GNU-style hash table. */ ++#define SHT_GNU_LIBLIST 0x6ffffff7 /* Prelink library list */ ++#define SHT_CHECKSUM 0x6ffffff8 /* Checksum for DSO content. */ ++#define SHT_LOSUNW 0x6ffffffa /* Sun-specific low bound. */ ++#define SHT_SUNW_move 0x6ffffffa ++#define SHT_SUNW_COMDAT 0x6ffffffb ++#define SHT_SUNW_syminfo 0x6ffffffc ++#define SHT_GNU_verdef 0x6ffffffd /* Version definition section. */ ++#define SHT_GNU_verneed 0x6ffffffe /* Version needs section. */ ++#define SHT_GNU_versym 0x6fffffff /* Version symbol table. */ ++#define SHT_HISUNW 0x6fffffff /* Sun-specific high bound. */ ++#define SHT_HIOS 0x6fffffff /* End OS-specific type */ ++#define SHT_LOPROC 0x70000000 /* Start of processor-specific */ ++#define SHT_HIPROC 0x7fffffff /* End of processor-specific */ ++#define SHT_LOUSER 0x80000000 /* Start of application-specific */ ++#define SHT_HIUSER 0x8fffffff /* End of application-specific */ ++ ++/* Legal values for sh_flags (section flags). */ ++ ++#define SHF_WRITE (1 << 0) /* Writable */ ++#define SHF_ALLOC (1 << 1) /* Occupies memory during execution */ ++#define SHF_EXECINSTR (1 << 2) /* Executable */ ++#define SHF_MERGE (1 << 4) /* Might be merged */ ++#define SHF_STRINGS (1 << 5) /* Contains nul-terminated strings */ ++#define SHF_INFO_LINK (1 << 6) /* `sh_info' contains SHT index */ ++#define SHF_LINK_ORDER (1 << 7) /* Preserve order after combining */ ++#define SHF_OS_NONCONFORMING (1 << 8) /* Non-standard OS specific handling ++ required */ ++#define SHF_GROUP (1 << 9) /* Section is member of a group. */ ++#define SHF_TLS (1 << 10) /* Section hold thread-local data. */ ++#define SHF_MASKOS 0x0ff00000 /* OS-specific. */ ++#define SHF_MASKPROC 0xf0000000 /* Processor-specific */ ++#define SHF_ORDERED (1 << 30) /* Special ordering requirement ++ (Solaris). */ ++#define SHF_EXCLUDE (1 << 31) /* Section is excluded unless ++ referenced or allocated (Solaris).*/ ++ ++/* Section group handling. */ ++#define GRP_COMDAT 0x1 /* Mark group as COMDAT. */ ++ ++/* Symbol table entry. */ ++ ++typedef struct ++{ ++ Elf32_Word st_name; /* Symbol name (string tbl index) */ ++ Elf32_Addr st_value; /* Symbol value */ ++ Elf32_Word st_size; /* Symbol size */ ++ unsigned char st_info; /* Symbol type and binding */ ++ unsigned char st_other; /* Symbol visibility */ ++ Elf32_Section st_shndx; /* Section index */ ++} Elf32_Sym; ++ ++typedef struct ++{ ++ Elf64_Word st_name; /* Symbol name (string tbl index) */ ++ unsigned char st_info; /* Symbol type and binding */ ++ unsigned char st_other; /* Symbol visibility */ ++ Elf64_Section st_shndx; /* Section index */ ++ Elf64_Addr st_value; /* Symbol value */ ++ Elf64_Xword st_size; /* Symbol size */ ++} Elf64_Sym; ++ ++/* The syminfo section if available contains additional information about ++ every dynamic symbol. */ ++ ++typedef struct ++{ ++ Elf32_Half si_boundto; /* Direct bindings, symbol bound to */ ++ Elf32_Half si_flags; /* Per symbol flags */ ++} Elf32_Syminfo; ++ ++typedef struct ++{ ++ Elf64_Half si_boundto; /* Direct bindings, symbol bound to */ ++ Elf64_Half si_flags; /* Per symbol flags */ ++} Elf64_Syminfo; ++ ++/* Possible values for si_boundto. */ ++#define SYMINFO_BT_SELF 0xffff /* Symbol bound to self */ ++#define SYMINFO_BT_PARENT 0xfffe /* Symbol bound to parent */ ++#define SYMINFO_BT_LOWRESERVE 0xff00 /* Beginning of reserved entries */ ++ ++/* Possible bitmasks for si_flags. */ ++#define SYMINFO_FLG_DIRECT 0x0001 /* Direct bound symbol */ ++#define SYMINFO_FLG_PASSTHRU 0x0002 /* Pass-thru symbol for translator */ ++#define SYMINFO_FLG_COPY 0x0004 /* Symbol is a copy-reloc */ ++#define SYMINFO_FLG_LAZYLOAD 0x0008 /* Symbol bound to object to be lazy ++ loaded */ ++/* Syminfo version values. */ ++#define SYMINFO_NONE 0 ++#define SYMINFO_CURRENT 1 ++#define SYMINFO_NUM 2 ++ ++ ++/* How to extract and insert information held in the st_info field. */ ++ ++#define ELF32_ST_BIND(val) (((unsigned char) (val)) >> 4) ++#define ELF32_ST_TYPE(val) ((val) & 0xf) ++#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) ++ ++/* Both Elf32_Sym and Elf64_Sym use the same one-byte st_info field. */ ++#define ELF64_ST_BIND(val) ELF32_ST_BIND (val) ++#define ELF64_ST_TYPE(val) ELF32_ST_TYPE (val) ++#define ELF64_ST_INFO(bind, type) ELF32_ST_INFO ((bind), (type)) ++ ++/* Legal values for ST_BIND subfield of st_info (symbol binding). */ ++ ++#define STB_LOCAL 0 /* Local symbol */ ++#define STB_GLOBAL 1 /* Global symbol */ ++#define STB_WEAK 2 /* Weak symbol */ ++#define STB_NUM 3 /* Number of defined types. */ ++#define STB_LOOS 10 /* Start of OS-specific */ ++#define STB_GNU_UNIQUE 10 /* Unique symbol. */ ++#define STB_HIOS 12 /* End of OS-specific */ ++#define STB_LOPROC 13 /* Start of processor-specific */ ++#define STB_HIPROC 15 /* End of processor-specific */ ++ ++/* Legal values for ST_TYPE subfield of st_info (symbol type). */ ++ ++#define STT_NOTYPE 0 /* Symbol type is unspecified */ ++#define STT_OBJECT 1 /* Symbol is a data object */ ++#define STT_FUNC 2 /* Symbol is a code object */ ++#define STT_SECTION 3 /* Symbol associated with a section */ ++#define STT_FILE 4 /* Symbol's name is file name */ ++#define STT_COMMON 5 /* Symbol is a common data object */ ++#define STT_TLS 6 /* Symbol is thread-local data object*/ ++#define STT_NUM 7 /* Number of defined types. */ ++#define STT_LOOS 10 /* Start of OS-specific */ ++#define STT_GNU_IFUNC 10 /* Symbol is indirect code object */ ++#define STT_HIOS 12 /* End of OS-specific */ ++#define STT_LOPROC 13 /* Start of processor-specific */ ++#define STT_HIPROC 15 /* End of processor-specific */ ++ ++ ++/* Symbol table indices are found in the hash buckets and chain table ++ of a symbol hash table section. This special index value indicates ++ the end of a chain, meaning no further symbols are found in that bucket. */ ++ ++#define STN_UNDEF 0 /* End of a chain. */ ++ ++ ++/* How to extract and insert information held in the st_other field. */ ++ ++#define ELF32_ST_VISIBILITY(o) ((o) & 0x03) ++ ++/* For ELF64 the definitions are the same. */ ++#define ELF64_ST_VISIBILITY(o) ELF32_ST_VISIBILITY (o) ++ ++/* Symbol visibility specification encoded in the st_other field. */ ++#define STV_DEFAULT 0 /* Default symbol visibility rules */ ++#define STV_INTERNAL 1 /* Processor specific hidden class */ ++#define STV_HIDDEN 2 /* Sym unavailable in other modules */ ++#define STV_PROTECTED 3 /* Not preemptible, not exported */ ++ ++ ++/* Relocation table entry without addend (in section of type SHT_REL). */ ++ ++typedef struct ++{ ++ Elf32_Addr r_offset; /* Address */ ++ Elf32_Word r_info; /* Relocation type and symbol index */ ++} Elf32_Rel; ++ ++/* I have seen two different definitions of the Elf64_Rel and ++ Elf64_Rela structures, so we'll leave them out until Novell (or ++ whoever) gets their act together. */ ++/* The following, at least, is used on Sparc v9, MIPS, and Alpha. */ ++ ++typedef struct ++{ ++ Elf64_Addr r_offset; /* Address */ ++ Elf64_Xword r_info; /* Relocation type and symbol index */ ++} Elf64_Rel; ++ ++/* Relocation table entry with addend (in section of type SHT_RELA). */ ++ ++typedef struct ++{ ++ Elf32_Addr r_offset; /* Address */ ++ Elf32_Word r_info; /* Relocation type and symbol index */ ++ Elf32_Sword r_addend; /* Addend */ ++} Elf32_Rela; ++ ++typedef struct ++{ ++ Elf64_Addr r_offset; /* Address */ ++ Elf64_Xword r_info; /* Relocation type and symbol index */ ++ Elf64_Sxword r_addend; /* Addend */ ++} Elf64_Rela; ++ ++/* How to extract and insert information held in the r_info field. */ ++ ++#define ELF32_R_SYM(val) ((val) >> 8) ++#define ELF32_R_TYPE(val) ((val) & 0xff) ++#define ELF32_R_INFO(sym, type) (((sym) << 8) + ((type) & 0xff)) ++ ++#define ELF64_R_SYM(i) ((i) >> 32) ++#define ELF64_R_TYPE(i) ((i) & 0xffffffff) ++#define ELF64_R_INFO(sym,type) ((((Elf64_Xword) (sym)) << 32) + (type)) ++ ++/* Program segment header. */ ++ ++typedef struct ++{ ++ Elf32_Word p_type; /* Segment type */ ++ Elf32_Off p_offset; /* Segment file offset */ ++ Elf32_Addr p_vaddr; /* Segment virtual address */ ++ Elf32_Addr p_paddr; /* Segment physical address */ ++ Elf32_Word p_filesz; /* Segment size in file */ ++ Elf32_Word p_memsz; /* Segment size in memory */ ++ Elf32_Word p_flags; /* Segment flags */ ++ Elf32_Word p_align; /* Segment alignment */ ++} Elf32_Phdr; ++ ++typedef struct ++{ ++ Elf64_Word p_type; /* Segment type */ ++ Elf64_Word p_flags; /* Segment flags */ ++ Elf64_Off p_offset; /* Segment file offset */ ++ Elf64_Addr p_vaddr; /* Segment virtual address */ ++ Elf64_Addr p_paddr; /* Segment physical address */ ++ Elf64_Xword p_filesz; /* Segment size in file */ ++ Elf64_Xword p_memsz; /* Segment size in memory */ ++ Elf64_Xword p_align; /* Segment alignment */ ++} Elf64_Phdr; ++ ++/* Special value for e_phnum. This indicates that the real number of ++ program headers is too large to fit into e_phnum. Instead the real ++ value is in the field sh_info of section 0. */ ++ ++#define PN_XNUM 0xffff ++ ++/* Legal values for p_type (segment type). */ ++ ++#define PT_NULL 0 /* Program header table entry unused */ ++#define PT_LOAD 1 /* Loadable program segment */ ++#define PT_DYNAMIC 2 /* Dynamic linking information */ ++#define PT_INTERP 3 /* Program interpreter */ ++#define PT_NOTE 4 /* Auxiliary information */ ++#define PT_SHLIB 5 /* Reserved */ ++#define PT_PHDR 6 /* Entry for header table itself */ ++#define PT_TLS 7 /* Thread-local storage segment */ ++#define PT_NUM 8 /* Number of defined types */ ++#define PT_LOOS 0x60000000 /* Start of OS-specific */ ++#define PT_GNU_EH_FRAME 0x6474e550 /* GCC .eh_frame_hdr segment */ ++#define PT_GNU_STACK 0x6474e551 /* Indicates stack executability */ ++#define PT_GNU_RELRO 0x6474e552 /* Read-only after relocation */ ++#define PT_LOSUNW 0x6ffffffa ++#define PT_SUNWBSS 0x6ffffffa /* Sun Specific segment */ ++#define PT_SUNWSTACK 0x6ffffffb /* Stack segment */ ++#define PT_HISUNW 0x6fffffff ++#define PT_HIOS 0x6fffffff /* End of OS-specific */ ++#define PT_LOPROC 0x70000000 /* Start of processor-specific */ ++#define PT_HIPROC 0x7fffffff /* End of processor-specific */ ++ ++/* Legal values for p_flags (segment flags). */ ++ ++#define PF_X (1 << 0) /* Segment is executable */ ++#define PF_W (1 << 1) /* Segment is writable */ ++#define PF_R (1 << 2) /* Segment is readable */ ++#define PF_MASKOS 0x0ff00000 /* OS-specific */ ++#define PF_MASKPROC 0xf0000000 /* Processor-specific */ ++ ++/* Legal values for note segment descriptor types for core files. */ ++ ++#define NT_PRSTATUS 1 /* Contains copy of prstatus struct */ ++#define NT_FPREGSET 2 /* Contains copy of fpregset struct */ ++#define NT_PRPSINFO 3 /* Contains copy of prpsinfo struct */ ++#define NT_PRXREG 4 /* Contains copy of prxregset struct */ ++#define NT_TASKSTRUCT 4 /* Contains copy of task structure */ ++#define NT_PLATFORM 5 /* String from sysinfo(SI_PLATFORM) */ ++#define NT_AUXV 6 /* Contains copy of auxv array */ ++#define NT_GWINDOWS 7 /* Contains copy of gwindows struct */ ++#define NT_ASRS 8 /* Contains copy of asrset struct */ ++#define NT_PSTATUS 10 /* Contains copy of pstatus struct */ ++#define NT_PSINFO 13 /* Contains copy of psinfo struct */ ++#define NT_PRCRED 14 /* Contains copy of prcred struct */ ++#define NT_UTSNAME 15 /* Contains copy of utsname struct */ ++#define NT_LWPSTATUS 16 /* Contains copy of lwpstatus struct */ ++#define NT_LWPSINFO 17 /* Contains copy of lwpinfo struct */ ++#define NT_PRFPXREG 20 /* Contains copy of fprxregset struct */ ++#define NT_PRXFPREG 0x46e62b7f /* Contains copy of user_fxsr_struct */ ++#define NT_PPC_VMX 0x100 /* PowerPC Altivec/VMX registers */ ++#define NT_PPC_SPE 0x101 /* PowerPC SPE/EVR registers */ ++#define NT_PPC_VSX 0x102 /* PowerPC VSX registers */ ++#define NT_386_TLS 0x200 /* i386 TLS slots (struct user_desc) */ ++#define NT_386_IOPERM 0x201 /* x86 io permission bitmap (1=deny) */ ++#define NT_X86_XSTATE 0x202 /* x86 extended state using xsave */ ++ ++/* Legal values for the note segment descriptor types for object files. */ ++ ++#define NT_VERSION 1 /* Contains a version string. */ ++ ++ ++/* Dynamic section entry. */ ++ ++typedef struct ++{ ++ Elf32_Sword d_tag; /* Dynamic entry type */ ++ union ++ { ++ Elf32_Word d_val; /* Integer value */ ++ Elf32_Addr d_ptr; /* Address value */ ++ } d_un; ++} Elf32_Dyn; ++ ++typedef struct ++{ ++ Elf64_Sxword d_tag; /* Dynamic entry type */ ++ union ++ { ++ Elf64_Xword d_val; /* Integer value */ ++ Elf64_Addr d_ptr; /* Address value */ ++ } d_un; ++} Elf64_Dyn; ++ ++/* Legal values for d_tag (dynamic entry type). */ ++ ++#define DT_NULL 0 /* Marks end of dynamic section */ ++#define DT_NEEDED 1 /* Name of needed library */ ++#define DT_PLTRELSZ 2 /* Size in bytes of PLT relocs */ ++#define DT_PLTGOT 3 /* Processor defined value */ ++#define DT_HASH 4 /* Address of symbol hash table */ ++#define DT_STRTAB 5 /* Address of string table */ ++#define DT_SYMTAB 6 /* Address of symbol table */ ++#define DT_RELA 7 /* Address of Rela relocs */ ++#define DT_RELASZ 8 /* Total size of Rela relocs */ ++#define DT_RELAENT 9 /* Size of one Rela reloc */ ++#define DT_STRSZ 10 /* Size of string table */ ++#define DT_SYMENT 11 /* Size of one symbol table entry */ ++#define DT_INIT 12 /* Address of init function */ ++#define DT_FINI 13 /* Address of termination function */ ++#define DT_SONAME 14 /* Name of shared object */ ++#define DT_RPATH 15 /* Library search path (deprecated) */ ++#define DT_SYMBOLIC 16 /* Start symbol search here */ ++#define DT_REL 17 /* Address of Rel relocs */ ++#define DT_RELSZ 18 /* Total size of Rel relocs */ ++#define DT_RELENT 19 /* Size of one Rel reloc */ ++#define DT_PLTREL 20 /* Type of reloc in PLT */ ++#define DT_DEBUG 21 /* For debugging; unspecified */ ++#define DT_TEXTREL 22 /* Reloc might modify .text */ ++#define DT_JMPREL 23 /* Address of PLT relocs */ ++#define DT_BIND_NOW 24 /* Process relocations of object */ ++#define DT_INIT_ARRAY 25 /* Array with addresses of init fct */ ++#define DT_FINI_ARRAY 26 /* Array with addresses of fini fct */ ++#define DT_INIT_ARRAYSZ 27 /* Size in bytes of DT_INIT_ARRAY */ ++#define DT_FINI_ARRAYSZ 28 /* Size in bytes of DT_FINI_ARRAY */ ++#define DT_RUNPATH 29 /* Library search path */ ++#define DT_FLAGS 30 /* Flags for the object being loaded */ ++#define DT_ENCODING 32 /* Start of encoded range */ ++#define DT_PREINIT_ARRAY 32 /* Array with addresses of preinit fct*/ ++#define DT_PREINIT_ARRAYSZ 33 /* size in bytes of DT_PREINIT_ARRAY */ ++#define DT_NUM 34 /* Number used */ ++#define DT_LOOS 0x6000000d /* Start of OS-specific */ ++#define DT_HIOS 0x6ffff000 /* End of OS-specific */ ++#define DT_LOPROC 0x70000000 /* Start of processor-specific */ ++#define DT_HIPROC 0x7fffffff /* End of processor-specific */ ++#define DT_PROCNUM DT_MIPS_NUM /* Most used by any processor */ ++ ++/* DT_* entries which fall between DT_VALRNGHI & DT_VALRNGLO use the ++ Dyn.d_un.d_val field of the Elf*_Dyn structure. This follows Sun's ++ approach. */ ++#define DT_VALRNGLO 0x6ffffd00 ++#define DT_GNU_PRELINKED 0x6ffffdf5 /* Prelinking timestamp */ ++#define DT_GNU_CONFLICTSZ 0x6ffffdf6 /* Size of conflict section */ ++#define DT_GNU_LIBLISTSZ 0x6ffffdf7 /* Size of library list */ ++#define DT_CHECKSUM 0x6ffffdf8 ++#define DT_PLTPADSZ 0x6ffffdf9 ++#define DT_MOVEENT 0x6ffffdfa ++#define DT_MOVESZ 0x6ffffdfb ++#define DT_FEATURE_1 0x6ffffdfc /* Feature selection (DTF_*). */ ++#define DT_POSFLAG_1 0x6ffffdfd /* Flags for DT_* entries, effecting ++ the following DT_* entry. */ ++#define DT_SYMINSZ 0x6ffffdfe /* Size of syminfo table (in bytes) */ ++#define DT_SYMINENT 0x6ffffdff /* Entry size of syminfo */ ++#define DT_VALRNGHI 0x6ffffdff ++#define DT_VALTAGIDX(tag) (DT_VALRNGHI - (tag)) /* Reverse order! */ ++#define DT_VALNUM 12 ++ ++/* DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the ++ Dyn.d_un.d_ptr field of the Elf*_Dyn structure. ++ ++ If any adjustment is made to the ELF object after it has been ++ built these entries will need to be adjusted. */ ++#define DT_ADDRRNGLO 0x6ffffe00 ++#define DT_GNU_HASH 0x6ffffef5 /* GNU-style hash table. */ ++#define DT_TLSDESC_PLT 0x6ffffef6 ++#define DT_TLSDESC_GOT 0x6ffffef7 ++#define DT_GNU_CONFLICT 0x6ffffef8 /* Start of conflict section */ ++#define DT_GNU_LIBLIST 0x6ffffef9 /* Library list */ ++#define DT_CONFIG 0x6ffffefa /* Configuration information. */ ++#define DT_DEPAUDIT 0x6ffffefb /* Dependency auditing. */ ++#define DT_AUDIT 0x6ffffefc /* Object auditing. */ ++#define DT_PLTPAD 0x6ffffefd /* PLT padding. */ ++#define DT_MOVETAB 0x6ffffefe /* Move table. */ ++#define DT_SYMINFO 0x6ffffeff /* Syminfo table. */ ++#define DT_ADDRRNGHI 0x6ffffeff ++#define DT_ADDRTAGIDX(tag) (DT_ADDRRNGHI - (tag)) /* Reverse order! */ ++#define DT_ADDRNUM 11 ++ ++/* The versioning entry types. The next are defined as part of the ++ GNU extension. */ ++#define DT_VERSYM 0x6ffffff0 ++ ++#define DT_RELACOUNT 0x6ffffff9 ++#define DT_RELCOUNT 0x6ffffffa ++ ++/* These were chosen by Sun. */ ++#define DT_FLAGS_1 0x6ffffffb /* State flags, see DF_1_* below. */ ++#define DT_VERDEF 0x6ffffffc /* Address of version definition ++ table */ ++#define DT_VERDEFNUM 0x6ffffffd /* Number of version definitions */ ++#define DT_VERNEED 0x6ffffffe /* Address of table with needed ++ versions */ ++#define DT_VERNEEDNUM 0x6fffffff /* Number of needed versions */ ++#define DT_VERSIONTAGIDX(tag) (DT_VERNEEDNUM - (tag)) /* Reverse order! */ ++#define DT_VERSIONTAGNUM 16 ++ ++/* Sun added these machine-independent extensions in the "processor-specific" ++ range. Be compatible. */ ++#define DT_AUXILIARY 0x7ffffffd /* Shared object to load before self */ ++#define DT_FILTER 0x7fffffff /* Shared object to get values from */ ++#define DT_EXTRATAGIDX(tag) ((Elf32_Word)-((Elf32_Sword) (tag) <<1>>1)-1) ++#define DT_EXTRANUM 3 ++ ++/* Values of `d_un.d_val' in the DT_FLAGS entry. */ ++#define DF_ORIGIN 0x00000001 /* Object may use DF_ORIGIN */ ++#define DF_SYMBOLIC 0x00000002 /* Symbol resolutions starts here */ ++#define DF_TEXTREL 0x00000004 /* Object contains text relocations */ ++#define DF_BIND_NOW 0x00000008 /* No lazy binding for this object */ ++#define DF_STATIC_TLS 0x00000010 /* Module uses the static TLS model */ ++ ++/* State flags selectable in the `d_un.d_val' element of the DT_FLAGS_1 ++ entry in the dynamic section. */ ++#define DF_1_NOW 0x00000001 /* Set RTLD_NOW for this object. */ ++#define DF_1_GLOBAL 0x00000002 /* Set RTLD_GLOBAL for this object. */ ++#define DF_1_GROUP 0x00000004 /* Set RTLD_GROUP for this object. */ ++#define DF_1_NODELETE 0x00000008 /* Set RTLD_NODELETE for this object.*/ ++#define DF_1_LOADFLTR 0x00000010 /* Trigger filtee loading at runtime.*/ ++#define DF_1_INITFIRST 0x00000020 /* Set RTLD_INITFIRST for this object*/ ++#define DF_1_NOOPEN 0x00000040 /* Set RTLD_NOOPEN for this object. */ ++#define DF_1_ORIGIN 0x00000080 /* $ORIGIN must be handled. */ ++#define DF_1_DIRECT 0x00000100 /* Direct binding enabled. */ ++#define DF_1_TRANS 0x00000200 ++#define DF_1_INTERPOSE 0x00000400 /* Object is used to interpose. */ ++#define DF_1_NODEFLIB 0x00000800 /* Ignore default lib search path. */ ++#define DF_1_NODUMP 0x00001000 /* Object can't be dldump'ed. */ ++#define DF_1_CONFALT 0x00002000 /* Configuration alternative created.*/ ++#define DF_1_ENDFILTEE 0x00004000 /* Filtee terminates filters search. */ ++#define DF_1_DISPRELDNE 0x00008000 /* Disp reloc applied at build time. */ ++#define DF_1_DISPRELPND 0x00010000 /* Disp reloc applied at run-time. */ ++ ++/* Flags for the feature selection in DT_FEATURE_1. */ ++#define DTF_1_PARINIT 0x00000001 ++#define DTF_1_CONFEXP 0x00000002 ++ ++/* Flags in the DT_POSFLAG_1 entry effecting only the next DT_* entry. */ ++#define DF_P1_LAZYLOAD 0x00000001 /* Lazyload following object. */ ++#define DF_P1_GROUPPERM 0x00000002 /* Symbols from next object are not ++ generally available. */ ++ ++/* Version definition sections. */ ++ ++typedef struct ++{ ++ Elf32_Half vd_version; /* Version revision */ ++ Elf32_Half vd_flags; /* Version information */ ++ Elf32_Half vd_ndx; /* Version Index */ ++ Elf32_Half vd_cnt; /* Number of associated aux entries */ ++ Elf32_Word vd_hash; /* Version name hash value */ ++ Elf32_Word vd_aux; /* Offset in bytes to verdaux array */ ++ Elf32_Word vd_next; /* Offset in bytes to next verdef ++ entry */ ++} Elf32_Verdef; ++ ++typedef struct ++{ ++ Elf64_Half vd_version; /* Version revision */ ++ Elf64_Half vd_flags; /* Version information */ ++ Elf64_Half vd_ndx; /* Version Index */ ++ Elf64_Half vd_cnt; /* Number of associated aux entries */ ++ Elf64_Word vd_hash; /* Version name hash value */ ++ Elf64_Word vd_aux; /* Offset in bytes to verdaux array */ ++ Elf64_Word vd_next; /* Offset in bytes to next verdef ++ entry */ ++} Elf64_Verdef; ++ ++ ++/* Legal values for vd_version (version revision). */ ++#define VER_DEF_NONE 0 /* No version */ ++#define VER_DEF_CURRENT 1 /* Current version */ ++#define VER_DEF_NUM 2 /* Given version number */ ++ ++/* Legal values for vd_flags (version information flags). */ ++#define VER_FLG_BASE 0x1 /* Version definition of file itself */ ++#define VER_FLG_WEAK 0x2 /* Weak version identifier */ ++ ++/* Versym symbol index values. */ ++#define VER_NDX_LOCAL 0 /* Symbol is local. */ ++#define VER_NDX_GLOBAL 1 /* Symbol is global. */ ++#define VER_NDX_LORESERVE 0xff00 /* Beginning of reserved entries. */ ++#define VER_NDX_ELIMINATE 0xff01 /* Symbol is to be eliminated. */ ++ ++/* Auxialiary version information. */ ++ ++typedef struct ++{ ++ Elf32_Word vda_name; /* Version or dependency names */ ++ Elf32_Word vda_next; /* Offset in bytes to next verdaux ++ entry */ ++} Elf32_Verdaux; ++ ++typedef struct ++{ ++ Elf64_Word vda_name; /* Version or dependency names */ ++ Elf64_Word vda_next; /* Offset in bytes to next verdaux ++ entry */ ++} Elf64_Verdaux; ++ ++ ++/* Version dependency section. */ ++ ++typedef struct ++{ ++ Elf32_Half vn_version; /* Version of structure */ ++ Elf32_Half vn_cnt; /* Number of associated aux entries */ ++ Elf32_Word vn_file; /* Offset of filename for this ++ dependency */ ++ Elf32_Word vn_aux; /* Offset in bytes to vernaux array */ ++ Elf32_Word vn_next; /* Offset in bytes to next verneed ++ entry */ ++} Elf32_Verneed; ++ ++typedef struct ++{ ++ Elf64_Half vn_version; /* Version of structure */ ++ Elf64_Half vn_cnt; /* Number of associated aux entries */ ++ Elf64_Word vn_file; /* Offset of filename for this ++ dependency */ ++ Elf64_Word vn_aux; /* Offset in bytes to vernaux array */ ++ Elf64_Word vn_next; /* Offset in bytes to next verneed ++ entry */ ++} Elf64_Verneed; ++ ++ ++/* Legal values for vn_version (version revision). */ ++#define VER_NEED_NONE 0 /* No version */ ++#define VER_NEED_CURRENT 1 /* Current version */ ++#define VER_NEED_NUM 2 /* Given version number */ ++ ++/* Auxiliary needed version information. */ ++ ++typedef struct ++{ ++ Elf32_Word vna_hash; /* Hash value of dependency name */ ++ Elf32_Half vna_flags; /* Dependency specific information */ ++ Elf32_Half vna_other; /* Unused */ ++ Elf32_Word vna_name; /* Dependency name string offset */ ++ Elf32_Word vna_next; /* Offset in bytes to next vernaux ++ entry */ ++} Elf32_Vernaux; ++ ++typedef struct ++{ ++ Elf64_Word vna_hash; /* Hash value of dependency name */ ++ Elf64_Half vna_flags; /* Dependency specific information */ ++ Elf64_Half vna_other; /* Unused */ ++ Elf64_Word vna_name; /* Dependency name string offset */ ++ Elf64_Word vna_next; /* Offset in bytes to next vernaux ++ entry */ ++} Elf64_Vernaux; ++ ++ ++/* Legal values for vna_flags. */ ++#define VER_FLG_WEAK 0x2 /* Weak version identifier */ ++ ++ ++/* Auxiliary vector. */ ++ ++/* This vector is normally only used by the program interpreter. The ++ usual definition in an ABI supplement uses the name auxv_t. The ++ vector is not usually defined in a standard file, but it ++ can't hurt. We rename it to avoid conflicts. The sizes of these ++ types are an arrangement between the exec server and the program ++ interpreter, so we don't fully specify them here. */ ++ ++typedef struct ++{ ++ uint32_t a_type; /* Entry type */ ++ union ++ { ++ uint32_t a_val; /* Integer value */ ++ /* We use to have pointer elements added here. We cannot do that, ++ though, since it does not work when using 32-bit definitions ++ on 64-bit platforms and vice versa. */ ++ } a_un; ++} Elf32_auxv_t; ++ ++typedef struct ++{ ++ uint64_t a_type; /* Entry type */ ++ union ++ { ++ uint64_t a_val; /* Integer value */ ++ /* We use to have pointer elements added here. We cannot do that, ++ though, since it does not work when using 32-bit definitions ++ on 64-bit platforms and vice versa. */ ++ } a_un; ++} Elf64_auxv_t; ++ ++/* Legal values for a_type (entry type). */ ++ ++#define AT_NULL 0 /* End of vector */ ++#define AT_IGNORE 1 /* Entry should be ignored */ ++#define AT_EXECFD 2 /* File descriptor of program */ ++#define AT_PHDR 3 /* Program headers for program */ ++#define AT_PHENT 4 /* Size of program header entry */ ++#define AT_PHNUM 5 /* Number of program headers */ ++#define AT_PAGESZ 6 /* System page size */ ++#define AT_BASE 7 /* Base address of interpreter */ ++#define AT_FLAGS 8 /* Flags */ ++#define AT_ENTRY 9 /* Entry point of program */ ++#define AT_NOTELF 10 /* Program is not ELF */ ++#define AT_UID 11 /* Real uid */ ++#define AT_EUID 12 /* Effective uid */ ++#define AT_GID 13 /* Real gid */ ++#define AT_EGID 14 /* Effective gid */ ++#define AT_CLKTCK 17 /* Frequency of times() */ ++ ++/* Some more special a_type values describing the hardware. */ ++#define AT_PLATFORM 15 /* String identifying platform. */ ++#define AT_HWCAP 16 /* Machine dependent hints about ++ processor capabilities. */ ++ ++/* This entry gives some information about the FPU initialization ++ performed by the kernel. */ ++#define AT_FPUCW 18 /* Used FPU control word. */ ++ ++/* Cache block sizes. */ ++#define AT_DCACHEBSIZE 19 /* Data cache block size. */ ++#define AT_ICACHEBSIZE 20 /* Instruction cache block size. */ ++#define AT_UCACHEBSIZE 21 /* Unified cache block size. */ ++ ++/* A special ignored value for PPC, used by the kernel to control the ++ interpretation of the AUXV. Must be > 16. */ ++#define AT_IGNOREPPC 22 /* Entry should be ignored. */ ++ ++#define AT_SECURE 23 /* Boolean, was exec setuid-like? */ ++ ++#define AT_BASE_PLATFORM 24 /* String identifying real platforms.*/ ++ ++#define AT_RANDOM 25 /* Address of 16 random bytes. */ ++ ++#define AT_EXECFN 31 /* Filename of executable. */ ++ ++/* Pointer to the global system page used for system calls and other ++ nice things. */ ++#define AT_SYSINFO 32 ++#define AT_SYSINFO_EHDR 33 ++ ++/* Shapes of the caches. Bits 0-3 contains associativity; bits 4-7 contains ++ log2 of line size; mask those to get cache size. */ ++#define AT_L1I_CACHESHAPE 34 ++#define AT_L1D_CACHESHAPE 35 ++#define AT_L2_CACHESHAPE 36 ++#define AT_L3_CACHESHAPE 37 ++ ++/* Note section contents. Each entry in the note section begins with ++ a header of a fixed form. */ ++ ++typedef struct ++{ ++ Elf32_Word n_namesz; /* Length of the note's name. */ ++ Elf32_Word n_descsz; /* Length of the note's descriptor. */ ++ Elf32_Word n_type; /* Type of the note. */ ++} Elf32_Nhdr; ++ ++typedef struct ++{ ++ Elf64_Word n_namesz; /* Length of the note's name. */ ++ Elf64_Word n_descsz; /* Length of the note's descriptor. */ ++ Elf64_Word n_type; /* Type of the note. */ ++} Elf64_Nhdr; ++ ++/* Known names of notes. */ ++ ++/* Solaris entries in the note section have this name. */ ++#define ELF_NOTE_SOLARIS "SUNW Solaris" ++ ++/* Note entries for GNU systems have this name. */ ++#define ELF_NOTE_GNU "GNU" ++ ++ ++/* Defined types of notes for Solaris. */ ++ ++/* Value of descriptor (one word) is desired pagesize for the binary. */ ++#define ELF_NOTE_PAGESIZE_HINT 1 ++ ++ ++/* Defined note types for GNU systems. */ ++ ++/* ABI information. The descriptor consists of words: ++ word 0: OS descriptor ++ word 1: major version of the ABI ++ word 2: minor version of the ABI ++ word 3: subminor version of the ABI ++*/ ++#define NT_GNU_ABI_TAG 1 ++#define ELF_NOTE_ABI NT_GNU_ABI_TAG /* Old name. */ ++ ++/* Known OSes. These values can appear in word 0 of an ++ NT_GNU_ABI_TAG note section entry. */ ++#define ELF_NOTE_OS_LINUX 0 ++#define ELF_NOTE_OS_GNU 1 ++#define ELF_NOTE_OS_SOLARIS2 2 ++#define ELF_NOTE_OS_FREEBSD 3 ++ ++/* Synthetic hwcap information. The descriptor begins with two words: ++ word 0: number of entries ++ word 1: bitmask of enabled entries ++ Then follow variable-length entries, one byte followed by a ++ '\0'-terminated hwcap name string. The byte gives the bit ++ number to test if enabled, (1U << bit) & bitmask. */ ++#define NT_GNU_HWCAP 2 ++ ++/* Build ID bits as generated by ld --build-id. ++ The descriptor consists of any nonzero number of bytes. */ ++#define NT_GNU_BUILD_ID 3 ++ ++/* Version note generated by GNU gold containing a version string. */ ++#define NT_GNU_GOLD_VERSION 4 ++ ++ ++/* Move records. */ ++typedef struct ++{ ++ Elf32_Xword m_value; /* Symbol value. */ ++ Elf32_Word m_info; /* Size and index. */ ++ Elf32_Word m_poffset; /* Symbol offset. */ ++ Elf32_Half m_repeat; /* Repeat count. */ ++ Elf32_Half m_stride; /* Stride info. */ ++} Elf32_Move; ++ ++typedef struct ++{ ++ Elf64_Xword m_value; /* Symbol value. */ ++ Elf64_Xword m_info; /* Size and index. */ ++ Elf64_Xword m_poffset; /* Symbol offset. */ ++ Elf64_Half m_repeat; /* Repeat count. */ ++ Elf64_Half m_stride; /* Stride info. */ ++} Elf64_Move; ++ ++/* Macro to construct move records. */ ++#define ELF32_M_SYM(info) ((info) >> 8) ++#define ELF32_M_SIZE(info) ((unsigned char) (info)) ++#define ELF32_M_INFO(sym, size) (((sym) << 8) + (unsigned char) (size)) ++ ++#define ELF64_M_SYM(info) ELF32_M_SYM (info) ++#define ELF64_M_SIZE(info) ELF32_M_SIZE (info) ++#define ELF64_M_INFO(sym, size) ELF32_M_INFO (sym, size) ++ ++ ++/* Motorola 68k specific definitions. */ ++ ++/* Values for Elf32_Ehdr.e_flags. */ ++#define EF_CPU32 0x00810000 ++ ++/* m68k relocs. */ ++ ++#define R_68K_NONE 0 /* No reloc */ ++#define R_68K_32 1 /* Direct 32 bit */ ++#define R_68K_16 2 /* Direct 16 bit */ ++#define R_68K_8 3 /* Direct 8 bit */ ++#define R_68K_PC32 4 /* PC relative 32 bit */ ++#define R_68K_PC16 5 /* PC relative 16 bit */ ++#define R_68K_PC8 6 /* PC relative 8 bit */ ++#define R_68K_GOT32 7 /* 32 bit PC relative GOT entry */ ++#define R_68K_GOT16 8 /* 16 bit PC relative GOT entry */ ++#define R_68K_GOT8 9 /* 8 bit PC relative GOT entry */ ++#define R_68K_GOT32O 10 /* 32 bit GOT offset */ ++#define R_68K_GOT16O 11 /* 16 bit GOT offset */ ++#define R_68K_GOT8O 12 /* 8 bit GOT offset */ ++#define R_68K_PLT32 13 /* 32 bit PC relative PLT address */ ++#define R_68K_PLT16 14 /* 16 bit PC relative PLT address */ ++#define R_68K_PLT8 15 /* 8 bit PC relative PLT address */ ++#define R_68K_PLT32O 16 /* 32 bit PLT offset */ ++#define R_68K_PLT16O 17 /* 16 bit PLT offset */ ++#define R_68K_PLT8O 18 /* 8 bit PLT offset */ ++#define R_68K_COPY 19 /* Copy symbol at runtime */ ++#define R_68K_GLOB_DAT 20 /* Create GOT entry */ ++#define R_68K_JMP_SLOT 21 /* Create PLT entry */ ++#define R_68K_RELATIVE 22 /* Adjust by program base */ ++#define R_68K_TLS_GD32 25 /* 32 bit GOT offset for GD */ ++#define R_68K_TLS_GD16 26 /* 16 bit GOT offset for GD */ ++#define R_68K_TLS_GD8 27 /* 8 bit GOT offset for GD */ ++#define R_68K_TLS_LDM32 28 /* 32 bit GOT offset for LDM */ ++#define R_68K_TLS_LDM16 29 /* 16 bit GOT offset for LDM */ ++#define R_68K_TLS_LDM8 30 /* 8 bit GOT offset for LDM */ ++#define R_68K_TLS_LDO32 31 /* 32 bit module-relative offset */ ++#define R_68K_TLS_LDO16 32 /* 16 bit module-relative offset */ ++#define R_68K_TLS_LDO8 33 /* 8 bit module-relative offset */ ++#define R_68K_TLS_IE32 34 /* 32 bit GOT offset for IE */ ++#define R_68K_TLS_IE16 35 /* 16 bit GOT offset for IE */ ++#define R_68K_TLS_IE8 36 /* 8 bit GOT offset for IE */ ++#define R_68K_TLS_LE32 37 /* 32 bit offset relative to ++ static TLS block */ ++#define R_68K_TLS_LE16 38 /* 16 bit offset relative to ++ static TLS block */ ++#define R_68K_TLS_LE8 39 /* 8 bit offset relative to ++ static TLS block */ ++#define R_68K_TLS_DTPMOD32 40 /* 32 bit module number */ ++#define R_68K_TLS_DTPREL32 41 /* 32 bit module-relative offset */ ++#define R_68K_TLS_TPREL32 42 /* 32 bit TP-relative offset */ ++/* Keep this the last entry. */ ++#define R_68K_NUM 43 ++ ++/* Intel 80386 specific definitions. */ ++ ++/* i386 relocs. */ ++ ++#define R_386_NONE 0 /* No reloc */ ++#define R_386_32 1 /* Direct 32 bit */ ++#define R_386_PC32 2 /* PC relative 32 bit */ ++#define R_386_GOT32 3 /* 32 bit GOT entry */ ++#define R_386_PLT32 4 /* 32 bit PLT address */ ++#define R_386_COPY 5 /* Copy symbol at runtime */ ++#define R_386_GLOB_DAT 6 /* Create GOT entry */ ++#define R_386_JMP_SLOT 7 /* Create PLT entry */ ++#define R_386_RELATIVE 8 /* Adjust by program base */ ++#define R_386_GOTOFF 9 /* 32 bit offset to GOT */ ++#define R_386_GOTPC 10 /* 32 bit PC relative offset to GOT */ ++#define R_386_32PLT 11 ++#define R_386_TLS_TPOFF 14 /* Offset in static TLS block */ ++#define R_386_TLS_IE 15 /* Address of GOT entry for static TLS ++ block offset */ ++#define R_386_TLS_GOTIE 16 /* GOT entry for static TLS block ++ offset */ ++#define R_386_TLS_LE 17 /* Offset relative to static TLS ++ block */ ++#define R_386_TLS_GD 18 /* Direct 32 bit for GNU version of ++ general dynamic thread local data */ ++#define R_386_TLS_LDM 19 /* Direct 32 bit for GNU version of ++ local dynamic thread local data ++ in LE code */ ++#define R_386_16 20 ++#define R_386_PC16 21 ++#define R_386_8 22 ++#define R_386_PC8 23 ++#define R_386_TLS_GD_32 24 /* Direct 32 bit for general dynamic ++ thread local data */ ++#define R_386_TLS_GD_PUSH 25 /* Tag for pushl in GD TLS code */ ++#define R_386_TLS_GD_CALL 26 /* Relocation for call to ++ __tls_get_addr() */ ++#define R_386_TLS_GD_POP 27 /* Tag for popl in GD TLS code */ ++#define R_386_TLS_LDM_32 28 /* Direct 32 bit for local dynamic ++ thread local data in LE code */ ++#define R_386_TLS_LDM_PUSH 29 /* Tag for pushl in LDM TLS code */ ++#define R_386_TLS_LDM_CALL 30 /* Relocation for call to ++ __tls_get_addr() in LDM code */ ++#define R_386_TLS_LDM_POP 31 /* Tag for popl in LDM TLS code */ ++#define R_386_TLS_LDO_32 32 /* Offset relative to TLS block */ ++#define R_386_TLS_IE_32 33 /* GOT entry for negated static TLS ++ block offset */ ++#define R_386_TLS_LE_32 34 /* Negated offset relative to static ++ TLS block */ ++#define R_386_TLS_DTPMOD32 35 /* ID of module containing symbol */ ++#define R_386_TLS_DTPOFF32 36 /* Offset in TLS block */ ++#define R_386_TLS_TPOFF32 37 /* Negated offset in static TLS block */ ++/* 38? */ ++#define R_386_TLS_GOTDESC 39 /* GOT offset for TLS descriptor. */ ++#define R_386_TLS_DESC_CALL 40 /* Marker of call through TLS ++ descriptor for ++ relaxation. */ ++#define R_386_TLS_DESC 41 /* TLS descriptor containing ++ pointer to code and to ++ argument, returning the TLS ++ offset for the symbol. */ ++#define R_386_IRELATIVE 42 /* Adjust indirectly by program base */ ++/* Keep this the last entry. */ ++#define R_386_NUM 43 ++ ++/* SUN SPARC specific definitions. */ ++ ++/* Legal values for ST_TYPE subfield of st_info (symbol type). */ ++ ++#define STT_SPARC_REGISTER 13 /* Global register reserved to app. */ ++ ++/* Values for Elf64_Ehdr.e_flags. */ ++ ++#define EF_SPARCV9_MM 3 ++#define EF_SPARCV9_TSO 0 ++#define EF_SPARCV9_PSO 1 ++#define EF_SPARCV9_RMO 2 ++#define EF_SPARC_LEDATA 0x800000 /* little endian data */ ++#define EF_SPARC_EXT_MASK 0xFFFF00 ++#define EF_SPARC_32PLUS 0x000100 /* generic V8+ features */ ++#define EF_SPARC_SUN_US1 0x000200 /* Sun UltraSPARC1 extensions */ ++#define EF_SPARC_HAL_R1 0x000400 /* HAL R1 extensions */ ++#define EF_SPARC_SUN_US3 0x000800 /* Sun UltraSPARCIII extensions */ ++ ++/* SPARC relocs. */ ++ ++#define R_SPARC_NONE 0 /* No reloc */ ++#define R_SPARC_8 1 /* Direct 8 bit */ ++#define R_SPARC_16 2 /* Direct 16 bit */ ++#define R_SPARC_32 3 /* Direct 32 bit */ ++#define R_SPARC_DISP8 4 /* PC relative 8 bit */ ++#define R_SPARC_DISP16 5 /* PC relative 16 bit */ ++#define R_SPARC_DISP32 6 /* PC relative 32 bit */ ++#define R_SPARC_WDISP30 7 /* PC relative 30 bit shifted */ ++#define R_SPARC_WDISP22 8 /* PC relative 22 bit shifted */ ++#define R_SPARC_HI22 9 /* High 22 bit */ ++#define R_SPARC_22 10 /* Direct 22 bit */ ++#define R_SPARC_13 11 /* Direct 13 bit */ ++#define R_SPARC_LO10 12 /* Truncated 10 bit */ ++#define R_SPARC_GOT10 13 /* Truncated 10 bit GOT entry */ ++#define R_SPARC_GOT13 14 /* 13 bit GOT entry */ ++#define R_SPARC_GOT22 15 /* 22 bit GOT entry shifted */ ++#define R_SPARC_PC10 16 /* PC relative 10 bit truncated */ ++#define R_SPARC_PC22 17 /* PC relative 22 bit shifted */ ++#define R_SPARC_WPLT30 18 /* 30 bit PC relative PLT address */ ++#define R_SPARC_COPY 19 /* Copy symbol at runtime */ ++#define R_SPARC_GLOB_DAT 20 /* Create GOT entry */ ++#define R_SPARC_JMP_SLOT 21 /* Create PLT entry */ ++#define R_SPARC_RELATIVE 22 /* Adjust by program base */ ++#define R_SPARC_UA32 23 /* Direct 32 bit unaligned */ ++ ++/* Additional Sparc64 relocs. */ ++ ++#define R_SPARC_PLT32 24 /* Direct 32 bit ref to PLT entry */ ++#define R_SPARC_HIPLT22 25 /* High 22 bit PLT entry */ ++#define R_SPARC_LOPLT10 26 /* Truncated 10 bit PLT entry */ ++#define R_SPARC_PCPLT32 27 /* PC rel 32 bit ref to PLT entry */ ++#define R_SPARC_PCPLT22 28 /* PC rel high 22 bit PLT entry */ ++#define R_SPARC_PCPLT10 29 /* PC rel trunc 10 bit PLT entry */ ++#define R_SPARC_10 30 /* Direct 10 bit */ ++#define R_SPARC_11 31 /* Direct 11 bit */ ++#define R_SPARC_64 32 /* Direct 64 bit */ ++#define R_SPARC_OLO10 33 /* 10bit with secondary 13bit addend */ ++#define R_SPARC_HH22 34 /* Top 22 bits of direct 64 bit */ ++#define R_SPARC_HM10 35 /* High middle 10 bits of ... */ ++#define R_SPARC_LM22 36 /* Low middle 22 bits of ... */ ++#define R_SPARC_PC_HH22 37 /* Top 22 bits of pc rel 64 bit */ ++#define R_SPARC_PC_HM10 38 /* High middle 10 bit of ... */ ++#define R_SPARC_PC_LM22 39 /* Low miggle 22 bits of ... */ ++#define R_SPARC_WDISP16 40 /* PC relative 16 bit shifted */ ++#define R_SPARC_WDISP19 41 /* PC relative 19 bit shifted */ ++#define R_SPARC_GLOB_JMP 42 /* was part of v9 ABI but was removed */ ++#define R_SPARC_7 43 /* Direct 7 bit */ ++#define R_SPARC_5 44 /* Direct 5 bit */ ++#define R_SPARC_6 45 /* Direct 6 bit */ ++#define R_SPARC_DISP64 46 /* PC relative 64 bit */ ++#define R_SPARC_PLT64 47 /* Direct 64 bit ref to PLT entry */ ++#define R_SPARC_HIX22 48 /* High 22 bit complemented */ ++#define R_SPARC_LOX10 49 /* Truncated 11 bit complemented */ ++#define R_SPARC_H44 50 /* Direct high 12 of 44 bit */ ++#define R_SPARC_M44 51 /* Direct mid 22 of 44 bit */ ++#define R_SPARC_L44 52 /* Direct low 10 of 44 bit */ ++#define R_SPARC_REGISTER 53 /* Global register usage */ ++#define R_SPARC_UA64 54 /* Direct 64 bit unaligned */ ++#define R_SPARC_UA16 55 /* Direct 16 bit unaligned */ ++#define R_SPARC_TLS_GD_HI22 56 ++#define R_SPARC_TLS_GD_LO10 57 ++#define R_SPARC_TLS_GD_ADD 58 ++#define R_SPARC_TLS_GD_CALL 59 ++#define R_SPARC_TLS_LDM_HI22 60 ++#define R_SPARC_TLS_LDM_LO10 61 ++#define R_SPARC_TLS_LDM_ADD 62 ++#define R_SPARC_TLS_LDM_CALL 63 ++#define R_SPARC_TLS_LDO_HIX22 64 ++#define R_SPARC_TLS_LDO_LOX10 65 ++#define R_SPARC_TLS_LDO_ADD 66 ++#define R_SPARC_TLS_IE_HI22 67 ++#define R_SPARC_TLS_IE_LO10 68 ++#define R_SPARC_TLS_IE_LD 69 ++#define R_SPARC_TLS_IE_LDX 70 ++#define R_SPARC_TLS_IE_ADD 71 ++#define R_SPARC_TLS_LE_HIX22 72 ++#define R_SPARC_TLS_LE_LOX10 73 ++#define R_SPARC_TLS_DTPMOD32 74 ++#define R_SPARC_TLS_DTPMOD64 75 ++#define R_SPARC_TLS_DTPOFF32 76 ++#define R_SPARC_TLS_DTPOFF64 77 ++#define R_SPARC_TLS_TPOFF32 78 ++#define R_SPARC_TLS_TPOFF64 79 ++#define R_SPARC_GOTDATA_HIX22 80 ++#define R_SPARC_GOTDATA_LOX10 81 ++#define R_SPARC_GOTDATA_OP_HIX22 82 ++#define R_SPARC_GOTDATA_OP_LOX10 83 ++#define R_SPARC_GOTDATA_OP 84 ++#define R_SPARC_H34 85 ++#define R_SPARC_SIZE32 86 ++#define R_SPARC_SIZE64 87 ++#define R_SPARC_WDISP10 88 ++#define R_SPARC_JMP_IREL 248 ++#define R_SPARC_IRELATIVE 249 ++#define R_SPARC_GNU_VTINHERIT 250 ++#define R_SPARC_GNU_VTENTRY 251 ++#define R_SPARC_REV32 252 ++/* Keep this the last entry. */ ++#define R_SPARC_NUM 253 ++ ++/* For Sparc64, legal values for d_tag of Elf64_Dyn. */ ++ ++#define DT_SPARC_REGISTER 0x70000001 ++#define DT_SPARC_NUM 2 ++ ++/* MIPS R3000 specific definitions. */ ++ ++/* Legal values for e_flags field of Elf32_Ehdr. */ ++ ++#define EF_MIPS_NOREORDER 1 /* A .noreorder directive was used */ ++#define EF_MIPS_PIC 2 /* Contains PIC code */ ++#define EF_MIPS_CPIC 4 /* Uses PIC calling sequence */ ++#define EF_MIPS_XGOT 8 ++#define EF_MIPS_64BIT_WHIRL 16 ++#define EF_MIPS_ABI2 32 ++#define EF_MIPS_ABI_ON32 64 ++#define EF_MIPS_ARCH 0xf0000000 /* MIPS architecture level */ ++ ++/* Legal values for MIPS architecture level. */ ++ ++#define EF_MIPS_ARCH_1 0x00000000 /* -mips1 code. */ ++#define EF_MIPS_ARCH_2 0x10000000 /* -mips2 code. */ ++#define EF_MIPS_ARCH_3 0x20000000 /* -mips3 code. */ ++#define EF_MIPS_ARCH_4 0x30000000 /* -mips4 code. */ ++#define EF_MIPS_ARCH_5 0x40000000 /* -mips5 code. */ ++#define EF_MIPS_ARCH_32 0x60000000 /* MIPS32 code. */ ++#define EF_MIPS_ARCH_64 0x70000000 /* MIPS64 code. */ ++ ++/* The following are non-official names and should not be used. */ ++ ++#define E_MIPS_ARCH_1 0x00000000 /* -mips1 code. */ ++#define E_MIPS_ARCH_2 0x10000000 /* -mips2 code. */ ++#define E_MIPS_ARCH_3 0x20000000 /* -mips3 code. */ ++#define E_MIPS_ARCH_4 0x30000000 /* -mips4 code. */ ++#define E_MIPS_ARCH_5 0x40000000 /* -mips5 code. */ ++#define E_MIPS_ARCH_32 0x60000000 /* MIPS32 code. */ ++#define E_MIPS_ARCH_64 0x70000000 /* MIPS64 code. */ ++ ++/* Special section indices. */ ++ ++#define SHN_MIPS_ACOMMON 0xff00 /* Allocated common symbols */ ++#define SHN_MIPS_TEXT 0xff01 /* Allocated test symbols. */ ++#define SHN_MIPS_DATA 0xff02 /* Allocated data symbols. */ ++#define SHN_MIPS_SCOMMON 0xff03 /* Small common symbols */ ++#define SHN_MIPS_SUNDEFINED 0xff04 /* Small undefined symbols */ ++ ++/* Legal values for sh_type field of Elf32_Shdr. */ ++ ++#define SHT_MIPS_LIBLIST 0x70000000 /* Shared objects used in link */ ++#define SHT_MIPS_MSYM 0x70000001 ++#define SHT_MIPS_CONFLICT 0x70000002 /* Conflicting symbols */ ++#define SHT_MIPS_GPTAB 0x70000003 /* Global data area sizes */ ++#define SHT_MIPS_UCODE 0x70000004 /* Reserved for SGI/MIPS compilers */ ++#define SHT_MIPS_DEBUG 0x70000005 /* MIPS ECOFF debugging information*/ ++#define SHT_MIPS_REGINFO 0x70000006 /* Register usage information */ ++#define SHT_MIPS_PACKAGE 0x70000007 ++#define SHT_MIPS_PACKSYM 0x70000008 ++#define SHT_MIPS_RELD 0x70000009 ++#define SHT_MIPS_IFACE 0x7000000b ++#define SHT_MIPS_CONTENT 0x7000000c ++#define SHT_MIPS_OPTIONS 0x7000000d /* Miscellaneous options. */ ++#define SHT_MIPS_SHDR 0x70000010 ++#define SHT_MIPS_FDESC 0x70000011 ++#define SHT_MIPS_EXTSYM 0x70000012 ++#define SHT_MIPS_DENSE 0x70000013 ++#define SHT_MIPS_PDESC 0x70000014 ++#define SHT_MIPS_LOCSYM 0x70000015 ++#define SHT_MIPS_AUXSYM 0x70000016 ++#define SHT_MIPS_OPTSYM 0x70000017 ++#define SHT_MIPS_LOCSTR 0x70000018 ++#define SHT_MIPS_LINE 0x70000019 ++#define SHT_MIPS_RFDESC 0x7000001a ++#define SHT_MIPS_DELTASYM 0x7000001b ++#define SHT_MIPS_DELTAINST 0x7000001c ++#define SHT_MIPS_DELTACLASS 0x7000001d ++#define SHT_MIPS_DWARF 0x7000001e /* DWARF debugging information. */ ++#define SHT_MIPS_DELTADECL 0x7000001f ++#define SHT_MIPS_SYMBOL_LIB 0x70000020 ++#define SHT_MIPS_EVENTS 0x70000021 /* Event section. */ ++#define SHT_MIPS_TRANSLATE 0x70000022 ++#define SHT_MIPS_PIXIE 0x70000023 ++#define SHT_MIPS_XLATE 0x70000024 ++#define SHT_MIPS_XLATE_DEBUG 0x70000025 ++#define SHT_MIPS_WHIRL 0x70000026 ++#define SHT_MIPS_EH_REGION 0x70000027 ++#define SHT_MIPS_XLATE_OLD 0x70000028 ++#define SHT_MIPS_PDR_EXCEPTION 0x70000029 ++ ++/* Legal values for sh_flags field of Elf32_Shdr. */ ++ ++#define SHF_MIPS_GPREL 0x10000000 /* Must be part of global data area */ ++#define SHF_MIPS_MERGE 0x20000000 ++#define SHF_MIPS_ADDR 0x40000000 ++#define SHF_MIPS_STRINGS 0x80000000 ++#define SHF_MIPS_NOSTRIP 0x08000000 ++#define SHF_MIPS_LOCAL 0x04000000 ++#define SHF_MIPS_NAMES 0x02000000 ++#define SHF_MIPS_NODUPE 0x01000000 ++ ++ ++/* Symbol tables. */ ++ ++/* MIPS specific values for `st_other'. */ ++#define STO_MIPS_DEFAULT 0x0 ++#define STO_MIPS_INTERNAL 0x1 ++#define STO_MIPS_HIDDEN 0x2 ++#define STO_MIPS_PROTECTED 0x3 ++#define STO_MIPS_PLT 0x8 ++#define STO_MIPS_SC_ALIGN_UNUSED 0xff ++ ++/* MIPS specific values for `st_info'. */ ++#define STB_MIPS_SPLIT_COMMON 13 ++ ++/* Entries found in sections of type SHT_MIPS_GPTAB. */ ++ ++typedef union ++{ ++ struct ++ { ++ Elf32_Word gt_current_g_value; /* -G value used for compilation */ ++ Elf32_Word gt_unused; /* Not used */ ++ } gt_header; /* First entry in section */ ++ struct ++ { ++ Elf32_Word gt_g_value; /* If this value were used for -G */ ++ Elf32_Word gt_bytes; /* This many bytes would be used */ ++ } gt_entry; /* Subsequent entries in section */ ++} Elf32_gptab; ++ ++/* Entry found in sections of type SHT_MIPS_REGINFO. */ ++ ++typedef struct ++{ ++ Elf32_Word ri_gprmask; /* General registers used */ ++ Elf32_Word ri_cprmask[4]; /* Coprocessor registers used */ ++ Elf32_Sword ri_gp_value; /* $gp register value */ ++} Elf32_RegInfo; ++ ++/* Entries found in sections of type SHT_MIPS_OPTIONS. */ ++ ++typedef struct ++{ ++ unsigned char kind; /* Determines interpretation of the ++ variable part of descriptor. */ ++ unsigned char size; /* Size of descriptor, including header. */ ++ Elf32_Section section; /* Section header index of section affected, ++ 0 for global options. */ ++ Elf32_Word info; /* Kind-specific information. */ ++} Elf_Options; ++ ++/* Values for `kind' field in Elf_Options. */ ++ ++#define ODK_NULL 0 /* Undefined. */ ++#define ODK_REGINFO 1 /* Register usage information. */ ++#define ODK_EXCEPTIONS 2 /* Exception processing options. */ ++#define ODK_PAD 3 /* Section padding options. */ ++#define ODK_HWPATCH 4 /* Hardware workarounds performed */ ++#define ODK_FILL 5 /* record the fill value used by the linker. */ ++#define ODK_TAGS 6 /* reserve space for desktop tools to write. */ ++#define ODK_HWAND 7 /* HW workarounds. 'AND' bits when merging. */ ++#define ODK_HWOR 8 /* HW workarounds. 'OR' bits when merging. */ ++ ++/* Values for `info' in Elf_Options for ODK_EXCEPTIONS entries. */ ++ ++#define OEX_FPU_MIN 0x1f /* FPE's which MUST be enabled. */ ++#define OEX_FPU_MAX 0x1f00 /* FPE's which MAY be enabled. */ ++#define OEX_PAGE0 0x10000 /* page zero must be mapped. */ ++#define OEX_SMM 0x20000 /* Force sequential memory mode? */ ++#define OEX_FPDBUG 0x40000 /* Force floating point debug mode? */ ++#define OEX_PRECISEFP OEX_FPDBUG ++#define OEX_DISMISS 0x80000 /* Dismiss invalid address faults? */ ++ ++#define OEX_FPU_INVAL 0x10 ++#define OEX_FPU_DIV0 0x08 ++#define OEX_FPU_OFLO 0x04 ++#define OEX_FPU_UFLO 0x02 ++#define OEX_FPU_INEX 0x01 ++ ++/* Masks for `info' in Elf_Options for an ODK_HWPATCH entry. */ ++ ++#define OHW_R4KEOP 0x1 /* R4000 end-of-page patch. */ ++#define OHW_R8KPFETCH 0x2 /* may need R8000 prefetch patch. */ ++#define OHW_R5KEOP 0x4 /* R5000 end-of-page patch. */ ++#define OHW_R5KCVTL 0x8 /* R5000 cvt.[ds].l bug. clean=1. */ ++ ++#define OPAD_PREFIX 0x1 ++#define OPAD_POSTFIX 0x2 ++#define OPAD_SYMBOL 0x4 ++ ++/* Entry found in `.options' section. */ ++ ++typedef struct ++{ ++ Elf32_Word hwp_flags1; /* Extra flags. */ ++ Elf32_Word hwp_flags2; /* Extra flags. */ ++} Elf_Options_Hw; ++ ++/* Masks for `info' in ElfOptions for ODK_HWAND and ODK_HWOR entries. */ ++ ++#define OHWA0_R4KEOP_CHECKED 0x00000001 ++#define OHWA1_R4KEOP_CLEAN 0x00000002 ++ ++/* MIPS relocs. */ ++ ++#define R_MIPS_NONE 0 /* No reloc */ ++#define R_MIPS_16 1 /* Direct 16 bit */ ++#define R_MIPS_32 2 /* Direct 32 bit */ ++#define R_MIPS_REL32 3 /* PC relative 32 bit */ ++#define R_MIPS_26 4 /* Direct 26 bit shifted */ ++#define R_MIPS_HI16 5 /* High 16 bit */ ++#define R_MIPS_LO16 6 /* Low 16 bit */ ++#define R_MIPS_GPREL16 7 /* GP relative 16 bit */ ++#define R_MIPS_LITERAL 8 /* 16 bit literal entry */ ++#define R_MIPS_GOT16 9 /* 16 bit GOT entry */ ++#define R_MIPS_PC16 10 /* PC relative 16 bit */ ++#define R_MIPS_CALL16 11 /* 16 bit GOT entry for function */ ++#define R_MIPS_GPREL32 12 /* GP relative 32 bit */ ++ ++#define R_MIPS_SHIFT5 16 ++#define R_MIPS_SHIFT6 17 ++#define R_MIPS_64 18 ++#define R_MIPS_GOT_DISP 19 ++#define R_MIPS_GOT_PAGE 20 ++#define R_MIPS_GOT_OFST 21 ++#define R_MIPS_GOT_HI16 22 ++#define R_MIPS_GOT_LO16 23 ++#define R_MIPS_SUB 24 ++#define R_MIPS_INSERT_A 25 ++#define R_MIPS_INSERT_B 26 ++#define R_MIPS_DELETE 27 ++#define R_MIPS_HIGHER 28 ++#define R_MIPS_HIGHEST 29 ++#define R_MIPS_CALL_HI16 30 ++#define R_MIPS_CALL_LO16 31 ++#define R_MIPS_SCN_DISP 32 ++#define R_MIPS_REL16 33 ++#define R_MIPS_ADD_IMMEDIATE 34 ++#define R_MIPS_PJUMP 35 ++#define R_MIPS_RELGOT 36 ++#define R_MIPS_JALR 37 ++#define R_MIPS_TLS_DTPMOD32 38 /* Module number 32 bit */ ++#define R_MIPS_TLS_DTPREL32 39 /* Module-relative offset 32 bit */ ++#define R_MIPS_TLS_DTPMOD64 40 /* Module number 64 bit */ ++#define R_MIPS_TLS_DTPREL64 41 /* Module-relative offset 64 bit */ ++#define R_MIPS_TLS_GD 42 /* 16 bit GOT offset for GD */ ++#define R_MIPS_TLS_LDM 43 /* 16 bit GOT offset for LDM */ ++#define R_MIPS_TLS_DTPREL_HI16 44 /* Module-relative offset, high 16 bits */ ++#define R_MIPS_TLS_DTPREL_LO16 45 /* Module-relative offset, low 16 bits */ ++#define R_MIPS_TLS_GOTTPREL 46 /* 16 bit GOT offset for IE */ ++#define R_MIPS_TLS_TPREL32 47 /* TP-relative offset, 32 bit */ ++#define R_MIPS_TLS_TPREL64 48 /* TP-relative offset, 64 bit */ ++#define R_MIPS_TLS_TPREL_HI16 49 /* TP-relative offset, high 16 bits */ ++#define R_MIPS_TLS_TPREL_LO16 50 /* TP-relative offset, low 16 bits */ ++#define R_MIPS_GLOB_DAT 51 ++#define R_MIPS_COPY 126 ++#define R_MIPS_JUMP_SLOT 127 ++/* Keep this the last entry. */ ++#define R_MIPS_NUM 128 ++ ++/* Legal values for p_type field of Elf32_Phdr. */ ++ ++#define PT_MIPS_REGINFO 0x70000000 /* Register usage information */ ++#define PT_MIPS_RTPROC 0x70000001 /* Runtime procedure table. */ ++#define PT_MIPS_OPTIONS 0x70000002 ++ ++/* Special program header types. */ ++ ++#define PF_MIPS_LOCAL 0x10000000 ++ ++/* Legal values for d_tag field of Elf32_Dyn. */ ++ ++#define DT_MIPS_RLD_VERSION 0x70000001 /* Runtime linker interface version */ ++#define DT_MIPS_TIME_STAMP 0x70000002 /* Timestamp */ ++#define DT_MIPS_ICHECKSUM 0x70000003 /* Checksum */ ++#define DT_MIPS_IVERSION 0x70000004 /* Version string (string tbl index) */ ++#define DT_MIPS_FLAGS 0x70000005 /* Flags */ ++#define DT_MIPS_BASE_ADDRESS 0x70000006 /* Base address */ ++#define DT_MIPS_MSYM 0x70000007 ++#define DT_MIPS_CONFLICT 0x70000008 /* Address of CONFLICT section */ ++#define DT_MIPS_LIBLIST 0x70000009 /* Address of LIBLIST section */ ++#define DT_MIPS_LOCAL_GOTNO 0x7000000a /* Number of local GOT entries */ ++#define DT_MIPS_CONFLICTNO 0x7000000b /* Number of CONFLICT entries */ ++#define DT_MIPS_LIBLISTNO 0x70000010 /* Number of LIBLIST entries */ ++#define DT_MIPS_SYMTABNO 0x70000011 /* Number of DYNSYM entries */ ++#define DT_MIPS_UNREFEXTNO 0x70000012 /* First external DYNSYM */ ++#define DT_MIPS_GOTSYM 0x70000013 /* First GOT entry in DYNSYM */ ++#define DT_MIPS_HIPAGENO 0x70000014 /* Number of GOT page table entries */ ++#define DT_MIPS_RLD_MAP 0x70000016 /* Address of run time loader map. */ ++#define DT_MIPS_DELTA_CLASS 0x70000017 /* Delta C++ class definition. */ ++#define DT_MIPS_DELTA_CLASS_NO 0x70000018 /* Number of entries in ++ DT_MIPS_DELTA_CLASS. */ ++#define DT_MIPS_DELTA_INSTANCE 0x70000019 /* Delta C++ class instances. */ ++#define DT_MIPS_DELTA_INSTANCE_NO 0x7000001a /* Number of entries in ++ DT_MIPS_DELTA_INSTANCE. */ ++#define DT_MIPS_DELTA_RELOC 0x7000001b /* Delta relocations. */ ++#define DT_MIPS_DELTA_RELOC_NO 0x7000001c /* Number of entries in ++ DT_MIPS_DELTA_RELOC. */ ++#define DT_MIPS_DELTA_SYM 0x7000001d /* Delta symbols that Delta ++ relocations refer to. */ ++#define DT_MIPS_DELTA_SYM_NO 0x7000001e /* Number of entries in ++ DT_MIPS_DELTA_SYM. */ ++#define DT_MIPS_DELTA_CLASSSYM 0x70000020 /* Delta symbols that hold the ++ class declaration. */ ++#define DT_MIPS_DELTA_CLASSSYM_NO 0x70000021 /* Number of entries in ++ DT_MIPS_DELTA_CLASSSYM. */ ++#define DT_MIPS_CXX_FLAGS 0x70000022 /* Flags indicating for C++ flavor. */ ++#define DT_MIPS_PIXIE_INIT 0x70000023 ++#define DT_MIPS_SYMBOL_LIB 0x70000024 ++#define DT_MIPS_LOCALPAGE_GOTIDX 0x70000025 ++#define DT_MIPS_LOCAL_GOTIDX 0x70000026 ++#define DT_MIPS_HIDDEN_GOTIDX 0x70000027 ++#define DT_MIPS_PROTECTED_GOTIDX 0x70000028 ++#define DT_MIPS_OPTIONS 0x70000029 /* Address of .options. */ ++#define DT_MIPS_INTERFACE 0x7000002a /* Address of .interface. */ ++#define DT_MIPS_DYNSTR_ALIGN 0x7000002b ++#define DT_MIPS_INTERFACE_SIZE 0x7000002c /* Size of the .interface section. */ ++#define DT_MIPS_RLD_TEXT_RESOLVE_ADDR 0x7000002d /* Address of rld_text_rsolve ++ function stored in GOT. */ ++#define DT_MIPS_PERF_SUFFIX 0x7000002e /* Default suffix of dso to be added ++ by rld on dlopen() calls. */ ++#define DT_MIPS_COMPACT_SIZE 0x7000002f /* (O32)Size of compact rel section. */ ++#define DT_MIPS_GP_VALUE 0x70000030 /* GP value for aux GOTs. */ ++#define DT_MIPS_AUX_DYNAMIC 0x70000031 /* Address of aux .dynamic. */ ++/* The address of .got.plt in an executable using the new non-PIC ABI. */ ++#define DT_MIPS_PLTGOT 0x70000032 ++/* The base of the PLT in an executable using the new non-PIC ABI if that ++ PLT is writable. For a non-writable PLT, this is omitted or has a zero ++ value. */ ++#define DT_MIPS_RWPLT 0x70000034 ++#define DT_MIPS_NUM 0x35 ++ ++/* Legal values for DT_MIPS_FLAGS Elf32_Dyn entry. */ ++ ++#define RHF_NONE 0 /* No flags */ ++#define RHF_QUICKSTART (1 << 0) /* Use quickstart */ ++#define RHF_NOTPOT (1 << 1) /* Hash size not power of 2 */ ++#define RHF_NO_LIBRARY_REPLACEMENT (1 << 2) /* Ignore LD_LIBRARY_PATH */ ++#define RHF_NO_MOVE (1 << 3) ++#define RHF_SGI_ONLY (1 << 4) ++#define RHF_GUARANTEE_INIT (1 << 5) ++#define RHF_DELTA_C_PLUS_PLUS (1 << 6) ++#define RHF_GUARANTEE_START_INIT (1 << 7) ++#define RHF_PIXIE (1 << 8) ++#define RHF_DEFAULT_DELAY_LOAD (1 << 9) ++#define RHF_REQUICKSTART (1 << 10) ++#define RHF_REQUICKSTARTED (1 << 11) ++#define RHF_CORD (1 << 12) ++#define RHF_NO_UNRES_UNDEF (1 << 13) ++#define RHF_RLD_ORDER_SAFE (1 << 14) ++ ++/* Entries found in sections of type SHT_MIPS_LIBLIST. */ ++ ++typedef struct ++{ ++ Elf32_Word l_name; /* Name (string table index) */ ++ Elf32_Word l_time_stamp; /* Timestamp */ ++ Elf32_Word l_checksum; /* Checksum */ ++ Elf32_Word l_version; /* Interface version */ ++ Elf32_Word l_flags; /* Flags */ ++} Elf32_Lib; ++ ++typedef struct ++{ ++ Elf64_Word l_name; /* Name (string table index) */ ++ Elf64_Word l_time_stamp; /* Timestamp */ ++ Elf64_Word l_checksum; /* Checksum */ ++ Elf64_Word l_version; /* Interface version */ ++ Elf64_Word l_flags; /* Flags */ ++} Elf64_Lib; ++ ++ ++/* Legal values for l_flags. */ ++ ++#define LL_NONE 0 ++#define LL_EXACT_MATCH (1 << 0) /* Require exact match */ ++#define LL_IGNORE_INT_VER (1 << 1) /* Ignore interface version */ ++#define LL_REQUIRE_MINOR (1 << 2) ++#define LL_EXPORTS (1 << 3) ++#define LL_DELAY_LOAD (1 << 4) ++#define LL_DELTA (1 << 5) ++ ++/* Entries found in sections of type SHT_MIPS_CONFLICT. */ ++ ++typedef Elf32_Addr Elf32_Conflict; ++ ++ ++/* HPPA specific definitions. */ ++ ++/* Legal values for e_flags field of Elf32_Ehdr. */ ++ ++#define EF_PARISC_TRAPNIL 0x00010000 /* Trap nil pointer dereference. */ ++#define EF_PARISC_EXT 0x00020000 /* Program uses arch. extensions. */ ++#define EF_PARISC_LSB 0x00040000 /* Program expects little endian. */ ++#define EF_PARISC_WIDE 0x00080000 /* Program expects wide mode. */ ++#define EF_PARISC_NO_KABP 0x00100000 /* No kernel assisted branch ++ prediction. */ ++#define EF_PARISC_LAZYSWAP 0x00400000 /* Allow lazy swapping. */ ++#define EF_PARISC_ARCH 0x0000ffff /* Architecture version. */ ++ ++/* Defined values for `e_flags & EF_PARISC_ARCH' are: */ ++ ++#define EFA_PARISC_1_0 0x020b /* PA-RISC 1.0 big-endian. */ ++#define EFA_PARISC_1_1 0x0210 /* PA-RISC 1.1 big-endian. */ ++#define EFA_PARISC_2_0 0x0214 /* PA-RISC 2.0 big-endian. */ ++ ++/* Additional section indeces. */ ++ ++#define SHN_PARISC_ANSI_COMMON 0xff00 /* Section for tenatively declared ++ symbols in ANSI C. */ ++#define SHN_PARISC_HUGE_COMMON 0xff01 /* Common blocks in huge model. */ ++ ++/* Legal values for sh_type field of Elf32_Shdr. */ ++ ++#define SHT_PARISC_EXT 0x70000000 /* Contains product specific ext. */ ++#define SHT_PARISC_UNWIND 0x70000001 /* Unwind information. */ ++#define SHT_PARISC_DOC 0x70000002 /* Debug info for optimized code. */ ++ ++/* Legal values for sh_flags field of Elf32_Shdr. */ ++ ++#define SHF_PARISC_SHORT 0x20000000 /* Section with short addressing. */ ++#define SHF_PARISC_HUGE 0x40000000 /* Section far from gp. */ ++#define SHF_PARISC_SBP 0x80000000 /* Static branch prediction code. */ ++ ++/* Legal values for ST_TYPE subfield of st_info (symbol type). */ ++ ++#define STT_PARISC_MILLICODE 13 /* Millicode function entry point. */ ++ ++#define STT_HP_OPAQUE (STT_LOOS + 0x1) ++#define STT_HP_STUB (STT_LOOS + 0x2) ++ ++/* HPPA relocs. */ ++ ++#define R_PARISC_NONE 0 /* No reloc. */ ++#define R_PARISC_DIR32 1 /* Direct 32-bit reference. */ ++#define R_PARISC_DIR21L 2 /* Left 21 bits of eff. address. */ ++#define R_PARISC_DIR17R 3 /* Right 17 bits of eff. address. */ ++#define R_PARISC_DIR17F 4 /* 17 bits of eff. address. */ ++#define R_PARISC_DIR14R 6 /* Right 14 bits of eff. address. */ ++#define R_PARISC_PCREL32 9 /* 32-bit rel. address. */ ++#define R_PARISC_PCREL21L 10 /* Left 21 bits of rel. address. */ ++#define R_PARISC_PCREL17R 11 /* Right 17 bits of rel. address. */ ++#define R_PARISC_PCREL17F 12 /* 17 bits of rel. address. */ ++#define R_PARISC_PCREL14R 14 /* Right 14 bits of rel. address. */ ++#define R_PARISC_DPREL21L 18 /* Left 21 bits of rel. address. */ ++#define R_PARISC_DPREL14R 22 /* Right 14 bits of rel. address. */ ++#define R_PARISC_GPREL21L 26 /* GP-relative, left 21 bits. */ ++#define R_PARISC_GPREL14R 30 /* GP-relative, right 14 bits. */ ++#define R_PARISC_LTOFF21L 34 /* LT-relative, left 21 bits. */ ++#define R_PARISC_LTOFF14R 38 /* LT-relative, right 14 bits. */ ++#define R_PARISC_SECREL32 41 /* 32 bits section rel. address. */ ++#define R_PARISC_SEGBASE 48 /* No relocation, set segment base. */ ++#define R_PARISC_SEGREL32 49 /* 32 bits segment rel. address. */ ++#define R_PARISC_PLTOFF21L 50 /* PLT rel. address, left 21 bits. */ ++#define R_PARISC_PLTOFF14R 54 /* PLT rel. address, right 14 bits. */ ++#define R_PARISC_LTOFF_FPTR32 57 /* 32 bits LT-rel. function pointer. */ ++#define R_PARISC_LTOFF_FPTR21L 58 /* LT-rel. fct ptr, left 21 bits. */ ++#define R_PARISC_LTOFF_FPTR14R 62 /* LT-rel. fct ptr, right 14 bits. */ ++#define R_PARISC_FPTR64 64 /* 64 bits function address. */ ++#define R_PARISC_PLABEL32 65 /* 32 bits function address. */ ++#define R_PARISC_PLABEL21L 66 /* Left 21 bits of fdesc address. */ ++#define R_PARISC_PLABEL14R 70 /* Right 14 bits of fdesc address. */ ++#define R_PARISC_PCREL64 72 /* 64 bits PC-rel. address. */ ++#define R_PARISC_PCREL22F 74 /* 22 bits PC-rel. address. */ ++#define R_PARISC_PCREL14WR 75 /* PC-rel. address, right 14 bits. */ ++#define R_PARISC_PCREL14DR 76 /* PC rel. address, right 14 bits. */ ++#define R_PARISC_PCREL16F 77 /* 16 bits PC-rel. address. */ ++#define R_PARISC_PCREL16WF 78 /* 16 bits PC-rel. address. */ ++#define R_PARISC_PCREL16DF 79 /* 16 bits PC-rel. address. */ ++#define R_PARISC_DIR64 80 /* 64 bits of eff. address. */ ++#define R_PARISC_DIR14WR 83 /* 14 bits of eff. address. */ ++#define R_PARISC_DIR14DR 84 /* 14 bits of eff. address. */ ++#define R_PARISC_DIR16F 85 /* 16 bits of eff. address. */ ++#define R_PARISC_DIR16WF 86 /* 16 bits of eff. address. */ ++#define R_PARISC_DIR16DF 87 /* 16 bits of eff. address. */ ++#define R_PARISC_GPREL64 88 /* 64 bits of GP-rel. address. */ ++#define R_PARISC_GPREL14WR 91 /* GP-rel. address, right 14 bits. */ ++#define R_PARISC_GPREL14DR 92 /* GP-rel. address, right 14 bits. */ ++#define R_PARISC_GPREL16F 93 /* 16 bits GP-rel. address. */ ++#define R_PARISC_GPREL16WF 94 /* 16 bits GP-rel. address. */ ++#define R_PARISC_GPREL16DF 95 /* 16 bits GP-rel. address. */ ++#define R_PARISC_LTOFF64 96 /* 64 bits LT-rel. address. */ ++#define R_PARISC_LTOFF14WR 99 /* LT-rel. address, right 14 bits. */ ++#define R_PARISC_LTOFF14DR 100 /* LT-rel. address, right 14 bits. */ ++#define R_PARISC_LTOFF16F 101 /* 16 bits LT-rel. address. */ ++#define R_PARISC_LTOFF16WF 102 /* 16 bits LT-rel. address. */ ++#define R_PARISC_LTOFF16DF 103 /* 16 bits LT-rel. address. */ ++#define R_PARISC_SECREL64 104 /* 64 bits section rel. address. */ ++#define R_PARISC_SEGREL64 112 /* 64 bits segment rel. address. */ ++#define R_PARISC_PLTOFF14WR 115 /* PLT-rel. address, right 14 bits. */ ++#define R_PARISC_PLTOFF14DR 116 /* PLT-rel. address, right 14 bits. */ ++#define R_PARISC_PLTOFF16F 117 /* 16 bits LT-rel. address. */ ++#define R_PARISC_PLTOFF16WF 118 /* 16 bits PLT-rel. address. */ ++#define R_PARISC_PLTOFF16DF 119 /* 16 bits PLT-rel. address. */ ++#define R_PARISC_LTOFF_FPTR64 120 /* 64 bits LT-rel. function ptr. */ ++#define R_PARISC_LTOFF_FPTR14WR 123 /* LT-rel. fct. ptr., right 14 bits. */ ++#define R_PARISC_LTOFF_FPTR14DR 124 /* LT-rel. fct. ptr., right 14 bits. */ ++#define R_PARISC_LTOFF_FPTR16F 125 /* 16 bits LT-rel. function ptr. */ ++#define R_PARISC_LTOFF_FPTR16WF 126 /* 16 bits LT-rel. function ptr. */ ++#define R_PARISC_LTOFF_FPTR16DF 127 /* 16 bits LT-rel. function ptr. */ ++#define R_PARISC_LORESERVE 128 ++#define R_PARISC_COPY 128 /* Copy relocation. */ ++#define R_PARISC_IPLT 129 /* Dynamic reloc, imported PLT */ ++#define R_PARISC_EPLT 130 /* Dynamic reloc, exported PLT */ ++#define R_PARISC_TPREL32 153 /* 32 bits TP-rel. address. */ ++#define R_PARISC_TPREL21L 154 /* TP-rel. address, left 21 bits. */ ++#define R_PARISC_TPREL14R 158 /* TP-rel. address, right 14 bits. */ ++#define R_PARISC_LTOFF_TP21L 162 /* LT-TP-rel. address, left 21 bits. */ ++#define R_PARISC_LTOFF_TP14R 166 /* LT-TP-rel. address, right 14 bits.*/ ++#define R_PARISC_LTOFF_TP14F 167 /* 14 bits LT-TP-rel. address. */ ++#define R_PARISC_TPREL64 216 /* 64 bits TP-rel. address. */ ++#define R_PARISC_TPREL14WR 219 /* TP-rel. address, right 14 bits. */ ++#define R_PARISC_TPREL14DR 220 /* TP-rel. address, right 14 bits. */ ++#define R_PARISC_TPREL16F 221 /* 16 bits TP-rel. address. */ ++#define R_PARISC_TPREL16WF 222 /* 16 bits TP-rel. address. */ ++#define R_PARISC_TPREL16DF 223 /* 16 bits TP-rel. address. */ ++#define R_PARISC_LTOFF_TP64 224 /* 64 bits LT-TP-rel. address. */ ++#define R_PARISC_LTOFF_TP14WR 227 /* LT-TP-rel. address, right 14 bits.*/ ++#define R_PARISC_LTOFF_TP14DR 228 /* LT-TP-rel. address, right 14 bits.*/ ++#define R_PARISC_LTOFF_TP16F 229 /* 16 bits LT-TP-rel. address. */ ++#define R_PARISC_LTOFF_TP16WF 230 /* 16 bits LT-TP-rel. address. */ ++#define R_PARISC_LTOFF_TP16DF 231 /* 16 bits LT-TP-rel. address. */ ++#define R_PARISC_GNU_VTENTRY 232 ++#define R_PARISC_GNU_VTINHERIT 233 ++#define R_PARISC_TLS_GD21L 234 /* GD 21-bit left. */ ++#define R_PARISC_TLS_GD14R 235 /* GD 14-bit right. */ ++#define R_PARISC_TLS_GDCALL 236 /* GD call to __t_g_a. */ ++#define R_PARISC_TLS_LDM21L 237 /* LD module 21-bit left. */ ++#define R_PARISC_TLS_LDM14R 238 /* LD module 14-bit right. */ ++#define R_PARISC_TLS_LDMCALL 239 /* LD module call to __t_g_a. */ ++#define R_PARISC_TLS_LDO21L 240 /* LD offset 21-bit left. */ ++#define R_PARISC_TLS_LDO14R 241 /* LD offset 14-bit right. */ ++#define R_PARISC_TLS_DTPMOD32 242 /* DTP module 32-bit. */ ++#define R_PARISC_TLS_DTPMOD64 243 /* DTP module 64-bit. */ ++#define R_PARISC_TLS_DTPOFF32 244 /* DTP offset 32-bit. */ ++#define R_PARISC_TLS_DTPOFF64 245 /* DTP offset 32-bit. */ ++#define R_PARISC_TLS_LE21L R_PARISC_TPREL21L ++#define R_PARISC_TLS_LE14R R_PARISC_TPREL14R ++#define R_PARISC_TLS_IE21L R_PARISC_LTOFF_TP21L ++#define R_PARISC_TLS_IE14R R_PARISC_LTOFF_TP14R ++#define R_PARISC_TLS_TPREL32 R_PARISC_TPREL32 ++#define R_PARISC_TLS_TPREL64 R_PARISC_TPREL64 ++#define R_PARISC_HIRESERVE 255 ++ ++/* Legal values for p_type field of Elf32_Phdr/Elf64_Phdr. */ ++ ++#define PT_HP_TLS (PT_LOOS + 0x0) ++#define PT_HP_CORE_NONE (PT_LOOS + 0x1) ++#define PT_HP_CORE_VERSION (PT_LOOS + 0x2) ++#define PT_HP_CORE_KERNEL (PT_LOOS + 0x3) ++#define PT_HP_CORE_COMM (PT_LOOS + 0x4) ++#define PT_HP_CORE_PROC (PT_LOOS + 0x5) ++#define PT_HP_CORE_LOADABLE (PT_LOOS + 0x6) ++#define PT_HP_CORE_STACK (PT_LOOS + 0x7) ++#define PT_HP_CORE_SHM (PT_LOOS + 0x8) ++#define PT_HP_CORE_MMF (PT_LOOS + 0x9) ++#define PT_HP_PARALLEL (PT_LOOS + 0x10) ++#define PT_HP_FASTBIND (PT_LOOS + 0x11) ++#define PT_HP_OPT_ANNOT (PT_LOOS + 0x12) ++#define PT_HP_HSL_ANNOT (PT_LOOS + 0x13) ++#define PT_HP_STACK (PT_LOOS + 0x14) ++ ++#define PT_PARISC_ARCHEXT 0x70000000 ++#define PT_PARISC_UNWIND 0x70000001 ++ ++/* Legal values for p_flags field of Elf32_Phdr/Elf64_Phdr. */ ++ ++#define PF_PARISC_SBP 0x08000000 ++ ++#define PF_HP_PAGE_SIZE 0x00100000 ++#define PF_HP_FAR_SHARED 0x00200000 ++#define PF_HP_NEAR_SHARED 0x00400000 ++#define PF_HP_CODE 0x01000000 ++#define PF_HP_MODIFY 0x02000000 ++#define PF_HP_LAZYSWAP 0x04000000 ++#define PF_HP_SBP 0x08000000 ++ ++ ++/* Alpha specific definitions. */ ++ ++/* Legal values for e_flags field of Elf64_Ehdr. */ ++ ++#define EF_ALPHA_32BIT 1 /* All addresses must be < 2GB. */ ++#define EF_ALPHA_CANRELAX 2 /* Relocations for relaxing exist. */ ++ ++/* Legal values for sh_type field of Elf64_Shdr. */ ++ ++/* These two are primerily concerned with ECOFF debugging info. */ ++#define SHT_ALPHA_DEBUG 0x70000001 ++#define SHT_ALPHA_REGINFO 0x70000002 ++ ++/* Legal values for sh_flags field of Elf64_Shdr. */ ++ ++#define SHF_ALPHA_GPREL 0x10000000 ++ ++/* Legal values for st_other field of Elf64_Sym. */ ++#define STO_ALPHA_NOPV 0x80 /* No PV required. */ ++#define STO_ALPHA_STD_GPLOAD 0x88 /* PV only used for initial ldgp. */ ++ ++/* Alpha relocs. */ ++ ++#define R_ALPHA_NONE 0 /* No reloc */ ++#define R_ALPHA_REFLONG 1 /* Direct 32 bit */ ++#define R_ALPHA_REFQUAD 2 /* Direct 64 bit */ ++#define R_ALPHA_GPREL32 3 /* GP relative 32 bit */ ++#define R_ALPHA_LITERAL 4 /* GP relative 16 bit w/optimization */ ++#define R_ALPHA_LITUSE 5 /* Optimization hint for LITERAL */ ++#define R_ALPHA_GPDISP 6 /* Add displacement to GP */ ++#define R_ALPHA_BRADDR 7 /* PC+4 relative 23 bit shifted */ ++#define R_ALPHA_HINT 8 /* PC+4 relative 16 bit shifted */ ++#define R_ALPHA_SREL16 9 /* PC relative 16 bit */ ++#define R_ALPHA_SREL32 10 /* PC relative 32 bit */ ++#define R_ALPHA_SREL64 11 /* PC relative 64 bit */ ++#define R_ALPHA_GPRELHIGH 17 /* GP relative 32 bit, high 16 bits */ ++#define R_ALPHA_GPRELLOW 18 /* GP relative 32 bit, low 16 bits */ ++#define R_ALPHA_GPREL16 19 /* GP relative 16 bit */ ++#define R_ALPHA_COPY 24 /* Copy symbol at runtime */ ++#define R_ALPHA_GLOB_DAT 25 /* Create GOT entry */ ++#define R_ALPHA_JMP_SLOT 26 /* Create PLT entry */ ++#define R_ALPHA_RELATIVE 27 /* Adjust by program base */ ++#define R_ALPHA_TLS_GD_HI 28 ++#define R_ALPHA_TLSGD 29 ++#define R_ALPHA_TLS_LDM 30 ++#define R_ALPHA_DTPMOD64 31 ++#define R_ALPHA_GOTDTPREL 32 ++#define R_ALPHA_DTPREL64 33 ++#define R_ALPHA_DTPRELHI 34 ++#define R_ALPHA_DTPRELLO 35 ++#define R_ALPHA_DTPREL16 36 ++#define R_ALPHA_GOTTPREL 37 ++#define R_ALPHA_TPREL64 38 ++#define R_ALPHA_TPRELHI 39 ++#define R_ALPHA_TPRELLO 40 ++#define R_ALPHA_TPREL16 41 ++/* Keep this the last entry. */ ++#define R_ALPHA_NUM 46 ++ ++/* Magic values of the LITUSE relocation addend. */ ++#define LITUSE_ALPHA_ADDR 0 ++#define LITUSE_ALPHA_BASE 1 ++#define LITUSE_ALPHA_BYTOFF 2 ++#define LITUSE_ALPHA_JSR 3 ++#define LITUSE_ALPHA_TLS_GD 4 ++#define LITUSE_ALPHA_TLS_LDM 5 ++ ++/* Legal values for d_tag of Elf64_Dyn. */ ++#define DT_ALPHA_PLTRO (DT_LOPROC + 0) ++#define DT_ALPHA_NUM 1 ++ ++/* PowerPC specific declarations */ ++ ++/* Values for Elf32/64_Ehdr.e_flags. */ ++#define EF_PPC_EMB 0x80000000 /* PowerPC embedded flag */ ++ ++/* Cygnus local bits below */ ++#define EF_PPC_RELOCATABLE 0x00010000 /* PowerPC -mrelocatable flag*/ ++#define EF_PPC_RELOCATABLE_LIB 0x00008000 /* PowerPC -mrelocatable-lib ++ flag */ ++ ++/* PowerPC relocations defined by the ABIs */ ++#define R_PPC_NONE 0 ++#define R_PPC_ADDR32 1 /* 32bit absolute address */ ++#define R_PPC_ADDR24 2 /* 26bit address, 2 bits ignored. */ ++#define R_PPC_ADDR16 3 /* 16bit absolute address */ ++#define R_PPC_ADDR16_LO 4 /* lower 16bit of absolute address */ ++#define R_PPC_ADDR16_HI 5 /* high 16bit of absolute address */ ++#define R_PPC_ADDR16_HA 6 /* adjusted high 16bit */ ++#define R_PPC_ADDR14 7 /* 16bit address, 2 bits ignored */ ++#define R_PPC_ADDR14_BRTAKEN 8 ++#define R_PPC_ADDR14_BRNTAKEN 9 ++#define R_PPC_REL24 10 /* PC relative 26 bit */ ++#define R_PPC_REL14 11 /* PC relative 16 bit */ ++#define R_PPC_REL14_BRTAKEN 12 ++#define R_PPC_REL14_BRNTAKEN 13 ++#define R_PPC_GOT16 14 ++#define R_PPC_GOT16_LO 15 ++#define R_PPC_GOT16_HI 16 ++#define R_PPC_GOT16_HA 17 ++#define R_PPC_PLTREL24 18 ++#define R_PPC_COPY 19 ++#define R_PPC_GLOB_DAT 20 ++#define R_PPC_JMP_SLOT 21 ++#define R_PPC_RELATIVE 22 ++#define R_PPC_LOCAL24PC 23 ++#define R_PPC_UADDR32 24 ++#define R_PPC_UADDR16 25 ++#define R_PPC_REL32 26 ++#define R_PPC_PLT32 27 ++#define R_PPC_PLTREL32 28 ++#define R_PPC_PLT16_LO 29 ++#define R_PPC_PLT16_HI 30 ++#define R_PPC_PLT16_HA 31 ++#define R_PPC_SDAREL16 32 ++#define R_PPC_SECTOFF 33 ++#define R_PPC_SECTOFF_LO 34 ++#define R_PPC_SECTOFF_HI 35 ++#define R_PPC_SECTOFF_HA 36 ++ ++/* PowerPC relocations defined for the TLS access ABI. */ ++#define R_PPC_TLS 67 /* none (sym+add)@tls */ ++#define R_PPC_DTPMOD32 68 /* word32 (sym+add)@dtpmod */ ++#define R_PPC_TPREL16 69 /* half16* (sym+add)@tprel */ ++#define R_PPC_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */ ++#define R_PPC_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */ ++#define R_PPC_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */ ++#define R_PPC_TPREL32 73 /* word32 (sym+add)@tprel */ ++#define R_PPC_DTPREL16 74 /* half16* (sym+add)@dtprel */ ++#define R_PPC_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */ ++#define R_PPC_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */ ++#define R_PPC_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */ ++#define R_PPC_DTPREL32 78 /* word32 (sym+add)@dtprel */ ++#define R_PPC_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */ ++#define R_PPC_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */ ++#define R_PPC_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */ ++#define R_PPC_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */ ++#define R_PPC_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */ ++#define R_PPC_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */ ++#define R_PPC_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */ ++#define R_PPC_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */ ++#define R_PPC_GOT_TPREL16 87 /* half16* (sym+add)@got@tprel */ ++#define R_PPC_GOT_TPREL16_LO 88 /* half16 (sym+add)@got@tprel@l */ ++#define R_PPC_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */ ++#define R_PPC_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */ ++#define R_PPC_GOT_DTPREL16 91 /* half16* (sym+add)@got@dtprel */ ++#define R_PPC_GOT_DTPREL16_LO 92 /* half16* (sym+add)@got@dtprel@l */ ++#define R_PPC_GOT_DTPREL16_HI 93 /* half16* (sym+add)@got@dtprel@h */ ++#define R_PPC_GOT_DTPREL16_HA 94 /* half16* (sym+add)@got@dtprel@ha */ ++ ++/* The remaining relocs are from the Embedded ELF ABI, and are not ++ in the SVR4 ELF ABI. */ ++#define R_PPC_EMB_NADDR32 101 ++#define R_PPC_EMB_NADDR16 102 ++#define R_PPC_EMB_NADDR16_LO 103 ++#define R_PPC_EMB_NADDR16_HI 104 ++#define R_PPC_EMB_NADDR16_HA 105 ++#define R_PPC_EMB_SDAI16 106 ++#define R_PPC_EMB_SDA2I16 107 ++#define R_PPC_EMB_SDA2REL 108 ++#define R_PPC_EMB_SDA21 109 /* 16 bit offset in SDA */ ++#define R_PPC_EMB_MRKREF 110 ++#define R_PPC_EMB_RELSEC16 111 ++#define R_PPC_EMB_RELST_LO 112 ++#define R_PPC_EMB_RELST_HI 113 ++#define R_PPC_EMB_RELST_HA 114 ++#define R_PPC_EMB_BIT_FLD 115 ++#define R_PPC_EMB_RELSDA 116 /* 16 bit relative offset in SDA */ ++ ++/* Diab tool relocations. */ ++#define R_PPC_DIAB_SDA21_LO 180 /* like EMB_SDA21, but lower 16 bit */ ++#define R_PPC_DIAB_SDA21_HI 181 /* like EMB_SDA21, but high 16 bit */ ++#define R_PPC_DIAB_SDA21_HA 182 /* like EMB_SDA21, adjusted high 16 */ ++#define R_PPC_DIAB_RELSDA_LO 183 /* like EMB_RELSDA, but lower 16 bit */ ++#define R_PPC_DIAB_RELSDA_HI 184 /* like EMB_RELSDA, but high 16 bit */ ++#define R_PPC_DIAB_RELSDA_HA 185 /* like EMB_RELSDA, adjusted high 16 */ ++ ++/* GNU extension to support local ifunc. */ ++#define R_PPC_IRELATIVE 248 ++ ++/* GNU relocs used in PIC code sequences. */ ++#define R_PPC_REL16 249 /* half16 (sym+add-.) */ ++#define R_PPC_REL16_LO 250 /* half16 (sym+add-.)@l */ ++#define R_PPC_REL16_HI 251 /* half16 (sym+add-.)@h */ ++#define R_PPC_REL16_HA 252 /* half16 (sym+add-.)@ha */ ++ ++/* This is a phony reloc to handle any old fashioned TOC16 references ++ that may still be in object files. */ ++#define R_PPC_TOC16 255 ++ ++/* PowerPC specific values for the Dyn d_tag field. */ ++#define DT_PPC_GOT (DT_LOPROC + 0) ++#define DT_PPC_NUM 1 ++ ++/* PowerPC64 relocations defined by the ABIs */ ++#define R_PPC64_NONE R_PPC_NONE ++#define R_PPC64_ADDR32 R_PPC_ADDR32 /* 32bit absolute address */ ++#define R_PPC64_ADDR24 R_PPC_ADDR24 /* 26bit address, word aligned */ ++#define R_PPC64_ADDR16 R_PPC_ADDR16 /* 16bit absolute address */ ++#define R_PPC64_ADDR16_LO R_PPC_ADDR16_LO /* lower 16bits of address */ ++#define R_PPC64_ADDR16_HI R_PPC_ADDR16_HI /* high 16bits of address. */ ++#define R_PPC64_ADDR16_HA R_PPC_ADDR16_HA /* adjusted high 16bits. */ ++#define R_PPC64_ADDR14 R_PPC_ADDR14 /* 16bit address, word aligned */ ++#define R_PPC64_ADDR14_BRTAKEN R_PPC_ADDR14_BRTAKEN ++#define R_PPC64_ADDR14_BRNTAKEN R_PPC_ADDR14_BRNTAKEN ++#define R_PPC64_REL24 R_PPC_REL24 /* PC-rel. 26 bit, word aligned */ ++#define R_PPC64_REL14 R_PPC_REL14 /* PC relative 16 bit */ ++#define R_PPC64_REL14_BRTAKEN R_PPC_REL14_BRTAKEN ++#define R_PPC64_REL14_BRNTAKEN R_PPC_REL14_BRNTAKEN ++#define R_PPC64_GOT16 R_PPC_GOT16 ++#define R_PPC64_GOT16_LO R_PPC_GOT16_LO ++#define R_PPC64_GOT16_HI R_PPC_GOT16_HI ++#define R_PPC64_GOT16_HA R_PPC_GOT16_HA ++ ++#define R_PPC64_COPY R_PPC_COPY ++#define R_PPC64_GLOB_DAT R_PPC_GLOB_DAT ++#define R_PPC64_JMP_SLOT R_PPC_JMP_SLOT ++#define R_PPC64_RELATIVE R_PPC_RELATIVE ++ ++#define R_PPC64_UADDR32 R_PPC_UADDR32 ++#define R_PPC64_UADDR16 R_PPC_UADDR16 ++#define R_PPC64_REL32 R_PPC_REL32 ++#define R_PPC64_PLT32 R_PPC_PLT32 ++#define R_PPC64_PLTREL32 R_PPC_PLTREL32 ++#define R_PPC64_PLT16_LO R_PPC_PLT16_LO ++#define R_PPC64_PLT16_HI R_PPC_PLT16_HI ++#define R_PPC64_PLT16_HA R_PPC_PLT16_HA ++ ++#define R_PPC64_SECTOFF R_PPC_SECTOFF ++#define R_PPC64_SECTOFF_LO R_PPC_SECTOFF_LO ++#define R_PPC64_SECTOFF_HI R_PPC_SECTOFF_HI ++#define R_PPC64_SECTOFF_HA R_PPC_SECTOFF_HA ++#define R_PPC64_ADDR30 37 /* word30 (S + A - P) >> 2 */ ++#define R_PPC64_ADDR64 38 /* doubleword64 S + A */ ++#define R_PPC64_ADDR16_HIGHER 39 /* half16 #higher(S + A) */ ++#define R_PPC64_ADDR16_HIGHERA 40 /* half16 #highera(S + A) */ ++#define R_PPC64_ADDR16_HIGHEST 41 /* half16 #highest(S + A) */ ++#define R_PPC64_ADDR16_HIGHESTA 42 /* half16 #highesta(S + A) */ ++#define R_PPC64_UADDR64 43 /* doubleword64 S + A */ ++#define R_PPC64_REL64 44 /* doubleword64 S + A - P */ ++#define R_PPC64_PLT64 45 /* doubleword64 L + A */ ++#define R_PPC64_PLTREL64 46 /* doubleword64 L + A - P */ ++#define R_PPC64_TOC16 47 /* half16* S + A - .TOC */ ++#define R_PPC64_TOC16_LO 48 /* half16 #lo(S + A - .TOC.) */ ++#define R_PPC64_TOC16_HI 49 /* half16 #hi(S + A - .TOC.) */ ++#define R_PPC64_TOC16_HA 50 /* half16 #ha(S + A - .TOC.) */ ++#define R_PPC64_TOC 51 /* doubleword64 .TOC */ ++#define R_PPC64_PLTGOT16 52 /* half16* M + A */ ++#define R_PPC64_PLTGOT16_LO 53 /* half16 #lo(M + A) */ ++#define R_PPC64_PLTGOT16_HI 54 /* half16 #hi(M + A) */ ++#define R_PPC64_PLTGOT16_HA 55 /* half16 #ha(M + A) */ ++ ++#define R_PPC64_ADDR16_DS 56 /* half16ds* (S + A) >> 2 */ ++#define R_PPC64_ADDR16_LO_DS 57 /* half16ds #lo(S + A) >> 2 */ ++#define R_PPC64_GOT16_DS 58 /* half16ds* (G + A) >> 2 */ ++#define R_PPC64_GOT16_LO_DS 59 /* half16ds #lo(G + A) >> 2 */ ++#define R_PPC64_PLT16_LO_DS 60 /* half16ds #lo(L + A) >> 2 */ ++#define R_PPC64_SECTOFF_DS 61 /* half16ds* (R + A) >> 2 */ ++#define R_PPC64_SECTOFF_LO_DS 62 /* half16ds #lo(R + A) >> 2 */ ++#define R_PPC64_TOC16_DS 63 /* half16ds* (S + A - .TOC.) >> 2 */ ++#define R_PPC64_TOC16_LO_DS 64 /* half16ds #lo(S + A - .TOC.) >> 2 */ ++#define R_PPC64_PLTGOT16_DS 65 /* half16ds* (M + A) >> 2 */ ++#define R_PPC64_PLTGOT16_LO_DS 66 /* half16ds #lo(M + A) >> 2 */ ++ ++/* PowerPC64 relocations defined for the TLS access ABI. */ ++#define R_PPC64_TLS 67 /* none (sym+add)@tls */ ++#define R_PPC64_DTPMOD64 68 /* doubleword64 (sym+add)@dtpmod */ ++#define R_PPC64_TPREL16 69 /* half16* (sym+add)@tprel */ ++#define R_PPC64_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */ ++#define R_PPC64_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */ ++#define R_PPC64_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */ ++#define R_PPC64_TPREL64 73 /* doubleword64 (sym+add)@tprel */ ++#define R_PPC64_DTPREL16 74 /* half16* (sym+add)@dtprel */ ++#define R_PPC64_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */ ++#define R_PPC64_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */ ++#define R_PPC64_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */ ++#define R_PPC64_DTPREL64 78 /* doubleword64 (sym+add)@dtprel */ ++#define R_PPC64_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */ ++#define R_PPC64_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */ ++#define R_PPC64_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */ ++#define R_PPC64_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */ ++#define R_PPC64_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */ ++#define R_PPC64_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */ ++#define R_PPC64_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */ ++#define R_PPC64_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */ ++#define R_PPC64_GOT_TPREL16_DS 87 /* half16ds* (sym+add)@got@tprel */ ++#define R_PPC64_GOT_TPREL16_LO_DS 88 /* half16ds (sym+add)@got@tprel@l */ ++#define R_PPC64_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */ ++#define R_PPC64_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */ ++#define R_PPC64_GOT_DTPREL16_DS 91 /* half16ds* (sym+add)@got@dtprel */ ++#define R_PPC64_GOT_DTPREL16_LO_DS 92 /* half16ds (sym+add)@got@dtprel@l */ ++#define R_PPC64_GOT_DTPREL16_HI 93 /* half16 (sym+add)@got@dtprel@h */ ++#define R_PPC64_GOT_DTPREL16_HA 94 /* half16 (sym+add)@got@dtprel@ha */ ++#define R_PPC64_TPREL16_DS 95 /* half16ds* (sym+add)@tprel */ ++#define R_PPC64_TPREL16_LO_DS 96 /* half16ds (sym+add)@tprel@l */ ++#define R_PPC64_TPREL16_HIGHER 97 /* half16 (sym+add)@tprel@higher */ ++#define R_PPC64_TPREL16_HIGHERA 98 /* half16 (sym+add)@tprel@highera */ ++#define R_PPC64_TPREL16_HIGHEST 99 /* half16 (sym+add)@tprel@highest */ ++#define R_PPC64_TPREL16_HIGHESTA 100 /* half16 (sym+add)@tprel@highesta */ ++#define R_PPC64_DTPREL16_DS 101 /* half16ds* (sym+add)@dtprel */ ++#define R_PPC64_DTPREL16_LO_DS 102 /* half16ds (sym+add)@dtprel@l */ ++#define R_PPC64_DTPREL16_HIGHER 103 /* half16 (sym+add)@dtprel@higher */ ++#define R_PPC64_DTPREL16_HIGHERA 104 /* half16 (sym+add)@dtprel@highera */ ++#define R_PPC64_DTPREL16_HIGHEST 105 /* half16 (sym+add)@dtprel@highest */ ++#define R_PPC64_DTPREL16_HIGHESTA 106 /* half16 (sym+add)@dtprel@highesta */ ++ ++/* GNU extension to support local ifunc. */ ++#define R_PPC64_JMP_IREL 247 ++#define R_PPC64_IRELATIVE 248 ++#define R_PPC64_REL16 249 /* half16 (sym+add-.) */ ++#define R_PPC64_REL16_LO 250 /* half16 (sym+add-.)@l */ ++#define R_PPC64_REL16_HI 251 /* half16 (sym+add-.)@h */ ++#define R_PPC64_REL16_HA 252 /* half16 (sym+add-.)@ha */ ++ ++/* PowerPC64 specific values for the Dyn d_tag field. */ ++#define DT_PPC64_GLINK (DT_LOPROC + 0) ++#define DT_PPC64_OPD (DT_LOPROC + 1) ++#define DT_PPC64_OPDSZ (DT_LOPROC + 2) ++#define DT_PPC64_NUM 3 ++ ++ ++/* ARM specific declarations */ ++ ++/* Processor specific flags for the ELF header e_flags field. */ ++#define EF_ARM_RELEXEC 0x01 ++#define EF_ARM_HASENTRY 0x02 ++#define EF_ARM_INTERWORK 0x04 ++#define EF_ARM_APCS_26 0x08 ++#define EF_ARM_APCS_FLOAT 0x10 ++#define EF_ARM_PIC 0x20 ++#define EF_ARM_ALIGN8 0x40 /* 8-bit structure alignment is in use */ ++#define EF_ARM_NEW_ABI 0x80 ++#define EF_ARM_OLD_ABI 0x100 ++#define EF_ARM_SOFT_FLOAT 0x200 ++#define EF_ARM_VFP_FLOAT 0x400 ++#define EF_ARM_MAVERICK_FLOAT 0x800 ++ ++ ++/* Other constants defined in the ARM ELF spec. version B-01. */ ++/* NB. These conflict with values defined above. */ ++#define EF_ARM_SYMSARESORTED 0x04 ++#define EF_ARM_DYNSYMSUSESEGIDX 0x08 ++#define EF_ARM_MAPSYMSFIRST 0x10 ++#define EF_ARM_EABIMASK 0XFF000000 ++ ++/* Constants defined in AAELF. */ ++#define EF_ARM_BE8 0x00800000 ++#define EF_ARM_LE8 0x00400000 ++ ++#define EF_ARM_EABI_VERSION(flags) ((flags) & EF_ARM_EABIMASK) ++#define EF_ARM_EABI_UNKNOWN 0x00000000 ++#define EF_ARM_EABI_VER1 0x01000000 ++#define EF_ARM_EABI_VER2 0x02000000 ++#define EF_ARM_EABI_VER3 0x03000000 ++#define EF_ARM_EABI_VER4 0x04000000 ++#define EF_ARM_EABI_VER5 0x05000000 ++ ++/* Additional symbol types for Thumb. */ ++#define STT_ARM_TFUNC STT_LOPROC /* A Thumb function. */ ++#define STT_ARM_16BIT STT_HIPROC /* A Thumb label. */ ++ ++/* ARM-specific values for sh_flags */ ++#define SHF_ARM_ENTRYSECT 0x10000000 /* Section contains an entry point */ ++#define SHF_ARM_COMDEF 0x80000000 /* Section may be multiply defined ++ in the input to a link step. */ ++ ++/* ARM-specific program header flags */ ++#define PF_ARM_SB 0x10000000 /* Segment contains the location ++ addressed by the static base. */ ++#define PF_ARM_PI 0x20000000 /* Position-independent segment. */ ++#define PF_ARM_ABS 0x40000000 /* Absolute segment. */ ++ ++/* Processor specific values for the Phdr p_type field. */ ++#define PT_ARM_EXIDX (PT_LOPROC + 1) /* ARM unwind segment. */ ++ ++/* Processor specific values for the Shdr sh_type field. */ ++#define SHT_ARM_EXIDX (SHT_LOPROC + 1) /* ARM unwind section. */ ++#define SHT_ARM_PREEMPTMAP (SHT_LOPROC + 2) /* Preemption details. */ ++#define SHT_ARM_ATTRIBUTES (SHT_LOPROC + 3) /* ARM attributes section. */ ++ ++ ++/* ARM relocs. */ ++ ++#define R_ARM_NONE 0 /* No reloc */ ++#define R_ARM_PC24 1 /* PC relative 26 bit branch */ ++#define R_ARM_ABS32 2 /* Direct 32 bit */ ++#define R_ARM_REL32 3 /* PC relative 32 bit */ ++#define R_ARM_PC13 4 ++#define R_ARM_ABS16 5 /* Direct 16 bit */ ++#define R_ARM_ABS12 6 /* Direct 12 bit */ ++#define R_ARM_THM_ABS5 7 ++#define R_ARM_ABS8 8 /* Direct 8 bit */ ++#define R_ARM_SBREL32 9 ++#define R_ARM_THM_PC22 10 ++#define R_ARM_THM_PC8 11 ++#define R_ARM_AMP_VCALL9 12 ++#define R_ARM_SWI24 13 /* Obsolete static relocation. */ ++#define R_ARM_TLS_DESC 13 /* Dynamic relocation. */ ++#define R_ARM_THM_SWI8 14 ++#define R_ARM_XPC25 15 ++#define R_ARM_THM_XPC22 16 ++#define R_ARM_TLS_DTPMOD32 17 /* ID of module containing symbol */ ++#define R_ARM_TLS_DTPOFF32 18 /* Offset in TLS block */ ++#define R_ARM_TLS_TPOFF32 19 /* Offset in static TLS block */ ++#define R_ARM_COPY 20 /* Copy symbol at runtime */ ++#define R_ARM_GLOB_DAT 21 /* Create GOT entry */ ++#define R_ARM_JUMP_SLOT 22 /* Create PLT entry */ ++#define R_ARM_RELATIVE 23 /* Adjust by program base */ ++#define R_ARM_GOTOFF 24 /* 32 bit offset to GOT */ ++#define R_ARM_GOTPC 25 /* 32 bit PC relative offset to GOT */ ++#define R_ARM_GOT32 26 /* 32 bit GOT entry */ ++#define R_ARM_PLT32 27 /* 32 bit PLT address */ ++#define R_ARM_ALU_PCREL_7_0 32 ++#define R_ARM_ALU_PCREL_15_8 33 ++#define R_ARM_ALU_PCREL_23_15 34 ++#define R_ARM_LDR_SBREL_11_0 35 ++#define R_ARM_ALU_SBREL_19_12 36 ++#define R_ARM_ALU_SBREL_27_20 37 ++#define R_ARM_TLS_GOTDESC 90 ++#define R_ARM_TLS_CALL 91 ++#define R_ARM_TLS_DESCSEQ 92 ++#define R_ARM_THM_TLS_CALL 93 ++#define R_ARM_GNU_VTENTRY 100 ++#define R_ARM_GNU_VTINHERIT 101 ++#define R_ARM_THM_PC11 102 /* thumb unconditional branch */ ++#define R_ARM_THM_PC9 103 /* thumb conditional branch */ ++#define R_ARM_TLS_GD32 104 /* PC-rel 32 bit for global dynamic ++ thread local data */ ++#define R_ARM_TLS_LDM32 105 /* PC-rel 32 bit for local dynamic ++ thread local data */ ++#define R_ARM_TLS_LDO32 106 /* 32 bit offset relative to TLS ++ block */ ++#define R_ARM_TLS_IE32 107 /* PC-rel 32 bit for GOT entry of ++ static TLS block offset */ ++#define R_ARM_TLS_LE32 108 /* 32 bit offset relative to static ++ TLS block */ ++#define R_ARM_THM_TLS_DESCSEQ 129 ++#define R_ARM_IRELATIVE 160 ++#define R_ARM_RXPC25 249 ++#define R_ARM_RSBREL32 250 ++#define R_ARM_THM_RPC22 251 ++#define R_ARM_RREL32 252 ++#define R_ARM_RABS22 253 ++#define R_ARM_RPC24 254 ++#define R_ARM_RBASE 255 ++/* Keep this the last entry. */ ++#define R_ARM_NUM 256 ++ ++/* IA-64 specific declarations. */ ++ ++/* Processor specific flags for the Ehdr e_flags field. */ ++#define EF_IA_64_MASKOS 0x0000000f /* os-specific flags */ ++#define EF_IA_64_ABI64 0x00000010 /* 64-bit ABI */ ++#define EF_IA_64_ARCH 0xff000000 /* arch. version mask */ ++ ++/* Processor specific values for the Phdr p_type field. */ ++#define PT_IA_64_ARCHEXT (PT_LOPROC + 0) /* arch extension bits */ ++#define PT_IA_64_UNWIND (PT_LOPROC + 1) /* ia64 unwind bits */ ++#define PT_IA_64_HP_OPT_ANOT (PT_LOOS + 0x12) ++#define PT_IA_64_HP_HSL_ANOT (PT_LOOS + 0x13) ++#define PT_IA_64_HP_STACK (PT_LOOS + 0x14) ++ ++/* Processor specific flags for the Phdr p_flags field. */ ++#define PF_IA_64_NORECOV 0x80000000 /* spec insns w/o recovery */ ++ ++/* Processor specific values for the Shdr sh_type field. */ ++#define SHT_IA_64_EXT (SHT_LOPROC + 0) /* extension bits */ ++#define SHT_IA_64_UNWIND (SHT_LOPROC + 1) /* unwind bits */ ++ ++/* Processor specific flags for the Shdr sh_flags field. */ ++#define SHF_IA_64_SHORT 0x10000000 /* section near gp */ ++#define SHF_IA_64_NORECOV 0x20000000 /* spec insns w/o recovery */ ++ ++/* Processor specific values for the Dyn d_tag field. */ ++#define DT_IA_64_PLT_RESERVE (DT_LOPROC + 0) ++#define DT_IA_64_NUM 1 ++ ++/* IA-64 relocations. */ ++#define R_IA64_NONE 0x00 /* none */ ++#define R_IA64_IMM14 0x21 /* symbol + addend, add imm14 */ ++#define R_IA64_IMM22 0x22 /* symbol + addend, add imm22 */ ++#define R_IA64_IMM64 0x23 /* symbol + addend, mov imm64 */ ++#define R_IA64_DIR32MSB 0x24 /* symbol + addend, data4 MSB */ ++#define R_IA64_DIR32LSB 0x25 /* symbol + addend, data4 LSB */ ++#define R_IA64_DIR64MSB 0x26 /* symbol + addend, data8 MSB */ ++#define R_IA64_DIR64LSB 0x27 /* symbol + addend, data8 LSB */ ++#define R_IA64_GPREL22 0x2a /* @gprel(sym + add), add imm22 */ ++#define R_IA64_GPREL64I 0x2b /* @gprel(sym + add), mov imm64 */ ++#define R_IA64_GPREL32MSB 0x2c /* @gprel(sym + add), data4 MSB */ ++#define R_IA64_GPREL32LSB 0x2d /* @gprel(sym + add), data4 LSB */ ++#define R_IA64_GPREL64MSB 0x2e /* @gprel(sym + add), data8 MSB */ ++#define R_IA64_GPREL64LSB 0x2f /* @gprel(sym + add), data8 LSB */ ++#define R_IA64_LTOFF22 0x32 /* @ltoff(sym + add), add imm22 */ ++#define R_IA64_LTOFF64I 0x33 /* @ltoff(sym + add), mov imm64 */ ++#define R_IA64_PLTOFF22 0x3a /* @pltoff(sym + add), add imm22 */ ++#define R_IA64_PLTOFF64I 0x3b /* @pltoff(sym + add), mov imm64 */ ++#define R_IA64_PLTOFF64MSB 0x3e /* @pltoff(sym + add), data8 MSB */ ++#define R_IA64_PLTOFF64LSB 0x3f /* @pltoff(sym + add), data8 LSB */ ++#define R_IA64_FPTR64I 0x43 /* @fptr(sym + add), mov imm64 */ ++#define R_IA64_FPTR32MSB 0x44 /* @fptr(sym + add), data4 MSB */ ++#define R_IA64_FPTR32LSB 0x45 /* @fptr(sym + add), data4 LSB */ ++#define R_IA64_FPTR64MSB 0x46 /* @fptr(sym + add), data8 MSB */ ++#define R_IA64_FPTR64LSB 0x47 /* @fptr(sym + add), data8 LSB */ ++#define R_IA64_PCREL60B 0x48 /* @pcrel(sym + add), brl */ ++#define R_IA64_PCREL21B 0x49 /* @pcrel(sym + add), ptb, call */ ++#define R_IA64_PCREL21M 0x4a /* @pcrel(sym + add), chk.s */ ++#define R_IA64_PCREL21F 0x4b /* @pcrel(sym + add), fchkf */ ++#define R_IA64_PCREL32MSB 0x4c /* @pcrel(sym + add), data4 MSB */ ++#define R_IA64_PCREL32LSB 0x4d /* @pcrel(sym + add), data4 LSB */ ++#define R_IA64_PCREL64MSB 0x4e /* @pcrel(sym + add), data8 MSB */ ++#define R_IA64_PCREL64LSB 0x4f /* @pcrel(sym + add), data8 LSB */ ++#define R_IA64_LTOFF_FPTR22 0x52 /* @ltoff(@fptr(s+a)), imm22 */ ++#define R_IA64_LTOFF_FPTR64I 0x53 /* @ltoff(@fptr(s+a)), imm64 */ ++#define R_IA64_LTOFF_FPTR32MSB 0x54 /* @ltoff(@fptr(s+a)), data4 MSB */ ++#define R_IA64_LTOFF_FPTR32LSB 0x55 /* @ltoff(@fptr(s+a)), data4 LSB */ ++#define R_IA64_LTOFF_FPTR64MSB 0x56 /* @ltoff(@fptr(s+a)), data8 MSB */ ++#define R_IA64_LTOFF_FPTR64LSB 0x57 /* @ltoff(@fptr(s+a)), data8 LSB */ ++#define R_IA64_SEGREL32MSB 0x5c /* @segrel(sym + add), data4 MSB */ ++#define R_IA64_SEGREL32LSB 0x5d /* @segrel(sym + add), data4 LSB */ ++#define R_IA64_SEGREL64MSB 0x5e /* @segrel(sym + add), data8 MSB */ ++#define R_IA64_SEGREL64LSB 0x5f /* @segrel(sym + add), data8 LSB */ ++#define R_IA64_SECREL32MSB 0x64 /* @secrel(sym + add), data4 MSB */ ++#define R_IA64_SECREL32LSB 0x65 /* @secrel(sym + add), data4 LSB */ ++#define R_IA64_SECREL64MSB 0x66 /* @secrel(sym + add), data8 MSB */ ++#define R_IA64_SECREL64LSB 0x67 /* @secrel(sym + add), data8 LSB */ ++#define R_IA64_REL32MSB 0x6c /* data 4 + REL */ ++#define R_IA64_REL32LSB 0x6d /* data 4 + REL */ ++#define R_IA64_REL64MSB 0x6e /* data 8 + REL */ ++#define R_IA64_REL64LSB 0x6f /* data 8 + REL */ ++#define R_IA64_LTV32MSB 0x74 /* symbol + addend, data4 MSB */ ++#define R_IA64_LTV32LSB 0x75 /* symbol + addend, data4 LSB */ ++#define R_IA64_LTV64MSB 0x76 /* symbol + addend, data8 MSB */ ++#define R_IA64_LTV64LSB 0x77 /* symbol + addend, data8 LSB */ ++#define R_IA64_PCREL21BI 0x79 /* @pcrel(sym + add), 21bit inst */ ++#define R_IA64_PCREL22 0x7a /* @pcrel(sym + add), 22bit inst */ ++#define R_IA64_PCREL64I 0x7b /* @pcrel(sym + add), 64bit inst */ ++#define R_IA64_IPLTMSB 0x80 /* dynamic reloc, imported PLT, MSB */ ++#define R_IA64_IPLTLSB 0x81 /* dynamic reloc, imported PLT, LSB */ ++#define R_IA64_COPY 0x84 /* copy relocation */ ++#define R_IA64_SUB 0x85 /* Addend and symbol difference */ ++#define R_IA64_LTOFF22X 0x86 /* LTOFF22, relaxable. */ ++#define R_IA64_LDXMOV 0x87 /* Use of LTOFF22X. */ ++#define R_IA64_TPREL14 0x91 /* @tprel(sym + add), imm14 */ ++#define R_IA64_TPREL22 0x92 /* @tprel(sym + add), imm22 */ ++#define R_IA64_TPREL64I 0x93 /* @tprel(sym + add), imm64 */ ++#define R_IA64_TPREL64MSB 0x96 /* @tprel(sym + add), data8 MSB */ ++#define R_IA64_TPREL64LSB 0x97 /* @tprel(sym + add), data8 LSB */ ++#define R_IA64_LTOFF_TPREL22 0x9a /* @ltoff(@tprel(s+a)), imm2 */ ++#define R_IA64_DTPMOD64MSB 0xa6 /* @dtpmod(sym + add), data8 MSB */ ++#define R_IA64_DTPMOD64LSB 0xa7 /* @dtpmod(sym + add), data8 LSB */ ++#define R_IA64_LTOFF_DTPMOD22 0xaa /* @ltoff(@dtpmod(sym + add)), imm22 */ ++#define R_IA64_DTPREL14 0xb1 /* @dtprel(sym + add), imm14 */ ++#define R_IA64_DTPREL22 0xb2 /* @dtprel(sym + add), imm22 */ ++#define R_IA64_DTPREL64I 0xb3 /* @dtprel(sym + add), imm64 */ ++#define R_IA64_DTPREL32MSB 0xb4 /* @dtprel(sym + add), data4 MSB */ ++#define R_IA64_DTPREL32LSB 0xb5 /* @dtprel(sym + add), data4 LSB */ ++#define R_IA64_DTPREL64MSB 0xb6 /* @dtprel(sym + add), data8 MSB */ ++#define R_IA64_DTPREL64LSB 0xb7 /* @dtprel(sym + add), data8 LSB */ ++#define R_IA64_LTOFF_DTPREL22 0xba /* @ltoff(@dtprel(s+a)), imm22 */ ++ ++/* SH specific declarations */ ++ ++/* Processor specific flags for the ELF header e_flags field. */ ++#define EF_SH_MACH_MASK 0x1f ++#define EF_SH_UNKNOWN 0x0 ++#define EF_SH1 0x1 ++#define EF_SH2 0x2 ++#define EF_SH3 0x3 ++#define EF_SH_DSP 0x4 ++#define EF_SH3_DSP 0x5 ++#define EF_SH4AL_DSP 0x6 ++#define EF_SH3E 0x8 ++#define EF_SH4 0x9 ++#define EF_SH2E 0xb ++#define EF_SH4A 0xc ++#define EF_SH2A 0xd ++#define EF_SH4_NOFPU 0x10 ++#define EF_SH4A_NOFPU 0x11 ++#define EF_SH4_NOMMU_NOFPU 0x12 ++#define EF_SH2A_NOFPU 0x13 ++#define EF_SH3_NOMMU 0x14 ++#define EF_SH2A_SH4_NOFPU 0x15 ++#define EF_SH2A_SH3_NOFPU 0x16 ++#define EF_SH2A_SH4 0x17 ++#define EF_SH2A_SH3E 0x18 ++ ++/* SH relocs. */ ++#define R_SH_NONE 0 ++#define R_SH_DIR32 1 ++#define R_SH_REL32 2 ++#define R_SH_DIR8WPN 3 ++#define R_SH_IND12W 4 ++#define R_SH_DIR8WPL 5 ++#define R_SH_DIR8WPZ 6 ++#define R_SH_DIR8BP 7 ++#define R_SH_DIR8W 8 ++#define R_SH_DIR8L 9 ++#define R_SH_SWITCH16 25 ++#define R_SH_SWITCH32 26 ++#define R_SH_USES 27 ++#define R_SH_COUNT 28 ++#define R_SH_ALIGN 29 ++#define R_SH_CODE 30 ++#define R_SH_DATA 31 ++#define R_SH_LABEL 32 ++#define R_SH_SWITCH8 33 ++#define R_SH_GNU_VTINHERIT 34 ++#define R_SH_GNU_VTENTRY 35 ++#define R_SH_TLS_GD_32 144 ++#define R_SH_TLS_LD_32 145 ++#define R_SH_TLS_LDO_32 146 ++#define R_SH_TLS_IE_32 147 ++#define R_SH_TLS_LE_32 148 ++#define R_SH_TLS_DTPMOD32 149 ++#define R_SH_TLS_DTPOFF32 150 ++#define R_SH_TLS_TPOFF32 151 ++#define R_SH_GOT32 160 ++#define R_SH_PLT32 161 ++#define R_SH_COPY 162 ++#define R_SH_GLOB_DAT 163 ++#define R_SH_JMP_SLOT 164 ++#define R_SH_RELATIVE 165 ++#define R_SH_GOTOFF 166 ++#define R_SH_GOTPC 167 ++/* Keep this the last entry. */ ++#define R_SH_NUM 256 ++ ++/* S/390 specific definitions. */ ++ ++/* Valid values for the e_flags field. */ ++ ++#define EF_S390_HIGH_GPRS 0x00000001 /* High GPRs kernel facility needed. */ ++ ++/* Additional s390 relocs */ ++ ++#define R_390_NONE 0 /* No reloc. */ ++#define R_390_8 1 /* Direct 8 bit. */ ++#define R_390_12 2 /* Direct 12 bit. */ ++#define R_390_16 3 /* Direct 16 bit. */ ++#define R_390_32 4 /* Direct 32 bit. */ ++#define R_390_PC32 5 /* PC relative 32 bit. */ ++#define R_390_GOT12 6 /* 12 bit GOT offset. */ ++#define R_390_GOT32 7 /* 32 bit GOT offset. */ ++#define R_390_PLT32 8 /* 32 bit PC relative PLT address. */ ++#define R_390_COPY 9 /* Copy symbol at runtime. */ ++#define R_390_GLOB_DAT 10 /* Create GOT entry. */ ++#define R_390_JMP_SLOT 11 /* Create PLT entry. */ ++#define R_390_RELATIVE 12 /* Adjust by program base. */ ++#define R_390_GOTOFF32 13 /* 32 bit offset to GOT. */ ++#define R_390_GOTPC 14 /* 32 bit PC relative offset to GOT. */ ++#define R_390_GOT16 15 /* 16 bit GOT offset. */ ++#define R_390_PC16 16 /* PC relative 16 bit. */ ++#define R_390_PC16DBL 17 /* PC relative 16 bit shifted by 1. */ ++#define R_390_PLT16DBL 18 /* 16 bit PC rel. PLT shifted by 1. */ ++#define R_390_PC32DBL 19 /* PC relative 32 bit shifted by 1. */ ++#define R_390_PLT32DBL 20 /* 32 bit PC rel. PLT shifted by 1. */ ++#define R_390_GOTPCDBL 21 /* 32 bit PC rel. GOT shifted by 1. */ ++#define R_390_64 22 /* Direct 64 bit. */ ++#define R_390_PC64 23 /* PC relative 64 bit. */ ++#define R_390_GOT64 24 /* 64 bit GOT offset. */ ++#define R_390_PLT64 25 /* 64 bit PC relative PLT address. */ ++#define R_390_GOTENT 26 /* 32 bit PC rel. to GOT entry >> 1. */ ++#define R_390_GOTOFF16 27 /* 16 bit offset to GOT. */ ++#define R_390_GOTOFF64 28 /* 64 bit offset to GOT. */ ++#define R_390_GOTPLT12 29 /* 12 bit offset to jump slot. */ ++#define R_390_GOTPLT16 30 /* 16 bit offset to jump slot. */ ++#define R_390_GOTPLT32 31 /* 32 bit offset to jump slot. */ ++#define R_390_GOTPLT64 32 /* 64 bit offset to jump slot. */ ++#define R_390_GOTPLTENT 33 /* 32 bit rel. offset to jump slot. */ ++#define R_390_PLTOFF16 34 /* 16 bit offset from GOT to PLT. */ ++#define R_390_PLTOFF32 35 /* 32 bit offset from GOT to PLT. */ ++#define R_390_PLTOFF64 36 /* 16 bit offset from GOT to PLT. */ ++#define R_390_TLS_LOAD 37 /* Tag for load insn in TLS code. */ ++#define R_390_TLS_GDCALL 38 /* Tag for function call in general ++ dynamic TLS code. */ ++#define R_390_TLS_LDCALL 39 /* Tag for function call in local ++ dynamic TLS code. */ ++#define R_390_TLS_GD32 40 /* Direct 32 bit for general dynamic ++ thread local data. */ ++#define R_390_TLS_GD64 41 /* Direct 64 bit for general dynamic ++ thread local data. */ ++#define R_390_TLS_GOTIE12 42 /* 12 bit GOT offset for static TLS ++ block offset. */ ++#define R_390_TLS_GOTIE32 43 /* 32 bit GOT offset for static TLS ++ block offset. */ ++#define R_390_TLS_GOTIE64 44 /* 64 bit GOT offset for static TLS ++ block offset. */ ++#define R_390_TLS_LDM32 45 /* Direct 32 bit for local dynamic ++ thread local data in LE code. */ ++#define R_390_TLS_LDM64 46 /* Direct 64 bit for local dynamic ++ thread local data in LE code. */ ++#define R_390_TLS_IE32 47 /* 32 bit address of GOT entry for ++ negated static TLS block offset. */ ++#define R_390_TLS_IE64 48 /* 64 bit address of GOT entry for ++ negated static TLS block offset. */ ++#define R_390_TLS_IEENT 49 /* 32 bit rel. offset to GOT entry for ++ negated static TLS block offset. */ ++#define R_390_TLS_LE32 50 /* 32 bit negated offset relative to ++ static TLS block. */ ++#define R_390_TLS_LE64 51 /* 64 bit negated offset relative to ++ static TLS block. */ ++#define R_390_TLS_LDO32 52 /* 32 bit offset relative to TLS ++ block. */ ++#define R_390_TLS_LDO64 53 /* 64 bit offset relative to TLS ++ block. */ ++#define R_390_TLS_DTPMOD 54 /* ID of module containing symbol. */ ++#define R_390_TLS_DTPOFF 55 /* Offset in TLS block. */ ++#define R_390_TLS_TPOFF 56 /* Negated offset in static TLS ++ block. */ ++#define R_390_20 57 /* Direct 20 bit. */ ++#define R_390_GOT20 58 /* 20 bit GOT offset. */ ++#define R_390_GOTPLT20 59 /* 20 bit offset to jump slot. */ ++#define R_390_TLS_GOTIE20 60 /* 20 bit GOT offset for static TLS ++ block offset. */ ++#define R_390_IRELATIVE 61 /* STT_GNU_IFUNC relocation. */ ++/* Keep this the last entry. */ ++#define R_390_NUM 62 ++ ++ ++/* CRIS relocations. */ ++#define R_CRIS_NONE 0 ++#define R_CRIS_8 1 ++#define R_CRIS_16 2 ++#define R_CRIS_32 3 ++#define R_CRIS_8_PCREL 4 ++#define R_CRIS_16_PCREL 5 ++#define R_CRIS_32_PCREL 6 ++#define R_CRIS_GNU_VTINHERIT 7 ++#define R_CRIS_GNU_VTENTRY 8 ++#define R_CRIS_COPY 9 ++#define R_CRIS_GLOB_DAT 10 ++#define R_CRIS_JUMP_SLOT 11 ++#define R_CRIS_RELATIVE 12 ++#define R_CRIS_16_GOT 13 ++#define R_CRIS_32_GOT 14 ++#define R_CRIS_16_GOTPLT 15 ++#define R_CRIS_32_GOTPLT 16 ++#define R_CRIS_32_GOTREL 17 ++#define R_CRIS_32_PLT_GOTREL 18 ++#define R_CRIS_32_PLT_PCREL 19 ++ ++#define R_CRIS_NUM 20 ++ ++ ++/* AMD x86-64 relocations. */ ++#define R_X86_64_NONE 0 /* No reloc */ ++#define R_X86_64_64 1 /* Direct 64 bit */ ++#define R_X86_64_PC32 2 /* PC relative 32 bit signed */ ++#define R_X86_64_GOT32 3 /* 32 bit GOT entry */ ++#define R_X86_64_PLT32 4 /* 32 bit PLT address */ ++#define R_X86_64_COPY 5 /* Copy symbol at runtime */ ++#define R_X86_64_GLOB_DAT 6 /* Create GOT entry */ ++#define R_X86_64_JUMP_SLOT 7 /* Create PLT entry */ ++#define R_X86_64_RELATIVE 8 /* Adjust by program base */ ++#define R_X86_64_GOTPCREL 9 /* 32 bit signed PC relative ++ offset to GOT */ ++#define R_X86_64_32 10 /* Direct 32 bit zero extended */ ++#define R_X86_64_32S 11 /* Direct 32 bit sign extended */ ++#define R_X86_64_16 12 /* Direct 16 bit zero extended */ ++#define R_X86_64_PC16 13 /* 16 bit sign extended pc relative */ ++#define R_X86_64_8 14 /* Direct 8 bit sign extended */ ++#define R_X86_64_PC8 15 /* 8 bit sign extended pc relative */ ++#define R_X86_64_DTPMOD64 16 /* ID of module containing symbol */ ++#define R_X86_64_DTPOFF64 17 /* Offset in module's TLS block */ ++#define R_X86_64_TPOFF64 18 /* Offset in initial TLS block */ ++#define R_X86_64_TLSGD 19 /* 32 bit signed PC relative offset ++ to two GOT entries for GD symbol */ ++#define R_X86_64_TLSLD 20 /* 32 bit signed PC relative offset ++ to two GOT entries for LD symbol */ ++#define R_X86_64_DTPOFF32 21 /* Offset in TLS block */ ++#define R_X86_64_GOTTPOFF 22 /* 32 bit signed PC relative offset ++ to GOT entry for IE symbol */ ++#define R_X86_64_TPOFF32 23 /* Offset in initial TLS block */ ++#define R_X86_64_PC64 24 /* PC relative 64 bit */ ++#define R_X86_64_GOTOFF64 25 /* 64 bit offset to GOT */ ++#define R_X86_64_GOTPC32 26 /* 32 bit signed pc relative ++ offset to GOT */ ++#define R_X86_64_GOT64 27 /* 64-bit GOT entry offset */ ++#define R_X86_64_GOTPCREL64 28 /* 64-bit PC relative offset ++ to GOT entry */ ++#define R_X86_64_GOTPC64 29 /* 64-bit PC relative offset to GOT */ ++#define R_X86_64_GOTPLT64 30 /* like GOT64, says PLT entry needed */ ++#define R_X86_64_PLTOFF64 31 /* 64-bit GOT relative offset ++ to PLT entry */ ++#define R_X86_64_SIZE32 32 /* Size of symbol plus 32-bit addend */ ++#define R_X86_64_SIZE64 33 /* Size of symbol plus 64-bit addend */ ++#define R_X86_64_GOTPC32_TLSDESC 34 /* GOT offset for TLS descriptor. */ ++#define R_X86_64_TLSDESC_CALL 35 /* Marker for call through TLS ++ descriptor. */ ++#define R_X86_64_TLSDESC 36 /* TLS descriptor. */ ++#define R_X86_64_IRELATIVE 37 /* Adjust indirectly by program base */ ++#define R_X86_64_RELATIVE64 38 /* 64-bit adjust by program base */ ++ ++#define R_X86_64_NUM 39 ++ ++ ++/* AM33 relocations. */ ++#define R_MN10300_NONE 0 /* No reloc. */ ++#define R_MN10300_32 1 /* Direct 32 bit. */ ++#define R_MN10300_16 2 /* Direct 16 bit. */ ++#define R_MN10300_8 3 /* Direct 8 bit. */ ++#define R_MN10300_PCREL32 4 /* PC-relative 32-bit. */ ++#define R_MN10300_PCREL16 5 /* PC-relative 16-bit signed. */ ++#define R_MN10300_PCREL8 6 /* PC-relative 8-bit signed. */ ++#define R_MN10300_GNU_VTINHERIT 7 /* Ancient C++ vtable garbage... */ ++#define R_MN10300_GNU_VTENTRY 8 /* ... collection annotation. */ ++#define R_MN10300_24 9 /* Direct 24 bit. */ ++#define R_MN10300_GOTPC32 10 /* 32-bit PCrel offset to GOT. */ ++#define R_MN10300_GOTPC16 11 /* 16-bit PCrel offset to GOT. */ ++#define R_MN10300_GOTOFF32 12 /* 32-bit offset from GOT. */ ++#define R_MN10300_GOTOFF24 13 /* 24-bit offset from GOT. */ ++#define R_MN10300_GOTOFF16 14 /* 16-bit offset from GOT. */ ++#define R_MN10300_PLT32 15 /* 32-bit PCrel to PLT entry. */ ++#define R_MN10300_PLT16 16 /* 16-bit PCrel to PLT entry. */ ++#define R_MN10300_GOT32 17 /* 32-bit offset to GOT entry. */ ++#define R_MN10300_GOT24 18 /* 24-bit offset to GOT entry. */ ++#define R_MN10300_GOT16 19 /* 16-bit offset to GOT entry. */ ++#define R_MN10300_COPY 20 /* Copy symbol at runtime. */ ++#define R_MN10300_GLOB_DAT 21 /* Create GOT entry. */ ++#define R_MN10300_JMP_SLOT 22 /* Create PLT entry. */ ++#define R_MN10300_RELATIVE 23 /* Adjust by program base. */ ++ ++#define R_MN10300_NUM 24 ++ ++ ++/* M32R relocs. */ ++#define R_M32R_NONE 0 /* No reloc. */ ++#define R_M32R_16 1 /* Direct 16 bit. */ ++#define R_M32R_32 2 /* Direct 32 bit. */ ++#define R_M32R_24 3 /* Direct 24 bit. */ ++#define R_M32R_10_PCREL 4 /* PC relative 10 bit shifted. */ ++#define R_M32R_18_PCREL 5 /* PC relative 18 bit shifted. */ ++#define R_M32R_26_PCREL 6 /* PC relative 26 bit shifted. */ ++#define R_M32R_HI16_ULO 7 /* High 16 bit with unsigned low. */ ++#define R_M32R_HI16_SLO 8 /* High 16 bit with signed low. */ ++#define R_M32R_LO16 9 /* Low 16 bit. */ ++#define R_M32R_SDA16 10 /* 16 bit offset in SDA. */ ++#define R_M32R_GNU_VTINHERIT 11 ++#define R_M32R_GNU_VTENTRY 12 ++/* M32R relocs use SHT_RELA. */ ++#define R_M32R_16_RELA 33 /* Direct 16 bit. */ ++#define R_M32R_32_RELA 34 /* Direct 32 bit. */ ++#define R_M32R_24_RELA 35 /* Direct 24 bit. */ ++#define R_M32R_10_PCREL_RELA 36 /* PC relative 10 bit shifted. */ ++#define R_M32R_18_PCREL_RELA 37 /* PC relative 18 bit shifted. */ ++#define R_M32R_26_PCREL_RELA 38 /* PC relative 26 bit shifted. */ ++#define R_M32R_HI16_ULO_RELA 39 /* High 16 bit with unsigned low */ ++#define R_M32R_HI16_SLO_RELA 40 /* High 16 bit with signed low */ ++#define R_M32R_LO16_RELA 41 /* Low 16 bit */ ++#define R_M32R_SDA16_RELA 42 /* 16 bit offset in SDA */ ++#define R_M32R_RELA_GNU_VTINHERIT 43 ++#define R_M32R_RELA_GNU_VTENTRY 44 ++#define R_M32R_REL32 45 /* PC relative 32 bit. */ ++ ++#define R_M32R_GOT24 48 /* 24 bit GOT entry */ ++#define R_M32R_26_PLTREL 49 /* 26 bit PC relative to PLT shifted */ ++#define R_M32R_COPY 50 /* Copy symbol at runtime */ ++#define R_M32R_GLOB_DAT 51 /* Create GOT entry */ ++#define R_M32R_JMP_SLOT 52 /* Create PLT entry */ ++#define R_M32R_RELATIVE 53 /* Adjust by program base */ ++#define R_M32R_GOTOFF 54 /* 24 bit offset to GOT */ ++#define R_M32R_GOTPC24 55 /* 24 bit PC relative offset to GOT */ ++#define R_M32R_GOT16_HI_ULO 56 /* High 16 bit GOT entry with unsigned ++ low */ ++#define R_M32R_GOT16_HI_SLO 57 /* High 16 bit GOT entry with signed ++ low */ ++#define R_M32R_GOT16_LO 58 /* Low 16 bit GOT entry */ ++#define R_M32R_GOTPC_HI_ULO 59 /* High 16 bit PC relative offset to ++ GOT with unsigned low */ ++#define R_M32R_GOTPC_HI_SLO 60 /* High 16 bit PC relative offset to ++ GOT with signed low */ ++#define R_M32R_GOTPC_LO 61 /* Low 16 bit PC relative offset to ++ GOT */ ++#define R_M32R_GOTOFF_HI_ULO 62 /* High 16 bit offset to GOT ++ with unsigned low */ ++#define R_M32R_GOTOFF_HI_SLO 63 /* High 16 bit offset to GOT ++ with signed low */ ++#define R_M32R_GOTOFF_LO 64 /* Low 16 bit offset to GOT */ ++#define R_M32R_NUM 256 /* Keep this the last entry. */ ++ ++ ++/* TILEPro relocations. */ ++#define R_TILEPRO_NONE 0 /* No reloc */ ++#define R_TILEPRO_32 1 /* Direct 32 bit */ ++#define R_TILEPRO_16 2 /* Direct 16 bit */ ++#define R_TILEPRO_8 3 /* Direct 8 bit */ ++#define R_TILEPRO_32_PCREL 4 /* PC relative 32 bit */ ++#define R_TILEPRO_16_PCREL 5 /* PC relative 16 bit */ ++#define R_TILEPRO_8_PCREL 6 /* PC relative 8 bit */ ++#define R_TILEPRO_LO16 7 /* Low 16 bit */ ++#define R_TILEPRO_HI16 8 /* High 16 bit */ ++#define R_TILEPRO_HA16 9 /* High 16 bit, adjusted */ ++#define R_TILEPRO_COPY 10 /* Copy relocation */ ++#define R_TILEPRO_GLOB_DAT 11 /* Create GOT entry */ ++#define R_TILEPRO_JMP_SLOT 12 /* Create PLT entry */ ++#define R_TILEPRO_RELATIVE 13 /* Adjust by program base */ ++#define R_TILEPRO_BROFF_X1 14 /* X1 pipe branch offset */ ++#define R_TILEPRO_JOFFLONG_X1 15 /* X1 pipe jump offset */ ++#define R_TILEPRO_JOFFLONG_X1_PLT 16 /* X1 pipe jump offset to PLT */ ++#define R_TILEPRO_IMM8_X0 17 /* X0 pipe 8-bit */ ++#define R_TILEPRO_IMM8_Y0 18 /* Y0 pipe 8-bit */ ++#define R_TILEPRO_IMM8_X1 19 /* X1 pipe 8-bit */ ++#define R_TILEPRO_IMM8_Y1 20 /* Y1 pipe 8-bit */ ++#define R_TILEPRO_MT_IMM15_X1 21 /* X1 pipe mtspr */ ++#define R_TILEPRO_MF_IMM15_X1 22 /* X1 pipe mfspr */ ++#define R_TILEPRO_IMM16_X0 23 /* X0 pipe 16-bit */ ++#define R_TILEPRO_IMM16_X1 24 /* X1 pipe 16-bit */ ++#define R_TILEPRO_IMM16_X0_LO 25 /* X0 pipe low 16-bit */ ++#define R_TILEPRO_IMM16_X1_LO 26 /* X1 pipe low 16-bit */ ++#define R_TILEPRO_IMM16_X0_HI 27 /* X0 pipe high 16-bit */ ++#define R_TILEPRO_IMM16_X1_HI 28 /* X1 pipe high 16-bit */ ++#define R_TILEPRO_IMM16_X0_HA 29 /* X0 pipe high 16-bit, adjusted */ ++#define R_TILEPRO_IMM16_X1_HA 30 /* X1 pipe high 16-bit, adjusted */ ++#define R_TILEPRO_IMM16_X0_PCREL 31 /* X0 pipe PC relative 16 bit */ ++#define R_TILEPRO_IMM16_X1_PCREL 32 /* X1 pipe PC relative 16 bit */ ++#define R_TILEPRO_IMM16_X0_LO_PCREL 33 /* X0 pipe PC relative low 16 bit */ ++#define R_TILEPRO_IMM16_X1_LO_PCREL 34 /* X1 pipe PC relative low 16 bit */ ++#define R_TILEPRO_IMM16_X0_HI_PCREL 35 /* X0 pipe PC relative high 16 bit */ ++#define R_TILEPRO_IMM16_X1_HI_PCREL 36 /* X1 pipe PC relative high 16 bit */ ++#define R_TILEPRO_IMM16_X0_HA_PCREL 37 /* X0 pipe PC relative ha() 16 bit */ ++#define R_TILEPRO_IMM16_X1_HA_PCREL 38 /* X1 pipe PC relative ha() 16 bit */ ++#define R_TILEPRO_IMM16_X0_GOT 39 /* X0 pipe 16-bit GOT offset */ ++#define R_TILEPRO_IMM16_X1_GOT 40 /* X1 pipe 16-bit GOT offset */ ++#define R_TILEPRO_IMM16_X0_GOT_LO 41 /* X0 pipe low 16-bit GOT offset */ ++#define R_TILEPRO_IMM16_X1_GOT_LO 42 /* X1 pipe low 16-bit GOT offset */ ++#define R_TILEPRO_IMM16_X0_GOT_HI 43 /* X0 pipe high 16-bit GOT offset */ ++#define R_TILEPRO_IMM16_X1_GOT_HI 44 /* X1 pipe high 16-bit GOT offset */ ++#define R_TILEPRO_IMM16_X0_GOT_HA 45 /* X0 pipe ha() 16-bit GOT offset */ ++#define R_TILEPRO_IMM16_X1_GOT_HA 46 /* X1 pipe ha() 16-bit GOT offset */ ++#define R_TILEPRO_MMSTART_X0 47 /* X0 pipe mm "start" */ ++#define R_TILEPRO_MMEND_X0 48 /* X0 pipe mm "end" */ ++#define R_TILEPRO_MMSTART_X1 49 /* X1 pipe mm "start" */ ++#define R_TILEPRO_MMEND_X1 50 /* X1 pipe mm "end" */ ++#define R_TILEPRO_SHAMT_X0 51 /* X0 pipe shift amount */ ++#define R_TILEPRO_SHAMT_X1 52 /* X1 pipe shift amount */ ++#define R_TILEPRO_SHAMT_Y0 53 /* Y0 pipe shift amount */ ++#define R_TILEPRO_SHAMT_Y1 54 /* Y1 pipe shift amount */ ++#define R_TILEPRO_DEST_IMM8_X1 55 /* X1 pipe destination 8-bit */ ++/* Relocs 56-59 are currently not defined. */ ++#define R_TILEPRO_TLS_GD_CALL 60 /* "jal" for TLS GD */ ++#define R_TILEPRO_IMM8_X0_TLS_GD_ADD 61 /* X0 pipe "addi" for TLS GD */ ++#define R_TILEPRO_IMM8_X1_TLS_GD_ADD 62 /* X1 pipe "addi" for TLS GD */ ++#define R_TILEPRO_IMM8_Y0_TLS_GD_ADD 63 /* Y0 pipe "addi" for TLS GD */ ++#define R_TILEPRO_IMM8_Y1_TLS_GD_ADD 64 /* Y1 pipe "addi" for TLS GD */ ++#define R_TILEPRO_TLS_IE_LOAD 65 /* "lw_tls" for TLS IE */ ++#define R_TILEPRO_IMM16_X0_TLS_GD 66 /* X0 pipe 16-bit TLS GD offset */ ++#define R_TILEPRO_IMM16_X1_TLS_GD 67 /* X1 pipe 16-bit TLS GD offset */ ++#define R_TILEPRO_IMM16_X0_TLS_GD_LO 68 /* X0 pipe low 16-bit TLS GD offset */ ++#define R_TILEPRO_IMM16_X1_TLS_GD_LO 69 /* X1 pipe low 16-bit TLS GD offset */ ++#define R_TILEPRO_IMM16_X0_TLS_GD_HI 70 /* X0 pipe high 16-bit TLS GD offset */ ++#define R_TILEPRO_IMM16_X1_TLS_GD_HI 71 /* X1 pipe high 16-bit TLS GD offset */ ++#define R_TILEPRO_IMM16_X0_TLS_GD_HA 72 /* X0 pipe ha() 16-bit TLS GD offset */ ++#define R_TILEPRO_IMM16_X1_TLS_GD_HA 73 /* X1 pipe ha() 16-bit TLS GD offset */ ++#define R_TILEPRO_IMM16_X0_TLS_IE 74 /* X0 pipe 16-bit TLS IE offset */ ++#define R_TILEPRO_IMM16_X1_TLS_IE 75 /* X1 pipe 16-bit TLS IE offset */ ++#define R_TILEPRO_IMM16_X0_TLS_IE_LO 76 /* X0 pipe low 16-bit TLS IE offset */ ++#define R_TILEPRO_IMM16_X1_TLS_IE_LO 77 /* X1 pipe low 16-bit TLS IE offset */ ++#define R_TILEPRO_IMM16_X0_TLS_IE_HI 78 /* X0 pipe high 16-bit TLS IE offset */ ++#define R_TILEPRO_IMM16_X1_TLS_IE_HI 79 /* X1 pipe high 16-bit TLS IE offset */ ++#define R_TILEPRO_IMM16_X0_TLS_IE_HA 80 /* X0 pipe ha() 16-bit TLS IE offset */ ++#define R_TILEPRO_IMM16_X1_TLS_IE_HA 81 /* X1 pipe ha() 16-bit TLS IE offset */ ++#define R_TILEPRO_TLS_DTPMOD32 82 /* ID of module containing symbol */ ++#define R_TILEPRO_TLS_DTPOFF32 83 /* Offset in TLS block */ ++#define R_TILEPRO_TLS_TPOFF32 84 /* Offset in static TLS block */ ++#define R_TILEPRO_IMM16_X0_TLS_LE 85 /* X0 pipe 16-bit TLS LE offset */ ++#define R_TILEPRO_IMM16_X1_TLS_LE 86 /* X1 pipe 16-bit TLS LE offset */ ++#define R_TILEPRO_IMM16_X0_TLS_LE_LO 87 /* X0 pipe low 16-bit TLS LE offset */ ++#define R_TILEPRO_IMM16_X1_TLS_LE_LO 88 /* X1 pipe low 16-bit TLS LE offset */ ++#define R_TILEPRO_IMM16_X0_TLS_LE_HI 89 /* X0 pipe high 16-bit TLS LE offset */ ++#define R_TILEPRO_IMM16_X1_TLS_LE_HI 90 /* X1 pipe high 16-bit TLS LE offset */ ++#define R_TILEPRO_IMM16_X0_TLS_LE_HA 91 /* X0 pipe ha() 16-bit TLS LE offset */ ++#define R_TILEPRO_IMM16_X1_TLS_LE_HA 92 /* X1 pipe ha() 16-bit TLS LE offset */ ++ ++#define R_TILEPRO_GNU_VTINHERIT 128 /* GNU C++ vtable hierarchy */ ++#define R_TILEPRO_GNU_VTENTRY 129 /* GNU C++ vtable member usage */ ++ ++#define R_TILEPRO_NUM 130 ++ ++ ++/* TILE-Gx relocations. */ ++#define R_TILEGX_NONE 0 /* No reloc */ ++#define R_TILEGX_64 1 /* Direct 64 bit */ ++#define R_TILEGX_32 2 /* Direct 32 bit */ ++#define R_TILEGX_16 3 /* Direct 16 bit */ ++#define R_TILEGX_8 4 /* Direct 8 bit */ ++#define R_TILEGX_64_PCREL 5 /* PC relative 64 bit */ ++#define R_TILEGX_32_PCREL 6 /* PC relative 32 bit */ ++#define R_TILEGX_16_PCREL 7 /* PC relative 16 bit */ ++#define R_TILEGX_8_PCREL 8 /* PC relative 8 bit */ ++#define R_TILEGX_HW0 9 /* hword 0 16-bit */ ++#define R_TILEGX_HW1 10 /* hword 1 16-bit */ ++#define R_TILEGX_HW2 11 /* hword 2 16-bit */ ++#define R_TILEGX_HW3 12 /* hword 3 16-bit */ ++#define R_TILEGX_HW0_LAST 13 /* last hword 0 16-bit */ ++#define R_TILEGX_HW1_LAST 14 /* last hword 1 16-bit */ ++#define R_TILEGX_HW2_LAST 15 /* last hword 2 16-bit */ ++#define R_TILEGX_COPY 16 /* Copy relocation */ ++#define R_TILEGX_GLOB_DAT 17 /* Create GOT entry */ ++#define R_TILEGX_JMP_SLOT 18 /* Create PLT entry */ ++#define R_TILEGX_RELATIVE 19 /* Adjust by program base */ ++#define R_TILEGX_BROFF_X1 20 /* X1 pipe branch offset */ ++#define R_TILEGX_JUMPOFF_X1 21 /* X1 pipe jump offset */ ++#define R_TILEGX_JUMPOFF_X1_PLT 22 /* X1 pipe jump offset to PLT */ ++#define R_TILEGX_IMM8_X0 23 /* X0 pipe 8-bit */ ++#define R_TILEGX_IMM8_Y0 24 /* Y0 pipe 8-bit */ ++#define R_TILEGX_IMM8_X1 25 /* X1 pipe 8-bit */ ++#define R_TILEGX_IMM8_Y1 26 /* Y1 pipe 8-bit */ ++#define R_TILEGX_DEST_IMM8_X1 27 /* X1 pipe destination 8-bit */ ++#define R_TILEGX_MT_IMM14_X1 28 /* X1 pipe mtspr */ ++#define R_TILEGX_MF_IMM14_X1 29 /* X1 pipe mfspr */ ++#define R_TILEGX_MMSTART_X0 30 /* X0 pipe mm "start" */ ++#define R_TILEGX_MMEND_X0 31 /* X0 pipe mm "end" */ ++#define R_TILEGX_SHAMT_X0 32 /* X0 pipe shift amount */ ++#define R_TILEGX_SHAMT_X1 33 /* X1 pipe shift amount */ ++#define R_TILEGX_SHAMT_Y0 34 /* Y0 pipe shift amount */ ++#define R_TILEGX_SHAMT_Y1 35 /* Y1 pipe shift amount */ ++#define R_TILEGX_IMM16_X0_HW0 36 /* X0 pipe hword 0 */ ++#define R_TILEGX_IMM16_X1_HW0 37 /* X1 pipe hword 0 */ ++#define R_TILEGX_IMM16_X0_HW1 38 /* X0 pipe hword 1 */ ++#define R_TILEGX_IMM16_X1_HW1 39 /* X1 pipe hword 1 */ ++#define R_TILEGX_IMM16_X0_HW2 40 /* X0 pipe hword 2 */ ++#define R_TILEGX_IMM16_X1_HW2 41 /* X1 pipe hword 2 */ ++#define R_TILEGX_IMM16_X0_HW3 42 /* X0 pipe hword 3 */ ++#define R_TILEGX_IMM16_X1_HW3 43 /* X1 pipe hword 3 */ ++#define R_TILEGX_IMM16_X0_HW0_LAST 44 /* X0 pipe last hword 0 */ ++#define R_TILEGX_IMM16_X1_HW0_LAST 45 /* X1 pipe last hword 0 */ ++#define R_TILEGX_IMM16_X0_HW1_LAST 46 /* X0 pipe last hword 1 */ ++#define R_TILEGX_IMM16_X1_HW1_LAST 47 /* X1 pipe last hword 1 */ ++#define R_TILEGX_IMM16_X0_HW2_LAST 48 /* X0 pipe last hword 2 */ ++#define R_TILEGX_IMM16_X1_HW2_LAST 49 /* X1 pipe last hword 2 */ ++#define R_TILEGX_IMM16_X0_HW0_PCREL 50 /* X0 pipe PC relative hword 0 */ ++#define R_TILEGX_IMM16_X1_HW0_PCREL 51 /* X1 pipe PC relative hword 0 */ ++#define R_TILEGX_IMM16_X0_HW1_PCREL 52 /* X0 pipe PC relative hword 1 */ ++#define R_TILEGX_IMM16_X1_HW1_PCREL 53 /* X1 pipe PC relative hword 1 */ ++#define R_TILEGX_IMM16_X0_HW2_PCREL 54 /* X0 pipe PC relative hword 2 */ ++#define R_TILEGX_IMM16_X1_HW2_PCREL 55 /* X1 pipe PC relative hword 2 */ ++#define R_TILEGX_IMM16_X0_HW3_PCREL 56 /* X0 pipe PC relative hword 3 */ ++#define R_TILEGX_IMM16_X1_HW3_PCREL 57 /* X1 pipe PC relative hword 3 */ ++#define R_TILEGX_IMM16_X0_HW0_LAST_PCREL 58 /* X0 pipe PC-rel last hword 0 */ ++#define R_TILEGX_IMM16_X1_HW0_LAST_PCREL 59 /* X1 pipe PC-rel last hword 0 */ ++#define R_TILEGX_IMM16_X0_HW1_LAST_PCREL 60 /* X0 pipe PC-rel last hword 1 */ ++#define R_TILEGX_IMM16_X1_HW1_LAST_PCREL 61 /* X1 pipe PC-rel last hword 1 */ ++#define R_TILEGX_IMM16_X0_HW2_LAST_PCREL 62 /* X0 pipe PC-rel last hword 2 */ ++#define R_TILEGX_IMM16_X1_HW2_LAST_PCREL 63 /* X1 pipe PC-rel last hword 2 */ ++#define R_TILEGX_IMM16_X0_HW0_GOT 64 /* X0 pipe hword 0 GOT offset */ ++#define R_TILEGX_IMM16_X1_HW0_GOT 65 /* X1 pipe hword 0 GOT offset */ ++/* Relocs 66-71 are currently not defined. */ ++#define R_TILEGX_IMM16_X0_HW0_LAST_GOT 72 /* X0 pipe last hword 0 GOT offset */ ++#define R_TILEGX_IMM16_X1_HW0_LAST_GOT 73 /* X1 pipe last hword 0 GOT offset */ ++#define R_TILEGX_IMM16_X0_HW1_LAST_GOT 74 /* X0 pipe last hword 1 GOT offset */ ++#define R_TILEGX_IMM16_X1_HW1_LAST_GOT 75 /* X1 pipe last hword 1 GOT offset */ ++/* Relocs 76-77 are currently not defined. */ ++#define R_TILEGX_IMM16_X0_HW0_TLS_GD 78 /* X0 pipe hword 0 TLS GD offset */ ++#define R_TILEGX_IMM16_X1_HW0_TLS_GD 79 /* X1 pipe hword 0 TLS GD offset */ ++#define R_TILEGX_IMM16_X0_HW0_TLS_LE 80 /* X0 pipe hword 0 TLS LE offset */ ++#define R_TILEGX_IMM16_X1_HW0_TLS_LE 81 /* X1 pipe hword 0 TLS LE offset */ ++#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE 82 /* X0 pipe last hword 0 LE off */ ++#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE 83 /* X1 pipe last hword 0 LE off */ ++#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE 84 /* X0 pipe last hword 1 LE off */ ++#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE 85 /* X1 pipe last hword 1 LE off */ ++#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD 86 /* X0 pipe last hword 0 GD off */ ++#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD 87 /* X1 pipe last hword 0 GD off */ ++#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD 88 /* X0 pipe last hword 1 GD off */ ++#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD 89 /* X1 pipe last hword 1 GD off */ ++/* Relocs 90-91 are currently not defined. */ ++#define R_TILEGX_IMM16_X0_HW0_TLS_IE 92 /* X0 pipe hword 0 TLS IE offset */ ++#define R_TILEGX_IMM16_X1_HW0_TLS_IE 93 /* X1 pipe hword 0 TLS IE offset */ ++/* Relocs 94-99 are currently not defined. */ ++#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE 100 /* X0 pipe last hword 0 IE off */ ++#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE 101 /* X1 pipe last hword 0 IE off */ ++#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE 102 /* X0 pipe last hword 1 IE off */ ++#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE 103 /* X1 pipe last hword 1 IE off */ ++/* Relocs 104-105 are currently not defined. */ ++#define R_TILEGX_TLS_DTPMOD64 106 /* 64-bit ID of symbol's module */ ++#define R_TILEGX_TLS_DTPOFF64 107 /* 64-bit offset in TLS block */ ++#define R_TILEGX_TLS_TPOFF64 108 /* 64-bit offset in static TLS block */ ++#define R_TILEGX_TLS_DTPMOD32 109 /* 32-bit ID of symbol's module */ ++#define R_TILEGX_TLS_DTPOFF32 110 /* 32-bit offset in TLS block */ ++#define R_TILEGX_TLS_TPOFF32 111 /* 32-bit offset in static TLS block */ ++#define R_TILEGX_TLS_GD_CALL 112 /* "jal" for TLS GD */ ++#define R_TILEGX_IMM8_X0_TLS_GD_ADD 113 /* X0 pipe "addi" for TLS GD */ ++#define R_TILEGX_IMM8_X1_TLS_GD_ADD 114 /* X1 pipe "addi" for TLS GD */ ++#define R_TILEGX_IMM8_Y0_TLS_GD_ADD 115 /* Y0 pipe "addi" for TLS GD */ ++#define R_TILEGX_IMM8_Y1_TLS_GD_ADD 116 /* Y1 pipe "addi" for TLS GD */ ++#define R_TILEGX_TLS_IE_LOAD 117 /* "ld_tls" for TLS IE */ ++#define R_TILEGX_IMM8_X0_TLS_ADD 118 /* X0 pipe "addi" for TLS GD/IE */ ++#define R_TILEGX_IMM8_X1_TLS_ADD 119 /* X1 pipe "addi" for TLS GD/IE */ ++#define R_TILEGX_IMM8_Y0_TLS_ADD 120 /* Y0 pipe "addi" for TLS GD/IE */ ++#define R_TILEGX_IMM8_Y1_TLS_ADD 121 /* Y1 pipe "addi" for TLS GD/IE */ ++ ++#define R_TILEGX_GNU_VTINHERIT 128 /* GNU C++ vtable hierarchy */ ++#define R_TILEGX_GNU_VTENTRY 129 /* GNU C++ vtable member usage */ ++ ++#define R_TILEGX_NUM 130 ++ ++#endif /* elf.h */ +diff --git a/scripts/mod/mk_elfconfig.c b/scripts/mod/mk_elfconfig.c +index e8cee4e4bc73..bba672c0ac8d 100644 +--- a/scripts/mod/mk_elfconfig.c ++++ b/scripts/mod/mk_elfconfig.c +@@ -2,7 +2,11 @@ + #include + #include + #include ++#ifndef __APPLE__ + #include ++#else ++#include "elf.h" ++#endif + + int + main(int argc, char **argv) +diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h +index ada3a36cc4bc..b77c2b100c1c 100644 +--- a/scripts/mod/modpost.h ++++ b/scripts/mod/modpost.h +@@ -10,7 +10,11 @@ + #include + #include + #include ++#if !(defined(__APPLE__) || defined(__CYGWIN__)) + #include ++#else ++#include "elf.h" ++#endif + #include "../../include/linux/module_symbol.h" + + #include +-- +2.51.0 + + +From ce8e117a6d444db0417063bea67049d2a685dac8 Mon Sep 17 00:00:00 2001 +From: Kevin Darbyshire-Bryant +Date: Wed, 5 Feb 2020 18:36:43 +0000 +Subject: [PATCH 335/517] file2alias: build on macos + +Signed-off-by: Kevin Darbyshire-Bryant +--- + scripts/mod/file2alias.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c +index 721e0e9f17ca..70d9013cad52 100644 +--- a/scripts/mod/file2alias.c ++++ b/scripts/mod/file2alias.c +@@ -35,6 +35,9 @@ typedef uint32_t __u32; + typedef uint16_t __u16; + typedef unsigned char __u8; + ++#ifdef __APPLE__ ++#define uuid_t compat_uuid_t ++#endif + /* UUID types for backward compatibility, don't use in new code */ + typedef struct { + __u8 b[16]; +-- +2.51.0 + + +From 85b0cd39287de717d1d7b9165119a1ab54d8429c Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Fri, 7 Jul 2017 17:04:08 +0200 +Subject: [PATCH 336/517] kernel: fix linux/spi/spidev.h portability issues + with musl + +Felix will try to get this define included into musl + +lede-commit: 795e7cf60de19e7a076a46874fab7bb88b43bbff +Signed-off-by: Felix Fietkau +--- + include/uapi/linux/spi/spidev.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/include/uapi/linux/spi/spidev.h b/include/uapi/linux/spi/spidev.h +index 0c3da08f2aff..2a6d51008256 100644 +--- a/include/uapi/linux/spi/spidev.h ++++ b/include/uapi/linux/spi/spidev.h +@@ -93,7 +93,7 @@ struct spi_ioc_transfer { + + /* not all platforms use or _IOC_TYPECHECK() ... */ + #define SPI_MSGSIZE(N) \ +- ((((N)*(sizeof (struct spi_ioc_transfer))) < (1 << _IOC_SIZEBITS)) \ ++ ((((N)*(sizeof (struct spi_ioc_transfer))) < (1 << 13)) \ + ? ((N)*(sizeof (struct spi_ioc_transfer))) : 0) + #define SPI_IOC_MESSAGE(N) _IOW(SPI_IOC_MAGIC, 0, char[SPI_MSGSIZE(N)]) + +-- +2.51.0 + + +From e29ddf5fd71094fc52c65223084759947c6bd3a3 Mon Sep 17 00:00:00 2001 +From: Imre Kaloz +Date: Fri, 7 Jul 2017 17:06:55 +0200 +Subject: [PATCH 337/517] use the openwrt lzma options for now + +lede-commit: 548de949f392049420a6a1feeef118b30ab8ea8c +Signed-off-by: Imre Kaloz +--- + lib/decompress.c | 1 + + scripts/Makefile.lib | 4 ++-- + 2 files changed, 3 insertions(+), 2 deletions(-) + +diff --git a/lib/decompress.c b/lib/decompress.c +index ab3fc90ffc64..b9c1e51e4ebb 100644 +--- a/lib/decompress.c ++++ b/lib/decompress.c +@@ -53,6 +53,7 @@ static const struct compress_format compressed_formats[] __initconst = { + { {0x1f, 0x9e}, "gzip", gunzip }, + { {0x42, 0x5a}, "bzip2", bunzip2 }, + { {0x5d, 0x00}, "lzma", unlzma }, ++ { {0x6d, 0x00}, "lzma-openwrt", unlzma }, + { {0xfd, 0x37}, "xz", unxz }, + { {0x89, 0x4c}, "lzo", unlzo }, + { {0x02, 0x21}, "lz4", unlz4 }, +diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib +index 85e41c68c2c5..cc6992a801a7 100644 +--- a/scripts/Makefile.lib ++++ b/scripts/Makefile.lib +@@ -359,10 +359,10 @@ quiet_cmd_bzip2_with_size = BZIP2 $@ + # --------------------------------------------------------------------------- + + quiet_cmd_lzma = LZMA $@ +- cmd_lzma = cat $(real-prereqs) | $(LZMA) -9 > $@ ++ cmd_lzma = cat $(real-prereqs) | $(LZMA) e -d20 -lc1 -lp2 -pb2 -eos -si -so > $@ + + quiet_cmd_lzma_with_size = LZMA $@ +- cmd_lzma_with_size = { cat $(real-prereqs) | $(LZMA) -9; $(size_append); } > $@ ++ cmd_lzma_with_size = { cat $(real-prereqs) | $(LZMA) e -d20 -lc1 -lp2 -pb2 -eos -si -so; $(size_append); } > $@ + + quiet_cmd_lzo = LZO $@ + cmd_lzo = cat $(real-prereqs) | $(KLZOP) -9 > $@ +-- +2.51.0 + + +From c6d1cf47863c85f7ae9be28da8fac7c491fe4ecd Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Mon, 3 Nov 2025 15:50:16 +0100 +Subject: [PATCH 338/517] hack: net: remove bogus netfilter dependencies + +lede-commit: 589d2a377dee27d206fc3725325309cf649e4df6 +Signed-off-by: Felix Fietkau +--- + net/netfilter/Kconfig | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig +index df2dc21304ef..f7cde787a680 100644 +--- a/net/netfilter/Kconfig ++++ b/net/netfilter/Kconfig +@@ -259,7 +259,6 @@ config NF_CONNTRACK_FTP + + config NF_CONNTRACK_H323 + tristate "H.323 protocol support" +- depends on IPV6 || IPV6=n + depends on NETFILTER_ADVANCED + help + H.323 is a VoIP signalling protocol from ITU-T. As one of the most +@@ -1120,7 +1119,6 @@ config NETFILTER_XT_TARGET_SECMARK + + config NETFILTER_XT_TARGET_TCPMSS + tristate '"TCPMSS" target support' +- depends on IPV6 || IPV6=n + default m if NETFILTER_ADVANCED=n + help + This option adds a `TCPMSS' target, which allows you to alter the +-- +2.51.0 + + +From d3f50001d74545ae24daed6e79a96c24cb8823ac Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Fri, 7 Jul 2017 17:09:21 +0200 +Subject: [PATCH 339/517] kconfig: owrt specifc dependencies + +Signed-off-by: John Crispin +--- + crypto/Kconfig | 10 +++++----- + drivers/bcma/Kconfig | 1 + + drivers/ssb/Kconfig | 3 ++- + lib/Kconfig | 8 ++++---- + net/Kconfig | 2 +- + net/netfilter/Kconfig | 2 +- + sound/core/Kconfig | 4 ++-- + 7 files changed, 16 insertions(+), 14 deletions(-) + +diff --git a/crypto/Kconfig b/crypto/Kconfig +index e7528986e94f..79fc693086b7 100644 +--- a/crypto/Kconfig ++++ b/crypto/Kconfig +@@ -55,7 +55,7 @@ config CRYPTO_FIPS_VERSION + By default the KERNELRELEASE value is used. + + config CRYPTO_ALGAPI +- tristate ++ tristate "ALGAPI" + select CRYPTO_ALGAPI2 + help + This option provides the API for cryptographic algorithms. +@@ -64,7 +64,7 @@ config CRYPTO_ALGAPI2 + tristate + + config CRYPTO_AEAD +- tristate ++ tristate "AEAD" + select CRYPTO_AEAD2 + select CRYPTO_ALGAPI + +@@ -82,7 +82,7 @@ config CRYPTO_SIG2 + select CRYPTO_ALGAPI2 + + config CRYPTO_SKCIPHER +- tristate ++ tristate "SKCIPHER" + select CRYPTO_SKCIPHER2 + select CRYPTO_ALGAPI + select CRYPTO_ECB +@@ -92,7 +92,7 @@ config CRYPTO_SKCIPHER2 + select CRYPTO_ALGAPI2 + + config CRYPTO_HASH +- tristate ++ tristate "HASH" + select CRYPTO_HASH2 + select CRYPTO_ALGAPI + +@@ -101,7 +101,7 @@ config CRYPTO_HASH2 + select CRYPTO_ALGAPI2 + + config CRYPTO_RNG +- tristate ++ tristate "RNG" + select CRYPTO_RNG2 + select CRYPTO_ALGAPI + +diff --git a/drivers/bcma/Kconfig b/drivers/bcma/Kconfig +index b9558ff20830..2e9732e5c565 100644 +--- a/drivers/bcma/Kconfig ++++ b/drivers/bcma/Kconfig +@@ -16,6 +16,7 @@ if BCMA + # Support for Block-I/O. SELECT this from the driver that needs it. + config BCMA_BLOCKIO + bool ++ default y + + config BCMA_HOST_PCI_POSSIBLE + bool +diff --git a/drivers/ssb/Kconfig b/drivers/ssb/Kconfig +index 1cf1a98952fa..2bcf62e64f6f 100644 +--- a/drivers/ssb/Kconfig ++++ b/drivers/ssb/Kconfig +@@ -29,6 +29,7 @@ config SSB_SPROM + config SSB_BLOCKIO + bool + depends on SSB ++ default y + + config SSB_PCIHOST_POSSIBLE + bool +@@ -49,7 +50,7 @@ config SSB_PCIHOST + config SSB_B43_PCI_BRIDGE + bool + depends on SSB_PCIHOST +- default n ++ default y + + config SSB_PCMCIAHOST_POSSIBLE + bool +diff --git a/lib/Kconfig b/lib/Kconfig +index e9088bd10a6c..1ddb823c425e 100644 +--- a/lib/Kconfig ++++ b/lib/Kconfig +@@ -457,16 +457,16 @@ config BCH_CONST_T + # Textsearch support is select'ed if needed + # + config TEXTSEARCH +- bool ++ bool "Textsearch support" + + config TEXTSEARCH_KMP +- tristate ++ tristate "Textsearch KMP" + + config TEXTSEARCH_BM +- tristate ++ tristate "Textsearch BM" + + config TEXTSEARCH_FSM +- tristate ++ tristate "Textsearch FSM" + + config BTREE + bool +diff --git a/net/Kconfig b/net/Kconfig +index a629f92dc86b..6744f55d9683 100644 +--- a/net/Kconfig ++++ b/net/Kconfig +@@ -484,7 +484,7 @@ config NET_DEVLINK + default n + + config PAGE_POOL +- bool ++ bool "Page pool support" + + config PAGE_POOL_STATS + default n +diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig +index f7cde787a680..944a47d0e2fd 100644 +--- a/net/netfilter/Kconfig ++++ b/net/netfilter/Kconfig +@@ -22,7 +22,7 @@ config NETFILTER_SKIP_EGRESS + def_bool NETFILTER_EGRESS && (NET_CLS_ACT || IFB) + + config NETFILTER_NETLINK +- tristate ++ tristate "Netfilter NFNETLINK interface" + + config NETFILTER_FAMILY_BRIDGE + bool +diff --git a/sound/core/Kconfig b/sound/core/Kconfig +index 2c5b9f964703..e2e942179a09 100644 +--- a/sound/core/Kconfig ++++ b/sound/core/Kconfig +@@ -17,7 +17,7 @@ config SND_DMAENGINE_PCM + tristate + + config SND_HWDEP +- tristate ++ tristate "Sound hardware support" + + config SND_SEQ_DEVICE + tristate +@@ -57,7 +57,7 @@ config SND_CORE_TEST + + + config SND_COMPRESS_OFFLOAD +- tristate ++ tristate "Compression offloading support" + + config SND_JACK + bool +-- +2.51.0 + + +From 96c73d623607c4b0d07e488648bc48d1b4297872 Mon Sep 17 00:00:00 2001 +From: OpenWrt community +Date: Wed, 13 Jul 2022 13:33:30 +0200 +Subject: [PATCH 340/517] Kconfig: add tristate for OID and ASNI string + +--- + init/Kconfig | 2 +- + lib/Kconfig | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/init/Kconfig b/init/Kconfig +index 0de264f33b49..dfc689f2a766 100644 +--- a/init/Kconfig ++++ b/init/Kconfig +@@ -2063,7 +2063,7 @@ config PADATA + bool + + config ASN1 +- tristate ++ tristate "ASN1" + help + Build a simple ASN.1 grammar compiler that produces a bytecode output + that can be interpreted by the ASN.1 stream decoder and used to +diff --git a/lib/Kconfig b/lib/Kconfig +index 1ddb823c425e..c8cc10b1f163 100644 +--- a/lib/Kconfig ++++ b/lib/Kconfig +@@ -642,7 +642,7 @@ config LIBFDT + bool + + config OID_REGISTRY +- tristate ++ tristate "OID" + help + Enable fast lookup object identifier registry. + +-- +2.51.0 + + +From 8aaddb765893f392454753b44f0a4de7fe456788 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Sat, 15 Jul 2017 21:12:38 +0200 +Subject: [PATCH 341/517] kernel: move regmap bloat out of the kernel image if + it is only being used in modules + +lede-commit: 96f39119815028073583e4fca3a9c5fe9141e998 +Signed-off-by: Felix Fietkau +--- + drivers/base/regmap/Kconfig | 21 ++++++++++++++++++--- + drivers/base/regmap/Makefile | 8 +++++--- + drivers/base/regmap/regmap.c | 3 +++ + include/linux/regmap.h | 2 +- + 4 files changed, 27 insertions(+), 7 deletions(-) + +diff --git a/drivers/base/regmap/Kconfig b/drivers/base/regmap/Kconfig +index b1affac70d5d..4a6c93b51767 100644 +--- a/drivers/base/regmap/Kconfig ++++ b/drivers/base/regmap/Kconfig +@@ -4,8 +4,7 @@ + # subsystems should select the appropriate symbols. + + config REGMAP +- bool +- default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_W1 || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ || REGMAP_SOUNDWIRE || REGMAP_SOUNDWIRE_MBQ || REGMAP_SCCB || REGMAP_I3C || REGMAP_SPI_AVMM || REGMAP_MDIO || REGMAP_FSI) ++ tristate + select IRQ_DOMAIN if REGMAP_IRQ + select MDIO_BUS if REGMAP_MDIO + help +@@ -19,7 +18,7 @@ config REGMAP + + config REGMAP_KUNIT + tristate "KUnit tests for regmap" +- depends on KUNIT && REGMAP ++ depends on KUNIT + default KUNIT_ALL_TESTS + select REGMAP_RAM + +@@ -34,60 +33,76 @@ config REGMAP_BUILD + normally enabled. + + config REGMAP_AC97 ++ select REGMAP + tristate + + config REGMAP_I2C ++ select REGMAP + tristate + depends on I2C + + config REGMAP_SLIMBUS ++ select REGMAP + tristate + depends on SLIMBUS + + config REGMAP_SPI ++ select REGMAP + tristate + depends on SPI + + config REGMAP_SPMI ++ select REGMAP + tristate + depends on SPMI + + config REGMAP_W1 ++ select REGMAP + tristate + depends on W1 + + config REGMAP_MDIO ++ select REGMAP + tristate + + config REGMAP_MMIO ++ select REGMAP + tristate + + config REGMAP_IRQ ++ select REGMAP + bool + + config REGMAP_RAM ++ select REGMAP + tristate + + config REGMAP_SOUNDWIRE ++ select REGMAP + tristate + depends on SOUNDWIRE + + config REGMAP_SOUNDWIRE_MBQ ++ select REGMAP + tristate + depends on SOUNDWIRE + + config REGMAP_SCCB ++ select REGMAP + tristate + depends on I2C + + config REGMAP_I3C ++ select REGMAP + tristate + depends on I3C + + config REGMAP_SPI_AVMM ++ select REGMAP + tristate + depends on SPI + + config REGMAP_FSI ++ select REGMAP + tristate + depends on FSI +diff --git a/drivers/base/regmap/Makefile b/drivers/base/regmap/Makefile +index 5fdd0845b45e..f171215a71f7 100644 +--- a/drivers/base/regmap/Makefile ++++ b/drivers/base/regmap/Makefile +@@ -2,9 +2,11 @@ + # For include/trace/define_trace.h to include trace.h + CFLAGS_regmap.o := -I$(src) + +-obj-$(CONFIG_REGMAP) += regmap.o regcache.o +-obj-$(CONFIG_REGMAP) += regcache-rbtree.o regcache-flat.o regcache-maple.o +-obj-$(CONFIG_DEBUG_FS) += regmap-debugfs.o ++regmap-core-objs = regmap.o regcache.o regcache-rbtree.o regcache-flat.o regcache-maple.o ++ifdef CONFIG_DEBUG_FS ++regmap-core-objs += regmap-debugfs.o ++endif ++obj-$(CONFIG_REGMAP) += regmap-core.o + obj-$(CONFIG_REGMAP_KUNIT) += regmap-kunit.o + obj-$(CONFIG_REGMAP_AC97) += regmap-ac97.o + obj-$(CONFIG_REGMAP_I2C) += regmap-i2c.o +diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c +index 66b3840bd96e..93d26238811d 100644 +--- a/drivers/base/regmap/regmap.c ++++ b/drivers/base/regmap/regmap.c +@@ -9,6 +9,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -3521,3 +3522,5 @@ static int __init regmap_initcall(void) + return 0; + } + postcore_initcall(regmap_initcall); ++ ++MODULE_LICENSE("GPL"); +diff --git a/include/linux/regmap.h b/include/linux/regmap.h +index f9ccad32fc5c..bb3765f8984d 100644 +--- a/include/linux/regmap.h ++++ b/include/linux/regmap.h +@@ -197,7 +197,7 @@ struct reg_sequence { + __ret ?: __tmp; \ + }) + +-#ifdef CONFIG_REGMAP ++#if IS_REACHABLE(CONFIG_REGMAP) + + enum regmap_endian { + /* Unspecified -> 0 -> Backwards compatible default */ +-- +2.51.0 + + +From d4c446b3081ba313c2fd5eba17b542e3beda61c6 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Fri, 7 Jul 2017 17:12:51 +0200 +Subject: [PATCH 342/517] kernel: prevent cryptomgr from pulling in useless + extra dependencies for tests that are not run + +Reduces kernel size after LZMA by about 5k on MIPS + +lede-commit: 044c316167e076479a344c59905e5b435b84a77f +Signed-off-by: Felix Fietkau +--- + crypto/Kconfig | 18 +++++++++--------- + crypto/algboss.c | 4 ++++ + 2 files changed, 13 insertions(+), 9 deletions(-) + +diff --git a/crypto/Kconfig b/crypto/Kconfig +index 79fc693086b7..0f9a815d0b5e 100644 +--- a/crypto/Kconfig ++++ b/crypto/Kconfig +@@ -149,15 +149,15 @@ config CRYPTO_MANAGER + cbc(aes). + + config CRYPTO_MANAGER2 +- def_tristate CRYPTO_MANAGER || (CRYPTO_MANAGER!=n && CRYPTO_ALGAPI=y) +- select CRYPTO_ACOMP2 +- select CRYPTO_AEAD2 +- select CRYPTO_AKCIPHER2 +- select CRYPTO_SIG2 +- select CRYPTO_HASH2 +- select CRYPTO_KPP2 +- select CRYPTO_RNG2 +- select CRYPTO_SKCIPHER2 ++ def_tristate CRYPTO_MANAGER || (CRYPTO_MANAGER!=n && CRYPTO_ALGAPI=y && !CRYPTO_MANAGER_DISABLE_TESTS) ++ select CRYPTO_ACOMP2 if !CRYPTO_MANAGER_DISABLE_TESTS ++ select CRYPTO_AEAD2 if !CRYPTO_MANAGER_DISABLE_TESTS ++ select CRYPTO_AKCIPHER2 if !CRYPTO_MANAGER_DISABLE_TESTS ++ select CRYPTO_SIG2 if !CRYPTO_MANAGER_DISABLE_TESTS ++ select CRYPTO_HASH2 if !CRYPTO_MANAGER_DISABLE_TESTS ++ select CRYPTO_KPP2 if !CRYPTO_MANAGER_DISABLE_TESTS ++ select CRYPTO_RNG2 if !CRYPTO_MANAGER_DISABLE_TESTS ++ select CRYPTO_SKCIPHER2 if !CRYPTO_MANAGER_DISABLE_TESTS + + config CRYPTO_USER + tristate "Userspace cryptographic algorithm configuration" +diff --git a/crypto/algboss.c b/crypto/algboss.c +index a20926bfd34e..3ac655fa7b94 100644 +--- a/crypto/algboss.c ++++ b/crypto/algboss.c +@@ -203,6 +203,10 @@ static int cryptomgr_schedule_test(struct crypto_alg *alg) + memcpy(param->alg, alg->cra_name, sizeof(param->alg)); + param->type = alg->cra_flags; + ++#ifdef CONFIG_CRYPTO_MANAGER_DISABLE_TESTS ++ param->type |= CRYPTO_ALG_TESTED; ++#endif ++ + thread = kthread_run(cryptomgr_test, param, "cryptomgr_test"); + if (IS_ERR(thread)) + goto err_free_param; +-- +2.51.0 + + +From c59c9285d6b0e298be700e8d067881d4f0804f26 Mon Sep 17 00:00:00 2001 +From: OpenWrt community +Date: Wed, 13 Jul 2022 13:35:18 +0200 +Subject: [PATCH 343/517] lib/crypto: add tristate string for ARC4 + +This makes it possible to select CONFIG_CRYPTO_LIB_ARC4 directly. We +need this to be able to compile this into the kernel and make use of it +from backports. +--- + lib/crypto/Kconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/lib/crypto/Kconfig b/lib/crypto/Kconfig +index b09e78da959a..6bd7c7ba58e6 100644 +--- a/lib/crypto/Kconfig ++++ b/lib/crypto/Kconfig +@@ -20,7 +20,7 @@ config CRYPTO_LIB_AESGCM + select CRYPTO_LIB_UTILS + + config CRYPTO_LIB_ARC4 +- tristate ++ tristate "ARC4 cipher library" + + config CRYPTO_LIB_GF128MUL + tristate +-- +2.51.0 + + +From 995f1f0db5478d75487df6df85dc4a2be4949a77 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Fri, 7 Jul 2017 17:13:44 +0200 +Subject: [PATCH 344/517] rfkill: add fake rfkill support + +allow building of modules depending on RFKILL even if RFKILL is not enabled. + +Signed-off-by: John Crispin +--- + include/linux/rfkill.h | 2 +- + net/Makefile | 2 +- + net/rfkill/Kconfig | 12 ++++++++---- + net/rfkill/Makefile | 2 +- + 4 files changed, 11 insertions(+), 7 deletions(-) + +diff --git a/include/linux/rfkill.h b/include/linux/rfkill.h +index 997b34197385..9ec57a9e7c9f 100644 +--- a/include/linux/rfkill.h ++++ b/include/linux/rfkill.h +@@ -64,7 +64,7 @@ struct rfkill_ops { + int (*set_block)(void *data, bool blocked); + }; + +-#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) ++#if defined(CONFIG_RFKILL_FULL) || defined(CONFIG_RFKILL_FULL_MODULE) + /** + * rfkill_alloc - Allocate rfkill structure + * @name: name of the struct -- the string is not copied internally +diff --git a/net/Makefile b/net/Makefile +index 65bb8c72a35e..d67f93b150e5 100644 +--- a/net/Makefile ++++ b/net/Makefile +@@ -51,7 +51,7 @@ obj-$(CONFIG_TIPC) += tipc/ + obj-$(CONFIG_NETLABEL) += netlabel/ + obj-$(CONFIG_IUCV) += iucv/ + obj-$(CONFIG_SMC) += smc/ +-obj-$(CONFIG_RFKILL) += rfkill/ ++obj-$(CONFIG_RFKILL_FULL) += rfkill/ + obj-$(CONFIG_NET_9P) += 9p/ + obj-$(CONFIG_CAIF) += caif/ + obj-$(CONFIG_DCB) += dcb/ +diff --git a/net/rfkill/Kconfig b/net/rfkill/Kconfig +index 83a7af8982bb..d05d6ae15032 100644 +--- a/net/rfkill/Kconfig ++++ b/net/rfkill/Kconfig +@@ -2,7 +2,11 @@ + # + # RF switch subsystem configuration + # +-menuconfig RFKILL ++config RFKILL ++ bool ++ default y ++ ++menuconfig RFKILL_FULL + tristate "RF switch subsystem support" + help + Say Y here if you want to have control over RF switches +@@ -14,19 +18,19 @@ menuconfig RFKILL + # LED trigger support + config RFKILL_LEDS + bool +- depends on RFKILL ++ depends on RFKILL_FULL + depends on LEDS_TRIGGERS = y || RFKILL = LEDS_TRIGGERS + default y + + config RFKILL_INPUT + bool "RF switch input support" if EXPERT +- depends on RFKILL ++ depends on RFKILL_FULL + depends on INPUT = y || RFKILL = INPUT + default y if !EXPERT + + config RFKILL_GPIO + tristate "GPIO RFKILL driver" +- depends on RFKILL ++ depends on RFKILL_FULL + depends on GPIOLIB || COMPILE_TEST + default n + help +diff --git a/net/rfkill/Makefile b/net/rfkill/Makefile +index dc47b6174ec5..be58b4119dac 100644 +--- a/net/rfkill/Makefile ++++ b/net/rfkill/Makefile +@@ -5,5 +5,5 @@ + + rfkill-y += core.o + rfkill-$(CONFIG_RFKILL_INPUT) += input.o +-obj-$(CONFIG_RFKILL) += rfkill.o ++obj-$(CONFIG_RFKILL_FULL) += rfkill.o + obj-$(CONFIG_RFKILL_GPIO) += rfkill-gpio.o +-- +2.51.0 + + +From 8e80abd396bc37470970931944b289314c894e81 Mon Sep 17 00:00:00 2001 +From: Ben Menchaca +Date: Fri, 7 Jun 2013 18:35:22 -0500 +Subject: [PATCH 345/517] MIPS: r4k_cache: use more efficient cache blast + +Optimize the compiler output for larger cache blast cases that are +common for DMA-based networking. + +Signed-off-by: Ben Menchaca +Signed-off-by: Felix Fietkau +--- + arch/mips/include/asm/r4kcache.h | 42 ++++++++++++++++++++++++++++---- + 1 file changed, 37 insertions(+), 5 deletions(-) + +diff --git a/arch/mips/include/asm/r4kcache.h b/arch/mips/include/asm/r4kcache.h +index da1cd1bbdbc5..1624b578a157 100644 +--- a/arch/mips/include/asm/r4kcache.h ++++ b/arch/mips/include/asm/r4kcache.h +@@ -290,14 +290,46 @@ static inline void prot##extra##blast_##pfx##cache##_range(unsigned long start, + unsigned long end) \ + { \ + unsigned long lsize = cpu_##desc##_line_size(); \ ++ unsigned long lsize_2 = lsize * 2; \ ++ unsigned long lsize_3 = lsize * 3; \ ++ unsigned long lsize_4 = lsize * 4; \ ++ unsigned long lsize_5 = lsize * 5; \ ++ unsigned long lsize_6 = lsize * 6; \ ++ unsigned long lsize_7 = lsize * 7; \ ++ unsigned long lsize_8 = lsize * 8; \ + unsigned long addr = start & ~(lsize - 1); \ +- unsigned long aend = (end - 1) & ~(lsize - 1); \ ++ unsigned long aend = (end + lsize - 1) & ~(lsize - 1); \ ++ int lines = (aend - addr) / lsize; \ + \ +- while (1) { \ ++ while (lines >= 8) { \ ++ prot##cache_op(hitop, addr); \ ++ prot##cache_op(hitop, addr + lsize); \ ++ prot##cache_op(hitop, addr + lsize_2); \ ++ prot##cache_op(hitop, addr + lsize_3); \ ++ prot##cache_op(hitop, addr + lsize_4); \ ++ prot##cache_op(hitop, addr + lsize_5); \ ++ prot##cache_op(hitop, addr + lsize_6); \ ++ prot##cache_op(hitop, addr + lsize_7); \ ++ addr += lsize_8; \ ++ lines -= 8; \ ++ } \ ++ \ ++ if (lines & 0x4) { \ ++ prot##cache_op(hitop, addr); \ ++ prot##cache_op(hitop, addr + lsize); \ ++ prot##cache_op(hitop, addr + lsize_2); \ ++ prot##cache_op(hitop, addr + lsize_3); \ ++ addr += lsize_4; \ ++ } \ ++ \ ++ if (lines & 0x2) { \ ++ prot##cache_op(hitop, addr); \ ++ prot##cache_op(hitop, addr + lsize); \ ++ addr += lsize_2; \ ++ } \ ++ \ ++ if (lines & 0x1) { \ + prot##cache_op(hitop, addr); \ +- if (addr == aend) \ +- break; \ +- addr += lsize; \ + } \ + } + +-- +2.51.0 + + +From fb6db57e6a54fc221b942ee771066ade1318a27a Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Mon, 14 Apr 2025 18:04:25 +0200 +Subject: [PATCH 346/517] mm: permit to declare custom execmem alloc/free + function + +Permit to declare custom execmem alloc/free function that bypass the +execmem API. This works by making the alloc/free function weak +permitting an arch to declare a replacement for them. + +Signed-off-by: Christian Marangi +Co-authored-by: Shiji Yang +--- + include/linux/moduleloader.h | 4 ++++ + mm/execmem.c | 14 ++++++++++++-- + 2 files changed, 16 insertions(+), 2 deletions(-) + +diff --git a/include/linux/moduleloader.h b/include/linux/moduleloader.h +index e395461d59e5..ee24ba60f51a 100644 +--- a/include/linux/moduleloader.h ++++ b/include/linux/moduleloader.h +@@ -122,4 +122,8 @@ void module_arch_cleanup(struct module *mod); + /* Any cleanup before freeing mod->module_init */ + void module_arch_freeing_init(struct module *mod); + ++enum execmem_type; ++void *arch_execmem_alloc(enum execmem_type type, size_t size); ++void arch_execmem_free(void *ptr); ++ + #endif +diff --git a/mm/execmem.c b/mm/execmem.c +index 0c4b36bc6d10..3b21780a196b 100644 +--- a/mm/execmem.c ++++ b/mm/execmem.c +@@ -52,14 +52,19 @@ static void *__execmem_alloc(struct execmem_range *range, size_t size) + return kasan_reset_tag(p); + } + +-void *execmem_alloc(enum execmem_type type, size_t size) ++void *__weak arch_execmem_alloc(enum execmem_type type, size_t size) + { + struct execmem_range *range = &execmem_info->ranges[type]; + + return __execmem_alloc(range, size); + } + +-void execmem_free(void *ptr) ++void *execmem_alloc(enum execmem_type type, size_t size) ++{ ++ return arch_execmem_alloc(type, size); ++} ++ ++void __weak arch_execmem_free(void *ptr) + { + /* + * This memory may be RO, and freeing RO memory in an interrupt is not +@@ -69,6 +74,11 @@ void execmem_free(void *ptr) + vfree(ptr); + } + ++void execmem_free(void *ptr) ++{ ++ arch_execmem_free(ptr); ++} ++ + static bool execmem_validate(struct execmem_info *info) + { + struct execmem_range *r = &info->ranges[EXECMEM_DEFAULT]; +-- +2.51.0 + + +From a72909bbbd432df45021d446dd0983251229c5a4 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Mon, 14 Apr 2025 18:05:45 +0200 +Subject: [PATCH 347/517] mips: replace -mlong-calls with -mno-long-calls if + possible + +This is a really old patch ported from MikroTik. It needs a an +additional patch to actually be implemented and both this and the old +one are considered HACK as they bypass normal kernel linux to make it +work. + +The original message quote: + +replace -mlong-calls with -mno-long-calls to make function +calls faster in kernel modules to achieve this, try to load +kernel modules to KSEG0 and if that doesn't work, use vmalloc +and fix up relocations with a jump table based on code from a +kernel patch by MikroTik. + +SVN-Revision: 16772 + +lede-commit: 3b3d64743ba2a874df9d70cd19e242205b0a788c +Signed-off-by: Felix Fietkau +Signed-off-by: Christian Marangi +--- + arch/mips/Makefile | 10 ++ + arch/mips/include/asm/module.h | 5 + + arch/mips/kernel/module.c | 281 ++++++++++++++++++++++++++++++++- + 3 files changed, 292 insertions(+), 4 deletions(-) + +diff --git a/arch/mips/Makefile b/arch/mips/Makefile +index 2a770f13a0cc..29a7c9a55358 100644 +--- a/arch/mips/Makefile ++++ b/arch/mips/Makefile +@@ -97,8 +97,18 @@ all-$(CONFIG_SYS_SUPPORTS_ZBOOT)+= vmlinuz + cflags-y += -G 0 -mno-abicalls -fno-pic -pipe -mno-branch-likely + cflags-y += -msoft-float -Wa,-msoft-float + LDFLAGS_vmlinux += -G 0 -static -n -nostdlib ++ifdef CONFIG_64BIT + KBUILD_AFLAGS_MODULE += -mlong-calls + KBUILD_CFLAGS_MODULE += -mlong-calls ++else ++ ifdef CONFIG_DYNAMIC_FTRACE ++ KBUILD_AFLAGS_MODULE += -mlong-calls ++ KBUILD_CFLAGS_MODULE += -mlong-calls ++ else ++ KBUILD_AFLAGS_MODULE += -mno-long-calls ++ KBUILD_CFLAGS_MODULE += -mno-long-calls ++ endif ++endif + + ifeq ($(CONFIG_RELOCATABLE),y) + LDFLAGS_vmlinux += --emit-relocs +diff --git a/arch/mips/include/asm/module.h b/arch/mips/include/asm/module.h +index 724a0882576b..9dfc597be586 100644 +--- a/arch/mips/include/asm/module.h ++++ b/arch/mips/include/asm/module.h +@@ -12,6 +12,11 @@ struct mod_arch_specific { + const struct exception_table_entry *dbe_start; + const struct exception_table_entry *dbe_end; + struct mips_hi16 *r_mips_hi16_list; ++ ++ void *phys_plt_tbl; ++ void *virt_plt_tbl; ++ unsigned int phys_plt_offset; ++ unsigned int virt_plt_offset; + }; + + typedef uint8_t Elf64_Byte; /* Type for a 8-bit quantity. */ +diff --git a/arch/mips/kernel/module.c b/arch/mips/kernel/module.c +index ba0f62d8eff5..bd731174b01e 100644 +--- a/arch/mips/kernel/module.c ++++ b/arch/mips/kernel/module.c +@@ -8,6 +8,7 @@ + + #undef DEBUG + ++#include + #include + #include + #include +@@ -19,6 +20,7 @@ + #include + #include + #include ++#include + #include + + struct mips_hi16 { +@@ -30,14 +32,254 @@ struct mips_hi16 { + static LIST_HEAD(dbe_list); + static DEFINE_SPINLOCK(dbe_lock); + ++/* ++ * Get the potential max trampolines size required of the init and ++ * non-init sections. Only used if we cannot find enough contiguous ++ * physically mapped memory to put the module into. ++ */ ++static unsigned int ++get_plt_size(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, ++ const char *secstrings, unsigned int symindex, bool is_init) ++{ ++ unsigned long ret = 0; ++ unsigned int i, j; ++ Elf_Sym *syms; ++ ++ /* Everything marked ALLOC (this includes the exported symbols) */ ++ for (i = 1; i < hdr->e_shnum; ++i) { ++ unsigned int info = sechdrs[i].sh_info; ++ ++ if (sechdrs[i].sh_type != SHT_REL ++ && sechdrs[i].sh_type != SHT_RELA) ++ continue; ++ ++ /* Not a valid relocation section? */ ++ if (info >= hdr->e_shnum) ++ continue; ++ ++ /* Don't bother with non-allocated sections */ ++ if (!(sechdrs[info].sh_flags & SHF_ALLOC)) ++ continue; ++ ++ /* If it's called *.init*, and we're not init, we're ++ not interested */ ++ if ((strstr(secstrings + sechdrs[i].sh_name, ".init") != 0) ++ != is_init) ++ continue; ++ ++ syms = (Elf_Sym *) sechdrs[symindex].sh_addr; ++ if (sechdrs[i].sh_type == SHT_REL) { ++ Elf_Mips_Rel *rel = (void *) sechdrs[i].sh_addr; ++ unsigned int size = sechdrs[i].sh_size / sizeof(*rel); ++ ++ for (j = 0; j < size; ++j) { ++ Elf_Sym *sym; ++ ++ if (ELF_MIPS_R_TYPE(rel[j]) != R_MIPS_26) ++ continue; ++ ++ sym = syms + ELF_MIPS_R_SYM(rel[j]); ++ if (!is_init && sym->st_shndx != SHN_UNDEF) ++ continue; ++ ++ ret += 4 * sizeof(int); ++ } ++ } else { ++ Elf_Mips_Rela *rela = (void *) sechdrs[i].sh_addr; ++ unsigned int size = sechdrs[i].sh_size / sizeof(*rela); ++ ++ for (j = 0; j < size; ++j) { ++ Elf_Sym *sym; ++ ++ if (ELF_MIPS_R_TYPE(rela[j]) != R_MIPS_26) ++ continue; ++ ++ sym = syms + ELF_MIPS_R_SYM(rela[j]); ++ if (!is_init && sym->st_shndx != SHN_UNDEF) ++ continue; ++ ++ ret += 4 * sizeof(int); ++ } ++ } ++ } ++ ++ return ret; ++} ++ ++#ifndef MODULES_VADDR ++static void *alloc_phys(unsigned long size) ++{ ++ unsigned order; ++ struct page *page; ++ struct page *p; ++ ++ size = PAGE_ALIGN(size); ++ order = get_order(size); ++ ++ page = alloc_pages(GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN | ++ __GFP_THISNODE, order); ++ if (!page) ++ return NULL; ++ ++ split_page(page, order); ++ ++ /* mark all pages except for the last one */ ++ for (p = page; p + 1 < page + (size >> PAGE_SHIFT); ++p) ++ set_bit(PG_owner_priv_1, &p->flags); ++ ++ for (p = page + (size >> PAGE_SHIFT); p < page + (1 << order); ++p) ++ __free_page(p); ++ ++ return page_address(page); ++} ++ ++static void free_phys(void *ptr) ++{ ++ struct page *page; ++ bool free; ++ ++ page = virt_to_page(ptr); ++ do { ++ free = test_and_clear_bit(PG_owner_priv_1, &page->flags); ++ __free_page(page); ++ page++; ++ } while (free); ++} ++ ++void *arch_execmem_alloc(enum execmem_type type, ++ size_t size) ++{ ++ void *ptr; ++ ++ ptr = alloc_phys(size); ++ ++ /* If we failed to allocate physically contiguous memory, ++ * fall back to regular vmalloc. The module loader code will ++ * create jump tables to handle long jumps */ ++ if (!ptr) ++ return vmalloc(size); ++ ++ return ptr; ++} ++#endif ++ ++static inline bool is_phys_addr(void *ptr) ++{ ++#ifdef CONFIG_64BIT ++ return (KSEGX((unsigned long)ptr) == CKSEG0); ++#else ++ return (KSEGX(ptr) == KSEG0); ++#endif ++} ++ ++#ifndef MODULES_VADDR ++/* Free memory returned from module_alloc */ ++void arch_execmem_free(void *ptr) ++{ ++ if (is_phys_addr(ptr)) ++ free_phys(ptr); ++ else ++ vfree(ptr); ++} ++#endif ++ ++static void *__module_alloc(int size, bool phys) ++{ ++ void *ptr; ++ ++ if (phys) ++ ptr = kmalloc(size, GFP_KERNEL); ++ else ++ ptr = vmalloc(size); ++ return ptr; ++} ++ ++static void __module_free(void *ptr) ++{ ++ if (is_phys_addr(ptr)) ++ kfree(ptr); ++ else ++ vfree(ptr); ++} ++ ++int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs, ++ char *secstrings, struct module *mod) ++{ ++ unsigned int symindex = 0; ++ unsigned int core_size, init_size; ++ int i; ++ ++ mod->arch.phys_plt_offset = 0; ++ mod->arch.virt_plt_offset = 0; ++ mod->arch.phys_plt_tbl = NULL; ++ mod->arch.virt_plt_tbl = NULL; ++ ++ if (IS_ENABLED(CONFIG_64BIT)) ++ return 0; ++ ++ for (i = 1; i < hdr->e_shnum; i++) ++ if (sechdrs[i].sh_type == SHT_SYMTAB) ++ symindex = i; ++ ++ core_size = get_plt_size(hdr, sechdrs, secstrings, symindex, false); ++ init_size = get_plt_size(hdr, sechdrs, secstrings, symindex, true); ++ ++ if ((core_size + init_size) == 0) ++ return 0; ++ ++ mod->arch.phys_plt_tbl = __module_alloc(core_size + init_size, 1); ++ if (!mod->arch.phys_plt_tbl) ++ return -ENOMEM; ++ ++ mod->arch.virt_plt_tbl = __module_alloc(core_size + init_size, 0); ++ if (!mod->arch.virt_plt_tbl) { ++ __module_free(mod->arch.phys_plt_tbl); ++ mod->arch.phys_plt_tbl = NULL; ++ return -ENOMEM; ++ } ++ ++ return 0; ++} ++ + static void apply_r_mips_32(u32 *location, u32 base, Elf_Addr v) + { + *location = base + v; + } + ++static Elf_Addr add_plt_entry_to(unsigned *plt_offset, ++ void *start, Elf_Addr v) ++{ ++ unsigned *tramp = start + *plt_offset; ++ *plt_offset += 4 * sizeof(int); ++ ++ /* adjust carry for addiu */ ++ if (v & 0x00008000) ++ v += 0x10000; ++ ++ tramp[0] = 0x3c190000 | (v >> 16); /* lui t9, hi16 */ ++ tramp[1] = 0x27390000 | (v & 0xffff); /* addiu t9, t9, lo16 */ ++ tramp[2] = 0x03200008; /* jr t9 */ ++ tramp[3] = 0x00000000; /* nop */ ++ ++ return (Elf_Addr) tramp; ++} ++ ++static Elf_Addr add_plt_entry(struct module *me, void *location, Elf_Addr v) ++{ ++ if (is_phys_addr(location)) ++ return add_plt_entry_to(&me->arch.phys_plt_offset, ++ me->arch.phys_plt_tbl, v); ++ else ++ return add_plt_entry_to(&me->arch.virt_plt_offset, ++ me->arch.virt_plt_tbl, v); ++ ++} ++ + static int apply_r_mips_26(struct module *me, u32 *location, u32 base, + Elf_Addr v) + { ++ u32 ofs = base & 0x03ffffff; ++ + if (v % 4) { + pr_err("module %s: dangerous R_MIPS_26 relocation\n", + me->name); +@@ -45,13 +287,17 @@ static int apply_r_mips_26(struct module *me, u32 *location, u32 base, + } + + if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) { +- pr_err("module %s: relocation overflow\n", +- me->name); +- return -ENOEXEC; ++ v = add_plt_entry(me, location, v + (ofs << 2)); ++ if (!v) { ++ pr_err("module %s: relocation overflow\n", ++ me->name); ++ return -ENOEXEC; ++ } ++ ofs = 0; + } + + *location = (*location & ~0x03ffffff) | +- ((base + (v >> 2)) & 0x03ffffff); ++ ((ofs + (v >> 2)) & 0x03ffffff); + + return 0; + } +@@ -431,9 +677,36 @@ int module_finalize(const Elf_Ehdr *hdr, + list_add(&me->arch.dbe_list, &dbe_list); + spin_unlock_irq(&dbe_lock); + } ++ ++ /* Get rid of the fixup trampoline if we're running the module ++ * from physically mapped address space */ ++ if (me->arch.phys_plt_offset == 0) { ++ __module_free(me->arch.phys_plt_tbl); ++ me->arch.phys_plt_tbl = NULL; ++ } ++ if (me->arch.virt_plt_offset == 0) { ++ __module_free(me->arch.virt_plt_tbl); ++ me->arch.virt_plt_tbl = NULL; ++ } ++ + return 0; + } + ++void module_arch_freeing_init(struct module *mod) ++{ ++ if (mod->state == MODULE_STATE_LIVE) ++ return; ++ ++ if (mod->arch.phys_plt_tbl) { ++ __module_free(mod->arch.phys_plt_tbl); ++ mod->arch.phys_plt_tbl = NULL; ++ } ++ if (mod->arch.virt_plt_tbl) { ++ __module_free(mod->arch.virt_plt_tbl); ++ mod->arch.virt_plt_tbl = NULL; ++ } ++} ++ + void module_arch_cleanup(struct module *mod) + { + spin_lock_irq(&dbe_lock); +-- +2.51.0 + + +From 016d53c3a76a0abd9c3a5f88b080ee9ebeee8a3e Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Wed, 7 Apr 2021 22:45:54 +0100 +Subject: [PATCH 348/517] mtd: blktrans: call add disks after mtd device + +Calling device_add_disk while holding mtd_table_mutex leads +to deadlock in case part_bits!=0 as block partition parsers +will try to open the newly created disks, trying to acquire +mutex once again. +Move device_add_disk to additional function called after +add partitions of an MTD device have been added and locks +have been released. + +Signed-off-by: Daniel Golle +--- + drivers/mtd/mtd_blkdevs.c | 40 ++++++++++++++++++++++++++---------- + drivers/mtd/mtdcore.c | 3 +++ + include/linux/mtd/blktrans.h | 1 + + 3 files changed, 33 insertions(+), 11 deletions(-) + +diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c +index 47ead84407cd..f27a807dc886 100644 +--- a/drivers/mtd/mtd_blkdevs.c ++++ b/drivers/mtd/mtd_blkdevs.c +@@ -379,19 +379,8 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) + if (new->readonly) + set_disk_ro(gd, 1); + +- ret = device_add_disk(&new->mtd->dev, gd, NULL); +- if (ret) +- goto out_cleanup_disk; +- +- if (new->disk_attributes) { +- ret = sysfs_create_group(&disk_to_dev(gd)->kobj, +- new->disk_attributes); +- WARN_ON(ret); +- } + return 0; + +-out_cleanup_disk: +- put_disk(new->disk); + out_free_tag_set: + blk_mq_free_tag_set(new->tag_set); + out_kfree_tag_set: +@@ -401,6 +390,35 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) + return ret; + } + ++void register_mtd_blktrans_devs(void) ++{ ++ struct mtd_blktrans_ops *tr; ++ struct mtd_blktrans_dev *dev, *next; ++ int ret; ++ ++ list_for_each_entry(tr, &blktrans_majors, list) { ++ list_for_each_entry_safe(dev, next, &tr->devs, list) { ++ if (disk_live(dev->disk)) ++ continue; ++ ++ ret = device_add_disk(&dev->mtd->dev, dev->disk, NULL); ++ if (ret) ++ goto out_cleanup_disk; ++ ++ if (dev->disk_attributes) { ++ ret = sysfs_create_group(&disk_to_dev(dev->disk)->kobj, ++ dev->disk_attributes); ++ WARN_ON(ret); ++ } ++ } ++ } ++ ++ return; ++ ++out_cleanup_disk: ++ put_disk(dev->disk); ++} ++ + int del_mtd_blktrans_dev(struct mtd_blktrans_dev *old) + { + unsigned long flags; +diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c +index 6b98d581ceeb..c34e31a915f2 100644 +--- a/drivers/mtd/mtdcore.c ++++ b/drivers/mtd/mtdcore.c +@@ -34,6 +34,7 @@ + + #include + #include ++#include + + #include "mtdcore.h" + +@@ -1132,6 +1133,8 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types, + register_reboot_notifier(&mtd->reboot_notifier); + } + ++ register_mtd_blktrans_devs(); ++ + out: + if (ret) { + nvmem_unregister(mtd->otp_user_nvmem); +diff --git a/include/linux/mtd/blktrans.h b/include/linux/mtd/blktrans.h +index 6e471436bba5..70f246a3dceb 100644 +--- a/include/linux/mtd/blktrans.h ++++ b/include/linux/mtd/blktrans.h +@@ -76,6 +76,7 @@ extern int deregister_mtd_blktrans(struct mtd_blktrans_ops *tr); + extern int add_mtd_blktrans_dev(struct mtd_blktrans_dev *dev); + extern int del_mtd_blktrans_dev(struct mtd_blktrans_dev *dev); + extern int mtd_blktrans_cease_background(struct mtd_blktrans_dev *dev); ++extern void register_mtd_blktrans_devs(void); + + /** + * module_mtd_blktrans() - Helper macro for registering a mtd blktrans driver +-- +2.51.0 + + +From 2be9bff250a6f8fe489c2b517985524c3ea64c18 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Mon, 7 Nov 2022 23:48:24 +0100 +Subject: [PATCH 349/517] mtd: support OpenWrt's MTD_ROOTFS_ROOT_DEV +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This allows setting ROOT_DEV to MTD partition named "rootfs". + +Signed-off-by: RafaÅ‚ MiÅ‚ecki +--- + drivers/mtd/mtdcore.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c +index c34e31a915f2..9bf60ad26daf 100644 +--- a/drivers/mtd/mtdcore.c ++++ b/drivers/mtd/mtdcore.c +@@ -803,7 +803,8 @@ int add_mtd_device(struct mtd_info *mtd) + + mutex_unlock(&mtd_table_mutex); + +- if (of_property_read_bool(mtd_get_of_node(mtd), "linux,rootfs")) { ++ if (of_property_read_bool(mtd_get_of_node(mtd), "linux,rootfs") || ++ (IS_ENABLED(CONFIG_MTD_ROOTFS_ROOT_DEV) && !strcmp(mtd->name, "rootfs") && ROOT_DEV == 0)) { + if (IS_BUILTIN(CONFIG_MTD)) { + pr_info("mtd: setting mtd%d (%s) as root device\n", mtd->index, mtd->name); + ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, mtd->index); +-- +2.51.0 + + +From eddbc1471956f3bd6a0090488fb8549dca8d962c Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Mon, 11 Oct 2021 00:53:14 +0200 +Subject: [PATCH 350/517] drivers: mtd: parsers: add nvmem support to + cmdlinepart + +Assuming cmdlinepart is only one level deep partition scheme and that +static partition are also defined in DTS, we can assign an of_node for +partition declared from bootargs. cmdlinepart have priority than +fiexed-partition parser so in this specific case the parser doesn't +assign an of_node. Fix this by searching a defined of_node using a +similar fixed_partition parser and if a partition is found with the same +label, check that it has the same offset and size and return the DT +of_node to correctly use NVMEM cells. + +Signed-off-by: Ansuel Smith +--- + drivers/mtd/parsers/cmdlinepart.c | 71 +++++++++++++++++++++++++++++++ + 1 file changed, 71 insertions(+) + +diff --git a/drivers/mtd/parsers/cmdlinepart.c b/drivers/mtd/parsers/cmdlinepart.c +index 504e5fa2b45b..fe8354cd6515 100644 +--- a/drivers/mtd/parsers/cmdlinepart.c ++++ b/drivers/mtd/parsers/cmdlinepart.c +@@ -43,6 +43,7 @@ + #include + #include + #include ++#include + + /* special size referring to all the remaining space in a partition */ + #define SIZE_REMAINING ULLONG_MAX +@@ -315,6 +316,68 @@ static int mtdpart_setup_real(char *s) + return 0; + } + ++static int search_fixed_partition(struct mtd_info *master, ++ struct mtd_partition *target_part, ++ struct mtd_partition *fixed_part) ++{ ++ struct device_node *mtd_node; ++ struct device_node *ofpart_node; ++ struct device_node *pp; ++ struct mtd_partition part; ++ const char *partname; ++ ++ mtd_node = mtd_get_of_node(master); ++ if (!mtd_node) ++ return -EINVAL; ++ ++ ofpart_node = of_get_child_by_name(mtd_node, "partitions"); ++ ++ for_each_child_of_node(ofpart_node, pp) { ++ const __be32 *reg; ++ int len; ++ int a_cells, s_cells; ++ ++ reg = of_get_property(pp, "reg", &len); ++ if (!reg) { ++ pr_debug("%s: ofpart partition %pOF (%pOF) missing reg property.\n", ++ master->name, pp, ++ mtd_node); ++ continue; ++ } ++ ++ a_cells = of_n_addr_cells(pp); ++ s_cells = of_n_size_cells(pp); ++ if (len / 4 != a_cells + s_cells) { ++ pr_debug("%s: ofpart partition %pOF (%pOF) error parsing reg property.\n", ++ master->name, pp, ++ mtd_node); ++ continue; ++ } ++ ++ part.offset = of_read_number(reg, a_cells); ++ part.size = of_read_number(reg + a_cells, s_cells); ++ part.of_node = pp; ++ ++ partname = of_get_property(pp, "label", &len); ++ if (!partname) ++ partname = of_get_property(pp, "name", &len); ++ part.name = partname; ++ ++ if (!strncmp(target_part->name, part.name, len)) { ++ if (part.offset != target_part->offset) ++ return -EINVAL; ++ ++ if (part.size != target_part->size) ++ return -EINVAL; ++ ++ memcpy(fixed_part, &part, sizeof(struct mtd_partition)); ++ return 0; ++ } ++ } ++ ++ return -EINVAL; ++} ++ + /* + * Main function to be called from the MTD mapping driver/device to + * obtain the partitioning information. At this point the command line +@@ -330,6 +393,7 @@ static int parse_cmdline_partitions(struct mtd_info *master, + int i, err; + struct cmdline_mtd_partition *part; + const char *mtd_id = master->name; ++ struct mtd_partition fixed_part; + + /* parse command line */ + if (!cmdline_parsed) { +@@ -374,6 +438,13 @@ static int parse_cmdline_partitions(struct mtd_info *master, + sizeof(*part->parts) * (part->num_parts - i)); + i--; + } ++ ++ err = search_fixed_partition(master, &part->parts[i], &fixed_part); ++ if (!err) { ++ part->parts[i].of_node = fixed_part.of_node; ++ pr_info("Found partition defined in DT for %s. Assigning OF node to support nvmem.", ++ part->parts[i].name); ++ } + } + + *pparts = kmemdup(part->parts, sizeof(*part->parts) * part->num_parts, +-- +2.51.0 + + +From b9b5fcad748eca6c1a4c8edcb34e2553f75f21aa Mon Sep 17 00:00:00 2001 +From: OpenWrt community +Date: Wed, 13 Jul 2022 13:41:44 +0200 +Subject: [PATCH 351/517] mtd/nand: add MediaTek NAND bad block managment table + +--- + drivers/mtd/nand/Kconfig | 4 ++++ + drivers/mtd/nand/Makefile | 1 + + 2 files changed, 5 insertions(+) + +diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig +index 5b0c2c95f10c..e775c64e355d 100644 +--- a/drivers/mtd/nand/Kconfig ++++ b/drivers/mtd/nand/Kconfig +@@ -46,6 +46,10 @@ config MTD_NAND_ECC_SW_BCH + ECC codes. They are used with NAND devices requiring more than 1 bit + of error correction. + ++config MTD_NAND_MTK_BMT ++ bool "Support MediaTek NAND Bad-block Management Table" ++ default n ++ + config MTD_NAND_ECC_MXIC + bool "Macronix external hardware ECC engine" + depends on HAS_IOMEM +diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile +index db516a45f0c5..2998d84bb5d0 100644 +--- a/drivers/mtd/nand/Makefile ++++ b/drivers/mtd/nand/Makefile +@@ -3,6 +3,7 @@ + nandcore-objs := core.o bbt.o + obj-$(CONFIG_MTD_NAND_CORE) += nandcore.o + obj-$(CONFIG_MTD_NAND_ECC_MEDIATEK) += ecc-mtk.o ++obj-$(CONFIG_MTD_NAND_MTK_BMT) += mtk_bmt.o mtk_bmt_v2.o mtk_bmt_bbt.o mtk_bmt_nmbm.o + ifeq ($(CONFIG_SPI_QPIC_SNAND),y) + obj-$(CONFIG_SPI_QPIC_SNAND) += qpic_common.o + else +-- +2.51.0 + + +From fe7abda0ec355ddcf7184b0245f70dbfcb25d1aa Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Mon, 3 Nov 2025 15:50:20 +0100 +Subject: [PATCH 352/517] LEGACY block: partitions: populate fwnode + +Assign matching firmware nodes to block partitions in order to allow +them to be referenced e.g. as NVMEM providers. + +REMOVE THIS PATCH ONCE ALL TARGETS ARE USING LINUX 6.12 AND ALL BOARDS +HAVE MIGRATED TO UPSTREAM DT BINDINGS. + +Signed-off-by: Daniel Golle +--- + block/partitions/core.c | 73 ++++++++++++++++++++++++++++++++++++++++ + drivers/mmc/core/block.c | 4 +++ + drivers/mmc/core/bus.c | 2 ++ + 3 files changed, 79 insertions(+) + +diff --git a/block/partitions/core.c b/block/partitions/core.c +index f5b5360dd518..29c9330b9050 100644 +--- a/block/partitions/core.c ++++ b/block/partitions/core.c +@@ -11,6 +11,8 @@ + #include + #include + #include ++#include ++ + #include "check.h" + + static int (*const check_part[])(struct parsed_partitions *) = { +@@ -285,6 +287,74 @@ static ssize_t whole_disk_show(struct device *dev, + } + static const DEVICE_ATTR(whole_disk, 0444, whole_disk_show, NULL); + ++static bool part_meta_match(const char *attr, const char *member, size_t length) ++{ ++ /* check if length of attr exceeds specified maximum length */ ++ if (strnlen(attr, length) == length) ++ return false; ++ ++ /* return true if strings match */ ++ return !strncmp(attr, member, length); ++} ++ ++static struct fwnode_handle *find_partition_fwnode(struct block_device *bdev) ++{ ++ struct fwnode_handle *fw_parts, *fw_part; ++ struct device *ddev = disk_to_dev(bdev->bd_disk); ++ const char *partname, *uuid; ++ u32 partno; ++ bool got_uuid, got_partname, got_partno; ++ ++ fw_parts = device_get_named_child_node(ddev, "partitions"); ++ if (!fw_parts) ++ return NULL; ++ ++ fwnode_for_each_child_node(fw_parts, fw_part) { ++ got_uuid = false; ++ got_partname = false; ++ got_partno = false; ++ /* ++ * In case 'uuid' is defined in the partitions firmware node ++ * require partition meta info being present and the specified ++ * uuid to match. ++ */ ++ got_uuid = !fwnode_property_read_string(fw_part, "uuid", &uuid); ++ if (got_uuid && (!bdev->bd_meta_info || ++ !part_meta_match(uuid, bdev->bd_meta_info->uuid, ++ PARTITION_META_INFO_UUIDLTH))) ++ continue; ++ ++ /* ++ * In case 'partname' is defined in the partitions firmware node ++ * require partition meta info being present and the specified ++ * volname to match. ++ */ ++ got_partname = !fwnode_property_read_string(fw_part, "partname", ++ &partname); ++ if (got_partname && (!bdev->bd_meta_info || ++ !part_meta_match(partname, ++ bdev->bd_meta_info->volname, ++ PARTITION_META_INFO_VOLNAMELTH))) ++ continue; ++ ++ /* ++ * In case 'partno' is defined in the partitions firmware node ++ * the specified partno needs to match. ++ */ ++ got_partno = !fwnode_property_read_u32(fw_part, "partno", &partno); ++ if (got_partno && bdev_partno(bdev) != partno) ++ continue; ++ ++ /* Skip if no matching criteria is present in firmware node */ ++ if (!got_uuid && !got_partname && !got_partno) ++ continue; ++ ++ return fw_part; ++ } ++ ++ return NULL; ++} ++ + /* + * Must be called either with open_mutex held, before a disk can be opened or + * after all disk users are gone. +@@ -361,6 +431,9 @@ static struct block_device *add_partition(struct gendisk *disk, int partno, + goto out_put; + } + ++ if (!pdev->fwnode && !pdev->of_node) ++ device_set_node(pdev, find_partition_fwnode(bdev)); ++ + /* delay uevent until 'holders' subdir is created */ + dev_set_uevent_suppress(pdev, 1); + err = device_add(pdev); +diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c +index f56eb44ec450..3c9443c7ac49 100644 +--- a/drivers/mmc/core/block.c ++++ b/drivers/mmc/core/block.c +@@ -2679,6 +2679,10 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, + if (area_type == MMC_BLK_DATA_AREA_MAIN) + dev_set_drvdata(&card->dev, md); + disk_fwnode = mmc_blk_get_partitions_node(parent, subname); ++ if (!disk_fwnode) ++ disk_fwnode = device_get_named_child_node(subname ? md->parent->parent : ++ md->parent, ++ subname ? subname : "block"); + ret = add_disk_fwnode(md->parent, md->disk, mmc_disk_attr_groups, + disk_fwnode); + if (ret) +diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c +index 4f3a26676ccb..359640be0592 100644 +--- a/drivers/mmc/core/bus.c ++++ b/drivers/mmc/core/bus.c +@@ -368,6 +368,8 @@ int mmc_add_card(struct mmc_card *card) + + mmc_add_card_debugfs(card); + card->dev.of_node = mmc_of_find_child_device(card->host, 0); ++ if (card->dev.of_node && !card->dev.fwnode) ++ card->dev.fwnode = &card->dev.of_node->fwnode; + + device_enable_async_suspend(&card->dev); + +-- +2.51.0 + + +From 70fcd329f0105febc763f81d177058026db6c5f3 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Tue, 23 Apr 2024 12:35:21 +0200 +Subject: [PATCH 353/517] net: enable fraglist GRO by default + +This can significantly improve performance for packet forwarding/bridging + +Signed-off-by: Felix Fietkau +--- + include/linux/netdev_features.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/include/linux/netdev_features.h b/include/linux/netdev_features.h +index e2e3dd919068..8b9e912f6db6 100644 +--- a/include/linux/netdev_features.h ++++ b/include/linux/netdev_features.h +@@ -235,10 +235,10 @@ static inline int find_next_netdev_feature(u64 feature, unsigned long start) + #define NETIF_F_UPPER_DISABLES NETIF_F_LRO + + /* changeable features with no special hardware requirements */ +-#define NETIF_F_SOFT_FEATURES (NETIF_F_GSO | NETIF_F_GRO) ++#define NETIF_F_SOFT_FEATURES (NETIF_F_GSO | NETIF_F_GRO | NETIF_F_GRO_FRAGLIST) + + /* Changeable features with no special hardware requirements that defaults to off. */ +-#define NETIF_F_SOFT_FEATURES_OFF (NETIF_F_GRO_FRAGLIST | NETIF_F_GRO_UDP_FWD) ++#define NETIF_F_SOFT_FEATURES_OFF (NETIF_F_GRO_UDP_FWD) + + #define NETIF_F_VLAN_FEATURES (NETIF_F_HW_VLAN_CTAG_FILTER | \ + NETIF_F_HW_VLAN_CTAG_RX | \ +-- +2.51.0 + + +From 9bc103b739dc6e694e05bcdc86b0583e94b5e140 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Fri, 3 Jan 2025 19:29:00 +0100 +Subject: [PATCH 354/517] net: page_pool: try to free deferred skbs while + waiting for pool release + +The NAPI defer list can accumulate no longer used skbs, which can be reused +during alloc. If this happens on a CPU that otherwise does not do any +rx softirq processing, skbs can be held indefinitely, causing warnings +on releasing page pools. +Deal with this by scheduling rx softirq on all CPUs. + +Patch by Lorenzo Bianconi + +Signed-off-by: Felix Fietkau +--- + net/core/page_pool.c | 18 +++++++++++++++++- + 1 file changed, 17 insertions(+), 1 deletion(-) + +diff --git a/net/core/page_pool.c b/net/core/page_pool.c +index 6a7d740b396f..c3a4ab60b6de 100644 +--- a/net/core/page_pool.c ++++ b/net/core/page_pool.c +@@ -1153,8 +1153,9 @@ static void page_pool_release_retry(struct work_struct *wq) + { + struct delayed_work *dwq = to_delayed_work(wq); + struct page_pool *pool = container_of(dwq, typeof(*pool), release_dw); ++ unsigned long flags; + void *netdev; +- int inflight; ++ int cpu, inflight; + + inflight = page_pool_release(pool); + /* In rare cases, a driver bug may cause inflight to go negative. +@@ -1166,6 +1167,21 @@ static void page_pool_release_retry(struct work_struct *wq) + if (inflight <= 0) + return; + ++ /* Run NET_RX_SOFTIRQ in order to free pending skbs in softnet_data ++ * defer_list that can stay in the list until we have enough queued ++ * traffic. ++ */ ++ local_irq_save(flags); ++ for_each_online_cpu(cpu) { ++ struct softnet_data *sd = &per_cpu(softnet_data, cpu); ++ ++ if (cpu == raw_smp_processor_id()) ++ raise_softirq_irqoff(NET_RX_SOFTIRQ); ++ else if (!cmpxchg(&sd->defer_ipi_scheduled, 0, 1)) ++ smp_call_function_single_async(cpu, &sd->defer_csd); ++ } ++ local_irq_restore(flags); ++ + /* Periodic warning for page pools the user can't see */ + netdev = READ_ONCE(pool->slow.netdev); + if (time_after_eq(jiffies, pool->defer_warn) && +-- +2.51.0 + + +From 07c08919265a04b1535d18e75a8de2fc6644e6b9 Mon Sep 17 00:00:00 2001 +From: Kevin Darbyshire-Bryant +Date: Sat, 23 Mar 2019 09:29:49 +0000 +Subject: [PATCH 355/517] netfilter: connmark: introduce set-dscpmark + +set-dscpmark is a method of storing the DSCP of an ip packet into +conntrack mark. In combination with a suitable tc filter action +(act_ctinfo) DSCP values are able to be stored in the mark on egress and +restored on ingress across links that otherwise alter or bleach DSCP. + +This is useful for qdiscs such as CAKE which are able to shape according +to policies based on DSCP. + +Ingress classification is traditionally a challenging task since +iptables rules haven't yet run and tc filter/eBPF programs are pre-NAT +lookups, hence are unable to see internal IPv4 addresses as used on the +typical home masquerading gateway. + +x_tables CONNMARK set-dscpmark target solves the problem of storing the +DSCP to the conntrack mark in a way suitable for the new act_ctinfo tc +action to restore. + +The set-dscpmark option accepts 2 parameters, a 32bit 'dscpmask' and a +32bit 'statemask'. The dscp mask must be 6 contiguous bits and +represents the area where the DSCP will be stored in the connmark. The +state mask is a minimum 1 bit length mask that must not overlap with the +dscpmask. It represents a flag which is set when the DSCP has been +stored in the conntrack mark. This is useful to implement a 'one shot' +iptables based classification where the 'complicated' iptables rules are +only run once to classify the connection on initial (egress) packet and +subsequent packets are all marked/restored with the same DSCP. A state +mask of zero disables the setting of a status bit/s. + +example syntax with a suitably modified iptables user space application: + +iptables -A QOS_MARK_eth0 -t mangle -j CONNMARK --set-dscpmark 0xfc000000/0x01000000 + +Would store the DSCP in the top 6 bits of the 32bit mark field, and use +the LSB of the top byte as the 'DSCP has been stored' marker. + +|----0xFC----conntrack mark----000000---| +| Bits 31-26 | bit 25 | bit24 |~~~ Bit 0| +| DSCP | unused | flag |unused | +|-----------------------0x01---000000---| + ^ ^ + | | + ---| Conditional flag + | set this when dscp +|-ip diffserv-| stored in mark +| 6 bits | +|-------------| + +an identically configured tc action to restore looks like: + +tc filter show dev eth0 ingress +filter parent ffff: protocol all pref 10 u32 chain 0 +filter parent ffff: protocol all pref 10 u32 chain 0 fh 800: ht divisor 1 +filter parent ffff: protocol all pref 10 u32 chain 0 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1: not_in_hw + match 00000000/00000000 at 0 + action order 1: ctinfo zone 0 pipe + index 2 ref 1 bind 1 dscp 0xfc000000/0x1000000 + + action order 2: mirred (Egress Redirect to device ifb4eth0) stolen + index 1 ref 1 bind 1 + +|----0xFC----conntrack mark----000000---| +| Bits 31-26 | bit 25 | bit24 |~~~ Bit 0| +| DSCP | unused | flag |unused | +|-----------------------0x01---000000---| + | | + | | + ---| Conditional flag + v only restore if set +|-ip diffserv-| +| 6 bits | +|-------------| + +Signed-off-by: Kevin Darbyshire-Bryant +--- + include/uapi/linux/netfilter/xt_connmark.h | 10 ++++ + net/netfilter/xt_connmark.c | 67 ++++++++++++++++++---- + 2 files changed, 67 insertions(+), 10 deletions(-) + +diff --git a/include/uapi/linux/netfilter/xt_connmark.h b/include/uapi/linux/netfilter/xt_connmark.h +index 41b578ccd03b..1ef51bca5cc7 100644 +--- a/include/uapi/linux/netfilter/xt_connmark.h ++++ b/include/uapi/linux/netfilter/xt_connmark.h +@@ -14,6 +14,11 @@ enum { + XT_CONNMARK_RESTORE + }; + ++enum { ++ XT_CONNMARK_VALUE = (1 << 0), ++ XT_CONNMARK_DSCP = (1 << 1) ++}; ++ + enum { + D_SHIFT_LEFT = 0, + D_SHIFT_RIGHT, +@@ -29,6 +34,11 @@ struct xt_connmark_tginfo2 { + __u8 shift_dir, shift_bits, mode; + }; + ++struct xt_connmark_tginfo3 { ++ __u32 ctmark, ctmask, nfmask; ++ __u8 shift_dir, shift_bits, mode, func; ++}; ++ + struct xt_connmark_mtinfo1 { + __u32 mark, mask; + __u8 invert; +diff --git a/net/netfilter/xt_connmark.c b/net/netfilter/xt_connmark.c +index 4277084de2e7..09e02d052ec7 100644 +--- a/net/netfilter/xt_connmark.c ++++ b/net/netfilter/xt_connmark.c +@@ -24,13 +24,13 @@ MODULE_ALIAS("ipt_connmark"); + MODULE_ALIAS("ip6t_connmark"); + + static unsigned int +-connmark_tg_shift(struct sk_buff *skb, const struct xt_connmark_tginfo2 *info) ++connmark_tg_shift(struct sk_buff *skb, const struct xt_connmark_tginfo3 *info) + { + enum ip_conntrack_info ctinfo; + u_int32_t new_targetmark; + struct nf_conn *ct; + u_int32_t newmark; +- u_int32_t oldmark; ++ u_int8_t dscp; + + ct = nf_ct_get(skb, &ctinfo); + if (ct == NULL) +@@ -38,13 +38,24 @@ connmark_tg_shift(struct sk_buff *skb, const struct xt_connmark_tginfo2 *info) + + switch (info->mode) { + case XT_CONNMARK_SET: +- oldmark = READ_ONCE(ct->mark); +- newmark = (oldmark & ~info->ctmask) ^ info->ctmark; +- if (info->shift_dir == D_SHIFT_RIGHT) +- newmark >>= info->shift_bits; +- else +- newmark <<= info->shift_bits; ++ newmark = READ_ONCE(ct->mark); ++ if (info->func & XT_CONNMARK_VALUE) { ++ newmark = (newmark & ~info->ctmask) ^ info->ctmark; ++ if (info->shift_dir == D_SHIFT_RIGHT) ++ newmark >>= info->shift_bits; ++ else ++ newmark <<= info->shift_bits; ++ } else if (info->func & XT_CONNMARK_DSCP) { ++ if (skb->protocol == htons(ETH_P_IP)) ++ dscp = ipv4_get_dsfield(ip_hdr(skb)) >> 2; ++ else if (skb->protocol == htons(ETH_P_IPV6)) ++ dscp = ipv6_get_dsfield(ipv6_hdr(skb)) >> 2; ++ else /* protocol doesn't have diffserv */ ++ break; + ++ newmark = (newmark & ~info->ctmark) | ++ (info->ctmask | (dscp << info->shift_bits)); ++ } + if (READ_ONCE(ct->mark) != newmark) { + WRITE_ONCE(ct->mark, newmark); + nf_conntrack_event_cache(IPCT_MARK, ct); +@@ -83,20 +94,36 @@ static unsigned int + connmark_tg(struct sk_buff *skb, const struct xt_action_param *par) + { + const struct xt_connmark_tginfo1 *info = par->targinfo; +- const struct xt_connmark_tginfo2 info2 = { ++ const struct xt_connmark_tginfo3 info3 = { + .ctmark = info->ctmark, + .ctmask = info->ctmask, + .nfmask = info->nfmask, + .mode = info->mode, ++ .func = XT_CONNMARK_VALUE + }; + +- return connmark_tg_shift(skb, &info2); ++ return connmark_tg_shift(skb, &info3); + } + + static unsigned int + connmark_tg_v2(struct sk_buff *skb, const struct xt_action_param *par) + { + const struct xt_connmark_tginfo2 *info = par->targinfo; ++ const struct xt_connmark_tginfo3 info3 = { ++ .ctmark = info->ctmark, ++ .ctmask = info->ctmask, ++ .nfmask = info->nfmask, ++ .mode = info->mode, ++ .func = XT_CONNMARK_VALUE ++ }; ++ ++ return connmark_tg_shift(skb, &info3); ++} ++ ++static unsigned int ++connmark_tg_v3(struct sk_buff *skb, const struct xt_action_param *par) ++{ ++ const struct xt_connmark_tginfo3 *info = par->targinfo; + + return connmark_tg_shift(skb, info); + } +@@ -168,6 +195,16 @@ static struct xt_target connmark_tg_reg[] __read_mostly = { + .destroy = connmark_tg_destroy, + .me = THIS_MODULE, + }, ++ { ++ .name = "CONNMARK", ++ .revision = 3, ++ .family = NFPROTO_IPV4, ++ .checkentry = connmark_tg_check, ++ .target = connmark_tg_v3, ++ .targetsize = sizeof(struct xt_connmark_tginfo3), ++ .destroy = connmark_tg_destroy, ++ .me = THIS_MODULE, ++ }, + #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) + { + .name = "CONNMARK", +@@ -189,6 +226,16 @@ static struct xt_target connmark_tg_reg[] __read_mostly = { + .destroy = connmark_tg_destroy, + .me = THIS_MODULE, + }, ++ { ++ .name = "CONNMARK", ++ .revision = 3, ++ .family = NFPROTO_IPV6, ++ .checkentry = connmark_tg_check, ++ .target = connmark_tg_v3, ++ .targetsize = sizeof(struct xt_connmark_tginfo3), ++ .destroy = connmark_tg_destroy, ++ .me = THIS_MODULE, ++ }, + #endif + }; + +-- +2.51.0 + + +From fd138131dfe7392f9794d929221cc4083f3661ed Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Tue, 20 Feb 2018 15:56:02 +0100 +Subject: [PATCH 356/517] netfilter: add xt_FLOWOFFLOAD target + +Signed-off-by: Felix Fietkau +--- + include/net/netfilter/nf_flow_table.h | 5 + + include/uapi/linux/netfilter/xt_FLOWOFFLOAD.h | 17 + + net/netfilter/Kconfig | 10 +- + net/netfilter/Makefile | 1 + + net/netfilter/nf_flow_table_core.c | 5 +- + net/netfilter/xt_FLOWOFFLOAD.c | 703 ++++++++++++++++++ + 6 files changed, 737 insertions(+), 4 deletions(-) + create mode 100644 include/uapi/linux/netfilter/xt_FLOWOFFLOAD.h + create mode 100644 net/netfilter/xt_FLOWOFFLOAD.c + +diff --git a/include/net/netfilter/nf_flow_table.h b/include/net/netfilter/nf_flow_table.h +index 1a6fca013165..2709725ee8cc 100644 +--- a/include/net/netfilter/nf_flow_table.h ++++ b/include/net/netfilter/nf_flow_table.h +@@ -294,6 +294,11 @@ void nf_flow_table_free(struct nf_flowtable *flow_table); + + void flow_offload_teardown(struct flow_offload *flow); + ++int nf_flow_table_iterate(struct nf_flowtable *flow_table, ++ void (*iter)(struct nf_flowtable *flowtable, ++ struct flow_offload *flow, void *data), ++ void *data); ++ + void nf_flow_snat_port(const struct flow_offload *flow, + struct sk_buff *skb, unsigned int thoff, + u8 protocol, enum flow_offload_tuple_dir dir); +diff --git a/include/uapi/linux/netfilter/xt_FLOWOFFLOAD.h b/include/uapi/linux/netfilter/xt_FLOWOFFLOAD.h +new file mode 100644 +index 000000000000..5841bbe0e3db +--- /dev/null ++++ b/include/uapi/linux/netfilter/xt_FLOWOFFLOAD.h +@@ -0,0 +1,17 @@ ++/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ ++#ifndef _XT_FLOWOFFLOAD_H ++#define _XT_FLOWOFFLOAD_H ++ ++#include ++ ++enum { ++ XT_FLOWOFFLOAD_HW = 1 << 0, ++ ++ XT_FLOWOFFLOAD_MASK = XT_FLOWOFFLOAD_HW ++}; ++ ++struct xt_flowoffload_target_info { ++ __u32 flags; ++}; ++ ++#endif /* _XT_FLOWOFFLOAD_H */ +diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig +index 944a47d0e2fd..e10e3b879121 100644 +--- a/net/netfilter/Kconfig ++++ b/net/netfilter/Kconfig +@@ -729,7 +729,6 @@ config NF_FLOW_TABLE + tristate "Netfilter flow table module" + depends on NETFILTER_INGRESS + depends on NF_CONNTRACK +- depends on NF_TABLES + help + This option adds the flow table core infrastructure. + +@@ -1025,6 +1024,15 @@ config NETFILTER_XT_TARGET_NOTRACK + depends on NETFILTER_ADVANCED + select NETFILTER_XT_TARGET_CT + ++config NETFILTER_XT_TARGET_FLOWOFFLOAD ++ tristate '"FLOWOFFLOAD" target support' ++ depends on NF_FLOW_TABLE ++ depends on NETFILTER_INGRESS ++ help ++ This option adds a `FLOWOFFLOAD' target, which uses the nf_flow_offload ++ module to speed up processing of packets by bypassing the usual ++ netfilter chains ++ + config NETFILTER_XT_TARGET_RATEEST + tristate '"RATEEST" target support' + depends on NETFILTER_ADVANCED +diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile +index f0aa4d7ef499..e9d11858a49b 100644 +--- a/net/netfilter/Makefile ++++ b/net/netfilter/Makefile +@@ -168,6 +168,7 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_CLASSIFY) += xt_CLASSIFY.o + obj-$(CONFIG_NETFILTER_XT_TARGET_CONNSECMARK) += xt_CONNSECMARK.o + obj-$(CONFIG_NETFILTER_XT_TARGET_CT) += xt_CT.o + obj-$(CONFIG_NETFILTER_XT_TARGET_DSCP) += xt_DSCP.o ++obj-$(CONFIG_NETFILTER_XT_TARGET_FLOWOFFLOAD) += xt_FLOWOFFLOAD.o + obj-$(CONFIG_NETFILTER_XT_TARGET_HL) += xt_HL.o + obj-$(CONFIG_NETFILTER_XT_TARGET_HMARK) += xt_HMARK.o + obj-$(CONFIG_NETFILTER_XT_TARGET_LED) += xt_LED.o +diff --git a/net/netfilter/nf_flow_table_core.c b/net/netfilter/nf_flow_table_core.c +index 54881f0e878a..f90303256229 100644 +--- a/net/netfilter/nf_flow_table_core.c ++++ b/net/netfilter/nf_flow_table_core.c +@@ -7,7 +7,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -373,8 +372,7 @@ flow_offload_lookup(struct nf_flowtable *flow_table, + } + EXPORT_SYMBOL_GPL(flow_offload_lookup); + +-static int +-nf_flow_table_iterate(struct nf_flowtable *flow_table, ++int nf_flow_table_iterate(struct nf_flowtable *flow_table, + void (*iter)(struct nf_flowtable *flowtable, + struct flow_offload *flow, void *data), + void *data) +@@ -435,6 +433,7 @@ static void nf_flow_offload_gc_step(struct nf_flowtable *flow_table, + nf_flow_offload_stats(flow_table, flow); + } + } ++EXPORT_SYMBOL_GPL(nf_flow_table_iterate); + + void nf_flow_table_gc_run(struct nf_flowtable *flow_table) + { +diff --git a/net/netfilter/xt_FLOWOFFLOAD.c b/net/netfilter/xt_FLOWOFFLOAD.c +new file mode 100644 +index 000000000000..08e0b945b4b0 +--- /dev/null ++++ b/net/netfilter/xt_FLOWOFFLOAD.c +@@ -0,0 +1,703 @@ ++/* ++ * Copyright (C) 2018-2021 Felix Fietkau ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++struct xt_flowoffload_hook { ++ struct hlist_node list; ++ struct nf_hook_ops ops; ++ struct net *net; ++ bool registered; ++ bool used; ++}; ++ ++struct xt_flowoffload_table { ++ struct nf_flowtable ft; ++ struct hlist_head hooks; ++ struct delayed_work work; ++}; ++ ++struct nf_forward_info { ++ const struct net_device *indev; ++ const struct net_device *outdev; ++ const struct net_device *hw_outdev; ++ struct id { ++ __u16 id; ++ __be16 proto; ++ } encap[NF_FLOW_TABLE_ENCAP_MAX]; ++ u8 num_encaps; ++ u8 ingress_vlans; ++ u8 h_source[ETH_ALEN]; ++ u8 h_dest[ETH_ALEN]; ++ enum flow_offload_xmit_type xmit_type; ++}; ++ ++static DEFINE_SPINLOCK(hooks_lock); ++ ++struct xt_flowoffload_table flowtable[2]; ++ ++static unsigned int ++xt_flowoffload_net_hook(void *priv, struct sk_buff *skb, ++ const struct nf_hook_state *state) ++{ ++ struct vlan_ethhdr *veth; ++ __be16 proto; ++ ++ switch (skb->protocol) { ++ case htons(ETH_P_8021Q): ++ veth = (struct vlan_ethhdr *)skb_mac_header(skb); ++ proto = veth->h_vlan_encapsulated_proto; ++ break; ++ case htons(ETH_P_PPP_SES): ++ if (!nf_flow_pppoe_proto(skb, &proto)) ++ return NF_ACCEPT; ++ break; ++ default: ++ proto = skb->protocol; ++ break; ++ } ++ ++ switch (proto) { ++ case htons(ETH_P_IP): ++ return nf_flow_offload_ip_hook(priv, skb, state); ++ case htons(ETH_P_IPV6): ++ return nf_flow_offload_ipv6_hook(priv, skb, state); ++ } ++ ++ return NF_ACCEPT; ++} ++ ++static int ++xt_flowoffload_create_hook(struct xt_flowoffload_table *table, ++ struct net_device *dev) ++{ ++ struct xt_flowoffload_hook *hook; ++ struct nf_hook_ops *ops; ++ ++ hook = kzalloc(sizeof(*hook), GFP_ATOMIC); ++ if (!hook) ++ return -ENOMEM; ++ ++ ops = &hook->ops; ++ ops->pf = NFPROTO_NETDEV; ++ ops->hooknum = NF_NETDEV_INGRESS; ++ ops->priority = 10; ++ ops->priv = &table->ft; ++ ops->hook = xt_flowoffload_net_hook; ++ ops->dev = dev; ++ ++ hlist_add_head(&hook->list, &table->hooks); ++ mod_delayed_work(system_power_efficient_wq, &table->work, 0); ++ ++ return 0; ++} ++ ++static struct xt_flowoffload_hook * ++flow_offload_lookup_hook(struct xt_flowoffload_table *table, ++ struct net_device *dev) ++{ ++ struct xt_flowoffload_hook *hook; ++ ++ hlist_for_each_entry(hook, &table->hooks, list) { ++ if (hook->ops.dev == dev) ++ return hook; ++ } ++ ++ return NULL; ++} ++ ++static void ++xt_flowoffload_check_device(struct xt_flowoffload_table *table, ++ struct net_device *dev) ++{ ++ struct xt_flowoffload_hook *hook; ++ ++ if (!dev) ++ return; ++ ++ spin_lock_bh(&hooks_lock); ++ hook = flow_offload_lookup_hook(table, dev); ++ if (hook) ++ hook->used = true; ++ else ++ xt_flowoffload_create_hook(table, dev); ++ spin_unlock_bh(&hooks_lock); ++} ++ ++static void ++xt_flowoffload_register_hooks(struct xt_flowoffload_table *table) ++{ ++ struct xt_flowoffload_hook *hook; ++ ++restart: ++ hlist_for_each_entry(hook, &table->hooks, list) { ++ if (hook->registered) ++ continue; ++ ++ hook->registered = true; ++ hook->net = dev_net(hook->ops.dev); ++ spin_unlock_bh(&hooks_lock); ++ nf_register_net_hook(hook->net, &hook->ops); ++ if (table->ft.flags & NF_FLOWTABLE_HW_OFFLOAD) ++ table->ft.type->setup(&table->ft, hook->ops.dev, ++ FLOW_BLOCK_BIND); ++ spin_lock_bh(&hooks_lock); ++ goto restart; ++ } ++ ++} ++ ++static bool ++xt_flowoffload_cleanup_hooks(struct xt_flowoffload_table *table) ++{ ++ struct xt_flowoffload_hook *hook; ++ bool active = false; ++ ++restart: ++ spin_lock_bh(&hooks_lock); ++ hlist_for_each_entry(hook, &table->hooks, list) { ++ if (hook->used || !hook->registered) { ++ active = true; ++ continue; ++ } ++ ++ hlist_del(&hook->list); ++ spin_unlock_bh(&hooks_lock); ++ if (table->ft.flags & NF_FLOWTABLE_HW_OFFLOAD) ++ table->ft.type->setup(&table->ft, hook->ops.dev, ++ FLOW_BLOCK_UNBIND); ++ nf_unregister_net_hook(hook->net, &hook->ops); ++ kfree(hook); ++ goto restart; ++ } ++ spin_unlock_bh(&hooks_lock); ++ ++ return active; ++} ++ ++static void ++xt_flowoffload_check_hook(struct nf_flowtable *flowtable, ++ struct flow_offload *flow, void *data) ++{ ++ struct xt_flowoffload_table *table; ++ struct flow_offload_tuple *tuple0 = &flow->tuplehash[0].tuple; ++ struct flow_offload_tuple *tuple1 = &flow->tuplehash[1].tuple; ++ struct xt_flowoffload_hook *hook; ++ ++ table = container_of(flowtable, struct xt_flowoffload_table, ft); ++ ++ spin_lock_bh(&hooks_lock); ++ hlist_for_each_entry(hook, &table->hooks, list) { ++ if (hook->ops.dev->ifindex != tuple0->iifidx && ++ hook->ops.dev->ifindex != tuple1->iifidx) ++ continue; ++ ++ hook->used = true; ++ } ++ spin_unlock_bh(&hooks_lock); ++} ++ ++static void ++xt_flowoffload_hook_work(struct work_struct *work) ++{ ++ struct xt_flowoffload_table *table; ++ struct xt_flowoffload_hook *hook; ++ int err; ++ ++ table = container_of(work, struct xt_flowoffload_table, work.work); ++ ++ spin_lock_bh(&hooks_lock); ++ xt_flowoffload_register_hooks(table); ++ hlist_for_each_entry(hook, &table->hooks, list) ++ hook->used = false; ++ spin_unlock_bh(&hooks_lock); ++ ++ err = nf_flow_table_iterate(&table->ft, xt_flowoffload_check_hook, ++ NULL); ++ if (err && err != -EAGAIN) ++ goto out; ++ ++ if (!xt_flowoffload_cleanup_hooks(table)) ++ return; ++ ++out: ++ queue_delayed_work(system_power_efficient_wq, &table->work, HZ); ++} ++ ++static bool ++xt_flowoffload_skip(struct sk_buff *skb, int family) ++{ ++ if (skb_sec_path(skb)) ++ return true; ++ ++ if (family == NFPROTO_IPV4) { ++ const struct ip_options *opt = &(IPCB(skb)->opt); ++ ++ if (unlikely(opt->optlen)) ++ return true; ++ } ++ ++ return false; ++} ++ ++static enum flow_offload_xmit_type nf_xmit_type(struct dst_entry *dst) ++{ ++ if (dst_xfrm(dst)) ++ return FLOW_OFFLOAD_XMIT_XFRM; ++ ++ return FLOW_OFFLOAD_XMIT_NEIGH; ++} ++ ++static void nf_default_forward_path(struct nf_flow_route *route, ++ struct dst_entry *dst_cache, ++ enum ip_conntrack_dir dir, ++ struct net_device **dev) ++{ ++ dev[!dir] = dst_cache->dev; ++ route->tuple[!dir].in.ifindex = dst_cache->dev->ifindex; ++ route->tuple[dir].dst = dst_cache; ++ route->tuple[dir].xmit_type = nf_xmit_type(dst_cache); ++} ++ ++static bool nf_is_valid_ether_device(const struct net_device *dev) ++{ ++ if (!dev || (dev->flags & IFF_LOOPBACK) || dev->type != ARPHRD_ETHER || ++ dev->addr_len != ETH_ALEN || !is_valid_ether_addr(dev->dev_addr)) ++ return false; ++ ++ return true; ++} ++ ++static void nf_dev_path_info(const struct net_device_path_stack *stack, ++ struct nf_forward_info *info, ++ unsigned char *ha) ++{ ++ const struct net_device_path *path; ++ int i; ++ ++ memcpy(info->h_dest, ha, ETH_ALEN); ++ ++ for (i = 0; i < stack->num_paths; i++) { ++ path = &stack->path[i]; ++ switch (path->type) { ++ case DEV_PATH_ETHERNET: ++ case DEV_PATH_DSA: ++ case DEV_PATH_VLAN: ++ case DEV_PATH_PPPOE: ++ info->indev = path->dev; ++ if (is_zero_ether_addr(info->h_source)) ++ memcpy(info->h_source, path->dev->dev_addr, ETH_ALEN); ++ ++ if (path->type == DEV_PATH_ETHERNET) ++ break; ++ if (path->type == DEV_PATH_DSA) { ++ i = stack->num_paths; ++ break; ++ } ++ ++ /* DEV_PATH_VLAN and DEV_PATH_PPPOE */ ++ if (info->num_encaps >= NF_FLOW_TABLE_ENCAP_MAX) { ++ info->indev = NULL; ++ break; ++ } ++ if (!info->outdev) ++ info->outdev = path->dev; ++ info->encap[info->num_encaps].id = path->encap.id; ++ info->encap[info->num_encaps].proto = path->encap.proto; ++ info->num_encaps++; ++ if (path->type == DEV_PATH_PPPOE) ++ memcpy(info->h_dest, path->encap.h_dest, ETH_ALEN); ++ break; ++ case DEV_PATH_BRIDGE: ++ if (is_zero_ether_addr(info->h_source)) ++ memcpy(info->h_source, path->dev->dev_addr, ETH_ALEN); ++ ++ switch (path->bridge.vlan_mode) { ++ case DEV_PATH_BR_VLAN_UNTAG_HW: ++ info->ingress_vlans |= BIT(info->num_encaps - 1); ++ break; ++ case DEV_PATH_BR_VLAN_TAG: ++ info->encap[info->num_encaps].id = path->bridge.vlan_id; ++ info->encap[info->num_encaps].proto = path->bridge.vlan_proto; ++ info->num_encaps++; ++ break; ++ case DEV_PATH_BR_VLAN_UNTAG: ++ info->num_encaps--; ++ break; ++ case DEV_PATH_BR_VLAN_KEEP: ++ break; ++ } ++ break; ++ default: ++ info->indev = NULL; ++ break; ++ } ++ } ++ if (!info->outdev) ++ info->outdev = info->indev; ++ ++ info->hw_outdev = info->indev; ++ ++ if (nf_is_valid_ether_device(info->indev)) ++ info->xmit_type = FLOW_OFFLOAD_XMIT_DIRECT; ++} ++ ++static int nf_dev_fill_forward_path(const struct nf_flow_route *route, ++ const struct dst_entry *dst_cache, ++ const struct nf_conn *ct, ++ enum ip_conntrack_dir dir, u8 *ha, ++ struct net_device_path_stack *stack) ++{ ++ const void *daddr = &ct->tuplehash[!dir].tuple.src.u3; ++ struct net_device *dev = dst_cache->dev; ++ struct neighbour *n; ++ u8 nud_state; ++ ++ if (!nf_is_valid_ether_device(dev)) ++ goto out; ++ ++ n = dst_neigh_lookup(dst_cache, daddr); ++ if (!n) ++ return -1; ++ ++ read_lock_bh(&n->lock); ++ nud_state = n->nud_state; ++ ether_addr_copy(ha, n->ha); ++ read_unlock_bh(&n->lock); ++ neigh_release(n); ++ ++ if (!(nud_state & NUD_VALID)) ++ return -1; ++ ++out: ++ return dev_fill_forward_path(dev, ha, stack); ++} ++ ++static void nf_dev_forward_path(struct nf_flow_route *route, ++ const struct nf_conn *ct, ++ enum ip_conntrack_dir dir, ++ struct net_device **devs) ++{ ++ const struct dst_entry *dst = route->tuple[dir].dst; ++ struct net_device_path_stack stack; ++ struct nf_forward_info info = {}; ++ unsigned char ha[ETH_ALEN]; ++ int i; ++ ++ if (nf_dev_fill_forward_path(route, dst, ct, dir, ha, &stack) >= 0) ++ nf_dev_path_info(&stack, &info, ha); ++ ++ devs[!dir] = (struct net_device *)info.indev; ++ if (!info.indev) ++ return; ++ ++ route->tuple[!dir].in.ifindex = info.indev->ifindex; ++ for (i = 0; i < info.num_encaps; i++) { ++ route->tuple[!dir].in.encap[i].id = info.encap[i].id; ++ route->tuple[!dir].in.encap[i].proto = info.encap[i].proto; ++ } ++ route->tuple[!dir].in.num_encaps = info.num_encaps; ++ route->tuple[!dir].in.ingress_vlans = info.ingress_vlans; ++ ++ if (info.xmit_type == FLOW_OFFLOAD_XMIT_DIRECT) { ++ memcpy(route->tuple[dir].out.h_source, info.h_source, ETH_ALEN); ++ memcpy(route->tuple[dir].out.h_dest, info.h_dest, ETH_ALEN); ++ route->tuple[dir].out.ifindex = info.outdev->ifindex; ++ route->tuple[dir].out.hw_ifindex = info.hw_outdev->ifindex; ++ route->tuple[dir].xmit_type = info.xmit_type; ++ } ++} ++ ++static int ++xt_flowoffload_route(struct sk_buff *skb, const struct nf_conn *ct, ++ const struct xt_action_param *par, ++ struct nf_flow_route *route, enum ip_conntrack_dir dir, ++ struct net_device **devs) ++{ ++ struct dst_entry *this_dst = skb_dst(skb); ++ struct dst_entry *other_dst = NULL; ++ struct flowi fl; ++ ++ memset(&fl, 0, sizeof(fl)); ++ switch (xt_family(par)) { ++ case NFPROTO_IPV4: ++ fl.u.ip4.daddr = ct->tuplehash[dir].tuple.src.u3.ip; ++ fl.u.ip4.flowi4_oif = xt_in(par)->ifindex; ++ break; ++ case NFPROTO_IPV6: ++ fl.u.ip6.saddr = ct->tuplehash[!dir].tuple.dst.u3.in6; ++ fl.u.ip6.daddr = ct->tuplehash[dir].tuple.src.u3.in6; ++ fl.u.ip6.flowi6_oif = xt_in(par)->ifindex; ++ break; ++ } ++ ++ if (!dst_hold_safe(this_dst)) ++ return -ENOENT; ++ ++ nf_route(xt_net(par), &other_dst, &fl, false, xt_family(par)); ++ if (!other_dst) { ++ dst_release(this_dst); ++ return -ENOENT; ++ } ++ ++ nf_default_forward_path(route, this_dst, dir, devs); ++ nf_default_forward_path(route, other_dst, !dir, devs); ++ ++ if (route->tuple[dir].xmit_type == FLOW_OFFLOAD_XMIT_NEIGH && ++ route->tuple[!dir].xmit_type == FLOW_OFFLOAD_XMIT_NEIGH) { ++ nf_dev_forward_path(route, ct, dir, devs); ++ nf_dev_forward_path(route, ct, !dir, devs); ++ } ++ ++ return 0; ++} ++ ++static unsigned int ++flowoffload_tg(struct sk_buff *skb, const struct xt_action_param *par) ++{ ++ struct xt_flowoffload_table *table; ++ const struct xt_flowoffload_target_info *info = par->targinfo; ++ struct tcphdr _tcph, *tcph = NULL; ++ enum ip_conntrack_info ctinfo; ++ enum ip_conntrack_dir dir; ++ struct nf_flow_route route = {}; ++ struct flow_offload *flow = NULL; ++ struct net_device *devs[2] = {}; ++ struct nf_conn *ct; ++ struct net *net; ++ ++ if (xt_flowoffload_skip(skb, xt_family(par))) ++ return XT_CONTINUE; ++ ++ ct = nf_ct_get(skb, &ctinfo); ++ if (ct == NULL) ++ return XT_CONTINUE; ++ ++ switch (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum) { ++ case IPPROTO_TCP: ++ if (ct->proto.tcp.state != TCP_CONNTRACK_ESTABLISHED) ++ return XT_CONTINUE; ++ ++ tcph = skb_header_pointer(skb, par->thoff, ++ sizeof(_tcph), &_tcph); ++ if (unlikely(!tcph || tcph->fin || tcph->rst)) ++ return XT_CONTINUE; ++ break; ++ case IPPROTO_UDP: ++ break; ++ default: ++ return XT_CONTINUE; ++ } ++ ++ if (nf_ct_ext_exist(ct, NF_CT_EXT_HELPER) || ++ ct->status & (IPS_SEQ_ADJUST | IPS_NAT_CLASH)) ++ return XT_CONTINUE; ++ ++ if (!nf_ct_is_confirmed(ct)) ++ return XT_CONTINUE; ++ ++ dir = CTINFO2DIR(ctinfo); ++ ++ devs[dir] = xt_out(par); ++ devs[!dir] = xt_in(par); ++ ++ if (!devs[dir] || !devs[!dir]) ++ return XT_CONTINUE; ++ ++ if (test_and_set_bit(IPS_OFFLOAD_BIT, &ct->status)) ++ return XT_CONTINUE; ++ ++ if (xt_flowoffload_route(skb, ct, par, &route, dir, devs) < 0) ++ goto err_flow_route; ++ ++ flow = flow_offload_alloc(ct); ++ if (!flow) ++ goto err_flow_alloc; ++ ++ flow_offload_route_init(flow, &route); ++ ++ if (tcph) { ++ ct->proto.tcp.seen[0].flags |= IP_CT_TCP_FLAG_BE_LIBERAL; ++ ct->proto.tcp.seen[1].flags |= IP_CT_TCP_FLAG_BE_LIBERAL; ++ } ++ ++ table = &flowtable[!!(info->flags & XT_FLOWOFFLOAD_HW)]; ++ ++ net = read_pnet(&table->ft.net); ++ if (!net) ++ write_pnet(&table->ft.net, xt_net(par)); ++ ++ __set_bit(NF_FLOW_HW_BIDIRECTIONAL, &flow->flags); ++ if (flow_offload_add(&table->ft, flow) < 0) ++ goto err_flow_add; ++ ++ xt_flowoffload_check_device(table, devs[0]); ++ xt_flowoffload_check_device(table, devs[1]); ++ ++ return XT_CONTINUE; ++ ++err_flow_add: ++ flow_offload_free(flow); ++err_flow_alloc: ++ dst_release(route.tuple[dir].dst); ++ dst_release(route.tuple[!dir].dst); ++err_flow_route: ++ clear_bit(IPS_OFFLOAD_BIT, &ct->status); ++ ++ return XT_CONTINUE; ++} ++ ++static int flowoffload_chk(const struct xt_tgchk_param *par) ++{ ++ struct xt_flowoffload_target_info *info = par->targinfo; ++ ++ if (info->flags & ~XT_FLOWOFFLOAD_MASK) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static struct xt_target offload_tg_reg __read_mostly = { ++ .family = NFPROTO_UNSPEC, ++ .name = "FLOWOFFLOAD", ++ .revision = 0, ++ .targetsize = sizeof(struct xt_flowoffload_target_info), ++ .usersize = sizeof(struct xt_flowoffload_target_info), ++ .checkentry = flowoffload_chk, ++ .target = flowoffload_tg, ++ .me = THIS_MODULE, ++}; ++ ++static int flow_offload_netdev_event(struct notifier_block *this, ++ unsigned long event, void *ptr) ++{ ++ struct xt_flowoffload_hook *hook0, *hook1; ++ struct net_device *dev = netdev_notifier_info_to_dev(ptr); ++ ++ if (event != NETDEV_UNREGISTER) ++ return NOTIFY_DONE; ++ ++ spin_lock_bh(&hooks_lock); ++ hook0 = flow_offload_lookup_hook(&flowtable[0], dev); ++ if (hook0) ++ hlist_del(&hook0->list); ++ ++ hook1 = flow_offload_lookup_hook(&flowtable[1], dev); ++ if (hook1) ++ hlist_del(&hook1->list); ++ spin_unlock_bh(&hooks_lock); ++ ++ if (hook0) { ++ nf_unregister_net_hook(hook0->net, &hook0->ops); ++ kfree(hook0); ++ } ++ ++ if (hook1) { ++ nf_unregister_net_hook(hook1->net, &hook1->ops); ++ kfree(hook1); ++ } ++ ++ nf_flow_table_cleanup(dev); ++ ++ return NOTIFY_DONE; ++} ++ ++static struct notifier_block flow_offload_netdev_notifier = { ++ .notifier_call = flow_offload_netdev_event, ++}; ++ ++static int nf_flow_rule_route_inet(struct net *net, ++ struct flow_offload *flow, ++ enum flow_offload_tuple_dir dir, ++ struct nf_flow_rule *flow_rule) ++{ ++ const struct flow_offload_tuple *flow_tuple = &flow->tuplehash[dir].tuple; ++ int err; ++ ++ switch (flow_tuple->l3proto) { ++ case NFPROTO_IPV4: ++ err = nf_flow_rule_route_ipv4(net, flow, dir, flow_rule); ++ break; ++ case NFPROTO_IPV6: ++ err = nf_flow_rule_route_ipv6(net, flow, dir, flow_rule); ++ break; ++ default: ++ err = -1; ++ break; ++ } ++ ++ return err; ++} ++ ++static struct nf_flowtable_type flowtable_inet = { ++ .family = NFPROTO_INET, ++ .init = nf_flow_table_init, ++ .setup = nf_flow_table_offload_setup, ++ .action = nf_flow_rule_route_inet, ++ .free = nf_flow_table_free, ++ .hook = xt_flowoffload_net_hook, ++ .owner = THIS_MODULE, ++}; ++ ++static int init_flowtable(struct xt_flowoffload_table *tbl) ++{ ++ INIT_DELAYED_WORK(&tbl->work, xt_flowoffload_hook_work); ++ tbl->ft.type = &flowtable_inet; ++ tbl->ft.flags = NF_FLOWTABLE_COUNTER; ++ ++ return nf_flow_table_init(&tbl->ft); ++} ++ ++static int __init xt_flowoffload_tg_init(void) ++{ ++ int ret; ++ ++ register_netdevice_notifier(&flow_offload_netdev_notifier); ++ ++ ret = init_flowtable(&flowtable[0]); ++ if (ret) ++ return ret; ++ ++ ret = init_flowtable(&flowtable[1]); ++ if (ret) ++ goto cleanup; ++ ++ flowtable[1].ft.flags |= NF_FLOWTABLE_HW_OFFLOAD; ++ ++ ret = xt_register_target(&offload_tg_reg); ++ if (ret) ++ goto cleanup2; ++ ++ return 0; ++ ++cleanup2: ++ nf_flow_table_free(&flowtable[1].ft); ++cleanup: ++ nf_flow_table_free(&flowtable[0].ft); ++ return ret; ++} ++ ++static void __exit xt_flowoffload_tg_exit(void) ++{ ++ xt_unregister_target(&offload_tg_reg); ++ unregister_netdevice_notifier(&flow_offload_netdev_notifier); ++ nf_flow_table_free(&flowtable[0].ft); ++ nf_flow_table_free(&flowtable[1].ft); ++} ++ ++MODULE_LICENSE("GPL"); ++module_init(xt_flowoffload_tg_init); ++module_exit(xt_flowoffload_tg_exit); +-- +2.51.0 + + +From a0ee647309aad3970467977ed72824d7c453aba4 Mon Sep 17 00:00:00 2001 +From: Imre Kaloz +Date: Fri, 7 Jul 2017 17:21:05 +0200 +Subject: [PATCH 357/517] mac80211: increase wireless mesh header size + +lede-commit 3d4466cfd8f75f717efdb1f96fdde3c70d865fc1 +Signed-off-by: Imre Kaloz +--- + include/linux/netdevice.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h +index c0a26b22f590..0f68392e0199 100644 +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -159,8 +159,8 @@ static inline bool dev_xmit_complete(int rc) + + #if defined(CONFIG_HYPERV_NET) + # define LL_MAX_HEADER 128 +-#elif defined(CONFIG_WLAN) || IS_ENABLED(CONFIG_AX25) +-# if defined(CONFIG_MAC80211_MESH) ++#elif defined(CONFIG_WLAN) || IS_ENABLED(CONFIG_AX25) || 1 ++# if defined(CONFIG_MAC80211_MESH) || 1 + # define LL_MAX_HEADER 128 + # else + # define LL_MAX_HEADER 96 +-- +2.51.0 + + +From 0444c74d164efb1fdec620766fd416d88fb65d4d Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Fri, 7 Jul 2017 17:21:53 +0200 +Subject: [PATCH 358/517] hack: net: fq_codel: tune defaults for small devices + +Assume that x86_64 devices always have a big memory and do not need this +optimization compared to devices with only 32 MB or 64 MB RAM. + +Signed-off-by: Felix Fietkau +--- + net/sched/sch_fq_codel.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/net/sched/sch_fq_codel.c b/net/sched/sch_fq_codel.c +index 551b7cbdae90..9f8741081cef 100644 +--- a/net/sched/sch_fq_codel.c ++++ b/net/sched/sch_fq_codel.c +@@ -472,7 +472,11 @@ static int fq_codel_init(struct Qdisc *sch, struct nlattr *opt, + + sch->limit = 10*1024; + q->flows_cnt = 1024; ++#ifdef CONFIG_X86_64 + q->memory_limit = 32 << 20; /* 32 MBytes */ ++#else ++ q->memory_limit = 4 << 20; /* 4 MBytes */ ++#endif + q->drop_batch_size = 64; + q->quantum = psched_mtu(qdisc_dev(sch)); + INIT_LIST_HEAD(&q->new_flows); +-- +2.51.0 + + +From 8bbcca90b9c5ef9e32a374a259d0ae25f128c95e Mon Sep 17 00:00:00 2001 +From: Rui Salvaterra +Date: Wed, 30 Mar 2022 22:51:55 +0100 +Subject: [PATCH 359/517] kernel: ct: size the hashtable more adequately + +To set the default size of the connection tracking hash table, a divider of +16384 becomes inadequate for a router handling lots of connections. Divide by +2048 instead, making the default size scale better with the available RAM. + +Signed-off-by: Rui Salvaterra +--- + net/netfilter/nf_conntrack_core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c +index f5bde4f13958..cdcc01fcd30f 100644 +--- a/net/netfilter/nf_conntrack_core.c ++++ b/net/netfilter/nf_conntrack_core.c +@@ -2648,7 +2648,7 @@ int nf_conntrack_init_start(void) + + if (!nf_conntrack_htable_size) { + nf_conntrack_htable_size +- = (((nr_pages << PAGE_SHIFT) / 16384) ++ = (((nr_pages << PAGE_SHIFT) / 2048) + / sizeof(struct hlist_head)); + if (BITS_PER_LONG >= 64 && + nr_pages > (4 * (1024 * 1024 * 1024 / PAGE_SIZE))) +-- +2.51.0 + + +From 2b0f67440761e35ef5eb7a2f3bc1e3d47deabf3c Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Fri, 7 Jul 2017 17:24:23 +0200 +Subject: [PATCH 360/517] net: swconfig: adds openwrt switch layer + +Signed-off-by: Felix Fietkau +--- + drivers/net/phy/Kconfig | 74 +++++++++++++++++++++++++++++++ + drivers/net/phy/Makefile | 15 +++++++ + include/linux/platform_data/b53.h | 3 ++ + 3 files changed, 92 insertions(+) + +diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig +index 8c92405b84d4..7b1a94e8aa8b 100644 +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -77,6 +77,80 @@ config SFP + depends on HWMON || HWMON=n + select MDIO_I2C + ++comment "Switch configuration API + drivers" ++ ++config SWCONFIG ++ tristate "Switch configuration API" ++ help ++ Switch configuration API using netlink. This allows ++ you to configure the VLAN features of certain switches. ++ ++config SWCONFIG_LEDS ++ bool "Switch LED trigger support" ++ depends on (SWCONFIG && LEDS_TRIGGERS) ++ ++config ADM6996_PHY ++ tristate "Driver for ADM6996 switches" ++ select SWCONFIG ++ help ++ Currently supports the ADM6996FC and ADM6996M switches. ++ Support for FC is very limited. ++ ++config AR8216_PHY ++ tristate "Driver for Atheros AR8216/8327 switches" ++ select SWCONFIG ++ select ETHERNET_PACKET_MANGLE ++ ++config AR8216_PHY_LEDS ++ bool "Atheros AR8216 switch LED support" ++ depends on (AR8216_PHY && LEDS_CLASS) ++ ++source "drivers/net/phy/b53/Kconfig" ++ ++config IP17XX_PHY ++ tristate "Driver for IC+ IP17xx switches" ++ select SWCONFIG ++ ++config PSB6970_PHY ++ tristate "Lantiq XWAY Tantos (PSB6970) Ethernet switch" ++ select SWCONFIG ++ ++config RTL8306_PHY ++ tristate "Driver for Realtek RTL8306S switches" ++ select SWCONFIG ++ ++config RTL8366_SMI ++ tristate "Driver for the RTL8366 SMI interface" ++ depends on GPIOLIB ++ help ++ This module implements the SMI interface protocol which is used ++ by some RTL8366 ethernet switch devices via the generic GPIO API. ++ ++if RTL8366_SMI ++ ++config RTL8366_SMI_DEBUG_FS ++ bool "RTL8366 SMI interface debugfs support" ++ depends on DEBUG_FS ++ default n ++ ++config RTL8366S_PHY ++ tristate "Driver for the Realtek RTL8366S switch" ++ select SWCONFIG ++ ++config RTL8366RB_PHY ++ tristate "Driver for the Realtek RTL8366RB switch" ++ select SWCONFIG ++ ++config RTL8367_PHY ++ tristate "Driver for the Realtek RTL8367R/M switches" ++ select SWCONFIG ++ ++config RTL8367B_PHY ++ tristate "Driver for the Realtek RTL8367R-VB switch" ++ select SWCONFIG ++ ++endif # RTL8366_SMI ++ + comment "MII PHY device drivers" + + config AS21XXX_PHY +diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile +index a9080b8d604e..5fefb4d699fb 100644 +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -27,6 +27,21 @@ libphy-$(CONFIG_OPEN_ALLIANCE_HELPERS) += open_alliance_helpers.o + obj-$(CONFIG_PHYLINK) += phylink.o + obj-$(CONFIG_PHYLIB) += libphy.o + ++obj-$(CONFIG_SWCONFIG) += swconfig.o ++obj-$(CONFIG_ADM6996_PHY) += adm6996.o ++obj-$(CONFIG_AR8216_PHY) += ar8xxx.o ++ar8xxx-y += ar8216.o ++ar8xxx-y += ar8327.o ++obj-$(CONFIG_SWCONFIG_B53) += b53/ ++obj-$(CONFIG_IP17XX_PHY) += ip17xx.o ++obj-$(CONFIG_PSB6970_PHY) += psb6970.o ++obj-$(CONFIG_RTL8306_PHY) += rtl8306.o ++obj-$(CONFIG_RTL8366_SMI) += rtl8366_smi.o ++obj-$(CONFIG_RTL8366S_PHY) += rtl8366s.o ++obj-$(CONFIG_RTL8366RB_PHY) += rtl8366rb.o ++obj-$(CONFIG_RTL8367_PHY) += rtl8367.o ++obj-$(CONFIG_RTL8367B_PHY) += rtl8367b.o ++ + obj-$(CONFIG_NETWORK_PHY_TIMESTAMPING) += mii_timestamper.o + + obj-$(CONFIG_SFP) += sfp.o +diff --git a/include/linux/platform_data/b53.h b/include/linux/platform_data/b53.h +index 6f6fed2b171d..2d90457926e5 100644 +--- a/include/linux/platform_data/b53.h ++++ b/include/linux/platform_data/b53.h +@@ -29,6 +29,9 @@ struct b53_platform_data { + u32 chip_id; + u16 enabled_ports; + ++ /* allow to specify an ethX alias */ ++ const char *alias; ++ + /* only used by MMAP'd driver */ + unsigned big_endian:1; + void __iomem *regs; +-- +2.51.0 + + +From 18a667d953110fd776c1a9850bc80c9290fa7527 Mon Sep 17 00:00:00 2001 +From: OpenWrt community +Date: Wed, 13 Jul 2022 13:45:56 +0200 +Subject: [PATCH 361/517] net/dsa/mv88e6xxx: disable ATU violation + +--- + drivers/net/dsa/mv88e6xxx/chip.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c +index 43e0482fe1fd..2b547c2a7f43 100644 +--- a/drivers/net/dsa/mv88e6xxx/chip.c ++++ b/drivers/net/dsa/mv88e6xxx/chip.c +@@ -3582,6 +3582,9 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port) + else + reg = 1 << port; + ++ /* Disable ATU member violation interrupt */ ++ reg |= MV88E6XXX_PORT_ASSOC_VECTOR_IGNORE_WRONG; ++ + err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ASSOC_VECTOR, + reg); + if (err) +-- +2.51.0 + + +From b3147d8d726ee0e591bb977db46056fa51385934 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Fri, 7 Jul 2017 17:25:00 +0200 +Subject: [PATCH 362/517] net: add packet mangeling + +ar8216 switches have a hardware bug, which renders normal 802.1q support +unusable. Packet mangling is required to fix up the vlan for incoming +packets. + +Signed-off-by: Felix Fietkau +--- + include/linux/netdevice.h | 10 ++++++++++ + include/linux/skbuff.h | 14 ++++---------- + net/Kconfig | 6 ++++++ + net/core/dev.c | 5 +++++ + net/core/skbuff.c | 17 +++++++++++++++++ + net/ethernet/eth.c | 6 ++++++ + 6 files changed, 48 insertions(+), 10 deletions(-) + +diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h +index 0f68392e0199..1d2dd73b6091 100644 +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -1687,6 +1687,7 @@ enum netdev_priv_flags { + IFF_L3MDEV_RX_HANDLER = 1<<29, + IFF_NO_ADDRCONF = BIT_ULL(30), + IFF_TX_SKB_NO_LINEAR = BIT_ULL(31), ++ IFF_NO_IP_ALIGN = BIT_ULL(32), + }; + + /* Specifies the type of the struct net_device::ml_priv pointer */ +@@ -2168,6 +2169,11 @@ struct net_device { + const struct tlsdev_ops *tlsdev_ops; + #endif + ++#ifdef CONFIG_ETHERNET_PACKET_MANGLE ++ void (*eth_mangle_rx)(struct net_device *dev, struct sk_buff *skb); ++ struct sk_buff *(*eth_mangle_tx)(struct net_device *dev, struct sk_buff *skb); ++#endif ++ + unsigned int operstate; + unsigned char link_mode; + +@@ -2237,6 +2243,10 @@ struct net_device { + struct mctp_dev __rcu *mctp_ptr; + #endif + ++#ifdef CONFIG_ETHERNET_PACKET_MANGLE ++ void *phy_ptr; /* PHY device specific data */ ++#endif ++ + /* + * Cache lines mostly used on receive path (including eth_type_trans()) + */ +diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h +index eb7b94939f46..d689ea0fa9f2 100644 +--- a/include/linux/skbuff.h ++++ b/include/linux/skbuff.h +@@ -3242,6 +3242,10 @@ static inline int pskb_trim(struct sk_buff *skb, unsigned int len) + return (len < skb->len) ? __pskb_trim(skb, len) : 0; + } + ++extern struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev, ++ unsigned int length, gfp_t gfp); ++ ++ + /** + * pskb_trim_unique - remove end from a paged unique (not cloned) buffer + * @skb: buffer to alter +@@ -3407,16 +3411,6 @@ static inline struct sk_buff *dev_alloc_skb(unsigned int length) + } + + +-static inline struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev, +- unsigned int length, gfp_t gfp) +-{ +- struct sk_buff *skb = __netdev_alloc_skb(dev, length + NET_IP_ALIGN, gfp); +- +- if (NET_IP_ALIGN && skb) +- skb_reserve(skb, NET_IP_ALIGN); +- return skb; +-} +- + static inline struct sk_buff *netdev_alloc_skb_ip_align(struct net_device *dev, + unsigned int length) + { +diff --git a/net/Kconfig b/net/Kconfig +index 6744f55d9683..c98df432683b 100644 +--- a/net/Kconfig ++++ b/net/Kconfig +@@ -26,6 +26,12 @@ menuconfig NET + + if NET + ++config ETHERNET_PACKET_MANGLE ++ bool ++ help ++ This option can be selected by phy drivers that need to mangle ++ packets going in or out of an ethernet device. ++ + config WANT_COMPAT_NETLINK_MESSAGES + bool + help +diff --git a/net/core/dev.c b/net/core/dev.c +index cfd32bd02a69..30a22db52d58 100644 +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -3658,6 +3658,11 @@ static int xmit_one(struct sk_buff *skb, struct net_device *dev, + if (dev_nit_active(dev)) + dev_queue_xmit_nit(skb, dev); + ++#ifdef CONFIG_ETHERNET_PACKET_MANGLE ++ if (dev->eth_mangle_tx && !(skb = dev->eth_mangle_tx(dev, skb))) ++ return NETDEV_TX_OK; ++#endif ++ + len = skb->len; + trace_net_dev_start_xmit(skb, dev); + rc = netdev_start_xmit(skb, dev, txq, more); +diff --git a/net/core/skbuff.c b/net/core/skbuff.c +index 6a92c03ee6f4..0a8628524de9 100644 +--- a/net/core/skbuff.c ++++ b/net/core/skbuff.c +@@ -64,6 +64,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -326,6 +327,22 @@ void *__napi_alloc_frag_align(unsigned int fragsz, unsigned int align_mask) + } + EXPORT_SYMBOL(__napi_alloc_frag_align); + ++struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev, ++ unsigned int length, gfp_t gfp) ++{ ++ struct sk_buff *skb = __netdev_alloc_skb(dev, length + NET_IP_ALIGN, gfp); ++ ++#ifdef CONFIG_ETHERNET_PACKET_MANGLE ++ if (dev && (dev->priv_flags & IFF_NO_IP_ALIGN)) ++ return skb; ++#endif ++ ++ if (NET_IP_ALIGN && skb) ++ skb_reserve(skb, NET_IP_ALIGN); ++ return skb; ++} ++EXPORT_SYMBOL(__netdev_alloc_skb_ip_align); ++ + void *__netdev_alloc_frag_align(unsigned int fragsz, unsigned int align_mask) + { + void *data; +diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c +index 4e3651101b86..b7fb89299528 100644 +--- a/net/ethernet/eth.c ++++ b/net/ethernet/eth.c +@@ -159,6 +159,12 @@ __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev) + const struct ethhdr *eth; + + skb->dev = dev; ++ ++#ifdef CONFIG_ETHERNET_PACKET_MANGLE ++ if (dev->eth_mangle_rx) ++ dev->eth_mangle_rx(dev, skb); ++#endif ++ + skb_reset_mac_header(skb); + + eth = eth_skb_pull_mac(skb); +-- +2.51.0 + + +From 2fb8b4eee5e48e4522386d31f25989d55aedab32 Mon Sep 17 00:00:00 2001 +From: Alex Marginean +Date: Tue, 27 Aug 2019 15:16:56 +0300 +Subject: [PATCH 363/517] drivers: net: phy: aquantia: enable AQR112 and AQR412 + +Adds support for AQR112 and AQR412 which is mostly based on existing code +with the addition of code configuring the protocol on system side. +This allows changing the system side protocol without having to deploy a +different firmware on the PHY. + +Signed-off-by: Alex Marginean +--- + drivers/net/phy/aquantia/aquantia_main.c | 72 +++++++++++++++++++++++- + 1 file changed, 70 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/phy/aquantia/aquantia_main.c b/drivers/net/phy/aquantia/aquantia_main.c +index 2008b98c689e..542c4d0d699e 100644 +--- a/drivers/net/phy/aquantia/aquantia_main.c ++++ b/drivers/net/phy/aquantia/aquantia_main.c +@@ -97,6 +97,29 @@ + #define AQR107_OP_IN_PROG_SLEEP 1000 + #define AQR107_OP_IN_PROG_TIMEOUT 100000 + ++/* registers in MDIO_MMD_VEND1 region */ ++#define AQUANTIA_VND1_GLOBAL_SC 0x000 ++#define AQUANTIA_VND1_GLOBAL_SC_LP BIT(0xb) ++ ++/* global start rate, the protocol associated with this speed is used by default ++ * on SI. ++ */ ++#define AQUANTIA_VND1_GSTART_RATE 0x31a ++#define AQUANTIA_VND1_GSTART_RATE_OFF 0 ++#define AQUANTIA_VND1_GSTART_RATE_100M 1 ++#define AQUANTIA_VND1_GSTART_RATE_1G 2 ++#define AQUANTIA_VND1_GSTART_RATE_10G 3 ++#define AQUANTIA_VND1_GSTART_RATE_2_5G 4 ++#define AQUANTIA_VND1_GSTART_RATE_5G 5 ++ ++/* SYSCFG registers for 100M, 1G, 2.5G, 5G, 10G */ ++#define AQUANTIA_VND1_GSYSCFG_BASE 0x31b ++#define AQUANTIA_VND1_GSYSCFG_100M 0 ++#define AQUANTIA_VND1_GSYSCFG_1G 1 ++#define AQUANTIA_VND1_GSYSCFG_2_5G 2 ++#define AQUANTIA_VND1_GSYSCFG_5G 3 ++#define AQUANTIA_VND1_GSYSCFG_10G 4 ++ + static int aqr107_get_sset_count(struct phy_device *phydev) + { + return AQR107_SGMII_STAT_SZ; +@@ -203,6 +226,51 @@ static int aqr_config_aneg(struct phy_device *phydev) + return genphy_c45_check_and_restart_aneg(phydev, changed); + } + ++static struct { ++ u16 syscfg; ++ int cnt; ++ u16 start_rate; ++} aquantia_syscfg[PHY_INTERFACE_MODE_MAX] = { ++ [PHY_INTERFACE_MODE_SGMII] = {0x04b, AQUANTIA_VND1_GSYSCFG_1G, ++ AQUANTIA_VND1_GSTART_RATE_1G}, ++ [PHY_INTERFACE_MODE_2500BASEX] = {0x144, AQUANTIA_VND1_GSYSCFG_2_5G, ++ AQUANTIA_VND1_GSTART_RATE_2_5G}, ++ [PHY_INTERFACE_MODE_XGMII] = {0x100, AQUANTIA_VND1_GSYSCFG_10G, ++ AQUANTIA_VND1_GSTART_RATE_10G}, ++ [PHY_INTERFACE_MODE_USXGMII] = {0x080, AQUANTIA_VND1_GSYSCFG_10G, ++ AQUANTIA_VND1_GSTART_RATE_10G}, ++}; ++ ++/* Sets up protocol on system side before calling aqr_config_aneg */ ++static int aqr_config_aneg_set_prot(struct phy_device *phydev) ++{ ++ int if_type = phydev->interface; ++ int i; ++ ++ if (!aquantia_syscfg[if_type].cnt) ++ return 0; ++ ++ /* set PHY in low power mode so we can configure protocols */ ++ phy_write_mmd(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GLOBAL_SC, ++ AQUANTIA_VND1_GLOBAL_SC_LP); ++ mdelay(10); ++ ++ /* set the default rate to enable the SI link */ ++ phy_write_mmd(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GSTART_RATE, ++ aquantia_syscfg[if_type].start_rate); ++ ++ for (i = 0; i <= aquantia_syscfg[if_type].cnt; i++) ++ phy_write_mmd(phydev, MDIO_MMD_VEND1, ++ AQUANTIA_VND1_GSYSCFG_BASE + i, ++ aquantia_syscfg[if_type].syscfg); ++ ++ /* wake PHY back up */ ++ phy_write_mmd(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GLOBAL_SC, 0); ++ mdelay(10); ++ ++ return aqr_config_aneg(phydev); ++} ++ + static int aqr_config_intr(struct phy_device *phydev) + { + bool en = phydev->interrupts == PHY_INTERRUPT_ENABLED; +@@ -972,7 +1040,7 @@ static struct phy_driver aqr_driver[] = { + PHY_ID_MATCH_MODEL(PHY_ID_AQR112), + .name = "Aquantia AQR112", + .probe = aqr107_probe, +- .config_aneg = aqr_config_aneg, ++ .config_aneg = aqr_config_aneg_set_prot, + .config_intr = aqr_config_intr, + .handle_interrupt = aqr_handle_interrupt, + .get_tunable = aqr107_get_tunable, +@@ -995,7 +1063,7 @@ static struct phy_driver aqr_driver[] = { + PHY_ID_MATCH_MODEL(PHY_ID_AQR412), + .name = "Aquantia AQR412", + .probe = aqr107_probe, +- .config_aneg = aqr_config_aneg, ++ .config_aneg = aqr_config_aneg_set_prot, + .config_intr = aqr_config_intr, + .handle_interrupt = aqr_handle_interrupt, + .get_tunable = aqr107_get_tunable, +-- +2.51.0 + + +From 36bebde61759d445e0eef0559c74377af98a3bbc Mon Sep 17 00:00:00 2001 +From: Alex Marginean +Date: Fri, 20 Sep 2019 18:22:52 +0300 +Subject: [PATCH 364/517] drivers: net: phy: aquantia: fix system side protocol + misconfiguration + +Do not set up protocols for speeds that are not supported by FW. Enabling +these protocols leads to link issues on system side. + +Signed-off-by: Alex Marginean +--- + drivers/net/phy/aquantia/aquantia_main.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/phy/aquantia/aquantia_main.c b/drivers/net/phy/aquantia/aquantia_main.c +index 542c4d0d699e..a5269b7ec26d 100644 +--- a/drivers/net/phy/aquantia/aquantia_main.c ++++ b/drivers/net/phy/aquantia/aquantia_main.c +@@ -259,10 +259,16 @@ static int aqr_config_aneg_set_prot(struct phy_device *phydev) + phy_write_mmd(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GSTART_RATE, + aquantia_syscfg[if_type].start_rate); + +- for (i = 0; i <= aquantia_syscfg[if_type].cnt; i++) ++ for (i = 0; i <= aquantia_syscfg[if_type].cnt; i++) { ++ u16 reg = phy_read_mmd(phydev, MDIO_MMD_VEND1, ++ AQUANTIA_VND1_GSYSCFG_BASE + i); ++ if (!reg) ++ continue; ++ + phy_write_mmd(phydev, MDIO_MMD_VEND1, + AQUANTIA_VND1_GSYSCFG_BASE + i, + aquantia_syscfg[if_type].syscfg); ++ } + + /* wake PHY back up */ + phy_write_mmd(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GLOBAL_SC, 0); +-- +2.51.0 + + +From 9d7a3fd6822d5ea9dcd306a8adad5b3c1160047a Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Thu, 23 Dec 2021 14:52:56 +0000 +Subject: [PATCH 365/517] net: phy: aquantia: add PHY_ID for AQR112R + +As advised by Ian Chang this PHY is used in Puzzle devices. + +Signed-off-by: Daniel Golle +--- + drivers/net/phy/aquantia/aquantia_main.c | 28 ++++++++++++++++++++++++ + 1 file changed, 28 insertions(+) + +diff --git a/drivers/net/phy/aquantia/aquantia_main.c b/drivers/net/phy/aquantia/aquantia_main.c +index a5269b7ec26d..f25e63480ec2 100644 +--- a/drivers/net/phy/aquantia/aquantia_main.c ++++ b/drivers/net/phy/aquantia/aquantia_main.c +@@ -32,6 +32,8 @@ + #define PHY_ID_AQR114C 0x31c31c22 + #define PHY_ID_AQR115C 0x31c31c33 + #define PHY_ID_AQR813 0x31c31cb2 ++#define PHY_ID_AQR112C 0x03a1b790 ++#define PHY_ID_AQR112R 0x31c31d12 + + #define MDIO_PHYXS_VEND_IF_STATUS 0xe812 + #define MDIO_PHYXS_VEND_IF_STATUS_TYPE_MASK GENMASK(7, 3) +@@ -1205,6 +1207,30 @@ static struct phy_driver aqr_driver[] = { + .led_hw_control_get = aqr_phy_led_hw_control_get, + .led_polarity_set = aqr_phy_led_polarity_set, + }, ++{ ++ PHY_ID_MATCH_MODEL(PHY_ID_AQR112C), ++ .name = "Aquantia AQR112C", ++ .probe = aqr107_probe, ++ .config_aneg = aqr_config_aneg_set_prot, ++ .config_intr = aqr_config_intr, ++ .handle_interrupt = aqr_handle_interrupt, ++ .read_status = aqr107_read_status, ++ .get_sset_count = aqr107_get_sset_count, ++ .get_strings = aqr107_get_strings, ++ .get_stats = aqr107_get_stats, ++}, ++{ ++ PHY_ID_MATCH_MODEL(PHY_ID_AQR112R), ++ .name = "Aquantia AQR112R", ++ .probe = aqr107_probe, ++ .config_aneg = aqr_config_aneg_set_prot, ++ .config_intr = aqr_config_intr, ++ .handle_interrupt = aqr_handle_interrupt, ++ .read_status = aqr107_read_status, ++ .get_sset_count = aqr107_get_sset_count, ++ .get_strings = aqr107_get_strings, ++ .get_stats = aqr107_get_stats, ++}, + }; + + module_phy_driver(aqr_driver); +@@ -1226,6 +1252,8 @@ static const struct mdio_device_id __maybe_unused aqr_tbl[] = { + { PHY_ID_MATCH_MODEL(PHY_ID_AQR114C) }, + { PHY_ID_MATCH_MODEL(PHY_ID_AQR115C) }, + { PHY_ID_MATCH_MODEL(PHY_ID_AQR813) }, ++ { PHY_ID_MATCH_MODEL(PHY_ID_AQR112C) }, ++ { PHY_ID_MATCH_MODEL(PHY_ID_AQR112R) }, + { } + }; + +-- +2.51.0 + + +From 41fcce1b7749447554e6dd24270895a39be0a7ce Mon Sep 17 00:00:00 2001 +From: Bo-Cun Chen +Date: Wed, 27 Nov 2024 13:36:49 +0800 +Subject: [PATCH 366/517] net: ethernet: mtk_eth_soc: add hw dump for forced + reset + +Without this patch, the ETH driver is unable to dump the registers +before triggering a forced reset. + +Signed-off-by: Bo-Cun Chen +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 55 +++++++++++++++++++++ + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 1 + + 2 files changed, 56 insertions(+) + +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +index bc217da6ffc7..7d8c6ee707d1 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -74,6 +74,7 @@ static const struct mtk_reg_map mtk_reg_map = { + .rx_ptr = 0x1900, + .rx_cnt_cfg = 0x1904, + .qcrx_ptr = 0x1908, ++ .page = 0x19f0, + .glo_cfg = 0x1a04, + .rst_idx = 0x1a08, + .delay_irq = 0x1a0c, +@@ -140,6 +141,7 @@ static const struct mtk_reg_map mt7986_reg_map = { + .rx_ptr = 0x4500, + .rx_cnt_cfg = 0x4504, + .qcrx_ptr = 0x4508, ++ .page = 0x45f0, + .glo_cfg = 0x4604, + .rst_idx = 0x4608, + .delay_irq = 0x460c, +@@ -191,6 +193,7 @@ static const struct mtk_reg_map mt7988_reg_map = { + .rx_ptr = 0x4500, + .rx_cnt_cfg = 0x4504, + .qcrx_ptr = 0x4508, ++ .page = 0x45f0, + .glo_cfg = 0x4604, + .rst_idx = 0x4608, + .delay_irq = 0x460c, +@@ -4053,6 +4056,56 @@ static void mtk_set_mcr_max_rx(struct mtk_mac *mac, u32 val) + mtk_w32(mac->hw, mcr_new, MTK_MAC_MCR(mac->id)); + } + ++static void mtk_hw_dump_reg(struct mtk_eth *eth, char *name, u32 offset, u32 range) ++{ ++ u32 cur = offset; ++ ++ pr_info("\n==================== %s ====================\n", name); ++ while (cur < offset + range) { ++ pr_info("0x%08x: %08x %08x %08x %08x\n", ++ cur, mtk_r32(eth, cur), mtk_r32(eth, cur + 0x4), ++ mtk_r32(eth, cur + 0x8), mtk_r32(eth, cur + 0xc)); ++ cur += 0x10; ++ } ++} ++ ++static void mtk_hw_dump(struct mtk_eth *eth) ++{ ++ const struct mtk_reg_map *reg_map = eth->soc->reg_map; ++ u32 id; ++ ++ mtk_hw_dump_reg(eth, "FE", 0x0, 0x600); ++ mtk_hw_dump_reg(eth, "FE", 0x1400, 0x300); ++ mtk_hw_dump_reg(eth, "ADMA", reg_map->pdma.rx_ptr, 0x300); ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) { ++ for (id = 0; id < MTK_QDMA_NUM_QUEUES / 16; id++) { ++ mtk_w32(eth, id, reg_map->qdma.page); ++ pr_info("\nQDMA PAGE:%x ", mtk_r32(eth, reg_map->qdma.page)); ++ mtk_hw_dump_reg(eth, "QDMA", reg_map->qdma.qtx_cfg, 0x100); ++ mtk_w32(eth, 0, reg_map->qdma.page); ++ } ++ mtk_hw_dump_reg(eth, "QDMA", reg_map->qdma.rx_ptr, 0x300); ++ } ++ if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) { ++ mtk_hw_dump_reg(eth, "WDMA0", reg_map->wdma_base[0], 0x400); ++ mtk_hw_dump_reg(eth, "WDMA1", reg_map->wdma_base[1], 0x400); ++ if (mtk_is_netsys_v3_or_greater(eth)) ++ mtk_hw_dump_reg(eth, "WDMA2", reg_map->wdma_base[2], 0x400); ++ } ++ mtk_hw_dump_reg(eth, "PPE0", reg_map->ppe_base + 0x200, 0x200); ++ if (!mtk_is_netsys_v1(eth)) ++ mtk_hw_dump_reg(eth, "PPE1", reg_map->ppe_base + 0x600, 0x200); ++ if (mtk_is_netsys_v3_or_greater(eth)) ++ mtk_hw_dump_reg(eth, "PPE2", reg_map->ppe_base + 0xE00, 0x200); ++ mtk_hw_dump_reg(eth, "GMAC", 0x10000, 0x300); ++ if (mtk_is_netsys_v3_or_greater(eth)) ++ mtk_hw_dump_reg(eth, "GMAC", 0x10300, 0x100); ++ if (mtk_is_netsys_v3_or_greater(eth)) { ++ mtk_hw_dump_reg(eth, "XGMAC0", 0x12000, 0x300); ++ mtk_hw_dump_reg(eth, "XGMAC1", 0x13000, 0x300); ++ } ++} ++ + static void mtk_hw_reset(struct mtk_eth *eth) + { + u32 val; +@@ -4532,6 +4585,8 @@ static void mtk_pending_work(struct work_struct *work) + rtnl_lock(); + set_bit(MTK_RESETTING, ð->state); + ++ mtk_hw_dump(eth); ++ + mtk_prepare_for_reset(eth); + mtk_wed_fe_reset(); + /* Run again reset preliminary configuration in order to avoid any +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +index c7ad88351a1b..d0e7ce0bcb96 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -1185,6 +1185,7 @@ struct mtk_reg_map { + u32 rx_ptr; /* rx base pointer */ + u32 rx_cnt_cfg; /* rx max count configuration */ + u32 qcrx_ptr; /* rx cpu pointer */ ++ u32 page; /* page configuration */ + u32 glo_cfg; /* global configuration */ + u32 rst_idx; /* reset index */ + u32 delay_irq; /* delay interrupt */ +-- +2.51.0 + + +From 3353024c7ed6fc97e113e5f2e4e94a94913f1a9a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= +Date: Mon, 3 Nov 2025 15:50:25 +0100 +Subject: [PATCH 367/517] + /home/cynerd/turris/upstream/openwrt/target/linux/generic/hack-6.12/735-net-phy-realtek-rtl8261n.patch + +--- + drivers/net/phy/Kconfig | 2 ++ + drivers/net/phy/Makefile | 1 + + 2 files changed, 3 insertions(+) + +diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig +index 7b1a94e8aa8b..0e672540a0fa 100644 +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -431,6 +431,8 @@ config QSEMI_PHY + + source "drivers/net/phy/realtek/Kconfig" + ++source "drivers/net/phy/rtl8261n/Kconfig" ++ + config RENESAS_PHY + tristate "Renesas PHYs" + help +diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile +index 5fefb4d699fb..d0f2b36d5c87 100644 +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -110,6 +110,7 @@ obj-$(CONFIG_NXP_TJA11XX_PHY) += nxp-tja11xx.o + obj-y += qcom/ + obj-$(CONFIG_QSEMI_PHY) += qsemi.o + obj-$(CONFIG_REALTEK_PHY) += realtek/ ++obj-y += rtl8261n/ + obj-$(CONFIG_RENESAS_PHY) += uPD60620.o + obj-$(CONFIG_ROCKCHIP_PHY) += rockchip.o + obj-$(CONFIG_SMSC_PHY) += smsc.o +-- +2.51.0 + + +From a0ea1cb120f6dabaf6dcd5dc79f5b5225718c901 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Mon, 27 Mar 2023 18:41:54 +0100 +Subject: [PATCH 368/517] generic: pcs-mtk-lynxi: add hack to use 2500Base-X + without AN + +Using 2500Base-T SFP modules e.g. on the BananaPi R3 requires manually +disabling auto-negotiation, e.g. using ethtool. While a proper fix +using SFP quirks is being discussed upstream, bring a work-around to +restore user experience to what it was before the switch to the +dedicated SGMII PCS driver. + +Signed-off-by: Daniel Golle +--- + drivers/net/pcs/pcs-mtk-lynxi.c | 24 ++++++++++++++++-------- + 1 file changed, 16 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/pcs/pcs-mtk-lynxi.c b/drivers/net/pcs/pcs-mtk-lynxi.c +index 9f32540bba9c..893cac2cec05 100644 +--- a/drivers/net/pcs/pcs-mtk-lynxi.c ++++ b/drivers/net/pcs/pcs-mtk-lynxi.c +@@ -129,14 +129,23 @@ static void mtk_pcs_lynxi_get_state(struct phylink_pcs *pcs, + struct phylink_link_state *state) + { + struct mtk_pcs_lynxi *mpcs = pcs_to_mtk_pcs_lynxi(pcs); +- unsigned int bm, adv; ++ unsigned int bm, bmsr, adv; + + /* Read the BMSR and LPA */ + regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &bm); +- regmap_read(mpcs->regmap, SGMSYS_PCS_ADVERTISE, &adv); ++ bmsr = FIELD_GET(SGMII_BMSR, bm); ++ ++ if (state->interface == PHY_INTERFACE_MODE_2500BASEX) { ++ state->link = !!(bmsr & BMSR_LSTATUS); ++ state->an_complete = !!(bmsr & BMSR_ANEGCOMPLETE); ++ state->speed = SPEED_2500; ++ state->duplex = DUPLEX_FULL; + +- phylink_mii_c22_pcs_decode_state(state, FIELD_GET(SGMII_BMSR, bm), +- FIELD_GET(SGMII_LPA, adv)); ++ return; ++ } ++ ++ regmap_read(mpcs->regmap, SGMSYS_PCS_ADVERTISE, &adv); ++ phylink_mii_c22_pcs_decode_state(state, bmsr, FIELD_GET(SGMII_LPA, adv)); + } + + static void mtk_sgmii_reset(struct mtk_pcs_lynxi *mpcs) +@@ -157,7 +166,7 @@ static int mtk_pcs_lynxi_config(struct phylink_pcs *pcs, unsigned int neg_mode, + { + struct mtk_pcs_lynxi *mpcs = pcs_to_mtk_pcs_lynxi(pcs); + bool mode_changed = false, changed; +- unsigned int rgc3, sgm_mode, bmcr; ++ unsigned int rgc3, sgm_mode, bmcr = 0; + int advertise, link_timer; + + advertise = phylink_mii_c22_pcs_encode_advertisement(interface, +@@ -180,9 +189,8 @@ static int mtk_pcs_lynxi_config(struct phylink_pcs *pcs, unsigned int neg_mode, + if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED) { + if (interface == PHY_INTERFACE_MODE_SGMII) + sgm_mode |= SGMII_SPEED_DUPLEX_AN; +- bmcr = BMCR_ANENABLE; +- } else { +- bmcr = 0; ++ if (interface != PHY_INTERFACE_MODE_2500BASEX) ++ bmcr = BMCR_ANENABLE; + } + + if (mpcs->interface != interface) { +-- +2.51.0 + + +From 969256813f6ef11793261d85649fa8fdd5cc1ff5 Mon Sep 17 00:00:00 2001 +From: David Bauer +Date: Sun, 26 Jul 2020 02:38:31 +0200 +Subject: [PATCH 369/517] net: usb: r8152: add LED configuration from OF + +This adds the ability to configure the LED configuration register using +OF. This way, the correct value for board specific LED configuration can +be determined. + +Signed-off-by: David Bauer +--- + drivers/net/usb/r8152.c | 23 +++++++++++++++++++++++ + 1 file changed, 23 insertions(+) + +diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c +index 3fcd2b736c5e..22ab3a08a6bc 100644 +--- a/drivers/net/usb/r8152.c ++++ b/drivers/net/usb/r8152.c +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -7047,6 +7048,22 @@ static void rtl_tally_reset(struct r8152 *tp) + ocp_write_word(tp, MCU_TYPE_PLA, PLA_RSTTALLY, ocp_data); + } + ++static int r8152_led_configuration(struct r8152 *tp) ++{ ++ u32 led_data; ++ int ret; ++ ++ ret = of_property_read_u32(tp->udev->dev.of_node, "realtek,led-data", ++ &led_data); ++ ++ if (ret) ++ return ret; ++ ++ ocp_write_word(tp, MCU_TYPE_PLA, PLA_LEDSEL, led_data); ++ ++ return 0; ++} ++ + static void r8152b_init(struct r8152 *tp) + { + u32 ocp_data; +@@ -7088,6 +7105,8 @@ static void r8152b_init(struct r8152 *tp) + ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL); + ocp_data &= ~(RX_AGG_DISABLE | RX_ZERO_EN); + ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data); ++ ++ r8152_led_configuration(tp); + } + + static void r8153_init(struct r8152 *tp) +@@ -7228,6 +7247,8 @@ static void r8153_init(struct r8152 *tp) + tp->coalesce = COALESCE_SLOW; + break; + } ++ ++ r8152_led_configuration(tp); + } + + static void r8153b_init(struct r8152 *tp) +@@ -7310,6 +7331,8 @@ static void r8153b_init(struct r8152 *tp) + rtl_tally_reset(tp); + + tp->coalesce = 15000; /* 15 us */ ++ ++ r8152_led_configuration(tp); + } + + static void r8153c_init(struct r8152 *tp) +-- +2.51.0 + + +From 8ed5aab6aef4043c297da7f4827030482eb477af Mon Sep 17 00:00:00 2001 +From: David Bauer +Date: Sun, 26 Jul 2020 15:30:33 +0200 +Subject: [PATCH 370/517] dt-bindings: net: add RTL8152 binding documentation + +Add binding documentation for the Realtek RTL8152 / RTL8153 USB ethernet +adapters. + +Signed-off-by: David Bauer +--- + .../bindings/net/realtek,rtl8152.yaml | 36 +++++++++++++++++++ + 1 file changed, 36 insertions(+) + create mode 100644 Documentation/devicetree/bindings/net/realtek,rtl8152.yaml + +diff --git a/Documentation/devicetree/bindings/net/realtek,rtl8152.yaml b/Documentation/devicetree/bindings/net/realtek,rtl8152.yaml +new file mode 100644 +index 000000000000..7501b074a499 +--- /dev/null ++++ b/Documentation/devicetree/bindings/net/realtek,rtl8152.yaml +@@ -0,0 +1,36 @@ ++# SPDX-License-Identifier: GPL-2.0 ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/net/realtek,rtl8152.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Realtek RTL8152/RTL8153 series USB ethernet ++ ++maintainers: ++ - David Bauer ++ ++properties: ++ compatible: ++ oneOf: ++ - items: ++ - enum: ++ - realtek,rtl8152 ++ - realtek,rtl8153 ++ ++ reg: ++ description: The device number on the USB bus ++ ++ realtek,led-data: ++ description: Value to be written to the LED configuration register. ++ ++required: ++ - compatible ++ - reg ++ ++examples: ++ - | ++ usb-eth@2 { ++ compatible = "realtek,rtl8153"; ++ reg = <2>; ++ realtek,led-data = <0x87>; ++ }; +\ No newline at end of file +-- +2.51.0 + + +From 3f30f686292664e0719b8a8f4d1f1dfb582fd655 Mon Sep 17 00:00:00 2001 +From: David Bauer +Date: Fri, 28 Apr 2023 01:53:01 +0200 +Subject: [PATCH 371/517] net: phy: mediatek-ge: add LED configuration + interface + +This adds a small hack similar to the one used for ar8xxx switches to +read a reg:value map for configuring the LED configuration registers. + +This allows OpenWrt to write device-specific LED action as well as blink +configurations. It is unlikely to be accepted upstream, as upstream +plans on integrating their own framework for handling these LEDs. + +Signed-off-by: David Bauer +--- + drivers/net/phy/mediatek/mtk-ge.c | 34 +++++++++++++++++++++++++++++++ + 1 file changed, 34 insertions(+) + +diff --git a/drivers/net/phy/mediatek/mtk-ge.c b/drivers/net/phy/mediatek/mtk-ge.c +index 73d9b72f9d9e..97d845c906dd 100644 +--- a/drivers/net/phy/mediatek/mtk-ge.c ++++ b/drivers/net/phy/mediatek/mtk-ge.c +@@ -1,4 +1,5 @@ + // SPDX-License-Identifier: GPL-2.0+ ++#include + #include + #include + #include +@@ -73,6 +74,36 @@ static int mt7530_phy_config_init(struct phy_device *phydev) + return 0; + } + ++static int mt7530_led_config_of(struct phy_device *phydev) ++{ ++ struct device_node *np = phydev->mdio.dev.of_node; ++ const __be32 *paddr; ++ int len; ++ int i; ++ ++ paddr = of_get_property(np, "mediatek,led-config", &len); ++ if (!paddr) ++ return 0; ++ ++ if (len < (2 * sizeof(*paddr))) ++ return -EINVAL; ++ ++ len /= sizeof(*paddr); ++ ++ phydev_warn(phydev, "Configure LED registers (num=%d)\n", len); ++ for (i = 0; i < len - 1; i += 2) { ++ u32 reg; ++ u32 val; ++ ++ reg = be32_to_cpup(paddr + i); ++ val = be32_to_cpup(paddr + i + 1); ++ ++ phy_write_mmd(phydev, MDIO_MMD_VEND2, reg, val); ++ } ++ ++ return 0; ++} ++ + static int mt7531_phy_config_init(struct phy_device *phydev) + { + mtk_gephy_config_init(phydev); +@@ -93,6 +124,9 @@ static int mt7531_phy_config_init(struct phy_device *phydev) + FIELD_PREP(MTK_TX_DELAY_PAIR_B_MASK, 0x4) | + FIELD_PREP(MTK_TX_DELAY_PAIR_D_MASK, 0x4)); + ++ /* LED Config*/ ++ mt7530_led_config_of(phydev); ++ + return 0; + } + +-- +2.51.0 + + +From e454aa294e15a7756316afb673b263b115ce67bc Mon Sep 17 00:00:00 2001 +From: Hauke Mehrtens +Date: Fri, 7 Jul 2017 17:26:01 +0200 +Subject: [PATCH 372/517] bcm53xx: bgmac: use srab switch driver + +use the srab switch driver on these SoCs. + +Signed-off-by: Hauke Mehrtens +--- + drivers/net/ethernet/broadcom/bgmac-bcma.c | 1 + + drivers/net/ethernet/broadcom/bgmac.c | 24 ++++++++++++++++++++++ + drivers/net/ethernet/broadcom/bgmac.h | 4 ++++ + 3 files changed, 29 insertions(+) + +diff --git a/drivers/net/ethernet/broadcom/bgmac-bcma.c b/drivers/net/ethernet/broadcom/bgmac-bcma.c +index 36f9bad28e6a..81db24b76591 100644 +--- a/drivers/net/ethernet/broadcom/bgmac-bcma.c ++++ b/drivers/net/ethernet/broadcom/bgmac-bcma.c +@@ -280,6 +280,7 @@ static int bgmac_probe(struct bcma_device *core) + bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST; + bgmac->feature_flags |= BGMAC_FEAT_NO_RESET; + bgmac->feature_flags |= BGMAC_FEAT_FORCE_SPEED_2500; ++ bgmac->feature_flags |= BGMAC_FEAT_SRAB; + break; + default: + bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST; +diff --git a/drivers/net/ethernet/broadcom/bgmac.c b/drivers/net/ethernet/broadcom/bgmac.c +index 6ffdc4229407..dd0138ee7337 100644 +--- a/drivers/net/ethernet/broadcom/bgmac.c ++++ b/drivers/net/ethernet/broadcom/bgmac.c +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -1408,6 +1409,17 @@ static const struct ethtool_ops bgmac_ethtool_ops = { + .set_link_ksettings = phy_ethtool_set_link_ksettings, + }; + ++static struct b53_platform_data bgmac_b53_pdata = { ++}; ++ ++static struct platform_device bgmac_b53_dev = { ++ .name = "b53-srab-switch", ++ .id = -1, ++ .dev = { ++ .platform_data = &bgmac_b53_pdata, ++ }, ++}; ++ + /************************************************** + * MII + **************************************************/ +@@ -1546,6 +1558,14 @@ int bgmac_enet_probe(struct bgmac *bgmac) + + bgmac->in_init = false; + ++ if ((bgmac->feature_flags & BGMAC_FEAT_SRAB) && !bgmac_b53_pdata.regs) { ++ bgmac_b53_pdata.regs = ioremap(0x18007000, 0x1000); ++ ++ err = platform_device_register(&bgmac_b53_dev); ++ if (!err) ++ bgmac->b53_device = &bgmac_b53_dev; ++ } ++ + err = register_netdev(bgmac->net_dev); + if (err) { + dev_err(bgmac->dev, "Cannot register net device\n"); +@@ -1568,6 +1588,10 @@ EXPORT_SYMBOL_GPL(bgmac_enet_probe); + + void bgmac_enet_remove(struct bgmac *bgmac) + { ++ if (bgmac->b53_device) ++ platform_device_unregister(&bgmac_b53_dev); ++ bgmac->b53_device = NULL; ++ + unregister_netdev(bgmac->net_dev); + phy_disconnect(bgmac->net_dev->phydev); + netif_napi_del(&bgmac->napi); +diff --git a/drivers/net/ethernet/broadcom/bgmac.h b/drivers/net/ethernet/broadcom/bgmac.h +index 6fee9a41839c..c75a00af5bf6 100644 +--- a/drivers/net/ethernet/broadcom/bgmac.h ++++ b/drivers/net/ethernet/broadcom/bgmac.h +@@ -387,6 +387,7 @@ + #define BGMAC_FEAT_CC4_IF_SW_TYPE_RGMII BIT(18) + #define BGMAC_FEAT_CC7_IF_TYPE_RGMII BIT(19) + #define BGMAC_FEAT_IDM_MASK BIT(20) ++#define BGMAC_FEAT_SRAB BIT(21) + + struct bgmac_slot_info { + union { +@@ -494,6 +495,9 @@ struct bgmac { + void (*cmn_maskset32)(struct bgmac *bgmac, u16 offset, u32 mask, + u32 set); + int (*phy_connect)(struct bgmac *bgmac); ++ ++ /* platform device for associated switch */ ++ struct platform_device *b53_device; + }; + + struct bgmac *bgmac_alloc(struct device *dev); +-- +2.51.0 + + +From 890a69a2cfb04b333d3fe41cf0998ec70c5c0734 Mon Sep 17 00:00:00 2001 +From: OpenWrt community +Date: Wed, 13 Jul 2022 13:49:26 +0200 +Subject: [PATCH 373/517] net/usb/qmi_wwan: add MeigLink modem support + +--- + drivers/net/usb/qmi_wwan.c | 6 ++++++ + drivers/usb/serial/option.c | 15 +++++++++++++++ + 2 files changed, 21 insertions(+) + +diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c +index f04da733240c..50b2e996488e 100644 +--- a/drivers/net/usb/qmi_wwan.c ++++ b/drivers/net/usb/qmi_wwan.c +@@ -1076,6 +1076,11 @@ static const struct usb_device_id products[] = { + USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0x581d, USB_CLASS_VENDOR_SPEC, 1, 7), + .driver_info = (unsigned long)&qmi_wwan_info, + }, ++ { /* Meiglink SGM828 */ ++ USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d49, USB_CLASS_VENDOR_SPEC, 0x10, 0x05), ++ .driver_info = (unsigned long)&qmi_wwan_info, ++ }, ++ + {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0122)}, /* Quectel RG650V */ + {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0125)}, /* Quectel EC25, EC20 R2.0 Mini PCIe */ + {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0306)}, /* Quectel EP06/EG06/EM06 */ +@@ -1083,6 +1088,7 @@ static const struct usb_device_id products[] = { + {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0620)}, /* Quectel EM160R-GL */ + {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0800)}, /* Quectel RM500Q-GL */ + {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0801)}, /* Quectel RM520N */ ++ {QMI_MATCH_FF_FF_FF(0x05c6, 0xf601)}, /* MeigLink SLM750 */ + + /* 3. Combined interface devices matching on interface number */ + {QMI_FIXED_INTF(0x0408, 0xea42, 4)}, /* Yota / Megafon M100-1 */ +diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c +index 62e984d20e59..2ce56d02aed7 100644 +--- a/drivers/usb/serial/option.c ++++ b/drivers/usb/serial/option.c +@@ -247,6 +247,11 @@ static void option_instat_callback(struct urb *urb); + #define UBLOX_PRODUCT_R410M 0x90b2 + /* These Yuga products use Qualcomm's vendor ID */ + #define YUGA_PRODUCT_CLM920_NC5 0x9625 ++/* These MeigLink products use Qualcomm's vendor ID */ ++#define MEIGLINK_PRODUCT_SLM750 0xf601 ++ ++#define MEIGLINK_VENDOR_ID 0x2dee ++#define MEIGLINK_PRODUCT_SLM828 0x4d49 + + #define QUECTEL_VENDOR_ID 0x2c7c + /* These Quectel products use Quectel's vendor ID */ +@@ -1154,6 +1159,11 @@ static const struct usb_device_id option_ids[] = { + { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x0023)}, /* ONYX 3G device */ + { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x9000), /* SIMCom SIM5218 */ + .driver_info = NCTRL(0) | NCTRL(1) | NCTRL(2) | NCTRL(3) | RSVD(4) }, ++ /* MeiG */ ++ { USB_DEVICE_AND_INTERFACE_INFO(MEIGLINK_VENDOR_ID, MEIGLINK_PRODUCT_SLM828, USB_CLASS_VENDOR_SPEC, 0x10, 0x01) }, ++ { USB_DEVICE_AND_INTERFACE_INFO(MEIGLINK_VENDOR_ID, MEIGLINK_PRODUCT_SLM828, USB_CLASS_VENDOR_SPEC, 0x10, 0x02) }, ++ { USB_DEVICE_AND_INTERFACE_INFO(MEIGLINK_VENDOR_ID, MEIGLINK_PRODUCT_SLM828, USB_CLASS_VENDOR_SPEC, 0x10, 0x03) }, ++ { USB_DEVICE_AND_INTERFACE_INFO(MEIGLINK_VENDOR_ID, MEIGLINK_PRODUCT_SLM828, USB_CLASS_VENDOR_SPEC, 0x10, 0x04) }, + /* Quectel products using Qualcomm vendor ID */ + { USB_DEVICE(QUALCOMM_VENDOR_ID, QUECTEL_PRODUCT_UC15)}, + { USB_DEVICE(QUALCOMM_VENDOR_ID, QUECTEL_PRODUCT_UC20), +@@ -1195,6 +1205,11 @@ static const struct usb_device_id option_ids[] = { + .driver_info = ZLP }, + { USB_DEVICE(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_BG96), + .driver_info = RSVD(4) }, ++ /* Meiglink products using Qualcomm vendor ID */ ++ // Works OK. In case of some issues check macros that are used by Quectel Products ++ { USB_DEVICE_AND_INTERFACE_INFO(QUALCOMM_VENDOR_ID, MEIGLINK_PRODUCT_SLM750, 0xff, 0xff, 0xff), ++ .driver_info = NUMEP2 }, ++ { USB_DEVICE_AND_INTERFACE_INFO(QUALCOMM_VENDOR_ID, MEIGLINK_PRODUCT_SLM750, 0xff, 0, 0) }, + { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EP06, 0xff, 0xff, 0xff), + .driver_info = RSVD(1) | RSVD(2) | RSVD(3) | RSVD(4) | NUMEP2 }, + { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EP06, 0xff, 0, 0) }, +-- +2.51.0 + + +From 16caa64f04b96be21c4d0929fae283bfc073b022 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Tue, 9 Apr 2024 17:06:38 +0100 +Subject: [PATCH 374/517] rndis_host: add a bunch of USB IDs + +Add a bunch of USB IDs found in various places online to the +RNDIS USB network driver. + +Signed-off-by: Daniel Golle +--- + drivers/net/usb/rndis_host.c | 40 ++++++++++++++++++++++++++++++++++++ + 1 file changed, 40 insertions(+) + +diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c +index 7b3739b29c8f..81ca6a4e9c06 100644 +--- a/drivers/net/usb/rndis_host.c ++++ b/drivers/net/usb/rndis_host.c +@@ -630,6 +630,16 @@ static const struct driver_info zte_rndis_info = { + .tx_fixup = rndis_tx_fixup, + }; + ++static const struct driver_info asr_rndis_info = { ++ .description = "Asr RNDIS device", ++ .flags = FLAG_WWAN | FLAG_POINTTOPOINT | FLAG_FRAMING_RN | FLAG_NO_SETINT | FLAG_NOARP, ++ .bind = rndis_bind, ++ .unbind = rndis_unbind, ++ .status = rndis_status, ++ .rx_fixup = rndis_rx_fixup, ++ .tx_fixup = rndis_tx_fixup, ++}; ++ + /*-------------------------------------------------------------------------*/ + + static const struct usb_device_id products [] = { +@@ -665,6 +675,36 @@ static const struct usb_device_id products [] = { + /* RNDIS for tethering */ + USB_INTERFACE_INFO(USB_CLASS_WIRELESS_CONTROLLER, 1, 3), + .driver_info = (unsigned long) &rndis_info, ++}, { ++ /* Quectel EG060V rndis device */ ++ USB_DEVICE_AND_INTERFACE_INFO(0x2c7c, 0x6004, ++ USB_CLASS_WIRELESS_CONTROLLER, 1, 3), ++ .driver_info = (unsigned long) &asr_rndis_info, ++}, { ++ /* Quectel EC200A rndis device */ ++ USB_DEVICE_AND_INTERFACE_INFO(0x2c7c, 0x6005, ++ USB_CLASS_WIRELESS_CONTROLLER, 1, 3), ++ .driver_info = (unsigned long) &asr_rndis_info, ++}, { ++ /* Quectel EC200T rndis device */ ++ USB_DEVICE_AND_INTERFACE_INFO(0x2c7c, 0x6026, ++ USB_CLASS_WIRELESS_CONTROLLER, 1, 3), ++ .driver_info = (unsigned long) &asr_rndis_info, ++}, { ++ /* Simcom A7906E rndis device */ ++ USB_DEVICE_AND_INTERFACE_INFO(0x1e0e, 0x9011, ++ USB_CLASS_WIRELESS_CONTROLLER, 1, 3), ++ .driver_info = (unsigned long) &asr_rndis_info, ++}, { ++ /* Meig SLM770A */ ++ USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d57, ++ USB_CLASS_WIRELESS_CONTROLLER, 1, 3), ++ .driver_info = (unsigned long) &asr_rndis_info, ++}, { ++ /* Meig SLM828 */ ++ USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d49, ++ USB_CLASS_WIRELESS_CONTROLLER, 1, 3), ++ .driver_info = (unsigned long) &asr_rndis_info, + }, { + /* Novatel Verizon USB730L */ + USB_INTERFACE_INFO(USB_CLASS_MISC, 4, 1), +-- +2.51.0 + + +From 35f347fc3508f2e506fd3d14677024e28f587056 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Tue, 12 Aug 2014 20:49:27 +0200 +Subject: [PATCH 375/517] GPIO: add named gpio exports + +Signed-off-by: John Crispin +--- + drivers/gpio/gpiolib-of.c | 72 +++++++++++++++++++++++++++++++++++ + drivers/gpio/gpiolib-sysfs.c | 17 ++++++++- + include/linux/gpio/consumer.h | 17 +++++++++ + 3 files changed, 105 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c +index 36f8c7bb79d8..1d700c06f850 100644 +--- a/drivers/gpio/gpiolib-of.c ++++ b/drivers/gpio/gpiolib-of.c +@@ -21,6 +21,8 @@ + + #include + #include ++#include ++#include + + #include "gpiolib.h" + #include "gpiolib-of.h" +@@ -1198,3 +1200,73 @@ void of_gpiochip_remove(struct gpio_chip *chip) + { + of_node_put(dev_of_node(&chip->gpiodev->dev)); + } ++ ++#ifdef CONFIG_GPIO_SYSFS ++ ++static const struct of_device_id gpio_export_ids[] = { ++ { .compatible = "gpio-export" }, ++ { /* sentinel */ } ++}; ++ ++static int of_gpio_export_probe(struct platform_device *pdev) ++{ ++ struct device_node *np = pdev->dev.of_node; ++ struct device_node *cnp; ++ u32 val; ++ int nb = 0; ++ ++ for_each_child_of_node(np, cnp) { ++ const char *name = NULL; ++ int gpio; ++ bool dmc; ++ int max_gpio = 1; ++ int i; ++ ++ of_property_read_string(cnp, "gpio-export,name", &name); ++ ++ if (!name) ++ max_gpio = of_gpio_named_count(cnp, "gpios"); ++ ++ for (i = 0; i < max_gpio; i++) { ++ struct gpio_desc *desc; ++ unsigned flags = 0; ++ enum of_gpio_flags of_flags; ++ ++ desc = of_get_named_gpiod_flags(cnp, "gpios", i, &of_flags); ++ if (IS_ERR(desc)) ++ return PTR_ERR(desc); ++ gpio = desc_to_gpio(desc); ++ ++ if (of_flags & OF_GPIO_ACTIVE_LOW) ++ flags |= GPIOF_ACTIVE_LOW; ++ ++ if (!of_property_read_u32(cnp, "gpio-export,output", &val)) ++ flags |= val ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; ++ else ++ flags |= GPIOF_IN; ++ ++ if (devm_gpio_request_one(&pdev->dev, gpio, flags, name ? name : of_node_full_name(np))) ++ continue; ++ ++ dmc = of_property_read_bool(cnp, "gpio-export,direction_may_change"); ++ gpio_export_with_name(gpio_to_desc(gpio), dmc, name); ++ nb++; ++ } ++ } ++ ++ dev_info(&pdev->dev, "%d gpio(s) exported\n", nb); ++ ++ return 0; ++} ++ ++static struct platform_driver gpio_export_driver = { ++ .driver = { ++ .name = "gpio-export", ++ .of_match_table = of_match_ptr(gpio_export_ids), ++ }, ++ .probe = of_gpio_export_probe, ++}; ++ ++module_platform_driver(gpio_export_driver); ++ ++#endif +diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c +index 17ed229412af..aa98c5b08e9f 100644 +--- a/drivers/gpio/gpiolib-sysfs.c ++++ b/drivers/gpio/gpiolib-sysfs.c +@@ -571,7 +571,7 @@ static struct class gpio_class = { + * Returns: + * 0 on success, or negative errno on failure. + */ +-int gpiod_export(struct gpio_desc *desc, bool direction_may_change) ++int __gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name) + { + const char *ioname = NULL; + struct gpio_device *gdev; +@@ -629,6 +629,8 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change) + offset = gpio_chip_hwgpio(desc); + if (guard.gc->names && guard.gc->names[offset]) + ioname = guard.gc->names[offset]; ++ if (name) ++ ioname = name; + + dev = device_create_with_groups(&gpio_class, &gdev->dev, + MKDEV(0, 0), data, gpio_groups, +@@ -650,8 +652,21 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change) + gpiod_dbg(desc, "%s: status %d\n", __func__, status); + return status; + } ++EXPORT_SYMBOL_GPL(__gpiod_export); ++ ++int gpiod_export(struct gpio_desc *desc, bool direction_may_change) ++{ ++ return __gpiod_export(desc, direction_may_change, NULL); ++} + EXPORT_SYMBOL_GPL(gpiod_export); + ++int gpio_export_with_name(struct gpio_desc *desc, bool direction_may_change, ++ const char *name) ++{ ++ return __gpiod_export(desc, direction_may_change, name); ++} ++EXPORT_SYMBOL_GPL(gpio_export_with_name); ++ + static int match_export(struct device *dev, const void *desc) + { + struct gpiod_data *data = dev_get_drvdata(dev); +diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h +index db2dfbae8edb..22066cc19831 100644 +--- a/include/linux/gpio/consumer.h ++++ b/include/linux/gpio/consumer.h +@@ -628,7 +628,10 @@ static inline int devm_acpi_dev_add_driver_gpios(struct device *dev, + + #if IS_ENABLED(CONFIG_GPIOLIB) && IS_ENABLED(CONFIG_GPIO_SYSFS) + ++int __gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name); + int gpiod_export(struct gpio_desc *desc, bool direction_may_change); ++int gpio_export_with_name(struct gpio_desc *desc, bool direction_may_change, ++ const char *name); + int gpiod_export_link(struct device *dev, const char *name, + struct gpio_desc *desc); + void gpiod_unexport(struct gpio_desc *desc); +@@ -637,12 +640,26 @@ void gpiod_unexport(struct gpio_desc *desc); + + #include + ++static inline int __gpiod_export(struct gpio_desc *desc, ++ bool direction_may_change, ++ const char *name) ++{ ++ return -ENOSYS; ++} ++ + static inline int gpiod_export(struct gpio_desc *desc, + bool direction_may_change) + { + return -ENOSYS; + } + ++static inline int gpio_export_with_name(struct gpio_desc *desc, ++ bool direction_may_change, ++ const char *name) ++{ ++ return -ENOSYS; ++} ++ + static inline int gpiod_export_link(struct device *dev, const char *name, + struct gpio_desc *desc) + { +-- +2.51.0 + + +From 07ee1fba26616921d99f3aa7fcf8afb7f542c7ef Mon Sep 17 00:00:00 2001 +From: OpenWrt community +Date: Fri, 12 May 2023 11:08:43 +0200 +Subject: [PATCH 376/517] ssb_sprom: add generic kernel support for Broadcom + Fallback SPROMs + +--- + drivers/bcma/Kconfig | 4 ++++ + drivers/bcma/Makefile | 1 + + drivers/bcma/bcma_private.h | 1 + + drivers/bcma/main.c | 8 ++++++++ + drivers/bcma/sprom.c | 23 ++++++++++++++--------- + drivers/ssb/Kconfig | 5 +++++ + drivers/ssb/Makefile | 1 + + drivers/ssb/main.c | 8 ++++++++ + drivers/ssb/sprom.c | 12 +++++++++++- + drivers/ssb/ssb_private.h | 2 +- + 10 files changed, 54 insertions(+), 11 deletions(-) + +diff --git a/drivers/bcma/Kconfig b/drivers/bcma/Kconfig +index 2e9732e5c565..eb02cf92a983 100644 +--- a/drivers/bcma/Kconfig ++++ b/drivers/bcma/Kconfig +@@ -18,6 +18,10 @@ config BCMA_BLOCKIO + bool + default y + ++config BCMA_FALLBACK_SPROM ++ bool ++ default y ++ + config BCMA_HOST_PCI_POSSIBLE + bool + depends on PCI = y +diff --git a/drivers/bcma/Makefile b/drivers/bcma/Makefile +index f8c37de35da2..defc2de5c38a 100644 +--- a/drivers/bcma/Makefile ++++ b/drivers/bcma/Makefile +@@ -11,6 +11,7 @@ bcma-$(CONFIG_BCMA_DRIVER_PCI_HOSTMODE) += driver_pci_host.o + bcma-$(CONFIG_BCMA_DRIVER_MIPS) += driver_mips.o + bcma-$(CONFIG_BCMA_DRIVER_GMAC_CMN) += driver_gmac_cmn.o + bcma-$(CONFIG_BCMA_DRIVER_GPIO) += driver_gpio.o ++bcma-$(CONFIG_BCMA_FALLBACK_SPROM) += fallback-sprom.o + bcma-$(CONFIG_BCMA_HOST_PCI) += host_pci.o + bcma-$(CONFIG_BCMA_HOST_SOC) += host_soc.o + obj-$(CONFIG_BCMA) += bcma.o +diff --git a/drivers/bcma/bcma_private.h b/drivers/bcma/bcma_private.h +index 6eded32d1aac..16c1ad8d0d76 100644 +--- a/drivers/bcma/bcma_private.h ++++ b/drivers/bcma/bcma_private.h +@@ -8,6 +8,7 @@ + + #include + #include ++#include "fallback-sprom.h" + + #define bcma_err(bus, fmt, ...) \ + dev_err((bus)->dev, "bus%d: " fmt, (bus)->num, ##__VA_ARGS__) +diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c +index 6842fe781eef..a7dcb8afc580 100644 +--- a/drivers/bcma/main.c ++++ b/drivers/bcma/main.c +@@ -671,6 +671,14 @@ static int __init bcma_modinit(void) + { + int err; + ++#ifdef CONFIG_BCMA_FALLBACK_SPROM ++ err = bcma_fbs_register(); ++ if (err) { ++ pr_err("Fallback SPROM initialization failed\n"); ++ err = 0; ++ } ++#endif /* CONFIG_BCMA_FALLBACK_SPROM */ ++ + err = bcma_init_bus_register(); + if (err) + return err; +diff --git a/drivers/bcma/sprom.c b/drivers/bcma/sprom.c +index e668ad7963fc..6024d6b61a01 100644 +--- a/drivers/bcma/sprom.c ++++ b/drivers/bcma/sprom.c +@@ -51,21 +51,26 @@ static int bcma_fill_sprom_with_fallback(struct bcma_bus *bus, + { + int err; + +- if (!get_fallback_sprom) { ++ if (get_fallback_sprom) ++ err = get_fallback_sprom(bus, out); ++ ++#ifdef CONFIG_BCMA_FALLBACK_SPROM ++ if (!get_fallback_sprom || err) ++ err = bcma_get_fallback_sprom(bus, out); ++#else ++ if (!get_fallback_sprom) + err = -ENOENT; +- goto fail; +- } ++#endif /* CONFIG_BCMA_FALLBACK_SPROM */ + +- err = get_fallback_sprom(bus, out); +- if (err) +- goto fail; ++ if (err) { ++ bcma_warn(bus, "Using fallback SPROM failed (err %d)\n", err); ++ return err; ++ } + + bcma_debug(bus, "Using SPROM revision %d provided by platform.\n", + bus->sprom.revision); ++ + return 0; +-fail: +- bcma_warn(bus, "Using fallback SPROM failed (err %d)\n", err); +- return err; + } + + /************************************************** +diff --git a/drivers/ssb/Kconfig b/drivers/ssb/Kconfig +index 2bcf62e64f6f..a878deeb0c32 100644 +--- a/drivers/ssb/Kconfig ++++ b/drivers/ssb/Kconfig +@@ -25,6 +25,11 @@ if SSB + config SSB_SPROM + bool + ++config SSB_FALLBACK_SPROM ++ bool ++ depends on SSB_PCIHOST ++ default y ++ + # Support for Block-I/O. SELECT this from the driver that needs it. + config SSB_BLOCKIO + bool +diff --git a/drivers/ssb/Makefile b/drivers/ssb/Makefile +index 142d33df040f..3edced378e31 100644 +--- a/drivers/ssb/Makefile ++++ b/drivers/ssb/Makefile +@@ -2,6 +2,7 @@ + # core + ssb-y += main.o scan.o + ssb-$(CONFIG_SSB_EMBEDDED) += embedded.o ++ssb-$(CONFIG_SSB_FALLBACK_SPROM) += fallback-sprom.o + ssb-$(CONFIG_SSB_SPROM) += sprom.o + + # host support +diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c +index aa6165e3db4a..a62bfefd27a4 100644 +--- a/drivers/ssb/main.c ++++ b/drivers/ssb/main.c +@@ -1289,6 +1289,14 @@ static int __init ssb_modinit(void) + { + int err; + ++#ifdef CONFIG_SSB_FALLBACK_SPROM ++ err = ssb_fbs_register(); ++ if (err) { ++ pr_err("Fallback SPROM initialization failed\n"); ++ err = 0; ++ } ++#endif /* CONFIG_SSB_FALLBACK_SPROM */ ++ + /* See the comment at the ssb_is_early_boot definition */ + ssb_is_early_boot = 0; + err = bus_register(&ssb_bustype); +diff --git a/drivers/ssb/sprom.c b/drivers/ssb/sprom.c +index 7cd553127861..1efc37466059 100644 +--- a/drivers/ssb/sprom.c ++++ b/drivers/ssb/sprom.c +@@ -180,10 +180,20 @@ int ssb_arch_register_fallback_sprom(int (*sprom_callback)(struct ssb_bus *bus, + + int ssb_fill_sprom_with_fallback(struct ssb_bus *bus, struct ssb_sprom *out) + { ++ int err; ++ ++ if (get_fallback_sprom) ++ err = get_fallback_sprom(bus, out); ++ ++#ifdef CONFIG_SSB_FALLBACK_SPROM ++ if (!get_fallback_sprom || err) ++ err = ssb_get_fallback_sprom(bus, out); ++#else + if (!get_fallback_sprom) + return -ENOENT; ++#endif /* CONFIG_SSB_FALLBACK_SPROM */ + +- return get_fallback_sprom(bus, out); ++ return err; + } + + /* https://bcm-v4.sipsolutions.net/802.11/IsSpromAvailable */ +diff --git a/drivers/ssb/ssb_private.h b/drivers/ssb/ssb_private.h +index 5f31bdfbe77f..7bdc9f80cd86 100644 +--- a/drivers/ssb/ssb_private.h ++++ b/drivers/ssb/ssb_private.h +@@ -8,7 +8,7 @@ + #include + #include + #include +- ++#include "fallback-sprom.h" + + /* pci.c */ + #ifdef CONFIG_SSB_PCIHOST +-- +2.51.0 + + +From 2ff5fac19d3f48f1890e0f07baa53f0f0ceddec0 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Sat, 8 Jul 2017 08:16:31 +0200 +Subject: [PATCH 377/517] debloat: add some debloat patches, strip down procfs + and make O_DIRECT support optional, saves ~15K after lzma on MIPS + +Signed-off-by: Felix Fietkau +--- + net/Kconfig | 3 +++ + net/core/Makefile | 3 ++- + net/core/sock.c | 19 +++++++++++++++++++ + net/core/sock_diag.c | 18 ------------------ + net/ipv4/Kconfig | 1 + + net/netlink/Kconfig | 1 + + net/packet/Kconfig | 1 + + net/unix/Kconfig | 1 + + net/xdp/Kconfig | 1 + + 9 files changed, 29 insertions(+), 19 deletions(-) + +diff --git a/net/Kconfig b/net/Kconfig +index c98df432683b..b1afb23fe2fb 100644 +--- a/net/Kconfig ++++ b/net/Kconfig +@@ -138,6 +138,9 @@ source "net/mptcp/Kconfig" + + endif # if INET + ++config SOCK_DIAG ++ bool ++ + config NETWORK_SECMARK + bool "Security Marking" + help +diff --git a/net/core/Makefile b/net/core/Makefile +index c3ebbaf9c81e..bd733d8aa76d 100644 +--- a/net/core/Makefile ++++ b/net/core/Makefile +@@ -11,12 +11,13 @@ obj-$(CONFIG_SYSCTL) += sysctl_net_core.o + + obj-y += dev.o dev_addr_lists.o dst.o netevent.o \ + neighbour.o rtnetlink.o utils.o link_watch.o filter.o \ +- sock_diag.o dev_ioctl.o tso.o sock_reuseport.o \ ++ dev_ioctl.o tso.o sock_reuseport.o \ + fib_notifier.o xdp.o flow_offload.o gro.o \ + netdev-genl.o netdev-genl-gen.o gso.o + + obj-$(CONFIG_NETDEV_ADDR_LIST_TEST) += dev_addr_lists_test.o + ++obj-$(CONFIG_SOCK_DIAG) += sock_diag.o + obj-y += net-sysfs.o + obj-y += hotdata.o + obj-y += netdev_rx_queue.o +diff --git a/net/core/sock.c b/net/core/sock.c +index 57fafa7cb47b..373671aee9c1 100644 +--- a/net/core/sock.c ++++ b/net/core/sock.c +@@ -118,6 +118,7 @@ + #include + #include + #include ++#include + + #include + +@@ -152,6 +153,7 @@ + + static DEFINE_MUTEX(proto_list_mutex); + static LIST_HEAD(proto_list); ++DEFINE_COOKIE(sock_cookie); + + static void sock_def_write_space_wfree(struct sock *sk); + static void sock_def_write_space(struct sock *sk); +@@ -587,6 +589,21 @@ int __sk_receive_skb(struct sock *sk, struct sk_buff *skb, + } + EXPORT_SYMBOL(__sk_receive_skb); + ++u64 __sock_gen_cookie(struct sock *sk) ++{ ++ u64 res = atomic64_read(&sk->sk_cookie); ++ ++ if (!res) { ++ u64 new = gen_cookie_next(&sock_cookie); ++ ++ atomic64_cmpxchg(&sk->sk_cookie, res, new); ++ ++ /* Another thread might have changed sk_cookie before us. */ ++ res = atomic64_read(&sk->sk_cookie); ++ } ++ return res; ++} ++ + INDIRECT_CALLABLE_DECLARE(struct dst_entry *ip6_dst_check(struct dst_entry *, + u32)); + INDIRECT_CALLABLE_DECLARE(struct dst_entry *ipv4_dst_check(struct dst_entry *, +@@ -2342,9 +2359,11 @@ static void __sk_free(struct sock *sk) + if (likely(sk->sk_net_refcnt)) + sock_inuse_add(sock_net(sk), -1); + ++#ifdef CONFIG_SOCK_DIAG + if (unlikely(sk->sk_net_refcnt && sock_diag_has_destroy_listeners(sk))) + sock_diag_broadcast_destroy(sk); + else ++#endif + sk_destruct(sk); + } + +diff --git a/net/core/sock_diag.c b/net/core/sock_diag.c +index a08eed9b9142..a915ec59f71d 100644 +--- a/net/core/sock_diag.c ++++ b/net/core/sock_diag.c +@@ -12,7 +12,6 @@ + #include + #include + #include +-#include + #include + #include + +@@ -22,23 +21,6 @@ static const struct sock_diag_inet_compat __rcu *inet_rcv_compat; + + static struct workqueue_struct *broadcast_wq; + +-DEFINE_COOKIE(sock_cookie); +- +-u64 __sock_gen_cookie(struct sock *sk) +-{ +- u64 res = atomic64_read(&sk->sk_cookie); +- +- if (!res) { +- u64 new = gen_cookie_next(&sock_cookie); +- +- atomic64_cmpxchg(&sk->sk_cookie, res, new); +- +- /* Another thread might have changed sk_cookie before us. */ +- res = atomic64_read(&sk->sk_cookie); +- } +- return res; +-} +- + int sock_diag_check_cookie(struct sock *sk, const __u32 *cookie) + { + u64 res; +diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig +index 6d2c97f8e9ef..9ffd577d8270 100644 +--- a/net/ipv4/Kconfig ++++ b/net/ipv4/Kconfig +@@ -423,6 +423,7 @@ config INET_TUNNEL + + config INET_DIAG + tristate "INET: socket monitoring interface" ++ select SOCK_DIAG + default y + help + Support for INET (TCP, DCCP, etc) socket monitoring interface used by +diff --git a/net/netlink/Kconfig b/net/netlink/Kconfig +index 1039d4f2ce11..ef355897a316 100644 +--- a/net/netlink/Kconfig ++++ b/net/netlink/Kconfig +@@ -5,6 +5,7 @@ + + config NETLINK_DIAG + tristate "NETLINK: socket monitoring interface" ++ select SOCK_DIAG + default n + help + Support for NETLINK socket monitoring interface used by the ss tool. +diff --git a/net/packet/Kconfig b/net/packet/Kconfig +index 2997382d597c..890796137daf 100644 +--- a/net/packet/Kconfig ++++ b/net/packet/Kconfig +@@ -19,6 +19,7 @@ config PACKET + config PACKET_DIAG + tristate "Packet: sockets monitoring interface" + depends on PACKET ++ select SOCK_DIAG + default n + help + Support for PF_PACKET sockets monitoring interface used by the ss tool. +diff --git a/net/unix/Kconfig b/net/unix/Kconfig +index 8b5d04210d7c..39203827d660 100644 +--- a/net/unix/Kconfig ++++ b/net/unix/Kconfig +@@ -24,6 +24,7 @@ config AF_UNIX_OOB + config UNIX_DIAG + tristate "UNIX: socket monitoring interface" + depends on UNIX ++ select SOCK_DIAG + default n + help + Support for UNIX socket monitoring interface used by the ss tool. +diff --git a/net/xdp/Kconfig b/net/xdp/Kconfig +index 71af2febe72a..719df49761a8 100644 +--- a/net/xdp/Kconfig ++++ b/net/xdp/Kconfig +@@ -10,6 +10,7 @@ config XDP_SOCKETS + config XDP_SOCKETS_DIAG + tristate "XDP sockets: monitoring interface" + depends on XDP_SOCKETS ++ select SOCK_DIAG + default n + help + Support for PF_XDP sockets monitoring interface used by the ss tool. +-- +2.51.0 + + +From ef4552222c3a92648951ff86c41905786a7ce3a9 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Sat, 8 Jul 2017 08:20:09 +0200 +Subject: [PATCH 378/517] debloat: procfs + +Signed-off-by: Felix Fietkau +--- + fs/locks.c | 2 ++ + fs/proc/Kconfig | 5 +++++ + fs/proc/consoles.c | 3 +++ + fs/proc/proc_tty.c | 11 ++++++++++- + include/net/snmp.h | 18 +++++++++++++++++- + ipc/msg.c | 3 +++ + ipc/sem.c | 2 ++ + ipc/shm.c | 2 ++ + ipc/util.c | 3 +++ + kernel/exec_domain.c | 2 ++ + kernel/irq/proc.c | 9 +++++++++ + kernel/time/timer_list.c | 2 ++ + mm/vmalloc.c | 3 +++ + mm/vmstat.c | 8 +++++--- + net/8021q/vlanproc.c | 6 ++++++ + net/core/net-procfs.c | 18 ++++++++++++------ + net/core/sock.c | 2 ++ + net/ipv4/fib_trie.c | 18 ++++++++++++------ + net/ipv4/inet_timewait_sock.c | 2 +- + net/ipv4/proc.c | 3 +++ + net/ipv4/route.c | 3 +++ + 21 files changed, 107 insertions(+), 18 deletions(-) + +diff --git a/fs/locks.c b/fs/locks.c +index 204847628f3e..7a98847ea331 100644 +--- a/fs/locks.c ++++ b/fs/locks.c +@@ -2971,6 +2971,8 @@ static const struct seq_operations locks_seq_operations = { + + static int __init proc_locks_init(void) + { ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return 0; + proc_create_seq_private("locks", 0, NULL, &locks_seq_operations, + sizeof(struct locks_iterator), NULL); + return 0; +diff --git a/fs/proc/Kconfig b/fs/proc/Kconfig +index d80a1431ef7b..f5ab3bdea5c0 100644 +--- a/fs/proc/Kconfig ++++ b/fs/proc/Kconfig +@@ -101,6 +101,11 @@ config PROC_CHILDREN + Say Y if you are running any user-space software which takes benefit from + this interface. For example, rkt is such a piece of software. + ++config PROC_STRIPPED ++ default n ++ depends on EXPERT ++ bool "Strip non-essential /proc functionality to reduce code size" ++ + config PROC_PID_ARCH_STATUS + def_bool n + depends on PROC_FS +diff --git a/fs/proc/consoles.c b/fs/proc/consoles.c +index b7cab1ad990d..e19f627a2cee 100644 +--- a/fs/proc/consoles.c ++++ b/fs/proc/consoles.c +@@ -110,6 +110,9 @@ static const struct seq_operations consoles_op = { + + static int __init proc_consoles_init(void) + { ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return 0; ++ + proc_create_seq("consoles", 0, NULL, &consoles_op); + return 0; + } +diff --git a/fs/proc/proc_tty.c b/fs/proc/proc_tty.c +index 5c6a5ceab2f1..0e83f4daedf0 100644 +--- a/fs/proc/proc_tty.c ++++ b/fs/proc/proc_tty.c +@@ -131,7 +131,10 @@ static const struct seq_operations tty_drivers_op = { + void proc_tty_register_driver(struct tty_driver *driver) + { + struct proc_dir_entry *ent; +- ++ ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return; ++ + if (!driver->driver_name || driver->proc_entry || + !driver->ops->proc_show) + return; +@@ -148,6 +151,9 @@ void proc_tty_unregister_driver(struct tty_driver *driver) + { + struct proc_dir_entry *ent; + ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return; ++ + ent = driver->proc_entry; + if (!ent) + return; +@@ -162,6 +168,9 @@ void proc_tty_unregister_driver(struct tty_driver *driver) + */ + void __init proc_tty_init(void) + { ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return; ++ + if (!proc_mkdir("tty", NULL)) + return; + proc_mkdir("tty/ldisc", NULL); /* Preserved: it's userspace visible */ +diff --git a/include/net/snmp.h b/include/net/snmp.h +index 468a67836e2f..f3ef151aa549 100644 +--- a/include/net/snmp.h ++++ b/include/net/snmp.h +@@ -124,6 +124,21 @@ struct linux_tls_mib { + #define DECLARE_SNMP_STAT(type, name) \ + extern __typeof__(type) __percpu *name + ++#ifdef CONFIG_PROC_STRIPPED ++#define __SNMP_STATS_DUMMY(mib) \ ++ do { (void) mib->mibs[0]; } while(0) ++ ++#define __SNMP_INC_STATS(mib, field) __SNMP_STATS_DUMMY(mib) ++#define SNMP_INC_STATS_ATOMIC_LONG(mib, field) __SNMP_STATS_DUMMY(mib) ++#define SNMP_INC_STATS(mib, field) __SNMP_STATS_DUMMY(mib) ++#define SNMP_DEC_STATS(mib, field) __SNMP_STATS_DUMMY(mib) ++#define __SNMP_ADD_STATS(mib, field, addend) __SNMP_STATS_DUMMY(mib) ++#define SNMP_ADD_STATS(mib, field, addend) __SNMP_STATS_DUMMY(mib) ++#define SNMP_UPD_PO_STATS(mib, basefield, addend) __SNMP_STATS_DUMMY(mib) ++#define __SNMP_UPD_PO_STATS(mib, basefield, addend) __SNMP_STATS_DUMMY(mib) ++ ++#else ++ + #define __SNMP_INC_STATS(mib, field) \ + __this_cpu_inc(mib->mibs[field]) + +@@ -154,8 +169,9 @@ struct linux_tls_mib { + __this_cpu_add(ptr[basefield##OCTETS], addend); \ + } while (0) + ++#endif + +-#if BITS_PER_LONG==32 ++#if (BITS_PER_LONG==32) && !defined(CONFIG_PROC_STRIPPED) + + #define __SNMP_ADD_STATS64(mib, field, addend) \ + do { \ +diff --git a/ipc/msg.c b/ipc/msg.c +index fd08b3cb36d7..c71638872929 100644 +--- a/ipc/msg.c ++++ b/ipc/msg.c +@@ -1370,6 +1370,9 @@ void __init msg_init(void) + { + msg_init_ns(&init_ipc_ns); + ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return; ++ + ipc_init_proc_interface("sysvipc/msg", + " key msqid perms cbytes qnum lspid lrpid uid gid cuid cgid stime rtime ctime\n", + IPC_MSG_IDS, sysvipc_msg_proc_show); +diff --git a/ipc/sem.c b/ipc/sem.c +index a39cdc7bf88f..859af9ece817 100644 +--- a/ipc/sem.c ++++ b/ipc/sem.c +@@ -268,6 +268,8 @@ void sem_exit_ns(struct ipc_namespace *ns) + void __init sem_init(void) + { + sem_init_ns(&init_ipc_ns); ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return; + ipc_init_proc_interface("sysvipc/sem", + " key semid perms nsems uid gid cuid cgid otime ctime\n", + IPC_SEM_IDS, sysvipc_sem_proc_show); +diff --git a/ipc/shm.c b/ipc/shm.c +index 492fcc699985..8d8be78ae889 100644 +--- a/ipc/shm.c ++++ b/ipc/shm.c +@@ -155,6 +155,8 @@ pure_initcall(ipc_ns_init); + + void __init shm_init(void) + { ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return; + ipc_init_proc_interface("sysvipc/shm", + #if BITS_PER_LONG <= 32 + " key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime rss swap\n", +diff --git a/ipc/util.c b/ipc/util.c +index 05cb9de66735..6a90d425e684 100644 +--- a/ipc/util.c ++++ b/ipc/util.c +@@ -141,6 +141,9 @@ void __init ipc_init_proc_interface(const char *path, const char *header, + struct proc_dir_entry *pde; + struct ipc_proc_iface *iface; + ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return; ++ + iface = kmalloc(sizeof(*iface), GFP_KERNEL); + if (!iface) + return; +diff --git a/kernel/exec_domain.c b/kernel/exec_domain.c +index 33f07c5f2515..4c226a052bcd 100644 +--- a/kernel/exec_domain.c ++++ b/kernel/exec_domain.c +@@ -29,6 +29,8 @@ static int execdomains_proc_show(struct seq_file *m, void *v) + + static int __init proc_execdomains_init(void) + { ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return 0; + proc_create_single("execdomains", 0, NULL, execdomains_proc_show); + return 0; + } +diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c +index 9081ada81c3d..6a6ed1559ac7 100644 +--- a/kernel/irq/proc.c ++++ b/kernel/irq/proc.c +@@ -339,6 +339,9 @@ void register_irq_proc(unsigned int irq, struct irq_desc *desc) + void __maybe_unused *irqp = (void *)(unsigned long) irq; + char name [MAX_NAMELEN]; + ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED) && !IS_ENABLED(CONFIG_SMP)) ++ return; ++ + if (!root_irq_dir || (desc->irq_data.chip == &no_irq_chip)) + return; + +@@ -397,6 +400,9 @@ void unregister_irq_proc(unsigned int irq, struct irq_desc *desc) + { + char name [MAX_NAMELEN]; + ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED) && !IS_ENABLED(CONFIG_SMP)) ++ return; ++ + if (!root_irq_dir || !desc->dir) + return; + #ifdef CONFIG_SMP +@@ -435,6 +441,9 @@ void init_irq_proc(void) + unsigned int irq; + struct irq_desc *desc; + ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED) && !IS_ENABLED(CONFIG_SMP)) ++ return; ++ + /* create /proc/irq */ + root_irq_dir = proc_mkdir("irq", NULL); + if (!root_irq_dir) +diff --git a/kernel/time/timer_list.c b/kernel/time/timer_list.c +index cfbb46cc4e76..9a1dea23d175 100644 +--- a/kernel/time/timer_list.c ++++ b/kernel/time/timer_list.c +@@ -354,6 +354,8 @@ static int __init init_timer_list_procfs(void) + { + struct proc_dir_entry *pe; + ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return 0; + pe = proc_create_seq_private("timer_list", 0400, NULL, &timer_list_sops, + sizeof(struct timer_list_iter), NULL); + if (!pe) +diff --git a/mm/vmalloc.c b/mm/vmalloc.c +index 3519c4e4f841..8a1d2bc055d9 100644 +--- a/mm/vmalloc.c ++++ b/mm/vmalloc.c +@@ -5074,6 +5074,9 @@ static int vmalloc_info_show(struct seq_file *m, void *p) + + static int __init proc_vmalloc_init(void) + { ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return 0; ++ + proc_create_single("vmallocinfo", 0400, NULL, vmalloc_info_show); + return 0; + } +diff --git a/mm/vmstat.c b/mm/vmstat.c +index 3f4134423912..7dc56a7829b5 100644 +--- a/mm/vmstat.c ++++ b/mm/vmstat.c +@@ -2195,10 +2195,12 @@ void __init init_mm_internals(void) + start_shepherd_timer(); + #endif + #ifdef CONFIG_PROC_FS +- proc_create_seq("buddyinfo", 0444, NULL, &fragmentation_op); +- proc_create_seq("pagetypeinfo", 0400, NULL, &pagetypeinfo_op); ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) { ++ proc_create_seq("buddyinfo", 0444, NULL, &fragmentation_op); ++ proc_create_seq("pagetypeinfo", 0400, NULL, &pagetypeinfo_op); ++ proc_create_seq("zoneinfo", 0444, NULL, &zoneinfo_op); ++ } + proc_create_seq("vmstat", 0444, NULL, &vmstat_op); +- proc_create_seq("zoneinfo", 0444, NULL, &zoneinfo_op); + #endif + } + +diff --git a/net/8021q/vlanproc.c b/net/8021q/vlanproc.c +index fa67374bda49..3434370ab83e 100644 +--- a/net/8021q/vlanproc.c ++++ b/net/8021q/vlanproc.c +@@ -93,6 +93,9 @@ void vlan_proc_cleanup(struct net *net) + { + struct vlan_net *vn = net_generic(net, vlan_net_id); + ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return; ++ + if (vn->proc_vlan_conf) + remove_proc_entry(name_conf, vn->proc_vlan_dir); + +@@ -112,6 +115,9 @@ int __net_init vlan_proc_init(struct net *net) + { + struct vlan_net *vn = net_generic(net, vlan_net_id); + ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return 0; ++ + vn->proc_vlan_dir = proc_net_mkdir(net, name_root, net->proc_net); + if (!vn->proc_vlan_dir) + goto err; +diff --git a/net/core/net-procfs.c b/net/core/net-procfs.c +index fa6d3969734a..5cafc5a9d3dc 100644 +--- a/net/core/net-procfs.c ++++ b/net/core/net-procfs.c +@@ -295,10 +295,12 @@ static int __net_init dev_proc_net_init(struct net *net) + if (!proc_create_net("dev", 0444, net->proc_net, &dev_seq_ops, + sizeof(struct seq_net_private))) + goto out; +- if (!proc_create_seq("softnet_stat", 0444, net->proc_net, ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED) && ++ !proc_create_seq("softnet_stat", 0444, net->proc_net, + &softnet_seq_ops)) + goto out_dev; +- if (!proc_create_net("ptype", 0444, net->proc_net, &ptype_seq_ops, ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED) && ++ !proc_create_net("ptype", 0444, net->proc_net, &ptype_seq_ops, + sizeof(struct seq_net_private))) + goto out_softnet; + +@@ -308,9 +310,11 @@ static int __net_init dev_proc_net_init(struct net *net) + out: + return rc; + out_ptype: +- remove_proc_entry("ptype", net->proc_net); ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ remove_proc_entry("ptype", net->proc_net); + out_softnet: +- remove_proc_entry("softnet_stat", net->proc_net); ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ remove_proc_entry("softnet_stat", net->proc_net); + out_dev: + remove_proc_entry("dev", net->proc_net); + goto out; +@@ -320,8 +324,10 @@ static void __net_exit dev_proc_net_exit(struct net *net) + { + wext_proc_exit(net); + +- remove_proc_entry("ptype", net->proc_net); +- remove_proc_entry("softnet_stat", net->proc_net); ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) { ++ remove_proc_entry("ptype", net->proc_net); ++ remove_proc_entry("softnet_stat", net->proc_net); ++ } + remove_proc_entry("dev", net->proc_net); + } + +diff --git a/net/core/sock.c b/net/core/sock.c +index 373671aee9c1..b8f37075a07e 100644 +--- a/net/core/sock.c ++++ b/net/core/sock.c +@@ -4277,6 +4277,8 @@ static __net_initdata struct pernet_operations proto_net_ops = { + + static int __init proto_init(void) + { ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return 0; + return register_pernet_subsys(&proto_net_ops); + } + +diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c +index b7440806041b..3708ed3ccb44 100644 +--- a/net/ipv4/fib_trie.c ++++ b/net/ipv4/fib_trie.c +@@ -3015,11 +3015,13 @@ static const struct seq_operations fib_route_seq_ops = { + + int __net_init fib_proc_init(struct net *net) + { +- if (!proc_create_net("fib_trie", 0444, net->proc_net, &fib_trie_seq_ops, ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED) && ++ !proc_create_net("fib_trie", 0444, net->proc_net, &fib_trie_seq_ops, + sizeof(struct fib_trie_iter))) + goto out1; + +- if (!proc_create_net_single("fib_triestat", 0444, net->proc_net, ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED) && ++ !proc_create_net_single("fib_triestat", 0444, net->proc_net, + fib_triestat_seq_show, NULL)) + goto out2; + +@@ -3030,17 +3032,21 @@ int __net_init fib_proc_init(struct net *net) + return 0; + + out3: +- remove_proc_entry("fib_triestat", net->proc_net); ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ remove_proc_entry("fib_triestat", net->proc_net); + out2: +- remove_proc_entry("fib_trie", net->proc_net); ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ remove_proc_entry("fib_trie", net->proc_net); + out1: + return -ENOMEM; + } + + void __net_exit fib_proc_exit(struct net *net) + { +- remove_proc_entry("fib_trie", net->proc_net); +- remove_proc_entry("fib_triestat", net->proc_net); ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) { ++ remove_proc_entry("fib_trie", net->proc_net); ++ remove_proc_entry("fib_triestat", net->proc_net); ++ } + remove_proc_entry("route", net->proc_net); + } + +diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c +index 337390ba85b4..a03d02dca981 100644 +--- a/net/ipv4/inet_timewait_sock.c ++++ b/net/ipv4/inet_timewait_sock.c +@@ -296,7 +296,7 @@ void __inet_twsk_schedule(struct inet_timewait_sock *tw, int timeo, bool rearm) + */ + + if (!rearm) { +- bool kill = timeo <= 4*HZ; ++ bool __maybe_unused kill = timeo <= 4*HZ; + + __NET_INC_STATS(twsk_net(tw), kill ? LINUX_MIB_TIMEWAITKILLED : + LINUX_MIB_TIMEWAITED); +diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c +index 40053a02bae1..3e32011883f3 100644 +--- a/net/ipv4/proc.c ++++ b/net/ipv4/proc.c +@@ -563,5 +563,8 @@ static __net_initdata struct pernet_operations ip_proc_ops = { + + int __init ip_misc_proc_init(void) + { ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return 0; ++ + return register_pernet_subsys(&ip_proc_ops); + } +diff --git a/net/ipv4/route.c b/net/ipv4/route.c +index 7d04df4fc660..a27025ff7b20 100644 +--- a/net/ipv4/route.c ++++ b/net/ipv4/route.c +@@ -382,6 +382,9 @@ static struct pernet_operations ip_rt_proc_ops __net_initdata = { + + static int __init ip_rt_proc_init(void) + { ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return 0; ++ + return register_pernet_subsys(&ip_rt_proc_ops); + } + +-- +2.51.0 + + +From 367044524b89a67e491b9fa119b1ba2fc7a7d560 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Sat, 8 Jul 2017 08:20:43 +0200 +Subject: [PATCH 379/517] debloat: dmabuf + +Signed-off-by: Felix Fietkau +--- + drivers/base/Kconfig | 2 +- + drivers/dma-buf/Makefile | 20 ++++++++++++-------- + drivers/dma-buf/dma-buf.c | 3 ++- + drivers/dma-buf/heaps/Makefile | 4 ++-- + fs/d_path.c | 1 + + kernel/sched/core.c | 1 + + net/Kconfig | 2 +- + 7 files changed, 20 insertions(+), 13 deletions(-) + +diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig +index 064eb52ff7e2..f17614172bf7 100644 +--- a/drivers/base/Kconfig ++++ b/drivers/base/Kconfig +@@ -198,7 +198,7 @@ config SOC_BUS + source "drivers/base/regmap/Kconfig" + + config DMA_SHARED_BUFFER +- bool ++ tristate + default n + select IRQ_WORK + help +diff --git a/drivers/dma-buf/Makefile b/drivers/dma-buf/Makefile +index 70ec901edf2c..4efa1df475f0 100644 +--- a/drivers/dma-buf/Makefile ++++ b/drivers/dma-buf/Makefile +@@ -1,12 +1,14 @@ + # SPDX-License-Identifier: GPL-2.0-only +-obj-y := dma-buf.o dma-fence.o dma-fence-array.o dma-fence-chain.o \ ++obj-$(CONFIG_DMA_SHARED_BUFFER) := dma-shared-buffer.o ++ ++dma-buf-objs-y := dma-buf.o dma-fence.o dma-fence-array.o dma-fence-chain.o \ + dma-fence-unwrap.o dma-resv.o +-obj-$(CONFIG_DMABUF_HEAPS) += dma-heap.o +-obj-$(CONFIG_DMABUF_HEAPS) += heaps/ +-obj-$(CONFIG_SYNC_FILE) += sync_file.o +-obj-$(CONFIG_SW_SYNC) += sw_sync.o sync_debug.o +-obj-$(CONFIG_UDMABUF) += udmabuf.o +-obj-$(CONFIG_DMABUF_SYSFS_STATS) += dma-buf-sysfs-stats.o ++dma-buf-objs-$(CONFIG_DMABUF_HEAPS) += dma-heap.o ++obj-$(CONFIG_DMABUF_HEAPS) += heaps/ ++dma-buf-objs-$(CONFIG_SYNC_FILE) += sync_file.o ++dma-buf-objs-$(CONFIG_SW_SYNC) += sw_sync.o sync_debug.o ++dma-buf-objs-$(CONFIG_UDMABUF) += udmabuf.o ++dma-buf-objs-$(CONFIG_DMABUF_SYSFS_STATS) += dma-buf-sysfs-stats.o + + dmabuf_selftests-y := \ + selftest.o \ +@@ -15,4 +17,6 @@ dmabuf_selftests-y := \ + st-dma-fence-unwrap.o \ + st-dma-resv.o + +-obj-$(CONFIG_DMABUF_SELFTESTS) += dmabuf_selftests.o ++dma-buf-objs-$(CONFIG_DMABUF_SELFTESTS) += dmabuf_selftests.o ++ ++dma-shared-buffer-objs := $(dma-buf-objs-y) +diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c +index afb8c1c50107..f2e5dd69b100 100644 +--- a/drivers/dma-buf/dma-buf.c ++++ b/drivers/dma-buf/dma-buf.c +@@ -1743,4 +1743,5 @@ static void __exit dma_buf_deinit(void) + kern_unmount(dma_buf_mnt); + dma_buf_uninit_sysfs_statistics(); + } +-__exitcall(dma_buf_deinit); ++module_exit(dma_buf_deinit); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/dma-buf/heaps/Makefile b/drivers/dma-buf/heaps/Makefile +index 974467791032..87f71c3ee6fb 100644 +--- a/drivers/dma-buf/heaps/Makefile ++++ b/drivers/dma-buf/heaps/Makefile +@@ -1,3 +1,3 @@ + # SPDX-License-Identifier: GPL-2.0 +-obj-$(CONFIG_DMABUF_HEAPS_SYSTEM) += system_heap.o +-obj-$(CONFIG_DMABUF_HEAPS_CMA) += cma_heap.o ++dma-buf-objs-$(CONFIG_DMABUF_HEAPS_SYSTEM) += system_heap.o ++dma-buf-objs-$(CONFIG_DMABUF_HEAPS_CMA) += cma_heap.o +diff --git a/fs/d_path.c b/fs/d_path.c +index 5f4da5c8d5db..69d49d7ab260 100644 +--- a/fs/d_path.c ++++ b/fs/d_path.c +@@ -314,6 +314,7 @@ char *dynamic_dname(char *buffer, int buflen, const char *fmt, ...) + buffer += buflen - sz; + return memcpy(buffer, temp, sz); + } ++EXPORT_SYMBOL_GPL(dynamic_dname); + + char *simple_dname(struct dentry *dentry, char *buffer, int buflen) + { +diff --git a/kernel/sched/core.c b/kernel/sched/core.c +index 4b1953b6c76a..ca7ee02dc916 100644 +--- a/kernel/sched/core.c ++++ b/kernel/sched/core.c +@@ -4433,6 +4433,7 @@ int wake_up_state(struct task_struct *p, unsigned int state) + { + return try_to_wake_up(p, state, 0); + } ++EXPORT_SYMBOL_GPL(wake_up_state); + + /* + * Perform scheduler related setup for a newly forked process p. +diff --git a/net/Kconfig b/net/Kconfig +index b1afb23fe2fb..5f179d2e74c2 100644 +--- a/net/Kconfig ++++ b/net/Kconfig +@@ -74,7 +74,7 @@ config SKB_EXTENSIONS + + config NET_DEVMEM + def_bool y +- depends on DMA_SHARED_BUFFER ++ depends on DMA_SHARED_BUFFER=y + depends on GENERIC_ALLOCATOR + depends on PAGE_POOL + +-- +2.51.0 + + +From 9856b0a5865ac77a4941f011da93921ca0a1fff4 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Sun, 16 Jul 2017 16:56:10 +0200 +Subject: [PATCH 380/517] lib: add uevent_next_seqnum() + +Signed-off-by: Felix Fietkau +--- + include/linux/kobject.h | 2 ++ + lib/kobject_uevent.c | 6 ++++++ + 2 files changed, 8 insertions(+) + +diff --git a/include/linux/kobject.h b/include/linux/kobject.h +index c8219505a79f..f9c97c9b9847 100644 +--- a/include/linux/kobject.h ++++ b/include/linux/kobject.h +@@ -219,4 +219,6 @@ int kobject_synth_uevent(struct kobject *kobj, const char *buf, size_t count); + __printf(2, 3) + int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...); + ++u64 uevent_next_seqnum(void); ++ + #endif /* _KOBJECT_H_ */ +diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c +index b7f2fa08d9c8..788d8959a2d3 100644 +--- a/lib/kobject_uevent.c ++++ b/lib/kobject_uevent.c +@@ -178,6 +178,12 @@ static int kobject_action_args(const char *buf, size_t count, + return r; + } + ++u64 uevent_next_seqnum(void) ++{ ++ return atomic64_inc_return(&uevent_seqnum); ++} ++EXPORT_SYMBOL_GPL(uevent_next_seqnum); ++ + /** + * kobject_synth_uevent - send synthetic uevent with arguments + * +-- +2.51.0 + + +From 84376022c24166ef12e2aff2b845a31f29fd43bf Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Sun, 16 Jul 2017 16:56:10 +0200 +Subject: [PATCH 381/517] lib: add broadcast_uevent() + +Signed-off-by: Felix Fietkau +--- + include/linux/kobject.h | 5 +++++ + lib/kobject_uevent.c | 37 +++++++++++++++++++++++++++++++++++++ + 2 files changed, 42 insertions(+) + +diff --git a/include/linux/kobject.h b/include/linux/kobject.h +index f9c97c9b9847..08d4818586b6 100644 +--- a/include/linux/kobject.h ++++ b/include/linux/kobject.h +@@ -32,6 +32,8 @@ + #define UEVENT_NUM_ENVP 64 /* number of env pointers */ + #define UEVENT_BUFFER_SIZE 2048 /* buffer for the variables */ + ++struct sk_buff; ++ + #ifdef CONFIG_UEVENT_HELPER + /* path to the userspace helper executed on an event */ + extern char uevent_helper[]; +@@ -221,4 +223,7 @@ int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...); + + u64 uevent_next_seqnum(void); + ++int broadcast_uevent(struct sk_buff *skb, __u32 pid, __u32 group, ++ gfp_t allocation); ++ + #endif /* _KOBJECT_H_ */ +diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c +index 788d8959a2d3..2716e02169d6 100644 +--- a/lib/kobject_uevent.c ++++ b/lib/kobject_uevent.c +@@ -698,6 +698,43 @@ int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...) + } + EXPORT_SYMBOL_GPL(add_uevent_var); + ++#if defined(CONFIG_NET) ++int broadcast_uevent(struct sk_buff *skb, __u32 pid, __u32 group, ++ gfp_t allocation) ++{ ++ struct uevent_sock *ue_sk; ++ int err = 0; ++ ++ /* send netlink message */ ++ mutex_lock(&uevent_sock_mutex); ++ list_for_each_entry(ue_sk, &uevent_sock_list, list) { ++ struct sock *uevent_sock = ue_sk->sk; ++ struct sk_buff *skb2; ++ ++ skb2 = skb_clone(skb, allocation); ++ if (!skb2) ++ break; ++ ++ err = netlink_broadcast(uevent_sock, skb2, pid, group, ++ allocation); ++ if (err) ++ break; ++ } ++ mutex_unlock(&uevent_sock_mutex); ++ ++ kfree_skb(skb); ++ return err; ++} ++#else ++int broadcast_uevent(struct sk_buff *skb, __u32 pid, __u32 group, ++ gfp_t allocation) ++{ ++ kfree_skb(skb); ++ return 0; ++} ++#endif ++EXPORT_SYMBOL_GPL(broadcast_uevent); ++ + #if defined(CONFIG_NET) + static int uevent_net_broadcast(struct sock *usk, struct sk_buff *skb, + struct netlink_ext_ack *extack) +-- +2.51.0 + + +From 809764a8e59e218960291427c0dfc3fec03896de Mon Sep 17 00:00:00 2001 +From: OpenWrt community +Date: Wed, 13 Jul 2022 13:52:28 +0200 +Subject: [PATCH 382/517] of/ftd: add device tree cmdline + +--- + drivers/of/fdt.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c +index 8c80f4dc8b3f..500807cccee4 100644 +--- a/drivers/of/fdt.c ++++ b/drivers/of/fdt.c +@@ -1049,6 +1049,9 @@ int __init early_init_dt_scan_chosen(char *cmdline) + p = of_get_flat_dt_prop(node, "bootargs", &l); + if (p != NULL && l > 0) + strscpy(cmdline, p, min(l, COMMAND_LINE_SIZE)); ++ p = of_get_flat_dt_prop(node, "bootargs-append", &l); ++ if (p != NULL && l > 0) ++ strlcat(cmdline, p, min_t(int, strlen(cmdline) + (int)l, COMMAND_LINE_SIZE)); + + handle_cmdline: + /* +-- +2.51.0 + + +From f9ab6c46d9c89e908775d62b0104f5a370a66023 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Tue, 19 Jul 2022 06:17:48 +0200 +Subject: [PATCH 383/517] Revert "Revert "Revert "driver core: Set + fw_devlink=on by default""" +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This reverts commit ea718c699055c8566eb64432388a04974c43b2ea. + +With of_platform_populate() called for MTD partitions that commit breaks +probing devices which reference MTD in device tree. + +Link: https://lore.kernel.org/all/696cb2da-20b9-b3dd-46d9-de4bf91a1506@gmail.com/T/#u +Signed-off-by: RafaÅ‚ MiÅ‚ecki +--- + drivers/base/core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/base/core.c b/drivers/base/core.c +index ba9b4cbef9e0..4bbd4c2c9448 100644 +--- a/drivers/base/core.c ++++ b/drivers/base/core.c +@@ -1653,7 +1653,7 @@ static void device_links_purge(struct device *dev) + #define FW_DEVLINK_FLAGS_RPM (FW_DEVLINK_FLAGS_ON | \ + DL_FLAG_PM_RUNTIME) + +-static u32 fw_devlink_flags = FW_DEVLINK_FLAGS_RPM; ++static u32 fw_devlink_flags = FW_DEVLINK_FLAGS_PERMISSIVE; + static int __init fw_devlink_setup(char *arg) + { + if (!arg) +-- +2.51.0 + + +From 0d4da66db0ee983798e8a0fc412539cdf4c8003a Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Tue, 17 Dec 2024 09:54:26 +0100 +Subject: [PATCH 384/517] pinctrl: mediatek: add support for MTK_PULL_PD_TYPE + +The MediaTek MT7988 SoC got some pins which only got configurable +pull-down but unlike previous designs there is no pull-up option. +Add new type MTK_PULL_PD_TYPE to support configuring such pins. + +Signed-off-by: Daniel Golle +Signed-off-by: Frank Wunderlich +Reviewed-by: AngeloGioacchino Del Regno +Link: https://lore.kernel.org/20241217085435.9586-2-linux@fw-web.de +Signed-off-by: Linus Walleij +--- + .../pinctrl/mediatek/pinctrl-mtk-common-v2.c | 73 ++++++++++++++++--- + .../pinctrl/mediatek/pinctrl-mtk-common-v2.h | 1 + + 2 files changed, 63 insertions(+), 11 deletions(-) + +diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c +index 54301fbba524..7b704cc55c9f 100644 +--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c ++++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c +@@ -573,7 +573,7 @@ EXPORT_SYMBOL_GPL(mtk_pinconf_bias_get_rev1); + */ + static int mtk_pinconf_bias_set_pu_pd(struct mtk_pinctrl *hw, + const struct mtk_pin_desc *desc, +- u32 pullup, u32 arg) ++ u32 pullup, u32 arg, bool pd_only) + { + int err, pu, pd; + +@@ -587,18 +587,34 @@ static int mtk_pinconf_bias_set_pu_pd(struct mtk_pinctrl *hw, + pu = 0; + pd = 1; + } else { +- err = -EINVAL; +- goto out; ++ return -EINVAL; + } + +- err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PU, pu); +- if (err) +- goto out; ++ if (!pd_only) { ++ err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PU, pu); ++ if (err) ++ return err; ++ } + +- err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PD, pd); ++ return mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PD, pd); ++} ++ ++static int mtk_pinconf_bias_set_pd(struct mtk_pinctrl *hw, ++ const struct mtk_pin_desc *desc, ++ u32 pullup, u32 arg) ++{ ++ int err, pd; ++ ++ if (arg != MTK_DISABLE && arg != MTK_ENABLE) ++ return -EINVAL; ++ ++ if (arg == MTK_DISABLE || pullup) ++ pd = 0; ++ else if (!pullup) ++ pd = 1; ++ ++ return mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PD, pd); + +-out: +- return err; + } + + static int mtk_pinconf_bias_set_pullsel_pullen(struct mtk_pinctrl *hw, +@@ -737,7 +753,7 @@ static int mtk_pinconf_bias_set_pu_pd_rsel(struct mtk_pinctrl *hw, + return err; + } + +- return mtk_pinconf_bias_set_pu_pd(hw, desc, pullup, enable); ++ return mtk_pinconf_bias_set_pu_pd(hw, desc, pullup, enable, false); + } + + int mtk_pinconf_bias_set_combo(struct mtk_pinctrl *hw, +@@ -758,8 +774,14 @@ int mtk_pinconf_bias_set_combo(struct mtk_pinctrl *hw, + return 0; + } + ++ if (try_all_type & MTK_PULL_PD_TYPE) { ++ err = mtk_pinconf_bias_set_pu_pd(hw, desc, pullup, arg, true); ++ if (!err) ++ return err; ++ } ++ + if (try_all_type & MTK_PULL_PU_PD_TYPE) { +- err = mtk_pinconf_bias_set_pu_pd(hw, desc, pullup, arg); ++ err = mtk_pinconf_bias_set_pu_pd(hw, desc, pullup, arg, false); + if (!err) + return 0; + } +@@ -878,6 +900,29 @@ static int mtk_pinconf_bias_get_pu_pd(struct mtk_pinctrl *hw, + return err; + } + ++static int mtk_pinconf_bias_get_pd(struct mtk_pinctrl *hw, ++ const struct mtk_pin_desc *desc, ++ u32 *pullup, u32 *enable) ++{ ++ int err, pd; ++ ++ err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PD, &pd); ++ if (err) ++ goto out; ++ ++ if (pd == 0) { ++ *pullup = 0; ++ *enable = MTK_DISABLE; ++ } else if (pd == 1) { ++ *pullup = 0; ++ *enable = MTK_ENABLE; ++ } else ++ err = -EINVAL; ++ ++out: ++ return err; ++} ++ + static int mtk_pinconf_bias_get_pullsel_pullen(struct mtk_pinctrl *hw, + const struct mtk_pin_desc *desc, + u32 *pullup, u32 *enable) +@@ -947,6 +992,12 @@ int mtk_pinconf_bias_get_combo(struct mtk_pinctrl *hw, + return 0; + } + ++ if (try_all_type & MTK_PULL_PD_TYPE) { ++ err = mtk_pinconf_bias_get_pd(hw, desc, pullup, enable); ++ if (!err) ++ return err; ++ } ++ + if (try_all_type & MTK_PULL_PU_PD_TYPE) { + err = mtk_pinconf_bias_get_pu_pd(hw, desc, pullup, enable); + if (!err) +diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.h b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.h +index 23688ca6d04e..9c271dc2b521 100644 +--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.h ++++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.h +@@ -24,6 +24,7 @@ + * turned on/off itself. But it can't be selected pull up/down + */ + #define MTK_PULL_RSEL_TYPE BIT(3) ++#define MTK_PULL_PD_TYPE BIT(4) + /* MTK_PULL_PU_PD_RSEL_TYPE is a type which is controlled by + * MTK_PULL_PU_PD_TYPE and MTK_PULL_RSEL_TYPE. + */ +-- +2.51.0 + + +From 9f6832a6bcf3fa5ef863246b5ae17537433342a8 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Tue, 17 Dec 2024 09:54:27 +0100 +Subject: [PATCH 385/517] pinctrl: mediatek: add MT7988 pinctrl driver +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add pinctrl driver for the MediaTek MT7988 SoC. + +Signed-off-by: Sam Shih +Signed-off-by: Daniel Golle +[correctly initialise for the function_desc structure] +Signed-off-by: Arınç ÜNAL +Signed-off-by: Frank Wunderlich +Reviewed-by: AngeloGioacchino Del Regno +Link: https://lore.kernel.org/20241217085435.9586-3-linux@fw-web.de +Signed-off-by: Linus Walleij +--- + drivers/pinctrl/mediatek/Kconfig | 7 + + drivers/pinctrl/mediatek/Makefile | 1 + + drivers/pinctrl/mediatek/pinctrl-mt7988.c | 1556 +++++++++++++++++++++ + 3 files changed, 1564 insertions(+) + create mode 100644 drivers/pinctrl/mediatek/pinctrl-mt7988.c + +diff --git a/drivers/pinctrl/mediatek/Kconfig b/drivers/pinctrl/mediatek/Kconfig +index 7af287252834..952110c783d4 100644 +--- a/drivers/pinctrl/mediatek/Kconfig ++++ b/drivers/pinctrl/mediatek/Kconfig +@@ -187,6 +187,13 @@ config PINCTRL_MT7986 + default ARM64 && ARCH_MEDIATEK + select PINCTRL_MTK_MOORE + ++config PINCTRL_MT7988 ++ bool "Mediatek MT7988 pin control" ++ depends on OF ++ depends on ARM64 || COMPILE_TEST ++ default ARM64 && ARCH_MEDIATEK ++ select PINCTRL_MTK_MOORE ++ + config PINCTRL_MT8167 + bool "MediaTek MT8167 pin control" + depends on OF +diff --git a/drivers/pinctrl/mediatek/Makefile b/drivers/pinctrl/mediatek/Makefile +index 680f7e8526e0..2b47ce030b54 100644 +--- a/drivers/pinctrl/mediatek/Makefile ++++ b/drivers/pinctrl/mediatek/Makefile +@@ -27,6 +27,7 @@ obj-$(CONFIG_PINCTRL_MT7623) += pinctrl-mt7623.o + obj-$(CONFIG_PINCTRL_MT7629) += pinctrl-mt7629.o + obj-$(CONFIG_PINCTRL_MT7981) += pinctrl-mt7981.o + obj-$(CONFIG_PINCTRL_MT7986) += pinctrl-mt7986.o ++obj-$(CONFIG_PINCTRL_MT7988) += pinctrl-mt7988.o + obj-$(CONFIG_PINCTRL_MT8167) += pinctrl-mt8167.o + obj-$(CONFIG_PINCTRL_MT8173) += pinctrl-mt8173.o + obj-$(CONFIG_PINCTRL_MT8183) += pinctrl-mt8183.o +diff --git a/drivers/pinctrl/mediatek/pinctrl-mt7988.c b/drivers/pinctrl/mediatek/pinctrl-mt7988.c +new file mode 100644 +index 000000000000..68b4097792b8 +--- /dev/null ++++ b/drivers/pinctrl/mediatek/pinctrl-mt7988.c +@@ -0,0 +1,1556 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * The MT7988 driver based on Linux generic pinctrl binding. ++ * ++ * Copyright (C) 2020 MediaTek Inc. ++ * Author: Sam Shih ++ */ ++ ++#include "pinctrl-moore.h" ++ ++enum mt7988_pinctrl_reg_page { ++ GPIO_BASE, ++ IOCFG_TR_BASE, ++ IOCFG_BR_BASE, ++ IOCFG_RB_BASE, ++ IOCFG_LB_BASE, ++ IOCFG_TL_BASE, ++}; ++ ++#define MT7988_PIN(_number, _name) MTK_PIN(_number, _name, 0, _number, DRV_GRP4) ++ ++#define PIN_FIELD_BASE(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit, \ ++ _x_bits) \ ++ PIN_FIELD_CALC(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit, \ ++ _x_bits, 32, 0) ++ ++#define PINS_FIELD_BASE(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit, \ ++ _x_bits) \ ++ PIN_FIELD_CALC(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit, \ ++ _x_bits, 32, 1) ++ ++static const struct mtk_pin_field_calc mt7988_pin_mode_range[] = { ++ PIN_FIELD(0, 83, 0x300, 0x10, 0, 4), ++}; ++ ++static const struct mtk_pin_field_calc mt7988_pin_dir_range[] = { ++ PIN_FIELD(0, 83, 0x0, 0x10, 0, 1), ++}; ++ ++static const struct mtk_pin_field_calc mt7988_pin_di_range[] = { ++ PIN_FIELD(0, 83, 0x200, 0x10, 0, 1), ++}; ++ ++static const struct mtk_pin_field_calc mt7988_pin_do_range[] = { ++ PIN_FIELD(0, 83, 0x100, 0x10, 0, 1), ++}; ++ ++static const struct mtk_pin_field_calc mt7988_pin_ies_range[] = { ++ PIN_FIELD_BASE(0, 0, 5, 0x30, 0x10, 13, 1), ++ PIN_FIELD_BASE(1, 1, 5, 0x30, 0x10, 14, 1), ++ PIN_FIELD_BASE(2, 2, 5, 0x30, 0x10, 11, 1), ++ PIN_FIELD_BASE(3, 3, 5, 0x30, 0x10, 12, 1), ++ PIN_FIELD_BASE(4, 4, 5, 0x30, 0x10, 0, 1), ++ PIN_FIELD_BASE(5, 5, 5, 0x30, 0x10, 9, 1), ++ PIN_FIELD_BASE(6, 6, 5, 0x30, 0x10, 10, 1), ++ ++ PIN_FIELD_BASE(7, 7, 4, 0x30, 0x10, 8, 1), ++ PIN_FIELD_BASE(8, 8, 4, 0x30, 0x10, 6, 1), ++ PIN_FIELD_BASE(9, 9, 4, 0x30, 0x10, 5, 1), ++ PIN_FIELD_BASE(10, 10, 4, 0x30, 0x10, 3, 1), ++ ++ PIN_FIELD_BASE(11, 11, 1, 0x40, 0x10, 0, 1), ++ PIN_FIELD_BASE(12, 12, 1, 0x40, 0x10, 21, 1), ++ PIN_FIELD_BASE(13, 13, 1, 0x40, 0x10, 1, 1), ++ PIN_FIELD_BASE(14, 14, 1, 0x40, 0x10, 2, 1), ++ ++ PIN_FIELD_BASE(15, 15, 5, 0x30, 0x10, 7, 1), ++ PIN_FIELD_BASE(16, 16, 5, 0x30, 0x10, 8, 1), ++ PIN_FIELD_BASE(17, 17, 5, 0x30, 0x10, 3, 1), ++ PIN_FIELD_BASE(18, 18, 5, 0x30, 0x10, 4, 1), ++ ++ PIN_FIELD_BASE(19, 19, 4, 0x30, 0x10, 7, 1), ++ PIN_FIELD_BASE(20, 20, 4, 0x30, 0x10, 4, 1), ++ ++ PIN_FIELD_BASE(21, 21, 3, 0x50, 0x10, 17, 1), ++ PIN_FIELD_BASE(22, 22, 3, 0x50, 0x10, 23, 1), ++ PIN_FIELD_BASE(23, 23, 3, 0x50, 0x10, 20, 1), ++ PIN_FIELD_BASE(24, 24, 3, 0x50, 0x10, 19, 1), ++ PIN_FIELD_BASE(25, 25, 3, 0x50, 0x10, 21, 1), ++ PIN_FIELD_BASE(26, 26, 3, 0x50, 0x10, 22, 1), ++ PIN_FIELD_BASE(27, 27, 3, 0x50, 0x10, 18, 1), ++ PIN_FIELD_BASE(28, 28, 3, 0x50, 0x10, 25, 1), ++ PIN_FIELD_BASE(29, 29, 3, 0x50, 0x10, 26, 1), ++ PIN_FIELD_BASE(30, 30, 3, 0x50, 0x10, 27, 1), ++ PIN_FIELD_BASE(31, 31, 3, 0x50, 0x10, 24, 1), ++ PIN_FIELD_BASE(32, 32, 3, 0x50, 0x10, 28, 1), ++ PIN_FIELD_BASE(33, 33, 3, 0x60, 0x10, 0, 1), ++ PIN_FIELD_BASE(34, 34, 3, 0x50, 0x10, 31, 1), ++ PIN_FIELD_BASE(35, 35, 3, 0x50, 0x10, 29, 1), ++ PIN_FIELD_BASE(36, 36, 3, 0x50, 0x10, 30, 1), ++ PIN_FIELD_BASE(37, 37, 3, 0x60, 0x10, 1, 1), ++ PIN_FIELD_BASE(38, 38, 3, 0x50, 0x10, 11, 1), ++ PIN_FIELD_BASE(39, 39, 3, 0x50, 0x10, 10, 1), ++ PIN_FIELD_BASE(40, 40, 3, 0x50, 0x10, 0, 1), ++ PIN_FIELD_BASE(41, 41, 3, 0x50, 0x10, 1, 1), ++ PIN_FIELD_BASE(42, 42, 3, 0x50, 0x10, 9, 1), ++ PIN_FIELD_BASE(43, 43, 3, 0x50, 0x10, 8, 1), ++ PIN_FIELD_BASE(44, 44, 3, 0x50, 0x10, 7, 1), ++ PIN_FIELD_BASE(45, 45, 3, 0x50, 0x10, 6, 1), ++ PIN_FIELD_BASE(46, 46, 3, 0x50, 0x10, 5, 1), ++ PIN_FIELD_BASE(47, 47, 3, 0x50, 0x10, 4, 1), ++ PIN_FIELD_BASE(48, 48, 3, 0x50, 0x10, 3, 1), ++ PIN_FIELD_BASE(49, 49, 3, 0x50, 0x10, 2, 1), ++ PIN_FIELD_BASE(50, 50, 3, 0x50, 0x10, 15, 1), ++ PIN_FIELD_BASE(51, 51, 3, 0x50, 0x10, 12, 1), ++ PIN_FIELD_BASE(52, 52, 3, 0x50, 0x10, 13, 1), ++ PIN_FIELD_BASE(53, 53, 3, 0x50, 0x10, 14, 1), ++ PIN_FIELD_BASE(54, 54, 3, 0x50, 0x10, 16, 1), ++ ++ PIN_FIELD_BASE(55, 55, 1, 0x40, 0x10, 14, 1), ++ PIN_FIELD_BASE(56, 56, 1, 0x40, 0x10, 15, 1), ++ PIN_FIELD_BASE(57, 57, 1, 0x40, 0x10, 13, 1), ++ PIN_FIELD_BASE(58, 58, 1, 0x40, 0x10, 4, 1), ++ PIN_FIELD_BASE(59, 59, 1, 0x40, 0x10, 5, 1), ++ PIN_FIELD_BASE(60, 60, 1, 0x40, 0x10, 6, 1), ++ PIN_FIELD_BASE(61, 61, 1, 0x40, 0x10, 3, 1), ++ PIN_FIELD_BASE(62, 62, 1, 0x40, 0x10, 7, 1), ++ PIN_FIELD_BASE(63, 63, 1, 0x40, 0x10, 20, 1), ++ PIN_FIELD_BASE(64, 64, 1, 0x40, 0x10, 8, 1), ++ PIN_FIELD_BASE(65, 65, 1, 0x40, 0x10, 9, 1), ++ PIN_FIELD_BASE(66, 66, 1, 0x40, 0x10, 10, 1), ++ PIN_FIELD_BASE(67, 67, 1, 0x40, 0x10, 11, 1), ++ PIN_FIELD_BASE(68, 68, 1, 0x40, 0x10, 12, 1), ++ ++ PIN_FIELD_BASE(69, 69, 5, 0x30, 0x10, 1, 1), ++ PIN_FIELD_BASE(70, 70, 5, 0x30, 0x10, 2, 1), ++ PIN_FIELD_BASE(71, 71, 5, 0x30, 0x10, 5, 1), ++ PIN_FIELD_BASE(72, 72, 5, 0x30, 0x10, 6, 1), ++ ++ PIN_FIELD_BASE(73, 73, 4, 0x30, 0x10, 10, 1), ++ PIN_FIELD_BASE(74, 74, 4, 0x30, 0x10, 1, 1), ++ PIN_FIELD_BASE(75, 75, 4, 0x30, 0x10, 11, 1), ++ PIN_FIELD_BASE(76, 76, 4, 0x30, 0x10, 9, 1), ++ PIN_FIELD_BASE(77, 77, 4, 0x30, 0x10, 2, 1), ++ PIN_FIELD_BASE(78, 78, 4, 0x30, 0x10, 0, 1), ++ PIN_FIELD_BASE(79, 79, 4, 0x30, 0x10, 12, 1), ++ ++ PIN_FIELD_BASE(80, 80, 1, 0x40, 0x10, 18, 1), ++ PIN_FIELD_BASE(81, 81, 1, 0x40, 0x10, 19, 1), ++ PIN_FIELD_BASE(82, 82, 1, 0x40, 0x10, 16, 1), ++ PIN_FIELD_BASE(83, 83, 1, 0x40, 0x10, 17, 1), ++}; ++ ++static const struct mtk_pin_field_calc mt7988_pin_smt_range[] = { ++ PIN_FIELD_BASE(0, 0, 5, 0xc0, 0x10, 13, 1), ++ PIN_FIELD_BASE(1, 1, 5, 0xc0, 0x10, 14, 1), ++ PIN_FIELD_BASE(2, 2, 5, 0xc0, 0x10, 11, 1), ++ PIN_FIELD_BASE(3, 3, 5, 0xc0, 0x10, 12, 1), ++ PIN_FIELD_BASE(4, 4, 5, 0xc0, 0x10, 0, 1), ++ PIN_FIELD_BASE(5, 5, 5, 0xc0, 0x10, 9, 1), ++ PIN_FIELD_BASE(6, 6, 5, 0xc0, 0x10, 10, 1), ++ ++ PIN_FIELD_BASE(7, 7, 4, 0xb0, 0x10, 8, 1), ++ PIN_FIELD_BASE(8, 8, 4, 0xb0, 0x10, 6, 1), ++ PIN_FIELD_BASE(9, 9, 4, 0xb0, 0x10, 5, 1), ++ PIN_FIELD_BASE(10, 10, 4, 0xb0, 0x10, 3, 1), ++ ++ PIN_FIELD_BASE(11, 11, 1, 0xe0, 0x10, 0, 1), ++ PIN_FIELD_BASE(12, 12, 1, 0xe0, 0x10, 21, 1), ++ PIN_FIELD_BASE(13, 13, 1, 0xe0, 0x10, 1, 1), ++ PIN_FIELD_BASE(14, 14, 1, 0xe0, 0x10, 2, 1), ++ ++ PIN_FIELD_BASE(15, 15, 5, 0xc0, 0x10, 7, 1), ++ PIN_FIELD_BASE(16, 16, 5, 0xc0, 0x10, 8, 1), ++ PIN_FIELD_BASE(17, 17, 5, 0xc0, 0x10, 3, 1), ++ PIN_FIELD_BASE(18, 18, 5, 0xc0, 0x10, 4, 1), ++ ++ PIN_FIELD_BASE(19, 19, 4, 0xb0, 0x10, 7, 1), ++ PIN_FIELD_BASE(20, 20, 4, 0xb0, 0x10, 4, 1), ++ ++ PIN_FIELD_BASE(21, 21, 3, 0x140, 0x10, 17, 1), ++ PIN_FIELD_BASE(22, 22, 3, 0x140, 0x10, 23, 1), ++ PIN_FIELD_BASE(23, 23, 3, 0x140, 0x10, 20, 1), ++ PIN_FIELD_BASE(24, 24, 3, 0x140, 0x10, 19, 1), ++ PIN_FIELD_BASE(25, 25, 3, 0x140, 0x10, 21, 1), ++ PIN_FIELD_BASE(26, 26, 3, 0x140, 0x10, 22, 1), ++ PIN_FIELD_BASE(27, 27, 3, 0x140, 0x10, 18, 1), ++ PIN_FIELD_BASE(28, 28, 3, 0x140, 0x10, 25, 1), ++ PIN_FIELD_BASE(29, 29, 3, 0x140, 0x10, 26, 1), ++ PIN_FIELD_BASE(30, 30, 3, 0x140, 0x10, 27, 1), ++ PIN_FIELD_BASE(31, 31, 3, 0x140, 0x10, 24, 1), ++ PIN_FIELD_BASE(32, 32, 3, 0x140, 0x10, 28, 1), ++ PIN_FIELD_BASE(33, 33, 3, 0x150, 0x10, 0, 1), ++ PIN_FIELD_BASE(34, 34, 3, 0x140, 0x10, 31, 1), ++ PIN_FIELD_BASE(35, 35, 3, 0x140, 0x10, 29, 1), ++ PIN_FIELD_BASE(36, 36, 3, 0x140, 0x10, 30, 1), ++ PIN_FIELD_BASE(37, 37, 3, 0x150, 0x10, 1, 1), ++ PIN_FIELD_BASE(38, 38, 3, 0x140, 0x10, 11, 1), ++ PIN_FIELD_BASE(39, 39, 3, 0x140, 0x10, 10, 1), ++ PIN_FIELD_BASE(40, 40, 3, 0x140, 0x10, 0, 1), ++ PIN_FIELD_BASE(41, 41, 3, 0x140, 0x10, 1, 1), ++ PIN_FIELD_BASE(42, 42, 3, 0x140, 0x10, 9, 1), ++ PIN_FIELD_BASE(43, 43, 3, 0x140, 0x10, 8, 1), ++ PIN_FIELD_BASE(44, 44, 3, 0x140, 0x10, 7, 1), ++ PIN_FIELD_BASE(45, 45, 3, 0x140, 0x10, 6, 1), ++ PIN_FIELD_BASE(46, 46, 3, 0x140, 0x10, 5, 1), ++ PIN_FIELD_BASE(47, 47, 3, 0x140, 0x10, 4, 1), ++ PIN_FIELD_BASE(48, 48, 3, 0x140, 0x10, 3, 1), ++ PIN_FIELD_BASE(49, 49, 3, 0x140, 0x10, 2, 1), ++ PIN_FIELD_BASE(50, 50, 3, 0x140, 0x10, 15, 1), ++ PIN_FIELD_BASE(51, 51, 3, 0x140, 0x10, 12, 1), ++ PIN_FIELD_BASE(52, 52, 3, 0x140, 0x10, 13, 1), ++ PIN_FIELD_BASE(53, 53, 3, 0x140, 0x10, 14, 1), ++ PIN_FIELD_BASE(54, 54, 3, 0x140, 0x10, 16, 1), ++ ++ PIN_FIELD_BASE(55, 55, 1, 0xe0, 0x10, 14, 1), ++ PIN_FIELD_BASE(56, 56, 1, 0xe0, 0x10, 15, 1), ++ PIN_FIELD_BASE(57, 57, 1, 0xe0, 0x10, 13, 1), ++ PIN_FIELD_BASE(58, 58, 1, 0xe0, 0x10, 4, 1), ++ PIN_FIELD_BASE(59, 59, 1, 0xe0, 0x10, 5, 1), ++ PIN_FIELD_BASE(60, 60, 1, 0xe0, 0x10, 6, 1), ++ PIN_FIELD_BASE(61, 61, 1, 0xe0, 0x10, 3, 1), ++ PIN_FIELD_BASE(62, 62, 1, 0xe0, 0x10, 7, 1), ++ PIN_FIELD_BASE(63, 63, 1, 0xe0, 0x10, 20, 1), ++ PIN_FIELD_BASE(64, 64, 1, 0xe0, 0x10, 8, 1), ++ PIN_FIELD_BASE(65, 65, 1, 0xe0, 0x10, 9, 1), ++ PIN_FIELD_BASE(66, 66, 1, 0xe0, 0x10, 10, 1), ++ PIN_FIELD_BASE(67, 67, 1, 0xe0, 0x10, 11, 1), ++ PIN_FIELD_BASE(68, 68, 1, 0xe0, 0x10, 12, 1), ++ ++ PIN_FIELD_BASE(69, 69, 5, 0xc0, 0x10, 1, 1), ++ PIN_FIELD_BASE(70, 70, 5, 0xc0, 0x10, 2, 1), ++ PIN_FIELD_BASE(71, 71, 5, 0xc0, 0x10, 5, 1), ++ PIN_FIELD_BASE(72, 72, 5, 0xc0, 0x10, 6, 1), ++ ++ PIN_FIELD_BASE(73, 73, 4, 0xb0, 0x10, 10, 1), ++ PIN_FIELD_BASE(74, 74, 4, 0xb0, 0x10, 1, 1), ++ PIN_FIELD_BASE(75, 75, 4, 0xb0, 0x10, 11, 1), ++ PIN_FIELD_BASE(76, 76, 4, 0xb0, 0x10, 9, 1), ++ PIN_FIELD_BASE(77, 77, 4, 0xb0, 0x10, 2, 1), ++ PIN_FIELD_BASE(78, 78, 4, 0xb0, 0x10, 0, 1), ++ PIN_FIELD_BASE(79, 79, 4, 0xb0, 0x10, 12, 1), ++ ++ PIN_FIELD_BASE(80, 80, 1, 0xe0, 0x10, 18, 1), ++ PIN_FIELD_BASE(81, 81, 1, 0xe0, 0x10, 19, 1), ++ PIN_FIELD_BASE(82, 82, 1, 0xe0, 0x10, 16, 1), ++ PIN_FIELD_BASE(83, 83, 1, 0xe0, 0x10, 17, 1), ++}; ++ ++static const struct mtk_pin_field_calc mt7988_pin_pu_range[] = { ++ PIN_FIELD_BASE(7, 7, 4, 0x60, 0x10, 5, 1), ++ PIN_FIELD_BASE(8, 8, 4, 0x60, 0x10, 4, 1), ++ PIN_FIELD_BASE(9, 9, 4, 0x60, 0x10, 3, 1), ++ PIN_FIELD_BASE(10, 10, 4, 0x60, 0x10, 2, 1), ++ ++ PIN_FIELD_BASE(13, 13, 1, 0x70, 0x10, 0, 1), ++ PIN_FIELD_BASE(14, 14, 1, 0x70, 0x10, 1, 1), ++ PIN_FIELD_BASE(63, 63, 1, 0x70, 0x10, 2, 1), ++ ++ PIN_FIELD_BASE(75, 75, 4, 0x60, 0x10, 7, 1), ++ PIN_FIELD_BASE(76, 76, 4, 0x60, 0x10, 6, 1), ++ PIN_FIELD_BASE(77, 77, 4, 0x60, 0x10, 1, 1), ++ PIN_FIELD_BASE(78, 78, 4, 0x60, 0x10, 0, 1), ++ PIN_FIELD_BASE(79, 79, 4, 0x60, 0x10, 8, 1), ++}; ++ ++static const struct mtk_pin_field_calc mt7988_pin_pd_range[] = { ++ PIN_FIELD_BASE(7, 7, 4, 0x40, 0x10, 5, 1), ++ PIN_FIELD_BASE(8, 8, 4, 0x40, 0x10, 4, 1), ++ PIN_FIELD_BASE(9, 9, 4, 0x40, 0x10, 3, 1), ++ PIN_FIELD_BASE(10, 10, 4, 0x40, 0x10, 2, 1), ++ ++ PIN_FIELD_BASE(13, 13, 1, 0x50, 0x10, 0, 1), ++ PIN_FIELD_BASE(14, 14, 1, 0x50, 0x10, 1, 1), ++ ++ PIN_FIELD_BASE(15, 15, 5, 0x40, 0x10, 4, 1), ++ PIN_FIELD_BASE(16, 16, 5, 0x40, 0x10, 5, 1), ++ PIN_FIELD_BASE(17, 17, 5, 0x40, 0x10, 0, 1), ++ PIN_FIELD_BASE(18, 18, 5, 0x40, 0x10, 1, 1), ++ ++ PIN_FIELD_BASE(63, 63, 1, 0x50, 0x10, 2, 1), ++ PIN_FIELD_BASE(71, 71, 5, 0x40, 0x10, 2, 1), ++ PIN_FIELD_BASE(72, 72, 5, 0x40, 0x10, 3, 1), ++ ++ PIN_FIELD_BASE(75, 75, 4, 0x40, 0x10, 7, 1), ++ PIN_FIELD_BASE(76, 76, 4, 0x40, 0x10, 6, 1), ++ PIN_FIELD_BASE(77, 77, 4, 0x40, 0x10, 1, 1), ++ PIN_FIELD_BASE(78, 78, 4, 0x40, 0x10, 0, 1), ++ PIN_FIELD_BASE(79, 79, 4, 0x40, 0x10, 8, 1), ++}; ++ ++static const struct mtk_pin_field_calc mt7988_pin_drv_range[] = { ++ PIN_FIELD_BASE(0, 0, 5, 0x00, 0x10, 21, 3), ++ PIN_FIELD_BASE(1, 1, 5, 0x00, 0x10, 24, 3), ++ PIN_FIELD_BASE(2, 2, 5, 0x00, 0x10, 15, 3), ++ PIN_FIELD_BASE(3, 3, 5, 0x00, 0x10, 18, 3), ++ PIN_FIELD_BASE(4, 4, 5, 0x00, 0x10, 0, 3), ++ PIN_FIELD_BASE(5, 5, 5, 0x00, 0x10, 9, 3), ++ PIN_FIELD_BASE(6, 6, 5, 0x00, 0x10, 12, 3), ++ ++ PIN_FIELD_BASE(7, 7, 4, 0x00, 0x10, 24, 3), ++ PIN_FIELD_BASE(8, 8, 4, 0x00, 0x10, 28, 3), ++ PIN_FIELD_BASE(9, 9, 4, 0x00, 0x10, 15, 3), ++ PIN_FIELD_BASE(10, 10, 4, 0x00, 0x10, 9, 3), ++ ++ PIN_FIELD_BASE(11, 11, 1, 0x00, 0x10, 0, 3), ++ PIN_FIELD_BASE(12, 12, 1, 0x20, 0x10, 3, 3), ++ PIN_FIELD_BASE(13, 13, 1, 0x00, 0x10, 3, 3), ++ PIN_FIELD_BASE(14, 14, 1, 0x00, 0x10, 6, 3), ++ ++ PIN_FIELD_BASE(19, 19, 4, 0x00, 0x10, 21, 3), ++ PIN_FIELD_BASE(20, 20, 4, 0x00, 0x10, 12, 3), ++ ++ PIN_FIELD_BASE(21, 21, 3, 0x10, 0x10, 21, 3), ++ PIN_FIELD_BASE(22, 22, 3, 0x20, 0x10, 9, 3), ++ PIN_FIELD_BASE(23, 23, 3, 0x20, 0x10, 0, 3), ++ PIN_FIELD_BASE(24, 24, 3, 0x10, 0x10, 27, 3), ++ PIN_FIELD_BASE(25, 25, 3, 0x20, 0x10, 3, 3), ++ PIN_FIELD_BASE(26, 26, 3, 0x20, 0x10, 6, 3), ++ PIN_FIELD_BASE(27, 27, 3, 0x10, 0x10, 24, 3), ++ PIN_FIELD_BASE(28, 28, 3, 0x20, 0x10, 15, 3), ++ PIN_FIELD_BASE(29, 29, 3, 0x20, 0x10, 18, 3), ++ PIN_FIELD_BASE(30, 30, 3, 0x20, 0x10, 21, 3), ++ PIN_FIELD_BASE(31, 31, 3, 0x20, 0x10, 12, 3), ++ PIN_FIELD_BASE(32, 32, 3, 0x20, 0x10, 24, 3), ++ PIN_FIELD_BASE(33, 33, 3, 0x30, 0x10, 6, 3), ++ PIN_FIELD_BASE(34, 34, 3, 0x30, 0x10, 3, 3), ++ PIN_FIELD_BASE(35, 35, 3, 0x20, 0x10, 27, 3), ++ PIN_FIELD_BASE(36, 36, 3, 0x30, 0x10, 0, 3), ++ PIN_FIELD_BASE(37, 37, 3, 0x30, 0x10, 9, 3), ++ PIN_FIELD_BASE(38, 38, 3, 0x10, 0x10, 3, 3), ++ PIN_FIELD_BASE(39, 39, 3, 0x10, 0x10, 0, 3), ++ PIN_FIELD_BASE(40, 40, 3, 0x00, 0x10, 0, 3), ++ PIN_FIELD_BASE(41, 41, 3, 0x00, 0x10, 3, 3), ++ PIN_FIELD_BASE(42, 42, 3, 0x00, 0x10, 27, 3), ++ PIN_FIELD_BASE(43, 43, 3, 0x00, 0x10, 24, 3), ++ PIN_FIELD_BASE(44, 44, 3, 0x00, 0x10, 21, 3), ++ PIN_FIELD_BASE(45, 45, 3, 0x00, 0x10, 18, 3), ++ PIN_FIELD_BASE(46, 46, 3, 0x00, 0x10, 15, 3), ++ PIN_FIELD_BASE(47, 47, 3, 0x00, 0x10, 12, 3), ++ PIN_FIELD_BASE(48, 48, 3, 0x00, 0x10, 9, 3), ++ PIN_FIELD_BASE(49, 49, 3, 0x00, 0x10, 6, 3), ++ PIN_FIELD_BASE(50, 50, 3, 0x10, 0x10, 15, 3), ++ PIN_FIELD_BASE(51, 51, 3, 0x10, 0x10, 6, 3), ++ PIN_FIELD_BASE(52, 52, 3, 0x10, 0x10, 9, 3), ++ PIN_FIELD_BASE(53, 53, 3, 0x10, 0x10, 12, 3), ++ PIN_FIELD_BASE(54, 54, 3, 0x10, 0x10, 18, 3), ++ ++ PIN_FIELD_BASE(55, 55, 1, 0x10, 0x10, 12, 3), ++ PIN_FIELD_BASE(56, 56, 1, 0x10, 0x10, 15, 3), ++ PIN_FIELD_BASE(57, 57, 1, 0x10, 0x10, 9, 3), ++ PIN_FIELD_BASE(58, 58, 1, 0x00, 0x10, 12, 3), ++ PIN_FIELD_BASE(59, 59, 1, 0x00, 0x10, 15, 3), ++ PIN_FIELD_BASE(60, 60, 1, 0x00, 0x10, 18, 3), ++ PIN_FIELD_BASE(61, 61, 1, 0x00, 0x10, 9, 3), ++ PIN_FIELD_BASE(62, 62, 1, 0x00, 0x10, 21, 3), ++ PIN_FIELD_BASE(63, 63, 1, 0x20, 0x10, 0, 3), ++ PIN_FIELD_BASE(64, 64, 1, 0x00, 0x10, 24, 3), ++ PIN_FIELD_BASE(65, 65, 1, 0x00, 0x10, 27, 3), ++ PIN_FIELD_BASE(66, 66, 1, 0x10, 0x10, 0, 3), ++ PIN_FIELD_BASE(67, 67, 1, 0x10, 0x10, 3, 3), ++ PIN_FIELD_BASE(68, 68, 1, 0x10, 0x10, 6, 3), ++ ++ PIN_FIELD_BASE(69, 69, 5, 0x00, 0x10, 3, 3), ++ PIN_FIELD_BASE(70, 70, 5, 0x00, 0x10, 6, 3), ++ ++ PIN_FIELD_BASE(73, 73, 4, 0x10, 0x10, 0, 3), ++ PIN_FIELD_BASE(74, 74, 4, 0x00, 0x10, 3, 3), ++ PIN_FIELD_BASE(75, 75, 4, 0x10, 0x10, 3, 3), ++ PIN_FIELD_BASE(76, 76, 4, 0x00, 0x10, 27, 3), ++ PIN_FIELD_BASE(77, 77, 4, 0x00, 0x10, 6, 3), ++ PIN_FIELD_BASE(78, 78, 4, 0x00, 0x10, 0, 3), ++ PIN_FIELD_BASE(79, 79, 4, 0x10, 0x10, 6, 3), ++ ++ PIN_FIELD_BASE(80, 80, 1, 0x10, 0x10, 24, 3), ++ PIN_FIELD_BASE(81, 81, 1, 0x10, 0x10, 27, 3), ++ PIN_FIELD_BASE(82, 82, 1, 0x10, 0x10, 18, 3), ++ PIN_FIELD_BASE(83, 83, 1, 0x10, 0x10, 21, 3), ++}; ++ ++static const struct mtk_pin_field_calc mt7988_pin_pupd_range[] = { ++ PIN_FIELD_BASE(0, 0, 5, 0x50, 0x10, 7, 1), ++ PIN_FIELD_BASE(1, 1, 5, 0x50, 0x10, 8, 1), ++ PIN_FIELD_BASE(2, 2, 5, 0x50, 0x10, 5, 1), ++ PIN_FIELD_BASE(3, 3, 5, 0x50, 0x10, 6, 1), ++ PIN_FIELD_BASE(4, 4, 5, 0x50, 0x10, 0, 1), ++ PIN_FIELD_BASE(5, 5, 5, 0x50, 0x10, 3, 1), ++ PIN_FIELD_BASE(6, 6, 5, 0x50, 0x10, 4, 1), ++ ++ PIN_FIELD_BASE(11, 11, 1, 0x60, 0x10, 0, 1), ++ PIN_FIELD_BASE(12, 12, 1, 0x60, 0x10, 18, 1), ++ ++ PIN_FIELD_BASE(19, 19, 4, 0x50, 0x10, 2, 1), ++ PIN_FIELD_BASE(20, 20, 4, 0x50, 0x10, 1, 1), ++ ++ PIN_FIELD_BASE(21, 21, 3, 0x70, 0x10, 17, 1), ++ PIN_FIELD_BASE(22, 22, 3, 0x70, 0x10, 23, 1), ++ PIN_FIELD_BASE(23, 23, 3, 0x70, 0x10, 20, 1), ++ PIN_FIELD_BASE(24, 24, 3, 0x70, 0x10, 19, 1), ++ PIN_FIELD_BASE(25, 25, 3, 0x70, 0x10, 21, 1), ++ PIN_FIELD_BASE(26, 26, 3, 0x70, 0x10, 22, 1), ++ PIN_FIELD_BASE(27, 27, 3, 0x70, 0x10, 18, 1), ++ PIN_FIELD_BASE(28, 28, 3, 0x70, 0x10, 25, 1), ++ PIN_FIELD_BASE(29, 29, 3, 0x70, 0x10, 26, 1), ++ PIN_FIELD_BASE(30, 30, 3, 0x70, 0x10, 27, 1), ++ PIN_FIELD_BASE(31, 31, 3, 0x70, 0x10, 24, 1), ++ PIN_FIELD_BASE(32, 32, 3, 0x70, 0x10, 28, 1), ++ PIN_FIELD_BASE(33, 33, 3, 0x80, 0x10, 0, 1), ++ PIN_FIELD_BASE(34, 34, 3, 0x70, 0x10, 31, 1), ++ PIN_FIELD_BASE(35, 35, 3, 0x70, 0x10, 29, 1), ++ PIN_FIELD_BASE(36, 36, 3, 0x70, 0x10, 30, 1), ++ PIN_FIELD_BASE(37, 37, 3, 0x80, 0x10, 1, 1), ++ PIN_FIELD_BASE(38, 38, 3, 0x70, 0x10, 11, 1), ++ PIN_FIELD_BASE(39, 39, 3, 0x70, 0x10, 10, 1), ++ PIN_FIELD_BASE(40, 40, 3, 0x70, 0x10, 0, 1), ++ PIN_FIELD_BASE(41, 41, 3, 0x70, 0x10, 1, 1), ++ PIN_FIELD_BASE(42, 42, 3, 0x70, 0x10, 9, 1), ++ PIN_FIELD_BASE(43, 43, 3, 0x70, 0x10, 8, 1), ++ PIN_FIELD_BASE(44, 44, 3, 0x70, 0x10, 7, 1), ++ PIN_FIELD_BASE(45, 45, 3, 0x70, 0x10, 6, 1), ++ PIN_FIELD_BASE(46, 46, 3, 0x70, 0x10, 5, 1), ++ PIN_FIELD_BASE(47, 47, 3, 0x70, 0x10, 4, 1), ++ PIN_FIELD_BASE(48, 48, 3, 0x70, 0x10, 3, 1), ++ PIN_FIELD_BASE(49, 49, 3, 0x70, 0x10, 2, 1), ++ PIN_FIELD_BASE(50, 50, 3, 0x70, 0x10, 15, 1), ++ PIN_FIELD_BASE(51, 51, 3, 0x70, 0x10, 12, 1), ++ PIN_FIELD_BASE(52, 52, 3, 0x70, 0x10, 13, 1), ++ PIN_FIELD_BASE(53, 53, 3, 0x70, 0x10, 14, 1), ++ PIN_FIELD_BASE(54, 54, 3, 0x70, 0x10, 16, 1), ++ ++ PIN_FIELD_BASE(55, 55, 1, 0x60, 0x10, 12, 1), ++ PIN_FIELD_BASE(56, 56, 1, 0x60, 0x10, 13, 1), ++ PIN_FIELD_BASE(57, 57, 1, 0x60, 0x10, 11, 1), ++ PIN_FIELD_BASE(58, 58, 1, 0x60, 0x10, 2, 1), ++ PIN_FIELD_BASE(59, 59, 1, 0x60, 0x10, 3, 1), ++ PIN_FIELD_BASE(60, 60, 1, 0x60, 0x10, 4, 1), ++ PIN_FIELD_BASE(61, 61, 1, 0x60, 0x10, 1, 1), ++ PIN_FIELD_BASE(62, 62, 1, 0x60, 0x10, 5, 1), ++ PIN_FIELD_BASE(64, 64, 1, 0x60, 0x10, 6, 1), ++ PIN_FIELD_BASE(65, 65, 1, 0x60, 0x10, 7, 1), ++ PIN_FIELD_BASE(66, 66, 1, 0x60, 0x10, 8, 1), ++ PIN_FIELD_BASE(67, 67, 1, 0x60, 0x10, 9, 1), ++ PIN_FIELD_BASE(68, 68, 1, 0x60, 0x10, 10, 1), ++ ++ PIN_FIELD_BASE(69, 69, 5, 0x50, 0x10, 1, 1), ++ PIN_FIELD_BASE(70, 70, 5, 0x50, 0x10, 2, 1), ++ ++ PIN_FIELD_BASE(73, 73, 4, 0x50, 0x10, 3, 1), ++ PIN_FIELD_BASE(74, 74, 4, 0x50, 0x10, 0, 1), ++ ++ PIN_FIELD_BASE(80, 80, 1, 0x60, 0x10, 16, 1), ++ PIN_FIELD_BASE(81, 81, 1, 0x60, 0x10, 17, 1), ++ PIN_FIELD_BASE(82, 82, 1, 0x60, 0x10, 14, 1), ++ PIN_FIELD_BASE(83, 83, 1, 0x60, 0x10, 15, 1), ++}; ++ ++static const struct mtk_pin_field_calc mt7988_pin_r0_range[] = { ++ PIN_FIELD_BASE(0, 0, 5, 0x60, 0x10, 7, 1), ++ PIN_FIELD_BASE(1, 1, 5, 0x60, 0x10, 8, 1), ++ PIN_FIELD_BASE(2, 2, 5, 0x60, 0x10, 5, 1), ++ PIN_FIELD_BASE(3, 3, 5, 0x60, 0x10, 6, 1), ++ PIN_FIELD_BASE(4, 4, 5, 0x60, 0x10, 0, 1), ++ PIN_FIELD_BASE(5, 5, 5, 0x60, 0x10, 3, 1), ++ PIN_FIELD_BASE(6, 6, 5, 0x60, 0x10, 4, 1), ++ ++ PIN_FIELD_BASE(11, 11, 1, 0x80, 0x10, 0, 1), ++ PIN_FIELD_BASE(12, 12, 1, 0x80, 0x10, 18, 1), ++ ++ PIN_FIELD_BASE(19, 19, 4, 0x70, 0x10, 2, 1), ++ PIN_FIELD_BASE(20, 20, 4, 0x70, 0x10, 1, 1), ++ ++ PIN_FIELD_BASE(21, 21, 3, 0x90, 0x10, 17, 1), ++ PIN_FIELD_BASE(22, 22, 3, 0x90, 0x10, 23, 1), ++ PIN_FIELD_BASE(23, 23, 3, 0x90, 0x10, 20, 1), ++ PIN_FIELD_BASE(24, 24, 3, 0x90, 0x10, 19, 1), ++ PIN_FIELD_BASE(25, 25, 3, 0x90, 0x10, 21, 1), ++ PIN_FIELD_BASE(26, 26, 3, 0x90, 0x10, 22, 1), ++ PIN_FIELD_BASE(27, 27, 3, 0x90, 0x10, 18, 1), ++ PIN_FIELD_BASE(28, 28, 3, 0x90, 0x10, 25, 1), ++ PIN_FIELD_BASE(29, 29, 3, 0x90, 0x10, 26, 1), ++ PIN_FIELD_BASE(30, 30, 3, 0x90, 0x10, 27, 1), ++ PIN_FIELD_BASE(31, 31, 3, 0x90, 0x10, 24, 1), ++ PIN_FIELD_BASE(32, 32, 3, 0x90, 0x10, 28, 1), ++ PIN_FIELD_BASE(33, 33, 3, 0xa0, 0x10, 0, 1), ++ PIN_FIELD_BASE(34, 34, 3, 0x90, 0x10, 31, 1), ++ PIN_FIELD_BASE(35, 35, 3, 0x90, 0x10, 29, 1), ++ PIN_FIELD_BASE(36, 36, 3, 0x90, 0x10, 30, 1), ++ PIN_FIELD_BASE(37, 37, 3, 0xa0, 0x10, 1, 1), ++ PIN_FIELD_BASE(38, 38, 3, 0x90, 0x10, 11, 1), ++ PIN_FIELD_BASE(39, 39, 3, 0x90, 0x10, 10, 1), ++ PIN_FIELD_BASE(40, 40, 3, 0x90, 0x10, 0, 1), ++ PIN_FIELD_BASE(41, 41, 3, 0x90, 0x10, 1, 1), ++ PIN_FIELD_BASE(42, 42, 3, 0x90, 0x10, 9, 1), ++ PIN_FIELD_BASE(43, 43, 3, 0x90, 0x10, 8, 1), ++ PIN_FIELD_BASE(44, 44, 3, 0x90, 0x10, 7, 1), ++ PIN_FIELD_BASE(45, 45, 3, 0x90, 0x10, 6, 1), ++ PIN_FIELD_BASE(46, 46, 3, 0x90, 0x10, 5, 1), ++ PIN_FIELD_BASE(47, 47, 3, 0x90, 0x10, 4, 1), ++ PIN_FIELD_BASE(48, 48, 3, 0x90, 0x10, 3, 1), ++ PIN_FIELD_BASE(49, 49, 3, 0x90, 0x10, 2, 1), ++ PIN_FIELD_BASE(50, 50, 3, 0x90, 0x10, 15, 1), ++ PIN_FIELD_BASE(51, 51, 3, 0x90, 0x10, 12, 1), ++ PIN_FIELD_BASE(52, 52, 3, 0x90, 0x10, 13, 1), ++ PIN_FIELD_BASE(53, 53, 3, 0x90, 0x10, 14, 1), ++ PIN_FIELD_BASE(54, 54, 3, 0x90, 0x10, 16, 1), ++ ++ PIN_FIELD_BASE(55, 55, 1, 0x80, 0x10, 12, 1), ++ PIN_FIELD_BASE(56, 56, 1, 0x80, 0x10, 13, 1), ++ PIN_FIELD_BASE(57, 57, 1, 0x80, 0x10, 11, 1), ++ PIN_FIELD_BASE(58, 58, 1, 0x80, 0x10, 2, 1), ++ PIN_FIELD_BASE(59, 59, 1, 0x80, 0x10, 3, 1), ++ PIN_FIELD_BASE(60, 60, 1, 0x80, 0x10, 4, 1), ++ PIN_FIELD_BASE(61, 61, 1, 0x80, 0x10, 1, 1), ++ PIN_FIELD_BASE(62, 62, 1, 0x80, 0x10, 5, 1), ++ PIN_FIELD_BASE(64, 64, 1, 0x80, 0x10, 6, 1), ++ PIN_FIELD_BASE(65, 65, 1, 0x80, 0x10, 7, 1), ++ PIN_FIELD_BASE(66, 66, 1, 0x80, 0x10, 8, 1), ++ PIN_FIELD_BASE(67, 67, 1, 0x80, 0x10, 9, 1), ++ PIN_FIELD_BASE(68, 68, 1, 0x80, 0x10, 10, 1), ++ ++ PIN_FIELD_BASE(69, 69, 5, 0x60, 0x10, 1, 1), ++ PIN_FIELD_BASE(70, 70, 5, 0x60, 0x10, 2, 1), ++ ++ PIN_FIELD_BASE(73, 73, 4, 0x70, 0x10, 3, 1), ++ PIN_FIELD_BASE(74, 74, 4, 0x70, 0x10, 0, 1), ++ ++ PIN_FIELD_BASE(80, 80, 1, 0x80, 0x10, 16, 1), ++ PIN_FIELD_BASE(81, 81, 1, 0x80, 0x10, 17, 1), ++ PIN_FIELD_BASE(82, 82, 1, 0x80, 0x10, 14, 1), ++ PIN_FIELD_BASE(83, 83, 1, 0x80, 0x10, 15, 1), ++}; ++ ++static const struct mtk_pin_field_calc mt7988_pin_r1_range[] = { ++ PIN_FIELD_BASE(0, 0, 5, 0x70, 0x10, 7, 1), ++ PIN_FIELD_BASE(1, 1, 5, 0x70, 0x10, 8, 1), ++ PIN_FIELD_BASE(2, 2, 5, 0x70, 0x10, 5, 1), ++ PIN_FIELD_BASE(3, 3, 5, 0x70, 0x10, 6, 1), ++ PIN_FIELD_BASE(4, 4, 5, 0x70, 0x10, 0, 1), ++ PIN_FIELD_BASE(5, 5, 5, 0x70, 0x10, 3, 1), ++ PIN_FIELD_BASE(6, 6, 5, 0x70, 0x10, 4, 1), ++ ++ PIN_FIELD_BASE(11, 11, 1, 0x90, 0x10, 0, 1), ++ PIN_FIELD_BASE(12, 12, 1, 0x90, 0x10, 18, 1), ++ ++ PIN_FIELD_BASE(19, 19, 4, 0x80, 0x10, 2, 1), ++ PIN_FIELD_BASE(20, 20, 4, 0x80, 0x10, 1, 1), ++ ++ PIN_FIELD_BASE(21, 21, 3, 0xb0, 0x10, 17, 1), ++ PIN_FIELD_BASE(22, 22, 3, 0xb0, 0x10, 23, 1), ++ PIN_FIELD_BASE(23, 23, 3, 0xb0, 0x10, 20, 1), ++ PIN_FIELD_BASE(24, 24, 3, 0xb0, 0x10, 19, 1), ++ PIN_FIELD_BASE(25, 25, 3, 0xb0, 0x10, 21, 1), ++ PIN_FIELD_BASE(26, 26, 3, 0xb0, 0x10, 22, 1), ++ PIN_FIELD_BASE(27, 27, 3, 0xb0, 0x10, 18, 1), ++ PIN_FIELD_BASE(28, 28, 3, 0xb0, 0x10, 25, 1), ++ PIN_FIELD_BASE(29, 29, 3, 0xb0, 0x10, 26, 1), ++ PIN_FIELD_BASE(30, 30, 3, 0xb0, 0x10, 27, 1), ++ PIN_FIELD_BASE(31, 31, 3, 0xb0, 0x10, 24, 1), ++ PIN_FIELD_BASE(32, 32, 3, 0xb0, 0x10, 28, 1), ++ PIN_FIELD_BASE(33, 33, 3, 0xc0, 0x10, 0, 1), ++ PIN_FIELD_BASE(34, 34, 3, 0xb0, 0x10, 31, 1), ++ PIN_FIELD_BASE(35, 35, 3, 0xb0, 0x10, 29, 1), ++ PIN_FIELD_BASE(36, 36, 3, 0xb0, 0x10, 30, 1), ++ PIN_FIELD_BASE(37, 37, 3, 0xc0, 0x10, 1, 1), ++ PIN_FIELD_BASE(38, 38, 3, 0xb0, 0x10, 11, 1), ++ PIN_FIELD_BASE(39, 39, 3, 0xb0, 0x10, 10, 1), ++ PIN_FIELD_BASE(40, 40, 3, 0xb0, 0x10, 0, 1), ++ PIN_FIELD_BASE(41, 41, 3, 0xb0, 0x10, 1, 1), ++ PIN_FIELD_BASE(42, 42, 3, 0xb0, 0x10, 9, 1), ++ PIN_FIELD_BASE(43, 43, 3, 0xb0, 0x10, 8, 1), ++ PIN_FIELD_BASE(44, 44, 3, 0xb0, 0x10, 7, 1), ++ PIN_FIELD_BASE(45, 45, 3, 0xb0, 0x10, 6, 1), ++ PIN_FIELD_BASE(46, 46, 3, 0xb0, 0x10, 5, 1), ++ PIN_FIELD_BASE(47, 47, 3, 0xb0, 0x10, 4, 1), ++ PIN_FIELD_BASE(48, 48, 3, 0xb0, 0x10, 3, 1), ++ PIN_FIELD_BASE(49, 49, 3, 0xb0, 0x10, 2, 1), ++ PIN_FIELD_BASE(50, 50, 3, 0xb0, 0x10, 15, 1), ++ PIN_FIELD_BASE(51, 51, 3, 0xb0, 0x10, 12, 1), ++ PIN_FIELD_BASE(52, 52, 3, 0xb0, 0x10, 13, 1), ++ PIN_FIELD_BASE(53, 53, 3, 0xb0, 0x10, 14, 1), ++ PIN_FIELD_BASE(54, 54, 3, 0xb0, 0x10, 16, 1), ++ ++ PIN_FIELD_BASE(55, 55, 1, 0x90, 0x10, 12, 1), ++ PIN_FIELD_BASE(56, 56, 1, 0x90, 0x10, 13, 1), ++ PIN_FIELD_BASE(57, 57, 1, 0x90, 0x10, 11, 1), ++ PIN_FIELD_BASE(58, 58, 1, 0x90, 0x10, 2, 1), ++ PIN_FIELD_BASE(59, 59, 1, 0x90, 0x10, 3, 1), ++ PIN_FIELD_BASE(60, 60, 1, 0x90, 0x10, 4, 1), ++ PIN_FIELD_BASE(61, 61, 1, 0x90, 0x10, 1, 1), ++ PIN_FIELD_BASE(62, 62, 1, 0x90, 0x10, 5, 1), ++ PIN_FIELD_BASE(64, 64, 1, 0x90, 0x10, 6, 1), ++ PIN_FIELD_BASE(65, 65, 1, 0x90, 0x10, 7, 1), ++ PIN_FIELD_BASE(66, 66, 1, 0x90, 0x10, 8, 1), ++ PIN_FIELD_BASE(67, 67, 1, 0x90, 0x10, 9, 1), ++ PIN_FIELD_BASE(68, 68, 1, 0x90, 0x10, 10, 1), ++ ++ PIN_FIELD_BASE(69, 69, 5, 0x70, 0x10, 1, 1), ++ PIN_FIELD_BASE(70, 70, 5, 0x70, 0x10, 2, 1), ++ ++ PIN_FIELD_BASE(73, 73, 4, 0x80, 0x10, 3, 1), ++ PIN_FIELD_BASE(74, 74, 4, 0x80, 0x10, 0, 1), ++ ++ PIN_FIELD_BASE(80, 80, 1, 0x90, 0x10, 16, 1), ++ PIN_FIELD_BASE(81, 81, 1, 0x90, 0x10, 17, 1), ++ PIN_FIELD_BASE(82, 82, 1, 0x90, 0x10, 14, 1), ++ PIN_FIELD_BASE(83, 83, 1, 0x90, 0x10, 15, 1), ++}; ++ ++static const unsigned int mt7988_pull_type[] = { ++ MTK_PULL_PUPD_R1R0_TYPE,/*0*/ MTK_PULL_PUPD_R1R0_TYPE,/*1*/ ++ MTK_PULL_PUPD_R1R0_TYPE,/*2*/ MTK_PULL_PUPD_R1R0_TYPE,/*3*/ ++ MTK_PULL_PUPD_R1R0_TYPE,/*4*/ MTK_PULL_PUPD_R1R0_TYPE,/*5*/ ++ MTK_PULL_PUPD_R1R0_TYPE,/*6*/ MTK_PULL_PU_PD_TYPE, /*7*/ ++ MTK_PULL_PU_PD_TYPE, /*8*/ MTK_PULL_PU_PD_TYPE, /*9*/ ++ MTK_PULL_PU_PD_TYPE, /*10*/ MTK_PULL_PUPD_R1R0_TYPE,/*11*/ ++ MTK_PULL_PUPD_R1R0_TYPE,/*12*/ MTK_PULL_PU_PD_TYPE, /*13*/ ++ MTK_PULL_PU_PD_TYPE, /*14*/ MTK_PULL_PD_TYPE, /*15*/ ++ MTK_PULL_PD_TYPE, /*16*/ MTK_PULL_PD_TYPE, /*17*/ ++ MTK_PULL_PD_TYPE, /*18*/ MTK_PULL_PUPD_R1R0_TYPE,/*19*/ ++ MTK_PULL_PUPD_R1R0_TYPE,/*20*/ MTK_PULL_PUPD_R1R0_TYPE,/*21*/ ++ MTK_PULL_PUPD_R1R0_TYPE,/*22*/ MTK_PULL_PUPD_R1R0_TYPE,/*23*/ ++ MTK_PULL_PUPD_R1R0_TYPE,/*24*/ MTK_PULL_PUPD_R1R0_TYPE,/*25*/ ++ MTK_PULL_PUPD_R1R0_TYPE,/*26*/ MTK_PULL_PUPD_R1R0_TYPE,/*27*/ ++ MTK_PULL_PUPD_R1R0_TYPE,/*28*/ MTK_PULL_PUPD_R1R0_TYPE,/*29*/ ++ MTK_PULL_PUPD_R1R0_TYPE,/*30*/ MTK_PULL_PUPD_R1R0_TYPE,/*31*/ ++ MTK_PULL_PUPD_R1R0_TYPE,/*32*/ MTK_PULL_PUPD_R1R0_TYPE,/*33*/ ++ MTK_PULL_PUPD_R1R0_TYPE,/*34*/ MTK_PULL_PUPD_R1R0_TYPE,/*35*/ ++ MTK_PULL_PUPD_R1R0_TYPE,/*36*/ MTK_PULL_PUPD_R1R0_TYPE,/*37*/ ++ MTK_PULL_PUPD_R1R0_TYPE,/*38*/ MTK_PULL_PUPD_R1R0_TYPE,/*39*/ ++ MTK_PULL_PUPD_R1R0_TYPE,/*40*/ MTK_PULL_PUPD_R1R0_TYPE,/*41*/ ++ MTK_PULL_PUPD_R1R0_TYPE,/*42*/ MTK_PULL_PUPD_R1R0_TYPE,/*43*/ ++ MTK_PULL_PUPD_R1R0_TYPE,/*44*/ MTK_PULL_PUPD_R1R0_TYPE,/*45*/ ++ MTK_PULL_PUPD_R1R0_TYPE,/*46*/ MTK_PULL_PUPD_R1R0_TYPE,/*47*/ ++ MTK_PULL_PUPD_R1R0_TYPE,/*48*/ MTK_PULL_PUPD_R1R0_TYPE,/*49*/ ++ MTK_PULL_PUPD_R1R0_TYPE,/*50*/ MTK_PULL_PUPD_R1R0_TYPE,/*51*/ ++ MTK_PULL_PUPD_R1R0_TYPE,/*52*/ MTK_PULL_PUPD_R1R0_TYPE,/*53*/ ++ MTK_PULL_PUPD_R1R0_TYPE,/*54*/ MTK_PULL_PUPD_R1R0_TYPE,/*55*/ ++ MTK_PULL_PUPD_R1R0_TYPE,/*56*/ MTK_PULL_PUPD_R1R0_TYPE,/*57*/ ++ MTK_PULL_PUPD_R1R0_TYPE,/*58*/ MTK_PULL_PUPD_R1R0_TYPE,/*59*/ ++ MTK_PULL_PUPD_R1R0_TYPE,/*60*/ MTK_PULL_PUPD_R1R0_TYPE,/*61*/ ++ MTK_PULL_PUPD_R1R0_TYPE,/*62*/ MTK_PULL_PU_PD_TYPE, /*63*/ ++ MTK_PULL_PUPD_R1R0_TYPE,/*64*/ MTK_PULL_PUPD_R1R0_TYPE,/*65*/ ++ MTK_PULL_PUPD_R1R0_TYPE,/*66*/ MTK_PULL_PUPD_R1R0_TYPE,/*67*/ ++ MTK_PULL_PUPD_R1R0_TYPE,/*68*/ MTK_PULL_PUPD_R1R0_TYPE,/*69*/ ++ MTK_PULL_PUPD_R1R0_TYPE,/*70*/ MTK_PULL_PD_TYPE, /*71*/ ++ MTK_PULL_PD_TYPE, /*72*/ MTK_PULL_PUPD_R1R0_TYPE,/*73*/ ++ MTK_PULL_PUPD_R1R0_TYPE,/*74*/ MTK_PULL_PU_PD_TYPE, /*75*/ ++ MTK_PULL_PU_PD_TYPE, /*76*/ MTK_PULL_PU_PD_TYPE, /*77*/ ++ MTK_PULL_PU_PD_TYPE, /*78*/ MTK_PULL_PU_PD_TYPE, /*79*/ ++ MTK_PULL_PUPD_R1R0_TYPE,/*80*/ MTK_PULL_PUPD_R1R0_TYPE,/*81*/ ++ MTK_PULL_PUPD_R1R0_TYPE,/*82*/ MTK_PULL_PUPD_R1R0_TYPE,/*83*/ ++}; ++ ++static const struct mtk_pin_reg_calc mt7988_reg_cals[] = { ++ [PINCTRL_PIN_REG_MODE] = MTK_RANGE(mt7988_pin_mode_range), ++ [PINCTRL_PIN_REG_DIR] = MTK_RANGE(mt7988_pin_dir_range), ++ [PINCTRL_PIN_REG_DI] = MTK_RANGE(mt7988_pin_di_range), ++ [PINCTRL_PIN_REG_DO] = MTK_RANGE(mt7988_pin_do_range), ++ [PINCTRL_PIN_REG_SMT] = MTK_RANGE(mt7988_pin_smt_range), ++ [PINCTRL_PIN_REG_IES] = MTK_RANGE(mt7988_pin_ies_range), ++ [PINCTRL_PIN_REG_PU] = MTK_RANGE(mt7988_pin_pu_range), ++ [PINCTRL_PIN_REG_PD] = MTK_RANGE(mt7988_pin_pd_range), ++ [PINCTRL_PIN_REG_DRV] = MTK_RANGE(mt7988_pin_drv_range), ++ [PINCTRL_PIN_REG_PUPD] = MTK_RANGE(mt7988_pin_pupd_range), ++ [PINCTRL_PIN_REG_R0] = MTK_RANGE(mt7988_pin_r0_range), ++ [PINCTRL_PIN_REG_R1] = MTK_RANGE(mt7988_pin_r1_range), ++}; ++ ++static const struct mtk_pin_desc mt7988_pins[] = { ++ MT7988_PIN(0, "UART2_RXD"), ++ MT7988_PIN(1, "UART2_TXD"), ++ MT7988_PIN(2, "UART2_CTS"), ++ MT7988_PIN(3, "UART2_RTS"), ++ MT7988_PIN(4, "GPIO_A"), ++ MT7988_PIN(5, "SMI_0_MDC"), ++ MT7988_PIN(6, "SMI_0_MDIO"), ++ MT7988_PIN(7, "PCIE30_2L_0_WAKE_N"), ++ MT7988_PIN(8, "PCIE30_2L_0_CLKREQ_N"), ++ MT7988_PIN(9, "PCIE30_1L_1_WAKE_N"), ++ MT7988_PIN(10, "PCIE30_1L_1_CLKREQ_N"), ++ MT7988_PIN(11, "GPIO_P"), ++ MT7988_PIN(12, "WATCHDOG"), ++ MT7988_PIN(13, "GPIO_RESET"), ++ MT7988_PIN(14, "GPIO_WPS"), ++ MT7988_PIN(15, "PMIC_I2C_SCL"), ++ MT7988_PIN(16, "PMIC_I2C_SDA"), ++ MT7988_PIN(17, "I2C_1_SCL"), ++ MT7988_PIN(18, "I2C_1_SDA"), ++ MT7988_PIN(19, "PCIE30_2L_0_PRESET_N"), ++ MT7988_PIN(20, "PCIE30_1L_1_PRESET_N"), ++ MT7988_PIN(21, "PWMD1"), ++ MT7988_PIN(22, "SPI0_WP"), ++ MT7988_PIN(23, "SPI0_HOLD"), ++ MT7988_PIN(24, "SPI0_CSB"), ++ MT7988_PIN(25, "SPI0_MISO"), ++ MT7988_PIN(26, "SPI0_MOSI"), ++ MT7988_PIN(27, "SPI0_CLK"), ++ MT7988_PIN(28, "SPI1_CSB"), ++ MT7988_PIN(29, "SPI1_MISO"), ++ MT7988_PIN(30, "SPI1_MOSI"), ++ MT7988_PIN(31, "SPI1_CLK"), ++ MT7988_PIN(32, "SPI2_CLK"), ++ MT7988_PIN(33, "SPI2_MOSI"), ++ MT7988_PIN(34, "SPI2_MISO"), ++ MT7988_PIN(35, "SPI2_CSB"), ++ MT7988_PIN(36, "SPI2_HOLD"), ++ MT7988_PIN(37, "SPI2_WP"), ++ MT7988_PIN(38, "EMMC_RSTB"), ++ MT7988_PIN(39, "EMMC_DSL"), ++ MT7988_PIN(40, "EMMC_CK"), ++ MT7988_PIN(41, "EMMC_CMD"), ++ MT7988_PIN(42, "EMMC_DATA_7"), ++ MT7988_PIN(43, "EMMC_DATA_6"), ++ MT7988_PIN(44, "EMMC_DATA_5"), ++ MT7988_PIN(45, "EMMC_DATA_4"), ++ MT7988_PIN(46, "EMMC_DATA_3"), ++ MT7988_PIN(47, "EMMC_DATA_2"), ++ MT7988_PIN(48, "EMMC_DATA_1"), ++ MT7988_PIN(49, "EMMC_DATA_0"), ++ MT7988_PIN(50, "PCM_FS_I2S_LRCK"), ++ MT7988_PIN(51, "PCM_CLK_I2S_BCLK"), ++ MT7988_PIN(52, "PCM_DRX_I2S_DIN"), ++ MT7988_PIN(53, "PCM_DTX_I2S_DOUT"), ++ MT7988_PIN(54, "PCM_MCK_I2S_MCLK"), ++ MT7988_PIN(55, "UART0_RXD"), ++ MT7988_PIN(56, "UART0_TXD"), ++ MT7988_PIN(57, "PWMD0"), ++ MT7988_PIN(58, "JTAG_JTDI"), ++ MT7988_PIN(59, "JTAG_JTDO"), ++ MT7988_PIN(60, "JTAG_JTMS"), ++ MT7988_PIN(61, "JTAG_JTCLK"), ++ MT7988_PIN(62, "JTAG_JTRST_N"), ++ MT7988_PIN(63, "USB_DRV_VBUS_P1"), ++ MT7988_PIN(64, "LED_A"), ++ MT7988_PIN(65, "LED_B"), ++ MT7988_PIN(66, "LED_C"), ++ MT7988_PIN(67, "LED_D"), ++ MT7988_PIN(68, "LED_E"), ++ MT7988_PIN(69, "GPIO_B"), ++ MT7988_PIN(70, "GPIO_C"), ++ MT7988_PIN(71, "I2C_2_SCL"), ++ MT7988_PIN(72, "I2C_2_SDA"), ++ MT7988_PIN(73, "PCIE30_2L_1_PRESET_N"), ++ MT7988_PIN(74, "PCIE30_1L_0_PRESET_N"), ++ MT7988_PIN(75, "PCIE30_2L_1_WAKE_N"), ++ MT7988_PIN(76, "PCIE30_2L_1_CLKREQ_N"), ++ MT7988_PIN(77, "PCIE30_1L_0_WAKE_N"), ++ MT7988_PIN(78, "PCIE30_1L_0_CLKREQ_N"), ++ MT7988_PIN(79, "USB_DRV_VBUS_P0"), ++ MT7988_PIN(80, "UART1_RXD"), ++ MT7988_PIN(81, "UART1_TXD"), ++ MT7988_PIN(82, "UART1_CTS"), ++ MT7988_PIN(83, "UART1_RTS"), ++}; ++ ++/* jtag */ ++static const int mt7988_tops_jtag0_0_pins[] = { 0, 1, 2, 3, 4 }; ++static int mt7988_tops_jtag0_0_funcs[] = { 2, 2, 2, 2, 2 }; ++ ++static const int mt7988_wo0_jtag_pins[] = { 50, 51, 52, 53, 54 }; ++static int mt7988_wo0_jtag_funcs[] = { 3, 3, 3, 3, 3 }; ++ ++static const int mt7988_wo1_jtag_pins[] = { 50, 51, 52, 53, 54 }; ++static int mt7988_wo1_jtag_funcs[] = { 4, 4, 4, 4, 4 }; ++ ++static const int mt7988_wo2_jtag_pins[] = { 50, 51, 52, 53, 54 }; ++static int mt7988_wo2_jtag_funcs[] = { 5, 5, 5, 5, 5 }; ++ ++static const int mt7988_jtag_pins[] = { 58, 59, 60, 61, 62 }; ++static int mt7988_jtag_funcs[] = { 1, 1, 1, 1, 1 }; ++ ++static const int mt7988_tops_jtag0_1_pins[] = { 58, 59, 60, 61, 62 }; ++static int mt7988_tops_jtag0_1_funcs[] = { 4, 4, 4, 4, 4 }; ++ ++/* int_usxgmii */ ++static const int mt7988_int_usxgmii_pins[] = { 2, 3 }; ++static int mt7988_int_usxgmii_funcs[] = { 3, 3 }; ++ ++/* pwm */ ++static const int mt7988_pwm0_pins[] = { 57 }; ++static int mt7988_pwm0_funcs[] = { 1 }; ++ ++static const int mt7988_pwm1_pins[] = { 21 }; ++static int mt7988_pwm1_funcs[] = { 1 }; ++ ++static const int mt7988_pwm2_pins[] = { 80 }; ++static int mt7988_pwm2_funcs[] = { 2 }; ++ ++static const int mt7988_pwm2_0_pins[] = { 58 }; ++static int mt7988_pwm2_0_funcs[] = { 5 }; ++ ++static const int mt7988_pwm3_pins[] = { 81 }; ++static int mt7988_pwm3_funcs[] = { 2 }; ++ ++static const int mt7988_pwm3_0_pins[] = { 59 }; ++static int mt7988_pwm3_0_funcs[] = { 5 }; ++ ++static const int mt7988_pwm4_pins[] = { 82 }; ++static int mt7988_pwm4_funcs[] = { 2 }; ++ ++static const int mt7988_pwm4_0_pins[] = { 60 }; ++static int mt7988_pwm4_0_funcs[] = { 5 }; ++ ++static const int mt7988_pwm5_pins[] = { 83 }; ++static int mt7988_pwm5_funcs[] = { 2 }; ++ ++static const int mt7988_pwm5_0_pins[] = { 61 }; ++static int mt7988_pwm5_0_funcs[] = { 5 }; ++ ++static const int mt7988_pwm6_pins[] = { 69 }; ++static int mt7988_pwm6_funcs[] = { 3 }; ++ ++static const int mt7988_pwm6_0_pins[] = { 62 }; ++static int mt7988_pwm6_0_funcs[] = { 5 }; ++ ++static const int mt7988_pwm7_pins[] = { 70 }; ++static int mt7988_pwm7_funcs[] = { 3 }; ++ ++static const int mt7988_pwm7_0_pins[] = { 4 }; ++static int mt7988_pwm7_0_funcs[] = { 3 }; ++ ++/* dfd */ ++static const int mt7988_dfd_pins[] = { 0, 1, 2, 3, 4 }; ++static int mt7988_dfd_funcs[] = { 4, 4, 4, 4, 4 }; ++ ++/* i2c */ ++static const int mt7988_xfi_phy0_i2c0_pins[] = { 0, 1 }; ++static int mt7988_xfi_phy0_i2c0_funcs[] = { 5, 5 }; ++ ++static const int mt7988_xfi_phy1_i2c0_pins[] = { 0, 1 }; ++static int mt7988_xfi_phy1_i2c0_funcs[] = { 6, 6 }; ++ ++static const int mt7988_xfi_phy_pll_i2c0_pins[] = { 3, 4 }; ++static int mt7988_xfi_phy_pll_i2c0_funcs[] = { 5, 5 }; ++ ++static const int mt7988_xfi_phy_pll_i2c1_pins[] = { 3, 4 }; ++static int mt7988_xfi_phy_pll_i2c1_funcs[] = { 6, 6 }; ++ ++static const int mt7988_i2c0_0_pins[] = { 5, 6 }; ++static int mt7988_i2c0_0_funcs[] = { 2, 2 }; ++ ++static const int mt7988_i2c1_sfp_pins[] = { 5, 6 }; ++static int mt7988_i2c1_sfp_funcs[] = { 4, 4 }; ++ ++static const int mt7988_xfi_pextp_phy0_i2c_pins[] = { 5, 6 }; ++static int mt7988_xfi_pextp_phy0_i2c_funcs[] = { 5, 5 }; ++ ++static const int mt7988_xfi_pextp_phy1_i2c_pins[] = { 5, 6 }; ++static int mt7988_xfi_pextp_phy1_i2c_funcs[] = { 6, 6 }; ++ ++static const int mt7988_i2c0_1_pins[] = { 15, 16 }; ++static int mt7988_i2c0_1_funcs[] = { 1, 1 }; ++ ++static const int mt7988_u30_phy_i2c0_pins[] = { 15, 16 }; ++static int mt7988_u30_phy_i2c0_funcs[] = { 2, 2 }; ++ ++static const int mt7988_u32_phy_i2c0_pins[] = { 15, 16 }; ++static int mt7988_u32_phy_i2c0_funcs[] = { 3, 3 }; ++ ++static const int mt7988_xfi_phy0_i2c1_pins[] = { 15, 16 }; ++static int mt7988_xfi_phy0_i2c1_funcs[] = { 5, 5 }; ++ ++static const int mt7988_xfi_phy1_i2c1_pins[] = { 15, 16 }; ++static int mt7988_xfi_phy1_i2c1_funcs[] = { 6, 6 }; ++ ++static const int mt7988_xfi_phy_pll_i2c2_pins[] = { 15, 16 }; ++static int mt7988_xfi_phy_pll_i2c2_funcs[] = { 7, 7 }; ++ ++static const int mt7988_i2c1_0_pins[] = { 17, 18 }; ++static int mt7988_i2c1_0_funcs[] = { 1, 1 }; ++ ++static const int mt7988_u30_phy_i2c1_pins[] = { 17, 18 }; ++static int mt7988_u30_phy_i2c1_funcs[] = { 2, 2 }; ++ ++static const int mt7988_u32_phy_i2c1_pins[] = { 17, 18 }; ++static int mt7988_u32_phy_i2c1_funcs[] = { 3, 3 }; ++ ++static const int mt7988_xfi_phy_pll_i2c3_pins[] = { 17, 18 }; ++static int mt7988_xfi_phy_pll_i2c3_funcs[] = { 4, 4 }; ++ ++static const int mt7988_sgmii0_i2c_pins[] = { 17, 18 }; ++static int mt7988_sgmii0_i2c_funcs[] = { 5, 5 }; ++ ++static const int mt7988_sgmii1_i2c_pins[] = { 17, 18 }; ++static int mt7988_sgmii1_i2c_funcs[] = { 6, 6 }; ++ ++static const int mt7988_i2c1_2_pins[] = { 69, 70 }; ++static int mt7988_i2c1_2_funcs[] = { 2, 2 }; ++ ++static const int mt7988_i2c2_0_pins[] = { 69, 70 }; ++static int mt7988_i2c2_0_funcs[] = { 4, 4 }; ++ ++static const int mt7988_i2c2_1_pins[] = { 71, 72 }; ++static int mt7988_i2c2_1_funcs[] = { 1, 1 }; ++ ++/* eth */ ++static const int mt7988_mdc_mdio0_pins[] = { 5, 6 }; ++static int mt7988_mdc_mdio0_funcs[] = { 1, 1 }; ++ ++static const int mt7988_2p5g_ext_mdio_pins[] = { 28, 29 }; ++static int mt7988_2p5g_ext_mdio_funcs[] = { 6, 6 }; ++ ++static const int mt7988_gbe_ext_mdio_pins[] = { 30, 31 }; ++static int mt7988_gbe_ext_mdio_funcs[] = { 6, 6 }; ++ ++static const int mt7988_mdc_mdio1_pins[] = { 69, 70 }; ++static int mt7988_mdc_mdio1_funcs[] = { 1, 1 }; ++ ++/* pcie */ ++static const int mt7988_pcie_wake_n0_0_pins[] = { 7 }; ++static int mt7988_pcie_wake_n0_0_funcs[] = { 1 }; ++ ++static const int mt7988_pcie_clk_req_n0_0_pins[] = { 8 }; ++static int mt7988_pcie_clk_req_n0_0_funcs[] = { 1 }; ++ ++static const int mt7988_pcie_wake_n3_0_pins[] = { 9 }; ++static int mt7988_pcie_wake_n3_0_funcs[] = { 1 }; ++ ++static const int mt7988_pcie_clk_req_n3_pins[] = { 10 }; ++static int mt7988_pcie_clk_req_n3_funcs[] = { 1 }; ++ ++static const int mt7988_pcie_clk_req_n0_1_pins[] = { 10 }; ++static int mt7988_pcie_clk_req_n0_1_funcs[] = { 2 }; ++ ++static const int mt7988_pcie_p0_phy_i2c_pins[] = { 7, 8 }; ++static int mt7988_pcie_p0_phy_i2c_funcs[] = { 3, 3 }; ++ ++static const int mt7988_pcie_p1_phy_i2c_pins[] = { 7, 8 }; ++static int mt7988_pcie_p1_phy_i2c_funcs[] = { 4, 4 }; ++ ++static const int mt7988_pcie_p3_phy_i2c_pins[] = { 9, 10 }; ++static int mt7988_pcie_p3_phy_i2c_funcs[] = { 4, 4 }; ++ ++static const int mt7988_pcie_p2_phy_i2c_pins[] = { 7, 8 }; ++static int mt7988_pcie_p2_phy_i2c_funcs[] = { 5, 5 }; ++ ++static const int mt7988_ckm_phy_i2c_pins[] = { 9, 10 }; ++static int mt7988_ckm_phy_i2c_funcs[] = { 5, 5 }; ++ ++static const int mt7988_pcie_wake_n0_1_pins[] = { 13 }; ++static int mt7988_pcie_wake_n0_1_funcs[] = { 2 }; ++ ++static const int mt7988_pcie_wake_n3_1_pins[] = { 14 }; ++static int mt7988_pcie_wake_n3_1_funcs[] = { 2 }; ++ ++static const int mt7988_pcie_2l_0_pereset_pins[] = { 19 }; ++static int mt7988_pcie_2l_0_pereset_funcs[] = { 1 }; ++ ++static const int mt7988_pcie_1l_1_pereset_pins[] = { 20 }; ++static int mt7988_pcie_1l_1_pereset_funcs[] = { 1 }; ++ ++static const int mt7988_pcie_clk_req_n2_1_pins[] = { 63 }; ++static int mt7988_pcie_clk_req_n2_1_funcs[] = { 2 }; ++ ++static const int mt7988_pcie_2l_1_pereset_pins[] = { 73 }; ++static int mt7988_pcie_2l_1_pereset_funcs[] = { 1 }; ++ ++static const int mt7988_pcie_1l_0_pereset_pins[] = { 74 }; ++static int mt7988_pcie_1l_0_pereset_funcs[] = { 1 }; ++ ++static const int mt7988_pcie_wake_n1_0_pins[] = { 75 }; ++static int mt7988_pcie_wake_n1_0_funcs[] = { 1 }; ++ ++static const int mt7988_pcie_clk_req_n1_pins[] = { 76 }; ++static int mt7988_pcie_clk_req_n1_funcs[] = { 1 }; ++ ++static const int mt7988_pcie_wake_n2_0_pins[] = { 77 }; ++static int mt7988_pcie_wake_n2_0_funcs[] = { 1 }; ++ ++static const int mt7988_pcie_clk_req_n2_0_pins[] = { 78 }; ++static int mt7988_pcie_clk_req_n2_0_funcs[] = { 1 }; ++ ++static const int mt7988_pcie_wake_n2_1_pins[] = { 79 }; ++static int mt7988_pcie_wake_n2_1_funcs[] = { 2 }; ++ ++/* pmic */ ++static const int mt7988_pmic_pins[] = { 11 }; ++static int mt7988_pmic_funcs[] = { 1 }; ++ ++/* watchdog */ ++static const int mt7988_watchdog_pins[] = { 12 }; ++static int mt7988_watchdog_funcs[] = { 1 }; ++ ++/* spi */ ++static const int mt7988_spi0_wp_hold_pins[] = { 22, 23 }; ++static int mt7988_spi0_wp_hold_funcs[] = { 1, 1 }; ++ ++static const int mt7988_spi0_pins[] = { 24, 25, 26, 27 }; ++static int mt7988_spi0_funcs[] = { 1, 1, 1, 1 }; ++ ++static const int mt7988_spi1_pins[] = { 28, 29, 30, 31 }; ++static int mt7988_spi1_funcs[] = { 1, 1, 1, 1 }; ++ ++static const int mt7988_spi2_pins[] = { 32, 33, 34, 35 }; ++static int mt7988_spi2_funcs[] = { 1, 1, 1, 1 }; ++ ++static const int mt7988_spi2_wp_hold_pins[] = { 36, 37 }; ++static int mt7988_spi2_wp_hold_funcs[] = { 1, 1 }; ++ ++/* flash */ ++static const int mt7988_snfi_pins[] = { 22, 23, 24, 25, 26, 27 }; ++static int mt7988_snfi_funcs[] = { 2, 2, 2, 2, 2, 2 }; ++ ++static const int mt7988_emmc_45_pins[] = { ++ 21, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37 ++}; ++static int mt7988_emmc_45_funcs[] = { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 }; ++ ++static const int mt7988_sdcard_pins[] = { 32, 33, 34, 35, 36, 37 }; ++static int mt7988_sdcard_funcs[] = { 5, 5, 5, 5, 5, 5 }; ++ ++static const int mt7988_emmc_51_pins[] = { 38, 39, 40, 41, 42, 43, ++ 44, 45, 46, 47, 48, 49 }; ++static int mt7988_emmc_51_funcs[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; ++ ++/* uart */ ++static const int mt7988_uart2_pins[] = { 0, 1, 2, 3 }; ++static int mt7988_uart2_funcs[] = { 1, 1, 1, 1 }; ++ ++static const int mt7988_tops_uart0_0_pins[] = { 22, 23 }; ++static int mt7988_tops_uart0_0_funcs[] = { 3, 3 }; ++ ++static const int mt7988_uart2_0_pins[] = { 28, 29, 30, 31 }; ++static int mt7988_uart2_0_funcs[] = { 2, 2, 2, 2 }; ++ ++static const int mt7988_uart1_0_pins[] = { 32, 33, 34, 35 }; ++static int mt7988_uart1_0_funcs[] = { 2, 2, 2, 2 }; ++ ++static const int mt7988_uart2_1_pins[] = { 32, 33, 34, 35 }; ++static int mt7988_uart2_1_funcs[] = { 3, 3, 3, 3 }; ++ ++static const int mt7988_net_wo0_uart_txd_0_pins[] = { 28 }; ++static int mt7988_net_wo0_uart_txd_0_funcs[] = { 3 }; ++ ++static const int mt7988_net_wo1_uart_txd_0_pins[] = { 29 }; ++static int mt7988_net_wo1_uart_txd_0_funcs[] = { 3 }; ++ ++static const int mt7988_net_wo2_uart_txd_0_pins[] = { 30 }; ++static int mt7988_net_wo2_uart_txd_0_funcs[] = { 3 }; ++ ++static const int mt7988_tops_uart1_0_pins[] = { 28, 29 }; ++static int mt7988_tops_uart1_0_funcs[] = { 4, 4 }; ++ ++static const int mt7988_tops_uart0_1_pins[] = { 30, 31 }; ++static int mt7988_tops_uart0_1_funcs[] = { 4, 4 }; ++ ++static const int mt7988_tops_uart1_1_pins[] = { 36, 37 }; ++static int mt7988_tops_uart1_1_funcs[] = { 3, 3 }; ++ ++static const int mt7988_uart0_pins[] = { 55, 56 }; ++static int mt7988_uart0_funcs[] = { 1, 1 }; ++ ++static const int mt7988_tops_uart0_2_pins[] = { 55, 56 }; ++static int mt7988_tops_uart0_2_funcs[] = { 2, 2 }; ++ ++static const int mt7988_uart2_2_pins[] = { 50, 51, 52, 53 }; ++static int mt7988_uart2_2_funcs[] = { 2, 2, 2, 2 }; ++ ++static const int mt7988_uart1_1_pins[] = { 58, 59, 60, 61 }; ++static int mt7988_uart1_1_funcs[] = { 2, 2, 2, 2 }; ++ ++static const int mt7988_uart2_3_pins[] = { 58, 59, 60, 61 }; ++static int mt7988_uart2_3_funcs[] = { 3, 3, 3, 3 }; ++ ++static const int mt7988_uart1_2_pins[] = { 80, 81, 82, 83 }; ++static int mt7988_uart1_2_funcs[] = { 1, 1, 1, 1 }; ++ ++static const int mt7988_uart1_2_lite_pins[] = { 80, 81 }; ++static int mt7988_uart1_2_lite_funcs[] = { 1, 1 }; ++ ++static const int mt7988_tops_uart1_2_pins[] = { 80, 81 }; ++static int mt7988_tops_uart1_2_funcs[] = { 4, 4, }; ++ ++static const int mt7988_net_wo0_uart_txd_1_pins[] = { 80 }; ++static int mt7988_net_wo0_uart_txd_1_funcs[] = { 3 }; ++ ++static const int mt7988_net_wo1_uart_txd_1_pins[] = { 81 }; ++static int mt7988_net_wo1_uart_txd_1_funcs[] = { 3 }; ++ ++static const int mt7988_net_wo2_uart_txd_1_pins[] = { 82 }; ++static int mt7988_net_wo2_uart_txd_1_funcs[] = { 3 }; ++ ++/* udi */ ++static const int mt7988_udi_pins[] = { 32, 33, 34, 35, 36 }; ++static int mt7988_udi_funcs[] = { 4, 4, 4, 4, 4 }; ++ ++/* i2s */ ++static const int mt7988_i2s_pins[] = { 50, 51, 52, 53, 54 }; ++static int mt7988_i2s_funcs[] = { 1, 1, 1, 1, 1 }; ++ ++/* pcm */ ++static const int mt7988_pcm_pins[] = { 50, 51, 52, 53 }; ++static int mt7988_pcm_funcs[] = { 1, 1, 1, 1 }; ++ ++/* led */ ++static const int mt7988_gbe0_led1_pins[] = { 58 }; ++static int mt7988_gbe0_led1_funcs[] = { 6 }; ++static const int mt7988_gbe1_led1_pins[] = { 59 }; ++static int mt7988_gbe1_led1_funcs[] = { 6 }; ++static const int mt7988_gbe2_led1_pins[] = { 60 }; ++static int mt7988_gbe2_led1_funcs[] = { 6 }; ++static const int mt7988_gbe3_led1_pins[] = { 61 }; ++static int mt7988_gbe3_led1_funcs[] = { 6 }; ++ ++static const int mt7988_2p5gbe_led1_pins[] = { 62 }; ++static int mt7988_2p5gbe_led1_funcs[] = { 6 }; ++ ++static const int mt7988_gbe0_led0_pins[] = { 64 }; ++static int mt7988_gbe0_led0_funcs[] = { 1 }; ++static const int mt7988_gbe1_led0_pins[] = { 65 }; ++static int mt7988_gbe1_led0_funcs[] = { 1 }; ++static const int mt7988_gbe2_led0_pins[] = { 66 }; ++static int mt7988_gbe2_led0_funcs[] = { 1 }; ++static const int mt7988_gbe3_led0_pins[] = { 67 }; ++static int mt7988_gbe3_led0_funcs[] = { 1 }; ++ ++static const int mt7988_2p5gbe_led0_pins[] = { 68 }; ++static int mt7988_2p5gbe_led0_funcs[] = { 1 }; ++ ++/* usb */ ++static const int mt7988_drv_vbus_p1_pins[] = { 63 }; ++static int mt7988_drv_vbus_p1_funcs[] = { 1 }; ++ ++static const int mt7988_drv_vbus_pins[] = { 79 }; ++static int mt7988_drv_vbus_funcs[] = { 1 }; ++ ++static const struct group_desc mt7988_groups[] = { ++ /* @GPIO(0,1,2,3): uart2 */ ++ PINCTRL_PIN_GROUP("uart2", mt7988_uart2), ++ /* @GPIO(0,1,2,3,4): tops_jtag0_0 */ ++ PINCTRL_PIN_GROUP("tops_jtag0_0", mt7988_tops_jtag0_0), ++ /* @GPIO(2,3): int_usxgmii */ ++ PINCTRL_PIN_GROUP("int_usxgmii", mt7988_int_usxgmii), ++ /* @GPIO(0,1,2,3,4): dfd */ ++ PINCTRL_PIN_GROUP("dfd", mt7988_dfd), ++ /* @GPIO(0,1): xfi_phy0_i2c0 */ ++ PINCTRL_PIN_GROUP("xfi_phy0_i2c0", mt7988_xfi_phy0_i2c0), ++ /* @GPIO(0,1): xfi_phy1_i2c0 */ ++ PINCTRL_PIN_GROUP("xfi_phy1_i2c0", mt7988_xfi_phy1_i2c0), ++ /* @GPIO(3,4): xfi_phy_pll_i2c0 */ ++ PINCTRL_PIN_GROUP("xfi_phy_pll_i2c0", mt7988_xfi_phy_pll_i2c0), ++ /* @GPIO(3,4): xfi_phy_pll_i2c1 */ ++ PINCTRL_PIN_GROUP("xfi_phy_pll_i2c1", mt7988_xfi_phy_pll_i2c1), ++ /* @GPIO(4): pwm7 */ ++ PINCTRL_PIN_GROUP("pwm7_0", mt7988_pwm7_0), ++ /* @GPIO(5,6) i2c0_0 */ ++ PINCTRL_PIN_GROUP("i2c0_0", mt7988_i2c0_0), ++ /* @GPIO(5,6) i2c1_sfp */ ++ PINCTRL_PIN_GROUP("i2c1_sfp", mt7988_i2c1_sfp), ++ /* @GPIO(5,6) xfi_pextp_phy0_i2c */ ++ PINCTRL_PIN_GROUP("xfi_pextp_phy0_i2c", mt7988_xfi_pextp_phy0_i2c), ++ /* @GPIO(5,6) xfi_pextp_phy1_i2c */ ++ PINCTRL_PIN_GROUP("xfi_pextp_phy1_i2c", mt7988_xfi_pextp_phy1_i2c), ++ /* @GPIO(5,6) mdc_mdio0 */ ++ PINCTRL_PIN_GROUP("mdc_mdio0", mt7988_mdc_mdio0), ++ /* @GPIO(7): pcie_wake_n0_0 */ ++ PINCTRL_PIN_GROUP("pcie_wake_n0_0", mt7988_pcie_wake_n0_0), ++ /* @GPIO(8): pcie_clk_req_n0_0 */ ++ PINCTRL_PIN_GROUP("pcie_clk_req_n0_0", mt7988_pcie_clk_req_n0_0), ++ /* @GPIO(9): pcie_wake_n3_0 */ ++ PINCTRL_PIN_GROUP("pcie_wake_n3_0", mt7988_pcie_wake_n3_0), ++ /* @GPIO(10): pcie_clk_req_n3 */ ++ PINCTRL_PIN_GROUP("pcie_clk_req_n3", mt7988_pcie_clk_req_n3), ++ /* @GPIO(10): pcie_clk_req_n0_1 */ ++ PINCTRL_PIN_GROUP("pcie_clk_req_n0_1", mt7988_pcie_clk_req_n0_1), ++ /* @GPIO(7,8) pcie_p0_phy_i2c */ ++ PINCTRL_PIN_GROUP("pcie_p0_phy_i2c", mt7988_pcie_p0_phy_i2c), ++ /* @GPIO(7,8) pcie_p1_phy_i2c */ ++ PINCTRL_PIN_GROUP("pcie_p1_phy_i2c", mt7988_pcie_p1_phy_i2c), ++ /* @GPIO(7,8) pcie_p2_phy_i2c */ ++ PINCTRL_PIN_GROUP("pcie_p2_phy_i2c", mt7988_pcie_p2_phy_i2c), ++ /* @GPIO(9,10) pcie_p3_phy_i2c */ ++ PINCTRL_PIN_GROUP("pcie_p3_phy_i2c", mt7988_pcie_p3_phy_i2c), ++ /* @GPIO(9,10) ckm_phy_i2c */ ++ PINCTRL_PIN_GROUP("ckm_phy_i2c", mt7988_ckm_phy_i2c), ++ /* @GPIO(11): pmic */ ++ PINCTRL_PIN_GROUP("pcie_pmic", mt7988_pmic), ++ /* @GPIO(12): watchdog */ ++ PINCTRL_PIN_GROUP("watchdog", mt7988_watchdog), ++ /* @GPIO(13): pcie_wake_n0_1 */ ++ PINCTRL_PIN_GROUP("pcie_wake_n0_1", mt7988_pcie_wake_n0_1), ++ /* @GPIO(14): pcie_wake_n3_1 */ ++ PINCTRL_PIN_GROUP("pcie_wake_n3_1", mt7988_pcie_wake_n3_1), ++ /* @GPIO(15,16) i2c0_1 */ ++ PINCTRL_PIN_GROUP("i2c0_1", mt7988_i2c0_1), ++ /* @GPIO(15,16) u30_phy_i2c0 */ ++ PINCTRL_PIN_GROUP("u30_phy_i2c0", mt7988_u30_phy_i2c0), ++ /* @GPIO(15,16) u32_phy_i2c0 */ ++ PINCTRL_PIN_GROUP("u32_phy_i2c0", mt7988_u32_phy_i2c0), ++ /* @GPIO(15,16) xfi_phy0_i2c1 */ ++ PINCTRL_PIN_GROUP("xfi_phy0_i2c1", mt7988_xfi_phy0_i2c1), ++ /* @GPIO(15,16) xfi_phy1_i2c1 */ ++ PINCTRL_PIN_GROUP("xfi_phy1_i2c1", mt7988_xfi_phy1_i2c1), ++ /* @GPIO(15,16) xfi_phy_pll_i2c2 */ ++ PINCTRL_PIN_GROUP("xfi_phy_pll_i2c2", mt7988_xfi_phy_pll_i2c2), ++ /* @GPIO(17,18) i2c1_0 */ ++ PINCTRL_PIN_GROUP("i2c1_0", mt7988_i2c1_0), ++ /* @GPIO(17,18) u30_phy_i2c1 */ ++ PINCTRL_PIN_GROUP("u30_phy_i2c1", mt7988_u30_phy_i2c1), ++ /* @GPIO(17,18) u32_phy_i2c1 */ ++ PINCTRL_PIN_GROUP("u32_phy_i2c1", mt7988_u32_phy_i2c1), ++ /* @GPIO(17,18) xfi_phy_pll_i2c3 */ ++ PINCTRL_PIN_GROUP("xfi_phy_pll_i2c3", mt7988_xfi_phy_pll_i2c3), ++ /* @GPIO(17,18) sgmii0_i2c */ ++ PINCTRL_PIN_GROUP("sgmii0_i2c", mt7988_sgmii0_i2c), ++ /* @GPIO(17,18) sgmii1_i2c */ ++ PINCTRL_PIN_GROUP("sgmii1_i2c", mt7988_sgmii1_i2c), ++ /* @GPIO(19): pcie_2l_0_pereset */ ++ PINCTRL_PIN_GROUP("pcie_2l_0_pereset", mt7988_pcie_2l_0_pereset), ++ /* @GPIO(20): pcie_1l_1_pereset */ ++ PINCTRL_PIN_GROUP("pcie_1l_1_pereset", mt7988_pcie_1l_1_pereset), ++ /* @GPIO(21): pwm1 */ ++ PINCTRL_PIN_GROUP("pwm1", mt7988_pwm1), ++ /* @GPIO(22,23) spi0_wp_hold */ ++ PINCTRL_PIN_GROUP("spi0_wp_hold", mt7988_spi0_wp_hold), ++ /* @GPIO(24,25,26,27) spi0 */ ++ PINCTRL_PIN_GROUP("spi0", mt7988_spi0), ++ /* @GPIO(28,29,30,31) spi1 */ ++ PINCTRL_PIN_GROUP("spi1", mt7988_spi1), ++ /* @GPIO(32,33,34,35) spi2 */ ++ PINCTRL_PIN_GROUP("spi2", mt7988_spi2), ++ /* @GPIO(36,37) spi2_wp_hold */ ++ PINCTRL_PIN_GROUP("spi2_wp_hold", mt7988_spi2_wp_hold), ++ /* @GPIO(22,23,24,25,26,27) snfi */ ++ PINCTRL_PIN_GROUP("snfi", mt7988_snfi), ++ /* @GPIO(22,23) tops_uart0_0 */ ++ PINCTRL_PIN_GROUP("tops_uart0_0", mt7988_tops_uart0_0), ++ /* @GPIO(28,29,30,31) uart2_0 */ ++ PINCTRL_PIN_GROUP("uart2_0", mt7988_uart2_0), ++ /* @GPIO(32,33,34,35) uart1_0 */ ++ PINCTRL_PIN_GROUP("uart1_0", mt7988_uart1_0), ++ /* @GPIO(32,33,34,35) uart2_1 */ ++ PINCTRL_PIN_GROUP("uart2_1", mt7988_uart2_1), ++ /* @GPIO(28) net_wo0_uart_txd_0 */ ++ PINCTRL_PIN_GROUP("net_wo0_uart_txd_0", mt7988_net_wo0_uart_txd_0), ++ /* @GPIO(29) net_wo1_uart_txd_0 */ ++ PINCTRL_PIN_GROUP("net_wo1_uart_txd_0", mt7988_net_wo1_uart_txd_0), ++ /* @GPIO(30) net_wo2_uart_txd_0 */ ++ PINCTRL_PIN_GROUP("net_wo2_uart_txd_0", mt7988_net_wo2_uart_txd_0), ++ /* @GPIO(28,29) tops_uart1_0 */ ++ PINCTRL_PIN_GROUP("tops_uart0_0", mt7988_tops_uart1_0), ++ /* @GPIO(30,31) tops_uart0_1 */ ++ PINCTRL_PIN_GROUP("tops_uart0_1", mt7988_tops_uart0_1), ++ /* @GPIO(36,37) tops_uart1_1 */ ++ PINCTRL_PIN_GROUP("tops_uart1_1", mt7988_tops_uart1_1), ++ /* @GPIO(32,33,34,35,36) udi */ ++ PINCTRL_PIN_GROUP("udi", mt7988_udi), ++ /* @GPIO(21,28,29,30,31,32,33,34,35,36,37) emmc_45 */ ++ PINCTRL_PIN_GROUP("emmc_45", mt7988_emmc_45), ++ /* @GPIO(32,33,34,35,36,37) sdcard */ ++ PINCTRL_PIN_GROUP("sdcard", mt7988_sdcard), ++ /* @GPIO(38,39,40,41,42,43,44,45,46,47,48,49) emmc_51 */ ++ PINCTRL_PIN_GROUP("emmc_51", mt7988_emmc_51), ++ /* @GPIO(28,29) 2p5g_ext_mdio */ ++ PINCTRL_PIN_GROUP("2p5g_ext_mdio", mt7988_2p5g_ext_mdio), ++ /* @GPIO(30,31) gbe_ext_mdio */ ++ PINCTRL_PIN_GROUP("gbe_ext_mdio", mt7988_gbe_ext_mdio), ++ /* @GPIO(50,51,52,53,54) i2s */ ++ PINCTRL_PIN_GROUP("i2s", mt7988_i2s), ++ /* @GPIO(50,51,52,53) pcm */ ++ PINCTRL_PIN_GROUP("pcm", mt7988_pcm), ++ /* @GPIO(55,56) uart0 */ ++ PINCTRL_PIN_GROUP("uart0", mt7988_uart0), ++ /* @GPIO(55,56) tops_uart0_2 */ ++ PINCTRL_PIN_GROUP("tops_uart0_2", mt7988_tops_uart0_2), ++ /* @GPIO(50,51,52,53) uart2_2 */ ++ PINCTRL_PIN_GROUP("uart2_2", mt7988_uart2_2), ++ /* @GPIO(50,51,52,53,54) wo0_jtag */ ++ PINCTRL_PIN_GROUP("wo0_jtag", mt7988_wo0_jtag), ++ /* @GPIO(50,51,52,53,54) wo1-wo1_jtag */ ++ PINCTRL_PIN_GROUP("wo1_jtag", mt7988_wo1_jtag), ++ /* @GPIO(50,51,52,53,54) wo2_jtag */ ++ PINCTRL_PIN_GROUP("wo2_jtag", mt7988_wo2_jtag), ++ /* @GPIO(57) pwm0 */ ++ PINCTRL_PIN_GROUP("pwm0", mt7988_pwm0), ++ /* @GPIO(58) pwm2_0 */ ++ PINCTRL_PIN_GROUP("pwm2_0", mt7988_pwm2_0), ++ /* @GPIO(59) pwm3_0 */ ++ PINCTRL_PIN_GROUP("pwm3_0", mt7988_pwm3_0), ++ /* @GPIO(60) pwm4_0 */ ++ PINCTRL_PIN_GROUP("pwm4_0", mt7988_pwm4_0), ++ /* @GPIO(61) pwm5_0 */ ++ PINCTRL_PIN_GROUP("pwm5_0", mt7988_pwm5_0), ++ /* @GPIO(58,59,60,61,62) jtag */ ++ PINCTRL_PIN_GROUP("jtag", mt7988_jtag), ++ /* @GPIO(58,59,60,61,62) tops_jtag0_1 */ ++ PINCTRL_PIN_GROUP("tops_jtag0_1", mt7988_tops_jtag0_1), ++ /* @GPIO(58,59,60,61) uart2_3 */ ++ PINCTRL_PIN_GROUP("uart2_3", mt7988_uart2_3), ++ /* @GPIO(58,59,60,61) uart1_1 */ ++ PINCTRL_PIN_GROUP("uart1_1", mt7988_uart1_1), ++ /* @GPIO(58,59,60,61) gbe_led1 */ ++ PINCTRL_PIN_GROUP("gbe0_led1", mt7988_gbe0_led1), ++ PINCTRL_PIN_GROUP("gbe1_led1", mt7988_gbe1_led1), ++ PINCTRL_PIN_GROUP("gbe2_led1", mt7988_gbe2_led1), ++ PINCTRL_PIN_GROUP("gbe3_led1", mt7988_gbe3_led1), ++ /* @GPIO(62) pwm6_0 */ ++ PINCTRL_PIN_GROUP("pwm6_0", mt7988_pwm6_0), ++ /* @GPIO(62) 2p5gbe_led1 */ ++ PINCTRL_PIN_GROUP("2p5gbe_led1", mt7988_2p5gbe_led1), ++ /* @GPIO(64,65,66,67) gbe_led0 */ ++ PINCTRL_PIN_GROUP("gbe0_led0", mt7988_gbe0_led0), ++ PINCTRL_PIN_GROUP("gbe1_led0", mt7988_gbe1_led0), ++ PINCTRL_PIN_GROUP("gbe2_led0", mt7988_gbe2_led0), ++ PINCTRL_PIN_GROUP("gbe3_led0", mt7988_gbe3_led0), ++ /* @GPIO(68) 2p5gbe_led0 */ ++ PINCTRL_PIN_GROUP("2p5gbe_led0", mt7988_2p5gbe_led0), ++ /* @GPIO(63) drv_vbus_p1 */ ++ PINCTRL_PIN_GROUP("drv_vbus_p1", mt7988_drv_vbus_p1), ++ /* @GPIO(63) pcie_clk_req_n2_1 */ ++ PINCTRL_PIN_GROUP("pcie_clk_req_n2_1", mt7988_pcie_clk_req_n2_1), ++ /* @GPIO(69, 70) mdc_mdio1 */ ++ PINCTRL_PIN_GROUP("mdc_mdio1", mt7988_mdc_mdio1), ++ /* @GPIO(69, 70) i2c1_2 */ ++ PINCTRL_PIN_GROUP("i2c1_2", mt7988_i2c1_2), ++ /* @GPIO(69) pwm6 */ ++ PINCTRL_PIN_GROUP("pwm6", mt7988_pwm6), ++ /* @GPIO(70) pwm7 */ ++ PINCTRL_PIN_GROUP("pwm7", mt7988_pwm7), ++ /* @GPIO(69,70) i2c2_0 */ ++ PINCTRL_PIN_GROUP("i2c2_0", mt7988_i2c2_0), ++ /* @GPIO(71,72) i2c2_1 */ ++ PINCTRL_PIN_GROUP("i2c2_1", mt7988_i2c2_1), ++ /* @GPIO(73) pcie_2l_1_pereset */ ++ PINCTRL_PIN_GROUP("pcie_2l_1_pereset", mt7988_pcie_2l_1_pereset), ++ /* @GPIO(74) pcie_1l_0_pereset */ ++ PINCTRL_PIN_GROUP("pcie_1l_0_pereset", mt7988_pcie_1l_0_pereset), ++ /* @GPIO(75) pcie_wake_n1_0 */ ++ PINCTRL_PIN_GROUP("pcie_wake_n1_0", mt7988_pcie_wake_n1_0), ++ /* @GPIO(76) pcie_clk_req_n1 */ ++ PINCTRL_PIN_GROUP("pcie_clk_req_n1", mt7988_pcie_clk_req_n1), ++ /* @GPIO(77) pcie_wake_n2_0 */ ++ PINCTRL_PIN_GROUP("pcie_wake_n2_0", mt7988_pcie_wake_n2_0), ++ /* @GPIO(78) pcie_clk_req_n2_0 */ ++ PINCTRL_PIN_GROUP("pcie_clk_req_n2_0", mt7988_pcie_clk_req_n2_0), ++ /* @GPIO(79) drv_vbus */ ++ PINCTRL_PIN_GROUP("drv_vbus", mt7988_drv_vbus), ++ /* @GPIO(79) pcie_wake_n2_1 */ ++ PINCTRL_PIN_GROUP("pcie_wake_n2_1", mt7988_pcie_wake_n2_1), ++ /* @GPIO(80,81,82,83) uart1_2 */ ++ PINCTRL_PIN_GROUP("uart1_2", mt7988_uart1_2), ++ /* @GPIO(80,81) uart1_2_lite */ ++ PINCTRL_PIN_GROUP("uart1_2_lite", mt7988_uart1_2_lite), ++ /* @GPIO(80) pwm2 */ ++ PINCTRL_PIN_GROUP("pwm2", mt7988_pwm2), ++ /* @GPIO(81) pwm3 */ ++ PINCTRL_PIN_GROUP("pwm3", mt7988_pwm3), ++ /* @GPIO(82) pwm4 */ ++ PINCTRL_PIN_GROUP("pwm4", mt7988_pwm4), ++ /* @GPIO(83) pwm5 */ ++ PINCTRL_PIN_GROUP("pwm5", mt7988_pwm5), ++ /* @GPIO(80) net_wo0_uart_txd_0 */ ++ PINCTRL_PIN_GROUP("net_wo0_uart_txd_0", mt7988_net_wo0_uart_txd_0), ++ /* @GPIO(81) net_wo1_uart_txd_0 */ ++ PINCTRL_PIN_GROUP("net_wo1_uart_txd_0", mt7988_net_wo1_uart_txd_0), ++ /* @GPIO(82) net_wo2_uart_txd_0 */ ++ PINCTRL_PIN_GROUP("net_wo2_uart_txd_0", mt7988_net_wo2_uart_txd_0), ++ /* @GPIO(80,81) tops_uart1_2 */ ++ PINCTRL_PIN_GROUP("tops_uart1_2", mt7988_tops_uart1_2), ++ /* @GPIO(80) net_wo0_uart_txd_1 */ ++ PINCTRL_PIN_GROUP("net_wo0_uart_txd_1", mt7988_net_wo0_uart_txd_1), ++ /* @GPIO(81) net_wo1_uart_txd_1 */ ++ PINCTRL_PIN_GROUP("net_wo1_uart_txd_1", mt7988_net_wo1_uart_txd_1), ++ /* @GPIO(82) net_wo2_uart_txd_1 */ ++ PINCTRL_PIN_GROUP("net_wo2_uart_txd_1", mt7988_net_wo2_uart_txd_1), ++}; ++ ++/* Joint those groups owning the same capability in user point of view which ++ * allows that people tend to use through the device tree. ++ */ ++static const char * const mt7988_jtag_groups[] = { ++ "tops_jtag0_0", "wo0_jtag", "wo1_jtag", ++ "wo2_jtag", "jtag", "tops_jtag0_1", ++}; ++static const char * const mt7988_int_usxgmii_groups[] = { ++ "int_usxgmii", ++}; ++static const char * const mt7988_pwm_groups[] = { ++ "pwm0", "pwm1", "pwm2", "pwm2_0", "pwm3", "pwm3_0", "pwm4", "pwm4_0", ++ "pwm5", "pwm5_0", "pwm6", "pwm6_0", "pwm7", "pwm7_0", ++ ++}; ++static const char * const mt7988_dfd_groups[] = { ++ "dfd", ++}; ++static const char * const mt7988_i2c_groups[] = { ++ "xfi_phy0_i2c0", ++ "xfi_phy1_i2c0", ++ "xfi_phy_pll_i2c0", ++ "xfi_phy_pll_i2c1", ++ "i2c0_0", ++ "i2c1_sfp", ++ "xfi_pextp_phy0_i2c", ++ "xfi_pextp_phy1_i2c", ++ "i2c0_1", ++ "u30_phy_i2c0", ++ "u32_phy_i2c0", ++ "xfi_phy0_i2c1", ++ "xfi_phy1_i2c1", ++ "xfi_phy_pll_i2c2", ++ "i2c1_0", ++ "u30_phy_i2c1", ++ "u32_phy_i2c1", ++ "xfi_phy_pll_i2c3", ++ "sgmii0_i2c", ++ "sgmii1_i2c", ++ "i2c1_2", ++ "i2c2_0", ++ "i2c2_1", ++}; ++static const char * const mt7988_ethernet_groups[] = { ++ "mdc_mdio0", ++ "2p5g_ext_mdio", ++ "gbe_ext_mdio", ++ "mdc_mdio1", ++}; ++static const char * const mt7988_pcie_groups[] = { ++ "pcie_wake_n0_0", "pcie_clk_req_n0_0", "pcie_wake_n3_0", ++ "pcie_clk_req_n3", "pcie_p0_phy_i2c", "pcie_p1_phy_i2c", ++ "pcie_p3_phy_i2c", "pcie_p2_phy_i2c", "ckm_phy_i2c", ++ "pcie_wake_n0_1", "pcie_wake_n3_1", "pcie_2l_0_pereset", ++ "pcie_1l_1_pereset", "pcie_clk_req_n2_1", "pcie_2l_1_pereset", ++ "pcie_1l_0_pereset", "pcie_wake_n1_0", "pcie_clk_req_n1", ++ "pcie_wake_n2_0", "pcie_clk_req_n2_0", "pcie_wake_n2_1", ++ "pcie_clk_req_n0_1" ++}; ++static const char * const mt7988_pmic_groups[] = { ++ "pmic", ++}; ++static const char * const mt7988_wdt_groups[] = { ++ "watchdog", ++}; ++static const char * const mt7988_spi_groups[] = { ++ "spi0", "spi0_wp_hold", "spi1", "spi2", "spi2_wp_hold", ++}; ++static const char * const mt7988_flash_groups[] = { "emmc_45", "sdcard", "snfi", ++ "emmc_51" }; ++static const char * const mt7988_uart_groups[] = { ++ "uart2", ++ "tops_uart0_0", ++ "uart2_0", ++ "uart1_0", ++ "uart2_1", ++ "net_wo0_uart_txd_0", ++ "net_wo1_uart_txd_0", ++ "net_wo2_uart_txd_0", ++ "tops_uart1_0", ++ "ops_uart0_1", ++ "ops_uart1_1", ++ "uart0", ++ "tops_uart0_2", ++ "uart1_1", ++ "uart2_3", ++ "uart1_2", ++ "uart1_2_lite", ++ "tops_uart1_2", ++ "net_wo0_uart_txd_1", ++ "net_wo1_uart_txd_1", ++ "net_wo2_uart_txd_1", ++}; ++static const char * const mt7988_udi_groups[] = { ++ "udi", ++}; ++static const char * const mt7988_audio_groups[] = { ++ "i2s", "pcm", ++}; ++static const char * const mt7988_led_groups[] = { ++ "gbe0_led1", "gbe1_led1", "gbe2_led1", "gbe3_led1", "2p5gbe_led1", ++ "gbe0_led0", "gbe1_led0", "gbe2_led0", "gbe3_led0", "2p5gbe_led0", ++ "wf5g_led0", "wf5g_led1", ++}; ++static const char * const mt7988_usb_groups[] = { ++ "drv_vbus", ++ "drv_vbus_p1", ++}; ++ ++static const struct function_desc mt7988_functions[] = { ++ { { "audio", mt7988_audio_groups, ARRAY_SIZE(mt7988_audio_groups) }, ++ NULL }, ++ { { "jtag", mt7988_jtag_groups, ARRAY_SIZE(mt7988_jtag_groups) }, ++ NULL }, ++ { { "int_usxgmii", mt7988_int_usxgmii_groups, ++ ARRAY_SIZE(mt7988_int_usxgmii_groups) }, ++ NULL }, ++ { { "pwm", mt7988_pwm_groups, ARRAY_SIZE(mt7988_pwm_groups) }, NULL }, ++ { { "dfd", mt7988_dfd_groups, ARRAY_SIZE(mt7988_dfd_groups) }, NULL }, ++ { { "i2c", mt7988_i2c_groups, ARRAY_SIZE(mt7988_i2c_groups) }, NULL }, ++ { { "eth", mt7988_ethernet_groups, ARRAY_SIZE(mt7988_ethernet_groups) }, ++ NULL }, ++ { { "pcie", mt7988_pcie_groups, ARRAY_SIZE(mt7988_pcie_groups) }, ++ NULL }, ++ { { "pmic", mt7988_pmic_groups, ARRAY_SIZE(mt7988_pmic_groups) }, ++ NULL }, ++ { { "watchdog", mt7988_wdt_groups, ARRAY_SIZE(mt7988_wdt_groups) }, ++ NULL }, ++ { { "spi", mt7988_spi_groups, ARRAY_SIZE(mt7988_spi_groups) }, NULL }, ++ { { "flash", mt7988_flash_groups, ARRAY_SIZE(mt7988_flash_groups) }, ++ NULL }, ++ { { "uart", mt7988_uart_groups, ARRAY_SIZE(mt7988_uart_groups) }, ++ NULL }, ++ { { "udi", mt7988_udi_groups, ARRAY_SIZE(mt7988_udi_groups) }, NULL }, ++ { { "usb", mt7988_usb_groups, ARRAY_SIZE(mt7988_usb_groups) }, NULL }, ++ { { "led", mt7988_led_groups, ARRAY_SIZE(mt7988_led_groups) }, NULL }, ++}; ++ ++static const struct mtk_eint_hw mt7988_eint_hw = { ++ .port_mask = 7, ++ .ports = 7, ++ .ap_num = ARRAY_SIZE(mt7988_pins), ++ .db_cnt = 16, ++}; ++ ++static const char * const mt7988_pinctrl_register_base_names[] = { ++ "gpio", "iocfg_tr", "iocfg_br", ++ "iocfg_rb", "iocfg_lb", "iocfg_tl", ++}; ++ ++static const struct mtk_pin_soc mt7988_data = { ++ .reg_cal = mt7988_reg_cals, ++ .pins = mt7988_pins, ++ .npins = ARRAY_SIZE(mt7988_pins), ++ .grps = mt7988_groups, ++ .ngrps = ARRAY_SIZE(mt7988_groups), ++ .funcs = mt7988_functions, ++ .nfuncs = ARRAY_SIZE(mt7988_functions), ++ .eint_hw = &mt7988_eint_hw, ++ .gpio_m = 0, ++ .ies_present = false, ++ .base_names = mt7988_pinctrl_register_base_names, ++ .nbase_names = ARRAY_SIZE(mt7988_pinctrl_register_base_names), ++ .bias_disable_set = mtk_pinconf_bias_disable_set, ++ .bias_disable_get = mtk_pinconf_bias_disable_get, ++ .bias_set = mtk_pinconf_bias_set, ++ .bias_get = mtk_pinconf_bias_get, ++ .pull_type = mt7988_pull_type, ++ .bias_set_combo = mtk_pinconf_bias_set_combo, ++ .bias_get_combo = mtk_pinconf_bias_get_combo, ++ .drive_set = mtk_pinconf_drive_set_rev1, ++ .drive_get = mtk_pinconf_drive_get_rev1, ++ .adv_pull_get = mtk_pinconf_adv_pull_get, ++ .adv_pull_set = mtk_pinconf_adv_pull_set, ++}; ++ ++static const struct of_device_id mt7988_pinctrl_of_match[] = { ++ { .compatible = "mediatek,mt7988-pinctrl" }, ++ {} ++}; ++ ++static int mt7988_pinctrl_probe(struct platform_device *pdev) ++{ ++ return mtk_moore_pinctrl_probe(pdev, &mt7988_data); ++} ++ ++static struct platform_driver mt7988_pinctrl_driver = { ++ .driver = { ++ .name = "mt7988-pinctrl", ++ .of_match_table = mt7988_pinctrl_of_match, ++ }, ++ .probe = mt7988_pinctrl_probe, ++}; ++ ++static int __init mt7988_pinctrl_init(void) ++{ ++ return platform_driver_register(&mt7988_pinctrl_driver); ++} ++arch_initcall(mt7988_pinctrl_init); +-- +2.51.0 + + +From 521e63edd7dc24d0a8474f682ce9256d9456c754 Mon Sep 17 00:00:00 2001 +From: Linus Walleij +Date: Wed, 8 Jan 2025 22:52:44 +0100 +Subject: [PATCH 386/517] pinctrl: mediatek: Drop mtk_pinconf_bias_set_pd() + +This function is unused and causing compile errors, delete it. + +Reported-by: Stephen Rothwell +Link: https://lore.kernel.org/linux-next/20250106164630.4447cd0d@canb.auug.org.au/ +Signed-off-by: Linus Walleij +--- + .../pinctrl/mediatek/pinctrl-mtk-common-v2.c | 18 ------------------ + 1 file changed, 18 deletions(-) + +diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c +index 7b704cc55c9f..00e95682b9f8 100644 +--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c ++++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c +@@ -599,24 +599,6 @@ static int mtk_pinconf_bias_set_pu_pd(struct mtk_pinctrl *hw, + return mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PD, pd); + } + +-static int mtk_pinconf_bias_set_pd(struct mtk_pinctrl *hw, +- const struct mtk_pin_desc *desc, +- u32 pullup, u32 arg) +-{ +- int err, pd; +- +- if (arg != MTK_DISABLE && arg != MTK_ENABLE) +- return -EINVAL; +- +- if (arg == MTK_DISABLE || pullup) +- pd = 0; +- else if (!pullup) +- pd = 1; +- +- return mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PD, pd); +- +-} +- + static int mtk_pinconf_bias_set_pullsel_pullen(struct mtk_pinctrl *hw, + const struct mtk_pin_desc *desc, + u32 pullup, u32 arg) +-- +2.51.0 + + +From 4e3da9d88396aac9caa6a20f414ed01d54adc02b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Wed, 5 Jun 2024 10:54:33 +0200 +Subject: [PATCH 387/517] arm64: dts: mediatek: mt7988: add UART controllers +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +MT7988 has three on-SoC UART controllers that support M16C450 and +M16550A modes. + +Signed-off-by: RafaÅ‚ MiÅ‚ecki +Reviewed-by: AngeloGioacchino Del Regno +Link: https://lore.kernel.org/r/20240605085433.26513-2-zajec5@gmail.com +Signed-off-by: Matthias Brugger +Signed-off-by: AngeloGioacchino Del Regno +--- + arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 35 ++++++++++++++++++++++- + 1 file changed, 34 insertions(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +index 284e240b7997..bf7468c00d11 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +@@ -86,7 +86,7 @@ infracfg: clock-controller@10001000 { + #clock-cells = <1>; + }; + +- clock-controller@1001b000 { ++ topckgen: clock-controller@1001b000 { + compatible = "mediatek,mt7988-topckgen", "syscon"; + reg = <0 0x1001b000 0 0x1000>; + #clock-cells = <1>; +@@ -124,6 +124,39 @@ pwm@10048000 { + status = "disabled"; + }; + ++ serial@11000000 { ++ compatible = "mediatek,mt7988-uart", "mediatek,mt6577-uart"; ++ reg = <0 0x11000000 0 0x100>; ++ interrupts = ; ++ interrupt-names = "uart", "wakeup"; ++ clocks = <&topckgen CLK_TOP_UART_SEL>, ++ <&infracfg CLK_INFRA_52M_UART0_CK>; ++ clock-names = "baud", "bus"; ++ status = "disabled"; ++ }; ++ ++ serial@11000100 { ++ compatible = "mediatek,mt7988-uart", "mediatek,mt6577-uart"; ++ reg = <0 0x11000100 0 0x100>; ++ interrupts = ; ++ interrupt-names = "uart", "wakeup"; ++ clocks = <&topckgen CLK_TOP_UART_SEL>, ++ <&infracfg CLK_INFRA_52M_UART1_CK>; ++ clock-names = "baud", "bus"; ++ status = "disabled"; ++ }; ++ ++ serial@11000200 { ++ compatible = "mediatek,mt7988-uart", "mediatek,mt6577-uart"; ++ reg = <0 0x11000200 0 0x100>; ++ interrupts = ; ++ interrupt-names = "uart", "wakeup"; ++ clocks = <&topckgen CLK_TOP_UART_SEL>, ++ <&infracfg CLK_INFRA_52M_UART2_CK>; ++ clock-names = "baud", "bus"; ++ status = "disabled"; ++ }; ++ + i2c@11003000 { + compatible = "mediatek,mt7981-i2c"; + reg = <0 0x11003000 0 0x1000>, +-- +2.51.0 + + +From 24ab7e822a0a6504bdec0061f051edbb3975c767 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Thu, 13 Jun 2024 21:59:33 +0200 +Subject: [PATCH 388/517] arm64: dts: mediatek: mt7988: add efuse block +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +MT7988 (AKA MediaTek Filogic 880) uses efuse for storing calibration +data. + +Signed-off-by: RafaÅ‚ MiÅ‚ecki +Link: https://lore.kernel.org/r/20240613195933.31089-2-zajec5@gmail.com +Signed-off-by: Matthias Brugger +Signed-off-by: AngeloGioacchino Del Regno +--- + arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +index bf7468c00d11..73561c7a3ad2 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +@@ -234,6 +234,13 @@ clock-controller@11f40000 { + #clock-cells = <1>; + }; + ++ efuse@11f50000 { ++ compatible = "mediatek,mt7988-efuse", "mediatek,efuse"; ++ reg = <0 0x11f50000 0 0x1000>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ }; ++ + clock-controller@15000000 { + compatible = "mediatek,mt7988-ethsys", "syscon"; + reg = <0 0x15000000 0 0x1000>; +-- +2.51.0 + + +From d8836ca9c42c01503f86c4f0e239eec89005713a Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Tue, 17 Dec 2024 09:54:29 +0100 +Subject: [PATCH 389/517] arm64: dts: mediatek: mt7988: Add pinctrl support + +Add mt7988a pinctrl node. + +Signed-off-by: Frank Wunderlich +Reviewed-by: AngeloGioacchino Del Regno +Link: https://lore.kernel.org/r/20241217085435.9586-5-linux@fw-web.de +Signed-off-by: AngeloGioacchino Del Regno +--- + arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 54 +++++++++++++++++++++++ + 1 file changed, 54 insertions(+) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +index 73561c7a3ad2..69998351489d 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +@@ -3,6 +3,7 @@ + #include + #include + #include ++#include + + / { + compatible = "mediatek,mt7988a"; +@@ -105,6 +106,59 @@ clock-controller@1001e000 { + #clock-cells = <1>; + }; + ++ pio: pinctrl@1001f000 { ++ compatible = "mediatek,mt7988-pinctrl"; ++ reg = <0 0x1001f000 0 0x1000>, ++ <0 0x11c10000 0 0x1000>, ++ <0 0x11d00000 0 0x1000>, ++ <0 0x11d20000 0 0x1000>, ++ <0 0x11e00000 0 0x1000>, ++ <0 0x11f00000 0 0x1000>, ++ <0 0x1000b000 0 0x1000>; ++ reg-names = "gpio", "iocfg_tr", ++ "iocfg_br", "iocfg_rb", ++ "iocfg_lb", "iocfg_tl", "eint"; ++ gpio-controller; ++ #gpio-cells = <2>; ++ gpio-ranges = <&pio 0 0 84>; ++ interrupt-controller; ++ interrupts = ; ++ interrupt-parent = <&gic>; ++ #interrupt-cells = <2>; ++ ++ pcie0_pins: pcie0-pins { ++ mux { ++ function = "pcie"; ++ groups = "pcie_2l_0_pereset", "pcie_clk_req_n0_0", ++ "pcie_wake_n0_0"; ++ }; ++ }; ++ ++ pcie1_pins: pcie1-pins { ++ mux { ++ function = "pcie"; ++ groups = "pcie_2l_1_pereset", "pcie_clk_req_n1", ++ "pcie_wake_n1_0"; ++ }; ++ }; ++ ++ pcie2_pins: pcie2-pins { ++ mux { ++ function = "pcie"; ++ groups = "pcie_1l_0_pereset", "pcie_clk_req_n2_0", ++ "pcie_wake_n2_0"; ++ }; ++ }; ++ ++ pcie3_pins: pcie3-pins { ++ mux { ++ function = "pcie"; ++ groups = "pcie_1l_1_pereset", "pcie_clk_req_n3", ++ "pcie_wake_n3_0"; ++ }; ++ }; ++ }; ++ + pwm@10048000 { + compatible = "mediatek,mt7988-pwm"; + reg = <0 0x10048000 0 0x1000>; +-- +2.51.0 + + +From f2c71d82b159b8019e0cc8e1845aa1b8905564e4 Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Tue, 17 Dec 2024 10:12:15 +0100 +Subject: [PATCH 390/517] arm64: dts: mediatek: mt7988: Add reserved memory + +Add memory range handled by ATF to not be touched by linux kernel. +ATF is SoC specific and not board-specific so add it to mt7988.dtsi. + +Signed-off-by: Frank Wunderlich +Reviewed-by: AngeloGioacchino Del Regno +Link: https://lore.kernel.org/r/20241217091238.16032-2-linux@fw-web.de +Signed-off-by: AngeloGioacchino Del Regno +--- + arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +index 69998351489d..8fc7160e23a8 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +@@ -62,6 +62,18 @@ psci { + method = "smc"; + }; + ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ /* 320 KiB reserved for ARM Trusted Firmware (BL31 and BL32) */ ++ secmon@43000000 { ++ reg = <0 0x43000000 0 0x50000>; ++ no-map; ++ }; ++ }; ++ + soc { + compatible = "simple-bus"; + ranges; +-- +2.51.0 + + +From 47c00a33f75dfb3da9f42b1e934d0491df437b92 Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Tue, 17 Dec 2024 10:12:16 +0100 +Subject: [PATCH 391/517] arm64: dts: mediatek: mt7988: Add mmc support + +Add devicetree node for MMC controller. + +Signed-off-by: Frank Wunderlich +Reviewed-by: AngeloGioacchino Del Regno +Link: https://lore.kernel.org/r/20241217091238.16032-3-linux@fw-web.de +Signed-off-by: AngeloGioacchino Del Regno +--- + arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 21 ++++++++++++++++++++- + 1 file changed, 20 insertions(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +index 8fc7160e23a8..62c2befb2f94 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +@@ -112,7 +112,7 @@ watchdog: watchdog@1001c000 { + #reset-cells = <1>; + }; + +- clock-controller@1001e000 { ++ apmixedsys: clock-controller@1001e000 { + compatible = "mediatek,mt7988-apmixedsys"; + reg = <0 0x1001e000 0 0x1000>; + #clock-cells = <1>; +@@ -293,6 +293,25 @@ usb@11200000 { + clock-names = "sys_ck", "ref_ck", "mcu_ck", "dma_ck", "xhci_ck"; + }; + ++ mmc0: mmc@11230000 { ++ compatible = "mediatek,mt7988-mmc"; ++ reg = <0 0x11230000 0 0x1000>, ++ <0 0x11D60000 0 0x1000>; ++ interrupts = ; ++ clocks = <&infracfg CLK_INFRA_MSDC400>, ++ <&infracfg CLK_INFRA_MSDC2_HCK>, ++ <&infracfg CLK_INFRA_66M_MSDC_0_HCK>, ++ <&infracfg CLK_INFRA_133M_MSDC_0_HCK>; ++ assigned-clocks = <&topckgen CLK_TOP_EMMC_250M_SEL>, ++ <&topckgen CLK_TOP_EMMC_400M_SEL>; ++ assigned-clock-parents = <&topckgen CLK_TOP_NET1PLL_D5_D2>, ++ <&apmixedsys CLK_APMIXED_MSDCPLL>; ++ clock-names = "source", "hclk", "axi_cg", "ahb_cg"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ + clock-controller@11f40000 { + compatible = "mediatek,mt7988-xfi-pll"; + reg = <0 0x11f40000 0 0x1000>; +-- +2.51.0 + + +From 18d2e044598267f937931938ebc27fb564d97c1c Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Tue, 17 Dec 2024 10:12:17 +0100 +Subject: [PATCH 392/517] arm64: dts: mediatek: mt7988: Add lvts node + +Add Low Voltage Thermal Sensor (LVTS) node for mt7988 SoC. + +Signed-off-by: Frank Wunderlich +Reviewed-by: AngeloGioacchino Del Regno +Link: https://lore.kernel.org/r/20241217091238.16032-4-linux@fw-web.de +Signed-off-by: AngeloGioacchino Del Regno +--- + arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +index 62c2befb2f94..e46f4dc0b453 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +@@ -4,6 +4,7 @@ + #include + #include + #include ++#include + + / { + compatible = "mediatek,mt7988a"; +@@ -97,6 +98,7 @@ infracfg: clock-controller@10001000 { + compatible = "mediatek,mt7988-infracfg", "syscon"; + reg = <0 0x10001000 0 0x1000>; + #clock-cells = <1>; ++ #reset-cells = <1>; + }; + + topckgen: clock-controller@1001b000 { +@@ -265,6 +267,17 @@ i2c@11005000 { + status = "disabled"; + }; + ++ lvts: lvts@1100a000 { ++ compatible = "mediatek,mt7988-lvts-ap"; ++ #thermal-sensor-cells = <1>; ++ reg = <0 0x1100a000 0 0x1000>; ++ clocks = <&infracfg CLK_INFRA_26M_THERM_SYSTEM>; ++ interrupts = ; ++ resets = <&infracfg MT7988_INFRA_RST1_THERM_CTRL_SWRST>; ++ nvmem-cells = <&lvts_calibration>; ++ nvmem-cell-names = "lvts-calib-data-1"; ++ }; ++ + usb@11190000 { + compatible = "mediatek,mt7988-xhci", "mediatek,mtk-xhci"; + reg = <0 0x11190000 0 0x2e00>, +@@ -324,6 +337,10 @@ efuse@11f50000 { + reg = <0 0x11f50000 0 0x1000>; + #address-cells = <1>; + #size-cells = <1>; ++ ++ lvts_calibration: calib@918 { ++ reg = <0x918 0x28>; ++ }; + }; + + clock-controller@15000000 { +-- +2.51.0 + + +From a2d9e3b266aaf5e9949459218934a94fc7cd85a3 Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Tue, 17 Dec 2024 10:12:18 +0100 +Subject: [PATCH 393/517] arm64: dts: mediatek: mt7988: Add thermal-zone + +Add basic thermal-zone node. + +Signed-off-by: Frank Wunderlich +Reviewed-by: AngeloGioacchino Del Regno +Link: https://lore.kernel.org/r/20241217091238.16032-5-linux@fw-web.de +Signed-off-by: AngeloGioacchino Del Regno +--- + arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +index e46f4dc0b453..16b28fcf1e3c 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +@@ -358,6 +358,21 @@ clock-controller@15031000 { + }; + }; + ++ thermal-zones { ++ cpu_thermal: cpu-thermal { ++ polling-delay-passive = <1000>; ++ polling-delay = <1000>; ++ thermal-sensors = <&lvts 0>; ++ trips { ++ cpu_trip_crit: crit { ++ temperature = <125000>; ++ hysteresis = <2000>; ++ type = "critical"; ++ }; ++ }; ++ }; ++ }; ++ + timer { + compatible = "arm,armv8-timer"; + interrupt-parent = <&gic>; +-- +2.51.0 + + +From bfde0dd54fbdfb71446eb27aa3ab94feafc012cf Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Tue, 17 Dec 2024 10:12:20 +0100 +Subject: [PATCH 394/517] arm64: dts: mediatek: mt7988: Add mcu-sys node for + cpu + +In preparation for adding support for CPU DVFS and clock tables for it, +add the MCUSYS clock controller node. + +Signed-off-by: Frank Wunderlich +Reviewed-by: AngeloGioacchino Del Regno +Link: https://lore.kernel.org/r/20241217091238.16032-7-linux@fw-web.de +Signed-off-by: AngeloGioacchino Del Regno +--- + arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +index 16b28fcf1e3c..5e53ea47f159 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +@@ -192,6 +192,12 @@ pwm@10048000 { + status = "disabled"; + }; + ++ mcusys: mcusys@100e0000 { ++ compatible = "mediatek,mt7988-mcusys", "syscon"; ++ reg = <0 0x100e0000 0 0x1000>; ++ #clock-cells = <1>; ++ }; ++ + serial@11000000 { + compatible = "mediatek,mt7988-uart", "mediatek,mt6577-uart"; + reg = <0 0x11000000 0 0x100>; +-- +2.51.0 + + +From a148d657d3d03a61d9612b016bfc699693c3dfc9 Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Tue, 17 Dec 2024 10:12:21 +0100 +Subject: [PATCH 395/517] arm64: dts: mediatek: mt7988: Add CPU OPP table for + clock scaling + +Add operating points defining frequency/voltages of cpu cores. + +Signed-off-by: Frank Wunderlich +Reviewed-by: AngeloGioacchino Del Regno +Link: https://lore.kernel.org/r/20241217091238.16032-8-linux@fw-web.de +Signed-off-by: AngeloGioacchino Del Regno +--- + arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 38 +++++++++++++++++++++++ + 1 file changed, 38 insertions(+) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +index 5e53ea47f159..a7954bf5c81e 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +@@ -21,6 +21,10 @@ cpu@0 { + reg = <0x0>; + device_type = "cpu"; + enable-method = "psci"; ++ clocks = <&mcusys CLK_MCU_ARM_DIV_SEL>, ++ <&topckgen CLK_TOP_XTAL>; ++ clock-names = "cpu", "intermediate"; ++ operating-points-v2 = <&cluster0_opp>; + }; + + cpu@1 { +@@ -28,6 +32,10 @@ cpu@1 { + reg = <0x1>; + device_type = "cpu"; + enable-method = "psci"; ++ clocks = <&mcusys CLK_MCU_ARM_DIV_SEL>, ++ <&topckgen CLK_TOP_XTAL>; ++ clock-names = "cpu", "intermediate"; ++ operating-points-v2 = <&cluster0_opp>; + }; + + cpu@2 { +@@ -35,6 +43,10 @@ cpu@2 { + reg = <0x2>; + device_type = "cpu"; + enable-method = "psci"; ++ clocks = <&mcusys CLK_MCU_ARM_DIV_SEL>, ++ <&topckgen CLK_TOP_XTAL>; ++ clock-names = "cpu", "intermediate"; ++ operating-points-v2 = <&cluster0_opp>; + }; + + cpu@3 { +@@ -42,6 +54,32 @@ cpu@3 { + reg = <0x3>; + device_type = "cpu"; + enable-method = "psci"; ++ clocks = <&mcusys CLK_MCU_ARM_DIV_SEL>, ++ <&topckgen CLK_TOP_XTAL>; ++ clock-names = "cpu", "intermediate"; ++ operating-points-v2 = <&cluster0_opp>; ++ }; ++ ++ cluster0_opp: opp-table-0 { ++ compatible = "operating-points-v2"; ++ opp-shared; ++ ++ opp-800000000 { ++ opp-hz = /bits/ 64 <800000000>; ++ opp-microvolt = <850000>; ++ }; ++ opp-1100000000 { ++ opp-hz = /bits/ 64 <1100000000>; ++ opp-microvolt = <850000>; ++ }; ++ opp-1500000000 { ++ opp-hz = /bits/ 64 <1500000000>; ++ opp-microvolt = <850000>; ++ }; ++ opp-1800000000 { ++ opp-hz = /bits/ 64 <1800000000>; ++ opp-microvolt = <900000>; ++ }; + }; + }; + +-- +2.51.0 + + +From a32293660d2f75d86ff0510e5080e1b6872cf19d Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Tue, 17 Dec 2024 10:12:22 +0100 +Subject: [PATCH 396/517] arm64: dts: mediatek: mt7988: Disable usb controllers + by default + +The controllers should be enabled at board level if used. + +Signed-off-by: Frank Wunderlich +Reviewed-by: AngeloGioacchino Del Regno +Link: https://lore.kernel.org/r/20241217091238.16032-9-linux@fw-web.de +Signed-off-by: AngeloGioacchino Del Regno +--- + arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +index a7954bf5c81e..f8b01f3fff32 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +@@ -334,6 +334,7 @@ usb@11190000 { + <&infracfg CLK_INFRA_133M_USB_HCK>, + <&infracfg CLK_INFRA_USB_XHCI>; + clock-names = "sys_ck", "ref_ck", "mcu_ck", "dma_ck", "xhci_ck"; ++ status = "disabled"; + }; + + usb@11200000 { +@@ -348,6 +349,7 @@ usb@11200000 { + <&infracfg CLK_INFRA_133M_USB_HCK_CK_P1>, + <&infracfg CLK_INFRA_USB_XHCI_CK_P1>; + clock-names = "sys_ck", "ref_ck", "mcu_ck", "dma_ck", "xhci_ck"; ++ status = "disabled"; + }; + + mmc0: mmc@11230000 { +-- +2.51.0 + + +From 1fdb543475c2e842edf667c3012ed827d7986831 Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Tue, 17 Dec 2024 10:12:23 +0100 +Subject: [PATCH 397/517] arm64: dts: mediatek: mt7988: Add t-phy for ssusb1 + +USB controller needs phys for working properly. +On mt7988 ssusb0 uses a xs-phy, ssusb uses t-phy. +For now add the t-phy for ssusb1. We can reuse the mt7986 compatible +here. + +Signed-off-by: Frank Wunderlich +Reviewed-by: AngeloGioacchino Del Regno +Link: https://lore.kernel.org/r/20241217091238.16032-10-linux@fw-web.de +Signed-off-by: AngeloGioacchino Del Regno +--- + arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 25 +++++++++++++++++++++++ + 1 file changed, 25 insertions(+) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +index f8b01f3fff32..209d170bce7f 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +@@ -349,6 +349,8 @@ usb@11200000 { + <&infracfg CLK_INFRA_133M_USB_HCK_CK_P1>, + <&infracfg CLK_INFRA_USB_XHCI_CK_P1>; + clock-names = "sys_ck", "ref_ck", "mcu_ck", "dma_ck", "xhci_ck"; ++ phys = <&tphyu2port0 PHY_TYPE_USB2>, ++ <&tphyu3port0 PHY_TYPE_USB3>; + status = "disabled"; + }; + +@@ -371,6 +373,29 @@ mmc0: mmc@11230000 { + status = "disabled"; + }; + ++ t-phy@11c50000 { ++ compatible = "mediatek,mt7986-tphy", ++ "mediatek,generic-tphy-v2"; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ status = "disabled"; ++ ++ tphyu2port0: usb-phy@11c50000 { ++ reg = <0 0x11c50000 0 0x700>; ++ clocks = <&infracfg CLK_INFRA_USB_UTMI_CK_P1>; ++ clock-names = "ref"; ++ #phy-cells = <1>; ++ }; ++ ++ tphyu3port0: usb-phy@11c50700 { ++ reg = <0 0x11c50700 0 0x900>; ++ clocks = <&infracfg CLK_INFRA_USB_PIPE_CK_P1>; ++ clock-names = "ref"; ++ #phy-cells = <1>; ++ }; ++ }; ++ + clock-controller@11f40000 { + compatible = "mediatek,mt7988-xfi-pll"; + reg = <0 0x11f40000 0 0x1000>; +-- +2.51.0 + + +From ba6afcc4d52795e58ce148e960c3fefe94468e69 Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Tue, 17 Dec 2024 10:12:24 +0100 +Subject: [PATCH 398/517] arm64: dts: mediatek: mt7988: Add pcie nodes + +Add pcie controllers for mt7988. Reuse mt7986 compatible. + +Signed-off-by: Frank Wunderlich +Reviewed-by: AngeloGioacchino Del Regno +Link: https://lore.kernel.org/r/20241217091238.16032-11-linux@fw-web.de +Signed-off-by: AngeloGioacchino Del Regno +--- + arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 152 ++++++++++++++++++++++ + 1 file changed, 152 insertions(+) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +index 209d170bce7f..74c75d5149d7 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +@@ -373,6 +373,158 @@ mmc0: mmc@11230000 { + status = "disabled"; + }; + ++ pcie@11280000 { ++ compatible = "mediatek,mt7986-pcie", ++ "mediatek,mt8192-pcie"; ++ device_type = "pci"; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ reg = <0 0x11280000 0 0x2000>; ++ reg-names = "pcie-mac"; ++ linux,pci-domain = <3>; ++ interrupts = ; ++ bus-range = <0x00 0xff>; ++ ranges = <0x81000000 0x00 0x20000000 0x00 ++ 0x20000000 0x00 0x00200000>, ++ <0x82000000 0x00 0x20200000 0x00 ++ 0x20200000 0x00 0x07e00000>; ++ clocks = <&infracfg CLK_INFRA_PCIE_PIPE_P2>, ++ <&infracfg CLK_INFRA_PCIE_GFMUX_TL_P2>, ++ <&infracfg CLK_INFRA_PCIE_PERI_26M_CK_P2>, ++ <&infracfg CLK_INFRA_133M_PCIE_CK_P2>; ++ clock-names = "pl_250m", "tl_26m", "peri_26m", ++ "top_133m"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pcie2_pins>; ++ status = "disabled"; ++ ++ #interrupt-cells = <1>; ++ interrupt-map-mask = <0 0 0 0x7>; ++ interrupt-map = <0 0 0 1 &pcie_intc2 0>, ++ <0 0 0 2 &pcie_intc2 1>, ++ <0 0 0 3 &pcie_intc2 2>, ++ <0 0 0 4 &pcie_intc2 3>; ++ pcie_intc2: interrupt-controller { ++ #address-cells = <0>; ++ #interrupt-cells = <1>; ++ interrupt-controller; ++ }; ++ }; ++ ++ pcie@11290000 { ++ compatible = "mediatek,mt7986-pcie", ++ "mediatek,mt8192-pcie"; ++ device_type = "pci"; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ reg = <0 0x11290000 0 0x2000>; ++ reg-names = "pcie-mac"; ++ linux,pci-domain = <2>; ++ interrupts = ; ++ bus-range = <0x00 0xff>; ++ ranges = <0x81000000 0x00 0x28000000 0x00 ++ 0x28000000 0x00 0x00200000>, ++ <0x82000000 0x00 0x28200000 0x00 ++ 0x28200000 0x00 0x07e00000>; ++ clocks = <&infracfg CLK_INFRA_PCIE_PIPE_P3>, ++ <&infracfg CLK_INFRA_PCIE_GFMUX_TL_P3>, ++ <&infracfg CLK_INFRA_PCIE_PERI_26M_CK_P3>, ++ <&infracfg CLK_INFRA_133M_PCIE_CK_P3>; ++ clock-names = "pl_250m", "tl_26m", "peri_26m", ++ "top_133m"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pcie3_pins>; ++ status = "disabled"; ++ ++ #interrupt-cells = <1>; ++ interrupt-map-mask = <0 0 0 0x7>; ++ interrupt-map = <0 0 0 1 &pcie_intc3 0>, ++ <0 0 0 2 &pcie_intc3 1>, ++ <0 0 0 3 &pcie_intc3 2>, ++ <0 0 0 4 &pcie_intc3 3>; ++ pcie_intc3: interrupt-controller { ++ #address-cells = <0>; ++ #interrupt-cells = <1>; ++ interrupt-controller; ++ }; ++ }; ++ ++ pcie@11300000 { ++ compatible = "mediatek,mt7986-pcie", ++ "mediatek,mt8192-pcie"; ++ device_type = "pci"; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ reg = <0 0x11300000 0 0x2000>; ++ reg-names = "pcie-mac"; ++ linux,pci-domain = <0>; ++ interrupts = ; ++ bus-range = <0x00 0xff>; ++ ranges = <0x81000000 0x00 0x30000000 0x00 ++ 0x30000000 0x00 0x00200000>, ++ <0x82000000 0x00 0x30200000 0x00 ++ 0x30200000 0x00 0x07e00000>; ++ clocks = <&infracfg CLK_INFRA_PCIE_PIPE_P0>, ++ <&infracfg CLK_INFRA_PCIE_GFMUX_TL_P0>, ++ <&infracfg CLK_INFRA_PCIE_PERI_26M_CK_P0>, ++ <&infracfg CLK_INFRA_133M_PCIE_CK_P0>; ++ clock-names = "pl_250m", "tl_26m", "peri_26m", ++ "top_133m"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pcie0_pins>; ++ status = "disabled"; ++ ++ #interrupt-cells = <1>; ++ interrupt-map-mask = <0 0 0 0x7>; ++ interrupt-map = <0 0 0 1 &pcie_intc0 0>, ++ <0 0 0 2 &pcie_intc0 1>, ++ <0 0 0 3 &pcie_intc0 2>, ++ <0 0 0 4 &pcie_intc0 3>; ++ pcie_intc0: interrupt-controller { ++ #address-cells = <0>; ++ #interrupt-cells = <1>; ++ interrupt-controller; ++ }; ++ }; ++ ++ pcie@11310000 { ++ compatible = "mediatek,mt7986-pcie", ++ "mediatek,mt8192-pcie"; ++ device_type = "pci"; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ reg = <0 0x11310000 0 0x2000>; ++ reg-names = "pcie-mac"; ++ linux,pci-domain = <1>; ++ interrupts = ; ++ bus-range = <0x00 0xff>; ++ ranges = <0x81000000 0x00 0x38000000 0x00 ++ 0x38000000 0x00 0x00200000>, ++ <0x82000000 0x00 0x38200000 0x00 ++ 0x38200000 0x00 0x07e00000>; ++ clocks = <&infracfg CLK_INFRA_PCIE_PIPE_P1>, ++ <&infracfg CLK_INFRA_PCIE_GFMUX_TL_P1>, ++ <&infracfg CLK_INFRA_PCIE_PERI_26M_CK_P1>, ++ <&infracfg CLK_INFRA_133M_PCIE_CK_P1>; ++ clock-names = "pl_250m", "tl_26m", "peri_26m", ++ "top_133m"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pcie1_pins>; ++ status = "disabled"; ++ ++ #interrupt-cells = <1>; ++ interrupt-map-mask = <0 0 0 0x7>; ++ interrupt-map = <0 0 0 1 &pcie_intc1 0>, ++ <0 0 0 2 &pcie_intc1 1>, ++ <0 0 0 3 &pcie_intc1 2>, ++ <0 0 0 4 &pcie_intc1 3>; ++ pcie_intc1: interrupt-controller { ++ #address-cells = <0>; ++ #interrupt-cells = <1>; ++ interrupt-controller; ++ }; ++ }; ++ + t-phy@11c50000 { + compatible = "mediatek,mt7986-tphy", + "mediatek,generic-tphy-v2"; +-- +2.51.0 + + +From a99265c23bb893b0b9c5f5ba13fdacb5a21652ce Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Tue, 17 Dec 2024 09:54:30 +0100 +Subject: [PATCH 399/517] arm64: dts: mediatek: mt7988a-bpi-r4: Add pinctrl + subnodes for bpi-r4 + +Add board specific pinctrl configurations on Bananapi R4. + +Signed-off-by: Frank Wunderlich +Reviewed-by: AngeloGioacchino Del Regno +Link: https://lore.kernel.org/r/20241217085435.9586-6-linux@fw-web.de +Signed-off-by: AngeloGioacchino Del Regno +--- + .../dts/mediatek/mt7988a-bananapi-bpi-r4.dts | 189 ++++++++++++++++++ + 1 file changed, 189 insertions(+) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts +index efc4ad0b08b8..aa2dabc041fd 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts +@@ -9,3 +9,192 @@ / { + model = "Banana Pi BPI-R4"; + chassis-type = "embedded"; + }; ++ ++&pio { ++ mdio0_pins: mdio0-pins { ++ mux { ++ function = "eth"; ++ groups = "mdc_mdio0"; ++ }; ++ ++ conf { ++ pins = "SMI_0_MDC", "SMI_0_MDIO"; ++ drive-strength = <8>; ++ }; ++ }; ++ ++ i2c0_pins: i2c0-g0-pins { ++ mux { ++ function = "i2c"; ++ groups = "i2c0_1"; ++ }; ++ }; ++ ++ i2c1_pins: i2c1-g0-pins { ++ mux { ++ function = "i2c"; ++ groups = "i2c1_0"; ++ }; ++ }; ++ ++ i2c1_sfp_pins: i2c1-sfp-g0-pins { ++ mux { ++ function = "i2c"; ++ groups = "i2c1_sfp"; ++ }; ++ }; ++ ++ i2c2_0_pins: i2c2-g0-pins { ++ mux { ++ function = "i2c"; ++ groups = "i2c2_0"; ++ }; ++ }; ++ ++ i2c2_1_pins: i2c2-g1-pins { ++ mux { ++ function = "i2c"; ++ groups = "i2c2_1"; ++ }; ++ }; ++ ++ gbe0_led0_pins: gbe0-led0-pins { ++ mux { ++ function = "led"; ++ groups = "gbe0_led0"; ++ }; ++ }; ++ ++ gbe1_led0_pins: gbe1-led0-pins { ++ mux { ++ function = "led"; ++ groups = "gbe1_led0"; ++ }; ++ }; ++ ++ gbe2_led0_pins: gbe2-led0-pins { ++ mux { ++ function = "led"; ++ groups = "gbe2_led0"; ++ }; ++ }; ++ ++ gbe3_led0_pins: gbe3-led0-pins { ++ mux { ++ function = "led"; ++ groups = "gbe3_led0"; ++ }; ++ }; ++ ++ gbe0_led1_pins: gbe0-led1-pins { ++ mux { ++ function = "led"; ++ groups = "gbe0_led1"; ++ }; ++ }; ++ ++ gbe1_led1_pins: gbe1-led1-pins { ++ mux { ++ function = "led"; ++ groups = "gbe1_led1"; ++ }; ++ }; ++ ++ gbe2_led1_pins: gbe2-led1-pins { ++ mux { ++ function = "led"; ++ groups = "gbe2_led1"; ++ }; ++ }; ++ ++ gbe3_led1_pins: gbe3-led1-pins { ++ mux { ++ function = "led"; ++ groups = "gbe3_led1"; ++ }; ++ }; ++ ++ i2p5gbe_led0_pins: 2p5gbe-led0-pins { ++ mux { ++ function = "led"; ++ groups = "2p5gbe_led0"; ++ }; ++ }; ++ ++ i2p5gbe_led1_pins: 2p5gbe-led1-pins { ++ mux { ++ function = "led"; ++ groups = "2p5gbe_led1"; ++ }; ++ }; ++ ++ mmc0_pins_emmc_45: mmc0-emmc-45-pins { ++ mux { ++ function = "flash"; ++ groups = "emmc_45"; ++ }; ++ }; ++ ++ mmc0_pins_emmc_51: mmc0-emmc-51-pins { ++ mux { ++ function = "flash"; ++ groups = "emmc_51"; ++ }; ++ }; ++ ++ mmc0_pins_sdcard: mmc0-sdcard-pins { ++ mux { ++ function = "flash"; ++ groups = "sdcard"; ++ }; ++ }; ++ ++ uart0_pins: uart0-pins { ++ mux { ++ function = "uart"; ++ groups = "uart0"; ++ }; ++ }; ++ ++ snfi_pins: snfi-pins { ++ mux { ++ function = "flash"; ++ groups = "snfi"; ++ }; ++ }; ++ ++ spi0_pins: spi0-pins { ++ mux { ++ function = "spi"; ++ groups = "spi0"; ++ }; ++ }; ++ ++ spi0_flash_pins: spi0-flash-pins { ++ mux { ++ function = "spi"; ++ groups = "spi0", "spi0_wp_hold"; ++ }; ++ }; ++ ++ spi1_pins: spi1-pins { ++ mux { ++ function = "spi"; ++ groups = "spi1"; ++ }; ++ }; ++ ++ spi2_pins: spi2-pins { ++ mux { ++ function = "spi"; ++ groups = "spi2"; ++ }; ++ }; ++ ++ spi2_flash_pins: spi2-flash-pins { ++ mux { ++ function = "spi"; ++ groups = "spi2", "spi2_wp_hold"; ++ }; ++ }; ++}; +-- +2.51.0 + + +From c311c2eff0873eac18886281d368b42581c01d1c Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Tue, 17 Dec 2024 10:12:25 +0100 +Subject: [PATCH 400/517] arm64: dts: mediatek: mt7988a-bpi-r4: Enable watchdog + +Enable the watchdog on Bananapi R4 board. + +Signed-off-by: Frank Wunderlich +Reviewed-by: AngeloGioacchino Del Regno +Link: https://lore.kernel.org/r/20241217091238.16032-12-linux@fw-web.de +Signed-off-by: AngeloGioacchino Del Regno +--- + arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts +index aa2dabc041fd..d914eae2b524 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts +@@ -198,3 +198,7 @@ mux { + }; + }; + }; ++ ++&watchdog { ++ status = "okay"; ++}; +-- +2.51.0 + + +From 65c66cd8018fd84c92c9ccf5f0c678d50229c7c5 Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Tue, 17 Dec 2024 10:12:26 +0100 +Subject: [PATCH 401/517] arm64: dts: mediatek: mt7988a-bpi-r4: Add fixed + regulators for 1v8 and 3v3 + +Add regulator nodes used for mmc to Bananapi R4 board. +This board has 1 MMC controller used for SDMMC and eMMC where only one can +be used at one time, selected by hardware switches. SD uses 3v3 for both +supplies and emmc uses both regulators. +So defining both regulators in board dts and referencing them in the dt +overlay. + +Signed-off-by: Frank Wunderlich +Reviewed-by: AngeloGioacchino Del Regno +Link: https://lore.kernel.org/r/20241217091238.16032-13-linux@fw-web.de +Signed-off-by: AngeloGioacchino Del Regno +--- + .../dts/mediatek/mt7988a-bananapi-bpi-r4.dts | 18 ++++++++++++++++++ + 1 file changed, 18 insertions(+) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts +index d914eae2b524..df53512c6890 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts +@@ -8,6 +8,24 @@ / { + compatible = "bananapi,bpi-r4", "mediatek,mt7988a"; + model = "Banana Pi BPI-R4"; + chassis-type = "embedded"; ++ ++ reg_1p8v: regulator-1p8v { ++ compatible = "regulator-fixed"; ++ regulator-name = "fixed-1.8V"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ reg_3p3v: regulator-3p3v { ++ compatible = "regulator-fixed"; ++ regulator-name = "fixed-3.3V"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; + }; + + &pio { +-- +2.51.0 + + +From fbf80ec8ea987d4b1502f5c3cd828178cd25ae60 Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Tue, 17 Dec 2024 10:12:28 +0100 +Subject: [PATCH 402/517] arm64: dts: mediatek: mt7988a-bpi-r4: Add thermal + configuration + +Add additional thermal trips to Bananapi R4 board. +SoC only contains the critical trip. + +Signed-off-by: Frank Wunderlich +Reviewed-by: AngeloGioacchino Del Regno +Link: https://lore.kernel.org/r/20241217091238.16032-15-linux@fw-web.de +Signed-off-by: AngeloGioacchino Del Regno +--- + .../dts/mediatek/mt7988a-bananapi-bpi-r4.dts | 28 +++++++++++++++++++ + 1 file changed, 28 insertions(+) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts +index df53512c6890..8a320d9da443 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts +@@ -28,6 +28,34 @@ reg_3p3v: regulator-3p3v { + }; + }; + ++&cpu_thermal { ++ trips { ++ cpu_trip_hot: hot { ++ temperature = <120000>; ++ hysteresis = <2000>; ++ type = "hot"; ++ }; ++ ++ cpu_trip_active_high: active-high { ++ temperature = <115000>; ++ hysteresis = <2000>; ++ type = "active"; ++ }; ++ ++ cpu_trip_active_med: active-med { ++ temperature = <85000>; ++ hysteresis = <2000>; ++ type = "active"; ++ }; ++ ++ cpu_trip_active_low: active-low { ++ temperature = <40000>; ++ hysteresis = <2000>; ++ type = "active"; ++ }; ++ }; ++}; ++ + &pio { + mdio0_pins: mdio0-pins { + mux { +-- +2.51.0 + + +From d9387686201948033cc157e6f558a74355d26df5 Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Tue, 17 Dec 2024 10:12:29 +0100 +Subject: [PATCH 403/517] arm64: dts: mediatek: mt7988a-bpi-r4: Enable serial0 + debug uart + +Enable the debug uart on Bananapi R4 board. + +Signed-off-by: Frank Wunderlich +Reviewed-by: AngeloGioacchino Del Regno +Link: https://lore.kernel.org/r/20241217091238.16032-16-linux@fw-web.de +Signed-off-by: AngeloGioacchino Del Regno +--- + arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts | 4 ++++ + arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 2 +- + 2 files changed, 5 insertions(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts +index 8a320d9da443..9037f35857a9 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts +@@ -245,6 +245,10 @@ mux { + }; + }; + ++&serial0 { ++ status = "okay"; ++}; ++ + &watchdog { + status = "okay"; + }; +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +index 74c75d5149d7..59a1ffc2edfc 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +@@ -236,7 +236,7 @@ mcusys: mcusys@100e0000 { + #clock-cells = <1>; + }; + +- serial@11000000 { ++ serial0: serial@11000000 { + compatible = "mediatek,mt7988-uart", "mediatek,mt6577-uart"; + reg = <0 0x11000000 0 0x100>; + interrupts = ; +-- +2.51.0 + + +From cf8247feecf2566f95bffc1b759132155c0f00de Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Tue, 17 Dec 2024 10:12:30 +0100 +Subject: [PATCH 404/517] arm64: dts: mediatek: mt7988a-bpi-r4: Add default + UART stdout + +Add chosen node on Bananapi R4 board with stdout and default bootargs. + +Signed-off-by: Frank Wunderlich +Reviewed-by: AngeloGioacchino Del Regno +Link: https://lore.kernel.org/r/20241217091238.16032-17-linux@fw-web.de +Signed-off-by: AngeloGioacchino Del Regno +--- + arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts +index 9037f35857a9..46117df7d44c 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts +@@ -9,6 +9,10 @@ / { + model = "Banana Pi BPI-R4"; + chassis-type = "embedded"; + ++ chosen { ++ stdout-path = "serial0:115200n8"; ++ }; ++ + reg_1p8v: regulator-1p8v { + compatible = "regulator-fixed"; + regulator-name = "fixed-1.8V"; +-- +2.51.0 + + +From 0ae0dc4c7db9945521c400ffdf8f02879b50689c Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Tue, 17 Dec 2024 10:12:31 +0100 +Subject: [PATCH 405/517] arm64: dts: mediatek: mt7988a-bpi-r4: Enable I2C + controllers + +Enable the I2C0, I2C2 controllers found on the BananaPi R4 board. +Both controllers are not accessible from user and having fixed spare +devices. I2C0 have a pmic connected, I2C2 is used with I2C-multiplexer +for e.g. SFP cages. +The missing I2C1 is connected to GPIO header which can have either GPIO +mode or I2C mode. + +Signed-off-by: Frank Wunderlich +Reviewed-by: AngeloGioacchino Del Regno +Link: https://lore.kernel.org/r/20241217091238.16032-18-linux@fw-web.de +Signed-off-by: AngeloGioacchino Del Regno +--- + .../boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts | 12 ++++++++++++ + arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 6 +++--- + 2 files changed, 15 insertions(+), 3 deletions(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts +index 46117df7d44c..3d165f7b29dc 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts +@@ -60,6 +60,18 @@ cpu_trip_active_low: active-low { + }; + }; + ++&i2c0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c0_pins>; ++ status = "okay"; ++}; ++ ++&i2c2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c2_1_pins>; ++ status = "okay"; ++}; ++ + &pio { + mdio0_pins: mdio0-pins { + mux { +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +index 59a1ffc2edfc..c0a49f68834a 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +@@ -269,7 +269,7 @@ serial@11000200 { + status = "disabled"; + }; + +- i2c@11003000 { ++ i2c0: i2c@11003000 { + compatible = "mediatek,mt7981-i2c"; + reg = <0 0x11003000 0 0x1000>, + <0 0x10217080 0 0x80>; +@@ -283,7 +283,7 @@ i2c@11003000 { + status = "disabled"; + }; + +- i2c@11004000 { ++ i2c1: i2c@11004000 { + compatible = "mediatek,mt7981-i2c"; + reg = <0 0x11004000 0 0x1000>, + <0 0x10217100 0 0x80>; +@@ -297,7 +297,7 @@ i2c@11004000 { + status = "disabled"; + }; + +- i2c@11005000 { ++ i2c2: i2c@11005000 { + compatible = "mediatek,mt7981-i2c"; + reg = <0 0x11005000 0 0x1000>, + <0 0x10217180 0 0x80>; +-- +2.51.0 + + +From cb1ff418a05559a1e32911d8721217269d978c3f Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Tue, 17 Dec 2024 10:12:32 +0100 +Subject: [PATCH 406/517] arm64: dts: mediatek: mt7988a-bpi-r4: Add PCA9545 I2C + Mux + +Bananapi R4 uses an i2c multiplexer for SFP slots, rtc and eeprom. +Add its node to the right i2c controller. + +Signed-off-by: Frank Wunderlich +Reviewed-by: AngeloGioacchino Del Regno +Link: https://lore.kernel.org/r/20241217091238.16032-19-linux@fw-web.de +Signed-off-by: AngeloGioacchino Del Regno +--- + .../dts/mediatek/mt7988a-bananapi-bpi-r4.dts | 41 +++++++++++++++++++ + 1 file changed, 41 insertions(+) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts +index 3d165f7b29dc..0dc1fd9265c6 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts +@@ -2,6 +2,8 @@ + + /dts-v1/; + ++#include ++ + #include "mt7988a.dtsi" + + / { +@@ -70,6 +72,45 @@ &i2c2 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c2_1_pins>; + status = "okay"; ++ ++ pca9545: i2c-mux@70 { ++ compatible = "nxp,pca9545"; ++ reg = <0x70>; ++ reset-gpios = <&pio 5 GPIO_ACTIVE_LOW>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ i2c@0 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0>; ++ ++ pcf8563: rtc@51 { ++ compatible = "nxp,pcf8563"; ++ reg = <0x51>; ++ #clock-cells = <0>; ++ }; ++ ++ eeprom@57 { ++ compatible = "atmel,24c02"; ++ reg = <0x57>; ++ size = <256>; ++ }; ++ ++ }; ++ ++ i2c_sfp1: i2c@1 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <1>; ++ }; ++ ++ i2c_sfp2: i2c@2 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <2>; ++ }; ++ }; + }; + + &pio { +-- +2.51.0 + + +From fc1e5be0bc78c5339f0d864251b4da8e72a4bf09 Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Tue, 17 Dec 2024 10:12:33 +0100 +Subject: [PATCH 407/517] arm64: dts: mediatek: mt7988a-bpi-r4: Enable t-phy + for ssusb1 + +Bananapi R4 uses t-phy for usb. Enable its node at board level. + +Signed-off-by: Frank Wunderlich +Reviewed-by: AngeloGioacchino Del Regno +Link: https://lore.kernel.org/r/20241217091238.16032-20-linux@fw-web.de +Signed-off-by: AngeloGioacchino Del Regno +--- + arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts | 4 ++++ + arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 2 +- + 2 files changed, 5 insertions(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts +index 0dc1fd9265c6..129031b0d784 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts +@@ -306,6 +306,10 @@ &serial0 { + status = "okay"; + }; + ++&tphy { ++ status = "okay"; ++}; ++ + &watchdog { + status = "okay"; + }; +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +index c0a49f68834a..0766ca0dd3f6 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +@@ -525,7 +525,7 @@ pcie_intc1: interrupt-controller { + }; + }; + +- t-phy@11c50000 { ++ tphy: t-phy@11c50000 { + compatible = "mediatek,mt7986-tphy", + "mediatek,generic-tphy-v2"; + #address-cells = <2>; +-- +2.51.0 + + +From 622671b5fc76a6544e1394c8ea019ad7e90a22f4 Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Tue, 17 Dec 2024 10:12:34 +0100 +Subject: [PATCH 408/517] arm64: dts: mediatek: mt7988a-bpi-r4: Enable ssusb1 + on bpi-r4 + +Enable usb on Bananapi R4 board. + +Signed-off-by: Frank Wunderlich +Reviewed-by: AngeloGioacchino Del Regno +Link: https://lore.kernel.org/r/20241217091238.16032-21-linux@fw-web.de +Signed-off-by: AngeloGioacchino Del Regno +--- + arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts | 4 ++++ + arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 2 +- + 2 files changed, 5 insertions(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts +index 129031b0d784..08d664d6449b 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts +@@ -306,6 +306,10 @@ &serial0 { + status = "okay"; + }; + ++&ssusb1 { ++ status = "okay"; ++}; ++ + &tphy { + status = "okay"; + }; +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +index 0766ca0dd3f6..f3e942db0b99 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +@@ -337,7 +337,7 @@ usb@11190000 { + status = "disabled"; + }; + +- usb@11200000 { ++ ssusb1: usb@11200000 { + compatible = "mediatek,mt7988-xhci", "mediatek,mtk-xhci"; + reg = <0 0x11200000 0 0x2e00>, + <0 0x11203e00 0 0x0100>; +-- +2.51.0 + + +From d985de90a4c6d7b466c7d42d85095604a83a63fe Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Tue, 17 Dec 2024 10:12:35 +0100 +Subject: [PATCH 409/517] arm64: dts: mediatek: mt7988a-bpi-r4: Enable pwm + +Enable pwm on Bananapi R4 board. + +Signed-off-by: Frank Wunderlich +Reviewed-by: AngeloGioacchino Del Regno +Link: https://lore.kernel.org/r/20241217091238.16032-22-linux@fw-web.de +Signed-off-by: AngeloGioacchino Del Regno +--- + arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts | 4 ++++ + arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 2 +- + 2 files changed, 5 insertions(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts +index 08d664d6449b..4b1eaf818b66 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts +@@ -302,6 +302,10 @@ mux { + }; + }; + ++&pwm { ++ status = "okay"; ++}; ++ + &serial0 { + status = "okay"; + }; +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +index f3e942db0b99..6f6a1a1c1d78 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +@@ -211,7 +211,7 @@ mux { + }; + }; + +- pwm@10048000 { ++ pwm: pwm@10048000 { + compatible = "mediatek,mt7988-pwm"; + reg = <0 0x10048000 0 0x1000>; + clocks = <&infracfg CLK_INFRA_66M_PWM_BCK>, +-- +2.51.0 + + +From 0d428f6a03e252a4977c226592370b6057ba47ec Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Tue, 17 Dec 2024 10:12:36 +0100 +Subject: [PATCH 410/517] arm64: dts: mediatek: mt7988a-bpi-r4: Enable pcie + +Enable the pci controllers on BPI-R4. + +Signed-off-by: Frank Wunderlich +Reviewed-by: AngeloGioacchino Del Regno +Link: https://lore.kernel.org/r/20241217091238.16032-23-linux@fw-web.de +Signed-off-by: AngeloGioacchino Del Regno +--- + .../dts/mediatek/mt7988a-bananapi-bpi-r4.dts | 20 +++++++++++++++++++ + arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 8 ++++---- + 2 files changed, 24 insertions(+), 4 deletions(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts +index 4b1eaf818b66..d6f1fca3323c 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts +@@ -113,6 +113,26 @@ i2c_sfp2: i2c@2 { + }; + }; + ++/* mPCIe SIM2 */ ++&pcie0 { ++ status = "okay"; ++}; ++ ++/* mPCIe SIM3 */ ++&pcie1 { ++ status = "okay"; ++}; ++ ++/* M.2 key-B SIM1 */ ++&pcie2 { ++ status = "okay"; ++}; ++ ++/* M.2 key-M SSD */ ++&pcie3 { ++ status = "okay"; ++}; ++ + &pio { + mdio0_pins: mdio0-pins { + mux { +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +index 6f6a1a1c1d78..7a5e16a97476 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +@@ -373,7 +373,7 @@ mmc0: mmc@11230000 { + status = "disabled"; + }; + +- pcie@11280000 { ++ pcie2: pcie@11280000 { + compatible = "mediatek,mt7986-pcie", + "mediatek,mt8192-pcie"; + device_type = "pci"; +@@ -411,7 +411,7 @@ pcie_intc2: interrupt-controller { + }; + }; + +- pcie@11290000 { ++ pcie3: pcie@11290000 { + compatible = "mediatek,mt7986-pcie", + "mediatek,mt8192-pcie"; + device_type = "pci"; +@@ -449,7 +449,7 @@ pcie_intc3: interrupt-controller { + }; + }; + +- pcie@11300000 { ++ pcie0: pcie@11300000 { + compatible = "mediatek,mt7986-pcie", + "mediatek,mt8192-pcie"; + device_type = "pci"; +@@ -487,7 +487,7 @@ pcie_intc0: interrupt-controller { + }; + }; + +- pcie@11310000 { ++ pcie1: pcie@11310000 { + compatible = "mediatek,mt7986-pcie", + "mediatek,mt8192-pcie"; + device_type = "pci"; +-- +2.51.0 + + +From b3e25597ce6ae8971e784945a00c8bdbd7866883 Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Fri, 20 Dec 2024 17:38:35 +0100 +Subject: [PATCH 411/517] arm64: dts: mediatek: mt7988a-bpi-r4: Add MediaTek + MT6682A/RT5190A PMIC + +Bananapi R4 Board contains a MT6682A pmic which is compatible to rt5190a. +Add its node to the i2 controller. + +The BananaPi R4 board has a MediaTek MT6682A PMIC, a rebrand of the +Richtek RT5190A chip, connected to the I2C0 bus. + +Add the relevant node and, while at it, also configure the regulators +from this PMIC that are used on this board. + +Only Buck2/Buck3 voltage can be controlled by software. + +BUCK4 input is 5V from BUCK1 output, and the resistor (mapped to RP30/RP31 +on BPI-R4) configures BUCK4 output to 1.8V. +LDO input is 3.3V from 3.3VD, and the resistor (mapped to RP38/RP40 on +BPI-R4) configures LDO output to 1.8V. + +Signed-off-by: Frank Wunderlich +Reviewed-by: AngeloGioacchino Del Regno +Link: https://lore.kernel.org/r/20241220163838.114786-2-linux@fw-web.de +Signed-off-by: AngeloGioacchino Del Regno +--- + .../dts/mediatek/mt7988a-bananapi-bpi-r4.dts | 50 +++++++++++++++++++ + 1 file changed, 50 insertions(+) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts +index d6f1fca3323c..27edc6b84f80 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts +@@ -3,6 +3,7 @@ + /dts-v1/; + + #include ++#include + + #include "mt7988a.dtsi" + +@@ -66,6 +67,55 @@ &i2c0 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c0_pins>; + status = "okay"; ++ ++ rt5190a_64: rt5190a@64 { ++ compatible = "richtek,rt5190a"; ++ reg = <0x64>; ++ vin2-supply = <&rt5190_buck1>; ++ vin3-supply = <&rt5190_buck1>; ++ vin4-supply = <&rt5190_buck1>; ++ ++ regulators { ++ rt5190_buck1: buck1 { ++ regulator-name = "rt5190a-buck1"; ++ regulator-min-microvolt = <5090000>; ++ regulator-max-microvolt = <5090000>; ++ regulator-allowed-modes = ++ , ; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ buck2 { ++ regulator-name = "vcore"; ++ regulator-min-microvolt = <600000>; ++ regulator-max-microvolt = <1400000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ rt5190_buck3: buck3 { ++ regulator-name = "vproc"; ++ regulator-min-microvolt = <600000>; ++ regulator-max-microvolt = <1400000>; ++ regulator-boot-on; ++ }; ++ buck4 { ++ regulator-name = "rt5190a-buck4"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-allowed-modes = ++ , ; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ldo { ++ regulator-name = "rt5190a-ldo"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ }; ++ }; + }; + + &i2c2 { +-- +2.51.0 + + +From 200185c61220ecb7982d5605701649e925c7e11b Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Fri, 20 Dec 2024 17:38:36 +0100 +Subject: [PATCH 412/517] arm64: dts: mediatek: mt7988a-bpi-r4: Add proc-supply + for cpus + +Add proc-supply property to cpus on Bananapi R4 board. + +Signed-off-by: Frank Wunderlich +Reviewed-by: AngeloGioacchino Del Regno +Link: https://lore.kernel.org/r/20241220163838.114786-3-linux@fw-web.de +Signed-off-by: AngeloGioacchino Del Regno +--- + .../dts/mediatek/mt7988a-bananapi-bpi-r4.dts | 16 ++++++++++++++++ + arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 8 ++++---- + 2 files changed, 20 insertions(+), 4 deletions(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts +index 27edc6b84f80..6623112c24c7 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts +@@ -35,6 +35,22 @@ reg_3p3v: regulator-3p3v { + }; + }; + ++&cpu0 { ++ proc-supply = <&rt5190_buck3>; ++}; ++ ++&cpu1 { ++ proc-supply = <&rt5190_buck3>; ++}; ++ ++&cpu2 { ++ proc-supply = <&rt5190_buck3>; ++}; ++ ++&cpu3 { ++ proc-supply = <&rt5190_buck3>; ++}; ++ + &cpu_thermal { + trips { + cpu_trip_hot: hot { +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +index 7a5e16a97476..88b56a24efca 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +@@ -16,7 +16,7 @@ cpus { + #address-cells = <1>; + #size-cells = <0>; + +- cpu@0 { ++ cpu0: cpu@0 { + compatible = "arm,cortex-a73"; + reg = <0x0>; + device_type = "cpu"; +@@ -27,7 +27,7 @@ cpu@0 { + operating-points-v2 = <&cluster0_opp>; + }; + +- cpu@1 { ++ cpu1: cpu@1 { + compatible = "arm,cortex-a73"; + reg = <0x1>; + device_type = "cpu"; +@@ -38,7 +38,7 @@ cpu@1 { + operating-points-v2 = <&cluster0_opp>; + }; + +- cpu@2 { ++ cpu2: cpu@2 { + compatible = "arm,cortex-a73"; + reg = <0x2>; + device_type = "cpu"; +@@ -49,7 +49,7 @@ cpu@2 { + operating-points-v2 = <&cluster0_opp>; + }; + +- cpu@3 { ++ cpu3: cpu@3 { + compatible = "arm,cortex-a73"; + reg = <0x3>; + device_type = "cpu"; +-- +2.51.0 + + +From 59d0aeb36921af8a5aea530485a6ede3adf9abc3 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Tue, 22 Apr 2025 15:24:29 +0200 +Subject: [PATCH 413/517] phy: mediatek: xsphy: support type switch by pericfg + +Patch from Sam Shih found in MediaTek SDK +released under GPL. + +Get syscon and use it to set the PHY type. +Extend support to PCIe and SGMII mode in addition to USB2 and USB3. + +Signed-off-by: Daniel Golle +Signed-off-by: Frank Wunderlich +Reviewed-by: AngeloGioacchino Del Regno +--- + drivers/phy/mediatek/phy-mtk-xsphy.c | 85 +++++++++++++++++++++++++++- + 1 file changed, 84 insertions(+), 1 deletion(-) + +diff --git a/drivers/phy/mediatek/phy-mtk-xsphy.c b/drivers/phy/mediatek/phy-mtk-xsphy.c +index 7c248f5cfca5..c0ddb9273cc3 100644 +--- a/drivers/phy/mediatek/phy-mtk-xsphy.c ++++ b/drivers/phy/mediatek/phy-mtk-xsphy.c +@@ -11,10 +11,12 @@ + #include + #include + #include ++#include + #include + #include + #include + #include ++#include + + #include "phy-mtk-io.h" + +@@ -81,12 +83,22 @@ + #define XSP_SR_COEF_DIVISOR 1000 + #define XSP_FM_DET_CYCLE_CNT 1024 + ++/* PHY switch between pcie/usb3/sgmii */ ++#define USB_PHY_SWITCH_CTRL 0x0 ++#define RG_PHY_SW_TYPE GENMASK(3, 0) ++#define RG_PHY_SW_PCIE 0x0 ++#define RG_PHY_SW_USB3 0x1 ++#define RG_PHY_SW_SGMII 0x2 ++ + struct xsphy_instance { + struct phy *phy; + void __iomem *port_base; + struct clk *ref_clk; /* reference clock of anolog phy */ + u32 index; + u32 type; ++ struct regmap *type_sw; ++ u32 type_sw_reg; ++ u32 type_sw_index; + /* only for HQA test */ + int efuse_intr; + int efuse_tx_imp; +@@ -259,6 +271,10 @@ static void phy_parse_property(struct mtk_xsphy *xsphy, + inst->efuse_intr, inst->efuse_tx_imp, + inst->efuse_rx_imp); + break; ++ case PHY_TYPE_PCIE: ++ case PHY_TYPE_SGMII: ++ /* nothing to do */ ++ break; + default: + dev_err(xsphy->dev, "incompatible phy type\n"); + return; +@@ -305,6 +321,62 @@ static void u3_phy_props_set(struct mtk_xsphy *xsphy, + RG_XTP_LN0_RX_IMPSEL, inst->efuse_rx_imp); + } + ++/* type switch for usb3/pcie/sgmii */ ++static int phy_type_syscon_get(struct xsphy_instance *instance, ++ struct device_node *dn) ++{ ++ struct of_phandle_args args; ++ int ret; ++ ++ /* type switch function is optional */ ++ if (!of_property_present(dn, "mediatek,syscon-type")) ++ return 0; ++ ++ ret = of_parse_phandle_with_fixed_args(dn, "mediatek,syscon-type", ++ 2, 0, &args); ++ if (ret) ++ return ret; ++ ++ instance->type_sw_reg = args.args[0]; ++ instance->type_sw_index = args.args[1] & 0x3; /* <=3 */ ++ instance->type_sw = syscon_node_to_regmap(args.np); ++ of_node_put(args.np); ++ dev_info(&instance->phy->dev, "type_sw - reg %#x, index %d\n", ++ instance->type_sw_reg, instance->type_sw_index); ++ ++ return PTR_ERR_OR_ZERO(instance->type_sw); ++} ++ ++static int phy_type_set(struct xsphy_instance *instance) ++{ ++ int type; ++ u32 offset; ++ ++ if (!instance->type_sw) ++ return 0; ++ ++ switch (instance->type) { ++ case PHY_TYPE_USB3: ++ type = RG_PHY_SW_USB3; ++ break; ++ case PHY_TYPE_PCIE: ++ type = RG_PHY_SW_PCIE; ++ break; ++ case PHY_TYPE_SGMII: ++ type = RG_PHY_SW_SGMII; ++ break; ++ case PHY_TYPE_USB2: ++ default: ++ return 0; ++ } ++ ++ offset = instance->type_sw_index * BITS_PER_BYTE; ++ regmap_update_bits(instance->type_sw, instance->type_sw_reg, ++ RG_PHY_SW_TYPE << offset, type << offset); ++ ++ return 0; ++} ++ + static int mtk_phy_init(struct phy *phy) + { + struct xsphy_instance *inst = phy_get_drvdata(phy); +@@ -325,6 +397,10 @@ static int mtk_phy_init(struct phy *phy) + case PHY_TYPE_USB3: + u3_phy_props_set(xsphy, inst); + break; ++ case PHY_TYPE_PCIE: ++ case PHY_TYPE_SGMII: ++ /* nothing to do, only used to set type */ ++ break; + default: + dev_err(xsphy->dev, "incompatible phy type\n"); + clk_disable_unprepare(inst->ref_clk); +@@ -403,12 +479,15 @@ static struct phy *mtk_phy_xlate(struct device *dev, + + inst->type = args->args[0]; + if (!(inst->type == PHY_TYPE_USB2 || +- inst->type == PHY_TYPE_USB3)) { ++ inst->type == PHY_TYPE_USB3 || ++ inst->type == PHY_TYPE_PCIE || ++ inst->type == PHY_TYPE_SGMII)) { + dev_err(dev, "unsupported phy type: %d\n", inst->type); + return ERR_PTR(-EINVAL); + } + + phy_parse_property(xsphy, inst); ++ phy_type_set(inst); + + return inst->phy; + } +@@ -510,6 +589,10 @@ static int mtk_xsphy_probe(struct platform_device *pdev) + dev_err(dev, "failed to get ref_clk(id-%d)\n", port); + return PTR_ERR(inst->ref_clk); + } ++ ++ retval = phy_type_syscon_get(inst, child_np); ++ if (retval) ++ return retval; + } + + provider = devm_of_phy_provider_register(dev, mtk_phy_xlate); +-- +2.51.0 + + +From 15a3afc987aa9c3756760898f296372abd94f71b Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Sat, 12 Oct 2024 16:38:23 +0200 +Subject: [PATCH 414/517] mmc: mtk-sd: add support for mt7988 + +Add support for mmc on MT7988 SoC. + +We can use mt7986 platform data in driver, but mt7988 needs different +clocks so for binding we need own compatible. + +Signed-off-by: Frank Wunderlich +Reviewed-by: AngeloGioacchino Del Regno +Message-ID: <20241012143826.7690-3-linux@fw-web.de> +Signed-off-by: Ulf Hansson +--- + drivers/mmc/host/mtk-sd.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c +index be9954f5bc0a..4a486eb77f3b 100644 +--- a/drivers/mmc/host/mtk-sd.c ++++ b/drivers/mmc/host/mtk-sd.c +@@ -631,6 +631,7 @@ static const struct of_device_id msdc_of_ids[] = { + { .compatible = "mediatek,mt7620-mmc", .data = &mt7620_compat}, + { .compatible = "mediatek,mt7622-mmc", .data = &mt7622_compat}, + { .compatible = "mediatek,mt7986-mmc", .data = &mt7986_compat}, ++ { .compatible = "mediatek,mt7988-mmc", .data = &mt7986_compat}, + { .compatible = "mediatek,mt8135-mmc", .data = &mt8135_compat}, + { .compatible = "mediatek,mt8173-mmc", .data = &mt8173_compat}, + { .compatible = "mediatek,mt8183-mmc", .data = &mt8183_compat}, +-- +2.51.0 + + +From 1cd673167f75da5662cfd2762a35245b0799b743 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= +Date: Mon, 3 Nov 2025 15:50:38 +0100 +Subject: [PATCH 415/517] + /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/100-dts-update-mt7622-rfb1.patch + +--- + arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts | 44 +++++++++++++------- + 1 file changed, 29 insertions(+), 15 deletions(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts b/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts +index 8c3e2e2578bc..5280ca95e5c1 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts +@@ -1,7 +1,6 @@ + /* +- * Copyright (c) 2017 MediaTek Inc. +- * Author: Ming Huang +- * Sean Wang ++ * Copyright (c) 2018 MediaTek Inc. ++ * Author: Ryder Lee + * + * SPDX-License-Identifier: (GPL-2.0 OR MIT) + */ +@@ -24,7 +23,7 @@ aliases { + + chosen { + stdout-path = "serial0:115200n8"; +- bootargs = "earlycon=uart8250,mmio32,0x11002000 swiotlb=512"; ++ bootargs = "earlycon=uart8250,mmio32,0x11002000 console=ttyS0,115200n1 swiotlb=512"; + }; + + cpus { +@@ -45,18 +44,18 @@ gpio-keys { + key-factory { + label = "factory"; + linux,code = ; +- gpios = <&pio 0 0>; ++ gpios = <&pio 0 GPIO_ACTIVE_LOW>; + }; + + key-wps { + label = "wps"; + linux,code = ; +- gpios = <&pio 102 0>; ++ gpios = <&pio 102 GPIO_ACTIVE_LOW>; + }; + }; + + memory@40000000 { +- reg = <0 0x40000000 0 0x20000000>; ++ reg = <0 0x40000000 0 0x40000000>; + device_type = "memory"; + }; + +@@ -134,9 +133,9 @@ mdio-bus { + #address-cells = <1>; + #size-cells = <0>; + +- switch@0 { ++ switch@1f { + compatible = "mediatek,mt7531"; +- reg = <0>; ++ reg = <31>; + reset-gpios = <&pio 54 0>; + + ports { +@@ -145,22 +144,22 @@ ports { + + port@0 { + reg = <0>; +- label = "lan0"; ++ label = "lan1"; + }; + + port@1 { + reg = <1>; +- label = "lan1"; ++ label = "lan2"; + }; + + port@2 { + reg = <2>; +- label = "lan2"; ++ label = "lan3"; + }; + + port@3 { + reg = <3>; +- label = "lan3"; ++ label = "lan4"; + }; + + port@4 { +@@ -264,7 +263,22 @@ &pcie0 { + status = "okay"; + }; + ++&pcie1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pcie1_pins>; ++ status = "okay"; ++}; ++ + &pio { ++ /* Attention: GPIO 90 is used to switch between PCIe@1,0 and ++ * SATA functions. i.e. output-high: PCIe, output-low: SATA ++ */ ++ asm_sel { ++ gpio-hog; ++ gpios = <90 GPIO_ACTIVE_HIGH>; ++ output-high; ++ }; ++ + /* eMMC is shared pin with parallel NAND */ + emmc_pins_default: emmc-pins-default { + mux { +@@ -541,11 +555,11 @@ &pwrap { + }; + + &sata { +- status = "okay"; ++ status = "disabled"; + }; + + &sata_phy { +- status = "okay"; ++ status = "disabled"; + }; + + &spi0 { +-- +2.51.0 + + +From 98902ead914a8b836afc3adb01d46eeeca1d9fd2 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= +Date: Mon, 3 Nov 2025 15:50:39 +0100 +Subject: [PATCH 416/517] + /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/101-dts-update-mt7629-rfb.patch + +--- + arch/arm/boot/dts/mediatek/mt7629-rfb.dts | 27 ++++++++++++++++++++++- + 1 file changed, 26 insertions(+), 1 deletion(-) + +diff --git a/arch/arm/boot/dts/mediatek/mt7629-rfb.dts b/arch/arm/boot/dts/mediatek/mt7629-rfb.dts +index f24ebc20732a..c1a306268730 100644 +--- a/arch/arm/boot/dts/mediatek/mt7629-rfb.dts ++++ b/arch/arm/boot/dts/mediatek/mt7629-rfb.dts +@@ -18,6 +18,7 @@ aliases { + + chosen { + stdout-path = "serial0:115200n8"; ++ bootargs = "earlycon=uart8250,mmio32,0x11002000 console=ttyS0,115200n8"; + }; + + gpio-keys { +@@ -70,6 +71,10 @@ gmac0: mac@0 { + compatible = "mediatek,eth-mac"; + reg = <0>; + phy-mode = "2500base-x"; ++ ++ nvmem-cells = <&macaddr_factory_2a>; ++ nvmem-cell-names = "mac-address"; ++ + fixed-link { + speed = <2500>; + full-duplex; +@@ -82,6 +87,9 @@ gmac1: mac@1 { + reg = <1>; + phy-mode = "gmii"; + phy-handle = <&phy0>; ++ ++ nvmem-cells = <&macaddr_factory_24>; ++ nvmem-cell-names = "mac-address"; + }; + + mdio: mdio-bus { +@@ -133,8 +141,9 @@ factory: partition@70000 { + }; + + partition@b0000 { +- label = "kernel"; ++ label = "firmware"; + reg = <0xb0000 0xb50000>; ++ compatible = "denx,fit"; + }; + }; + }; +@@ -273,3 +282,19 @@ &watchdog { + pinctrl-0 = <&watchdog_pins>; + status = "okay"; + }; ++ ++&factory { ++ nvmem-layout { ++ compatible = "fixed-layout"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ macaddr_factory_24: macaddr@24 { ++ reg = <0x24 0x6>; ++ }; ++ ++ macaddr_factory_2a: macaddr@2a { ++ reg = <0x2a 0x6>; ++ }; ++ }; ++}; +-- +2.51.0 + + +From 89b17d34e902fd03937449e3bac9fba792144827 Mon Sep 17 00:00:00 2001 +From: Chuanhong Guo +Date: Fri, 29 Apr 2022 10:40:56 +0800 +Subject: [PATCH 417/517] arm: mediatek: select arch timer for mt7623 + +Signed-off-by: Chuanhong Guo +--- + arch/arm/mach-mediatek/Kconfig | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm/mach-mediatek/Kconfig b/arch/arm/mach-mediatek/Kconfig +index 35a3430c7942..8a8d9142260a 100644 +--- a/arch/arm/mach-mediatek/Kconfig ++++ b/arch/arm/mach-mediatek/Kconfig +@@ -26,6 +26,7 @@ config MACH_MT6592 + config MACH_MT7623 + bool "MediaTek MT7623 SoCs support" + default ARCH_MEDIATEK ++ select HAVE_ARM_ARCH_TIMER + + config MACH_MT7629 + bool "MediaTek MT7629 SoCs support" +-- +2.51.0 + + +From fe577f41bdfe2ec80ddc1a83bb3b71a6690dd2be Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= +Date: Mon, 3 Nov 2025 15:50:40 +0100 +Subject: [PATCH 418/517] + /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/104-mt7622-add-snor-irq.patch + +--- + arch/arm64/boot/dts/mediatek/mt7622.dtsi | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7622.dtsi b/arch/arm64/boot/dts/mediatek/mt7622.dtsi +index 917fa39a74f8..bc40287b8f55 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi +@@ -575,6 +575,7 @@ nor_flash: spi@11014000 { + compatible = "mediatek,mt7622-nor", + "mediatek,mt8173-nor"; + reg = <0 0x11014000 0 0xe0>; ++ interrupts = ; + clocks = <&pericfg CLK_PERI_FLASH_PD>, + <&topckgen CLK_TOP_FLASH_SEL>; + clock-names = "spi", "sf"; +-- +2.51.0 + + +From 6d49971735a5928b5a1b13714f6931bb70a4bfe9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= +Date: Mon, 3 Nov 2025 15:50:40 +0100 +Subject: [PATCH 419/517] + /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/105-dts-mt7622-enable-pstore.patch + +--- + arch/arm64/boot/dts/mediatek/mt7622.dtsi | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7622.dtsi b/arch/arm64/boot/dts/mediatek/mt7622.dtsi +index bc40287b8f55..9aeca60effc0 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi +@@ -135,6 +135,13 @@ reserved-memory { + #size-cells = <2>; + ranges; + ++ /* 64 KiB reserved for ramoops/pstore */ ++ ramoops@42ff0000 { ++ compatible = "ramoops"; ++ reg = <0 0x42ff0000 0 0x10000>; ++ record-size = <0x1000>; ++ }; ++ + /* 192 KiB reserved for ARM Trusted Firmware (BL31) */ + secmon_reserved: secmon@43000000 { + reg = <0 0x43000000 0 0x30000>; +-- +2.51.0 + + +From 840aa57c1c8487ed681cf4dcae1d3d710c0b2b2d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= +Date: Mon, 3 Nov 2025 15:50:41 +0100 +Subject: [PATCH 420/517] + /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/106-dts-mt7622-disable_btif.patch + +--- + arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts | 4 ---- + arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts | 4 ---- + 2 files changed, 8 deletions(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts +index d12eac9b3eeb..e516e8357082 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts +@@ -109,10 +109,6 @@ &bch { + status = "disabled"; + }; + +-&btif { +- status = "okay"; +-}; +- + &cir { + pinctrl-names = "default"; + pinctrl-0 = <&irrx_pins>; +diff --git a/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts b/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts +index 5280ca95e5c1..06b708e8fd0e 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts +@@ -90,10 +90,6 @@ &bch { + status = "disabled"; + }; + +-&btif { +- status = "okay"; +-}; +- + &cir { + pinctrl-names = "default"; + pinctrl-0 = <&irrx_pins>; +-- +2.51.0 + + +From 8240371de56292ac0183c36f963744c6f54df9fc Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= +Date: Mon, 3 Nov 2025 15:50:41 +0100 +Subject: [PATCH 421/517] + /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/110-dts-fix-bpi2-console.patch + +--- + arch/arm/boot/dts/mediatek/mt7623n-bananapi-bpi-r2.dts | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm/boot/dts/mediatek/mt7623n-bananapi-bpi-r2.dts b/arch/arm/boot/dts/mediatek/mt7623n-bananapi-bpi-r2.dts +index a37f3fa223c7..4275d1214f49 100644 +--- a/arch/arm/boot/dts/mediatek/mt7623n-bananapi-bpi-r2.dts ++++ b/arch/arm/boot/dts/mediatek/mt7623n-bananapi-bpi-r2.dts +@@ -19,6 +19,7 @@ aliases { + + chosen { + stdout-path = "serial2:115200n8"; ++ bootargs = "console=ttyS2,115200n8 console=tty1"; + }; + + connector { +-- +2.51.0 + + +From 1afd404bb68fc69428d4e9a312a8a0a4dd49e6f6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= +Date: Mon, 3 Nov 2025 15:50:41 +0100 +Subject: [PATCH 422/517] + /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/111-dts-fix-bpi64-console.patch + +--- + arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts +index e516e8357082..6490fa754ddd 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts +@@ -24,7 +24,7 @@ aliases { + + chosen { + stdout-path = "serial0:115200n8"; +- bootargs = "earlycon=uart8250,mmio32,0x11002000 swiotlb=512"; ++ bootargs = "earlycon=uart8250,mmio32,0x11002000 console=ttyS0,115200n1 swiotlb=512"; + }; + + cpus { +-- +2.51.0 + + +From ddce26c256090622c46bad02c8b588a096d6c290 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= +Date: Mon, 3 Nov 2025 15:50:42 +0100 +Subject: [PATCH 423/517] + /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/112-dts-fix-bpi64-lan-names.patch + +--- + arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts +index 6490fa754ddd..0bea189e91db 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts +@@ -20,6 +20,7 @@ / { + + aliases { + serial0 = &uart0; ++ ethernet0 = &gmac0; + }; + + chosen { +@@ -164,22 +165,22 @@ port@0 { + + port@1 { + reg = <1>; +- label = "lan0"; ++ label = "lan1"; + }; + + port@2 { + reg = <2>; +- label = "lan1"; ++ label = "lan2"; + }; + + port@3 { + reg = <3>; +- label = "lan2"; ++ label = "lan3"; + }; + + port@4 { + reg = <4>; +- label = "lan3"; ++ label = "lan4"; + }; + + port@5 { +-- +2.51.0 + + +From 2fa7e103e880630228e8349e155155ff63baceca Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= +Date: Mon, 3 Nov 2025 15:50:42 +0100 +Subject: [PATCH 424/517] + /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/113-dts-fix-bpi64-leds-and-buttons.patch + +--- + .../dts/mediatek/mt7622-bananapi-bpi-r64.dts | 20 ++++++++++++------- + 1 file changed, 13 insertions(+), 7 deletions(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts +index 0bea189e91db..35b7f3b79d6b 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts +@@ -21,6 +21,12 @@ / { + aliases { + serial0 = &uart0; + ethernet0 = &gmac0; ++ led-boot = &led_system_green; ++ led-failsafe = &led_system_blue; ++ led-running = &led_system_green; ++ led-upgrade = &led_system_blue; ++ mmc0 = &mmc0; ++ mmc1 = &mmc1; + }; + + chosen { +@@ -44,8 +50,8 @@ gpio-keys { + compatible = "gpio-keys"; + + factory-key { +- label = "factory"; +- linux,code = ; ++ label = "reset"; ++ linux,code = ; + gpios = <&pio 0 GPIO_ACTIVE_HIGH>; + }; + +@@ -59,17 +65,17 @@ wps-key { + leds { + compatible = "gpio-leds"; + +- led-0 { ++ led_system_green: led-0 { + label = "bpi-r64:pio:green"; + color = ; + gpios = <&pio 89 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + +- led-1 { +- label = "bpi-r64:pio:red"; +- color = ; +- gpios = <&pio 88 GPIO_ACTIVE_HIGH>; ++ led_system_blue: led-1 { ++ label = "bpi-r64:pio:blue"; ++ color = ; ++ gpios = <&pio 85 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + }; +-- +2.51.0 + + +From ead9f5e3bff60916a5920349f44eb821f71468da Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= +Date: Mon, 3 Nov 2025 15:50:43 +0100 +Subject: [PATCH 425/517] + /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/114-dts-bpi64-disable-rtc.patch + +--- + arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts +index 35b7f3b79d6b..77ecf5086c2c 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts +@@ -599,6 +599,10 @@ &pwrap { + status = "okay"; + }; + ++&rtc { ++ status = "disabled"; ++}; ++ + &sata { + status = "disabled"; + }; +-- +2.51.0 + + +From 1b51556c1ab773999e0472f79357ae4595364e61 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Sat, 1 Feb 2025 04:24:17 +0000 +Subject: [PATCH 426/517] Revert "arm64: dts: mediatek: fix t-phy unit name" + +This reverts commit 963c3b0c47ec29b4c49c9f45965cd066f419d17f. +--- + arch/arm64/boot/dts/mediatek/mt7622.dtsi | 2 +- + arch/arm64/boot/dts/mediatek/mt7986a.dtsi | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7622.dtsi b/arch/arm64/boot/dts/mediatek/mt7622.dtsi +index 9aeca60effc0..c1fb43eefc83 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi +@@ -908,7 +908,7 @@ sata: sata@1a200000 { + status = "disabled"; + }; + +- sata_phy: t-phy { ++ sata_phy: t-phy@1a243000 { + compatible = "mediatek,mt7622-tphy", + "mediatek,generic-tphy-v1"; + #address-cells = <2>; +diff --git a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi +index 559990dcd1d1..f9aaf3f20cd7 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi +@@ -428,7 +428,7 @@ pcie_intc: interrupt-controller { + }; + }; + +- pcie_phy: t-phy { ++ pcie_phy: t-phy@11c00000 { + compatible = "mediatek,mt7986-tphy", + "mediatek,generic-tphy-v2"; + ranges; +-- +2.51.0 + + +From fb543ac462d31ffc4d6ed11dad784849cf06b7c4 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Fri, 28 Jun 2024 12:55:40 +0200 +Subject: [PATCH 427/517] arm64: dts: mediatek: mt7622: readd syscon to pciesys + node + +Sata node reference the pciesys with the property mediatek,phy-node +and that is used as a syscon to access the pciesys regs. + +Readd the syscon compatible to pciesys node to restore correct +functionality of the SATA interface. + +Fixes: 3ba5a6159434 ("arm64: dts: mediatek: mt7622: fix clock controllers") +Reported-by: Frank Wunderlich +Co-developed-by: Frank Wunderlich +Signed-off-by: Frank Wunderlich +Signed-off-by: Christian Marangi +Cc: stable@vger.kernel.org +--- + arch/arm64/boot/dts/mediatek/mt7622.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7622.dtsi b/arch/arm64/boot/dts/mediatek/mt7622.dtsi +index c1fb43eefc83..f2e526840582 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi +@@ -798,7 +798,7 @@ u2port1: usb-phy@1a0c5000 { + }; + + pciesys: clock-controller@1a100800 { +- compatible = "mediatek,mt7622-pciesys"; ++ compatible = "mediatek,mt7622-pciesys", "syscon"; + reg = <0 0x1a100800 0 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; +-- +2.51.0 + + +From e5cb89538893dfe9c929bda92a429a768aff7b94 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Wed, 28 Dec 2022 23:44:42 +0000 +Subject: [PATCH 428/517] complete mt7981 dts + +working: + * Ethernet (fully working incl. ppe) + * UART + * SPI-NAND flash + * thermal sensors (SoC and mxl-gpy) + * random number generator via SMC + * USB 1.1, 2.0 and 3.0 + * WiFi with MT7976C 2.4G+5G DBDC incl. WED offloading + * PWM +--- + arch/arm64/boot/dts/mediatek/mt7981b.dtsi | 566 +++++++++++++++++++++- + 1 file changed, 554 insertions(+), 12 deletions(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7981b.dtsi b/arch/arm64/boot/dts/mediatek/mt7981b.dtsi +index 5cbea9cd411f..6a816e5c1f46 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7981b.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7981b.dtsi +@@ -1,7 +1,14 @@ + // SPDX-License-Identifier: GPL-2.0-only OR MIT + + #include ++#include ++#include + #include ++#include ++#include ++#include ++#include ++#include + #include + + / { +@@ -41,6 +48,57 @@ psci { + method = "smc"; + }; + ++ fan: pwm-fan { ++ compatible = "pwm-fan"; ++ /* cooling level (0, 1, 2, 3) : (0% duty, 50% duty, 75% duty, 100% duty) */ ++ cooling-levels = <0 128 192 255>; ++ #cooling-cells = <2>; ++ status = "disabled"; ++ }; ++ ++ reg_3p3v: regulator-3p3v { ++ compatible = "regulator-fixed"; ++ regulator-name = "fixed-3.3V"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ /* 64 KiB reserved for ramoops/pstore */ ++ ramoops@42ff0000 { ++ compatible = "ramoops"; ++ reg = <0 0x42ff0000 0 0x10000>; ++ record-size = <0x1000>; ++ }; ++ ++ /* 192 KiB reserved for ARM Trusted Firmware (BL31) */ ++ secmon_reserved: secmon@43000000 { ++ reg = <0 0x43000000 0 0x30000>; ++ no-map; ++ }; ++ ++ wmcpu_emi: wmcpu-reserved@47c80000 { ++ reg = <0 0x47c80000 0 0x100000>; ++ no-map; ++ }; ++ ++ wo_emi0: wo-emi@47d80000 { ++ reg = <0 0x47d80000 0 0x40000>; ++ no-map; ++ }; ++ ++ wo_data: wo-data@47dc0000 { ++ reg = <0 0x47dc0000 0 0x240000>; ++ no-map; ++ }; ++ }; ++ + soc { + compatible = "simple-bus"; + ranges; +@@ -76,13 +134,13 @@ watchdog: watchdog@1001c000 { + #reset-cells = <1>; + }; + +- clock-controller@1001e000 { +- compatible = "mediatek,mt7981-apmixedsys"; ++ apmixedsys: clock-controller@1001e000 { ++ compatible = "mediatek,mt7981-apmixedsys", "syscon"; + reg = <0 0x1001e000 0 0x1000>; + #clock-cells = <1>; + }; + +- pwm@10048000 { ++ pwm: pwm@10048000 { + compatible = "mediatek,mt7981-pwm"; + reg = <0 0x10048000 0 0x1000>; + clocks = <&infracfg CLK_INFRA_PWM_STA>, +@@ -94,7 +152,21 @@ pwm@10048000 { + #pwm-cells = <2>; + }; + +- serial@11002000 { ++ crypto: crypto@10320000 { ++ compatible = "inside-secure,safexcel-eip97"; ++ reg = <0 0x10320000 0 0x40000>; ++ interrupts = , ++ , ++ , ++ ; ++ interrupt-names = "ring0", "ring1", "ring2", "ring3"; ++ clocks = <&topckgen CLK_TOP_EIP97B>; ++ clock-names = "top_eip97_ck"; ++ assigned-clocks = <&topckgen CLK_TOP_EIP97B_SEL>; ++ assigned-clock-parents = <&topckgen CLK_TOP_CB_NET1_D5>; ++ }; ++ ++ uart0: serial@11002000 { + compatible = "mediatek,mt7981-uart", "mediatek,mt6577-uart"; + reg = <0 0x11002000 0 0x100>; + interrupts = ; +@@ -105,7 +177,7 @@ serial@11002000 { + status = "disabled"; + }; + +- serial@11003000 { ++ uart1: serial@11003000 { + compatible = "mediatek,mt7981-uart", "mediatek,mt6577-uart"; + reg = <0 0x11003000 0 0x100>; + interrupts = ; +@@ -116,7 +188,7 @@ serial@11003000 { + status = "disabled"; + }; + +- serial@11004000 { ++ uart2: serial@11004000 { + compatible = "mediatek,mt7981-uart", "mediatek,mt6577-uart"; + reg = <0 0x11004000 0 0x100>; + interrupts = ; +@@ -127,11 +199,12 @@ serial@11004000 { + status = "disabled"; + }; + +- i2c@11007000 { ++ i2c0: i2c@11007000 { + compatible = "mediatek,mt7981-i2c"; + reg = <0 0x11007000 0 0x1000>, + <0 0x10217080 0 0x80>; + interrupts = ; ++ clock-div = <1>; + clocks = <&infracfg CLK_INFRA_I2C0_CK>, + <&infracfg CLK_INFRA_AP_DMA_CK>, + <&infracfg CLK_INFRA_I2C_MCK_CK>, +@@ -142,7 +215,32 @@ i2c@11007000 { + status = "disabled"; + }; + +- spi@11009000 { ++ thermal: thermal@1100c800 { ++ #thermal-sensor-cells = <1>; ++ compatible = "mediatek,mt7981-thermal", "mediatek,mt7986-thermal"; ++ reg = <0 0x1100c800 0 0x800>; ++ interrupts = ; ++ clocks = <&infracfg CLK_INFRA_THERM_CK>, ++ <&infracfg CLK_INFRA_ADC_26M_CK>; ++ clock-names = "therm", "auxadc"; ++ mediatek,auxadc = <&auxadc>; ++ mediatek,apmixedsys = <&apmixedsys>; ++ nvmem-cells = <&thermal_calibration>; ++ nvmem-cell-names = "calibration-data"; ++ }; ++ ++ auxadc: adc@1100d000 { ++ compatible = "mediatek,mt7981-auxadc", ++ "mediatek,mt7986-auxadc", ++ "mediatek,mt7622-auxadc"; ++ reg = <0 0x1100d000 0 0x1000>; ++ clocks = <&infracfg CLK_INFRA_ADC_26M_CK>, ++ <&infracfg CLK_INFRA_ADC_FRC_CK>; ++ clock-names = "main", "32k"; ++ #io-channel-cells = <1>; ++ }; ++ ++ spi2: spi@11009000 { + compatible = "mediatek,mt7981-spi-ipm", "mediatek,spi-ipm"; + reg = <0 0x11009000 0 0x1000>; + interrupts = ; +@@ -156,7 +254,7 @@ spi@11009000 { + status = "disabled"; + }; + +- spi@1100a000 { ++ spi0: spi@1100a000 { + compatible = "mediatek,mt7981-spi-ipm", "mediatek,spi-ipm"; + reg = <0 0x1100a000 0 0x1000>; + interrupts = ; +@@ -170,7 +268,7 @@ spi@1100a000 { + status = "disabled"; + }; + +- spi@1100b000 { ++ spi1: spi@1100b000 { + compatible = "mediatek,mt7981-spi-ipm", "mediatek,spi-ipm"; + reg = <0 0x1100b000 0 0x1000>; + interrupts = ; +@@ -184,6 +282,41 @@ spi@1100b000 { + status = "disabled"; + }; + ++ pcie: pcie@11280000 { ++ compatible = "mediatek,mt7981-pcie", ++ "mediatek,mt8192-pcie"; ++ device_type = "pci"; ++ reg = <0 0x11280000 0 0x4000>; ++ reg-names = "pcie-mac"; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ interrupts = ; ++ bus-range = <0x00 0xff>; ++ ranges = <0x82000000 0 0x20000000 ++ 0x0 0x20000000 0 0x10000000>; ++ status = "disabled"; ++ ++ clocks = <&infracfg CLK_INFRA_IPCIE_CK>, ++ <&infracfg CLK_INFRA_IPCIE_PIPE_CK>, ++ <&infracfg CLK_INFRA_IPCIER_CK>, ++ <&infracfg CLK_INFRA_IPCIEB_CK>; ++ ++ phys = <&u3port0 PHY_TYPE_PCIE>; ++ phy-names = "pcie-phy"; ++ ++ #interrupt-cells = <1>; ++ interrupt-map-mask = <0 0 0 7>; ++ interrupt-map = <0 0 0 1 &pcie_intc 0>, ++ <0 0 0 2 &pcie_intc 1>, ++ <0 0 0 3 &pcie_intc 2>, ++ <0 0 0 4 &pcie_intc 3>; ++ pcie_intc: interrupt-controller { ++ interrupt-controller; ++ #address-cells = <0>; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ + pio: pinctrl@11d00000 { + compatible = "mediatek,mt7981-pinctrl"; + reg = <0 0x11d00000 0 0x1000>, +@@ -204,6 +337,49 @@ pio: pinctrl@11d00000 { + gpio-controller; + #gpio-cells = <2>; + #interrupt-cells = <2>; ++ ++ mdio_pins: mdc-mdio-pins { ++ mux { ++ function = "eth"; ++ groups = "smi_mdc_mdio"; ++ }; ++ }; ++ ++ uart0_pins: uart0-pins { ++ mux { ++ function = "uart"; ++ groups = "uart0"; ++ }; ++ }; ++ ++ wifi_dbdc_pins: wifi-dbdc-pins { ++ mux { ++ function = "eth"; ++ groups = "wf0_mode1"; ++ }; ++ conf { ++ pins = "WF_HB1", "WF_HB2", "WF_HB3", "WF_HB4", ++ "WF_HB0", "WF_HB0_B", "WF_HB5", "WF_HB6", ++ "WF_HB7", "WF_HB8", "WF_HB9", "WF_HB10", ++ "WF_TOP_CLK", "WF_TOP_DATA", "WF_XO_REQ", ++ "WF_CBA_RESETB", "WF_DIG_RESETB"; ++ drive-strength = ; ++ }; ++ }; ++ ++ gbe_led0_pins: gbe-led0-pins { ++ mux { ++ function = "led"; ++ groups = "gbe_led0"; ++ }; ++ }; ++ ++ gbe_led1_pins: gbe-led1-pins { ++ mux { ++ function = "led"; ++ groups = "gbe_led1"; ++ }; ++ }; + }; + + efuse@11f20000 { +@@ -211,17 +387,318 @@ efuse@11f20000 { + reg = <0 0x11f20000 0 0x1000>; + #address-cells = <1>; + #size-cells = <1>; ++ ++ thermal_calibration: thermal-calib@274 { ++ reg = <0x274 0xc>; ++ }; ++ ++ phy_calibration: phy-calib@8dc { ++ reg = <0x8dc 0x10>; ++ }; ++ ++ comb_rx_imp_p0: usb3-rx-imp@8c8 { ++ reg = <0x8c8 1>; ++ bits = <0 5>; ++ }; ++ ++ comb_tx_imp_p0: usb3-tx-imp@8c8 { ++ reg = <0x8c8 2>; ++ bits = <5 5>; ++ }; ++ ++ comb_intr_p0: usb3-intr@8c9 { ++ reg = <0x8c9 1>; ++ bits = <2 6>; ++ }; + }; + +- clock-controller@15000000 { ++ ethsys: clock-controller@15000000 { + compatible = "mediatek,mt7981-ethsys", "syscon"; + reg = <0 0x15000000 0 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + +- wifi@18000000 { ++ wed: wed@15010000 { ++ compatible = "mediatek,mt7981-wed", ++ "mediatek,mt7986-wed", ++ "syscon"; ++ reg = <0 0x15010000 0 0x1000>; ++ interrupt-parent = <&gic>; ++ interrupts = ; ++ memory-region = <&wo_emi0>, <&wo_data>; ++ memory-region-names = "wo-emi", "wo-data"; ++ mediatek,wo-ccif = <&wo_ccif0>; ++ mediatek,wo-ilm = <&wo_ilm0>; ++ mediatek,wo-dlm = <&wo_dlm0>; ++ mediatek,wo-cpuboot = <&wo_cpuboot>; ++ }; ++ ++ eth: ethernet@15100000 { ++ compatible = "mediatek,mt7981-eth"; ++ reg = <0 0x15100000 0 0x80000>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ interrupts = , ++ , ++ , ++ ; ++ clocks = <ðsys CLK_ETH_FE_EN>, ++ <ðsys CLK_ETH_GP2_EN>, ++ <ðsys CLK_ETH_GP1_EN>, ++ <ðsys CLK_ETH_WOCPU0_EN>, ++ <&sgmiisys0 CLK_SGM0_TX_EN>, ++ <&sgmiisys0 CLK_SGM0_RX_EN>, ++ <&sgmiisys0 CLK_SGM0_CK0_EN>, ++ <&sgmiisys0 CLK_SGM0_CDR_CK0_EN>, ++ <&sgmiisys1 CLK_SGM1_TX_EN>, ++ <&sgmiisys1 CLK_SGM1_RX_EN>, ++ <&sgmiisys1 CLK_SGM1_CK1_EN>, ++ <&sgmiisys1 CLK_SGM1_CDR_CK1_EN>, ++ <&topckgen CLK_TOP_SGM_REG>, ++ <&topckgen CLK_TOP_NETSYS_SEL>, ++ <&topckgen CLK_TOP_NETSYS_500M_SEL>; ++ clock-names = "fe", "gp2", "gp1", "wocpu0", ++ "sgmii_tx250m", "sgmii_rx250m", ++ "sgmii_cdr_ref", "sgmii_cdr_fb", ++ "sgmii2_tx250m", "sgmii2_rx250m", ++ "sgmii2_cdr_ref", "sgmii2_cdr_fb", ++ "sgmii_ck", "netsys0", "netsys1"; ++ assigned-clocks = <&topckgen CLK_TOP_NETSYS_2X_SEL>, ++ <&topckgen CLK_TOP_SGM_325M_SEL>; ++ assigned-clock-parents = <&topckgen CLK_TOP_CB_NET2_800M>, ++ <&topckgen CLK_TOP_CB_SGM_325M>; ++ mediatek,ethsys = <ðsys>; ++ mediatek,sgmiisys = <&sgmiisys0>, <&sgmiisys1>; ++ mediatek,infracfg = <&topmisc>; ++ mediatek,wed = <&wed>; ++ status = "disabled"; ++ ++ mdio_bus: mdio-bus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ int_gbe_phy: ethernet-phy@0 { ++ reg = <0>; ++ compatible = "ethernet-phy-ieee802.3-c22"; ++ phy-mode = "gmii"; ++ phy-is-integrated; ++ nvmem-cells = <&phy_calibration>; ++ nvmem-cell-names = "phy-cal-data"; ++ ++ leds { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ int_gbe_phy_led0: int-gbe-phy-led0@0 { ++ reg = <0>; ++ function = LED_FUNCTION_LAN; ++ pinctrl-0 = <&gbe_led0_pins>; ++ pinctrl-names = "default"; ++ status = "disabled"; ++ }; ++ ++ int_gbe_phy_led1: int-gbe-phy-led1@1 { ++ reg = <1>; ++ function = LED_FUNCTION_LAN; ++ pinctrl-0 = <&gbe_led1_pins>; ++ pinctrl-names = "default"; ++ status = "disabled"; ++ }; ++ }; ++ }; ++ }; ++ }; ++ ++ wdma: wdma@15104800 { ++ compatible = "mediatek,wed-wdma"; ++ reg = <0 0x15104800 0 0x400>, ++ <0 0x15104c00 0 0x400>; ++ }; ++ ++ ap2woccif: ap2woccif@151a5000 { ++ compatible = "mediatek,ap2woccif"; ++ reg = <0 0x151a5000 0 0x1000>, ++ <0 0x151ad000 0 0x1000>; ++ interrupt-parent = <&gic>; ++ interrupts = , ++ ; ++ }; ++ ++ wo_dlm0: syscon@151e8000 { ++ compatible = "mediatek,mt7986-wo-dlm", "syscon"; ++ reg = <0 0x151e8000 0 0x2000>; ++ }; ++ ++ wo_ilm0: syscon@151e0000 { ++ compatible = "mediatek,mt7986-wo-ilm", "syscon"; ++ reg = <0 0x151e0000 0 0x8000>; ++ }; ++ ++ wo_cpuboot: syscon@15194000 { ++ compatible = "mediatek,mt7986-wo-cpuboot", "syscon"; ++ reg = <0 0x15194000 0 0x1000>; ++ }; ++ ++ wo_ccif0: syscon@151a5000 { ++ compatible = "mediatek,mt7986-wo-ccif", "syscon"; ++ reg = <0 0x151a5000 0 0x1000>; ++ interrupt-parent = <&gic>; ++ interrupts = ; ++ }; ++ ++ sgmiisys0: syscon@10060000 { ++ compatible = "mediatek,mt7981-sgmiisys_0", "mediatek,mt7986-sgmiisys_0", "syscon"; ++ reg = <0 0x10060000 0 0x1000>; ++ mediatek,pnswap; ++ #clock-cells = <1>; ++ }; ++ ++ sgmiisys1: syscon@10070000 { ++ compatible = "mediatek,mt7981-sgmiisys_1", "mediatek,mt7986-sgmiisys_1", "syscon"; ++ reg = <0 0x10070000 0 0x1000>; ++ #clock-cells = <1>; ++ }; ++ ++ topmisc: topmisc@11d10000 { ++ compatible = "mediatek,mt7981-topmisc", "syscon"; ++ reg = <0 0x11d10000 0 0x10000>; ++ #clock-cells = <1>; ++ }; ++ ++ snand: snfi@11005000 { ++ compatible = "mediatek,mt7986-snand"; ++ reg = <0 0x11005000 0 0x1000>, <0 0x11006000 0 0x1000>; ++ reg-names = "nfi", "ecc"; ++ interrupts = ; ++ clocks = <&infracfg CLK_INFRA_SPINFI1_CK>, ++ <&infracfg CLK_INFRA_NFI1_CK>, ++ <&infracfg CLK_INFRA_NFI_HCK_CK>; ++ clock-names = "pad_clk", "nfi_clk", "nfi_hclk"; ++ assigned-clocks = <&topckgen CLK_TOP_SPINFI_SEL>, ++ <&topckgen CLK_TOP_NFI1X_SEL>; ++ assigned-clock-parents = <&topckgen CLK_TOP_CB_M_D8>, ++ <&topckgen CLK_TOP_CB_M_D8>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ mmc0: mmc@11230000 { ++ compatible = "mediatek,mt7986-mmc", ++ "mediatek,mt7981-mmc"; ++ reg = <0 0x11230000 0 0x1000>, <0 0x11c20000 0 0x1000>; ++ interrupts = ; ++ clocks = <&infracfg CLK_INFRA_MSDC_CK>, ++ <&infracfg CLK_INFRA_MSDC_HCK_CK>, ++ <&infracfg CLK_INFRA_MSDC_66M_CK>, ++ <&infracfg CLK_INFRA_MSDC_133M_CK>; ++ assigned-clocks = <&topckgen CLK_TOP_EMMC_208M_SEL>, ++ <&topckgen CLK_TOP_EMMC_400M_SEL>; ++ assigned-clock-parents = <&topckgen CLK_TOP_CB_M_D2>, ++ <&topckgen CLK_TOP_CB_NET2_D2>; ++ clock-names = "source", "hclk", "axi_cg", "ahb_cg"; ++ status = "disabled"; ++ }; ++ ++ wed_pcie: wed_pcie@10003000 { ++ compatible = "mediatek,wed_pcie"; ++ reg = <0 0x10003000 0 0x10>; ++ }; ++ ++ consys: consys@10000000 { ++ compatible = "mediatek,mt7981-consys"; ++ reg = <0 0x10000000 0 0x8600000>; ++ memory-region = <&wmcpu_emi>; ++ }; ++ ++ xhci: usb@11200000 { ++ compatible = "mediatek,mt7986-xhci", ++ "mediatek,mtk-xhci"; ++ reg = <0 0x11200000 0 0x2e00>, ++ <0 0x11203e00 0 0x0100>; ++ reg-names = "mac", "ippc"; ++ interrupts = ; ++ clocks = <&infracfg CLK_INFRA_IUSB_SYS_CK>, ++ <&infracfg CLK_INFRA_IUSB_CK>, ++ <&infracfg CLK_INFRA_IUSB_133_CK>, ++ <&infracfg CLK_INFRA_IUSB_66M_CK>, ++ <&topckgen CLK_TOP_U2U3_XHCI_SEL>; ++ clock-names = "sys_ck", ++ "ref_ck", ++ "mcu_ck", ++ "dma_ck", ++ "xhci_ck"; ++ phys = <&u2port0 PHY_TYPE_USB2>, ++ <&u3port0 PHY_TYPE_USB3>; ++ vusb33-supply = <®_3p3v>; ++ status = "disabled"; ++ }; ++ ++ usb_phy: usb-phy@11e10000 { ++ compatible = "mediatek,mt7981", ++ "mediatek,generic-tphy-v2"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges = <0 0 0x11e10000 0x1700>; ++ status = "disabled"; ++ ++ u2port0: usb-phy@0 { ++ reg = <0x0 0x700>; ++ clocks = <&topckgen CLK_TOP_USB_FRMCNT_SEL>; ++ clock-names = "ref"; ++ #phy-cells = <1>; ++ }; ++ ++ u3port0: usb-phy@700 { ++ reg = <0x700 0x900>; ++ clocks = <&topckgen CLK_TOP_USB3_PHY_SEL>; ++ clock-names = "ref"; ++ #phy-cells = <1>; ++ mediatek,syscon-type = <&topmisc 0x218 0>; ++ status = "okay"; ++ }; ++ }; ++ ++ ++ afe: audio-controller@11210000 { ++ compatible = "mediatek,mt79xx-audio"; ++ reg = <0 0x11210000 0 0x9000>; ++ interrupts = ; ++ clocks = <&infracfg CLK_INFRA_AUD_BUS_CK>, ++ <&infracfg CLK_INFRA_AUD_26M_CK>, ++ <&infracfg CLK_INFRA_AUD_L_CK>, ++ <&infracfg CLK_INFRA_AUD_AUD_CK>, ++ <&infracfg CLK_INFRA_AUD_EG2_CK>, ++ <&topckgen CLK_TOP_AUD_SEL>; ++ clock-names = "aud_bus_ck", ++ "aud_26m_ck", ++ "aud_l_ck", ++ "aud_aud_ck", ++ "aud_eg2_ck", ++ "aud_sel"; ++ assigned-clocks = <&topckgen CLK_TOP_AUD_SEL>, ++ <&topckgen CLK_TOP_A1SYS_SEL>, ++ <&topckgen CLK_TOP_AUD_L_SEL>, ++ <&topckgen CLK_TOP_A_TUNER_SEL>; ++ assigned-clock-parents = <&topckgen CLK_TOP_CB_APLL2_196M>, ++ <&topckgen CLK_TOP_APLL2_D4>, ++ <&topckgen CLK_TOP_CB_APLL2_196M>, ++ <&topckgen CLK_TOP_APLL2_D4>; ++ status = "disabled"; ++ }; ++ ++ ice: ice_debug { ++ compatible = "mediatek,mt7981-ice_debug", ++ "mediatek,mt2701-ice_debug"; ++ clocks = <&infracfg CLK_INFRA_DBG_CK>; ++ clock-names = "ice_dbg"; ++ }; ++ ++ wifi: wifi@18000000 { + compatible = "mediatek,mt7981-wmac"; ++ pinctrl-0 = <&wifi_dbdc_pins>; ++ pinctrl-names = "dbdc"; + reg = <0 0x18000000 0 0x1000000>, + <0 0x10003000 0 0x1000>, + <0 0x11d10000 0 0x1000>; +@@ -234,6 +711,67 @@ wifi@18000000 { + clock-names = "mcu", "ap2conn"; + resets = <&watchdog MT7986_TOPRGU_CONSYS_SW_RST>; + reset-names = "consys"; ++ memory-region = <&wmcpu_emi>; ++ status = "disabled"; ++ }; ++ }; ++ ++ thermal-zones { ++ cpu_thermal: cpu-thermal { ++ polling-delay-passive = <1000>; ++ polling-delay = <1000>; ++ thermal-sensors = <&thermal 0>; ++ trips { ++ cpu_trip_crit: crit { ++ temperature = <125000>; ++ hysteresis = <2000>; ++ type = "critical"; ++ }; ++ ++ cpu_trip_hot: hot { ++ temperature = <120000>; ++ hysteresis = <2000>; ++ type = "hot"; ++ }; ++ ++ cpu_trip_active_high: active-high { ++ temperature = <115000>; ++ hysteresis = <2000>; ++ type = "active"; ++ }; ++ ++ cpu_trip_active_med: active-med { ++ temperature = <85000>; ++ hysteresis = <2000>; ++ type = "active"; ++ }; ++ ++ cpu_trip_active_low: active-low { ++ temperature = <60000>; ++ hysteresis = <2000>; ++ type = "active"; ++ }; ++ }; ++ ++ cooling-maps { ++ cpu-active-high { ++ /* active: set fan to cooling level 3 */ ++ cooling-device = <&fan 3 3>; ++ trip = <&cpu_trip_active_high>; ++ }; ++ ++ cpu-active-med { ++ /* active: set fan to cooling level 2 */ ++ cooling-device = <&fan 2 2>; ++ trip = <&cpu_trip_active_med>; ++ }; ++ ++ cpu-active-low { ++ /* passive: set fan to cooling level 1 */ ++ cooling-device = <&fan 1 1>; ++ trip = <&cpu_trip_active_low>; ++ }; ++ }; + }; + }; + +@@ -245,4 +783,8 @@ timer { + , + ; + }; ++ ++ trng { ++ compatible = "mediatek,mt7981-rng"; ++ }; + }; +-- +2.51.0 + + +From 7d19b9de2f9cfb1e02cd61673bfe0a1f8b8453e6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= +Date: Mon, 3 Nov 2025 15:50:44 +0100 +Subject: [PATCH 429/517] + /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/121-hack-spi-nand-1b-bbm.patch + +--- + drivers/mtd/nand/spi/core.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c +index 8e56ca65ac4f..8a3c9db90c6f 100644 +--- a/drivers/mtd/nand/spi/core.c ++++ b/drivers/mtd/nand/spi/core.c +@@ -913,7 +913,7 @@ static int spinand_mtd_write(struct mtd_info *mtd, loff_t to, + static bool spinand_isbad(struct nand_device *nand, const struct nand_pos *pos) + { + struct spinand_device *spinand = nand_to_spinand(nand); +- u8 marker[2] = { }; ++ u8 marker[1] = { }; + struct nand_page_io_req req = { + .pos = *pos, + .ooblen = sizeof(marker), +@@ -924,7 +924,7 @@ static bool spinand_isbad(struct nand_device *nand, const struct nand_pos *pos) + + spinand_select_target(spinand, pos->target); + spinand_read_page(spinand, &req); +- if (marker[0] != 0xff || marker[1] != 0xff) ++ if (marker[0] != 0xff) + return true; + + return false; +-- +2.51.0 + + +From f657099ea98f26165a6c283903770c12936addc6 Mon Sep 17 00:00:00 2001 +From: Xiangsheng Hou +Date: Thu, 6 Jun 2019 16:29:04 +0800 +Subject: [PATCH 430/517] spi: spi-mem: Mediatek: Add SPI Nand support for + MT7629 + +Signed-off-by: Xiangsheng Hou +--- + arch/arm/boot/dts/mediatek/mt7629-rfb.dts | 44 +++++++++++++++++++++++ + arch/arm/boot/dts/mediatek/mt7629.dtsi | 21 +++++++++++ + 2 files changed, 65 insertions(+) + +diff --git a/arch/arm/boot/dts/mediatek/mt7629-rfb.dts b/arch/arm/boot/dts/mediatek/mt7629-rfb.dts +index c1a306268730..b999fae80fed 100644 +--- a/arch/arm/boot/dts/mediatek/mt7629-rfb.dts ++++ b/arch/arm/boot/dts/mediatek/mt7629-rfb.dts +@@ -255,6 +255,50 @@ mux { + }; + }; + ++&bch { ++ status = "okay"; ++}; ++ ++&snfi { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&serial_nand_pins>; ++ status = "okay"; ++ flash@0 { ++ compatible = "spi-nand"; ++ reg = <0>; ++ spi-tx-bus-width = <4>; ++ spi-rx-bus-width = <4>; ++ nand-ecc-engine = <&snfi>; ++ ++ partitions { ++ compatible = "fixed-partitions"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ partition@0 { ++ label = "Bootloader"; ++ reg = <0x00000 0x0100000>; ++ read-only; ++ }; ++ ++ partition@100000 { ++ label = "Config"; ++ reg = <0x100000 0x0040000>; ++ }; ++ ++ partition@140000 { ++ label = "factory"; ++ reg = <0x140000 0x0080000>; ++ }; ++ ++ partition@1c0000 { ++ label = "firmware"; ++ reg = <0x1c0000 0x1000000>; ++ }; ++ }; ++ }; ++}; ++ + &spi { + pinctrl-names = "default"; + pinctrl-0 = <&spi_pins>; +diff --git a/arch/arm/boot/dts/mediatek/mt7629.dtsi b/arch/arm/boot/dts/mediatek/mt7629.dtsi +index acab0883a3bb..cdbe85d8b030 100644 +--- a/arch/arm/boot/dts/mediatek/mt7629.dtsi ++++ b/arch/arm/boot/dts/mediatek/mt7629.dtsi +@@ -271,6 +271,27 @@ i2c: i2c@11007000 { + status = "disabled"; + }; + ++ snfi: spi@1100d000 { ++ compatible = "mediatek,mt7629-snand"; ++ reg = <0x1100d000 0x1000>; ++ interrupts = ; ++ clocks = <&pericfg CLK_PERI_NFI_PD>, <&pericfg CLK_PERI_SNFI_PD>; ++ clock-names = "nfi_clk", "pad_clk"; ++ nand-ecc-engine = <&bch>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ bch: ecc@1100e000 { ++ compatible = "mediatek,mt7622-ecc"; ++ reg = <0x1100e000 0x1000>; ++ interrupts = ; ++ clocks = <&pericfg CLK_PERI_NFIECC_PD>; ++ clock-names = "nfiecc_clk"; ++ status = "disabled"; ++ }; ++ + spi: spi@1100a000 { + compatible = "mediatek,mt7629-spi", + "mediatek,mt7622-spi"; +-- +2.51.0 + + +From cac818b46d4cc0b9162576bf3e338ac2bdca1d9b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= +Date: Mon, 3 Nov 2025 15:50:44 +0100 +Subject: [PATCH 431/517] + /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/131-dts-mt7622-add-snand-support.patch + +--- + arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts | 59 ++++++++++++++++++++ + 1 file changed, 59 insertions(+) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts b/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts +index 06b708e8fd0e..e64201b79292 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts +@@ -558,6 +558,65 @@ &sata_phy { + status = "disabled"; + }; + ++&bch { ++ status = "okay"; ++}; ++ ++&snfi { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&serial_nand_pins>; ++ status = "okay"; ++ flash@0 { ++ compatible = "spi-nand"; ++ reg = <0>; ++ spi-tx-bus-width = <4>; ++ spi-rx-bus-width = <4>; ++ nand-ecc-engine = <&snfi>; ++ ++ partitions { ++ compatible = "fixed-partitions"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ partition@0 { ++ label = "Preloader"; ++ reg = <0x00000 0x0080000>; ++ read-only; ++ }; ++ ++ partition@80000 { ++ label = "ATF"; ++ reg = <0x80000 0x0040000>; ++ }; ++ ++ partition@c0000 { ++ label = "Bootloader"; ++ reg = <0xc0000 0x0080000>; ++ }; ++ ++ partition@140000 { ++ label = "Config"; ++ reg = <0x140000 0x0080000>; ++ }; ++ ++ partition@1c0000 { ++ label = "Factory"; ++ reg = <0x1c0000 0x0100000>; ++ }; ++ ++ partition@200000 { ++ label = "firmware"; ++ reg = <0x2c0000 0x2000000>; ++ }; ++ ++ partition@2200000 { ++ label = "User_data"; ++ reg = <0x22c0000 0x4000000>; ++ }; ++ }; ++ }; ++}; ++ + &spi0 { + pinctrl-names = "default"; + pinctrl-0 = <&spic0_pins>; +-- +2.51.0 + + +From 01d5c5c6ba4d56b1908d51aa9327727440bdb0ef Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= +Date: Mon, 3 Nov 2025 15:50:45 +0100 +Subject: [PATCH 432/517] + /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/140-dts-fix-wmac-support-for-mt7622-rfb1.patch + +--- + arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts b/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts +index e64201b79292..a478bab2e8cf 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts +@@ -599,7 +599,7 @@ partition@140000 { + reg = <0x140000 0x0080000>; + }; + +- partition@1c0000 { ++ factory: partition@1c0000 { + label = "Factory"; + reg = <0x1c0000 0x0100000>; + }; +@@ -660,5 +660,6 @@ &watchdog { + &wmac { + pinctrl-names = "default"; + pinctrl-0 = <&wmac_pins>; ++ mediatek,mtd-eeprom = <&factory 0x0000>; + status = "okay"; + }; +-- +2.51.0 + + +From 1669509614ddf5ffb64bde85f4bcaafeefb65f64 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= +Date: Mon, 3 Nov 2025 15:50:45 +0100 +Subject: [PATCH 433/517] + /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/150-dts-mt7623-eip97-inside-secure-support.patch + +--- + arch/arm/boot/dts/mediatek/mt7623.dtsi | 10 ++++------ + 1 file changed, 4 insertions(+), 6 deletions(-) + +diff --git a/arch/arm/boot/dts/mediatek/mt7623.dtsi b/arch/arm/boot/dts/mediatek/mt7623.dtsi +index fd7a89cc337d..c6b7d1713096 100644 +--- a/arch/arm/boot/dts/mediatek/mt7623.dtsi ++++ b/arch/arm/boot/dts/mediatek/mt7623.dtsi +@@ -995,17 +995,15 @@ gmac1: mac@1 { + }; + + crypto: crypto@1b240000 { +- compatible = "mediatek,eip97-crypto"; ++ compatible = "inside-secure,safexcel-eip97"; + reg = <0 0x1b240000 0 0x20000>; + interrupts = , + , + , +- , +- ; ++ ; ++ interrupt-names = "ring0", "ring1", "ring2", "ring3"; + clocks = <ðsys CLK_ETHSYS_CRYPTO>; +- clock-names = "cryp"; +- power-domains = <&scpsys MT2701_POWER_DOMAIN_ETH>; +- status = "disabled"; ++ status = "okay"; + }; + + bdpsys: syscon@1c000000 { +-- +2.51.0 + + +From 260ac5379c33a9757834519325577441a7b062cf Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= +Date: Mon, 3 Nov 2025 15:50:46 +0100 +Subject: [PATCH 434/517] + /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/160-dts-mt7623-bpi-r2-earlycon.patch + +--- + arch/arm/boot/dts/mediatek/mt7623n-bananapi-bpi-r2.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm/boot/dts/mediatek/mt7623n-bananapi-bpi-r2.dts b/arch/arm/boot/dts/mediatek/mt7623n-bananapi-bpi-r2.dts +index 4275d1214f49..f68e99ca7027 100644 +--- a/arch/arm/boot/dts/mediatek/mt7623n-bananapi-bpi-r2.dts ++++ b/arch/arm/boot/dts/mediatek/mt7623n-bananapi-bpi-r2.dts +@@ -19,7 +19,7 @@ aliases { + + chosen { + stdout-path = "serial2:115200n8"; +- bootargs = "console=ttyS2,115200n8 console=tty1"; ++ bootargs = "earlycon=uart8250,mmio32,0x11004000 console=ttyS2,115200n8 console=tty1"; + }; + + connector { +-- +2.51.0 + + +From 5303571fd150e453bf13f523f4fc32bc946807e6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= +Date: Mon, 3 Nov 2025 15:50:46 +0100 +Subject: [PATCH 435/517] + /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/161-dts-mt7623-bpi-r2-mmc-device-order.patch + +--- + arch/arm/boot/dts/mediatek/mt7623n-bananapi-bpi-r2.dts | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/arch/arm/boot/dts/mediatek/mt7623n-bananapi-bpi-r2.dts b/arch/arm/boot/dts/mediatek/mt7623n-bananapi-bpi-r2.dts +index f68e99ca7027..fdec3d8170e6 100644 +--- a/arch/arm/boot/dts/mediatek/mt7623n-bananapi-bpi-r2.dts ++++ b/arch/arm/boot/dts/mediatek/mt7623n-bananapi-bpi-r2.dts +@@ -15,6 +15,8 @@ / { + + aliases { + serial2 = &uart2; ++ mmc0 = &mmc0; ++ mmc1 = &mmc1; + }; + + chosen { +-- +2.51.0 + + +From 2e82a39d56d22f1dc86a594687ebdb74b18910ee Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= +Date: Mon, 3 Nov 2025 15:50:47 +0100 +Subject: [PATCH 436/517] + /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/162-dts-mt7623-bpi-r2-led-aliases.patch + +--- + arch/arm/boot/dts/mediatek/mt7623n-bananapi-bpi-r2.dts | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/boot/dts/mediatek/mt7623n-bananapi-bpi-r2.dts b/arch/arm/boot/dts/mediatek/mt7623n-bananapi-bpi-r2.dts +index fdec3d8170e6..d980f068bde9 100644 +--- a/arch/arm/boot/dts/mediatek/mt7623n-bananapi-bpi-r2.dts ++++ b/arch/arm/boot/dts/mediatek/mt7623n-bananapi-bpi-r2.dts +@@ -17,6 +17,10 @@ aliases { + serial2 = &uart2; + mmc0 = &mmc0; + mmc1 = &mmc1; ++ led-boot = &led_system_green; ++ led-failsafe = &led_system_blue; ++ led-running = &led_system_green; ++ led-upgrade = &led_system_blue; + }; + + chosen { +@@ -112,13 +116,13 @@ leds { + pinctrl-names = "default"; + pinctrl-0 = <&led_pins_a>; + +- blue { ++ led_system_blue: blue { + label = "bpi-r2:pio:blue"; + gpios = <&pio 240 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + +- green { ++ led_system_green: green { + label = "bpi-r2:pio:green"; + gpios = <&pio 241 GPIO_ACTIVE_LOW>; + default-state = "off"; +-- +2.51.0 + + +From c0a89fcb4019825cf792107ebf3295f058f3d0df Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= +Date: Mon, 3 Nov 2025 15:50:47 +0100 +Subject: [PATCH 437/517] + /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/163-dts-mt7623-bpi-r2-ethernet-alias.patch + +--- + arch/arm/boot/dts/mediatek/mt7623n-bananapi-bpi-r2.dts | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm/boot/dts/mediatek/mt7623n-bananapi-bpi-r2.dts b/arch/arm/boot/dts/mediatek/mt7623n-bananapi-bpi-r2.dts +index d980f068bde9..7ff310fdb138 100644 +--- a/arch/arm/boot/dts/mediatek/mt7623n-bananapi-bpi-r2.dts ++++ b/arch/arm/boot/dts/mediatek/mt7623n-bananapi-bpi-r2.dts +@@ -15,6 +15,7 @@ / { + + aliases { + serial2 = &uart2; ++ ethernet0 = &gmac0; + mmc0 = &mmc0; + mmc1 = &mmc1; + led-boot = &led_system_green; +-- +2.51.0 + + +From 820e8b578867d75a0221837af059984f72a348c4 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= +Date: Mon, 3 Nov 2025 15:50:47 +0100 +Subject: [PATCH 438/517] + /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/164-dts-mt7623-bpi-r2-rootdisk-for-fitblk.patch + +--- + .../dts/mediatek/mt7623n-bananapi-bpi-r2.dts | 32 ++++++++++++++++++- + 1 file changed, 31 insertions(+), 1 deletion(-) + +diff --git a/arch/arm/boot/dts/mediatek/mt7623n-bananapi-bpi-r2.dts b/arch/arm/boot/dts/mediatek/mt7623n-bananapi-bpi-r2.dts +index 7ff310fdb138..9b1cf2c7f672 100644 +--- a/arch/arm/boot/dts/mediatek/mt7623n-bananapi-bpi-r2.dts ++++ b/arch/arm/boot/dts/mediatek/mt7623n-bananapi-bpi-r2.dts +@@ -26,7 +26,9 @@ aliases { + + chosen { + stdout-path = "serial2:115200n8"; +- bootargs = "earlycon=uart8250,mmio32,0x11004000 console=ttyS2,115200n8 console=tty1"; ++ bootargs = "root=/dev/fit0 rootwait earlycon=uart8250,mmio32,0x11004000 console=ttyS2,115200n8 console=tty1"; ++ rootdisk-emmc = <&emmc_rootdisk>; ++ rootdisk-sd = <&sd_rootdisk>; + }; + + connector { +@@ -338,6 +340,20 @@ &mmc0 { + vmmc-supply = <®_3p3v>; + vqmmc-supply = <®_1p8v>; + non-removable; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ card@0 { ++ compatible = "mmc-card"; ++ reg = <0>; ++ ++ partitions { ++ compatible = "msdos-partitions"; ++ emmc_rootdisk: block-partition-fit { ++ partno = <3>; ++ }; ++ }; ++ }; + }; + + &mmc1 { +@@ -351,6 +367,20 @@ &mmc1 { + cd-gpios = <&pio 261 GPIO_ACTIVE_LOW>; + vmmc-supply = <®_3p3v>; + vqmmc-supply = <®_3p3v>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ card@0 { ++ compatible = "mmc-card"; ++ reg = <0>; ++ ++ partitions { ++ compatible = "msdos-partitions"; ++ sd_rootdisk: block-partition-fit { ++ partno = <3>; ++ }; ++ }; ++ }; + }; + + &mt6323keys { +-- +2.51.0 + + +From 39278041735b59e066bd4440b141b69aaddc07ee Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Tue, 22 Apr 2025 15:24:25 +0200 +Subject: [PATCH 439/517] arm64: dts: mediatek: mt7988a-bpi-r4: allow hw + variants of bpi-r4 + +Sinovoip has released other variants of Bananapi-R4 board. +The known changes affecting only the LAN SFP+ slot which is replaced +by a 2.5G phy with optional PoE. + +Just move the common parts to a new dtsi and keep differences (only +i2c for lan-sfp) in dts. + +Signed-off-by: Frank Wunderlich +Acked-by: Krzysztof Kozlowski +Reviewed-by: AngeloGioacchino Del Regno +--- + arch/arm64/boot/dts/mediatek/Makefile | 6 + + .../mediatek/mt7988a-bananapi-bpi-r4-2g5.dts | 11 + + .../dts/mediatek/mt7988a-bananapi-bpi-r4.dts | 400 +----------------- + .../dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi | 399 +++++++++++++++++ + 4 files changed, 421 insertions(+), 395 deletions(-) + create mode 100644 arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-2g5.dts + create mode 100644 arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi + +diff --git a/arch/arm64/boot/dts/mediatek/Makefile b/arch/arm64/boot/dts/mediatek/Makefile +index 8fd7b2bb7a15..cd70066352b6 100644 +--- a/arch/arm64/boot/dts/mediatek/Makefile ++++ b/arch/arm64/boot/dts/mediatek/Makefile +@@ -21,6 +21,9 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += mt7986a-bananapi-bpi-r3-sd.dtbo + dtb-$(CONFIG_ARCH_MEDIATEK) += mt7986a-rfb.dtb + dtb-$(CONFIG_ARCH_MEDIATEK) += mt7986b-rfb.dtb + dtb-$(CONFIG_ARCH_MEDIATEK) += mt7988a-bananapi-bpi-r4.dtb ++dtb-$(CONFIG_ARCH_MEDIATEK) += mt7988a-bananapi-bpi-r4-2g5.dtb ++dtb-$(CONFIG_ARCH_MEDIATEK) += mt7988a-bananapi-bpi-r4-emmc.dtbo ++dtb-$(CONFIG_ARCH_MEDIATEK) += mt7988a-bananapi-bpi-r4-sd.dtbo + dtb-$(CONFIG_ARCH_MEDIATEK) += mt8167-pumpkin.dtb + dtb-$(CONFIG_ARCH_MEDIATEK) += mt8173-elm.dtb + dtb-$(CONFIG_ARCH_MEDIATEK) += mt8173-elm-hana.dtb +@@ -90,3 +93,6 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += mt8516-pumpkin.dtb + # Device tree overlays support + DTC_FLAGS_mt7986a-bananapi-bpi-r3 := -@ + DTC_FLAGS_mt7986a-bananapi-bpi-r3-mini := -@ ++DTC_FLAGS_mt7988a-bananapi-bpi-r4 := -@ ++DTC_FLAGS_mt7988a-bananapi-bpi-r4-2g5 := -@ ++DTC_FLAGS_mt8395-radxa-nio-12l := -@ +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-2g5.dts b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-2g5.dts +new file mode 100644 +index 000000000000..53de9c113f60 +--- /dev/null ++++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-2g5.dts +@@ -0,0 +1,11 @@ ++// SPDX-License-Identifier: GPL-2.0-only OR MIT ++ ++/dts-v1/; ++ ++#include "mt7988a-bananapi-bpi-r4.dtsi" ++ ++/ { ++ compatible = "bananapi,bpi-r4-2g5", "bananapi,bpi-r4", "mediatek,mt7988a"; ++ model = "Banana Pi BPI-R4 (1x SFP+, 1x 2.5GbE)"; ++ chassis-type = "embedded"; ++}; +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts +index 6623112c24c7..36bd1ef2efab 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts +@@ -2,408 +2,18 @@ + + /dts-v1/; + +-#include +-#include +- +-#include "mt7988a.dtsi" ++#include "mt7988a-bananapi-bpi-r4.dtsi" + + / { + compatible = "bananapi,bpi-r4", "mediatek,mt7988a"; +- model = "Banana Pi BPI-R4"; ++ model = "Banana Pi BPI-R4 (2x SFP+)"; + chassis-type = "embedded"; +- +- chosen { +- stdout-path = "serial0:115200n8"; +- }; +- +- reg_1p8v: regulator-1p8v { +- compatible = "regulator-fixed"; +- regulator-name = "fixed-1.8V"; +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <1800000>; +- regulator-boot-on; +- regulator-always-on; +- }; +- +- reg_3p3v: regulator-3p3v { +- compatible = "regulator-fixed"; +- regulator-name = "fixed-3.3V"; +- regulator-min-microvolt = <3300000>; +- regulator-max-microvolt = <3300000>; +- regulator-boot-on; +- regulator-always-on; +- }; + }; + +-&cpu0 { +- proc-supply = <&rt5190_buck3>; +-}; +- +-&cpu1 { +- proc-supply = <&rt5190_buck3>; +-}; +- +-&cpu2 { +- proc-supply = <&rt5190_buck3>; +-}; +- +-&cpu3 { +- proc-supply = <&rt5190_buck3>; +-}; +- +-&cpu_thermal { +- trips { +- cpu_trip_hot: hot { +- temperature = <120000>; +- hysteresis = <2000>; +- type = "hot"; +- }; +- +- cpu_trip_active_high: active-high { +- temperature = <115000>; +- hysteresis = <2000>; +- type = "active"; +- }; +- +- cpu_trip_active_med: active-med { +- temperature = <85000>; +- hysteresis = <2000>; +- type = "active"; +- }; +- +- cpu_trip_active_low: active-low { +- temperature = <40000>; +- hysteresis = <2000>; +- type = "active"; +- }; +- }; +-}; +- +-&i2c0 { +- pinctrl-names = "default"; +- pinctrl-0 = <&i2c0_pins>; +- status = "okay"; +- +- rt5190a_64: rt5190a@64 { +- compatible = "richtek,rt5190a"; +- reg = <0x64>; +- vin2-supply = <&rt5190_buck1>; +- vin3-supply = <&rt5190_buck1>; +- vin4-supply = <&rt5190_buck1>; +- +- regulators { +- rt5190_buck1: buck1 { +- regulator-name = "rt5190a-buck1"; +- regulator-min-microvolt = <5090000>; +- regulator-max-microvolt = <5090000>; +- regulator-allowed-modes = +- , ; +- regulator-boot-on; +- regulator-always-on; +- }; +- buck2 { +- regulator-name = "vcore"; +- regulator-min-microvolt = <600000>; +- regulator-max-microvolt = <1400000>; +- regulator-boot-on; +- regulator-always-on; +- }; +- rt5190_buck3: buck3 { +- regulator-name = "vproc"; +- regulator-min-microvolt = <600000>; +- regulator-max-microvolt = <1400000>; +- regulator-boot-on; +- }; +- buck4 { +- regulator-name = "rt5190a-buck4"; +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <1800000>; +- regulator-allowed-modes = +- , ; +- regulator-boot-on; +- regulator-always-on; +- }; +- ldo { +- regulator-name = "rt5190a-ldo"; +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <1800000>; +- regulator-boot-on; +- regulator-always-on; +- }; +- }; +- }; +-}; +- +-&i2c2 { +- pinctrl-names = "default"; +- pinctrl-0 = <&i2c2_1_pins>; +- status = "okay"; +- +- pca9545: i2c-mux@70 { +- compatible = "nxp,pca9545"; +- reg = <0x70>; +- reset-gpios = <&pio 5 GPIO_ACTIVE_LOW>; ++&pca9545 { ++ i2c_sfp2: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; +- +- i2c@0 { +- #address-cells = <1>; +- #size-cells = <0>; +- reg = <0>; +- +- pcf8563: rtc@51 { +- compatible = "nxp,pcf8563"; +- reg = <0x51>; +- #clock-cells = <0>; +- }; +- +- eeprom@57 { +- compatible = "atmel,24c02"; +- reg = <0x57>; +- size = <256>; +- }; +- +- }; +- +- i2c_sfp1: i2c@1 { +- #address-cells = <1>; +- #size-cells = <0>; +- reg = <1>; +- }; +- +- i2c_sfp2: i2c@2 { +- #address-cells = <1>; +- #size-cells = <0>; +- reg = <2>; +- }; +- }; +-}; +- +-/* mPCIe SIM2 */ +-&pcie0 { +- status = "okay"; +-}; +- +-/* mPCIe SIM3 */ +-&pcie1 { +- status = "okay"; +-}; +- +-/* M.2 key-B SIM1 */ +-&pcie2 { +- status = "okay"; +-}; +- +-/* M.2 key-M SSD */ +-&pcie3 { +- status = "okay"; +-}; +- +-&pio { +- mdio0_pins: mdio0-pins { +- mux { +- function = "eth"; +- groups = "mdc_mdio0"; +- }; +- +- conf { +- pins = "SMI_0_MDC", "SMI_0_MDIO"; +- drive-strength = <8>; +- }; +- }; +- +- i2c0_pins: i2c0-g0-pins { +- mux { +- function = "i2c"; +- groups = "i2c0_1"; +- }; +- }; +- +- i2c1_pins: i2c1-g0-pins { +- mux { +- function = "i2c"; +- groups = "i2c1_0"; +- }; +- }; +- +- i2c1_sfp_pins: i2c1-sfp-g0-pins { +- mux { +- function = "i2c"; +- groups = "i2c1_sfp"; +- }; +- }; +- +- i2c2_0_pins: i2c2-g0-pins { +- mux { +- function = "i2c"; +- groups = "i2c2_0"; +- }; ++ reg = <2>; + }; +- +- i2c2_1_pins: i2c2-g1-pins { +- mux { +- function = "i2c"; +- groups = "i2c2_1"; +- }; +- }; +- +- gbe0_led0_pins: gbe0-led0-pins { +- mux { +- function = "led"; +- groups = "gbe0_led0"; +- }; +- }; +- +- gbe1_led0_pins: gbe1-led0-pins { +- mux { +- function = "led"; +- groups = "gbe1_led0"; +- }; +- }; +- +- gbe2_led0_pins: gbe2-led0-pins { +- mux { +- function = "led"; +- groups = "gbe2_led0"; +- }; +- }; +- +- gbe3_led0_pins: gbe3-led0-pins { +- mux { +- function = "led"; +- groups = "gbe3_led0"; +- }; +- }; +- +- gbe0_led1_pins: gbe0-led1-pins { +- mux { +- function = "led"; +- groups = "gbe0_led1"; +- }; +- }; +- +- gbe1_led1_pins: gbe1-led1-pins { +- mux { +- function = "led"; +- groups = "gbe1_led1"; +- }; +- }; +- +- gbe2_led1_pins: gbe2-led1-pins { +- mux { +- function = "led"; +- groups = "gbe2_led1"; +- }; +- }; +- +- gbe3_led1_pins: gbe3-led1-pins { +- mux { +- function = "led"; +- groups = "gbe3_led1"; +- }; +- }; +- +- i2p5gbe_led0_pins: 2p5gbe-led0-pins { +- mux { +- function = "led"; +- groups = "2p5gbe_led0"; +- }; +- }; +- +- i2p5gbe_led1_pins: 2p5gbe-led1-pins { +- mux { +- function = "led"; +- groups = "2p5gbe_led1"; +- }; +- }; +- +- mmc0_pins_emmc_45: mmc0-emmc-45-pins { +- mux { +- function = "flash"; +- groups = "emmc_45"; +- }; +- }; +- +- mmc0_pins_emmc_51: mmc0-emmc-51-pins { +- mux { +- function = "flash"; +- groups = "emmc_51"; +- }; +- }; +- +- mmc0_pins_sdcard: mmc0-sdcard-pins { +- mux { +- function = "flash"; +- groups = "sdcard"; +- }; +- }; +- +- uart0_pins: uart0-pins { +- mux { +- function = "uart"; +- groups = "uart0"; +- }; +- }; +- +- snfi_pins: snfi-pins { +- mux { +- function = "flash"; +- groups = "snfi"; +- }; +- }; +- +- spi0_pins: spi0-pins { +- mux { +- function = "spi"; +- groups = "spi0"; +- }; +- }; +- +- spi0_flash_pins: spi0-flash-pins { +- mux { +- function = "spi"; +- groups = "spi0", "spi0_wp_hold"; +- }; +- }; +- +- spi1_pins: spi1-pins { +- mux { +- function = "spi"; +- groups = "spi1"; +- }; +- }; +- +- spi2_pins: spi2-pins { +- mux { +- function = "spi"; +- groups = "spi2"; +- }; +- }; +- +- spi2_flash_pins: spi2-flash-pins { +- mux { +- function = "spi"; +- groups = "spi2", "spi2_wp_hold"; +- }; +- }; +-}; +- +-&pwm { +- status = "okay"; +-}; +- +-&serial0 { +- status = "okay"; +-}; +- +-&ssusb1 { +- status = "okay"; +-}; +- +-&tphy { +- status = "okay"; +-}; +- +-&watchdog { +- status = "okay"; + }; +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi +new file mode 100644 +index 000000000000..0d332822971d +--- /dev/null ++++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi +@@ -0,0 +1,399 @@ ++// SPDX-License-Identifier: GPL-2.0-only OR MIT ++ ++/dts-v1/; ++ ++#include ++#include ++ ++#include "mt7988a.dtsi" ++ ++/ { ++ chosen { ++ stdout-path = "serial0:115200n8"; ++ }; ++ ++ reg_1p8v: regulator-1p8v { ++ compatible = "regulator-fixed"; ++ regulator-name = "fixed-1.8V"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ reg_3p3v: regulator-3p3v { ++ compatible = "regulator-fixed"; ++ regulator-name = "fixed-3.3V"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++}; ++ ++&cpu0 { ++ proc-supply = <&rt5190_buck3>; ++}; ++ ++&cpu1 { ++ proc-supply = <&rt5190_buck3>; ++}; ++ ++&cpu2 { ++ proc-supply = <&rt5190_buck3>; ++}; ++ ++&cpu3 { ++ proc-supply = <&rt5190_buck3>; ++}; ++ ++&cpu_thermal { ++ trips { ++ cpu_trip_hot: hot { ++ temperature = <120000>; ++ hysteresis = <2000>; ++ type = "hot"; ++ }; ++ ++ cpu_trip_active_high: active-high { ++ temperature = <115000>; ++ hysteresis = <2000>; ++ type = "active"; ++ }; ++ ++ cpu_trip_active_med: active-med { ++ temperature = <85000>; ++ hysteresis = <2000>; ++ type = "active"; ++ }; ++ ++ cpu_trip_active_low: active-low { ++ temperature = <40000>; ++ hysteresis = <2000>; ++ type = "active"; ++ }; ++ }; ++}; ++ ++&i2c0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c0_pins>; ++ status = "okay"; ++ ++ rt5190a_64: rt5190a@64 { ++ compatible = "richtek,rt5190a"; ++ reg = <0x64>; ++ vin2-supply = <&rt5190_buck1>; ++ vin3-supply = <&rt5190_buck1>; ++ vin4-supply = <&rt5190_buck1>; ++ ++ regulators { ++ rt5190_buck1: buck1 { ++ regulator-name = "rt5190a-buck1"; ++ regulator-min-microvolt = <5090000>; ++ regulator-max-microvolt = <5090000>; ++ regulator-allowed-modes = ++ , ; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ buck2 { ++ regulator-name = "vcore"; ++ regulator-min-microvolt = <600000>; ++ regulator-max-microvolt = <1400000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ rt5190_buck3: buck3 { ++ regulator-name = "vproc"; ++ regulator-min-microvolt = <600000>; ++ regulator-max-microvolt = <1400000>; ++ regulator-boot-on; ++ }; ++ buck4 { ++ regulator-name = "rt5190a-buck4"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-allowed-modes = ++ , ; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ldo { ++ regulator-name = "rt5190a-ldo"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ }; ++ }; ++}; ++ ++&i2c2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c2_1_pins>; ++ status = "okay"; ++ ++ pca9545: i2c-mux@70 { ++ compatible = "nxp,pca9545"; ++ reg = <0x70>; ++ reset-gpios = <&pio 5 GPIO_ACTIVE_LOW>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ i2c@0 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0>; ++ ++ pcf8563: rtc@51 { ++ compatible = "nxp,pcf8563"; ++ reg = <0x51>; ++ #clock-cells = <0>; ++ }; ++ ++ eeprom@57 { ++ compatible = "atmel,24c02"; ++ reg = <0x57>; ++ size = <256>; ++ }; ++ ++ }; ++ ++ i2c_sfp1: i2c@1 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <1>; ++ }; ++ }; ++}; ++ ++/* mPCIe SIM2 */ ++&pcie0 { ++ status = "okay"; ++}; ++ ++/* mPCIe SIM3 */ ++&pcie1 { ++ status = "okay"; ++}; ++ ++/* M.2 key-B SIM1 */ ++&pcie2 { ++ status = "okay"; ++}; ++ ++/* M.2 key-M SSD */ ++&pcie3 { ++ status = "okay"; ++}; ++ ++&pio { ++ mdio0_pins: mdio0-pins { ++ mux { ++ function = "eth"; ++ groups = "mdc_mdio0"; ++ }; ++ ++ conf { ++ pins = "SMI_0_MDC", "SMI_0_MDIO"; ++ drive-strength = <8>; ++ }; ++ }; ++ ++ i2c0_pins: i2c0-g0-pins { ++ mux { ++ function = "i2c"; ++ groups = "i2c0_1"; ++ }; ++ }; ++ ++ i2c1_pins: i2c1-g0-pins { ++ mux { ++ function = "i2c"; ++ groups = "i2c1_0"; ++ }; ++ }; ++ ++ i2c1_sfp_pins: i2c1-sfp-g0-pins { ++ mux { ++ function = "i2c"; ++ groups = "i2c1_sfp"; ++ }; ++ }; ++ ++ i2c2_0_pins: i2c2-g0-pins { ++ mux { ++ function = "i2c"; ++ groups = "i2c2_0"; ++ }; ++ }; ++ ++ i2c2_1_pins: i2c2-g1-pins { ++ mux { ++ function = "i2c"; ++ groups = "i2c2_1"; ++ }; ++ }; ++ ++ gbe0_led0_pins: gbe0-led0-pins { ++ mux { ++ function = "led"; ++ groups = "gbe0_led0"; ++ }; ++ }; ++ ++ gbe1_led0_pins: gbe1-led0-pins { ++ mux { ++ function = "led"; ++ groups = "gbe1_led0"; ++ }; ++ }; ++ ++ gbe2_led0_pins: gbe2-led0-pins { ++ mux { ++ function = "led"; ++ groups = "gbe2_led0"; ++ }; ++ }; ++ ++ gbe3_led0_pins: gbe3-led0-pins { ++ mux { ++ function = "led"; ++ groups = "gbe3_led0"; ++ }; ++ }; ++ ++ gbe0_led1_pins: gbe0-led1-pins { ++ mux { ++ function = "led"; ++ groups = "gbe0_led1"; ++ }; ++ }; ++ ++ gbe1_led1_pins: gbe1-led1-pins { ++ mux { ++ function = "led"; ++ groups = "gbe1_led1"; ++ }; ++ }; ++ ++ gbe2_led1_pins: gbe2-led1-pins { ++ mux { ++ function = "led"; ++ groups = "gbe2_led1"; ++ }; ++ }; ++ ++ gbe3_led1_pins: gbe3-led1-pins { ++ mux { ++ function = "led"; ++ groups = "gbe3_led1"; ++ }; ++ }; ++ ++ i2p5gbe_led0_pins: 2p5gbe-led0-pins { ++ mux { ++ function = "led"; ++ groups = "2p5gbe_led0"; ++ }; ++ }; ++ ++ i2p5gbe_led1_pins: 2p5gbe-led1-pins { ++ mux { ++ function = "led"; ++ groups = "2p5gbe_led1"; ++ }; ++ }; ++ ++ mmc0_pins_emmc_45: mmc0-emmc-45-pins { ++ mux { ++ function = "flash"; ++ groups = "emmc_45"; ++ }; ++ }; ++ ++ mmc0_pins_emmc_51: mmc0-emmc-51-pins { ++ mux { ++ function = "flash"; ++ groups = "emmc_51"; ++ }; ++ }; ++ ++ mmc0_pins_sdcard: mmc0-sdcard-pins { ++ mux { ++ function = "flash"; ++ groups = "sdcard"; ++ }; ++ }; ++ ++ uart0_pins: uart0-pins { ++ mux { ++ function = "uart"; ++ groups = "uart0"; ++ }; ++ }; ++ ++ snfi_pins: snfi-pins { ++ mux { ++ function = "flash"; ++ groups = "snfi"; ++ }; ++ }; ++ ++ spi0_pins: spi0-pins { ++ mux { ++ function = "spi"; ++ groups = "spi0"; ++ }; ++ }; ++ ++ spi0_flash_pins: spi0-flash-pins { ++ mux { ++ function = "spi"; ++ groups = "spi0", "spi0_wp_hold"; ++ }; ++ }; ++ ++ spi1_pins: spi1-pins { ++ mux { ++ function = "spi"; ++ groups = "spi1"; ++ }; ++ }; ++ ++ spi2_pins: spi2-pins { ++ mux { ++ function = "spi"; ++ groups = "spi2"; ++ }; ++ }; ++ ++ spi2_flash_pins: spi2-flash-pins { ++ mux { ++ function = "spi"; ++ groups = "spi2", "spi2_wp_hold"; ++ }; ++ }; ++}; ++ ++&pwm { ++ status = "okay"; ++}; ++ ++&serial0 { ++ status = "okay"; ++}; ++ ++&ssusb1 { ++ status = "okay"; ++}; ++ ++&tphy { ++ status = "okay"; ++}; ++ ++&watchdog { ++ status = "okay"; ++}; +-- +2.51.0 + + +From 85dec32b37881f3eb8fa393afcc9c32d1a685667 Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Tue, 22 Apr 2025 15:24:30 +0200 +Subject: [PATCH 440/517] arm64: dts: mediatek: mt7988: Add xsphy for + ssusb0/pcie2 + +First usb and third pcie controller on mt7988 need a xs-phy to work +properly. + +Signed-off-by: Frank Wunderlich +Reviewed-by: AngeloGioacchino Del Regno +--- + arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 36 +++++++++++++++++++++++ + 1 file changed, 36 insertions(+) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +index 88b56a24efca..a59f8708f0ef 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +@@ -334,6 +334,8 @@ usb@11190000 { + <&infracfg CLK_INFRA_133M_USB_HCK>, + <&infracfg CLK_INFRA_USB_XHCI>; + clock-names = "sys_ck", "ref_ck", "mcu_ck", "dma_ck", "xhci_ck"; ++ phys = <&xphyu2port0 PHY_TYPE_USB2>, ++ <&xphyu3port0 PHY_TYPE_USB3>; + status = "disabled"; + }; + +@@ -398,6 +400,9 @@ pcie2: pcie@11280000 { + pinctrl-0 = <&pcie2_pins>; + status = "disabled"; + ++ phys = <&xphyu3port0 PHY_TYPE_PCIE>; ++ phy-names = "pcie-phy"; ++ + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0x7>; + interrupt-map = <0 0 0 1 &pcie_intc2 0>, +@@ -548,6 +553,37 @@ tphyu3port0: usb-phy@11c50700 { + }; + }; + ++ ++ topmisc: system-controller@11d10084 { ++ compatible = "mediatek,mt7988-topmisc", ++ "syscon"; ++ reg = <0 0x11d10084 0 0xff80>; ++ }; ++ ++ xs-phy@11e10000 { ++ compatible = "mediatek,mt7988-xsphy", ++ "mediatek,xsphy"; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ status = "disabled"; ++ ++ xphyu2port0: usb-phy@11e10000 { ++ reg = <0 0x11e10000 0 0x400>; ++ clocks = <&infracfg CLK_INFRA_USB_UTMI>; ++ clock-names = "ref"; ++ #phy-cells = <1>; ++ }; ++ ++ xphyu3port0: usb-phy@11e13000 { ++ reg = <0 0x11e13400 0 0x500>; ++ clocks = <&infracfg CLK_INFRA_USB_PIPE>; ++ clock-names = "ref"; ++ #phy-cells = <1>; ++ mediatek,syscon-type = <&topmisc 0x194 0>; ++ }; ++ }; ++ + clock-controller@11f40000 { + compatible = "mediatek,mt7988-xfi-pll"; + reg = <0 0x11f40000 0 0x1000>; +-- +2.51.0 + + +From 72b8292bf3f9f14d1effee2ba565704bd95cdaa2 Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Tue, 22 Apr 2025 15:24:31 +0200 +Subject: [PATCH 441/517] arm64: dts: mediatek: mt7988a-bpi-r4: enable xsphy + +Enable XS-Phy on Bananapi R4 for pcie2. + +Signed-off-by: Frank Wunderlich +Reviewed-by: AngeloGioacchino Del Regno +--- + arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi | 4 ++++ + arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 2 +- + 2 files changed, 5 insertions(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi +index 0d332822971d..37e541a98ee1 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi +@@ -397,3 +397,7 @@ &tphy { + &watchdog { + status = "okay"; + }; ++ ++&xsphy { ++ status = "okay"; ++}; +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +index a59f8708f0ef..8f6d1dfae24a 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +@@ -560,7 +560,7 @@ topmisc: system-controller@11d10084 { + reg = <0 0x11d10084 0 0xff80>; + }; + +- xs-phy@11e10000 { ++ xsphy: xs-phy@11e10000 { + compatible = "mediatek,mt7988-xsphy", + "mediatek,xsphy"; + #address-cells = <2>; +-- +2.51.0 + + +From ac56a2fb07e5a0cc06c96d60801d5f6f88a05715 Mon Sep 17 00:00:00 2001 +From: Sky Huang +Date: Wed, 19 Feb 2025 16:39:09 +0800 +Subject: [PATCH 442/517] dts: mt7988a: Add built-in ethernet phy firmware node + +Add built-in ethernet phy firmware node in mt7988a.dtsi. + +Signed-off-by: Sky Huang +--- + arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +index 8f6d1dfae24a..1bd5f6f7cab9 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +@@ -322,6 +322,12 @@ lvts: lvts@1100a000 { + nvmem-cell-names = "lvts-calib-data-1"; + }; + ++ phyfw: phy-firmware@f000000 { ++ compatible = "mediatek,2p5gphy-fw"; ++ reg = <0 0x0f100000 0 0x20000>, ++ <0 0x0f0f0018 0 0x20>; ++ }; ++ + usb@11190000 { + compatible = "mediatek,mt7988-xhci", "mediatek,mtk-xhci"; + reg = <0 0x11190000 0 0x2e00>, +-- +2.51.0 + + +From 963d669897db001e98a3beda0efdc1c36c416c8f Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Sun, 11 May 2025 16:19:20 +0200 +Subject: [PATCH 443/517] arm64: dts: mediatek: mt7988: add spi controllers + +Add SPI controllers for mt7988. + +Signed-off-by: Daniel Golle +Signed-off-by: Frank Wunderlich +--- + arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 45 +++++++++++++++++++++++ + 1 file changed, 45 insertions(+) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +index 1bd5f6f7cab9..00804f5d7cfb 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +@@ -311,6 +311,51 @@ i2c2: i2c@11005000 { + status = "disabled"; + }; + ++ spi0: spi@11007000 { ++ compatible = "mediatek,mt7988-spi-quad", "mediatek,spi-ipm"; ++ reg = <0 0x11007000 0 0x100>; ++ interrupts = ; ++ clocks = <&topckgen CLK_TOP_MPLL_D2>, ++ <&topckgen CLK_TOP_SPI_SEL>, ++ <&infracfg CLK_INFRA_104M_SPI0>, ++ <&infracfg CLK_INFRA_66M_SPI0_HCK>; ++ clock-names = "parent-clk", "sel-clk", "spi-clk", ++ "hclk"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ spi1: spi@11008000 { ++ compatible = "mediatek,mt7988-spi-single", "mediatek,spi-ipm"; ++ reg = <0 0x11008000 0 0x100>; ++ interrupts = ; ++ clocks = <&topckgen CLK_TOP_MPLL_D2>, ++ <&topckgen CLK_TOP_SPIM_MST_SEL>, ++ <&infracfg CLK_INFRA_104M_SPI1>, ++ <&infracfg CLK_INFRA_66M_SPI1_HCK>; ++ clock-names = "parent-clk", "sel-clk", "spi-clk", ++ "hclk"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ spi2: spi@11009000 { ++ compatible = "mediatek,mt7988-spi-quad", "mediatek,spi-ipm"; ++ reg = <0 0x11009000 0 0x100>; ++ interrupts = ; ++ clocks = <&topckgen CLK_TOP_MPLL_D2>, ++ <&topckgen CLK_TOP_SPI_SEL>, ++ <&infracfg CLK_INFRA_104M_SPI2_BCK>, ++ <&infracfg CLK_INFRA_66M_SPI2_HCK>; ++ clock-names = "parent-clk", "sel-clk", "spi-clk", ++ "hclk"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ + lvts: lvts@1100a000 { + compatible = "mediatek,mt7988-lvts-ap"; + #thermal-sensor-cells = <1>; +-- +2.51.0 + + +From bf8119d36aa8a45ef759d007d1f380559ce5c75b Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Sun, 11 May 2025 16:19:21 +0200 +Subject: [PATCH 444/517] arm64: dts: mediatek: mt7988: move uart0 and spi1 + pins to soc dtsi + +In order to use uart0 or spi1 there is only 1 possible pin definition +so move them to soc dtsi to reuse them in other boards and avoiding +conflict if defined twice. + +Suggested-by: Daniel Golle +Signed-off-by: Frank Wunderlich +--- + .../dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi | 14 -------------- + arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 18 ++++++++++++++++++ + 2 files changed, 18 insertions(+), 14 deletions(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi +index 37e541a98ee1..23b267cd47ac 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi +@@ -328,13 +328,6 @@ mux { + }; + }; + +- uart0_pins: uart0-pins { +- mux { +- function = "uart"; +- groups = "uart0"; +- }; +- }; +- + snfi_pins: snfi-pins { + mux { + function = "flash"; +@@ -356,13 +349,6 @@ mux { + }; + }; + +- spi1_pins: spi1-pins { +- mux { +- function = "spi"; +- groups = "spi1"; +- }; +- }; +- + spi2_pins: spi2-pins { + mux { + function = "spi"; +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +index 00804f5d7cfb..e6f453cba690 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +@@ -209,6 +209,20 @@ mux { + "pcie_wake_n3_0"; + }; + }; ++ ++ spi1_pins: spi1-pins { ++ mux { ++ function = "spi"; ++ groups = "spi1"; ++ }; ++ }; ++ ++ uart0_pins: uart0-pins { ++ mux { ++ function = "uart"; ++ groups = "uart0"; ++ }; ++ }; + }; + + pwm: pwm@10048000 { +@@ -244,6 +258,8 @@ serial0: serial@11000000 { + clocks = <&topckgen CLK_TOP_UART_SEL>, + <&infracfg CLK_INFRA_52M_UART0_CK>; + clock-names = "baud", "bus"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&uart0_pins>; + status = "disabled"; + }; + +@@ -338,6 +354,8 @@ spi1: spi@11008000 { + "hclk"; + #address-cells = <1>; + #size-cells = <0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spi1_pins>; + status = "disabled"; + }; + +-- +2.51.0 + + +From 47332041261f52b7abadb9697e530606ae4a04d1 Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Sun, 11 May 2025 16:19:22 +0200 +Subject: [PATCH 445/517] arm64: dts: mediatek: mt7988: add cci node + +Add cci devicetree node for cpu frequency scaling. + +Signed-off-by: Daniel Golle +Signed-off-by: Frank Wunderlich +--- + arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 33 +++++++++++++++++++++++ + 1 file changed, 33 insertions(+) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +index e6f453cba690..c0012ecc0279 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +@@ -12,6 +12,35 @@ / { + #address-cells = <2>; + #size-cells = <2>; + ++ cci: cci { ++ compatible = "mediatek,mt8183-cci"; ++ clocks = <&mcusys CLK_MCU_BUS_DIV_SEL>, ++ <&topckgen CLK_TOP_XTAL>; ++ clock-names = "cci", "intermediate"; ++ operating-points-v2 = <&cci_opp>; ++ }; ++ ++ cci_opp: opp-table-cci { ++ compatible = "operating-points-v2"; ++ opp-shared; ++ opp-480000000 { ++ opp-hz = /bits/ 64 <480000000>; ++ opp-microvolt = <850000>; ++ }; ++ opp-660000000 { ++ opp-hz = /bits/ 64 <660000000>; ++ opp-microvolt = <850000>; ++ }; ++ opp-900000000 { ++ opp-hz = /bits/ 64 <900000000>; ++ opp-microvolt = <850000>; ++ }; ++ opp-1080000000 { ++ opp-hz = /bits/ 64 <1080000000>; ++ opp-microvolt = <900000>; ++ }; ++ }; ++ + cpus { + #address-cells = <1>; + #size-cells = <0>; +@@ -25,6 +54,7 @@ cpu0: cpu@0 { + <&topckgen CLK_TOP_XTAL>; + clock-names = "cpu", "intermediate"; + operating-points-v2 = <&cluster0_opp>; ++ mediatek,cci = <&cci>; + }; + + cpu1: cpu@1 { +@@ -36,6 +66,7 @@ cpu1: cpu@1 { + <&topckgen CLK_TOP_XTAL>; + clock-names = "cpu", "intermediate"; + operating-points-v2 = <&cluster0_opp>; ++ mediatek,cci = <&cci>; + }; + + cpu2: cpu@2 { +@@ -47,6 +78,7 @@ cpu2: cpu@2 { + <&topckgen CLK_TOP_XTAL>; + clock-names = "cpu", "intermediate"; + operating-points-v2 = <&cluster0_opp>; ++ mediatek,cci = <&cci>; + }; + + cpu3: cpu@3 { +@@ -58,6 +90,7 @@ cpu3: cpu@3 { + <&topckgen CLK_TOP_XTAL>; + clock-names = "cpu", "intermediate"; + operating-points-v2 = <&cluster0_opp>; ++ mediatek,cci = <&cci>; + }; + + cluster0_opp: opp-table-0 { +-- +2.51.0 + + +From 8eaa49fa6b1ad51e5ff86d8996611202f0b91f60 Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Sun, 11 May 2025 16:19:23 +0200 +Subject: [PATCH 446/517] arm64: dts: mediatek: mt7988: add phy calibration + efuse subnodes + +MT7988 contains buildin mt753x switch which needs calibration data from +efuse. + +Signed-off-by: Daniel Golle +Signed-off-by: Frank Wunderlich +--- + arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +index c0012ecc0279..9b5f1d8b7a5e 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +@@ -702,6 +702,22 @@ efuse@11f50000 { + lvts_calibration: calib@918 { + reg = <0x918 0x28>; + }; ++ ++ phy_calibration_p0: calib@940 { ++ reg = <0x940 0x10>; ++ }; ++ ++ phy_calibration_p1: calib@954 { ++ reg = <0x954 0x10>; ++ }; ++ ++ phy_calibration_p2: calib@968 { ++ reg = <0x968 0x10>; ++ }; ++ ++ phy_calibration_p3: calib@97c { ++ reg = <0x97c 0x10>; ++ }; + }; + + clock-controller@15000000 { +-- +2.51.0 + + +From 55218122074b172b336b24d381b46308fcfef693 Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Sun, 11 May 2025 16:19:24 +0200 +Subject: [PATCH 447/517] arm64: dts: mediatek: mt7988: add basic + ethernet-nodes + +Add basic ethernet related nodes. + +Mac1+2 needs pcs (sgmii+usxgmii) to work correctly which will be linked +later when driver is merged. + +Signed-off-by: Daniel Golle +Signed-off-by: Frank Wunderlich +--- + arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 124 +++++++++++++++++++++- + 1 file changed, 121 insertions(+), 3 deletions(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +index 9b5f1d8b7a5e..87c39335c528 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +@@ -686,7 +686,28 @@ xphyu3port0: usb-phy@11e13000 { + }; + }; + +- clock-controller@11f40000 { ++ xfi_tphy0: phy@11f20000 { ++ compatible = "mediatek,mt7988-xfi-tphy"; ++ reg = <0 0x11f20000 0 0x10000>; ++ resets = <&watchdog 14>; ++ clocks = <&xfi_pll CLK_XFIPLL_PLL_EN>, ++ <&topckgen CLK_TOP_XFI_PHY_0_XTAL_SEL>; ++ clock-names = "xfipll", "topxtal"; ++ mediatek,usxgmii-performance-errata; ++ #phy-cells = <0>; ++ }; ++ ++ xfi_tphy1: phy@11f30000 { ++ compatible = "mediatek,mt7988-xfi-tphy"; ++ reg = <0 0x11f30000 0 0x10000>; ++ resets = <&watchdog 15>; ++ clocks = <&xfi_pll CLK_XFIPLL_PLL_EN>, ++ <&topckgen CLK_TOP_XFI_PHY_1_XTAL_SEL>; ++ clock-names = "xfipll", "topxtal"; ++ #phy-cells = <0>; ++ }; ++ ++ xfi_pll: clock-controller@11f40000 { + compatible = "mediatek,mt7988-xfi-pll"; + reg = <0 0x11f40000 0 0x1000>; + resets = <&watchdog 16>; +@@ -720,19 +741,116 @@ phy_calibration_p3: calib@97c { + }; + }; + +- clock-controller@15000000 { ++ ethsys: clock-controller@15000000 { + compatible = "mediatek,mt7988-ethsys", "syscon"; + reg = <0 0x15000000 0 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + +- clock-controller@15031000 { ++ ethwarp: clock-controller@15031000 { + compatible = "mediatek,mt7988-ethwarp"; + reg = <0 0x15031000 0 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; + }; ++ ++ eth: ethernet@15100000 { ++ compatible = "mediatek,mt7988-eth"; ++ reg = <0 0x15100000 0 0x80000>, ++ <0 0x15400000 0 0x200000>; ++ interrupts = , ++ , ++ , ++ ; ++ clocks = <ðsys CLK_ETHDMA_CRYPT0_EN>, ++ <ðsys CLK_ETHDMA_FE_EN>, ++ <ðsys CLK_ETHDMA_GP2_EN>, ++ <ðsys CLK_ETHDMA_GP1_EN>, ++ <ðsys CLK_ETHDMA_GP3_EN>, ++ <ðwarp CLK_ETHWARP_WOCPU2_EN>, ++ <ðwarp CLK_ETHWARP_WOCPU1_EN>, ++ <ðwarp CLK_ETHWARP_WOCPU0_EN>, ++ <ðsys CLK_ETHDMA_ESW_EN>, ++ <&topckgen CLK_TOP_ETH_GMII_SEL>, ++ <&topckgen CLK_TOP_ETH_REFCK_50M_SEL>, ++ <&topckgen CLK_TOP_ETH_SYS_200M_SEL>, ++ <&topckgen CLK_TOP_ETH_SYS_SEL>, ++ <&topckgen CLK_TOP_ETH_XGMII_SEL>, ++ <&topckgen CLK_TOP_ETH_MII_SEL>, ++ <&topckgen CLK_TOP_NETSYS_SEL>, ++ <&topckgen CLK_TOP_NETSYS_500M_SEL>, ++ <&topckgen CLK_TOP_NETSYS_PAO_2X_SEL>, ++ <&topckgen CLK_TOP_NETSYS_SYNC_250M_SEL>, ++ <&topckgen CLK_TOP_NETSYS_PPEFB_250M_SEL>, ++ <&topckgen CLK_TOP_NETSYS_WARP_SEL>, ++ <ðsys CLK_ETHDMA_XGP1_EN>, ++ <ðsys CLK_ETHDMA_XGP2_EN>, ++ <ðsys CLK_ETHDMA_XGP3_EN>; ++ clock-names = "crypto", "fe", "gp2", "gp1", ++ "gp3", ++ "ethwarp_wocpu2", "ethwarp_wocpu1", ++ "ethwarp_wocpu0", "esw", "top_eth_gmii_sel", ++ "top_eth_refck_50m_sel", "top_eth_sys_200m_sel", ++ "top_eth_sys_sel", "top_eth_xgmii_sel", ++ "top_eth_mii_sel", "top_netsys_sel", ++ "top_netsys_500m_sel", "top_netsys_pao_2x_sel", ++ "top_netsys_sync_250m_sel", ++ "top_netsys_ppefb_250m_sel", ++ "top_netsys_warp_sel","xgp1", "xgp2", "xgp3"; ++ assigned-clocks = <&topckgen CLK_TOP_NETSYS_2X_SEL>, ++ <&topckgen CLK_TOP_NETSYS_GSW_SEL>, ++ <&topckgen CLK_TOP_USXGMII_SBUS_0_SEL>, ++ <&topckgen CLK_TOP_USXGMII_SBUS_1_SEL>, ++ <&topckgen CLK_TOP_SGM_0_SEL>, ++ <&topckgen CLK_TOP_SGM_1_SEL>; ++ assigned-clock-parents = <&apmixedsys CLK_APMIXED_NET2PLL>, ++ <&topckgen CLK_TOP_NET1PLL_D4>, ++ <&topckgen CLK_TOP_NET1PLL_D8_D4>, ++ <&topckgen CLK_TOP_NET1PLL_D8_D4>, ++ <&apmixedsys CLK_APMIXED_SGMPLL>, ++ <&apmixedsys CLK_APMIXED_SGMPLL>; ++ mediatek,ethsys = <ðsys>; ++ mediatek,infracfg = <&topmisc>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ gmac0: mac@0 { ++ compatible = "mediatek,eth-mac"; ++ reg = <0>; ++ phy-mode = "internal"; ++ ++ fixed-link { ++ speed = <10000>; ++ full-duplex; ++ pause; ++ }; ++ }; ++ ++ gmac1: mac@1 { ++ compatible = "mediatek,eth-mac"; ++ reg = <1>; ++ status = "disabled"; ++ }; ++ ++ gmac2: mac@2 { ++ compatible = "mediatek,eth-mac"; ++ reg = <2>; ++ status = "disabled"; ++ }; ++ ++ mdio_bus: mdio-bus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ /* internal 2.5G PHY */ ++ int_2p5g_phy: ethernet-phy@f { ++ reg = <15>; ++ compatible = "ethernet-phy-ieee802.3-c45"; ++ phy-mode = "internal"; ++ }; ++ }; ++ }; + }; + + thermal-zones { +-- +2.51.0 + + +From 19b301d95660bf872d694d0180f3e1fc9eb51a5a Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Sun, 11 May 2025 16:19:25 +0200 +Subject: [PATCH 448/517] arm64: dts: mediatek: mt7988: add switch node + +Add mt7988 builtin mt753x switch nodes. + +Signed-off-by: Daniel Golle +Signed-off-by: Frank Wunderlich +--- + arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 154 ++++++++++++++++++++++ + 1 file changed, 154 insertions(+) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +index 87c39335c528..f19e884f13be 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +@@ -5,6 +5,7 @@ + #include + #include + #include ++#include + + / { + compatible = "mediatek,mt7988a"; +@@ -748,6 +749,159 @@ ethsys: clock-controller@15000000 { + #reset-cells = <1>; + }; + ++ switch: switch@15020000 { ++ compatible = "mediatek,mt7988-switch"; ++ reg = <0 0x15020000 0 0x8000>; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ interrupt-parent = <&gic>; ++ interrupts = ; ++ resets = <ðwarp MT7988_ETHWARP_RST_SWITCH>; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ gsw_port0: port@0 { ++ reg = <0>; ++ phy-mode = "internal"; ++ phy-handle = <&gsw_phy0>; ++ }; ++ ++ gsw_port1: port@1 { ++ reg = <1>; ++ phy-mode = "internal"; ++ phy-handle = <&gsw_phy1>; ++ }; ++ ++ gsw_port2: port@2 { ++ reg = <2>; ++ phy-mode = "internal"; ++ phy-handle = <&gsw_phy2>; ++ }; ++ ++ gsw_port3: port@3 { ++ reg = <3>; ++ phy-mode = "internal"; ++ phy-handle = <&gsw_phy3>; ++ }; ++ ++ port@6 { ++ reg = <6>; ++ ethernet = <&gmac0>; ++ phy-mode = "internal"; ++ ++ fixed-link { ++ speed = <10000>; ++ full-duplex; ++ pause; ++ }; ++ }; ++ }; ++ ++ mdio { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ mediatek,pio = <&pio>; ++ ++ gsw_phy0: ethernet-phy@0 { ++ compatible = "ethernet-phy-ieee802.3-c22"; ++ reg = <0>; ++ interrupts = <0>; ++ phy-mode = "internal"; ++ nvmem-cells = <&phy_calibration_p0>; ++ nvmem-cell-names = "phy-cal-data"; ++ ++ leds { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ gsw_phy0_led0: led@0 { ++ reg = <0>; ++ status = "disabled"; ++ }; ++ ++ gsw_phy0_led1: led@1 { ++ reg = <1>; ++ status = "disabled"; ++ }; ++ }; ++ }; ++ ++ gsw_phy1: ethernet-phy@1 { ++ compatible = "ethernet-phy-ieee802.3-c22"; ++ reg = <1>; ++ interrupts = <1>; ++ phy-mode = "internal"; ++ nvmem-cells = <&phy_calibration_p1>; ++ nvmem-cell-names = "phy-cal-data"; ++ ++ leds { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ gsw_phy1_led0: led@0 { ++ reg = <0>; ++ status = "disabled"; ++ }; ++ ++ gsw_phy1_led1: led@1 { ++ reg = <1>; ++ status = "disabled"; ++ }; ++ }; ++ }; ++ ++ gsw_phy2: ethernet-phy@2 { ++ compatible = "ethernet-phy-ieee802.3-c22"; ++ reg = <2>; ++ interrupts = <2>; ++ phy-mode = "internal"; ++ nvmem-cells = <&phy_calibration_p2>; ++ nvmem-cell-names = "phy-cal-data"; ++ ++ leds { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ gsw_phy2_led0: led@0 { ++ reg = <0>; ++ status = "disabled"; ++ }; ++ ++ gsw_phy2_led1: led@1 { ++ reg = <1>; ++ status = "disabled"; ++ }; ++ }; ++ }; ++ ++ gsw_phy3: ethernet-phy@3 { ++ compatible = "ethernet-phy-ieee802.3-c22"; ++ reg = <3>; ++ interrupts = <3>; ++ phy-mode = "internal"; ++ nvmem-cells = <&phy_calibration_p3>; ++ nvmem-cell-names = "phy-cal-data"; ++ ++ leds { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ gsw_phy3_led0: led@0 { ++ reg = <0>; ++ status = "disabled"; ++ }; ++ ++ gsw_phy3_led1: led@1 { ++ reg = <1>; ++ status = "disabled"; ++ }; ++ }; ++ }; ++ }; ++ }; ++ + ethwarp: clock-controller@15031000 { + compatible = "mediatek,mt7988-ethwarp"; + reg = <0 0x15031000 0 0x1000>; +-- +2.51.0 + + +From 7991a17ef4b6834d4ecc1bfb7fa2df0bc2ffff4d Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Sun, 11 May 2025 16:26:50 +0200 +Subject: [PATCH 449/517] arm64: dts: mediatek: mt7988a-bpi-r4: Add fan and + coolingmaps + +Add Fan and cooling maps for Bananpi-R4 board. + +Signed-off-by: Frank Wunderlich +--- + .../dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi | 29 +++++++++++++++++++ + 1 file changed, 29 insertions(+) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi +index 23b267cd47ac..c6f84de82a4d 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi +@@ -12,6 +12,15 @@ chosen { + stdout-path = "serial0:115200n8"; + }; + ++ fan: pwm-fan { ++ compatible = "pwm-fan"; ++ /* cooling level (0, 1, 2, 3) : (0% duty, 30% duty, 50% duty, 100% duty) */ ++ cooling-levels = <0 80 128 255>; ++ #cooling-cells = <2>; ++ pwms = <&pwm 0 50000>; ++ status = "okay"; ++ }; ++ + reg_1p8v: regulator-1p8v { + compatible = "regulator-fixed"; + regulator-name = "fixed-1.8V"; +@@ -73,6 +82,26 @@ cpu_trip_active_low: active-low { + type = "active"; + }; + }; ++ ++ cooling-maps { ++ map-cpu-active-high { ++ /* active: set fan to cooling level 2 */ ++ cooling-device = <&fan 3 3>; ++ trip = <&cpu_trip_active_high>; ++ }; ++ ++ map-cpu-active-med { ++ /* active: set fan to cooling level 1 */ ++ cooling-device = <&fan 2 2>; ++ trip = <&cpu_trip_active_med>; ++ }; ++ ++ map-cpu-active-low { ++ /* active: set fan to cooling level 0 */ ++ cooling-device = <&fan 1 1>; ++ trip = <&cpu_trip_active_low>; ++ }; ++ }; + }; + + &i2c0 { +-- +2.51.0 + + +From 34036bee1ee2975448782b641760094739edb0b2 Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Sun, 11 May 2025 16:26:51 +0200 +Subject: [PATCH 450/517] arm64: dts: mediatek: mt7988a-bpi-r4: configure + spi-nodes + +Configure and enable SPI nodes on Bananapi R4 board. + +Signed-off-by: Frank Wunderlich +--- + .../dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi | 32 +++++++++++++++++++ + 1 file changed, 32 insertions(+) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi +index c6f84de82a4d..81ba045e0e0e 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi +@@ -401,6 +401,38 @@ &serial0 { + status = "okay"; + }; + ++&spi0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spi0_flash_pins>; ++ status = "okay"; ++ ++ spi_nand: flash@0 { ++ compatible = "spi-nand"; ++ reg = <0>; ++ spi-max-frequency = <52000000>; ++ spi-tx-bus-width = <4>; ++ spi-rx-bus-width = <4>; ++ }; ++}; ++ ++&spi1 { ++ status = "okay"; ++}; ++ ++&spi_nand { ++ partitions { ++ compatible = "fixed-partitions"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ partition@0 { ++ label = "bl2"; ++ reg = <0x0 0x200000>; ++ read-only; ++ }; ++ }; ++}; ++ + &ssusb1 { + status = "okay"; + }; +-- +2.51.0 + + +From b3d73b099fe717cb56b4a817cb25f08484f84568 Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Sun, 11 May 2025 16:26:52 +0200 +Subject: [PATCH 451/517] arm64: dts: mediatek: mt7988a-bpi-r4: add proc-supply + for cci + +CCI requires proc-supply. Add it on board level. + +Signed-off-by: Frank Wunderlich +--- + arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi +index 81ba045e0e0e..afa9e3b2b16a 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi +@@ -40,6 +40,10 @@ reg_3p3v: regulator-3p3v { + }; + }; + ++&cci { ++ proc-supply = <&rt5190_buck3>; ++}; ++ + &cpu0 { + proc-supply = <&rt5190_buck3>; + }; +-- +2.51.0 + + +From 0f84f4d23dd468c858924446723397acf590d0dc Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Sun, 11 May 2025 16:26:53 +0200 +Subject: [PATCH 452/517] arm64: dts: mediatek: mt7988a-bpi-r4: add sfp cages + and link to gmac + +Add SFP cages to Bananapi-R4 board. The 2.5g phy variant only contains the +wan-SFP, so add this to common dtsi and the lan-sfp only to the dual-SFP +variant. + +Signed-off-by: Daniel Golle +Signed-off-by: Frank Wunderlich +--- + .../mediatek/mt7988a-bananapi-bpi-r4-2g5.dts | 11 +++++++++++ + .../dts/mediatek/mt7988a-bananapi-bpi-r4.dts | 18 ++++++++++++++++++ + .../dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi | 18 ++++++++++++++++++ + 3 files changed, 47 insertions(+) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-2g5.dts b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-2g5.dts +index 53de9c113f60..574ac1b853a6 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-2g5.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-2g5.dts +@@ -9,3 +9,14 @@ / { + model = "Banana Pi BPI-R4 (1x SFP+, 1x 2.5GbE)"; + chassis-type = "embedded"; + }; ++ ++&gmac1 { ++ phy-mode = "internal"; ++ phy-connection-type = "internal"; ++ phy = <&int_2p5g_phy>; ++}; ++ ++&int_2p5g_phy { ++ pinctrl-names = "i2p5gbe-led"; ++ pinctrl-0 = <&i2p5gbe_led0_pins>; ++}; +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts +index 36bd1ef2efab..3136dc4ba4cc 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts +@@ -8,6 +8,24 @@ / { + compatible = "bananapi,bpi-r4", "mediatek,mt7988a"; + model = "Banana Pi BPI-R4 (2x SFP+)"; + chassis-type = "embedded"; ++ ++ /* SFP2 cage (LAN) */ ++ sfp2: sfp2 { ++ compatible = "sff,sfp"; ++ i2c-bus = <&i2c_sfp2>; ++ los-gpios = <&pio 2 GPIO_ACTIVE_HIGH>; ++ mod-def0-gpios = <&pio 83 GPIO_ACTIVE_LOW>; ++ tx-disable-gpios = <&pio 0 GPIO_ACTIVE_HIGH>; ++ tx-fault-gpios = <&pio 1 GPIO_ACTIVE_HIGH>; ++ rate-select0-gpios = <&pio 3 GPIO_ACTIVE_LOW>; ++ maximum-power-milliwatt = <3000>; ++ }; ++}; ++ ++&gmac1 { ++ sfp = <&sfp2>; ++ managed = "in-band-status"; ++ phy-mode = "usxgmii"; + }; + + &pca9545 { +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi +index afa9e3b2b16a..d40c8dbcd18e 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi +@@ -38,6 +38,18 @@ reg_3p3v: regulator-3p3v { + regulator-boot-on; + regulator-always-on; + }; ++ ++ /* SFP1 cage (WAN) */ ++ sfp1: sfp1 { ++ compatible = "sff,sfp"; ++ i2c-bus = <&i2c_sfp1>; ++ los-gpios = <&pio 54 GPIO_ACTIVE_HIGH>; ++ mod-def0-gpios = <&pio 82 GPIO_ACTIVE_LOW>; ++ tx-disable-gpios = <&pio 70 GPIO_ACTIVE_HIGH>; ++ tx-fault-gpios = <&pio 69 GPIO_ACTIVE_HIGH>; ++ rate-select0-gpios = <&pio 21 GPIO_ACTIVE_LOW>; ++ maximum-power-milliwatt = <3000>; ++ }; + }; + + &cci { +@@ -108,6 +120,12 @@ map-cpu-active-low { + }; + }; + ++&gmac2 { ++ sfp = <&sfp1>; ++ managed = "in-band-status"; ++ phy-mode = "usxgmii"; ++}; ++ + &i2c0 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c0_pins>; +-- +2.51.0 + + +From 2fb0f965b31d743d149659417366d2dc2fead79e Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Sun, 11 May 2025 16:26:54 +0200 +Subject: [PATCH 453/517] arm64: dts: mediatek: mt7988a-bpi-r4: configure + switch phys and leds + +Assign pinctrl to switch phys and leds. + +Signed-off-by: Daniel Golle +Signed-off-by: Frank Wunderlich +--- + .../dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi | 48 +++++++++++++++++++ + 1 file changed, 48 insertions(+) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi +index d40c8dbcd18e..7258039fda58 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi +@@ -126,6 +126,54 @@ &gmac2 { + phy-mode = "usxgmii"; + }; + ++&gsw_phy0 { ++ pinctrl-names = "gbe-led"; ++ label = "wan"; ++ pinctrl-0 = <&gbe0_led0_pins>; ++}; ++ ++&gsw_phy0_led0 { ++ status = "okay"; ++ function = LED_FUNCTION_WAN; ++ color = ; ++}; ++ ++&gsw_phy1 { ++ pinctrl-names = "gbe-led"; ++ label = "lan1"; ++ pinctrl-0 = <&gbe1_led0_pins>; ++}; ++ ++&gsw_phy1_led0 { ++ status = "okay"; ++ function = LED_FUNCTION_LAN; ++ color = ; ++}; ++ ++&gsw_phy2 { ++ pinctrl-names = "gbe-led"; ++ label = "lan2"; ++ pinctrl-0 = <&gbe2_led0_pins>; ++}; ++ ++&gsw_phy2_led0 { ++ status = "okay"; ++ function = LED_FUNCTION_LAN; ++ color = ; ++}; ++ ++&gsw_phy3 { ++ pinctrl-names = "gbe-led"; ++ label = "lan3"; ++ pinctrl-0 = <&gbe3_led0_pins>; ++}; ++ ++&gsw_phy3_led0 { ++ status = "okay"; ++ function = LED_FUNCTION_LAN; ++ color = ; ++}; ++ + &i2c0 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c0_pins>; +-- +2.51.0 + + +From 1760d4553e831d99af6db3e3d8825f8930d39c0d Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Thu, 8 May 2025 04:03:58 +0100 +Subject: [PATCH 454/517] arm64: dts: mt7988a: add serial1 and serial2 aliases + +Add aliases serial1 and serial2, so boards can make use of the +auxilary UARTs of the MediaTek MT7988 SoC. + +Signed-off-by: Daniel Golle +--- + arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +index f19e884f13be..52b640f31249 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +@@ -297,7 +297,7 @@ serial0: serial@11000000 { + status = "disabled"; + }; + +- serial@11000100 { ++ serial1: serial@11000100 { + compatible = "mediatek,mt7988-uart", "mediatek,mt6577-uart"; + reg = <0 0x11000100 0 0x100>; + interrupts = ; +@@ -308,7 +308,7 @@ serial@11000100 { + status = "disabled"; + }; + +- serial@11000200 { ++ serial2: serial@11000200 { + compatible = "mediatek,mt7988-uart", "mediatek,mt6577-uart"; + reg = <0 0x11000200 0 0x100>; + interrupts = ; +-- +2.51.0 + + +From 6161581d6eeb1e01aefde06e5872308860e1100f Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Thu, 26 Jun 2025 00:54:32 +0100 +Subject: [PATCH 455/517] arm64: dts: mt7988a: complete dtsi + +Work-in-progress patch to complete mt7988a.dtsi +--- + arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 156 +++++++++++++++++++++- + 1 file changed, 154 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +index 52b640f31249..b2338231fab4 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +@@ -193,7 +193,7 @@ apmixedsys: clock-controller@1001e000 { + }; + + pio: pinctrl@1001f000 { +- compatible = "mediatek,mt7988-pinctrl"; ++ compatible = "mediatek,mt7988-pinctrl", "syscon"; + reg = <0 0x1001f000 0 0x1000>, + <0 0x11c10000 0 0x1000>, + <0 0x11d00000 0 0x1000>, +@@ -212,6 +212,13 @@ pio: pinctrl@1001f000 { + interrupt-parent = <&gic>; + #interrupt-cells = <2>; + ++ snfi_pins: snfi-pins { ++ mux { ++ function = "flash"; ++ groups = "snfi"; ++ }; ++ }; ++ + pcie0_pins: pcie0-pins { + mux { + function = "pcie"; +@@ -278,6 +285,60 @@ pwm: pwm@10048000 { + status = "disabled"; + }; + ++ sgmiisys0: syscon@10060000 { ++ compatible = "mediatek,mt7988-sgmiisys", ++ "mediatek,mt7988-sgmiisys0", ++ "syscon", ++ "simple-mfd"; ++ reg = <0 0x10060000 0 0x1000>; ++ resets = <&watchdog 1>; ++ #clock-cells = <1>; ++ ++ sgmiipcs0: pcs { ++ compatible = "mediatek,mt7988-sgmii"; ++ clocks = <&topckgen CLK_TOP_SGM_0_SEL>, ++ <&sgmiisys0 CLK_SGM0_TX_EN>, ++ <&sgmiisys0 CLK_SGM0_RX_EN>; ++ clock-names = "sgmii_sel", "sgmii_tx", "sgmii_rx"; ++ #pcs-cells = <0>; ++ }; ++ }; ++ ++ sgmiisys1: syscon@10070000 { ++ compatible = "mediatek,mt7988-sgmiisys", ++ "mediatek,mt7988-sgmiisys1", ++ "syscon", ++ "simple-mfd"; ++ reg = <0 0x10070000 0 0x1000>; ++ resets = <&watchdog 2>; ++ #clock-cells = <1>; ++ ++ sgmiipcs1: pcs { ++ compatible = "mediatek,mt7988-sgmii"; ++ clocks = <&topckgen CLK_TOP_SGM_1_SEL>, ++ <&sgmiisys1 CLK_SGM1_TX_EN>, ++ <&sgmiisys1 CLK_SGM1_RX_EN>; ++ clock-names = "sgmii_sel", "sgmii_tx", "sgmii_rx"; ++ #pcs-cells = <0>; ++ }; ++ }; ++ ++ usxgmiisys0: pcs@10080000 { ++ compatible = "mediatek,mt7988-usxgmiisys"; ++ reg = <0 0x10080000 0 0x1000>; ++ resets = <&watchdog 12>; ++ clocks = <&topckgen CLK_TOP_USXGMII_SBUS_0_SEL>; ++ #pcs-cells = <0>; ++ }; ++ ++ usxgmiisys1: pcs@10081000 { ++ compatible = "mediatek,mt7988-usxgmiisys"; ++ reg = <0 0x10081000 0 0x1000>; ++ resets = <&watchdog 13>; ++ clocks = <&topckgen CLK_TOP_USXGMII_SBUS_1_SEL>; ++ #pcs-cells = <0>; ++ }; ++ + mcusys: mcusys@100e0000 { + compatible = "mediatek,mt7988-mcusys", "syscon"; + reg = <0 0x100e0000 0 0x1000>; +@@ -319,6 +380,32 @@ serial2: serial@11000200 { + status = "disabled"; + }; + ++ snand: spi@11001000 { ++ compatible = "mediatek,mt7986-snand"; ++ reg = <0 0x11001000 0 0x1000>; ++ interrupts = ; ++ clocks = <&infracfg CLK_INFRA_SPINFI>, ++ <&infracfg CLK_INFRA_NFI>, ++ <&infracfg CLK_INFRA_66M_NFI_HCK>; ++ clock-names = "pad_clk", "nfi_clk", "nfi_hclk"; ++ nand-ecc-engine = <&bch>; ++ mediatek,quad-spi; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&snfi_pins>; ++ status = "disabled"; ++ }; ++ ++ bch: ecc@11002000 { ++ compatible = "mediatek,mt7686-ecc"; ++ reg = <0 0x11002000 0 0x1000>; ++ interrupts = ; ++ clocks = <&infracfg CLK_INFRA_NFI>; ++ clock-names = "nfiecc_clk"; ++ status = "disabled"; ++ }; ++ + i2c0: i2c@11003000 { + compatible = "mediatek,mt7981-i2c"; + reg = <0 0x11003000 0 0x1000>, +@@ -425,7 +512,7 @@ phyfw: phy-firmware@f000000 { + <0 0x0f0f0018 0 0x20>; + }; + +- usb@11190000 { ++ ssusb0: usb@11190000 { + compatible = "mediatek,mt7988-xhci", "mediatek,mtk-xhci"; + reg = <0 0x11190000 0 0x2e00>, + <0 0x11193e00 0 0x0100>; +@@ -459,6 +546,35 @@ ssusb1: usb@11200000 { + status = "disabled"; + }; + ++ afe: audio-controller@11210000 { ++ compatible = "mediatek,mt79xx-audio"; ++ reg = <0 0x11210000 0 0x9000>; ++ interrupts = ; ++ clocks = <&infracfg CLK_INFRA_66M_AUD_SLV_BCK>, ++ <&infracfg CLK_INFRA_AUD_26M>, ++ <&infracfg CLK_INFRA_AUD_L>, ++ <&infracfg CLK_INFRA_AUD_AUD>, ++ <&infracfg CLK_INFRA_AUD_EG2>, ++ <&topckgen CLK_TOP_AUD_SEL>, ++ <&topckgen CLK_TOP_AUD_I2S_M>; ++ clock-names = "aud_bus_ck", ++ "aud_26m_ck", ++ "aud_l_ck", ++ "aud_aud_ck", ++ "aud_eg2_ck", ++ "aud_sel", ++ "aud_i2s_m"; ++ assigned-clocks = <&topckgen CLK_TOP_AUD_SEL>, ++ <&topckgen CLK_TOP_A1SYS_SEL>, ++ <&topckgen CLK_TOP_AUD_L_SEL>, ++ <&topckgen CLK_TOP_A_TUNER_SEL>; ++ assigned-clock-parents = <&apmixedsys CLK_APMIXED_APLL2>, ++ <&topckgen CLK_TOP_APLL2_D4>, ++ <&apmixedsys CLK_APMIXED_APLL2>, ++ <&topckgen CLK_TOP_APLL2_D4>; ++ status = "disabled"; ++ }; ++ + mmc0: mmc@11230000 { + compatible = "mediatek,mt7988-mmc"; + reg = <0 0x11230000 0 0x1000>, +@@ -721,6 +837,10 @@ efuse@11f50000 { + #address-cells = <1>; + #size-cells = <1>; + ++ cpufreq_calibration: calib@278 { ++ reg = <0x278 0x1>; ++ }; ++ + lvts_calibration: calib@918 { + reg = <0x918 0x28>; + }; +@@ -984,12 +1104,16 @@ fixed-link { + gmac1: mac@1 { + compatible = "mediatek,eth-mac"; + reg = <1>; ++ pcs-handle = <&sgmiipcs1>, <&usxgmiisys1>; ++ phys = <&xfi_tphy1>; + status = "disabled"; + }; + + gmac2: mac@2 { + compatible = "mediatek,eth-mac"; + reg = <2>; ++ pcs-handle = <&sgmiipcs0>, <&usxgmiisys0>; ++ phys = <&xfi_tphy0>; + status = "disabled"; + }; + +@@ -1002,9 +1126,37 @@ int_2p5g_phy: ethernet-phy@f { + reg = <15>; + compatible = "ethernet-phy-ieee802.3-c45"; + phy-mode = "internal"; ++ ++ leds { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ i2p5gbe_led0: i2p5gbe-led0@0 { ++ reg = <0>; ++ function = LED_FUNCTION_LAN; ++ status = "disabled"; ++ }; ++ ++ i2p5gbe_led1: i2p5gbe-led1@1 { ++ reg = <1>; ++ function = LED_FUNCTION_LAN; ++ status = "disabled"; ++ }; ++ }; + }; + }; + }; ++ ++ crypto: crypto@15600000 { ++ compatible = "inside-secure,safexcel-eip197b"; ++ reg = <0 0x15600000 0 0x180000>; ++ interrupts = , ++ , ++ , ++ ; ++ interrupt-names = "ring0", "ring1", "ring2", "ring3"; ++ status = "okay"; ++ }; + }; + + thermal-zones { +-- +2.51.0 + + +From 35fcc31a8c177e9f346b6556757d3e565c83a136 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Wed, 22 Feb 2023 19:15:49 +0000 +Subject: [PATCH 456/517] dts: arm64: mediatek: add MT7988A reference board + device tree + +Complete device tree include for the MediaTek MT7988A SoC and make use +of it by adding the device tree of the MediaTek MT7988A Reference Board +as well as overlays for various options regarding the connected +network interfaces and storage devices present. + +Available options for GMAC1 (eth0): + * internal 4-port 1GE switch + +Available options for GMAC2 (eth1): + * internal 2.5G PHY + * external MaxLinear 2.5G PHY + * external Aquantia AQR113C PHY + * SFP+ cage + +Available options for GMAC3 (eth2): + * external MaxLinear 2.5G PHY + * external Aquantia AQR113C PHY + * SFP+ cage + +Available storage options: + * eMMC + * SNFI (ECC-less SPI-NAND with BCH done in SoC) + * SPI-NAND (with ECC done by the flash die) + * SPI-NOR + * SD card + +Signed-off-by: Sam Shih +Signed-off-by: Daniel Golle +--- + arch/arm64/boot/dts/mediatek/Makefile | 13 + + .../boot/dts/mediatek/mt7988a-rfb-emmc.dtso | 62 +++ + .../dts/mediatek/mt7988a-rfb-eth1-aqr.dtso | 41 ++ + .../mediatek/mt7988a-rfb-eth1-i2p5g-phy.dtso | 30 ++ + .../dts/mediatek/mt7988a-rfb-eth1-mxl.dtso | 39 ++ + .../dts/mediatek/mt7988a-rfb-eth1-sfp.dtso | 47 ++ + .../dts/mediatek/mt7988a-rfb-eth2-aqr.dtso | 41 ++ + .../dts/mediatek/mt7988a-rfb-eth2-mxl.dtso | 39 ++ + .../dts/mediatek/mt7988a-rfb-eth2-sfp.dtso | 47 ++ + .../boot/dts/mediatek/mt7988a-rfb-sd.dtso | 60 +++ + .../dts/mediatek/mt7988a-rfb-snfi-nand.dtso | 85 ++++ + .../mt7988a-rfb-spim-nand-factory.dtso | 87 ++++ + .../dts/mediatek/mt7988a-rfb-spim-nand.dtso | 77 +++ + .../dts/mediatek/mt7988a-rfb-spim-nor.dtso | 69 +++ + arch/arm64/boot/dts/mediatek/mt7988a-rfb.dts | 471 ++++++++++++++++++ + 15 files changed, 1208 insertions(+) + create mode 100644 arch/arm64/boot/dts/mediatek/mt7988a-rfb-emmc.dtso + create mode 100644 arch/arm64/boot/dts/mediatek/mt7988a-rfb-eth1-aqr.dtso + create mode 100644 arch/arm64/boot/dts/mediatek/mt7988a-rfb-eth1-i2p5g-phy.dtso + create mode 100644 arch/arm64/boot/dts/mediatek/mt7988a-rfb-eth1-mxl.dtso + create mode 100644 arch/arm64/boot/dts/mediatek/mt7988a-rfb-eth1-sfp.dtso + create mode 100644 arch/arm64/boot/dts/mediatek/mt7988a-rfb-eth2-aqr.dtso + create mode 100644 arch/arm64/boot/dts/mediatek/mt7988a-rfb-eth2-mxl.dtso + create mode 100644 arch/arm64/boot/dts/mediatek/mt7988a-rfb-eth2-sfp.dtso + create mode 100644 arch/arm64/boot/dts/mediatek/mt7988a-rfb-sd.dtso + create mode 100644 arch/arm64/boot/dts/mediatek/mt7988a-rfb-snfi-nand.dtso + create mode 100644 arch/arm64/boot/dts/mediatek/mt7988a-rfb-spim-nand-factory.dtso + create mode 100644 arch/arm64/boot/dts/mediatek/mt7988a-rfb-spim-nand.dtso + create mode 100644 arch/arm64/boot/dts/mediatek/mt7988a-rfb-spim-nor.dtso + create mode 100644 arch/arm64/boot/dts/mediatek/mt7988a-rfb.dts + +diff --git a/arch/arm64/boot/dts/mediatek/Makefile b/arch/arm64/boot/dts/mediatek/Makefile +index cd70066352b6..82f7332077c4 100644 +--- a/arch/arm64/boot/dts/mediatek/Makefile ++++ b/arch/arm64/boot/dts/mediatek/Makefile +@@ -24,6 +24,19 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += mt7988a-bananapi-bpi-r4.dtb + dtb-$(CONFIG_ARCH_MEDIATEK) += mt7988a-bananapi-bpi-r4-2g5.dtb + dtb-$(CONFIG_ARCH_MEDIATEK) += mt7988a-bananapi-bpi-r4-emmc.dtbo + dtb-$(CONFIG_ARCH_MEDIATEK) += mt7988a-bananapi-bpi-r4-sd.dtbo ++dtb-$(CONFIG_ARCH_MEDIATEK) += mt7988a-rfb.dtb ++dtb-$(CONFIG_ARCH_MEDIATEK) += mt7988a-rfb-emmc.dtbo ++dtb-$(CONFIG_ARCH_MEDIATEK) += mt7988a-rfb-eth1-aqr.dtbo ++dtb-$(CONFIG_ARCH_MEDIATEK) += mt7988a-rfb-eth1-i2p5g-phy.dtbo ++dtb-$(CONFIG_ARCH_MEDIATEK) += mt7988a-rfb-eth1-mxl.dtbo ++dtb-$(CONFIG_ARCH_MEDIATEK) += mt7988a-rfb-eth1-sfp.dtbo ++dtb-$(CONFIG_ARCH_MEDIATEK) += mt7988a-rfb-eth2-aqr.dtbo ++dtb-$(CONFIG_ARCH_MEDIATEK) += mt7988a-rfb-eth2-mxl.dtbo ++dtb-$(CONFIG_ARCH_MEDIATEK) += mt7988a-rfb-eth2-sfp.dtbo ++dtb-$(CONFIG_ARCH_MEDIATEK) += mt7988a-rfb-sd.dtbo ++dtb-$(CONFIG_ARCH_MEDIATEK) += mt7988a-rfb-snfi-nand.dtbo ++dtb-$(CONFIG_ARCH_MEDIATEK) += mt7988a-rfb-spim-nand.dtbo ++dtb-$(CONFIG_ARCH_MEDIATEK) += mt7988a-rfb-spim-nor.dtbo + dtb-$(CONFIG_ARCH_MEDIATEK) += mt8167-pumpkin.dtb + dtb-$(CONFIG_ARCH_MEDIATEK) += mt8173-elm.dtb + dtb-$(CONFIG_ARCH_MEDIATEK) += mt8173-elm-hana.dtb +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-rfb-emmc.dtso b/arch/arm64/boot/dts/mediatek/mt7988a-rfb-emmc.dtso +new file mode 100644 +index 000000000000..b430ec3f27b8 +--- /dev/null ++++ b/arch/arm64/boot/dts/mediatek/mt7988a-rfb-emmc.dtso +@@ -0,0 +1,62 @@ ++// SPDX-License-Identifier: (GPL-2.0 OR MIT) ++/* ++ * Copyright (C) 2021 MediaTek Inc. ++ * Author: Frank Wunderlich ++ */ ++ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "mediatek,mt7988a-rfb", "mediatek,mt7988a"; ++ ++ fragment@0 { ++ target = <&mmc0>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ pinctrl-names = "default", "state_uhs"; ++ pinctrl-0 = <&mmc0_pins_emmc_51>; ++ pinctrl-1 = <&mmc0_pins_emmc_51>; ++ bus-width = <8>; ++ max-frequency = <200000000>; ++ cap-mmc-highspeed; ++ mmc-hs200-1_8v; ++ mmc-hs400-1_8v; ++ hs400-ds-delay = <0x12814>; ++ vqmmc-supply = <®_1p8v>; ++ vmmc-supply = <®_3p3v>; ++ non-removable; ++ no-sd; ++ no-sdio; ++ status = "okay"; ++ ++ card@0 { ++ compatible = "mmc-card"; ++ reg = <0>; ++ ++ partitions { ++ compatible = "gpt-partitions"; ++ ++ block-partition-env { ++ partname = "ubootenv"; ++ nvmem-layout { ++ compatible = "u-boot,env-layout"; ++ }; ++ }; ++ ++ emmc_root: block-partition-production { ++ partname = "production"; ++ }; ++ }; ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target-path = "/chosen"; ++ __overlay__ { ++ rootdisk-emmc = <&emmc_root>; ++ }; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-rfb-eth1-aqr.dtso b/arch/arm64/boot/dts/mediatek/mt7988a-rfb-eth1-aqr.dtso +new file mode 100644 +index 000000000000..d21a61ad19fe +--- /dev/null ++++ b/arch/arm64/boot/dts/mediatek/mt7988a-rfb-eth1-aqr.dtso +@@ -0,0 +1,41 @@ ++// SPDX-License-Identifier: (GPL-2.0 OR MIT) ++/* ++ * Copyright (C) 2022 MediaTek Inc. ++ * Author: Sam.Shih ++ */ ++ ++/dts-v1/; ++/plugin/; ++ ++#include ++ ++/ { ++ compatible = "mediatek,mt7988a-rfb", "mediatek,mt7988a"; ++ ++ fragment@0 { ++ target = <&mdio_bus>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ /* external Aquantia AQR113C */ ++ phy0: ethernet-phy@0 { ++ reg = <0>; ++ compatible = "ethernet-phy-ieee802.3-c45"; ++ reset-gpios = <&pio 72 GPIO_ACTIVE_LOW>; ++ reset-assert-us = <100000>; ++ reset-deassert-us = <221000>; ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&gmac1>; ++ __overlay__ { ++ phy-mode = "usxgmii"; ++ phy-connection-type = "usxgmii"; ++ phy = <&phy0>; ++ status = "okay"; ++ }; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-rfb-eth1-i2p5g-phy.dtso b/arch/arm64/boot/dts/mediatek/mt7988a-rfb-eth1-i2p5g-phy.dtso +new file mode 100644 +index 000000000000..86ab7566dc29 +--- /dev/null ++++ b/arch/arm64/boot/dts/mediatek/mt7988a-rfb-eth1-i2p5g-phy.dtso +@@ -0,0 +1,30 @@ ++// SPDX-License-Identifier: (GPL-2.0 OR MIT) ++/* ++ * Copyright (C) 2022 MediaTek Inc. ++ * Author: Sam.Shih ++ */ ++ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "mediatek,mt7988a-rfb", "mediatek,mt7988a"; ++ ++ fragment@0 { ++ target = <&gmac1>; ++ __overlay__ { ++ phy-mode = "internal"; ++ phy-connection-type = "internal"; ++ phy = <&int_2p5g_phy>; ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&int_2p5g_phy>; ++ __overlay__ { ++ pinctrl-names = "i2p5gbe-led"; ++ pinctrl-0 = <&i2p5gbe_led0_pins>; ++ }; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-rfb-eth1-mxl.dtso b/arch/arm64/boot/dts/mediatek/mt7988a-rfb-eth1-mxl.dtso +new file mode 100644 +index 000000000000..34a23bbd7eb0 +--- /dev/null ++++ b/arch/arm64/boot/dts/mediatek/mt7988a-rfb-eth1-mxl.dtso +@@ -0,0 +1,39 @@ ++// SPDX-License-Identifier: (GPL-2.0 OR MIT) ++/* ++ * Copyright (C) 2022 MediaTek Inc. ++ * Author: Sam.Shih ++ */ ++ ++/dts-v1/; ++/plugin/; ++ ++#include ++ ++/ { ++ compatible = "mediatek,mt7988a-rfb", "mediatek,mt7988a"; ++ ++ fragment@0 { ++ target = <&mdio_bus>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ /* external Maxlinear GPY211C */ ++ phy13: ethernet-phy@13 { ++ reg = <13>; ++ compatible = "ethernet-phy-ieee802.3-c45"; ++ phy-mode = "2500base-x"; ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&gmac1>; ++ __overlay__ { ++ phy-mode = "2500base-x"; ++ phy-connection-type = "2500base-x"; ++ phy = <&phy13>; ++ status = "okay"; ++ }; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-rfb-eth1-sfp.dtso b/arch/arm64/boot/dts/mediatek/mt7988a-rfb-eth1-sfp.dtso +new file mode 100644 +index 000000000000..ef5e4b360441 +--- /dev/null ++++ b/arch/arm64/boot/dts/mediatek/mt7988a-rfb-eth1-sfp.dtso +@@ -0,0 +1,47 @@ ++// SPDX-License-Identifier: (GPL-2.0 OR MIT) ++/* ++ * Copyright (C) 2022 MediaTek Inc. ++ * Author: Sam.Shih ++ */ ++ ++/dts-v1/; ++/plugin/; ++ ++#include ++ ++/ { ++ compatible = "mediatek,mt7988a-rfb", "mediatek,mt7988a"; ++ ++ fragment@0 { ++ target = <&i2c2>; ++ __overlay__ { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c2_pins>; ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@1 { ++ target-path = "/"; ++ __overlay__ { ++ sfp_esp1: sfp@1 { ++ compatible = "sff,sfp"; ++ i2c-bus = <&i2c2>; ++ mod-def0-gpios = <&pio 82 GPIO_ACTIVE_LOW>; ++ los-gpios = <&pio 81 GPIO_ACTIVE_HIGH>; ++ tx-disable-gpios = <&pio 36 GPIO_ACTIVE_HIGH>; ++ maximum-power-milliwatt = <3000>; ++ }; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&gmac1>; ++ __overlay__ { ++ phy-mode = "10gbase-r"; ++ managed = "in-band-status"; ++ sfp = <&sfp_esp1>; ++ status = "okay"; ++ }; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-rfb-eth2-aqr.dtso b/arch/arm64/boot/dts/mediatek/mt7988a-rfb-eth2-aqr.dtso +new file mode 100644 +index 000000000000..140391fc45a8 +--- /dev/null ++++ b/arch/arm64/boot/dts/mediatek/mt7988a-rfb-eth2-aqr.dtso +@@ -0,0 +1,41 @@ ++// SPDX-License-Identifier: (GPL-2.0 OR MIT) ++/* ++ * Copyright (C) 2022 MediaTek Inc. ++ * Author: Sam.Shih ++ */ ++ ++/dts-v1/; ++/plugin/; ++ ++#include ++ ++/ { ++ compatible = "mediatek,mt7988a-rfb", "mediatek,mt7988a"; ++ ++ fragment@0 { ++ target = <&mdio_bus>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ /* external Aquantia AQR113C */ ++ phy8: ethernet-phy@8 { ++ reg = <8>; ++ compatible = "ethernet-phy-ieee802.3-c45"; ++ reset-gpios = <&pio 71 GPIO_ACTIVE_LOW>; ++ reset-assert-us = <100000>; ++ reset-deassert-us = <221000>; ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&gmac2>; ++ __overlay__ { ++ phy-mode = "usxgmii"; ++ phy-connection-type = "usxgmii"; ++ phy = <&phy8>; ++ status = "okay"; ++ }; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-rfb-eth2-mxl.dtso b/arch/arm64/boot/dts/mediatek/mt7988a-rfb-eth2-mxl.dtso +new file mode 100644 +index 000000000000..19e0b2799fc8 +--- /dev/null ++++ b/arch/arm64/boot/dts/mediatek/mt7988a-rfb-eth2-mxl.dtso +@@ -0,0 +1,39 @@ ++// SPDX-License-Identifier: (GPL-2.0 OR MIT) ++/* ++ * Copyright (C) 2022 MediaTek Inc. ++ * Author: Sam.Shih ++ */ ++ ++/dts-v1/; ++/plugin/; ++ ++#include ++ ++/ { ++ compatible = "mediatek,mt7988a-rfb", "mediatek,mt7988a"; ++ ++ fragment@0 { ++ target = <&mdio_bus>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ /* external Maxlinear GPY211C */ ++ phy5: ethernet-phy@5 { ++ reg = <5>; ++ compatible = "ethernet-phy-ieee802.3-c45"; ++ phy-mode = "2500base-x"; ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&gmac2>; ++ __overlay__ { ++ phy-mode = "2500base-x"; ++ phy-connection-type = "2500base-x"; ++ phy = <&phy5>; ++ status = "okay"; ++ }; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-rfb-eth2-sfp.dtso b/arch/arm64/boot/dts/mediatek/mt7988a-rfb-eth2-sfp.dtso +new file mode 100644 +index 000000000000..83d65322eb0e +--- /dev/null ++++ b/arch/arm64/boot/dts/mediatek/mt7988a-rfb-eth2-sfp.dtso +@@ -0,0 +1,47 @@ ++// SPDX-License-Identifier: (GPL-2.0 OR MIT) ++/* ++ * Copyright (C) 2022 MediaTek Inc. ++ * Author: Sam.Shih ++ */ ++ ++/dts-v1/; ++/plugin/; ++ ++#include ++ ++/ { ++ compatible = "mediatek,mt7988a-rfb", "mediatek,mt7988a"; ++ ++ fragment@0 { ++ target = <&i2c1>; ++ __overlay__ { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c1_pins>; ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@1 { ++ target-path = "/"; ++ __overlay__ { ++ sfp_esp0: sfp@0 { ++ compatible = "sff,sfp"; ++ i2c-bus = <&i2c1>; ++ mod-def0-gpios = <&pio 35 GPIO_ACTIVE_LOW>; ++ los-gpios = <&pio 33 GPIO_ACTIVE_HIGH>; ++ tx-disable-gpios = <&pio 29 GPIO_ACTIVE_HIGH>; ++ maximum-power-milliwatt = <3000>; ++ }; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&gmac2>; ++ __overlay__ { ++ phy-mode = "10gbase-r"; ++ managed = "in-band-status"; ++ sfp = <&sfp_esp0>; ++ status = "okay"; ++ }; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-rfb-sd.dtso b/arch/arm64/boot/dts/mediatek/mt7988a-rfb-sd.dtso +new file mode 100644 +index 000000000000..9a06c425a0b2 +--- /dev/null ++++ b/arch/arm64/boot/dts/mediatek/mt7988a-rfb-sd.dtso +@@ -0,0 +1,60 @@ ++// SPDX-License-Identifier: (GPL-2.0 OR MIT) ++/* ++ * Copyright (C) 2023 MediaTek Inc. ++ * Author: Frank Wunderlich ++ */ ++ ++/dts-v1/; ++/plugin/; ++ ++#include ++ ++/ { ++ compatible = "mediatek,mt7988a-rfb", "mediatek,mt7988a"; ++ ++ fragment@0 { ++ target-path = <&mmc0>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ pinctrl-names = "default", "state_uhs"; ++ pinctrl-0 = <&mmc0_pins_sdcard>; ++ pinctrl-1 = <&mmc0_pins_sdcard>; ++ cd-gpios = <&pio 69 GPIO_ACTIVE_LOW>; ++ bus-width = <4>; ++ max-frequency = <52000000>; ++ cap-sd-highspeed; ++ vmmc-supply = <®_3p3v>; ++ vqmmc-supply = <®_3p3v>; ++ no-mmc; ++ status = "okay"; ++ ++ card@0 { ++ compatible = "mmc-card"; ++ reg = <0>; ++ ++ partitions { ++ compatible = "gpt-partitions"; ++ ++ block-partition-env { ++ partname = "ubootenv"; ++ nvmem-layout { ++ compatible = "u-boot,env-layout"; ++ }; ++ }; ++ ++ sd_root: block-partition-production { ++ partname = "production"; ++ }; ++ }; ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target-path = "/chosen"; ++ __overlay__ { ++ rootdisk-sd = <&sd_root>; ++ }; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-rfb-snfi-nand.dtso b/arch/arm64/boot/dts/mediatek/mt7988a-rfb-snfi-nand.dtso +new file mode 100644 +index 000000000000..f334de82e9d4 +--- /dev/null ++++ b/arch/arm64/boot/dts/mediatek/mt7988a-rfb-snfi-nand.dtso +@@ -0,0 +1,85 @@ ++// SPDX-License-Identifier: (GPL-2.0 OR MIT) ++/* ++ * Copyright (C) 2022 MediaTek Inc. ++ * Author: Sam.Shih ++ */ ++ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "mediatek,mt7988a-rfb", "mediatek,mt7988a"; ++ ++ fragment@0 { ++ target = <&snand>; ++ __overlay__ { ++ status = "okay"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ flash@0 { ++ compatible = "spi-nand"; ++ reg = <0>; ++ spi-max-frequency = <52000000>; ++ spi-tx-bus-width = <4>; ++ spi-rx-bus-width = <4>; ++ ++ partitions { ++ compatible = "fixed-partitions"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ partition@0 { ++ label = "BL2"; ++ reg = <0x00000 0x0200000>; ++ read-only; ++ }; ++ ++ ubi_part: partition@200000 { ++ label = "ubi"; ++ reg = <0x0200000 0x7e00000>; ++ compatible = "linux,ubi"; ++ ++ volumes { ++ ubi-volume-ubootenv { ++ volname = "ubootenv"; ++ nvmem-layout { ++ compatible = "u-boot,env-redundant-bool"; ++ }; ++ }; ++ ++ ubi-volume-ubootenv2 { ++ volname = "ubootenv2"; ++ nvmem-layout { ++ compatible = "u-boot,env-redundant-bool"; ++ }; ++ }; ++ ++ snfi_root: ubi-volume-fit { ++ volname = "fit"; ++ }; ++ }; ++ }; ++ }; ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&bch>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@2 { ++ target-path = "/chosen"; ++ __overlay__ { ++ /* ++ * U-Boot currently cannot detect diffrentiate between ++ * SD and SNFI boot media and always uses rootdisk-sd in ++ * both cases ++ */ ++ rootdisk-sd = <&snfi_root>; ++ }; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-rfb-spim-nand-factory.dtso b/arch/arm64/boot/dts/mediatek/mt7988a-rfb-spim-nand-factory.dtso +new file mode 100644 +index 000000000000..4b554a1bdeb4 +--- /dev/null ++++ b/arch/arm64/boot/dts/mediatek/mt7988a-rfb-spim-nand-factory.dtso +@@ -0,0 +1,87 @@ ++// SPDX-License-Identifier: (GPL-2.0 OR MIT) ++ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "mediatek,mt7988a-rfb", "mediatek,mt7988a"; ++ ++ fragment@0 { ++ target = <&ubi_part>; ++ ++ __overlay__ { ++ volumes { ++ ubi_factory: ubi-volume-factory { ++ volname = "factory"; ++ ++ nvmem-layout { ++ compatible = "fixed-layout"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ eeprom_wmac: eeprom@0 { ++ reg = <0x0 0x1e00>; ++ }; ++ ++ gmac2_mac: eeprom@fffee { ++ reg = <0xfffee 0x6>; ++ }; ++ ++ gmac1_mac: eeprom@ffff4 { ++ reg = <0xffff4 0x6>; ++ }; ++ ++ gmac0_mac: eeprom@ffffa { ++ reg = <0xffffa 0x6>; ++ }; ++ }; ++ }; ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&pcie0>; ++ __overlay__ { ++ #address-cells = <3>; ++ #size-cells = <2>; ++ ++ pcie@0,0 { ++ reg = <0x0000 0 0 0 0>; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ ++ wifi@0,0 { ++ compatible = "mediatek,mt76"; ++ reg = <0x0000 0 0 0 0>; ++ nvmem-cell-names = "eeprom"; ++ nvmem-cells = <&eeprom_wmac>; ++ }; ++ }; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&gmac0>; ++ __overlay__ { ++ nvmem-cell-names = "mac-address"; ++ nvmem-cells = <&gmac0_mac>; ++ }; ++ }; ++ ++ fragment@3 { ++ target = <&gmac1>; ++ __overlay__ { ++ nvmem-cell-names = "mac-address"; ++ nvmem-cells = <&gmac1_mac>; ++ }; ++ }; ++ ++ fragment@4 { ++ target = <&gmac2>; ++ __overlay__ { ++ nvmem-cell-names = "mac-address"; ++ nvmem-cells = <&gmac2_mac>; ++ }; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-rfb-spim-nand.dtso b/arch/arm64/boot/dts/mediatek/mt7988a-rfb-spim-nand.dtso +new file mode 100644 +index 000000000000..e7efd375620d +--- /dev/null ++++ b/arch/arm64/boot/dts/mediatek/mt7988a-rfb-spim-nand.dtso +@@ -0,0 +1,77 @@ ++// SPDX-License-Identifier: (GPL-2.0 OR MIT) ++/* ++ * Copyright (C) 2022 MediaTek Inc. ++ * Author: Sam.Shih ++ */ ++ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "mediatek,mt7988a-rfb", "mediatek,mt7988a"; ++ ++ fragment@0 { ++ target = <&spi0>; ++ __overlay__ { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spi0_flash_pins>; ++ status = "okay"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ flash@0 { ++ compatible = "spi-nand"; ++ reg = <0>; ++ spi-max-frequency = <52000000>; ++ spi-tx-bus-width = <4>; ++ spi-rx-bus-width = <4>; ++ ++ partitions { ++ compatible = "fixed-partitions"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ partition@0 { ++ label = "BL2"; ++ reg = <0x00000 0x0200000>; ++ read-only; ++ }; ++ ++ ubi_part: partition@200000 { ++ label = "ubi"; ++ reg = <0x0200000 0x7e00000>; ++ compatible = "linux,ubi"; ++ ++ volumes { ++ ubi-volume-ubootenv { ++ volname = "ubootenv"; ++ nvmem-layout { ++ compatible = "u-boot,env-redundant-bool"; ++ }; ++ }; ++ ++ ubi-volume-ubootenv2 { ++ volname = "ubootenv2"; ++ nvmem-layout { ++ compatible = "u-boot,env-redundant-bool"; ++ }; ++ }; ++ ++ ubi_root: ubi-volume-fit { ++ volname = "fit"; ++ }; ++ ++ }; ++ }; ++ }; ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target-path = "/chosen"; ++ __overlay__ { ++ rootdisk-spim-nand = <&ubi_root>; ++ }; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-rfb-spim-nor.dtso b/arch/arm64/boot/dts/mediatek/mt7988a-rfb-spim-nor.dtso +new file mode 100644 +index 000000000000..4c9bc70ff712 +--- /dev/null ++++ b/arch/arm64/boot/dts/mediatek/mt7988a-rfb-spim-nor.dtso +@@ -0,0 +1,69 @@ ++// SPDX-License-Identifier: (GPL-2.0 OR MIT) ++/* ++ * Copyright (C) 2022 MediaTek Inc. ++ * Author: Sam.Shih ++ */ ++ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "mediatek,mt7988a-rfb", "mediatek,mt7988a"; ++ ++ fragment@0 { ++ target = <&spi2>; ++ __overlay__ { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spi2_flash_pins>; ++ status = "okay"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ flash@0 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "jedec,spi-nor"; ++ spi-cal-enable; ++ spi-cal-mode = "read-data"; ++ spi-cal-datalen = <7>; ++ spi-cal-data = /bits/ 8 < ++ 0x53 0x46 0x5F 0x42 0x4F 0x4F 0x54>; /* SF_BOOT */ ++ spi-cal-addrlen = <1>; ++ spi-cal-addr = /bits/ 32 <0x0>; ++ reg = <0>; ++ spi-max-frequency = <52000000>; ++ spi-tx-bus-width = <4>; ++ spi-rx-bus-width = <4>; ++ ++ partition@0 { ++ label = "BL2"; ++ reg = <0x0 0x40000>; ++ }; ++ partition@40000 { ++ label = "u-boot-env"; ++ reg = <0x40000 0x10000>; ++ }; ++ partition@50000 { ++ label = "Factory"; ++ reg = <0x50000 0x200000>; ++ }; ++ partition@250000 { ++ label = "FIP"; ++ reg = <0x250000 0x80000>; ++ }; ++ nor_root: partition@2D0000 { ++ label = "firmware"; ++ reg = <0x2d0000 0x1d30000>; ++ compatible = "denx,fit"; ++ }; ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target-path = "/chosen"; ++ __overlay__ { ++ rootdisk-nor = <&nor_root>; ++ }; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-rfb.dts b/arch/arm64/boot/dts/mediatek/mt7988a-rfb.dts +new file mode 100644 +index 000000000000..01989041d9c2 +--- /dev/null ++++ b/arch/arm64/boot/dts/mediatek/mt7988a-rfb.dts +@@ -0,0 +1,471 @@ ++// SPDX-License-Identifier: (GPL-2.0 OR MIT) ++/* ++ * Copyright (C) 2022 MediaTek Inc. ++ * Author: Sam.Shih ++ */ ++ ++/dts-v1/; ++#include ++#include ++#include ++ ++#include "mt7988a.dtsi" ++ ++/ { ++ model = "MediaTek MT7988A Reference Board"; ++ compatible = "mediatek,mt7988a-rfb", ++ "mediatek,mt7988a"; ++ ++ chosen { ++ bootargs = "console=ttyS0,115200n1 \ ++ earlycon=uart8250,mmio32,0x11000000 \ ++ pci=pcie_bus_perf"; ++ }; ++ ++ memory@40000000 { ++ reg = <0 0x40000000 0 0x40000000>; ++ device_type = "memory"; ++ }; ++ ++ reg_1p8v: regulator-1p8v { ++ compatible = "regulator-fixed"; ++ regulator-name = "fixed-1.8V"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ reg_3p3v: regulator-3p3v { ++ compatible = "regulator-fixed"; ++ regulator-name = "fixed-3.3V"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++}; ++ ++ð { ++ pinctrl-0 = <&mdio0_pins>; ++ pinctrl-names = "default"; ++}; ++ ++&gmac0 { ++ status = "okay"; ++}; ++ ++&cpu0 { ++ proc-supply = <&rt5190_buck3>; ++}; ++ ++&cpu1 { ++ proc-supply = <&rt5190_buck3>; ++}; ++ ++&cpu2 { ++ proc-supply = <&rt5190_buck3>; ++}; ++ ++&cpu3 { ++ proc-supply = <&rt5190_buck3>; ++}; ++ ++&cci { ++ proc-supply = <&rt5190_buck3>; ++}; ++ ++ð { ++ status = "okay"; ++}; ++ ++&switch { ++ status = "okay"; ++}; ++ ++&gsw_phy0 { ++ pinctrl-names = "gbe-led"; ++ pinctrl-0 = <&gbe0_led0_pins>; ++}; ++ ++&gsw_phy0_led0 { ++ status = "okay"; ++ function = LED_FUNCTION_LAN; ++ color = ; ++}; ++ ++&gsw_port0 { ++ label = "lan0"; ++}; ++ ++&gsw_phy1 { ++ pinctrl-names = "gbe-led"; ++ pinctrl-0 = <&gbe1_led0_pins>; ++}; ++ ++&gsw_phy1_led0 { ++ status = "okay"; ++ function = LED_FUNCTION_LAN; ++ color = ; ++}; ++ ++&gsw_port1 { ++ label = "lan1"; ++}; ++ ++&gsw_phy2 { ++ pinctrl-names = "gbe-led"; ++ pinctrl-0 = <&gbe2_led0_pins>; ++}; ++ ++&gsw_phy2_led0 { ++ status = "okay"; ++ function = LED_FUNCTION_LAN; ++ color = ; ++}; ++ ++&gsw_port2 { ++ label = "lan2"; ++}; ++ ++&gsw_phy3 { ++ pinctrl-names = "gbe-led"; ++ pinctrl-0 = <&gbe3_led0_pins>; ++}; ++ ++&gsw_phy3_led0 { ++ status = "okay"; ++ function = LED_FUNCTION_LAN; ++ color = ; ++}; ++ ++&gsw_port3 { ++ label = "lan3"; ++}; ++ ++&i2c0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c0_pins>; ++ status = "okay"; ++ ++ rt5190a_64: rt5190a@64 { ++ compatible = "richtek,rt5190a"; ++ reg = <0x64>; ++ /*interrupts-extended = <&gpio26 0 IRQ_TYPE_LEVEL_LOW>;*/ ++ vin2-supply = <&rt5190_buck1>; ++ vin3-supply = <&rt5190_buck1>; ++ vin4-supply = <&rt5190_buck1>; ++ ++ regulators { ++ rt5190_buck1: buck1 { ++ regulator-name = "rt5190a-buck1"; ++ regulator-min-microvolt = <5090000>; ++ regulator-max-microvolt = <5090000>; ++ regulator-allowed-modes = ++ ; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ buck2 { ++ regulator-name = "vcore"; ++ regulator-min-microvolt = <600000>; ++ regulator-max-microvolt = <1400000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ rt5190_buck3: buck3 { ++ regulator-name = "vproc"; ++ regulator-min-microvolt = <600000>; ++ regulator-max-microvolt = <1400000>; ++ regulator-boot-on; ++ }; ++ buck4 { ++ regulator-name = "rt5190a-buck4"; ++ regulator-min-microvolt = <850000>; ++ regulator-max-microvolt = <850000>; ++ regulator-allowed-modes = ++ ; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ldo { ++ regulator-name = "rt5190a-ldo"; ++ regulator-min-microvolt = <1200000>; ++ regulator-max-microvolt = <1200000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ }; ++ }; ++}; ++ ++&pcie0 { ++ status = "okay"; ++}; ++ ++&pcie1 { ++ status = "okay"; ++}; ++ ++&pcie2 { ++ status = "disabled"; ++}; ++ ++&pcie3 { ++ status = "okay"; ++}; ++ ++&pio { ++ mdio0_pins: mdio0-pins { ++ mux { ++ function = "eth"; ++ groups = "mdc_mdio0"; ++ }; ++ ++ conf { ++ groups = "mdc_mdio0"; ++ drive-strength = ; ++ }; ++ }; ++ ++ gbe0_led0_pins: gbe0-led0-pins { ++ mux { ++ function = "led"; ++ groups = "gbe0_led0"; ++ }; ++ }; ++ ++ gbe1_led0_pins: gbe1-led0-pins { ++ mux { ++ function = "led"; ++ groups = "gbe1_led0"; ++ }; ++ }; ++ ++ gbe2_led0_pins: gbe2-led0-pins { ++ mux { ++ function = "led"; ++ groups = "gbe2_led0"; ++ }; ++ }; ++ ++ gbe3_led0_pins: gbe3-led0-pins { ++ mux { ++ function = "led"; ++ groups = "gbe3_led0"; ++ }; ++ }; ++ ++ gbe0_led1_pins: gbe0-led1-pins { ++ mux { ++ function = "led"; ++ groups = "gbe0_led1"; ++ }; ++ }; ++ ++ gbe1_led1_pins: gbe1-led1-pins { ++ mux { ++ function = "led"; ++ groups = "gbe1_led1"; ++ }; ++ }; ++ ++ gbe2_led1_pins: gbe2-led1-pins { ++ mux { ++ function = "led"; ++ groups = "gbe2_led1"; ++ }; ++ }; ++ ++ gbe3_led1_pins: gbe3-led1-pins { ++ mux { ++ function = "led"; ++ groups = "gbe3_led1"; ++ }; ++ }; ++ ++ i2c0_pins: i2c0-g0-pins { ++ mux { ++ function = "i2c"; ++ groups = "i2c0_1"; ++ }; ++ }; ++ ++ i2c1_pins: i2c1-g0-pins { ++ mux { ++ function = "i2c"; ++ groups = "i2c1_0"; ++ }; ++ }; ++ ++ i2c1_sfp_pins: i2c1-sfp-g0-pins { ++ mux { ++ function = "i2c"; ++ groups = "i2c1_sfp"; ++ }; ++ }; ++ ++ i2c2_0_pins: i2c2-g0-pins { ++ mux { ++ function = "i2c"; ++ groups = "i2c2_0"; ++ }; ++ }; ++ ++ i2c2_1_pins: i2c2-g1-pins { ++ mux { ++ function = "i2c"; ++ groups = "i2c2_1"; ++ }; ++ }; ++ ++ i2p5gbe_led0_pins: 2p5gbe-led0-pins { ++ mux { ++ function = "led"; ++ groups = "2p5gbe_led0"; ++ }; ++ }; ++ ++ i2p5gbe_led1_pins: 2p5gbe-led1-pins { ++ mux { ++ function = "led"; ++ groups = "2p5gbe_led1"; ++ }; ++ }; ++ ++ mmc0_pins_emmc_51: mmc0-emmc-51-pins { ++ mux { ++ function = "flash"; ++ groups = "emmc_51"; ++ }; ++ }; ++ ++ mmc0_pins_sdcard: mmc0-sdcard-pins { ++ mux { ++ function = "flash"; ++ groups = "sdcard"; ++ }; ++ }; ++ ++ spi0_pins: spi0-pins { ++ mux { ++ function = "spi"; ++ groups = "spi0"; ++ }; ++ }; ++ ++ spi0_flash_pins: spi0-flash-pins { ++ mux { ++ function = "spi"; ++ groups = "spi0", "spi0_wp_hold"; ++ }; ++ }; ++ ++ spi2_pins: spi2-pins { ++ mux { ++ function = "spi"; ++ groups = "spi2"; ++ }; ++ }; ++ ++ spi2_flash_pins: spi2-flash-pins { ++ mux { ++ function = "spi"; ++ groups = "spi2", "spi2_wp_hold"; ++ }; ++ }; ++ ++ uart0_pins: uart0-pins { ++ mux { ++ function = "uart"; ++ groups = "uart0"; ++ }; ++ }; ++ ++ uart1_0_pins: uart1-0-pins { ++ mux { ++ function = "uart"; ++ groups = "uart1_0"; ++ }; ++ }; ++ ++ uart1_1_pins: uart1-1-pins { ++ mux { ++ function = "uart"; ++ groups = "uart1_1"; ++ }; ++ }; ++ ++ uart1_2_pins: uart1-2-pins { ++ mux { ++ function = "uart"; ++ groups = "uart1_2"; ++ }; ++ }; ++ ++ uart1_2_lite_pins: uart1-2-lite-pins { ++ mux { ++ function = "uart"; ++ groups = "uart1_2_lite"; ++ }; ++ }; ++ ++ uart2_pins: uart2-pins { ++ mux { ++ function = "uart"; ++ groups = "uart2"; ++ }; ++ }; ++ ++ uart2_0_pins: uart2-0-pins { ++ mux { ++ function = "uart"; ++ groups = "uart2_0"; ++ }; ++ }; ++ ++ uart2_1_pins: uart2-1-pins { ++ mux { ++ function = "uart"; ++ groups = "uart2_1"; ++ }; ++ }; ++ ++ uart2_2_pins: uart2-2-pins { ++ mux { ++ function = "uart"; ++ groups = "uart2_2"; ++ }; ++ }; ++ ++ uart2_3_pins: uart2-3-pins { ++ mux { ++ function = "uart"; ++ groups = "uart2_3"; ++ }; ++ }; ++}; ++ ++&ssusb0 { ++ status = "okay"; ++}; ++ ++&ssusb1 { ++ status = "okay"; ++}; ++ ++&tphy { ++ status = "okay"; ++}; ++ ++&serial0 { ++ status = "okay"; ++}; ++ ++&watchdog { ++ status = "okay"; ++}; ++ ++&xsphy { ++ status = "okay"; ++}; +-- +2.51.0 + + +From bee4aa5461f67063cafc2a29b4049e844c637b7e Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Wed, 26 Jul 2023 14:56:28 +0100 +Subject: [PATCH 457/517] WIP: add BPi-R4 + +--- + .../mediatek/mt7988a-bananapi-bpi-r4-2g5.dts | 13 + + .../mt7988a-bananapi-bpi-r4-emmc.dtso | 56 ++++ + .../mediatek/mt7988a-bananapi-bpi-r4-rtc.dtso | 19 ++ + .../mediatek/mt7988a-bananapi-bpi-r4-sd.dtso | 54 ++++ + .../dts/mediatek/mt7988a-bananapi-bpi-r4.dts | 8 + + .../dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi | 241 +++++++++++++----- + 6 files changed, 328 insertions(+), 63 deletions(-) + create mode 100644 arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-emmc.dtso + create mode 100644 arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-rtc.dtso + create mode 100644 arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-sd.dtso + +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-2g5.dts b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-2g5.dts +index 574ac1b853a6..a88bc88576d6 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-2g5.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-2g5.dts +@@ -20,3 +20,16 @@ &int_2p5g_phy { + pinctrl-names = "i2p5gbe-led"; + pinctrl-0 = <&i2p5gbe_led0_pins>; + }; ++ ++&gmac1 { ++ phy-mode = "internal"; ++ phy-connection-type = "internal"; ++ phy = <&int_2p5g_phy>; ++ openwrt,netdev-name = "lan4"; ++ status = "okay"; ++}; ++ ++&int_2p5g_phy { ++ pinctrl-names = "i2p5gbe-led"; ++ pinctrl-0 = <&i2p5gbe_led0_pins>; ++}; +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-emmc.dtso b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-emmc.dtso +new file mode 100644 +index 000000000000..92cf2a2e2b53 +--- /dev/null ++++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-emmc.dtso +@@ -0,0 +1,56 @@ ++// SPDX-License-Identifier: (GPL-2.0 OR MIT) ++/* ++ * Copyright (C) 2021 MediaTek Inc. ++ * Author: Frank Wunderlich ++ */ ++ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "bananapi,bpi-r4", "mediatek,mt7988a"; ++}; ++ ++&{/soc/mmc@11230000} { ++ pinctrl-names = "default", "state_uhs"; ++ pinctrl-0 = <&mmc0_pins_emmc_51>; ++ pinctrl-1 = <&mmc0_pins_emmc_51>; ++ bus-width = <8>; ++ max-frequency = <200000000>; ++ cap-mmc-highspeed; ++ mmc-hs200-1_8v; ++ mmc-hs400-1_8v; ++ hs400-ds-delay = <0x12814>; ++ vqmmc-supply = <®_1p8v>; ++ vmmc-supply = <®_3p3v>; ++ non-removable; ++ no-sd; ++ no-sdio; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ card@0 { ++ compatible = "mmc-card"; ++ reg = <0>; ++ ++ partitions { ++ compatible = "gpt-partitions"; ++ ++ block-partition-env { ++ partname = "ubootenv"; ++ nvmem-layout { ++ compatible = "u-boot,env-layout"; ++ }; ++ }; ++ ++ emmc_rootfs: block-partition-production { ++ partname = "production"; ++ }; ++ }; ++ }; ++}; ++ ++&{/chosen} { ++ rootdisk-emmc = <&emmc_rootfs>; ++}; +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-rtc.dtso b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-rtc.dtso +new file mode 100644 +index 000000000000..39910b8cfee1 +--- /dev/null ++++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-rtc.dtso +@@ -0,0 +1,19 @@ ++// SPDX-License-Identifier: (GPL-2.0 OR MIT) ++/* ++ * Copyright (C) 2023 ++ * Author: Daniel Golle ++ */ ++ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "bananapi,bpi-r4", "mediatek,mt7988a"; ++ ++ fragment@0 { ++ target = <&pcf8563>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-sd.dtso b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-sd.dtso +new file mode 100644 +index 000000000000..8c74010998cb +--- /dev/null ++++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-sd.dtso +@@ -0,0 +1,54 @@ ++// SPDX-License-Identifier: (GPL-2.0 OR MIT) ++/* ++ * Copyright (C) 2023 MediaTek Inc. ++ * Author: Frank Wunderlich ++ */ ++ ++/dts-v1/; ++/plugin/; ++ ++#include ++ ++/ { ++ compatible = "bananapi,bpi-r4", "mediatek,mt7988a"; ++}; ++ ++&{/soc/mmc@11230000} { ++ pinctrl-names = "default", "state_uhs"; ++ pinctrl-0 = <&mmc0_pins_sdcard>; ++ pinctrl-1 = <&mmc0_pins_sdcard>; ++ cd-gpios = <&pio 12 GPIO_ACTIVE_LOW>; ++ bus-width = <4>; ++ max-frequency = <52000000>; ++ cap-sd-highspeed; ++ vmmc-supply = <®_3p3v>; ++ vqmmc-supply = <®_3p3v>; ++ no-mmc; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ card@0 { ++ compatible = "mmc-card"; ++ reg = <0>; ++ ++ partitions { ++ compatible = "gpt-partitions"; ++ ++ block-partition-env { ++ partname = "ubootenv"; ++ nvmem-layout { ++ compatible = "u-boot,env-layout"; ++ }; ++ }; ++ ++ sd_rootfs: block-partition-production { ++ partname = "production"; ++ }; ++ }; ++ }; ++}; ++ ++&{/chosen} { ++ rootdisk-sd = <&sd_rootfs>; ++}; +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts +index 3136dc4ba4cc..bab30961d6c4 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts +@@ -35,3 +35,11 @@ i2c_sfp2: i2c@2 { + reg = <2>; + }; + }; ++ ++&gmac1 { ++ sfp = <&sfp2>; ++ managed = "in-band-status"; ++ phy-mode = "usxgmii"; ++ openwrt,netdev-name = "sfp-lan"; ++ status = "okay"; ++}; +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi +index 7258039fda58..f22e5737750c 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi +@@ -3,6 +3,8 @@ + /dts-v1/; + + #include ++#include ++#include + #include + + #include "mt7988a.dtsi" +@@ -10,6 +12,8 @@ + / { + chosen { + stdout-path = "serial0:115200n8"; ++ bootargs = "console=ttyS0,115200n1 pci=pcie_bus_perf ubi.block=0,fit root=/dev/fit0"; ++ rootdisk-spim-nand = <&ubi_rootfs>; + }; + + fan: pwm-fan { +@@ -50,6 +54,142 @@ sfp1: sfp1 { + rate-select0-gpios = <&pio 21 GPIO_ACTIVE_LOW>; + maximum-power-milliwatt = <3000>; + }; ++ ++ aliases { ++ ethernet0 = &gmac0; ++ ethernet1 = &gmac1; ++ ethernet2 = &gmac2; ++ serial0 = &serial0; ++ led-boot = &led_green; ++ led-failsafe = &led_green; ++ led-running = &led_green; ++ led-upgrade = &led_green; ++ }; ++ ++ memory@40000000 { ++ reg = <0x00 0x40000000 0x00 0x10000000>; ++ device_type = "memory"; ++ }; ++ ++ /* SFP1 cage (WAN) */ ++ sfp1: sfp1 { ++ compatible = "sff,sfp"; ++ i2c-bus = <&i2c_sfp1>; ++ los-gpios = <&pio 54 GPIO_ACTIVE_HIGH>; ++ mod-def0-gpios = <&pio 82 GPIO_ACTIVE_LOW>; ++ tx-disable-gpios = <&pio 70 GPIO_ACTIVE_HIGH>; ++ tx-fault-gpios = <&pio 69 GPIO_ACTIVE_HIGH>; ++ rate-select0-gpios = <&pio 21 GPIO_ACTIVE_LOW>; ++ maximum-power-milliwatt = <3000>; ++ }; ++ ++ gpio-keys { ++ compatible = "gpio-keys"; ++ ++ wps { ++ label = "WPS"; ++ linux,code = ; ++ gpios = <&pio 14 GPIO_ACTIVE_LOW>; ++ }; ++ }; ++ ++ gpio-leds { ++ compatible = "gpio-leds"; ++ ++ led_green: led-green { ++ function = LED_FUNCTION_STATUS; ++ color = ; ++ gpios = <&pio 79 GPIO_ACTIVE_HIGH>; ++ default-state = "on"; ++ }; ++ ++ led_blue: led-blue { ++ function = LED_FUNCTION_WPS; ++ color = ; ++ gpios = <&pio 63 GPIO_ACTIVE_HIGH>; ++ default-state = "off"; ++ }; ++ }; ++}; ++ ++ð { ++ status = "okay"; ++}; ++ ++&gmac0 { ++ status = "okay"; ++}; ++ ++&gmac2 { ++ sfp = <&sfp1>; ++ managed = "in-band-status"; ++ phy-mode = "usxgmii"; ++ openwrt,netdev-name = "sfp-wan"; ++ status = "okay"; ++}; ++ ++&switch { ++ status = "okay"; ++}; ++ ++&gsw_phy0 { ++ pinctrl-names = "gbe-led"; ++ pinctrl-0 = <&gbe0_led0_pins>; ++}; ++ ++&gsw_port0 { ++ label = "wan"; ++}; ++ ++&gsw_phy0_led0 { ++ status = "okay"; ++ function = LED_FUNCTION_WAN; ++ color = ; ++}; ++ ++&gsw_phy1 { ++ pinctrl-names = "gbe-led"; ++ pinctrl-0 = <&gbe1_led0_pins>; ++}; ++ ++&gsw_port1 { ++ label = "lan1"; ++}; ++ ++&gsw_phy1_led0 { ++ status = "okay"; ++ function = LED_FUNCTION_LAN; ++ color = ; ++}; ++ ++&gsw_phy2 { ++ pinctrl-names = "gbe-led"; ++ pinctrl-0 = <&gbe2_led0_pins>; ++}; ++ ++&gsw_port2 { ++ label = "lan2"; ++}; ++ ++&gsw_phy2_led0 { ++ status = "okay"; ++ function = LED_FUNCTION_LAN; ++ color = ; ++}; ++ ++&gsw_phy3 { ++ pinctrl-names = "gbe-led"; ++ pinctrl-0 = <&gbe3_led0_pins>; ++}; ++ ++&gsw_port3 { ++ label = "lan3"; ++}; ++ ++&gsw_phy3_led0 { ++ status = "okay"; ++ function = LED_FUNCTION_LAN; ++ color = ; + }; + + &cci { +@@ -174,6 +314,10 @@ &gsw_phy3_led0 { + color = ; + }; + ++&cci { ++ proc-supply = <&rt5190_buck3>; ++}; ++ + &i2c0 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c0_pins>; +@@ -265,6 +409,14 @@ i2c_sfp1: i2c@1 { + #size-cells = <0>; + reg = <1>; + }; ++ ++ i2c_wifi: i2c@3 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <3>; ++ ++ status = "disabled"; ++ }; + }; + }; + +@@ -364,34 +516,6 @@ mux { + }; + }; + +- gbe0_led1_pins: gbe0-led1-pins { +- mux { +- function = "led"; +- groups = "gbe0_led1"; +- }; +- }; +- +- gbe1_led1_pins: gbe1-led1-pins { +- mux { +- function = "led"; +- groups = "gbe1_led1"; +- }; +- }; +- +- gbe2_led1_pins: gbe2-led1-pins { +- mux { +- function = "led"; +- groups = "gbe2_led1"; +- }; +- }; +- +- gbe3_led1_pins: gbe3-led1-pins { +- mux { +- function = "led"; +- groups = "gbe3_led1"; +- }; +- }; +- + i2p5gbe_led0_pins: 2p5gbe-led0-pins { + mux { + function = "led"; +@@ -399,13 +523,6 @@ mux { + }; + }; + +- i2p5gbe_led1_pins: 2p5gbe-led1-pins { +- mux { +- function = "led"; +- groups = "2p5gbe_led1"; +- }; +- }; +- + mmc0_pins_emmc_45: mmc0-emmc-45-pins { + mux { + function = "flash"; +@@ -427,40 +544,12 @@ mux { + }; + }; + +- snfi_pins: snfi-pins { +- mux { +- function = "flash"; +- groups = "snfi"; +- }; +- }; +- +- spi0_pins: spi0-pins { +- mux { +- function = "spi"; +- groups = "spi0"; +- }; +- }; +- + spi0_flash_pins: spi0-flash-pins { + mux { + function = "spi"; + groups = "spi0", "spi0_wp_hold"; + }; + }; +- +- spi2_pins: spi2-pins { +- mux { +- function = "spi"; +- groups = "spi2"; +- }; +- }; +- +- spi2_flash_pins: spi2-flash-pins { +- mux { +- function = "spi"; +- groups = "spi2", "spi2_wp_hold"; +- }; +- }; + }; + + &pwm { +@@ -500,6 +589,32 @@ partition@0 { + reg = <0x0 0x200000>; + read-only; + }; ++ ++ partition@200000 { ++ label = "ubi"; ++ reg = <0x200000 0x7e00000>; ++ compatible = "linux,ubi"; ++ ++ volumes { ++ ubi-volume-ubootenv { ++ volname = "ubootenv"; ++ nvmem-layout { ++ compatible = "u-boot,env-redundant-bool-layout"; ++ }; ++ }; ++ ++ ubi-volume-ubootenv2 { ++ volname = "ubootenv2"; ++ nvmem-layout { ++ compatible = "u-boot,env-redundant-bool-layout"; ++ }; ++ }; ++ ++ ubi_rootfs: ubi-volume-fit { ++ volname = "fit"; ++ }; ++ }; ++ }; + }; + }; + +-- +2.51.0 + + +From e9a4d50305620d1f59c45d3294121bddcff090c7 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Tue, 26 Apr 2022 20:51:36 +0100 +Subject: [PATCH 458/517] arm64: dts: mediatek: mt7622: fix GICv2 range + +With the current range specified for the CPU interface there is an +error message at boot: + +GIC: GICv2 detected, but range too small and irqchip.gicv2_force_probe not set + +Setting irqchip.gicv2_force_probe=1 in bootargs results in: + +GIC: Aliased GICv2 at 0x0000000010320000, trying to find the canonical range over 128kB +GIC: Adjusting CPU interface base to 0x000000001032f000 +GIC: Using split EOI/Deactivate mode + +Using the adjusted CPU interface base and 8K size results in only the +final line remaining and fully working system as well as /proc/interrupts +showing additional IPI3,4,5,6: + +IPI3: 0 0 CPU stop (for crash dump) interrupts +IPI4: 0 0 Timer broadcast interrupts +IPI5: 0 0 IRQ work interrupts +IPI6: 0 0 CPU wake-up interrupts + +Signed-off-by: Daniel Golle +--- + arch/arm64/boot/dts/mediatek/mt7622.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7622.dtsi b/arch/arm64/boot/dts/mediatek/mt7622.dtsi +index f2e526840582..39c57987412e 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi +@@ -345,7 +345,7 @@ gic: interrupt-controller@10300000 { + #interrupt-cells = <3>; + interrupt-parent = <&gic>; + reg = <0 0x10310000 0 0x1000>, +- <0 0x10320000 0 0x1000>, ++ <0 0x1032f000 0 0x2000>, + <0 0x10340000 0 0x2000>, + <0 0x10360000 0 0x2000>; + }; +-- +2.51.0 + + +From 0e859ccadea781e3c84c4891d729beb5b5ced245 Mon Sep 17 00:00:00 2001 +From: Bruno Umuarama +Date: Thu, 13 Oct 2022 21:18:21 +0000 +Subject: [PATCH 459/517] mediatek: mt7623: fix thermal zone +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Raising the temperatures for passive and active trips. @VA1DER +proposed at issue 9396 to remove passive trip. This commit relates to +his suggestion. + +Without this patch. the CPU will be throttled all the way down to 98MHz +if the temperature rises even a degree above the trip point, and it was +further discovered that if the internal temperature of the device is +above the first trip point temperature when it boots then it will start +in a throttled state and even +$ echo disabled > /sys/class/thermal/thermal_zone0/mode +will have no effect. + +The patch increases the passive trip point and active cooling map. The +throttling temperature will then be at 77°C and 82°C, which is still a +low enough temperature for ARM devices to not be in the real danger +zone, and gives some operational headroom. + +Signed-off-by: Bruno Umuarama +--- + arch/arm/boot/dts/mediatek/mt7623.dtsi | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/boot/dts/mediatek/mt7623.dtsi b/arch/arm/boot/dts/mediatek/mt7623.dtsi +index c6b7d1713096..94e1ca43fee9 100644 +--- a/arch/arm/boot/dts/mediatek/mt7623.dtsi ++++ b/arch/arm/boot/dts/mediatek/mt7623.dtsi +@@ -160,13 +160,13 @@ cpu_thermal: cpu-thermal { + + trips { + cpu_passive: cpu-passive { +- temperature = <57000>; ++ temperature = <77000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu_active: cpu-active { +- temperature = <67000>; ++ temperature = <82000>; + hysteresis = <2000>; + type = "active"; + }; +-- +2.51.0 + + +From 003346fae7e183886b6a3f9e991816b9758ab316 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= +Date: Mon, 3 Nov 2025 15:50:54 +0100 +Subject: [PATCH 460/517] + /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/194-dts-mt7968a-add-ramoops.patch + +--- + arch/arm64/boot/dts/mediatek/mt7986a.dtsi | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi +index f9aaf3f20cd7..39c4cee4b270 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi +@@ -68,6 +68,14 @@ reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; ++ ++ /* 64 KiB reserved for ramoops/pstore */ ++ ramoops@42ff0000 { ++ compatible = "ramoops"; ++ reg = <0 0x42ff0000 0 0x10000>; ++ record-size = <0x1000>; ++ }; ++ + /* 192 KiB reserved for ARM Trusted Firmware (BL31) */ + secmon_reserved: secmon@43000000 { + reg = <0 0x43000000 0 0x30000>; +-- +2.51.0 + + +From 7a4997adcfa4baacbc3101f5a46b9afcc9ce3fd2 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= +Date: Mon, 3 Nov 2025 15:50:54 +0100 +Subject: [PATCH 461/517] + /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/195-dts-mt7986a-bpi-r3-leds-port-names-and-wifi-eeprom.patch + +--- + .../mediatek/mt7986a-bananapi-bpi-r3-nor.dtso | 1 + + .../dts/mediatek/mt7986a-bananapi-bpi-r3.dts | 146 +++++++++++++++++- + 2 files changed, 140 insertions(+), 7 deletions(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-nor.dtso b/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-nor.dtso +index 6a0d529b54ac..7cbdd574aa9a 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-nor.dtso ++++ b/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-nor.dtso +@@ -55,6 +55,7 @@ partition@180000 { + partition@c00000 { + label = "fit"; + reg = <0xc00000 0x1400000>; ++ compatible = "denx,fit"; + }; + }; + }; +diff --git a/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3.dts b/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3.dts +index ed79ad1ae871..5e0c2941928d 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3.dts +@@ -23,6 +23,10 @@ aliases { + serial0 = &uart0; + ethernet0 = &gmac0; + ethernet1 = &gmac1; ++ led-boot = &green_led; ++ led-failsafe = &green_led; ++ led-running = &green_led; ++ led-upgrade = &blue_led; + }; + + chosen { +@@ -418,27 +422,27 @@ port@0 { + + port@1 { + reg = <1>; +- label = "lan0"; ++ label = "lan1"; + }; + + port@2 { + reg = <2>; +- label = "lan1"; ++ label = "lan2"; + }; + + port@3 { + reg = <3>; +- label = "lan2"; ++ label = "lan3"; + }; + + port@4 { + reg = <4>; +- label = "lan3"; ++ label = "lan4"; + }; + + port5: port@5 { + reg = <5>; +- label = "lan4"; ++ label = "sfp2"; + phy-mode = "2500base-x"; + sfp = <&sfp2>; + managed = "in-band-status"; +@@ -489,9 +493,137 @@ &watchdog { + + &wifi { + status = "okay"; +- pinctrl-names = "default", "dbdc"; ++ pinctrl-names = "default"; + pinctrl-0 = <&wf_2g_5g_pins>, <&wf_led_pins>; +- pinctrl-1 = <&wf_dbdc_pins>, <&wf_led_pins>; ++ ++ mediatek,eeprom-data = <0x86790900 0x000c4326 0x60000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x01000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000800 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x24649090 0x00280000 0x05100000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00021e00 0x021e0002 0x1e00021e 0x00022800 0x02280002 0x28000228 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00008080 0x8080fdf7 ++ 0x0903150d 0x80808080 0x80808080 0x05050d0d 0x1313c6c6 0xc3c3c200 0x00c200c2 0x00008182 ++ 0x8585c2c2 0x82828282 0x858500c2 0xc2000081 0x82858587 0x87c2c200 0x81818285 0x858787c2 ++ 0xc2000081 0x82858587 0x87c2c200 0x00818285 0x858787c2 0xc2000081 0x82858587 0x87c4c4c2 ++ 0xc100c300 0xc3c3c100 0x818383c3 0xc3c3c100 0x81838300 0xc2c2c2c0 0x81828484 0x000000c3 ++ 0xc3c3c100 0x81838386 0x86c3c3c3 0xc1008183 0x838686c2 0xc2c2c081 0x82848486 0x86c3c3c3 ++ 0xc1008183 0x838686c3 0xc3c3c100 0x81838386 0x86c3c3c3 0xc1008183 0x83868622 0x28002228 ++ 0x00222800 0x22280000 0xdddddddd 0xdddddddd 0xddbbbbbb 0xccccccdd 0xdddddddd 0xdddddddd ++ 0xeeeeeecc 0xccccdddd 0xdddddddd 0x004a5662 0x0000004a 0x56620000 0x004a5662 0x0000004a ++ 0x56620000 0x88888888 0x33333326 0x26262626 0x26262600 0x33333326 0x26262626 0x26262600 ++ 0x33333326 0x26262626 0x26262600 0x33333326 0x26262626 0x26262600 0x00000000 0xf0f0cc00 ++ 0x00000000 0x0000aaaa 0xaabbbbbb 0xcccccccc 0xccccbbbb 0xbbbbbbbb 0xbbbbbbaa 0xaaaabbbb ++ 0xbbaaaaaa 0x999999aa 0xaaaabbbb 0xbbcccccc 0x00000000 0x0000aaaa 0xaa000000 0xbbbbbbbb ++ 0xbbbbaaaa 0xaa999999 0xaaaaaaaa 0xaaaaaaaa 0xaaaaaaaa 0xaaaaaaaa 0xaaaabbbb 0xbbbbbbbb ++ 0x00000000 0x00000000 0x00000000 0x99999999 0x9999aaaa 0xaaaaaaaa 0x999999aa 0xaaaaaaaa ++ 0xaaaaaaaa 0xaaaaaaaa 0xaaaabbbb 0xbbbbbbbb 0x00000000 0x0000eeee 0xeeffffff 0xcccccccc ++ 0xccccdddd 0xddbbbbbb 0xccccccbb 0xbbbbbbbb 0xbbbbbbbb 0xbbbbbbbb 0xbbbbcccc 0xccdddddd ++ 0x00516200 0x686e0051 0x6200686e 0x00516200 0x686e0051 0x6200686e 0x00516200 0x686e0051 ++ 0x6200686e 0x00516200 0x686e0051 0x6200686e 0x00516200 0x686e0051 0x6200686e 0x00516200 ++ 0x686e0051 0x6200686e 0x00516200 0x686e0051 0x6200686e 0x00516200 0x686e0051 0x6200686e ++ 0x00516200 0x686e0051 0x6200686e 0x00516200 0x686e0051 0x6200686e 0x00516200 0x686e0051 ++ 0x6200686e 0x00516200 0x686e0051 0x6200686e 0x00516200 0x686e0051 0x6200686e 0x00516200 ++ 0x686e0051 0x6200686e 0x00516200 0x686e0051 0x6200686e 0x00516200 0x686e0051 0x6200686e ++ 0x88888888 0x88888888 0x88888888 0x88888888 0x88888888 0x88888888 0x88888888 0x88888888 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000001 0x06000100 0x01050002 0x00ff0300 ++ 0xf900fe03 0x00000000 0x00000000 0x0000009b 0x6e370000 0x00000000 0x00fc0009 0x0a00fe00 ++ 0x060700fe 0x00070800 0x05000b0a 0x00000000 0x00000000 0x000000e2 0x96460000 0x00000000 ++ 0x000400f7 0xf8000300 0xfcfe0003 0x00fbfc00 0xee00e3f2 0x00000000 0x00000000 0x00000011 ++ 0xbb550000 0x00000000 0x000600f6 0xfc000300 0xfbfe0004 0x00fafe00 0xf600ecf2 0x00000000 ++ 0x00000000 0x0000001f 0xbf580000 0x00000000 0x000600f5 0xf6000400 0xf8f90004 0x00f7f800 ++ 0xf700f0f4 0x00000000 0x00000000 0x00000024 0xbe570000 0x00000000 0x000800f8 0xfe000600 ++ 0xf8fd0007 0x00f9fe00 0xf500f0f4 0x00000000 0x00000000 0x0000002d 0xd6610000 0x00000000 ++ 0x000400f7 0xfc000500 0xf7fc0005 0x00f7fc00 0xf900f5f8 0x00000000 0x00000000 0x00000026 ++ 0xd96e0000 0x00000000 0x000400f7 0xf9000600 0xf5f70005 0x00f5f800 0xf900f4f7 0x00000000 ++ 0x00000000 0x0000001b 0xce690000 0x00000000 0x000300f8 0xf8000600 0xf6f60004 0x00f6f700 ++ 0xf900f4f7 0x00000000 0x00000000 0x00000018 0xd8720000 0x00000000 0x00000000 0x02404002 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0xc1c2c1c2 0x41c341c3 0x3fc13fc1 0x40c13fc2 0x3fc240c1 0x41c040c0 0x3fc23fc2 0x40c13fc2 ++ 0x3fc140c0 0x41c040c0 0x3fc33fc3 0x40c23fc2 0x3fc240c1 0x41c040c0 0x3fc23fc2 0x40c23fc2 ++ 0x3fc140c1 0x41c040c0 0x00000000 0x00000000 0x41c741c7 0xc1c7c1c7 0x00000000 0x00000000 ++ 0x3fc03fc0 0x3fc03fc0 0x3fc03fc0 0x3fc03fc0 0x3fc03fc0 0x3fc03fc0 0x3fc03fc0 0x3fc03fc0 ++ 0x3fc03fc0 0x3fc03fc0 0x3fc03fc0 0x3fc03fc0 0x3fc03fc0 0x3fc03fc0 0x3fc03fc0 0x3fc03fc0 ++ 0x00a0ce00 0x00000000 0xb6840000 0x00000000 0x00000000 0x00000000 0x18181818 0x18181818 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x004b5763 0x0000004b 0x57630000 0x004b5763 0x0000004b 0x57630000 0x88888888 0x08474759 ++ 0x69780849 0x49596d7a 0x0849495a 0x6d790848 0x48596c78 0x08484858 0x6a780848 0x48586a78 ++ 0x08484858 0x6c78084a 0x4a5b6d79 0x08474759 0x697a0848 0x48596b79 0x08484859 0x6c7a0848 ++ 0x48586c79 0x08484857 0x68770848 0x48576877 0x08484857 0x6a77084a 0x4a5a6a77 0x08464659 ++ 0x69790848 0x48586b79 0x08484858 0x6c7a0848 0x48596c79 0x08484857 0x68770848 0x48576877 ++ 0x08494958 0x6d7a084b 0x4b5c6c77 0x0847475a 0x6a7b0849 0x495a6e7c 0x0849495a 0x6e7c0849 ++ 0x495b6e7c 0x08494959 0x6a7a0849 0x49596a7a 0x084a4a5a 0x6f7d084b 0x4b5c6e7b 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x85848484 ++ 0xc3c4c4c5 0xc4c3c33f 0xc3c3c2c2 0xc2c2c03f 0xc3c3c3c4 0xc4c4c33f 0xc2c2c2c2 0xc1c3c1c1 ++ 0xc0c08282 0x83848686 0x88880000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00001111 0x00000000 ++ 0x8080f703 0x10808080 0x80050d13 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x000000a4 0xce000000 0x0000b684 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000>; + + led { + led-active-low; +-- +2.51.0 + + +From 9301b8648c259afbd936ca0d82993486c7f8621c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= +Date: Mon, 3 Nov 2025 15:50:55 +0100 +Subject: [PATCH 462/517] + /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/196-dts-mt7986a-bpi-r3-use-all-ubi-nand-layout.patch + +--- + .../mt7986a-bananapi-bpi-r3-emmc.dtso | 19 ++++++++++++ + .../mt7986a-bananapi-bpi-r3-nand.dtso | 29 +++++++++---------- + .../mediatek/mt7986a-bananapi-bpi-r3-nor.dtso | 6 +++- + .../mediatek/mt7986a-bananapi-bpi-r3-sd.dtso | 19 ++++++++++++ + 4 files changed, 57 insertions(+), 16 deletions(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-emmc.dtso b/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-emmc.dtso +index 047a8388811e..888f1e20374b 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-emmc.dtso ++++ b/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-emmc.dtso +@@ -21,5 +21,24 @@ / { + non-removable; + no-sd; + no-sdio; ++ #address-cells = <1>; ++ #size-cells = <0>; + status = "okay"; ++ ++ card@0 { ++ compatible = "mmc-card"; ++ reg = <0>; ++ ++ partitions { ++ compatible = "gpt-partitions"; ++ ++ emmc_rootdisk: block-partition-production { ++ partname = "production"; ++ }; ++ }; ++ }; ++}; ++ ++&{/chosen} { ++ rootdisk-emmc = <&emmc_rootdisk>; + }; +diff --git a/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-nand.dtso b/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-nand.dtso +index 24398f8a7da4..2b998cc9b054 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-nand.dtso ++++ b/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-nand.dtso +@@ -29,25 +29,24 @@ partitions { + + partition@0 { + label = "bl2"; +- reg = <0x0 0x100000>; +- read-only; ++ reg = <0x0 0x200000>; + }; + +- partition@100000 { +- label = "reserved"; +- reg = <0x100000 0x280000>; +- }; +- +- partition@380000 { +- label = "fip"; +- reg = <0x380000 0x200000>; +- read-only; +- }; +- +- partition@580000 { ++ partition@200000 { + label = "ubi"; +- reg = <0x580000 0x7a80000>; ++ reg = <0x200000 0x7e00000>; ++ compatible = "linux,ubi"; ++ ++ volumes { ++ nand_rootdisk: ubi-volume-fit { ++ volname = "fit"; ++ }; ++ }; + }; + }; + }; + }; ++ ++&{/chosen} { ++ rootdisk-spim-nand = <&nand_rootdisk>; ++}; +diff --git a/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-nor.dtso b/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-nor.dtso +index 7cbdd574aa9a..384ceab38e3f 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-nor.dtso ++++ b/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-nor.dtso +@@ -52,7 +52,7 @@ partition@180000 { + reg = <0x180000 0xa80000>; + }; + +- partition@c00000 { ++ nor_rootdisk: partition@c00000 { + label = "fit"; + reg = <0xc00000 0x1400000>; + compatible = "denx,fit"; +@@ -60,3 +60,7 @@ partition@c00000 { + }; + }; + }; ++ ++&{/chosen} { ++ rootdisk-nor = <&nor_rootdisk>; ++}; +diff --git a/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-sd.dtso b/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-sd.dtso +index d9e01967acc4..98be406ecae1 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-sd.dtso ++++ b/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-sd.dtso +@@ -15,5 +15,24 @@ / { + bus-width = <4>; + max-frequency = <52000000>; + cap-sd-highspeed; ++ #address-cells = <1>; ++ #size-cells = <0>; + status = "okay"; ++ ++ card@0 { ++ compatible = "mmc-card"; ++ reg = <0>; ++ ++ partitions { ++ compatible = "gpt-partitions"; ++ ++ sd_rootdisk: block-partition-production { ++ partname = "production"; ++ }; ++ }; ++ }; ++}; ++ ++&{/chosen} { ++ rootdisk-sd = <&sd_rootdisk>; + }; +-- +2.51.0 + + +From a3d2dc6ef2ff5f5cb44223775f18f400b3d25f64 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= +Date: Mon, 3 Nov 2025 15:50:55 +0100 +Subject: [PATCH 463/517] + /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/198-dts-mt7988a-enable-wed.patch + +--- + arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 137 ++++++++++++++++++++++ + 1 file changed, 137 insertions(+) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +index b2338231fab4..5717729f563c 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +@@ -145,6 +145,32 @@ secmon@43000000 { + reg = <0 0x43000000 0 0x50000>; + no-map; + }; ++ ++ wmcpu_emi: wmcpu-reserved@47cc0000 { ++ reg = <0 0x47cc0000 0 0x00100000>; ++ no-map; ++ }; ++ ++ wo_emi0: wo-emi@4f600000 { ++ reg = <0 0x4f600000 0 0x40000>; ++ no-map; ++ }; ++ ++ wo_emi1: wo-emi@4f640000 { ++ reg = <0 0x4f640000 0 0x40000>; ++ no-map; ++ }; ++ ++ wo_emi2: wo-emi@4f680000 { ++ reg = <0 0x4f680000 0 0x40000>; ++ no-map; ++ }; ++ ++ wo_data: wo-data@4f700000 { ++ reg = <0 0x4f700000 0 0x800000>; ++ no-map; ++ shared = <1>; ++ }; + }; + + soc { +@@ -867,6 +893,50 @@ ethsys: clock-controller@15000000 { + reg = <0 0x15000000 0 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ }; ++ ++ wed0: wed@15010000 { ++ compatible = "mediatek,mt7988-wed", ++ "syscon"; ++ reg = <0 0x15010000 0 0x2000>; ++ interrupt-parent = <&gic>; ++ interrupts = ; ++ memory-region = <&wo_emi0>, <&wo_data>; ++ memory-region-names = "wo-emi", "wo-data"; ++ mediatek,wo-ccif = <&wo_ccif0>; ++ mediatek,wo-ilm = <&wo_ilm0>; ++ mediatek,wo-dlm = <&wo_dlm0>; ++ mediatek,wo-cpuboot = <&wo_cpuboot0>; ++ }; ++ ++ wed1: wed@15012000 { ++ compatible = "mediatek,mt7988-wed", ++ "syscon"; ++ reg = <0 0x15012000 0 0x2000>; ++ interrupt-parent = <&gic>; ++ interrupts = ; ++ memory-region = <&wo_emi1>, <&wo_data>; ++ memory-region-names = "wo-emi", "wo-data"; ++ mediatek,wo-ccif = <&wo_ccif1>; ++ mediatek,wo-ilm = <&wo_ilm1>; ++ mediatek,wo-dlm = <&wo_dlm1>; ++ mediatek,wo-cpuboot = <&wo_cpuboot1>; ++ }; ++ ++ wed2: wed@15014000 { ++ compatible = "mediatek,mt7988-wed", ++ "syscon"; ++ reg = <0 0x15014000 0 0x2000>; ++ interrupt-parent = <&gic>; ++ interrupts = ; ++ memory-region = <&wo_emi2>, <&wo_data>; ++ memory-region-names = "wo-emi", "wo-data"; ++ mediatek,wo-ccif = <&wo_ccif2>; ++ mediatek,wo-ilm = <&wo_ilm2>; ++ mediatek,wo-dlm = <&wo_dlm2>; ++ mediatek,wo-cpuboot = <&wo_cpuboot2>; + }; + + switch: switch@15020000 { +@@ -1086,6 +1156,7 @@ eth: ethernet@15100000 { + <&apmixedsys CLK_APMIXED_SGMPLL>; + mediatek,ethsys = <ðsys>; + mediatek,infracfg = <&topmisc>; ++ mediatek,wed = <&wed0>, <&wed1>, <&wed2>; + #address-cells = <1>; + #size-cells = <0>; + +@@ -1147,6 +1218,72 @@ i2p5gbe_led1: i2p5gbe-led1@1 { + }; + }; + ++ wo_ccif0: syscon@151a5000 { ++ compatible = "mediatek,mt7988-wo-ccif", "syscon"; ++ reg = <0 0x151a5000 0 0x1000>; ++ interrupt-parent = <&gic>; ++ interrupts = ; ++ }; ++ ++ wo_ccif1: syscon@152a5000 { ++ compatible = "mediatek,mt7988-wo-ccif", "syscon"; ++ reg = <0 0x152a5000 0 0x1000>; ++ interrupt-parent = <&gic>; ++ interrupts = ; ++ }; ++ ++ wo_ccif2: syscon@153a5000 { ++ compatible = "mediatek,mt7988-wo-ccif", "syscon"; ++ reg = <0 0x153a5000 0 0x1000>; ++ interrupt-parent = <&gic>; ++ interrupts = ; ++ }; ++ ++ wo_ilm0: syscon@151e0000 { ++ compatible = "mediatek,mt7988-wo-ilm", "syscon"; ++ reg = <0 0x151e0000 0 0x8000>; ++ }; ++ ++ wo_ilm1: syscon@152e0000 { ++ compatible = "mediatek,mt7988-wo-ilm", "syscon"; ++ reg = <0 0x152e0000 0 0x8000>; ++ }; ++ ++ wo_ilm2: syscon@153e0000 { ++ compatible = "mediatek,mt7988-wo-ilm", "syscon"; ++ reg = <0 0x153e0000 0 0x8000>; ++ }; ++ ++ wo_dlm0: syscon@151e8000 { ++ compatible = "mediatek,mt7988-wo-dlm", "syscon"; ++ reg = <0 0x151e8000 0 0x2000>; ++ }; ++ ++ wo_dlm1: syscon@152e8000 { ++ compatible = "mediatek,mt7988-wo-dlm", "syscon"; ++ reg = <0 0x152e8000 0 0x2000>; ++ }; ++ ++ wo_dlm2: syscon@153e8000 { ++ compatible = "mediatek,mt7988-wo-dlm", "syscon"; ++ reg = <0 0x153e8000 0 0x2000>; ++ }; ++ ++ wo_cpuboot0: syscon@15194000 { ++ compatible = "mediatek,mt7988-wo-cpuboot", "syscon"; ++ reg = <0 0x15194000 0 0x1000>; ++ }; ++ ++ wo_cpuboot1: syscon@15294000 { ++ compatible = "mediatek,mt7988-wo-cpuboot", "syscon"; ++ reg = <0 0x15294000 0 0x1000>; ++ }; ++ ++ wo_cpuboot2: syscon@15394000 { ++ compatible = "mediatek,mt7988-wo-cpuboot", "syscon"; ++ reg = <0 0x15394000 0 0x1000>; ++ }; ++ + crypto: crypto@15600000 { + compatible = "inside-secure,safexcel-eip197b"; + reg = <0 0x15600000 0 0x180000>; +-- +2.51.0 + + +From a578fcc5a7b10a8a40c829a21a9d9db28b7c8cd7 Mon Sep 17 00:00:00 2001 +From: Shiji Yang +Date: Sun, 10 Aug 2025 18:11:01 +0800 +Subject: [PATCH 464/517] arm64: dts: mediatek: mt7986: increase ATF reserved + memory to 256 kiB + +The latest Mediatek open-source Trusted Firmware-A project has +reserved 256 KiB for BL2 and BL31. It is better to increase the +reserved memory region in the Linux kernel to protect the data. + +Signed-off-by: Shiji Yang +--- + arch/arm64/boot/dts/mediatek/mt7986a.dtsi | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi +index 39c4cee4b270..9a8d7db31261 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi +@@ -76,9 +76,9 @@ ramoops@42ff0000 { + record-size = <0x1000>; + }; + +- /* 192 KiB reserved for ARM Trusted Firmware (BL31) */ ++ /* 256 KiB reserved for ARM Trusted Firmware (BL31 + BL32) */ + secmon_reserved: secmon@43000000 { +- reg = <0 0x43000000 0 0x30000>; ++ reg = <0 0x43000000 0 0x40000>; + no-map; + }; + +-- +2.51.0 + + +From 58d452682aae8137393174cc17db1b3277413904 Mon Sep 17 00:00:00 2001 +From: Kristian Evensen +Date: Mon, 30 Apr 2018 14:38:01 +0200 +Subject: [PATCH 465/517] phy: phy-mtk-tphy: Add hifsys-support + +--- + drivers/phy/mediatek/phy-mtk-tphy.c | 20 ++++++++++++++++++++ + 1 file changed, 20 insertions(+) + +diff --git a/drivers/phy/mediatek/phy-mtk-tphy.c b/drivers/phy/mediatek/phy-mtk-tphy.c +index 3f7095ec5978..4662518a38ed 100644 +--- a/drivers/phy/mediatek/phy-mtk-tphy.c ++++ b/drivers/phy/mediatek/phy-mtk-tphy.c +@@ -18,6 +18,8 @@ + #include + #include + #include ++#include ++#include + + #include "phy-mtk-io.h" + +@@ -271,6 +273,9 @@ + + #define USER_BUF_LEN(count) min_t(size_t, 8, (count)) + ++#define HIF_SYSCFG1 0x14 ++#define HIF_SYSCFG1_PHY2_MASK (0x3 << 20) ++ + enum mtk_phy_version { + MTK_PHY_V1 = 1, + MTK_PHY_V2, +@@ -339,6 +344,7 @@ struct mtk_tphy { + void __iomem *sif_base; /* only shared sif */ + const struct mtk_phy_pdata *pdata; + struct mtk_phy_instance **phys; ++ struct regmap *hif; + int nphys; + int src_ref_clk; /* MHZ, reference clock for slew rate calibrate */ + int src_coef; /* coefficient for slew rate calibrate */ +@@ -973,6 +979,10 @@ static void pcie_phy_instance_init(struct mtk_tphy *tphy, + if (tphy->pdata->version != MTK_PHY_V1) + return; + ++ if (tphy->hif) ++ regmap_update_bits(tphy->hif, HIF_SYSCFG1, ++ HIF_SYSCFG1_PHY2_MASK, 0); ++ + mtk_phy_update_bits(phya + U3P_U3_PHYA_DA_REG0, + P3A_RG_XTAL_EXT_PE1H | P3A_RG_XTAL_EXT_PE2H, + FIELD_PREP(P3A_RG_XTAL_EXT_PE1H, 0x2) | +@@ -1621,6 +1631,16 @@ static int mtk_tphy_probe(struct platform_device *pdev) + &tphy->src_coef); + } + ++ if (of_find_property(np, "mediatek,phy-switch", NULL)) { ++ tphy->hif = syscon_regmap_lookup_by_phandle(np, ++ "mediatek,phy-switch"); ++ if (IS_ERR(tphy->hif)) { ++ dev_err(&pdev->dev, ++ "missing \"mediatek,phy-switch\" phandle\n"); ++ return PTR_ERR(tphy->hif); ++ } ++ } ++ + port = 0; + for_each_child_of_node_scoped(np, child_np) { + struct mtk_phy_instance *instance; +-- +2.51.0 + + +From e45d21bc40ab81b4a082310763c9f0ef19f980ec Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Fri, 1 Nov 2024 03:19:39 +0000 +Subject: [PATCH 466/517] clk: mediatek: mt7988-infracfg: SPI0 clocks are not + critical + +SPI0 clocks have wrongly been marked as critical while, probably due +to the SPI driver not requesting them. This can (and should) be addressed +in device tree instead. +Remove CLK_IS_CRITICAL flag from clocks related to SPI0. + +Fixes: 4b4719437d85 ("clk: mediatek: add drivers for MT7988 SoC") +Signed-off-by: Daniel Golle +--- + drivers/clk/mediatek/clk-mt7988-infracfg.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/drivers/clk/mediatek/clk-mt7988-infracfg.c b/drivers/clk/mediatek/clk-mt7988-infracfg.c +index ef8267319d91..c40e18c27f12 100644 +--- a/drivers/clk/mediatek/clk-mt7988-infracfg.c ++++ b/drivers/clk/mediatek/clk-mt7988-infracfg.c +@@ -196,12 +196,10 @@ static const struct mtk_gate infra_clks[] = { + GATE_INFRA2(CLK_INFRA_SPINFI, "infra_f_fspinfi", "spinfi_sel", 10), + GATE_INFRA2_FLAGS(CLK_INFRA_66M_NFI_HCK, "infra_hf_66m_nfi_hck", "sysaxi_sel", 11, + CLK_IS_CRITICAL), +- GATE_INFRA2_FLAGS(CLK_INFRA_104M_SPI0, "infra_hf_104m_spi0", "infra_mux_spi0_sel", 12, +- CLK_IS_CRITICAL), ++ GATE_INFRA2(CLK_INFRA_104M_SPI0, "infra_hf_104m_spi0", "infra_mux_spi0_sel", 12), + GATE_INFRA2(CLK_INFRA_104M_SPI1, "infra_hf_104m_spi1", "infra_mux_spi1_sel", 13), + GATE_INFRA2(CLK_INFRA_104M_SPI2_BCK, "infra_hf_104m_spi2_bck", "infra_mux_spi2_sel", 14), +- GATE_INFRA2_FLAGS(CLK_INFRA_66M_SPI0_HCK, "infra_hf_66m_spi0_hck", "sysaxi_sel", 15, +- CLK_IS_CRITICAL), ++ GATE_INFRA2(CLK_INFRA_66M_SPI0_HCK, "infra_hf_66m_spi0_hck", "sysaxi_sel", 15), + GATE_INFRA2(CLK_INFRA_66M_SPI1_HCK, "infra_hf_66m_spi1_hck", "sysaxi_sel", 16), + GATE_INFRA2(CLK_INFRA_66M_SPI2_HCK, "infra_hf_66m_spi2_hck", "sysaxi_sel", 17), + GATE_INFRA2(CLK_INFRA_66M_FLASHIF_AXI, "infra_hf_66m_flashif_axi", "sysaxi_sel", 18), +-- +2.51.0 + + +From 2635aa94e576bbcaf5fdfe2a2ac47d35203f0ff1 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Wed, 25 Jan 2023 00:27:49 +0000 +Subject: [PATCH 467/517] hwrng: add driver for MediaTek TRNG SMC + +Add driver providing kernel-side support for the Random Number +Generator hardware found on Mediatek SoCs which have a driver in ARM +TrustedFirmware-A allowing Linux to read random numbers using a +non-standard vendor-defined Secure Monitor Call. + +Signed-off-by: Daniel Golle +--- + drivers/char/hw_random/Kconfig | 17 +++++++ + drivers/char/hw_random/Makefile | 1 + + drivers/char/hw_random/mtk-rng-v2.c | 76 +++++++++++++++++++++++++++++ + 3 files changed, 94 insertions(+) + create mode 100644 drivers/char/hw_random/mtk-rng-v2.c + +diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig +index f0dde77f50b4..fc19371e6217 100644 +--- a/drivers/char/hw_random/Kconfig ++++ b/drivers/char/hw_random/Kconfig +@@ -452,6 +452,23 @@ config HW_RANDOM_MTK + + If unsure, say Y. + ++config HW_RANDOM_MTK_V2 ++ tristate "Mediatek Random Number Generator support (v2/SMC)" ++ depends on HAVE_ARM_SMCCC ++ depends on HW_RANDOM ++ depends on (ARM64 && ARCH_MEDIATEK) || COMPILE_TEST ++ default y ++ help ++ This driver provides kernel-side support for the Random Number ++ Generator hardware found on Mediatek SoCs which have a driver ++ in ARM TrustedFirmware-A allowing Linux to read using a non- ++ standard vendor-defined Secure Monitor Call. ++ ++ To compile this driver as a module, choose M here. the ++ module will be called mtk-rng-v2. ++ ++ If unsure, say Y. ++ + config HW_RANDOM_S390 + tristate "S390 True Random Number Generator support" + depends on S390 +diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile +index 01f012eab440..3403f6b9282a 100644 +--- a/drivers/char/hw_random/Makefile ++++ b/drivers/char/hw_random/Makefile +@@ -39,6 +39,7 @@ obj-$(CONFIG_HW_RANDOM_PIC32) += pic32-rng.o + obj-$(CONFIG_HW_RANDOM_MESON) += meson-rng.o + obj-$(CONFIG_HW_RANDOM_CAVIUM) += cavium-rng.o cavium-rng-vf.o + obj-$(CONFIG_HW_RANDOM_MTK) += mtk-rng.o ++obj-$(CONFIG_HW_RANDOM_MTK_V2) += mtk-rng-v2.o + obj-$(CONFIG_HW_RANDOM_S390) += s390-trng.o + obj-$(CONFIG_HW_RANDOM_KEYSTONE) += ks-sa-rng.o + obj-$(CONFIG_HW_RANDOM_OPTEE) += optee-rng.o +diff --git a/drivers/char/hw_random/mtk-rng-v2.c b/drivers/char/hw_random/mtk-rng-v2.c +new file mode 100644 +index 000000000000..8c506a7897d0 +--- /dev/null ++++ b/drivers/char/hw_random/mtk-rng-v2.c +@@ -0,0 +1,76 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Driver for Mediatek Hardware Random Number Generator (v2/SMCC) ++ * ++ * Copyright (C) 2023 Daniel Golle ++ * based on patch from Mingming Su ++ */ ++#define MTK_RNG_DEV KBUILD_MODNAME ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define MTK_SIP_KERNEL_GET_RND MTK_SIP_SMC_CMD(0x550) ++ ++static int mtk_rng_v2_read(struct hwrng *rng, void *buf, size_t max, bool wait) ++{ ++ struct arm_smccc_res res; ++ int retval = 0; ++ ++ while (max >= sizeof(u32)) { ++ arm_smccc_smc(MTK_SIP_KERNEL_GET_RND, 0, 0, 0, 0, 0, 0, 0, ++ &res); ++ if (res.a0) ++ break; ++ ++ *(u32 *)buf = res.a1; ++ retval += sizeof(u32); ++ buf += sizeof(u32); ++ max -= sizeof(u32); ++ } ++ ++ return retval || !wait ? retval : -EIO; ++} ++ ++static int mtk_rng_v2_probe(struct platform_device *pdev) ++{ ++ struct hwrng *trng; ++ ++ trng = devm_kzalloc(&pdev->dev, sizeof(*trng), GFP_KERNEL); ++ if (!trng) ++ return -ENOMEM; ++ ++ trng->name = pdev->name; ++ trng->read = mtk_rng_v2_read; ++ trng->quality = 900; ++ ++ return devm_hwrng_register(&pdev->dev, trng); ++} ++ ++static const struct of_device_id mtk_rng_v2_match[] = { ++ { .compatible = "mediatek,mt7981-rng" }, ++ { .compatible = "mediatek,mt7987-rng" }, ++ { .compatible = "mediatek,mt7988-rng" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, mtk_rng_v2_match); ++ ++static struct platform_driver mtk_rng_v2_driver = { ++ .probe = mtk_rng_v2_probe, ++ .driver = { ++ .name = KBUILD_MODNAME, ++ .of_match_table = mtk_rng_v2_match, ++ }, ++}; ++module_platform_driver(mtk_rng_v2_driver); ++ ++MODULE_DESCRIPTION("Mediatek Random Number Generator Driver (v2/SMC)"); ++MODULE_AUTHOR("Daniel Golle "); ++MODULE_LICENSE("GPL"); +-- +2.51.0 + + +From 7ab0a6fa1cbc0955011ee9d40ee6dd4ab9e3eade Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= +Date: Mon, 3 Nov 2025 15:50:56 +0100 +Subject: [PATCH 468/517] + /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/330-snand-mtk-bmt-support.patch + +--- + drivers/mtd/nand/spi/core.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c +index 8a3c9db90c6f..685a92a50fe6 100644 +--- a/drivers/mtd/nand/spi/core.c ++++ b/drivers/mtd/nand/spi/core.c +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + + static int spinand_read_reg_op(struct spinand_device *spinand, u8 reg, u8 *val) + { +@@ -1574,6 +1575,7 @@ static int spinand_probe(struct spi_mem *mem) + if (ret) + return ret; + ++ mtk_bmt_attach(mtd); + ret = mtd_device_register(mtd, NULL, 0); + if (ret) + goto err_spinand_cleanup; +@@ -1581,6 +1583,7 @@ static int spinand_probe(struct spi_mem *mem) + return 0; + + err_spinand_cleanup: ++ mtk_bmt_detach(mtd); + spinand_cleanup(spinand); + + return ret; +@@ -1599,6 +1602,7 @@ static int spinand_remove(struct spi_mem *mem) + if (ret) + return ret; + ++ mtk_bmt_detach(mtd); + spinand_cleanup(spinand); + + return 0; +-- +2.51.0 + + +From 14a79939d2d384b4a9bf0ff262a01071e4e1b559 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= +Date: Mon, 3 Nov 2025 15:50:57 +0100 +Subject: [PATCH 469/517] + /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/331-mt7622-rfb1-enable-bmt.patch + +--- + arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts b/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts +index a478bab2e8cf..d6c52654e5ed 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts +@@ -572,6 +572,7 @@ flash@0 { + spi-tx-bus-width = <4>; + spi-rx-bus-width = <4>; + nand-ecc-engine = <&snfi>; ++ mediatek,bmt-v2; + + partitions { + compatible = "fixed-partitions"; +-- +2.51.0 + + +From aa4935c265e21729b534f8fd79fe2411dec468a4 Mon Sep 17 00:00:00 2001 +From: Davide Fioravanti +Date: Fri, 8 Jan 2021 15:35:24 +0100 +Subject: [PATCH 470/517] mtd: spinand: Add support for the Fidelix FM35X1GA + +Datasheet: http://www.hobos.com.cn/upload/datasheet/DS35X1GAXXX_100_rev00.pdf + +Signed-off-by: Davide Fioravanti +--- + drivers/mtd/nand/spi/Makefile | 2 +- + drivers/mtd/nand/spi/core.c | 1 + + drivers/mtd/nand/spi/fidelix.c | 76 ++++++++++++++++++++++++++++++++++ + include/linux/mtd/spinand.h | 1 + + 4 files changed, 79 insertions(+), 1 deletion(-) + create mode 100644 drivers/mtd/nand/spi/fidelix.c + +diff --git a/drivers/mtd/nand/spi/Makefile b/drivers/mtd/nand/spi/Makefile +index f725f0c67307..27dc57924f19 100644 +--- a/drivers/mtd/nand/spi/Makefile ++++ b/drivers/mtd/nand/spi/Makefile +@@ -1,4 +1,4 @@ + # SPDX-License-Identifier: GPL-2.0 +-spinand-objs := core.o alliancememory.o ato.o esmt.o etron.o fmsh.o foresee.o gigadevice.o ++spinand-objs := core.o alliancememory.o ato.o esmt.o etron.o fidelix.o fmsh.o foresee.o gigadevice.o + spinand-objs += macronix.o micron.o paragon.o toshiba.o winbond.o xtx.o + obj-$(CONFIG_MTD_SPI_NAND) += spinand.o +diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c +index 685a92a50fe6..d0071aba4f77 100644 +--- a/drivers/mtd/nand/spi/core.c ++++ b/drivers/mtd/nand/spi/core.c +@@ -1162,6 +1162,7 @@ static const struct spinand_manufacturer *spinand_manufacturers[] = { + &esmt_c8_spinand_manufacturer, + &etron_spinand_manufacturer, + &fmsh_spinand_manufacturer, ++ &fidelix_spinand_manufacturer, + &foresee_spinand_manufacturer, + &gigadevice_spinand_manufacturer, + ¯onix_spinand_manufacturer, +diff --git a/drivers/mtd/nand/spi/fidelix.c b/drivers/mtd/nand/spi/fidelix.c +new file mode 100644 +index 000000000000..039bf331813c +--- /dev/null ++++ b/drivers/mtd/nand/spi/fidelix.c +@@ -0,0 +1,76 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (c) 2020 Davide Fioravanti ++ */ ++ ++#include ++#include ++#include ++ ++#define SPINAND_MFR_FIDELIX 0xE5 ++#define FIDELIX_ECCSR_MASK 0x0F ++ ++static SPINAND_OP_VARIANTS(read_cache_variants, ++ SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0)); ++ ++static SPINAND_OP_VARIANTS(write_cache_variants, ++ SPINAND_PROG_LOAD_X4(true, 0, NULL, 0), ++ SPINAND_PROG_LOAD(true, 0, NULL, 0)); ++ ++static SPINAND_OP_VARIANTS(update_cache_variants, ++ SPINAND_PROG_LOAD_X4(true, 0, NULL, 0), ++ SPINAND_PROG_LOAD(true, 0, NULL, 0)); ++ ++static int fm35x1ga_ooblayout_ecc(struct mtd_info *mtd, int section, ++ struct mtd_oob_region *region) ++{ ++ if (section > 3) ++ return -ERANGE; ++ ++ region->offset = (16 * section) + 8; ++ region->length = 8; ++ ++ return 0; ++} ++ ++static int fm35x1ga_ooblayout_free(struct mtd_info *mtd, int section, ++ struct mtd_oob_region *region) ++{ ++ if (section > 3) ++ return -ERANGE; ++ ++ region->offset = (16 * section) + 2; ++ region->length = 6; ++ ++ return 0; ++} ++ ++static const struct mtd_ooblayout_ops fm35x1ga_ooblayout = { ++ .ecc = fm35x1ga_ooblayout_ecc, ++ .free = fm35x1ga_ooblayout_free, ++}; ++ ++static const struct spinand_info fidelix_spinand_table[] = { ++ SPINAND_INFO("FM35X1GA", ++ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x71), ++ NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), ++ NAND_ECCREQ(4, 512), ++ SPINAND_INFO_OP_VARIANTS(&read_cache_variants, ++ &write_cache_variants, ++ &update_cache_variants), ++ SPINAND_HAS_QE_BIT, ++ SPINAND_ECCINFO(&fm35x1ga_ooblayout, NULL)), ++}; ++ ++static const struct spinand_manufacturer_ops fidelix_spinand_manuf_ops = { ++}; ++ ++const struct spinand_manufacturer fidelix_spinand_manufacturer = { ++ .id = SPINAND_MFR_FIDELIX, ++ .name = "Fidelix", ++ .chips = fidelix_spinand_table, ++ .nchips = ARRAY_SIZE(fidelix_spinand_table), ++ .ops = &fidelix_spinand_manuf_ops, ++}; +diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h +index e5b6ac340383..11f7a6a1a31f 100644 +--- a/include/linux/mtd/spinand.h ++++ b/include/linux/mtd/spinand.h +@@ -265,6 +265,7 @@ extern const struct spinand_manufacturer ato_spinand_manufacturer; + extern const struct spinand_manufacturer esmt_c8_spinand_manufacturer; + extern const struct spinand_manufacturer etron_spinand_manufacturer; + extern const struct spinand_manufacturer fmsh_spinand_manufacturer; ++extern const struct spinand_manufacturer fidelix_spinand_manufacturer; + extern const struct spinand_manufacturer foresee_spinand_manufacturer; + extern const struct spinand_manufacturer gigadevice_spinand_manufacturer; + extern const struct spinand_manufacturer macronix_spinand_manufacturer; +-- +2.51.0 + + +From 3444bd6e424a34dfa604bd275471bbc90db46127 Mon Sep 17 00:00:00 2001 +From: Sam Shih +Date: Fri, 19 Apr 2024 17:59:07 +0100 +Subject: [PATCH 471/517] cpufreq: mediatek: Add support for MT7988A + +This add cpufreq support for mediatek MT7988A SoC. + +The platform data of MT7988A is different from previous MediaTek SoCs, +so we add a new compatible and platform data for it. + +Signed-off-by: Sam Shih +--- + drivers/cpufreq/mediatek-cpufreq.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/cpufreq/mediatek-cpufreq.c b/drivers/cpufreq/mediatek-cpufreq.c +index 663f61565cf7..fa6633d44ac9 100644 +--- a/drivers/cpufreq/mediatek-cpufreq.c ++++ b/drivers/cpufreq/mediatek-cpufreq.c +@@ -744,6 +744,7 @@ static const struct of_device_id mtk_cpufreq_machines[] __initconst __maybe_unus + { .compatible = "mediatek,mt7622", .data = &mt7622_platform_data }, + { .compatible = "mediatek,mt7623", .data = &mt7623_platform_data }, + { .compatible = "mediatek,mt7988a", .data = &mt7988_platform_data }, ++ { .compatible = "mediatek,mt7988d", .data = &mt7988_platform_data }, + { .compatible = "mediatek,mt8167", .data = &mt8516_platform_data }, + { .compatible = "mediatek,mt817x", .data = &mt2701_platform_data }, + { .compatible = "mediatek,mt8173", .data = &mt2701_platform_data }, +-- +2.51.0 + + +From ee055daffe2d0aa9cdc5229ef49bd46c8cfb4078 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= +Date: Mon, 3 Nov 2025 15:50:58 +0100 +Subject: [PATCH 472/517] + /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/400-crypto-add-eip97-inside-secure-support.patch + +--- + drivers/crypto/inside-secure/safexcel.c | 8 ++++++++ + drivers/crypto/inside-secure/safexcel.h | 1 + + 2 files changed, 9 insertions(+) + +diff --git a/drivers/crypto/inside-secure/safexcel.c b/drivers/crypto/inside-secure/safexcel.c +index f5c1912aa564..c0a1fa1f7169 100644 +--- a/drivers/crypto/inside-secure/safexcel.c ++++ b/drivers/crypto/inside-secure/safexcel.c +@@ -608,6 +608,14 @@ static int safexcel_hw_init(struct safexcel_crypto_priv *priv) + val |= EIP197_MST_CTRL_TX_MAX_CMD(5); + writel(val, EIP197_HIA_AIC(priv) + EIP197_HIA_MST_CTRL); + } ++ /* ++ * Set maximum number of TX commands to 2^4 = 16 for EIP97 HW2.1/HW2.3 ++ */ ++ else { ++ val = 0; ++ val |= EIP97_MST_CTRL_TX_MAX_CMD(4); ++ writel(val, EIP197_HIA_AIC(priv) + EIP197_HIA_MST_CTRL); ++ } + + /* Configure wr/rd cache values */ + writel(EIP197_MST_CTRL_RD_CACHE(RD_CACHE_4BITS) | +diff --git a/drivers/crypto/inside-secure/safexcel.h b/drivers/crypto/inside-secure/safexcel.h +index 0c79ad78d1c0..2ad691a84180 100644 +--- a/drivers/crypto/inside-secure/safexcel.h ++++ b/drivers/crypto/inside-secure/safexcel.h +@@ -315,6 +315,7 @@ + #define EIP197_MST_CTRL_RD_CACHE(n) (((n) & 0xf) << 0) + #define EIP197_MST_CTRL_WD_CACHE(n) (((n) & 0xf) << 4) + #define EIP197_MST_CTRL_TX_MAX_CMD(n) (((n) & 0xf) << 20) ++#define EIP97_MST_CTRL_TX_MAX_CMD(n) (((n) & 0xf) << 4) + #define EIP197_MST_CTRL_BYTE_SWAP BIT(24) + #define EIP197_MST_CTRL_NO_BYTE_SWAP BIT(25) + #define EIP197_MST_CTRL_BYTE_SWAP_BITS GENMASK(25, 24) +-- +2.51.0 + + +From 6048c6fc7613b02d5f9b4ea8e3c18b08e33164f9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= +Date: Mon, 3 Nov 2025 15:50:58 +0100 +Subject: [PATCH 473/517] + /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/401-crypto-fix-eip97-cache-incoherent.patch + +--- + drivers/crypto/inside-secure/safexcel.h | 3 +++ + drivers/crypto/inside-secure/safexcel_hash.c | 4 ++-- + 2 files changed, 5 insertions(+), 2 deletions(-) + +diff --git a/drivers/crypto/inside-secure/safexcel.h b/drivers/crypto/inside-secure/safexcel.h +index 2ad691a84180..c2c1773104e3 100644 +--- a/drivers/crypto/inside-secure/safexcel.h ++++ b/drivers/crypto/inside-secure/safexcel.h +@@ -743,6 +743,9 @@ struct safexcel_priv_data { + /* Priority we use for advertising our algorithms */ + #define SAFEXCEL_CRA_PRIORITY 300 + ++/* System cache line size */ ++#define SYSTEM_CACHELINE_SIZE 64 ++ + /* SM3 digest result for zero length message */ + #define EIP197_SM3_ZEROM_HASH "\x1A\xB2\x1D\x83\x55\xCF\xA1\x7F" \ + "\x8E\x61\x19\x48\x31\xE8\x1A\x8F" \ +diff --git a/drivers/crypto/inside-secure/safexcel_hash.c b/drivers/crypto/inside-secure/safexcel_hash.c +index af4b978189e5..eb640382e17b 100644 +--- a/drivers/crypto/inside-secure/safexcel_hash.c ++++ b/drivers/crypto/inside-secure/safexcel_hash.c +@@ -55,9 +55,9 @@ struct safexcel_ahash_req { + u8 block_sz; /* block size, only set once */ + u8 digest_sz; /* output digest size, only set once */ + __le32 state[SHA3_512_BLOCK_SIZE / +- sizeof(__le32)] __aligned(sizeof(__le32)); ++ sizeof(__le32)] __aligned(SYSTEM_CACHELINE_SIZE); + +- u64 len; ++ u64 len __aligned(SYSTEM_CACHELINE_SIZE); + u64 processed; + + u8 cache[HASH_CACHE_SIZE] __aligned(sizeof(u32)); +-- +2.51.0 + + +From a97801fc420b739ae5139abf71e1016a1f09e646 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= +Date: Mon, 3 Nov 2025 15:50:59 +0100 +Subject: [PATCH 474/517] + /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/410-bt-mtk-serial-fix.patch + +--- + drivers/tty/serial/8250/8250.h | 1 + + drivers/tty/serial/8250/8250_port.c | 7 ++++++- + 2 files changed, 7 insertions(+), 1 deletion(-) + +diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h +index 10a706fe4b24..927a286d185a 100644 +--- a/drivers/tty/serial/8250/8250.h ++++ b/drivers/tty/serial/8250/8250.h +@@ -86,6 +86,7 @@ struct serial8250_config { + * STOP PARITY EPAR SPAR WLEN5 WLEN6 + */ + #define UART_CAP_NOTEMT BIT(18) /* UART without interrupt on TEMT available */ ++#define UART_CAP_NMOD BIT(19) /* UART doesn't do termios */ + + #define UART_BUG_QUOT BIT(0) /* UART has buggy quot LSB */ + #define UART_BUG_TXEN BIT(1) /* UART has buggy TX IIR status */ +diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c +index 03aca7eaca16..6005f78838e8 100644 +--- a/drivers/tty/serial/8250/8250_port.c ++++ b/drivers/tty/serial/8250/8250_port.c +@@ -276,7 +276,7 @@ static const struct serial8250_config uart_config[] = { + .tx_loadsz = 16, + .fcr = UART_FCR_ENABLE_FIFO | + UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT, +- .flags = UART_CAP_FIFO, ++ .flags = UART_CAP_FIFO | UART_CAP_NMOD, + }, + [PORT_NPCM] = { + .name = "Nuvoton 16550", +@@ -2729,6 +2729,11 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, + unsigned long flags; + unsigned int baud, quot, frac = 0; + ++ if (up->capabilities & UART_CAP_NMOD) { ++ termios->c_cflag = 0; ++ return; ++ } ++ + if (up->capabilities & UART_CAP_MINI) { + termios->c_cflag &= ~(CSTOPB | PARENB | PARODD | CMSPAR); + if ((termios->c_cflag & CSIZE) == CS5 || +-- +2.51.0 + + +From 4711a23773c1c01b04b8c28af3dd375e28e0c5a2 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= +Date: Mon, 3 Nov 2025 15:50:59 +0100 +Subject: [PATCH 475/517] + /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/411-mtd-spinand-fix-support-for-FORESEE.patch + +--- + drivers/mtd/nand/spi/foresee.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/mtd/nand/spi/foresee.c b/drivers/mtd/nand/spi/foresee.c +index 8a01582c0f53..f762d514a362 100644 +--- a/drivers/mtd/nand/spi/foresee.c ++++ b/drivers/mtd/nand/spi/foresee.c +@@ -22,8 +22,8 @@ static SPINAND_OP_VARIANTS(write_cache_variants, + SPINAND_PROG_LOAD(true, 0, NULL, 0)); + + static SPINAND_OP_VARIANTS(update_cache_variants, +- SPINAND_PROG_LOAD_X4(false, 0, NULL, 0), +- SPINAND_PROG_LOAD(false, 0, NULL, 0)); ++ SPINAND_PROG_LOAD_X4(true, 0, NULL, 0), ++ SPINAND_PROG_LOAD(true, 0, NULL, 0)); + + static int f35sqa002g_ooblayout_ecc(struct mtd_info *mtd, int section, + struct mtd_oob_region *region) +-- +2.51.0 + + +From a40812a662070cc3134ec9bd21e5ca0bb42bd872 Mon Sep 17 00:00:00 2001 +From: "SkyLake.Huang" +Date: Thu, 23 Jun 2022 18:29:51 +0800 +Subject: [PATCH 476/517] drivers: spi-mt65xx: Move chip_config to driver's + private data + +Signed-off-by: SkyLake.Huang +--- + drivers/spi/spi-mt65xx.c | 29 +++++++++--------------- + include/linux/platform_data/spi-mt65xx.h | 17 -------------- + 2 files changed, 11 insertions(+), 35 deletions(-) + delete mode 100644 include/linux/platform_data/spi-mt65xx.h + +diff --git a/drivers/spi/spi-mt65xx.c b/drivers/spi/spi-mt65xx.c +index dfee244fc317..6830325cab71 100644 +--- a/drivers/spi/spi-mt65xx.c ++++ b/drivers/spi/spi-mt65xx.c +@@ -15,7 +15,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -172,6 +171,8 @@ struct mtk_spi { + struct device *dev; + dma_addr_t tx_dma; + dma_addr_t rx_dma; ++ u32 sample_sel; ++ u32 get_tick_dly; + }; + + static const struct mtk_spi_compatible mtk_common_compat; +@@ -217,15 +218,6 @@ static const struct mtk_spi_compatible mt6893_compat = { + .no_need_unprepare = true, + }; + +-/* +- * A piece of default chip info unless the platform +- * supplies it. +- */ +-static const struct mtk_chip_config mtk_default_chip_info = { +- .sample_sel = 0, +- .tick_delay = 0, +-}; +- + static const struct of_device_id mtk_spi_of_match[] = { + { .compatible = "mediatek,spi-ipm", + .data = (void *)&mtk_ipm_compat, +@@ -353,7 +345,6 @@ static int mtk_spi_hw_init(struct spi_controller *host, + { + u16 cpha, cpol; + u32 reg_val; +- struct mtk_chip_config *chip_config = spi->controller_data; + struct mtk_spi *mdata = spi_controller_get_devdata(host); + + cpha = spi->mode & SPI_CPHA ? 1 : 0; +@@ -403,7 +394,7 @@ static int mtk_spi_hw_init(struct spi_controller *host, + else + reg_val &= ~SPI_CMD_CS_POL; + +- if (chip_config->sample_sel) ++ if (mdata->sample_sel) + reg_val |= SPI_CMD_SAMPLE_SEL; + else + reg_val &= ~SPI_CMD_SAMPLE_SEL; +@@ -430,20 +421,20 @@ static int mtk_spi_hw_init(struct spi_controller *host, + if (mdata->dev_comp->ipm_design) { + reg_val = readl(mdata->base + SPI_CMD_REG); + reg_val &= ~SPI_CMD_IPM_GET_TICKDLY_MASK; +- reg_val |= ((chip_config->tick_delay & 0x7) ++ reg_val |= ((mdata->get_tick_dly & 0x7) + << SPI_CMD_IPM_GET_TICKDLY_OFFSET); + writel(reg_val, mdata->base + SPI_CMD_REG); + } else { + reg_val = readl(mdata->base + SPI_CFG1_REG); + reg_val &= ~SPI_CFG1_GET_TICK_DLY_MASK; +- reg_val |= ((chip_config->tick_delay & 0x7) ++ reg_val |= ((mdata->get_tick_dly & 0x7) + << SPI_CFG1_GET_TICK_DLY_OFFSET); + writel(reg_val, mdata->base + SPI_CFG1_REG); + } + } else { + reg_val = readl(mdata->base + SPI_CFG1_REG); + reg_val &= ~SPI_CFG1_GET_TICK_DLY_MASK_V1; +- reg_val |= ((chip_config->tick_delay & 0x3) ++ reg_val |= ((mdata->get_tick_dly & 0x3) + << SPI_CFG1_GET_TICK_DLY_OFFSET_V1); + writel(reg_val, mdata->base + SPI_CFG1_REG); + } +@@ -733,9 +724,6 @@ static int mtk_spi_setup(struct spi_device *spi) + { + struct mtk_spi *mdata = spi_controller_get_devdata(spi->controller); + +- if (!spi->controller_data) +- spi->controller_data = (void *)&mtk_default_chip_info; +- + if (mdata->dev_comp->need_pad_sel && spi_get_csgpiod(spi, 0)) + /* CS de-asserted, gpiolib will handle inversion */ + gpiod_direction_output(spi_get_csgpiod(spi, 0), 0); +@@ -1146,6 +1134,11 @@ static int mtk_spi_probe(struct platform_device *pdev) + host->use_gpio_descriptors = true; + + mdata = spi_controller_get_devdata(host); ++ ++ /* Set device configs to default first. Calibrate it later. */ ++ mdata->sample_sel = 0; ++ mdata->get_tick_dly = 2; ++ + mdata->dev_comp = device_get_match_data(dev); + + if (mdata->dev_comp->enhance_timing) +diff --git a/include/linux/platform_data/spi-mt65xx.h b/include/linux/platform_data/spi-mt65xx.h +deleted file mode 100644 +index f0db674f07b8..000000000000 +--- a/include/linux/platform_data/spi-mt65xx.h ++++ /dev/null +@@ -1,17 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0-only */ +-/* +- * MTK SPI bus driver definitions +- * +- * Copyright (c) 2015 MediaTek Inc. +- * Author: Leilk Liu +- */ +- +-#ifndef ____LINUX_PLATFORM_DATA_SPI_MTK_H +-#define ____LINUX_PLATFORM_DATA_SPI_MTK_H +- +-/* Board specific platform_data */ +-struct mtk_chip_config { +- u32 sample_sel; +- u32 tick_delay; +-}; +-#endif +-- +2.51.0 + + +From 5d3efaf4850193f1e68e7cba13464ff909cbbb10 Mon Sep 17 00:00:00 2001 +From: "SkyLake.Huang" +Date: Thu, 23 Jun 2022 18:35:52 +0800 +Subject: [PATCH 477/517] drivers: spi: Add support for dynamic calibration + +Signed-off-by: SkyLake.Huang +--- + drivers/spi/spi.c | 137 ++++++++++++++++++++++++++++++++++++++++ + include/linux/spi/spi.h | 42 ++++++++++++ + 2 files changed, 179 insertions(+) + +diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c +index 5ad9f4a2148f..8d5144801178 100644 +--- a/drivers/spi/spi.c ++++ b/drivers/spi/spi.c +@@ -1494,6 +1494,70 @@ static int spi_transfer_wait(struct spi_controller *ctlr, + return 0; + } + ++int spi_do_calibration(struct spi_controller *ctlr, struct spi_device *spi, ++ int (*cal_read)(void *priv, u32 *addr, int addrlen, u8 *buf, int readlen), void *drv_priv) ++{ ++ int datalen = ctlr->cal_rule->datalen; ++ int addrlen = ctlr->cal_rule->addrlen; ++ u8 *buf; ++ int ret; ++ int i; ++ struct list_head *cal_head, *listptr; ++ struct spi_cal_target *target; ++ ++ /* Calculate calibration result */ ++ int hit_val, total_hit, origin; ++ bool hit; ++ ++ /* Make sure we can start calibration */ ++ if(!ctlr->cal_target || !ctlr->cal_rule || !ctlr->append_caldata) ++ return 0; ++ ++ buf = kzalloc(datalen * sizeof(u8), GFP_KERNEL); ++ if(!buf) ++ return -ENOMEM; ++ ++ ret = ctlr->append_caldata(ctlr); ++ if (ret) ++ goto cal_end; ++ ++ cal_head = ctlr->cal_target; ++ list_for_each(listptr, cal_head) { ++ target = list_entry(listptr, struct spi_cal_target, list); ++ ++ hit = false; ++ hit_val = 0; ++ total_hit = 0; ++ origin = *target->cal_item; ++ ++ for(i=target->cal_min; i<=target->cal_max; i+=target->step) { ++ *target->cal_item = i; ++ ret = (*cal_read)(drv_priv, ctlr->cal_rule->addr, addrlen, buf, datalen); ++ if(ret) ++ break; ++ dev_dbg(&spi->dev, "controller cal item value: 0x%x\n", i); ++ if(memcmp(ctlr->cal_rule->match_data, buf, datalen * sizeof(u8)) == 0) { ++ hit = true; ++ hit_val += i; ++ total_hit++; ++ dev_dbg(&spi->dev, "golden data matches data read!\n"); ++ } ++ } ++ if(hit) { ++ *target->cal_item = DIV_ROUND_CLOSEST(hit_val, total_hit); ++ dev_info(&spi->dev, "calibration result: 0x%x", *target->cal_item); ++ } else { ++ *target->cal_item = origin; ++ dev_warn(&spi->dev, "calibration failed, fallback to default: 0x%x", origin); ++ } ++ } ++ ++cal_end: ++ kfree(buf); ++ return ret? ret: 0; ++} ++EXPORT_SYMBOL_GPL(spi_do_calibration); ++ + static void _spi_transfer_delay_ns(u32 ns) + { + if (!ns) +@@ -2352,6 +2416,75 @@ void spi_flush_queue(struct spi_controller *ctlr) + /*-------------------------------------------------------------------------*/ + + #if defined(CONFIG_OF) ++static inline void alloc_cal_data(struct list_head **cal_target, ++ struct spi_cal_rule **cal_rule, bool enable) ++{ ++ if(enable) { ++ *cal_target = kmalloc(sizeof(struct list_head), GFP_KERNEL); ++ INIT_LIST_HEAD(*cal_target); ++ *cal_rule = kmalloc(sizeof(struct spi_cal_rule), GFP_KERNEL); ++ } else { ++ kfree(*cal_target); ++ kfree(*cal_rule); ++ } ++} ++ ++static int of_spi_parse_cal_dt(struct spi_controller *ctlr, struct spi_device *spi, ++ struct device_node *nc) ++{ ++ u32 value; ++ int rc; ++ const char *cal_mode; ++ ++ rc = of_property_read_bool(nc, "spi-cal-enable"); ++ if (rc) ++ alloc_cal_data(&ctlr->cal_target, &ctlr->cal_rule, true); ++ else ++ return 0; ++ ++ rc = of_property_read_string(nc, "spi-cal-mode", &cal_mode); ++ if(!rc) { ++ if(strcmp("read-data", cal_mode) == 0){ ++ ctlr->cal_rule->mode = SPI_CAL_READ_DATA; ++ } else if(strcmp("read-pp", cal_mode) == 0) { ++ ctlr->cal_rule->mode = SPI_CAL_READ_PP; ++ return 0; ++ } else if(strcmp("read-sfdp", cal_mode) == 0){ ++ ctlr->cal_rule->mode = SPI_CAL_READ_SFDP; ++ return 0; ++ } ++ } else ++ goto err; ++ ++ ctlr->cal_rule->datalen = 0; ++ rc = of_property_read_u32(nc, "spi-cal-datalen", &value); ++ if(!rc && value > 0) { ++ ctlr->cal_rule->datalen = value; ++ ++ ctlr->cal_rule->match_data = kzalloc(value * sizeof(u8), GFP_KERNEL); ++ rc = of_property_read_u8_array(nc, "spi-cal-data", ++ ctlr->cal_rule->match_data, value); ++ if(rc) ++ kfree(ctlr->cal_rule->match_data); ++ } ++ ++ rc = of_property_read_u32(nc, "spi-cal-addrlen", &value); ++ if(!rc && value > 0) { ++ ctlr->cal_rule->addrlen = value; ++ ++ ctlr->cal_rule->addr = kzalloc(value * sizeof(u32), GFP_KERNEL); ++ rc = of_property_read_u32_array(nc, "spi-cal-addr", ++ ctlr->cal_rule->addr, value); ++ if(rc) ++ kfree(ctlr->cal_rule->addr); ++ } ++ return 0; ++ ++err: ++ alloc_cal_data(&ctlr->cal_target, &ctlr->cal_rule, false); ++ return 0; ++} ++ + static void of_spi_parse_dt_cs_delay(struct device_node *nc, + struct spi_delay *delay, const char *prop) + { +@@ -2516,6 +2649,10 @@ of_register_spi_device(struct spi_controller *ctlr, struct device_node *nc) + if (rc) + goto err_out; + ++ rc = of_spi_parse_cal_dt(ctlr, spi, nc); ++ if (rc) ++ goto err_out; ++ + /* Store a pointer to the node in the device structure */ + of_node_get(nc); + +diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h +index 71ad766932d3..9ccc08819613 100644 +--- a/include/linux/spi/spi.h ++++ b/include/linux/spi/spi.h +@@ -348,6 +348,40 @@ struct spi_driver { + struct device_driver driver; + }; + ++enum { ++ SPI_CAL_READ_DATA = 0, ++ SPI_CAL_READ_PP = 1, /* only for SPI-NAND */ ++ SPI_CAL_READ_SFDP = 2, /* only for SPI-NOR */ ++}; ++ ++struct nand_addr { ++ unsigned int lun; ++ unsigned int plane; ++ unsigned int eraseblock; ++ unsigned int page; ++ unsigned int dataoffs; ++}; ++ ++/** ++ * Read calibration rule from device dts node. ++ * Once calibration result matches the rule, we regard is as success. ++ */ ++struct spi_cal_rule { ++ int datalen; ++ u8 *match_data; ++ int addrlen; ++ u32 *addr; ++ int mode; ++}; ++ ++struct spi_cal_target { ++ u32 *cal_item; ++ int cal_min; /* min of cal_item */ ++ int cal_max; /* max of cal_item */ ++ int step; /* Increase/decrease cal_item */ ++ struct list_head list; ++}; ++ + #define to_spi_driver(__drv) \ + ( __drv ? container_of_const(__drv, struct spi_driver, driver) : NULL ) + +@@ -754,6 +788,11 @@ struct spi_controller { + void *dummy_rx; + void *dummy_tx; + ++ /* For calibration */ ++ int (*append_caldata)(struct spi_controller *ctlr); ++ struct list_head *cal_target; ++ struct spi_cal_rule *cal_rule; ++ + int (*fw_translate_cs)(struct spi_controller *ctlr, unsigned cs); + + /* +@@ -1657,6 +1696,9 @@ spi_register_board_info(struct spi_board_info const *info, unsigned n) + { return 0; } + #endif + ++extern int spi_do_calibration(struct spi_controller *ctlr, ++ struct spi_device *spi, int (*cal_read)(void *, u32 *, int, u8 *, int), void *drv_priv); ++ + /* + * If you're hotplugging an adapter with devices (parport, USB, etc) + * use spi_new_device() to describe each device. You can also call +-- +2.51.0 + + +From 98ba0b15846cc6f0664d651a42a650cf5af8ce71 Mon Sep 17 00:00:00 2001 +From: "SkyLake.Huang" +Date: Thu, 23 Jun 2022 18:37:55 +0800 +Subject: [PATCH 478/517] drivers: spi-mem: Add spi calibration hook + +Signed-off-by: SkyLake.Huang +--- + drivers/spi/spi-mem.c | 8 ++++++++ + include/linux/spi/spi-mem.h | 4 ++++ + 2 files changed, 12 insertions(+) + +diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c +index 17b8baf749e6..597e6157d051 100644 +--- a/drivers/spi/spi-mem.c ++++ b/drivers/spi/spi-mem.c +@@ -466,6 +466,14 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) + } + EXPORT_SYMBOL_GPL(spi_mem_exec_op); + ++int spi_mem_do_calibration(struct spi_mem *mem, ++ int (*cal_read)(void *priv, u32 *addr, int addrlen, u8 *buf, int readlen), ++ void *priv) ++{ ++ return spi_do_calibration(mem->spi->controller, mem->spi, cal_read, priv); ++} ++EXPORT_SYMBOL_GPL(spi_mem_do_calibration); ++ + /** + * spi_mem_get_name() - Return the SPI mem device name to be used by the + * upper layer if necessary +diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h +index f866d5c8ed32..821ab7055640 100644 +--- a/include/linux/spi/spi-mem.h ++++ b/include/linux/spi/spi-mem.h +@@ -372,6 +372,10 @@ bool spi_mem_supports_op(struct spi_mem *mem, + int spi_mem_exec_op(struct spi_mem *mem, + const struct spi_mem_op *op); + ++int spi_mem_do_calibration(struct spi_mem *mem, ++ int (*cal_read)(void *, u32 *, int, u8 *, int), ++ void *priv); ++ + const char *spi_mem_get_name(struct spi_mem *mem); + + struct spi_mem_dirmap_desc * +-- +2.51.0 + + +From 4471f9130681170008741e9988d8a96767a3b5ba Mon Sep 17 00:00:00 2001 +From: "SkyLake.Huang" +Date: Thu, 23 Jun 2022 18:39:03 +0800 +Subject: [PATCH 479/517] drivers: spi-mt65xx: Add controller's calibration + paramter + +Signed-off-by: SkyLake.Huang +--- + drivers/spi/spi-mt65xx.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/drivers/spi/spi-mt65xx.c b/drivers/spi/spi-mt65xx.c +index 6830325cab71..906e188987c8 100644 +--- a/drivers/spi/spi-mt65xx.c ++++ b/drivers/spi/spi-mt65xx.c +@@ -842,6 +842,21 @@ static irqreturn_t mtk_spi_interrupt(int irq, void *dev_id) + return IRQ_WAKE_THREAD; + } + ++static int mtk_spi_append_caldata(struct spi_controller *ctlr) ++{ ++ struct spi_cal_target *cal_target = kmalloc(sizeof(*cal_target), GFP_KERNEL); ++ struct mtk_spi *mdata = spi_controller_get_devdata(ctlr); ++ ++ cal_target->cal_item = &mdata->get_tick_dly; ++ cal_target->cal_min = 0; ++ cal_target->cal_max = 7; ++ cal_target->step = 1; ++ ++ list_add(&cal_target->list, ctlr->cal_target); ++ ++ return 0; ++} ++ + static int mtk_spi_mem_adjust_op_size(struct spi_mem *mem, + struct spi_mem_op *op) + { +@@ -1132,6 +1147,7 @@ static int mtk_spi_probe(struct platform_device *pdev) + host->setup = mtk_spi_setup; + host->set_cs_timing = mtk_spi_set_hw_cs_timing; + host->use_gpio_descriptors = true; ++ host->append_caldata = mtk_spi_append_caldata; + + mdata = spi_controller_get_devdata(host); + +-- +2.51.0 + + +From 12093e201819865a1a75fad0932a37f7213f0195 Mon Sep 17 00:00:00 2001 +From: "SkyLake.Huang" +Date: Thu, 23 Jun 2022 18:39:56 +0800 +Subject: [PATCH 480/517] drivers: mtd: spinand: Add calibration support for + spinand + +Signed-off-by: SkyLake.Huang +--- + drivers/mtd/nand/spi/core.c | 54 +++++++++++++++++++++++++++++++++++++ + 1 file changed, 54 insertions(+) + +diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c +index d0071aba4f77..ed8a2d2b2dd2 100644 +--- a/drivers/mtd/nand/spi/core.c ++++ b/drivers/mtd/nand/spi/core.c +@@ -1200,6 +1200,56 @@ static int spinand_manufacturer_match(struct spinand_device *spinand, + return -EOPNOTSUPP; + } + ++static int spinand_cal_read(void *priv, u32 *addr, int addrlen, u8 *buf, int readlen) { ++ struct spinand_device *spinand = (struct spinand_device *)priv; ++ struct device *dev = &spinand->spimem->spi->dev; ++ struct spi_mem_op op = SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, buf, readlen); ++ struct nand_pos pos; ++ struct nand_page_io_req req; ++ u8 status; ++ int ret; ++ ++ if(addrlen != sizeof(struct nand_addr)/sizeof(unsigned int)) { ++ dev_err(dev, "Must provide correct addr(length) for spinand calibration\n"); ++ return -EINVAL; ++ } ++ ++ ret = spinand_reset_op(spinand); ++ if (ret) ++ return ret; ++ ++ /* We should store our golden data in first target because ++ * we can't switch target at this moment. ++ */ ++ pos = (struct nand_pos){ ++ .target = 0, ++ .lun = *addr, ++ .plane = *(addr+1), ++ .eraseblock = *(addr+2), ++ .page = *(addr+3), ++ }; ++ ++ req = (struct nand_page_io_req){ ++ .pos = pos, ++ .dataoffs = *(addr+4), ++ .datalen = readlen, ++ .databuf.in = buf, ++ .mode = MTD_OPS_AUTO_OOB, ++ }; ++ ++ ret = spinand_load_page_op(spinand, &req); ++ if (ret) ++ return ret; ++ ++ ret = spinand_wait(spinand, &status); ++ if (ret < 0) ++ return ret; ++ ++ ret = spi_mem_exec_op(spinand->spimem, &op); ++ ++ return 0; ++} ++ + static int spinand_id_detect(struct spinand_device *spinand) + { + u8 *id = spinand->id.data; +@@ -1451,6 +1501,10 @@ static int spinand_init(struct spinand_device *spinand) + if (!spinand->scratchbuf) + return -ENOMEM; + ++ ret = spi_mem_do_calibration(spinand->spimem, spinand_cal_read, spinand); ++ if (ret) ++ dev_err(dev, "Failed to calibrate SPI-NAND (err = %d)\n", ret); ++ + ret = spinand_detect(spinand); + if (ret) + goto err_free_bufs; +-- +2.51.0 + + +From 4041e34414c85a3f4bbfd292b255cce4eb722b49 Mon Sep 17 00:00:00 2001 +From: "SkyLake.Huang" +Date: Thu, 23 Jun 2022 18:40:59 +0800 +Subject: [PATCH 481/517] drivers: mtd: spi-nor: Add calibration support for + spi-nor + +Signed-off-by: SkyLake.Huang +--- + drivers/mtd/nand/spi/core.c | 5 ++++- + drivers/mtd/spi-nor/core.c | 15 +++++++++++++++ + 2 files changed, 19 insertions(+), 1 deletion(-) + +diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c +index ed8a2d2b2dd2..a74bda5c4965 100644 +--- a/drivers/mtd/nand/spi/core.c ++++ b/drivers/mtd/nand/spi/core.c +@@ -1241,7 +1241,10 @@ static int spinand_cal_read(void *priv, u32 *addr, int addrlen, u8 *buf, int rea + if (ret) + return ret; + +- ret = spinand_wait(spinand, &status); ++ ret = spinand_wait(spinand, ++ SPINAND_READ_INITIAL_DELAY_US, ++ SPINAND_READ_POLL_DELAY_US, ++ &status); + if (ret < 0) + return ret; + +diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c +index 5bb7da0ef34d..de146408e605 100644 +--- a/drivers/mtd/spi-nor/core.c ++++ b/drivers/mtd/spi-nor/core.c +@@ -3300,6 +3300,18 @@ static const struct flash_info *spi_nor_match_name(struct spi_nor *nor, + return NULL; + } + ++static int spi_nor_cal_read(void *priv, u32 *addr, int addrlen, u8 *buf, int readlen) ++{ ++ struct spi_nor *nor = (struct spi_nor *)priv; ++ ++ nor->reg_proto = SNOR_PROTO_1_1_1; ++ nor->read_proto = SNOR_PROTO_1_1_1; ++ nor->read_opcode = SPINOR_OP_READ; ++ nor->read_dummy = 0; ++ ++ return nor->controller_ops->read(nor, *addr, readlen, buf); ++} ++ + static const struct flash_info *spi_nor_get_flash_info(struct spi_nor *nor, + const char *name) + { +@@ -3474,6 +3486,9 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, + if (ret) + return ret; + ++ if(nor->spimem) ++ spi_mem_do_calibration(nor->spimem, spi_nor_cal_read, nor); ++ + info = spi_nor_get_flash_info(nor, name); + if (IS_ERR(info)) + return PTR_ERR(info); +-- +2.51.0 + + +From 989bc477ae72c09f5068823fd74d038b4219c6f2 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Wed, 12 Jul 2023 13:38:35 +0100 +Subject: [PATCH 482/517] nvmem: add layout for Adtran devices + +Adtran stores unique factory data on GPT partitions on the eMMC. +Using blk-nvmem the 'mfginfo' partition gets exposes as NVMEM provider. + +Add layout driver to parse mfginfo, mainly to provide MAC addresses to +Ethernet and wireless interfaces. + +Variable names are converted to lower-case and '_' is replaced with '-' +in order to comply with the device tree node naming convention. +The main MAC address always ends on a 0 and up to 16 addresses are +alocated for each device to use for various interfaces. + +Implement post-processing function for 'MFG_MAC' variable ('mfg-mac' +node name in device tree) adding the nvmem cell index to the least +significant digit of the MAC address. + +Signed-off-by: Daniel Golle +--- + drivers/nvmem/layouts/Kconfig | 9 +++ + drivers/nvmem/layouts/Makefile | 1 + + drivers/nvmem/layouts/adtran.c | 135 +++++++++++++++++++++++++++++++++ + 3 files changed, 145 insertions(+) + create mode 100644 drivers/nvmem/layouts/adtran.c + +diff --git a/drivers/nvmem/layouts/Kconfig b/drivers/nvmem/layouts/Kconfig +index 58df4ad61e13..3b8ef65629b7 100644 +--- a/drivers/nvmem/layouts/Kconfig ++++ b/drivers/nvmem/layouts/Kconfig +@@ -8,6 +8,15 @@ if NVMEM_LAYOUTS + + menu "Layout Types" + ++config NVMEM_LAYOUT_ADTRAN ++ tristate "Adtran mfginfo layout support" ++ select GENERIC_NET_UTILS ++ help ++ Say Y here if you want to support the layout used by Adtran for ++ mfginfo. ++ ++ If unsure, say N. ++ + config NVMEM_LAYOUT_SL28_VPD + tristate "Kontron sl28 VPD layout support" + select CRC8 +diff --git a/drivers/nvmem/layouts/Makefile b/drivers/nvmem/layouts/Makefile +index 060ddf18d05a..75902980e89a 100644 +--- a/drivers/nvmem/layouts/Makefile ++++ b/drivers/nvmem/layouts/Makefile +@@ -6,4 +6,5 @@ + obj-$(CONFIG_NVMEM_LAYOUT_SL28_VPD) += sl28vpd.o + obj-$(CONFIG_NVMEM_LAYOUT_ONIE_TLV) += onie-tlv.o + obj-$(CONFIG_NVMEM_LAYOUT_U_BOOT_ENV) += u-boot-env.o ++obj-$(CONFIG_NVMEM_LAYOUT_ADTRAN) += adtran.o + obj-$(CONFIG_NVMEM_LAYOUT_ASCII_ENV) += ascii-env.o +diff --git a/drivers/nvmem/layouts/adtran.c b/drivers/nvmem/layouts/adtran.c +new file mode 100644 +index 000000000000..65f55f413917 +--- /dev/null ++++ b/drivers/nvmem/layouts/adtran.c +@@ -0,0 +1,135 @@ ++// SPDX-License-Identifier: GPL-2.0 ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * Adtran devices usually come with a main MAC address ending on 0 and ++ * hence may have up to 16 MAC addresses per device. ++ * The main MAC address is stored as variable MFG_MAC in ASCII format. ++ */ ++static int adtran_mac_address_pp(void *priv, const char *id, int index, ++ unsigned int offset, void *buf, ++ size_t bytes) ++{ ++ u8 mac[ETH_ALEN]; ++ ++ if (WARN_ON(bytes != 3 * ETH_ALEN - 1)) ++ return -EINVAL; ++ ++ if (!mac_pton(buf, mac)) ++ return -EINVAL; ++ ++ if (index) ++ eth_addr_add(mac, index); ++ ++ ether_addr_copy(buf, mac); ++ ++ return 0; ++} ++ ++static int adtran_add_cells(struct nvmem_layout *layout) ++{ ++ struct nvmem_device *nvmem = layout->nvmem; ++ struct nvmem_cell_info info; ++ struct device_node *layout_np; ++ char mfginfo[1024], *c, *t, *p; ++ int ret = -EINVAL; ++ ++ ret = nvmem_device_read(nvmem, 0, sizeof(mfginfo), mfginfo); ++ if (ret < 0) ++ return ret; ++ else if (ret != sizeof(mfginfo)) ++ return -EIO; ++ ++ layout_np = of_nvmem_layout_get_container(nvmem); ++ if (!layout_np) ++ return -ENOENT; ++ ++ c = mfginfo; ++ while (*c != 0xff) { ++ memset(&info, 0, sizeof(info)); ++ if (*c == '#') ++ goto nextline; ++ ++ t = strchr(c, '='); ++ if (!t) ++ goto nextline; ++ ++ *t = '\0'; ++ ++t; ++ info.offset = t - mfginfo; ++ /* process variable name: convert to lower-case, '_' -> '-' */ ++ p = c; ++ do { ++ *p = tolower(*p); ++ if (*p == '_') ++ *p = '-'; ++ } while (*++p); ++ info.name = c; ++ c = strchr(t, 0xa); /* find newline */ ++ if (!c) ++ break; ++ ++ info.bytes = c - t; ++ if (!strcmp(info.name, "mfg-mac")) { ++ info.raw_len = info.bytes; ++ info.bytes = ETH_ALEN; ++ info.read_post_process = adtran_mac_address_pp; ++ } ++ ++ info.np = of_get_child_by_name(layout_np, info.name); ++ ret = nvmem_add_one_cell(nvmem, &info); ++ if (ret) ++ break; ++ ++ ++c; ++ continue; ++ ++nextline: ++ c = strchr(c, 0xa); /* find newline */ ++ if (!c) ++ break; ++ ++c; ++ } ++ ++ of_node_put(layout_np); ++ ++ return ret; ++} ++ ++static int adtran_probe(struct nvmem_layout *layout) ++{ ++ layout->add_cells = adtran_add_cells; ++ ++ return nvmem_layout_register(layout); ++} ++ ++static void adtran_remove(struct nvmem_layout *layout) ++{ ++ nvmem_layout_unregister(layout); ++} ++ ++static const struct of_device_id adtran_of_match_table[] = { ++ { .compatible = "adtran,mfginfo" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, adtran_of_match_table); ++ ++static struct nvmem_layout_driver adtran_layout = { ++ .driver = { ++ .owner = THIS_MODULE, ++ .name = "adtran-layout", ++ .of_match_table = adtran_of_match_table, ++ }, ++ .probe = adtran_probe, ++ .remove = adtran_remove, ++}; ++module_nvmem_layout_driver(adtran_layout); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Daniel Golle "); ++MODULE_DESCRIPTION("NVMEM layout driver for Adtran mfginfo"); +-- +2.51.0 + + +From 21831b4ae092e1a34c89accb466796f284aecccd Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= +Date: Mon, 3 Nov 2025 15:51:02 +0100 +Subject: [PATCH 483/517] + /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/500-gsw-rtl8367s-mt7622-support.patch + +--- + drivers/net/phy/Kconfig | 6 ++++++ + drivers/net/phy/Makefile | 1 + + 2 files changed, 7 insertions(+) + +diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig +index 0e672540a0fa..2fcb9544a3b0 100644 +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -443,6 +443,12 @@ config ROCKCHIP_PHY + help + Currently supports the integrated Ethernet PHY. + ++config RTL8367S_GSW ++ tristate "rtl8367 Gigabit Switch support for mt7622" ++ depends on NET_VENDOR_MEDIATEK ++ help ++ This driver supports rtl8367s in mt7622 ++ + config SMSC_PHY + tristate "SMSC PHYs" + select CRC16 +diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile +index d0f2b36d5c87..f869dd4a7ff4 100644 +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -113,6 +113,7 @@ obj-$(CONFIG_REALTEK_PHY) += realtek/ + obj-y += rtl8261n/ + obj-$(CONFIG_RENESAS_PHY) += uPD60620.o + obj-$(CONFIG_ROCKCHIP_PHY) += rockchip.o ++obj-$(CONFIG_RTL8367S_GSW) += rtk/ + obj-$(CONFIG_SMSC_PHY) += smsc.o + obj-$(CONFIG_STE10XP) += ste10Xp.o + obj-$(CONFIG_TERANETICS_PHY) += teranetics.o +-- +2.51.0 + + +From 3e406f4731e75b7970b37050aacbeba4dec6adbc Mon Sep 17 00:00:00 2001 +From: qizhong cheng +Date: Mon, 27 Dec 2021 21:31:10 +0800 +Subject: [PATCH 484/517] PCI: mediatek: Assert PERST# for 100ms for power and + clock to stabilize +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Described in PCIe CEM specification sections 2.2 (PERST# Signal) and +2.2.1 (Initial Power-Up (G3 to S0)). The deassertion of PERST# should +be delayed 100ms (TPVPERL) for the power and clock to become stable. + +Link: https://lore.kernel.org/r/20211227133110.14500-1-qizhong.cheng@mediatek.com +Signed-off-by: qizhong cheng +Signed-off-by: Lorenzo Pieralisi +Acked-by: Pali Rohár +--- + drivers/pci/controller/pcie-mediatek.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/pci/controller/pcie-mediatek.c b/drivers/pci/controller/pcie-mediatek.c +index 7f7d04c2ea57..bebad5744f6a 100644 +--- a/drivers/pci/controller/pcie-mediatek.c ++++ b/drivers/pci/controller/pcie-mediatek.c +@@ -700,6 +700,13 @@ static int mtk_pcie_startup_port_v2(struct mtk_pcie_port *port) + */ + msleep(100); + ++ /* ++ * Described in PCIe CEM specification sections 2.2 (PERST# Signal) and ++ * 2.2.1 (Initial Power-Up (G3 to S0)). The deassertion of PERST# should ++ * be delayed 100ms (TPVPERL) for the power and clock to become stable. ++ */ ++ msleep(100); ++ + /* De-assert PHY, PE, PIPE, MAC and configuration reset */ + val = readl(port->base + PCIE_RST_CTRL); + val |= PCIE_PHY_RSTB | PCIE_PERSTB | PCIE_PIPE_SRSTB | +-- +2.51.0 + + +From 2b9d1f47e69e82aed8f0bd2a2d90058b0e3d419d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= +Date: Mon, 3 Nov 2025 15:51:03 +0100 +Subject: [PATCH 485/517] + /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/602-arm64-dts-mediatek-add-mt7622-pcie-slot-node.patch + +--- + arch/arm64/boot/dts/mediatek/mt7622.dtsi | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7622.dtsi b/arch/arm64/boot/dts/mediatek/mt7622.dtsi +index 39c57987412e..ce802c3b22df 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi +@@ -844,6 +844,12 @@ pcie_intc0: interrupt-controller { + #address-cells = <0>; + #interrupt-cells = <1>; + }; ++ ++ slot0: pcie@0,0 { ++ reg = <0x0000 0 0 0 0>; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ }; + }; + + pcie1: pcie@1a145000 { +@@ -882,6 +888,12 @@ pcie_intc1: interrupt-controller { + #address-cells = <0>; + #interrupt-cells = <1>; + }; ++ ++ slot1: pcie@1,0 { ++ reg = <0x0800 0 0 0 0>; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ }; + }; + + sata: sata@1a200000 { +-- +2.51.0 + + +From 69fde5ab7287db38c278acdb564529d89ad28e10 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Fri, 4 Sep 2020 18:33:27 +0200 +Subject: [PATCH 486/517] pcie-mediatek: fix clearing interrupt status + +Clearing the status needs to happen after running the handler, otherwise +we will get an extra spurious interrupt after the cause has been cleared + +Signed-off-by: Felix Fietkau +--- + drivers/pci/controller/pcie-mediatek.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/pci/controller/pcie-mediatek.c b/drivers/pci/controller/pcie-mediatek.c +index bebad5744f6a..b723cdfab3a0 100644 +--- a/drivers/pci/controller/pcie-mediatek.c ++++ b/drivers/pci/controller/pcie-mediatek.c +@@ -599,9 +599,9 @@ static void mtk_pcie_intr_handler(struct irq_desc *desc) + if (status & INTX_MASK) { + for_each_set_bit_from(bit, &status, PCI_NUM_INTX + INTX_SHIFT) { + /* Clear the INTx */ +- writel(1 << bit, port->base + PCIE_INT_STATUS); + generic_handle_domain_irq(port->irq_domain, + bit - INTX_SHIFT); ++ writel(1 << bit, port->base + PCIE_INT_STATUS); + } + } + +-- +2.51.0 + + +From 02b4f75a67349d0d6d444424714f3af80ee1d8b1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= +Date: Mon, 3 Nov 2025 15:51:03 +0100 +Subject: [PATCH 487/517] + /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/611-pcie-mediatek-gen3-PERST-for-100ms.patch + +--- + drivers/pci/controller/pcie-mediatek-gen3.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/drivers/pci/controller/pcie-mediatek-gen3.c b/drivers/pci/controller/pcie-mediatek-gen3.c +index 66ce4b5d309b..ebc9f95871f9 100644 +--- a/drivers/pci/controller/pcie-mediatek-gen3.c ++++ b/drivers/pci/controller/pcie-mediatek-gen3.c +@@ -416,7 +416,13 @@ static int mtk_pcie_startup_port(struct mtk_gen3_pcie *pcie) + msleep(100); + + /* De-assert reset signals */ +- val &= ~(PCIE_MAC_RSTB | PCIE_PHY_RSTB | PCIE_BRG_RSTB | PCIE_PE_RSTB); ++ val &= ~(PCIE_MAC_RSTB | PCIE_PHY_RSTB | PCIE_BRG_RSTB); ++ writel_relaxed(val, pcie->base + PCIE_RST_CTRL_REG); ++ ++ msleep(100); ++ ++ /* De-assert PERST# signals */ ++ val &= ~(PCIE_PE_RSTB); + writel_relaxed(val, pcie->base + PCIE_RST_CTRL_REG); + + /* Check if the link is up or not */ +-- +2.51.0 + + +From c4fd81f1dc30a95d6edce67a6cbc0fa933c403b2 Mon Sep 17 00:00:00 2001 +From: Sky Huang +Date: Wed, 19 Feb 2025 16:39:08 +0800 +Subject: [PATCH 488/517] net: phy: mediatek: Add 2.5Gphy firmware dt-bindings + and dts node + +Add 2.5Gphy firmware dt-bindings and dts node since mtk-2p5ge +driver requires firmware to run. Also, update MAINTAINERS for +MediaTek's built-in 2.5Gphy dt-bindings and change MAINTAINER's name. + +Signed-off-by: Sky Huang +--- + .../bindings/net/mediatek,2p5gphy-fw.yaml | 37 +++++++++++++++++++ + MAINTAINERS | 3 +- + 2 files changed, 39 insertions(+), 1 deletion(-) + create mode 100644 Documentation/devicetree/bindings/net/mediatek,2p5gphy-fw.yaml + +diff --git a/Documentation/devicetree/bindings/net/mediatek,2p5gphy-fw.yaml b/Documentation/devicetree/bindings/net/mediatek,2p5gphy-fw.yaml +new file mode 100644 +index 000000000000..56ebe88b8921 +--- /dev/null ++++ b/Documentation/devicetree/bindings/net/mediatek,2p5gphy-fw.yaml +@@ -0,0 +1,37 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/net/mediatek,2p5gphy-fw.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: MediaTek Built-in 2.5G Ethernet PHY ++ ++maintainers: ++ - Sky Huang ++ ++description: | ++ MediaTek Built-in 2.5G Ethernet PHY needs to load firmware so it can ++ run correctly. ++ ++properties: ++ compatible: ++ const: "mediatek,2p5gphy-fw" ++ ++ reg: ++ items: ++ - description: pmb firmware load address ++ - description: firmware trigger register ++ ++required: ++ - compatible ++ - reg ++ ++additionalProperties: false ++ ++examples: ++ - | ++ phyfw: phy-firmware@f000000 { ++ compatible = "mediatek,2p5gphy-fw"; ++ reg = <0 0x0f100000 0 0x20000>, ++ <0 0x0f0f0018 0 0x20>; ++ }; +diff --git a/MAINTAINERS b/MAINTAINERS +index 3a22c29b35a6..f04fc126dd78 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -14426,9 +14426,10 @@ F: include/linux/pcs/pcs-mtk-usxgmii.h + MEDIATEK ETHERNET PHY DRIVERS + M: Daniel Golle + M: Qingfang Deng +-M: SkyLake Huang ++M: Sky Huang + L: netdev@vger.kernel.org + S: Maintained ++F: Documentation/devicetree/bindings/net/mediatek,2p5gphy-fw.yaml + F: drivers/net/phy/mediatek/mtk-ge-soc.c + F: drivers/net/phy/mediatek/mtk-phy-lib.c + F: drivers/net/phy/mediatek/mtk-ge.c +-- +2.51.0 + + +From 6b90226390bcd6d572873fe141aa5eec27f598ba Mon Sep 17 00:00:00 2001 +From: Sky Huang +Date: Wed, 19 Feb 2025 16:39:10 +0800 +Subject: [PATCH 489/517] net: phy: mediatek: add driver for built-in 2.5G + ethernet PHY on MT7988 + +Add support for internal 2.5Gphy on MT7988. This driver will load +necessary firmware and add appropriate time delay to make sure +that firmware works stably. Also, certain control registers will +be set to fix link-up issues. + +Signed-off-by: Sky Huang +--- + MAINTAINERS | 1 + + drivers/net/phy/mediatek/Kconfig | 11 + + drivers/net/phy/mediatek/Makefile | 1 + + drivers/net/phy/mediatek/mtk-2p5ge.c | 342 +++++++++++++++++++++++++++ + 4 files changed, 355 insertions(+) + create mode 100644 drivers/net/phy/mediatek/mtk-2p5ge.c + +diff --git a/MAINTAINERS b/MAINTAINERS +index f04fc126dd78..8495e72f363b 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -14430,6 +14430,7 @@ M: Sky Huang + L: netdev@vger.kernel.org + S: Maintained + F: Documentation/devicetree/bindings/net/mediatek,2p5gphy-fw.yaml ++F: drivers/net/phy/mediatek/mtk-2p5ge.c + F: drivers/net/phy/mediatek/mtk-ge-soc.c + F: drivers/net/phy/mediatek/mtk-phy-lib.c + F: drivers/net/phy/mediatek/mtk-ge.c +diff --git a/drivers/net/phy/mediatek/Kconfig b/drivers/net/phy/mediatek/Kconfig +index 4308002bb82c..6f8f69213aae 100644 +--- a/drivers/net/phy/mediatek/Kconfig ++++ b/drivers/net/phy/mediatek/Kconfig +@@ -26,3 +26,14 @@ config MEDIATEK_GE_SOC_PHY + the MT7981 and MT7988 SoCs. These PHYs need calibration data + present in the SoCs efuse and will dynamically calibrate VCM + (common-mode voltage) during startup. ++ ++config MEDIATEK_2P5GE_PHY ++ tristate "MediaTek 2.5Gb Ethernet PHYs" ++ depends on (ARM64 && ARCH_MEDIATEK) || COMPILE_TEST ++ select MTK_NET_PHYLIB ++ help ++ Supports MediaTek SoC built-in 2.5Gb Ethernet PHYs. ++ ++ This will load necessary firmware and add appropriate time delay. ++ Accelerate this procedure through internal pbus instead of MDIO ++ bus. Certain link-up issues will also be fixed here. +diff --git a/drivers/net/phy/mediatek/Makefile b/drivers/net/phy/mediatek/Makefile +index 814879d0abe5..c6db8abd2c9c 100644 +--- a/drivers/net/phy/mediatek/Makefile ++++ b/drivers/net/phy/mediatek/Makefile +@@ -2,3 +2,4 @@ + obj-$(CONFIG_MTK_NET_PHYLIB) += mtk-phy-lib.o + obj-$(CONFIG_MEDIATEK_GE_PHY) += mtk-ge.o + obj-$(CONFIG_MEDIATEK_GE_SOC_PHY) += mtk-ge-soc.o ++obj-$(CONFIG_MEDIATEK_2P5GE_PHY) += mtk-2p5ge.o +diff --git a/drivers/net/phy/mediatek/mtk-2p5ge.c b/drivers/net/phy/mediatek/mtk-2p5ge.c +new file mode 100644 +index 000000000000..9e5a0331e719 +--- /dev/null ++++ b/drivers/net/phy/mediatek/mtk-2p5ge.c +@@ -0,0 +1,342 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mtk.h" ++ ++#define MTK_2P5GPHY_ID_MT7988 (0x00339c11) ++ ++#define MT7988_2P5GE_PMB_FW "mediatek/mt7988/i2p5ge-phy-pmb.bin" ++#define MT7988_2P5GE_PMB_FW_SIZE (0x20000) ++#define MD32_EN_CFG (0x18) ++#define MD32_EN BIT(0) ++ ++#define BASE100T_STATUS_EXTEND (0x10) ++#define BASE1000T_STATUS_EXTEND (0x11) ++#define EXTEND_CTRL_AND_STATUS (0x16) ++ ++#define PHY_AUX_CTRL_STATUS (0x1d) ++#define PHY_AUX_DPX_MASK GENMASK(5, 5) ++#define PHY_AUX_SPEED_MASK GENMASK(4, 2) ++ ++/* Registers on MDIO_MMD_VEND1 */ ++#define MTK_PHY_LPI_PCS_DSP_CTRL (0x121) ++#define MTK_PHY_LPI_SIG_EN_LO_THRESH100_MASK GENMASK(12, 8) ++ ++#define MTK_PHY_HOST_CMD1 0x800e ++#define MTK_PHY_HOST_CMD2 0x800f ++/* Registers on Token Ring debug nodes */ ++/* ch_addr = 0x0, node_addr = 0xf, data_addr = 0x3c */ ++#define AUTO_NP_10XEN BIT(6) ++ ++struct mtk_i2p5ge_phy_priv { ++ bool fw_loaded; ++}; ++ ++enum { ++ PHY_AUX_SPD_10 = 0, ++ PHY_AUX_SPD_100, ++ PHY_AUX_SPD_1000, ++ PHY_AUX_SPD_2500, ++}; ++ ++static int mt798x_2p5ge_phy_load_fw(struct phy_device *phydev) ++{ ++ struct mtk_i2p5ge_phy_priv *priv = phydev->priv; ++ void __iomem *mcu_csr_base, *pmb_addr; ++ struct device *dev = &phydev->mdio.dev; ++ const struct firmware *fw; ++ struct device_node *np; ++ int ret, i; ++ u32 reg; ++ ++ np = of_find_compatible_node(NULL, NULL, "mediatek,2p5gphy-fw"); ++ if (!np) ++ return -ENOENT; ++ ++ pmb_addr = of_iomap(np, 0); ++ if (!pmb_addr) ++ return -ENOMEM; ++ mcu_csr_base = of_iomap(np, 1); ++ if (!mcu_csr_base) { ++ ret = -ENOMEM; ++ goto free_pmb; ++ } ++ ++ ret = request_firmware(&fw, MT7988_2P5GE_PMB_FW, dev); ++ if (ret) { ++ dev_err(dev, "failed to load firmware: %s, ret: %d\n", ++ MT7988_2P5GE_PMB_FW, ret); ++ goto free; ++ } ++ ++ if (fw->size != MT7988_2P5GE_PMB_FW_SIZE) { ++ dev_err(dev, "Firmware size 0x%zx != 0x%x\n", ++ fw->size, MT7988_2P5GE_PMB_FW_SIZE); ++ ret = -EINVAL; ++ goto release_fw; ++ } ++ ++ reg = readw(mcu_csr_base + MD32_EN_CFG); ++ if (reg & MD32_EN) { ++ phy_set_bits(phydev, MII_BMCR, BMCR_RESET); ++ usleep_range(10000, 11000); ++ } ++ phy_set_bits(phydev, MII_BMCR, BMCR_PDOWN); ++ ++ /* Write magic number to safely stall MCU */ ++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_HOST_CMD1, 0x1100); ++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_HOST_CMD2, 0x00df); ++ ++ for (i = 0; i < MT7988_2P5GE_PMB_FW_SIZE - 1; i += 4) ++ writel(*((uint32_t *)(fw->data + i)), pmb_addr + i); ++ ++ if (!priv->fw_loaded) ++ dev_info(dev, "Firmware date code: %x/%x/%x, version: %x.%x\n", ++ be16_to_cpu(*((__be16 *)(fw->data + ++ MT7988_2P5GE_PMB_FW_SIZE - 8))), ++ *(fw->data + MT7988_2P5GE_PMB_FW_SIZE - 6), ++ *(fw->data + MT7988_2P5GE_PMB_FW_SIZE - 5), ++ *(fw->data + MT7988_2P5GE_PMB_FW_SIZE - 2), ++ *(fw->data + MT7988_2P5GE_PMB_FW_SIZE - 1)); ++ ++ writew(reg & ~MD32_EN, mcu_csr_base + MD32_EN_CFG); ++ writew(reg | MD32_EN, mcu_csr_base + MD32_EN_CFG); ++ phy_set_bits(phydev, MII_BMCR, BMCR_RESET); ++ /* We need a delay here to stabilize initialization of MCU */ ++ usleep_range(7000, 8000); ++ ++ priv->fw_loaded = true; ++ ++release_fw: ++ release_firmware(fw); ++free: ++ iounmap(mcu_csr_base); ++free_pmb: ++ iounmap(pmb_addr); ++ ++ return ret; ++} ++ ++static int mt798x_2p5ge_phy_config_init(struct phy_device *phydev) ++{ ++ struct pinctrl *pinctrl; ++ int ret; ++ ++ /* Check if PHY interface type is compatible */ ++ if (phydev->interface != PHY_INTERFACE_MODE_INTERNAL) ++ return -ENODEV; ++ ++ ret = mt798x_2p5ge_phy_load_fw(phydev); ++ if (ret < 0) ++ return ret; ++ ++ /* Setup LED */ ++ phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_LED0_ON_CTRL, ++ MTK_PHY_LED_ON_POLARITY | MTK_PHY_LED_ON_LINK10 | ++ MTK_PHY_LED_ON_LINK100 | MTK_PHY_LED_ON_LINK1000 | ++ MTK_PHY_LED_ON_LINK2500); ++ phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_LED1_ON_CTRL, ++ MTK_PHY_LED_ON_FDX | MTK_PHY_LED_ON_HDX); ++ ++ /* Switch pinctrl after setting polarity to avoid bogus blinking */ ++ pinctrl = devm_pinctrl_get_select(&phydev->mdio.dev, "i2p5gbe-led"); ++ if (IS_ERR(pinctrl) && PTR_ERR(pinctrl) != -ENODEV) ++ dev_err(&phydev->mdio.dev, "Fail to set LED pins!\n"); ++ ++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LPI_PCS_DSP_CTRL, ++ MTK_PHY_LPI_SIG_EN_LO_THRESH100_MASK, 0); ++ ++ /* Enable 16-bit next page exchange bit if 1000-BT isn't advertising */ ++ mtk_tr_modify(phydev, 0x0, 0xf, 0x3c, AUTO_NP_10XEN, ++ FIELD_PREP(AUTO_NP_10XEN, 0x1)); ++ ++ /* Enable HW auto downshift */ ++ phy_modify_paged(phydev, MTK_PHY_PAGE_EXTENDED_1, ++ MTK_PHY_AUX_CTRL_AND_STATUS, ++ 0, MTK_PHY_ENABLE_DOWNSHIFT); ++ ++ return 0; ++} ++ ++static int mt798x_2p5ge_phy_config_aneg(struct phy_device *phydev) ++{ ++ bool changed = false; ++ u32 adv; ++ int ret; ++ ++ ret = genphy_c45_an_config_aneg(phydev); ++ if (ret < 0) ++ return ret; ++ if (ret > 0) ++ changed = true; ++ ++ /* Clause 45 doesn't define 1000BaseT support. Use Clause 22 instead in ++ * our design. ++ */ ++ adv = linkmode_adv_to_mii_ctrl1000_t(phydev->advertising); ++ ret = phy_modify_changed(phydev, MII_CTRL1000, ADVERTISE_1000FULL, adv); ++ if (ret < 0) ++ return ret; ++ if (ret > 0) ++ changed = true; ++ ++ return __genphy_config_aneg(phydev, changed); ++} ++ ++static int mt798x_2p5ge_phy_get_features(struct phy_device *phydev) ++{ ++ int ret; ++ ++ ret = genphy_c45_pma_read_abilities(phydev); ++ if (ret) ++ return ret; ++ ++ /* This phy can't handle collision, and neither can (XFI)MAC it's ++ * connected to. Although it can do HDX handshake, it doesn't support ++ * CSMA/CD that HDX requires. ++ */ ++ linkmode_clear_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT, ++ phydev->supported); ++ ++ return 0; ++} ++ ++static int mt798x_2p5ge_phy_read_status(struct phy_device *phydev) ++{ ++ int ret; ++ ++ /* When MDIO_STAT1_LSTATUS is raised genphy_c45_read_link(), this phy ++ * actually hasn't finished AN. So use CL22's link update function ++ * instead. ++ */ ++ ret = genphy_update_link(phydev); ++ if (ret) ++ return ret; ++ ++ phydev->speed = SPEED_UNKNOWN; ++ phydev->duplex = DUPLEX_UNKNOWN; ++ phydev->pause = 0; ++ phydev->asym_pause = 0; ++ ++ /* We'll read link speed through vendor specific registers down below. ++ * So remove phy_resolve_aneg_linkmode (AN on) & genphy_c45_read_pma ++ * (AN off). ++ */ ++ if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete) { ++ ret = genphy_c45_read_lpa(phydev); ++ if (ret < 0) ++ return ret; ++ ++ /* Clause 45 doesn't define 1000BaseT support. Read the link ++ * partner's 1G advertisement via Clause 22. ++ */ ++ ret = phy_read(phydev, MII_STAT1000); ++ if (ret < 0) ++ return ret; ++ mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, ret); ++ } else if (phydev->autoneg == AUTONEG_DISABLE) { ++ linkmode_zero(phydev->lp_advertising); ++ } ++ ++ if (phydev->link) { ++ ret = phy_read(phydev, PHY_AUX_CTRL_STATUS); ++ if (ret < 0) ++ return ret; ++ ++ switch (FIELD_GET(PHY_AUX_SPEED_MASK, ret)) { ++ case PHY_AUX_SPD_10: ++ phydev->speed = SPEED_10; ++ break; ++ case PHY_AUX_SPD_100: ++ phydev->speed = SPEED_100; ++ break; ++ case PHY_AUX_SPD_1000: ++ phydev->speed = SPEED_1000; ++ break; ++ case PHY_AUX_SPD_2500: ++ phydev->speed = SPEED_2500; ++ break; ++ } ++ ++ phydev->duplex = DUPLEX_FULL; ++ /* FIXME: ++ * The current firmware always enables rate adaptation mode. ++ */ ++ phydev->rate_matching = RATE_MATCH_PAUSE; ++ } ++ ++ return 0; ++} ++ ++static int mt798x_2p5ge_phy_get_rate_matching(struct phy_device *phydev, ++ phy_interface_t iface) ++{ ++ return RATE_MATCH_PAUSE; ++} ++ ++static int mt798x_2p5ge_phy_probe(struct phy_device *phydev) ++{ ++ struct mtk_i2p5ge_phy_priv *priv; ++ ++ priv = devm_kzalloc(&phydev->mdio.dev, ++ sizeof(struct mtk_i2p5ge_phy_priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ switch (phydev->drv->phy_id) { ++ case MTK_2P5GPHY_ID_MT7988: ++ /* The original hardware only sets MDIO_DEVS_PMAPMD */ ++ phydev->c45_ids.mmds_present |= MDIO_DEVS_PCS | ++ MDIO_DEVS_AN | ++ MDIO_DEVS_VEND1 | ++ MDIO_DEVS_VEND2; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ priv->fw_loaded = false; ++ phydev->priv = priv; ++ ++ return 0; ++} ++ ++static struct phy_driver mtk_2p5gephy_driver[] = { ++ { ++ PHY_ID_MATCH_MODEL(MTK_2P5GPHY_ID_MT7988), ++ .name = "MediaTek MT7988 2.5GbE PHY", ++ .probe = mt798x_2p5ge_phy_probe, ++ .config_init = mt798x_2p5ge_phy_config_init, ++ .config_aneg = mt798x_2p5ge_phy_config_aneg, ++ .get_features = mt798x_2p5ge_phy_get_features, ++ .read_status = mt798x_2p5ge_phy_read_status, ++ .get_rate_matching = mt798x_2p5ge_phy_get_rate_matching, ++ .suspend = genphy_suspend, ++ .resume = genphy_resume, ++ .read_page = mtk_phy_read_page, ++ .write_page = mtk_phy_write_page, ++ }, ++}; ++ ++module_phy_driver(mtk_2p5gephy_driver); ++ ++static struct mdio_device_id __maybe_unused mtk_2p5ge_phy_tbl[] = { ++ { PHY_ID_MATCH_VENDOR(0x00339c00) }, ++ { } ++}; ++ ++MODULE_DESCRIPTION("MediaTek 2.5Gb Ethernet PHY driver"); ++MODULE_AUTHOR("SkyLake Huang "); ++MODULE_LICENSE("GPL"); ++ ++MODULE_DEVICE_TABLE(mdio, mtk_2p5ge_phy_tbl); ++MODULE_FIRMWARE(MT7988_2P5GE_PMB_FW); +-- +2.51.0 + + +From a42eb788cf9cd31ab5c465f6a0843ff7530cb20d Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Fri, 4 Sep 2020 18:42:42 +0200 +Subject: [PATCH 490/517] pci: pcie-mediatek: add support for coherent DMA + +It improves performance by eliminating the need for a cache flush for DMA on +attached devices + +Signed-off-by: Felix Fietkau +--- + arch/arm64/boot/dts/mediatek/mt7622.dtsi | 8 ++++++- + drivers/pci/controller/pcie-mediatek.c | 27 ++++++++++++++++++++++++ + 2 files changed, 34 insertions(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7622.dtsi b/arch/arm64/boot/dts/mediatek/mt7622.dtsi +index ce802c3b22df..c4216828487e 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi +@@ -832,6 +832,9 @@ pcie0: pcie@1a143000 { + bus-range = <0x00 0xff>; + ranges = <0x82000000 0 0x20000000 0x0 0x20000000 0 0x8000000>; + status = "disabled"; ++ dma-coherent; ++ mediatek,hifsys = <&hifsys>; ++ mediatek,cci-control = <&cci_control2>; + + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; +@@ -876,6 +879,9 @@ pcie1: pcie@1a145000 { + bus-range = <0x00 0xff>; + ranges = <0x82000000 0 0x28000000 0x0 0x28000000 0 0x8000000>; + status = "disabled"; ++ dma-coherent; ++ mediatek,hifsys = <&hifsys>; ++ mediatek,cci-control = <&cci_control2>; + + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; +@@ -937,7 +943,7 @@ sata_port: sata-phy@1a243000 { + }; + + hifsys: clock-controller@1af00000 { +- compatible = "mediatek,mt7622-hifsys"; ++ compatible = "mediatek,mt7622-hifsys", "syscon"; + reg = <0 0x1af00000 0 0x70>; + #clock-cells = <1>; + }; +diff --git a/drivers/pci/controller/pcie-mediatek.c b/drivers/pci/controller/pcie-mediatek.c +index b723cdfab3a0..daec88901679 100644 +--- a/drivers/pci/controller/pcie-mediatek.c ++++ b/drivers/pci/controller/pcie-mediatek.c +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -139,6 +140,11 @@ + #define PCIE_LINK_STATUS_V2 0x804 + #define PCIE_PORT_LINKUP_V2 BIT(10) + ++/* DMA channel mapping */ ++#define HIFSYS_DMA_AG_MAP 0x008 ++#define HIFSYS_DMA_AG_MAP_PCIE0 BIT(0) ++#define HIFSYS_DMA_AG_MAP_PCIE1 BIT(1) ++ + struct mtk_pcie_port; + + /** +@@ -1052,6 +1058,27 @@ static int mtk_pcie_setup(struct mtk_pcie *pcie) + struct mtk_pcie_port *port, *tmp; + int err, slot; + ++ if (of_dma_is_coherent(node)) { ++ struct regmap *con; ++ u32 mask; ++ ++ con = syscon_regmap_lookup_by_phandle(node, ++ "mediatek,cci-control"); ++ /* enable CPU/bus coherency */ ++ if (!IS_ERR(con)) ++ regmap_write(con, 0, 3); ++ ++ con = syscon_regmap_lookup_by_phandle(node, ++ "mediatek,hifsys"); ++ if (IS_ERR(con)) { ++ dev_err(dev, "missing hifsys node\n"); ++ return PTR_ERR(con); ++ } ++ ++ mask = HIFSYS_DMA_AG_MAP_PCIE0 | HIFSYS_DMA_AG_MAP_PCIE1; ++ regmap_update_bits(con, HIFSYS_DMA_AG_MAP, mask, mask); ++ } ++ + slot = of_get_pci_domain_nr(dev->of_node); + if (slot < 0) { + for_each_available_child_of_node(node, child) { +-- +2.51.0 + + +From 1c08409b312633c3478c952996235c3de2976465 Mon Sep 17 00:00:00 2001 +From: Jip de Beer +Date: Sun, 9 Jan 2022 13:14:04 +0100 +Subject: [PATCH 491/517] mediatek mt7622: fix 300mhz typo in dts + +The lowest frequency should be 300MHz, since that is the label +assigned to the OPP in the mt7622.dtsi device tree, while there is one +missing zero in the actual value. + +To be clear, the lowest frequency should be 300MHz instead of 30MHz. + +As mentioned @dangowrt on the OpenWrt forum there is no benefit in +leaving 30MHz as the lowest frequency. + +Signed-off-by: Jip de Beer +Signed-off-by: Fritz D. Ansel +--- + arch/arm64/boot/dts/mediatek/mt7622.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7622.dtsi b/arch/arm64/boot/dts/mediatek/mt7622.dtsi +index c4216828487e..4ffc52a101f7 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi +@@ -24,7 +24,7 @@ cpu_opp_table: opp-table { + compatible = "operating-points-v2"; + opp-shared; + opp-300000000 { +- opp-hz = /bits/ 64 <30000000>; ++ opp-hz = /bits/ 64 <300000000>; + opp-microvolt = <950000>; + }; + +-- +2.51.0 + + +From a0cda045c7e0d8dc0a6164cd45c6ae3d84fadcbb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= +Date: Mon, 3 Nov 2025 15:51:05 +0100 +Subject: [PATCH 492/517] + /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/722-remove-300Hz-to-prevent-freeze.patch + +--- + arch/arm64/boot/dts/mediatek/mt7622.dtsi | 16 +++++++++++----- + 1 file changed, 11 insertions(+), 5 deletions(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7622.dtsi b/arch/arm64/boot/dts/mediatek/mt7622.dtsi +index 4ffc52a101f7..8ea9ae91c45c 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi +@@ -23,11 +23,17 @@ / { + cpu_opp_table: opp-table { + compatible = "operating-points-v2"; + opp-shared; +- opp-300000000 { +- opp-hz = /bits/ 64 <300000000>; +- opp-microvolt = <950000>; +- }; +- ++ /* Due to the bug described at the link below, remove the 300 MHz clock to avoid a low ++ * voltage condition that can cause a hang when rebooting the RT3200/E8450. ++ * ++ * https://forum.openwrt.org/t/belkin-rt3200-linksys-e8450-wifi-ax-discussion/94302/1490 ++ * ++ * opp-300000000 { ++ * opp-hz = /bits/ 64 <300000000>; ++ * opp-microvolt = <950000>; ++ * }; ++ * ++ */ + opp-437500000 { + opp-hz = /bits/ 64 <437500000>; + opp-microvolt = <1000000>; +-- +2.51.0 + + +From 19f58b171d2812a5f40b48d4a61d7627996ac650 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Thu, 6 Apr 2023 23:36:50 +0100 +Subject: [PATCH 493/517] net: phy: mxl-gpy: don't use SGMII AN if using + phylink + +MAC drivers using phylink expect SGMII in-band-status to be switched off +when attached to a PHY. Make sure this is the case also for mxl-gpy which +keeps SGMII in-band-status in case of SGMII interface mode is used. + +Signed-off-by: Daniel Golle +--- + drivers/net/phy/mxl-gpy.c | 19 ++++++++++++++++--- + 1 file changed, 16 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/phy/mxl-gpy.c b/drivers/net/phy/mxl-gpy.c +index e0bdbb66df5c..48fe9241cab3 100644 +--- a/drivers/net/phy/mxl-gpy.c ++++ b/drivers/net/phy/mxl-gpy.c +@@ -380,8 +380,11 @@ static bool gpy_2500basex_chk(struct phy_device *phydev) + + phydev->speed = SPEED_2500; + phydev->interface = PHY_INTERFACE_MODE_2500BASEX; +- phy_modify_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_SGMII_CTRL, +- VSPEC1_SGMII_CTRL_ANEN, 0); ++ ++ if (!phydev->phylink) ++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_SGMII_CTRL, ++ VSPEC1_SGMII_CTRL_ANEN, 0); ++ + return true; + } + +@@ -432,6 +435,14 @@ static int gpy_config_aneg(struct phy_device *phydev) + u32 adv; + int ret; + ++ /* Disable SGMII auto-negotiation if using phylink */ ++ if (phydev->phylink) { ++ ret = phy_modify_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_SGMII_CTRL, ++ VSPEC1_SGMII_CTRL_ANEN, 0); ++ if (ret < 0) ++ return ret; ++ } ++ + if (phydev->autoneg == AUTONEG_DISABLE) { + /* Configure half duplex with genphy_setup_forced, + * because genphy_c45_pma_setup_forced does not support. +@@ -554,6 +565,8 @@ static int gpy_update_interface(struct phy_device *phydev) + switch (phydev->speed) { + case SPEED_2500: + phydev->interface = PHY_INTERFACE_MODE_2500BASEX; ++ if (phydev->phylink) ++ break; + ret = phy_modify_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_SGMII_CTRL, + VSPEC1_SGMII_CTRL_ANEN, 0); + if (ret < 0) { +@@ -567,7 +580,7 @@ static int gpy_update_interface(struct phy_device *phydev) + case SPEED_100: + case SPEED_10: + phydev->interface = PHY_INTERFACE_MODE_SGMII; +- if (gpy_sgmii_aneg_en(phydev)) ++ if (phydev->phylink || gpy_sgmii_aneg_en(phydev)) + break; + /* Enable and restart SGMII ANEG for 10/100/1000Mbps link speed + * if ANEG is disabled (in 2500-BaseX mode). +-- +2.51.0 + + +From 1afe6c2034b55a0e26d3e458c83c8d09b8da783b Mon Sep 17 00:00:00 2001 +From: Robert Marko +Date: Sat, 23 Mar 2024 20:21:14 +0100 +Subject: [PATCH 494/517] net: phy: add Airoha EN8801SC PHY + +Airoha EN8801SC Gigabit PHY is used on Edgecore EAP111, so include a +modified version of MTK SDK driver. + +Signed-off-by: Robert Marko +--- + drivers/net/phy/Kconfig | 5 +++++ + drivers/net/phy/Makefile | 1 + + 2 files changed, 6 insertions(+) + +diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig +index 2fcb9544a3b0..c627136d9ed0 100644 +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -165,6 +165,11 @@ config AS21XXX_PHY + AS21210PB1 that all register with the PHY ID 0x7500 0x7500 + before the firmware is loaded. + ++config AIROHA_EN8801SC_PHY ++ tristate "Airoha EN8801SC Gigabit PHY" ++ help ++ Currently supports the Airoha EN8801SC PHY. ++ + config AIR_EN8811H_PHY + tristate "Airoha EN8811H 2.5 Gigabit PHY" + help +diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile +index f869dd4a7ff4..845ee491e8d9 100644 +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -50,6 +50,7 @@ obj-y += $(sfp-obj-y) $(sfp-obj-m) + + obj-$(CONFIG_ADIN_PHY) += adin.o + obj-$(CONFIG_ADIN1100_PHY) += adin1100.o ++obj-$(CONFIG_AIROHA_EN8801SC_PHY) += en8801sc.o + obj-$(CONFIG_AIR_EN8811H_PHY) += air_en8811h.o + obj-$(CONFIG_AMD_PHY) += amd.o + obj-$(CONFIG_AMCC_QT2025_PHY) += qt2025.o +-- +2.51.0 + + +From e1f280932e8365d4a856f205554968ae9aea46c8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= +Date: Mon, 3 Nov 2025 15:51:06 +0100 +Subject: [PATCH 495/517] + /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/736-net-pcs-mtk_usxgmii-add-polarity-control.patch + +--- + drivers/net/pcs/pcs-mtk-usxgmii.c | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/drivers/net/pcs/pcs-mtk-usxgmii.c b/drivers/net/pcs/pcs-mtk-usxgmii.c +index 9691d9e73790..4ce212e366e9 100644 +--- a/drivers/net/pcs/pcs-mtk-usxgmii.c ++++ b/drivers/net/pcs/pcs-mtk-usxgmii.c +@@ -52,6 +52,12 @@ + #define USXGMII_LPA GENMASK(15, 0) + #define USXGMII_LPA_LATCH BIT(31) + ++/* Register to control PCS polarity */ ++#define RG_PHY_TOP_CTRL0 0x82C ++#define USXGMII_PN_SWAP_MASK GENMASK(1, 0) ++#define USXGMII_PN_SWAP_RX BIT(1) ++#define USXGMII_PN_SWAP_TX BIT(0) ++ + /* Register to read PCS link status */ + #define RG_PCS_RX_STATUS0 0x904 + #define RG_PCS_RX_STATUS_UPDATE BIT(16) +@@ -74,6 +80,7 @@ struct mtk_usxgmii_pcs { + struct clk *clk; + struct reset_control *reset; + phy_interface_t interface; ++ unsigned int polarity; + unsigned int neg_mode; + struct list_head node; + }; +@@ -155,6 +162,10 @@ static int mtk_usxgmii_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode + + mtk_usxgmii_reset(mpcs); + ++ /* Configure the interface polarity */ ++ mtk_m32(mpcs, RG_PHY_TOP_CTRL0, ++ USXGMII_PN_SWAP_MASK, mpcs->polarity); ++ + /* Setup USXGMII AN ctrl */ + mtk_m32(mpcs, RG_PCS_AN_CTRL0, + USXGMII_AN_SYNC_CNT | USXGMII_AN_ENABLE, +@@ -332,6 +343,7 @@ static const struct phylink_pcs_ops mtk_usxgmii_pcs_ops = { + static int mtk_usxgmii_probe(struct platform_device *pdev) + { + struct device *dev = &pdev->dev; ++ struct device_node *np = dev->of_node; + struct mtk_usxgmii_pcs *mpcs; + + mpcs = devm_kzalloc(dev, sizeof(*mpcs), GFP_KERNEL); +@@ -342,6 +354,13 @@ static int mtk_usxgmii_probe(struct platform_device *pdev) + if (IS_ERR(mpcs->base)) + return PTR_ERR(mpcs->base); + ++ if (of_property_read_bool(np->parent, "mediatek,pnswap")) ++ mpcs->polarity = USXGMII_PN_SWAP_TX | USXGMII_PN_SWAP_RX; ++ else if (of_property_read_bool(np, "mediatek,pnswap-tx")) ++ mpcs->polarity = USXGMII_PN_SWAP_TX; ++ else if (of_property_read_bool(np, "mediatek,pnswap-rx")) ++ mpcs->polarity = USXGMII_PN_SWAP_RX; ++ + mpcs->dev = dev; + mpcs->pcs.ops = &mtk_usxgmii_pcs_ops; + mpcs->pcs.poll = true; +-- +2.51.0 + + +From 82fbdfafa6531553caab6cf3b09e8f969956ff1d Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Mon, 9 Dec 2024 14:44:17 +0100 +Subject: [PATCH 496/517] net: dsa: Add Airoha AN8855 support + +This small series add the initial support for the Airoha AN8855 Switch. + +It's a 5 port Gigabit Switch with SGMII/HSGMII upstream port. + +This is starting to get in the wild and there are already some router +having this switch chip. + +It's conceptually similar to mediatek switch but register and bits +are different. And there is that massive Hell that is the PCS +configuration. +Saddly for that part we have absolutely NO documentation currently. + +There is this special thing where PHY needs to be calibrated with values +from the switch efuse. (the thing have a whole cpu timer and MCU) + +Changes v11: +- Address reviews from Christophe (spell mistake + dev_err_probe) +- Fix kconfig dependency for MFD driver (depends on MDIO_DEVICE instead of MDIO) + (indirectly fix link error for mdio APIs) +- Fix copy-paste error for MFD driver of_table +- Fix compilation error for PHY (move NVMEM to .config) +- Drop unneeded NVMEM node from MDIO example schema (from Andrew) +- Adapt MFD example schema to MDIO reg property restrictions +Changes v10: +- Entire rework to MFD + split to MDIO, EFUSE, SWITCH separate drivers +- Drop EEE OPs (while Russell finish RFC for EEE changes) +- Use new pcs_inpand OPs +- Drop AN restart function and move to pcs_config +- Enable assisted_learning and disable CPU learn (preparation for fdb_isolation) +- Move EFUSE read in Internal PHY driver to .config to handle EPROBE_DEFER + (needed now that NVMEM driver is register externally instead of internally to switch + node) +Changes v9: +- Error out on using 5G speed as currently not supported +- Add missing MAC_2500FD in phylink mac_capabilities +- Add comment and improve if condition for an8855_phylink_mac_config +Changes v8: +- Add port Fast Age support +- Add support for Port Isolation +- Use correct register for Learning Disable +- Add support for Ageing Time OP +- Set default PVID to 0 by default +- Add mdb OPs +- Add port change MTU +- Fix support for Upper VLAN +Changes v7: +- Fix devm_dsa_register_switch wrong export symbol +Changes v6: +- Drop standard MIB and handle with ethtool OPs (as requested by Jakub) +- Cosmetic: use bool instead of 0 or 1 +Changes v5: +- Add devm_dsa_register_switch() patch +- Add Reviewed-by tag for DT patch +Changes v4: +- Set regmap readable_table static (mute compilation warning) +- Add support for port_bridge flags (LEARNING, FLOOD) +- Reset fdb struct in fdb_dump +- Drop support_asym_pause in port_enable +- Add define for get_phy_flags +- Fix bug for port not inititially part of a bridge + (in an8855_setup the port matrix was always cleared but + the CPU port was never initially added) +- Disable learning and flood for user port by default +- Set CPU port to flood and learning by default +- Correctly AND force duplex and flow control in an8855_phylink_mac_link_up +- Drop RGMII from pcs_config +- Check ret in "Disable AN if not in autoneg" +- Use devm_mutex_init +- Fix typo for AN8855_PORT_CHECK_MODE +- Better define AN8855_STP_LISTENING = AN8855_STP_BLOCKING +- Fix typo in AN8855_PHY_EN_DOWN_SHIFT +- Use paged helper for PHY +- Skip calibration in config_init if priv not defined +Changes v3: +- Out of RFC +- Switch PHY code to select_page API +- Better describe masks and bits in PHY driver for ADC register +- Drop raw values and use define for mii read/write +- Switch to absolute PHY address +- Replace raw values with mask and bits for pcs_config +- Fix typo for ext-surge property name +- Drop support for relocating Switch base PHY address on the bus +Changes v2: +- Drop mutex guard patch +- Drop guard usage in DSA driver +- Use __mdiobus_write/read +- Check return condition and return errors for mii read/write +- Fix wrong logic for EEE +- Fix link_down (don't force link down with autoneg) +- Fix forcing speed on sgmii autoneg +- Better document link speed for sgmii reg +- Use standard define for sgmii reg +- Imlement nvmem support to expose switch EFUSE +- Rework PHY calibration with the use of NVMEM producer/consumer +- Update DT with new NVMEM property +- Move aneg validation for 2500-basex in pcs_config +- Move r50Ohm table and function to PHY driver + +Christian Marangi (9): + dt-bindings: nvmem: Document support for Airoha AN8855 Switch EFUSE + dt-bindings: net: Document support for Airoha AN8855 Switch Virtual + MDIO + dt-bindings: net: dsa: Document support for Airoha AN8855 DSA Switch + dt-bindings: mfd: Document support for Airoha AN8855 Switch SoC + mfd: an8855: Add support for Airoha AN8855 Switch MFD + net: mdio: Add Airoha AN8855 Switch MDIO Passtrough + nvmem: an8855: Add support for Airoha AN8855 Switch EFUSE + net: dsa: Add Airoha AN8855 5-Port Gigabit DSA Switch driver + net: phy: Add Airoha AN8855 Internal Switch Gigabit PHY + + .../bindings/mfd/airoha,an8855-mfd.yaml | 178 ++ + .../bindings/net/airoha,an8855-mdio.yaml | 56 + + .../net/dsa/airoha,an8855-switch.yaml | 105 + + .../bindings/nvmem/airoha,an8855-efuse.yaml | 123 + + MAINTAINERS | 17 + + drivers/mfd/Kconfig | 10 + + drivers/mfd/Makefile | 1 + + drivers/mfd/airoha-an8855.c | 278 ++ + drivers/net/dsa/Kconfig | 9 + + drivers/net/dsa/Makefile | 1 + + drivers/net/dsa/an8855.c | 2310 +++++++++++++++++ + drivers/net/dsa/an8855.h | 783 ++++++ + drivers/net/mdio/Kconfig | 9 + + drivers/net/mdio/Makefile | 1 + + drivers/net/mdio/mdio-an8855.c | 113 + + drivers/net/phy/Kconfig | 5 + + drivers/net/phy/Makefile | 1 + + drivers/net/phy/air_an8855.c | 267 ++ + drivers/nvmem/Kconfig | 11 + + drivers/nvmem/Makefile | 2 + + drivers/nvmem/an8855-efuse.c | 63 + + include/linux/mfd/airoha-an8855-mfd.h | 41 + + 22 files changed, 4384 insertions(+) + create mode 100644 Documentation/devicetree/bindings/mfd/airoha,an8855-mfd.yaml + create mode 100644 Documentation/devicetree/bindings/net/airoha,an8855-mdio.yaml + create mode 100644 Documentation/devicetree/bindings/net/dsa/airoha,an8855-switch.yaml + create mode 100644 Documentation/devicetree/bindings/nvmem/airoha,an8855-efuse.yaml + create mode 100644 drivers/mfd/airoha-an8855.c + create mode 100644 drivers/net/dsa/an8855.c + create mode 100644 drivers/net/dsa/an8855.h + create mode 100644 drivers/net/mdio/mdio-an8855.c + create mode 100644 drivers/net/phy/air_an8855.c + create mode 100644 drivers/nvmem/an8855-efuse.c + create mode 100644 include/linux/mfd/airoha-an8855-mfd.h +--- + drivers/mfd/Kconfig | 10 ++++++++++ + drivers/mfd/Makefile | 1 + + drivers/net/dsa/Kconfig | 9 +++++++++ + drivers/net/dsa/Makefile | 1 + + drivers/net/mdio/Kconfig | 9 +++++++++ + drivers/net/mdio/Makefile | 1 + + drivers/net/phy/Kconfig | 5 +++++ + drivers/net/phy/Makefile | 1 + + drivers/nvmem/Kconfig | 11 +++++++++++ + drivers/nvmem/Makefile | 2 ++ + 10 files changed, 50 insertions(+) + +diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig +index f9325bcce1b9..340d8a03558c 100644 +--- a/drivers/mfd/Kconfig ++++ b/drivers/mfd/Kconfig +@@ -53,6 +53,16 @@ config MFD_ALTERA_SYSMGR + using regmap_mmio accesses for ARM32 parts and SMC calls to + EL3 for ARM64 parts. + ++config MFD_AIROHA_AN8855 ++ tristate "Airoha AN8855 Switch MFD" ++ select MFD_CORE ++ select MDIO_DEVICE ++ depends on NETDEVICES && OF ++ help ++ Support for the Airoha AN8855 Switch MFD. This is a SoC Switch ++ that provides various peripherals. Currently it provides a ++ DSA switch and a NVMEM provider. ++ + config MFD_ACT8945A + tristate "Active-semi ACT8945A" + select MFD_CORE +diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile +index 2a9f91e81af8..da210d16c7bb 100644 +--- a/drivers/mfd/Makefile ++++ b/drivers/mfd/Makefile +@@ -9,6 +9,7 @@ obj-$(CONFIG_MFD_88PM800) += 88pm800.o 88pm80x.o + obj-$(CONFIG_MFD_88PM805) += 88pm805.o 88pm80x.o + obj-$(CONFIG_MFD_88PM886_PMIC) += 88pm886.o + obj-$(CONFIG_MFD_ACT8945A) += act8945a.o ++obj-$(CONFIG_MFD_AIROHA_AN8855) += airoha-an8855.o + obj-$(CONFIG_MFD_SM501) += sm501.o + obj-$(CONFIG_ARCH_BCM2835) += bcm2835-pm.o + obj-$(CONFIG_MFD_BCM590XX) += bcm590xx.o +diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig +index b7b473e3fc02..37a4a0b7ae96 100644 +--- a/drivers/net/dsa/Kconfig ++++ b/drivers/net/dsa/Kconfig +@@ -24,6 +24,15 @@ config NET_DSA_LOOP + This enables support for a fake mock-up switch chip which + exercises the DSA APIs. + ++config NET_DSA_AN8855 ++ tristate "Airoha AN8855 Ethernet switch support" ++ depends on MFD_AIROHA_AN8855 ++ depends on NET_DSA ++ select NET_DSA_TAG_MTK ++ help ++ This enables support for the Airoha AN8855 Ethernet switch ++ chip. ++ + source "drivers/net/dsa/hirschmann/Kconfig" + + config NET_DSA_LANTIQ_GSWIP +diff --git a/drivers/net/dsa/Makefile b/drivers/net/dsa/Makefile +index 23dbdf1a36a8..1e9d01ef7490 100644 +--- a/drivers/net/dsa/Makefile ++++ b/drivers/net/dsa/Makefile +@@ -6,6 +6,7 @@ ifdef CONFIG_NET_DSA_LOOP + obj-$(CONFIG_FIXED_PHY) += dsa_loop_bdinfo.o + endif + obj-$(CONFIG_NET_DSA_KS8995) += ks8995.o ++obj-$(CONFIG_NET_DSA_AN8855) += an8855.o + obj-$(CONFIG_NET_DSA_LANTIQ_GSWIP) += lantiq_gswip.o + obj-$(CONFIG_NET_DSA_MT7530) += mt7530.o + obj-$(CONFIG_NET_DSA_MT7530_MDIO) += mt7530-mdio.o +diff --git a/drivers/net/mdio/Kconfig b/drivers/net/mdio/Kconfig +index 4a7a303be2f7..3d417948e73a 100644 +--- a/drivers/net/mdio/Kconfig ++++ b/drivers/net/mdio/Kconfig +@@ -61,6 +61,15 @@ config MDIO_XGENE + This module provides a driver for the MDIO busses found in the + APM X-Gene SoC's. + ++config MDIO_AN8855 ++ tristate "Airoha AN8855 Switch MDIO bus controller" ++ depends on MFD_AIROHA_AN8855 ++ depends on OF_MDIO ++ help ++ This module provides a driver for the Airoha AN8855 Switch ++ that requires a MDIO passtrough as switch address is shared ++ with the internal PHYs and requires additional page handling. ++ + config MDIO_ASPEED + tristate "ASPEED MDIO bus controller" + depends on ARCH_ASPEED || COMPILE_TEST +diff --git a/drivers/net/mdio/Makefile b/drivers/net/mdio/Makefile +index 1015f0db4531..546c4e55b475 100644 +--- a/drivers/net/mdio/Makefile ++++ b/drivers/net/mdio/Makefile +@@ -5,6 +5,7 @@ obj-$(CONFIG_ACPI_MDIO) += acpi_mdio.o + obj-$(CONFIG_FWNODE_MDIO) += fwnode_mdio.o + obj-$(CONFIG_OF_MDIO) += of_mdio.o + ++obj-$(CONFIG_MDIO_AN8855) += mdio-an8855.o + obj-$(CONFIG_MDIO_ASPEED) += mdio-aspeed.o + obj-$(CONFIG_MDIO_BCM_IPROC) += mdio-bcm-iproc.o + obj-$(CONFIG_MDIO_BCM_UNIMAC) += mdio-bcm-unimac.o +diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig +index c627136d9ed0..2682c7ba2b14 100644 +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -170,6 +170,11 @@ config AIROHA_EN8801SC_PHY + help + Currently supports the Airoha EN8801SC PHY. + ++config AIR_AN8855_PHY ++ tristate "Airoha AN8855 Internal Gigabit PHY" ++ help ++ Currently supports the internal Airoha AN8855 Switch PHY. ++ + config AIR_EN8811H_PHY + tristate "Airoha EN8811H 2.5 Gigabit PHY" + help +diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile +index 845ee491e8d9..d75b8fab63eb 100644 +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -51,6 +51,7 @@ obj-y += $(sfp-obj-y) $(sfp-obj-m) + obj-$(CONFIG_ADIN_PHY) += adin.o + obj-$(CONFIG_ADIN1100_PHY) += adin1100.o + obj-$(CONFIG_AIROHA_EN8801SC_PHY) += en8801sc.o ++obj-$(CONFIG_AIR_AN8855_PHY) += air_an8855.o + obj-$(CONFIG_AIR_EN8811H_PHY) += air_en8811h.o + obj-$(CONFIG_AMD_PHY) += amd.o + obj-$(CONFIG_AMCC_QT2025_PHY) += qt2025.o +diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig +index 51257aa2cd3e..9b998a92189a 100644 +--- a/drivers/nvmem/Kconfig ++++ b/drivers/nvmem/Kconfig +@@ -29,6 +29,17 @@ source "drivers/nvmem/layouts/Kconfig" + + # Devices + ++config NVMEM_AN8855_EFUSE ++ tristate "Airoha AN8855 eFuse support" ++ depends on MFD_AIROHA_AN8855 || COMPILE_TEST ++ help ++ Say y here to enable support for reading eFuses on Airoha AN8855 ++ Switch. These are e.g. used to store factory programmed ++ calibration data required for the PHY. ++ ++ This driver can also be built as a module. If so, the module will ++ be called nvmem-an8855-efuse. ++ + config NVMEM_APPLE_EFUSES + tristate "Apple eFuse support" + depends on ARCH_APPLE || COMPILE_TEST +diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile +index 68fcf845f417..6c6a49cb9890 100644 +--- a/drivers/nvmem/Makefile ++++ b/drivers/nvmem/Makefile +@@ -10,6 +10,8 @@ nvmem_layouts-y := layouts.o + obj-y += layouts/ + + # Devices ++obj-$(CONFIG_NVMEM_AN8855_EFUSE) += nvmem-an8855-efuse.o ++nvmem-an8855-efuse-y := an8855-efuse.o + obj-$(CONFIG_NVMEM_APPLE_EFUSES) += nvmem-apple-efuses.o + nvmem-apple-efuses-y := apple-efuses.o + obj-$(CONFIG_NVMEM_BCM_OCOTP) += nvmem-bcm-ocotp.o +-- +2.51.0 + + +From 744a0be88f4d250f79d3ae4beaba2a4bcab033c4 Mon Sep 17 00:00:00 2001 +From: Maso Huang +Date: Thu, 7 Sep 2023 10:54:37 +0800 +Subject: [PATCH 497/517] arm64: dts: mt7986: add afe + +--- + arch/arm64/boot/dts/mediatek/mt7986a.dtsi | 23 +++++++++++++++++++++++ + 1 file changed, 23 insertions(+) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi +index 9a8d7db31261..49b5839eb7e9 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi +@@ -202,6 +202,29 @@ pio: pinctrl@1001f000 { + #interrupt-cells = <2>; + }; + ++ afe: audio-controller@11210000 { ++ compatible = "mediatek,mt7986-afe"; ++ reg = <0 0x11210000 0 0x9000>; ++ #sound-dai-cells = <0>; ++ interrupts = ; ++ clocks = <&infracfg CLK_INFRA_AUD_BUS_CK>, ++ <&infracfg CLK_INFRA_AUD_26M_CK>, ++ <&infracfg CLK_INFRA_AUD_L_CK>, ++ <&infracfg CLK_INFRA_AUD_AUD_CK>, ++ <&infracfg CLK_INFRA_AUD_EG2_CK>; ++ clock-names = "aud_bus_ck", ++ "aud_26m_ck", ++ "aud_l_ck", ++ "aud_aud_ck", ++ "aud_eg2_ck"; ++ assigned-clocks = <&topckgen CLK_TOP_A1SYS_SEL>, ++ <&topckgen CLK_TOP_AUD_L_SEL>, ++ <&topckgen CLK_TOP_A_TUNER_SEL>; ++ assigned-clock-parents = <&topckgen CLK_TOP_APLL2_D4>, ++ <&apmixedsys CLK_APMIXED_APLL2>, ++ <&topckgen CLK_TOP_APLL2_D4>; ++ }; ++ + pwm: pwm@10048000 { + compatible = "mediatek,mt7986-pwm"; + reg = <0 0x10048000 0 0x1000>; +-- +2.51.0 + + +From 9576cb9f4d5b90fdbae13c30eaca52d4e77dfb50 Mon Sep 17 00:00:00 2001 +From: Maso Huang +Date: Thu, 7 Sep 2023 10:54:37 +0800 +Subject: [PATCH 498/517] arm64: dts: mt7986: add sound wm8960 + +--- + .../dts/mediatek/mt7986a-rfb-spim-nand.dts | 40 +++++++++++++++++++ + 1 file changed, 40 insertions(+) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7986a-rfb-spim-nand.dts b/arch/arm64/boot/dts/mediatek/mt7986a-rfb-spim-nand.dts +index 479a5ca2fc4d..85ec95de405f 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7986a-rfb-spim-nand.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7986a-rfb-spim-nand.dts +@@ -4,6 +4,36 @@ + + / { + compatible = "mediatek,mt7986a-rfb-snand"; ++ ++ sound_wm8960 { ++ compatible = "mediatek,mt7986-wm8960-sound"; ++ audio-routing = "Headphone", "HP_L", ++ "Headphone", "HP_R", ++ "LINPUT1", "AMIC", ++ "RINPUT1", "AMIC"; ++ ++ status = "okay"; ++ ++ platform { ++ sound-dai = <&afe>; ++ }; ++ ++ codec { ++ sound-dai = <&wm8960>; ++ }; ++ }; ++}; ++ ++&i2c0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c_pins>; ++ status = "okay"; ++ ++ wm8960: wm8960@1a { ++ compatible = "wlf,wm8960"; ++ #sound-dai-cells = <0>; ++ reg = <0x1a>; ++ }; + }; + + &spi0 { +@@ -50,3 +80,13 @@ partition@580000 { + &wifi { + mediatek,mtd-eeprom = <&factory 0>; + }; ++ ++&pio { ++ i2c_pins: i2c-pins-3-4 { ++ mux { ++ function = "i2c"; ++ groups = "i2c"; ++ }; ++ }; ++}; ++ +-- +2.51.0 + + +From 865785365dda36ad89ca2a72db9304f5c9cd7b5d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= +Date: Mon, 3 Nov 2025 15:51:07 +0100 +Subject: [PATCH 499/517] + /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/864-arm64-dts-mt7986-add-sound-overlay-for-bpi-r3.patch + +--- + arch/arm64/boot/dts/mediatek/Makefile | 1 + + ...7986a-bananapi-bpi-r3-respeaker-2mics.dtso | 65 +++++++++++++++++++ + 2 files changed, 66 insertions(+) + create mode 100644 arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-respeaker-2mics.dtso + +diff --git a/arch/arm64/boot/dts/mediatek/Makefile b/arch/arm64/boot/dts/mediatek/Makefile +index 82f7332077c4..7d4c852cb124 100644 +--- a/arch/arm64/boot/dts/mediatek/Makefile ++++ b/arch/arm64/boot/dts/mediatek/Makefile +@@ -18,6 +18,7 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += mt7986a-bananapi-bpi-r3-emmc.dtbo + dtb-$(CONFIG_ARCH_MEDIATEK) += mt7986a-bananapi-bpi-r3-nand.dtbo + dtb-$(CONFIG_ARCH_MEDIATEK) += mt7986a-bananapi-bpi-r3-nor.dtbo + dtb-$(CONFIG_ARCH_MEDIATEK) += mt7986a-bananapi-bpi-r3-sd.dtbo ++dtb-$(CONFIG_ARCH_MEDIATEK) += mt7986a-bananapi-bpi-r3-respeaker-2mics.dtbo + dtb-$(CONFIG_ARCH_MEDIATEK) += mt7986a-rfb.dtb + dtb-$(CONFIG_ARCH_MEDIATEK) += mt7986b-rfb.dtb + dtb-$(CONFIG_ARCH_MEDIATEK) += mt7988a-bananapi-bpi-r4.dtb +diff --git a/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-respeaker-2mics.dtso b/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-respeaker-2mics.dtso +new file mode 100644 +index 000000000000..e583875154a3 +--- /dev/null ++++ b/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-respeaker-2mics.dtso +@@ -0,0 +1,65 @@ ++// SPDX-License-Identifier: (GPL-2.0 OR MIT) ++/* ++ * Copyright (C) 2023 MediaTek Inc. ++ * Author: Maso Huang ++ */ ++ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "bananapi,bpi-r3", "mediatek,mt7986a"; ++ ++ fragment@0 { ++ target-path = "/"; ++ __overlay__ { ++ sound_wm8960 { ++ compatible = "mediatek,mt7986-wm8960-sound"; ++ audio-routing = "Headphone", "HP_L", ++ "Headphone", "HP_R", ++ "LINPUT1", "AMIC", ++ "RINPUT1", "AMIC"; ++ ++ status = "okay"; ++ ++ platform { ++ sound-dai = <&afe>; ++ }; ++ ++ codec { ++ sound-dai = <&wm8960>; ++ }; ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&i2c0>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c_pins>; ++ clock-frequency = <400000>; ++ status = "okay"; ++ ++ wm8960: wm8960@1a { ++ compatible = "wlf,wm8960"; ++ #sound-dai-cells = <0>; ++ reg = <0x1a>; ++ }; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&pio>; ++ __overlay__ { ++ i2c_pins: i2c-pins-3-4 { ++ mux { ++ function = "i2c"; ++ groups = "i2c"; ++ }; ++ }; ++ }; ++ }; ++}; +-- +2.51.0 + + +From 58396f54f6a0640436a55866eb4ff7567d54ec08 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= +Date: Mon, 3 Nov 2025 15:51:08 +0100 +Subject: [PATCH 500/517] + /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/900-dts-mt7622-bpi-r64-aliases-for-dtoverlay.patch + +--- + .../mt7622-bananapi-bpi-r64-pcie1.dtso | 17 ++++++++++ + .../mt7622-bananapi-bpi-r64-sata.dtso | 31 +++++++++++++++++++ + .../dts/mediatek/mt7622-bananapi-bpi-r64.dts | 2 +- + 3 files changed, 49 insertions(+), 1 deletion(-) + create mode 100644 arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64-pcie1.dtso + create mode 100644 arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64-sata.dtso + +diff --git a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64-pcie1.dtso b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64-pcie1.dtso +new file mode 100644 +index 000000000000..6be1ea2a8a13 +--- /dev/null ++++ b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64-pcie1.dtso +@@ -0,0 +1,17 @@ ++/* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */ ++ ++#include ++ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "bananapi,bpi-r64", "mediatek,mt7622"; ++ ++ fragment@0 { ++ target = <&asmsel>; ++ __overlay__ { ++ gpios = <90 GPIO_ACTIVE_HIGH>; ++ }; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64-sata.dtso b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64-sata.dtso +new file mode 100644 +index 000000000000..160423348b4c +--- /dev/null ++++ b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64-sata.dtso +@@ -0,0 +1,31 @@ ++/* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */ ++ ++#include ++ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "bananapi,bpi-r64", "mediatek,mt7622"; ++ ++ fragment@0 { ++ target = <&asmsel>; ++ __overlay__ { ++ gpios = <90 GPIO_ACTIVE_LOW>; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&sata>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&sata_phy>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts +index 77ecf5086c2c..b8cc6b9516e5 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts +@@ -323,7 +323,7 @@ &pio { + /* Attention: GPIO 90 is used to switch between PCIe@1,0 and + * SATA functions. i.e. output-high: PCIe, output-low: SATA + */ +- asm_sel { ++ asmsel: asm_sel { + gpio-hog; + gpios = <90 GPIO_ACTIVE_HIGH>; + output-high; +-- +2.51.0 + + +From 98b9ffa72c8692d6441504a508fdbeaa83418ebc Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= +Date: Mon, 3 Nov 2025 15:51:08 +0100 +Subject: [PATCH 501/517] + /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/901-arm-add-cmdline-override.patch + +--- + arch/arm/Kconfig | 8 ++++++++ + arch/arm64/Kconfig | 8 ++++++++ + drivers/of/fdt.c | 11 +++++++++++ + 3 files changed, 27 insertions(+) + +diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig +index d5bf16462bdb..bb39e14b7486 100644 +--- a/arch/arm/Kconfig ++++ b/arch/arm/Kconfig +@@ -1505,6 +1505,14 @@ config ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEND + + endchoice + ++config CMDLINE_OVERRIDE ++ bool "Use alternative cmdline from device tree" ++ help ++ Some bootloaders may have uneditable bootargs. While CMDLINE_FORCE can ++ be used, this is not a good option for kernels that are shared across ++ devices. This setting enables using "chosen/cmdline-override" as the ++ cmdline if it exists in the device tree. ++ + config CMDLINE + string "Default kernel command string" + default "" +diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig +index 40ae4dd961b1..788c05232708 100644 +--- a/arch/arm64/Kconfig ++++ b/arch/arm64/Kconfig +@@ -2381,6 +2381,14 @@ config CMDLINE_FORCE + + endchoice + ++config CMDLINE_OVERRIDE ++ bool "Use alternative cmdline from device tree" ++ help ++ Some bootloaders may have uneditable bootargs. While CMDLINE_FORCE can ++ be used, this is not a good option for kernels that are shared across ++ devices. This setting enables using "chosen/cmdline-override" as the ++ cmdline if it exists in the device tree. ++ + config EFI_STUB + bool + +diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c +index 500807cccee4..1ca6cb71a908 100644 +--- a/drivers/of/fdt.c ++++ b/drivers/of/fdt.c +@@ -1053,6 +1053,17 @@ int __init early_init_dt_scan_chosen(char *cmdline) + if (p != NULL && l > 0) + strlcat(cmdline, p, min_t(int, strlen(cmdline) + (int)l, COMMAND_LINE_SIZE)); + ++ /* CONFIG_CMDLINE_OVERRIDE is used to fallback to a different ++ * device tree option of chosen/bootargs-override. This is ++ * helpful on boards where u-boot sets bootargs, and is unable ++ * to be modified. ++ */ ++#ifdef CONFIG_CMDLINE_OVERRIDE ++ p = of_get_flat_dt_prop(node, "bootargs-override", &l); ++ if (p != NULL && l > 0) ++ strscpy(cmdline, p, min((int)l, COMMAND_LINE_SIZE)); ++#endif ++ + handle_cmdline: + /* + * CONFIG_CMDLINE is meant to be a default in case nothing else +-- +2.51.0 + + +From 9aafa16a5e03d1d3488357d03c769324d01d9546 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= +Date: Mon, 3 Nov 2025 15:51:08 +0100 +Subject: [PATCH 502/517] + /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/910-dts-mt7622-bpi-r64-wifi-eeprom.patch + +--- + .../dts/mediatek/mt7622-bananapi-bpi-r64.dts | 23 +++++++++++++++++++ + 1 file changed, 23 insertions(+) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts +index b8cc6b9516e5..456d260b5edf 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts +@@ -650,5 +650,28 @@ &watchdog { + }; + + &wmac { ++ mediatek,eeprom-data = <0x22760500 0x0 0x0 0x0 ++ 0x0 0x0 0x0 0x0 ++ 0x0 0x0 0x0 0x0 ++ 0x0 0x44000020 0x0 0x10002000 ++ 0x4400 0x4000000 0x0 0x0 ++ 0x200000b3 0x40b6c3c3 0x26000000 0x41c42600 ++ 0x41c4 0x26000000 0xc0c52600 0x0 ++ 0x0 0x0 0x0 0x0 ++ 0x0 0x0 0x0 0x0 ++ 0x0 0x0 0x0 0x0 ++ 0x0 0x0 0x0 0x0 ++ 0x0 0x0 0x0 0xc6c6 ++ 0xc3c3c2c1 0xc300c3 0x818181 0x83c1c182 ++ 0x83838382 0x0 0x0 0x0 ++ 0x0 0x0 0x0 0x0 ++ 0x84002e00 0x90000087 0x8a000000 0x0 ++ 0x0 0x0 0x0 0x0 ++ 0x0 0x0 0x0 0x0 ++ 0xb000009 0x0 0x0 0x0 ++ 0x0 0x0 0x0 0x0 ++ 0x0 0x0 0x0 0x0 ++ 0x0 0x0 0x0 0x7707>; ++ + status = "okay"; + }; +-- +2.51.0 + + +From c4409ad0cbfc4b8700cf01d1670473352839322c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= +Date: Mon, 3 Nov 2025 15:51:09 +0100 +Subject: [PATCH 503/517] + /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/911-dts-mt7622-bpi-r64-add-rootdisk.patch + +--- + .../dts/mediatek/mt7622-bananapi-bpi-r64.dts | 78 +++++++++++++++++-- + 1 file changed, 70 insertions(+), 8 deletions(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts +index 456d260b5edf..bec66209492f 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts +@@ -32,6 +32,9 @@ aliases { + chosen { + stdout-path = "serial0:115200n8"; + bootargs = "earlycon=uart8250,mmio32,0x11002000 console=ttyS0,115200n1 swiotlb=512"; ++ rootdisk-emmc = <&emmc_rootfs>; ++ rootdisk-sd = <&sd_rootfs>; ++ rootdisk-snfi = <&ubi_rootfs>; + }; + + cpus { +@@ -245,6 +248,28 @@ &mmc0 { + assigned-clocks = <&topckgen CLK_TOP_MSDC30_0_SEL>; + assigned-clock-parents = <&topckgen CLK_TOP_UNIV48M>; + non-removable; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ card@0 { ++ compatible = "mmc-card"; ++ reg = <0>; ++ ++ block { ++ compatible = "block-device"; ++ partitions { ++ block-partition-env { ++ partname = "ubootenv"; ++ nvmem-layout { ++ compatible = "u-boot,env"; ++ }; ++ }; ++ emmc_rootfs: block-partition-production { ++ partname = "production"; ++ }; ++ }; ++ }; ++ }; + }; + + &mmc1 { +@@ -260,6 +285,28 @@ &mmc1 { + vqmmc-supply = <®_3p3v>; + assigned-clocks = <&topckgen CLK_TOP_MSDC30_1_SEL>; + assigned-clock-parents = <&topckgen CLK_TOP_UNIV48M>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ card@0 { ++ compatible = "mmc-card"; ++ reg = <0>; ++ ++ block { ++ compatible = "block-device"; ++ partitions { ++ block-partition-env { ++ partname = "ubootenv"; ++ nvmem-layout { ++ compatible = "u-boot,env"; ++ }; ++ }; ++ sd_rootfs: block-partition-production { ++ partname = "production"; ++ }; ++ }; ++ }; ++ }; + }; + + &nandc { +@@ -293,15 +340,30 @@ partition@0 { + read-only; + }; + +- partition@80000 { +- label = "fip"; +- reg = <0x80000 0x200000>; +- read-only; +- }; +- +- ubi: partition@280000 { ++ ubi: partition@80000 { + label = "ubi"; +- reg = <0x280000 0x7d80000>; ++ reg = <0x80000 0x7f80000>; ++ compatible = "linux,ubi"; ++ ++ volumes { ++ ubi-volume-ubootenv { ++ volname = "ubootenv"; ++ nvmem-layout { ++ compatible = "u-boot,env-redundant-bool"; ++ }; ++ }; ++ ++ ubi-volume-ubootenv2 { ++ volname = "ubootenv2"; ++ nvmem-layout { ++ compatible = "u-boot,env-redundant-bool"; ++ }; ++ }; ++ ++ ubi_rootfs: ubi-volume-fit { ++ volname = "fit"; ++ }; ++ }; + }; + }; + }; +-- +2.51.0 + + +From 0f6cc451cecc15b12cf113f5046e9985bc23f7a7 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Fri, 9 May 2025 02:38:51 +0100 +Subject: [PATCH 504/517] block: partitions: msdos: add OF node by partition + number + +A hack for some legacy boards... + +Signed-off-by: Daniel Golle +--- + block/partitions/msdos.c | 36 +++++++++++++++++++++++++++++++++--- + 1 file changed, 33 insertions(+), 3 deletions(-) + +diff --git a/block/partitions/msdos.c b/block/partitions/msdos.c +index 073be78ba0b0..857893fa5c39 100644 +--- a/block/partitions/msdos.c ++++ b/block/partitions/msdos.c +@@ -27,6 +27,7 @@ + */ + #include + #include ++#include + + #include "check.h" + #include "efi.h" +@@ -116,6 +117,26 @@ static void set_info(struct parsed_partitions *state, int slot, + state->parts[slot].has_info = true; + } + ++static struct device_node *find_partno_of_node(struct device_node *partitions_np, ++ int partno) ++{ ++ int np_partno; ++ ++ if (!partitions_np || ++ !of_device_is_compatible(partitions_np, "msdos-partitions")) ++ return NULL; ++ ++ for_each_available_child_of_node_scoped(partitions_np, np) { ++ if (!of_property_read_u32(np, "partno", &np_partno) && ++ partno != np_partno) ++ continue; ++ ++ return np; ++ } ++ ++ return NULL; ++} ++ + /* + * Create devices for each logical partition in an extended partition. + * The logical partitions form a linked list, with each entry being +@@ -131,6 +152,8 @@ static void parse_extended(struct parsed_partitions *state, + sector_t first_sector, sector_t first_size, + u32 disksig) + { ++ struct device *ddev = disk_to_dev(state->disk); ++ struct device_node *partitions_np = of_node_get(ddev->of_node); + struct msdos_partition *p; + Sector sect; + unsigned char *data; +@@ -190,7 +213,8 @@ static void parse_extended(struct parsed_partitions *state, + continue; + } + +- put_partition(state, state->next, next, size); ++ of_put_partition(state, state->next, next, size, ++ find_partno_of_node(partitions_np, state->next)); + set_info(state, state->next, disksig); + if (p->sys_ind == LINUX_RAID_PARTITION) + state->parts[state->next].flags = ADDPART_FLAG_RAID; +@@ -580,6 +604,8 @@ static struct { + + int msdos_partition(struct parsed_partitions *state) + { ++ struct device *ddev = disk_to_dev(state->disk); ++ struct device_node *partitions_np = of_node_get(ddev->of_node); + sector_t sector_size; + Sector sect; + unsigned char *data; +@@ -676,14 +702,18 @@ int msdos_partition(struct parsed_partitions *state) + sector_t n = 2; + + n = min(size, max(sector_size, n)); +- put_partition(state, slot, start, n); ++ of_put_partition(state, slot, start, n, ++ find_partno_of_node(partitions_np, ++ slot)); + + strlcat(state->pp_buf, " <", PAGE_SIZE); + parse_extended(state, start, size, disksig); + strlcat(state->pp_buf, " >", PAGE_SIZE); + continue; + } +- put_partition(state, slot, start, size); ++ of_put_partition(state, slot, start, size, ++ find_partno_of_node(partitions_np, ++ slot)); + set_info(state, slot, disksig); + if (p->sys_ind == LINUX_RAID_PARTITION) + state->parts[slot].flags = ADDPART_FLAG_RAID; +-- +2.51.0 + + +From cad132ca9e315f20dca290a1b8f5b7c71e5796be Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= +Date: Mon, 3 Nov 2025 15:51:10 +0100 +Subject: [PATCH 505/517] + /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/930-spi-mt65xx-enable-sel-clk.patch + +--- + drivers/spi/spi-mt65xx.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/spi/spi-mt65xx.c b/drivers/spi/spi-mt65xx.c +index 906e188987c8..4aed51720298 100644 +--- a/drivers/spi/spi-mt65xx.c ++++ b/drivers/spi/spi-mt65xx.c +@@ -1237,8 +1237,15 @@ static int mtk_spi_probe(struct platform_device *pdev) + if (ret < 0) + return dev_err_probe(dev, ret, "failed to enable hclk\n"); + ++ ret = clk_prepare_enable(mdata->sel_clk); ++ if (ret < 0) { ++ clk_disable_unprepare(mdata->spi_hclk); ++ return dev_err_probe(dev, ret, "failed to enable sel_clk\n"); ++ } ++ + ret = clk_prepare_enable(mdata->spi_clk); + if (ret < 0) { ++ clk_disable_unprepare(mdata->sel_clk); + clk_disable_unprepare(mdata->spi_hclk); + return dev_err_probe(dev, ret, "failed to enable spi_clk\n"); + } +-- +2.51.0 + + +From 23e8f05982b92a225fe2f9dc1475feefd6aedd52 Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Sun, 12 Mar 2023 16:40:31 +0100 +Subject: [PATCH 506/517] net: ethernet: mtk_wed: rename + mtk_wed_get_memory_region in mtk_wed_get_reserved_memory_region + +This is a preliminary patch to move wed ilm/dlm and cpuboot properties in +dedicated dts nodes. + +Signed-off-by: Lorenzo Bianconi +--- + drivers/net/ethernet/mediatek/mtk_wed_mcu.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/mediatek/mtk_wed_mcu.c b/drivers/net/ethernet/mediatek/mtk_wed_mcu.c +index c06e5ad18b01..ed97ca29b4e5 100644 +--- a/drivers/net/ethernet/mediatek/mtk_wed_mcu.c ++++ b/drivers/net/ethernet/mediatek/mtk_wed_mcu.c +@@ -234,8 +234,8 @@ int mtk_wed_mcu_msg_update(struct mtk_wed_device *dev, int id, void *data, + } + + static int +-mtk_wed_get_memory_region(struct mtk_wed_hw *hw, int index, +- struct mtk_wed_wo_memory_region *region) ++mtk_wed_get_reserved_memory_region(struct mtk_wed_hw *hw, int index, ++ struct mtk_wed_wo_memory_region *region) + { + struct reserved_mem *rmem; + struct device_node *np; +@@ -325,7 +325,7 @@ mtk_wed_mcu_load_firmware(struct mtk_wed_wo *wo) + if (index < 0) + continue; + +- ret = mtk_wed_get_memory_region(wo->hw, index, &mem_region[i]); ++ ret = mtk_wed_get_reserved_memory_region(wo->hw, index, &mem_region[i]); + if (ret) + return ret; + } +-- +2.51.0 + + +From e8e2af046559ce38fcdb522f4cc1337ea0932a70 Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Sat, 11 Mar 2023 16:32:41 +0100 +Subject: [PATCH 507/517] arm64: dts: mt7986: move cpuboot in a dedicated node + +Signed-off-by: Lorenzo Bianconi +--- + arch/arm64/boot/dts/mediatek/mt7986a.dtsi | 21 +++++++++++---------- + 1 file changed, 11 insertions(+), 10 deletions(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi +index 49b5839eb7e9..d7908645dbf8 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi +@@ -121,12 +121,6 @@ wo_dlm1: wo-dlm@151f8000 { + reg = <0 0x151f8000 0 0x2000>; + no-map; + }; +- +- wo_boot: wo-boot@15194000 { +- reg = <0 0x15194000 0 0x1000>; +- no-map; +- }; +- + }; + + soc { +@@ -533,10 +527,11 @@ wed0: wed@15010000 { + interrupt-parent = <&gic>; + interrupts = ; + memory-region = <&wo_emi0>, <&wo_ilm0>, <&wo_dlm0>, +- <&wo_data>, <&wo_boot>; ++ <&wo_data>; + memory-region-names = "wo-emi", "wo-ilm", "wo-dlm", +- "wo-data", "wo-boot"; ++ "wo-data"; + mediatek,wo-ccif = <&wo_ccif0>; ++ mediatek,wo-cpuboot = <&wo_cpuboot>; + }; + + wed1: wed@15011000 { +@@ -546,10 +541,11 @@ wed1: wed@15011000 { + interrupt-parent = <&gic>; + interrupts = ; + memory-region = <&wo_emi1>, <&wo_ilm1>, <&wo_dlm1>, +- <&wo_data>, <&wo_boot>; ++ <&wo_data>; + memory-region-names = "wo-emi", "wo-ilm", "wo-dlm", +- "wo-data", "wo-boot"; ++ "wo-data"; + mediatek,wo-ccif = <&wo_ccif1>; ++ mediatek,wo-cpuboot = <&wo_cpuboot>; + }; + + eth: ethernet@15100000 { +@@ -607,6 +603,11 @@ wo_ccif1: syscon@151ad000 { + interrupts = ; + }; + ++ wo_cpuboot: syscon@15194000 { ++ compatible = "mediatek,mt7986-wo-cpuboot", "syscon"; ++ reg = <0 0x15194000 0 0x1000>; ++ }; ++ + wifi: wifi@18000000 { + compatible = "mediatek,mt7986-wmac"; + reg = <0 0x18000000 0 0x1000000>, +-- +2.51.0 + + +From 4a24e54ea7cff129f0ad3a539c091b92228885d4 Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Sat, 11 Mar 2023 18:13:04 +0100 +Subject: [PATCH 508/517] net: ethernet: mtk_wed: move cpuboot in a dedicated + dts node + +Since the cpuboot memory region is not part of the RAM SoC, move cpuboot +in a deidicated syscon node. +This patch helps to keep backward-compatibility with older version of +uboot codebase where we have a limit of 8 reserved-memory dts child +nodes. +Keep backward-compatibility with older dts version where cpuboot was +defined as reserved-memory child node. + +Signed-off-by: Lorenzo Bianconi +--- + drivers/net/ethernet/mediatek/mtk_wed_mcu.c | 33 ++++++++++++++++----- + drivers/net/ethernet/mediatek/mtk_wed_wo.h | 1 + + 2 files changed, 26 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/ethernet/mediatek/mtk_wed_mcu.c b/drivers/net/ethernet/mediatek/mtk_wed_mcu.c +index ed97ca29b4e5..87f8d0def161 100644 +--- a/drivers/net/ethernet/mediatek/mtk_wed_mcu.c ++++ b/drivers/net/ethernet/mediatek/mtk_wed_mcu.c +@@ -32,14 +32,25 @@ static struct mtk_wed_wo_memory_region mem_region[] = { + }, + }; + +-static u32 wo_r32(u32 reg) ++static u32 wo_r32(struct mtk_wed_wo *wo, u32 reg) + { +- return readl(mem_region[MTK_WED_WO_REGION_BOOT].addr + reg); ++ u32 val; ++ ++ if (!wo->boot_regmap) ++ return readl(mem_region[MTK_WED_WO_REGION_BOOT].addr + reg); ++ ++ if (regmap_read(wo->boot_regmap, reg, &val)) ++ val = ~0; ++ ++ return val; + } + +-static void wo_w32(u32 reg, u32 val) ++static void wo_w32(struct mtk_wed_wo *wo, u32 reg, u32 val) + { +- writel(val, mem_region[MTK_WED_WO_REGION_BOOT].addr + reg); ++ if (wo->boot_regmap) ++ regmap_write(wo->boot_regmap, reg, val); ++ else ++ writel(val, mem_region[MTK_WED_WO_REGION_BOOT].addr + reg); + } + + static struct sk_buff * +@@ -317,6 +328,9 @@ mtk_wed_mcu_load_firmware(struct mtk_wed_wo *wo) + u32 val, boot_cr; + int ret, i; + ++ wo->boot_regmap = syscon_regmap_lookup_by_phandle(wo->hw->node, ++ "mediatek,wo-cpuboot"); ++ + /* load firmware region metadata */ + for (i = 0; i < ARRAY_SIZE(mem_region); i++) { + int index = of_property_match_string(wo->hw->node, +@@ -325,6 +339,9 @@ mtk_wed_mcu_load_firmware(struct mtk_wed_wo *wo) + if (index < 0) + continue; + ++ if (index == MTK_WED_WO_REGION_BOOT && !IS_ERR(wo->boot_regmap)) ++ continue; ++ + ret = mtk_wed_get_reserved_memory_region(wo->hw, index, &mem_region[i]); + if (ret) + return ret; +@@ -373,13 +390,13 @@ mtk_wed_mcu_load_firmware(struct mtk_wed_wo *wo) + boot_cr = MTK_WO_MCU_CFG_LS_WA_BOOT_ADDR_ADDR; + else + boot_cr = MTK_WO_MCU_CFG_LS_WM_BOOT_ADDR_ADDR; +- wo_w32(boot_cr, mem_region[MTK_WED_WO_REGION_EMI].phy_addr >> 16); ++ wo_w32(wo, boot_cr, mem_region[MTK_WED_WO_REGION_EMI].phy_addr >> 16); + /* wo firmware reset */ +- wo_w32(MTK_WO_MCU_CFG_LS_WF_MCCR_CLR_ADDR, 0xc00); ++ wo_w32(wo, MTK_WO_MCU_CFG_LS_WF_MCCR_CLR_ADDR, 0xc00); + +- val = wo_r32(MTK_WO_MCU_CFG_LS_WF_MCU_CFG_WM_WA_ADDR) | ++ val = wo_r32(wo, MTK_WO_MCU_CFG_LS_WF_MCU_CFG_WM_WA_ADDR) | + MTK_WO_MCU_CFG_LS_WF_WM_WA_WM_CPU_RSTB_MASK; +- wo_w32(MTK_WO_MCU_CFG_LS_WF_MCU_CFG_WM_WA_ADDR, val); ++ wo_w32(wo, MTK_WO_MCU_CFG_LS_WF_MCU_CFG_WM_WA_ADDR, val); + out: + release_firmware(fw); + +diff --git a/drivers/net/ethernet/mediatek/mtk_wed_wo.h b/drivers/net/ethernet/mediatek/mtk_wed_wo.h +index c01b1e8428f6..1b06f79662e3 100644 +--- a/drivers/net/ethernet/mediatek/mtk_wed_wo.h ++++ b/drivers/net/ethernet/mediatek/mtk_wed_wo.h +@@ -231,6 +231,7 @@ struct mtk_wed_wo_queue { + struct mtk_wed_wo { + struct mtk_wed_hw *hw; + ++ struct regmap *boot_regmap; + struct mtk_wed_wo_queue q_tx; + struct mtk_wed_wo_queue q_rx; + +-- +2.51.0 + + +From d66901ae6cee48a1b0735d43f780d2b1372a734f Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Sun, 12 Mar 2023 18:51:47 +0100 +Subject: [PATCH 509/517] net: ethernet: mtk_wed: move ilm a dedicated dts node + +Since the ilm memory region is not part of the RAM SoC, move ilm in a +deidicated syscon node. +This patch helps to keep backward-compatibility with older version of +uboot codebase where we have a limit of 8 reserved-memory dts child +nodes. +Keep backward-compatibility with older dts version where ilm was defined +as reserved-memory child node. + +Signed-off-by: Lorenzo Bianconi +--- + drivers/net/ethernet/mediatek/mtk_wed_mcu.c | 45 +++++++++++++++++++-- + 1 file changed, 42 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/mediatek/mtk_wed_mcu.c b/drivers/net/ethernet/mediatek/mtk_wed_mcu.c +index 87f8d0def161..81f77492e1ef 100644 +--- a/drivers/net/ethernet/mediatek/mtk_wed_mcu.c ++++ b/drivers/net/ethernet/mediatek/mtk_wed_mcu.c +@@ -319,6 +319,39 @@ mtk_wed_mcu_run_firmware(struct mtk_wed_wo *wo, const struct firmware *fw) + return 0; + } + ++static int ++mtk_wed_mcu_load_ilm(struct mtk_wed_wo *wo) ++{ ++ struct mtk_wed_wo_memory_region *ilm_region; ++ struct resource res; ++ struct device_node *np; ++ int ret; ++ ++ np = of_parse_phandle(wo->hw->node, "mediatek,wo-ilm", 0); ++ if (!np) ++ return 0; ++ ++ ret = of_address_to_resource(np, 0, &res); ++ of_node_put(np); ++ ++ if (ret < 0) ++ return ret; ++ ++ ilm_region = &mem_region[MTK_WED_WO_REGION_ILM]; ++ ilm_region->phy_addr = res.start; ++ ilm_region->size = resource_size(&res); ++ ilm_region->addr = devm_ioremap(wo->hw->dev, res.start, ++ resource_size(&res)); ++ ++ if (!IS_ERR(ilm_region->addr)) ++ return 0; ++ ++ ret = PTR_ERR(ilm_region->addr); ++ ilm_region->addr = NULL; ++ ++ return ret; ++} ++ + static int + mtk_wed_mcu_load_firmware(struct mtk_wed_wo *wo) + { +@@ -328,14 +361,20 @@ mtk_wed_mcu_load_firmware(struct mtk_wed_wo *wo) + u32 val, boot_cr; + int ret, i; + ++ mtk_wed_mcu_load_ilm(wo); + wo->boot_regmap = syscon_regmap_lookup_by_phandle(wo->hw->node, + "mediatek,wo-cpuboot"); + + /* load firmware region metadata */ + for (i = 0; i < ARRAY_SIZE(mem_region); i++) { +- int index = of_property_match_string(wo->hw->node, +- "memory-region-names", +- mem_region[i].name); ++ int index; ++ ++ if (mem_region[i].addr) ++ continue; ++ ++ index = of_property_match_string(wo->hw->node, ++ "memory-region-names", ++ mem_region[i].name); + if (index < 0) + continue; + +-- +2.51.0 + + +From 660d36d99016c57f240fd84219aed006f716de11 Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Mon, 13 Mar 2023 15:45:16 +0100 +Subject: [PATCH 510/517] net: ethernet: mtk_wed: move dlm a dedicated dts node + +Since the dlm memory region is not part of the RAM SoC, move dlm in a +deidicated syscon node. +This patch helps to keep backward-compatibility with older version of +uboot codebase where we have a limit of 8 reserved-memory dts child +nodes. +Keep backward-compatibility with older dts version where dlm was defined +as reserved-memory child node. + +Signed-off-by: Lorenzo Bianconi +--- + drivers/net/ethernet/mediatek/mtk_wed.c | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/drivers/net/ethernet/mediatek/mtk_wed.c b/drivers/net/ethernet/mediatek/mtk_wed.c +index 1e369a059edd..3c22aaefa267 100644 +--- a/drivers/net/ethernet/mediatek/mtk_wed.c ++++ b/drivers/net/ethernet/mediatek/mtk_wed.c +@@ -1333,6 +1333,24 @@ mtk_wed_rro_alloc(struct mtk_wed_device *dev) + struct device_node *np; + int index; + ++ np = of_parse_phandle(dev->hw->node, "mediatek,wo-dlm", 0); ++ if (np) { ++ struct resource res; ++ int ret; ++ ++ ret = of_address_to_resource(np, 0, &res); ++ of_node_put(np); ++ ++ if (ret < 0) ++ return ret; ++ ++ dev->rro.miod_phys = res.start; ++ goto out; ++ } ++ ++ /* For backward compatibility, we need to check if DLM ++ * node is defined through reserved memory property. ++ */ + index = of_property_match_string(dev->hw->node, "memory-region-names", + "wo-dlm"); + if (index < 0) +@@ -1349,6 +1367,7 @@ mtk_wed_rro_alloc(struct mtk_wed_device *dev) + return -ENODEV; + + dev->rro.miod_phys = rmem->base; ++out: + dev->rro.fdbk_phys = MTK_WED_MIOD_COUNT + dev->rro.miod_phys; + + return mtk_wed_rro_ring_alloc(dev, &dev->rro.ring, +-- +2.51.0 + + +From ddab7743c6cc805854cde7032aa185f501007ae3 Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Mon, 13 Mar 2023 15:10:56 +0100 +Subject: [PATCH 511/517] arm64: dts: mt7986: move ilm in a dedicated node + +Since the ilm memory region is not part of the RAM SoC, move ilm in a +deidicated syscon node. +This patch helps to keep backward-compatibility with older version of +uboot codebase where we have a limit of 8 reserved-memory dts child +nodes. + +Signed-off-by: Lorenzo Bianconi +--- + arch/arm64/boot/dts/mediatek/mt7986a.dtsi | 34 +++++++++++------------ + 1 file changed, 16 insertions(+), 18 deletions(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi +index d7908645dbf8..60e12fba069c 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi +@@ -97,16 +97,6 @@ wo_emi1: wo-emi@4fd40000 { + no-map; + }; + +- wo_ilm0: wo-ilm@151e0000 { +- reg = <0 0x151e0000 0 0x8000>; +- no-map; +- }; +- +- wo_ilm1: wo-ilm@151f0000 { +- reg = <0 0x151f0000 0 0x8000>; +- no-map; +- }; +- + wo_data: wo-data@4fd80000 { + reg = <0 0x4fd80000 0 0x240000>; + no-map; +@@ -526,11 +516,10 @@ wed0: wed@15010000 { + reg = <0 0x15010000 0 0x1000>; + interrupt-parent = <&gic>; + interrupts = ; +- memory-region = <&wo_emi0>, <&wo_ilm0>, <&wo_dlm0>, +- <&wo_data>; +- memory-region-names = "wo-emi", "wo-ilm", "wo-dlm", +- "wo-data"; ++ memory-region = <&wo_emi0>, <&wo_dlm0>, <&wo_data>; ++ memory-region-names = "wo-emi", "wo-dlm", "wo-data"; + mediatek,wo-ccif = <&wo_ccif0>; ++ mediatek,wo-ilm = <&wo_ilm0>; + mediatek,wo-cpuboot = <&wo_cpuboot>; + }; + +@@ -540,11 +529,10 @@ wed1: wed@15011000 { + reg = <0 0x15011000 0 0x1000>; + interrupt-parent = <&gic>; + interrupts = ; +- memory-region = <&wo_emi1>, <&wo_ilm1>, <&wo_dlm1>, +- <&wo_data>; +- memory-region-names = "wo-emi", "wo-ilm", "wo-dlm", +- "wo-data"; ++ memory-region = <&wo_emi1>, <&wo_dlm1>, <&wo_data>; ++ memory-region-names = "wo-emi", "wo-dlm", "wo-data"; + mediatek,wo-ccif = <&wo_ccif1>; ++ mediatek,wo-ilm = <&wo_ilm1>; + mediatek,wo-cpuboot = <&wo_cpuboot>; + }; + +@@ -603,6 +591,16 @@ wo_ccif1: syscon@151ad000 { + interrupts = ; + }; + ++ wo_ilm0: syscon@151e0000 { ++ compatible = "mediatek,mt7986-wo-ilm", "syscon"; ++ reg = <0 0x151e0000 0 0x8000>; ++ }; ++ ++ wo_ilm1: syscon@151f0000 { ++ compatible = "mediatek,mt7986-wo-ilm", "syscon"; ++ reg = <0 0x151f0000 0 0x8000>; ++ }; ++ + wo_cpuboot: syscon@15194000 { + compatible = "mediatek,mt7986-wo-cpuboot", "syscon"; + reg = <0 0x15194000 0 0x1000>; +-- +2.51.0 + + +From f8607a0f13c5a3138a6a6c20d8954f0abeb98cc5 Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Mon, 13 Mar 2023 15:53:30 +0100 +Subject: [PATCH 512/517] arm64: dts: mt7986: move dlm in a dedicated node + +Since the dlm memory region is not part of the RAM SoC, move dlm in a +deidicated syscon node. +This patch helps to keep backward-compatibility with older version of +uboot codebase where we have a limit of 8 reserved-memory dts child +nodes. + +Signed-off-by: Lorenzo Bianconi +--- + arch/arm64/boot/dts/mediatek/mt7986a.dtsi | 30 ++++++++++++----------- + 1 file changed, 16 insertions(+), 14 deletions(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi +index 60e12fba069c..f8a99686e374 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi +@@ -101,16 +101,6 @@ wo_data: wo-data@4fd80000 { + reg = <0 0x4fd80000 0 0x240000>; + no-map; + }; +- +- wo_dlm0: wo-dlm@151e8000 { +- reg = <0 0x151e8000 0 0x2000>; +- no-map; +- }; +- +- wo_dlm1: wo-dlm@151f8000 { +- reg = <0 0x151f8000 0 0x2000>; +- no-map; +- }; + }; + + soc { +@@ -516,10 +506,11 @@ wed0: wed@15010000 { + reg = <0 0x15010000 0 0x1000>; + interrupt-parent = <&gic>; + interrupts = ; +- memory-region = <&wo_emi0>, <&wo_dlm0>, <&wo_data>; +- memory-region-names = "wo-emi", "wo-dlm", "wo-data"; ++ memory-region = <&wo_emi0>, <&wo_data>; ++ memory-region-names = "wo-emi", "wo-data"; + mediatek,wo-ccif = <&wo_ccif0>; + mediatek,wo-ilm = <&wo_ilm0>; ++ mediatek,wo-dlm = <&wo_dlm0>; + mediatek,wo-cpuboot = <&wo_cpuboot>; + }; + +@@ -529,10 +520,11 @@ wed1: wed@15011000 { + reg = <0 0x15011000 0 0x1000>; + interrupt-parent = <&gic>; + interrupts = ; +- memory-region = <&wo_emi1>, <&wo_dlm1>, <&wo_data>; +- memory-region-names = "wo-emi", "wo-dlm", "wo-data"; ++ memory-region = <&wo_emi1>, <&wo_data>; ++ memory-region-names = "wo-emi", "wo-data"; + mediatek,wo-ccif = <&wo_ccif1>; + mediatek,wo-ilm = <&wo_ilm1>; ++ mediatek,wo-dlm = <&wo_dlm1>; + mediatek,wo-cpuboot = <&wo_cpuboot>; + }; + +@@ -601,6 +593,16 @@ wo_ilm1: syscon@151f0000 { + reg = <0 0x151f0000 0 0x8000>; + }; + ++ wo_dlm0: syscon@151e8000 { ++ compatible = "mediatek,mt7986-wo-dlm", "syscon"; ++ reg = <0 0x151e8000 0 0x2000>; ++ }; ++ ++ wo_dlm1: syscon@151f8000 { ++ compatible = "mediatek,mt7986-wo-dlm", "syscon"; ++ reg = <0 0x151f8000 0 0x2000>; ++ }; ++ + wo_cpuboot: syscon@15194000 { + compatible = "mediatek,mt7986-wo-cpuboot", "syscon"; + reg = <0 0x15194000 0 0x1000>; +-- +2.51.0 + + +From 74446121fe51ebdad4b00400a1b92340f0a61fee Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= +Date: Mon, 3 Nov 2025 15:51:12 +0100 +Subject: [PATCH 513/517] + /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/950-smartrg-i2c-led-driver.patch + +--- + drivers/leds/Kconfig | 10 ++++++++++ + drivers/leds/Makefile | 1 + + 2 files changed, 11 insertions(+) + +diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig +index c275963c498c..7dd68878d84b 100644 +--- a/drivers/leds/Kconfig ++++ b/drivers/leds/Kconfig +@@ -977,6 +977,16 @@ source "drivers/leds/flash/Kconfig" + comment "RGB LED drivers" + source "drivers/leds/rgb/Kconfig" + ++config LEDS_SMARTRG_LED ++ tristate "LED support for Adtran SmartRG" ++ depends on LEDS_CLASS && I2C && OF ++ help ++ This option enables support for the Adtran SmartRG platform ++ system LED driver. ++ ++ To compile this driver as a module, choose M here: the module ++ will be called leds-smartrg-system. ++ + comment "LED Triggers" + source "drivers/leds/trigger/Kconfig" + +diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile +index 32241451b805..1eabbf823afe 100644 +--- a/drivers/leds/Makefile ++++ b/drivers/leds/Makefile +@@ -81,6 +81,7 @@ obj-$(CONFIG_LEDS_POWERNV) += leds-powernv.o + obj-$(CONFIG_LEDS_PWM) += leds-pwm.o + obj-$(CONFIG_LEDS_REGULATOR) += leds-regulator.o + obj-$(CONFIG_LEDS_SC27XX_BLTC) += leds-sc27xx-bltc.o ++obj-$(CONFIG_LEDS_SMARTRG_LED) += leds-smartrg-system.o + obj-$(CONFIG_LEDS_SUN50I_A100) += leds-sun50i-a100.o + obj-$(CONFIG_LEDS_ST1202) += leds-st1202.o + obj-$(CONFIG_LEDS_SUNFIRE) += leds-sunfire.o +-- +2.51.0 + + +From ce803bc11bfcaf5bb6c01c942ecd8a1d3549164c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= +Date: Mon, 3 Nov 2025 15:51:12 +0100 +Subject: [PATCH 514/517] + /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/955-dts-mt7968a-bpi-r3-add-label-to-gmac-for-sfp1-port.patch + +--- + arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3.dts | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3.dts b/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3.dts +index 5e0c2941928d..db8928987342 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3.dts +@@ -195,6 +195,7 @@ gmac1: mac@1 { + phy-mode = "2500base-x"; + sfp = <&sfp1>; + managed = "in-band-status"; ++ openwrt,netdev-name = "sfp1"; + }; + + mdio: mdio-bus { +-- +2.51.0 + + +From 4df705cab8dd3bb7be1c5f456cda96d665847a47 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Thu, 6 Feb 2025 05:07:20 +0000 +Subject: [PATCH 515/517] mtd: spinand: add work-around to prevent bootloader + wiping mtdparts + +ASUS makes use of U-Boot's fdt_fixup_mtdparts() function which applies +the partitions defined in U-Boot's mtdparts and mtdids environment +variables to the devicetree passed over to Linux. + +The undesired side-effect is that in this way also all additional +properties and child nodes get wiped, preventing NVMEM cells to be +defined for MTD partitions or UBI volumes. + +To work-around this issue, add an additional compatible string +'u-boot-dont-touch-spi-nand' which can be used instead of 'spi-nand' in +case the replacement of the MTD partitions by U-Boot should be skipped +alltogether. + +In practise this is mostly relevant for SPI-NAND which anyway comes only +with two partitions nowadays: 'Bootloader' and 'UBI_DEV'. Hence this +work-around is applicable for SPI-NAND only. Similar work-arounds for +other MTD devices can be created as well should they actually be needed. + +Signed-off-by: Daniel Golle +--- + drivers/mtd/nand/spi/core.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c +index a74bda5c4965..1dcffc2bbd18 100644 +--- a/drivers/mtd/nand/spi/core.c ++++ b/drivers/mtd/nand/spi/core.c +@@ -1668,6 +1668,7 @@ static int spinand_remove(struct spi_mem *mem) + + static const struct spi_device_id spinand_ids[] = { + { .name = "spi-nand" }, ++ { .name = "u-boot-dont-touch-spi-nand" }, + { /* sentinel */ }, + }; + MODULE_DEVICE_TABLE(spi, spinand_ids); +@@ -1675,6 +1676,7 @@ MODULE_DEVICE_TABLE(spi, spinand_ids); + #ifdef CONFIG_OF + static const struct of_device_id spinand_of_ids[] = { + { .compatible = "spi-nand" }, ++ { .compatible = "u-boot-dont-touch-spi-nand" }, + { /* sentinel */ }, + }; + MODULE_DEVICE_TABLE(of, spinand_of_ids); +-- +2.51.0 + + +From 3c06beabf11952531131a8c93d4a7e11267b2b49 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= +Date: Mon, 3 Nov 2025 15:51:13 +0100 +Subject: [PATCH 516/517] + /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/965-dts-mt7988a-add-trng-support.patch + +--- + arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +index 5717729f563c..d907769259ca 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +@@ -1319,4 +1319,8 @@ timer { + , + ; + }; ++ ++ trng { ++ compatible = "mediatek,mt7988-rng"; ++ }; + }; +-- +2.51.0 + + +From 1e87e9227c60dd7f73de3aec9882ffd5423113ad Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= +Date: Thu, 2 Oct 2025 11:54:23 +0200 +Subject: [PATCH 517/517] Pull OpenWrt One device tree from OpenWrt master + +The commit used: 915a57ccd9086db88ee74cfa531ff13f8652a447 +--- + .../boot/dts/mediatek/mt7981b-openwrt-one.dts | 460 +++++++++++++++++- + 1 file changed, 457 insertions(+), 3 deletions(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7981b-openwrt-one.dts b/arch/arm64/boot/dts/mediatek/mt7981b-openwrt-one.dts +index 4f6cbb491287..5f54506b2cba 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7981b-openwrt-one.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7981b-openwrt-one.dts +@@ -1,15 +1,469 @@ +-// SPDX-License-Identifier: GPL-2.0-only OR MIT ++// SPDX-License-Identifier: (GPL-2.0 OR MIT) + + /dts-v1/; +- + #include "mt7981b.dtsi" + + / { +- compatible = "openwrt,one", "mediatek,mt7981b"; + model = "OpenWrt One"; ++ compatible = "openwrt,one", "mediatek,mt7981"; ++ ++ aliases { ++ ethernet0 = &gmac1; ++ label-mac-device = &gmac0; ++ led-boot = &led_status_white; ++ led-failsafe = &led_status_red; ++ led-running = &led_status_green; ++ led-upgrade = &led_status_green; ++ serial0 = &uart0; ++ }; ++ ++ chosen { ++ stdout-path = "serial0:115200n8"; ++ rootdisk = <&ubi_fit_volume>; ++ }; + + memory@40000000 { + reg = <0 0x40000000 0 0x40000000>; + device_type = "memory"; + }; ++ ++ reg_3p3v: regulator-3p3v { ++ compatible = "regulator-fixed"; ++ regulator-name = "fixed-3.3V"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ reg_5v: regulator-5v { ++ compatible = "regulator-fixed"; ++ regulator-name = "fixed-5V"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ gpio-keys { ++ compatible = "gpio-keys"; ++ ++ user { ++ label = "user"; ++ linux,code = ; ++ gpios = <&pio 0 GPIO_ACTIVE_LOW>; ++ }; ++ ++ reset { ++ label = "reset"; ++ linux,code = ; ++ gpios = <&pio 1 GPIO_ACTIVE_LOW>; ++ }; ++ }; ++ ++ pwm-leds { ++ compatible = "pwm-leds"; ++ ++ led_status_white: led-0 { ++ color = ; ++ function = LED_FUNCTION_STATUS; ++ pwms = <&pwm 0 10000>; ++ linux,default-trigger = "pattern"; ++ led-pattern = <0 500 25 500>; ++ }; ++ ++ led_status_green: led-1 { ++ color = ; ++ function = LED_FUNCTION_STATUS; ++ pwms = <&pwm 1 10000>; ++ }; ++ }; ++ ++ gpio-leds { ++ compatible = "gpio-leds"; ++ ++ led_status_red: led-0 { ++ color = ; ++ function = LED_FUNCTION_STATUS; ++ gpios = <&pio 9 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ led-1 { ++ function = LED_FUNCTION_LAN; ++ color = ; ++ gpios = <&pio 34 GPIO_ACTIVE_LOW>; ++ }; ++ ++ led-2 { ++ function = LED_FUNCTION_LAN; ++ color = ; ++ gpios = <&pio 35 GPIO_ACTIVE_LOW>; ++ }; ++ }; ++ ++ gpio-export { ++ compatible = "gpio-export"; ++ ++ gpio-0 { ++ gpio-export,name = "mikrobus-reset"; ++ gpio-export,output = <1>; ++ gpios = <&pio 2 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ gpio-1 { ++ gpio-export,name = "watchdog-enable"; ++ gpio-export,output = <1>; ++ gpios = <&pio 11 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ gpio-2 { ++ gpio-export,name = "usb-enable"; ++ gpio-export,output = <1>; ++ gpios = <&pio 14 GPIO_ACTIVE_HIGH>; ++ }; ++ }; ++ ++ gpio-watchdog { ++ compatible = "linux,wdt-gpio"; ++ gpios = <&pio 8 GPIO_ACTIVE_LOW>; ++ hw_algo = "toggle"; ++ hw_margin_ms = <25000>; ++ always-running; ++ }; ++}; ++ ++ð { ++ status = "okay"; ++ ++ gmac0: mac@0 { ++ compatible = "mediatek,eth-mac"; ++ reg = <0>; ++ phy-handle = <&phy15>; ++ phy-mode = "2500base-x"; ++ nvmem-cell-names = "mac-address"; ++ nvmem-cells = <&macaddr_factory_24>; ++ }; ++ ++ gmac1: mac@1 { ++ compatible = "mediatek,eth-mac"; ++ reg = <1>; ++ phy-mode = "gmii"; ++ phy-handle = <&int_gbe_phy>; ++ }; ++}; ++ ++&mdio_bus { ++ phy15: phy@f { ++ reg = <0xf>; ++ ++ airoha,pnswap-rx; ++ ++ interrupt-parent = <&pio>; ++ interrupts = <38 IRQ_TYPE_EDGE_FALLING>; ++ reset-gpios = <&pio 39 GPIO_ACTIVE_LOW>; ++ reset-assert-us = <10000>; ++ reset-deassert-us = <20000>; ++ ++ phy-mode = "2500base-x"; ++ full-duplex; ++ pause; ++ ++ leds { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ led@0 { ++ reg = <0>; ++ function = LED_FUNCTION_WAN; ++ color = ; ++ }; ++ ++ led@1 { ++ reg = <1>; ++ function = LED_FUNCTION_WAN; ++ color = ; ++ }; ++ }; ++ }; ++}; ++ ++&crypto { ++ status = "okay"; ++}; ++ ++&pio { ++ spi0_flash_pins: spi0-pins { ++ mux { ++ function = "spi"; ++ groups = "spi0", "spi0_wp_hold"; ++ }; ++ ++ conf-pu { ++ pins = "SPI0_CS", "SPI0_HOLD", "SPI0_WP"; ++ drive-strength = ; ++ bias-pull-up = ; ++ }; ++ ++ conf-pd { ++ pins = "SPI0_CLK", "SPI0_MOSI", "SPI0_MISO"; ++ drive-strength = ; ++ bias-pull-down = ; ++ }; ++ }; ++ ++ spi1_flash_pins: spi1-pins { ++ mux { ++ function = "spi"; ++ groups = "spi1_1"; ++ }; ++ ++ conf-pu { ++ pins = "SPI1_CS"; ++ drive-strength = ; ++ bias-pull-up = ; ++ }; ++ ++ conf-pd { ++ pins = "SPI1_CLK", "SPI1_MOSI", "SPI1_MISO"; ++ drive-strength = ; ++ bias-pull-down = ; ++ }; ++ }; ++ ++ spi2_flash_pins: spi2-pins { ++ mux { ++ function = "spi"; ++ groups = "spi2"; ++ }; ++ ++ conf-pu { ++ pins = "SPI2_CS", "SPI2_WP"; ++ drive-strength = ; ++ bias-pull-up = ; ++ }; ++ ++ conf-pd { ++ pins = "SPI2_CLK", "SPI2_MOSI", "SPI2_MISO"; ++ drive-strength = ; ++ bias-pull-down = ; ++ }; ++ }; ++ ++ i2c_pins: i2c-pins { ++ mux { ++ function = "i2c"; ++ groups = "i2c0_0"; ++ }; ++ }; ++ ++ uart2_pins: uart2-pins { ++ mux { ++ function = "uart"; ++ groups = "uart2_0_tx_rx"; ++ }; ++ }; ++ ++ pwm_pins: pwm-pins { ++ mux { ++ function = "pwm"; ++ groups = "pwm0_0", "pwm1_1"; ++ }; ++ }; ++ ++ pcie_pins: pcie-pins { ++ mux { ++ function = "pcie"; ++ groups = "pcie_pereset"; ++ }; ++ }; ++}; ++ ++&pwm { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pwm_pins>; ++ status = "okay"; ++}; ++ ++&i2c0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c_pins>; ++ status = "okay"; ++ ++ rtc@51 { ++ compatible = "nxp,pcf8563"; ++ reg = <0x51>; ++ }; ++}; ++ ++&spi0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spi0_flash_pins>; ++ cs-gpios = <0>, <0>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ flash@1 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "spi-nand"; ++ reg = <1>; ++ spi-max-frequency = <52000000>; ++ ++ spi-cal-enable; ++ spi-cal-mode = "read-data"; ++ spi-cal-datalen = <7>; ++ spi-cal-data = /bits/ 8 <0x53 0x50 0x49 0x4E 0x41 0x4E 0x44>; ++ spi-cal-addrlen = <5>; ++ spi-cal-addr = /bits/ 32 <0x0 0x0 0x0 0x0 0x0>; ++ ++ partitions { ++ compatible = "fixed-partitions"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ partition@0 { ++ label = "bl2"; ++ reg = <0x0 0x100000>; ++ read-only; ++ }; ++ ++ partition@580000 { ++ label = "ubi"; ++ reg = <0x100000 0xFF00000>; ++ compatible = "linux,ubi"; ++ ++ volumes { ++ ubi_fit_volume: ubi-volume-fit { ++ volname = "fit"; ++ }; ++ }; ++ }; ++ }; ++ }; ++}; ++ ++&spi1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spi1_flash_pins>; ++ status = "okay"; ++}; ++ ++&spi2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spi2_flash_pins>; ++ status = "okay"; ++ ++ flash@0 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "jedec,spi-nor"; ++ reg = <0>; ++ ++ spi-max-frequency = <52000000>; ++ ++ partitions { ++ compatible = "fixed-partitions"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ partition@0 { ++ label = "bl2-nor"; ++ reg = <0x00000 0x40000>; ++ }; ++ ++ partition@40000 { ++ label = "factory"; ++ reg = <0x40000 0xc0000>; ++ read-only; ++ ++ nvmem-layout { ++ compatible = "fixed-layout"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ eeprom_factory_0: eeprom@0 { ++ reg = <0x0 0x1000>; ++ }; ++ ++ macaddr_factory_4: macaddr@4 { ++ reg = <0x4 0x6>; ++ compatible = "mac-base"; ++ #nvmem-cell-cells = <1>; ++ }; ++ ++ macaddr_factory_24: macaddr@24 { ++ reg = <0x24 0x6>; ++ compatible = "mac-base"; ++ }; ++ }; ++ }; ++ ++ partition@100000 { ++ label = "fip-nor"; ++ reg = <0x100000 0x80000>; ++ }; ++ ++ partition@180000 { ++ label = "recovery"; ++ reg = <0x180000 0xc80000>; ++ }; ++ }; ++ }; ++}; ++ ++&xhci { ++ phys = <&u2port0 PHY_TYPE_USB2>; ++ vusb33-supply = <®_3p3v>; ++ vbus-supply = <®_5v>; ++ mediatek,u3p-dis-msk = <0x01>; ++ status = "okay"; ++}; ++ ++&uart0 { ++ status = "okay"; ++}; ++ ++&uart2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&uart2_pins>; ++ status = "okay"; ++}; ++ ++&usb_phy { ++ status = "okay"; ++}; ++ ++&watchdog { ++ status = "okay"; ++}; ++ ++&wifi { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ nvmem-cells = <&eeprom_factory_0>; ++ nvmem-cell-names = "eeprom"; ++ status = "okay"; ++ ++ band@0 { ++ reg = <0>; ++ nvmem-cells = <&macaddr_factory_4 0>; ++ nvmem-cell-names = "mac-address"; ++ }; ++ ++ band@1 { ++ reg = <1>; ++ nvmem-cells = <&macaddr_factory_4 7>; ++ nvmem-cell-names = "mac-address"; ++ }; ++}; ++ ++&pcie { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pcie_pins>; ++ status = "okay"; ++}; ++ ++&sgmiisys0 { ++ /delete-node/ mediatek,pnswap; + }; +-- +2.51.0 + -- cgit v1.2.3