mirror of
https://github.com/FUjr/gl-infra-builder.git
synced 2025-12-16 09:10:02 +00:00
1888 lines
49 KiB
Diff
1888 lines
49 KiB
Diff
From 120ee81bb20b8aa01998916c87f763bdcc9e327f Mon Sep 17 00:00:00 2001
|
|
From: "GL.iNet-Hongjian.Zhang" <hongjian.zhang@gl-inet.com>
|
|
Date: Sat, 18 Sep 2021 10:39:16 +0800
|
|
Subject: [PATCH 2/8] ath79: add support for gl mifi
|
|
|
|
---
|
|
target/linux/ath79/dts/ar9330_glinet.dtsi | 218 +++
|
|
.../linux/ath79/dts/ar9331_glinet_gl-mifi.dts | 83 +-
|
|
.../net/ethernet/atheros/ag71xx/Makefile | 1 +
|
|
.../ethernet/atheros/ag71xx/ag71xx_ar7240.c | 1349 +++++++++++++++++
|
|
.../net/ethernet/atheros/ag71xx/ag71xx_main.c | 4 +
|
|
.../generic/base-files/etc/board.d/01_leds | 1 -
|
|
.../etc/uci-defaults/04_led_migration | 3 -
|
|
target/linux/ath79/image/generic.mk | 10 -
|
|
target/linux/ath79/image/nand.mk | 10 +
|
|
.../ath79/nand/base-files/etc/board.d/01_leds | 6 +
|
|
.../nand/base-files/etc/board.d/02_network | 3 +
|
|
11 files changed, 1647 insertions(+), 41 deletions(-)
|
|
create mode 100644 target/linux/ath79/dts/ar9330_glinet.dtsi
|
|
create mode 100755 target/linux/ath79/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_ar7240.c
|
|
|
|
diff --git a/target/linux/ath79/dts/ar9330_glinet.dtsi b/target/linux/ath79/dts/ar9330_glinet.dtsi
|
|
new file mode 100644
|
|
index 0000000000..77387bf37c
|
|
--- /dev/null
|
|
+++ b/target/linux/ath79/dts/ar9330_glinet.dtsi
|
|
@@ -0,0 +1,218 @@
|
|
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
|
|
+#include <dt-bindings/clock/ath79-clk.h>
|
|
+#include "ath79.dtsi"
|
|
+
|
|
+/ {
|
|
+ compatible = "qca,ar9330";
|
|
+
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <1>;
|
|
+
|
|
+ cpus {
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+
|
|
+ cpu@0 {
|
|
+ device_type = "cpu";
|
|
+ compatible = "mips,mips24Kc";
|
|
+ clocks = <&pll ATH79_CLK_CPU>;
|
|
+ reg = <0>;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ chosen {
|
|
+ bootargs = "console=ttyATH0,115200";
|
|
+ };
|
|
+
|
|
+ ahb {
|
|
+ apb {
|
|
+ ddr_ctrl: memory-controller@18000000 {
|
|
+ compatible = "qca,ar7240-ddr-controller";
|
|
+ reg = <0x18000000 0x100>;
|
|
+
|
|
+ #qca,ddr-wb-channel-cells = <1>;
|
|
+ };
|
|
+
|
|
+ uart: uart@18020000 {
|
|
+ compatible = "qca,ar9330-uart";
|
|
+ reg = <0x18020000 0x14>;
|
|
+
|
|
+ interrupts = <3>;
|
|
+
|
|
+ clocks = <&pll ATH79_CLK_REF>;
|
|
+ clock-names = "uart";
|
|
+
|
|
+ status = "disabled";
|
|
+ };
|
|
+
|
|
+ gpio: gpio@18040000 {
|
|
+ compatible = "qca,ar7100-gpio";
|
|
+ reg = <0x18040000 0x34>;
|
|
+ interrupts = <2>;
|
|
+
|
|
+ ngpios = <30>;
|
|
+
|
|
+ gpio-controller;
|
|
+ #gpio-cells = <2>;
|
|
+
|
|
+ interrupt-controller;
|
|
+ #interrupt-cells = <2>;
|
|
+ };
|
|
+
|
|
+ pinmux: pinmux@18040028 {
|
|
+ compatible = "pinctrl-single";
|
|
+ reg = <0x18040028 0x8>;
|
|
+
|
|
+ pinctrl-single,bit-per-mux;
|
|
+ pinctrl-single,register-width = <32>;
|
|
+ pinctrl-single,function-mask = <0x1>;
|
|
+ #pinctrl-cells = <2>;
|
|
+
|
|
+ jtag_disable_pins: pinmux_jtag_disable_pins {
|
|
+ pinctrl-single,bits = <0x0 0x1 0x1>;
|
|
+ };
|
|
+
|
|
+ switch_led_disable_pins: pinmux_switch_led_disable_pins {
|
|
+ pinctrl-single,bits = <0x0 0x0 0xf8>;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ pll: pll-controller@18050000 {
|
|
+ compatible = "qca,ar9330-pll";
|
|
+ reg = <0x18050000 0x100>;
|
|
+
|
|
+ #clock-cells = <1>;
|
|
+ };
|
|
+
|
|
+ wdt: wdt@18060008 {
|
|
+ compatible = "qca,ar7130-wdt";
|
|
+ reg = <0x18060008 0x8>;
|
|
+
|
|
+ interrupts = <4>;
|
|
+
|
|
+ clocks = <&pll ATH79_CLK_AHB>;
|
|
+ clock-names = "wdt";
|
|
+ };
|
|
+
|
|
+ rst: reset-controller@1806001c {
|
|
+ compatible = "qca,ar7100-reset";
|
|
+ reg = <0x1806001c 0x4>;
|
|
+
|
|
+ #reset-cells = <1>;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ usb: usb@1b000000 {
|
|
+ compatible = "generic-ehci";
|
|
+ reg = <0x1b000000 0x200>;
|
|
+
|
|
+ interrupts = <3>;
|
|
+ resets = <&rst 5>;
|
|
+ reset-names = "usb-host";
|
|
+ dr_mode = "host";
|
|
+
|
|
+ has-transaction-translator;
|
|
+ caps-offset = <0x100>;
|
|
+
|
|
+ phy-names = "usb-phy";
|
|
+ phys = <&usb_phy>;
|
|
+
|
|
+ status = "disabled";
|
|
+ };
|
|
+
|
|
+ spi: spi@1f000000 {
|
|
+ compatible = "qca,ar7100-spi";
|
|
+ reg = <0x1f000000 0x10>;
|
|
+
|
|
+ clocks = <&pll ATH79_CLK_AHB>;
|
|
+ clock-names = "ahb";
|
|
+
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+
|
|
+ status = "disabled";
|
|
+ };
|
|
+
|
|
+ gmac: gmac@18070000 {
|
|
+ compatible = "qca,ar9330-gmac";
|
|
+ reg = <0x18070000 0x4>;
|
|
+ };
|
|
+
|
|
+ wmac: wmac@18100000 {
|
|
+ compatible = "qca,ar9330-wmac";
|
|
+ reg = <0x18100000 0x20000>;
|
|
+
|
|
+ interrupts = <2>;
|
|
+
|
|
+ status = "disabled";
|
|
+ };
|
|
+ };
|
|
+
|
|
+ usb_phy: usb-phy {
|
|
+ compatible = "qca,ar7200-usb-phy";
|
|
+
|
|
+ reset-names = "usb-phy", "usb-suspend-override";
|
|
+ resets = <&rst 4>, <&rst 3>;
|
|
+
|
|
+ #phy-cells = <0>;
|
|
+
|
|
+ status = "disabled";
|
|
+ };
|
|
+};
|
|
+
|
|
+&cpuintc {
|
|
+ qca,ddr-wb-channel-interrupts = <2>, <3>;
|
|
+ qca,ddr-wb-channels = <&ddr_ctrl 3>, <&ddr_ctrl 2>;
|
|
+};
|
|
+
|
|
+ð0 {
|
|
+ compatible = "qca,ar9330-eth", "syscon";
|
|
+
|
|
+ pll-data = <0x00110000 0x00001099 0x00991099>;
|
|
+
|
|
+ resets = <&rst 9>;
|
|
+ reset-names = "mac";
|
|
+ phy-mode = "mii";
|
|
+ phy-handle = <&swphy4>;
|
|
+};
|
|
+
|
|
+&mdio1 {
|
|
+ status = "okay";
|
|
+ compatible = "qca,ar9330-mdio";
|
|
+
|
|
+ resets = <&rst 23>;
|
|
+ reset-names = "mdio";
|
|
+ builtin-switch;
|
|
+
|
|
+ builtin_switch: switch0@1f {
|
|
+ compatible = "qca,ar8216-builtin";
|
|
+ reg = <0x1f>;
|
|
+ resets = <&rst 8>;
|
|
+ reset-names = "switch";
|
|
+
|
|
+ mdio-bus {
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+
|
|
+ swphy4: ethernet-phy@4 {
|
|
+ reg = <4>;
|
|
+ phy-mode = "mii";
|
|
+ };
|
|
+ };
|
|
+ };
|
|
+};
|
|
+
|
|
+ð1 {
|
|
+ compatible = "qca,ar9330-eth", "syscon";
|
|
+
|
|
+ pll-data = <0x00110000 0x00001099 0x00991099>;
|
|
+ phy-mode = "gmii";
|
|
+
|
|
+ resets = <&rst 13>;
|
|
+ reset-names = "mac";
|
|
+
|
|
+ fixed-link {
|
|
+ speed = <1000>;
|
|
+ full-duplex;
|
|
+ };
|
|
+};
|
|
diff --git a/target/linux/ath79/dts/ar9331_glinet_gl-mifi.dts b/target/linux/ath79/dts/ar9331_glinet_gl-mifi.dts
|
|
index 7d6e7bd4af..863275b712 100644
|
|
--- a/target/linux/ath79/dts/ar9331_glinet_gl-mifi.dts
|
|
+++ b/target/linux/ath79/dts/ar9331_glinet_gl-mifi.dts
|
|
@@ -1,39 +1,59 @@
|
|
// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
|
|
|
|
-#include "ar9331.dtsi"
|
|
+#include "ar9330_glinet.dtsi"
|
|
|
|
#include <dt-bindings/gpio/gpio.h>
|
|
#include <dt-bindings/input/input.h>
|
|
|
|
/ {
|
|
- compatible = "glinet,gl-mifi", "qca,ar9331";
|
|
+ compatible = "glinet,gl-mifi", "qca,ar9330";
|
|
model = "GL.iNet GL-MiFi";
|
|
|
|
- aliases {
|
|
- label-mac-device = ð0;
|
|
- };
|
|
-
|
|
- leds {
|
|
+ aliases {
|
|
+ serial0 = &uart;
|
|
+ };
|
|
+
|
|
+ gl_hw {
|
|
+ compatible = "gl-hw-info";
|
|
+
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <1>;
|
|
+ model = "mifi";
|
|
+ wan = "eth0";
|
|
+ lan = "eth1";
|
|
+ build-in-modem = "1-1.2";
|
|
+ reset-button = "gpio-11";
|
|
+ usb-port = "1-1.3";
|
|
+ factory_data {
|
|
+ device_mac = "art";
|
|
+ device_ddns = "art", "0x10";
|
|
+ device_sn_bak = "art", "0x20";
|
|
+ device_sn = "art", "0x30";
|
|
+ country_code = "art", "0x88";
|
|
+ };
|
|
+ };
|
|
+
|
|
+ leds {
|
|
compatible = "gpio-leds";
|
|
|
|
wlan {
|
|
- label = "green:wlan";
|
|
+ label = "gl-mifi:green:wlan";
|
|
gpios = <&gpio 1 GPIO_ACTIVE_HIGH>;
|
|
linux,default-trigger = "phy0tpt";
|
|
};
|
|
|
|
lan {
|
|
- label = "green:lan";
|
|
+ label = "gl-mifi:green:lan";
|
|
gpios = <&gpio 16 GPIO_ACTIVE_HIGH>;
|
|
};
|
|
|
|
wan {
|
|
- label = "green:wan";
|
|
+ label = "gl-mifi:green:wan";
|
|
gpios = <&gpio 27 GPIO_ACTIVE_HIGH>;
|
|
};
|
|
|
|
- 3g4g {
|
|
- label = "green:3g4g";
|
|
+ net {
|
|
+ label = "gl-mifi:green:net";
|
|
gpios = <&gpio 0 GPIO_ACTIVE_HIGH>;
|
|
};
|
|
};
|
|
@@ -49,14 +69,6 @@
|
|
};
|
|
};
|
|
|
|
- reg_usb_vbus: reg_usb_vbus {
|
|
- compatible = "regulator-fixed";
|
|
- regulator-name = "usb_vbus";
|
|
- regulator-min-microvolt = <5000000>;
|
|
- regulator-max-microvolt = <5000000>;
|
|
- gpio = <&gpio 6 GPIO_ACTIVE_LOW>;
|
|
- };
|
|
-
|
|
gpio-export {
|
|
compatible = "gpio-export";
|
|
|
|
@@ -65,14 +77,27 @@
|
|
gpio-export,output = <0>;
|
|
gpios = <&gpio 7 GPIO_ACTIVE_LOW>;
|
|
};
|
|
+ gpio_usb_power {
|
|
+ gpio-export,name = "usb_power";
|
|
+ gpio-export,output = <0>;
|
|
+ gpios = <&gpio 6 GPIO_ACTIVE_LOW>;
|
|
+ };
|
|
};
|
|
};
|
|
|
|
+&uart {
|
|
+ status = "okay";
|
|
+};
|
|
+
|
|
&usb {
|
|
status = "okay";
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
|
|
- dr_mode = "host";
|
|
- vbus-supply = <®_usb_vbus>;
|
|
+ hub_port: port@1 {
|
|
+ reg = <1>;
|
|
+ #trigger-source-cells = <0>;
|
|
+ };
|
|
};
|
|
|
|
&usb_phy {
|
|
@@ -122,6 +147,14 @@
|
|
status = "okay";
|
|
|
|
mtd-mac-address = <&art 0x0>;
|
|
+ ifname = "eth0";
|
|
+};
|
|
+
|
|
+ð1 {
|
|
+ status = "okay";
|
|
+
|
|
+ mtd-mac-address = <&art 0x0>;
|
|
+ ifname = "eth1";
|
|
|
|
gmac-config {
|
|
device = <&gmac>;
|
|
@@ -131,14 +164,10 @@
|
|
};
|
|
};
|
|
|
|
-ð1 {
|
|
- status = "okay";
|
|
-
|
|
- mtd-mac-address = <&art 0x0>;
|
|
-};
|
|
|
|
&wmac {
|
|
status = "okay";
|
|
|
|
mtd-cal-data = <&art 0x1000>;
|
|
+ mtd-mac-address = <&art 0x0>;
|
|
};
|
|
diff --git a/target/linux/ath79/files/drivers/net/ethernet/atheros/ag71xx/Makefile b/target/linux/ath79/files/drivers/net/ethernet/atheros/ag71xx/Makefile
|
|
index 87add0d208..480dbb62c0 100644
|
|
--- a/target/linux/ath79/files/drivers/net/ethernet/atheros/ag71xx/Makefile
|
|
+++ b/target/linux/ath79/files/drivers/net/ethernet/atheros/ag71xx/Makefile
|
|
@@ -9,5 +9,6 @@ ag71xx-y += ag71xx_phy.o
|
|
|
|
ag71xx-$(CONFIG_AG71XX_DEBUG_FS) += ag71xx_debugfs.o
|
|
|
|
+obj-$(CONFIG_AG71XX) += ag71xx_ar7240.o
|
|
obj-$(CONFIG_AG71XX) += ag71xx_mdio.o
|
|
obj-$(CONFIG_AG71XX) += ag71xx.o
|
|
diff --git a/target/linux/ath79/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_ar7240.c b/target/linux/ath79/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_ar7240.c
|
|
new file mode 100755
|
|
index 0000000000..600e0d49d2
|
|
--- /dev/null
|
|
+++ b/target/linux/ath79/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_ar7240.c
|
|
@@ -0,0 +1,1349 @@
|
|
+/*
|
|
+ * Driver for the built-in ethernet switch of the Atheros AR7240 SoC
|
|
+ * Copyright (c) 2010 Gabor Juhos <juhosg@openwrt.org>
|
|
+ * Copyright (c) 2010 Felix Fietkau <nbd@nbd.name>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation.
|
|
+ *
|
|
+ */
|
|
+
|
|
+#include <linux/etherdevice.h>
|
|
+#include <linux/list.h>
|
|
+#include <linux/netdevice.h>
|
|
+#include <linux/of_mdio.h>
|
|
+#include <linux/of_net.h>
|
|
+#include <linux/phy.h>
|
|
+#include <linux/mii.h>
|
|
+#include <linux/bitops.h>
|
|
+#include <linux/switch.h>
|
|
+#include "ag71xx.h"
|
|
+
|
|
+#define BITM(_count) (BIT(_count) - 1)
|
|
+#define BITS(_shift, _count) (BITM(_count) << _shift)
|
|
+
|
|
+#define AR7240_REG_MASK_CTRL 0x00
|
|
+#define AR7240_MASK_CTRL_REVISION_M BITM(8)
|
|
+#define AR7240_MASK_CTRL_VERSION_M BITM(8)
|
|
+#define AR7240_MASK_CTRL_VERSION_S 8
|
|
+#define AR7240_MASK_CTRL_VERSION_AR7240 0x01
|
|
+#define AR7240_MASK_CTRL_VERSION_AR934X 0x02
|
|
+#define AR7240_MASK_CTRL_SOFT_RESET BIT(31)
|
|
+
|
|
+#define AR7240_REG_MAC_ADDR0 0x20
|
|
+#define AR7240_REG_MAC_ADDR1 0x24
|
|
+
|
|
+#define AR7240_REG_FLOOD_MASK 0x2c
|
|
+#define AR7240_FLOOD_MASK_BROAD_TO_CPU BIT(26)
|
|
+
|
|
+#define AR7240_REG_GLOBAL_CTRL 0x30
|
|
+#define AR7240_GLOBAL_CTRL_MTU_M BITM(11)
|
|
+#define AR9340_GLOBAL_CTRL_MTU_M BITM(14)
|
|
+
|
|
+#define AR7240_REG_VTU 0x0040
|
|
+#define AR7240_VTU_OP BITM(3)
|
|
+#define AR7240_VTU_OP_NOOP 0x0
|
|
+#define AR7240_VTU_OP_FLUSH 0x1
|
|
+#define AR7240_VTU_OP_LOAD 0x2
|
|
+#define AR7240_VTU_OP_PURGE 0x3
|
|
+#define AR7240_VTU_OP_REMOVE_PORT 0x4
|
|
+#define AR7240_VTU_ACTIVE BIT(3)
|
|
+#define AR7240_VTU_FULL BIT(4)
|
|
+#define AR7240_VTU_PORT BITS(8, 4)
|
|
+#define AR7240_VTU_PORT_S 8
|
|
+#define AR7240_VTU_VID BITS(16, 12)
|
|
+#define AR7240_VTU_VID_S 16
|
|
+#define AR7240_VTU_PRIO BITS(28, 3)
|
|
+#define AR7240_VTU_PRIO_S 28
|
|
+#define AR7240_VTU_PRIO_EN BIT(31)
|
|
+
|
|
+#define AR7240_REG_VTU_DATA 0x0044
|
|
+#define AR7240_VTUDATA_MEMBER BITS(0, 10)
|
|
+#define AR7240_VTUDATA_VALID BIT(11)
|
|
+
|
|
+#define AR7240_REG_ATU 0x50
|
|
+#define AR7240_ATU_FLUSH_ALL 0x1
|
|
+
|
|
+#define AR7240_REG_AT_CTRL 0x5c
|
|
+#define AR7240_AT_CTRL_AGE_TIME BITS(0, 15)
|
|
+#define AR7240_AT_CTRL_AGE_EN BIT(17)
|
|
+#define AR7240_AT_CTRL_LEARN_CHANGE BIT(18)
|
|
+#define AR7240_AT_CTRL_RESERVED BIT(19)
|
|
+#define AR7240_AT_CTRL_ARP_EN BIT(20)
|
|
+
|
|
+#define AR7240_REG_TAG_PRIORITY 0x70
|
|
+
|
|
+#define AR7240_REG_SERVICE_TAG 0x74
|
|
+#define AR7240_SERVICE_TAG_M BITM(16)
|
|
+
|
|
+#define AR7240_REG_CPU_PORT 0x78
|
|
+#define AR7240_MIRROR_PORT_S 4
|
|
+#define AR7240_MIRROR_PORT_M BITM(4)
|
|
+#define AR7240_CPU_PORT_EN BIT(8)
|
|
+
|
|
+#define AR7240_REG_MIB_FUNCTION0 0x80
|
|
+#define AR7240_MIB_TIMER_M BITM(16)
|
|
+#define AR7240_MIB_AT_HALF_EN BIT(16)
|
|
+#define AR7240_MIB_BUSY BIT(17)
|
|
+#define AR7240_MIB_FUNC_S 24
|
|
+#define AR7240_MIB_FUNC_M BITM(3)
|
|
+#define AR7240_MIB_FUNC_NO_OP 0x0
|
|
+#define AR7240_MIB_FUNC_FLUSH 0x1
|
|
+#define AR7240_MIB_FUNC_CAPTURE 0x3
|
|
+
|
|
+#define AR7240_REG_MDIO_CTRL 0x98
|
|
+#define AR7240_MDIO_CTRL_DATA_M BITM(16)
|
|
+#define AR7240_MDIO_CTRL_REG_ADDR_S 16
|
|
+#define AR7240_MDIO_CTRL_PHY_ADDR_S 21
|
|
+#define AR7240_MDIO_CTRL_CMD_WRITE 0
|
|
+#define AR7240_MDIO_CTRL_CMD_READ BIT(27)
|
|
+#define AR7240_MDIO_CTRL_MASTER_EN BIT(30)
|
|
+#define AR7240_MDIO_CTRL_BUSY BIT(31)
|
|
+
|
|
+#define AR7240_REG_PORT_BASE(_port) (0x100 + (_port) * 0x100)
|
|
+
|
|
+#define AR7240_REG_PORT_STATUS(_port) (AR7240_REG_PORT_BASE((_port)) + 0x00)
|
|
+#define AR7240_PORT_STATUS_SPEED_S 0
|
|
+#define AR7240_PORT_STATUS_SPEED_M BITM(2)
|
|
+#define AR7240_PORT_STATUS_SPEED_10 0
|
|
+#define AR7240_PORT_STATUS_SPEED_100 1
|
|
+#define AR7240_PORT_STATUS_SPEED_1000 2
|
|
+#define AR7240_PORT_STATUS_TXMAC BIT(2)
|
|
+#define AR7240_PORT_STATUS_RXMAC BIT(3)
|
|
+#define AR7240_PORT_STATUS_TXFLOW BIT(4)
|
|
+#define AR7240_PORT_STATUS_RXFLOW BIT(5)
|
|
+#define AR7240_PORT_STATUS_DUPLEX BIT(6)
|
|
+#define AR7240_PORT_STATUS_LINK_UP BIT(8)
|
|
+#define AR7240_PORT_STATUS_LINK_AUTO BIT(9)
|
|
+#define AR7240_PORT_STATUS_LINK_PAUSE BIT(10)
|
|
+
|
|
+#define AR7240_REG_PORT_CTRL(_port) (AR7240_REG_PORT_BASE((_port)) + 0x04)
|
|
+#define AR7240_PORT_CTRL_STATE_M BITM(3)
|
|
+#define AR7240_PORT_CTRL_STATE_DISABLED 0
|
|
+#define AR7240_PORT_CTRL_STATE_BLOCK 1
|
|
+#define AR7240_PORT_CTRL_STATE_LISTEN 2
|
|
+#define AR7240_PORT_CTRL_STATE_LEARN 3
|
|
+#define AR7240_PORT_CTRL_STATE_FORWARD 4
|
|
+#define AR7240_PORT_CTRL_LEARN_LOCK BIT(7)
|
|
+#define AR7240_PORT_CTRL_VLAN_MODE_S 8
|
|
+#define AR7240_PORT_CTRL_VLAN_MODE_KEEP 0
|
|
+#define AR7240_PORT_CTRL_VLAN_MODE_STRIP 1
|
|
+#define AR7240_PORT_CTRL_VLAN_MODE_ADD 2
|
|
+#define AR7240_PORT_CTRL_VLAN_MODE_DOUBLE_TAG 3
|
|
+#define AR7240_PORT_CTRL_IGMP_SNOOP BIT(10)
|
|
+#define AR7240_PORT_CTRL_HEADER BIT(11)
|
|
+#define AR7240_PORT_CTRL_MAC_LOOP BIT(12)
|
|
+#define AR7240_PORT_CTRL_SINGLE_VLAN BIT(13)
|
|
+#define AR7240_PORT_CTRL_LEARN BIT(14)
|
|
+#define AR7240_PORT_CTRL_DOUBLE_TAG BIT(15)
|
|
+#define AR7240_PORT_CTRL_MIRROR_TX BIT(16)
|
|
+#define AR7240_PORT_CTRL_MIRROR_RX BIT(17)
|
|
+
|
|
+#define AR7240_REG_PORT_VLAN(_port) (AR7240_REG_PORT_BASE((_port)) + 0x08)
|
|
+
|
|
+#define AR7240_PORT_VLAN_DEFAULT_ID_S 0
|
|
+#define AR7240_PORT_VLAN_DEST_PORTS_S 16
|
|
+#define AR7240_PORT_VLAN_MODE_S 30
|
|
+#define AR7240_PORT_VLAN_MODE_PORT_ONLY 0
|
|
+#define AR7240_PORT_VLAN_MODE_PORT_FALLBACK 1
|
|
+#define AR7240_PORT_VLAN_MODE_VLAN_ONLY 2
|
|
+#define AR7240_PORT_VLAN_MODE_SECURE 3
|
|
+
|
|
+
|
|
+#define AR7240_REG_STATS_BASE(_port) (0x20000 + (_port) * 0x100)
|
|
+
|
|
+#define AR7240_STATS_RXBROAD 0x00
|
|
+#define AR7240_STATS_RXPAUSE 0x04
|
|
+#define AR7240_STATS_RXMULTI 0x08
|
|
+#define AR7240_STATS_RXFCSERR 0x0c
|
|
+#define AR7240_STATS_RXALIGNERR 0x10
|
|
+#define AR7240_STATS_RXRUNT 0x14
|
|
+#define AR7240_STATS_RXFRAGMENT 0x18
|
|
+#define AR7240_STATS_RX64BYTE 0x1c
|
|
+#define AR7240_STATS_RX128BYTE 0x20
|
|
+#define AR7240_STATS_RX256BYTE 0x24
|
|
+#define AR7240_STATS_RX512BYTE 0x28
|
|
+#define AR7240_STATS_RX1024BYTE 0x2c
|
|
+#define AR7240_STATS_RX1518BYTE 0x30
|
|
+#define AR7240_STATS_RXMAXBYTE 0x34
|
|
+#define AR7240_STATS_RXTOOLONG 0x38
|
|
+#define AR7240_STATS_RXGOODBYTE 0x3c
|
|
+#define AR7240_STATS_RXBADBYTE 0x44
|
|
+#define AR7240_STATS_RXOVERFLOW 0x4c
|
|
+#define AR7240_STATS_FILTERED 0x50
|
|
+#define AR7240_STATS_TXBROAD 0x54
|
|
+#define AR7240_STATS_TXPAUSE 0x58
|
|
+#define AR7240_STATS_TXMULTI 0x5c
|
|
+#define AR7240_STATS_TXUNDERRUN 0x60
|
|
+#define AR7240_STATS_TX64BYTE 0x64
|
|
+#define AR7240_STATS_TX128BYTE 0x68
|
|
+#define AR7240_STATS_TX256BYTE 0x6c
|
|
+#define AR7240_STATS_TX512BYTE 0x70
|
|
+#define AR7240_STATS_TX1024BYTE 0x74
|
|
+#define AR7240_STATS_TX1518BYTE 0x78
|
|
+#define AR7240_STATS_TXMAXBYTE 0x7c
|
|
+#define AR7240_STATS_TXOVERSIZE 0x80
|
|
+#define AR7240_STATS_TXBYTE 0x84
|
|
+#define AR7240_STATS_TXCOLLISION 0x8c
|
|
+#define AR7240_STATS_TXABORTCOL 0x90
|
|
+#define AR7240_STATS_TXMULTICOL 0x94
|
|
+#define AR7240_STATS_TXSINGLECOL 0x98
|
|
+#define AR7240_STATS_TXEXCDEFER 0x9c
|
|
+#define AR7240_STATS_TXDEFER 0xa0
|
|
+#define AR7240_STATS_TXLATECOL 0xa4
|
|
+
|
|
+#define AR7240_PORT_CPU 0
|
|
+#define AR7240_NUM_PORTS 6
|
|
+#define AR7240_NUM_PHYS 5
|
|
+
|
|
+#define AR7240_PHY_ID1 0x004d
|
|
+#define AR7240_PHY_ID2 0xd041
|
|
+
|
|
+#define AR934X_PHY_ID1 0x004d
|
|
+#define AR934X_PHY_ID2 0xd042
|
|
+
|
|
+#define AR7240_MAX_VLANS 16
|
|
+
|
|
+#define AR934X_REG_OPER_MODE0 0x04
|
|
+#define AR934X_OPER_MODE0_MAC_GMII_EN BIT(6)
|
|
+#define AR934X_OPER_MODE0_PHY_MII_EN BIT(10)
|
|
+
|
|
+#define AR934X_REG_OPER_MODE1 0x08
|
|
+#define AR934X_REG_OPER_MODE1_PHY4_MII_EN BIT(28)
|
|
+
|
|
+#define AR934X_REG_FLOOD_MASK 0x2c
|
|
+#define AR934X_FLOOD_MASK_MC_DP(_p) BIT(16 + (_p))
|
|
+#define AR934X_FLOOD_MASK_BC_DP(_p) BIT(25 + (_p))
|
|
+
|
|
+#define AR934X_REG_QM_CTRL 0x3c
|
|
+#define AR934X_QM_CTRL_ARP_EN BIT(15)
|
|
+
|
|
+#define AR934X_REG_AT_CTRL 0x5c
|
|
+#define AR934X_AT_CTRL_AGE_TIME BITS(0, 15)
|
|
+#define AR934X_AT_CTRL_AGE_EN BIT(17)
|
|
+#define AR934X_AT_CTRL_LEARN_CHANGE BIT(18)
|
|
+
|
|
+#define AR934X_MIB_ENABLE BIT(30)
|
|
+
|
|
+#define AR934X_REG_PORT_BASE(_port) (0x100 + (_port) * 0x100)
|
|
+
|
|
+#define AR934X_REG_PORT_VLAN1(_port) (AR934X_REG_PORT_BASE((_port)) + 0x08)
|
|
+#define AR934X_PORT_VLAN1_DEFAULT_SVID_S 0
|
|
+#define AR934X_PORT_VLAN1_FORCE_DEFAULT_VID_EN BIT(12)
|
|
+#define AR934X_PORT_VLAN1_PORT_TLS_MODE BIT(13)
|
|
+#define AR934X_PORT_VLAN1_PORT_VLAN_PROP_EN BIT(14)
|
|
+#define AR934X_PORT_VLAN1_PORT_CLONE_EN BIT(15)
|
|
+#define AR934X_PORT_VLAN1_DEFAULT_CVID_S 16
|
|
+#define AR934X_PORT_VLAN1_FORCE_PORT_VLAN_EN BIT(28)
|
|
+#define AR934X_PORT_VLAN1_ING_PORT_PRI_S 29
|
|
+
|
|
+#define AR934X_REG_PORT_VLAN2(_port) (AR934X_REG_PORT_BASE((_port)) + 0x0c)
|
|
+#define AR934X_PORT_VLAN2_PORT_VID_MEM_S 16
|
|
+#define AR934X_PORT_VLAN2_8021Q_MODE_S 30
|
|
+#define AR934X_PORT_VLAN2_8021Q_MODE_PORT_ONLY 0
|
|
+#define AR934X_PORT_VLAN2_8021Q_MODE_PORT_FALLBACK 1
|
|
+#define AR934X_PORT_VLAN2_8021Q_MODE_VLAN_ONLY 2
|
|
+#define AR934X_PORT_VLAN2_8021Q_MODE_SECURE 3
|
|
+
|
|
+#define sw_to_ar7240(_dev) container_of(_dev, struct ar7240sw, swdev)
|
|
+
|
|
+struct ar7240sw_port_stat {
|
|
+ unsigned long rx_broadcast;
|
|
+ unsigned long rx_pause;
|
|
+ unsigned long rx_multicast;
|
|
+ unsigned long rx_fcs_error;
|
|
+ unsigned long rx_align_error;
|
|
+ unsigned long rx_runt;
|
|
+ unsigned long rx_fragments;
|
|
+ unsigned long rx_64byte;
|
|
+ unsigned long rx_128byte;
|
|
+ unsigned long rx_256byte;
|
|
+ unsigned long rx_512byte;
|
|
+ unsigned long rx_1024byte;
|
|
+ unsigned long rx_1518byte;
|
|
+ unsigned long rx_maxbyte;
|
|
+ unsigned long rx_toolong;
|
|
+ unsigned long rx_good_byte;
|
|
+ unsigned long rx_bad_byte;
|
|
+ unsigned long rx_overflow;
|
|
+ unsigned long filtered;
|
|
+
|
|
+ unsigned long tx_broadcast;
|
|
+ unsigned long tx_pause;
|
|
+ unsigned long tx_multicast;
|
|
+ unsigned long tx_underrun;
|
|
+ unsigned long tx_64byte;
|
|
+ unsigned long tx_128byte;
|
|
+ unsigned long tx_256byte;
|
|
+ unsigned long tx_512byte;
|
|
+ unsigned long tx_1024byte;
|
|
+ unsigned long tx_1518byte;
|
|
+ unsigned long tx_maxbyte;
|
|
+ unsigned long tx_oversize;
|
|
+ unsigned long tx_byte;
|
|
+ unsigned long tx_collision;
|
|
+ unsigned long tx_abortcol;
|
|
+ unsigned long tx_multicol;
|
|
+ unsigned long tx_singlecol;
|
|
+ unsigned long tx_excdefer;
|
|
+ unsigned long tx_defer;
|
|
+ unsigned long tx_xlatecol;
|
|
+};
|
|
+
|
|
+struct ar7240sw {
|
|
+ struct mii_bus *mii_bus;
|
|
+ struct mii_bus *switch_mii_bus;
|
|
+ struct device_node *of_node;
|
|
+ struct device_node *mdio_node;
|
|
+ struct switch_dev swdev;
|
|
+ int num_ports;
|
|
+ u8 ver;
|
|
+ bool vlan;
|
|
+ u16 vlan_id[AR7240_MAX_VLANS];
|
|
+ u8 vlan_table[AR7240_MAX_VLANS];
|
|
+ u8 vlan_tagged;
|
|
+ u16 pvid[AR7240_NUM_PORTS];
|
|
+ char buf[80];
|
|
+
|
|
+ rwlock_t stats_lock;
|
|
+ struct ar7240sw_port_stat port_stats[AR7240_NUM_PORTS];
|
|
+};
|
|
+
|
|
+struct ar7240sw_hw_stat {
|
|
+ char string[ETH_GSTRING_LEN];
|
|
+ int sizeof_stat;
|
|
+ int reg;
|
|
+};
|
|
+
|
|
+static DEFINE_MUTEX(reg_mutex);
|
|
+
|
|
+static inline int sw_is_ar7240(struct ar7240sw *as)
|
|
+{
|
|
+ return as->ver == AR7240_MASK_CTRL_VERSION_AR7240;
|
|
+}
|
|
+
|
|
+static inline int sw_is_ar934x(struct ar7240sw *as)
|
|
+{
|
|
+ return as->ver == AR7240_MASK_CTRL_VERSION_AR934X;
|
|
+}
|
|
+
|
|
+static inline u32 ar7240sw_port_mask(struct ar7240sw *as, int port)
|
|
+{
|
|
+ return BIT(port);
|
|
+}
|
|
+
|
|
+static inline u32 ar7240sw_port_mask_all(struct ar7240sw *as)
|
|
+{
|
|
+ return BIT(as->swdev.ports) - 1;
|
|
+}
|
|
+
|
|
+static inline u32 ar7240sw_port_mask_but(struct ar7240sw *as, int port)
|
|
+{
|
|
+ return ar7240sw_port_mask_all(as) & ~BIT(port);
|
|
+}
|
|
+
|
|
+static inline u16 mk_phy_addr(u32 reg)
|
|
+{
|
|
+ return 0x17 & ((reg >> 4) | 0x10);
|
|
+}
|
|
+
|
|
+static inline u16 mk_phy_reg(u32 reg)
|
|
+{
|
|
+ return (reg << 1) & 0x1e;
|
|
+}
|
|
+
|
|
+static inline u16 mk_high_addr(u32 reg)
|
|
+{
|
|
+ return (reg >> 7) & 0x1ff;
|
|
+}
|
|
+
|
|
+static u32 __ar7240sw_reg_read(struct mii_bus *mii, u32 reg)
|
|
+{
|
|
+ unsigned long flags;
|
|
+ u16 phy_addr;
|
|
+ u16 phy_reg;
|
|
+ u32 hi, lo;
|
|
+
|
|
+ reg = (reg & 0xfffffffc) >> 2;
|
|
+ phy_addr = mk_phy_addr(reg);
|
|
+ phy_reg = mk_phy_reg(reg);
|
|
+
|
|
+ local_irq_save(flags);
|
|
+ mutex_lock(&mii->mdio_lock);
|
|
+ mii->write(mii, 0x1f, 0x10, mk_high_addr(reg));
|
|
+ lo = (u32) mii->read(mii, phy_addr, phy_reg);
|
|
+ hi = (u32) mii->read(mii, phy_addr, phy_reg + 1);
|
|
+ mutex_unlock(&mii->mdio_lock);
|
|
+ local_irq_restore(flags);
|
|
+
|
|
+ return (hi << 16) | lo;
|
|
+}
|
|
+
|
|
+static void __ar7240sw_reg_write(struct mii_bus *mii, u32 reg, u32 val)
|
|
+{
|
|
+ unsigned long flags;
|
|
+ u16 phy_addr;
|
|
+ u16 phy_reg;
|
|
+
|
|
+ reg = (reg & 0xfffffffc) >> 2;
|
|
+ phy_addr = mk_phy_addr(reg);
|
|
+ phy_reg = mk_phy_reg(reg);
|
|
+
|
|
+ local_irq_save(flags);
|
|
+ mutex_lock(&mii->mdio_lock);
|
|
+ mii->write(mii, 0x1f, 0x10, mk_high_addr(reg));
|
|
+ mii->write(mii, phy_addr, phy_reg + 1, (val >> 16));
|
|
+ mii->write(mii, phy_addr, phy_reg, (val & 0xffff));
|
|
+ mutex_unlock(&mii->mdio_lock);
|
|
+ local_irq_restore(flags);
|
|
+}
|
|
+
|
|
+static u32 ar7240sw_reg_read(struct mii_bus *mii, u32 reg_addr)
|
|
+{
|
|
+ u32 ret;
|
|
+
|
|
+ mutex_lock(®_mutex);
|
|
+ ret = __ar7240sw_reg_read(mii, reg_addr);
|
|
+ mutex_unlock(®_mutex);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static void ar7240sw_reg_write(struct mii_bus *mii, u32 reg_addr, u32 reg_val)
|
|
+{
|
|
+ mutex_lock(®_mutex);
|
|
+ __ar7240sw_reg_write(mii, reg_addr, reg_val);
|
|
+ mutex_unlock(®_mutex);
|
|
+}
|
|
+
|
|
+static u32 ar7240sw_reg_rmw(struct mii_bus *mii, u32 reg, u32 mask, u32 val)
|
|
+{
|
|
+ u32 t;
|
|
+
|
|
+ mutex_lock(®_mutex);
|
|
+ t = __ar7240sw_reg_read(mii, reg);
|
|
+ t &= ~mask;
|
|
+ t |= val;
|
|
+ __ar7240sw_reg_write(mii, reg, t);
|
|
+ mutex_unlock(®_mutex);
|
|
+
|
|
+ return t;
|
|
+}
|
|
+
|
|
+static void ar7240sw_reg_set(struct mii_bus *mii, u32 reg, u32 val)
|
|
+{
|
|
+ u32 t;
|
|
+
|
|
+ mutex_lock(®_mutex);
|
|
+ t = __ar7240sw_reg_read(mii, reg);
|
|
+ t |= val;
|
|
+ __ar7240sw_reg_write(mii, reg, t);
|
|
+ mutex_unlock(®_mutex);
|
|
+}
|
|
+
|
|
+static int __ar7240sw_reg_wait(struct mii_bus *mii, u32 reg, u32 mask, u32 val,
|
|
+ unsigned timeout)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ for (i = 0; i < timeout; i++) {
|
|
+ u32 t;
|
|
+
|
|
+ t = __ar7240sw_reg_read(mii, reg);
|
|
+ if ((t & mask) == val)
|
|
+ return 0;
|
|
+
|
|
+ usleep_range(1000, 2000);
|
|
+ }
|
|
+
|
|
+ return -ETIMEDOUT;
|
|
+}
|
|
+
|
|
+static int ar7240sw_reg_wait(struct mii_bus *mii, u32 reg, u32 mask, u32 val,
|
|
+ unsigned timeout)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ mutex_lock(®_mutex);
|
|
+ ret = __ar7240sw_reg_wait(mii, reg, mask, val, timeout);
|
|
+ mutex_unlock(®_mutex);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+int ar7240sw_phy_read(struct mii_bus *bus, int phy_addr, int reg_addr)
|
|
+{
|
|
+ u32 t, val = 0xffff;
|
|
+ int err;
|
|
+ struct ar7240sw *as = bus->priv;
|
|
+ struct mii_bus *mii = as->mii_bus;
|
|
+
|
|
+ if (phy_addr >= AR7240_NUM_PHYS)
|
|
+ return 0xffff;
|
|
+
|
|
+ mutex_lock(®_mutex);
|
|
+ t = (reg_addr << AR7240_MDIO_CTRL_REG_ADDR_S) |
|
|
+ (phy_addr << AR7240_MDIO_CTRL_PHY_ADDR_S) |
|
|
+ AR7240_MDIO_CTRL_MASTER_EN |
|
|
+ AR7240_MDIO_CTRL_BUSY |
|
|
+ AR7240_MDIO_CTRL_CMD_READ;
|
|
+
|
|
+ __ar7240sw_reg_write(mii, AR7240_REG_MDIO_CTRL, t);
|
|
+ err = __ar7240sw_reg_wait(mii, AR7240_REG_MDIO_CTRL,
|
|
+ AR7240_MDIO_CTRL_BUSY, 0, 5);
|
|
+ if (!err)
|
|
+ val = __ar7240sw_reg_read(mii, AR7240_REG_MDIO_CTRL);
|
|
+ mutex_unlock(®_mutex);
|
|
+
|
|
+ return val & AR7240_MDIO_CTRL_DATA_M;
|
|
+}
|
|
+
|
|
+int ar7240sw_phy_write(struct mii_bus *bus, int phy_addr, int reg_addr,
|
|
+ u16 reg_val)
|
|
+{
|
|
+ u32 t;
|
|
+ int ret;
|
|
+ struct ar7240sw *as = bus->priv;
|
|
+ struct mii_bus *mii = as->mii_bus;
|
|
+
|
|
+ if (phy_addr >= AR7240_NUM_PHYS)
|
|
+ return -EINVAL;
|
|
+
|
|
+ mutex_lock(®_mutex);
|
|
+ t = (phy_addr << AR7240_MDIO_CTRL_PHY_ADDR_S) |
|
|
+ (reg_addr << AR7240_MDIO_CTRL_REG_ADDR_S) |
|
|
+ AR7240_MDIO_CTRL_MASTER_EN |
|
|
+ AR7240_MDIO_CTRL_BUSY |
|
|
+ AR7240_MDIO_CTRL_CMD_WRITE |
|
|
+ reg_val;
|
|
+
|
|
+ __ar7240sw_reg_write(mii, AR7240_REG_MDIO_CTRL, t);
|
|
+ ret = __ar7240sw_reg_wait(mii, AR7240_REG_MDIO_CTRL,
|
|
+ AR7240_MDIO_CTRL_BUSY, 0, 5);
|
|
+ mutex_unlock(®_mutex);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int ar7240sw_capture_stats(struct ar7240sw *as)
|
|
+{
|
|
+ struct mii_bus *mii = as->mii_bus;
|
|
+ int port;
|
|
+ int ret;
|
|
+
|
|
+ write_lock(&as->stats_lock);
|
|
+
|
|
+ /* Capture the hardware statistics for all ports */
|
|
+ ar7240sw_reg_rmw(mii, AR7240_REG_MIB_FUNCTION0,
|
|
+ (AR7240_MIB_FUNC_M << AR7240_MIB_FUNC_S),
|
|
+ (AR7240_MIB_FUNC_CAPTURE << AR7240_MIB_FUNC_S));
|
|
+
|
|
+ /* Wait for the capturing to complete. */
|
|
+ ret = ar7240sw_reg_wait(mii, AR7240_REG_MIB_FUNCTION0,
|
|
+ AR7240_MIB_BUSY, 0, 10);
|
|
+
|
|
+ if (ret)
|
|
+ goto unlock;
|
|
+
|
|
+ for (port = 0; port < AR7240_NUM_PORTS; port++) {
|
|
+ unsigned int base;
|
|
+ struct ar7240sw_port_stat *stats;
|
|
+
|
|
+ base = AR7240_REG_STATS_BASE(port);
|
|
+ stats = &as->port_stats[port];
|
|
+
|
|
+#define READ_STAT(_r) ar7240sw_reg_read(mii, base + AR7240_STATS_ ## _r)
|
|
+
|
|
+ stats->rx_good_byte += READ_STAT(RXGOODBYTE);
|
|
+ stats->tx_byte += READ_STAT(TXBYTE);
|
|
+
|
|
+#undef READ_STAT
|
|
+ }
|
|
+
|
|
+ ret = 0;
|
|
+
|
|
+unlock:
|
|
+ write_unlock(&as->stats_lock);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static void ar7240sw_disable_port(struct ar7240sw *as, unsigned port)
|
|
+{
|
|
+ ar7240sw_reg_write(as->mii_bus, AR7240_REG_PORT_CTRL(port),
|
|
+ AR7240_PORT_CTRL_STATE_DISABLED);
|
|
+}
|
|
+
|
|
+static void ar7240sw_setup(struct ar7240sw *as)
|
|
+{
|
|
+ struct mii_bus *mii = as->mii_bus;
|
|
+
|
|
+ /* Enable CPU port, and disable mirror port */
|
|
+ ar7240sw_reg_write(mii, AR7240_REG_CPU_PORT,
|
|
+ AR7240_CPU_PORT_EN |
|
|
+ (15 << AR7240_MIRROR_PORT_S));
|
|
+
|
|
+ /* Setup TAG priority mapping */
|
|
+ ar7240sw_reg_write(mii, AR7240_REG_TAG_PRIORITY, 0xfa50);
|
|
+
|
|
+ if (sw_is_ar934x(as)) {
|
|
+ /* Enable aging, MAC replacing */
|
|
+ ar7240sw_reg_write(mii, AR934X_REG_AT_CTRL,
|
|
+ 0x2b /* 5 min age time */ |
|
|
+ AR934X_AT_CTRL_AGE_EN |
|
|
+ AR934X_AT_CTRL_LEARN_CHANGE);
|
|
+ /* Enable ARP frame acknowledge */
|
|
+ ar7240sw_reg_set(mii, AR934X_REG_QM_CTRL,
|
|
+ AR934X_QM_CTRL_ARP_EN);
|
|
+ /* Enable Broadcast/Multicast frames transmitted to the CPU */
|
|
+ ar7240sw_reg_set(mii, AR934X_REG_FLOOD_MASK,
|
|
+ AR934X_FLOOD_MASK_BC_DP(0) |
|
|
+ AR934X_FLOOD_MASK_MC_DP(0));
|
|
+
|
|
+ /* setup MTU */
|
|
+ ar7240sw_reg_rmw(mii, AR7240_REG_GLOBAL_CTRL,
|
|
+ AR9340_GLOBAL_CTRL_MTU_M,
|
|
+ AR9340_GLOBAL_CTRL_MTU_M);
|
|
+
|
|
+ /* Enable MIB counters */
|
|
+ ar7240sw_reg_set(mii, AR7240_REG_MIB_FUNCTION0,
|
|
+ AR934X_MIB_ENABLE);
|
|
+
|
|
+ } else {
|
|
+ /* Enable ARP frame acknowledge, aging, MAC replacing */
|
|
+ ar7240sw_reg_write(mii, AR7240_REG_AT_CTRL,
|
|
+ AR7240_AT_CTRL_RESERVED |
|
|
+ 0x2b /* 5 min age time */ |
|
|
+ AR7240_AT_CTRL_AGE_EN |
|
|
+ AR7240_AT_CTRL_ARP_EN |
|
|
+ AR7240_AT_CTRL_LEARN_CHANGE);
|
|
+ /* Enable Broadcast frames transmitted to the CPU */
|
|
+ ar7240sw_reg_set(mii, AR7240_REG_FLOOD_MASK,
|
|
+ AR7240_FLOOD_MASK_BROAD_TO_CPU);
|
|
+
|
|
+ /* setup MTU */
|
|
+ ar7240sw_reg_rmw(mii, AR7240_REG_GLOBAL_CTRL,
|
|
+ AR7240_GLOBAL_CTRL_MTU_M,
|
|
+ AR7240_GLOBAL_CTRL_MTU_M);
|
|
+ }
|
|
+
|
|
+ /* setup Service TAG */
|
|
+ ar7240sw_reg_rmw(mii, AR7240_REG_SERVICE_TAG, AR7240_SERVICE_TAG_M, 0);
|
|
+}
|
|
+
|
|
+/* inspired by phy_poll_reset in drivers/net/phy/phy_device.c */
|
|
+static int
|
|
+ar7240sw_phy_poll_reset(struct mii_bus *bus)
|
|
+{
|
|
+ const unsigned int sleep_msecs = 20;
|
|
+ int ret, elapsed, i;
|
|
+
|
|
+ for (elapsed = sleep_msecs; elapsed <= 600;
|
|
+ elapsed += sleep_msecs) {
|
|
+ msleep(sleep_msecs);
|
|
+ for (i = 0; i < AR7240_NUM_PHYS; i++) {
|
|
+ ret = ar7240sw_phy_read(bus, i, MII_BMCR);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+ if (ret & BMCR_RESET)
|
|
+ break;
|
|
+ if (i == AR7240_NUM_PHYS - 1) {
|
|
+ usleep_range(1000, 2000);
|
|
+ return 0;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ return -ETIMEDOUT;
|
|
+}
|
|
+
|
|
+static int ar7240sw_reset(struct ar7240sw *as)
|
|
+{
|
|
+ struct mii_bus *mii = as->mii_bus;
|
|
+ struct mii_bus *swmii = as->switch_mii_bus;
|
|
+ int ret;
|
|
+ int i;
|
|
+
|
|
+ /* Set all ports to disabled state. */
|
|
+ for (i = 0; i < AR7240_NUM_PORTS; i++)
|
|
+ ar7240sw_disable_port(as, i);
|
|
+
|
|
+ /* Wait for transmit queues to drain. */
|
|
+ usleep_range(2000, 3000);
|
|
+
|
|
+ /* Reset the switch. */
|
|
+ ar7240sw_reg_write(mii, AR7240_REG_MASK_CTRL,
|
|
+ AR7240_MASK_CTRL_SOFT_RESET);
|
|
+
|
|
+ ret = ar7240sw_reg_wait(mii, AR7240_REG_MASK_CTRL,
|
|
+ AR7240_MASK_CTRL_SOFT_RESET, 0, 1000);
|
|
+
|
|
+ /* setup PHYs */
|
|
+ for (i = 0; i < AR7240_NUM_PHYS; i++) {
|
|
+ ar7240sw_phy_write(swmii, i, MII_ADVERTISE,
|
|
+ ADVERTISE_ALL | ADVERTISE_PAUSE_CAP |
|
|
+ ADVERTISE_PAUSE_ASYM);
|
|
+ ar7240sw_phy_write(swmii, i, MII_BMCR,
|
|
+ BMCR_RESET | BMCR_ANENABLE);
|
|
+ }
|
|
+ ret = ar7240sw_phy_poll_reset(swmii);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ ar7240sw_setup(as);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static void ar7240sw_setup_port(struct ar7240sw *as, unsigned port, u8 portmask)
|
|
+{
|
|
+ struct mii_bus *mii = as->mii_bus;
|
|
+ u32 ctrl;
|
|
+ u32 vid, mode;
|
|
+
|
|
+ ctrl = AR7240_PORT_CTRL_STATE_FORWARD | AR7240_PORT_CTRL_LEARN |
|
|
+ AR7240_PORT_CTRL_SINGLE_VLAN;
|
|
+
|
|
+ if (port == AR7240_PORT_CPU) {
|
|
+ ar7240sw_reg_write(mii, AR7240_REG_PORT_STATUS(port),
|
|
+ AR7240_PORT_STATUS_SPEED_1000 |
|
|
+ AR7240_PORT_STATUS_TXFLOW |
|
|
+ AR7240_PORT_STATUS_RXFLOW |
|
|
+ AR7240_PORT_STATUS_TXMAC |
|
|
+ AR7240_PORT_STATUS_RXMAC |
|
|
+ AR7240_PORT_STATUS_DUPLEX);
|
|
+ } else {
|
|
+ ar7240sw_reg_write(mii, AR7240_REG_PORT_STATUS(port),
|
|
+ AR7240_PORT_STATUS_LINK_AUTO);
|
|
+ }
|
|
+
|
|
+ /* Set the default VID for this port */
|
|
+ if (as->vlan) {
|
|
+ vid = as->vlan_id[as->pvid[port]];
|
|
+ mode = AR7240_PORT_VLAN_MODE_SECURE;
|
|
+ } else {
|
|
+ vid = port;
|
|
+ mode = AR7240_PORT_VLAN_MODE_PORT_ONLY;
|
|
+ }
|
|
+
|
|
+ if (as->vlan) {
|
|
+ if (as->vlan_tagged & BIT(port))
|
|
+ ctrl |= AR7240_PORT_CTRL_VLAN_MODE_ADD <<
|
|
+ AR7240_PORT_CTRL_VLAN_MODE_S;
|
|
+ else
|
|
+ ctrl |= AR7240_PORT_CTRL_VLAN_MODE_STRIP <<
|
|
+ AR7240_PORT_CTRL_VLAN_MODE_S;
|
|
+ } else {
|
|
+ ctrl |= AR7240_PORT_CTRL_VLAN_MODE_KEEP <<
|
|
+ AR7240_PORT_CTRL_VLAN_MODE_S;
|
|
+ }
|
|
+
|
|
+ if (!portmask) {
|
|
+ if (port == AR7240_PORT_CPU)
|
|
+ portmask = ar7240sw_port_mask_but(as, AR7240_PORT_CPU);
|
|
+ else
|
|
+ portmask = ar7240sw_port_mask(as, AR7240_PORT_CPU);
|
|
+ }
|
|
+
|
|
+ /* preserve mirror rx&tx flags */
|
|
+ ctrl |= ar7240sw_reg_read(mii, AR7240_REG_PORT_CTRL(port)) &
|
|
+ (AR7240_PORT_CTRL_MIRROR_RX | AR7240_PORT_CTRL_MIRROR_TX);
|
|
+
|
|
+ /* allow the port to talk to all other ports, but exclude its
|
|
+ * own ID to prevent frames from being reflected back to the
|
|
+ * port that they came from */
|
|
+ portmask &= ar7240sw_port_mask_but(as, port);
|
|
+
|
|
+ ar7240sw_reg_write(mii, AR7240_REG_PORT_CTRL(port), ctrl);
|
|
+ if (sw_is_ar934x(as)) {
|
|
+ u32 vlan1, vlan2;
|
|
+
|
|
+ vlan1 = (vid << AR934X_PORT_VLAN1_DEFAULT_CVID_S);
|
|
+ vlan2 = (portmask << AR934X_PORT_VLAN2_PORT_VID_MEM_S) |
|
|
+ (mode << AR934X_PORT_VLAN2_8021Q_MODE_S);
|
|
+ ar7240sw_reg_write(mii, AR934X_REG_PORT_VLAN1(port), vlan1);
|
|
+ ar7240sw_reg_write(mii, AR934X_REG_PORT_VLAN2(port), vlan2);
|
|
+ } else {
|
|
+ u32 vlan;
|
|
+
|
|
+ vlan = vid | (mode << AR7240_PORT_VLAN_MODE_S) |
|
|
+ (portmask << AR7240_PORT_VLAN_DEST_PORTS_S);
|
|
+
|
|
+ ar7240sw_reg_write(mii, AR7240_REG_PORT_VLAN(port), vlan);
|
|
+ }
|
|
+}
|
|
+
|
|
+static int
|
|
+ar7240_set_vid(struct switch_dev *dev, const struct switch_attr *attr,
|
|
+ struct switch_val *val)
|
|
+{
|
|
+ struct ar7240sw *as = sw_to_ar7240(dev);
|
|
+ as->vlan_id[val->port_vlan] = val->value.i;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+ar7240_get_vid(struct switch_dev *dev, const struct switch_attr *attr,
|
|
+ struct switch_val *val)
|
|
+{
|
|
+ struct ar7240sw *as = sw_to_ar7240(dev);
|
|
+ val->value.i = as->vlan_id[val->port_vlan];
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+ar7240_set_pvid(struct switch_dev *dev, int port, int vlan)
|
|
+{
|
|
+ struct ar7240sw *as = sw_to_ar7240(dev);
|
|
+
|
|
+ /* make sure no invalid PVIDs get set */
|
|
+
|
|
+ if (vlan >= dev->vlans)
|
|
+ return -EINVAL;
|
|
+
|
|
+ as->pvid[port] = vlan;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+ar7240_get_pvid(struct switch_dev *dev, int port, int *vlan)
|
|
+{
|
|
+ struct ar7240sw *as = sw_to_ar7240(dev);
|
|
+ *vlan = as->pvid[port];
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+ar7240_get_ports(struct switch_dev *dev, struct switch_val *val)
|
|
+{
|
|
+ struct ar7240sw *as = sw_to_ar7240(dev);
|
|
+ u8 ports = as->vlan_table[val->port_vlan];
|
|
+ int i;
|
|
+
|
|
+ val->len = 0;
|
|
+ for (i = 0; i < as->swdev.ports; i++) {
|
|
+ struct switch_port *p;
|
|
+
|
|
+ if (!(ports & (1 << i)))
|
|
+ continue;
|
|
+
|
|
+ p = &val->value.ports[val->len++];
|
|
+ p->id = i;
|
|
+ if (as->vlan_tagged & (1 << i))
|
|
+ p->flags = (1 << SWITCH_PORT_FLAG_TAGGED);
|
|
+ else
|
|
+ p->flags = 0;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+ar7240_set_ports(struct switch_dev *dev, struct switch_val *val)
|
|
+{
|
|
+ struct ar7240sw *as = sw_to_ar7240(dev);
|
|
+ u8 *vt = &as->vlan_table[val->port_vlan];
|
|
+ int i, j;
|
|
+
|
|
+ *vt = 0;
|
|
+ for (i = 0; i < val->len; i++) {
|
|
+ struct switch_port *p = &val->value.ports[i];
|
|
+
|
|
+ if (p->flags & (1 << SWITCH_PORT_FLAG_TAGGED))
|
|
+ as->vlan_tagged |= (1 << p->id);
|
|
+ else {
|
|
+ as->vlan_tagged &= ~(1 << p->id);
|
|
+ as->pvid[p->id] = val->port_vlan;
|
|
+
|
|
+ /* make sure that an untagged port does not
|
|
+ * appear in other vlans */
|
|
+ for (j = 0; j < AR7240_MAX_VLANS; j++) {
|
|
+ if (j == val->port_vlan)
|
|
+ continue;
|
|
+ as->vlan_table[j] &= ~(1 << p->id);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ *vt |= 1 << p->id;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+ar7240_set_vlan(struct switch_dev *dev, const struct switch_attr *attr,
|
|
+ struct switch_val *val)
|
|
+{
|
|
+ struct ar7240sw *as = sw_to_ar7240(dev);
|
|
+ as->vlan = !!val->value.i;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+ar7240_get_vlan(struct switch_dev *dev, const struct switch_attr *attr,
|
|
+ struct switch_val *val)
|
|
+{
|
|
+ struct ar7240sw *as = sw_to_ar7240(dev);
|
|
+ val->value.i = as->vlan;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void
|
|
+ar7240_vtu_op(struct ar7240sw *as, u32 op, u32 val)
|
|
+{
|
|
+ struct mii_bus *mii = as->mii_bus;
|
|
+
|
|
+ if (ar7240sw_reg_wait(mii, AR7240_REG_VTU, AR7240_VTU_ACTIVE, 0, 5))
|
|
+ return;
|
|
+
|
|
+ if ((op & AR7240_VTU_OP) == AR7240_VTU_OP_LOAD) {
|
|
+ val &= AR7240_VTUDATA_MEMBER;
|
|
+ val |= AR7240_VTUDATA_VALID;
|
|
+ ar7240sw_reg_write(mii, AR7240_REG_VTU_DATA, val);
|
|
+ }
|
|
+ op |= AR7240_VTU_ACTIVE;
|
|
+ ar7240sw_reg_write(mii, AR7240_REG_VTU, op);
|
|
+}
|
|
+
|
|
+static int
|
|
+ar7240_hw_apply(struct switch_dev *dev)
|
|
+{
|
|
+ struct ar7240sw *as = sw_to_ar7240(dev);
|
|
+ u8 portmask[AR7240_NUM_PORTS];
|
|
+ int i, j;
|
|
+
|
|
+ /* flush all vlan translation unit entries */
|
|
+ ar7240_vtu_op(as, AR7240_VTU_OP_FLUSH, 0);
|
|
+
|
|
+ memset(portmask, 0, sizeof(portmask));
|
|
+ if (as->vlan) {
|
|
+ /* calculate the port destination masks and load vlans
|
|
+ * into the vlan translation unit */
|
|
+ for (j = 0; j < AR7240_MAX_VLANS; j++) {
|
|
+ u8 vp = as->vlan_table[j];
|
|
+
|
|
+ if (!vp)
|
|
+ continue;
|
|
+
|
|
+ for (i = 0; i < as->swdev.ports; i++) {
|
|
+ u8 mask = (1 << i);
|
|
+ if (vp & mask)
|
|
+ portmask[i] |= vp & ~mask;
|
|
+ }
|
|
+
|
|
+ ar7240_vtu_op(as,
|
|
+ AR7240_VTU_OP_LOAD |
|
|
+ (as->vlan_id[j] << AR7240_VTU_VID_S),
|
|
+ as->vlan_table[j]);
|
|
+ }
|
|
+ } else {
|
|
+ /* vlan disabled:
|
|
+ * isolate all ports, but connect them to the cpu port */
|
|
+ for (i = 0; i < as->swdev.ports; i++) {
|
|
+ if (i == AR7240_PORT_CPU)
|
|
+ continue;
|
|
+
|
|
+ portmask[i] = 1 << AR7240_PORT_CPU;
|
|
+ portmask[AR7240_PORT_CPU] |= (1 << i);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* update the port destination mask registers and tag settings */
|
|
+ for (i = 0; i < as->swdev.ports; i++)
|
|
+ ar7240sw_setup_port(as, i, portmask[i]);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+ar7240_reset_switch(struct switch_dev *dev)
|
|
+{
|
|
+ struct ar7240sw *as = sw_to_ar7240(dev);
|
|
+ ar7240sw_reset(as);
|
|
+
|
|
+ /* ar7240 reapply hardware settings*/
|
|
+ if (sw_is_ar7240(as))
|
|
+ ar7240_hw_apply(dev);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+ar7240_get_port_link(struct switch_dev *dev, int port,
|
|
+ struct switch_port_link *link)
|
|
+{
|
|
+ struct ar7240sw *as = sw_to_ar7240(dev);
|
|
+ struct mii_bus *mii = as->mii_bus;
|
|
+ u32 status;
|
|
+
|
|
+ if (port >= AR7240_NUM_PORTS)
|
|
+ return -EINVAL;
|
|
+
|
|
+ status = ar7240sw_reg_read(mii, AR7240_REG_PORT_STATUS(port));
|
|
+ link->aneg = !!(status & AR7240_PORT_STATUS_LINK_AUTO);
|
|
+ if (link->aneg) {
|
|
+ link->link = !!(status & AR7240_PORT_STATUS_LINK_UP);
|
|
+ if (!link->link)
|
|
+ return 0;
|
|
+ } else {
|
|
+ link->link = true;
|
|
+ }
|
|
+
|
|
+ link->duplex = !!(status & AR7240_PORT_STATUS_DUPLEX);
|
|
+ link->tx_flow = !!(status & AR7240_PORT_STATUS_TXFLOW);
|
|
+ link->rx_flow = !!(status & AR7240_PORT_STATUS_RXFLOW);
|
|
+ switch (status & AR7240_PORT_STATUS_SPEED_M) {
|
|
+ case AR7240_PORT_STATUS_SPEED_10:
|
|
+ link->speed = SWITCH_PORT_SPEED_10;
|
|
+ break;
|
|
+ case AR7240_PORT_STATUS_SPEED_100:
|
|
+ link->speed = SWITCH_PORT_SPEED_100;
|
|
+ break;
|
|
+ case AR7240_PORT_STATUS_SPEED_1000:
|
|
+ link->speed = SWITCH_PORT_SPEED_1000;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+ar7240_get_port_stats(struct switch_dev *dev, int port,
|
|
+ struct switch_port_stats *stats)
|
|
+{
|
|
+ struct ar7240sw *as = sw_to_ar7240(dev);
|
|
+
|
|
+ if (port >= AR7240_NUM_PORTS)
|
|
+ return -EINVAL;
|
|
+
|
|
+ ar7240sw_capture_stats(as);
|
|
+
|
|
+ read_lock(&as->stats_lock);
|
|
+ stats->rx_bytes = as->port_stats[port].rx_good_byte;
|
|
+ stats->tx_bytes = as->port_stats[port].tx_byte;
|
|
+ read_unlock(&as->stats_lock);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+ar7240_set_mirror_monitor_port(struct switch_dev *dev,
|
|
+ const struct switch_attr *attr,
|
|
+ struct switch_val *val)
|
|
+{
|
|
+ struct ar7240sw *as = sw_to_ar7240(dev);
|
|
+ struct mii_bus *mii = as->mii_bus;
|
|
+
|
|
+ int port = val->value.i;
|
|
+
|
|
+ if (port > 15)
|
|
+ return -EINVAL;
|
|
+
|
|
+ ar7240sw_reg_rmw(mii, AR7240_REG_CPU_PORT,
|
|
+ AR7240_MIRROR_PORT_M << AR7240_MIRROR_PORT_S,
|
|
+ port << AR7240_MIRROR_PORT_S);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+ar7240_get_mirror_monitor_port(struct switch_dev *dev,
|
|
+ const struct switch_attr *attr,
|
|
+ struct switch_val *val)
|
|
+{
|
|
+ struct ar7240sw *as = sw_to_ar7240(dev);
|
|
+ struct mii_bus *mii = as->mii_bus;
|
|
+
|
|
+ u32 ret;
|
|
+
|
|
+ ret = ar7240sw_reg_read(mii, AR7240_REG_CPU_PORT);
|
|
+ val->value.i = (ret >> AR7240_MIRROR_PORT_S) & AR7240_MIRROR_PORT_M;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+ar7240_set_mirror_rx(struct switch_dev *dev, const struct switch_attr *attr,
|
|
+ struct switch_val *val)
|
|
+{
|
|
+ struct ar7240sw *as = sw_to_ar7240(dev);
|
|
+ struct mii_bus *mii = as->mii_bus;
|
|
+
|
|
+ int port = val->port_vlan;
|
|
+
|
|
+ if (port >= dev->ports)
|
|
+ return -EINVAL;
|
|
+
|
|
+ if (val && val->value.i == 1)
|
|
+ ar7240sw_reg_set(mii, AR7240_REG_PORT_CTRL(port),
|
|
+ AR7240_PORT_CTRL_MIRROR_RX);
|
|
+ else
|
|
+ ar7240sw_reg_rmw(mii, AR7240_REG_PORT_CTRL(port),
|
|
+ AR7240_PORT_CTRL_MIRROR_RX, 0);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+ar7240_get_mirror_rx(struct switch_dev *dev, const struct switch_attr *attr,
|
|
+ struct switch_val *val)
|
|
+{
|
|
+ struct ar7240sw *as = sw_to_ar7240(dev);
|
|
+ struct mii_bus *mii = as->mii_bus;
|
|
+
|
|
+ u32 ctrl;
|
|
+
|
|
+ int port = val->port_vlan;
|
|
+
|
|
+ if (port >= dev->ports)
|
|
+ return -EINVAL;
|
|
+
|
|
+ ctrl = ar7240sw_reg_read(mii, AR7240_REG_PORT_CTRL(port));
|
|
+
|
|
+ if ((ctrl & AR7240_PORT_CTRL_MIRROR_RX) == AR7240_PORT_CTRL_MIRROR_RX)
|
|
+ val->value.i = 1;
|
|
+ else
|
|
+ val->value.i = 0;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+ar7240_set_mirror_tx(struct switch_dev *dev, const struct switch_attr *attr,
|
|
+ struct switch_val *val)
|
|
+{
|
|
+ struct ar7240sw *as = sw_to_ar7240(dev);
|
|
+ struct mii_bus *mii = as->mii_bus;
|
|
+
|
|
+ int port = val->port_vlan;
|
|
+
|
|
+ if (port >= dev->ports)
|
|
+ return -EINVAL;
|
|
+
|
|
+ if (val && val->value.i == 1)
|
|
+ ar7240sw_reg_set(mii, AR7240_REG_PORT_CTRL(port),
|
|
+ AR7240_PORT_CTRL_MIRROR_TX);
|
|
+ else
|
|
+ ar7240sw_reg_rmw(mii, AR7240_REG_PORT_CTRL(port),
|
|
+ AR7240_PORT_CTRL_MIRROR_TX, 0);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+ar7240_get_mirror_tx(struct switch_dev *dev, const struct switch_attr *attr,
|
|
+ struct switch_val *val)
|
|
+{
|
|
+ struct ar7240sw *as = sw_to_ar7240(dev);
|
|
+ struct mii_bus *mii = as->mii_bus;
|
|
+
|
|
+ u32 ctrl;
|
|
+
|
|
+ int port = val->port_vlan;
|
|
+
|
|
+ if (port >= dev->ports)
|
|
+ return -EINVAL;
|
|
+
|
|
+ ctrl = ar7240sw_reg_read(mii, AR7240_REG_PORT_CTRL(port));
|
|
+
|
|
+ if ((ctrl & AR7240_PORT_CTRL_MIRROR_TX) == AR7240_PORT_CTRL_MIRROR_TX)
|
|
+ val->value.i = 1;
|
|
+ else
|
|
+ val->value.i = 0;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static struct switch_attr ar7240_globals[] = {
|
|
+ {
|
|
+ .type = SWITCH_TYPE_INT,
|
|
+ .name = "enable_vlan",
|
|
+ .description = "Enable VLAN mode",
|
|
+ .set = ar7240_set_vlan,
|
|
+ .get = ar7240_get_vlan,
|
|
+ .max = 1
|
|
+ },
|
|
+ {
|
|
+ .type = SWITCH_TYPE_INT,
|
|
+ .name = "mirror_monitor_port",
|
|
+ .description = "Mirror monitor port",
|
|
+ .set = ar7240_set_mirror_monitor_port,
|
|
+ .get = ar7240_get_mirror_monitor_port,
|
|
+ .max = 15
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct switch_attr ar7240_port[] = {
|
|
+ {
|
|
+ .type = SWITCH_TYPE_INT,
|
|
+ .name = "enable_mirror_rx",
|
|
+ .description = "Enable mirroring of RX packets",
|
|
+ .set = ar7240_set_mirror_rx,
|
|
+ .get = ar7240_get_mirror_rx,
|
|
+ .max = 1
|
|
+ },
|
|
+ {
|
|
+ .type = SWITCH_TYPE_INT,
|
|
+ .name = "enable_mirror_tx",
|
|
+ .description = "Enable mirroring of TX packets",
|
|
+ .set = ar7240_set_mirror_tx,
|
|
+ .get = ar7240_get_mirror_tx,
|
|
+ .max = 1
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct switch_attr ar7240_vlan[] = {
|
|
+ {
|
|
+ .type = SWITCH_TYPE_INT,
|
|
+ .name = "vid",
|
|
+ .description = "VLAN ID",
|
|
+ .set = ar7240_set_vid,
|
|
+ .get = ar7240_get_vid,
|
|
+ .max = 4094,
|
|
+ },
|
|
+};
|
|
+
|
|
+static const struct switch_dev_ops ar7240_ops = {
|
|
+ .attr_global = {
|
|
+ .attr = ar7240_globals,
|
|
+ .n_attr = ARRAY_SIZE(ar7240_globals),
|
|
+ },
|
|
+ .attr_port = {
|
|
+ .attr = ar7240_port,
|
|
+ .n_attr = ARRAY_SIZE(ar7240_port),
|
|
+ },
|
|
+ .attr_vlan = {
|
|
+ .attr = ar7240_vlan,
|
|
+ .n_attr = ARRAY_SIZE(ar7240_vlan),
|
|
+ },
|
|
+ .get_port_pvid = ar7240_get_pvid,
|
|
+ .set_port_pvid = ar7240_set_pvid,
|
|
+ .get_vlan_ports = ar7240_get_ports,
|
|
+ .set_vlan_ports = ar7240_set_ports,
|
|
+ .apply_config = ar7240_hw_apply,
|
|
+ .reset_switch = ar7240_reset_switch,
|
|
+ .get_port_link = ar7240_get_port_link,
|
|
+ .get_port_stats = ar7240_get_port_stats,
|
|
+};
|
|
+
|
|
+static int
|
|
+ag71xx_ar7240_probe(struct mdio_device *mdiodev)
|
|
+{
|
|
+ struct mii_bus *mii = mdiodev->bus;
|
|
+ struct ar7240sw *as;
|
|
+ struct switch_dev *swdev;
|
|
+ struct reset_control *switch_reset;
|
|
+ u32 ctrl;
|
|
+ int phy_if_mode, err, i;
|
|
+
|
|
+ as = devm_kzalloc(&mdiodev->dev, sizeof(*as), GFP_KERNEL);
|
|
+ if (!as)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ as->mii_bus = mii;
|
|
+ as->of_node = mdiodev->dev.of_node;
|
|
+ as->mdio_node = of_get_child_by_name(as->of_node, "mdio-bus");
|
|
+
|
|
+ swdev = &as->swdev;
|
|
+
|
|
+ switch_reset = devm_reset_control_get_optional(&mdiodev->dev, "switch");
|
|
+ if (switch_reset) {
|
|
+ reset_control_assert(switch_reset);
|
|
+ msleep(50);
|
|
+ reset_control_deassert(switch_reset);
|
|
+ msleep(200);
|
|
+ }
|
|
+
|
|
+ ctrl = ar7240sw_reg_read(mii, AR7240_REG_MASK_CTRL);
|
|
+ as->ver = (ctrl >> AR7240_MASK_CTRL_VERSION_S) &
|
|
+ AR7240_MASK_CTRL_VERSION_M;
|
|
+
|
|
+ if (sw_is_ar7240(as)) {
|
|
+ swdev->name = "AR7240/AR9330 built-in switch";
|
|
+ swdev->ports = AR7240_NUM_PORTS - 1;
|
|
+ } else if (sw_is_ar934x(as)) {
|
|
+ swdev->name = "AR934X built-in switch";
|
|
+ phy_if_mode = of_get_phy_mode(as->of_node);
|
|
+
|
|
+ if (phy_if_mode == PHY_INTERFACE_MODE_GMII) {
|
|
+ ar7240sw_reg_set(mii, AR934X_REG_OPER_MODE0,
|
|
+ AR934X_OPER_MODE0_MAC_GMII_EN);
|
|
+ } else if (phy_if_mode == PHY_INTERFACE_MODE_MII) {
|
|
+ ar7240sw_reg_set(mii, AR934X_REG_OPER_MODE0,
|
|
+ AR934X_OPER_MODE0_PHY_MII_EN);
|
|
+ } else {
|
|
+ pr_err("%s: invalid PHY interface mode\n",
|
|
+ dev_name(&mdiodev->dev));
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ if (of_property_read_bool(as->of_node, "phy4-mii-enable")) {
|
|
+ ar7240sw_reg_set(mii, AR934X_REG_OPER_MODE1,
|
|
+ AR934X_REG_OPER_MODE1_PHY4_MII_EN);
|
|
+ swdev->ports = AR7240_NUM_PORTS - 1;
|
|
+ } else {
|
|
+ swdev->ports = AR7240_NUM_PORTS;
|
|
+ }
|
|
+ } else {
|
|
+ pr_err("%s: unsupported chip, ctrl=%08x\n",
|
|
+ dev_name(&mdiodev->dev), ctrl);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ swdev->cpu_port = AR7240_PORT_CPU;
|
|
+ swdev->vlans = AR7240_MAX_VLANS;
|
|
+ swdev->ops = &ar7240_ops;
|
|
+ swdev->alias = dev_name(&mdiodev->dev);
|
|
+
|
|
+ if ((err = register_switch(&as->swdev, NULL)) < 0)
|
|
+ return err;
|
|
+
|
|
+ pr_info("%s: Found an %s\n", dev_name(&mdiodev->dev), swdev->name);
|
|
+
|
|
+ as->switch_mii_bus = devm_mdiobus_alloc(&mdiodev->dev);
|
|
+ as->switch_mii_bus->name = "ar7240sw_mdio";
|
|
+ as->switch_mii_bus->read = ar7240sw_phy_read;
|
|
+ as->switch_mii_bus->write = ar7240sw_phy_write;
|
|
+ as->switch_mii_bus->priv = as;
|
|
+ as->switch_mii_bus->parent = &mdiodev->dev;
|
|
+ snprintf(as->switch_mii_bus->id, MII_BUS_ID_SIZE, "%s", dev_name(&mdiodev->dev));
|
|
+
|
|
+ if(as->mdio_node) {
|
|
+ err = of_mdiobus_register(as->switch_mii_bus, as->mdio_node);
|
|
+ if (err)
|
|
+ return err;
|
|
+ }
|
|
+
|
|
+ /* initialize defaults */
|
|
+ for (i = 0; i < AR7240_MAX_VLANS; i++)
|
|
+ as->vlan_id[i] = i;
|
|
+
|
|
+ as->vlan_table[0] = ar7240sw_port_mask_all(as);
|
|
+ ar7240sw_reset(as);
|
|
+ ar7240_hw_apply(&as->swdev);
|
|
+ rwlock_init(&as->stats_lock);
|
|
+ dev_set_drvdata(&mdiodev->dev, as);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void
|
|
+ag71xx_ar7240_remove(struct mdio_device *mdiodev)
|
|
+{
|
|
+ struct ar7240sw *as = dev_get_drvdata(&mdiodev->dev);
|
|
+ if(as->mdio_node)
|
|
+ mdiobus_unregister(as->switch_mii_bus);
|
|
+ unregister_switch(&as->swdev);
|
|
+}
|
|
+
|
|
+static const struct of_device_id ag71xx_sw_of_match[] = {
|
|
+ { .compatible = "qca,ar8216-builtin" },
|
|
+ { .compatible = "qca,ar8229-builtin" },
|
|
+ { /* sentinel */ },
|
|
+};
|
|
+
|
|
+static struct mdio_driver ag71xx_sw_driver = {
|
|
+ .probe = ag71xx_ar7240_probe,
|
|
+ .remove = ag71xx_ar7240_remove,
|
|
+ .mdiodrv.driver = {
|
|
+ .name = "ag71xx-switch",
|
|
+ .of_match_table = ag71xx_sw_of_match,
|
|
+ },
|
|
+};
|
|
+
|
|
+mdio_module_driver(ag71xx_sw_driver);
|
|
+MODULE_LICENSE("GPL");
|
|
diff --git a/target/linux/ath79/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_main.c b/target/linux/ath79/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_main.c
|
|
index 84b0f9e4ac..79b3e64b16 100644
|
|
--- a/target/linux/ath79/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_main.c
|
|
+++ b/target/linux/ath79/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_main.c
|
|
@@ -1516,6 +1516,7 @@ static int ag71xx_probe(struct platform_device *pdev)
|
|
struct resource *res;
|
|
struct ag71xx *ag;
|
|
const void *mac_addr;
|
|
+ const char *ifname = NULL;
|
|
u32 max_frame_len;
|
|
int tx_size, err;
|
|
|
|
@@ -1730,6 +1731,9 @@ static int ag71xx_probe(struct platform_device *pdev)
|
|
|
|
platform_set_drvdata(pdev, dev);
|
|
|
|
+ if(!of_property_read_string(np, "ifname",&ifname))
|
|
+ memcpy(dev->name,ifname,strlen(ifname)+1);
|
|
+
|
|
err = register_netdev(dev);
|
|
if (err) {
|
|
dev_err(&pdev->dev, "unable to register net device\n");
|
|
diff --git a/target/linux/ath79/generic/base-files/etc/board.d/01_leds b/target/linux/ath79/generic/base-files/etc/board.d/01_leds
|
|
index 7c5eeb1112..985adfc6a7 100755
|
|
--- a/target/linux/ath79/generic/base-files/etc/board.d/01_leds
|
|
+++ b/target/linux/ath79/generic/base-files/etc/board.d/01_leds
|
|
@@ -204,7 +204,6 @@ etactica,eg200)
|
|
ucidef_set_led_netdev "lan" "LAN" "red:eth0" "eth0"
|
|
ucidef_set_led_oneshot "modbus" "Modbus" "red:modbus" "100" "33"
|
|
;;
|
|
-glinet,gl-mifi|\
|
|
qxwlan,e600g-v2-8m|\
|
|
qxwlan,e600g-v2-16m|\
|
|
qxwlan,e600gac-v2-8m|\
|
|
diff --git a/target/linux/ath79/generic/base-files/etc/uci-defaults/04_led_migration b/target/linux/ath79/generic/base-files/etc/uci-defaults/04_led_migration
|
|
index e9b0fade38..fba1fdcd59 100644
|
|
--- a/target/linux/ath79/generic/base-files/etc/uci-defaults/04_led_migration
|
|
+++ b/target/linux/ath79/generic/base-files/etc/uci-defaults/04_led_migration
|
|
@@ -14,9 +14,6 @@ dlink,dap-1330-a1)
|
|
engenius,epg5000)
|
|
migrate_leds ":wlan-2g=:wlan2g" ":wlan-5g=:wlan5g"
|
|
;;
|
|
-glinet,gl-mifi)
|
|
- migrate_leds ":net=:3g4g"
|
|
- ;;
|
|
meraki,mr12)
|
|
migrate_leds ":wifi=:link" ":wan=:lan"
|
|
;;
|
|
diff --git a/target/linux/ath79/image/generic.mk b/target/linux/ath79/image/generic.mk
|
|
index 5ba64b9803..05ed698401 100644
|
|
--- a/target/linux/ath79/image/generic.mk
|
|
+++ b/target/linux/ath79/image/generic.mk
|
|
@@ -1198,16 +1198,6 @@ define Device/glinet_gl-ar750
|
|
endef
|
|
TARGET_DEVICES += glinet_gl-ar750
|
|
|
|
-define Device/glinet_gl-mifi
|
|
- SOC := ar9331
|
|
- DEVICE_VENDOR := GL.iNET
|
|
- DEVICE_MODEL := GL-MiFi
|
|
- DEVICE_PACKAGES := kmod-usb-chipidea2
|
|
- IMAGE_SIZE := 16000k
|
|
- SUPPORTED_DEVICES += gl-mifi
|
|
-endef
|
|
-TARGET_DEVICES += glinet_gl-mifi
|
|
-
|
|
define Device/glinet_gl-usb150
|
|
SOC := ar9331
|
|
DEVICE_VENDOR := GL.iNET
|
|
diff --git a/target/linux/ath79/image/nand.mk b/target/linux/ath79/image/nand.mk
|
|
index cfc07f14a3..0c6dd699f5 100644
|
|
--- a/target/linux/ath79/image/nand.mk
|
|
+++ b/target/linux/ath79/image/nand.mk
|
|
@@ -107,6 +107,16 @@ define Device/glinet_gl-ar300m-nor
|
|
endef
|
|
TARGET_DEVICES += glinet_gl-ar300m-nor
|
|
|
|
+define Device/glinet_gl-mifi
|
|
+ SOC := ar9331
|
|
+ DEVICE_VENDOR := GL.iNET
|
|
+ DEVICE_MODEL := GL-MiFi
|
|
+ DEVICE_PACKAGES := kmod-usb-chipidea2
|
|
+ IMAGE_SIZE := 16000k
|
|
+ SUPPORTED_DEVICES += gl-mifi glinet,gl-mifi
|
|
+endef
|
|
+TARGET_DEVICES += glinet_gl-mifi
|
|
+
|
|
define Device/glinet_gl-xe300-common
|
|
SOC := qca9531
|
|
DEVICE_VENDOR := GL.iNet
|
|
diff --git a/target/linux/ath79/nand/base-files/etc/board.d/01_leds b/target/linux/ath79/nand/base-files/etc/board.d/01_leds
|
|
index 4a90c4673f..16545083fb 100755
|
|
--- a/target/linux/ath79/nand/base-files/etc/board.d/01_leds
|
|
+++ b/target/linux/ath79/nand/base-files/etc/board.d/01_leds
|
|
@@ -11,6 +11,12 @@ glinet,gl-ar300m-nand|\
|
|
glinet,gl-ar300m-nor)
|
|
ucidef_set_led_netdev "lan" "LAN" "green:lan" "eth0"
|
|
;;
|
|
+glinet,gl-mifi)
|
|
+ ucidef_set_led_wlan "wlan" "WLAN" "gl-mifi:green:wlan" "phy0tpt"
|
|
+ ucidef_set_led_netdev "wan" "WAN" "gl-mifi:green:wan" "eth0"
|
|
+ ucidef_set_led_switch "lan" "LAN" "gl-mifi:green:lan" "switch0" "0x2"
|
|
+ ucidef_set_led_netdev "3gnet" "3GNET" "gl-mifi:green:net" "3g-wan"
|
|
+ ;;
|
|
glinet,gl-xe300-iot|\
|
|
glinet,gl-xe300-nor|\
|
|
glinet,gl-xe300-nor-nand)
|
|
diff --git a/target/linux/ath79/nand/base-files/etc/board.d/02_network b/target/linux/ath79/nand/base-files/etc/board.d/02_network
|
|
index 17348e001b..73e23e5eb9 100755
|
|
--- a/target/linux/ath79/nand/base-files/etc/board.d/02_network
|
|
+++ b/target/linux/ath79/nand/base-files/etc/board.d/02_network
|
|
@@ -21,6 +21,9 @@ ath79_setup_interfaces()
|
|
ucidef_add_switch "switch0" \
|
|
"0@eth0" "2:lan:2" "3:lan:1" "1:wan"
|
|
;;
|
|
+ glinet,gl-mifi)
|
|
+ ucidef_set_interfaces_lan_wan "eth1" "eth0"
|
|
+ ;;
|
|
glinet,gl-xe300-iot|\
|
|
glinet,gl-xe300-nor|\
|
|
glinet,gl-xe300-nor-nand)
|
|
--
|
|
2.17.1
|
|
|