diff options
author | John Crispin <john@phrozen.org> | 2019-08-02 10:33:28 +0200 |
---|---|---|
committer | John Crispin <john@phrozen.org> | 2019-08-02 10:36:11 +0200 |
commit | 66458c49aa14ebc9ba2e4f9b6a323b8ff122807b (patch) | |
tree | 43cd8477d8341136c691d49b139038b14793f635 /target/linux/mediatek | |
parent | cb49e46a8a4526d86270ced3ba3aa90225ca82d7 (diff) | |
download | upstream-66458c49aa14ebc9ba2e4f9b6a323b8ff122807b.tar.gz upstream-66458c49aa14ebc9ba2e4f9b6a323b8ff122807b.tar.bz2 upstream-66458c49aa14ebc9ba2e4f9b6a323b8ff122807b.zip |
mediatek: add v4.19 support
Bump the target to v4.19. Add a patch with additional eth driver
fixes/features that MTK provided aswell as the driver for the new mt7530
switch.
Signed-off-by: John Crispin <john@phrozen.org>
Diffstat (limited to 'target/linux/mediatek')
35 files changed, 13220 insertions, 3 deletions
diff --git a/target/linux/mediatek/base-files/etc/hotplug.d/iface/99-mtk-lro b/target/linux/mediatek/base-files/etc/hotplug.d/iface/99-mtk-lro new file mode 100755 index 0000000000..9a2ffaeed8 --- /dev/null +++ b/target/linux/mediatek/base-files/etc/hotplug.d/iface/99-mtk-lro @@ -0,0 +1,14 @@ +[ ifup = "$ACTION" ] && { + [ -n "$DEVICE" ] && { + if [ "$INTERFACE" == "lan" ]; then + if [ -f /usr/sbin/ethtool ]; then + ifname=eth0 + lan_ip=`uci -q get network.lan.ipaddr` + ethdrv=`ethtool -i $ifname | grep mtk_soc_eth` + [ -n "$ethdrv" ] && { + ethtool -N $ifname flow-type tcp4 dst-ip $lan_ip loc 0 + } + fi + fi + } +} diff --git a/target/linux/mediatek/files-4.19/arch/arm/boot/dts/mt7629-lynx-rfb.dts b/target/linux/mediatek/files-4.19/arch/arm/boot/dts/mt7629-lynx-rfb.dts new file mode 100755 index 0000000000..f3fadd301a --- /dev/null +++ b/target/linux/mediatek/files-4.19/arch/arm/boot/dts/mt7629-lynx-rfb.dts @@ -0,0 +1,314 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2019 MediaTek Inc. + * Author: Ryder Lee <ryder.lee@mediatek.com> + */ + +/dts-v1/; +#include <dt-bindings/input/input.h> +#include "mt7629.dtsi" + +/ { + model = "MediaTek MT7629 reference board"; + compatible = "mediatek,mt7629-rfb", "mediatek,mt7629"; + + aliases { + serial0 = &uart0; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + gpio-keys { + compatible = "gpio-keys"; + + reset { + label = "factory"; + linux,code = <KEY_RESTART>; + gpios = <&pio 60 GPIO_ACTIVE_LOW>; + }; + + wps { + label = "wps"; + linux,code = <KEY_WPS_BUTTON>; + gpios = <&pio 58 GPIO_ACTIVE_LOW>; + }; + }; + + gsw: gsw@0 { + compatible = "mediatek,mt753x"; + mediatek,ethsys = <ðsys>; + #address-cells = <1>; + #size-cells = <0>; + }; + + memory@40000000 { + device_type = "memory"; + reg = <0 0x40000000 0 0x10000000>; + }; + + 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; + }; +}; + +ð { + pinctrl-names = "default"; + pinctrl-0 = <&ephy_leds_pins>; + status = "okay"; + + gmac0: mac@0 { + compatible = "mediatek,eth-mac"; + reg = <0>; + phy-mode = "sgmii"; + fixed-link { + speed = <1000>; + full-duplex; + pause; + }; + }; + + gmac1: mac@1 { + compatible = "mediatek,eth-mac"; + reg = <1>; + phy-handle = <&phy0>; + }; + + mdio: mdio-bus { + #address-cells = <1>; + #size-cells = <0>; + + phy0: ethernet-phy@0 { + reg = <0>; + phy-mode = "gmii"; + }; + }; +}; + +&gsw { + mediatek,mdio = <&mdio>; + mediatek,portmap = "llllw"; + mediatek,mdio_master_pinmux = <0>; + reset-gpios = <&pio 28 0>; + interrupt-parent = <&pio>; + interrupts = <6 IRQ_TYPE_LEVEL_HIGH>; + status = "okay"; + + port6: port@6 { + compatible = "mediatek,mt753x-port"; + reg = <6>; + phy-mode = "sgmii"; + fixed-link { + speed = <2500>; + full-duplex; + }; + }; +}; + +&i2c { + pinctrl-names = "default"; + pinctrl-0 = <&i2c_pins>; + status = "okay"; +}; + +&qspi { + pinctrl-names = "default"; + pinctrl-0 = <&qspi_pins>; + status = "okay"; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "u-boot"; + reg = <0x00000 0x60000>; + read-only; + }; + + partition@60000 { + label = "u-boot-env"; + reg = <0x60000 0x10000>; + read-only; + }; + + factory: partition@70000 { + label = "Factory"; + reg = <0x70000 0x40000>; + read-only; + }; + + partition@b0000 { + label = "Kernel"; + reg = <0xb0000 0xb50000>; + }; + }; + }; +}; + +&pio { + eth_pins: eth-pins { + mux { + function = "eth"; + groups = "mdc_mdio"; + }; + }; + + ephy_leds_pins: ephy-leds-pins { + mux { + function = "led"; + groups = "gphy_leds_0", "ephy_leds"; + }; + }; + + i2c_pins: i2c-pins { + mux { + function = "i2c"; + groups = "i2c_0"; + }; + + conf { + pins = "I2C_SDA", "I2C_SCL"; + drive-strength = <4>; + bias-disable; + }; + }; + + pcie_pins: pcie-pins { + mux { + function = "pcie"; + groups = "pcie_clkreq", + "pcie_pereset", + "pcie_wake"; + }; + }; + + pwm_pins: pwm-pins { + mux { + function = "pwm"; + groups = "pwm_0"; + }; + }; + + /* Serial NAND is shared pin with SPI-NOR */ + serial_nand_pins: serial-nand-pins { + mux { + function = "flash"; + groups = "snfi"; + }; + }; + + spi_pins: spi-pins { + mux { + function = "spi"; + groups = "spi_0"; + }; + }; + + /* SPI-NOR is shared pin with serial NAND */ + qspi_pins: qspi-pins { + mux { + function = "flash"; + groups = "spi_nor"; + }; + }; + + uart0_pins: uart0-pins { + mux { + function = "uart"; + groups = "uart0_txd_rxd" ; + }; + }; + + uart1_pins: uart1-pins { + mux { + function = "uart"; + groups = "uart1_0_tx_rx" ; + }; + }; + + uart2_pins: uart2-pins { + mux { + function = "uart"; + groups = "uart2_0_txd_rxd" ; + }; + }; + + watchdog_pins: watchdog-pins { + mux { + function = "watchdog"; + groups = "watchdog"; + }; + }; + + wmac0_pins: wmac0-pins { + mux { + function = "wifi"; + groups = "wf0_5g"; + drive-strength = <4>; + }; + }; + + wmac1_pins: wmac0-pins { + mux { + function = "wifi"; + groups = "wf0_2g"; + drive-strength = <4>; + }; + }; +}; + +&spi { + pinctrl-names = "default"; + pinctrl-0 = <&spi_pins>; + status = "okay"; +}; + +&uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_pins>; + status = "okay"; +}; + +&ssusb { + vusb33-supply = <®_3p3v>; + vbus-supply = <®_5v>; + status = "okay"; +}; + +&u3phy1 { + status = "okay"; +}; + +&watchdog { + pinctrl-names = "default"; + pinctrl-0 = <&watchdog_pins>; + status = "okay"; +}; + +&wmac { + pinctrl-names = "default"; + pinctrl-0 = <&wmac0_pins>; + pinctrl-1 = <&wmac1_pins>; + status = "okay"; +}; diff --git a/target/linux/mediatek/files-4.19/arch/arm/boot/dts/mt7629-rfb.dts b/target/linux/mediatek/files-4.19/arch/arm/boot/dts/mt7629-rfb.dts new file mode 100755 index 0000000000..8043238fea --- /dev/null +++ b/target/linux/mediatek/files-4.19/arch/arm/boot/dts/mt7629-rfb.dts @@ -0,0 +1,294 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2019 MediaTek Inc. + * Author: Ryder Lee <ryder.lee@mediatek.com> + */ + +/dts-v1/; +#include <dt-bindings/input/input.h> +#include "mt7629.dtsi" + +/ { + model = "MediaTek MT7629 reference board"; + compatible = "mediatek,mt7629-rfb", "mediatek,mt7629"; + + aliases { + serial0 = &uart0; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + gpio-keys { + compatible = "gpio-keys"; + + reset { + label = "factory"; + linux,code = <KEY_RESTART>; + gpios = <&pio 60 GPIO_ACTIVE_LOW>; + }; + + wps { + label = "wps"; + linux,code = <KEY_WPS_BUTTON>; + gpios = <&pio 58 GPIO_ACTIVE_LOW>; + }; + }; + + memory@40000000 { + device_type = "memory"; + reg = <0 0x40000000 0 0x10000000>; + }; + + 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; + }; + + rtkgsw: rtkgsw@0 { + compatible = "mediatek,rtk-gsw"; + mediatek,ethsys = <ðsys>; + mediatek,mdio = <&mdio>; + status = "okay"; + }; +}; + +ð { + pinctrl-names = "default"; + pinctrl-0 = <&ephy_leds_pins>; + status = "okay"; + + gmac0: mac@0 { + compatible = "mediatek,eth-mac"; + reg = <0>; + phy-mode = "sgmii"; + fixed-link { + speed = <1000>; + full-duplex; + pause; + }; + }; + + gmac1: mac@1 { + compatible = "mediatek,eth-mac"; + reg = <1>; + phy-handle = <&phy0>; + }; + + mdio: mdio-bus { + #address-cells = <1>; + #size-cells = <0>; + + phy0: ethernet-phy@0 { + reg = <0>; + phy-mode = "gmii"; + }; + }; +}; + +&i2c { + pinctrl-names = "default"; + pinctrl-0 = <&i2c_pins>; + status = "okay"; +}; + +&qspi { + pinctrl-names = "default"; + pinctrl-0 = <&qspi_pins>; + status = "okay"; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "u-boot"; + reg = <0x00000 0x60000>; + read-only; + }; + + partition@60000 { + label = "u-boot-env"; + reg = <0x60000 0x10000>; + read-only; + }; + + factory: partition@70000 { + label = "Factory"; + reg = <0x70000 0x40000>; + read-only; + }; + + partition@b0000 { + label = "Kernel"; + reg = <0xb0000 0xb50000>; + }; + }; + }; +}; + +&pio { + eth_pins: eth-pins { + mux { + function = "eth"; + groups = "mdc_mdio"; + }; + }; + + ephy_leds_pins: ephy-leds-pins { + mux { + function = "led"; + groups = "gphy_leds_0", "ephy_leds"; + }; + }; + + i2c_pins: i2c-pins { + mux { + function = "i2c"; + groups = "i2c_0"; + }; + + conf { + pins = "I2C_SDA", "I2C_SCL"; + drive-strength = <4>; + bias-disable; + }; + }; + + pcie_pins: pcie-pins { + mux { + function = "pcie"; + groups = "pcie_clkreq", + "pcie_pereset", + "pcie_wake"; + }; + }; + + pwm_pins: pwm-pins { + mux { + function = "pwm"; + groups = "pwm_0"; + }; + }; + + /* Serial NAND is shared pin with SPI-NOR */ + serial_nand_pins: serial-nand-pins { + mux { + function = "flash"; + groups = "snfi"; + }; + }; + + spi_pins: spi-pins { + mux { + function = "spi"; + groups = "spi_0"; + }; + }; + + /* SPI-NOR is shared pin with serial NAND */ + qspi_pins: qspi-pins { + mux { + function = "flash"; + groups = "spi_nor"; + }; + }; + + uart0_pins: uart0-pins { + mux { + function = "uart"; + groups = "uart0_txd_rxd" ; + }; + }; + + uart1_pins: uart1-pins { + mux { + function = "uart"; + groups = "uart1_0_tx_rx" ; + }; + }; + + uart2_pins: uart2-pins { + mux { + function = "uart"; + groups = "uart2_0_txd_rxd" ; + }; + }; + + watchdog_pins: watchdog-pins { + mux { + function = "watchdog"; + groups = "watchdog"; + }; + }; + + wmac0_pins: wmac0-pins { + mux { + function = "wifi"; + groups = "wf0_5g"; + drive-strength = <4>; + }; + }; + + wmac1_pins: wmac0-pins { + mux { + function = "wifi"; + groups = "wf0_2g"; + drive-strength = <4>; + }; + }; +}; + +&spi { + pinctrl-names = "default"; + pinctrl-0 = <&spi_pins>; + status = "okay"; +}; + +&uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_pins>; + status = "okay"; +}; + +&ssusb { + vusb33-supply = <®_3p3v>; + vbus-supply = <®_5v>; + status = "okay"; +}; + +&u3phy1 { + status = "okay"; +}; + +&watchdog { + pinctrl-names = "default"; + pinctrl-0 = <&watchdog_pins>; + status = "okay"; +}; + +&wmac { + pinctrl-names = "default"; + pinctrl-0 = <&wmac0_pins>; + pinctrl-1 = <&wmac1_pins>; + status = "okay"; +}; diff --git a/target/linux/mediatek/files-4.19/arch/arm/boot/dts/mt7629.dtsi b/target/linux/mediatek/files-4.19/arch/arm/boot/dts/mt7629.dtsi new file mode 100755 index 0000000000..53f47796b8 --- /dev/null +++ b/target/linux/mediatek/files-4.19/arch/arm/boot/dts/mt7629.dtsi @@ -0,0 +1,423 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2019 MediaTek Inc. + * + * Author: Ryder Lee <ryder.lee@mediatek.com> + */ + +#include <dt-bindings/interrupt-controller/irq.h> +#include <dt-bindings/interrupt-controller/arm-gic.h> +#include <dt-bindings/clock/mt7629-clk.h> +#include <dt-bindings/power/mt7622-power.h> +#include <dt-bindings/gpio/gpio.h> +#include <dt-bindings/phy/phy.h> +#include <dt-bindings/reset/mt7629-resets.h> + +/ { + compatible = "mediatek,mt7629"; + interrupt-parent = <&sysirq>; + #address-cells = <2>; + #size-cells = <2>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + enable-method = "mediatek,mt6589-smp"; + + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a7"; + reg = <0x0>; + clock-frequency = <1250000000>; + cci-control-port = <&cci_control2>; + }; + + cpu1: cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a7"; + reg = <0x1>; + clock-frequency = <1250000000>; + cci-control-port = <&cci_control2>; + }; + }; + + pmu { + compatible = "arm,cortex-a7-pmu"; + interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_LOW>, + <GIC_SPI 9 IRQ_TYPE_LEVEL_LOW>; + interrupt-affinity = <&cpu0>, <&cpu1>; + }; + + clk20m: oscillator-0 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <20000000>; + clock-output-names = "clk20m"; + }; + + clk40m: oscillator-1 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <40000000>; + clock-output-names = "clkxtal"; + }; + + timer { + compatible = "arm,armv7-timer"; + interrupt-parent = <&gic>; + interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>, + <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>, + <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>, + <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>; + clock-frequency = <20000000>; + arm,cpu-registers-not-fw-configured; + }; + + soc { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + infracfg: syscon@10000000 { + compatible = "mediatek,mt7629-infracfg", "syscon"; + reg = <0x10000000 0x1000>; + #clock-cells = <1>; + }; + + pericfg: syscon@10002000 { + compatible = "mediatek,mt7629-pericfg", "syscon"; + reg = <0x10002000 0x1000>; + #clock-cells = <1>; + }; + + scpsys: scpsys@10006000 { + compatible = "mediatek,mt7629-scpsys", + "mediatek,mt7622-scpsys"; + #power-domain-cells = <1>; + reg = <0x10006000 0x1000>; + clocks = <&topckgen CLK_TOP_HIF_SEL>; + clock-names = "hif_sel"; + assigned-clocks = <&topckgen CLK_TOP_HIF_SEL>; + assigned-clock-parents = <&topckgen CLK_TOP_UNIVPLL1_D2>; + infracfg = <&infracfg>; + }; + + timer: timer@10009000 { + compatible = "mediatek,mt7629-timer", + "mediatek,mt6765-timer"; + reg = <0x10009000 0x60>; + interrupts = <GIC_SPI 169 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 170 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk20m>; + clock-names = "clk20m"; + }; + + sysirq: interrupt-controller@10200a80 { + compatible = "mediatek,mt7629-sysirq", + "mediatek,mt6577-sysirq"; + reg = <0x10200a80 0x20>; + interrupt-controller; + #interrupt-cells = <3>; + interrupt-parent = <&gic>; + }; + + apmixedsys: syscon@10209000 { + compatible = "mediatek,mt7629-apmixedsys", "syscon"; + reg = <0x10209000 0x1000>; + #clock-cells = <1>; + }; + + rng: rng@1020f000 { + compatible = "mediatek,mt7629-rng", + "mediatek,mt7623-rng"; + reg = <0x1020f000 0x100>; + clocks = <&infracfg CLK_INFRA_TRNG_PD>; + clock-names = "rng"; + }; + + topckgen: syscon@10210000 { + compatible = "mediatek,mt7629-topckgen", "syscon"; + reg = <0x10210000 0x1000>; + #clock-cells = <1>; + }; + + watchdog: watchdog@10212000 { + compatible = "mediatek,mt7629-wdt", + "mediatek,mt6589-wdt"; + reg = <0x10212000 0x100>; + }; + + pio: pinctrl@10217000 { + compatible = "mediatek,mt7629-pinctrl"; + reg = <0x10217000 0x8000>, + <0x10005000 0x1000>; + reg-names = "base", "eint"; + gpio-controller; + gpio-ranges = <&pio 0 0 79>; + #gpio-cells = <2>; + #interrupt-cells = <2>; + interrupt-controller; + interrupts = <GIC_SPI 153 IRQ_TYPE_LEVEL_HIGH>; + interrupt-parent = <&gic>; + }; + + gic: interrupt-controller@10300000 { + compatible = "arm,gic-400"; + interrupt-controller; + #interrupt-cells = <3>; + interrupt-parent = <&gic>; + reg = <0x10310000 0x1000>, + <0x10320000 0x1000>, + <0x10340000 0x2000>, + <0x10360000 0x2000>; + }; + + cci: cci@10390000 { + compatible = "arm,cci-400"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x10390000 0x1000>; + ranges = <0 0x10390000 0x10000>; + + cci_control0: slave-if@1000 { + compatible = "arm,cci-400-ctrl-if"; + interface-type = "ace-lite"; + reg = <0x1000 0x1000>; + }; + + cci_control1: slave-if@4000 { + compatible = "arm,cci-400-ctrl-if"; + interface-type = "ace"; + reg = <0x4000 0x1000>; + }; + + cci_control2: slave-if@5000 { + compatible = "arm,cci-400-ctrl-if"; + interface-type = "ace"; + reg = <0x5000 0x1000>; + }; + + pmu@9000 { + compatible = "arm,cci-400-pmu,r1"; + reg = <0x9000 0x5000>; + interrupts = <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>; + }; + }; + + uart0: serial@11002000 { + compatible = "mediatek,mt7629-uart", + "mediatek,mt6577-uart"; + reg = <0x11002000 0x400>; + interrupts = <GIC_SPI 91 IRQ_TYPE_LEVEL_LOW>; + clocks = <&topckgen CLK_TOP_UART_SEL>, + <&pericfg CLK_PERI_UART0_PD>; + clock-names = "baud", "bus"; + status = "disabled"; + }; + + uart1: serial@11003000 { + compatible = "mediatek,mt7629-uart", + "mediatek,mt6577-uart"; + reg = <0x11003000 0x400>; + interrupts = <GIC_SPI 92 IRQ_TYPE_LEVEL_LOW>; + clocks = <&topckgen CLK_TOP_UART_SEL>, + <&pericfg CLK_PERI_UART1_PD>; + clock-names = "baud", "bus"; + status = "disabled"; + }; + + uart2: serial@11004000 { + compatible = "mediatek,mt7629-uart", + "mediatek,mt6577-uart"; + reg = <0x11004000 0x400>; + interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_LOW>; + clocks = <&topckgen CLK_TOP_UART_SEL>, + <&pericfg CLK_PERI_UART2_PD>; + clock-names = "baud", "bus"; + status = "disabled"; + }; + + i2c: i2c@11007000 { + compatible = "mediatek,mt7629-i2c", + "mediatek,mt2712-i2c"; + reg = <0x11007000 0x90>, + <0x11000100 0x80>; + interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_LOW>; + clock-div = <4>; + clocks = <&pericfg CLK_PERI_I2C0_PD>, + <&pericfg CLK_PERI_AP_DMA_PD>; + clock-names = "main", "dma"; + assigned-clocks = <&topckgen CLK_TOP_AXI_SEL>; + assigned-clock-parents = <&topckgen CLK_TOP_SYSPLL1_D2>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + spi: spi@1100a000 { + compatible = "mediatek,mt7629-spi", + "mediatek,mt7622-spi"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x1100a000 0x100>; + interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_LOW>; + clocks = <&topckgen CLK_TOP_SYSPLL3_D2>, + <&topckgen CLK_TOP_SPI0_SEL>, + <&pericfg CLK_PERI_SPI0_PD>; + clock-names = "parent-clk", "sel-clk", "spi-clk"; + status = "disabled"; + }; + + qspi: spi@11014000 { + compatible = "mediatek,mt7629-nor", + "mediatek,mt8173-nor"; + reg = <0x11014000 0xe0>; + clocks = <&pericfg CLK_PERI_FLASH_PD>, + <&topckgen CLK_TOP_FLASH_SEL>; + clock-names = "spi", "sf"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + wmac: wmac@18000000 { + compatible = "mediatek,mt7629-wmac"; + reg = <0x18000000 0x100000>; + interrupts = <GIC_SPI 211 IRQ_TYPE_LEVEL_LOW>, + <GIC_SPI 129 IRQ_TYPE_LEVEL_LOW>; + mediatek,mtd-eeprom = <&factory 0x0000>; + status = "disabled"; + }; + + ssusbsys: syscon@1a000000 { + compatible = "mediatek,mt7629-ssusbsys", "syscon"; + reg = <0x1a000000 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + ssusb: usb@1a0c0000 { + compatible = "mediatek,mt7629-xhci", + "mediatek,mtk-xhci"; + reg = <0x1a0c0000 0x01000>, + <0x1a0c3e00 0x0100>; + reg-names = "mac", "ippc"; + interrupts = <GIC_SPI 232 IRQ_TYPE_LEVEL_LOW>; + clocks = <&ssusbsys CLK_SSUSB_SYS_EN>, + <&ssusbsys CLK_SSUSB_REF_EN>, + <&ssusbsys CLK_SSUSB_MCU_EN>, + <&ssusbsys CLK_SSUSB_DMA_EN>; + clock-names = "sys_ck", "ref_ck", "mcu_ck", "dma_ck"; + assigned-clocks = <&topckgen CLK_TOP_AXI_SEL>, + <&topckgen CLK_TOP_SATA_SEL>, + <&topckgen CLK_TOP_HIF_SEL>; + assigned-clock-parents = <&topckgen CLK_TOP_SYSPLL1_D2>, + <&topckgen CLK_TOP_UNIVPLL2_D4>, + <&topckgen CLK_TOP_UNIVPLL1_D2>; + power-domains = <&scpsys MT7622_POWER_DOMAIN_HIF1>; + phys = <&u2port0 PHY_TYPE_USB2>, + <&u3port0 PHY_TYPE_USB3>; + status = "disabled"; + }; + + u3phy1: usb-phy@1a0c4000 { + compatible = "mediatek,generic-tphy-v2"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + status = "disabled"; + + u2port0: usb-phy@1a0c4000 { + reg = <0x1a0c4000 0x700>; + clocks = <&ssusbsys CLK_SSUSB_U2_PHY_EN>; + clock-names = "ref"; + #phy-cells = <1>; + status = "okay"; + }; + + u3port0: usb-phy@1a1c4700 { + reg = <0x1a1c4700 0x700>; + clocks = <&clk20m>; + clock-names = "ref"; + #phy-cells = <1>; + status = "okay"; + }; + }; + + pciesys: syscon@1a100800 { + compatible = "mediatek,mt7629-pciesys", "syscon"; + reg = <0x1a100800 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + ethsys: syscon@1b000000 { + compatible = "mediatek,mt7629-ethsys", "syscon"; + reg = <0x1b000000 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + eth: ethernet@1b100000 { + compatible = "mediatek,mt7629-eth", + "syscon"; + reg = <0x1b100000 0x20000>; + interrupts = <GIC_SPI 223 IRQ_TYPE_LEVEL_LOW>, + <GIC_SPI 224 IRQ_TYPE_LEVEL_LOW>, + <GIC_SPI 225 IRQ_TYPE_LEVEL_LOW>; + clocks = <&topckgen CLK_TOP_ETH_SEL>, + <&topckgen CLK_TOP_F10M_REF_SEL>, + <ðsys CLK_ETH_ESW_EN>, + <ðsys CLK_ETH_GP0_EN>, + <ðsys CLK_ETH_GP1_EN>, + <ðsys CLK_ETH_GP2_EN>, + <ðsys CLK_ETH_FE_EN>, + <&sgmiisys0 CLK_SGMII_TX_EN>, + <&sgmiisys0 CLK_SGMII_RX_EN>, + <&sgmiisys0 CLK_SGMII_CDR_REF>, + <&sgmiisys0 CLK_SGMII_CDR_FB>, + <&sgmiisys1 CLK_SGMII_TX_EN>, + <&sgmiisys1 CLK_SGMII_RX_EN>, + <&sgmiisys1 CLK_SGMII_CDR_REF>, + <&sgmiisys1 CLK_SGMII_CDR_FB>, + <&apmixedsys CLK_APMIXED_SGMIPLL>, + <&apmixedsys CLK_APMIXED_ETH2PLL>; + clock-names = "ethif", "sgmiitop", "esw", "gp0", "gp1", "gp2", + "fe", "sgmii_tx250m", "sgmii_rx250m", + "sgmii_cdr_ref", "sgmii_cdr_fb", + "sgmii2_tx250m", "sgmii2_rx250m", + "sgmii2_cdr_ref", "sgmii2_cdr_fb", + "sgmii_ck", "eth2pll"; + assigned-clocks = <&topckgen CLK_TOP_ETH_SEL>, + <&topckgen CLK_TOP_F10M_REF_SEL>; + assigned-clock-parents = <&topckgen CLK_TOP_UNIVPLL1_D2>, + <&topckgen CLK_TOP_SGMIIPLL_D2>; + power-domains = <&scpsys MT7622_POWER_DOMAIN_ETHSYS>; + mediatek,ethsys = <ðsys>; + mediatek,sgmiisys = <&sgmiisys0>,<&sgmiisys1>; + mediatek,infracfg = <&infracfg>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + sgmiisys0: syscon@1b128000 { + compatible = "mediatek,mt7629-sgmiisys", "syscon"; + reg = <0x1b128000 0x3000>; + #clock-cells = <1>; + mediatek,physpeed = "2500"; + }; + + sgmiisys1: syscon@1b130000 { + compatible = "mediatek,mt7629-sgmiisys", "syscon"; + reg = <0x1b130000 0x3000>; + #clock-cells = <1>; + mediatek,physpeed = "2500"; + }; + }; +}; diff --git a/target/linux/mediatek/files-4.19/arch/arm64/boot/dts/mediatek/a.patch b/target/linux/mediatek/files-4.19/arch/arm64/boot/dts/mediatek/a.patch new file mode 100644 index 0000000000..7312b476c0 --- /dev/null +++ b/target/linux/mediatek/files-4.19/arch/arm64/boot/dts/mediatek/a.patch @@ -0,0 +1,19 @@ +[?25l[J[J[J[J[J[J[?2004h[?25h[?1049h[22;0;0t[?1h=[?2004h[1;76r[?12h[?12l[22;2t[22;1t[27m[23m[29m[m[H[2J[?25l[76;1H"mt7622-lynx-rfb1.dts" 605L, 11203C[1;1H/*
+ * Copyright (c) 2017 MediaTek Inc.
+ * Author: Ming Huang <ming.huang@mediatek.com>
+ *[9CSean Wang <sean.wang@mediatek.com>
+ *
+ * SPDX-License-Identifier: (GPL-2.0 OR MIT)
+ */
+
+/dts-v1/;
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/gpio/gpio.h>
+
+#include "mt7622.dtsi"
+#include "mt6380.dtsi"
+
+/ {[17;9Hmodel = "MediaTek MT7622 RFB1 board";[18;9Hcompatible = "mediatek,mt7622-rfb1", "mediatek,mt7622";[20;9Haliases {[21;17Hserial0 = &uart0;[22;9H};[24;9Hchosen {[25;17Hstdout-path = "serial0:115200n8";[26;17Hbootargs = "earlycon=uart8250,mmio32,0x11002000 swiotlb=512";[27;9H};[29;9Hcpus {[30;17Hcpu@0 {[31;25Hproc-supply = <&mt6380_vcpu_reg>;[32;25Hsram-supply = <&mt6380_vm_reg>;[33;17H};[35;17Hcpu@1 {[36;25Hproc-supply = <&mt6380_vcpu_reg>;[37;25Hsram-supply = <&mt6380_vm_reg>;[38;17H};[39;9H};[41;9Hgpio-keys {[42;17Hcompatible = "gpio-keys";[43;17Hpoll-interval = <100>;[45;17Hfactory {[46;25Hlabel = "factory";[47;25Hlinux,code = <BTN_0>;[48;25Hgpios = <&pio 0 0>;[49;17H};[51;17Hwps {[52;25Hlabel = "wps";[53;25Hlinux,code = <KEY_WPS_BUTTON>;[54;25Hgpios = <&pio 102 0>;[55;17H};[56;9H};[58;9Hgsw: gsw@0 {[59;17Hcompatible = "mediatek,mt753x";[60;17Hmediatek,ethsys = <ðsys>;[61;17H#address-cells = <1>;[62;17H#size-cells = <0>;[63;9H};[65;9Hmemory {[66;17Hreg = <0 0x40000000 0 0x3F000000>;[67;9H};[69;9Hreg_1p8v: regulator-1p8v {[70;17Hcompatible = "regulator-fixed";[71;17Hregulator-name = "fixed-1.8V";[72;17Hregulator-min-microvolt = <1800000>;[73;17Hregulator-max-microvolt = <1800000>;[74;17Hregulator-always-on;[75;9H};[1;1H[?25h
+ [?25l[76;1HType :qa! and press <Enter> to abandon all changes and exit Vim[2;2H[?25h[76;1H[?2004l[?1l>[?1049l[23;0;0tVim: Caught deadly signal TERM
+Vim: Finished.
+[76;1H[23;2t[23;1t[22;2t[22;1t[23;2t[23;1t
\ No newline at end of file diff --git a/target/linux/mediatek/files-4.19/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts b/target/linux/mediatek/files-4.19/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts new file mode 100644 index 0000000000..62a876c02f --- /dev/null +++ b/target/linux/mediatek/files-4.19/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts @@ -0,0 +1,574 @@ +/* + * Copyright (c) 2018 MediaTek Inc. + * Author: Ryder Lee <ryder.lee@mediatek.com> + * + * SPDX-License-Identifier: (GPL-2.0 OR MIT) + */ + +/dts-v1/; +#include <dt-bindings/input/input.h> +#include <dt-bindings/gpio/gpio.h> + +#include "mt7622.dtsi" +#include "mt6380.dtsi" + +/ { + model = "Bananapi BPI-R64"; + compatible = "bananapi,bpi-r64", "mediatek,mt7622"; + + aliases { + serial0 = &uart0; + }; + + chosen { + stdout-path = "serial0:115200n8"; + bootargs = "earlycon=uart8250,mmio32,0x11002000 swiotlb=512"; + }; + + cpus { + cpu@0 { + proc-supply = <&mt6380_vcpu_reg>; + sram-supply = <&mt6380_vm_reg>; + }; + + cpu@1 { + proc-supply = <&mt6380_vcpu_reg>; + sram-supply = <&mt6380_vm_reg>; + }; + }; + + gpio-keys { + compatible = "gpio-keys"; + + factory { + label = "factory"; + linux,code = <BTN_0>; + gpios = <&pio 0 GPIO_ACTIVE_HIGH>; + }; + + wps { + label = "wps"; + linux,code = <KEY_WPS_BUTTON>; + gpios = <&pio 102 GPIO_ACTIVE_LOW>; + }; + }; + + leds { + compatible = "gpio-leds"; + + green { + label = "bpi-r64:pio:green"; + gpios = <&pio 89 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + + red { + label = "bpi-r64:pio:red"; + gpios = <&pio 88 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + }; + + gsw: gsw@0 { + compatible = "mediatek,mt753x"; + mediatek,ethsys = <ðsys>; + #address-cells = <1>; + #size-cells = <0>; + }; + + memory { + reg = <0 0x40000000 0 0x40000000>; + }; + + reg_1p8v: regulator-1p8v { + compatible = "regulator-fixed"; + regulator-name = "fixed-1.8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + 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; + }; +}; + +&bch { + status = "disabled"; +}; + +&btif { + status = "okay"; +}; + +&cir { + pinctrl-names = "default"; + pinctrl-0 = <&irrx_pins>; + status = "okay"; +}; + +ð { + pinctrl-names = "default"; + pinctrl-0 = <ð_pins>; + status = "okay"; + + gmac1: mac@1 { + compatible = "mediatek,eth-mac"; + reg = <1>; + phy-handle = <&phy5>; + }; + + mdio: mdio-bus { + #address-cells = <1>; + #size-cells = <0>; + + phy5: ethernet-phy@5 { + reg = <5>; + phy-mode = "sgmii"; + }; + }; +}; + +&i2c1 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c1_pins>; + status = "okay"; +}; + +&i2c2 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c2_pins>; + status = "okay"; +}; + +&mmc0 { + pinctrl-names = "default", "state_uhs"; + pinctrl-0 = <&emmc_pins_default>; + pinctrl-1 = <&emmc_pins_uhs>; + status = "okay"; + bus-width = <8>; + max-frequency = <50000000>; + cap-mmc-highspeed; + mmc-hs200-1_8v; + vmmc-supply = <®_3p3v>; + vqmmc-supply = <®_1p8v>; + assigned-clocks = <&topckgen CLK_TOP_MSDC30_0_SEL>; + assigned-clock-parents = <&topckgen CLK_TOP_UNIV48M>; + non-removable; +}; + +&mmc1 { + pinctrl-names = "default", "state_uhs"; + pinctrl-0 = <&sd0_pins_default>; + pinctrl-1 = <&sd0_pins_uhs>; + status = "okay"; + bus-width = <4>; + max-frequency = <50000000>; + cap-sd-highspeed; + r_smpl = <1>; + cd-gpios = <&pio 81 GPIO_ACTIVE_LOW>; + vmmc-supply = <®_3p3v>; + vqmmc-supply = <®_3p3v>; + assigned-clocks = <&topckgen CLK_TOP_MSDC30_1_SEL>; + assigned-clock-parents = <&topckgen CLK_TOP_UNIV48M>; +}; + +&nandc { + pinctrl-names = "default"; + pinctrl-0 = <¶llel_nand_pins>; + status = "disabled"; +}; + +&nor_flash { + pinctrl-names = "default"; + pinctrl-0 = <&spi_nor_pins>; + status = "disabled"; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + }; +}; + +&pcie { + pinctrl-names = "default"; + pinctrl-0 = <&pcie0_pins>, <&pcie1_pins>; + status = "okay"; + + pcie@0,0 { + status = "okay"; + }; + + pcie@1,0 { + 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 { + function = "emmc", "emmc_rst"; + groups = "emmc"; + }; + + /* "NDL0","NDL1","NDL2","NDL3","NDL4","NDL5","NDL6","NDL7", + * "NRB","NCLE" pins are used as DAT0,DAT1,DAT2,DAT3,DAT4, + * DAT5,DAT6,DAT7,CMD,CLK for eMMC respectively + */ + conf-cmd-dat { + pins = "NDL0", "NDL1", "NDL2", + "NDL3", "NDL4", "NDL5", + "NDL6", "NDL7", "NRB"; + input-enable; + bias-pull-up; + }; + + conf-clk { + pins = "NCLE"; + bias-pull-down; + }; + }; + + emmc_pins_uhs: emmc-pins-uhs { + mux { + function = "emmc"; + groups = "emmc"; + }; + + conf-cmd-dat { + pins = "NDL0", "NDL1", "NDL2", + "NDL3", "NDL4", "NDL5", + "NDL6", "NDL7", "NRB"; + input-enable; + drive-strength = <4>; + bias-pull-up; + }; + + conf-clk { + pins = "NCLE"; + drive-strength = <4>; + bias-pull-down; + }; + }; + + eth_pins: eth-pins { + mux { + function = "eth"; + groups = "mdc_mdio", "rgmii_via_gmac2"; + }; + }; + + i2c1_pins: i2c1-pins { + mux { + function = "i2c"; + groups = "i2c1_0"; + }; + }; + + i2c2_pins: i2c2-pins { + mux { + function = "i2c"; + groups = "i2c2_0"; + }; + }; + + i2s1_pins: i2s1-pins { + mux { + function = "i2s"; + groups = "i2s_out_mclk_bclk_ws", + "i2s1_in_data", + "i2s1_out_data"; + }; + + conf { + pins = "I2S1_IN", "I2S1_OUT", "I2S_BCLK", + "I2S_WS", "I2S_MCLK"; + drive-strength = <12>; + bias-pull-down; + }; + }; + + irrx_pins: irrx-pins { + mux { + function = "ir"; + groups = "ir_1_rx"; + }; + }; + + irtx_pins: irtx-pins { + mux { + function = "ir"; + groups = "ir_1_tx"; + }; + }; + + /* Parallel nand is shared pin with eMMC */ + parallel_nand_pins: parallel-nand-pins { + mux { + function = "flash"; + groups = "par_nand"; + }; + }; + + pcie0_pins: pcie0-pins { + mux { + function = "pcie"; + groups = "pcie0_pad_perst", + "pcie0_1_waken", + "pcie0_1_clkreq"; + }; + }; + + pcie1_pins: pcie1-pins { + mux { + function = "pcie"; + groups = "pcie1_pad_perst", + "pcie1_0_waken", + "pcie1_0_clkreq"; + }; + }; + + pmic_bus_pins: pmic-bus-pins { + mux { + function = "pmic"; + groups = "pmic_bus"; + }; + }; + + pwm7_pins: pwm1-2-pins { + mux { + function = "pwm"; + groups = "pwm_ch7_2"; + }; + }; + + wled_pins: wled-pins { + mux { + function = "led"; + groups = "wled"; + }; + }; + + sd0_pins_default: sd0-pins-default { + mux { + function = "sd"; + groups = "sd_0"; + }; + + /* "I2S2_OUT, "I2S4_IN"", "I2S3_IN", "I2S2_IN", + * "I2S4_OUT", "I2S3_OUT" are used as DAT0, DAT1, + * DAT2, DAT3, CMD, CLK for SD respectively. + */ + conf-cmd-data { + pins = "I2S2_OUT", "I2S4_IN", "I2S3_IN", + "I2S2_IN","I2S4_OUT"; + input-enable; + drive-strength = <8>; + bias-pull-up; + }; + conf-clk { + pins = "I2S3_OUT"; + drive-strength = <12>; + bias-pull-down; + }; + conf-cd { + pins = "TXD3"; + bias-pull-up; + }; + }; + + sd0_pins_uhs: sd0-pins-uhs { + mux { + function = "sd"; + groups = "sd_0"; + }; + + conf-cmd-data { + pins = "I2S2_OUT", "I2S4_IN", "I2S3_IN", + "I2S2_IN","I2S4_OUT"; + input-enable; + bias-pull-up; + }; + + conf-clk { + pins = "I2S3_OUT"; + bias-pull-down; + }; + }; + + /* Serial NAND is shared pin with SPI-NOR */ + serial_nand_pins: serial-nand-pins { + mux { + function = "flash"; + groups = "snfi"; + }; + }; + + spic0_pins: spic0-pins { + mux { + function = "spi"; + groups = "spic0_0"; + }; + }; + + spic1_pins: spic1-pins { + mux { + function = "spi"; + groups = "spic1_0"; + }; + }; + + /* SPI-NOR is shared pin with serial NAND */ + spi_nor_pins: spi-nor-pins { + mux { + function = "flash"; + groups = "spi_nor"; + }; + }; + + /* serial NAND is shared pin with SPI-NOR */ + serial_nand_pins: serial-nand-pins { + mux { + function = "flash"; + groups = "snfi"; + }; + }; + + uart0_pins: uart0-pins { + mux { + function = "uart"; + groups = "uart0_0_tx_rx" ; + }; + }; + + uart2_pins: uart2-pins { + mux { + function = "uart"; + groups = "uart2_1_tx_rx" ; + }; + }; + + watchdog_pins: watchdog-pins { + mux { + function = "watchdog"; + groups = "watchdog"; + }; + }; +}; + +&pwm { + pinctrl-names = "default"; + pinctrl-0 = <&pwm7_pins>; + status = "okay"; +}; + +&pwrap { + pinctrl-names = "default"; + pinctrl-0 = <&pmic_bus_pins>; + + status = "okay"; +}; + +&sata { + status = "disable"; +}; + +&sata_phy { + status = "disable"; +}; + +&spi0 { + pinctrl-names = "default"; + pinctrl-0 = <&spic0_pins>; + status = "okay"; +}; + +&spi1 { + pinctrl-names = "default"; + pinctrl-0 = <&spic1_pins>; + status = "okay"; +}; + +&ssusb { + vusb33-supply = <®_3p3v>; + vbus-supply = <®_5v>; + status = "okay"; +}; + +&u3phy { + status = "okay"; +}; + +&uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_pins>; + status = "okay"; +}; + +&uart2 { + pinctrl-names = "default"; + pinctrl-0 = <&uart2_pins>; + status = "okay"; +}; + +&watchdog { + pinctrl-names = "default"; + pinctrl-0 = <&watchdog_pins>; + status = "okay"; +}; + +&gsw { + mediatek,mdio = <&mdio>; + mediatek,portmap = "llllw"; + mediatek,mdio_master_pinmux = <0>; + reset-gpios = <&pio 54 0>; + interrupt-parent = <&pio>; + interrupts = <53 IRQ_TYPE_LEVEL_HIGH>; + status = "okay"; + + port5: port@5 { + compatible = "mediatek,mt753x-port"; + reg = <5>; + phy-mode = "rgmii"; + fixed-link { + speed = <1000>; + full-duplex; + }; + }; + + port6: port@6 { + compatible = "mediatek,mt753x-port"; + reg = <6>; + phy-mode = "sgmii"; + fixed-link { + speed = <2500>; + full-duplex; + }; + }; +}; + + diff --git a/target/linux/mediatek/files-4.19/arch/arm64/boot/dts/mediatek/mt7622-lynx-rfb1.dts b/target/linux/mediatek/files-4.19/arch/arm64/boot/dts/mediatek/mt7622-lynx-rfb1.dts new file mode 100755 index 0000000000..1045851509 --- /dev/null +++ b/target/linux/mediatek/files-4.19/arch/arm64/boot/dts/mediatek/mt7622-lynx-rfb1.dts @@ -0,0 +1,605 @@ +/* + * Copyright (c) 2017 MediaTek Inc. + * Author: Ming Huang <ming.huang@mediatek.com> + * Sean Wang <sean.wang@mediatek.com> + * + * SPDX-License-Identifier: (GPL-2.0 OR MIT) + */ + +/dts-v1/; +#include <dt-bindings/input/input.h> +#include <dt-bindings/gpio/gpio.h> + +#include "mt7622.dtsi" +#include "mt6380.dtsi" + +/ { + model = "MediaTek MT7622 RFB1 board"; + compatible = "mediatek,mt7622-rfb1", "mediatek,mt7622"; + + aliases { + serial0 = &uart0; + }; + + chosen { + stdout-path = "serial0:115200n8"; + bootargs = "earlycon=uart8250,mmio32,0x11002000 swiotlb=512"; + }; + + cpus { + cpu@0 { + proc-supply = <&mt6380_vcpu_reg>; + sram-supply = <&mt6380_vm_reg>; + }; + + cpu@1 { + proc-supply = <&mt6380_vcpu_reg>; + sram-supply = <&mt6380_vm_reg>; + }; + }; + + gpio-keys { + compatible = "gpio-keys"; + poll-interval = <100>; + + factory { + label = "factory"; + linux,code = <BTN_0>; + gpios = <&pio 0 0>; + }; + + wps { + label = "wps"; + linux,code = <KEY_WPS_BUTTON>; + gpios = <&pio 102 0>; + }; + }; + + gsw: gsw@0 { + compatible = "mediatek,mt753x"; + mediatek,ethsys = <ðsys>; + #address-cells = <1>; + #size-cells = <0>; + }; + + memory { + reg = <0 0x40000000 0 0x3F000000>; + }; + + reg_1p8v: regulator-1p8v { + compatible = "regulator-fixed"; + regulator-name = "fixed-1.8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + 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; + }; +}; + +&pcie { + pinctrl-names = "default", "pcie1_pins"; + pinctrl-0 = <&pcie0_pins>; + pinctrl-1 = <&pcie1_pins>; + status = "okay"; + + pcie@0,0 { + status = "okay"; + }; + + pcie@1,0 { + status = "okay"; + }; + +}; + +&pio { + /* eMMC is shared pin with parallel NAND */ + emmc_pins_default: emmc-pins-default { + mux { + function = "emmc", "emmc_rst"; + groups = "emmc"; + }; + + /* "NDL0","NDL1","NDL2","NDL3","NDL4","NDL5","NDL6","NDL7", + * "NRB","NCLE" pins are used as DAT0,DAT1,DAT2,DAT3,DAT4, + * DAT5,DAT6,DAT7,CMD,CLK for eMMC respectively + */ + conf-cmd-dat { + pins = "NDL0", "NDL1", "NDL2", + "NDL3", "NDL4", "NDL5", + "NDL6", "NDL7", "NRB"; + input-enable; + bias-pull-up; + }; + + conf-clk { + pins = "NCLE"; + bias-pull-down; + }; + }; + + emmc_pins_uhs: emmc-pins-uhs { + mux { + function = "emmc"; + groups = "emmc"; + }; + + conf-cmd-dat { + pins = "NDL0", "NDL1", "NDL2", + "NDL3", "NDL4", "NDL5", + "NDL6", "NDL7", "NRB"; + input-enable; + drive-strength = <4>; + bias-pull-up; + }; + + conf-clk { + pins = "NCLE"; + drive-strength = <4>; + bias-pull-down; + }; + }; + + eth_pins: eth-pins { + mux { + function = "eth"; + groups = "mdc_mdio", "rgmii_via_gmac2"; + }; + }; + + i2c1_pins: i2c1-pins { + mux { + function = "i2c"; + groups = "i2c1_0"; + }; + }; + + i2c2_pins: i2c2-pins { + mux { + function = "i2c"; + groups = "i2c2_0"; + }; + }; + + i2s1_pins: i2s1-pins { + mux { + function = "i2s"; + groups = "i2s_out_mclk_bclk_ws", + "i2s1_in_data", + "i2s1_out_data"; + }; + + conf { + pins = "I2S1_IN", "I2S1_OUT", "I2S_BCLK", + "I2S_WS", "I2S_MCLK"; + drive-strength = <12>; + bias-pull-down; + }; + }; + + irrx_pins: irrx-pins { + mux { + function = "ir"; + groups = "ir_1_rx"; + }; + }; + + irtx_pins: irtx-pins { + mux { + function = "ir"; + groups = "ir_1_tx"; + }; + }; + + /* Parallel nand is shared pin with eMMC */ + parallel_nand_pins: parallel-nand-pins { + mux { + function = "flash"; + groups = "par_nand"; + }; + }; + + pcie0_pins: pcie0-pins { + mux { + function = "pcie"; + groups = "pcie0_pad_perst", + "pcie0_1_waken", + "pcie0_1_clkreq"; + }; + }; + + pcie1_pins: pcie1-pins { + mux { + function = "pcie"; + groups = "pcie1_pad_perst", + "pcie1_0_waken", + "pcie1_0_clkreq"; + }; + }; + + pmic_bus_pins: pmic-bus-pins { + mux { + function = "pmic"; + groups = "pmic_bus"; + }; + }; + + pwm7_pins: pwm1-2-pins { + mux { + function = "pwm"; + groups = "pwm_ch7_2"; + }; + }; + + wled_pins: wled-pins { + mux { + function = "led"; + groups = "wled"; + }; + }; + + sd0_pins_default: sd0-pins-default { + mux { + function = "sd"; + groups = "sd_0"; + }; + + /* "I2S2_OUT, "I2S4_IN"", "I2S3_IN", "I2S2_IN", + * "I2S4_OUT", "I2S3_OUT" are used as DAT0, DAT1, + * DAT2, DAT3, CMD, CLK for SD respectively. + */ + conf-cmd-data { + pins = "I2S2_OUT", "I2S4_IN", "I2S3_IN", + "I2S2_IN","I2S4_OUT"; + input-enable; + drive-strength = <8>; + bias-pull-up; + }; + conf-clk { + pins = "I2S3_OUT"; + drive-strength = <12>; + bias-pull-down; + }; + conf-cd { + pins = "TXD3"; + bias-pull-up; + }; + }; + + sd0_pins_uhs: sd0-pins-uhs { + mux { + function = "sd"; + groups = "sd_0"; + }; + + conf-cmd-data { + pins = "I2S2_OUT", "I2S4_IN", "I2S3_IN", + "I2S2_IN","I2S4_OUT"; + input-enable; + bias-pull-up; + }; + + conf-clk { + pins = "I2S3_OUT"; + bias-pull-down; + }; + }; + + /* Serial NAND is shared pin with SPI-NOR */ + serial_nand_pins: serial-nand-pins { + mux { + function = "flash"; + groups = "snfi"; + }; + }; + + spic0_pins: spic0-pins { + mux { + function = "spi"; + groups = "spic0_0"; + }; + }; + + spic1_pins: spic1-pins { + mux { + function = "spi"; + groups = "spic1_0"; + }; + }; + + /* SPI-NOR is shared pin with serial NAND */ + spi_nor_pins: spi-nor-pins { + mux { + function = "flash"; + groups = "spi_nor"; + }; + }; + + /* serial NAND is shared pin with SPI-NOR */ + serial_nand_pins: serial-nand-pins { + mux { + function = "flash"; + groups = "snfi"; + }; + }; + + uart0_pins: uart0-pins { + mux { + function = "uart"; + groups = "uart0_0_tx_rx" ; + }; + }; + + uart2_pins: uart2-pins { + mux { + function = "uart"; + groups = "uart2_1_tx_rx" ; + }; + }; + + watchdog_pins: watchdog-pins { + mux { + function = "watchdog"; + groups = "watchdog"; + }; + }; +}; + +&bch { + status = "okay"; +}; + +&btif { + status = "okay"; +}; + +&cir { + pinctrl-names = "default"; + pinctrl-0 = <&irrx_pins>; + status = "okay"; +}; + +ð { + status = "okay"; + gmac0: mac@0 { + compatible = "mediatek,eth-mac"; + reg = <0>; + phy-mode = "sgmii"; + fixed-link { + speed = <1000>; + full-duplex; + pause; + }; + }; + gmac1: mac@1 { + compatible = "mediatek,eth-mac"; + reg = <1>; + phy-mode = "rgmii"; + fixed-link { + speed = <1000>; + full-duplex; + pause; + }; + }; + mdio: mdio-bus { + #address-cells = <1>; + #size-cells = <0>; + }; +}; + +&gsw { + mediatek,mdio = <&mdio>; + mediatek,portmap = "llllw"; + mediatek,mdio_master_pinmux = <0>; + reset-gpios = <&pio 54 0>; + interrupt-parent = <&pio>; + interrupts = <53 IRQ_TYPE_LEVEL_HIGH>; + status = "okay"; + + port5: port@5 { + compatible = "mediatek,mt753x-port"; + reg = <5>; + phy-mode = "rgmii"; + fixed-link { + speed = <1000>; + full-duplex; + }; + }; + + port6: port@6 { + compatible = "mediatek,mt753x-port"; + reg = <6>; + phy-mode = "sgmii"; + fixed-link { + speed = <2500>; + full-duplex; + }; + }; +}; + +&i2c1 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c1_pins>; + status = "okay"; +}; + +&i2c2 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c2_pins>; + status = "okay"; +}; + +&mmc0 { + pinctrl-names = "default", "state_uhs"; + pinctrl-0 = <&emmc_pins_default>; + pinctrl-1 = <&emmc_pins_uhs>; + status = "okay"; + bus-width = <8>; + max-frequency = <50000000>; + cap-mmc-highspeed; + mmc-hs200-1_8v; + vmmc-supply = <®_3p3v>; + vqmmc-supply = <®_1p8v>; + assigned-clocks = <&topckgen CLK_TOP_MSDC30_0_SEL>; + assigned-clock-parents = <&topckgen CLK_TOP_UNIV48M>; + non-removable; +}; + +&mmc1 { + pinctrl-names = "default", "state_uhs"; + pinctrl-0 = <&sd0_pins_default>; + pinctrl-1 = <&sd0_pins_uhs>; + status = "okay"; + bus-width = <4>; + max-frequency = <50000000>; + cap-sd-highspeed; + r_smpl = <1>; + cd-gpios = <&pio 81 GPIO_ACTIVE_LOW>; + vmmc-supply = <®_3p3v>; + vqmmc-supply = <®_3p3v>; + assigned-clocks = <&topckgen CLK_TOP_MSDC30_1_SEL>; + assigned-clock-parents = <&topckgen CLK_TOP_UNIV48M>; +}; + +&nandc { + pinctrl-names = "default"; + pinctrl-0 = <¶llel_nand_pins>; + status = "disabled"; +}; + +&nor_flash { + pinctrl-names = "default"; + pinctrl-0 = <&spi_nor_pins>; + status = "disabled"; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + }; +}; + +&pwm { + pinctrl-names = "default"; + pinctrl-0 = <&pwm7_pins>; + status = "okay"; +}; + +&pwrap { + pinctrl-names = "default"; + pinctrl-0 = <&pmic_bus_pins>; + + status = "okay"; +}; + +&snfi { + pinctrl-names = "default"; + pinctrl-0 = <&serial_nand_pins>; + status = "okay"; + + spi_nand@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "spi-nand"; + spi-max-frequency = <104000000>; + reg = <0>; + + 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 0x0040000>; + }; + + partition@200000 { + label = "Kernel"; + reg = <0x200000 0x2000000>; + }; + + partition@2200000 { + label = "User_data"; + reg = <0x2200000 0x4000000>; + }; + }; + }; +}; + +&spi0 { + pinctrl-names = "default"; + pinctrl-0 = <&spic0_pins>; + status = "okay"; +}; + +&spi1 { + pinctrl-names = "default"; + pinctrl-0 = <&spic1_pins>; + status = "okay"; +}; + +&ssusb { + vusb33-supply = <®_3p3v>; + vbus-supply = <®_5v>; + status = "okay"; +}; + +&u3phy { + status = "okay"; +}; + +&uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_pins>; + status = "okay"; +}; + +&uart2 { + pinctrl-names = "default"; + pinctrl-0 = <&uart2_pins>; + status = "okay"; +}; + +&watchdog { + pinctrl-names = "default"; + pinctrl-0 = <&watchdog_pins>; + status = "okay"; +}; diff --git a/target/linux/mediatek/files-4.19/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts b/target/linux/mediatek/files-4.19/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts new file mode 100755 index 0000000000..3805c5c4ce --- /dev/null +++ b/target/linux/mediatek/files-4.19/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts @@ -0,0 +1,576 @@ +/* + * Copyright (c) 2017 MediaTek Inc. + * Author: Ming Huang <ming.huang@mediatek.com> + * Sean Wang <sean.wang@mediatek.com> + * + * SPDX-License-Identifier: (GPL-2.0 OR MIT) + */ + +/dts-v1/; +#include <dt-bindings/input/input.h> +#include <dt-bindings/gpio/gpio.h> + +#include "mt7622.dtsi" +#include "mt6380.dtsi" + +/ { + model = "MediaTek MT7622 RFB1 board"; + compatible = "mediatek,mt7622-rfb1", "mediatek,mt7622"; + + aliases { + serial0 = &uart0; + }; + + chosen { + stdout-path = "serial0:115200n8"; + bootargs = "earlycon=uart8250,mmio32,0x11002000 swiotlb=512"; + }; + + cpus { + cpu@0 { + proc-supply = <&mt6380_vcpu_reg>; + sram-supply = <&mt6380_vm_reg>; + }; + + cpu@1 { + proc-supply = <&mt6380_vcpu_reg>; + sram-supply = <&mt6380_vm_reg>; + }; + }; + + gpio-keys { + compatible = "gpio-keys"; + poll-interval = <100>; + + factory { + label = "factory"; + linux,code = <BTN_0>; + gpios = <&pio 0 0>; + }; + + wps { + label = "wps"; + linux,code = <KEY_WPS_BUTTON>; + gpios = <&pio 102 0>; + }; + }; + + memory { + reg = <0 0x40000000 0 0x3F000000>; + }; + + reg_1p8v: regulator-1p8v { + compatible = "regulator-fixed"; + regulator-name = "fixed-1.8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + 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; + }; + + rtkgsw: rtkgsw@0 { + compatible = "mediatek,rtk-gsw"; + mediatek,ethsys = <ðsys>; + mediatek,mdio = <&mdio>; + mediatek,reset-pin = <&pio 54 0>; + status = "okay"; + }; +}; + +&pcie { + pinctrl-names = "default", "pcie1_pins"; + pinctrl-0 = <&pcie0_pins>; + pinctrl-1 = <&pcie1_pins>; + status = "okay"; + + pcie@0,0 { + status = "okay"; + }; + + pcie@1,0 { + status = "okay"; + }; + +}; + +&pio { + /* eMMC is shared pin with parallel NAND */ + emmc_pins_default: emmc-pins-default { + mux { + function = "emmc", "emmc_rst"; + groups = "emmc"; + }; + + /* "NDL0","NDL1","NDL2","NDL3","NDL4","NDL5","NDL6","NDL7", + * "NRB","NCLE" pins are used as DAT0,DAT1,DAT2,DAT3,DAT4, + * DAT5,DAT6,DAT7,CMD,CLK for eMMC respectively + */ + conf-cmd-dat { + pins = "NDL0", "NDL1", "NDL2", + "NDL3", "NDL4", "NDL5", + "NDL6", "NDL7", "NRB"; + input-enable; + bias-pull-up; + }; + + conf-clk { + pins = "NCLE"; + bias-pull-down; + }; + }; + + emmc_pins_uhs: emmc-pins-uhs { + mux { + function = "emmc"; + groups = "emmc"; + }; + + conf-cmd-dat { + pins = "NDL0", "NDL1", "NDL2", + "NDL3", "NDL4", "NDL5", + "NDL6", "NDL7", "NRB"; + input-enable; + drive-strength = <4>; + bias-pull-up; + }; + + conf-clk { + pins = "NCLE"; + drive-strength = <4>; + bias-pull-down; + }; + }; + + eth_pins: eth-pins { + mux { + function = "eth"; + groups = "mdc_mdio", "rgmii_via_gmac2"; + }; + }; + + i2c1_pins: i2c1-pins { + mux { + function = "i2c"; + groups = "i2c1_0"; + }; + }; + + i2c2_pins: i2c2-pins { + mux { + function = "i2c"; + groups = "i2c2_0"; + }; + }; + + i2s1_pins: i2s1-pins { + mux { + function = "i2s"; + groups = "i2s_out_mclk_bclk_ws", + "i2s1_in_data", + "i2s1_out_data"; + }; + + conf { + pins = "I2S1_IN", "I2S1_OUT", "I2S_BCLK", + "I2S_WS", "I2S_MCLK"; + drive-strength = <12>; + bias-pull-down; + }; + }; + + irrx_pins: irrx-pins { + mux { + function = "ir"; + groups = "ir_1_rx"; + }; + }; + + irtx_pins: irtx-pins { + mux { + function = "ir"; + groups = "ir_1_tx"; + }; + }; + + /* Parallel nand is shared pin with eMMC */ + parallel_nand_pins: parallel-nand-pins { + mux { + function = "flash"; + groups = "par_nand"; + }; + }; + + pcie0_pins: pcie0-pins { + mux { + function = "pcie"; + groups = "pcie0_pad_perst", + "pcie0_1_waken", + "pcie0_1_clkreq"; + }; + }; + + pcie1_pins: pcie1-pins { + mux { + function = "pcie"; + groups = "pcie1_pad_perst", + "pcie1_0_waken", + "pcie1_0_clkreq"; + }; + }; + + pmic_bus_pins: pmic-bus-pins { + mux { + function = "pmic"; + groups = "pmic_bus"; + }; + }; + + pwm7_pins: pwm1-2-pins { + mux { + function = "pwm"; + groups = "pwm_ch7_2"; + }; + }; + + wled_pins: wled-pins { + mux { + function = "led"; + groups = "wled"; + }; + }; + + sd0_pins_default: sd0-pins-default { + mux { + function = "sd"; + groups = "sd_0"; + }; + + /* "I2S2_OUT, "I2S4_IN"", "I2S3_IN", "I2S2_IN", + * "I2S4_OUT", "I2S3_OUT" are used as DAT0, DAT1, + * DAT2, DAT3, CMD, CLK for SD respectively. + */ + conf-cmd-data { + pins = "I2S2_OUT", "I2S4_IN", "I2S3_IN", + "I2S2_IN","I2S4_OUT"; + input-enable; + drive-strength = <8>; + bias-pull-up; + }; + conf-clk { + pins = "I2S3_OUT"; + drive-strength = <12>; + bias-pull-down; + }; + conf-cd { + pins = "TXD3"; + bias-pull-up; + }; + }; + + sd0_pins_uhs: sd0-pins-uhs { + mux { + function = "sd"; + groups = "sd_0"; + }; + + conf-cmd-data { + pins = "I2S2_OUT", "I2S4_IN", "I2S3_IN", + "I2S2_IN","I2S4_OUT"; + input-enable; + bias-pull-up; + }; + + conf-clk { + pins = "I2S3_OUT"; + bias-pull-down; + }; + }; + + /* Serial NAND is shared pin with SPI-NOR */ + serial_nand_pins: serial-nand-pins { + mux { + function = "flash"; + groups = "snfi"; + }; + }; + + spic0_pins: spic0-pins { + mux { + function = "spi"; + groups = "spic0_0"; + }; + }; + + spic1_pins: spic1-pins { + mux { + function = "spi"; + groups = "spic1_0"; + }; + }; + + /* SPI-NOR is shared pin with serial NAND */ + spi_nor_pins: spi-nor-pins { + mux { + function = "flash"; + groups = "spi_nor"; + }; + }; + + /* serial NAND is shared pin with SPI-NOR */ + serial_nand_pins: serial-nand-pins { + mux { + function = "flash"; + groups = "snfi"; + }; + }; + + uart0_pins: uart0-pins { + mux { + function = "uart"; + groups = "uart0_0_tx_rx" ; + }; + }; + + uart2_pins: uart2-pins { + mux { + function = "uart"; + groups = "uart2_1_tx_rx" ; + }; + }; + + watchdog_pins: watchdog-pins { + mux { + function = "watchdog"; + groups = "watchdog"; + }; + }; +}; + +&bch { + status = "okay"; +}; + +&btif { + status = "okay"; +}; + +&cir { + pinctrl-names = "default"; + pinctrl-0 = <&irrx_pins>; + status = "okay"; +}; + +ð { + status = "okay"; + gmac0: mac@0 { + compatible = "mediatek,eth-mac"; + reg = <0>; + phy-mode = "sgmii"; + fixed-link { + speed = <1000>; + full-duplex; + pause; + }; + }; + gmac1: mac@1 { + compatible = "mediatek,eth-mac"; + reg = <1>; + phy-mode = "rgmii"; + fixed-link { + speed = <1000>; + full-duplex; + pause; + }; + }; + mdio: mdio-bus { + #address-cells = <1>; + #size-cells = <0>; + }; +}; + +&i2c1 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c1_pins>; + status = "okay"; +}; + +&i2c2 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c2_pins>; + status = "okay"; +}; + +&mmc0 { + pinctrl-names = "default", "state_uhs"; + pinctrl-0 = <&emmc_pins_default>; + pinctrl-1 = <&emmc_pins_uhs>; + status = "okay"; + bus-width = <8>; + max-frequency = <50000000>; + cap-mmc-highspeed; + mmc-hs200-1_8v; + vmmc-supply = <®_3p3v>; + vqmmc-supply = <®_1p8v>; + assigned-clocks = <&topckgen CLK_TOP_MSDC30_0_SEL>; + assigned-clock-parents = <&topckgen CLK_TOP_UNIV48M>; + non-removable; +}; + +&mmc1 { + pinctrl-names = "default", "state_uhs"; + pinctrl-0 = <&sd0_pins_default>; + pinctrl-1 = <&sd0_pins_uhs>; + status = "okay"; + bus-width = <4>; + max-frequency = <50000000>; + cap-sd-highspeed; + r_smpl = <1>; + cd-gpios = <&pio 81 GPIO_ACTIVE_LOW>; + vmmc-supply = <®_3p3v>; + vqmmc-supply = <®_3p3v>; + assigned-clocks = <&topckgen CLK_TOP_MSDC30_1_SEL>; + assigned-clock-parents = <&topckgen CLK_TOP_UNIV48M>; +}; + +&nandc { + pinctrl-names = "default"; + pinctrl-0 = <¶llel_nand_pins>; + status = "disabled"; +}; + +&nor_flash { + pinctrl-names = "default"; + pinctrl-0 = <&spi_nor_pins>; + status = "disabled"; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + }; +}; + +&pwm { + pinctrl-names = "default"; + pinctrl-0 = <&pwm7_pins>; + status = "okay"; +}; + +&pwrap { + pinctrl-names = "default"; + pinctrl-0 = <&pmic_bus_pins>; + + status = "okay"; +}; + +&snfi { + pinctrl-names = "default"; + pinctrl-0 = <&serial_nand_pins>; + status = "okay"; + + spi_nand@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "spi-nand"; + spi-max-frequency = <104000000>; + reg = <0>; + + 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 0x0040000>; + }; + + partition@200000 { + label = "Kernel"; + reg = <0x200000 0x2000000>; + }; + + partition@2200000 { + label = "User_data"; + reg = <0x2200000 0x4000000>; + }; + }; + }; +}; + +&spi0 { + pinctrl-names = "default"; + pinctrl-0 = <&spic0_pins>; + status = "okay"; +}; + +&spi1 { + pinctrl-names = "default"; + pinctrl-0 = <&spic1_pins>; + status = "okay"; +}; + +&ssusb { + vusb33-supply = <®_3p3v>; + vbus-supply = <®_5v>; + status = "okay"; +}; + +&u3phy { + status = "okay"; +}; + +&uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_pins>; + status = "okay"; +}; + +&uart2 { + pinctrl-names = "default"; + pinctrl-0 = <&uart2_pins>; + status = "okay"; +}; + +&watchdog { + pinctrl-names = "default"; + pinctrl-0 = <&watchdog_pins>; + status = "okay"; +}; diff --git a/target/linux/mediatek/files-4.19/arch/arm64/boot/dts/mediatek/mt7622.dtsi b/target/linux/mediatek/files-4.19/arch/arm64/boot/dts/mediatek/mt7622.dtsi new file mode 100755 index 0000000000..3fdd06a8d3 --- /dev/null +++ b/target/linux/mediatek/files-4.19/arch/arm64/boot/dts/mediatek/mt7622.dtsi @@ -0,0 +1,903 @@ +/* + * Copyright (c) 2017 MediaTek Inc. + * Author: Ming Huang <ming.huang@mediatek.com> + * Sean Wang <sean.wang@mediatek.com> + * + * SPDX-License-Identifier: (GPL-2.0 OR MIT) + */ + +#include <dt-bindings/interrupt-controller/irq.h> +#include <dt-bindings/interrupt-controller/arm-gic.h> +#include <dt-bindings/clock/mt7622-clk.h> +#include <dt-bindings/phy/phy.h> +#include <dt-bindings/power/mt7622-power.h> +#include <dt-bindings/reset/mt7622-reset.h> +#include <dt-bindings/thermal/thermal.h> + +/ { + compatible = "mediatek,mt7622"; + interrupt-parent = <&sysirq>; + #address-cells = <2>; + #size-cells = <2>; + + cpu_opp_table: opp-table { + compatible = "operating-points-v2"; + opp-shared; + opp-300000000 { + opp-hz = /bits/ 64 <30000000>; + opp-microvolt = <950000>; + }; + + opp-437500000 { + opp-hz = /bits/ 64 <437500000>; + opp-microvolt = <1000000>; + }; + + opp-600000000 { + opp-hz = /bits/ 64 <600000000>; + opp-microvolt = <1050000>; + }; + + opp-812500000 { + opp-hz = /bits/ 64 <812500000>; + opp-microvolt = <1100000>; + }; + + opp-1025000000 { + opp-hz = /bits/ 64 <1025000000>; + opp-microvolt = <1150000>; + }; + + opp-1137500000 { + opp-hz = /bits/ 64 <1137500000>; + opp-microvolt = <1200000>; + }; + + opp-1262500000 { + opp-hz = /bits/ 64 <1262500000>; + opp-microvolt = <1250000>; + }; + + opp-1350000000 { + opp-hz = /bits/ 64 <1350000000>; + opp-microvolt = <1310000>; + }; + }; + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a53", "arm,armv8"; + reg = <0x0 0x0>; + clocks = <&infracfg CLK_INFRA_MUX1_SEL>, + <&apmixedsys CLK_APMIXED_MAIN_CORE_EN>; + clock-names = "cpu", "intermediate"; + operating-points-v2 = <&cpu_opp_table>; + #cooling-cells = <2>; + enable-method = "psci"; + clock-frequency = <1300000000>; + }; + + cpu1: cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a53", "arm,armv8"; + reg = <0x0 0x1>; + clocks = <&infracfg CLK_INFRA_MUX1_SEL>, + <&apmixedsys CLK_APMIXED_MAIN_CORE_EN>; + clock-names = "cpu", "intermediate"; + operating-points-v2 = <&cpu_opp_table>; + #cooling-cells = <2>; + enable-method = "psci"; + clock-frequency = <1300000000>; + }; + }; + + pwrap_clk: dummy40m { + compatible = "fixed-clock"; + clock-frequency = <40000000>; + #clock-cells = <0>; + }; + + clk25m: oscillator { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <25000000>; + clock-output-names = "clkxtal"; + }; + + psci { + compatible = "arm,psci-0.2"; + method = "smc"; + }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + /* 192 KiB reserved for ARM Trusted Firmware (BL31) */ + secmon_reserved: secmon@43000000 { + reg = <0 0x43000000 0 0x30000>; + no-map; + }; + }; + + thermal-zones { + cpu_thermal: cpu-thermal { + polling-delay-passive = <1000>; + polling-delay = <1000>; + + thermal-sensors = <&thermal 0>; + + trips { + cpu_passive: cpu-passive { + temperature = <47000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu_active: cpu-active { + temperature = <67000>; + hysteresis = <2000>; + type = "active"; + }; + + cpu_hot: cpu-hot { + temperature = <87000>; + hysteresis = <2000>; + type = "hot"; + }; + + cpu-crit { + temperature = <107000>; + hysteresis = <2000>; + type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&cpu_passive>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + + map1 { + trip = <&cpu_active>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + + map2 { + trip = <&cpu_hot>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; + }; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupt-parent = <&gic>; + interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(2) | + IRQ_TYPE_LEVEL_HIGH)>, + <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(2) | + IRQ_TYPE_LEVEL_HIGH)>, + <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(2) | + IRQ_TYPE_LEVEL_HIGH)>, + <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(2) | + IRQ_TYPE_LEVEL_HIGH)>; + }; + + infracfg: infracfg@10000000 { + compatible = "mediatek,mt7622-infracfg", + "syscon"; + reg = <0 0x10000000 0 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + pwrap: pwrap@10001000 { + compatible = "mediatek,mt7622-pwrap"; + reg = <0 0x10001000 0 0x250>; + reg-names = "pwrap"; + clocks = <&infracfg CLK_INFRA_PMIC_PD>, <&pwrap_clk>; + clock-names = "spi", "wrap"; + resets = <&infracfg MT7622_INFRA_PMIC_WRAP_RST>; + reset-names = "pwrap"; + interrupts = <GIC_SPI 163 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + }; + + pericfg: pericfg@10002000 { + compatible = "mediatek,mt7622-pericfg", + "syscon"; + reg = <0 0x10002000 0 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + scpsys: scpsys@10006000 { + compatible = "mediatek,mt7622-scpsys", + "syscon"; + #power-domain-cells = <1>; + reg = <0 0x10006000 0 0x1000>; + interrupts = <GIC_SPI 165 IRQ_TYPE_LEVEL_LOW>, + <GIC_SPI 166 IRQ_TYPE_LEVEL_LOW>, + <GIC_SPI 167 IRQ_TYPE_LEVEL_LOW>, + <GIC_SPI 168 IRQ_TYPE_LEVEL_LOW>; + infracfg = <&infracfg>; + clocks = <&topckgen CLK_TOP_HIF_SEL>; + clock-names = "hif_sel"; + }; + + cir: cir@10009000 { + compatible = "mediatek,mt7622-cir"; + reg = <0 0x10009000 0 0x1000>; + interrupts = <GIC_SPI 175 IRQ_TYPE_LEVEL_LOW>; + clocks = <&infracfg CLK_INFRA_IRRX_PD>, + <&topckgen CLK_TOP_AXI_SEL>; + clock-names = "clk", "bus"; + status = "disabled"; + }; + + sysirq: interrupt-controller@10200620 { + compatible = "mediatek,mt7622-sysirq", + "mediatek,mt6577-sysirq"; + interrupt-controller; + #interrupt-cells = <3>; + interrupt-parent = <&gic>; + reg = <0 0x10200620 0 0x20>; + }; + + efuse: efuse@10206000 { + compatible = "mediatek,mt7622-efuse", + "mediatek,efuse"; + reg = <0 0x10206000 0 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + + thermal_calibration: calib@198 { + reg = <0x198 0xc>; + }; + }; + + apmixedsys: apmixedsys@10209000 { + compatible = "mediatek,mt7622-apmixedsys", + "syscon"; + reg = <0 0x10209000 0 0x1000>; + #clock-cells = <1>; + }; + + topckgen: topckgen@10210000 { + compatible = "mediatek,mt7622-topckgen", + "syscon"; + reg = <0 0x10210000 0 0x1000>; + #clock-cells = <1>; + }; + + rng: rng@1020f000 { + compatible = "mediatek,mt7622-rng", + "mediatek,mt7623-rng"; + reg = <0 0x1020f000 0 0x1000>; + clocks = <&infracfg CLK_INFRA_TRNG>; + clock-names = "rng"; + }; + + pio: pinctrl@10211000 { + compatible = "mediatek,mt7622-pinctrl"; + reg = <0 0x10211000 0 0x1000>, + <0 0x10005000 0 0x1000>; + reg-names = "base", "eint"; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pio 0 0 103>; + interrupt-controller; + interrupts = <GIC_SPI 153 IRQ_TYPE_LEVEL_HIGH>; + interrupt-parent = <&gic>; + #interrupt-cells = <2>; + }; + + watchdog: watchdog@10212000 { + compatible = "mediatek,mt7622-wdt", + "mediatek,mt6589-wdt"; + reg = <0 0x10212000 0 0x800>; + }; + + rtc: rtc@10212800 { + compatible = "mediatek,mt7622-rtc", + "mediatek,soc-rtc"; + reg = <0 0x10212800 0 0x200>; + interrupts = <GIC_SPI 129 IRQ_TYPE_LEVEL_LOW>; + clocks = <&topckgen CLK_TOP_RTC>; + clock-names = "rtc"; + }; + + gic: interrupt-controller@10300000 { + compatible = "arm,gic-400"; + interrupt-controller; + #interrupt-cells = <3>; + interrupt-parent = <&gic>; + reg = <0 0x10310000 0 0x1000>, + <0 0x10320000 0 0x1000>, + <0 0x10340000 0 0x2000>, + <0 0x10360000 0 0x2000>; + }; + + auxadc: adc@11001000 { + compatible = "mediatek,mt7622-auxadc"; + reg = <0 0x11001000 0 0x1000>; + clocks = <&pericfg CLK_PERI_AUXADC_PD>; + clock-names = "main"; + #io-channel-cells = <1>; + }; + + uart0: serial@11002000 { + compatible = "mediatek,mt7622-uart", + "mediatek,mt6577-uart"; + reg = <0 0x11002000 0 0x400>; + interrupts = <GIC_SPI 91 IRQ_TYPE_LEVEL_LOW>; + clocks = <&topckgen CLK_TOP_UART_SEL>, + <&pericfg CLK_PERI_UART0_PD>; + clock-names = "baud", "bus"; + status = "disabled"; + }; + + uart1: serial@11003000 { + compatible = "mediatek,mt7622-uart", + "mediatek,mt6577-uart"; + reg = <0 0x11003000 0 0x400>; + interrupts = <GIC_SPI 92 IRQ_TYPE_LEVEL_LOW>; + clocks = <&topckgen CLK_TOP_UART_SEL>, + <&pericfg CLK_PERI_UART1_PD>; + clock-names = "baud", "bus"; + status = "disabled"; + }; + + uart2: serial@11004000 { + compatible = "mediatek,mt7622-uart", + "mediatek,mt6577-uart"; + reg = <0 0x11004000 0 0x400>; + interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_LOW>; + clocks = <&topckgen CLK_TOP_UART_SEL>, + <&pericfg CLK_PERI_UART2_PD>; + clock-names = "baud", "bus"; + status = "disabled"; + }; + + uart3: serial@11005000 { + compatible = "mediatek,mt7622-uart", + "mediatek,mt6577-uart"; + reg = <0 0x11005000 0 0x400>; + interrupts = <GIC_SPI 94 IRQ_TYPE_LEVEL_LOW>; + clocks = <&topckgen CLK_TOP_UART_SEL>, + <&pericfg CLK_PERI_UART3_PD>; + clock-names = "baud", "bus"; + status = "disabled"; + }; + + pwm: pwm@11006000 { + compatible = "mediatek,mt7622-pwm"; + reg = <0 0x11006000 0 0x1000>; + interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_LOW>; + clocks = <&topckgen CLK_TOP_PWM_SEL>, + <&pericfg CLK_PERI_PWM_PD>, + <&pericfg CLK_PERI_PWM1_PD>, + <&pericfg CLK_PERI_PWM2_PD>, + <&pericfg CLK_PERI_PWM3_PD>, + <&pericfg CLK_PERI_PWM4_PD>, + <&pericfg CLK_PERI_PWM5_PD>, + <&pericfg CLK_PERI_PWM6_PD>; + clock-names = "top", "main", "pwm1", "pwm2", "pwm3", "pwm4", + "pwm5", "pwm6"; + status = "disabled"; + }; + + i2c0: i2c@11007000 { + compatible = "mediatek,mt7622-i2c"; + reg = <0 0x11007000 0 0x90>, + <0 0x11000100 0 0x80>; + interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_LOW>; + clock-div = <16>; + clocks = <&pericfg CLK_PERI_I2C0_PD>, + <&pericfg CLK_PERI_AP_DMA_PD>; + clock-names = "main", "dma"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c1: i2c@11008000 { + compatible = "mediatek,mt7622-i2c"; + reg = <0 0x11008000 0 0x90>, + <0 0x11000180 0 0x80>; + interrupts = <GIC_SPI 85 IRQ_TYPE_LEVEL_LOW>; + clock-div = <16>; + clocks = <&pericfg CLK_PERI_I2C1_PD>, + <&pericfg CLK_PERI_AP_DMA_PD>; + clock-names = "main", "dma"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c2: i2c@11009000 { + compatible = "mediatek,mt7622-i2c"; + reg = <0 0x11009000 0 0x90>, + <0 0x11000200 0 0x80>; + interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_LOW>; + clock-div = <16>; + clocks = <&pericfg CLK_PERI_I2C2_PD>, + <&pericfg CLK_PERI_AP_DMA_PD>; + clock-names = "main", "dma"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + spi0: spi@1100a000 { + compatible = "mediatek,mt7622-spi"; + reg = <0 0x1100a000 0 0x100>; + interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_LOW>; + clocks = <&topckgen CLK_TOP_SYSPLL3_D2>, + <&topckgen CLK_TOP_SPI0_SEL>, + <&pericfg CLK_PERI_SPI0_PD>; + clock-names = "parent-clk", "sel-clk", "spi-clk"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + thermal: thermal@1100b000 { + #thermal-sensor-cells = <1>; + compatible = "mediatek,mt7622-thermal"; + reg = <0 0x1100b000 0 0x1000>; + interrupts = <0 78 IRQ_TYPE_LEVEL_LOW>; + clocks = <&pericfg CLK_PERI_THERM_PD>, + <&pericfg CLK_PERI_AUXADC_PD>; + clock-names = "therm", "auxadc"; + resets = <&pericfg MT7622_PERI_THERM_SW_RST>; + reset-names = "therm"; + mediatek,auxadc = <&auxadc>; + mediatek,apmixedsys = <&apmixedsys>; + nvmem-cells = <&thermal_calibration>; + nvmem-cell-names = "calibration-data"; + }; + + btif: serial@1100c000 { + compatible = "mediatek,mt7622-btif", + "mediatek,mtk-btif"; + reg = <0 0x1100c000 0 0x1000>; + interrupts = <GIC_SPI 90 IRQ_TYPE_LEVEL_LOW>; + clocks = <&pericfg CLK_PERI_BTIF_PD>; + clock-names = "main"; + reg-shift = <2>; + reg-io-width = <4>; + status = "disabled"; + + bluetooth { + compatible = "mediatek,mt7622-bluetooth"; + power-domains = <&scpsys MT7622_POWER_DOMAIN_WB>; + clocks = <&clk25m>; + clock-names = "ref"; + }; + }; + + nandc: nfi@1100d000 { + compatible = "mediatek,mt7622-nfc"; + reg = <0 0x1100D000 0 0x1000>; + interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_LOW>; + clocks = <&pericfg CLK_PERI_NFI_PD>, + <&pericfg CLK_PERI_SNFI_PD>; + clock-names = "nfi_clk", "pad_clk"; + ecc-engine = <&bch>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + bch: ecc@1100e000 { + compatible = "mediatek,mt7622-ecc"; + reg = <0 0x1100e000 0 0x1000>; + interrupts = <GIC_SPI 95 IRQ_TYPE_LEVEL_LOW>; + clocks = <&pericfg CLK_PERI_NFIECC_PD>; + clock-names = "nfiecc_clk"; + status = "disabled"; + }; + + nor_flash: spi@11014000 { + compatible = "mediatek,mt7622-nor", + "mediatek,mt8173-nor"; + reg = <0 0x11014000 0 0xe0>; + clocks = <&pericfg CLK_PERI_FLASH_PD>, + <&topckgen CLK_TOP_FLASH_SEL>; + clock-names = "spi", "sf"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + snfi: spi@1100d000 { + compatible = "mediatek,mt7622-snfi"; + reg = <0 0x1100d000 0 0x1000>; + interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_LOW>; + clocks = <&pericfg CLK_PERI_NFI_PD>, + <&pericfg CLK_PERI_SNFI_PD>; + clock-names = "nfi_clk", "spi_clk"; + ecc-engine = <&bch>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + spi1: spi@11016000 { + compatible = "mediatek,mt7622-spi"; + reg = <0 0x11016000 0 0x100>; + interrupts = <GIC_SPI 122 IRQ_TYPE_LEVEL_LOW>; + clocks = <&topckgen CLK_TOP_SYSPLL3_D2>, + <&topckgen CLK_TOP_SPI1_SEL>, + <&pericfg CLK_PERI_SPI1_PD>; + clock-names = "parent-clk", "sel-clk", "spi-clk"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + uart4: serial@11019000 { + compatible = "mediatek,mt7622-uart", + "mediatek,mt6577-uart"; + reg = <0 0x11019000 0 0x400>; + interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_LOW>; + clocks = <&topckgen CLK_TOP_UART_SEL>, + <&pericfg CLK_PERI_UART4_PD>; + clock-names = "baud", "bus"; + status = "disabled"; + }; + + audsys: clock-controller@11220000 { + compatible = "mediatek,mt7622-audsys", "syscon"; + reg = <0 0x11220000 0 0x2000>; + #clock-cells = <1>; + + afe: audio-controller { + compatible = "mediatek,mt7622-audio"; + interrupts = <GIC_SPI 144 IRQ_TYPE_LEVEL_LOW>, + <GIC_SPI 145 IRQ_TYPE_LEVEL_LOW>; + interrupt-names = "afe", "asys"; + + clocks = <&infracfg CLK_INFRA_AUDIO_PD>, + <&topckgen CLK_TOP_AUD1_SEL>, + <&topckgen CLK_TOP_AUD2_SEL>, + <&topckgen CLK_TOP_A1SYS_HP_DIV_PD>, + <&topckgen CLK_TOP_A2SYS_HP_DIV_PD>, + <&topckgen CLK_TOP_I2S0_MCK_SEL>, + <&topckgen CLK_TOP_I2S1_MCK_SEL>, + <&topckgen CLK_TOP_I2S2_MCK_SEL>, + <&topckgen CLK_TOP_I2S3_MCK_SEL>, + <&topckgen CLK_TOP_I2S0_MCK_DIV>, + <&topckgen CLK_TOP_I2S1_MCK_DIV>, + <&topckgen CLK_TOP_I2S2_MCK_DIV>, + <&topckgen CLK_TOP_I2S3_MCK_DIV>, + <&topckgen CLK_TOP_I2S0_MCK_DIV_PD>, + <&topckgen CLK_TOP_I2S1_MCK_DIV_PD>, + <&topckgen CLK_TOP_I2S2_MCK_DIV_PD>, + <&topckgen CLK_TOP_I2S3_MCK_DIV_PD>, + <&audsys CLK_AUDIO_I2SO1>, + <&audsys CLK_AUDIO_I2SO2>, + <&audsys CLK_AUDIO_I2SO3>, + <&audsys CLK_AUDIO_I2SO4>, + <&audsys CLK_AUDIO_I2SIN1>, + <&audsys CLK_AUDIO_I2SIN2>, + <&audsys CLK_AUDIO_I2SIN3>, + <&audsys CLK_AUDIO_I2SIN4>, + <&audsys CLK_AUDIO_ASRCO1>, + <&audsys CLK_AUDIO_ASRCO2>, + <&audsys CLK_AUDIO_ASRCO3>, + <&audsys CLK_AUDIO_ASRCO4>, + <&audsys CLK_AUDIO_AFE>, + <&audsys CLK_AUDIO_AFE_CONN>, + <&audsys CLK_AUDIO_A1SYS>, + <&audsys CLK_AUDIO_A2SYS>; + + clock-names = "infra_sys_audio_clk", + "top_audio_mux1_sel", + "top_audio_mux2_sel", + "top_audio_a1sys_hp", + "top_audio_a2sys_hp", + "i2s0_src_sel", + "i2s1_src_sel", + "i2s2_src_sel", + "i2s3_src_sel", + "i2s0_src_div", + "i2s1_src_div", + "i2s2_src_div", + "i2s3_src_div", + "i2s0_mclk_en", + "i2s1_mclk_en", + "i2s2_mclk_en", + "i2s3_mclk_en", + "i2so0_hop_ck", + "i2so1_hop_ck", + "i2so2_hop_ck", + "i2so3_hop_ck", + "i2si0_hop_ck", + "i2si1_hop_ck", + "i2si2_hop_ck", + "i2si3_hop_ck", + "asrc0_out_ck", + "asrc1_out_ck", + "asrc2_out_ck", + "asrc3_out_ck", + "audio_afe_pd", + "audio_afe_conn_pd", + "audio_a1sys_pd", + "audio_a2sys_pd"; + + assigned-clocks = <&topckgen CLK_TOP_A1SYS_HP_SEL>, + <&topckgen CLK_TOP_A2SYS_HP_SEL>, + <&topckgen CLK_TOP_A1SYS_HP_DIV>, + <&topckgen CLK_TOP_A2SYS_HP_DIV>; + assigned-clock-parents = <&topckgen CLK_TOP_AUD1PLL>, + <&topckgen CLK_TOP_AUD2PLL>; + assigned-clock-rates = <0>, <0>, <49152000>, <45158400>; + }; + }; + + mmc0: mmc@11230000 { + compatible = "mediatek,mt7622-mmc"; + reg = <0 0x11230000 0 0x1000>; + interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_LOW>; + clocks = <&pericfg CLK_PERI_MSDC30_0_PD>, + <&topckgen CLK_TOP_MSDC50_0_SEL>; + clock-names = "source", "hclk"; + status = "disabled"; + }; + + mmc1: mmc@11240000 { + compatible = "mediatek,mt7622-mmc"; + reg = <0 0x11240000 0 0x1000>; + interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_LOW>; + clocks = <&pericfg CLK_PERI_MSDC30_1_PD>, + <&topckgen CLK_TOP_AXI_SEL>; + clock-names = "source", "hclk"; + status = "disabled"; + }; + + ssusbsys: ssusbsys@1a000000 { + compatible = "mediatek,mt7622-ssusbsys", + "syscon"; + reg = <0 0x1a000000 0 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + ssusb: usb@1a0c0000 { + compatible = "mediatek,mt7622-xhci", + "mediatek,mtk-xhci"; + reg = <0 0x1a0c0000 0 0x01000>, + <0 0x1a0c4700 0 0x0100>; + reg-names = "mac", "ippc"; + interrupts = <GIC_SPI 232 IRQ_TYPE_LEVEL_LOW>; + power-domains = <&scpsys MT7622_POWER_DOMAIN_HIF1>; + clocks = <&ssusbsys CLK_SSUSB_SYS_EN>, + <&ssusbsys CLK_SSUSB_REF_EN>, + <&ssusbsys CLK_SSUSB_MCU_EN>, + <&ssusbsys CLK_SSUSB_DMA_EN>; + clock-names = "sys_ck", "ref_ck", "mcu_ck", "dma_ck"; + phys = <&u2port0 PHY_TYPE_USB2>, + <&u3port0 PHY_TYPE_USB3>, + <&u2port1 PHY_TYPE_USB2>; + + status = "disabled"; + }; + + u3phy: usb-phy@1a0c4000 { + compatible = "mediatek,mt7622-u3phy", + "mediatek,generic-tphy-v1"; + reg = <0 0x1a0c4000 0 0x700>; + #address-cells = <2>; + #size-cells = <2>; + ranges; + status = "disabled"; + + u2port0: usb-phy@1a0c4800 { + reg = <0 0x1a0c4800 0 0x0100>; + #phy-cells = <1>; + clocks = <&ssusbsys CLK_SSUSB_U2_PHY_EN>; + clock-names = "ref"; + }; + + u3port0: usb-phy@1a0c4900 { + reg = <0 0x1a0c4900 0 0x0700>; + #phy-cells = <1>; + clocks = <&clk25m>; + clock-names = "ref"; + }; + + u2port1: usb-phy@1a0c5000 { + reg = <0 0x1a0c5000 0 0x0100>; + #phy-cells = <1>; + clocks = <&ssusbsys CLK_SSUSB_U2_PHY_1P_EN>; + clock-names = "ref"; + }; + }; + + pciesys: pciesys@1a100800 { + compatible = "mediatek,mt7622-pciesys", + "syscon"; + reg = <0 0x1a100800 0 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + pcie: pcie@1a140000 { + compatible = "mediatek,mt7622-pcie"; + device_type = "pci"; + reg = <0 0x1a140000 0 0x1000>, + <0 0x1a143000 0 0x1000>, + <0 0x1a145000 0 0x1000>; + reg-names = "subsys", "port0", "port1"; + #address-cells = <3>; + #size-cells = <2>; + interrupts = <GIC_SPI 228 IRQ_TYPE_LEVEL_LOW>, + <GIC_SPI 229 IRQ_TYPE_LEVEL_LOW>; + clocks = <&pciesys CLK_PCIE_P0_MAC_EN>, + <&pciesys CLK_PCIE_P1_MAC_EN>, + <&pciesys CLK_PCIE_P0_AHB_EN>, + <&pciesys CLK_PCIE_P0_AHB_EN>, + <&pciesys CLK_PCIE_P0_AUX_EN>, + <&pciesys CLK_PCIE_P1_AUX_EN>, + <&pciesys CLK_PCIE_P0_AXI_EN>, + <&pciesys CLK_PCIE_P1_AXI_EN>, + <&pciesys CLK_PCIE_P0_OBFF_EN>, + <&pciesys CLK_PCIE_P1_OBFF_EN>, + <&pciesys CLK_PCIE_P0_PIPE_EN>, + <&pciesys CLK_PCIE_P1_PIPE_EN>; + clock-names = "sys_ck0", "sys_ck1", "ahb_ck0", "ahb_ck1", + "aux_ck0", "aux_ck1", "axi_ck0", "axi_ck1", + "obff_ck0", "obff_ck1", "pipe_ck0", "pipe_ck1"; + power-domains = <&scpsys MT7622_POWER_DOMAIN_HIF0>; + bus-range = <0x00 0xff>; + ranges = <0x82000000 0 0x20000000 0x0 0x20000000 0 0x10000000>; + status = "disabled"; + + pcie0: pcie@0,0 { + reg = <0x0000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + ranges; + status = "disabled"; + + num-lanes = <1>; + interrupt-map-mask = <0 0 0 7>; + 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 { + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <1>; + }; + }; + + pcie1: pcie@1,0 { + reg = <0x0800 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + ranges; + status = "disabled"; + + num-lanes = <1>; + interrupt-map-mask = <0 0 0 7>; + 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 { + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <1>; + }; + }; + }; + + sata: sata@1a200000 { + compatible = "mediatek,mt7622-ahci", + "mediatek,mtk-ahci"; + reg = <0 0x1a200000 0 0x1100>; + interrupts = <GIC_SPI 233 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "hostc"; + clocks = <&pciesys CLK_SATA_AHB_EN>, + <&pciesys CLK_SATA_AXI_EN>, + <&pciesys CLK_SATA_ASIC_EN>, + <&pciesys CLK_SATA_RBC_EN>, + <&pciesys CLK_SATA_PM_EN>; + clock-names = "ahb", "axi", "asic", "rbc", "pm"; + phys = <&sata_port PHY_TYPE_SATA>; + phy-names = "sata-phy"; + ports-implemented = <0x1>; + power-domains = <&scpsys MT7622_POWER_DOMAIN_HIF0>; + resets = <&pciesys MT7622_SATA_AXI_BUS_RST>, + <&pciesys MT7622_SATA_PHY_SW_RST>, + <&pciesys MT7622_SATA_PHY_REG_RST>; + reset-names = "axi", "sw", "reg"; + mediatek,phy-mode = <&pciesys>; + status = "disabled"; + }; + + sata_phy: sata-phy@1a243000 { + compatible = "mediatek,generic-tphy-v1"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + status = "disabled"; + + sata_port: sata-phy@1a243000 { + reg = <0 0x1a243000 0 0x0100>; + clocks = <&topckgen CLK_TOP_ETH_500M>; + clock-names = "ref"; + #phy-cells = <1>; + }; + }; + + ethsys: syscon@1b000000 { + compatible = "mediatek,mt7622-ethsys", + "syscon"; + reg = <0 0x1b000000 0 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + hsdma: dma-controller@1b007000 { + compatible = "mediatek,mt7622-hsdma"; + reg = <0 0x1b007000 0 0x1000>; + interrupts = <GIC_SPI 219 IRQ_TYPE_LEVEL_LOW>; + clocks = <ðsys CLK_ETH_HSDMA_EN>; + clock-names = "hsdma"; + power-domains = <&scpsys MT7622_POWER_DOMAIN_ETHSYS>; + #dma-cells = <1>; + }; + + eth: ethernet@1b100000 { + compatible = "mediatek,mt7622-eth", + "mediatek,mt2701-eth", + "syscon"; + reg = <0 0x1b100000 0 0x20000>; + interrupts = <GIC_SPI 223 IRQ_TYPE_LEVEL_LOW>, + <GIC_SPI 224 IRQ_TYPE_LEVEL_LOW>, + <GIC_SPI 225 IRQ_TYPE_LEVEL_LOW>; + clocks = <&topckgen CLK_TOP_ETH_SEL>, + <ðsys CLK_ETH_ESW_EN>, + <ðsys CLK_ETH_GP0_EN>, + <ðsys CLK_ETH_GP1_EN>, + <ðsys CLK_ETH_GP2_EN>, + <&sgmiisys CLK_SGMII_TX250M_EN>, + <&sgmiisys CLK_SGMII_RX250M_EN>, + <&sgmiisys CLK_SGMII_CDR_REF>, + <&sgmiisys CLK_SGMII_CDR_FB>, + <&topckgen CLK_TOP_SGMIIPLL>, + <&apmixedsys CLK_APMIXED_ETH2PLL>; + clock-names = "ethif", "esw", "gp0", "gp1", "gp2", + "sgmii_tx250m", "sgmii_rx250m", + "sgmii_cdr_ref", "sgmii_cdr_fb", "sgmii_ck", + "eth2pll"; + power-domains = <&scpsys MT7622_POWER_DOMAIN_ETHSYS>; + mediatek,ethsys = <ðsys>; + mediatek,sgmiisys = <&sgmiisys>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + sgmiisys: sgmiisys@1b128000 { + compatible = "mediatek,mt7622-sgmiisys", + "syscon"; + reg = <0 0x1b128000 0 0x3000>; + #clock-cells = <1>; + mediatek,physpeed = "2500"; + }; +}; diff --git a/target/linux/mediatek/files-4.19/drivers/net/phy/mtk/mt753x/Kconfig b/target/linux/mediatek/files-4.19/drivers/net/phy/mtk/mt753x/Kconfig new file mode 100644 index 0000000000..cf83c6a436 --- /dev/null +++ b/target/linux/mediatek/files-4.19/drivers/net/phy/mtk/mt753x/Kconfig @@ -0,0 +1,4 @@ + +config MT753X_GSW + tristate "Driver for the MediaTek MT753x switch" + diff --git a/target/linux/mediatek/files-4.19/drivers/net/phy/mtk/mt753x/Makefile b/target/linux/mediatek/files-4.19/drivers/net/phy/mtk/mt753x/Makefile new file mode 100644 index 0000000000..3829bacfe9 --- /dev/null +++ b/target/linux/mediatek/files-4.19/drivers/net/phy/mtk/mt753x/Makefile @@ -0,0 +1,11 @@ +# +# Makefile for MediaTek MT753x gigabit switch +# + +obj-$(CONFIG_MT753X_GSW) += mt753x.o + +mt753x-$(CONFIG_SWCONFIG) += mt753x_swconfig.o + +mt753x-y += mt753x_mdio.o mt7530.o mt7531.o \ + mt753x_common.o mt753x_nl.o + diff --git a/target/linux/mediatek/files-4.19/drivers/net/phy/mtk/mt753x/mt7530.c b/target/linux/mediatek/files-4.19/drivers/net/phy/mtk/mt753x/mt7530.c new file mode 100644 index 0000000000..45d4984c1a --- /dev/null +++ b/target/linux/mediatek/files-4.19/drivers/net/phy/mtk/mt753x/mt7530.c @@ -0,0 +1,602 @@ +/* + * Driver for MediaTek MT7530 gigabit switch + * + * Copyright (C) 2018 MediaTek Inc. All Rights Reserved. + * + * Author: Weijie Gao <weijie.gao@mediatek.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <linux/kernel.h> +#include <linux/delay.h> + +#include "mt753x.h" +#include "mt753x_regs.h" + +/* MT7530 registers */ + +/* Unique fields of PMCR for MT7530 */ +#define FORCE_MODE BIT(15) + +/* Unique fields of GMACCR for MT7530 */ +#define VLAN_SUPT_NO_S 14 +#define VLAN_SUPT_NO_M 0x1c000 +#define LATE_COL_DROP BIT(13) + +/* Unique fields of (M)HWSTRAP for MT7530 */ +#define BOND_OPTION BIT(24) +#define P5_PHY0_SEL BIT(20) +#define CHG_TRAP BIT(16) +#define LOOPDET_DIS BIT(14) +#define P5_INTF_SEL_GMAC5 BIT(13) +#define SMI_ADDR_S 11 +#define SMI_ADDR_M 0x1800 +#define XTAL_FSEL_S 9 +#define XTAL_FSEL_M 0x600 +#define P6_INTF_DIS BIT(8) +#define P5_INTF_MODE_RGMII BIT(7) +#define P5_INTF_DIS_S BIT(6) +#define C_MDIO_BPS_S BIT(5) +#define EEPROM_EN_S BIT(4) + +/* PHY EEE Register bitmap of define */ +#define PHY_DEV07 0x07 +#define PHY_DEV07_REG_03C 0x3c + +/* PHY Extend Register 0x14 bitmap of define */ +#define PHY_EXT_REG_14 0x14 + +/* Fields of PHY_EXT_REG_14 */ +#define PHY_EN_DOWN_SHFIT BIT(4) + +/* PHY Token Ring Register 0x10 bitmap of define */ +#define PHY_TR_REG_10 0x10 + +/* PHY Token Ring Register 0x12 bitmap of define */ +#define PHY_TR_REG_12 0x12 + +/* PHY LPI PCS/DSP Control Register bitmap of define */ +#define PHY_LPI_REG_11 0x11 + +/* PHY DEV 0x1e Register bitmap of define */ +#define PHY_DEV1E 0x1e +#define PHY_DEV1E_REG_123 0x123 +#define PHY_DEV1E_REG_A6 0xa6 + +/* Values of XTAL_FSEL */ +#define XTAL_20MHZ 1 +#define XTAL_40MHZ 2 +#define XTAL_25MHZ 3 + +#define P6ECR 0x7830 +#define P6_INTF_MODE_TRGMII BIT(0) + +#define TRGMII_TXCTRL 0x7a40 +#define TRAIN_TXEN BIT(31) +#define TXC_INV BIT(30) +#define TX_DOEO BIT(29) +#define TX_RST BIT(28) + +#define TRGMII_TD0_CTRL 0x7a50 +#define TRGMII_TD1_CTRL 0x7a58 +#define TRGMII_TD2_CTRL 0x7a60 +#define TRGMII_TD3_CTRL 0x7a68 +#define TRGMII_TXCTL_CTRL 0x7a70 +#define TRGMII_TCK_CTRL 0x7a78 +#define TRGMII_TD_CTRL(n) (0x7a50 + (n) * 8) +#define NUM_TRGMII_CTRL 6 +#define TX_DMPEDRV BIT(31) +#define TX_DM_SR BIT(15) +#define TX_DMERODT BIT(14) +#define TX_DMOECTL BIT(13) +#define TX_TAP_S 8 +#define TX_TAP_M 0xf00 +#define TX_TRAIN_WD_S 0 +#define TX_TRAIN_WD_M 0xff + +#define TRGMII_TD0_ODT 0x7a54 +#define TRGMII_TD1_ODT 0x7a5c +#define TRGMII_TD2_ODT 0x7a64 +#define TRGMII_TD3_ODT 0x7a6c +#define TRGMII_TXCTL_ODT 0x7574 +#define TRGMII_TCK_ODT 0x757c +#define TRGMII_TD_ODT(n) (0x7a54 + (n) * 8) +#define NUM_TRGMII_ODT 6 +#define TX_DM_DRVN_PRE_S 30 +#define TX_DM_DRVN_PRE_M 0xc0000000 +#define TX_DM_DRVP_PRE_S 28 +#define TX_DM_DRVP_PRE_M 0x30000000 +#define TX_DM_TDSEL_S 24 +#define TX_DM_TDSEL_M 0xf000000 +#define TX_ODTEN BIT(23) +#define TX_DME_PRE BIT(20) +#define TX_DM_DRVNT0 BIT(19) +#define TX_DM_DRVPT0 BIT(18) +#define TX_DM_DRVNTE BIT(17) +#define TX_DM_DRVPTE BIT(16) +#define TX_DM_ODTN_S 12 +#define TX_DM_ODTN_M 0x7000 +#define TX_DM_ODTP_S 8 +#define TX_DM_ODTP_M 0x700 +#define TX_DM_DRVN_S 4 +#define TX_DM_DRVN_M 0xf0 +#define TX_DM_DRVP_S 0 +#define TX_DM_DRVP_M 0x0f + +#define P5RGMIIRXCR 0x7b00 +#define CSR_RGMII_RCTL_CFG_S 24 +#define CSR_RGMII_RCTL_CFG_M 0x7000000 +#define CSR_RGMII_RXD_CFG_S 16 +#define CSR_RGMII_RXD_CFG_M 0x70000 +#define CSR_RGMII_EDGE_ALIGN BIT(8) +#define CSR_RGMII_RXC_90DEG_CFG_S 4 +#define CSR_RGMII_RXC_90DEG_CFG_M 0xf0 +#define CSR_RGMII_RXC_0DEG_CFG_S 0 +#define CSR_RGMII_RXC_0DEG_CFG_M 0x0f + +#define P5RGMIITXCR 0x7b04 +#define CSR_RGMII_TXEN_CFG_S 16 +#define CSR_RGMII_TXEN_CFG_M 0x70000 +#define CSR_RGMII_TXD_CFG_S 8 +#define CSR_RGMII_TXD_CFG_M 0x700 +#define CSR_RGMII_TXC_CFG_S 0 +#define CSR_RGMII_TXC_CFG_M 0x1f + +#define CHIP_REV 0x7ffc +#define CHIP_NAME_S 16 +#define CHIP_NAME_M 0xffff0000 +#define CHIP_REV_S 0 +#define CHIP_REV_M 0x0f + +/* MMD registers */ +#define CORE_PLL_GROUP2 0x401 +#define RG_SYSPLL_EN_NORMAL BIT(15) +#define RG_SYSPLL_VODEN BIT(14) +#define RG_SYSPLL_POSDIV_S 5 +#define RG_SYSPLL_POSDIV_M 0x60 + +#define CORE_PLL_GROUP4 0x403 +#define RG_SYSPLL_DDSFBK_EN BIT(12) +#define RG_SYSPLL_BIAS_EN BIT(11) +#define RG_SYSPLL_BIAS_LPF_EN BIT(10) + +#define CORE_PLL_GROUP5 0x404 +#define RG_LCDDS_PCW_NCPO1_S 0 +#define RG_LCDDS_PCW_NCPO1_M 0xffff + +#define CORE_PLL_GROUP6 0x405 +#define RG_LCDDS_PCW_NCPO0_S 0 +#define RG_LCDDS_PCW_NCPO0_M 0xffff + +#define CORE_PLL_GROUP7 0x406 +#define RG_LCDDS_PWDB BIT(15) +#define RG_LCDDS_ISO_EN BIT(13) +#define RG_LCCDS_C_S 4 +#define RG_LCCDS_C_M 0x70 +#define RG_LCDDS_PCW_NCPO_CHG BIT(3) + +#define CORE_PLL_GROUP10 0x409 +#define RG_LCDDS_SSC_DELTA_S 0 +#define RG_LCDDS_SSC_DELTA_M 0xfff + +#define CORE_PLL_GROUP11 0x40a +#define RG_LCDDS_SSC_DELTA1_S 0 +#define RG_LCDDS_SSC_DELTA1_M 0xfff + +#define CORE_GSWPLL_GCR_1 0x040d +#define GSWPLL_PREDIV_S 14 +#define GSWPLL_PREDIV_M 0xc000 +#define GSWPLL_POSTDIV_200M_S 12 +#define GSWPLL_POSTDIV_200M_M 0x3000 +#define GSWPLL_EN_PRE BIT(11) +#define GSWPLL_FBKSEL BIT(10) +#define GSWPLL_BP BIT(9) +#define GSWPLL_BR BIT(8) +#define GSWPLL_FBKDIV_200M_S 0 +#define GSWPLL_FBKDIV_200M_M 0xff + +#define CORE_GSWPLL_GCR_2 0x040e +#define GSWPLL_POSTDIV_500M_S 8 +#define GSWPLL_POSTDIV_500M_M 0x300 +#define GSWPLL_FBKDIV_500M_S 0 +#define GSWPLL_FBKDIV_500M_M 0xff + +#define TRGMII_GSW_CLK_CG 0x0410 +#define TRGMIICK_EN BIT(1) +#define GSWCK_EN BIT(0) + +static int mt7530_mii_read(struct gsw_mt753x *gsw, int phy, int reg) +{ + if (phy < MT753X_NUM_PHYS) + phy = (gsw->phy_base + phy) & MT753X_SMI_ADDR_MASK; + + return mdiobus_read(gsw->host_bus, phy, reg); +} + +static void mt7530_mii_write(struct gsw_mt753x *gsw, int phy, int reg, u16 val) +{ + if (phy < MT753X_NUM_PHYS) + phy = (gsw->phy_base + phy) & MT753X_SMI_ADDR_MASK; + + mdiobus_write(gsw->host_bus, phy, reg, val); +} + +static int mt7530_mmd_read(struct gsw_mt753x *gsw, int addr, int devad, u16 reg) +{ + u16 val; + + if (addr < MT753X_NUM_PHYS) + addr = (gsw->phy_base + addr) & MT753X_SMI_ADDR_MASK; + + mutex_lock(&gsw->host_bus->mdio_lock); + + gsw->host_bus->write(gsw->host_bus, addr, MII_MMD_ACC_CTL_REG, + (MMD_ADDR << MMD_CMD_S) | + ((devad << MMD_DEVAD_S) & MMD_DEVAD_M)); + + gsw->host_bus->write(gsw->host_bus, addr, MII_MMD_ADDR_DATA_REG, reg); + + gsw->host_bus->write(gsw->host_bus, addr, MII_MMD_ACC_CTL_REG, + (MMD_DATA << MMD_CMD_S) | + ((devad << MMD_DEVAD_S) & MMD_DEVAD_M)); + + val = gsw->host_bus->read(gsw->host_bus, addr, MII_MMD_ADDR_DATA_REG); + + mutex_unlock(&gsw->host_bus->mdio_lock); + + return val; +} + +static void mt7530_mmd_write(struct gsw_mt753x *gsw, int addr, int devad, + u16 reg, u16 val) +{ + if (addr < MT753X_NUM_PHYS) + addr = (gsw->phy_base + addr) & MT753X_SMI_ADDR_MASK; + + mutex_lock(&gsw->host_bus->mdio_lock); + + gsw->host_bus->write(gsw->host_bus, addr, MII_MMD_ACC_CTL_REG, + (MMD_ADDR << MMD_CMD_S) | + ((devad << MMD_DEVAD_S) & MMD_DEVAD_M)); + + gsw->host_bus->write(gsw->host_bus, addr, MII_MMD_ADDR_DATA_REG, reg); + + gsw->host_bus->write(gsw->host_bus, addr, MII_MMD_ACC_CTL_REG, + (MMD_DATA << MMD_CMD_S) | + ((devad << MMD_DEVAD_S) & MMD_DEVAD_M)); + + gsw->host_bus->write(gsw->host_bus, addr, MII_MMD_ADDR_DATA_REG, val); + + mutex_unlock(&gsw->host_bus->mdio_lock); +} + +static void mt7530_core_reg_write(struct gsw_mt753x *gsw, u32 reg, u32 val) +{ + gsw->mmd_write(gsw, 0, 0x1f, reg, val); +} + +static int mt7530_mac_port_setup(struct gsw_mt753x *gsw) +{ + u32 hwstrap, p6ecr = 0, p5mcr, p6mcr, phyad; + + hwstrap = mt753x_reg_read(gsw, HWSTRAP); + hwstrap &= ~(P6_INTF_DIS | P5_INTF_MODE_RGMII | P5_INTF_DIS_S); + hwstrap |= CHG_TRAP | P5_INTF_SEL_GMAC5; + + if (gsw->direct_phy_access) + hwstrap &= ~C_MDIO_BPS_S; + else + hwstrap |= C_MDIO_BPS_S; + + if (!gsw->port5_cfg.enabled) { + p5mcr = FORCE_MODE; + hwstrap |= P5_INTF_DIS_S; + } else { + p5mcr = (IPG_96BIT_WITH_SHORT_IPG << IPG_CFG_S) | + MAC_MODE | MAC_TX_EN | MAC_RX_EN | + BKOFF_EN | BACKPR_EN; + + if (gsw->port5_cfg.force_link) { + p5mcr |= FORCE_MODE | FORCE_LINK | FORCE_RX_FC | + FORCE_TX_FC; + p5mcr |= gsw->port5_cfg.speed << FORCE_SPD_S; + + if (gsw->port5_cfg.duplex) + p5mcr |= FORCE_DPX; + } + + switch (gsw->port5_cfg.phy_mode) { + case PHY_INTERFACE_MODE_MII: + case PHY_INTERFACE_MODE_GMII: + break; + case PHY_INTERFACE_MODE_RGMII: + hwstrap |= P5_INTF_MODE_RGMII; + break; + default: + dev_info(gsw->dev, "%s is not supported by port5\n", + phy_modes(gsw->port5_cfg.phy_mode)); + p5mcr = FORCE_MODE; + hwstrap |= P5_INTF_DIS_S; + } + + /* Port5 to PHY direct mode */ + if (of_property_read_u32(gsw->port5_cfg.np, "phy-address", + &phyad)) + goto parse_p6; + + if (phyad != 0 && phyad != 4) { + dev_info(gsw->dev, + "Only PHY 0/4 can be connected to Port 5\n"); + goto parse_p6; + } + + hwstrap &= ~P5_INTF_SEL_GMAC5; + if (phyad == 0) + hwstrap |= P5_PHY0_SEL; + else + hwstrap &= ~P5_PHY0_SEL; + } + +parse_p6: + if (!gsw->port6_cfg.enabled) { + p6mcr = FORCE_MODE; + hwstrap |= P6_INTF_DIS; + } else { + p6mcr = (IPG_96BIT_WITH_SHORT_IPG << IPG_CFG_S) | + MAC_MODE | MAC_TX_EN | MAC_RX_EN | + BKOFF_EN | BACKPR_EN; + + if (gsw->port6_cfg.force_link) { + p6mcr |= FORCE_MODE | FORCE_LINK | FORCE_RX_FC | + FORCE_TX_FC; + p6mcr |= gsw->port6_cfg.speed << FORCE_SPD_S; + + if (gsw->port6_cfg.duplex) + p6mcr |= FORCE_DPX; + } + + switch (gsw->port6_cfg.phy_mode) { + case PHY_INTERFACE_MODE_RGMII: + break; + case PHY_INTERFACE_MODE_TRGMII: + /* set MT7530 central align */ + p6ecr = BIT(1); /* TODO: confirm this */ + break; + default: + dev_info(gsw->dev, "%s is not supported by port6\n", + phy_modes(gsw->port6_cfg.phy_mode)); + p6mcr = FORCE_MODE; + hwstrap |= P6_INTF_DIS; + } + } + + mt753x_reg_write(gsw, MHWSTRAP, hwstrap); + mt753x_reg_write(gsw, P6ECR, p6ecr); + + mt753x_reg_write(gsw, PMCR(5), p5mcr); + mt753x_reg_write(gsw, PMCR(6), p6mcr); + + return 0; +} + +static void mt7530_core_pll_setup(struct gsw_mt753x *gsw) +{ + u32 hwstrap, val, ncpo1, ssc_delta; + int i; + + hwstrap = mt753x_reg_read(gsw, HWSTRAP); + + switch ((hwstrap & XTAL_FSEL_M) >> XTAL_FSEL_S) { + case XTAL_40MHZ: + /* Disable MT7530 core clock */ + mt7530_core_reg_write(gsw, TRGMII_GSW_CLK_CG, 0); + + /* disable MT7530 PLL */ + mt7530_core_reg_write(gsw, CORE_GSWPLL_GCR_1, + (2 << GSWPLL_POSTDIV_200M_S) | + (32 << GSWPLL_FBKDIV_200M_S)); + + /* For MT7530 core clock = 500Mhz */ + mt7530_core_reg_write(gsw, CORE_GSWPLL_GCR_2, + (1 << GSWPLL_POSTDIV_500M_S) | + (25 << GSWPLL_FBKDIV_500M_S)); + + /* Enable MT7530 PLL */ + mt7530_core_reg_write(gsw, CORE_GSWPLL_GCR_1, + (2 << GSWPLL_POSTDIV_200M_S) | + (32 << GSWPLL_FBKDIV_200M_S) | + GSWPLL_EN_PRE); + + usleep_range(20, 40); + + /* Enable MT7530 core clock */ + mt7530_core_reg_write(gsw, TRGMII_GSW_CLK_CG, GSWCK_EN); + break; + default: + /* TODO: PLL settings for 20/25MHz */ + break; + } + + if (gsw->port6_cfg.enabled && + gsw->port6_cfg.phy_mode == PHY_INTERFACE_MODE_TRGMII) { + ncpo1 = 0x1400; + ssc_delta = 0x57; + } else { + /* RGMII */ + ncpo1 = 0x0c80; + ssc_delta = 0x87; + } + + /* Setup the MT7530 TRGMII Tx Clock */ + mt7530_core_reg_write(gsw, CORE_PLL_GROUP5, ncpo1); + mt7530_core_reg_write(gsw, CORE_PLL_GROUP6, 0); + mt7530_core_reg_write(gsw, CORE_PLL_GROUP10, ssc_delta); + mt7530_core_reg_write(gsw, CORE_PLL_GROUP11, ssc_delta); + mt7530_core_reg_write(gsw, CORE_PLL_GROUP4, + RG_SYSPLL_DDSFBK_EN | + RG_SYSPLL_BIAS_EN | RG_SYSPLL_BIAS_LPF_EN); + + mt7530_core_reg_write(gsw, CORE_PLL_GROUP2, + RG_SYSPLL_EN_NORMAL | RG_SYSPLL_VODEN | + (1 << RG_SYSPLL_POSDIV_S)); + + mt7530_core_reg_write(gsw, CORE_PLL_GROUP7, + RG_LCDDS_PCW_NCPO_CHG | (3 << RG_LCCDS_C_S) | + RG_LCDDS_PWDB | RG_LCDDS_ISO_EN); + + /* Enable MT7530 TRGMII clock */ + mt7530_core_reg_write(gsw, TRGMII_GSW_CLK_CG, GSWCK_EN | TRGMIICK_EN); + + val = mt753x_reg_read(gsw, TRGMII_TXCTRL); + val &= ~TXC_INV; + mt753x_reg_write(gsw, TRGMII_TXCTRL, val); + + /* lower Tx Driving */ + for (i = 0 ; i < NUM_TRGMII_ODT; i++) + mt753x_reg_write(gsw, TRGMII_TD_ODT(i), + (8 << TX_DM_DRVP_S) | (8 << TX_DM_DRVN_S)); + + mt753x_reg_write(gsw, TRGMII_TCK_CTRL, + (8 << TX_TAP_S) | (0x55 << TX_TRAIN_WD_S)); + + /* delay setting for 10/1000M */ + mt753x_reg_write(gsw, P5RGMIIRXCR, + CSR_RGMII_EDGE_ALIGN | + (2 << CSR_RGMII_RXC_0DEG_CFG_S)); + mt753x_reg_write(gsw, P5RGMIITXCR, 0x14 << CSR_RGMII_TXC_CFG_S); +} + +static int mt7530_sw_detect(struct gsw_mt753x *gsw, struct chip_rev *crev) +{ + u32 rev; + + rev = mt753x_reg_read(gsw, CHIP_REV); + + if (((rev & CHIP_NAME_M) >> CHIP_NAME_S) == MT7530) { + if (crev) { + crev->rev = rev & CHIP_REV_M; + crev->name = "MT7530"; + } + + return 0; + } + + return -ENODEV; +} + +static void mt7530_phy_setting(struct gsw_mt753x *gsw) +{ + int i; + u32 val; + + for (i = 0; i < MT753X_NUM_PHYS; i++) { + /* Disable EEE */ + gsw->mmd_write(gsw, i, PHY_DEV07, PHY_DEV07_REG_03C, 0); + + /* Enable HW auto downshift */ + gsw->mii_write(gsw, i, 0x1f, 0x1); + val = gsw->mii_read(gsw, i, PHY_EXT_REG_14); + val |= PHY_EN_DOWN_SHFIT; + gsw->mii_write(gsw, i, PHY_EXT_REG_14, val); + + /* Increase SlvDPSready time */ + gsw->mii_write(gsw, i, 0x1f, 0x52b5); + gsw->mii_write(gsw, i, PHY_TR_REG_10, 0xafae); + gsw->mii_write(gsw, i, PHY_TR_REG_12, 0x2f); + gsw->mii_write(gsw, i, PHY_TR_REG_10, 0x8fae); + + /* Increase post_update_timer */ + gsw->mii_write(gsw, i, 0x1f, 0x3); + gsw->mii_write(gsw, i, PHY_LPI_REG_11, 0x4b); + gsw->mii_write(gsw, i, 0x1f, 0); + + /* Adjust 100_mse_threshold */ + gsw->mmd_write(gsw, i, PHY_DEV1E, PHY_DEV1E_REG_123, 0xffff); + + /* Disable mcc */ + gsw->mmd_write(gsw, i, PHY_DEV1E, PHY_DEV1E_REG_A6, 0x300); + } +} + +static int mt7530_sw_init(struct gsw_mt753x *gsw) +{ + int i; + u32 val; + + gsw->direct_phy_access = of_property_read_bool(gsw->dev->of_node, + "mt7530,direct-phy-access"); + + /* Force MT7530 to use (in)direct PHY access */ + val = mt753x_reg_read(gsw, HWSTRAP); + val |= CHG_TRAP; + if (gsw->direct_phy_access) + val &= ~C_MDIO_BPS_S; + else + val |= C_MDIO_BPS_S; + mt753x_reg_write(gsw, MHWSTRAP, val); + + /* Read PHY address base from HWSTRAP */ + gsw->phy_base = (((val & SMI_ADDR_M) >> SMI_ADDR_S) << 3) + 8; + gsw->phy_base &= MT753X_SMI_ADDR_MASK; + + if (gsw->direct_phy_access) { + gsw->mii_read = mt7530_mii_read; + gsw->mii_write = mt7530_mii_write; + gsw->mmd_read = mt7530_mmd_read; + gsw->mmd_write = mt7530_mmd_write; + } else { + gsw->mii_read = mt753x_mii_read; + gsw->mii_write = mt753x_mii_write; + gsw->mmd_read = mt753x_mmd_ind_read; + gsw->mmd_write = mt753x_mmd_ind_write; + } + + for (i = 0; i < MT753X_NUM_PHYS; i++) { + val = gsw->mii_read(gsw, i, MII_BMCR); + val |= BMCR_PDOWN; + gsw->mii_write(gsw, i, MII_BMCR, val); + } + + /* Force MAC link down before reset */ + mt753x_reg_write(gsw, PMCR(5), FORCE_MODE); + mt753x_reg_write(gsw, PMCR(6), FORCE_MODE); + + /* Switch soft reset */ + /* BUG: sw reset causes gsw int flooding */ + mt753x_reg_write(gsw, SYS_CTRL, SW_PHY_RST | SW_SYS_RST | SW_REG_RST); + usleep_range(10, 20); + + /* global mac control settings configuration */ + mt753x_reg_write(gsw, GMACCR, + LATE_COL_DROP | (15 << MTCC_LMT_S) | + (2 << MAX_RX_JUMBO_S) | RX_PKT_LEN_MAX_JUMBO); + + mt7530_core_pll_setup(gsw); + mt7530_mac_port_setup(gsw); + + return 0; +} + +static int mt7530_sw_post_init(struct gsw_mt753x *gsw) +{ + int i; + u32 val; + + mt7530_phy_setting(gsw); + + for (i = 0; i < MT753X_NUM_PHYS; i++) { + val = gsw->mii_read(gsw, i, MII_BMCR); + val &= ~BMCR_PDOWN; + gsw->mii_write(gsw, i, MII_BMCR, val); + } + + return 0; +} + +struct mt753x_sw_id mt7530_id = { + .model = MT7530, + .detect = mt7530_sw_detect, + .init = mt7530_sw_init, + .post_init = mt7530_sw_post_init +}; diff --git a/target/linux/mediatek/files-4.19/drivers/net/phy/mtk/mt753x/mt7530.h b/target/linux/mediatek/files-4.19/drivers/net/phy/mtk/mt753x/mt7530.h new file mode 100644 index 0000000000..b4c8a02861 --- /dev/null +++ b/target/linux/mediatek/files-4.19/drivers/net/phy/mtk/mt753x/mt7530.h @@ -0,0 +1,14 @@ +/* + * Copyright (C) 2018 MediaTek Inc. All Rights Reserved. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _MT7530_H_ +#define _MT7530_H_ + +#include "mt753x.h" + +extern struct mt753x_sw_id mt7530_id; + +#endif /* _MT7530_H_ */ diff --git a/target/linux/mediatek/files-4.19/drivers/net/phy/mtk/mt753x/mt7531.c b/target/linux/mediatek/files-4.19/drivers/net/phy/mtk/mt753x/mt7531.c new file mode 100644 index 0000000000..4d44141a61 --- /dev/null +++ b/target/linux/mediatek/files-4.19/drivers/net/phy/mtk/mt753x/mt7531.c @@ -0,0 +1,851 @@ +/* + * Driver for MediaTek MT7531 gigabit switch + * + * Copyright (C) 2018 MediaTek Inc. All Rights Reserved. + * + * Author: Zhanguo Ju <zhanguo.ju@mediatek.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/hrtimer.h> + +#include "mt753x.h" +#include "mt753x_regs.h" + +/* MT7531 registers */ +#define SGMII_REG_BASE 0x5000 +#define SGMII_REG_PORT_BASE 0x1000 +#define SGMII_REG(p, r) (SGMII_REG_BASE + \ + (p) * SGMII_REG_PORT_BASE + (r)) +#define PCS_CONTROL_1(p) SGMII_REG(p, 0x00) +#define SGMII_MODE(p) SGMII_REG(p, 0x20) +#define QPHY_PWR_STATE_CTRL(p) SGMII_REG(p, 0xe8) +#define PHYA_CTRL_SIGNAL3(p) SGMII_REG(p, 0x128) + +/* Fields of PCS_CONTROL_1 */ +#define SGMII_LINK_STATUS BIT(18) +#define SGMII_AN_ENABLE BIT(12) +#define SGMII_AN_RESTART BIT(9) + +/* Fields of SGMII_MODE */ +#define SGMII_REMOTE_FAULT_DIS BIT(8) +#define SGMII_IF_MODE_FORCE_DUPLEX BIT(4) +#define SGMII_IF_MODE_FORCE_SPEED_S 0x2 +#define SGMII_IF_MODE_FORCE_SPEED_M 0x0c +#define SGMII_IF_MODE_ADVERT_AN BIT(1) + +/* Values of SGMII_IF_MODE_FORCE_SPEED */ +#define SGMII_IF_MODE_FORCE_SPEED_10 0 +#define SGMII_IF_MODE_FORCE_SPEED_100 1 +#define SGMII_IF_MODE_FORCE_SPEED_1000 2 + +/* Fields of QPHY_PWR_STATE_CTRL */ +#define PHYA_PWD BIT(4) + +/* Fields of PHYA_CTRL_SIGNAL3 */ +#define RG_TPHY_SPEED_S 2 +#define RG_TPHY_SPEED_M 0x0c + +/* Values of RG_TPHY_SPEED */ +#define RG_TPHY_SPEED_1000 0 +#define RG_TPHY_SPEED_2500 1 + +/* Unique fields of (M)HWSTRAP for MT7531 */ +#define XTAL_FSEL_S 7 +#define XTAL_FSEL_M BIT(7) +#define PHY_EN BIT(6) +#define CHG_STRAP BIT(8) + +/* Efuse Register Define */ +#define GBE_EFUSE 0x7bc8 +#define GBE_SEL_EFUSE_EN BIT(0) + +/* PHY ENABLE Register bitmap define */ +#define PHY_DEV1F 0x1f +#define PHY_DEV1F_REG_44 0x44 +#define PHY_DEV1F_REG_268 0x268 +#define PHY_DEV1F_REG_269 0x269 +#define PHY_DEV1F_REG_403 0x403 + +/* Fields of PHY_DEV1F_REG_403 */ +#define GBE_EFUSE_SETTING BIT(3) +#define PHY_EN_BYPASS_MODE BIT(4) +#define POWER_ON_OFF BIT(5) + +/* PHY EEE Register bitmap of define */ +#define PHY_DEV07 0x07 +#define PHY_DEV07_REG_03C 0x3c + +/* PHY Extend Register 0x14 bitmap of define */ +#define PHY_EXT_REG_14 0x14 + +/* Fields of PHY_EXT_REG_14 */ +#define PHY_EN_DOWN_SHFIT BIT(4) + +/* PHY Extend Register 0x17 bitmap of define */ +#define PHY_EXT_REG_17 0x17 + +/* Fields of PHY_EXT_REG_17 */ +#define PHY_LINKDOWN_POWER_SAVING_EN BIT(4) + +/* PHY Token Ring Register 0x10 bitmap of define */ +#define PHY_TR_REG_10 0x10 + +/* PHY Token Ring Register 0x12 bitmap of define */ +#define PHY_TR_REG_12 0x12 + +/* PHY DEV 0x1e Register bitmap of define */ +#define PHY_DEV1E 0x1e +#define PHY_DEV1E_REG_13 0x13 +#define PHY_DEV1E_REG_14 0x14 +#define PHY_DEV1E_REG_41 0x41 +#define PHY_DEV1E_REG_A6 0xa6 +#define PHY_DEV1E_REG_0C6 0x0c6 +#define PHY_DEV1E_REG_0FE 0x0fe +#define PHY_DEV1E_REG_123 0x123 +#define PHY_DEV1E_REG_189 0x189 + +/* Fields of PHY_DEV1E_REG_0C6 */ +#define PHY_POWER_SAVING_S 8 +#define PHY_POWER_SAVING_M 0x300 +#define PHY_POWER_SAVING_TX 0x0 + +/* Fields of PHY_DEV1E_REG_189 */ +#define DESCRAMBLER_CLEAR_EN 0x1 + +/* Values of XTAL_FSEL_S */ +#define XTAL_40MHZ 0 +#define XTAL_25MHZ 1 + +#define PLLGP_EN 0x7820 +#define EN_COREPLL BIT(2) +#define SW_CLKSW BIT(1) +#define SW_PLLGP BIT(0) + +#define PLLGP_CR0 0x78a8 +#define RG_COREPLL_EN BIT(22) +#define RG_COREPLL_POSDIV_S 23 +#define RG_COREPLL_POSDIV_M 0x3800000 +#define RG_COREPLL_SDM_PCW_S 1 +#define RG_COREPLL_SDM_PCW_M 0x3ffffe +#define RG_COREPLL_SDM_PCW_CHG BIT(0) + +/* TOP Signals Status Register */ +#define TOP_SIG_SR 0x780c +#define PAD_DUAL_SGMII_EN BIT(1) + +/* RGMII and SGMII PLL clock */ +#define ANA_PLLGP_CR2 0x78b0 +#define ANA_PLLGP_CR5 0x78bc + +/* GPIO mode define */ +#define GPIO_MODE_REGS(x) (0x7c0c + ((x / 8) * 4)) +#define GPIO_MODE_S 4 + +/* GPIO GROUP IOLB SMT0 Control */ +#define SMT0_IOLB 0x7f04 +#define SMT_IOLB_5_SMI_MDC_EN BIT(5) + +/* Unique fields of PMCR for MT7531 */ +#define FORCE_MODE_EEE1G BIT(25) +#define FORCE_MODE_EEE100 BIT(26) +#define FORCE_MODE_TX_FC BIT(27) +#define FORCE_MODE_RX_FC BIT(28) +#define FORCE_MODE_DPX BIT(29) +#define FORCE_MODE_SPD BIT(30) +#define FORCE_MODE_LNK BIT(31) +#define FORCE_MODE BIT(15) + +#define CHIP_REV 0x781C +#define CHIP_NAME_S 16 +#define CHIP_NAME_M 0xffff0000 +#define CHIP_REV_S 0 +#define CHIP_REV_M 0x0f +#define CHIP_REV_E1 0x0 + +#define CLKGEN_CTRL 0x7500 +#define CLK_SKEW_OUT_S 8 +#define CLK_SKEW_OUT_M 0x300 +#define CLK_SKEW_IN_S 6 +#define CLK_SKEW_IN_M 0xc0 +#define RXCLK_NO_DELAY BIT(5) +#define TXCLK_NO_REVERSE BIT(4) +#define GP_MODE_S 1 +#define GP_MODE_M 0x06 +#define GP_CLK_EN BIT(0) + +/* Values of GP_MODE */ +#define GP_MODE_RGMII 0 +#define GP_MODE_MII 1 +#define GP_MODE_REV_MII 2 + +/* Values of CLK_SKEW_IN */ +#define CLK_SKEW_IN_NO_CHANGE 0 +#define CLK_SKEW_IN_DELAY_100PPS 1 +#define CLK_SKEW_IN_DELAY_200PPS 2 +#define CLK_SKEW_IN_REVERSE 3 + +/* Values of CLK_SKEW_OUT */ +#define CLK_SKEW_OUT_NO_CHANGE 0 +#define CLK_SKEW_OUT_DELAY_100PPS 1 +#define CLK_SKEW_OUT_DELAY_200PPS 2 +#define CLK_SKEW_OUT_REVERSE 3 + +/* Proprietory Control Register of Internal Phy device 0x1e */ +#define RXADC_CONTROL_3 0xc2 +#define RXADC_LDO_CONTROL_2 0xd3 + +/* Proprietory Control Register of Internal Phy device 0x1f */ +#define TXVLD_DA_271 0x271 +#define TXVLD_DA_272 0x272 +#define TXVLD_DA_273 0x273 + +/* DSP Channel and NOD_ADDR*/ +#define DSP_CH 0x2 +#define DSP_NOD_ADDR 0xD + +/* gpio pinmux pins and functions define */ +static int gpio_int_pins[] = {0}; +static int gpio_int_funcs[] = {1}; +static int gpio_mdc_pins[] = {11, 20}; +static int gpio_mdc_funcs[] = {2, 2}; +static int gpio_mdio_pins[] = {12, 21}; +static int gpio_mdio_funcs[] = {2, 2}; + +static int mt7531_set_port_sgmii_force_mode(struct gsw_mt753x *gsw, u32 port, + struct mt753x_port_cfg *port_cfg) +{ + u32 speed, port_base, val; + ktime_t timeout; + u32 timeout_us; + + if (port < 5 || port >= MT753X_NUM_PORTS) { + dev_info(gsw->dev, "port %d is not a SGMII port\n", port); + return -EINVAL; + } + + port_base = port - 5; + + switch (port_cfg->speed) { + case MAC_SPD_1000: + speed = RG_TPHY_SPEED_1000; + break; + case MAC_SPD_2500: + speed = RG_TPHY_SPEED_2500; + break; + default: + dev_info(gsw->dev, "invalid SGMII speed idx %d for port %d\n", + port_cfg->speed, port); + + speed = RG_TPHY_SPEED_1000; + } + + /* Step 1: Speed select register setting */ + val = mt753x_reg_read(gsw, PHYA_CTRL_SIGNAL3(port_base)); + val &= ~RG_TPHY_SPEED_M; + val |= speed << RG_TPHY_SPEED_S; + mt753x_reg_write(gsw, PHYA_CTRL_SIGNAL3(port_base), val); + + /* Step 2 : Disable AN */ + val = mt753x_reg_read(gsw, PCS_CONTROL_1(port_base)); + val &= ~SGMII_AN_ENABLE; + mt753x_reg_write(gsw, PCS_CONTROL_1(port_base), val); + + /* Step 3: SGMII force mode setting */ + val = mt753x_reg_read(gsw, SGMII_MODE(port_base)); + val &= ~SGMII_IF_MODE_ADVERT_AN; + val &= ~SGMII_IF_MODE_FORCE_SPEED_M; + val |= SGMII_IF_MODE_FORCE_SPEED_1000 << SGMII_IF_MODE_FORCE_SPEED_S; + val |= SGMII_IF_MODE_FORCE_DUPLEX; + /* For sgmii force mode, 0 is full duplex and 1 is half duplex */ + if (port_cfg->duplex) + val &= ~SGMII_IF_MODE_FORCE_DUPLEX; + + mt753x_reg_write(gsw, SGMII_MODE(port_base), val); + + /* Step 4: XXX: Disable Link partner's AN and set force mode */ + + /* Step 5: XXX: Special setting for PHYA ==> reserved for flexible */ + + /* Step 6 : Release PHYA power down state */ + val = mt753x_reg_read(gsw, QPHY_PWR_STATE_CTRL(port_base)); + val &= ~PHYA_PWD; + mt753x_reg_write(gsw, QPHY_PWR_STATE_CTRL(port_base), val); + + /* Step 7 : Polling SGMII_LINK_STATUS */ + timeout_us = 2000000; + timeout = ktime_add_us(ktime_get(), timeout_us); + while (1) { + val = mt753x_reg_read(gsw, PCS_CONTROL_1(port_base)); + val &= SGMII_LINK_STATUS; + + if (val) + break; + + if (ktime_compare(ktime_get(), timeout) > 0) + return -ETIMEDOUT; + } + + return 0; +} + +static int mt7531_set_port_sgmii_an_mode(struct gsw_mt753x *gsw, u32 port, + struct mt753x_port_cfg *port_cfg) +{ + u32 speed, port_base, val; + ktime_t timeout; + u32 timeout_us; + + if (port < 5 || port >= MT753X_NUM_PORTS) { + dev_info(gsw->dev, "port %d is not a SGMII port\n", port); + return -EINVAL; + } + + port_base = port - 5; + + switch (port_cfg->speed) { + case MAC_SPD_1000: + speed = RG_TPHY_SPEED_1000; + break; + case MAC_SPD_2500: + speed = RG_TPHY_SPEED_2500; + break; + default: + dev_info(gsw->dev, "invalid SGMII speed idx %d for port %d\n", + port_cfg->speed, port); + + speed = RG_TPHY_SPEED_1000; + } + + /* Step 1: Speed select register setting */ + val = mt753x_reg_read(gsw, PHYA_CTRL_SIGNAL3(port_base)); + val &= ~RG_TPHY_SPEED_M; + val |= speed << RG_TPHY_SPEED_S; + mt753x_reg_write(gsw, PHYA_CTRL_SIGNAL3(port_base), val); + + /* Step 2: Remote fault disable */ + val = mt753x_reg_read(gsw, SGMII_MODE(port)); + val |= SGMII_REMOTE_FAULT_DIS; + mt753x_reg_write(gsw, SGMII_MODE(port), val); + + /* Step 3: Setting Link partner's AN enable = 1 */ + + /* Step 4: Setting Link partner's device ability for speed/duplex */ + + /* Step 5: AN re-start */ + val = mt753x_reg_read(gsw, PCS_CONTROL_1(port)); + val |= SGMII_AN_RESTART; + mt753x_reg_write(gsw, PCS_CONTROL_1(port), val); + + /* Step 6: Special setting for PHYA ==> reserved for flexible */ + + /* Step 7 : Polling SGMII_LINK_STATUS */ + timeout_us = 2000000; + timeout = ktime_add_us(ktime_get(), timeout_us); + while (1) { + val = mt753x_reg_read(gsw, PCS_CONTROL_1(port_base)); + val &= SGMII_LINK_STATUS; + + if (val) + break; + + if (ktime_compare(ktime_get(), timeout) > 0) + return -ETIMEDOUT; + } + + return 0; +} + +static int mt7531_set_port_rgmii(struct gsw_mt753x *gsw, u32 port) +{ + u32 val; + + if (port != 5) { + dev_info(gsw->dev, "RGMII mode is not available for port %d\n", + port); + return -EINVAL; + } + + val = mt753x_reg_read(gsw, CLKGEN_CTRL); + val |= GP_CLK_EN; + val &= ~GP_MODE_M; + val |= GP_MODE_RGMII << GP_MODE_S; + val |= TXCLK_NO_REVERSE; + val |= RXCLK_NO_DELAY; + val &= ~CLK_SKEW_IN_M; + val |= CLK_SKEW_IN_NO_CHANGE << CLK_SKEW_IN_S; + val &= ~CLK_SKEW_OUT_M; + val |= CLK_SKEW_OUT_NO_CHANGE << CLK_SKEW_OUT_S; + mt753x_reg_write(gsw, CLKGEN_CTRL, val); + + return 0; +} + +static int mt7531_mac_port_setup(struct gsw_mt753x *gsw, u32 port, + struct mt753x_port_cfg *port_cfg) +{ + u32 pmcr; + u32 speed; + + if (port < 5 || port >= MT753X_NUM_PORTS) { + dev_info(gsw->dev, "port %d is not a MAC port\n", port); + return -EINVAL; + } + + if (port_cfg->enabled) { + pmcr = (IPG_96BIT_WITH_SHORT_IPG << IPG_CFG_S) | + MAC_MODE | MAC_TX_EN | MAC_RX_EN | + BKOFF_EN | BACKPR_EN; + + if (port_cfg->force_link) { + /* PMCR's speed field 0x11 is reserved, + * sw should set 0x10 + */ + speed = port_cfg->speed; + if (port_cfg->speed == MAC_SPD_2500) + speed = MAC_SPD_1000; + + pmcr |= FORCE_MODE_LNK | FORCE_LINK | + FORCE_MODE_SPD | FORCE_MODE_DPX | + FORCE_MODE_RX_FC | FORCE_MODE_TX_FC | + FORCE_RX_FC | FORCE_TX_FC | + (speed << FORCE_SPD_S); + + if (port_cfg->duplex) + pmcr |= FORCE_DPX; + } + } else { + pmcr = FORCE_MODE_LNK; + } + + switch (port_cfg->phy_mode) { + case PHY_INTERFACE_MODE_RGMII: + mt7531_set_port_rgmii(gsw, port); + break; + case PHY_INTERFACE_MODE_SGMII: + if (port_cfg->force_link) + mt7531_set_port_sgmii_force_mode(gsw, port, port_cfg); + else + mt7531_set_port_sgmii_an_mode(gsw, port, port_cfg); + break; + default: + if (port_cfg->enabled) + dev_info(gsw->dev, "%s is not supported by port %d\n", + phy_modes(port_cfg->phy_mode), port); + + pmcr = FORCE_MODE_LNK; + } + + mt753x_reg_write(gsw, PMCR(port), pmcr); + + return 0; +} + +static void mt7531_core_pll_setup(struct gsw_mt753x *gsw) +{ + u32 hwstrap; + u32 val; + + val = mt753x_reg_read(gsw, TOP_SIG_SR); + if (val & PAD_DUAL_SGMII_EN) + return; + + hwstrap = mt753x_reg_read(gsw, HWSTRAP); + + switch ((hwstrap & XTAL_FSEL_M) >> XTAL_FSEL_S) { + case XTAL_25MHZ: + /* Step 1 : Disable MT7531 COREPLL */ + val = mt753x_reg_read(gsw, PLLGP_EN); + val &= ~EN_COREPLL; + mt753x_reg_write(gsw, PLLGP_EN, val); + + /* Step 2: switch to XTAL output */ + val = mt753x_reg_read(gsw, PLLGP_EN); + val |= SW_CLKSW; + mt753x_reg_write(gsw, PLLGP_EN, val); + + val = mt753x_reg_read(gsw, PLLGP_CR0); + val &= ~RG_COREPLL_EN; + mt753x_reg_write(gsw, PLLGP_CR0, val); + + /* Step 3: disable PLLGP and enable program PLLGP */ + val = mt753x_reg_read(gsw, PLLGP_EN); + val |= SW_PLLGP; + mt753x_reg_write(gsw, PLLGP_EN, val); + + /* Step 4: program COREPLL output frequency to 500MHz */ + val = mt753x_reg_read(gsw, PLLGP_CR0); + val &= ~RG_COREPLL_POSDIV_M; + val |= 2 << RG_COREPLL_POSDIV_S; + mt753x_reg_write(gsw, PLLGP_CR0, val); + usleep_range(25, 35); + + val = mt753x_reg_read(gsw, PLLGP_CR0); + val &= ~RG_COREPLL_SDM_PCW_M; + val |= 0x140000 << RG_COREPLL_SDM_PCW_S; + mt753x_reg_write(gsw, PLLGP_CR0, val); + + /* Set feedback divide ratio update signal to high */ + val = mt753x_reg_read(gsw, PLLGP_CR0); + val |= RG_COREPLL_SDM_PCW_CHG; + mt753x_reg_write(gsw, PLLGP_CR0, val); + /* Wait for at least 16 XTAL clocks */ + usleep_range(10, 20); + + /* Step 5: set feedback divide ratio update signal to low */ + val = mt753x_reg_read(gsw, PLLGP_CR0); + val &= ~RG_COREPLL_SDM_PCW_CHG; + mt753x_reg_write(gsw, PLLGP_CR0, val); + + /* Enable 325M clock for SGMII */ + mt753x_reg_write(gsw, ANA_PLLGP_CR5, 0xad0000); + + /* Enable 250SSC clock for RGMII */ + mt753x_reg_write(gsw, ANA_PLLGP_CR2, 0x4f40000); + + /* Step 6: Enable MT7531 PLL */ + val = mt753x_reg_read(gsw, PLLGP_CR0); + val |= RG_COREPLL_EN; + mt753x_reg_write(gsw, PLLGP_CR0, val); + + val = mt753x_reg_read(gsw, PLLGP_EN); + val |= EN_COREPLL; + mt753x_reg_write(gsw, PLLGP_EN, val); + usleep_range(25, 35); + + break; + case XTAL_40MHZ: + /* Step 1 : Disable MT7531 COREPLL */ + val = mt753x_reg_read(gsw, PLLGP_EN); + val &= ~EN_COREPLL; + mt753x_reg_write(gsw, PLLGP_EN, val); + + /* Step 2: switch to XTAL output */ + val = mt753x_reg_read(gsw, PLLGP_EN); + val |= SW_CLKSW; + mt753x_reg_write(gsw, PLLGP_EN, val); + + val = mt753x_reg_read(gsw, PLLGP_CR0); + val &= ~RG_COREPLL_EN; + mt753x_reg_write(gsw, PLLGP_CR0, val); + + /* Step 3: disable PLLGP and enable program PLLGP */ + val = mt753x_reg_read(gsw, PLLGP_EN); + val |= SW_PLLGP; + mt753x_reg_write(gsw, PLLGP_EN, val); + + /* Step 4: program COREPLL output frequency to 500MHz */ + val = mt753x_reg_read(gsw, PLLGP_CR0); + val &= ~RG_COREPLL_POSDIV_M; + val |= 2 << RG_COREPLL_POSDIV_S; + mt753x_reg_write(gsw, PLLGP_CR0, val); + usleep_range(25, 35); + + val = mt753x_reg_read(gsw, PLLGP_CR0); + val &= ~RG_COREPLL_SDM_PCW_M; + val |= 0x190000 << RG_COREPLL_SDM_PCW_S; + mt753x_reg_write(gsw, PLLGP_CR0, val); + + /* Set feedback divide ratio update signal to high */ + val = mt753x_reg_read(gsw, PLLGP_CR0); + val |= RG_COREPLL_SDM_PCW_CHG; + mt753x_reg_write(gsw, PLLGP_CR0, val); + /* Wait for at least 16 XTAL clocks */ + usleep_range(10, 20); + + /* Step 5: set feedback divide ratio update signal to low */ + val = mt753x_reg_read(gsw, PLLGP_CR0); + val &= ~RG_COREPLL_SDM_PCW_CHG; + mt753x_reg_write(gsw, PLLGP_CR0, val); + + /* Enable 325M clock for SGMII */ + mt753x_reg_write(gsw, ANA_PLLGP_CR5, 0xad0000); + + /* Enable 250SSC clock for RGMII */ + mt753x_reg_write(gsw, ANA_PLLGP_CR2, 0x4f40000); + + /* Step 6: Enable MT7531 PLL */ + val = mt753x_reg_read(gsw, PLLGP_CR0); + val |= RG_COREPLL_EN; + mt753x_reg_write(gsw, PLLGP_CR0, val); + + val = mt753x_reg_read(gsw, PLLGP_EN); + val |= EN_COREPLL; + mt753x_reg_write(gsw, PLLGP_EN, val); + usleep_range(25, 35); + break; + } +} + +static int mt7531_internal_phy_calibration(struct gsw_mt753x *gsw) +{ + return 0; +} + +static int mt7531_sw_detect(struct gsw_mt753x *gsw, struct chip_rev *crev) +{ + u32 rev, topsig; + + rev = mt753x_reg_read(gsw, CHIP_REV); + + if (((rev & CHIP_NAME_M) >> CHIP_NAME_S) == MT7531) { + if (crev) { + topsig = mt753x_reg_read(gsw, TOP_SIG_SR); + + crev->rev = rev & CHIP_REV_M; + crev->name = topsig & PAD_DUAL_SGMII_EN ? + "MT7531AE" : "MT7531BE"; + } + + return 0; + } + + return -ENODEV; +} + +static void pinmux_set_mux_7531(struct gsw_mt753x *gsw, u32 pin, u32 mode) +{ + u32 val; + + val = mt753x_reg_read(gsw, GPIO_MODE_REGS(pin)); + val &= ~(0xf << (pin & 7) * GPIO_MODE_S); + val |= mode << (pin & 7) * GPIO_MODE_S; + mt753x_reg_write(gsw, GPIO_MODE_REGS(pin), val); +} + +static int mt7531_set_gpio_pinmux(struct gsw_mt753x *gsw) +{ + u32 group = 0; + struct device_node *np = gsw->dev->of_node; + + /* Set GPIO 0 interrupt mode */ + pinmux_set_mux_7531(gsw, gpio_int_pins[0], gpio_int_funcs[0]); + + of_property_read_u32(np, "mediatek,mdio_master_pinmux", &group); + + /* group = 0: do nothing, 1: 1st group (AE), 2: 2nd group (BE) */ + if (group > 0 && group <= 2) { + group--; + pinmux_set_mux_7531(gsw, gpio_mdc_pins[group], + gpio_mdc_funcs[group]); + pinmux_set_mux_7531(gsw, gpio_mdio_pins[group], + gpio_mdio_funcs[group]); + } + + return 0; +} + +static void mt7531_phy_setting(struct gsw_mt753x *gsw) +{ + int i; + u32 val; + + /* Adjust DAC TX Delay */ + gsw->mmd_write(gsw, 0, PHY_DEV1F, PHY_DEV1F_REG_44, 0xc0); + + for (i = 0; i < MT753X_NUM_PHYS; i++) { + /* Disable EEE */ + gsw->mmd_write(gsw, i, PHY_DEV07, PHY_DEV07_REG_03C, 0); + + /* Enable HW auto downshift */ + gsw->mii_write(gsw, i, 0x1f, 0x1); + val = gsw->mii_read(gsw, i, PHY_EXT_REG_14); + val |= PHY_EN_DOWN_SHFIT; + gsw->mii_write(gsw, i, PHY_EXT_REG_14, val); + + /* Increase SlvDPSready time */ + gsw->mii_write(gsw, i, 0x1f, 0x52b5); + gsw->mii_write(gsw, i, PHY_TR_REG_10, 0xafae); + gsw->mii_write(gsw, i, PHY_TR_REG_12, 0x2f); + gsw->mii_write(gsw, i, PHY_TR_REG_10, 0x8fae); + gsw->mii_write(gsw, i, 0x1f, 0); + + /* Adjust 100_mse_threshold */ + gsw->mmd_write(gsw, i, PHY_DEV1E, PHY_DEV1E_REG_123, 0xffff); + + /* Disable mcc */ + gsw->mmd_write(gsw, i, PHY_DEV1E, PHY_DEV1E_REG_A6, 0x300); + + /* PHY link down power saving enable */ + val = gsw->mii_read(gsw, i, PHY_EXT_REG_17); + val |= PHY_LINKDOWN_POWER_SAVING_EN; + gsw->mii_write(gsw, i, PHY_EXT_REG_17, val); + + val = gsw->mmd_read(gsw, i, PHY_DEV1E, PHY_DEV1E_REG_0C6); + val &= ~PHY_POWER_SAVING_M; + val |= PHY_POWER_SAVING_TX << PHY_POWER_SAVING_S; + gsw->mmd_write(gsw, i, PHY_DEV1E, PHY_DEV1E_REG_0C6, val); + + /* Set TX Pair delay selection */ + gsw->mmd_write(gsw, i, PHY_DEV1E, PHY_DEV1E_REG_13, 0x404); + gsw->mmd_write(gsw, i, PHY_DEV1E, PHY_DEV1E_REG_14, 0x404); + } +} + +static void mt7531_adjust_line_driving(struct gsw_mt753x *gsw, u32 port) +{ + /* For ADC timing margin window for LDO calibration */ + gsw->mmd_write(gsw, port, PHY_DEV1E, RXADC_LDO_CONTROL_2, 0x2222); + + /* Adjust AD sample timing */ + gsw->mmd_write(gsw, port, PHY_DEV1E, RXADC_CONTROL_3, 0x4444); + + /* Adjust Line driver current for different mode */ + gsw->mmd_write(gsw, port, PHY_DEV1F, TXVLD_DA_271, 0x2c63); + + /* Adjust Line driver current for different mode */ + gsw->mmd_write(gsw, port, PHY_DEV1F, TXVLD_DA_272, 0xc6b); + + /* Adjust Line driver amplitude for 10BT */ + gsw->mmd_write(gsw, port, PHY_DEV1F, TXVLD_DA_273, 0x3000); + + /* Adjust RX Echo path filter */ + gsw->mmd_write(gsw, port, PHY_DEV1E, PHY_DEV1E_REG_0FE, 0x2); + + /* Adjust RX HVGA bias current */ + gsw->mmd_write(gsw, port, PHY_DEV1E, PHY_DEV1E_REG_41, 0x3333); + + /* Adjust TX class AB driver 1 */ + gsw->mmd_write(gsw, port, PHY_DEV1F, PHY_DEV1F_REG_268, 0x3aa); + + /* Adjust TX class AB driver 2 */ + gsw->mmd_write(gsw, port, PHY_DEV1F, PHY_DEV1F_REG_269, 0xaaaa); +} + +static void mt7531_eee_setting(struct gsw_mt753x *gsw, u32 port) +{ + u32 tr_reg_control; + u32 val; + + /* Disable generate signal to clear the scramble_lock when lpi mode */ + val = gsw->mmd_read(gsw, port, PHY_DEV1E, PHY_DEV1E_REG_189); + val &= ~DESCRAMBLER_CLEAR_EN; + gsw->mmd_write(gsw, port, PHY_DEV1E, PHY_DEV1E_REG_189, val); + + /* roll back CR*/ + gsw->mii_write(gsw, port, 0x1f, 0x52b5); + gsw->mmd_write(gsw, port, 0x1e, 0x2d1, 0); + tr_reg_control = (1 << 15) | (0 << 13) | (DSP_CH << 11) | + (DSP_NOD_ADDR << 7) | (0x8 << 1); + gsw->mii_write(gsw, port, 17, 0x1b); + gsw->mii_write(gsw, port, 18, 0); + gsw->mii_write(gsw, port, 16, tr_reg_control); + tr_reg_control = (1 << 15) | (0 << 13) | (DSP_CH << 11) | + (DSP_NOD_ADDR << 7) | (0xf << 1); + gsw->mii_write(gsw, port, 17, 0); + gsw->mii_write(gsw, port, 18, 0); + gsw->mii_write(gsw, port, 16, tr_reg_control); + + tr_reg_control = (1 << 15) | (0 << 13) | (DSP_CH << 11) | + (DSP_NOD_ADDR << 7) | (0x10 << 1); + gsw->mii_write(gsw, port, 17, 0x500); + gsw->mii_write(gsw, port, 18, 0); + gsw->mii_write(gsw, port, 16, tr_reg_control); + gsw->mii_write(gsw, port, 0x1f, 0); +} + +static int mt7531_sw_init(struct gsw_mt753x *gsw) +{ + int i; + u32 val; + + gsw->phy_base = (gsw->smi_addr + 1) & MT753X_SMI_ADDR_MASK; + + gsw->mii_read = mt753x_mii_read; + gsw->mii_write = mt753x_mii_write; + gsw->mmd_read = mt753x_mmd_read; + gsw->mmd_write = mt753x_mmd_write; + + for (i = 0; i < MT753X_NUM_PHYS; i++) { + val = gsw->mii_read(gsw, i, MII_BMCR); + val |= BMCR_ISOLATE; + gsw->mii_write(gsw, i, MII_BMCR, val); + } + + /* Force MAC link down before reset */ + mt753x_reg_write(gsw, PMCR(5), FORCE_MODE_LNK); + mt753x_reg_write(gsw, PMCR(6), FORCE_MODE_LNK); + + /* Switch soft reset */ + mt753x_reg_write(gsw, SYS_CTRL, SW_SYS_RST | SW_REG_RST); + usleep_range(10, 20); + + /* Enable MDC input Schmitt Trigger */ + val = mt753x_reg_read(gsw, SMT0_IOLB); + mt753x_reg_write(gsw, SMT0_IOLB, val | SMT_IOLB_5_SMI_MDC_EN); + + /* Set 7531 gpio pinmux */ + mt7531_set_gpio_pinmux(gsw); + + /* Global mac control settings */ + mt753x_reg_write(gsw, GMACCR, + (15 << MTCC_LMT_S) | (11 << MAX_RX_JUMBO_S) | + RX_PKT_LEN_MAX_JUMBO); + + mt7531_core_pll_setup(gsw); + mt7531_mac_port_setup(gsw, 5, &gsw->port5_cfg); + mt7531_mac_port_setup(gsw, 6, &gsw->port6_cfg); + + return 0; +} + +static int mt7531_sw_post_init(struct gsw_mt753x *gsw) +{ + int i; + u32 val; + + /* Internal PHYs are disabled by default. SW should enable them. + * Note that this may already be enabled in bootloader stage. + */ + val = gsw->mmd_read(gsw, 0, PHY_DEV1F, PHY_DEV1F_REG_403); + val |= PHY_EN_BYPASS_MODE; + val &= ~POWER_ON_OFF; + gsw->mmd_write(gsw, 0, PHY_DEV1F, PHY_DEV1F_REG_403, val); + + mt7531_phy_setting(gsw); + + for (i = 0; i < MT753X_NUM_PHYS; i++) { + val = gsw->mii_read(gsw, i, MII_BMCR); + val &= ~BMCR_ISOLATE; + gsw->mii_write(gsw, i, MII_BMCR, val); + } + + for (i = 0; i < MT753X_NUM_PHYS; i++) + mt7531_adjust_line_driving(gsw, i); + + for (i = 0; i < MT753X_NUM_PHYS; i++) + mt7531_eee_setting(gsw, i); + + val = mt753x_reg_read(gsw, CHIP_REV); + val &= CHIP_REV_M; + if (val == CHIP_REV_E1) { + mt7531_internal_phy_calibration(gsw); + } else { + val = mt753x_reg_read(gsw, GBE_EFUSE); + if (val & GBE_SEL_EFUSE_EN) { + val = gsw->mmd_read(gsw, 0, PHY_DEV1F, + PHY_DEV1F_REG_403); + val &= ~GBE_EFUSE_SETTING; + gsw->mmd_write(gsw, 0, PHY_DEV1F, PHY_DEV1F_REG_403, + val); + } else { + mt7531_internal_phy_calibration(gsw); + } + } + + return 0; +} + +struct mt753x_sw_id mt7531_id = { + .model = MT7531, + .detect = mt7531_sw_detect, + .init = mt7531_sw_init, + .post_init = mt7531_sw_post_init +}; + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Zhanguo Ju <zhanguo.ju@mediatek.com>"); +MODULE_DESCRIPTION("Driver for MediaTek MT753x Gigabit Switch"); diff --git a/target/linux/mediatek/files-4.19/drivers/net/phy/mtk/mt753x/mt7531.h b/target/linux/mediatek/files-4.19/drivers/net/phy/mtk/mt753x/mt7531.h new file mode 100644 index 0000000000..736cb0c349 --- /dev/null +++ b/target/linux/mediatek/files-4.19/drivers/net/phy/mtk/mt753x/mt7531.h @@ -0,0 +1,14 @@ +/* + * Copyright (C) 2018 MediaTek Inc. All Rights Reserved. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _MT7531_H_ +#define _MT7531_H_ + +#include "mt753x.h" + +extern struct mt753x_sw_id mt7531_id; + +#endif /* _MT7531_H_ */ diff --git a/target/linux/mediatek/files-4.19/drivers/net/phy/mtk/mt753x/mt753x.h b/target/linux/mediatek/files-4.19/drivers/net/phy/mtk/mt753x/mt753x.h new file mode 100644 index 0000000000..b9bca5416f --- /dev/null +++ b/target/linux/mediatek/files-4.19/drivers/net/phy/mtk/mt753x/mt753x.h @@ -0,0 +1,232 @@ +/* + * Driver for MediaTek MT753x gigabit switch + * + * Copyright (C) 2018 MediaTek Inc. All Rights Reserved. + * + * Author: Weijie Gao <weijie.gao@mediatek.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _MT753X_H_ +#define _MT753X_H_ + +#include <linux/list.h> +#include <linux/mutex.h> +#include <linux/netdevice.h> +#include <linux/of_mdio.h> +#include <linux/workqueue.h> +#include <linux/gpio/consumer.h> + +#ifdef CONFIG_SWCONFIG +#include <linux/switch.h> +#endif + +#define MT753X_DFL_CPU_PORT 6 +#define MT753X_NUM_PORTS 7 +#define MT753X_NUM_PHYS 5 +#define MT753X_NUM_VLANS 4095 + +#define MT753X_MAX_VID 4095 +#define MT753X_MIN_VID 0 + +#define MT753X_DFL_SMI_ADDR 0x1f +#define MT753X_SMI_ADDR_MASK 0x1f + +struct gsw_mt753x; + +enum mt753x_model { + MT7530 = 0x7530, + MT7531 = 0x7531 +}; + +struct mt753x_port_entry { + u16 pvid; +}; + +struct mt753x_vlan_entry { + u16 vid; + u8 member; + u8 etags; +}; + +struct mt753x_port_cfg { + struct device_node *np; + int phy_mode; + u32 enabled: 1; + u32 force_link: 1; + u32 speed: 2; + u32 duplex: 1; +}; + +struct mt753x_phy { + struct gsw_mt753x *gsw; + struct net_device netdev; + struct phy_device *phydev; +}; + +struct gsw_mt753x { + u32 id; + + struct device *dev; + struct mii_bus *host_bus; + struct mii_bus *gphy_bus; + struct mutex mii_lock; /* MII access lock */ + u32 smi_addr; + u32 phy_base; + int direct_phy_access; + + enum mt753x_model model; + const char *name; + + struct mt753x_port_cfg port5_cfg; + struct mt753x_port_cfg port6_cfg; + + bool phy_status_poll; + struct mt753x_phy phys[MT753X_NUM_PHYS]; + + int phy_link_sts; + + int irq; + int reset_pin; + struct work_struct irq_worker; + +#ifdef CONFIG_SWCONFIG + struct switch_dev swdev; + + struct mt753x_vlan_entry vlan_entries[MT753X_NUM_VLANS]; + struct mt753x_port_entry port_entries[MT753X_NUM_PORTS]; + + int global_vlan_enable; + u32 cpu_port; +#endif + + int (*mii_read)(struct gsw_mt753x *gsw, int phy, int reg); + void (*mii_write)(struct gsw_mt753x *gsw, int phy, int reg, u16 val); + + int (*mmd_read)(struct gsw_mt753x *gsw, int addr, int devad, u16 reg); + void (*mmd_write)(struct gsw_mt753x *gsw, int addr, int devad, u16 reg, + u16 val); + + struct list_head list; +}; + +struct chip_rev { + const char *name; + u32 rev; +}; + +struct mt753x_sw_id { + enum mt753x_model model; + int (*detect)(struct gsw_mt753x *gsw, struct chip_rev *crev); + int (*init)(struct gsw_mt753x *gsw); + int (*post_init)(struct gsw_mt753x *gsw); +}; + +extern struct list_head mt753x_devs; + +struct gsw_mt753x *mt753x_get_gsw(u32 id); +struct gsw_mt753x *mt753x_get_first_gsw(void); +void mt753x_put_gsw(void); +void mt753x_lock_gsw(void); + +u32 mt753x_reg_read(struct gsw_mt753x *gsw, u32 reg); +void mt753x_reg_write(struct gsw_mt753x *gsw, u32 reg, u32 val); + +int mt753x_mii_read(struct gsw_mt753x *gsw, int phy, int reg); +void mt753x_mii_write(struct gsw_mt753x *gsw, int phy, int reg, u16 val); + +int mt753x_mmd_read(struct gsw_mt753x *gsw, int addr, int devad, u16 reg); +void mt753x_mmd_write(struct gsw_mt753x *gsw, int addr, int devad, u16 reg, + u16 val); + +int mt753x_mmd_ind_read(struct gsw_mt753x *gsw, int addr, int devad, u16 reg); +void mt753x_mmd_ind_write(struct gsw_mt753x *gsw, int addr, int devad, u16 reg, + u16 val); + +void mt753x_irq_worker(struct work_struct *work); +void mt753x_irq_enable(struct gsw_mt753x *gsw); + +/* MDIO Indirect Access Registers */ +#define MII_MMD_ACC_CTL_REG 0x0d +#define MMD_CMD_S 14 +#define MMD_CMD_M 0xc000 +#define MMD_DEVAD_S 0 +#define MMD_DEVAD_M 0x1f + +/* MMD_CMD: MMD commands */ +#define MMD_ADDR 0 +#define MMD_DATA 1 + +#define MII_MMD_ADDR_DATA_REG 0x0e + +/* Procedure of MT753x Internal Register Access + * + * 1. Internal Register Address + * + * The MT753x has a 16-bit register address and each register is 32-bit. + * This means the lowest two bits are not used as the register address is + * 4-byte aligned. + * + * Rest of the valid bits are divided into two parts: + * Bit 15..6 is the Page address + * Bit 5..2 is the low address + * + * ------------------------------------------------------------------- + * | 15 14 13 12 11 10 9 8 7 6 | 5 4 3 2 | 1 0 | + * |----------------------------------------|---------------|--------| + * | Page Address | Address | Unused | + * ------------------------------------------------------------------- + * + * 2. MDIO access timing + * + * The MT753x uses the following MDIO timing for a single register read + * + * Phase 1: Write Page Address + * ------------------------------------------------------------------- + * | ST | OP | PHY_ADDR | TYPE | RSVD | TA | RSVD | PAGE_ADDR | + * ------------------------------------------------------------------- + * | 01 | 01 | 11111 | 1 | 1111 | xx | 00000 | REG_ADDR[15..6] | + * ------------------------------------------------------------------- + * + * Phase 2: Write low Address & Read low word + * ------------------------------------------------------------------- + * | ST | OP | PHY_ADDR | TYPE | LOW_ADDR | TA | DATA | + * ------------------------------------------------------------------- + * | 01 | 10 | 11111 | 0 | REG_ADDR[5..2] | xx | DATA[15..0] | + * ------------------------------------------------------------------- + * + * Phase 3: Read high word + * ------------------------------------------------------------------- + * | ST | OP | PHY_ADDR | TYPE | RSVD | TA | DATA | + * ------------------------------------------------------------------- + * | 01 | 10 | 11111 | 1 | 0000 | xx | DATA[31..16] | + * ------------------------------------------------------------------- + * + * The MT753x uses the following MDIO timing for a single register write + * + * Phase 1: Write Page Address (The same as read) + * + * Phase 2: Write low Address and low word + * ------------------------------------------------------------------- + * | ST | OP | PHY_ADDR | TYPE | LOW_ADDR | TA | DATA | + * ------------------------------------------------------------------- + * | 01 | 01 | 11111 | 0 | REG_ADDR[5..2] | xx | DATA[15..0] | + * ------------------------------------------------------------------- + * + * Phase 3: write high word + * ------------------------------------------------------------------- + * | ST | OP | PHY_ADDR | TYPE | RSVD | TA | DATA | + * ------------------------------------------------------------------- + * | 01 | 01 | 11111 | 1 | 0000 | xx | DATA[31..16] | + * ------------------------------------------------------------------- + * + */ + +/* Internal Register Address fields */ +#define MT753X_REG_PAGE_ADDR_S 6 +#define MT753X_REG_PAGE_ADDR_M 0xffc0 +#define MT753X_REG_ADDR_S 2 +#define MT753X_REG_ADDR_M 0x3c + +#endif /* _MT753X_H_ */ diff --git a/target/linux/mediatek/files-4.19/drivers/net/phy/mtk/mt753x/mt753x_common.c b/target/linux/mediatek/files-4.19/drivers/net/phy/mtk/mt753x/mt753x_common.c new file mode 100644 index 0000000000..c836a63607 --- /dev/null +++ b/target/linux/mediatek/files-4.19/drivers/net/phy/mtk/mt753x/mt753x_common.c @@ -0,0 +1,94 @@ +/* + * Common part for MediaTek MT753x gigabit switch + * + * Copyright (C) 2018 MediaTek Inc. All Rights Reserved. + * + * Author: Weijie Gao <weijie.gao@mediatek.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <linux/kernel.h> +#include <linux/delay.h> + +#include "mt753x.h" +#include "mt753x_regs.h" + +void mt753x_irq_enable(struct gsw_mt753x *gsw) +{ + u32 val; + int i; + + /* Record initial PHY link status */ + for (i = 0; i < MT753X_NUM_PHYS; i++) { + val = gsw->mii_read(gsw, i, MII_BMSR); + if (val & BMSR_LSTATUS) + gsw->phy_link_sts |= BIT(i); + } + + val = BIT(MT753X_NUM_PHYS) - 1; + + mt753x_reg_write(gsw, SYS_INT_EN, val); +} + +static void display_port_link_status(struct gsw_mt753x *gsw, u32 port) +{ + u32 pmsr, speed_bits; + const char *speed; + + pmsr = mt753x_reg_read(gsw, PMSR(port)); + + speed_bits = (pmsr & MAC_SPD_STS_M) >> MAC_SPD_STS_S; + + switch (speed_bits) { + case MAC_SPD_10: + speed = "10Mbps"; + break; + case MAC_SPD_100: + speed = "100Mbps"; + break; + case MAC_SPD_1000: + speed = "1Gbps"; + break; + case MAC_SPD_2500: + speed = "2.5Gbps"; + break; + } + + if (pmsr & MAC_LNK_STS) { + dev_info(gsw->dev, "Port %d Link is Up - %s/%s\n", + port, speed, (pmsr & MAC_DPX_STS) ? "Full" : "Half"); + } else { + dev_info(gsw->dev, "Port %d Link is Down\n", port); + } +} + +void mt753x_irq_worker(struct work_struct *work) +{ + struct gsw_mt753x *gsw; + u32 sts, physts, laststs; + int i; + + gsw = container_of(work, struct gsw_mt753x, irq_worker); + + sts = mt753x_reg_read(gsw, SYS_INT_STS); + + /* Check for changed PHY link status */ + for (i = 0; i < MT753X_NUM_PHYS; i++) { + if (!(sts & PHY_LC_INT(i))) + continue; + + laststs = gsw->phy_link_sts & BIT(i); + physts = !!(gsw->mii_read(gsw, i, MII_BMSR) & BMSR_LSTATUS); + physts <<= i; + + if (physts ^ laststs) { + gsw->phy_link_sts ^= BIT(i); + display_port_link_status(gsw, i); + } + } + + mt753x_reg_write(gsw, SYS_INT_STS, sts); + + enable_irq(gsw->irq); +} diff --git a/target/linux/mediatek/files-4.19/drivers/net/phy/mtk/mt753x/mt753x_mdio.c b/target/linux/mediatek/files-4.19/drivers/net/phy/mtk/mt753x/mt753x_mdio.c new file mode 100644 index 0000000000..695713eed4 --- /dev/null +++ b/target/linux/mediatek/files-4.19/drivers/net/phy/mtk/mt753x/mt753x_mdio.c @@ -0,0 +1,740 @@ +/* + * Driver for MediaTek MT753x gigabit switch + * + * Copyright (C) 2018 MediaTek Inc. All Rights Reserved. + * + * Author: Weijie Gao <weijie.gao@mediatek.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/delay.h> +#include <linux/reset.h> +#include <linux/hrtimer.h> +#include <linux/mii.h> +#include <linux/of_mdio.h> +#include <linux/of_platform.h> +#include <linux/of_gpio.h> +#include <linux/of_net.h> +#include <linux/of_irq.h> +#include <linux/phy.h> + +#include "mt753x.h" +#include "mt753x_swconfig.h" +#include "mt753x_regs.h" +#include "mt753x_nl.h" +#include "mt7530.h" +#include "mt7531.h" + +static u32 mt753x_id; +struct list_head mt753x_devs; +static DEFINE_MUTEX(mt753x_devs_lock); + +static struct mt753x_sw_id *mt753x_sw_ids[] = { + &mt7530_id, + &mt7531_id, +}; + +u32 mt753x_reg_read(struct gsw_mt753x *gsw, u32 reg) +{ + u32 high, low; + + mutex_lock(&gsw->host_bus->mdio_lock); + + gsw->host_bus->write(gsw->host_bus, gsw->smi_addr, 0x1f, + (reg & MT753X_REG_PAGE_ADDR_M) >> MT753X_REG_PAGE_ADDR_S); + + low = gsw->host_bus->read(gsw->host_bus, gsw->smi_addr, + (reg & MT753X_REG_ADDR_M) >> MT753X_REG_ADDR_S); + + high = gsw->host_bus->read(gsw->host_bus, gsw->smi_addr, 0x10); + + mutex_unlock(&gsw->host_bus->mdio_lock); + + return (high << 16) | (low & 0xffff); +} + +void mt753x_reg_write(struct gsw_mt753x *gsw, u32 reg, u32 val) +{ + mutex_lock(&gsw->host_bus->mdio_lock); + + gsw->host_bus->write(gsw->host_bus, gsw->smi_addr, 0x1f, + (reg & MT753X_REG_PAGE_ADDR_M) >> MT753X_REG_PAGE_ADDR_S); + + gsw->host_bus->write(gsw->host_bus, gsw->smi_addr, + (reg & MT753X_REG_ADDR_M) >> MT753X_REG_ADDR_S, val & 0xffff); + + gsw->host_bus->write(gsw->host_bus, gsw->smi_addr, 0x10, val >> 16); + + mutex_unlock(&gsw->host_bus->mdio_lock); +} + +/* Indirect MDIO clause 22/45 access */ +static int mt753x_mii_rw(struct gsw_mt753x *gsw, int phy, int reg, u16 data, + u32 cmd, u32 st) +{ + ktime_t timeout; + u32 val, timeout_us; + int ret = 0; + + timeout_us = 100000; + timeout = ktime_add_us(ktime_get(), timeout_us); + while (1) { + val = mt753x_reg_read(gsw, PHY_IAC); + + if ((val & PHY_ACS_ST) == 0) + break; + + if (ktime_compare(ktime_get(), timeout) > 0) + return -ETIMEDOUT; + } + + val = (st << MDIO_ST_S) | + ((cmd << MDIO_CMD_S) & MDIO_CMD_M) | + ((phy << MDIO_PHY_ADDR_S) & MDIO_PHY_ADDR_M) | + ((reg << MDIO_REG_ADDR_S) & MDIO_REG_ADDR_M); + + if (cmd == MDIO_CMD_WRITE || cmd == MDIO_CMD_ADDR) + val |= data & MDIO_RW_DATA_M; + + mt753x_reg_write(gsw, PHY_IAC, val | PHY_ACS_ST); + + timeout_us = 100000; + timeout = ktime_add_us(ktime_get(), timeout_us); + while (1) { + val = mt753x_reg_read(gsw, PHY_IAC); + + if ((val & PHY_ACS_ST) == 0) + break; + + if (ktime_compare(ktime_get(), timeout) > 0) + return -ETIMEDOUT; + } + + if (cmd == MDIO_CMD_READ || cmd == MDIO_CMD_READ_C45) { + val = mt753x_reg_read(gsw, PHY_IAC); + ret = val & MDIO_RW_DATA_M; + } + + return ret; +} + +int mt753x_mii_read(struct gsw_mt753x *gsw, int phy, int reg) +{ + int val; + + if (phy < MT753X_NUM_PHYS) + phy = (gsw->phy_base + phy) & MT753X_SMI_ADDR_MASK; + + mutex_lock(&gsw->mii_lock); + val = mt753x_mii_rw(gsw, phy, reg, 0, MDIO_CMD_READ, MDIO_ST_C22); + mutex_unlock(&gsw->mii_lock); + + return val; +} + +void mt753x_mii_write(struct gsw_mt753x *gsw, int phy, int reg, u16 val) +{ + if (phy < MT753X_NUM_PHYS) + phy = (gsw->phy_base + phy) & MT753X_SMI_ADDR_MASK; + + mutex_lock(&gsw->mii_lock); + mt753x_mii_rw(gsw, phy, reg, val, MDIO_CMD_WRITE, MDIO_ST_C22); + mutex_unlock(&gsw->mii_lock); +} + +int mt753x_mmd_read(struct gsw_mt753x *gsw, int addr, int devad, u16 reg) +{ + int val; + + if (addr < MT753X_NUM_PHYS) + addr = (gsw->phy_base + addr) & MT753X_SMI_ADDR_MASK; + + mutex_lock(&gsw->mii_lock); + mt753x_mii_rw(gsw, addr, devad, reg, MDIO_CMD_ADDR, MDIO_ST_C45); + val = mt753x_mii_rw(gsw, addr, devad, 0, MDIO_CMD_READ_C45, + MDIO_ST_C45); + mutex_unlock(&gsw->mii_lock); + + return val; +} + +void mt753x_mmd_write(struct gsw_mt753x *gsw, int addr, int devad, u16 reg, + u16 val) +{ + if (addr < MT753X_NUM_PHYS) + addr = (gsw->phy_base + addr) & MT753X_SMI_ADDR_MASK; + + mutex_lock(&gsw->mii_lock); + mt753x_mii_rw(gsw, addr, devad, reg, MDIO_CMD_ADDR, MDIO_ST_C45); + mt753x_mii_rw(gsw, addr, devad, val, MDIO_CMD_WRITE, MDIO_ST_C45); + mutex_unlock(&gsw->mii_lock); +} + +int mt753x_mmd_ind_read(struct gsw_mt753x *gsw, int addr, int devad, u16 reg) +{ + u16 val; + + if (addr < MT753X_NUM_PHYS) + addr = (gsw->phy_base + addr) & MT753X_SMI_ADDR_MASK; + + mutex_lock(&gsw->mii_lock); + + mt753x_mii_rw(gsw, addr, MII_MMD_ACC_CTL_REG, + (MMD_ADDR << MMD_CMD_S) | + ((devad << MMD_DEVAD_S) & MMD_DEVAD_M), + MDIO_CMD_WRITE, MDIO_ST_C22); + + mt753x_mii_rw(gsw, addr, MII_MMD_ADDR_DATA_REG, reg, + MDIO_CMD_WRITE, MDIO_ST_C22); + + mt753x_mii_rw(gsw, addr, MII_MMD_ACC_CTL_REG, + (MMD_DATA << MMD_CMD_S) | + ((devad << MMD_DEVAD_S) & MMD_DEVAD_M), + MDIO_CMD_WRITE, MDIO_ST_C22); + + val = mt753x_mii_rw(gsw, addr, MII_MMD_ADDR_DATA_REG, 0, + MDIO_CMD_READ, MDIO_ST_C22); + + mutex_unlock(&gsw->mii_lock); + + return val; +} + +void mt753x_mmd_ind_write(struct gsw_mt753x *gsw, int addr, int devad, u16 reg, + u16 val) +{ + if (addr < MT753X_NUM_PHYS) + addr = (gsw->phy_base + addr) & MT753X_SMI_ADDR_MASK; + + mutex_lock(&gsw->mii_lock); + + mt753x_mii_rw(gsw, addr, MII_MMD_ACC_CTL_REG, + (MMD_ADDR << MMD_CMD_S) | + ((devad << MMD_DEVAD_S) & MMD_DEVAD_M), + MDIO_CMD_WRITE, MDIO_ST_C22); + + mt753x_mii_rw(gsw, addr, MII_MMD_ADDR_DATA_REG, reg, + MDIO_CMD_WRITE, MDIO_ST_C22); + + mt753x_mii_rw(gsw, addr, MII_MMD_ACC_CTL_REG, + (MMD_DATA << MMD_CMD_S) | + ((devad << MMD_DEVAD_S) & MMD_DEVAD_M), + MDIO_CMD_WRITE, MDIO_ST_C22); + + mt753x_mii_rw(gsw, addr, MII_MMD_ADDR_DATA_REG, val, + MDIO_CMD_WRITE, MDIO_ST_C22); + + mutex_unlock(&gsw->mii_lock); +} + +static void mt753x_load_port_cfg(struct gsw_mt753x *gsw) +{ + struct device_node *port_np; + struct device_node *fixed_link_node; + struct mt753x_port_cfg *port_cfg; + u32 port; + + for_each_child_of_node(gsw->dev->of_node, port_np) { + if (!of_device_is_compatible(port_np, "mediatek,mt753x-port")) + continue; + + if (!of_device_is_available(port_np)) + continue; + + if (of_property_read_u32(port_np, "reg", &port)) + continue; + + switch (port) { + case 5: + port_cfg = &gsw->port5_cfg; + break; + case 6: + port_cfg = &gsw->port6_cfg; + break; + default: + continue; + } + + if (port_cfg->enabled) { + dev_info(gsw->dev, "duplicated node for port%d\n", + port_cfg->phy_mode); + continue; + } + + port_cfg->np = port_np; + + port_cfg->phy_mode = of_get_phy_mode(port_np); + if (port_cfg->phy_mode < 0) { + dev_info(gsw->dev, "incorrect phy-mode %d\n", port); + continue; + } + + fixed_link_node = of_get_child_by_name(port_np, "fixed-link"); + if (fixed_link_node) { + u32 speed; + + port_cfg->force_link = 1; + port_cfg->duplex = of_property_read_bool( + fixed_link_node, + "full-duplex"); + + if (of_property_read_u32(fixed_link_node, "speed", + &speed)) { + speed = 0; + continue; + } + + of_node_put(fixed_link_node); + + switch (speed) { + case 10: + port_cfg->speed = MAC_SPD_10; + break; + case 100: + port_cfg->speed = MAC_SPD_100; + break; + case 1000: + port_cfg->speed = MAC_SPD_1000; + break; + case 2500: + port_cfg->speed = MAC_SPD_2500; + break; + default: + dev_info(gsw->dev, "incorrect speed %d\n", + speed); + continue; + } + } + + port_cfg->enabled = 1; + } +} + +static void mt753x_add_gsw(struct gsw_mt753x *gsw) +{ + mutex_lock(&mt753x_devs_lock); + gsw->id = mt753x_id++; + INIT_LIST_HEAD(&gsw->list); + list_add_tail(&gsw->list, &mt753x_devs); + mutex_unlock(&mt753x_devs_lock); +} + +static void mt753x_remove_gsw(struct gsw_mt753x *gsw) +{ + mutex_lock(&mt753x_devs_lock); + list_del(&gsw->list); + mutex_unlock(&mt753x_devs_lock); +} + +struct gsw_mt753x *mt753x_get_gsw(u32 id) +{ + struct gsw_mt753x *dev; + + mutex_lock(&mt753x_devs_lock); + + list_for_each_entry(dev, &mt753x_devs, list) { + if (dev->id == id) + return dev; + } + + mutex_unlock(&mt753x_devs_lock); + + return NULL; +} + +struct gsw_mt753x *mt753x_get_first_gsw(void) +{ + struct gsw_mt753x *dev; + + mutex_lock(&mt753x_devs_lock); + + list_for_each_entry(dev, &mt753x_devs, list) + return dev; + + mutex_unlock(&mt753x_devs_lock); + + return NULL; +} + +void mt753x_put_gsw(void) +{ + mutex_unlock(&mt753x_devs_lock); +} + +void mt753x_lock_gsw(void) +{ + mutex_lock(&mt753x_devs_lock); +} + +static int mt753x_hw_reset(struct gsw_mt753x *gsw) +{ + struct device_node *np = gsw->dev->of_node; + struct reset_control *rstc; + int mcm; + int ret = -EINVAL; + + mcm = of_property_read_bool(np, "mediatek,mcm"); + if (mcm) { + rstc = devm_reset_control_get(gsw->dev, "mcm"); + ret = IS_ERR(rstc); + if (IS_ERR(rstc)) { + dev_err(gsw->dev, "Missing reset ctrl of switch\n"); + return ret; + } + + reset_control_assert(rstc); + msleep(30); + reset_control_deassert(rstc); + + gsw->reset_pin = -1; + return 0; + } + + gsw->reset_pin = of_get_named_gpio(np, "reset-gpios", 0); + if (gsw->reset_pin < 0) { + dev_err(gsw->dev, "Missing reset pin of switch\n"); + return ret; + } + + ret = devm_gpio_request(gsw->dev, gsw->reset_pin, "mt753x-reset"); + if (ret) { + dev_info(gsw->dev, "Failed to request gpio %d\n", + gsw->reset_pin); + return ret; + } + + gpio_direction_output(gsw->reset_pin, 0); + msleep(30); + gpio_set_value(gsw->reset_pin, 1); + msleep(500); + + return 0; +} + +static int mt753x_mdio_read(struct mii_bus *bus, int addr, int reg) +{ + struct gsw_mt753x *gsw = bus->priv; + + return gsw->mii_read(gsw, addr, reg); +} + +static int mt753x_mdio_write(struct mii_bus *bus, int addr, int reg, u16 val) +{ + struct gsw_mt753x *gsw = bus->priv; + + gsw->mii_write(gsw, addr, reg, val); + + return 0; +} + +static const struct net_device_ops mt753x_dummy_netdev_ops = { +}; + +static void mt753x_phy_link_handler(struct net_device *dev) +{ + struct mt753x_phy *phy = container_of(dev, struct mt753x_phy, netdev); + struct phy_device *phydev = phy->phydev; + struct gsw_mt753x *gsw = phy->gsw; + u32 port = phy - gsw->phys; + + if (phydev->link) { + dev_info(gsw->dev, + "Port %d Link is Up - %s/%s - flow control %s\n", + port, phy_speed_to_str(phydev->speed), + (phydev->duplex == DUPLEX_FULL) ? "Full" : "Half", + phydev->pause ? "rx/tx" : "off"); + } else { + dev_info(gsw->dev, "Port %d Link is Down\n", port); + } +} + +static void mt753x_connect_internal_phys(struct gsw_mt753x *gsw, + struct device_node *mii_np) +{ + struct device_node *phy_np; + struct mt753x_phy *phy; + int phy_mode; + u32 phyad; + + if (!mii_np) + return; + + for_each_child_of_node(mii_np, phy_np) { + if (of_property_read_u32(phy_np, "reg", &phyad)) + continue; + + if (phyad >= MT753X_NUM_PHYS) + continue; + + phy_mode = of_get_phy_mode(phy_np); + if (phy_mode < 0) { + dev_info(gsw->dev, "incorrect phy-mode %d for PHY %d\n", + phy_mode, phyad); + continue; + } + + phy = &gsw->phys[phyad]; + phy->gsw = gsw; + + init_dummy_netdev(&phy->netdev); + phy->netdev.netdev_ops = &mt753x_dummy_netdev_ops; + + phy->phydev = of_phy_connect(&phy->netdev, phy_np, + mt753x_phy_link_handler, 0, phy_mode); + if (!phy->phydev) { + dev_info(gsw->dev, "could not connect to PHY %d\n", + phyad); + continue; + } + + phy_start(phy->phydev); + } +} + +static void mt753x_disconnect_internal_phys(struct gsw_mt753x *gsw) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(gsw->phys); i++) { + if (gsw->phys[i].phydev) { + phy_stop(gsw->phys[i].phydev); + phy_disconnect(gsw->phys[i].phydev); + gsw->phys[i].phydev = NULL; + } + } +} + +static int mt753x_mdio_register(struct gsw_mt753x *gsw) +{ + struct device_node *mii_np; + int i, ret; + + mii_np = of_get_child_by_name(gsw->dev->of_node, "mdio-bus"); + if (mii_np && !of_device_is_available(mii_np)) { + ret = -ENODEV; + goto err_put_node; + } + + gsw->gphy_bus = devm_mdiobus_alloc(gsw->dev); + if (!gsw->gphy_bus) { + ret = -ENOMEM; + goto err_put_node; + } + + gsw->gphy_bus->name = "mt753x_mdio"; + gsw->gphy_bus->read = mt753x_mdio_read; + gsw->gphy_bus->write = mt753x_mdio_write; + gsw->gphy_bus->priv = gsw; + gsw->gphy_bus->parent = gsw->dev; + gsw->gphy_bus->phy_mask = BIT(MT753X_NUM_PHYS) - 1; + + for (i = 0; i < PHY_MAX_ADDR; i++) + gsw->gphy_bus->irq[i] = PHY_POLL; + + if (mii_np) + snprintf(gsw->gphy_bus->id, MII_BUS_ID_SIZE, "%s@%s", + mii_np->name, gsw->dev->of_node->name); + else + snprintf(gsw->gphy_bus->id, MII_BUS_ID_SIZE, "mdio@%s", + gsw->dev->of_node->name); + + ret = of_mdiobus_register(gsw->gphy_bus, mii_np); + + if (ret) { + devm_mdiobus_free(gsw->dev, gsw->gphy_bus); + gsw->gphy_bus = NULL; + } else { + if (gsw->phy_status_poll) + mt753x_connect_internal_phys(gsw, mii_np); + } + +err_put_node: + if (mii_np) + of_node_put(mii_np); + + return ret; +} + +static irqreturn_t mt753x_irq_handler(int irq, void *dev) +{ + struct gsw_mt753x *gsw = dev; + + disable_irq_nosync(gsw->irq); + + schedule_work(&gsw->irq_worker); + + return IRQ_HANDLED; +} + +static int mt753x_probe(struct platform_device *pdev) +{ + struct gsw_mt753x *gsw; + struct mt753x_sw_id *sw; + struct device_node *np = pdev->dev.of_node; + struct device_node *mdio; + struct mii_bus *mdio_bus; + int ret = -EINVAL; + struct chip_rev rev; + int i; + + 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 gsw_mt753x), GFP_KERNEL); + if (!gsw) + return -ENOMEM; + + gsw->host_bus = mdio_bus; + gsw->dev = &pdev->dev; + mutex_init(&gsw->mii_lock); + + /* Switch hard reset */ + mt753x_hw_reset(gsw); + + /* Fetch the SMI address dirst */ + if (of_property_read_u32(np, "mediatek,smi-addr", &gsw->smi_addr)) + gsw->smi_addr = MT753X_DFL_SMI_ADDR; + + /* Load MAC port configurations */ + mt753x_load_port_cfg(gsw); + + /* Check for valid switch and then initialize */ + for (i = 0; i < ARRAY_SIZE(mt753x_sw_ids); i++) { + if (!mt753x_sw_ids[i]->detect(gsw, &rev)) { + sw = mt753x_sw_ids[i]; + + gsw->name = rev.name; + gsw->model = sw->model; + + dev_info(gsw->dev, "Switch is MediaTek %s rev %d", + gsw->name, rev.rev); + + /* Initialize the switch */ + ret = sw->init(gsw); + if (ret) + goto fail; + + break; + } + } + + if (i >= ARRAY_SIZE(mt753x_sw_ids)) { + dev_err(gsw->dev, "No mt753x switch found\n"); + goto fail; + } + + gsw->irq = platform_get_irq(pdev, 0); + if (gsw->irq >= 0) { + ret = devm_request_irq(gsw->dev, gsw->irq, mt753x_irq_handler, + 0, dev_name(gsw->dev), gsw); + if (ret) { + dev_err(gsw->dev, "Failed to request irq %d\n", + gsw->irq); + goto fail; + } + + INIT_WORK(&gsw->irq_worker, mt753x_irq_worker); + } + + platform_set_drvdata(pdev, gsw); + + gsw->phy_status_poll = of_property_read_bool(gsw->dev->of_node, + "mediatek,phy-poll"); + + mt753x_add_gsw(gsw); + + mt753x_mdio_register(gsw); + +#ifdef CONFIG_SWCONFIG + mt753x_swconfig_init(gsw); +#endif + + if (sw->post_init) + sw->post_init(gsw); + + if (gsw->irq >= 0) + mt753x_irq_enable(gsw); + + return 0; + +fail: + devm_kfree(&pdev->dev, gsw); + + return ret; +} + +static int mt753x_remove(struct platform_device *pdev) +{ + struct gsw_mt753x *gsw = platform_get_drvdata(pdev); + + if (gsw->irq >= 0) + cancel_work_sync(&gsw->irq_worker); + + if (gsw->reset_pin >= 0) + devm_gpio_free(&pdev->dev, gsw->reset_pin); + +#ifdef CONFIG_SWCONFIG + mt753x_swconfig_destroy(gsw); +#endif + + mt753x_disconnect_internal_phys(gsw); + + mdiobus_unregister(gsw->gphy_bus); + + mt753x_remove_gsw(gsw); + + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static const struct of_device_id mt753x_ids[] = { + { .compatible = "mediatek,mt753x" }, + { }, +}; + +MODULE_DEVICE_TABLE(of, mt753x_ids); + +static struct platform_driver mt753x_driver = { + .probe = mt753x_probe, + .remove = mt753x_remove, + .driver = { + .name = "mt753x", + .of_match_table = mt753x_ids, + }, +}; + +static int __init mt753x_init(void) +{ + int ret; + + INIT_LIST_HEAD(&mt753x_devs); + ret = platform_driver_register(&mt753x_driver); + + mt753x_nl_init(); + + return ret; +} +module_init(mt753x_init); + +static void __exit mt753x_exit(void) +{ + mt753x_nl_exit(); + + platform_driver_unregister(&mt753x_driver); +} +module_exit(mt753x_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Weijie Gao <weijie.gao@mediatek.com>"); +MODULE_DESCRIPTION("Driver for MediaTek MT753x Gigabit Switch"); diff --git a/target/linux/mediatek/files-4.19/drivers/net/phy/mtk/mt753x/mt753x_nl.c b/target/linux/mediatek/files-4.19/drivers/net/phy/mtk/mt753x/mt753x_nl.c new file mode 100644 index 0000000000..756df4e21f --- /dev/null +++ b/target/linux/mediatek/files-4.19/drivers/net/phy/mtk/mt753x/mt753x_nl.c @@ -0,0 +1,386 @@ +/* + * Configuration layer for MediaTek MT753x gigabit switch + * + * Copyright (C) 2018 MediaTek Inc. All Rights Reserved. + * + * Author: Sirui Zhao <Sirui.Zhao@mediatek.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <net/genetlink.h> + +#include "mt753x.h" +#include "mt753x_nl.h" + +#define MT753X_NL_CMD_REQ_ATTRS(attr) \ + .required_attrs = attr, \ + .nr_required_attrs = ARRAY_SIZE(attr), + +struct mt753x_nl_cmd_item { + enum mt753x_cmd cmd; + bool require_dev; + int (*process)(struct genl_info *info, struct gsw_mt753x *gsw); + u32 nr_required_attrs; + const enum mt753x_attr *required_attrs; +}; + +static int mt753x_nl_response(struct sk_buff *skb, struct genl_info *info); + +static const struct nla_policy mt753x_nl_cmd_policy[] = { + [MT753X_ATTR_TYPE_MESG] = { .type = NLA_STRING }, + [MT753X_ATTR_TYPE_PHY] = { .type = NLA_S32 }, + [MT753X_ATTR_TYPE_REG] = { .type = NLA_S32 }, + [MT753X_ATTR_TYPE_VAL] = { .type = NLA_S32 }, + [MT753X_ATTR_TYPE_DEV_NAME] = { .type = NLA_S32 }, + [MT753X_ATTR_TYPE_DEV_ID] = { .type = NLA_S32 }, + [MT753X_ATTR_TYPE_DEVAD] = { .type = NLA_S32 }, +}; + +static const struct genl_ops mt753x_nl_ops[] = { + { + .cmd = MT753X_CMD_REQUEST, + .doit = mt753x_nl_response, + .policy = mt753x_nl_cmd_policy, + .flags = GENL_ADMIN_PERM, + }, { + .cmd = MT753X_CMD_READ, + .doit = mt753x_nl_response, + .policy = mt753x_nl_cmd_policy, + .flags = GENL_ADMIN_PERM, + }, { + .cmd = MT753X_CMD_WRITE, + .doit = mt753x_nl_response, + .policy = mt753x_nl_cmd_policy, + .flags = GENL_ADMIN_PERM, + }, +}; + +static struct genl_family mt753x_nl_family = { +// .id = GENL_ID_GENERATE, + .name = MT753X_GENL_NAME, + .version = MT753X_GENL_VERSION, + .maxattr = MT753X_NR_ATTR_TYPE, + .ops = mt753x_nl_ops, + .n_ops = ARRAY_SIZE(mt753x_nl_ops), +}; + +static int mt753x_nl_list_devs(char *buff, int size) +{ + struct gsw_mt753x *gsw; + int len, total = 0; + char buf[80]; + + memset(buff, 0, size); + + mt753x_lock_gsw(); + + list_for_each_entry(gsw, &mt753x_devs, list) { + len = snprintf(buf, sizeof(buf), + "id: %d, model: %s, node: %s\n", + gsw->id, gsw->name, gsw->dev->of_node->name); + strncat(buff, buf, size - total); + total += len; + } + + mt753x_put_gsw(); + + return total; +} + +static int mt753x_nl_prepare_reply(struct genl_info *info, u8 cmd, + struct sk_buff **skbp) +{ + struct sk_buff *msg; + void *reply; + + if (!info) + return -EINVAL; + + msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + /* Construct send-back message header */ + reply = genlmsg_put(msg, info->snd_portid, info->snd_seq, + &mt753x_nl_family, 0, cmd); + if (!reply) { + nlmsg_free(msg); + return -EINVAL; + } + + *skbp = msg; + return 0; +} + +static int mt753x_nl_send_reply(struct sk_buff *skb, struct genl_info *info) +{ + struct genlmsghdr *genlhdr = nlmsg_data(nlmsg_hdr(skb)); + void *reply = genlmsg_data(genlhdr); + + /* Finalize a generic netlink message (update message header) */ + genlmsg_end(skb, reply); + + /* reply to a request */ + return genlmsg_reply(skb, info); +} + +static s32 mt753x_nl_get_s32(struct genl_info *info, enum mt753x_attr attr, + s32 defval) +{ + struct nlattr *na; + + na = info->attrs[attr]; + if (na) + return nla_get_s32(na); + + return defval; +} + +static int mt753x_nl_get_u32(struct genl_info *info, enum mt753x_attr attr, + u32 *val) +{ + struct nlattr *na; + + na = info->attrs[attr]; + if (na) { + *val = nla_get_u32(na); + return 0; + } + + return -1; +} + +static struct gsw_mt753x *mt753x_nl_parse_find_gsw(struct genl_info *info) +{ + struct gsw_mt753x *gsw; + struct nlattr *na; + int gsw_id; + + na = info->attrs[MT753X_ATTR_TYPE_DEV_ID]; + if (na) { + gsw_id = nla_get_s32(na); + if (gsw_id >= 0) + gsw = mt753x_get_gsw(gsw_id); + else + gsw = mt753x_get_first_gsw(); + } else { + gsw = mt753x_get_first_gsw(); + } + + return gsw; +} + +static int mt753x_nl_get_swdevs(struct genl_info *info, struct gsw_mt753x *gsw) +{ + struct sk_buff *rep_skb = NULL; + char dev_info[512]; + int ret; + + ret = mt753x_nl_list_devs(dev_info, sizeof(dev_info)); + if (!ret) { + pr_info("No switch registered\n"); + return -EINVAL; + } + + ret = mt753x_nl_prepare_reply(info, MT753X_CMD_REPLY, &rep_skb); + if (ret < 0) + goto err; + + ret = nla_put_string(rep_skb, MT753X_ATTR_TYPE_MESG, dev_info); + if (ret < 0) + goto err; + + return mt753x_nl_send_reply(rep_skb, info); + +err: + if (rep_skb) + nlmsg_free(rep_skb); + + return ret; +} + +static int mt753x_nl_reply_read(struct genl_info *info, struct gsw_mt753x *gsw) +{ + struct sk_buff *rep_skb = NULL; + s32 phy, devad, reg; + int ret, value; + + phy = mt753x_nl_get_s32(info, MT753X_ATTR_TYPE_PHY, -1); + devad = mt753x_nl_get_s32(info, MT753X_ATTR_TYPE_DEVAD, -1); + reg = mt753x_nl_get_s32(info, MT753X_ATTR_TYPE_REG, -1); + + if (reg < 0) + goto err; + + ret = mt753x_nl_prepare_reply(info, MT753X_CMD_READ, &rep_skb); + if (ret < 0) + goto err; + + if (phy >= 0) { + if (devad < 0) + value = gsw->mii_read(gsw, phy, reg); + else + value = gsw->mmd_read(gsw, phy, devad, reg); + } else { + value = mt753x_reg_read(gsw, reg); + } + + ret = nla_put_s32(rep_skb, MT753X_ATTR_TYPE_REG, reg); + if (ret < 0) + goto err; + + ret = nla_put_s32(rep_skb, MT753X_ATTR_TYPE_VAL, value); + if (ret < 0) + goto err; + + return mt753x_nl_send_reply(rep_skb, info); + +err: + if (rep_skb) + nlmsg_free(rep_skb); + + return ret; +} + +static int mt753x_nl_reply_write(struct genl_info *info, struct gsw_mt753x *gsw) +{ + struct sk_buff *rep_skb = NULL; + s32 phy, devad, reg; + u32 value; + int ret; + + phy = mt753x_nl_get_s32(info, MT753X_ATTR_TYPE_PHY, -1); + devad = mt753x_nl_get_s32(info, MT753X_ATTR_TYPE_DEVAD, -1); + reg = mt753x_nl_get_s32(info, MT753X_ATTR_TYPE_REG, -1); + + if (mt753x_nl_get_u32(info, MT753X_ATTR_TYPE_VAL, &value)) + goto err; + + if (reg < 0) + goto err; + + ret = mt753x_nl_prepare_reply(info, MT753X_CMD_WRITE, &rep_skb); + if (ret < 0) + goto err; + + if (phy >= 0) { + if (devad < 0) + gsw->mii_write(gsw, phy, reg, value); + else + gsw->mmd_write(gsw, phy, devad, reg, value); + } else { + mt753x_reg_write(gsw, reg, value); + } + + ret = nla_put_s32(rep_skb, MT753X_ATTR_TYPE_REG, reg); + if (ret < 0) + goto err; + + ret = nla_put_s32(rep_skb, MT753X_ATTR_TYPE_VAL, value); + if (ret < 0) + goto err; + + return mt753x_nl_send_reply(rep_skb, info); + +err: + if (rep_skb) + nlmsg_free(rep_skb); + + return ret; +} + +static const enum mt753x_attr mt753x_nl_cmd_read_attrs[] = { + MT753X_ATTR_TYPE_REG +}; + +static const enum mt753x_attr mt753x_nl_cmd_write_attrs[] = { + MT753X_ATTR_TYPE_REG, + MT753X_ATTR_TYPE_VAL +}; + +static const struct mt753x_nl_cmd_item mt753x_nl_cmds[] = { + { + .cmd = MT753X_CMD_REQUEST, + .require_dev = false, + .process = mt753x_nl_get_swdevs + }, { + .cmd = MT753X_CMD_READ, + .require_dev = true, + .process = mt753x_nl_reply_read, + MT753X_NL_CMD_REQ_ATTRS(mt753x_nl_cmd_read_attrs) + }, { + .cmd = MT753X_CMD_WRITE, + .require_dev = true, + .process = mt753x_nl_reply_write, + MT753X_NL_CMD_REQ_ATTRS(mt753x_nl_cmd_write_attrs) + } +}; + +static int mt753x_nl_response(struct sk_buff *skb, struct genl_info *info) +{ + struct genlmsghdr *hdr = nlmsg_data(info->nlhdr); + const struct mt753x_nl_cmd_item *cmditem = NULL; + struct gsw_mt753x *gsw = NULL; + u32 sat_req_attrs = 0; + int i, ret; + + for (i = 0; i < ARRAY_SIZE(mt753x_nl_cmds); i++) { + if (hdr->cmd == mt753x_nl_cmds[i].cmd) { + cmditem = &mt753x_nl_cmds[i]; + break; + } + } + + if (!cmditem) { + pr_info("mt753x-nl: unknown cmd %u\n", hdr->cmd); + return -EINVAL; + } + + for (i = 0; i < cmditem->nr_required_attrs; i++) { + if (info->attrs[cmditem->required_attrs[i]]) + sat_req_attrs++; + } + + if (sat_req_attrs != cmditem->nr_required_attrs) { + pr_info("mt753x-nl: missing required attr(s) for cmd %u\n", + hdr->cmd); + return -EINVAL; + } + + if (cmditem->require_dev) { + gsw = mt753x_nl_parse_find_gsw(info); + if (!gsw) { + pr_info("mt753x-nl: failed to find switch dev\n"); + return -EINVAL; + } + } + + ret = cmditem->process(info, gsw); + + mt753x_put_gsw(); + + return ret; +} + +int __init mt753x_nl_init(void) +{ + int ret; + + ret = genl_register_family(&mt753x_nl_family); + if (ret) { + pr_info("mt753x-nl: genl_register_family_with_ops failed\n"); + return ret; + } + + return 0; +} + +void __exit mt753x_nl_exit(void) +{ + genl_unregister_family(&mt753x_nl_family); +} diff --git a/target/linux/mediatek/files-4.19/drivers/net/phy/mtk/mt753x/mt753x_nl.h b/target/linux/mediatek/files-4.19/drivers/net/phy/mtk/mt753x/mt753x_nl.h new file mode 100644 index 0000000000..f6a1df34e6 --- /dev/null +++ b/target/linux/mediatek/files-4.19/drivers/net/phy/mtk/mt753x/mt753x_nl.h @@ -0,0 +1,47 @@ +/* + * Driver for MediaTek MT753x gigabit switch + * + * Copyright (C) 2018 MediaTek Inc. All Rights Reserved. + * + * Author: Sirui Zhao <Sirui.Zhao@mediatek.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _MT753X_NL_H_ +#define _MT753X_NL_H_ + +#define MT753X_GENL_NAME "mt753x" +#define MT753X_GENL_VERSION 0x1 + +enum mt753x_cmd { + MT753X_CMD_UNSPEC = 0, + MT753X_CMD_REQUEST, + MT753X_CMD_REPLY, + MT753X_CMD_READ, + MT753X_CMD_WRITE, + + __MT753X_CMD_MAX, +}; + +enum mt753x_attr { + MT753X_ATTR_TYPE_UNSPEC = 0, + MT753X_ATTR_TYPE_MESG, + MT753X_ATTR_TYPE_PHY, + MT753X_ATTR_TYPE_DEVAD, + MT753X_ATTR_TYPE_REG, + MT753X_ATTR_TYPE_VAL, + MT753X_ATTR_TYPE_DEV_NAME, + MT753X_ATTR_TYPE_DEV_ID, + + __MT753X_ATTR_TYPE_MAX, +}; + +#define MT753X_NR_ATTR_TYPE (__MT753X_ATTR_TYPE_MAX - 1) + +#ifdef __KERNEL__ +int __init mt753x_nl_init(void); +void __exit mt753x_nl_exit(void); +#endif /* __KERNEL__ */ + +#endif /* _MT753X_NL_H_ */ diff --git a/target/linux/mediatek/files-4.19/drivers/net/phy/mtk/mt753x/mt753x_regs.h b/target/linux/mediatek/files-4.19/drivers/net/phy/mtk/mt753x/mt753x_regs.h new file mode 100644 index 0000000000..15255277ab --- /dev/null +++ b/target/linux/mediatek/files-4.19/drivers/net/phy/mtk/mt753x/mt753x_regs.h @@ -0,0 +1,298 @@ +/* + * Register definitions for MediaTek MT753x Gigabit switches + * + * Copyright (C) 2018 MediaTek Inc. All Rights Reserved. + * + * Author: Weijie Gao <weijie.gao@mediatek.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _MT753X_REGS_H_ +#define _MT753X_REGS_H_ + +#include <linux/bitops.h> + +/* Values of Egress TAG Control */ +#define ETAG_CTRL_UNTAG 0 +#define ETAG_CTRL_TAG 2 +#define ETAG_CTRL_SWAP 1 +#define ETAG_CTRL_STACK 3 + +#define VTCR 0x90 +#define VAWD1 0x94 +#define VAWD2 0x98 + +/* Fields of VTCR */ +#define VTCR_BUSY BIT(31) +#define IDX_INVLD BIT(16) +#define VTCR_FUNC_S 12 +#define VTCR_FUNC_M 0xf000 +#define VTCR_VID_S 0 +#define VTCR_VID_M 0xfff + +/* Values of VTCR_FUNC */ +#define VTCR_READ_VLAN_ENTRY 0 +#define VTCR_WRITE_VLAN_ENTRY 1 +#define VTCR_INVD_VLAN_ENTRY 2 +#define VTCR_ENABLE_VLAN_ENTRY 3 +#define VTCR_READ_ACL_ENTRY 4 +#define VTCR_WRITE_ACL_ENTRY 5 +#define VTCR_READ_TRTCM_TABLE 6 +#define VTCR_WRITE_TRTCM_TABLE 7 +#define VTCR_READ_ACL_MASK_ENTRY 8 +#define VTCR_WRITE_ACL_MASK_ENTRY 9 +#define VTCR_READ_ACL_RULE_ENTRY 10 +#define VTCR_WRITE_ACL_RULE_ENTRY 11 +#define VTCR_READ_ACL_RATE_ENTRY 12 +#define VTCR_WRITE_ACL_RATE_ENTRY 13 + +/* VLAN entry fields */ +/* VAWD1 */ +#define PORT_STAG BIT(31) +#define IVL_MAC BIT(30) +#define EG_CON BIT(29) +#define VTAG_EN BIT(28) +#define COPY_PRI BIT(27) +#define USER_PRI_S 24 +#define USER_PRI_M 0x7000000 +#define PORT_MEM_S 16 +#define PORT_MEM_M 0xff0000 +#define S_TAG1_S 4 +#define S_TAG1_M 0xfff0 +#define FID_S 1 +#define FID_M 0x0e +#define VENTRY_VALID BIT(0) + +/* VAWD2 */ +#define S_TAG2_S 16 +#define S_TAG2_M 0xffff0000 +#define PORT_ETAG_S(p) ((p) * 2) +#define PORT_ETAG_M 0x03 + +#define PORT_CTRL_BASE 0x2000 +#define PORT_CTRL_PORT_OFFSET 0x100 +#define PORT_CTRL_REG(p, r) (PORT_CTRL_BASE + \ + (p) * PORT_CTRL_PORT_OFFSET + (r)) +#define CKGCR(p) PORT_CTRL_REG(p, 0x00) +#define PCR(p) PORT_CTRL_REG(p, 0x04) +#define PIC(p) PORT_CTRL_REG(p, 0x08) +#define PSC(p) PORT_CTRL_REG(p, 0x0c) +#define PVC(p) PORT_CTRL_REG(p, 0x10) +#define PPBV1(p) PORT_CTRL_REG(p, 0x14) +#define PPBV2(p) PORT_CTRL_REG(p, 0x18) +#define BSR(p) PORT_CTRL_REG(p, 0x1c) +#define STAG01 PORT_CTRL_REG(p, 0x20) +#define STAG23 PORT_CTRL_REG(p, 0x24) +#define STAG45 PORT_CTRL_REG(p, 0x28) +#define STAG67 PORT_CTRL_REG(p, 0x2c) + +#define PPBV(p, g) (PPBV1(p) + ((g) / 2) * 4) + +/* Fields of PCR */ +#define MLDV2_EN BIT(30) +#define EG_TAG_S 28 +#define EG_TAG_M 0x30000000 +#define PORT_PRI_S 24 +#define PORT_PRI_M 0x7000000 +#define PORT_MATRIX_S 16 +#define PORT_MATRIX_M 0xff0000 +#define UP2DSCP_EN BIT(12) +#define UP2TAG_EN BIT(11) +#define ACL_EN BIT(10) +#define PORT_TX_MIR BIT(9) +#define PORT_RX_MIR BIT(8) +#define ACL_MIR BIT(7) +#define MIS_PORT_FW_S 4 +#define MIS_PORT_FW_M 0x70 +#define VLAN_MIS BIT(2) +#define PORT_VLAN_S 0 +#define PORT_VLAN_M 0x03 + +/* Values of PORT_VLAN */ +#define PORT_MATRIX_MODE 0 +#define FALLBACK_MODE 1 +#define CHECK_MODE 2 +#define SECURITY_MODE 3 + +/* Fields of PVC */ +#define STAG_VPID_S 16 +#define STAG_VPID_M 0xffff0000 +#define DIS_PVID BIT(15) +#define FORCE_PVID BIT(14) +#define PT_VPM BIT(12) +#define PT_OPTION BIT(11) +#define PVC_EG_TAG_S 8 +#define PVC_EG_TAG_M 0x700 +#define VLAN_ATTR_S 6 +#define VLAN_ATTR_M 0xc0 +#define PVC_PORT_STAG BIT(5) +#define BC_LKYV_EN BIT(4) +#define MC_LKYV_EN BIT(3) +#define UC_LKYV_EN BIT(2) +#define ACC_FRM_S 0 +#define ACC_FRM_M 0x03 + +/* Values of VLAN_ATTR */ +#define VA_USER_PORT 0 +#define VA_STACK_PORT 1 +#define VA_TRANSLATION_PORT 2 +#define VA_TRANSPARENT_PORT 3 + +/* Fields of PPBV */ +#define GRP_PORT_PRI_S(g) (((g) % 2) * 16 + 13) +#define GRP_PORT_PRI_M 0x07 +#define GRP_PORT_VID_S(g) (((g) % 2) * 16) +#define GRP_PORT_VID_M 0xfff + +#define PORT_MAC_CTRL_BASE 0x3000 +#define PORT_MAC_CTRL_PORT_OFFSET 0x100 +#define PORT_MAC_CTRL_REG(p, r) (PORT_MAC_CTRL_BASE + \ + (p) * PORT_MAC_CTRL_PORT_OFFSET + (r)) +#define PMCR(p) PORT_MAC_CTRL_REG(p, 0x00) +#define PMEEECR(p) PORT_MAC_CTRL_REG(p, 0x04) +#define PMSR(p) PORT_MAC_CTRL_REG(p, 0x08) +#define PINT_EN(p) PORT_MAC_CTRL_REG(p, 0x10) +#define PINT_STS(p) PORT_MAC_CTRL_REG(p, 0x14) + +#define GMACCR (PORT_MAC_CTRL_BASE + 0xe0) +#define TXCRC_EN BIT(19) +#define RXCRC_EN BIT(18) +#define PRMBL_LMT_EN BIT(17) +#define MTCC_LMT_S 9 +#define MTCC_LMT_M 0x1e00 +#define MAX_RX_JUMBO_S 2 +#define MAX_RX_JUMBO_M 0x3c +#define MAX_RX_PKT_LEN_S 0 +#define MAX_RX_PKT_LEN_M 0x3 + +/* Values of MAX_RX_PKT_LEN */ +#define RX_PKT_LEN_1518 0 +#define RX_PKT_LEN_1536 1 +#define RX_PKT_LEN_1522 2 +#define RX_PKT_LEN_MAX_JUMBO 3 + +/* Fields of PMCR */ +#define IPG_CFG_S 18 +#define IPG_CFG_M 0xc0000 +#define EXT_PHY BIT(17) +#define MAC_MODE BIT(16) +#define MAC_TX_EN BIT(14) +#define MAC_RX_EN BIT(13) +#define MAC_PRE BIT(11) +#define BKOFF_EN BIT(9) +#define BACKPR_EN BIT(8) +#define FORCE_EEE1G BIT(7) +#define FORCE_EEE1000 BIT(6) +#define FORCE_RX_FC BIT(5) +#define FORCE_TX_FC BIT(4) +#define FORCE_SPD_S 2 +#define FORCE_SPD_M 0x0c +#define FORCE_DPX BIT(1) +#define FORCE_LINK BIT(0) + +/* Fields of PMSR */ +#define EEE1G_STS BIT(7) +#define EEE100_STS BIT(6) +#define RX_FC_STS BIT(5) +#define TX_FC_STS BIT(4) +#define MAC_SPD_STS_S 2 +#define MAC_SPD_STS_M 0x0c +#define MAC_DPX_STS BIT(1) +#define MAC_LNK_STS BIT(0) + +/* Values of MAC_SPD_STS */ +#define MAC_SPD_10 0 +#define MAC_SPD_100 1 +#define MAC_SPD_1000 2 +#define MAC_SPD_2500 3 + +/* Values of IPG_CFG */ +#define IPG_96BIT 0 +#define IPG_96BIT_WITH_SHORT_IPG 1 +#define IPG_64BIT 2 + +#define MIB_COUNTER_BASE 0x4000 +#define MIB_COUNTER_PORT_OFFSET 0x100 +#define MIB_COUNTER_REG(p, r) (MIB_COUNTER_BASE + \ + (p) * MIB_COUNTER_PORT_OFFSET + (r)) +#define STATS_TDPC 0x00 +#define STATS_TCRC 0x04 +#define STATS_TUPC 0x08 +#define STATS_TMPC 0x0C +#define STATS_TBPC 0x10 +#define STATS_TCEC 0x14 +#define STATS_TSCEC 0x18 +#define STATS_TMCEC 0x1C +#define STATS_TDEC 0x20 +#define STATS_TLCEC 0x24 +#define STATS_TXCEC 0x28 +#define STATS_TPPC 0x2C +#define STATS_TL64PC 0x30 +#define STATS_TL65PC 0x34 +#define STATS_TL128PC 0x38 +#define STATS_TL256PC 0x3C +#define STATS_TL512PC 0x40 +#define STATS_TL1024PC 0x44 +#define STATS_TOC 0x48 +#define STATS_RDPC 0x60 +#define STATS_RFPC 0x64 +#define STATS_RUPC 0x68 +#define STATS_RMPC 0x6C +#define STATS_RBPC 0x70 +#define STATS_RAEPC 0x74 +#define STATS_RCEPC 0x78 +#define STATS_RUSPC 0x7C +#define STATS_RFEPC 0x80 +#define STATS_ROSPC 0x84 +#define STATS_RJEPC 0x88 +#define STATS_RPPC 0x8C +#define STATS_RL64PC 0x90 +#define STATS_RL65PC 0x94 +#define STATS_RL128PC 0x98 +#define STATS_RL256PC 0x9C +#define STATS_RL512PC 0xA0 +#define STATS_RL1024PC 0xA4 +#define STATS_ROC 0xA8 +#define STATS_RDPC_CTRL 0xB0 +#define STATS_RDPC_ING 0xB4 +#define STATS_RDPC_ARL 0xB8 + +#define SYS_CTRL 0x7000 +#define SW_PHY_RST BIT(2) +#define SW_SYS_RST BIT(1) +#define SW_REG_RST BIT(0) + +#define SYS_INT_EN 0x7008 +#define SYS_INT_STS 0x700c +#define MAC_PC_INT BIT(16) +#define PHY_INT(p) BIT((p) + 8) +#define PHY_LC_INT(p) BIT(p) + +#define PHY_IAC 0x701c +#define PHY_ACS_ST BIT(31) +#define MDIO_REG_ADDR_S 25 +#define MDIO_REG_ADDR_M 0x3e000000 +#define MDIO_PHY_ADDR_S 20 +#define MDIO_PHY_ADDR_M 0x1f00000 +#define MDIO_CMD_S 18 +#define MDIO_CMD_M 0xc0000 +#define MDIO_ST_S 16 +#define MDIO_ST_M 0x30000 +#define MDIO_RW_DATA_S 0 +#define MDIO_RW_DATA_M 0xffff + +/* MDIO_CMD: MDIO commands */ +#define MDIO_CMD_ADDR 0 +#define MDIO_CMD_WRITE 1 +#define MDIO_CMD_READ 2 +#define MDIO_CMD_READ_C45 3 + +/* MDIO_ST: MDIO start field */ +#define MDIO_ST_C45 0 +#define MDIO_ST_C22 1 + +#define HWSTRAP 0x7800 +#define MHWSTRAP 0x7804 + +#endif /* _MT753X_REGS_H_ */ diff --git a/target/linux/mediatek/files-4.19/drivers/net/phy/mtk/mt753x/mt753x_swconfig.c b/target/linux/mediatek/files-4.19/drivers/net/phy/mtk/mt753x/mt753x_swconfig.c new file mode 100644 index 0000000000..fb2ee1c1b7 --- /dev/null +++ b/target/linux/mediatek/files-4.19/drivers/net/phy/mtk/mt753x/mt753x_swconfig.c @@ -0,0 +1,695 @@ +/* + * OpenWrt swconfig support for MediaTek MT753x Gigabit switch + * + * Copyright (C) 2018 MediaTek Inc. All Rights Reserved. + * + * Author: Weijie Gao <weijie.gao@mediatek.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <linux/if.h> +#include <linux/list.h> +#include <linux/if_ether.h> +#include <linux/skbuff.h> +#include <linux/netdevice.h> +#include <linux/netlink.h> +#include <linux/bitops.h> +#include <net/genetlink.h> +#include <linux/delay.h> +#include <linux/phy.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/lockdep.h> +#include <linux/workqueue.h> +#include <linux/of_device.h> + +#include "mt753x.h" +#include "mt753x_swconfig.h" +#include "mt753x_regs.h" + +#define MT753X_PORT_MIB_TXB_ID 18 /* TxByte */ +#define MT753X_PORT_MIB_RXB_ID 37 /* RxByte */ + +#define MIB_DESC(_s, _o, _n) \ + { \ + .size = (_s), \ + .offset = (_o), \ + .name = (_n), \ + } + +struct mt753x_mib_desc { + unsigned int size; + unsigned int offset; + const char *name; +}; + +static const struct mt753x_mib_desc mt753x_mibs[] = { + MIB_DESC(1, STATS_TDPC, "TxDrop"), + MIB_DESC(1, STATS_TCRC, "TxCRC"), + MIB_DESC(1, STATS_TUPC, "TxUni"), + MIB_DESC(1, STATS_TMPC, "TxMulti"), + MIB_DESC(1, STATS_TBPC, "TxBroad"), + MIB_DESC(1, STATS_TCEC, "TxCollision"), + MIB_DESC(1, STATS_TSCEC, "TxSingleCol"), + MIB_DESC(1, STATS_TMCEC, "TxMultiCol"), + MIB_DESC(1, STATS_TDEC, "TxDefer"), + MIB_DESC(1, STATS_TLCEC, "TxLateCol"), + MIB_DESC(1, STATS_TXCEC, "TxExcCol"), + MIB_DESC(1, STATS_TPPC, "TxPause"), + MIB_DESC(1, STATS_TL64PC, "Tx64Byte"), + MIB_DESC(1, STATS_TL65PC, "Tx65Byte"), + MIB_DESC(1, STATS_TL128PC, "Tx128Byte"), + MIB_DESC(1, STATS_TL256PC, "Tx256Byte"), + MIB_DESC(1, STATS_TL512PC, "Tx512Byte"), + MIB_DESC(1, STATS_TL1024PC, "Tx1024Byte"), + MIB_DESC(2, STATS_TOC, "TxByte"), + MIB_DESC(1, STATS_RDPC, "RxDrop"), + MIB_DESC(1, STATS_RFPC, "RxFiltered"), + MIB_DESC(1, STATS_RUPC, "RxUni"), + MIB_DESC(1, STATS_RMPC, "RxMulti"), + MIB_DESC(1, STATS_RBPC, "RxBroad"), + MIB_DESC(1, STATS_RAEPC, "RxAlignErr"), + MIB_DESC(1, STATS_RCEPC, "RxCRC"), + MIB_DESC(1, STATS_RUSPC, "RxUnderSize"), + MIB_DESC(1, STATS_RFEPC, "RxFragment"), + MIB_DESC(1, STATS_ROSPC, "RxOverSize"), + MIB_DESC(1, STATS_RJEPC, "RxJabber"), + MIB_DESC(1, STATS_RPPC, "RxPause"), + MIB_DESC(1, STATS_RL64PC, "Rx64Byte"), + MIB_DESC(1, STATS_RL65PC, "Rx65Byte"), + MIB_DESC(1, STATS_RL128PC, "Rx128Byte"), + MIB_DESC(1, STATS_RL256PC, "Rx256Byte"), + MIB_DESC(1, STATS_RL512PC, "Rx512Byte"), + MIB_DESC(1, STATS_RL1024PC, "Rx1024Byte"), + MIB_DESC(2, STATS_ROC, "RxByte"), + MIB_DESC(1, STATS_RDPC_CTRL, "RxCtrlDrop"), + MIB_DESC(1, STATS_RDPC_ING, "RxIngDrop"), + MIB_DESC(1, STATS_RDPC_ARL, "RxARLDrop") +}; + +enum { + /* Global attributes. */ + MT753X_ATTR_ENABLE_VLAN, +}; + +struct mt753x_mapping { + char *name; + u16 pvids[MT753X_NUM_PORTS]; + u8 members[MT753X_NUM_VLANS]; + u8 etags[MT753X_NUM_VLANS]; + u16 vids[MT753X_NUM_VLANS]; +} mt753x_defaults[] = { + { + .name = "llllw", + .pvids = { 1, 1, 1, 1, 2, 2, 1 }, + .members = { 0, 0x4f, 0x30 }, + .etags = { 0, 0, 0 }, + .vids = { 0, 1, 2 }, + }, { + .name = "wllll", + .pvids = { 2, 1, 1, 1, 1, 2, 1 }, + .members = { 0, 0x5e, 0x21 }, + .etags = { 0, 0, 0 }, + .vids = { 0, 1, 2 }, + }, { + .name = "lwlll", + .pvids = { 1, 2, 1, 1, 1, 2, 1 }, + .members = { 0, 0x5d, 0x22 }, + .etags = { 0, 0, 0 }, + .vids = { 0, 1, 2 }, + }, +}; + +struct mt753x_mapping *mt753x_find_mapping(struct device_node *np) +{ + const char *map; + int i; + + if (of_property_read_string(np, "mediatek,portmap", &map)) + return NULL; + + for (i = 0; i < ARRAY_SIZE(mt753x_defaults); i++) + if (!strcmp(map, mt753x_defaults[i].name)) + return &mt753x_defaults[i]; + + return NULL; +} + +static void mt753x_apply_mapping(struct gsw_mt753x *gsw, + struct mt753x_mapping *map) +{ + int i = 0; + + for (i = 0; i < MT753X_NUM_PORTS; i++) + gsw->port_entries[i].pvid = map->pvids[i]; + + for (i = 0; i < MT753X_NUM_VLANS; i++) { + gsw->vlan_entries[i].member = map->members[i]; + gsw->vlan_entries[i].etags = map->etags[i]; + gsw->vlan_entries[i].vid = map->vids[i]; + } +} + +static int mt753x_get_vlan_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct gsw_mt753x *gsw = container_of(dev, struct gsw_mt753x, swdev); + + val->value.i = gsw->global_vlan_enable; + + return 0; +} + +static int mt753x_set_vlan_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct gsw_mt753x *gsw = container_of(dev, struct gsw_mt753x, swdev); + + gsw->global_vlan_enable = val->value.i != 0; + + return 0; +} + +static int mt753x_get_port_pvid(struct switch_dev *dev, int port, int *val) +{ + struct gsw_mt753x *gsw = container_of(dev, struct gsw_mt753x, swdev); + + if (port >= MT753X_NUM_PORTS) + return -EINVAL; + + *val = mt753x_reg_read(gsw, PPBV1(port)); + *val &= GRP_PORT_VID_M; + + return 0; +} + +static int mt753x_set_port_pvid(struct switch_dev *dev, int port, int pvid) +{ + struct gsw_mt753x *gsw = container_of(dev, struct gsw_mt753x, swdev); + + if (port >= MT753X_NUM_PORTS) + return -EINVAL; + + if (pvid < MT753X_MIN_VID || pvid > MT753X_MAX_VID) + return -EINVAL; + + gsw->port_entries[port].pvid = pvid; + + return 0; +} + +static void mt753x_vlan_ctrl(struct gsw_mt753x *gsw, u32 cmd, u32 val) +{ + int i; + + mt753x_reg_write(gsw, VTCR, + VTCR_BUSY | ((cmd << VTCR_FUNC_S) & VTCR_FUNC_M) | + (val & VTCR_VID_M)); + + for (i = 0; i < 300; i++) { + u32 val = mt753x_reg_read(gsw, VTCR); + + if ((val & VTCR_BUSY) == 0) + break; + + usleep_range(1000, 1100); + } + + if (i == 300) + dev_info(gsw->dev, "vtcr timeout\n"); +} + +static int mt753x_get_vlan_ports(struct switch_dev *dev, struct switch_val *val) +{ + struct gsw_mt753x *gsw = container_of(dev, struct gsw_mt753x, swdev); + u32 member; + u32 etags; + int i; + + val->len = 0; + + if (val->port_vlan < 0 || val->port_vlan >= MT753X_NUM_VLANS) + return -EINVAL; + + mt753x_vlan_ctrl(gsw, VTCR_READ_VLAN_ENTRY, val->port_vlan); + + member = mt753x_reg_read(gsw, VAWD1); + member &= PORT_MEM_M; + member >>= PORT_MEM_S; + + etags = mt753x_reg_read(gsw, VAWD2); + + for (i = 0; i < MT753X_NUM_PORTS; i++) { + struct switch_port *p; + int etag; + + if (!(member & BIT(i))) + continue; + + p = &val->value.ports[val->len++]; + p->id = i; + + etag = (etags >> PORT_ETAG_S(i)) & PORT_ETAG_M; + + if (etag == ETAG_CTRL_TAG) + p->flags |= BIT(SWITCH_PORT_FLAG_TAGGED); + else if (etag != ETAG_CTRL_UNTAG) + dev_info(gsw->dev, + "vlan egress tag control neither untag nor tag.\n"); + } + + return 0; +} + +static int mt753x_set_vlan_ports(struct switch_dev *dev, struct switch_val *val) +{ + struct gsw_mt753x *gsw = container_of(dev, struct gsw_mt753x, swdev); + u8 member = 0; + u8 etags = 0; + int i; + + if (val->port_vlan < 0 || val->port_vlan >= MT753X_NUM_VLANS || + val->len > MT753X_NUM_PORTS) + return -EINVAL; + + for (i = 0; i < val->len; i++) { + struct switch_port *p = &val->value.ports[i]; + + if (p->id >= MT753X_NUM_PORTS) + return -EINVAL; + + member |= BIT(p->id); + + if (p->flags & BIT(SWITCH_PORT_FLAG_TAGGED)) + etags |= BIT(p->id); + } + + gsw->vlan_entries[val->port_vlan].member = member; + gsw->vlan_entries[val->port_vlan].etags = etags; + + return 0; +} + +static int mt753x_set_vid(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct gsw_mt753x *gsw = container_of(dev, struct gsw_mt753x, swdev); + int vlan; + u16 vid; + + vlan = val->port_vlan; + vid = (u16)val->value.i; + + if (vlan < 0 || vlan >= MT753X_NUM_VLANS) + return -EINVAL; + + if (vid < MT753X_MIN_VID || vid > MT753X_MAX_VID) + return -EINVAL; + + gsw->vlan_entries[vlan].vid = vid; + return 0; +} + +static int mt753x_get_vid(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + val->value.i = val->port_vlan; + return 0; +} + +static int mt753x_get_port_link(struct switch_dev *dev, int port, + struct switch_port_link *link) +{ + struct gsw_mt753x *gsw = container_of(dev, struct gsw_mt753x, swdev); + u32 speed, pmsr; + + if (port < 0 || port >= MT753X_NUM_PORTS) + return -EINVAL; + + pmsr = mt753x_reg_read(gsw, PMSR(port)); + + link->link = pmsr & MAC_LNK_STS; + link->duplex = pmsr & MAC_DPX_STS; + speed = (pmsr & MAC_SPD_STS_M) >> MAC_SPD_STS_S; + + switch (speed) { + case MAC_SPD_10: + link->speed = SWITCH_PORT_SPEED_10; + break; + case MAC_SPD_100: + link->speed = SWITCH_PORT_SPEED_100; + break; + case MAC_SPD_1000: + link->speed = SWITCH_PORT_SPEED_1000; + break; + case MAC_SPD_2500: + /* TODO: swconfig has no support for 2500 now */ + link->speed = SWITCH_PORT_SPEED_UNKNOWN; + break; + } + + return 0; +} + +static int mt753x_set_port_link(struct switch_dev *dev, int port, + struct switch_port_link *link) +{ +#ifndef MODULE + if (port >= MT753X_NUM_PHYS) + return -EINVAL; + + return switch_generic_set_link(dev, port, link); +#else + return -ENOTSUPP; +#endif +} + +static u64 get_mib_counter(struct gsw_mt753x *gsw, int i, int port) +{ + unsigned int offset; + u64 lo, hi, hi2; + + offset = mt753x_mibs[i].offset; + + if (mt753x_mibs[i].size == 1) + return mt753x_reg_read(gsw, MIB_COUNTER_REG(port, offset)); + + do { + hi = mt753x_reg_read(gsw, MIB_COUNTER_REG(port, offset + 4)); + lo = mt753x_reg_read(gsw, MIB_COUNTER_REG(port, offset)); + hi2 = mt753x_reg_read(gsw, MIB_COUNTER_REG(port, offset + 4)); + } while (hi2 != hi); + + return (hi << 32) | lo; +} + +static int mt753x_get_port_mib(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + static char buf[4096]; + struct gsw_mt753x *gsw = container_of(dev, struct gsw_mt753x, swdev); + int i, len = 0; + + if (val->port_vlan >= MT753X_NUM_PORTS) + return -EINVAL; + + len += snprintf(buf + len, sizeof(buf) - len, + "Port %d MIB counters\n", val->port_vlan); + + for (i = 0; i < ARRAY_SIZE(mt753x_mibs); ++i) { + u64 counter; + + len += snprintf(buf + len, sizeof(buf) - len, + "%-11s: ", mt753x_mibs[i].name); + counter = get_mib_counter(gsw, i, val->port_vlan); + len += snprintf(buf + len, sizeof(buf) - len, "%llu\n", + counter); + } + + val->value.s = buf; + val->len = len; + return 0; +} + +static int mt753x_get_port_stats(struct switch_dev *dev, int port, + struct switch_port_stats *stats) +{ + struct gsw_mt753x *gsw = container_of(dev, struct gsw_mt753x, swdev); + + if (port < 0 || port >= MT753X_NUM_PORTS) + return -EINVAL; + + stats->tx_bytes = get_mib_counter(gsw, MT753X_PORT_MIB_TXB_ID, port); + stats->rx_bytes = get_mib_counter(gsw, MT753X_PORT_MIB_RXB_ID, port); + + return 0; +} + +static void mt753x_port_isolation(struct gsw_mt753x *gsw) +{ + int i; + + for (i = 0; i < MT753X_NUM_PORTS; i++) + mt753x_reg_write(gsw, PCR(i), + BIT(gsw->cpu_port) << PORT_MATRIX_S); + + mt753x_reg_write(gsw, PCR(gsw->cpu_port), PORT_MATRIX_M); + + for (i = 0; i < MT753X_NUM_PORTS; i++) + mt753x_reg_write(gsw, PVC(i), + (0x8100 << STAG_VPID_S) | + (VA_TRANSPARENT_PORT << VLAN_ATTR_S)); +} + +static void mt753x_write_vlan_entry(struct gsw_mt753x *gsw, int vlan, u16 vid, + u8 ports, u8 etags) +{ + int port; + u32 val; + + /* vlan port membership */ + if (ports) + mt753x_reg_write(gsw, VAWD1, + IVL_MAC | VTAG_EN | VENTRY_VALID | + ((ports << PORT_MEM_S) & PORT_MEM_M)); + else + mt753x_reg_write(gsw, VAWD1, 0); + + /* egress mode */ + val = 0; + for (port = 0; port < MT753X_NUM_PORTS; port++) { + if (etags & BIT(port)) + val |= ETAG_CTRL_TAG << PORT_ETAG_S(port); + else + val |= ETAG_CTRL_UNTAG << PORT_ETAG_S(port); + } + mt753x_reg_write(gsw, VAWD2, val); + + /* write to vlan table */ + mt753x_vlan_ctrl(gsw, VTCR_WRITE_VLAN_ENTRY, vid); +} + +static int mt753x_apply_config(struct switch_dev *dev) +{ + struct gsw_mt753x *gsw = container_of(dev, struct gsw_mt753x, swdev); + int i, j; + u8 tag_ports; + u8 untag_ports; + + if (!gsw->global_vlan_enable) { + mt753x_port_isolation(gsw); + return 0; + } + + /* set all ports as security mode */ + for (i = 0; i < MT753X_NUM_PORTS; i++) + mt753x_reg_write(gsw, PCR(i), + PORT_MATRIX_M | SECURITY_MODE); + + /* check if a port is used in tag/untag vlan egress mode */ + tag_ports = 0; + untag_ports = 0; + + for (i = 0; i < MT753X_NUM_VLANS; i++) { + u8 member = gsw->vlan_entries[i].member; + u8 etags = gsw->vlan_entries[i].etags; + + if (!member) + continue; + + for (j = 0; j < MT753X_NUM_PORTS; j++) { + if (!(member & BIT(j))) + continue; + + if (etags & BIT(j)) + tag_ports |= 1u << j; + else + untag_ports |= 1u << j; + } + } + + /* set all untag-only ports as transparent and the rest as user port */ + for (i = 0; i < MT753X_NUM_PORTS; i++) { + u32 pvc_mode = 0x8100 << STAG_VPID_S; + + if (untag_ports & BIT(i) && !(tag_ports & BIT(i))) + pvc_mode = (0x8100 << STAG_VPID_S) | + (VA_TRANSPARENT_PORT << VLAN_ATTR_S); + + mt753x_reg_write(gsw, PVC(i), pvc_mode); + } + + /* first clear the swtich vlan table */ + for (i = 0; i < MT753X_NUM_VLANS; i++) + mt753x_write_vlan_entry(gsw, i, i, 0, 0); + + /* now program only vlans with members to avoid + * clobbering remapped entries in later iterations + */ + for (i = 0; i < MT753X_NUM_VLANS; i++) { + u16 vid = gsw->vlan_entries[i].vid; + u8 member = gsw->vlan_entries[i].member; + u8 etags = gsw->vlan_entries[i].etags; + + if (member) + mt753x_write_vlan_entry(gsw, i, vid, member, etags); + } + + /* Port Default PVID */ + for (i = 0; i < MT753X_NUM_PORTS; i++) { + int vlan = gsw->port_entries[i].pvid; + u16 pvid = 0; + u32 val; + + if (vlan < MT753X_NUM_VLANS && gsw->vlan_entries[vlan].member) + pvid = gsw->vlan_entries[vlan].vid; + + val = mt753x_reg_read(gsw, PPBV1(i)); + val &= ~GRP_PORT_VID_M; + val |= pvid; + mt753x_reg_write(gsw, PPBV1(i), val); + } + + return 0; +} + +static int mt753x_reset_switch(struct switch_dev *dev) +{ + struct gsw_mt753x *gsw = container_of(dev, struct gsw_mt753x, swdev); + int i; + + memset(gsw->port_entries, 0, sizeof(gsw->port_entries)); + memset(gsw->vlan_entries, 0, sizeof(gsw->vlan_entries)); + + /* set default vid of each vlan to the same number of vlan, so the vid + * won't need be set explicitly. + */ + for (i = 0; i < MT753X_NUM_VLANS; i++) + gsw->vlan_entries[i].vid = i; + + return 0; +} + +static int mt753x_phy_read16(struct switch_dev *dev, int addr, u8 reg, + u16 *value) +{ + struct gsw_mt753x *gsw = container_of(dev, struct gsw_mt753x, swdev); + + *value = gsw->mii_read(gsw, addr, reg); + + return 0; +} + +static int mt753x_phy_write16(struct switch_dev *dev, int addr, u8 reg, + u16 value) +{ + struct gsw_mt753x *gsw = container_of(dev, struct gsw_mt753x, swdev); + + gsw->mii_write(gsw, addr, reg, value); + + return 0; +} + +static const struct switch_attr mt753x_global[] = { + { + .type = SWITCH_TYPE_INT, + .name = "enable_vlan", + .description = "VLAN mode (1:enabled)", + .max = 1, + .id = MT753X_ATTR_ENABLE_VLAN, + .get = mt753x_get_vlan_enable, + .set = mt753x_set_vlan_enable, + } +}; + +static const struct switch_attr mt753x_port[] = { + { + .type = SWITCH_TYPE_STRING, + .name = "mib", + .description = "Get MIB counters for port", + .get = mt753x_get_port_mib, + .set = NULL, + }, +}; + +static const struct switch_attr mt753x_vlan[] = { + { + .type = SWITCH_TYPE_INT, + .name = "vid", + .description = "VLAN ID (0-4094)", + .set = mt753x_set_vid, + .get = mt753x_get_vid, + .max = 4094, + }, +}; + +static const struct switch_dev_ops mt753x_swdev_ops = { + .attr_global = { + .attr = mt753x_global, + .n_attr = ARRAY_SIZE(mt753x_global), + }, + .attr_port = { + .attr = mt753x_port, + .n_attr = ARRAY_SIZE(mt753x_port), + }, + .attr_vlan = { + .attr = mt753x_vlan, + .n_attr = ARRAY_SIZE(mt753x_vlan), + }, + .get_vlan_ports = mt753x_get_vlan_ports, + .set_vlan_ports = mt753x_set_vlan_ports, + .get_port_pvid = mt753x_get_port_pvid, + .set_port_pvid = mt753x_set_port_pvid, + .get_port_link = mt753x_get_port_link, + .set_port_link = mt753x_set_port_link, + .get_port_stats = mt753x_get_port_stats, + .apply_config = mt753x_apply_config, + .reset_switch = mt753x_reset_switch, + .phy_read16 = mt753x_phy_read16, + .phy_write16 = mt753x_phy_write16, +}; + +int mt753x_swconfig_init(struct gsw_mt753x *gsw) +{ + struct device_node *np = gsw->dev->of_node; + struct switch_dev *swdev; + struct mt753x_mapping *map; + int ret; + + if (of_property_read_u32(np, "mediatek,cpuport", &gsw->cpu_port)) + gsw->cpu_port = MT753X_DFL_CPU_PORT; + + swdev = &gsw->swdev; + + swdev->name = gsw->name; + swdev->alias = gsw->name; + swdev->cpu_port = gsw->cpu_port; + swdev->ports = MT753X_NUM_PORTS; + swdev->vlans = MT753X_NUM_VLANS; + swdev->ops = &mt753x_swdev_ops; + + ret = register_switch(swdev, NULL); + if (ret) { + dev_err(gsw->dev, "Failed to register switch %s\n", + swdev->name); + return ret; + } + + map = mt753x_find_mapping(gsw->dev->of_node); + if (map) + mt753x_apply_mapping(gsw, map); + mt753x_apply_config(swdev); + + return 0; +} + +void mt753x_swconfig_destroy(struct gsw_mt753x *gsw) +{ + unregister_switch(&gsw->swdev); +} diff --git a/target/linux/mediatek/files-4.19/drivers/net/phy/mtk/mt753x/mt753x_swconfig.h b/target/linux/mediatek/files-4.19/drivers/net/phy/mtk/mt753x/mt753x_swconfig.h new file mode 100644 index 0000000000..971a2cc90a --- /dev/null +++ b/target/linux/mediatek/files-4.19/drivers/net/phy/mtk/mt753x/mt753x_swconfig.h @@ -0,0 +1,19 @@ +/* + * OpenWrt swconfig support for MediaTek MT753x Gigabit switch + * + * Copyright (C) 2018 MediaTek Inc. All Rights Reserved. + * + * Author: Weijie Gao <weijie.gao@mediatek.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _MT753X_SWCONFIG_H_ +#define _MT753X_SWCONFIG_H_ + +#include <linux/switch.h> + +int mt753x_swconfig_init(struct gsw_mt753x *gsw); +void mt753x_swconfig_destroy(struct gsw_mt753x *gsw); + +#endif /* _MT753X_SWCONFIG_H_ */ diff --git a/target/linux/mediatek/image/mt7622.mk b/target/linux/mediatek/image/mt7622.mk index 86b25ce33c..1644a3ea68 100644 --- a/target/linux/mediatek/image/mt7622.mk +++ b/target/linux/mediatek/image/mt7622.mk @@ -1,9 +1,26 @@ define Device/MTK-RFB1 - DEVICE_TITLE := MTK7622 rfb1 AP + DEVICE_TITLE := MTK7622 rfb1 AP DEVICE_DTS := mt7622-rfb1 DEVICE_DTS_DIR := $(DTS_DIR)/mediatek - SUPPORTED_DEVICES := mt7622 DEVICE_PACKAGES := kmod-usb-core kmod-usb-ohci kmod-usb2 kmod-usb3 \ - kmod-ata-core kmod-ata-ahci-mtk + kmod-ata-core kmod-ata-ahci-mtk endef TARGET_DEVICES += MTK-RFB1 + +define Device/MTK-LYNX-RFB1 + DEVICE_TITLE := MTK7622 Lynx rfb1 AP + DEVICE_DTS := mt7622-lynx-rfb1 + DEVICE_DTS_DIR := $(DTS_DIR)/mediatek + DEVICE_PACKAGES := kmod-usb-core kmod-usb-ohci kmod-usb2 kmod-usb3 \ + kmod-ata-core kmod-ata-ahci-mtk +endef +TARGET_DEVICES += MTK-LYNX-RFB1 + +define Device/BPI-R64 + DEVICE_TITLE := Bannan Pi R64 + DEVICE_DTS := mt7622-bananapi-bpi-r64 + DEVICE_DTS_DIR := $(DTS_DIR)/mediatek + DEVICE_PACKAGES := kmod-usb-core kmod-usb-ohci kmod-usb2 kmod-usb3 \ + kmod-ata-core kmod-ata-ahci-mtk +endef +TARGET_DEVICES += BPI-R64 diff --git a/target/linux/mediatek/mt7622/config-4.19 b/target/linux/mediatek/mt7622/config-4.19 new file mode 100755 index 0000000000..5e3ceb3574 --- /dev/null +++ b/target/linux/mediatek/mt7622/config-4.19 @@ -0,0 +1,596 @@ +CONFIG_64BIT=y +CONFIG_AHCI_MTK=y +# CONFIG_ANDROID_DEFAULT_SETTING is not set +CONFIG_ARCH_CLOCKSOURCE_DATA=y +CONFIG_ARCH_DMA_ADDR_T_64BIT=y +CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y +CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y +CONFIG_ARCH_HAS_ELF_RANDOMIZE=y +CONFIG_ARCH_HAS_FAST_MULTIPLIER=y +CONFIG_ARCH_HAS_FORTIFY_SOURCE=y +CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y +CONFIG_ARCH_HAS_HOLES_MEMORYMODEL=y +CONFIG_ARCH_HAS_KCOV=y +CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y +CONFIG_ARCH_HAS_PTE_SPECIAL=y +CONFIG_ARCH_HAS_SET_MEMORY=y +CONFIG_ARCH_HAS_SG_CHAIN=y +CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y +CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y +CONFIG_ARCH_HAS_SYSCALL_WRAPPER=y +CONFIG_ARCH_HAS_TICK_BROADCAST=y +CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y +CONFIG_ARCH_INLINE_READ_LOCK=y +CONFIG_ARCH_INLINE_READ_LOCK_BH=y +CONFIG_ARCH_INLINE_READ_LOCK_IRQ=y +CONFIG_ARCH_INLINE_READ_LOCK_IRQSAVE=y +CONFIG_ARCH_INLINE_READ_UNLOCK=y +CONFIG_ARCH_INLINE_READ_UNLOCK_BH=y +CONFIG_ARCH_INLINE_READ_UNLOCK_IRQ=y +CONFIG_ARCH_INLINE_READ_UNLOCK_IRQRESTORE=y +CONFIG_ARCH_INLINE_SPIN_LOCK=y +CONFIG_ARCH_INLINE_SPIN_LOCK_BH=y +CONFIG_ARCH_INLINE_SPIN_LOCK_IRQ=y +CONFIG_ARCH_INLINE_SPIN_LOCK_IRQSAVE=y +CONFIG_ARCH_INLINE_SPIN_TRYLOCK=y +CONFIG_ARCH_INLINE_SPIN_TRYLOCK_BH=y +CONFIG_ARCH_INLINE_SPIN_UNLOCK=y +CONFIG_ARCH_INLINE_SPIN_UNLOCK_BH=y +CONFIG_ARCH_INLINE_SPIN_UNLOCK_IRQ=y +CONFIG_ARCH_INLINE_SPIN_UNLOCK_IRQRESTORE=y +CONFIG_ARCH_INLINE_WRITE_LOCK=y +CONFIG_ARCH_INLINE_WRITE_LOCK_BH=y +CONFIG_ARCH_INLINE_WRITE_LOCK_IRQ=y +CONFIG_ARCH_INLINE_WRITE_LOCK_IRQSAVE=y +CONFIG_ARCH_INLINE_WRITE_UNLOCK=y +CONFIG_ARCH_INLINE_WRITE_UNLOCK_BH=y +CONFIG_ARCH_INLINE_WRITE_UNLOCK_IRQ=y +CONFIG_ARCH_INLINE_WRITE_UNLOCK_IRQRESTORE=y +CONFIG_ARCH_MEDIATEK=y +CONFIG_ARCH_MMAP_RND_BITS=18 +CONFIG_ARCH_MMAP_RND_BITS_MAX=24 +CONFIG_ARCH_MMAP_RND_BITS_MIN=18 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS=11 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=11 +CONFIG_ARCH_PROC_KCORE_TEXT=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_ARCH_SPARSEMEM_DEFAULT=y +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y +CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y +CONFIG_ARCH_SUPPORTS_INT128=y +CONFIG_ARCH_SUPPORTS_LTO_CLANG=y +CONFIG_ARCH_SUPPORTS_MEMORY_FAILURE=y +CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y +CONFIG_ARCH_SUPPORTS_UPROBES=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y +CONFIG_ARCH_USE_QUEUED_RWLOCKS=y +CONFIG_ARCH_USE_QUEUED_SPINLOCKS=y +CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION=y +CONFIG_ARCH_WANT_FRAME_POINTERS=y +CONFIG_ARCH_WANT_HUGE_PMD_SHARE=y +CONFIG_ARM64=y +# CONFIG_ARM64_16K_PAGES is not set +CONFIG_ARM64_4K_PAGES=y +# CONFIG_ARM64_64K_PAGES is not set +CONFIG_ARM64_CONT_SHIFT=4 +# CONFIG_ARM64_CRYPTO is not set +# CONFIG_ARM64_ERRATUM_1463225 is not set +CONFIG_ARM64_HW_AFDBM=y +# CONFIG_ARM64_LSE_ATOMICS is not set +CONFIG_ARM64_PAGE_SHIFT=12 +CONFIG_ARM64_PAN=y +CONFIG_ARM64_PA_BITS=48 +CONFIG_ARM64_PA_BITS_48=y +# CONFIG_ARM64_PMEM is not set +# CONFIG_ARM64_PTDUMP_DEBUGFS is not set +# CONFIG_ARM64_RANDOMIZE_TEXT_OFFSET is not set +CONFIG_ARM64_SSBD=y +CONFIG_ARM64_SVE=y +# CONFIG_ARM64_SW_TTBR0_PAN is not set +CONFIG_ARM64_UAO=y +CONFIG_ARM64_VA_BITS=39 +CONFIG_ARM64_VA_BITS_39=y +# CONFIG_ARM64_VA_BITS_48 is not set +CONFIG_ARM64_VHE=y +# CONFIG_ARMV8_DEPRECATED is not set +CONFIG_ARM_AMBA=y +CONFIG_ARM_ARCH_TIMER=y +CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y +CONFIG_ARM_GIC=y +CONFIG_ARM_GIC_V2M=y +CONFIG_ARM_GIC_V3=y +CONFIG_ARM_GIC_V3_ITS=y +CONFIG_ARM_GIC_V3_ITS_PCI=y +CONFIG_ARM_MEDIATEK_CPUFREQ=y +CONFIG_ARM_PMU=y +CONFIG_ARM_PSCI_FW=y +# CONFIG_ARM_SP805_WATCHDOG is not set +CONFIG_ATA=y +CONFIG_AUDIT_ARCH_COMPAT_GENERIC=y +CONFIG_BLK_DEV_SD=y +CONFIG_BLK_MQ_PCI=y +CONFIG_BLK_SCSI_REQUEST=y +CONFIG_BLOCK_COMPAT=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_BSD_PROCESS_ACCT_V3=y +CONFIG_BT=y +CONFIG_BT_BCM=y +CONFIG_BT_BREDR=y +CONFIG_BT_DEBUGFS=y +CONFIG_BT_HCIUART=y +CONFIG_BT_HCIUART_BCM=y +# CONFIG_BT_HCIUART_INTEL is not set +# CONFIG_BT_HCIUART_NOKIA is not set +CONFIG_BT_HCIUART_QCA=y +CONFIG_BT_HCIUART_SERDEV=y +CONFIG_BT_HCIVHCI=y +CONFIG_BT_HS=y +CONFIG_BT_LE=y +CONFIG_BT_MTKUART=y +CONFIG_BT_QCA=y +CONFIG_BUILD_BIN2C=y +CONFIG_CC_HAS_ASM_GOTO=y +CONFIG_CLKDEV_LOOKUP=y +CONFIG_CLKSRC_MMIO=y +CONFIG_CLOCK_THERMAL=y +CONFIG_CLONE_BACKWARDS=y +CONFIG_COMMON_CLK=y +CONFIG_COMMON_CLK_MEDIATEK=y +CONFIG_COMMON_CLK_MT2712=y +# CONFIG_COMMON_CLK_MT2712_BDPSYS is not set +# CONFIG_COMMON_CLK_MT2712_IMGSYS is not set +# CONFIG_COMMON_CLK_MT2712_JPGDECSYS is not set +# CONFIG_COMMON_CLK_MT2712_MFGCFG is not set +# CONFIG_COMMON_CLK_MT2712_MMSYS is not set +# CONFIG_COMMON_CLK_MT2712_VDECSYS is not set +# CONFIG_COMMON_CLK_MT2712_VENCSYS is not set +# CONFIG_COMMON_CLK_MT6779 is not set +# CONFIG_COMMON_CLK_MT6797 is not set +CONFIG_COMMON_CLK_MT7622=y +CONFIG_COMMON_CLK_MT7622_AUDSYS=y +CONFIG_COMMON_CLK_MT7622_ETHSYS=y +CONFIG_COMMON_CLK_MT7622_HIFSYS=y +# CONFIG_COMMON_CLK_MT8173 is not set +CONFIG_COMPAT=y +CONFIG_COMPAT_32BIT_TIME=y +CONFIG_COMPAT_BINFMT_ELF=y +CONFIG_COMPAT_NETLINK_MESSAGES=y +CONFIG_COMPAT_OLD_SIGACTION=y +CONFIG_CONSOLE_LOGLEVEL_DEFAULT=15 +# CONFIG_CPUFREQ_DT is not set +# CONFIG_CPU_BIG_ENDIAN is not set +CONFIG_CPU_FREQ=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_ATTR_SET=y +CONFIG_CPU_FREQ_GOV_COMMON=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_STAT=y +# CONFIG_CPU_FREQ_TIMES is not set +CONFIG_CPU_RMAP=y +CONFIG_CPU_THERMAL=y +CONFIG_CRC16=y +# CONFIG_CRYPTO_ADIANTUM is not set +CONFIG_CRYPTO_AEAD=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_CMAC=y +CONFIG_CRYPTO_DRBG=y +CONFIG_CRYPTO_DRBG_HMAC=y +CONFIG_CRYPTO_DRBG_MENU=y +CONFIG_CRYPTO_ECB=y +CONFIG_CRYPTO_ECDH=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_JITTERENTROPY=y +CONFIG_CRYPTO_KPP=y +CONFIG_CRYPTO_KPP2=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +CONFIG_CRYPTO_NULL2=y +CONFIG_CRYPTO_RNG=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_RNG_DEFAULT=y +CONFIG_CRYPTO_SHA256=y +CONFIG_CRYPTO_WORKQUEUE=y +CONFIG_CUSTOM_KERNEL_LCM="" +CONFIG_CUSTOM_LCM_X="0" +CONFIG_CUSTOM_LCM_Y="0" +CONFIG_DCACHE_WORD_ACCESS=y +CONFIG_DEFAULT_IOSCHED="noop" +CONFIG_DEFAULT_NOOP=y +# CONFIG_DEVAPC_ARCH_V1 is not set +# CONFIG_DEVAPC_MT6779 is not set +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_DMADEVICES=y +CONFIG_DMATEST=y +CONFIG_DMA_DIRECT_OPS=y +CONFIG_DMA_ENGINE=y +CONFIG_DMA_ENGINE_RAID=y +CONFIG_DMA_OF=y +CONFIG_DMA_VIRTUAL_CHANNELS=y +CONFIG_DTC=y +CONFIG_DYNAMIC_DEBUG=y +CONFIG_EDAC_SUPPORT=y +CONFIG_EINT_MTK=y +# CONFIG_ENERGY_MODEL is not set +CONFIG_FIXED_PHY=y +CONFIG_FIX_EARLYCON_MEM=y +# CONFIG_FLATMEM_MANUAL is not set +CONFIG_FRAME_POINTER=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_GENERIC_ARCH_TOPOLOGY=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_GENERIC_CPU_AUTOPROBE=y +CONFIG_GENERIC_CSUM=y +CONFIG_GENERIC_EARLY_IOREMAP=y +CONFIG_GENERIC_IDLE_POLL_SETUP=y +CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y +CONFIG_GENERIC_IRQ_MULTI_HANDLER=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_GENERIC_IRQ_SHOW_LEVEL=y +CONFIG_GENERIC_MSI_IRQ=y +CONFIG_GENERIC_MSI_IRQ_DOMAIN=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_PHY=y +CONFIG_GENERIC_PINCONF=y +CONFIG_GENERIC_PINCTRL_GROUPS=y +CONFIG_GENERIC_PINMUX_FUNCTIONS=y +CONFIG_GENERIC_SCHED_CLOCK=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GLOB=y +CONFIG_GPIOLIB=y +# CONFIG_GPS is not set +CONFIG_HANDLE_DOMAIN_IRQ=y +CONFIG_HARDEN_BRANCH_PREDICTOR=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_HAS_DMA=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT_MAP=y +CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y +CONFIG_HAVE_ARCH_AUDITSYSCALL=y +CONFIG_HAVE_ARCH_BITREVERSE=y +CONFIG_HAVE_ARCH_HUGE_VMAP=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y +CONFIG_HAVE_ARCH_KASAN=y +CONFIG_HAVE_ARCH_KGDB=y +CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS=y +CONFIG_HAVE_ARCH_PFN_VALID=y +CONFIG_HAVE_ARCH_PREL32_RELOCATIONS=y +CONFIG_HAVE_ARCH_SECCOMP_FILTER=y +CONFIG_HAVE_ARCH_THREAD_STRUCT_WHITELIST=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y +CONFIG_HAVE_ARCH_VMAP_STACK=y +CONFIG_HAVE_ARM_SMCCC=y +CONFIG_HAVE_CLK=y +CONFIG_HAVE_CLK_PREPARE=y +CONFIG_HAVE_CMPXCHG_DOUBLE=y +CONFIG_HAVE_CMPXCHG_LOCAL=y +CONFIG_HAVE_CONTEXT_TRACKING=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_HAVE_DEBUG_BUGVERBOSE=y +CONFIG_HAVE_DEBUG_KMEMLEAK=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_EBPF_JIT=y +CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_HAVE_GENERIC_GUP=y +CONFIG_HAVE_HW_BREAKPOINT=y +CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y +CONFIG_HAVE_MEMBLOCK=y +CONFIG_HAVE_MEMORY_PRESENT=y +CONFIG_HAVE_NET_DSA=y +CONFIG_HAVE_PATA_PLATFORM=y +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_HAVE_PERF_REGS=y +CONFIG_HAVE_PERF_USER_STACK_DUMP=y +CONFIG_HAVE_RCU_TABLE_FREE=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_RSEQ=y +CONFIG_HAVE_SCHED_AVG_IRQ=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_UID16=y +CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y +CONFIG_HOLES_IN_ZONE=y +# CONFIG_HUGETLBFS is not set +CONFIG_ICPLUS_PHY=y +CONFIG_IIO=y +# CONFIG_IIO_BUFFER is not set +# CONFIG_IIO_TRIGGER is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000 +CONFIG_INITRAMFS_SOURCE="" +CONFIG_INLINE_READ_LOCK=y +CONFIG_INLINE_READ_LOCK_BH=y +CONFIG_INLINE_READ_LOCK_IRQ=y +CONFIG_INLINE_READ_LOCK_IRQSAVE=y +CONFIG_INLINE_READ_UNLOCK_BH=y +CONFIG_INLINE_READ_UNLOCK_IRQRESTORE=y +CONFIG_INLINE_SPIN_LOCK=y +CONFIG_INLINE_SPIN_LOCK_BH=y +CONFIG_INLINE_SPIN_LOCK_IRQ=y +CONFIG_INLINE_SPIN_LOCK_IRQSAVE=y +CONFIG_INLINE_SPIN_TRYLOCK=y +CONFIG_INLINE_SPIN_TRYLOCK_BH=y +CONFIG_INLINE_SPIN_UNLOCK_BH=y +CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE=y +CONFIG_INLINE_WRITE_LOCK=y +CONFIG_INLINE_WRITE_LOCK_BH=y +CONFIG_INLINE_WRITE_LOCK_IRQ=y +CONFIG_INLINE_WRITE_LOCK_IRQSAVE=y +CONFIG_INLINE_WRITE_UNLOCK_BH=y +CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE=y +# CONFIG_INTERCONNECT is not set +# CONFIG_IOSCHED_DEADLINE is not set +CONFIG_IRQCHIP=y +CONFIG_IRQ_DOMAIN=y +CONFIG_IRQ_DOMAIN_HIERARCHY=y +CONFIG_IRQ_FORCED_THREADING=y +CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_IRQ_WORK=y +CONFIG_JUMP_LABEL=y +CONFIG_LCM_HEIGHT="1920" +CONFIG_LCM_WIDTH="1080" +# CONFIG_LEGACY_ENERGY_MODEL_DT is not set +CONFIG_LIBFDT=y +CONFIG_LOCK_DEBUGGING_SUPPORT=y +CONFIG_LOCK_SPIN_ON_OWNER=y +CONFIG_LTO_NONE=y +CONFIG_MAGIC_SYSRQ=y +# CONFIG_MARVELL_88Q_PHY is not set +CONFIG_MDIO_BUS=y +CONFIG_MDIO_DEVICE=y +CONFIG_MEDIATEK_MT6577_AUXADC=y +CONFIG_MEDIATEK_WATCHDOG=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEMFD_CREATE=y +CONFIG_MESSAGE_LOGLEVEL_DEFAULT=7 +CONFIG_MFD_SYSCON=y +CONFIG_MIGRATION=y +CONFIG_MMC=y +CONFIG_MMC_MTK=y +# CONFIG_MMC_TIFM_SD is not set +# CONFIG_MMPROFILE is not set +CONFIG_MODULES_TREE_LOOKUP=y +CONFIG_MODULES_USE_ELF_RELA=y +CONFIG_MT753X_GSW=y +# CONFIG_MTD_GPT_PARTS is not set +CONFIG_MTD_NAND=y +CONFIG_MTD_NAND_CORE=y +CONFIG_MTD_NAND_ECC=y +CONFIG_MTD_NAND_MTK=y +CONFIG_MTD_SPI_NAND=y +CONFIG_MTD_SPI_NOR=y +CONFIG_MTD_SPLIT_FIRMWARE=y +CONFIG_MTD_SPLIT_FIRMWARE_NAME="Kernel" +CONFIG_MTD_SPLIT_FIT_FW=y +CONFIG_MTD_SPLIT_UIMAGE_FW=y +# CONFIG_MTK_AAL_SUPPORT is not set +# CONFIG_MTK_ANDROID_DEFAULT_SETTING is not set +# CONFIG_MTK_ATF_LOGGER is not set +# CONFIG_MTK_BTIF is not set +# CONFIG_MTK_CMDQ is not set +# CONFIG_MTK_COMBO is not set +# CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH is not set +# CONFIG_MTK_CONN_LTE_IDC_SUPPORT is not set +# CONFIG_MTK_CONN_MT3337_CHIP_SUPPORT is not set +# CONFIG_MTK_CONSUMER_PARTIAL_UPDATE_SUPPORT is not set +# CONFIG_MTK_DEVAPC is not set +# CONFIG_MTK_DHCPV6C_WIFI is not set +# CONFIG_MTK_DISPLAY_LOW_MEMORY_DEBUG_SUPPORT is not set +CONFIG_MTK_DISP_PLATFORM="" +# CONFIG_MTK_DRE30_SUPPORT is not set +# CONFIG_MTK_DVFSRC is not set +# CONFIG_MTK_EFUSE is not set +# CONFIG_MTK_GED_SUPPORT is not set +# CONFIG_MTK_GPS_SUPPORT is not set +# CONFIG_MTK_GPU_COMMON_DVFS_SUPPORT is not set +# CONFIG_MTK_GPU_SUPPORT is not set +CONFIG_MTK_GPU_VERSION="" +CONFIG_MTK_HSDMA=y +CONFIG_MTK_ICE_DEBUG=y +CONFIG_MTK_INFRACFG=y +# CONFIG_MTK_LCM is not set +# CONFIG_MTK_LCM_DEVICE_TREE_SUPPORT is not set +CONFIG_MTK_LCM_PHYSICAL_ROTATION="" +# CONFIG_MTK_MERGE_INTERFACE_SUPPORT is not set +# CONFIG_MTK_MET_CORE is not set +# CONFIG_MTK_MET_MEM_ALLOC is not set +# CONFIG_MTK_MMDVFS is not set +# CONFIG_MTK_MMPROFILE_SUPPORT is not set +# CONFIG_MTK_OD_SUPPORT is not set +# CONFIG_MTK_OVERLAY_ENGINE_SUPPORT is not set +CONFIG_MTK_PMIC_WRAP=y +CONFIG_MTK_PQ_COLOR_MODE="DISP" +# CONFIG_MTK_REBOOT_MODE is not set +# CONFIG_MTK_ROUND_CORNER_SUPPORT is not set +# CONFIG_MTK_SCHED_INTEROP is not set +CONFIG_MTK_SCPSYS=y +# CONFIG_MTK_SCPSYS_BRINGUP is not set +# CONFIG_MTK_SPMTWAM is not set +CONFIG_MTK_THERMAL=y +CONFIG_MTK_TIMER=y +# CONFIG_MTK_TINYSYS_SSPM_PLT_SUPPORT is not set +# CONFIG_MTK_TINYSYS_SSPM_SUPPORT is not set +# CONFIG_MTK_VIDEOX is not set +# CONFIG_MTPROF is not set +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_NEED_SG_DMA_LENGTH=y +CONFIG_NET_FLOW_LIMIT=y +CONFIG_NET_MEDIATEK_SOC=y +CONFIG_NET_VENDOR_MEDIATEK=y +CONFIG_NLS=y +CONFIG_NO_BOOTMEM=y +CONFIG_NO_HZ_COMMON=y +CONFIG_NO_HZ_IDLE=y +CONFIG_NR_CPUS=2 +# CONFIG_NUMA is not set +CONFIG_NVMEM=y +# CONFIG_NXP_TJA1100_PHY is not set +CONFIG_OF=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_EARLY_FLATTREE=y +CONFIG_OF_FLATTREE=y +CONFIG_OF_GPIO=y +CONFIG_OF_IRQ=y +CONFIG_OF_KOBJ=y +CONFIG_OF_MDIO=y +CONFIG_OF_NET=y +CONFIG_OF_RESERVED_MEM=y +CONFIG_OLD_SIGSUSPEND3=y +CONFIG_PADATA=y +CONFIG_PARTITION_PERCPU=y +CONFIG_PCI=y +CONFIG_PCIE_MEDIATEK=y +CONFIG_PCI_DEBUG=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCI_DOMAINS_GENERIC=y +CONFIG_PCI_MSI=y +CONFIG_PCI_MSI_IRQ_DOMAIN=y +CONFIG_PERF_EVENTS=y +CONFIG_PGTABLE_LEVELS=3 +CONFIG_PHYLIB=y +CONFIG_PHYS_ADDR_T_64BIT=y +CONFIG_PHY_MTK_TPHY=y +# CONFIG_PHY_MTK_UFS is not set +# CONFIG_PHY_MTK_XSPHY is not set +CONFIG_PINCTRL=y +# CONFIG_PINCTRL_MT2712 is not set +# CONFIG_PINCTRL_MT6765 is not set +# CONFIG_PINCTRL_MT6779 is not set +# CONFIG_PINCTRL_MT6797 is not set +CONFIG_PINCTRL_MT7622=y +# CONFIG_PINCTRL_MT8173 is not set +# CONFIG_PINCTRL_MT8183 is not set +CONFIG_PINCTRL_MTK_MOORE=y +CONFIG_PM=y +CONFIG_PM_CLK=y +# CONFIG_PM_DEBUG is not set +CONFIG_PM_GENERIC_DOMAINS=y +CONFIG_PM_GENERIC_DOMAINS_OF=y +CONFIG_PM_OPP=y +CONFIG_POWER_RESET=y +CONFIG_POWER_RESET_SYSCON=y +CONFIG_POWER_SUPPLY=y +CONFIG_PRINTK_TIME=y +# CONFIG_PROC_UID is not set +# CONFIG_PSI is not set +CONFIG_PWM=y +CONFIG_PWM_MEDIATEK=y +# CONFIG_PWM_MTK_DISP is not set +CONFIG_PWM_SYSFS=y +CONFIG_QUEUED_RWLOCKS=y +CONFIG_QUEUED_SPINLOCKS=y +# CONFIG_RANDOMIZE_BASE is not set +CONFIG_RAS=y +CONFIG_RATIONAL=y +# CONFIG_RAVE_SP_CORE is not set +CONFIG_RCU_NEED_SEGCBLIST=y +CONFIG_RCU_STALL_COMMON=y +CONFIG_REALTEK_PHY=y +CONFIG_REFCOUNT_FULL=y +CONFIG_REGMAP=y +CONFIG_REGMAP_MMIO=y +CONFIG_REGMAP_SPI=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_MT6380=y +CONFIG_RESET_CONTROLLER=y +CONFIG_RFS_ACCEL=y +CONFIG_RPS=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_MT7622=y +CONFIG_RTC_I2C_AND_SPI=y +CONFIG_RTL8367S_GSW=y +CONFIG_RWSEM_SPIN_ON_OWNER=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_SCHED_MC=y +# CONFIG_SCHED_TUNE is not set +CONFIG_SCSI=y +# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set +# CONFIG_SECURITY_PERF_EVENTS_RESTRICT is not set +CONFIG_SERIAL_8250_FSL=y +CONFIG_SERIAL_8250_MT6577=y +CONFIG_SERIAL_8250_NR_UARTS=3 +CONFIG_SERIAL_8250_RUNTIME_UARTS=3 +# CONFIG_SERIAL_AMBA_PL011 is not set +CONFIG_SERIAL_DEV_BUS=y +CONFIG_SERIAL_DEV_CTRL_TTYPORT=y +CONFIG_SERIAL_OF_PLATFORM=y +CONFIG_SG_POOL=y +# CONFIG_SINGLE_PANEL_OUTPUT is not set +CONFIG_SMP=y +CONFIG_SPARSEMEM=y +CONFIG_SPARSEMEM_EXTREME=y +CONFIG_SPARSEMEM_MANUAL=y +CONFIG_SPARSEMEM_VMEMMAP=y +CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y +CONFIG_SPARSE_IRQ=y +CONFIG_SPI=y +CONFIG_SPI_MASTER=y +CONFIG_SPI_MEM=y +CONFIG_SPI_MT65XX=y +# CONFIG_SPI_MTK_QUADSPI is not set +CONFIG_SPI_MTK_SNFI=y +CONFIG_SRCU=y +CONFIG_SWIOTLB=y +CONFIG_SWPHY=y +CONFIG_SYSCTL_EXCEPTION_TRACE=y +CONFIG_SYSVIPC_COMPAT=y +CONFIG_SYS_SUPPORTS_HUGETLBFS=y +CONFIG_THERMAL=y +CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y +CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0 +CONFIG_THERMAL_EMULATION=y +CONFIG_THERMAL_GOV_BANG_BANG=y +CONFIG_THERMAL_GOV_FAIR_SHARE=y +CONFIG_THERMAL_GOV_POWER_ALLOCATOR=y +CONFIG_THERMAL_GOV_STEP_WISE=y +CONFIG_THERMAL_GOV_USER_SPACE=y +CONFIG_THERMAL_OF=y +CONFIG_THERMAL_WRITABLE_TRIPS=y +CONFIG_THREAD_INFO_IN_TASK=y +CONFIG_TICK_CPU_ACCOUNTING=y +CONFIG_TIMER_OF=y +CONFIG_TIMER_PROBE=y +CONFIG_TREE_RCU=y +CONFIG_TREE_SRCU=y +# CONFIG_UNMAP_KERNEL_AT_EL0 is not set +CONFIG_USB=y +CONFIG_USB_COMMON=y +# CONFIG_USB_EHCI_HCD is not set +CONFIG_USB_SUPPORT=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_XHCI_MTK=y +# CONFIG_USB_XHCI_PLATFORM is not set +CONFIG_VMAP_STACK=y +CONFIG_WATCHDOG_CORE=y +# CONFIG_WATCHDOG_PRETIMEOUT_DEFAULT_GOV_NOOP is not set +CONFIG_WATCHDOG_PRETIMEOUT_DEFAULT_GOV_PANIC=y +CONFIG_WATCHDOG_PRETIMEOUT_GOV=y +# CONFIG_WATCHDOG_PRETIMEOUT_GOV_NOOP is not set +CONFIG_WATCHDOG_PRETIMEOUT_GOV_PANIC=y +CONFIG_WATCHDOG_SYSFS=y +CONFIG_XPS=y +CONFIG_ZONE_DMA32=y diff --git a/target/linux/mediatek/patches-4.19/0001-arm-dts-mediatek-add-basic-support-for-MT7629-SoC.patch b/target/linux/mediatek/patches-4.19/0001-arm-dts-mediatek-add-basic-support-for-MT7629-SoC.patch new file mode 100755 index 0000000000..904f44402a --- /dev/null +++ b/target/linux/mediatek/patches-4.19/0001-arm-dts-mediatek-add-basic-support-for-MT7629-SoC.patch @@ -0,0 +1,94 @@ +From acb69c6600c3df52f0b3610801f3fd44c4392333 Mon Sep 17 00:00:00 2001 +Message-Id: <acb69c6600c3df52f0b3610801f3fd44c4392333.1559210220.git.ryder.lee@mediatek.com> +From: Ryder Lee <ryder.lee@mediatek.com> +Date: Wed, 13 Mar 2019 16:42:15 +0800 +Subject: [PATCH] arm: dts: mediatek: add basic support for MT7629 SoC + +This adds basic support for MT7629 reference board. + +Signed-off-by: Ryder Lee <ryder.lee@mediatek.com> +--- + include/dt-bindings/reset/mt7629-resets.h | 71 ++++ + 4 files changed, 704 insertions(+) + create mode 100644 include/dt-bindings/reset/mt7629-resets.h + +diff --git a/include/dt-bindings/reset/mt7629-resets.h b/include/dt-bindings/reset/mt7629-resets.h +new file mode 100644 +index 000000000000..6bb85734f68d +--- /dev/null ++++ b/include/dt-bindings/reset/mt7629-resets.h +@@ -0,0 +1,71 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2019 MediaTek Inc. ++ */ ++ ++#ifndef _DT_BINDINGS_RESET_CONTROLLER_MT7629 ++#define _DT_BINDINGS_RESET_CONTROLLER_MT7629 ++ ++/* INFRACFG resets */ ++#define MT7629_INFRA_EMI_MPU_RST 0 ++#define MT7629_INFRA_UART5_RST 2 ++#define MT7629_INFRA_CIRQ_EINT_RST 3 ++#define MT7629_INFRA_APXGPT_RST 4 ++#define MT7629_INFRA_SCPSYS_RST 5 ++#define MT7629_INFRA_KP_RST 6 ++#define MT7629_INFRA_SPI1_RST 7 ++#define MT7629_INFRA_SPI4_RST 8 ++#define MT7629_INFRA_SYSTIMER_RST 9 ++#define MT7629_INFRA_IRRX_RST 10 ++#define MT7629_INFRA_AO_BUS_RST 16 ++#define MT7629_INFRA_EMI_RST 32 ++#define MT7629_INFRA_APMIXED_RST 35 ++#define MT7629_INFRA_MIPI_RST 36 ++#define MT7629_INFRA_TRNG_RST 37 ++#define MT7629_INFRA_SYSCIRQ_RST 38 ++#define MT7629_INFRA_MIPI_CSI_RST 39 ++#define MT7629_INFRA_GCE_FAXI_RST 40 ++#define MT7629_INFRA_I2C_SRAM_RST 41 ++#define MT7629_INFRA_IOMMU_RST 47 ++ ++/* PERICFG resets */ ++#define MT7629_PERI_UART0_SW_RST 0 ++#define MT7629_PERI_UART1_SW_RST 1 ++#define MT7629_PERI_UART2_SW_RST 2 ++#define MT7629_PERI_BTIF_SW_RST 6 ++#define MT7629_PERI_PWN_SW_RST 8 ++#define MT7629_PERI_DMA_SW_RST 11 ++#define MT7629_PERI_NFI_SW_RST 14 ++#define MT7629_PERI_I2C0_SW_RST 22 ++#define MT7629_PERI_SPI0_SW_RST 33 ++#define MT7629_PERI_SPI1_SW_RST 34 ++#define MT7629_PERI_FLASHIF_SW_RST 36 ++ ++/* PCIe Subsystem resets */ ++#define MT7629_PCIE1_CORE_RST 19 ++#define MT7629_PCIE1_MMIO_RST 20 ++#define MT7629_PCIE1_HRST 21 ++#define MT7629_PCIE1_USER_RST 22 ++#define MT7629_PCIE1_PIPE_RST 23 ++#define MT7629_PCIE0_CORE_RST 27 ++#define MT7629_PCIE0_MMIO_RST 28 ++#define MT7629_PCIE0_HRST 29 ++#define MT7629_PCIE0_USER_RST 30 ++#define MT7629_PCIE0_PIPE_RST 31 ++ ++/* SSUSB Subsystem resets */ ++#define MT7629_SSUSB_PHY_PWR_RST 3 ++#define MT7629_SSUSB_MAC_PWR_RST 4 ++ ++/* ETH Subsystem resets */ ++#define MT7629_ETHSYS_SYS_RST 0 ++#define MT7629_ETHSYS_MCM_RST 2 ++#define MT7629_ETHSYS_HSDMA_RST 5 ++#define MT7629_ETHSYS_FE_RST 6 ++#define MT7629_ETHSYS_ESW_RST 16 ++#define MT7629_ETHSYS_GMAC_RST 23 ++#define MT7629_ETHSYS_EPHY_RST 24 ++#define MT7629_ETHSYS_CRYPTO_RST 29 ++#define MT7629_ETHSYS_PPE_RST 31 ++ ++#endif /* _DT_BINDINGS_RESET_CONTROLLER_MT7629 */ +-- +2.18.0 + diff --git a/target/linux/mediatek/patches-4.19/0001-eth-sync-from-mtk-lede.patch b/target/linux/mediatek/patches-4.19/0001-eth-sync-from-mtk-lede.patch new file mode 100644 index 0000000000..c5521c416b --- /dev/null +++ b/target/linux/mediatek/patches-4.19/0001-eth-sync-from-mtk-lede.patch @@ -0,0 +1,1658 @@ +Index: linux-4.19.57/drivers/net/ethernet/mediatek/Kconfig +=================================================================== +--- linux-4.19.57.orig/drivers/net/ethernet/mediatek/Kconfig ++++ linux-4.19.57/drivers/net/ethernet/mediatek/Kconfig +@@ -1,6 +1,6 @@ + config NET_VENDOR_MEDIATEK + bool "MediaTek ethernet driver" +- depends on ARCH_MEDIATEK ++ depends on ARCH_MEDIATEK || RALINK + ---help--- + If you have a Mediatek SoC with ethernet, say Y. + +Index: linux-4.19.57/drivers/net/ethernet/mediatek/Makefile +=================================================================== +--- linux-4.19.57.orig/drivers/net/ethernet/mediatek/Makefile ++++ linux-4.19.57/drivers/net/ethernet/mediatek/Makefile +@@ -2,4 +2,5 @@ + # Makefile for the Mediatek SoCs built-in ethernet macs + # + +-obj-$(CONFIG_NET_MEDIATEK_SOC) += mtk_eth_soc.o ++obj-$(CONFIG_NET_MEDIATEK_SOC) += mtk_eth_soc.o mtk_sgmii.o \ ++ mtk_eth_path.o +Index: linux-4.19.57/drivers/net/ethernet/mediatek/mtk_eth_path.c +=================================================================== +--- /dev/null ++++ linux-4.19.57/drivers/net/ethernet/mediatek/mtk_eth_path.c +@@ -0,0 +1,333 @@ ++/* ++ * Copyright (C) 2018 MediaTek Inc. ++ * ++ * 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 of the License ++ * ++ * 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. ++ * ++ * Copyright (C) 2018 Sean Wang <sean.wang@mediatek.com> ++ */ ++ ++#include <linux/phy.h> ++#include <linux/regmap.h> ++ ++#include "mtk_eth_soc.h" ++ ++struct mtk_eth_muxc { ++ int (*set_path)(struct mtk_eth *eth, int path); ++}; ++ ++static const char * const mtk_eth_mux_name[] = { ++ "mux_gdm1_to_gmac1_esw", "mux_gmac2_gmac0_to_gephy", ++ "mux_u3_gmac2_to_qphy", "mux_gmac1_gmac2_to_sgmii_rgmii", ++ "mux_gmac12_to_gephy_sgmii", ++}; ++ ++static const char * const mtk_eth_path_name[] = { ++ "gmac1_rgmii", "gmac1_trgmii", "gmac1_sgmii", "gmac2_rgmii", ++ "gmac2_sgmii", "gmac2_gephy", "gdm1_esw", ++}; ++ ++static int set_mux_gdm1_to_gmac1_esw(struct mtk_eth *eth, int path) ++{ ++ u32 val, mask, set; ++ bool updated = true; ++ ++ switch (path) { ++ case MTK_ETH_PATH_GMAC1_SGMII: ++ mask = ~(u32)MTK_MUX_TO_ESW; ++ set = 0; ++ break; ++ case MTK_ETH_PATH_GDM1_ESW: ++ mask = ~(u32)MTK_MUX_TO_ESW; ++ set = MTK_MUX_TO_ESW; ++ break; ++ default: ++ updated = false; ++ break; ++ }; ++ ++ if (updated) { ++ val = mtk_r32(eth, MTK_MAC_MISC); ++ val = (val & mask) | set; ++ mtk_w32(eth, val, MTK_MAC_MISC); ++ } ++ ++ dev_info(eth->dev, "path %s in %s updated = %d\n", ++ mtk_eth_path_name[path], __func__, updated); ++ ++ return 0; ++} ++ ++static int set_mux_gmac2_gmac0_to_gephy(struct mtk_eth *eth, int path) ++{ ++ unsigned int val = 0; ++ bool updated = true; ++ ++ switch (path) { ++ case MTK_ETH_PATH_GMAC2_GEPHY: ++ val = ~(u32)GEPHY_MAC_SEL; ++ break; ++ default: ++ updated = false; ++ break; ++ } ++ ++ if (updated) ++ regmap_update_bits(eth->infra, INFRA_MISC2, GEPHY_MAC_SEL, val); ++ ++ dev_info(eth->dev, "path %s in %s updated = %d\n", ++ mtk_eth_path_name[path], __func__, updated); ++ ++ return 0; ++} ++ ++static int set_mux_u3_gmac2_to_qphy(struct mtk_eth *eth, int path) ++{ ++ unsigned int val = 0; ++ bool updated = true; ++ ++ switch (path) { ++ case MTK_ETH_PATH_GMAC2_SGMII: ++ val = CO_QPHY_SEL; ++ break; ++ default: ++ updated = false; ++ break; ++ } ++ ++ if (updated) ++ regmap_update_bits(eth->infra, INFRA_MISC2, CO_QPHY_SEL, val); ++ ++ dev_info(eth->dev, "path %s in %s updated = %d\n", ++ mtk_eth_path_name[path], __func__, updated); ++ ++ return 0; ++} ++ ++static int set_mux_gmac1_gmac2_to_sgmii_rgmii(struct mtk_eth *eth, int path) ++{ ++ unsigned int val = 0; ++ bool updated = true; ++ ++ switch (path) { ++ case MTK_ETH_PATH_GMAC1_SGMII: ++ val = SYSCFG0_SGMII_GMAC1; ++ break; ++ case MTK_ETH_PATH_GMAC2_SGMII: ++ val = SYSCFG0_SGMII_GMAC2; ++ break; ++ case MTK_ETH_PATH_GMAC1_RGMII: ++ case MTK_ETH_PATH_GMAC2_RGMII: ++ regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val); ++ val &= SYSCFG0_SGMII_MASK; ++ ++ if ((path == MTK_GMAC1_RGMII && val == SYSCFG0_SGMII_GMAC1) || ++ (path == MTK_GMAC2_RGMII && val == SYSCFG0_SGMII_GMAC2)) ++ val = 0; ++ else ++ updated = false; ++ break; ++ default: ++ updated = false; ++ break; ++ }; ++ ++ if (updated) ++ regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0, ++ SYSCFG0_SGMII_MASK, val); ++ ++ dev_info(eth->dev, "path %s in %s updated = %d\n", ++ mtk_eth_path_name[path], __func__, updated); ++ ++ return 0; ++} ++ ++static int set_mux_gmac12_to_gephy_sgmii(struct mtk_eth *eth, int path) ++{ ++ unsigned int val = 0; ++ bool updated = true; ++ ++ regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val); ++ ++ switch (path) { ++ case MTK_ETH_PATH_GMAC1_SGMII: ++ val |= SYSCFG0_SGMII_GMAC1_V2; ++ break; ++ case MTK_ETH_PATH_GMAC2_GEPHY: ++ val &= ~(u32)SYSCFG0_SGMII_GMAC2_V2; ++ break; ++ case MTK_ETH_PATH_GMAC2_SGMII: ++ val |= SYSCFG0_SGMII_GMAC2_V2; ++ break; ++ default: ++ updated = false; ++ }; ++ ++ if (updated) ++ regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0, ++ SYSCFG0_SGMII_MASK, val); ++ ++ if (!updated) ++ dev_info(eth->dev, "path %s no needs updatiion in %s\n", ++ mtk_eth_path_name[path], __func__); ++ ++ dev_info(eth->dev, "path %s in %s updated = %d\n", ++ mtk_eth_path_name[path], __func__, updated); ++ ++ return 0; ++} ++ ++static const struct mtk_eth_muxc mtk_eth_muxc[] = { ++ { .set_path = set_mux_gdm1_to_gmac1_esw, }, ++ { .set_path = set_mux_gmac2_gmac0_to_gephy, }, ++ { .set_path = set_mux_u3_gmac2_to_qphy, }, ++ { .set_path = set_mux_gmac1_gmac2_to_sgmii_rgmii, }, ++ { .set_path = set_mux_gmac12_to_gephy_sgmii, } ++}; ++ ++static int mtk_eth_mux_setup(struct mtk_eth *eth, int path) ++{ ++ int i, err = 0; ++ ++ if (!MTK_HAS_CAPS(eth->soc->caps, MTK_PATH_BIT(path))) { ++ dev_info(eth->dev, "path %s isn't support on the SoC\n", ++ mtk_eth_path_name[path]); ++ return -EINVAL; ++ } ++ ++ if (!MTK_HAS_CAPS(eth->soc->caps, MTK_MUX)) ++ return 0; ++ ++ /* Setup MUX in path fabric */ ++ for (i = 0; i < MTK_ETH_MUX_MAX; i++) { ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_MUX_BIT(i))) { ++ err = mtk_eth_muxc[i].set_path(eth, path); ++ if (err) ++ goto out; ++ } else { ++ dev_info(eth->dev, "mux %s isn't present on the SoC\n", ++ mtk_eth_mux_name[i]); ++ } ++ } ++ ++out: ++ return err; ++} ++ ++static int mtk_gmac_sgmii_path_setup(struct mtk_eth *eth, int mac_id) ++{ ++ unsigned int val = 0; ++ int sid, err, path; ++ ++ path = (mac_id == 0) ? MTK_ETH_PATH_GMAC1_SGMII : ++ MTK_ETH_PATH_GMAC2_SGMII; ++ ++ /* Setup proper MUXes along the path */ ++ err = mtk_eth_mux_setup(eth, path); ++ if (err) ++ return err; ++ ++ /* The path GMAC to SGMII will be enabled once the SGMIISYS is being ++ * setup done. ++ */ ++ regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val); ++ ++ regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0, ++ SYSCFG0_SGMII_MASK, ~(u32)SYSCFG0_SGMII_MASK); ++ ++ /* Decide how GMAC and SGMIISYS be mapped */ ++ sid = (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_SGMII)) ? 0 : mac_id; ++ ++ /* Setup SGMIISYS with the determined property */ ++ if (MTK_HAS_FLAGS(eth->sgmii->flags[sid], MTK_SGMII_PHYSPEED_AN)) ++ err = mtk_sgmii_setup_mode_an(eth->sgmii, sid); ++ else ++ err = mtk_sgmii_setup_mode_force(eth->sgmii, sid); ++ ++ if (err) ++ return err; ++ ++ regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0, ++ SYSCFG0_SGMII_MASK, val); ++ ++ return 0; ++} ++ ++static int mtk_gmac_gephy_path_setup(struct mtk_eth *eth, int mac_id) ++{ ++ int err, path = 0; ++ ++ if (mac_id == 1) ++ path = MTK_ETH_PATH_GMAC2_GEPHY; ++ ++ if (!path) ++ return -EINVAL; ++ ++ /* Setup proper MUXes along the path */ ++ err = mtk_eth_mux_setup(eth, path); ++ if (err) ++ return err; ++ ++ return 0; ++} ++ ++static int mtk_gmac_rgmii_path_setup(struct mtk_eth *eth, int mac_id) ++{ ++ int err, path; ++ ++ path = (mac_id == 0) ? MTK_ETH_PATH_GMAC1_RGMII : ++ MTK_ETH_PATH_GMAC2_RGMII; ++ ++ /* Setup proper MUXes along the path */ ++ err = mtk_eth_mux_setup(eth, path); ++ if (err) ++ return err; ++ ++ return 0; ++} ++ ++int mtk_setup_hw_path(struct mtk_eth *eth, int mac_id, int phymode) ++{ ++ int err; ++ ++ switch (phymode) { ++ case PHY_INTERFACE_MODE_TRGMII: ++ case PHY_INTERFACE_MODE_RGMII_TXID: ++ case PHY_INTERFACE_MODE_RGMII_RXID: ++ case PHY_INTERFACE_MODE_RGMII_ID: ++ case PHY_INTERFACE_MODE_RGMII: ++ case PHY_INTERFACE_MODE_MII: ++ case PHY_INTERFACE_MODE_REVMII: ++ case PHY_INTERFACE_MODE_RMII: ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_RGMII)) { ++ err = mtk_gmac_rgmii_path_setup(eth, mac_id); ++ if (err) ++ return err; ++ } ++ break; ++ case PHY_INTERFACE_MODE_SGMII: ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_SGMII)) { ++ err = mtk_gmac_sgmii_path_setup(eth, mac_id); ++ if (err) ++ return err; ++ } ++ break; ++ case PHY_INTERFACE_MODE_GMII: ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_GEPHY)) { ++ err = mtk_gmac_gephy_path_setup(eth, mac_id); ++ if (err) ++ return err; ++ } ++ break; ++ default: ++ break; ++ } ++ ++ return 0; ++} +Index: linux-4.19.57/drivers/net/ethernet/mediatek/mtk_eth_soc.c +=================================================================== +--- linux-4.19.57.orig/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ linux-4.19.57/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -23,6 +23,7 @@ + #include <linux/reset.h> + #include <linux/tcp.h> + #include <linux/interrupt.h> ++#include <linux/mdio.h> + #include <linux/pinctrl/devinfo.h> + + #include "mtk_eth_soc.h" +@@ -54,8 +55,10 @@ static const struct mtk_ethtool_stats { + }; + + static const char * const mtk_clks_source_name[] = { +- "ethif", "esw", "gp0", "gp1", "gp2", "trgpll", "sgmii_tx250m", +- "sgmii_rx250m", "sgmii_cdr_ref", "sgmii_cdr_fb", "sgmii_ck", "eth2pll" ++ "ethif", "sgmiitop", "esw", "gp0", "gp1", "gp2", "fe", "trgpll", ++ "sgmii_tx250m", "sgmii_rx250m", "sgmii_cdr_ref", "sgmii_cdr_fb", ++ "sgmii2_tx250m", "sgmii2_rx250m", "sgmii2_cdr_ref", "sgmii2_cdr_fb", ++ "sgmii_ck", "eth2pll", + }; + + void mtk_w32(struct mtk_eth *eth, u32 val, unsigned reg) +@@ -84,8 +87,8 @@ static int mtk_mdio_busy_wait(struct mtk + return -1; + } + +-static u32 _mtk_mdio_write(struct mtk_eth *eth, u32 phy_addr, +- u32 phy_register, u32 write_data) ++u32 _mtk_mdio_write(struct mtk_eth *eth, u32 phy_addr, ++ u32 phy_register, u32 write_data) + { + if (mtk_mdio_busy_wait(eth)) + return -1; +@@ -103,7 +106,7 @@ static u32 _mtk_mdio_write(struct mtk_et + return 0; + } + +-static u32 _mtk_mdio_read(struct mtk_eth *eth, int phy_addr, int phy_reg) ++u32 _mtk_mdio_read(struct mtk_eth *eth, int phy_addr, int phy_reg) + { + u32 d; + +@@ -123,6 +126,34 @@ static u32 _mtk_mdio_read(struct mtk_eth + return d; + } + ++u32 mtk_cl45_ind_read(struct mtk_eth *eth, u32 port, u32 devad, u32 reg, u32 *data) ++{ ++ mutex_lock(ð->mii_bus->mdio_lock); ++ ++ _mtk_mdio_write(eth, port, MII_MMD_ACC_CTL_REG, devad); ++ _mtk_mdio_write(eth, port, MII_MMD_ADDR_DATA_REG, reg); ++ _mtk_mdio_write(eth, port, MII_MMD_ACC_CTL_REG, MMD_OP_MODE_DATA | devad); ++ *data = _mtk_mdio_read(eth, port, MII_MMD_ADDR_DATA_REG); ++ ++ mutex_unlock(ð->mii_bus->mdio_lock); ++ ++ return 0; ++} ++ ++u32 mtk_cl45_ind_write(struct mtk_eth *eth, u32 port, u32 devad, u32 reg, u32 data) ++{ ++ mutex_lock(ð->mii_bus->mdio_lock); ++ ++ _mtk_mdio_write(eth, port, MII_MMD_ACC_CTL_REG, devad); ++ _mtk_mdio_write(eth, port, MII_MMD_ADDR_DATA_REG, reg); ++ _mtk_mdio_write(eth, port, MII_MMD_ACC_CTL_REG, MMD_OP_MODE_DATA | devad); ++ _mtk_mdio_write(eth, port, MII_MMD_ADDR_DATA_REG, data); ++ ++ mutex_unlock(ð->mii_bus->mdio_lock); ++ ++ return 0; ++} ++ + static int mtk_mdio_write(struct mii_bus *bus, int phy_addr, + int phy_reg, u16 val) + { +@@ -165,51 +196,12 @@ static void mtk_gmac0_rgmii_adjust(struc + mtk_w32(eth, val, TRGMII_TCK_CTRL); + } + +-static void mtk_gmac_sgmii_hw_setup(struct mtk_eth *eth, int mac_id) +-{ +- u32 val; +- +- /* Setup the link timer and QPHY power up inside SGMIISYS */ +- regmap_write(eth->sgmiisys, SGMSYS_PCS_LINK_TIMER, +- SGMII_LINK_TIMER_DEFAULT); +- +- regmap_read(eth->sgmiisys, SGMSYS_SGMII_MODE, &val); +- val |= SGMII_REMOTE_FAULT_DIS; +- regmap_write(eth->sgmiisys, SGMSYS_SGMII_MODE, val); +- +- regmap_read(eth->sgmiisys, SGMSYS_PCS_CONTROL_1, &val); +- val |= SGMII_AN_RESTART; +- regmap_write(eth->sgmiisys, SGMSYS_PCS_CONTROL_1, val); +- +- regmap_read(eth->sgmiisys, SGMSYS_QPHY_PWR_STATE_CTRL, &val); +- val &= ~SGMII_PHYA_PWD; +- regmap_write(eth->sgmiisys, SGMSYS_QPHY_PWR_STATE_CTRL, val); +- +- /* Determine MUX for which GMAC uses the SGMII interface */ +- if (MTK_HAS_CAPS(eth->soc->caps, MTK_DUAL_GMAC_SHARED_SGMII)) { +- regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val); +- val &= ~SYSCFG0_SGMII_MASK; +- val |= !mac_id ? SYSCFG0_SGMII_GMAC1 : SYSCFG0_SGMII_GMAC2; +- regmap_write(eth->ethsys, ETHSYS_SYSCFG0, val); +- +- dev_info(eth->dev, "setup shared sgmii for gmac=%d\n", +- mac_id); +- } +- +- /* Setup the GMAC1 going through SGMII path when SoC also support +- * ESW on GMAC1 +- */ +- if (MTK_HAS_CAPS(eth->soc->caps, MTK_GMAC1_ESW | MTK_GMAC1_SGMII) && +- !mac_id) { +- mtk_w32(eth, 0, MTK_MAC_MISC); +- dev_info(eth->dev, "setup gmac1 going through sgmii"); +- } +-} +- + static void mtk_phy_link_adjust(struct net_device *dev) + { + struct mtk_mac *mac = netdev_priv(dev); ++ struct mtk_eth *eth = mac->hw; + u16 lcl_adv = 0, rmt_adv = 0; ++ u32 lcl_eee = 0, rmt_eee = 0; + u8 flowctrl; + u32 mcr = MAC_MCR_MAX_RX_1536 | MAC_MCR_IPG_CFG | + MAC_MCR_FORCE_MODE | MAC_MCR_TX_EN | +@@ -229,7 +221,7 @@ static void mtk_phy_link_adjust(struct n + }; + + if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_GMAC1_TRGMII) && +- !mac->id && !mac->trgmii) ++ !mac->id && !mac->trgmii) + mtk_gmac0_rgmii_adjust(mac->hw, dev->phydev->speed); + + if (dev->phydev->link) +@@ -259,7 +251,16 @@ static void mtk_phy_link_adjust(struct n + flowctrl & FLOW_CTRL_RX ? "enabled" : "disabled", + flowctrl & FLOW_CTRL_TX ? "enabled" : "disabled"); + } ++ /*EEE capability*/ ++ mtk_cl45_ind_read(eth, 0, MDIO_MMD_AN, MDIO_AN_EEE_ADV, &lcl_eee); ++ mtk_cl45_ind_read(eth, 0, MDIO_MMD_AN, MDIO_AN_EEE_LPABLE, &rmt_eee); ++ ++ if ((lcl_eee & rmt_eee & MDIO_EEE_1000T) == MDIO_EEE_1000T) ++ mcr |= MAC_MCR_MDIO_EEE_1000T; ++ if ((lcl_eee & rmt_eee & MDIO_EEE_100TX) == MDIO_EEE_100TX) ++ mcr |= MAC_MCR_MDIO_EEE_100TX; + ++ /*Setup MCR*/ + mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id)); + + if (dev->phydev->link) +@@ -290,10 +291,10 @@ static int mtk_phy_connect_node(struct m + return -ENODEV; + } + +- dev_info(eth->dev, +- "connected mac %d to PHY at %s [uid=%08x, driver=%s]\n", +- mac->id, phydev_name(phydev), phydev->phy_id, +- phydev->drv->name); ++ dev_info(eth->dev, ++ "connected mac %d to PHY at %s [uid=%08x, driver=%s]\n", ++ mac->id, phydev_name(phydev), phydev->phy_id, ++ phydev->drv->name); + + return 0; + } +@@ -304,6 +305,7 @@ static int mtk_phy_connect(struct net_de + struct mtk_eth *eth; + struct device_node *np; + u32 val; ++ int err; + + eth = mac->hw; + np = of_parse_phandle(mac->of_node, "phy-handle", 0); +@@ -313,6 +315,10 @@ static int mtk_phy_connect(struct net_de + if (!np) + return -ENODEV; + ++ err = mtk_setup_hw_path(eth, mac->id, of_get_phy_mode(np)); ++ if (err) ++ goto err_phy; ++ + mac->ge_mode = 0; + switch (of_get_phy_mode(np)) { + case PHY_INTERFACE_MODE_TRGMII: +@@ -323,10 +329,9 @@ static int mtk_phy_connect(struct net_de + case PHY_INTERFACE_MODE_RGMII: + break; + case PHY_INTERFACE_MODE_SGMII: +- if (MTK_HAS_CAPS(eth->soc->caps, MTK_SGMII)) +- mtk_gmac_sgmii_hw_setup(eth, mac->id); + break; + case PHY_INTERFACE_MODE_MII: ++ case PHY_INTERFACE_MODE_GMII: + mac->ge_mode = 1; + break; + case PHY_INTERFACE_MODE_REVMII: +@@ -355,7 +360,7 @@ static int mtk_phy_connect(struct net_de + dev->phydev->speed = 0; + dev->phydev->duplex = 0; + +- if (of_phy_is_fixed_link(mac->of_node)) ++ if (!strncmp(dev->phydev->drv->name, "Generic", 7)) + dev->phydev->supported |= + SUPPORTED_Pause | SUPPORTED_Asym_Pause; + +@@ -535,37 +540,37 @@ static void mtk_stats_update(struct mtk_ + } + + static void mtk_get_stats64(struct net_device *dev, +- struct rtnl_link_stats64 *storage) ++ struct rtnl_link_stats64 *storage) + { +- struct mtk_mac *mac = netdev_priv(dev); +- struct mtk_hw_stats *hw_stats = mac->hw_stats; +- unsigned int start; +- +- if (netif_running(dev) && netif_device_present(dev)) { +- if (spin_trylock_bh(&hw_stats->stats_lock)) { +- mtk_stats_update_mac(mac); +- spin_unlock_bh(&hw_stats->stats_lock); +- } +- } +- +- do { +- start = u64_stats_fetch_begin_irq(&hw_stats->syncp); +- storage->rx_packets = hw_stats->rx_packets; +- storage->tx_packets = hw_stats->tx_packets; +- storage->rx_bytes = hw_stats->rx_bytes; +- storage->tx_bytes = hw_stats->tx_bytes; +- storage->collisions = hw_stats->tx_collisions; +- storage->rx_length_errors = hw_stats->rx_short_errors + +- hw_stats->rx_long_errors; +- storage->rx_over_errors = hw_stats->rx_overflow; +- storage->rx_crc_errors = hw_stats->rx_fcs_errors; +- storage->rx_errors = hw_stats->rx_checksum_errors; +- storage->tx_aborted_errors = hw_stats->tx_skip; +- } while (u64_stats_fetch_retry_irq(&hw_stats->syncp, start)); +- +- storage->tx_errors = dev->stats.tx_errors; +- storage->rx_dropped = dev->stats.rx_dropped; +- storage->tx_dropped = dev->stats.tx_dropped; ++ struct mtk_mac *mac = netdev_priv(dev); ++ struct mtk_hw_stats *hw_stats = mac->hw_stats; ++ unsigned int start; ++ ++ if (netif_running(dev) && netif_device_present(dev)) { ++ if (spin_trylock_bh(&hw_stats->stats_lock)) { ++ mtk_stats_update_mac(mac); ++ spin_unlock_bh(&hw_stats->stats_lock); ++ } ++ } ++ ++ do { ++ start = u64_stats_fetch_begin_irq(&hw_stats->syncp); ++ storage->rx_packets = hw_stats->rx_packets; ++ storage->tx_packets = hw_stats->tx_packets; ++ storage->rx_bytes = hw_stats->rx_bytes; ++ storage->tx_bytes = hw_stats->tx_bytes; ++ storage->collisions = hw_stats->tx_collisions; ++ storage->rx_length_errors = hw_stats->rx_short_errors + ++ hw_stats->rx_long_errors; ++ storage->rx_over_errors = hw_stats->rx_overflow; ++ storage->rx_crc_errors = hw_stats->rx_fcs_errors; ++ storage->rx_errors = hw_stats->rx_checksum_errors; ++ storage->tx_aborted_errors = hw_stats->tx_skip; ++ } while (u64_stats_fetch_retry_irq(&hw_stats->syncp, start)); ++ ++ storage->tx_errors = dev->stats.tx_errors; ++ storage->rx_dropped = dev->stats.rx_dropped; ++ storage->tx_dropped = dev->stats.tx_dropped; + } + + static inline int mtk_max_frag_size(int mtu) +@@ -605,10 +610,10 @@ static int mtk_init_fq_dma(struct mtk_et + dma_addr_t dma_addr; + int i; + +- eth->scratch_ring = dma_zalloc_coherent(eth->dev, +- cnt * sizeof(struct mtk_tx_dma), +- ð->phy_scratch_ring, +- GFP_ATOMIC); ++ eth->scratch_ring = dma_alloc_coherent(eth->dev, ++ cnt * sizeof(struct mtk_tx_dma), ++ ð->phy_scratch_ring, ++ GFP_ATOMIC | __GFP_ZERO); + if (unlikely(!eth->scratch_ring)) + return -ENOMEM; + +@@ -623,6 +628,7 @@ static int mtk_init_fq_dma(struct mtk_et + if (unlikely(dma_mapping_error(eth->dev, dma_addr))) + return -ENOMEM; + ++ memset(eth->scratch_ring, 0x0, sizeof(struct mtk_tx_dma) * cnt); + phy_ring_tail = eth->phy_scratch_ring + + (sizeof(struct mtk_tx_dma) * (cnt - 1)); + +@@ -673,7 +679,7 @@ static void mtk_tx_unmap(struct mtk_eth + } + tx_buf->flags = 0; + if (tx_buf->skb && +- (tx_buf->skb != (struct sk_buff *)MTK_DMA_DUMMY_DESC)) ++ (tx_buf->skb != (struct sk_buff *)MTK_DMA_DUMMY_DESC)) + dev_kfree_skb_any(tx_buf->skb); + tx_buf->skb = NULL; + } +@@ -689,6 +695,7 @@ static int mtk_tx_map(struct sk_buff *sk + unsigned int nr_frags; + int i, n_desc = 1; + u32 txd4 = 0, fport; ++ u32 qid = 0; + + itxd = ring->next_free; + if (itxd == ring->last_free) +@@ -708,9 +715,10 @@ static int mtk_tx_map(struct sk_buff *sk + if (skb->ip_summed == CHECKSUM_PARTIAL) + txd4 |= TX_DMA_CHKSUM; + +- /* VLAN header offload */ +- if (skb_vlan_tag_present(skb)) +- txd4 |= TX_DMA_INS_VLAN | skb_vlan_tag_get(skb); ++#if defined(CONFIG_NET_MEDIATEK_HW_QOS) ++ qid = skb->mark & (MTK_QDMA_TX_MASK); ++ qid += (!mac->id) ? (MTK_QDMA_TX_MASK + 1) : 0; ++#endif + + mapped_addr = dma_map_single(eth->dev, skb->data, + skb_headlen(skb), DMA_TO_DEVICE); +@@ -727,6 +735,7 @@ static int mtk_tx_map(struct sk_buff *sk + /* TX SG offload */ + txd = itxd; + nr_frags = skb_shinfo(skb)->nr_frags; ++ + for (i = 0; i < nr_frags; i++) { + struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i]; + unsigned int offset = 0; +@@ -753,10 +762,10 @@ static int mtk_tx_map(struct sk_buff *sk + last_frag = true; + + WRITE_ONCE(txd->txd1, mapped_addr); +- WRITE_ONCE(txd->txd3, (TX_DMA_SWC | ++ WRITE_ONCE(txd->txd3, (TX_DMA_SWC | QID_LOW_BITS(qid) | + TX_DMA_PLEN0(frag_map_size) | + last_frag * TX_DMA_LS0)); +- WRITE_ONCE(txd->txd4, fport); ++ WRITE_ONCE(txd->txd4, fport | QID_HIGH_BITS(qid)); + + tx_buf = mtk_desc_to_tx_buf(ring, txd); + memset(tx_buf, 0, sizeof(*tx_buf)); +@@ -775,9 +784,9 @@ static int mtk_tx_map(struct sk_buff *sk + /* store skb to cleanup */ + itx_buf->skb = skb; + +- WRITE_ONCE(itxd->txd4, txd4); + WRITE_ONCE(itxd->txd3, (TX_DMA_SWC | TX_DMA_PLEN0(skb_headlen(skb)) | +- (!nr_frags * TX_DMA_LS0))); ++ (!nr_frags * TX_DMA_LS0)) | QID_LOW_BITS(qid)); ++ WRITE_ONCE(itxd->txd4, txd4 | QID_HIGH_BITS(qid)); + + netdev_sent_queue(dev, skb->len); + skb_tx_timestamp(skb); +@@ -922,7 +931,7 @@ drop: + return NETDEV_TX_OK; + } + +-static struct mtk_rx_ring *mtk_get_rx_ring(struct mtk_eth *eth) ++struct mtk_rx_ring *mtk_get_rx_ring(struct mtk_eth *eth) + { + int i; + struct mtk_rx_ring *ring; +@@ -991,10 +1000,24 @@ static int mtk_poll_rx(struct napi_struc + break; + + /* find out which mac the packet come from. values start at 1 */ ++#if defined(CONFIG_NET_DSA) ++ mac = (trxd.rxd4 >> 22) & 0x1; ++ mac = (mac + 1) % 2; ++#else + mac = (trxd.rxd4 >> RX_DMA_FPORT_SHIFT) & +- RX_DMA_FPORT_MASK; +- mac--; +- ++ RX_DMA_FPORT_MASK; ++ /* From QDMA(5). This is a external interface case of HWNAT. ++ * When the incoming frame comes from an external interface ++ * rather than GMAC1/GMAC2, HWNAT driver sends the original ++ * frame to PPE via PPD(ping pong device) for HWNAT RX ++ * frame learning. After learning, PPE transmit the ++ * original frame back to PPD again to run SW NAT path. ++ */ ++ if (mac == 5) ++ mac = 0; ++ else ++ mac--; ++#endif + if (unlikely(mac < 0 || mac >= MTK_MAC_COUNT || + !eth->netdev[mac])) + goto release_desc; +@@ -1044,6 +1067,7 @@ static int mtk_poll_rx(struct napi_struc + RX_DMA_VID(trxd.rxd3)) + __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), + RX_DMA_VID(trxd.rxd3)); ++ + skb_record_rx_queue(skb, 0); + napi_gro_receive(napi, skb); + +@@ -1128,7 +1152,7 @@ static int mtk_poll_tx(struct mtk_eth *e + } + + if (mtk_queue_stopped(eth) && +- (atomic_read(&ring->free_count) > ring->thresh)) ++ (atomic_read(&ring->free_count) > ring->thresh)) + mtk_wake_queue(eth); + + return total; +@@ -1220,11 +1244,14 @@ static int mtk_tx_alloc(struct mtk_eth * + if (!ring->buf) + goto no_tx_mem; + +- ring->dma = dma_zalloc_coherent(eth->dev, MTK_DMA_SIZE * sz, +- &ring->phys, GFP_ATOMIC); ++ ring->dma = dma_alloc_coherent(eth->dev, ++ MTK_DMA_SIZE * sz, ++ &ring->phys, ++ GFP_ATOMIC | __GFP_ZERO); + if (!ring->dma) + goto no_tx_mem; + ++ memset(ring->dma, 0, MTK_DMA_SIZE * sz); + for (i = 0; i < MTK_DMA_SIZE; i++) { + int next = (i + 1) % MTK_DMA_SIZE; + u32 next_ptr = ring->phys + next * sz; +@@ -1317,9 +1344,10 @@ static int mtk_rx_alloc(struct mtk_eth * + return -ENOMEM; + } + +- ring->dma = dma_zalloc_coherent(eth->dev, +- rx_dma_size * sizeof(*ring->dma), +- &ring->phys, GFP_ATOMIC); ++ ring->dma = dma_alloc_coherent(eth->dev, ++ rx_dma_size * sizeof(*ring->dma), ++ &ring->phys, ++ GFP_ATOMIC | __GFP_ZERO); + if (!ring->dma) + return -ENOMEM; + +@@ -1516,8 +1544,8 @@ static int mtk_hwlro_add_ipaddr(struct n + int hwlro_idx; + + if ((fsp->flow_type != TCP_V4_FLOW) || +- (!fsp->h_u.tcp_ip4_spec.ip4dst) || +- (fsp->location > 1)) ++ (!fsp->h_u.tcp_ip4_spec.ip4dst) || ++ (fsp->location > 1)) + return -EINVAL; + + mac->hwlro_ip[fsp->location] = htonl(fsp->h_u.tcp_ip4_spec.ip4dst); +@@ -1744,6 +1772,34 @@ static void mtk_tx_timeout(struct net_de + schedule_work(ð->pending_work); + } + ++static irqreturn_t mtk_handle_irq_tx_rx(int irq, void *_eth) ++{ ++ struct mtk_eth *eth = _eth; ++ u32 tx_status, rx_status; ++ ++ tx_status = mtk_r32(eth, MTK_QMTK_INT_STATUS); ++ ++ if (tx_status & MTK_TX_DONE_INT) { ++ if (likely(napi_schedule_prep(ð->tx_napi))) { ++ mtk_tx_irq_disable(eth, MTK_TX_DONE_INT); ++ __napi_schedule(ð->tx_napi); ++ } ++ mtk_w32(eth, tx_status, MTK_QMTK_INT_STATUS); ++ } ++ ++ rx_status = mtk_r32(eth, MTK_PDMA_INT_STATUS); ++ ++ if (rx_status & MTK_RX_DONE_INT) { ++ if (likely(napi_schedule_prep(ð->rx_napi))) { ++ mtk_rx_irq_disable(eth, MTK_RX_DONE_INT); ++ __napi_schedule(ð->rx_napi); ++ } ++ mtk_w32(eth, rx_status, MTK_PDMA_INT_STATUS); ++ } ++ ++ return IRQ_HANDLED; ++} ++ + static irqreturn_t mtk_handle_irq_rx(int irq, void *_eth) + { + struct mtk_eth *eth = _eth; +@@ -1784,8 +1840,8 @@ static void mtk_poll_controller(struct n + + static int mtk_start_dma(struct mtk_eth *eth) + { +- u32 rx_2b_offset = (NET_IP_ALIGN == 2) ? MTK_RX_2B_OFFSET : 0; + int err; ++ u32 rx_2b_offet = (NET_IP_ALIGN == 2) ? MTK_RX_2B_OFFSET : 0; + + err = mtk_dma_init(eth); + if (err) { +@@ -1801,7 +1857,7 @@ static int mtk_start_dma(struct mtk_eth + MTK_QDMA_GLO_CFG); + + mtk_w32(eth, +- MTK_RX_DMA_EN | rx_2b_offset | ++ MTK_RX_DMA_EN | rx_2b_offet | + MTK_RX_BT_32DWORDS | MTK_MULTI_EN, + MTK_PDMA_GLO_CFG); + +@@ -1814,7 +1870,7 @@ static int mtk_open(struct net_device *d + struct mtk_eth *eth = mac->hw; + + /* we run 2 netdevs on the same dma ring so we only bring it up once */ +- if (!refcount_read(ð->dma_refcnt)) { ++ if (!atomic_read(ð->dma_refcnt)) { + int err = mtk_start_dma(eth); + + if (err) +@@ -1824,10 +1880,8 @@ static int mtk_open(struct net_device *d + napi_enable(ð->rx_napi); + mtk_tx_irq_enable(eth, MTK_TX_DONE_INT); + mtk_rx_irq_enable(eth, MTK_RX_DONE_INT); +- refcount_set(ð->dma_refcnt, 1); + } +- else +- refcount_inc(ð->dma_refcnt); ++ atomic_inc(ð->dma_refcnt); + + phy_start(dev->phydev); + netif_start_queue(dev); +@@ -1867,7 +1921,7 @@ static int mtk_stop(struct net_device *d + phy_stop(dev->phydev); + + /* only shutdown DMA if this is the last user */ +- if (!refcount_dec_and_test(ð->dma_refcnt)) ++ if (!atomic_dec_and_test(ð->dma_refcnt)) + return 0; + + mtk_tx_irq_disable(eth, MTK_TX_DONE_INT); +@@ -1973,14 +2027,16 @@ static int mtk_hw_init(struct mtk_eth *e + val = mtk_r32(eth, MTK_CDMQ_IG_CTRL); + mtk_w32(eth, val | MTK_CDMQ_STAG_EN, MTK_CDMQ_IG_CTRL); + +- /* Enable RX VLan Offloading */ +- mtk_w32(eth, 1, MTK_CDMP_EG_CTRL); ++ /* Disable RX VLan Offloading */ ++ mtk_w32(eth, 0, MTK_CDMP_EG_CTRL); ++ ++#if defined(CONFIG_NET_DSA) ++ mtk_w32(eth, 0x81000001, MTK_CDMP_IG_CTRL); ++#endif + +- /* enable interrupt delay for RX */ +- mtk_w32(eth, MTK_PDMA_DELAY_RX_DELAY, MTK_PDMA_DELAY_INT); ++ mtk_w32(eth, 0x8f0f8f0f, MTK_PDMA_DELAY_INT); ++ mtk_w32(eth, 0x8f0f8f0f, MTK_QDMA_DELAY_INT); + +- /* disable delay and normal interrupt */ +- mtk_w32(eth, 0, MTK_QDMA_DELAY_INT); + mtk_tx_irq_disable(eth, ~0); + mtk_rx_irq_disable(eth, ~0); + mtk_w32(eth, RST_GL_PSE, MTK_RST_GL); +@@ -2172,27 +2228,27 @@ static int mtk_cleanup(struct mtk_eth *e + } + + static int mtk_get_link_ksettings(struct net_device *ndev, +- struct ethtool_link_ksettings *cmd) ++ struct ethtool_link_ksettings *cmd) + { +- struct mtk_mac *mac = netdev_priv(ndev); ++ struct mtk_mac *mac = netdev_priv(ndev); + +- if (unlikely(test_bit(MTK_RESETTING, &mac->hw->state))) +- return -EBUSY; ++ if (unlikely(test_bit(MTK_RESETTING, &mac->hw->state))) ++ return -EBUSY; + +- phy_ethtool_ksettings_get(ndev->phydev, cmd); ++ phy_ethtool_ksettings_get(ndev->phydev, cmd); + +- return 0; ++ return 0; + } + + static int mtk_set_link_ksettings(struct net_device *ndev, +- const struct ethtool_link_ksettings *cmd) ++ const struct ethtool_link_ksettings *cmd) + { +- struct mtk_mac *mac = netdev_priv(ndev); ++ struct mtk_mac *mac = netdev_priv(ndev); + +- if (unlikely(test_bit(MTK_RESETTING, &mac->hw->state))) +- return -EBUSY; ++ if (unlikely(test_bit(MTK_RESETTING, &mac->hw->state))) ++ return -EBUSY; + +- return phy_ethtool_ksettings_set(ndev->phydev, cmd); ++ return phy_ethtool_ksettings_set(ndev->phydev, cmd); + } + + static void mtk_get_drvinfo(struct net_device *dev, +@@ -2355,8 +2411,8 @@ static int mtk_set_rxnfc(struct net_devi + } + + static const struct ethtool_ops mtk_ethtool_ops = { +- .get_link_ksettings = mtk_get_link_ksettings, +- .set_link_ksettings = mtk_set_link_ksettings, ++ .get_link_ksettings = mtk_get_link_ksettings, ++ .set_link_ksettings = mtk_set_link_ksettings, + .get_drvinfo = mtk_get_drvinfo, + .get_msglevel = mtk_get_msglevel, + .set_msglevel = mtk_set_msglevel, +@@ -2366,7 +2422,7 @@ static const struct ethtool_ops mtk_etht + .get_sset_count = mtk_get_sset_count, + .get_ethtool_stats = mtk_get_ethtool_stats, + .get_rxnfc = mtk_get_rxnfc, +- .set_rxnfc = mtk_set_rxnfc, ++ .set_rxnfc = mtk_set_rxnfc, + }; + + static const struct net_device_ops mtk_netdev_ops = { +@@ -2463,6 +2519,7 @@ static int mtk_probe(struct platform_dev + { + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + struct device_node *mac_np; ++ const struct of_device_id *match; + struct mtk_eth *eth; + int err; + int i; +@@ -2471,7 +2528,8 @@ static int mtk_probe(struct platform_dev + if (!eth) + return -ENOMEM; + +- eth->soc = of_device_get_match_data(&pdev->dev); ++ match = of_match_device(of_mtk_match, &pdev->dev); ++ eth->soc = (struct mtk_soc_data *)match->data; + + eth->dev = &pdev->dev; + eth->base = devm_ioremap_resource(&pdev->dev, res); +@@ -2489,26 +2547,37 @@ static int mtk_probe(struct platform_dev + return PTR_ERR(eth->ethsys); + } + +- if (MTK_HAS_CAPS(eth->soc->caps, MTK_SGMII)) { +- eth->sgmiisys = +- syscon_regmap_lookup_by_phandle(pdev->dev.of_node, +- "mediatek,sgmiisys"); +- if (IS_ERR(eth->sgmiisys)) { +- dev_err(&pdev->dev, "no sgmiisys regmap found\n"); +- return PTR_ERR(eth->sgmiisys); ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_INFRA)) { ++ eth->infra = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, ++ "mediatek,infracfg"); ++ if (IS_ERR(eth->infra)) { ++ dev_info(&pdev->dev, "no ethsys regmap found\n"); ++ return PTR_ERR(eth->infra); + } + } + ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_SGMII)) { ++ eth->sgmii = devm_kzalloc(eth->dev, sizeof(*eth->sgmii), ++ GFP_KERNEL); ++ if (!eth->sgmii) ++ return -ENOMEM; ++ ++ err = mtk_sgmii_init(eth->sgmii, pdev->dev.of_node, ++ eth->soc->ana_rgc3); ++ if (err) ++ return err; ++ } ++ + if (eth->soc->required_pctl) { + eth->pctl = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, + "mediatek,pctl"); + if (IS_ERR(eth->pctl)) { +- dev_err(&pdev->dev, "no pctl regmap found\n"); ++ dev_info(&pdev->dev, "no pctl regmap found\n"); + return PTR_ERR(eth->pctl); + } + } + +- for (i = 0; i < 3; i++) { ++ for (i = 0; i < eth->soc->irq_num; i++) { + eth->irq[i] = platform_get_irq(pdev, i); + if (eth->irq[i] < 0) { + dev_err(&pdev->dev, "no IRQ%d resource found\n", i); +@@ -2552,15 +2621,22 @@ static int mtk_probe(struct platform_dev + goto err_deinit_hw; + } + +- err = devm_request_irq(eth->dev, eth->irq[1], mtk_handle_irq_tx, 0, +- dev_name(eth->dev), eth); +- if (err) +- goto err_free_dev; ++ if (eth->soc->irq_num > 1) { ++ err = devm_request_irq(eth->dev, eth->irq[1], mtk_handle_irq_tx, 0, ++ dev_name(eth->dev), eth); ++ if (err) ++ goto err_free_dev; + +- err = devm_request_irq(eth->dev, eth->irq[2], mtk_handle_irq_rx, 0, +- dev_name(eth->dev), eth); +- if (err) +- goto err_free_dev; ++ err = devm_request_irq(eth->dev, eth->irq[2], mtk_handle_irq_rx, 0, ++ dev_name(eth->dev), eth); ++ if (err) ++ goto err_free_dev; ++ } else { ++ err = devm_request_irq(eth->dev, eth->irq[0], mtk_handle_irq_tx_rx, 0, ++ dev_name(eth->dev), eth); ++ if (err) ++ goto err_free_dev; ++ } + + err = mtk_mdio_init(eth); + if (err) +@@ -2626,27 +2702,48 @@ static int mtk_remove(struct platform_de + } + + static const struct mtk_soc_data mt2701_data = { +- .caps = MTK_GMAC1_TRGMII | MTK_HWLRO, ++ .caps = MT7623_CAPS | MTK_HWLRO, + .required_clks = MT7623_CLKS_BITMAP, + .required_pctl = true, ++ .irq_num = 3, + }; + + static const struct mtk_soc_data mt7622_data = { +- .caps = MTK_DUAL_GMAC_SHARED_SGMII | MTK_GMAC1_ESW | MTK_HWLRO, ++ .ana_rgc3 = 0x2028, ++ .caps = MT7622_CAPS | MTK_HWLRO, + .required_clks = MT7622_CLKS_BITMAP, + .required_pctl = false, ++ .irq_num = 3, + }; + + static const struct mtk_soc_data mt7623_data = { +- .caps = MTK_GMAC1_TRGMII | MTK_HWLRO, ++ .caps = MT7623_CAPS | MTK_HWLRO, + .required_clks = MT7623_CLKS_BITMAP, + .required_pctl = true, ++ .irq_num = 3, ++}; ++ ++static const struct mtk_soc_data leopard_data = { ++ .ana_rgc3 = 0x128, ++ .caps = LEOPARD_CAPS | MTK_HWLRO, ++ .required_clks = LEOPARD_CLKS_BITMAP, ++ .required_pctl = false, ++ .irq_num = 3, ++}; ++ ++static const struct mtk_soc_data mt7621_data = { ++ .caps = MT7621_CAPS, ++ .required_clks = MT7621_CLKS_BITMAP, ++ .required_pctl = false, ++ .irq_num = 1, + }; + + const struct of_device_id of_mtk_match[] = { + { .compatible = "mediatek,mt2701-eth", .data = &mt2701_data}, + { .compatible = "mediatek,mt7622-eth", .data = &mt7622_data}, + { .compatible = "mediatek,mt7623-eth", .data = &mt7623_data}, ++ { .compatible = "mediatek,mt7629-eth", .data = &leopard_data}, ++ { .compatible = "mediatek,mt7621-eth", .data = &mt7621_data}, + {}, + }; + MODULE_DEVICE_TABLE(of, of_mtk_match); +Index: linux-4.19.57/drivers/net/ethernet/mediatek/mtk_eth_soc.h +=================================================================== +--- linux-4.19.57.orig/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ linux-4.19.57/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -15,13 +15,17 @@ + #ifndef MTK_ETH_H + #define MTK_ETH_H + ++#include <linux/dma-mapping.h> ++#include <linux/netdevice.h> ++#include <linux/of_net.h> ++#include <linux/u64_stats_sync.h> + #include <linux/refcount.h> + + #define MTK_QDMA_PAGE_SIZE 2048 + #define MTK_MAX_RX_LENGTH 1536 + #define MTK_TX_DMA_BUF_LEN 0x3fff +-#define MTK_DMA_SIZE 256 +-#define MTK_NAPI_WEIGHT 64 ++#define MTK_DMA_SIZE 2048 ++#define MTK_NAPI_WEIGHT 256 + #define MTK_MAC_COUNT 2 + #define MTK_RX_ETH_HLEN (VLAN_ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN) + #define MTK_RX_HLEN (NET_SKB_PAD + MTK_RX_ETH_HLEN + NET_IP_ALIGN) +@@ -36,8 +40,6 @@ + NETIF_MSG_TX_ERR) + #define MTK_HW_FEATURES (NETIF_F_IP_CSUM | \ + NETIF_F_RXCSUM | \ +- NETIF_F_HW_VLAN_CTAG_TX | \ +- NETIF_F_HW_VLAN_CTAG_RX | \ + NETIF_F_SG | NETIF_F_TSO | \ + NETIF_F_TSO6 | \ + NETIF_F_IPV6_CSUM) +@@ -76,6 +78,9 @@ + #define MTK_CDMQ_IG_CTRL 0x1400 + #define MTK_CDMQ_STAG_EN BIT(0) + ++/* CDMP Ingress Control Register */ ++#define MTK_CDMP_IG_CTRL 0x400 ++ + /* CDMP Exgress Control Register */ + #define MTK_CDMP_EG_CTRL 0x404 + +@@ -225,8 +230,9 @@ + #define MTK_TX_DONE_INT1 BIT(1) + #define MTK_TX_DONE_INT0 BIT(0) + #define MTK_RX_DONE_INT MTK_RX_DONE_DLY +-#define MTK_TX_DONE_INT (MTK_TX_DONE_INT0 | MTK_TX_DONE_INT1 | \ +- MTK_TX_DONE_INT2 | MTK_TX_DONE_INT3) ++#define MTK_TX_DONE_DLY BIT(28) ++#define MTK_TX_DONE_INT MTK_TX_DONE_DLY ++ + + /* QDMA Interrupt grouping registers */ + #define MTK_QDMA_INT_GRP1 0x1a20 +@@ -267,6 +273,12 @@ + #define MTK_GDM1_TX_GBCNT 0x2400 + #define MTK_STAT_OFFSET 0x40 + ++/* QDMA TX NUM */ ++#define MTK_QDMA_TX_NUM 16 ++#define MTK_QDMA_TX_MASK ((MTK_QDMA_TX_NUM / 2) - 1) ++#define QID_LOW_BITS(x) ((x) & 0xf) ++#define QID_HIGH_BITS(x) ((((x) >> 4) & 0x3) & GENMASK(21, 20)) ++ + /* QDMA descriptor txd4 */ + #define TX_DMA_CHKSUM (0x7 << 29) + #define TX_DMA_TSO BIT(28) +@@ -316,6 +328,8 @@ + #define MAC_MCR_RX_EN BIT(13) + #define MAC_MCR_BACKOFF_EN BIT(9) + #define MAC_MCR_BACKPR_EN BIT(8) ++#define MAC_MCR_MDIO_EEE_1000T BIT(7) ++#define MAC_MCR_MDIO_EEE_100TX 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) +@@ -368,9 +382,11 @@ + #define ETHSYS_SYSCFG0 0x14 + #define SYSCFG0_GE_MASK 0x3 + #define SYSCFG0_GE_MODE(x, y) (x << (12 + (y * 2))) +-#define SYSCFG0_SGMII_MASK (3 << 8) +-#define SYSCFG0_SGMII_GMAC1 ((2 << 8) & GENMASK(9, 8)) +-#define SYSCFG0_SGMII_GMAC2 ((3 << 8) & GENMASK(9, 8)) ++#define SYSCFG0_SGMII_MASK GENMASK(9, 8) ++#define SYSCFG0_SGMII_GMAC1 ((2 << 8) & SYSCFG0_SGMII_MASK) ++#define SYSCFG0_SGMII_GMAC2 ((3 << 8) & SYSCFG0_SGMII_MASK) ++#define SYSCFG0_SGMII_GMAC1_V2 BIT(9) ++#define SYSCFG0_SGMII_GMAC2_V2 BIT(8) + + /* ethernet subsystem clock register */ + #define ETHSYS_CLKCFG0 0x2c +@@ -398,6 +414,16 @@ + #define SGMSYS_QPHY_PWR_STATE_CTRL 0xe8 + #define SGMII_PHYA_PWD BIT(4) + ++/* Infrasys subsystem config registers */ ++#define INFRA_MISC2 0x70c ++#define CO_QPHY_SEL BIT(0) ++#define GEPHY_MAC_SEL BIT(1) ++ ++/*MDIO control*/ ++#define MII_MMD_ACC_CTL_REG 0x0d ++#define MII_MMD_ADDR_DATA_REG 0x0e ++#define MMD_OP_MODE_DATA BIT(14) ++ + struct mtk_rx_dma { + unsigned int rxd1; + unsigned int rxd2; +@@ -462,15 +488,21 @@ enum mtk_tx_flags { + */ + enum mtk_clks_map { + MTK_CLK_ETHIF, ++ MTK_CLK_SGMIITOP, + MTK_CLK_ESW, + MTK_CLK_GP0, + MTK_CLK_GP1, + MTK_CLK_GP2, ++ MTK_CLK_FE, + MTK_CLK_TRGPLL, + MTK_CLK_SGMII_TX_250M, + MTK_CLK_SGMII_RX_250M, + MTK_CLK_SGMII_CDR_REF, + MTK_CLK_SGMII_CDR_FB, ++ MTK_CLK_SGMII2_TX_250M, ++ MTK_CLK_SGMII2_RX_250M, ++ MTK_CLK_SGMII2_CDR_REF, ++ MTK_CLK_SGMII2_CDR_FB, + MTK_CLK_SGMII_CK, + MTK_CLK_ETH2PLL, + MTK_CLK_MAX +@@ -488,6 +520,22 @@ enum mtk_clks_map { + BIT(MTK_CLK_SGMII_CDR_FB) | \ + BIT(MTK_CLK_SGMII_CK) | \ + BIT(MTK_CLK_ETH2PLL)) ++#define LEOPARD_CLKS_BITMAP (BIT(MTK_CLK_ETHIF) | BIT(MTK_CLK_ESW) | \ ++ BIT(MTK_CLK_GP0) | BIT(MTK_CLK_GP1) | \ ++ BIT(MTK_CLK_GP2) | BIT(MTK_CLK_FE) | \ ++ BIT(MTK_CLK_SGMII_TX_250M) | \ ++ BIT(MTK_CLK_SGMII_RX_250M) | \ ++ BIT(MTK_CLK_SGMII_CDR_REF) | \ ++ BIT(MTK_CLK_SGMII_CDR_FB) | \ ++ BIT(MTK_CLK_SGMII2_TX_250M) | \ ++ BIT(MTK_CLK_SGMII2_RX_250M) | \ ++ BIT(MTK_CLK_SGMII2_CDR_REF) | \ ++ BIT(MTK_CLK_SGMII2_CDR_FB) | \ ++ BIT(MTK_CLK_SGMII_CK) | \ ++ BIT(MTK_CLK_ETH2PLL) | BIT(MTK_CLK_SGMIITOP)) ++ ++#define MT7621_CLKS_BITMAP 0 ++ + enum mtk_dev_state { + MTK_HW_INIT, + MTK_RESETTING +@@ -557,35 +605,149 @@ struct mtk_rx_ring { + u32 crx_idx_reg; + }; + +-#define MTK_TRGMII BIT(0) +-#define MTK_GMAC1_TRGMII (BIT(1) | MTK_TRGMII) +-#define MTK_ESW BIT(4) +-#define MTK_GMAC1_ESW (BIT(5) | MTK_ESW) +-#define MTK_SGMII BIT(8) +-#define MTK_GMAC1_SGMII (BIT(9) | MTK_SGMII) +-#define MTK_GMAC2_SGMII (BIT(10) | MTK_SGMII) +-#define MTK_DUAL_GMAC_SHARED_SGMII (BIT(11) | MTK_GMAC1_SGMII | \ +- MTK_GMAC2_SGMII) ++enum mtk_eth_mux { ++ MTK_ETH_MUX_GDM1_TO_GMAC1_ESW, ++ MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY, ++ MTK_ETH_MUX_U3_GMAC2_TO_QPHY, ++ MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII, ++ MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII, ++ MTK_ETH_MUX_MAX, ++}; ++ ++enum mtk_eth_path { ++ MTK_ETH_PATH_GMAC1_RGMII, ++ MTK_ETH_PATH_GMAC1_TRGMII, ++ MTK_ETH_PATH_GMAC1_SGMII, ++ MTK_ETH_PATH_GMAC2_RGMII, ++ MTK_ETH_PATH_GMAC2_SGMII, ++ MTK_ETH_PATH_GMAC2_GEPHY, ++ MTK_ETH_PATH_GDM1_ESW, ++ MTK_ETH_PATH_MAX, ++}; ++ ++/* Capability for function group */ ++#define MTK_RGMII BIT(0) ++#define MTK_TRGMII BIT(1) ++#define MTK_SGMII BIT(2) ++#define MTK_ESW BIT(3) ++#define MTK_GEPHY BIT(4) ++#define MTK_MUX BIT(5) ++#define MTK_INFRA BIT(6) ++#define MTK_SHARED_SGMII BIT(7) ++ ++/* Capability for features on SoCs */ ++#define MTK_PATH_BIT(x) BIT((x) + 10) ++ ++#define MTK_GMAC1_RGMII \ ++ (MTK_PATH_BIT(MTK_ETH_PATH_GMAC1_RGMII) | MTK_RGMII) ++ ++#define MTK_GMAC1_TRGMII \ ++ (MTK_PATH_BIT(MTK_ETH_PATH_GMAC1_TRGMII) | MTK_TRGMII) ++ ++#define MTK_GMAC1_SGMII \ ++ (MTK_PATH_BIT(MTK_ETH_PATH_GMAC1_SGMII) | MTK_SGMII) ++ ++#define MTK_GMAC2_RGMII \ ++ (MTK_PATH_BIT(MTK_ETH_PATH_GMAC2_RGMII) | MTK_RGMII) ++ ++#define MTK_GMAC2_SGMII \ ++ (MTK_PATH_BIT(MTK_ETH_PATH_GMAC2_SGMII) | MTK_SGMII) ++ ++#define MTK_GMAC2_GEPHY \ ++ (MTK_PATH_BIT(MTK_ETH_PATH_GMAC2_GEPHY) | MTK_GEPHY) ++ ++#define MTK_GDM1_ESW \ ++ (MTK_PATH_BIT(MTK_ETH_PATH_GDM1_ESW) | MTK_ESW) ++ ++#define MTK_MUX_BIT(x) BIT((x) + 20) ++ ++/* Capability for MUXes present on SoCs */ ++/* 0: GDM1 -> GMAC1, 1: GDM1 -> ESW */ ++#define MTK_MUX_GDM1_TO_GMAC1_ESW \ ++ (MTK_MUX_BIT(MTK_ETH_MUX_GDM1_TO_GMAC1_ESW) | MTK_MUX) ++ ++/* 0: GMAC2 -> GEPHY, 1: GMAC0 -> GePHY */ ++#define MTK_MUX_GMAC2_GMAC0_TO_GEPHY \ ++ (MTK_MUX_BIT(MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY) | MTK_MUX | MTK_INFRA) ++ ++/* 0: U3 -> QPHY, 1: GMAC2 -> QPHY */ ++#define MTK_MUX_U3_GMAC2_TO_QPHY \ ++ (MTK_MUX_BIT(MTK_ETH_MUX_U3_GMAC2_TO_QPHY) | MTK_MUX | MTK_INFRA) ++ ++/* 2: GMAC1 -> SGMII, 3: GMAC2 -> SGMII */ ++#define MTK_MUX_GMAC1_GMAC2_TO_SGMII_RGMII \ ++ (MTK_MUX_BIT(MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII) | MTK_MUX | \ ++ MTK_SHARED_SGMII) ++ ++/* 0: GMACx -> GEPHY, 1: GMACx -> SGMII where x is 1 or 2 */ ++#define MTK_MUX_GMAC12_TO_GEPHY_SGMII \ ++ (MTK_MUX_BIT(MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII) | MTK_MUX) ++ + #define MTK_HWLRO BIT(12) ++ + #define MTK_HAS_CAPS(caps, _x) (((caps) & (_x)) == (_x)) + ++#define MT7622_CAPS (MTK_GMAC1_RGMII | MTK_GMAC1_SGMII | MTK_GMAC2_RGMII | \ ++ MTK_GMAC2_SGMII | MTK_GDM1_ESW | \ ++ MTK_MUX_GDM1_TO_GMAC1_ESW | \ ++ MTK_MUX_GMAC1_GMAC2_TO_SGMII_RGMII) ++ ++#define MT7623_CAPS (MTK_GMAC1_RGMII | MTK_GMAC1_TRGMII | MTK_GMAC2_RGMII) ++ ++#define LEOPARD_CAPS (MTK_GMAC1_SGMII | MTK_GMAC2_SGMII | MTK_GMAC2_GEPHY | \ ++ MTK_GDM1_ESW | MTK_MUX_GDM1_TO_GMAC1_ESW | \ ++ MTK_MUX_GMAC2_GMAC0_TO_GEPHY | \ ++ MTK_MUX_U3_GMAC2_TO_QPHY | \ ++ MTK_MUX_GMAC12_TO_GEPHY_SGMII) ++ ++#define MT7621_CAPS (MTK_GMAC1_RGMII | MTK_GMAC1_TRGMII | MTK_GMAC2_RGMII) ++ + /* struct mtk_eth_data - This is the structure holding all differences + * among various plaforms ++ * @ana_rgc3: The offset for register ANA_RGC3 related to ++ * sgmiisys syscon + * @caps Flags shown the extra capability for the SoC + * @required_clks Flags shown the bitmap for required clocks on + * the target SoC + * @required_pctl A bool value to show whether the SoC requires + * the extra setup for those pins used by GMAC. ++ * @irq_num total eth irq num support in target SoC + */ + struct mtk_soc_data { ++ u32 ana_rgc3; + u32 caps; + u32 required_clks; + bool required_pctl; ++ u32 irq_num; + }; + + /* currently no SoC has more than 2 macs */ + #define MTK_MAX_DEVS 2 + ++struct mtk_eth_debug { ++ struct dentry *root; ++}; ++ ++#define MTK_SGMII_PHYSPEED_AN BIT(31) ++#define MTK_SGMII_PHYSPEED_MASK GENMASK(0, 2) ++#define MTK_SGMII_PHYSPEED_1000 BIT(0) ++#define MTK_SGMII_PHYSPEED_2500 BIT(1) ++#define MTK_HAS_FLAGS(flags, _x) (((flags) & (_x)) == (_x)) ++ ++/* struct mtk_sgmii - This is the structure holding sgmii regmap and its ++ * characteristics ++ * @regmap: The register map pointing at the range used to setup ++ * SGMII modes ++ * @flags: The enum refers to which mode the sgmii wants to run on ++ * @ana_rgc3: The offset refers to register ANA_RGC3 related to regmap ++ */ ++ ++struct mtk_sgmii { ++ struct regmap *regmap[MTK_MAX_DEVS]; ++ u32 flags[MTK_MAX_DEVS]; ++ u32 ana_rgc3; ++}; ++ + /* struct mtk_eth - This is the main datasructure for holding the state + * of the driver + * @dev: The device pointer +@@ -601,14 +763,15 @@ struct mtk_soc_data { + * @msg_enable: Ethtool msg level + * @ethsys: The register map pointing at the range used to setup + * MII modes +- * @sgmiisys: The register map pointing at the range used to setup +- * SGMII modes ++ * @infra: The register map pointing at the range used to setup ++ * SGMII and GePHY path + * @pctl: The register map pointing at the range used to setup + * GMAC port drive/slew values + * @dma_refcnt: track how many netdevs are using the DMA engine + * @tx_ring: Pointer to the memory holding info about the TX ring + * @rx_ring: Pointer to the memory holding info about the RX ring +- * @rx_ring_qdma: Pointer to the memory holding info about the QDMA RX ring ++ * @rx_ring_qdma: Pointer to the memory holding info about the QDMA RX ++ * ring + * @tx_napi: The TX NAPI struct + * @rx_napi: The RX NAPI struct + * @scratch_ring: Newer SoCs need memory for a second HW managed TX ring +@@ -619,13 +782,16 @@ struct mtk_soc_data { + * @pending_work: The workqueue used to reset the dma ring + * @state: Initialization and runtime state of the device + * @soc: Holding specific data among vaious SoCs ++ * @debug: Holding specific data for mtk_eth_dbg usage. + */ + + struct mtk_eth { + struct device *dev; + void __iomem *base; + spinlock_t page_lock; ++ /* spin_lock for enable/disable tx irq critial section */ + spinlock_t tx_irq_lock; ++ /* spin_lock for enable/disable rx irq critial section */ + spinlock_t rx_irq_lock; + struct net_device dummy_dev; + struct net_device *netdev[MTK_MAX_DEVS]; +@@ -634,10 +800,11 @@ struct mtk_eth { + u32 msg_enable; + unsigned long sysclk; + struct regmap *ethsys; +- struct regmap *sgmiisys; ++ struct regmap *infra; ++ struct mtk_sgmii *sgmii; + struct regmap *pctl; + bool hwlro; +- refcount_t dma_refcnt; ++ atomic_t dma_refcnt; + struct mtk_tx_ring tx_ring; + struct mtk_rx_ring rx_ring[MTK_MAX_RX_RING_NUM]; + struct mtk_rx_ring rx_ring_qdma; +@@ -653,6 +820,7 @@ struct mtk_eth { + unsigned long state; + + const struct mtk_soc_data *soc; ++ struct mtk_eth_debug debug; + }; + + /* struct mtk_mac - the structure that holds the info about the MACs of the +@@ -664,6 +832,7 @@ struct mtk_eth { + * @hw_stats: Packet statistics counter + * @trgmii Indicate if the MAC uses TRGMII connected to internal + switch ++ * @phy_dev: The attached PHY if available + */ + struct mtk_mac { + int id; +@@ -674,6 +843,7 @@ struct mtk_mac { + __be32 hwlro_ip[MTK_MAX_LRO_IP_CNT]; + int hwlro_ip_cnt; + bool trgmii; ++ struct phy_device *phy_dev; + }; + + /* the struct describing the SoC. these are declared in the soc_xyz.c files */ +@@ -685,4 +855,10 @@ void mtk_stats_update_mac(struct mtk_mac + void mtk_w32(struct mtk_eth *eth, u32 val, unsigned reg); + u32 mtk_r32(struct mtk_eth *eth, unsigned reg); + ++int mtk_sgmii_init(struct mtk_sgmii *ss, struct device_node *np, ++ u32 ana_rgc3); ++int mtk_sgmii_setup_mode_an(struct mtk_sgmii *ss, int id); ++int mtk_sgmii_setup_mode_force(struct mtk_sgmii *ss, int id); ++int mtk_setup_hw_path(struct mtk_eth *eth, int mac_id, int phymode); ++ + #endif /* MTK_ETH_H */ +Index: linux-4.19.57/drivers/net/ethernet/mediatek/mtk_sgmii.c +=================================================================== +--- /dev/null ++++ linux-4.19.57/drivers/net/ethernet/mediatek/mtk_sgmii.c +@@ -0,0 +1,114 @@ ++/* ++ * Copyright (C) 2018 MediaTek Inc. ++ * ++ * 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 of the License ++ * ++ * 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. ++ * ++ * Copyright (C) 2018 Sean Wang <sean.wang@mediatek.com> ++ */ ++ ++#include <linux/mfd/syscon.h> ++#include <linux/of.h> ++#include <linux/regmap.h> ++ ++#include "mtk_eth_soc.h" ++ ++int mtk_sgmii_init(struct mtk_sgmii *ss, struct device_node *r, u32 ana_rgc3) ++{ ++ struct device_node *np; ++ const char *str; ++ int i, err; ++ ++ ss->ana_rgc3 = ana_rgc3; ++ ++ for (i = 0; i < MTK_MAX_DEVS; i++) { ++ np = of_parse_phandle(r, "mediatek,sgmiisys", i); ++ if (!np) ++ break; ++ ++ ss->regmap[i] = syscon_node_to_regmap(np); ++ if (IS_ERR(ss->regmap[i])) ++ return PTR_ERR(ss->regmap[i]); ++ ++ err = of_property_read_string(np, "mediatek,physpeed", &str); ++ if (err) ++ return err; ++ ++ if (!strcmp(str, "2500")) ++ pr_info("sean debug physpeed = 2500\n"); ++ ++ if (!strcmp(str, "2500")) ++ ss->flags[i] |= MTK_SGMII_PHYSPEED_2500; ++ else if (!strcmp(str, "1000")) ++ ss->flags[i] |= MTK_SGMII_PHYSPEED_1000; ++ else if (!strcmp(str, "auto")) ++ ss->flags[i] |= MTK_SGMII_PHYSPEED_AN; ++ else ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++int mtk_sgmii_setup_mode_an(struct mtk_sgmii *ss, int id) ++{ ++ unsigned int val; ++ ++ if (!ss->regmap[id]) ++ return -EINVAL; ++ ++ /* Setup the link timer and QPHY power up inside SGMIISYS */ ++ regmap_write(ss->regmap[id], SGMSYS_PCS_LINK_TIMER, ++ SGMII_LINK_TIMER_DEFAULT); ++ ++ regmap_read(ss->regmap[id], SGMSYS_SGMII_MODE, &val); ++ val |= SGMII_REMOTE_FAULT_DIS; ++ regmap_write(ss->regmap[id], SGMSYS_SGMII_MODE, val); ++ ++ regmap_read(ss->regmap[id], SGMSYS_PCS_CONTROL_1, &val); ++ val |= SGMII_AN_RESTART; ++ regmap_write(ss->regmap[id], SGMSYS_PCS_CONTROL_1, val); ++ ++ regmap_read(ss->regmap[id], SGMSYS_QPHY_PWR_STATE_CTRL, &val); ++ val &= ~SGMII_PHYA_PWD; ++ regmap_write(ss->regmap[id], SGMSYS_QPHY_PWR_STATE_CTRL, val); ++ ++ return 0; ++} ++ ++int mtk_sgmii_setup_mode_force(struct mtk_sgmii *ss, int id) ++{ ++ unsigned int val; ++ int mode; ++ ++ if (!ss->regmap[id]) ++ return -EINVAL; ++ ++ regmap_read(ss->regmap[id], ss->ana_rgc3, &val); ++ val &= ~GENMASK(2, 3); ++ mode = ss->flags[id] & MTK_SGMII_PHYSPEED_MASK; ++ val |= (mode == MTK_SGMII_PHYSPEED_1000) ? 0 : BIT(2); ++ regmap_write(ss->regmap[id], ss->ana_rgc3, val); ++ ++ /* disable SGMII AN */ ++ regmap_read(ss->regmap[id], SGMSYS_PCS_CONTROL_1, &val); ++ val &= ~BIT(12); ++ regmap_write(ss->regmap[id], SGMSYS_PCS_CONTROL_1, val); ++ ++ /* SGMII force mode setting */ ++ val = 0x31120019; ++ regmap_write(ss->regmap[id], SGMSYS_SGMII_MODE, val); ++ ++ /* Release PHYA power down state */ ++ regmap_read(ss->regmap[id], SGMSYS_QPHY_PWR_STATE_CTRL, &val); ++ val &= ~SGMII_PHYA_PWD; ++ regmap_write(ss->regmap[id], SGMSYS_QPHY_PWR_STATE_CTRL, val); ++ ++ return 0; ++} diff --git a/target/linux/mediatek/patches-4.19/0003-mt7531-gsw-internal_phy_calibration.patch b/target/linux/mediatek/patches-4.19/0003-mt7531-gsw-internal_phy_calibration.patch new file mode 100644 index 0000000000..6eba4017d7 --- /dev/null +++ b/target/linux/mediatek/patches-4.19/0003-mt7531-gsw-internal_phy_calibration.patch @@ -0,0 +1,1259 @@ +--- a/drivers/net/phy/mtk/mt753x/Makefile ++++ b/drivers/net/phy/mtk/mt753x/Makefile +@@ -5,6 +5,6 @@ + obj-$(CONFIG_MT753X_GSW) += mt753x.o + + mt753x-y += mt753x_mdio.o mt7530.o mt7531.o \ +- mt753x_common.o mt753x_nl.o ++ mt753x_common.o mt753x_nl.o mt753x_phy.o + + +--- a/drivers/net/phy/mtk/mt753x/mt7531.c ++++ b/drivers/net/phy/mtk/mt753x/mt7531.c +@@ -454,6 +454,21 @@ static void mt7531_core_pll_setup(struct gsw_mt753x *gsw) + + static int mt7531_internal_phy_calibration(struct gsw_mt753x *gsw) + { ++ u32 i; ++ int ret; ++ ++ dev_info(gsw->dev,">>>>>>>>>>>>>>>>>>>>>>>>>>>>> START CALIBRATION:\n"); ++ for (i = 0; i < 5; i++) { ++ dev_info(gsw->dev, "-------- gephy-calbration (port:%d) --------\n", ++ i); ++ ret = mt753x_phy_calibration(gsw, i); ++ ++ /* set Auto-negotiation with giga extension. */ ++ gsw->mii_write(gsw, i, 0, 0x1340); ++ if (ret) ++ return ret; ++ } ++ + return 0; + } + +--- a/drivers/net/phy/mtk/mt753x/mt753x.h ++++ b/drivers/net/phy/mtk/mt753x/mt753x.h +@@ -141,6 +141,8 @@ void mt753x_mmd_ind_write(struct gsw_mt753x *gsw, int addr, int devad, u16 reg, + void mt753x_irq_worker(struct work_struct *work); + void mt753x_irq_enable(struct gsw_mt753x *gsw); + ++int mt753x_phy_calibration(struct gsw_mt753x *gsw, u8 phyaddr); ++ + /* MDIO Indirect Access Registers */ + #define MII_MMD_ACC_CTL_REG 0x0d + #define MMD_CMD_S 14 +--- /dev/null ++++ b/drivers/net/phy/mtk/mt753x/mt753x_phy.c +@@ -0,0 +1,1061 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Common part for MediaTek MT753x gigabit switch ++ * ++ * Copyright (C) 2018 MediaTek Inc. All Rights Reserved. ++ * ++ * Author: Weijie Gao <weijie.gao@mediatek.com> ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/delay.h> ++ ++#include "mt753x.h" ++#include "mt753x_regs.h" ++#include "mt753x_phy.h" ++ ++u32 tc_phy_read_dev_reg(struct gsw_mt753x *gsw, u32 port_num, u32 dev_addr, u32 reg_addr) ++{ ++ u32 phy_val; ++ phy_val = gsw->mmd_read(gsw, port_num, dev_addr, reg_addr); ++ ++ //printk("switch phy cl45 r %d 0x%x 0x%x = %x\n",port_num, dev_addr, reg_addr, phy_val); ++ //switch_phy_read_cl45(port_num, dev_addr, reg_addr, &phy_val); ++ return phy_val; ++} ++ ++void tc_phy_write_dev_reg(struct gsw_mt753x *gsw, u32 port_num, u32 dev_addr, u32 reg_addr, u32 write_data) ++{ ++ u32 phy_val; ++ gsw->mmd_write(gsw, port_num, dev_addr, reg_addr, write_data); ++ phy_val = gsw->mmd_read(gsw, port_num, dev_addr, reg_addr); ++ //printk("switch phy cl45 w %d 0x%x 0x%x 0x%x --> read back 0x%x\n",port_num, dev_addr, reg_addr, write_data, phy_val); ++ //switch_phy_write_cl45(port_num, dev_addr, reg_addr, write_data); ++} ++ ++void switch_phy_write(struct gsw_mt753x *gsw, u32 port_num, u32 reg_addr, u32 write_data){ ++ gsw->mii_write(gsw, port_num, reg_addr, write_data); ++} ++ ++u32 switch_phy_read(struct gsw_mt753x *gsw, u32 port_num, u32 reg_addr){ ++ return gsw->mii_read(gsw, port_num, reg_addr); ++} ++ ++const u8 MT753x_ZCAL_TO_R50ohm_GE_TBL_100[64] = { ++ 127, 127, 127, 127, 127, 127, 127, 127, ++ 127, 127, 127, 127, 127, 123, 122, 117, ++ 115, 112, 103, 100, 98, 87, 85, 83, ++ 81, 72, 70, 68, 66, 64, 55, 53, ++ 52, 50, 49, 48, 38, 36, 35, 34, ++ 33, 32, 22, 21, 20, 19, 18, 17, ++ 16, 7, 6, 5, 4, 3, 2, 1, ++ 0, 0, 0, 0, 0, 0, 0, 0 ++}; ++ ++const u8 MT753x_TX_OFFSET_TBL[64] = { ++ 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, ++ 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, ++ 0xf, 0xe, 0xd, 0xc, 0xb, 0xa, 0x9, 0x8, ++ 0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1, 0x0, ++ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, ++ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, ++ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, ++ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f ++}; ++ ++u8 ge_cal_flag; ++ ++u8 all_ge_ana_cal_wait(struct gsw_mt753x *gsw, u32 delay, u32 phyaddr) // for EN7512 ++{ ++ u8 all_ana_cal_status; ++ u32 cnt, tmp_1e_17c; ++ //tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x017c, 0x0001); // da_calin_flag pull high ++ tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x17c, 0x0001); ++ //printk("delay = %d\n", delay); ++ ++ cnt = 10000; ++ do { ++ udelay(delay); ++ cnt--; ++ all_ana_cal_status = tc_phy_read_dev_reg(gsw, PHY0, 0x1e, 0x17b) & 0x1; ++ ++ } while ((all_ana_cal_status == 0) && (cnt != 0)); ++ ++ ++ if(all_ana_cal_status == 1) { ++ tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x17c, 0); ++ return all_ana_cal_status; ++ } else { ++ tmp_1e_17c = tc_phy_read_dev_reg(gsw, PHY0, 0x1e, 0x17c); ++ if ((tmp_1e_17c & 0x1) != 1) { ++ pr_info("FIRST MDC/MDIO write error\n"); ++ pr_info("FIRST 1e_17c = %x\n", tc_phy_read_dev_reg(gsw, PHY0, 0x1e, 0x17c)); ++ ++ } ++ printk("re-K again\n"); ++ ++ tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x17c, 0); ++ tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x17c, 0x0001); ++ cnt = 10000; ++ do { ++ udelay(delay); ++ cnt--; ++ tmp_1e_17c = tc_phy_read_dev_reg(gsw, PHY0, 0x1e, 0x17c); ++ if ((tmp_1e_17c & 0x1) != 1) { ++ pr_info("SECOND MDC/MDIO write error\n"); ++ pr_info("SECOND 1e_17c = %x\n", tc_phy_read_dev_reg(gsw, PHY0, 0x1e, 0x17c)); ++ tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x17c, 0x0001); ++ tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x17c, 0x0001); ++ tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x17c, 0x0001); ++ } ++ } while ((cnt != 0) && (tmp_1e_17c == 0)); ++ ++ cnt = 10000; ++ do { ++ udelay(delay); ++ cnt--; ++ all_ana_cal_status = tc_phy_read_dev_reg(gsw, PHY0, 0x1e, 0x17b) & 0x1; ++ ++ } while ((all_ana_cal_status == 0) && (cnt != 0)); ++ ++ tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x17c, 0); ++ } ++ ++ if(all_ana_cal_status == 0){ ++ pr_info("!!!!!!!!!!!! dev1Eh_reg17b ERROR\n"); ++ } ++ ++ return all_ana_cal_status; ++} ++ ++ ++ ++ ++int ge_cal_rext(struct gsw_mt753x *gsw, u8 phyaddr, u32 delay) ++{ ++ u8 rg_zcal_ctrl, all_ana_cal_status; ++ u16 ad_cal_comp_out_init; ++ u16 dev1e_e0_ana_cal_r5; ++ int calibration_polarity; ++ u8 cnt = 0; ++ u16 dev1e_17a_tmp, dev1e_e0_tmp; ++ ++ /* *** Iext/Rext Cal start ************ */ ++ all_ana_cal_status = ANACAL_INIT; ++ /* analog calibration enable, Rext calibration enable */ ++ /* 1e_db[12]:rg_cal_ckinv, [8]:rg_ana_calen, [4]:rg_rext_calen, [0]:rg_zcalen_a */ ++ /* 1e_dc[0]:rg_txvos_calen */ ++ /* 1e_e1[4]:rg_cal_refsel(0:1.2V) */ ++ //tc_phy_write_dev_reg(phyaddr, 0x1e, 0x00db, 0x1110) ++ tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x00db, 0x1110); ++ //tc_phy_write_dev_reg(phyaddr, 0x1e, 0x00dc, 0x0000); ++ tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x00dc, 0); ++ //tc_phy_write_dev_reg(phyaddr, 0x1e, 0x00e1, 0x0000); ++ //tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x00e1, 0x10); ++ ++ rg_zcal_ctrl = 0x20;/* start with 0 dB */ ++ dev1e_e0_ana_cal_r5 = tc_phy_read_dev_reg(gsw, PHY0, 0x1e, 0xe0); // get default value ++ /* 1e_e0[5:0]:rg_zcal_ctrl */ ++ tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0xe0, rg_zcal_ctrl); ++ all_ana_cal_status = all_ge_ana_cal_wait(gsw, delay, phyaddr);/* delay 20 usec */ ++ ++ if (all_ana_cal_status == 0) { ++ all_ana_cal_status = ANACAL_ERROR; ++ printk(" GE Rext AnaCal ERROR init! \r\n"); ++ return -1; ++ } ++ /* 1e_17a[8]:ad_cal_comp_out */ ++ ad_cal_comp_out_init = (tc_phy_read_dev_reg(gsw, PHY0, 0x1e, 0x017a) >> 8) & 0x1; ++ if (ad_cal_comp_out_init == 1) ++ calibration_polarity = -1; ++ else /* ad_cal_comp_out_init == 0 */ ++ calibration_polarity = 1; ++ cnt = 0; ++ while (all_ana_cal_status < ANACAL_ERROR) { ++ cnt++; ++ rg_zcal_ctrl += calibration_polarity; ++ tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0xe0, (rg_zcal_ctrl)); ++ all_ana_cal_status = all_ge_ana_cal_wait(gsw, delay, phyaddr); /* delay 20 usec */ ++ dev1e_17a_tmp = tc_phy_read_dev_reg(gsw, PHY0, 0x1e, 0x017a); ++ if (all_ana_cal_status == 0) { ++ all_ana_cal_status = ANACAL_ERROR; ++ printk(" GE Rext AnaCal ERROR 2! \r\n"); ++ return -1; ++ } else if (((dev1e_17a_tmp >> 8) & 0x1) != ad_cal_comp_out_init) { ++ all_ana_cal_status = ANACAL_FINISH; ++ //printk(" GE Rext AnaCal Done! (%d)(0x%x) \r\n", cnt, rg_zcal_ctrl); ++ } else { ++ dev1e_17a_tmp = tc_phy_read_dev_reg(gsw, PHY0, 0x1e, 0x017a); ++ dev1e_e0_tmp = tc_phy_read_dev_reg(gsw, PHY0, 0x1e, 0xe0); ++ if ((rg_zcal_ctrl == 0x3F) || (rg_zcal_ctrl == 0x00)) { ++ all_ana_cal_status = ANACAL_SATURATION; /* need to FT(IC fail?) */ ++ printk(" GE Rext AnaCal Saturation! \r\n"); ++ rg_zcal_ctrl = 0x20; /* 0 dB */ ++ } ++ } ++ } ++ ++ if (all_ana_cal_status == ANACAL_ERROR) { ++ rg_zcal_ctrl = 0x20; /* 0 dB */ ++ tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x00e0, (dev1e_e0_ana_cal_r5 | rg_zcal_ctrl)); ++ } else if(all_ana_cal_status == ANACAL_FINISH){ ++ //tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x00e0, (dev1e_e0_ana_cal_r5 | rg_zcal_ctrl)); ++ tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x00e0, ((rg_zcal_ctrl << 8) | rg_zcal_ctrl)); ++ printk("0x1e-e0 = %x\n", tc_phy_read_dev_reg(gsw, PHY0, 0x1e, 0x00e0)); ++ /* **** 1f_115[2:0] = rg_zcal_ctrl[5:3] // Mog review */ ++ tc_phy_write_dev_reg(gsw, PHY0, 0x1f, 0x0115, ((rg_zcal_ctrl & 0x3f) >> 3)); ++ printk("0x1f-115 = %x\n", tc_phy_read_dev_reg(gsw, PHY0, 0x1f, 0x115)); ++ printk(" GE Rext AnaCal Done! (%d)(0x%x) \r\n", cnt, rg_zcal_ctrl); ++ ge_cal_flag = 1; ++ } else { ++ printk("GE Rxet cal something wrong2\n"); ++ } ++ tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x00db, 0x0000); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x00db, 0x0000); ++ tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x00dc, 0x0000); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x00dc, 0x0000); ++} ++ ++//----------------------------------------------------------------- ++int ge_cal_r50(struct gsw_mt753x *gsw, u8 phyaddr, u32 delay) ++{ ++ u8 rg_zcal_ctrl, all_ana_cal_status, calibration_pair; ++ u16 ad_cal_comp_out_init; ++ u16 dev1e_e0_ana_cal_r5; ++ int calibration_polarity; ++ u8 cnt = 0; ++ tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x00db, 0x1100); // 1e_db[12]:rg_cal_ckinv, [8]:rg_ana_calen, [4]:rg_rext_calen, [0]:rg_zcalen_a ++ tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x00dc, 0x0000); // 1e_dc[0]:rg_txvos_calen ++ ++ for(calibration_pair = ANACAL_PAIR_A; calibration_pair <= ANACAL_PAIR_D; calibration_pair ++) { ++ rg_zcal_ctrl = 0x20; // start with 0 dB ++ dev1e_e0_ana_cal_r5 = (tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x00e0) & (~0x003f)); ++ tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x00e0, (dev1e_e0_ana_cal_r5 | rg_zcal_ctrl)); // 1e_e0[5:0]:rg_zcal_ctrl ++ if(calibration_pair == ANACAL_PAIR_A) ++ { ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x00db, 0x1101); // 1e_db[12]:rg_cal_ckinv, [8]:rg_ana_calen, [4]:rg_rext_calen, [0]:rg_zcalen_a ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x00dc, 0x0000); ++ //printk("R50 pair A 1e_db=%x 1e_db=%x\n", tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x00db), tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x00dc)); ++ ++ } ++ else if(calibration_pair == ANACAL_PAIR_B) ++ { ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x00db, 0x1100); // 1e_db[12]:rg_cal_ckinv, [8]:rg_ana_calen, [4]:rg_rext_calen, [0]:rg_zcalen_a ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x00dc, 0x1000); // 1e_dc[12]:rg_zcalen_b ++ //printk("R50 pair B 1e_db=%x 1e_db=%x\n", tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x00db),tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x00dc)); ++ ++ } ++ else if(calibration_pair == ANACAL_PAIR_C) ++ { ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x00db, 0x1100); // 1e_db[12]:rg_cal_ckinv, [8]:rg_ana_calen, [4]:rg_rext_calen, [0]:rg_zcalen_a ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x00dc, 0x0100); // 1e_dc[8]:rg_zcalen_c ++ //printk("R50 pair C 1e_db=%x 1e_db=%x\n", tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x00db), tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x00dc)); ++ ++ } ++ else // if(calibration_pair == ANACAL_PAIR_D) ++ { ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x00db, 0x1100); // 1e_db[12]:rg_cal_ckinv, [8]:rg_ana_calen, [4]:rg_rext_calen, [0]:rg_zcalen_a ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x00dc, 0x0010); // 1e_dc[4]:rg_zcalen_d ++ //printk("R50 pair D 1e_db=%x 1e_db=%x\n", tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x00db), tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x00dc)); ++ ++ } ++ ++ all_ana_cal_status = all_ge_ana_cal_wait(gsw, delay, phyaddr); // delay 20 usec ++ if(all_ana_cal_status == 0) ++ { ++ all_ana_cal_status = ANACAL_ERROR; ++ printk( "GE R50 AnaCal ERROR init! \r\n"); ++ return -1; ++ } ++ ++ ad_cal_comp_out_init = (tc_phy_read_dev_reg(gsw, PHY0, 0x1e, 0x017a)>>8) & 0x1; // 1e_17a[8]:ad_cal_comp_out ++ if(ad_cal_comp_out_init == 1) ++ calibration_polarity = -1; ++ else ++ calibration_polarity = 1; ++ ++ cnt = 0; ++ while(all_ana_cal_status < ANACAL_ERROR) ++ { ++ cnt ++; ++ rg_zcal_ctrl += calibration_polarity; ++ tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x00e0, (dev1e_e0_ana_cal_r5 | rg_zcal_ctrl)); ++ all_ana_cal_status = all_ge_ana_cal_wait(gsw, delay, phyaddr); // delay 20 usec ++ ++ if(all_ana_cal_status == 0) ++ { ++ all_ana_cal_status = ANACAL_ERROR; ++ printk( " GE R50 AnaCal ERROR 2! \r\n"); ++ return -1; ++ } ++ else if(((tc_phy_read_dev_reg(gsw, PHY0, 0x1e, 0x017a)>>8)&0x1) != ad_cal_comp_out_init) ++ { ++ all_ana_cal_status = ANACAL_FINISH; ++ } ++ else { ++ if((rg_zcal_ctrl == 0x3F)||(rg_zcal_ctrl == 0x00)) ++ { ++ all_ana_cal_status = ANACAL_SATURATION; // need to FT ++ printk( " GE R50 AnaCal Saturation! \r\n"); ++ } ++ } ++ } ++ ++ if(all_ana_cal_status == ANACAL_ERROR) { ++ rg_zcal_ctrl = 0x20; // 0 dB ++ //tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x00e0, (dev1e_e0_ana_cal_r5 | rg_zcal_ctrl)); ++ } ++ else { ++ rg_zcal_ctrl = MT753x_ZCAL_TO_R50ohm_GE_TBL_100[rg_zcal_ctrl - 9]; // wait Mog zcal/r50 mapping table ++ printk( " GE R50 AnaCal Done! (%d) (0x%x)(0x%x) \r\n", cnt, rg_zcal_ctrl, (rg_zcal_ctrl|0x80)); ++ } ++ ++ if(calibration_pair == ANACAL_PAIR_A) { ++ ad_cal_comp_out_init = tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x0174) & (~0x7f00); ++ //ad_cal_comp_out_init = tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x0174); ++ //printk( " GE-a 1e_174(0x%x)(0x%x), 1e_175(0x%x) \r\n", tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x0174), ad_cal_comp_out_init, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x0175)); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x0174, (ad_cal_comp_out_init | (((rg_zcal_ctrl<<8)&0xff00) | 0x8000))); // 1e_174[15:8] ++ //printk( " GE-a 1e_174(0x%x), 1e_175(0x%x) \r\n", tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x0174), tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x0175)); ++ } ++ else if(calibration_pair == ANACAL_PAIR_B) { ++ ad_cal_comp_out_init = tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x0174) & (~0x007f); ++ //ad_cal_comp_out_init = tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x0174); ++ //printk( " GE-b 1e_174(0x%x)(0x%x), 1e_175(0x%x) \r\n", tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x0174), ad_cal_comp_out_init, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x0175)); ++ ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x0174, (ad_cal_comp_out_init | (((rg_zcal_ctrl<<0)&0x00ff) | 0x0080))); // 1e_174[7:0] ++ //printk( " GE-b 1e_174(0x%x), 1e_175(0x%x) \r\n", tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x0174), tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x0175)); ++ } ++ else if(calibration_pair == ANACAL_PAIR_C) { ++ ad_cal_comp_out_init = tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x0175) & (~0x7f00); ++ //ad_cal_comp_out_init = tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x0175); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x0175, (ad_cal_comp_out_init | (((rg_zcal_ctrl<<8)&0xff00) | 0x8000))); // 1e_175[15:8] ++ //printk( " GE-c 1e_174(0x%x), 1e_175(0x%x) \r\n", tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x0174), tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x0175)); ++ } else {// if(calibration_pair == ANACAL_PAIR_D) ++ ad_cal_comp_out_init = tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x0175) & (~0x007f); ++ //ad_cal_comp_out_init = tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x0175); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x0175, (ad_cal_comp_out_init | (((rg_zcal_ctrl<<0)&0x00ff) | 0x0080))); // 1e_175[7:0] ++ //printk( " GE-d 1e_174(0x%x), 1e_175(0x%x) \r\n", tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x0174), tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x0175)); ++ } ++ //tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x00e0, ((rg_zcal_ctrl<<8)|rg_zcal_ctrl)); ++ } ++ ++ printk( " GE 1e_174(0x%x), 1e_175(0x%x) \r\n", tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x0174), tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x0175)); ++ tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x00db, 0x0000); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x00db, 0x0000); ++ tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x00dc, 0x0000); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x00dc, 0x0000); ++} ++ ++int ge_cal_tx_offset(struct gsw_mt753x *gsw, u8 phyaddr, u32 delay) ++{ ++ u8 all_ana_cal_status, calibration_pair; ++ u16 ad_cal_comp_out_init; ++ int calibration_polarity, tx_offset_temp; ++ u8 tx_offset_reg_shift, tabl_idx, i; ++ u8 cnt = 0; ++ u16 tx_offset_reg, reg_temp, cal_temp; ++ //switch_phy_write(phyaddr, R0, 0x2100);//harry tmp ++ tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x00db, 0x0100); // 1e_db[12]:rg_cal_ckinv, [8]:rg_ana_calen, [4]:rg_rext_calen, [0]:rg_zcalen_a ++ tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x00dc, 0x0001); // 1e_dc[0]:rg_txvos_calen ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x0096, 0x8000); // 1e_96[15]:bypass_tx_offset_cal, Hw bypass, Fw cal ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x003e, 0xf808); // 1e_3e ++ for(i = 0; i <= 4; i++) ++ tc_phy_write_dev_reg(gsw, i, 0x1e, 0x00dd, 0x0000); ++ for(calibration_pair = ANACAL_PAIR_A; calibration_pair <= ANACAL_PAIR_D; calibration_pair ++) ++ { ++ tabl_idx = 31; ++ tx_offset_temp = MT753x_TX_OFFSET_TBL[tabl_idx]; ++ ++ if(calibration_pair == ANACAL_PAIR_A) { ++ //tc_phy_write_dev_reg(phyaddr, 0x1e, 0x145, 0x5010); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x00dd, 0x1000); // 1e_dd[12]:rg_txg_calen_a ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x017d, (0x8000|DAC_IN_0V)); // 1e_17d:dac_in0_a ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x0181, (0x8000|DAC_IN_0V)); // 1e_181:dac_in1_a ++ //printk("tx offset pairA 1e_dd = %x, 1e_17d=%x, 1e_181=%x\n", tc_phy_read_dev_reg(phyaddr, 0x1e, 0x00dd), tc_phy_read_dev_reg(phyaddr, 0x1e, 0x017d), tc_phy_read_dev_reg(phyaddr, 0x1e, 0x0181)); ++ reg_temp = (tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x0172) & (~0x3f00)); ++ tx_offset_reg_shift = 8; // 1e_172[13:8] ++ tx_offset_reg = 0x0172; ++ ++ //tc_phy_write_dev_reg(phyaddr, 0x1e, tx_offset_reg, (reg_temp|(tx_offset_temp<<tx_offset_reg_shift))); ++ } else if(calibration_pair == ANACAL_PAIR_B) { ++ //tc_phy_write_dev_reg(phyaddr, 0x1e, 0x145, 0x5018); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x00dd, 0x0100); // 1e_dd[8]:rg_txg_calen_b ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x017e, (0x8000|DAC_IN_0V)); // 1e_17e:dac_in0_b ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x0182, (0x8000|DAC_IN_0V)); // 1e_182:dac_in1_b ++ //printk("tx offset pairB 1e_dd = %x, 1e_17d=%x, 1e_181=%x\n", tc_phy_read_dev_reg(phyaddr, 0x1e, 0x00dd), tc_phy_read_dev_reg(phyaddr, 0x1e, 0x017d), tc_phy_read_dev_reg(phyaddr, 0x1e, 0x0181)); ++ reg_temp = (tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x0172) & (~0x003f)); ++ tx_offset_reg_shift = 0; // 1e_172[5:0] ++ tx_offset_reg = 0x0172; ++ //tc_phy_write_dev_reg(phyaddr, 0x1e, tx_offset_reg, (reg_temp|(tx_offset_temp<<tx_offset_reg_shift))); ++ } else if(calibration_pair == ANACAL_PAIR_C) { ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x00dd, 0x0010); // 1e_dd[4]:rg_txg_calen_c ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x017f, (0x8000|DAC_IN_0V)); // 1e_17f:dac_in0_c ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x0183, (0x8000|DAC_IN_0V)); // 1e_183:dac_in1_c ++ reg_temp = (tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x0173) & (~0x3f00)); ++ //printk("tx offset pairC 1e_dd = %x, 1e_17d=%x, 1e_181=%x\n", tc_phy_read_dev_reg(phyaddr, 0x1e, 0x00dd), tc_phy_read_dev_reg(phyaddr, 0x1e, 0x017d), tc_phy_read_dev_reg(phyaddr, 0x1e, 0x0181)); ++ tx_offset_reg_shift = 8; // 1e_173[13:8] ++ tx_offset_reg = 0x0173; ++ //tc_phy_write_dev_reg(phyaddr, 0x1e, tx_offset_reg, (reg_temp|(tx_offset_temp<<tx_offset_reg_shift))); ++ } else {// if(calibration_pair == ANACAL_PAIR_D) ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x00dd, 0x0001); // 1e_dd[0]:rg_txg_calen_d ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x0180, (0x8000|DAC_IN_0V)); // 1e_180:dac_in0_d ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x0184, (0x8000|DAC_IN_0V)); // 1e_184:dac_in1_d ++ //printk("tx offset pairD 1e_dd = %x, 1e_17d=%x, 1e_181=%x\n", tc_phy_read_dev_reg(phyaddr, 0x1e, 0x00dd), tc_phy_read_dev_reg(phyaddr, 0x1e, 0x017d), tc_phy_read_dev_reg(phyaddr, 0x1e, 0x0181)); ++ reg_temp = (tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x0173) & (~0x003f)); ++ tx_offset_reg_shift = 0; // 1e_173[5:0] ++ tx_offset_reg = 0x0173; ++ //tc_phy_write_dev_reg(phyaddr, 0x1e, tx_offset_reg, (reg_temp|(tx_offset_temp<<tx_offset_reg_shift))); ++ } ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, tx_offset_reg, (reg_temp|(tx_offset_temp<<tx_offset_reg_shift))); // 1e_172, 1e_173 ++ all_ana_cal_status = all_ge_ana_cal_wait(gsw, delay, phyaddr); // delay 20 usec ++ if(all_ana_cal_status == 0) { ++ all_ana_cal_status = ANACAL_ERROR; ++ printk( " GE Tx offset AnaCal ERROR init! \r\n"); ++ return -1; ++ } ++ ++ ad_cal_comp_out_init = (tc_phy_read_dev_reg(gsw, PHY0, 0x1e, 0x017a)>>8) & 0x1; // 1e_17a[8]:ad_cal_comp_out ++ if(ad_cal_comp_out_init == 1) ++ calibration_polarity = 1; ++ else ++ calibration_polarity = -1; ++ ++ cnt = 0; ++ //printk("TX offset cnt = %d, tabl_idx= %x, offset_val = %x\n", cnt, tabl_idx, MT753x_TX_OFFSET_TBL[tabl_idx]); ++ while(all_ana_cal_status < ANACAL_ERROR) { ++ ++ cnt ++; ++ tabl_idx += calibration_polarity; ++ //tx_offset_temp += calibration_polarity; ++ //cal_temp = tx_offset_temp; ++ cal_temp = MT753x_TX_OFFSET_TBL[tabl_idx]; ++ //printk("TX offset cnt = %d, tabl_idx= %x, offset_val = %x\n", cnt, tabl_idx, MT753x_TX_OFFSET_TBL[tabl_idx]); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, tx_offset_reg, (reg_temp|(cal_temp<<tx_offset_reg_shift))); ++ ++ all_ana_cal_status = all_ge_ana_cal_wait(gsw, delay, phyaddr); // delay 20 usec ++ if(all_ana_cal_status == 0) { ++ all_ana_cal_status = ANACAL_ERROR; ++ printk( " GE Tx offset AnaCal ERROR init 2! \r\n"); ++ return -1; ++ } else if(((tc_phy_read_dev_reg(gsw, PHY0, 0x1e, 0x017a)>>8)&0x1) != ad_cal_comp_out_init) { ++ all_ana_cal_status = ANACAL_FINISH; ++ } else { ++ if((tabl_idx == 0)||(tabl_idx == 0x3f)) { ++ all_ana_cal_status = ANACAL_SATURATION; // need to FT ++ printk( " GE Tx offset AnaCal Saturation! \r\n"); ++ } ++ } ++ } ++ ++ if(all_ana_cal_status == ANACAL_ERROR) { ++ tx_offset_temp = TX_AMP_OFFSET_0MV; ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, tx_offset_reg, (reg_temp|(tx_offset_temp<<tx_offset_reg_shift))); ++ } else { ++ printk( " GE Tx offset AnaCal Done! (pair-%d)(%d)(0x%x) 0x1e_%x=0x%x\n", calibration_pair, cnt, MT753x_TX_OFFSET_TBL[tabl_idx], tx_offset_reg, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_offset_reg)); ++ } ++ } ++ ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x017d, 0x0000); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x017e, 0x0000); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x017f, 0x0000); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x0180, 0x0000); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x0181, 0x0000); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x0182, 0x0000); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x0183, 0x0000); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x0184, 0x0000); ++ ++ tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x00db, 0x0000); // disable analog calibration circuit ++ tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x00dc, 0x0000); // disable Tx offset calibration circuit ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x00db, 0x0000); // disable analog calibration circuit ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x00dc, 0x0000); // disable Tx offset calibration circuit ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x003e, 0x0000); // disable Tx VLD force mode ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x00dd, 0x0000); // disable Tx offset/amplitude calibration circuit ++} ++ ++int ge_cal_tx_amp(struct gsw_mt753x *gsw, u8 phyaddr, u32 delay) ++{ ++ u8 all_ana_cal_status, calibration_pair, i; ++ u16 ad_cal_comp_out_init; ++ int calibration_polarity; ++ u32 tx_amp_reg_shift; ++ u16 reg_temp; ++ u32 tx_amp_temp, tx_amp_reg, cnt=0, tx_amp_reg_100; ++ u32 debug_tmp, reg_backup, reg_tmp; ++ tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x00db, 0x1100); // 1e_db[12]:rg_cal_ckinv, [8]:rg_ana_calen, [4]:rg_rext_calen, [0]:rg_zcalen_a ++ tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x00dc, 0x0001); // 1e_dc[0]:rg_txvos_calen ++ tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x00e1, 0x0010); // 1e_e1[4]:select 1V ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x003e, 0xf808); // 1e_3e:enable Tx VLD ++ ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x11, 0xff00); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1f, 0x27a, 0x33); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0xc9, 0xffff); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1f, 0x300, 0x4); ++ for(i = 0; i <= 4; i++) ++ tc_phy_write_dev_reg(gsw, i, 0x1e, 0x00dd, 0x0000); ++ for(calibration_pair = ANACAL_PAIR_A; calibration_pair <= ANACAL_PAIR_D; calibration_pair ++) { ++ tx_amp_temp = 0x20; // start with 0 dB ++ ++ if(calibration_pair == ANACAL_PAIR_A) { ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x00dd, 0x1000); // 1e_dd[12]:tx_a amp calibration enable ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x017d, (0x8000|DAC_IN_2V)); // 1e_17d:dac_in0_a ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x0181, (0x8000|DAC_IN_2V)); // 1e_181:dac_in1_a ++ reg_temp = (tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x012) & (~0xfc00)); ++ tx_amp_reg_shift = 10; // 1e_12[15:10] ++ tx_amp_reg = 0x12; ++ tx_amp_reg_100 = 0x16; ++ } else if(calibration_pair == ANACAL_PAIR_B) { ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x00dd, 0x0100); // 1e_dd[8]:tx_b amp calibration enable ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x017e, (0x8000|DAC_IN_2V)); // 1e_17e:dac_in0_b ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x0182, (0x8000|DAC_IN_2V)); // 1e_182:dac_in1_b ++ reg_temp = (tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x017) & (~0x3f00)); ++ tx_amp_reg_shift = 8; // 1e_17[13:8] ++ tx_amp_reg = 0x17; ++ tx_amp_reg_100 = 0x18; ++ } else if(calibration_pair == ANACAL_PAIR_C) { ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x00dd, 0x0010); // 1e_dd[4]:tx_c amp calibration enable ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x017f, (0x8000|DAC_IN_2V)); // 1e_17f:dac_in0_c ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x0183, (0x8000|DAC_IN_2V)); // 1e_183:dac_in1_c ++ reg_temp = (tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x019) & (~0x3f00)); ++ tx_amp_reg_shift = 8; // 1e_19[13:8] ++ tx_amp_reg = 0x19; ++ tx_amp_reg_100 = 0x20; ++ } else { //if(calibration_pair == ANACAL_PAIR_D) ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x00dd, 0x0001); // 1e_dd[0]:tx_d amp calibration enable ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x0180, (0x8000|DAC_IN_2V)); // 1e_180:dac_in0_d ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x0184, (0x8000|DAC_IN_2V)); // 1e_184:dac_in1_d ++ reg_temp = (tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x021) & (~0x3f00)); ++ tx_amp_reg_shift = 8; // 1e_21[13:8] ++ tx_amp_reg = 0x21; ++ tx_amp_reg_100 = 0x22; ++ } ++ tc_phy_write_dev_reg( gsw, phyaddr, 0x1e, tx_amp_reg, (tx_amp_temp|(tx_amp_temp<<tx_amp_reg_shift))); // 1e_12, 1e_17, 1e_19, 1e_21 ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100, (tx_amp_temp|(tx_amp_temp<<tx_amp_reg_shift))); ++ all_ana_cal_status = all_ge_ana_cal_wait(gsw, delay, phyaddr); // delay 20 usec ++ if(all_ana_cal_status == 0) { ++ all_ana_cal_status = ANACAL_ERROR; ++ printk( " GE Tx amp AnaCal ERROR init init! \r\n"); ++ return -1; ++ } ++ ++ ad_cal_comp_out_init = (tc_phy_read_dev_reg(gsw, PHY0, 0x1e, 0x017a)>>8) & 0x1; // 1e_17a[8]:ad_cal_comp_out ++ if(ad_cal_comp_out_init == 1) ++ calibration_polarity = -1; ++ else ++ calibration_polarity = 1; ++ ++ cnt =0; ++ while(all_ana_cal_status < ANACAL_ERROR) { ++ cnt ++; ++ tx_amp_temp += calibration_polarity; ++ //printk("tx_amp : %x, 1e %x = %x\n", tx_amp_temp, tx_amp_reg, (reg_temp|(tx_amp_temp<<tx_amp_reg_shift))); ++ tc_phy_write_dev_reg( gsw, phyaddr, 0x1e, tx_amp_reg, (tx_amp_temp|(tx_amp_temp<<tx_amp_reg_shift))); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100, (tx_amp_temp|(tx_amp_temp<<tx_amp_reg_shift))); ++ all_ana_cal_status = all_ge_ana_cal_wait(gsw, delay, phyaddr); // delay 20 usec ++ if(all_ana_cal_status == 0) { ++ all_ana_cal_status = ANACAL_ERROR; ++ printk( " GE Tx amp AnaCal ERROR 2! \r\n"); ++ return -1; ++ } else if(((tc_phy_read_dev_reg(gsw, PHY0, 0x1e, 0x017a)>>8)&0x1) != ad_cal_comp_out_init) { ++ //printk("TX AMP ANACAL_FINISH\n"); ++ all_ana_cal_status = ANACAL_FINISH; ++ if (phyaddr == 0) { ++ if (calibration_pair == ANACAL_PAIR_A) ++ tx_amp_temp = tx_amp_temp - 2; ++ else if(calibration_pair == ANACAL_PAIR_B) ++ tx_amp_temp = tx_amp_temp - 1; ++ else if(calibration_pair == ANACAL_PAIR_C) ++ tx_amp_temp = tx_amp_temp - 2; ++ else if(calibration_pair == ANACAL_PAIR_D) ++ tx_amp_temp = tx_amp_temp - 1; ++ } else if (phyaddr == 1) { ++ if (calibration_pair == ANACAL_PAIR_A) ++ tx_amp_temp = tx_amp_temp - 1; ++ else if(calibration_pair == ANACAL_PAIR_B) ++ tx_amp_temp = tx_amp_temp ; ++ else if(calibration_pair == ANACAL_PAIR_C) ++ tx_amp_temp = tx_amp_temp - 1; ++ else if(calibration_pair == ANACAL_PAIR_D) ++ tx_amp_temp = tx_amp_temp - 1; ++ } else if (phyaddr == 2) { ++ if (calibration_pair == ANACAL_PAIR_A) ++ tx_amp_temp = tx_amp_temp; ++ else if(calibration_pair == ANACAL_PAIR_B) ++ tx_amp_temp = tx_amp_temp - 1; ++ else if(calibration_pair == ANACAL_PAIR_C) ++ tx_amp_temp = tx_amp_temp; ++ else if(calibration_pair == ANACAL_PAIR_D) ++ tx_amp_temp = tx_amp_temp - 1; ++ } else if (phyaddr == 3) { ++ tx_amp_temp = tx_amp_temp; ++ } else if (phyaddr == 4) { ++ if (calibration_pair == ANACAL_PAIR_A) ++ tx_amp_temp = tx_amp_temp; ++ else if(calibration_pair == ANACAL_PAIR_B) ++ tx_amp_temp = tx_amp_temp - 1; ++ else if(calibration_pair == ANACAL_PAIR_C) ++ tx_amp_temp = tx_amp_temp; ++ else if(calibration_pair == ANACAL_PAIR_D) ++ tx_amp_temp = tx_amp_temp; ++ } ++ reg_temp = tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg)&(~0xff00); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100,(tx_amp_temp|((tx_amp_temp)<<tx_amp_reg_shift))); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg, (tx_amp_temp|((tx_amp_temp)<<tx_amp_reg_shift))); ++ if (phyaddr == 0) { ++ if ((tx_amp_reg == 0x12) || (tx_amp_reg == 0x17)) { ++ //printk("before : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg)); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg, ((tx_amp_temp|((tx_amp_temp)<<tx_amp_reg_shift)) + 7)); ++ //printk("after : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg)); ++ } ++ if (tx_amp_reg_100 == 0x16) { ++ //printk("before : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg_100, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100)); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100,(tx_amp_temp|((tx_amp_temp+1+4)<<tx_amp_reg_shift))); ++ //printk("after : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg_100, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100)); ++ } ++ if (tx_amp_reg_100 == 0x18) { ++ //printk("before : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg_100, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100)); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100,(tx_amp_temp|((tx_amp_temp+4)<<tx_amp_reg_shift))); ++ //printk("after : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg_100, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100)); ++ } ++ } else if (phyaddr == 1) { ++ if (tx_amp_reg == 0x12) { ++ //printk("before : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg)); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg, ((tx_amp_temp|((tx_amp_temp)<<tx_amp_reg_shift)) + 9)); ++ //printk("after : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg)); ++ } ++ if (tx_amp_reg == 0x17){ ++ //printk("before : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg)); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg, ((tx_amp_temp|((tx_amp_temp)<<tx_amp_reg_shift)) + 7)); ++ //printk("after : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg)); ++ } ++ if (tx_amp_reg_100 == 0x16) { ++ //printk("before : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg_100, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100)); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100,(tx_amp_temp|((tx_amp_temp+4)<<tx_amp_reg_shift))); ++ //printk("after : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg_100, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100)); ++ } ++ if (tx_amp_reg_100 == 0x18) { ++ //printk("before : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg_100, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100)); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100,(tx_amp_temp|((tx_amp_temp-1+4)<<tx_amp_reg_shift))); ++ //printk("after : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg_100, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100)); ++ } ++ } else if (phyaddr == 2) { ++ if ((tx_amp_reg == 0x12) || (tx_amp_reg == 0x17)) { ++ //printk("before : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg)); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg, ((tx_amp_temp|((tx_amp_temp)<<tx_amp_reg_shift)) + 6)); ++ //printk("after : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg)); ++ } ++ if ((tx_amp_reg_100 == 0x16) || (tx_amp_reg_100 == 0x18)) { ++ //printk("before : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg_100, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100)); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100,(tx_amp_temp|((tx_amp_temp-1+4)<<tx_amp_reg_shift))); ++ //printk("after : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg_100, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100)); ++ } ++ } else if (phyaddr == 3) { ++ if (tx_amp_reg == 0x12) { ++ //printk("before : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg)); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg, ((tx_amp_temp|((tx_amp_temp)<<tx_amp_reg_shift)) + 4)); ++ //printk("after : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg)); ++ } ++ if (tx_amp_reg == 0x17) { ++ //printk("before : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg)); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg, ((tx_amp_temp|((tx_amp_temp)<<tx_amp_reg_shift)) + 7)); ++ //printk("after : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg)); ++ } ++ if (tx_amp_reg_100 == 0x16) { ++ //printk("before : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg_100, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100)); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100,(tx_amp_temp|((tx_amp_temp-2+4)<<tx_amp_reg_shift))); ++ //printk("after : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg_100, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100)); ++ } ++ if (tx_amp_reg_100 == 0x18) { ++ //printk("before : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg_100, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100)); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100,(tx_amp_temp|((tx_amp_temp-1+3)<<tx_amp_reg_shift))); ++ //printk("after : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg_100, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100)); ++ } ++ } else if (phyaddr == 4) { ++ if ((tx_amp_reg == 0x12) || (tx_amp_reg == 0x17)) { ++ //printk("before : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg)); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg, ((tx_amp_temp|((tx_amp_temp)<<tx_amp_reg_shift)) + 5)); ++ //printk("after : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg)); ++ } ++ if (tx_amp_reg_100 == 0x16) { ++ //printk("before : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg_100, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100)); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100,(tx_amp_temp|((tx_amp_temp-2+4)<<tx_amp_reg_shift))); ++ //printk("after : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg_100, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100)); ++ } ++ if (tx_amp_reg_100 == 0x18) { ++ //printk("before : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg_100, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100)); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100,(tx_amp_temp|((tx_amp_temp-1+4)<<tx_amp_reg_shift))); ++ //printk("after : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg_100, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100)); ++ } ++ } ++ ++ if (calibration_pair == ANACAL_PAIR_A){ ++ reg_backup = tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x12); ++ reg_tmp = ((reg_backup & 0xfc00) >> 10); ++ reg_tmp -= 8; ++ reg_backup = (reg_backup & (~0xfc00)); ++ reg_backup |= (reg_tmp << 10); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x12, reg_backup); ++ reg_backup = tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x12); ++ //printk("PORT[%d] 1e.012 = %x (OFFSET_1000M_PAIR_A)\n", phyaddr, reg_backup); ++ reg_backup = tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x16); ++ reg_tmp = ((reg_backup & 0x3f) >> 0); ++ reg_tmp -= 8; ++ reg_backup = (reg_backup & (~0x3f)); ++ reg_backup |= (reg_tmp << 0); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x16, reg_backup); ++ reg_backup = tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x16); ++ //printk("PORT[%d] 1e.016 = %x (OFFSET_TESTMODE_1000M_PAIR_A)\n", phyaddr, reg_backup); ++ } ++ else if(calibration_pair == ANACAL_PAIR_B){ ++ reg_backup = tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x17); ++ reg_tmp = ((reg_backup & 0x3f00) >> 8); ++ reg_tmp -= 8; ++ reg_backup = (reg_backup & (~0x3f00)); ++ reg_backup |= (reg_tmp << 8); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x17, reg_backup); ++ reg_backup = tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x17); ++ //printk("PORT[%d] 1e.017 = %x (OFFSET_1000M_PAIR_B)\n", phyaddr, reg_backup); ++ reg_backup = tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x18); ++ reg_tmp = ((reg_backup & 0x3f) >> 0); ++ reg_tmp -= 8; ++ reg_backup = (reg_backup & (~0x3f)); ++ reg_backup |= (reg_tmp << 0); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x18, reg_backup); ++ reg_backup = tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x18); ++ //printk("PORT[%d] 1e.018 = %x (OFFSET_TESTMODE_1000M_PAIR_B)\n", phyaddr, reg_backup); ++ } ++ else if(calibration_pair == ANACAL_PAIR_C){ ++ reg_backup = tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x19); ++ reg_tmp = ((reg_backup & 0x3f00) >> 8); ++ reg_tmp -= 8; ++ reg_backup = (reg_backup & (~0x3f00)); ++ reg_backup |= (reg_tmp << 8); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x19, reg_backup); ++ reg_backup = tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x19); ++ //printk("PORT[%d] 1e.019 = %x (OFFSET_1000M_PAIR_C)\n", phyaddr, reg_backup); ++ reg_backup = tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x20); ++ reg_tmp = ((reg_backup & 0x3f) >> 0); ++ reg_tmp -= 8; ++ reg_backup = (reg_backup & (~0x3f)); ++ reg_backup |= (reg_tmp << 0); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x20, reg_backup); ++ reg_backup = tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x20); ++ //printk("PORT[%d] 1e.020 = %x (OFFSET_TESTMODE_1000M_PAIR_C)\n", phyaddr, reg_backup); ++ } ++ else if(calibration_pair == ANACAL_PAIR_D){ ++ reg_backup = tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x21); ++ reg_tmp = ((reg_backup & 0x3f00) >> 8); ++ reg_tmp -= 8; ++ reg_backup = (reg_backup & (~0x3f00)); ++ reg_backup |= (reg_tmp << 8); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x21, reg_backup); ++ reg_backup = tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x21); ++ //printk("PORT[%d] 1e.021 = %x (OFFSET_1000M_PAIR_D)\n", phyaddr, reg_backup); ++ reg_backup = tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x22); ++ reg_tmp = ((reg_backup & 0x3f) >> 0); ++ reg_tmp -= 8; ++ reg_backup = (reg_backup & (~0x3f)); ++ reg_backup |= (reg_tmp << 0); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x22, reg_backup); ++ reg_backup = tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x22); ++ //printk("PORT[%d] 1e.022 = %x (OFFSET_TESTMODE_1000M_PAIR_D)\n", phyaddr, reg_backup); ++ } ++ ++ if (calibration_pair == ANACAL_PAIR_A){ ++ //printk("PORT (%d) TX_AMP PAIR (A) FINAL CALIBRATION RESULT\n", phyaddr); ++ debug_tmp = tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x12); ++ //printk("1e.012 = 0x%x\n", debug_tmp); ++ debug_tmp = tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x16); ++ //printk("1e.016 = 0x%x\n", debug_tmp); ++ } ++ ++ else if(calibration_pair == ANACAL_PAIR_B){ ++ //printk("PORT (%d) TX_AMP PAIR (A) FINAL CALIBRATION RESULT\n", phyaddr); ++ debug_tmp = tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x17); ++ //printk("1e.017 = 0x%x\n", debug_tmp); ++ debug_tmp = tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x18); ++ //printk("1e.018 = 0x%x\n", debug_tmp); ++ } ++ else if(calibration_pair == ANACAL_PAIR_C){ ++ //printk("PORT (%d) TX_AMP PAIR (A) FINAL CALIBRATION RESULT\n", phyaddr); ++ debug_tmp = tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x19); ++ //printk("1e.019 = 0x%x\n", debug_tmp); ++ debug_tmp = tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x20); ++ //printk("1e.020 = 0x%x\n", debug_tmp); ++ } ++ else if(calibration_pair == ANACAL_PAIR_D){ ++ //printk("PORT (%d) TX_AMP PAIR (A) FINAL CALIBRATION RESULT\n", phyaddr); ++ debug_tmp = tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x21); ++ //printk("1e.021 = 0x%x\n", debug_tmp); ++ debug_tmp = tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x22); ++ //printk("1e.022 = 0x%x\n", debug_tmp); ++ } ++ ++ ++ printk( " GE Tx amp AnaCal Done! (pair-%d)(1e_%x = 0x%x)\n", calibration_pair, tx_amp_reg, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg)); ++ ++ } else { ++ if((tx_amp_temp == 0x3f)||(tx_amp_temp == 0x00)) { ++ all_ana_cal_status = ANACAL_SATURATION; // need to FT ++ printk( " GE Tx amp AnaCal Saturation! \r\n"); ++ } ++ } ++ } ++ ++ if(all_ana_cal_status == ANACAL_ERROR) { ++ tx_amp_temp = 0x20; ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg, (reg_temp|(tx_amp_temp<<tx_amp_reg_shift))); ++ } ++ } ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x017d, 0x0000); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x017e, 0x0000); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x017f, 0x0000); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x0180, 0x0000); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x0181, 0x0000); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x0182, 0x0000); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x0183, 0x0000); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x0184, 0x0000); ++ ++ /* disable analog calibration circuit */ ++ tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x00db, 0x0000); ++ tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x00dc, 0x0000); // disable Tx offset calibration circuit ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x00db, 0x0000); // disable analog calibration circuit ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x00dc, 0x0000); // disable Tx offset calibration circuit ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x003e, 0x0000); // disable Tx VLD force mode ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x00dd, 0x0000); // disable Tx offset/amplitude calibration circuit ++ ++ ++ ++ //tc_phy_write_dev_reg(gsw, phyaddr, 0x1f, 0x273, 0x2000); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0xc9, 0x0fff); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x145, 0x1000); ++ ++} ++ ++//----------------------------------------------------------------- ++ ++int phy_calibration(struct gsw_mt753x *gsw, u8 phyaddr) ++{ ++ u32 reg_tmp,reg_tmp0, reg_tmp1, i; ++ u32 CALDLY = 40; ++ int ret; ++ /* set [12]AN disable, [8]full duplex, [13/6]1000Mbps */ ++ //tc_phy_write_dev_reg(phyaddr, 0x0, 0x0140); ++ switch_phy_write(gsw, phyaddr, R0, 0x140); ++ ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x145, 0x1010);/* fix mdi */ ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, RG_185, 0);/* disable tx slew control */ ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1f, 0x100, 0xc000);/* BG voltage output */ ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1f, 0x403, 0x1099); //bypass efuse ++ ++#if (1) ++ // 1f_27c[12:8] cr_da_tx_i2mpb_10m Trimming TX bias setup(@10M) ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1f, 0x27c, 0x1f1f); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1f, 0x27c, 0x3300); ++ ++ reg_tmp1 = tc_phy_read_dev_reg(gsw, PHY0, 0x1f, 0x27c); ++ //dev1Fh_reg273h TXVLD DA register - Adjust voltage mode TX amplitude. ++ //tc_phy_write_dev_reg(phyaddr, 0x1f, 0x273, 0); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1f, 0x273, 0x1000); ++ //reg_tmp1 = tc_phy_read_dev_reg(gsw, phyaddr, 0x1f, 0x273); ++ //printk("reg_tmp1273 = %x\n", reg_tmp1); ++ /*1e_11 TX overshoot Enable (PAIR A/B/C/D) in gbe mode*/ ++ ++ reg_tmp = tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x11); ++ reg_tmp = reg_tmp | (0xf << 12); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x11, reg_tmp); ++ tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x00e1, 0x10); ++ /* calibration start ============ */ ++ printk("CALDLY = %d\n", CALDLY); ++ if(ge_cal_flag == 0){ ++ ret = ge_cal_rext(gsw, 0, CALDLY); ++ if (ret == -1){ ++ printk("ge_cal_rext error K port =%d\n", phyaddr); ++ return ret; ++ } ++ ge_cal_flag = 1; ++ } ++ ++ /* *** R50 Cal start ***************************** */ ++ /*phyaddress = 0*/ ++ ret = ge_cal_r50(gsw, phyaddr, CALDLY); ++ if (ret == -1){ ++ printk("R50 error K port =%d\n", phyaddr); ++ return ret; ++ } ++ /* *** R50 Cal end *** */ ++ /* *** Tx offset Cal start *********************** */ ++ ret = ge_cal_tx_offset(gsw, phyaddr, CALDLY); ++ if (ret == -1){ ++ printk("ge_cal_tx_offset error K port =%d\n", phyaddr); ++ return ret; ++ } ++ /* *** Tx offset Cal end *** */ ++ ++ /* *** Tx Amp Cal start *** */ ++ ret = ge_cal_tx_amp(gsw, phyaddr, CALDLY); ++ if (ret == -1){ ++ printk("ge_cal_tx_amp error K port =%d\n", phyaddr); ++ return ret; ++ } ++ /* *** Tx Amp Cal end *** */ ++ /*tmp maybe changed*/ ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1f, 0x27c, 0x1111); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1f, 0x27b, 0x47); ++ //tc_phy_write_dev_reg(gsw, phyaddr, 0x1f, 0x273, 0x2000); ++ ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x3a8, 0x0810); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x3aa, 0x0008); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x3ab, 0x0810); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x3ad, 0x0008); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x3ae, 0x0106); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x3b0, 0x0001); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x3b1, 0x0106); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x3b3, 0x0001); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x18c, 0x0001); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x18d, 0x0001); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x18e, 0x0001); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x18f, 0x0001); ++ ++ /*da_tx_bias1_b_tx_standby = 5'b10 (dev1eh_reg3aah[12:8])*/ ++ reg_tmp = tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x3aa); ++ reg_tmp = reg_tmp & ~(0x1f00); ++ reg_tmp = reg_tmp | 0x2 << 8; ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x3aa, reg_tmp); ++ ++ /*da_tx_bias1_a_tx_standby = 5'b10 (dev1eh_reg3a9h[4:0])*/ ++ reg_tmp = tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x3a9); ++ reg_tmp = reg_tmp & ~(0x1f); ++ reg_tmp = reg_tmp | 0x2; ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x3a9, reg_tmp); ++#endif ++} ++ ++void rx_dc_offset(struct gsw_mt753x *gsw, u8 phyaddr) ++{ ++ u32 reg_tmp1; ++ ++ pr_info("PORT %d RX_DC_OFFSET\n", phyaddr); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x96, 0x8000); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x37, 0x3); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x107, 0x4000); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x171, 0x1e5); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x39, 0x200f); ++ udelay(40); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x39, 0x000f); ++ udelay(40); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x171, 0x65); ++} ++ ++void check_rx_dc_offset_pair_a(struct gsw_mt753x *gsw, u8 phyaddr) ++{ ++ u32 reg_tmp; ++ u8 reg_val; ++ ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1f, 0x15, (phyaddr << 13) | 0x114f); ++ reg_tmp = tc_phy_read_dev_reg(gsw, phyaddr, 0x1f, 0x1a); ++ reg_tmp = reg_tmp & 0xff; ++ pr_info("before pairA output = %x\n", reg_tmp); ++ udelay(40); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1f, 0x15, (phyaddr << 13) | 0x1142); ++ udelay(40); ++ reg_tmp = tc_phy_read_dev_reg(gsw, phyaddr, 0x1f, 0x1a); ++ reg_tmp = reg_tmp & 0xff; ++ pr_info("after pairA output = %x\n", reg_tmp); ++ if ((reg_tmp & 0x80) != 0) ++ reg_tmp = (~reg_tmp) + 1; ++ if ((reg_tmp & 0xff) >4) ++ pr_info("pairA RX_DC_OFFSET error"); ++} ++ ++void check_rx_dc_offset_pair_b(struct gsw_mt753x *gsw, u8 phyaddr) ++{ ++ u32 reg_tmp; ++ u8 reg_val; ++ ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1f, 0x15, (phyaddr << 13) | 0x1151); ++ reg_tmp = tc_phy_read_dev_reg(gsw, phyaddr, 0x1f, 0x1a); ++ reg_tmp = reg_tmp & 0xff; ++ pr_info("before pairB output = %x\n", reg_tmp); ++ udelay(40); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1f, 0x15, (phyaddr << 13) | 0x1143); ++ udelay(40); ++ reg_tmp = tc_phy_read_dev_reg(gsw, phyaddr, 0x1f, 0x1a); ++ reg_tmp = reg_tmp & 0xff; ++ pr_info("after pairB output = %x\n", reg_tmp); ++ if ((reg_tmp & 0x80) != 0) ++ reg_tmp = (~reg_tmp) + 1; ++ if ((reg_tmp & 0xff) >4) ++ pr_info("pairB RX_DC_OFFSET error"); ++} ++ ++void check_rx_dc_offset_pair_c(struct gsw_mt753x *gsw, u8 phyaddr) ++{ ++ u32 reg_tmp; ++ u8 reg_val; ++ ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1f, 0x15, (phyaddr << 13) | 0x1153); ++ reg_tmp = tc_phy_read_dev_reg(gsw, phyaddr, 0x1f, 0x1a); ++ reg_tmp = reg_tmp & 0xff; ++ pr_info("before pairC output = %x\n", reg_tmp); ++ udelay(40); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1f, 0x15, (phyaddr << 13) | 0x1144); ++ udelay(40); ++ reg_tmp = tc_phy_read_dev_reg(gsw, phyaddr, 0x1f, 0x1a); ++ reg_tmp = reg_tmp & 0xff; ++ pr_info("after pairC output = %x\n", reg_tmp); ++ if ((reg_tmp & 0x80) != 0) ++ reg_tmp = (~reg_tmp) + 1; ++ if ((reg_tmp & 0xff) >4) ++ pr_info("pairC RX_DC_OFFSET error"); ++} ++ ++void check_rx_dc_offset_pair_d(struct gsw_mt753x *gsw, u8 phyaddr) ++{ ++ u32 reg_tmp; ++ u8 reg_val; ++ ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1f, 0x15, (phyaddr << 13) | 0x1155); ++ reg_tmp = tc_phy_read_dev_reg(gsw, phyaddr, 0x1f, 0x1a); ++ reg_tmp = reg_tmp & 0xff; ++ pr_info("before pairD output = %x\n", reg_tmp); ++ udelay(40); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1f, 0x15, (phyaddr << 13) | 0x1145); ++ udelay(40); ++ reg_tmp = tc_phy_read_dev_reg(gsw, phyaddr, 0x1f, 0x1a); ++ reg_tmp = reg_tmp & 0xff; ++ pr_info("after pairD output = %x\n", reg_tmp); ++ if ((reg_tmp & 0x80) != 0) ++ reg_tmp = (~reg_tmp) + 1; ++ if ((reg_tmp & 0xff) >4) ++ pr_info("pairD RX_DC_OFFSET error"); ++} ++ ++ ++int mt753x_phy_calibration(struct gsw_mt753x *gsw, u8 phyaddr){ ++ ++ int ret; ++ ++ phy_calibration(gsw, phyaddr); ++ ++ /*eye pic*/ ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x0, 0x187); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x1, 0x1c9); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x2, 0x1c6); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x3, 0x182); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x4, 0x208); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x5, 0x205); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x6, 0x384); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x7, 0x3cb); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x8, 0x3c4); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x9, 0x30a); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0xa, 0x00b); ++ tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0xb, 0x002); ++ ++ rx_dc_offset(gsw, phyaddr); ++ check_rx_dc_offset_pair_a(gsw, phyaddr); ++ check_rx_dc_offset_pair_b(gsw, phyaddr); ++ check_rx_dc_offset_pair_c(gsw, phyaddr); ++ check_rx_dc_offset_pair_d(gsw, phyaddr); ++ ++ return ret; ++} +diff --git a/target/linux/generic/files/drivers/net/phy/mtk/mt753x/mt753x_phy.h b/target/linux/generic/files/drivers/net/phy/mtk/mt753x/mt753x_phy.h +new file mode 100755 +--- /dev/null ++++ b/drivers/net/phy/mtk/mt753x/mt753x_phy.h +@@ -0,0 +1,145 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ ++/* ++ * Register definitions for MediaTek MT753x Gigabit switches ++ * ++ * Copyright (C) 2018 MediaTek Inc. All Rights Reserved. ++ * ++ * Author: Weijie Gao <weijie.gao@mediatek.com> ++ */ ++ ++#ifndef _MT753X_PHY_H_ ++#define _MT753X_PHY_H_ ++ ++#include <linux/bitops.h> ++ ++/*phy calibration use*/ ++#define DEV_1E 0x1E ++/*global device 0x1f, always set P0*/ ++#define DEV_1F 0x1F ++ ++ ++/************IEXT/REXT CAL***************/ ++/* bits range: for example BITS(16,23) = 0xFF0000*/ ++#define BITS(m, n) (~(BIT(m) - 1) & ((BIT(n) - 1) | BIT(n))) ++#define ANACAL_INIT 0x01 ++#define ANACAL_ERROR 0xFD ++#define ANACAL_SATURATION 0xFE ++#define ANACAL_FINISH 0xFF ++#define ANACAL_PAIR_A 0 ++#define ANACAL_PAIR_B 1 ++#define ANACAL_PAIR_C 2 ++#define ANACAL_PAIR_D 3 ++#define DAC_IN_0V 0x00 ++#define DAC_IN_2V 0xf0 ++#define TX_AMP_OFFSET_0MV 0x20 ++#define TX_AMP_OFFSET_VALID_BITS 6 ++ ++#define R0 0 ++#define PHY0 0 ++#define PHY1 1 ++#define PHY2 2 ++#define PHY3 3 ++#define PHY4 4 ++#define ANA_TEST_MODE BITS(8, 15) ++#define TST_TCLK_SEL BITs(6, 7) ++#define ANA_TEST_VGA_RG 0x100 ++ ++#define FORCE_MDI_CROSS_OVER BITS(3, 4) ++#define T10_TEST_CTL_RG 0x145 ++#define RG_185 0x185 ++#define RG_TX_SLEW BIT(0) ++#define ANA_CAL_0 0xdb ++#define RG_CAL_CKINV BIT(12) ++#define RG_ANA_CALEN BIT(8) ++#define RG_REXT_CALEN BIT(4) ++#define RG_ZCALEN_A BIT(0) ++#define ANA_CAL_1 0xdc ++#define RG_ZCALEN_B BIT(12) ++#define RG_ZCALEN_C BIT(8) ++#define RG_ZCALEN_D BIT(4) ++#define RG_TXVOS_CALEN BIT(0) ++#define ANA_CAL_6 0xe1 ++#define RG_CAL_REFSEL BIT(4) ++#define RG_CAL_COMP_PWD BIT(0) ++#define ANA_CAL_5 0xe0 ++#define RG_REXT_TRIM BITs(8, 13) ++#define RG_ZCAL_CTRL BITs(0, 5) ++#define RG_17A 0x17a ++#define AD_CAL_COMP_OUT BIT(8) ++#define RG_17B 0x17b ++#define AD_CAL_CLK bit(0) ++#define RG_17C 0x17c ++#define DA_CALIN_FLAG bit(0) ++/************R50 CAL****************************/ ++#define RG_174 0x174 ++#define RG_R50OHM_RSEL_TX_A_EN BIT[15] ++#define CR_R50OHM_RSEL_TX_A BITS[8:14] ++#define RG_R50OHM_RSEL_TX_B_EN BIT[7] ++#define CR_R50OHM_RSEL_TX_B BITS[6:0] ++#define RG_175 0x175 ++#define RG_R50OHM_RSEL_TX_C_EN BITS[15] ++#define CR_R50OHM_RSEL_TX_C BITS[8:14] ++#define RG_R50OHM_RSEL_TX_D_EN BIT[7] ++#define CR_R50OHM_RSEL_TX_D BITS[0:6] ++/**********TX offset Calibration***************************/ ++#define RG_95 0x96 ++#define BYPASS_TX_OFFSET_CAL BIT(15) ++#define RG_3E 0x3e ++#define BYPASS_PD_TXVLD_A BIT(15) ++#define BYPASS_PD_TXVLD_B BIT(14) ++#define BYPASS_PD_TXVLD_C BIT(13) ++#define BYPASS_PD_TXVLD_D BIT(12) ++#define BYPASS_PD_TX_10M BIT(11) ++#define POWER_DOWN_TXVLD_A BIT(7) ++#define POWER_DOWN_TXVLD_B BIT(6) ++#define POWER_DOWN_TXVLD_C BIT(5) ++#define POWER_DOWN_TXVLD_D BIT(4) ++#define POWER_DOWN_TX_10M BIT(3) ++#define RG_DD 0xdd ++#define RG_TXG_CALEN_A BIT(12) ++#define RG_TXG_CALEN_B BIT(8) ++#define RG_TXG_CALEN_C BIT(4) ++#define RG_TXG_CALEN_D BIT(0) ++#define RG_17D 0x17D ++#define FORCE_DASN_DAC_IN0_A BIT(15) ++#define DASN_DAC_IN0_A BITS(0, 9) ++#define RG_17E 0x17E ++#define FORCE_DASN_DAC_IN0_B BIT(15) ++#define DASN_DAC_IN0_B BITS(0, 9) ++#define RG_17F 0x17F ++ ++#define FORCE_DASN_DAC_IN0_C BIT(15) ++#define DASN_DAC_IN0_C BITS(0, 9) ++#define RG_180 0x180 ++#define FORCE_DASN_DAC_IN0_D BIT(15) ++#define DASN_DAC_IN0_D BITS(0, 9) ++ ++#define RG_181 0x181 ++#define FORCE_DASN_DAC_IN1_A BIT(15) ++#define DASN_DAC_IN1_A BITS(0, 9) ++#define RG_182 0x182 ++#define FORCE_DASN_DAC_IN1_B BIT(15) ++#define DASN_DAC_IN1_B BITS(0, 9) ++#define RG_183 0x183 ++#define FORCE_DASN_DAC_IN1_C BIT15] ++#define DASN_DAC_IN1_C BITS(0, 9) ++#define RG_184 0x184 ++#define FORCE_DASN_DAC_IN1_D BIT(15) ++#define DASN_DAC_IN1_D BITS(0, 9) ++#define RG_172 0x172 ++#define CR_TX_AMP_OFFSET_A BITS(8, 13) ++#define CR_TX_AMP_OFFSET_B BITS(0, 5) ++#define RG_173 0x173 ++#define CR_TX_AMP_OFFSET_C BITS(8, 13) ++#define CR_TX_AMP_OFFSET_D BITS(0, 5) ++/**********TX Amp Calibration ***************************/ ++#define RG_12 0x12 ++#define DA_TX_I2MPB_A_GBE BITS(10, 15) ++#define RG_17 0x17 ++#define DA_TX_I2MPB_B_GBE BITS(8, 13) ++#define RG_19 0x19 ++#define DA_TX_I2MPB_C_GBE BITS(8, 13) ++#define RG_21 0x21 ++#define DA_TX_I2MPB_D_GBE BITS(8, 13) ++ ++#endif /* _MT753X_REGS_H_ */ diff --git a/target/linux/mediatek/patches-4.19/0003-switch-add-mt7531.patch b/target/linux/mediatek/patches-4.19/0003-switch-add-mt7531.patch new file mode 100644 index 0000000000..65e56e4940 --- /dev/null +++ b/target/linux/mediatek/patches-4.19/0003-switch-add-mt7531.patch @@ -0,0 +1,23 @@ +Index: linux-4.19.57/drivers/net/phy/Kconfig +=================================================================== +--- linux-4.19.57.orig/drivers/net/phy/Kconfig ++++ linux-4.19.57/drivers/net/phy/Kconfig +@@ -292,6 +292,8 @@ config RTL8367B_PHY + + endif # RTL8366_SMI + ++source "drivers/net/phy/mtk/mt753x/Kconfig" ++ + comment "MII PHY device drivers" + + config SFP +Index: linux-4.19.57/drivers/net/phy/Makefile +=================================================================== +--- linux-4.19.57.orig/drivers/net/phy/Makefile ++++ linux-4.19.57/drivers/net/phy/Makefile +@@ -100,3 +100,5 @@ obj-$(CONFIG_STE10XP) += ste10Xp.o + obj-$(CONFIG_TERANETICS_PHY) += teranetics.o + obj-$(CONFIG_VITESSE_PHY) += vitesse.o + obj-$(CONFIG_XILINX_GMII2RGMII) += xilinx_gmii2rgmii.o ++obj-$(CONFIG_MT753X_GSW) += mtk/mt753x/ ++ diff --git a/target/linux/mediatek/patches-4.19/0227-arm-dts-Add-Unielec-U7623-DTS.patch b/target/linux/mediatek/patches-4.19/0227-arm-dts-Add-Unielec-U7623-DTS.patch new file mode 100644 index 0000000000..d6e63714e3 --- /dev/null +++ b/target/linux/mediatek/patches-4.19/0227-arm-dts-Add-Unielec-U7623-DTS.patch @@ -0,0 +1,419 @@ +From 004eb24e939b5b31f828333f37fb5cb2a877d6f2 Mon Sep 17 00:00:00 2001 +From: Kristian Evensen <kristian.evensen@gmail.com> +Date: Sun, 17 Jun 2018 14:41:47 +0200 +Subject: [PATCH] arm: dts: Add Unielec U7623 DTS + +--- + arch/arm/boot/dts/Makefile | 1 + + .../dts/mt7623a-unielec-u7623-02-emmc-512M.dts | 18 + + .../boot/dts/mt7623a-unielec-u7623-02-emmc.dtsi | 366 +++++++++++++++++++++ + 3 files changed, 385 insertions(+) + create mode 100644 arch/arm/boot/dts/mt7623a-unielec-u7623-02-emmc-512M.dts + create mode 100644 arch/arm/boot/dts/mt7623a-unielec-u7623-02-emmc.dtsi + +Index: linux-4.19.57/arch/arm/boot/dts/Makefile +=================================================================== +--- linux-4.19.57.orig/arch/arm/boot/dts/Makefile ++++ linux-4.19.57/arch/arm/boot/dts/Makefile +@@ -1193,6 +1193,7 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += \ + mt7623a-rfb-nand.dtb \ + mt7623n-rfb-emmc.dtb \ + mt7623n-bananapi-bpi-r2.dtb \ ++ mt7623a-unielec-u7623-02-emmc-512M.dtb \ + mt8127-moose.dtb \ + mt8135-evbp1.dtb + dtb-$(CONFIG_ARCH_ZX) += zx296702-ad1.dtb +Index: linux-4.19.57/arch/arm/boot/dts/mt7623a-unielec-u7623-02-emmc-512M.dts +=================================================================== +--- /dev/null ++++ linux-4.19.57/arch/arm/boot/dts/mt7623a-unielec-u7623-02-emmc-512M.dts +@@ -0,0 +1,18 @@ ++/* ++ * Copyright 2018 Kristian Evensen <kristian.evensen@gmail.com> ++ * ++ * SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++ */ ++ ++/dts-v1/; ++#include "mt7623a-unielec-u7623-02-emmc.dtsi" ++ ++/ { ++ model = "UniElec U7623-02 eMMC (512M RAM)"; ++ compatible = "unielec,u7623-02-emmc-512m", "unielec,u7623-02-emmc", "mediatek,mt7623"; ++ ++ memory@80000000 { ++ device_type = "memory"; ++ reg = <0 0x80000000 0 0x20000000>; ++ }; ++}; +Index: linux-4.19.57/arch/arm/boot/dts/mt7623a-unielec-u7623-02-emmc.dtsi +=================================================================== +--- /dev/null ++++ linux-4.19.57/arch/arm/boot/dts/mt7623a-unielec-u7623-02-emmc.dtsi +@@ -0,0 +1,366 @@ ++/* ++ * Copyright 2018 Kristian Evensen <kristian.evensen@gmail.com> ++ * ++ * SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++ */ ++ ++#include <dt-bindings/input/input.h> ++#include "mt7623.dtsi" ++#include "mt6323.dtsi" ++ ++/ { ++ compatible = "unielec,u7623-02-emmc", "mediatek,mt7623"; ++ ++ aliases { ++ serial2 = &uart2; ++ }; ++ ++ chosen { ++ bootargs = "root=/dev/mmcblk0p2 rootfstype=squashfs,f2fs"; ++ stdout-path = "serial2:115200n8"; ++ }; ++ ++ cpus { ++ cpu@0 { ++ proc-supply = <&mt6323_vproc_reg>; ++ }; ++ ++ cpu@1 { ++ proc-supply = <&mt6323_vproc_reg>; ++ }; ++ ++ cpu@2 { ++ proc-supply = <&mt6323_vproc_reg>; ++ }; ++ ++ cpu@3 { ++ proc-supply = <&mt6323_vproc_reg>; ++ }; ++ }; ++ ++ 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; ++ }; ++ ++ gpio-keys { ++ compatible = "gpio-keys"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&key_pins_a>; ++ ++ factory { ++ label = "factory"; ++ linux,code = <KEY_RESTART>; ++ gpios = <&pio 256 GPIO_ACTIVE_LOW>; ++ }; ++ }; ++ ++ leds { ++ compatible = "gpio-leds"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&led_pins_unielec>; ++ ++ led3 { ++ label = "u7623-01:green:led3"; ++ gpios = <&pio 14 GPIO_ACTIVE_LOW>; ++ default-state = "off"; ++ }; ++ ++ led4 { ++ label = "u7623-01:green:led4"; ++ gpios = <&pio 15 GPIO_ACTIVE_LOW>; ++ default-state = "off"; ++ }; ++ }; ++ ++ mt7530: switch@0 { ++ compatible = "mediatek,mt7530"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ }; ++}; ++ ++&crypto { ++ status = "okay"; ++}; ++ ++ð { ++ status = "okay"; ++ ++ gmac0: mac@0 { ++ compatible = "mediatek,eth-mac"; ++ reg = <0>; ++ phy-mode = "trgmii"; ++ ++ fixed-link { ++ speed = <1000>; ++ full-duplex; ++ pause; ++ }; ++ }; ++ ++ mdio: mdio-bus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ phy5: ethernet-phy@5 { ++ reg = <5>; ++ phy-mode = "rgmii-rxid"; ++ }; ++ }; ++}; ++ ++&mt7530 { ++ compatible = "mediatek,mt7530"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0>; ++ pinctrl-names = "default"; ++ mediatek,mcm; ++ resets = <ðsys 2>; ++ reset-names = "mcm"; ++ core-supply = <&mt6323_vpa_reg>; ++ io-supply = <&mt6323_vemc3v3_reg>; ++ ++ dsa,mii-bus = <&mdio>; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0>; ++ ++ port@0 { ++ reg = <0>; ++ label = "lan0"; ++ cpu = <&cpu_port0>; ++ }; ++ ++ port@1 { ++ reg = <1>; ++ label = "lan1"; ++ cpu = <&cpu_port0>; ++ }; ++ ++ port@2 { ++ reg = <2>; ++ label = "lan2"; ++ cpu = <&cpu_port0>; ++ }; ++ ++ port@3 { ++ reg = <3>; ++ label = "lan3"; ++ cpu = <&cpu_port0>; ++ }; ++ ++ port@4 { ++ reg = <4>; ++ label = "wan"; ++ cpu = <&cpu_port0>; ++ }; ++ ++ cpu_port0: port@6 { ++ reg = <6>; ++ label = "cpu"; ++ ethernet = <&gmac0>; ++ phy-mode = "trgmii"; ++ ++ fixed-link { ++ speed = <1000>; ++ full-duplex; ++ }; ++ }; ++ }; ++}; ++ ++&mmc0 { ++ pinctrl-names = "default", "state_uhs"; ++ pinctrl-0 = <&mmc0_pins_default>; ++ pinctrl-1 = <&mmc0_pins_uhs>; ++ status = "okay"; ++ bus-width = <8>; ++ max-frequency = <50000000>; ++ cap-mmc-highspeed; ++ vmmc-supply = <®_3p3v>; ++ vqmmc-supply = <®_1p8v>; ++ non-removable; ++}; ++ ++&pio { ++ key_pins_a: keys-alt { ++ pins-keys { ++ pinmux = <MT7623_PIN_256_GPIO256_FUNC_GPIO256>, ++ <MT7623_PIN_257_GPIO257_FUNC_GPIO257>; ++ input-enable; ++ }; ++ }; ++ ++ led_pins_unielec: leds-unielec { ++ pins-leds { ++ pinmux = <MT7623_PIN_14_GPIO14_FUNC_GPIO14>, ++ <MT7623_PIN_15_GPIO15_FUNC_GPIO15>; ++ }; ++ }; ++ ++ mmc0_pins_default: mmc0default { ++ pins_cmd_dat { ++ pinmux = <MT7623_PIN_111_MSDC0_DAT7_FUNC_MSDC0_DAT7>, ++ <MT7623_PIN_112_MSDC0_DAT6_FUNC_MSDC0_DAT6>, ++ <MT7623_PIN_113_MSDC0_DAT5_FUNC_MSDC0_DAT5>, ++ <MT7623_PIN_114_MSDC0_DAT4_FUNC_MSDC0_DAT4>, ++ <MT7623_PIN_118_MSDC0_DAT3_FUNC_MSDC0_DAT3>, ++ <MT7623_PIN_119_MSDC0_DAT2_FUNC_MSDC0_DAT2>, ++ <MT7623_PIN_120_MSDC0_DAT1_FUNC_MSDC0_DAT1>, ++ <MT7623_PIN_121_MSDC0_DAT0_FUNC_MSDC0_DAT0>, ++ <MT7623_PIN_116_MSDC0_CMD_FUNC_MSDC0_CMD>; ++ input-enable; ++ bias-pull-up; ++ }; ++ ++ pins_clk { ++ pinmux = <MT7623_PIN_117_MSDC0_CLK_FUNC_MSDC0_CLK>; ++ bias-pull-down; ++ }; ++ ++ pins_rst { ++ pinmux = <MT7623_PIN_115_MSDC0_RSTB_FUNC_MSDC0_RSTB>; ++ bias-pull-up; ++ }; ++ }; ++ ++ mmc0_pins_uhs: mmc0 { ++ pins_cmd_dat { ++ pinmux = <MT7623_PIN_111_MSDC0_DAT7_FUNC_MSDC0_DAT7>, ++ <MT7623_PIN_112_MSDC0_DAT6_FUNC_MSDC0_DAT6>, ++ <MT7623_PIN_113_MSDC0_DAT5_FUNC_MSDC0_DAT5>, ++ <MT7623_PIN_114_MSDC0_DAT4_FUNC_MSDC0_DAT4>, ++ <MT7623_PIN_118_MSDC0_DAT3_FUNC_MSDC0_DAT3>, ++ <MT7623_PIN_119_MSDC0_DAT2_FUNC_MSDC0_DAT2>, ++ <MT7623_PIN_120_MSDC0_DAT1_FUNC_MSDC0_DAT1>, ++ <MT7623_PIN_121_MSDC0_DAT0_FUNC_MSDC0_DAT0>, ++ <MT7623_PIN_116_MSDC0_CMD_FUNC_MSDC0_CMD>; ++ input-enable; ++ drive-strength = <MTK_DRIVE_2mA>; ++ bias-pull-up = <MTK_PUPD_SET_R1R0_01>; ++ }; ++ ++ pins_clk { ++ pinmux = <MT7623_PIN_117_MSDC0_CLK_FUNC_MSDC0_CLK>; ++ drive-strength = <MTK_DRIVE_2mA>; ++ bias-pull-down = <MTK_PUPD_SET_R1R0_01>; ++ }; ++ ++ pins_rst { ++ pinmux = <MT7623_PIN_115_MSDC0_RSTB_FUNC_MSDC0_RSTB>; ++ bias-pull-up; ++ }; ++ }; ++ ++ pwm_pins_a: pwm@0 { ++ pins_pwm { ++ pinmux = <MT7623_PIN_203_PWM0_FUNC_PWM0>, ++ <MT7623_PIN_204_PWM1_FUNC_PWM1>, ++ <MT7623_PIN_205_PWM2_FUNC_PWM2>, ++ <MT7623_PIN_206_PWM3_FUNC_PWM3>, ++ <MT7623_PIN_207_PWM4_FUNC_PWM4>; ++ }; ++ }; ++ ++ uart2_pins_b: uart@2 { ++ pins_dat { ++ pinmux = <MT7623_PIN_200_URXD2_FUNC_URXD2>, ++ <MT7623_PIN_201_UTXD2_FUNC_UTXD2>; ++ }; ++ }; ++ ++ pcie_default: pcie_pin_default { ++ pins_cmd_dat { ++ pinmux = <MT7623_PIN_208_AUD_EXT_CK1_FUNC_PCIE0_PERST_N>, ++ <MT7623_PIN_209_AUD_EXT_CK2_FUNC_PCIE1_PERST_N>; ++ bias-disable; ++ }; ++ }; ++}; ++ ++&pwm { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pwm_pins_a>; ++ status = "okay"; ++}; ++ ++&pwrap { ++ mt6323 { ++ mt6323led: led { ++ compatible = "mediatek,mt6323-led"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ led@0 { ++ reg = <0>; ++ label = "led0"; ++ default-state = "off"; ++ }; ++ }; ++ }; ++}; ++ ++&uart2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&uart2_pins_b>; ++ status = "okay"; ++}; ++ ++&usb1 { ++ vusb33-supply = <®_3p3v>; ++ vbus-supply = <®_3p3v>; ++ status = "okay"; ++}; ++ ++&u3phy1 { ++ status = "okay"; ++}; ++ ++&u3phy2 { ++ status = "okay"; ++ mediatek,phy-switch = <&hifsys>; ++}; ++ ++&pcie { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pcie_default>; ++ status = "okay"; ++ ++ pcie@1,0 { ++ status = "okay"; ++ }; ++ ++ pcie@2,0 { ++ status = "okay"; ++ }; ++}; ++ ++&pcie1_phy { ++ status = "okay"; ++}; ++ diff --git a/target/linux/mediatek/patches-4.19/0301-mtd-mtk-ecc-move-mtk-ecc-header-file-to-include-mtd.patch b/target/linux/mediatek/patches-4.19/0301-mtd-mtk-ecc-move-mtk-ecc-header-file-to-include-mtd.patch new file mode 100755 index 0000000000..fcfb3dc368 --- /dev/null +++ b/target/linux/mediatek/patches-4.19/0301-mtd-mtk-ecc-move-mtk-ecc-header-file-to-include-mtd.patch @@ -0,0 +1,48 @@ +From a2479dc254ebe31c84fbcfda73f35e2321576494 Mon Sep 17 00:00:00 2001 +From: Xiangsheng Hou <xiangsheng.hou@mediatek.com> +Date: Tue, 19 Mar 2019 13:57:38 +0800 +Subject: [PATCH 1/6] mtd: mtk ecc: move mtk ecc header file to include/mtd + +Change-Id: I8dc1d30e21b40d68ef5efd9587012f82970156a5 +Signed-off-by: Xiangsheng Hou <xiangsheng.hou@mediatek.com> +--- + drivers/mtd/nand/raw/mtk_ecc.c | 3 +-- + drivers/mtd/nand/raw/mtk_nand.c | 2 +- + {drivers/mtd/nand/raw => include/linux/mtd}/mtk_ecc.h | 0 + 3 files changed, 2 insertions(+), 3 deletions(-) + rename {drivers/mtd/nand/raw => include/linux/mtd}/mtk_ecc.h (100%) + +diff --git a/drivers/mtd/nand/raw/mtk_ecc.c b/drivers/mtd/nand/raw/mtk_ecc.c +index 6432bd70c3b3..32e9784b0d4f 100644 +--- a/drivers/mtd/nand/raw/mtk_ecc.c ++++ b/drivers/mtd/nand/raw/mtk_ecc.c +@@ -23,8 +23,7 @@ + #include <linux/of.h> + #include <linux/of_platform.h> + #include <linux/mutex.h> +- +-#include "mtk_ecc.h" ++#include <linux/mtd/mtk_ecc.h> + + #define ECC_IDLE_MASK BIT(0) + #define ECC_IRQ_EN BIT(0) +diff --git a/drivers/mtd/nand/raw/mtk_nand.c b/drivers/mtd/nand/raw/mtk_nand.c +index 57b5ed1699e3..e201f1417fba 100644 +--- a/drivers/mtd/nand/raw/mtk_nand.c ++++ b/drivers/mtd/nand/raw/mtk_nand.c +@@ -25,7 +25,7 @@ + #include <linux/iopoll.h> + #include <linux/of.h> + #include <linux/of_device.h> +-#include "mtk_ecc.h" ++#include <linux/mtd/mtk_ecc.h> + + /* NAND controller register definition */ + #define NFI_CNFG (0x00) +diff --git a/drivers/mtd/nand/raw/mtk_ecc.h b/include/linux/mtd/mtk_ecc.h +similarity index 100% +rename from drivers/mtd/nand/raw/mtk_ecc.h +rename to include/linux/mtd/mtk_ecc.h +-- +2.20.1 + diff --git a/target/linux/mediatek/patches-4.19/0303-mtd-spinand-disable-on-die-ECC.patch b/target/linux/mediatek/patches-4.19/0303-mtd-spinand-disable-on-die-ECC.patch new file mode 100755 index 0000000000..eeb096acda --- /dev/null +++ b/target/linux/mediatek/patches-4.19/0303-mtd-spinand-disable-on-die-ECC.patch @@ -0,0 +1,36 @@ +From b341f120cfc9ca1dfd48364b7f36ac2c1fbdea43 Mon Sep 17 00:00:00 2001 +From: Xiangsheng Hou <xiangsheng.hou@mediatek.com> +Date: Wed, 3 Apr 2019 16:30:01 +0800 +Subject: [PATCH 3/6] mtd: spinand: disable on-die ECC + +Change-Id: I9745adaed5295202fabbe8ab8947885c57a5b847 +Signed-off-by: Xiangsheng Hou <xiangsheng.hou@mediatek.com> +--- + 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 30f83649c481..3b6eac391350 100644 +--- a/drivers/mtd/nand/spi/core.c ++++ b/drivers/mtd/nand/spi/core.c +@@ -554,7 +554,7 @@ static int spinand_mtd_read(struct mtd_info *mtd, loff_t from, + int ret = 0; + + if (ops->mode != MTD_OPS_RAW && spinand->eccinfo.ooblayout) +- enable_ecc = true; ++ enable_ecc = false; + + mutex_lock(&spinand->lock); + +@@ -602,7 +602,7 @@ static int spinand_mtd_write(struct mtd_info *mtd, loff_t to, + int ret = 0; + + if (ops->mode != MTD_OPS_RAW && mtd->ooblayout) +- enable_ecc = true; ++ enable_ecc = false; + + mutex_lock(&spinand->lock); + +-- +2.20.1 + diff --git a/target/linux/mediatek/patches-4.19/0304-dt-bindings-ARM-MediaTek-Document-devicetree-binding.patch b/target/linux/mediatek/patches-4.19/0304-dt-bindings-ARM-MediaTek-Document-devicetree-binding.patch new file mode 100755 index 0000000000..a605fd1190 --- /dev/null +++ b/target/linux/mediatek/patches-4.19/0304-dt-bindings-ARM-MediaTek-Document-devicetree-binding.patch @@ -0,0 +1,66 @@ +From 28ec0b7e48bb27435a8b3134019b88628faf497f Mon Sep 17 00:00:00 2001 +From: Xiangsheng Hou <xiangsheng.hou@mediatek.com> +Date: Tue, 11 Dec 2018 17:37:28 +0800 +Subject: [PATCH 4/6] dt-bindings: ARM: MediaTek: Document devicetree bindings + for SPI NAND interface + +Change-Id: I9ece142055ae27100da95826fb3ea1960c2994e6 +Signed-off-by: Xiangsheng Hou <xiangsheng.hou@mediatek.com> +--- + .../devicetree/bindings/spi/spi-mtk-snfi.txt | 44 +++++++++++++++++++ + 1 file changed, 44 insertions(+) + create mode 100644 Documentation/devicetree/bindings/spi/spi-mtk-snfi.txt + +diff --git a/Documentation/devicetree/bindings/spi/spi-mtk-snfi.txt b/Documentation/devicetree/bindings/spi/spi-mtk-snfi.txt +new file mode 100644 +index 000000000000..a09c476c5289 +--- /dev/null ++++ b/Documentation/devicetree/bindings/spi/spi-mtk-snfi.txt +@@ -0,0 +1,44 @@ ++MediaTek SoCs SPI NAND FLASH interface (SNFI) DT binding ++ ++This file documents the device tree bindings for MTK SoCs SPI NAND controller. ++Note that Parallel Nand and SPI NAND is alternative on MTK SoCs. ++ ++Required properties: ++- compatible: should be "mediatek,mt7622-snfi" ++- reg: base physical address and size of SNFI. ++- interrupts: interrupts of SNFI. ++- clocks: SNFI required clocks. ++- clock-names: SNFI clocks internal names. ++- #address-cells: NAND chip index, should be 1. ++- #size-cells: Should be 0. ++ ++Example: ++ snfi: spi@1100d000 { ++ compatible = "mediatek,mt7622-snfi"; ++ reg = <0 0x1100d000 0 0x1000>; ++ interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_LOW>; ++ clocks = <&pericfg CLK_PERI_NFI_PD>, ++ <&pericfg CLK_PERI_SNFI_PD>; ++ clock-names = "nfi_clk", "spi_clk"; ++ ecc-engine = <&bch>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ }; ++ ++Subnodes properties: ++- Should use spi-nand framework, see Documentation/devicetree/bindings/mtd/spi-nand.txt ++ ++Example: ++&snfi { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&serial_nand_pins>; ++ status = "okay"; ++ ++ spi_nand@0 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "spi-nand"; ++ spi-max-frequency = <104000000>; ++ reg = <0>; ++ }; ++}; +-- +2.20.1 + diff --git a/target/linux/mediatek/patches-4.19/0306-spi-spi-mem-MediaTek-Add-SPI-NAND-Flash-interface-dr.patch b/target/linux/mediatek/patches-4.19/0306-spi-spi-mem-MediaTek-Add-SPI-NAND-Flash-interface-dr.patch new file mode 100644 index 0000000000..c307abead9 --- /dev/null +++ b/target/linux/mediatek/patches-4.19/0306-spi-spi-mem-MediaTek-Add-SPI-NAND-Flash-interface-dr.patch @@ -0,0 +1,1235 @@ +From 1ecb38eabd90efe93957d0a822a167560c39308a Mon Sep 17 00:00:00 2001 +From: Xiangsheng Hou <xiangsheng.hou@mediatek.com> +Date: Wed, 20 Mar 2019 16:19:51 +0800 +Subject: [PATCH 6/6] spi: spi-mem: MediaTek: Add SPI NAND Flash interface + driver for MediaTek MT7622 + +Change-Id: I3e78406bb9b46b0049d3988a5c71c7069e4f809c +Signed-off-by: Xiangsheng Hou <xiangsheng.hou@mediatek.com> +--- + drivers/spi/Kconfig | 9 + + drivers/spi/Makefile | 1 + + drivers/spi/spi-mtk-snfi.c | 1183 ++++++++++++++++++++++++++++++++++++ + 3 files changed, 1193 insertions(+) + create mode 100644 drivers/spi/spi-mtk-snfi.c + +Index: linux-4.19.48/drivers/spi/spi-mtk-snfi.c +=================================================================== +--- /dev/null ++++ linux-4.19.48/drivers/spi/spi-mtk-snfi.c +@@ -0,0 +1,1183 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Driver for MediaTek SPI Nand interface ++ * ++ * Copyright (C) 2018 MediaTek Inc. ++ * Authors: Xiangsheng Hou <xiangsheng.hou@mediatek.com> ++ * ++ */ ++ ++#include <linux/clk.h> ++#include <linux/delay.h> ++#include <linux/dma-mapping.h> ++#include <linux/interrupt.h> ++#include <linux/iopoll.h> ++#include <linux/mtd/mtd.h> ++#include <linux/mtd/mtk_ecc.h> ++#include <linux/mtd/spinand.h> ++#include <linux/module.h> ++#include <linux/of.h> ++#include <linux/of_device.h> ++#include <linux/platform_device.h> ++#include <linux/spi/spi.h> ++#include <linux/spi/spi-mem.h> ++ ++/* NAND controller register definition */ ++/* NFI control */ ++#define NFI_CNFG 0x00 ++#define CNFG_DMA BIT(0) ++#define CNFG_READ_EN BIT(1) ++#define CNFG_DMA_BURST_EN BIT(2) ++#define CNFG_BYTE_RW BIT(6) ++#define CNFG_HW_ECC_EN BIT(8) ++#define CNFG_AUTO_FMT_EN BIT(9) ++#define CNFG_OP_PROGRAM (3UL << 12) ++#define CNFG_OP_CUST (6UL << 12) ++#define NFI_PAGEFMT 0x04 ++#define PAGEFMT_512 0 ++#define PAGEFMT_2K 1 ++#define PAGEFMT_4K 2 ++#define PAGEFMT_FDM_SHIFT 8 ++#define PAGEFMT_FDM_ECC_SHIFT 12 ++#define NFI_CON 0x08 ++#define CON_FIFO_FLUSH BIT(0) ++#define CON_NFI_RST BIT(1) ++#define CON_BRD BIT(8) ++#define CON_BWR BIT(9) ++#define CON_SEC_SHIFT 12 ++#define NFI_INTR_EN 0x10 ++#define INTR_AHB_DONE_EN BIT(6) ++#define NFI_INTR_STA 0x14 ++#define NFI_CMD 0x20 ++#define NFI_STA 0x60 ++#define STA_EMP_PAGE BIT(12) ++#define NAND_FSM_MASK (0x1f << 24) ++#define NFI_FSM_MASK (0xf << 16) ++#define NFI_ADDRCNTR 0x70 ++#define CNTR_MASK GENMASK(16, 12) ++#define ADDRCNTR_SEC_SHIFT 12 ++#define ADDRCNTR_SEC(val) \ ++ (((val) & CNTR_MASK) >> ADDRCNTR_SEC_SHIFT) ++#define NFI_STRADDR 0x80 ++#define NFI_BYTELEN 0x84 ++#define NFI_CSEL 0x90 ++#define NFI_FDML(x) (0xa0 + (x) * sizeof(u32) * 2) ++#define NFI_FDMM(x) (0xa4 + (x) * sizeof(u32) * 2) ++#define NFI_MASTER_STA 0x224 ++#define MASTER_STA_MASK 0x0fff ++/* NFI_SPI control */ ++#define SNFI_MAC_OUTL 0x504 ++#define SNFI_MAC_INL 0x508 ++#define SNFI_RD_CTL2 0x510 ++#define RD_CMD_MASK 0x00ff ++#define RD_DUMMY_SHIFT 8 ++#define SNFI_RD_CTL3 0x514 ++#define RD_ADDR_MASK 0xffff ++#define SNFI_MISC_CTL 0x538 ++#define RD_MODE_X2 BIT(16) ++#define RD_MODE_X4 (2UL << 16) ++#define RD_QDUAL_IO (4UL << 16) ++#define RD_MODE_MASK (7UL << 16) ++#define RD_CUSTOM_EN BIT(6) ++#define WR_CUSTOM_EN BIT(7) ++#define WR_X4_EN BIT(20) ++#define SW_RST BIT(28) ++#define SNFI_MISC_CTL2 0x53c ++#define WR_LEN_SHIFT 16 ++#define SNFI_PG_CTL1 0x524 ++#define WR_LOAD_CMD_SHIFT 8 ++#define SNFI_PG_CTL2 0x528 ++#define WR_LOAD_ADDR_MASK 0xffff ++#define SNFI_MAC_CTL 0x500 ++#define MAC_WIP BIT(0) ++#define MAC_WIP_READY BIT(1) ++#define MAC_TRIG BIT(2) ++#define MAC_EN BIT(3) ++#define MAC_SIO_SEL BIT(4) ++#define SNFI_STA_CTL1 0x550 ++#define SPI_STATE_IDLE 0xf ++#define SNFI_CNFG 0x55c ++#define SNFI_MODE_EN BIT(0) ++#define SNFI_GPRAM_DATA 0x800 ++#define SNFI_GPRAM_MAX_LEN 16 ++ ++/* Dummy command trigger NFI to spi mode */ ++#define NAND_CMD_DUMMYREAD 0x00 ++#define NAND_CMD_DUMMYPROG 0x80 ++ ++#define MTK_TIMEOUT 500000 ++#define MTK_RESET_TIMEOUT 1000000 ++#define MTK_SNFC_MIN_SPARE 16 ++#define KB(x) ((x) * 1024UL) ++ ++/* ++ * supported spare size of each IP. ++ * order should be the same with the spare size bitfiled defination of ++ * register NFI_PAGEFMT. ++ */ ++static const u8 spare_size_mt7622[] = { ++ 16, 26, 27, 28 ++}; ++ ++struct mtk_snfi_caps { ++ const u8 *spare_size; ++ u8 num_spare_size; ++ u32 nand_sec_size; ++ u8 nand_fdm_size; ++ u8 nand_fdm_ecc_size; ++ u8 ecc_parity_bits; ++ u8 pageformat_spare_shift; ++ u8 bad_mark_swap; ++}; ++ ++struct mtk_snfi_bad_mark_ctl { ++ void (*bm_swap)(struct spi_mem *mem, u8 *buf, int raw); ++ u32 sec; ++ u32 pos; ++}; ++ ++struct mtk_snfi_nand_chip { ++ struct mtk_snfi_bad_mark_ctl bad_mark; ++ u32 spare_per_sector; ++}; ++ ++struct mtk_snfi_clk { ++ struct clk *nfi_clk; ++ struct clk *spi_clk; ++}; ++ ++struct mtk_snfi { ++ const struct mtk_snfi_caps *caps; ++ struct mtk_snfi_nand_chip snfi_nand; ++ struct mtk_snfi_clk clk; ++ struct mtk_ecc_config ecc_cfg; ++ struct mtk_ecc *ecc; ++ struct completion done; ++ struct device *dev; ++ ++ void __iomem *regs; ++ ++ u8 *buffer; ++}; ++ ++static inline u8 *oob_ptr(struct spi_mem *mem, int i) ++{ ++ struct spinand_device *spinand = spi_mem_get_drvdata(mem); ++ struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master); ++ struct mtk_snfi_nand_chip *snfi_nand = &snfi->snfi_nand; ++ u8 *poi; ++ ++ /* map the sector's FDM data to free oob: ++ * the beginning of the oob area stores the FDM data of bad mark ++ */ ++ ++ if (i < snfi_nand->bad_mark.sec) ++ poi = spinand->oobbuf + (i + 1) * snfi->caps->nand_fdm_size; ++ else if (i == snfi_nand->bad_mark.sec) ++ poi = spinand->oobbuf; ++ else ++ poi = spinand->oobbuf + i * snfi->caps->nand_fdm_size; ++ ++ return poi; ++} ++ ++static inline int mtk_data_len(struct spi_mem *mem) ++{ ++ struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master); ++ struct mtk_snfi_nand_chip *snfi_nand = &snfi->snfi_nand; ++ ++ return snfi->caps->nand_sec_size + snfi_nand->spare_per_sector; ++} ++ ++static inline u8 *mtk_oob_ptr(struct spi_mem *mem, ++ const u8 *p, int i) ++{ ++ struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master); ++ ++ return (u8 *)p + i * mtk_data_len(mem) + snfi->caps->nand_sec_size; ++} ++ ++static void mtk_snfi_bad_mark_swap(struct spi_mem *mem, ++ u8 *buf, int raw) ++{ ++ struct spinand_device *spinand = spi_mem_get_drvdata(mem); ++ struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master); ++ struct mtk_snfi_nand_chip *snfi_nand = &snfi->snfi_nand; ++ u32 bad_pos = snfi_nand->bad_mark.pos; ++ ++ if (raw) ++ bad_pos += snfi_nand->bad_mark.sec * mtk_data_len(mem); ++ else ++ bad_pos += snfi_nand->bad_mark.sec * snfi->caps->nand_sec_size; ++ ++ swap(spinand->oobbuf[0], buf[bad_pos]); ++} ++ ++static void mtk_snfi_set_bad_mark_ctl(struct mtk_snfi_bad_mark_ctl *bm_ctl, ++ struct spi_mem *mem) ++{ ++ struct spinand_device *spinand = spi_mem_get_drvdata(mem); ++ struct mtd_info *mtd = spinand_to_mtd(spinand); ++ ++ bm_ctl->bm_swap = mtk_snfi_bad_mark_swap; ++ bm_ctl->sec = mtd->writesize / mtk_data_len(mem); ++ bm_ctl->pos = mtd->writesize % mtk_data_len(mem); ++} ++ ++static void mtk_snfi_mac_enable(struct mtk_snfi *snfi) ++{ ++ u32 mac; ++ ++ mac = readl(snfi->regs + SNFI_MAC_CTL); ++ mac &= ~MAC_SIO_SEL; ++ mac |= MAC_EN; ++ ++ writel(mac, snfi->regs + SNFI_MAC_CTL); ++} ++ ++static int mtk_snfi_mac_trigger(struct mtk_snfi *snfi) ++{ ++ u32 mac, reg; ++ int ret = 0; ++ ++ mac = readl(snfi->regs + SNFI_MAC_CTL); ++ mac |= MAC_TRIG; ++ writel(mac, snfi->regs + SNFI_MAC_CTL); ++ ++ ret = readl_poll_timeout_atomic(snfi->regs + SNFI_MAC_CTL, reg, ++ reg & MAC_WIP_READY, 10, ++ MTK_TIMEOUT); ++ if (ret < 0) { ++ dev_err(snfi->dev, "polling wip ready for read timeout\n"); ++ return -EIO; ++ } ++ ++ ret = readl_poll_timeout_atomic(snfi->regs + SNFI_MAC_CTL, reg, ++ !(reg & MAC_WIP), 10, ++ MTK_TIMEOUT); ++ if (ret < 0) { ++ dev_err(snfi->dev, "polling flash update timeout\n"); ++ return -EIO; ++ } ++ ++ return ret; ++} ++ ++static void mtk_snfi_mac_leave(struct mtk_snfi *snfi) ++{ ++ u32 mac; ++ ++ mac = readl(snfi->regs + SNFI_MAC_CTL); ++ mac &= ~(MAC_TRIG | MAC_EN | MAC_SIO_SEL); ++ writel(mac, snfi->regs + SNFI_MAC_CTL); ++} ++ ++static int mtk_snfi_mac_op(struct mtk_snfi *snfi) ++{ ++ int ret = 0; ++ ++ mtk_snfi_mac_enable(snfi); ++ ++ ret = mtk_snfi_mac_trigger(snfi); ++ if (ret) ++ return ret; ++ ++ mtk_snfi_mac_leave(snfi); ++ ++ return ret; ++} ++ ++static irqreturn_t mtk_snfi_irq(int irq, void *id) ++{ ++ struct mtk_snfi *snfi = id; ++ u16 sta, ien; ++ ++ sta = readw(snfi->regs + NFI_INTR_STA); ++ ien = readw(snfi->regs + NFI_INTR_EN); ++ ++ if (!(sta & ien)) ++ return IRQ_NONE; ++ ++ writew(~sta & ien, snfi->regs + NFI_INTR_EN); ++ complete(&snfi->done); ++ ++ return IRQ_HANDLED; ++} ++ ++static int mtk_snfi_enable_clk(struct device *dev, struct mtk_snfi_clk *clk) ++{ ++ int ret; ++ ++ ret = clk_prepare_enable(clk->nfi_clk); ++ if (ret) { ++ dev_err(dev, "failed to enable nfi clk\n"); ++ return ret; ++ } ++ ++ ret = clk_prepare_enable(clk->spi_clk); ++ if (ret) { ++ dev_err(dev, "failed to enable spi clk\n"); ++ clk_disable_unprepare(clk->nfi_clk); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static void mtk_snfi_disable_clk(struct mtk_snfi_clk *clk) ++{ ++ clk_disable_unprepare(clk->nfi_clk); ++ clk_disable_unprepare(clk->spi_clk); ++} ++ ++static int mtk_snfi_reset(struct mtk_snfi *snfi) ++{ ++ u32 val; ++ int ret; ++ ++ /* SW reset controller */ ++ val = readl(snfi->regs + SNFI_MISC_CTL) | SW_RST; ++ writel(val, snfi->regs + SNFI_MISC_CTL); ++ ++ ret = readw_poll_timeout(snfi->regs + SNFI_STA_CTL1, val, ++ !(val & SPI_STATE_IDLE), 50, ++ MTK_RESET_TIMEOUT); ++ if (ret) { ++ dev_warn(snfi->dev, "spi state active in reset [0x%x] = 0x%x\n", ++ SNFI_STA_CTL1, val); ++ return ret; ++ } ++ ++ val = readl(snfi->regs + SNFI_MISC_CTL); ++ val &= ~SW_RST; ++ writel(val, snfi->regs + SNFI_MISC_CTL); ++ ++ /* reset all registers and force the NFI master to terminate */ ++ writew(CON_FIFO_FLUSH | CON_NFI_RST, snfi->regs + NFI_CON); ++ ret = readw_poll_timeout(snfi->regs + NFI_STA, val, ++ !(val & (NFI_FSM_MASK | NAND_FSM_MASK)), 50, ++ MTK_RESET_TIMEOUT); ++ if (ret) { ++ dev_warn(snfi->dev, "nfi active in reset [0x%x] = 0x%x\n", ++ NFI_STA, val); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int mtk_snfi_set_spare_per_sector(struct spinand_device *spinand, ++ const struct mtk_snfi_caps *caps, ++ u32 *sps) ++{ ++ struct mtd_info *mtd = spinand_to_mtd(spinand); ++ const u8 *spare = caps->spare_size; ++ u32 sectors, i, closest_spare = 0; ++ ++ sectors = mtd->writesize / caps->nand_sec_size; ++ *sps = mtd->oobsize / sectors; ++ ++ if (*sps < MTK_SNFC_MIN_SPARE) ++ return -EINVAL; ++ ++ for (i = 0; i < caps->num_spare_size; i++) { ++ if (*sps >= spare[i] && spare[i] >= spare[closest_spare]) { ++ closest_spare = i; ++ if (*sps == spare[i]) ++ break; ++ } ++ } ++ ++ *sps = spare[closest_spare]; ++ ++ return 0; ++} ++ ++static void mtk_snfi_read_fdm_data(struct spi_mem *mem, ++ u32 sectors) ++{ ++ struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master); ++ const struct mtk_snfi_caps *caps = snfi->caps; ++ u32 vall, valm; ++ int i, j; ++ u8 *oobptr; ++ ++ for (i = 0; i < sectors; i++) { ++ oobptr = oob_ptr(mem, i); ++ vall = readl(snfi->regs + NFI_FDML(i)); ++ valm = readl(snfi->regs + NFI_FDMM(i)); ++ ++ for (j = 0; j < caps->nand_fdm_size; j++) ++ oobptr[j] = (j >= 4 ? valm : vall) >> ((j % 4) * 8); ++ } ++} ++ ++static void mtk_snfi_write_fdm_data(struct spi_mem *mem, ++ u32 sectors) ++{ ++ struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master); ++ const struct mtk_snfi_caps *caps = snfi->caps; ++ u32 vall, valm; ++ int i, j; ++ u8 *oobptr; ++ ++ for (i = 0; i < sectors; i++) { ++ oobptr = oob_ptr(mem, i); ++ vall = 0; ++ valm = 0; ++ for (j = 0; j < 8; j++) { ++ if (j < 4) ++ vall |= (j < caps->nand_fdm_size ? oobptr[j] : ++ 0xff) << (j * 8); ++ else ++ valm |= (j < caps->nand_fdm_size ? oobptr[j] : ++ 0xff) << ((j - 4) * 8); ++ } ++ writel(vall, snfi->regs + NFI_FDML(i)); ++ writel(valm, snfi->regs + NFI_FDMM(i)); ++ } ++} ++ ++static int mtk_snfi_update_ecc_stats(struct spi_mem *mem, ++ u8 *buf, u32 sectors) ++{ ++ struct spinand_device *spinand = spi_mem_get_drvdata(mem); ++ struct mtd_info *mtd = spinand_to_mtd(spinand); ++ struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master); ++ struct mtk_ecc_stats stats; ++ int rc, i; ++ ++ rc = readl(snfi->regs + NFI_STA) & STA_EMP_PAGE; ++ if (rc) { ++ memset(buf, 0xff, sectors * snfi->caps->nand_sec_size); ++ for (i = 0; i < sectors; i++) ++ memset(spinand->oobbuf, 0xff, ++ snfi->caps->nand_fdm_size); ++ return 0; ++ } ++ ++ mtk_ecc_get_stats(snfi->ecc, &stats, sectors); ++ mtd->ecc_stats.corrected += stats.corrected; ++ mtd->ecc_stats.failed += stats.failed; ++ ++ return 0; ++} ++ ++static int mtk_snfi_hw_runtime_config(struct spi_mem *mem) ++{ ++ struct spinand_device *spinand = spi_mem_get_drvdata(mem); ++ struct mtd_info *mtd = spinand_to_mtd(spinand); ++ struct nand_device *nand = mtd_to_nanddev(mtd); ++ struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master); ++ const struct mtk_snfi_caps *caps = snfi->caps; ++ struct mtk_snfi_nand_chip *snfi_nand = &snfi->snfi_nand; ++ u32 fmt, spare, i = 0; ++ int ret; ++ ++ ret = mtk_snfi_set_spare_per_sector(spinand, caps, &spare); ++ if (ret) ++ return ret; ++ ++ /* calculate usable oob bytes for ecc parity data */ ++ snfi_nand->spare_per_sector = spare; ++ spare -= caps->nand_fdm_size; ++ ++ nand->memorg.oobsize = snfi_nand->spare_per_sector ++ * (mtd->writesize / caps->nand_sec_size); ++ mtd->oobsize = nanddev_per_page_oobsize(nand); ++ ++ snfi->ecc_cfg.strength = (spare << 3) / caps->ecc_parity_bits; ++ mtk_ecc_adjust_strength(snfi->ecc, &snfi->ecc_cfg.strength); ++ ++ switch (mtd->writesize) { ++ case 512: ++ fmt = PAGEFMT_512; ++ break; ++ case KB(2): ++ fmt = PAGEFMT_2K; ++ break; ++ case KB(4): ++ fmt = PAGEFMT_4K; ++ break; ++ default: ++ dev_err(snfi->dev, "invalid page len: %d\n", mtd->writesize); ++ return -EINVAL; ++ } ++ ++ /* Setup PageFormat */ ++ while (caps->spare_size[i] != snfi_nand->spare_per_sector) { ++ i++; ++ if (i == (caps->num_spare_size - 1)) { ++ dev_err(snfi->dev, "invalid spare size %d\n", ++ snfi_nand->spare_per_sector); ++ return -EINVAL; ++ } ++ } ++ ++ fmt |= i << caps->pageformat_spare_shift; ++ fmt |= caps->nand_fdm_size << PAGEFMT_FDM_SHIFT; ++ fmt |= caps->nand_fdm_ecc_size << PAGEFMT_FDM_ECC_SHIFT; ++ writel(fmt, snfi->regs + NFI_PAGEFMT); ++ ++ snfi->ecc_cfg.len = caps->nand_sec_size + caps->nand_fdm_ecc_size; ++ ++ mtk_snfi_set_bad_mark_ctl(&snfi_nand->bad_mark, mem); ++ ++ return 0; ++} ++ ++static int mtk_snfi_read_from_cache(struct spi_mem *mem, ++ const struct spi_mem_op *op, int oob_on) ++{ ++ struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master); ++ struct spinand_device *spinand = spi_mem_get_drvdata(mem); ++ struct mtd_info *mtd = spinand_to_mtd(spinand); ++ u32 sectors = mtd->writesize / snfi->caps->nand_sec_size; ++ struct mtk_snfi_nand_chip *snfi_nand = &snfi->snfi_nand; ++ u32 reg, len, col_addr = 0; ++ int dummy_cycle, ret; ++ dma_addr_t dma_addr; ++ ++ len = sectors * (snfi->caps->nand_sec_size ++ + snfi_nand->spare_per_sector); ++ ++ dma_addr = dma_map_single(snfi->dev, snfi->buffer, ++ len, DMA_FROM_DEVICE); ++ ret = dma_mapping_error(snfi->dev, dma_addr); ++ if (ret) { ++ dev_err(snfi->dev, "dma mapping error\n"); ++ return -EINVAL; ++ } ++ ++ /* set Read cache command and dummy cycle */ ++ dummy_cycle = (op->dummy.nbytes << 3) >> (ffs(op->dummy.buswidth) - 1); ++ reg = ((op->cmd.opcode & RD_CMD_MASK) | ++ (dummy_cycle << RD_DUMMY_SHIFT)); ++ writel(reg, snfi->regs + SNFI_RD_CTL2); ++ ++ writel((col_addr & RD_ADDR_MASK), snfi->regs + SNFI_RD_CTL3); ++ ++ reg = readl(snfi->regs + SNFI_MISC_CTL); ++ reg |= RD_CUSTOM_EN; ++ reg &= ~(RD_MODE_MASK | WR_X4_EN); ++ ++ /* set data and addr buswidth */ ++ if (op->data.buswidth == 4) ++ reg |= RD_MODE_X4; ++ else if (op->data.buswidth == 2) ++ reg |= RD_MODE_X2; ++ ++ if (op->addr.buswidth == 4 || op->addr.buswidth == 2) ++ reg |= RD_QDUAL_IO; ++ writel(reg, snfi->regs + SNFI_MISC_CTL); ++ ++ writel(len, snfi->regs + SNFI_MISC_CTL2); ++ writew(sectors << CON_SEC_SHIFT, snfi->regs + NFI_CON); ++ reg = readw(snfi->regs + NFI_CNFG); ++ reg |= CNFG_READ_EN | CNFG_DMA_BURST_EN | CNFG_DMA | CNFG_OP_CUST; ++ ++ if (!oob_on) { ++ reg |= CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN; ++ writew(reg, snfi->regs + NFI_CNFG); ++ ++ snfi->ecc_cfg.mode = ECC_NFI_MODE; ++ snfi->ecc_cfg.sectors = sectors; ++ snfi->ecc_cfg.op = ECC_DECODE; ++ ret = mtk_ecc_enable(snfi->ecc, &snfi->ecc_cfg); ++ if (ret) { ++ dev_err(snfi->dev, "ecc enable failed\n"); ++ /* clear NFI_CNFG */ ++ reg &= ~(CNFG_READ_EN | CNFG_DMA_BURST_EN | CNFG_DMA | ++ CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN); ++ writew(reg, snfi->regs + NFI_CNFG); ++ goto out; ++ } ++ } else { ++ writew(reg, snfi->regs + NFI_CNFG); ++ } ++ ++ writel(lower_32_bits(dma_addr), snfi->regs + NFI_STRADDR); ++ readw(snfi->regs + NFI_INTR_STA); ++ writew(INTR_AHB_DONE_EN, snfi->regs + NFI_INTR_EN); ++ ++ init_completion(&snfi->done); ++ ++ /* set dummy command to trigger NFI enter SPI mode */ ++ writew(NAND_CMD_DUMMYREAD, snfi->regs + NFI_CMD); ++ reg = readl(snfi->regs + NFI_CON) | CON_BRD; ++ writew(reg, snfi->regs + NFI_CON); ++ ++ ret = wait_for_completion_timeout(&snfi->done, msecs_to_jiffies(500)); ++ if (!ret) { ++ dev_err(snfi->dev, "read ahb done timeout\n"); ++ writew(0, snfi->regs + NFI_INTR_EN); ++ ret = -ETIMEDOUT; ++ goto out; ++ } ++ ++ ret = readl_poll_timeout_atomic(snfi->regs + NFI_BYTELEN, reg, ++ ADDRCNTR_SEC(reg) >= sectors, 10, ++ MTK_TIMEOUT); ++ if (ret < 0) { ++ dev_err(snfi->dev, "polling read byte len timeout\n"); ++ ret = -EIO; ++ } else { ++ if (!oob_on) { ++ ret = mtk_ecc_wait_done(snfi->ecc, ECC_DECODE); ++ if (ret) { ++ dev_warn(snfi->dev, "wait ecc done timeout\n"); ++ } else { ++ mtk_snfi_update_ecc_stats(mem, snfi->buffer, ++ sectors); ++ mtk_snfi_read_fdm_data(mem, sectors); ++ } ++ } ++ } ++ ++ if (oob_on) ++ goto out; ++ ++ mtk_ecc_disable(snfi->ecc); ++out: ++ dma_unmap_single(snfi->dev, dma_addr, len, DMA_FROM_DEVICE); ++ writel(0, snfi->regs + NFI_CON); ++ writel(0, snfi->regs + NFI_CNFG); ++ reg = readl(snfi->regs + SNFI_MISC_CTL); ++ reg &= ~RD_CUSTOM_EN; ++ writel(reg, snfi->regs + SNFI_MISC_CTL); ++ ++ return ret; ++} ++ ++static int mtk_snfi_write_to_cache(struct spi_mem *mem, ++ const struct spi_mem_op *op, ++ int oob_on) ++{ ++ struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master); ++ struct spinand_device *spinand = spi_mem_get_drvdata(mem); ++ struct mtd_info *mtd = spinand_to_mtd(spinand); ++ u32 sectors = mtd->writesize / snfi->caps->nand_sec_size; ++ struct mtk_snfi_nand_chip *snfi_nand = &snfi->snfi_nand; ++ u32 reg, len, col_addr = 0; ++ dma_addr_t dma_addr; ++ int ret; ++ ++ len = sectors * (snfi->caps->nand_sec_size ++ + snfi_nand->spare_per_sector); ++ ++ dma_addr = dma_map_single(snfi->dev, snfi->buffer, len, ++ DMA_TO_DEVICE); ++ ret = dma_mapping_error(snfi->dev, dma_addr); ++ if (ret) { ++ dev_err(snfi->dev, "dma mapping error\n"); ++ return -EINVAL; ++ } ++ ++ /* set program load cmd and address */ ++ reg = (op->cmd.opcode << WR_LOAD_CMD_SHIFT); ++ writel(reg, snfi->regs + SNFI_PG_CTL1); ++ writel(col_addr & WR_LOAD_ADDR_MASK, snfi->regs + SNFI_PG_CTL2); ++ ++ reg = readl(snfi->regs + SNFI_MISC_CTL); ++ reg |= WR_CUSTOM_EN; ++ reg &= ~(RD_MODE_MASK | WR_X4_EN); ++ ++ if (op->data.buswidth == 4) ++ reg |= WR_X4_EN; ++ writel(reg, snfi->regs + SNFI_MISC_CTL); ++ ++ writel(len << WR_LEN_SHIFT, snfi->regs + SNFI_MISC_CTL2); ++ writew(sectors << CON_SEC_SHIFT, snfi->regs + NFI_CON); ++ ++ reg = readw(snfi->regs + NFI_CNFG); ++ reg &= ~(CNFG_READ_EN | CNFG_BYTE_RW); ++ reg |= CNFG_DMA | CNFG_DMA_BURST_EN | CNFG_OP_PROGRAM; ++ ++ if (!oob_on) { ++ reg |= CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN; ++ writew(reg, snfi->regs + NFI_CNFG); ++ ++ snfi->ecc_cfg.mode = ECC_NFI_MODE; ++ snfi->ecc_cfg.op = ECC_ENCODE; ++ ret = mtk_ecc_enable(snfi->ecc, &snfi->ecc_cfg); ++ if (ret) { ++ dev_err(snfi->dev, "ecc enable failed\n"); ++ /* clear NFI_CNFG */ ++ reg &= ~(CNFG_DMA_BURST_EN | CNFG_DMA | ++ CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN); ++ writew(reg, snfi->regs + NFI_CNFG); ++ dma_unmap_single(snfi->dev, dma_addr, len, ++ DMA_FROM_DEVICE); ++ goto out; ++ } ++ /* write OOB into the FDM registers (OOB area in MTK NAND) */ ++ mtk_snfi_write_fdm_data(mem, sectors); ++ } else { ++ writew(reg, snfi->regs + NFI_CNFG); ++ } ++ writel(lower_32_bits(dma_addr), snfi->regs + NFI_STRADDR); ++ readw(snfi->regs + NFI_INTR_STA); ++ writew(INTR_AHB_DONE_EN, snfi->regs + NFI_INTR_EN); ++ ++ init_completion(&snfi->done); ++ ++ /* set dummy command to trigger NFI enter SPI mode */ ++ writew(NAND_CMD_DUMMYPROG, snfi->regs + NFI_CMD); ++ reg = readl(snfi->regs + NFI_CON) | CON_BWR; ++ writew(reg, snfi->regs + NFI_CON); ++ ++ ret = wait_for_completion_timeout(&snfi->done, msecs_to_jiffies(500)); ++ if (!ret) { ++ dev_err(snfi->dev, "custom program done timeout\n"); ++ writew(0, snfi->regs + NFI_INTR_EN); ++ ret = -ETIMEDOUT; ++ goto ecc_disable; ++ } ++ ++ ret = readl_poll_timeout_atomic(snfi->regs + NFI_ADDRCNTR, reg, ++ ADDRCNTR_SEC(reg) >= sectors, ++ 10, MTK_TIMEOUT); ++ if (ret) ++ dev_err(snfi->dev, "hwecc write timeout\n"); ++ ++ecc_disable: ++ mtk_ecc_disable(snfi->ecc); ++ ++out: ++ dma_unmap_single(snfi->dev, dma_addr, len, DMA_TO_DEVICE); ++ writel(0, snfi->regs + NFI_CON); ++ writel(0, snfi->regs + NFI_CNFG); ++ reg = readl(snfi->regs + SNFI_MISC_CTL); ++ reg &= ~WR_CUSTOM_EN; ++ writel(reg, snfi->regs + SNFI_MISC_CTL); ++ ++ return ret; ++} ++ ++static int mtk_snfi_read(struct spi_mem *mem, ++ const struct spi_mem_op *op) ++{ ++ struct spinand_device *spinand = spi_mem_get_drvdata(mem); ++ struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master); ++ struct mtd_info *mtd = spinand_to_mtd(spinand); ++ struct mtk_snfi_nand_chip *snfi_nand = &snfi->snfi_nand; ++ u32 col_addr = op->addr.val; ++ int i, ret, sectors, oob_on = false; ++ ++ if (col_addr == mtd->writesize) ++ oob_on = true; ++ ++ ret = mtk_snfi_read_from_cache(mem, op, oob_on); ++ if (ret) { ++ dev_warn(snfi->dev, "read from cache fail\n"); ++ return ret; ++ } ++ ++ sectors = mtd->writesize / snfi->caps->nand_sec_size; ++ for (i = 0; i < sectors; i++) { ++ if (oob_on) ++ memcpy(oob_ptr(mem, i), ++ mtk_oob_ptr(mem, snfi->buffer, i), ++ snfi->caps->nand_fdm_size); ++ ++ if (i == snfi_nand->bad_mark.sec && snfi->caps->bad_mark_swap) ++ snfi_nand->bad_mark.bm_swap(mem, snfi->buffer, ++ oob_on); ++ } ++ ++ if (!oob_on) ++ memcpy(spinand->databuf, snfi->buffer, mtd->writesize); ++ ++ return ret; ++} ++ ++static int mtk_snfi_write(struct spi_mem *mem, ++ const struct spi_mem_op *op) ++{ ++ struct spinand_device *spinand = spi_mem_get_drvdata(mem); ++ struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master); ++ struct mtd_info *mtd = spinand_to_mtd(spinand); ++ struct mtk_snfi_nand_chip *snfi_nand = &snfi->snfi_nand; ++ u32 ret, i, sectors, col_addr = op->addr.val; ++ int oob_on = false; ++ ++ if (col_addr == mtd->writesize) ++ oob_on = true; ++ ++ sectors = mtd->writesize / snfi->caps->nand_sec_size; ++ memset(snfi->buffer, 0xff, mtd->writesize + mtd->oobsize); ++ ++ if (!oob_on) ++ memcpy(snfi->buffer, spinand->databuf, mtd->writesize); ++ ++ for (i = 0; i < sectors; i++) { ++ if (i == snfi_nand->bad_mark.sec && snfi->caps->bad_mark_swap) ++ snfi_nand->bad_mark.bm_swap(mem, snfi->buffer, oob_on); ++ ++ if (oob_on) ++ memcpy(mtk_oob_ptr(mem, snfi->buffer, i), ++ oob_ptr(mem, i), ++ snfi->caps->nand_fdm_size); ++ } ++ ++ ret = mtk_snfi_write_to_cache(mem, op, oob_on); ++ if (ret) ++ dev_warn(snfi->dev, "write to cache fail\n"); ++ ++ return ret; ++} ++ ++static int mtk_snfi_command_exec(struct mtk_snfi *snfi, ++ const u8 *txbuf, u8 *rxbuf, ++ const u32 txlen, const u32 rxlen) ++{ ++ u32 tmp, i, j, reg, m; ++ u8 *p_tmp = (u8 *)(&tmp); ++ int ret = 0; ++ ++ /* Moving tx data to NFI_SPI GPRAM */ ++ for (i = 0, m = 0; i < txlen; ) { ++ for (j = 0, tmp = 0; i < txlen && j < 4; i++, j++) ++ p_tmp[j] = txbuf[i]; ++ ++ writel(tmp, snfi->regs + SNFI_GPRAM_DATA + m); ++ m += 4; ++ } ++ ++ writel(txlen, snfi->regs + SNFI_MAC_OUTL); ++ writel(rxlen, snfi->regs + SNFI_MAC_INL); ++ ret = mtk_snfi_mac_op(snfi); ++ if (ret) ++ return ret; ++ ++ /* For NULL input data, this loop will be skipped */ ++ if (rxlen) ++ for (i = 0, m = 0; i < rxlen; ) { ++ reg = readl(snfi->regs + ++ SNFI_GPRAM_DATA + m); ++ for (j = 0; i < rxlen && j < 4; i++, j++, rxbuf++) { ++ if (m == 0 && i == 0) ++ j = i + txlen; ++ *rxbuf = (reg >> (j * 8)) & 0xFF; ++ } ++ m += 4; ++ } ++ ++ return ret; ++} ++ ++/* ++ * mtk_snfi_exec_op - to process command/data to send to the ++ * SPI NAND by mtk controller ++ */ ++static int mtk_snfi_exec_op(struct spi_mem *mem, ++ const struct spi_mem_op *op) ++ ++{ ++ struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master); ++ struct spinand_device *spinand = spi_mem_get_drvdata(mem); ++ struct mtd_info *mtd = spinand_to_mtd(spinand); ++ struct nand_device *nand = mtd_to_nanddev(mtd); ++ const struct spi_mem_op *read_cache; ++ const struct spi_mem_op *write_cache; ++ u32 tmpbufsize, txlen = 0, rxlen = 0; ++ u8 *txbuf, *rxbuf = NULL, *buf; ++ int i, ret = 0; ++ ++ ret = mtk_snfi_reset(snfi); ++ if (ret) { ++ dev_warn(snfi->dev, "reset spi memory controller fail\n"); ++ return ret; ++ } ++ ++ /*if bbt initial, framework have detect nand information */ ++ if (nand->bbt.cache) { ++ read_cache = spinand->op_templates.read_cache; ++ write_cache = spinand->op_templates.write_cache; ++ ++ ret = mtk_snfi_hw_runtime_config(mem); ++ if (ret) ++ return ret; ++ ++ /* For Read/Write with cache, Erase use framework flow */ ++ if (op->cmd.opcode == read_cache->cmd.opcode) { ++ ret = mtk_snfi_read(mem, op); ++ if (ret) ++ dev_warn(snfi->dev, "snfi read fail\n"); ++ return ret; ++ } else if (op->cmd.opcode == write_cache->cmd.opcode) { ++ ret = mtk_snfi_write(mem, op); ++ if (ret) ++ dev_warn(snfi->dev, "snfi write fail\n"); ++ return ret; ++ } ++ } ++ ++ tmpbufsize = sizeof(op->cmd.opcode) + op->addr.nbytes + ++ op->dummy.nbytes + op->data.nbytes; ++ ++ txbuf = kzalloc(tmpbufsize, GFP_KERNEL); ++ if (!txbuf) ++ return -ENOMEM; ++ ++ txbuf[txlen++] = op->cmd.opcode; ++ ++ if (op->addr.nbytes) ++ for (i = 0; i < op->addr.nbytes; i++) ++ txbuf[txlen++] = op->addr.val >> ++ (8 * (op->addr.nbytes - i - 1)); ++ ++ txlen += op->dummy.nbytes; ++ ++ if (op->data.dir == SPI_MEM_DATA_OUT) ++ for (i = 0; i < op->data.nbytes; i++) { ++ buf = (u8 *)op->data.buf.out; ++ txbuf[txlen++] = buf[i]; ++ } ++ ++ if (op->data.dir == SPI_MEM_DATA_IN) { ++ rxbuf = (u8 *)op->data.buf.in; ++ rxlen += op->data.nbytes; ++ } ++ ++ ret = mtk_snfi_command_exec(snfi, txbuf, rxbuf, txlen, rxlen); ++ kfree(txbuf); ++ ++ return ret; ++} ++ ++static int mtk_snfi_init(struct mtk_snfi *snfi) ++{ ++ int ret; ++ ++ /* Reset the state machine and data FIFO */ ++ ret = mtk_snfi_reset(snfi); ++ if (ret) { ++ dev_warn(snfi->dev, "MTK reset controller fail\n"); ++ return ret; ++ } ++ ++ snfi->buffer = devm_kzalloc(snfi->dev, 4096 + 256, GFP_KERNEL); ++ if (!snfi->buffer) ++ return -ENOMEM; ++ ++ /* Clear interrupt, read clear. */ ++ readw(snfi->regs + NFI_INTR_STA); ++ writew(0, snfi->regs + NFI_INTR_EN); ++ ++ writel(0, snfi->regs + NFI_CON); ++ writel(0, snfi->regs + NFI_CNFG); ++ ++ /* Change to NFI_SPI mode. */ ++ writel(SNFI_MODE_EN, snfi->regs + SNFI_CNFG); ++ ++ return 0; ++} ++ ++static int mtk_snfi_check_buswidth(u8 width) ++{ ++ switch (width) { ++ case 1: ++ case 2: ++ case 4: ++ return 0; ++ ++ default: ++ break; ++ } ++ ++ return -ENOTSUPP; ++} ++ ++static bool mtk_snfi_supports_op(struct spi_mem *mem, ++ const struct spi_mem_op *op) ++{ ++ int ret = 0; ++ ++ /* For MTK Spi Nand controller, cmd buswidth just support 1 bit*/ ++ if (op->cmd.buswidth != 1) ++ ret = -ENOTSUPP; ++ ++ if (op->addr.nbytes) ++ ret |= mtk_snfi_check_buswidth(op->addr.buswidth); ++ ++ if (op->dummy.nbytes) ++ ret |= mtk_snfi_check_buswidth(op->dummy.buswidth); ++ ++ if (op->data.nbytes) ++ ret |= mtk_snfi_check_buswidth(op->data.buswidth); ++ ++ if (ret) ++ return false; ++ ++ return true; ++} ++ ++static const struct spi_controller_mem_ops mtk_snfi_ops = { ++ .supports_op = mtk_snfi_supports_op, ++ .exec_op = mtk_snfi_exec_op, ++}; ++ ++static const struct mtk_snfi_caps snfi_mt7622 = { ++ .spare_size = spare_size_mt7622, ++ .num_spare_size = 4, ++ .nand_sec_size = 512, ++ .nand_fdm_size = 8, ++ .nand_fdm_ecc_size = 1, ++ .ecc_parity_bits = 13, ++ .pageformat_spare_shift = 4, ++ .bad_mark_swap = 0, ++}; ++ ++static const struct of_device_id mtk_snfi_id_table[] = { ++ { .compatible = "mediatek,mt7622-snfi", .data = &snfi_mt7622, }, ++ { /* sentinel */ } ++}; ++ ++static int mtk_snfi_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct device_node *np = dev->of_node; ++ struct spi_controller *ctlr; ++ struct mtk_snfi *snfi; ++ struct resource *res; ++ int ret = 0, irq; ++ ++ ctlr = spi_alloc_master(&pdev->dev, sizeof(*snfi)); ++ if (!ctlr) ++ return -ENOMEM; ++ ++ snfi = spi_controller_get_devdata(ctlr); ++ snfi->caps = of_device_get_match_data(dev); ++ snfi->dev = dev; ++ ++ snfi->ecc = of_mtk_ecc_get(np); ++ if (IS_ERR_OR_NULL(snfi->ecc)) ++ goto err_put_master; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ snfi->regs = devm_ioremap_resource(dev, res); ++ if (IS_ERR(snfi->regs)) { ++ ret = PTR_ERR(snfi->regs); ++ goto release_ecc; ++ } ++ ++ /* find the clocks */ ++ snfi->clk.nfi_clk = devm_clk_get(dev, "nfi_clk"); ++ if (IS_ERR(snfi->clk.nfi_clk)) { ++ dev_err(dev, "no nfi clk\n"); ++ ret = PTR_ERR(snfi->clk.nfi_clk); ++ goto release_ecc; ++ } ++ ++ snfi->clk.spi_clk = devm_clk_get(dev, "spi_clk"); ++ if (IS_ERR(snfi->clk.spi_clk)) { ++ dev_err(dev, "no spi clk\n"); ++ ret = PTR_ERR(snfi->clk.spi_clk); ++ goto release_ecc; ++ } ++ ++ ret = mtk_snfi_enable_clk(dev, &snfi->clk); ++ if (ret) ++ goto release_ecc; ++ ++ /* find the irq */ ++ irq = platform_get_irq(pdev, 0); ++ if (irq < 0) { ++ dev_err(dev, "no snfi irq resource\n"); ++ ret = -EINVAL; ++ goto clk_disable; ++ } ++ ++ ret = devm_request_irq(dev, irq, mtk_snfi_irq, 0, "mtk-snfi", snfi); ++ if (ret) { ++ dev_err(dev, "failed to request snfi irq\n"); ++ goto clk_disable; ++ } ++ ++ ret = dma_set_mask(dev, DMA_BIT_MASK(32)); ++ if (ret) { ++ dev_err(dev, "failed to set dma mask\n"); ++ goto clk_disable; ++ } ++ ++ ctlr->dev.of_node = np; ++ ctlr->mem_ops = &mtk_snfi_ops; ++ ++ platform_set_drvdata(pdev, snfi); ++ ret = mtk_snfi_init(snfi); ++ if (ret) { ++ dev_err(dev, "failed to init snfi\n"); ++ goto clk_disable; ++ } ++ ++ ret = devm_spi_register_master(dev, ctlr); ++ if (ret) ++ goto clk_disable; ++ ++ return 0; ++ ++clk_disable: ++ mtk_snfi_disable_clk(&snfi->clk); ++ ++release_ecc: ++ mtk_ecc_release(snfi->ecc); ++ ++err_put_master: ++ spi_master_put(ctlr); ++ ++ dev_err(dev, "MediaTek SPI NAND interface probe failed %d\n", ret); ++ return ret; ++} ++ ++static int mtk_snfi_remove(struct platform_device *pdev) ++{ ++ struct mtk_snfi *snfi = platform_get_drvdata(pdev); ++ ++ mtk_snfi_disable_clk(&snfi->clk); ++ ++ return 0; ++} ++ ++static int mtk_snfi_suspend(struct platform_device *pdev, pm_message_t state) ++{ ++ struct mtk_snfi *snfi = platform_get_drvdata(pdev); ++ ++ mtk_snfi_disable_clk(&snfi->clk); ++ ++ return 0; ++} ++ ++static int mtk_snfi_resume(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct mtk_snfi *snfi = dev_get_drvdata(dev); ++ int ret; ++ ++ ret = mtk_snfi_enable_clk(dev, &snfi->clk); ++ if (ret) ++ return ret; ++ ++ ret = mtk_snfi_init(snfi); ++ if (ret) ++ dev_err(dev, "failed to init snfi controller\n"); ++ ++ return ret; ++} ++ ++static struct platform_driver mtk_snfi_driver = { ++ .driver = { ++ .name = "mtk-snfi", ++ .of_match_table = mtk_snfi_id_table, ++ }, ++ .probe = mtk_snfi_probe, ++ .remove = mtk_snfi_remove, ++ .suspend = mtk_snfi_suspend, ++ .resume = mtk_snfi_resume, ++}; ++ ++module_platform_driver(mtk_snfi_driver); ++ ++MODULE_LICENSE("GPL v2"); ++MODULE_AUTHOR("Xiangsheng Hou <xiangsheng.hou@mediatek.com>"); ++MODULE_DESCRIPTION("Mediatek SPI Memory Interface Driver"); +Index: linux-4.19.48/drivers/spi/Kconfig +=================================================================== +--- linux-4.19.48.orig/drivers/spi/Kconfig ++++ linux-4.19.48/drivers/spi/Kconfig +@@ -389,6 +389,15 @@ config SPI_MT65XX + say Y or M here.If you are not sure, say N. + SPI drivers for Mediatek MT65XX and MT81XX series ARM SoCs. + ++config SPI_MTK_SNFI ++ tristate "MediaTek SPI NAND interface" ++ select MTD_SPI_NAND ++ help ++ This selects the SPI NAND FLASH interface(SNFI), ++ which could be found on MediaTek Soc. ++ Say Y or M here.If you are not sure, say N. ++ Note Parallel Nand and SPI NAND is alternative on MediaTek SoCs. ++ + config SPI_NUC900 + tristate "Nuvoton NUC900 series SPI" + depends on ARCH_W90X900 +Index: linux-4.19.48/drivers/spi/Makefile +=================================================================== +--- linux-4.19.48.orig/drivers/spi/Makefile ++++ linux-4.19.48/drivers/spi/Makefile +@@ -57,6 +57,7 @@ obj-$(CONFIG_SPI_MPC512x_PSC) += spi-mp + obj-$(CONFIG_SPI_MPC52xx_PSC) += spi-mpc52xx-psc.o + obj-$(CONFIG_SPI_MPC52xx) += spi-mpc52xx.o + obj-$(CONFIG_SPI_MT65XX) += spi-mt65xx.o ++obj-$(CONFIG_SPI_MTK_SNFI) += spi-mtk-snfi.o + obj-$(CONFIG_SPI_MXS) += spi-mxs.o + obj-$(CONFIG_SPI_NUC900) += spi-nuc900.o + obj-$(CONFIG_SPI_OC_TINY) += spi-oc-tiny.o diff --git a/target/linux/mediatek/patches-4.19/0900-bt-mtk-serial-fix.patch b/target/linux/mediatek/patches-4.19/0900-bt-mtk-serial-fix.patch new file mode 100755 index 0000000000..ae1ef16a79 --- /dev/null +++ b/target/linux/mediatek/patches-4.19/0900-bt-mtk-serial-fix.patch @@ -0,0 +1,37 @@ +diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h +index ebfb0bd..2b9ba39 100644 +--- a/drivers/tty/serial/8250/8250.h ++++ b/drivers/tty/serial/8250/8250.h +@@ -80,6 +80,7 @@ struct serial8250_config { + #define UART_CAP_MINI (1 << 17) /* Mini UART on BCM283X family lacks: + * STOP PARITY EPAR SPAR WLEN5 WLEN6 + */ ++#define UART_CAP_NMOD (1 << 18) /* UART doesn't do termios */ + + #define UART_BUG_QUOT (1 << 0) /* UART has buggy quot LSB */ + #define UART_BUG_TXEN (1 << 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 c39482b..e4a69a0 100644 +--- a/drivers/tty/serial/8250/8250_port.c ++++ b/drivers/tty/serial/8250/8250_port.c +@@ -297,7 +297,7 @@ + .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", +@@ -2663,6 +2663,11 @@ static unsigned int serial8250_get_baud_rate(struct uart_port *port, + 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 || |