From 1dd12dd09efa86b811200d85aa2852d0a6781c6f Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Mon, 14 Jan 2019 20:16:36 +0100 Subject: [PATCH] apm821xx: wndr4700: mx60: convert to DSA This patch converts both the wndr4700 and mx60 to use a patched qca8k driver to drive DSA. Both have to be converted since the old AR8216 phy/swconfig driver had to be disabled as otherwise it would conflict with the dsa driver since swconfig utilizes the phy framework. Signed-off-by: Christian Lamparter --- .../base-files/etc/board.d/02_network | 3 +- target/linux/apm821xx/dts/meraki-mx60.dts | 103 +++- .../linux/apm821xx/dts/netgear-wndr4700.dts | 105 +++- target/linux/apm821xx/nand/config-default | 8 +- .../patches-4.19/703-qca8k_QCA8337N.patch | 486 ++++++++++++++++++ .../704-net-emac-dsa-header-patch | 80 +++ 6 files changed, 761 insertions(+), 24 deletions(-) create mode 100644 target/linux/apm821xx/patches-4.19/703-qca8k_QCA8337N.patch create mode 100644 target/linux/apm821xx/patches-4.19/704-net-emac-dsa-header-patch diff --git a/target/linux/apm821xx/base-files/etc/board.d/02_network b/target/linux/apm821xx/base-files/etc/board.d/02_network index 69bc038bd4..660c7e32e8 100755 --- a/target/linux/apm821xx/base-files/etc/board.d/02_network +++ b/target/linux/apm821xx/base-files/etc/board.d/02_network @@ -21,8 +21,7 @@ netgear,wndap660) ;; meraki,mx60|\ netgear,wndr4700) - ucidef_add_switch "switch0" \ - "0@eth0" "4:lan" "3:lan" "2:lan" "1:lan" "5:wan" + ucidef_set_interfaces_lan_wan "lan1 lan2 lan3 lan4" "wan" ;; *) diff --git a/target/linux/apm821xx/dts/meraki-mx60.dts b/target/linux/apm821xx/dts/meraki-mx60.dts index fc3213e92c..228d86d62d 100644 --- a/target/linux/apm821xx/dts/meraki-mx60.dts +++ b/target/linux/apm821xx/dts/meraki-mx60.dts @@ -92,21 +92,104 @@ &EMAC0 { status = "okay"; - phy-handle = <&phy0>; + phy-mode = "rgmii-id"; + emac,extra-mtu-size-for-dsa = <2>; /* Atheros Header */ - mdio { + fixed-link { + speed = <1000>; + full-duplex; + pause; + asym-pause; + }; + + mdio0: mdio { #address-cells = <1>; #size-cells = <0>; + phy0: ethernet-phy@0 { - compatible = "ethernet-phy-id004d.d034"; reg = <0>; - qca,ar8327-initvals = < - 0x0010 0x40000000 - 0x0624 0x007f7f7f - 0x0004 0x07a00000 /* PAD0_MODE */ - 0x000c 0x01000000 /* PAD6_MODE */ - 0x007c 0x0000007e /* PORT0_STATUS */ - >; + }; + + phy1: ethernet-phy@1 { + reg = <1>; + }; + + phy2: ethernet-phy@2 { + reg = <2>; + }; + + phy3: ethernet-phy@3 { + reg = <3>; + }; + + phy4: ethernet-phy@4 { + reg = <4>; + }; + + switch: switch@1f { + compatible = "qca,qca8327"; + status = "okay"; + reg = <0x1f>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + label = "cpu"; + ethernet = <&EMAC0>; + phy-mode = "rgmii-id"; + qca,rxclk-delay = <2>; + qca,txclk-delay = <2>; + + fixed-link { + speed = <1000>; + full-duplex; + pause; + asym-pause; + }; + }; + + port@1 { + reg = <1>; + label = "lan4"; + phy-handle = <&phy0>; + }; + + port@2 { + reg = <2>; + label = "lan3"; + phy-handle = <&phy1>; + }; + + port@3 { + reg = <3>; + label = "lan2"; + phy-handle = <&phy2>; + }; + + port@4 { + reg = <4>; + label = "lan1"; + phy-handle = <&phy3>; + }; + + port@5 { + reg = <5>; + label = "wan"; + phy-handle = <&phy4>; + + /* + * The AR8327 Datasheet states that + * rx_delay_en always sets 1000M + * delay to 2ns! Even when the + * rx_delay_sel is 0. + */ + phy-mode = "internal"; + qca,rxclk-delay = <0>; + }; + }; }; }; }; diff --git a/target/linux/apm821xx/dts/netgear-wndr4700.dts b/target/linux/apm821xx/dts/netgear-wndr4700.dts index 14f6762110..4a8ee0c0f8 100644 --- a/target/linux/apm821xx/dts/netgear-wndr4700.dts +++ b/target/linux/apm821xx/dts/netgear-wndr4700.dts @@ -281,27 +281,110 @@ }; }; - &EMAC0 { status = "okay"; - phy-handle = <&phy0>; fifo-entry-size = <10>; + phy-mode = "rgmii-id"; + emac,extra-mtu-size-for-dsa = <2>; /* Atheros Header */ + + fixed-link { + speed = <1000>; + full-duplex; + pause; + asym-pause; + }; - mdio { + mdio0: mdio { #address-cells = <1>; #size-cells = <0>; + phy0: ethernet-phy@0 { - device_type = "ethernet-phy"; reg = <0>; - qca,ar8327-initvals = < - 0x0010 0x40000000 - 0x0624 0x007f7f7f - 0x0004 0x07a00000 /* PAD0_MODE */ - 0x000c 0x01000000 /* PAD6_MODE */ - 0x007c 0x0000007e /* PORT0_STATUS */ - >; + }; + + phy1: ethernet-phy@1 { + reg = <1>; + }; + + phy2: ethernet-phy@2 { + reg = <2>; + }; + + phy3: ethernet-phy@3 { + reg = <3>; + }; + + phy4: ethernet-phy@4 { + reg = <4>; + }; + + switch: switch@1f { + compatible = "qca,qca8327"; + status = "okay"; + reg = <0x1f>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + label = "cpu"; + ethernet = <&EMAC0>; + phy-mode = "rgmii-id"; + qca,rxclk-delay = <2>; + qca,txclk-delay = <2>; + + fixed-link { + speed = <1000>; + full-duplex; + pause; + asym-pause; + }; + }; + + port@1 { + reg = <1>; + label = "lan4"; + phy-handle = <&phy0>; + }; + + port@2 { + reg = <2>; + label = "lan3"; + phy-handle = <&phy1>; + }; + + port@3 { + reg = <3>; + label = "lan2"; + phy-handle = <&phy2>; + }; + + port@4 { + reg = <4>; + label = "lan1"; + phy-handle = <&phy3>; + }; + + port@5 { + reg = <5>; + label = "wan"; + phy-handle = <&phy4>; + + /* + * The AR8327 Datasheet states that + * rx_delay_en always sets 1000M + * delay to 2ns! Even when the + * rx_delay_sel is 0. + */ + phy-mode = "internal"; + qca,rxclk-delay = <0>; + }; + }; }; }; + }; &POB0 { diff --git a/target/linux/apm821xx/nand/config-default b/target/linux/apm821xx/nand/config-default index 1c05a83fb1..2741dc0790 100644 --- a/target/linux/apm821xx/nand/config-default +++ b/target/linux/apm821xx/nand/config-default @@ -1,5 +1,5 @@ CONFIG_AT803X_PHY=y -CONFIG_AR8216_PHY=y +# CONFIG_AR8216_PHY is not set CONFIG_DMADEVICES=y CONFIG_DMA_ENGINE=y CONFIG_DW_DMAC_CORE=y @@ -15,6 +15,12 @@ CONFIG_SATA_PMP=y CONFIG_GENERIC_PHY=y CONFIG_SATA_DWC=y # CONFIG_SATA_DWC_DEBUG is not set +CONFIG_NET_DSA=y +CONFIG_NET_DSA_LEGACY=y +CONFIG_NET_DSA_QCA8K=y +# CONFIG_NET_DSA_REALTEK_SMI is not set +CONFIG_NET_DSA_TAG_QCA=y +# CONFIG_NET_DSA_VITESSE_VSC73XX is not set CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_GPIOLIB=y diff --git a/target/linux/apm821xx/patches-4.19/703-qca8k_QCA8337N.patch b/target/linux/apm821xx/patches-4.19/703-qca8k_QCA8337N.patch new file mode 100644 index 0000000000..ed4d6e1925 --- /dev/null +++ b/target/linux/apm821xx/patches-4.19/703-qca8k_QCA8337N.patch @@ -0,0 +1,486 @@ +--- a/drivers/net/dsa/qca8k.h ++++ b/drivers/net/dsa/qca8k.h +@@ -27,11 +27,14 @@ + #define QCA8K_NUM_FDB_RECORDS 2048 + + #define QCA8K_CPU_PORT 0 ++#define QCA8K_MAC5_PORT 5 ++#define QCA8K_MAC6_PORT 6 + + /* Global control registers */ + #define QCA8K_REG_MASK_CTRL 0x000 +-#define QCA8K_MASK_CTRL_ID_M 0xff +-#define QCA8K_MASK_CTRL_ID_S 8 ++#define QCA8K_MASK_CTRL_DEVICE_ID_S 8 ++#define QCA8K_MASK_CTRL_DEVICE_ID_M GENMASK(15,8) ++#define QCA8K_MASK_CTRL_REVISION_ID_M GENMASK(7, 0) + #define QCA8K_REG_PORT0_PAD_CTRL 0x004 + #define QCA8K_REG_PORT5_PAD_CTRL 0x008 + #define QCA8K_REG_PORT6_PAD_CTRL 0x00c +@@ -41,13 +44,19 @@ + #define QCA8K_PORT_PAD_RGMII_RX_DELAY(x) \ + ((0x10 + (x & 0x3)) << 20) + #define QCA8K_PORT_PAD_RGMII_RX_DELAY_EN BIT(24) ++#define QCA8K_PORT_PAD_RGMII_TX_DELAY_EN BIT(25) + #define QCA8K_PORT_PAD_SGMII_EN BIT(7) ++#define QCA8K_REG_PWS_REG 0x010 ++#define QCA8K_PWS_REG_8327_PACKAGE148_EN BIT(30) ++#define QCA8K_PWS_REG_8337_PACKAGEMIN_EN BIT(28) + #define QCA8K_REG_MODULE_EN 0x030 + #define QCA8K_MODULE_EN_MIB BIT(0) + #define QCA8K_REG_MIB 0x034 + #define QCA8K_MIB_FLUSH BIT(24) + #define QCA8K_MIB_CPU_KEEP BIT(20) + #define QCA8K_MIB_BUSY BIT(17) ++#define QCA8K_REG_MAX_FRAME_SIZE 0x078 ++#define QCA8K_MAX_FRAME_SIZE_MTU GENMASK(14, 0) + #define QCA8K_GOL_MAC_ADDR0 0x60 + #define QCA8K_GOL_MAC_ADDR1 0x64 + #define QCA8K_REG_PORT_STATUS(_i) (0x07c + (_i) * 4) +@@ -63,6 +72,7 @@ + #define QCA8K_PORT_STATUS_LINK_UP BIT(8) + #define QCA8K_PORT_STATUS_LINK_AUTO BIT(9) + #define QCA8K_PORT_STATUS_LINK_PAUSE BIT(10) ++#define QCA8K_PORT_STATUS_LINK_FLOW_CONTROL BIT(12) + #define QCA8K_REG_PORT_HDR_CTRL(_i) (0x9c + (_i * 4)) + #define QCA8K_PORT_HDR_CTRL_RX_MASK GENMASK(3, 2) + #define QCA8K_PORT_HDR_CTRL_RX_S 2 +@@ -114,6 +124,11 @@ + #define QCA8K_GLOBAL_FW_CTRL1_UC_DP_S 0 + #define QCA8K_PORT_LOOKUP_CTRL(_i) (0x660 + (_i) * 0xc) + #define QCA8K_PORT_LOOKUP_MEMBER GENMASK(6, 0) ++#define QCA8K_PORT_LOOKUP_VLAN_MODE_MASK GENMASK(9, 8) ++#define QCA8K_PORT_LOOKUP_VLAN_MODE_DISABLE (0 << 8) ++#define QCA8K_PORT_LOOKUP_VLAN_MODE_FALLBACK (1 << 8) ++#define QCA8K_PORT_LOOKUP_VLAN_MODE_CHECK (2 << 8) ++#define QCA8K_PORT_LOOKUP_VLAN_MODE_SECURE (3 << 8) + #define QCA8K_PORT_LOOKUP_STATE_MASK GENMASK(18, 16) + #define QCA8K_PORT_LOOKUP_STATE_DISABLED (0 << 16) + #define QCA8K_PORT_LOOKUP_STATE_BLOCKING (1 << 16) +@@ -141,6 +156,8 @@ + /* QCA specific MII registers */ + #define MII_ATH_MMD_ADDR 0x0d + #define MII_ATH_MMD_DATA 0x0e ++#define MII_ATH_DBG_ADDR 0x1d ++#define MII_ATH_DBG_DATA 0x1e + + enum { + QCA8K_PORT_SPEED_10M = 0, +@@ -168,6 +185,8 @@ struct qca8k_priv { + struct dsa_switch *ds; + struct mutex reg_mutex; + struct device *dev; ++ unsigned int chip_id; ++ unsigned int chip_rev; + }; + + struct qca8k_mib_desc { +--- a/drivers/net/dsa/qca8k.c ++++ b/drivers/net/dsa/qca8k.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -192,6 +193,63 @@ qca8k_rmw(struct qca8k_priv *priv, u32 r + } + + static void ++qca8k_phy_dbg_read(struct qca8k_priv *priv, int phy_addr, ++ u16 dbg_addr, u16 *dbg_data) ++{ ++ struct mii_bus *bus = priv->bus; ++ ++ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); ++ __mdiobus_write(bus, phy_addr, MII_ATH_DBG_ADDR, dbg_addr); ++ *dbg_data = __mdiobus_read(bus, phy_addr, MII_ATH_DBG_DATA); ++ mutex_unlock(&bus->mdio_lock); ++} ++ ++static void ++qca8k_phy_dbg_write(struct qca8k_priv *priv, int phy_addr, ++ u16 dbg_addr, u16 dbg_data) ++{ ++ struct mii_bus *bus = priv->bus; ++ ++ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); ++ __mdiobus_write(bus, phy_addr, MII_ATH_DBG_ADDR, dbg_addr); ++ __mdiobus_write(bus, phy_addr, MII_ATH_DBG_DATA, dbg_data); ++ mutex_unlock(&bus->mdio_lock); ++} ++ ++static inline void ++qca8k_phy_mmd_prep(struct mii_bus *bus, int phy_addr, u16 addr, u16 reg) ++{ ++ __mdiobus_write(bus, phy_addr, MII_ATH_MMD_ADDR, addr); ++ __mdiobus_write(bus, phy_addr, MII_ATH_MMD_DATA, reg); ++ __mdiobus_write(bus, phy_addr, MII_ATH_MMD_ADDR, addr | 0x4000); ++} ++ ++static void ++qca8k_phy_mmd_write(struct qca8k_priv *priv, int phy_addr, u16 addr, u16 reg, u16 data) ++{ ++ struct mii_bus *bus = priv->bus; ++ ++ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); ++ qca8k_phy_mmd_prep(bus, phy_addr, addr, reg); ++ __mdiobus_write(bus, phy_addr, MII_ATH_MMD_DATA, data); ++ mutex_unlock(&bus->mdio_lock); ++} ++ ++static u16 ++qca8k_phy_mmd_read(struct qca8k_priv *priv, int phy_addr, u16 addr, u16 reg) ++{ ++ struct mii_bus *bus = priv->bus; ++ u16 data; ++ ++ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); ++ qca8k_phy_mmd_prep(bus, phy_addr, addr, reg); ++ data = __mdiobus_read(bus, phy_addr, MII_ATH_MMD_DATA); ++ mutex_unlock(&bus->mdio_lock); ++ ++ return data; ++} ++ ++static void + qca8k_reg_set(struct qca8k_priv *priv, u32 reg, u32 val) + { + qca8k_rmw(priv, reg, 0, val); +@@ -417,16 +475,46 @@ qca8k_mib_init(struct qca8k_priv *priv) + mutex_unlock(&priv->reg_mutex); + } + ++static bool is_qca833x_rgmii_compat(struct qca8k_priv *priv) ++{ ++ int tmp; ++ ++ if (!(of_device_is_compatible(priv->dev->of_node, "qca8k,qca8337") || ++ of_device_is_compatible(priv->dev->of_node, "qca8k,qca8334"))) ++ return false; ++ ++ tmp = of_get_phy_mode(priv->ds->ports[QCA8K_CPU_PORT].dn); ++ if (tmp == PHY_INTERFACE_MODE_RGMII) { ++ tmp = of_get_phy_mode(priv->ds->ports[QCA8K_MAC5_PORT].dn); ++ if (tmp < 0) ++ return true; ++ } ++ return false; ++} ++ + static int +-qca8k_set_pad_ctrl(struct qca8k_priv *priv, int port, int mode) ++qca8k_set_pad_ctrl(struct qca8k_priv *priv, int port) + { +- u32 reg; ++ struct device_node *dn = priv->ds->ports[port].dn; ++ int phy_mode = -1; ++ u32 reg, val = 0; ++ int rgmii_rxclk_delay = 0; ++ int rgmii_txclk_delay = 0; ++ bool legacy_compat = false; ++ ++ if (!dn) { ++ pr_info("skip not specified port %d\n", port); ++ return 0; ++ } + + switch (port) { +- case 0: ++ case QCA8K_CPU_PORT: + reg = QCA8K_REG_PORT0_PAD_CTRL; + break; +- case 6: ++ case QCA8K_MAC5_PORT: ++ reg = QCA8K_REG_PORT5_PAD_CTRL; ++ break; ++ case QCA8K_MAC6_PORT: + reg = QCA8K_REG_PORT6_PAD_CTRL; + break; + default: +@@ -434,31 +522,78 @@ qca8k_set_pad_ctrl(struct qca8k_priv *pr + return -EINVAL; + } + ++ /* Initialize port pad mode (xMII type, delays...) */ ++ phy_mode = of_get_phy_mode(dn); ++ if (phy_mode < 0) { ++ if (is_qca833x_rgmii_compat(priv)) { ++ if (port == 5) { ++ pr_warn("legacy qca8k configuration found... please update your DT."); ++ legacy_compat = true; ++ rgmii_rxclk_delay = 3; ++ rgmii_txclk_delay = 3; ++ } ++ } else { ++ pr_err("Can't find phy-mode for port %d\n", port); ++ return phy_mode; ++ } ++ } ++ ++ /* rgmii's txclk and rxclk delay can be set even on links that ++ * aren't connected to a RGMII CPU interface. So make it possible ++ * to specify the value even if it seems seemingly strange. ++ */ ++ if (legacy_compat || ++ !of_property_read_u32(dn, "qca,rxclk-delay", &rgmii_rxclk_delay) || ++ phy_mode == PHY_INTERFACE_MODE_RGMII_ID || ++ phy_mode == PHY_INTERFACE_MODE_RGMII_RXID) { ++ if (rgmii_rxclk_delay > 3) { ++ pr_err("Invalid or missing rxclk-delay\n"); ++ return -EINVAL; ++ } ++ ++ val |= QCA8K_PORT_PAD_RGMII_RX_DELAY(rgmii_rxclk_delay) | ++ QCA8K_PORT_PAD_RGMII_RX_DELAY_EN; ++ ++ }; ++ ++ if (legacy_compat || ++ !of_property_read_u32(dn, "qca,txclk-delay", &rgmii_txclk_delay) || ++ phy_mode == PHY_INTERFACE_MODE_RGMII_ID || ++ phy_mode == PHY_INTERFACE_MODE_RGMII_TXID) { ++ if (rgmii_txclk_delay > 3) { ++ pr_err("Invalid or missing txclk-delay\n"); ++ return -EINVAL; ++ } ++ ++ val |= QCA8K_PORT_PAD_RGMII_TX_DELAY(rgmii_txclk_delay) | ++ QCA8K_PORT_PAD_RGMII_TX_DELAY_EN; ++ } + /* Configure a port to be directly connected to an external + * PHY or MAC. + */ +- switch (mode) { ++ switch (phy_mode) { + case PHY_INTERFACE_MODE_RGMII: +- qca8k_write(priv, reg, +- QCA8K_PORT_PAD_RGMII_EN | +- QCA8K_PORT_PAD_RGMII_TX_DELAY(3) | +- QCA8K_PORT_PAD_RGMII_RX_DELAY(3)); +- +- /* According to the datasheet, RGMII delay is enabled through +- * PORT5_PAD_CTRL for all ports, rather than individual port +- * registers +- */ +- qca8k_write(priv, QCA8K_REG_PORT5_PAD_CTRL, +- QCA8K_PORT_PAD_RGMII_RX_DELAY_EN); ++ case PHY_INTERFACE_MODE_RGMII_ID: ++ case PHY_INTERFACE_MODE_RGMII_RXID: ++ case PHY_INTERFACE_MODE_RGMII_TXID: ++ val |= QCA8K_PORT_PAD_RGMII_EN; + break; + case PHY_INTERFACE_MODE_SGMII: +- qca8k_write(priv, reg, QCA8K_PORT_PAD_SGMII_EN); ++ if (port != 5) ++ val |= QCA8K_PORT_PAD_SGMII_EN; ++ else { ++ pr_err("Port 5 does not support SGMII\n"); ++ return -EINVAL; ++ } ++ break; ++ case PHY_INTERFACE_MODE_INTERNAL: + break; + default: +- pr_err("xMII mode %d not supported\n", mode); ++ pr_err("xMII mode %d not supported\n", phy_mode); + return -EINVAL; + } + ++ qca8k_write(priv, reg, val); + return 0; + } + +@@ -471,17 +606,71 @@ qca8k_port_set_status(struct qca8k_priv + if (port > 0 && port < 6) + mask |= QCA8K_PORT_STATUS_LINK_AUTO; + +- if (enable) ++ if (enable) { ++ /* hw limitation: if there's traffic when the port ++ * gets configured, the port may not work properly ++ * (no rx!). Currently, we need to disable it completely ++ * first. ++ */ ++ u32 val; ++ ++ val = qca8k_read(priv, QCA8K_REG_PORT_STATUS(port)); ++ qca8k_write(priv, QCA8K_REG_PORT_STATUS(port), 0); ++ msleep(100); ++ val |= QCA8K_PORT_STATUS_LINK_FLOW_CONTROL; ++ qca8k_write(priv, QCA8K_REG_PORT_STATUS(port), val); + qca8k_reg_set(priv, QCA8K_REG_PORT_STATUS(port), mask); +- else ++ } else + qca8k_reg_clear(priv, QCA8K_REG_PORT_STATUS(port), mask); + } + ++static void ++qca8327_phy_fixup(struct qca8k_priv *priv, int phy) ++{ ++ switch (priv->chip_rev) { ++ case 1: ++ /* For 100M waveform */ ++ qca8k_phy_dbg_write(priv, phy, 0, 0x02ea); ++ /* Turn on Gigabit clock */ ++ qca8k_phy_dbg_write(priv, phy, 0x3d, 0x68a0); ++ break; ++ ++ case 2: ++ qca8k_phy_mmd_write(priv, phy, 0x7, 0x3c, 0x0); ++ /* fallthrough */ ++ case 4: ++ qca8k_phy_mmd_write(priv, phy, 0x3, 0x800d, 0x803f); ++ qca8k_phy_dbg_write(priv, phy, 0x3d, 0x6860); ++ qca8k_phy_dbg_write(priv, phy, 0x5, 0x2c46); ++ qca8k_phy_dbg_write(priv, phy, 0x3c, 0x6000); ++ break; ++ } ++} ++ ++static int ++qca8k_to_real_phy(struct dsa_switch *ds, int phy) ++{ ++ struct device_node *phy_dn, *port_dn; ++ int id; ++ ++ port_dn = ds->ports[phy].dn; ++ if (!port_dn) ++ return -EINVAL; ++ ++ phy_dn = of_parse_phandle(port_dn, "phy-handle", 0); ++ if (!phy_dn) ++ return -ENODEV; ++ ++ id = of_mdio_parse_addr(ds->dev, phy_dn); ++ of_node_put(phy_dn); ++ return id; ++} ++ + static int + qca8k_setup(struct dsa_switch *ds) + { + struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; +- int ret, i, phy_mode = -1; ++ int ret, i; + u32 mask; + + /* Make sure that port 0 is the cpu port */ +@@ -498,13 +687,20 @@ qca8k_setup(struct dsa_switch *ds) + if (IS_ERR(priv->regmap)) + pr_warn("regmap initialization failed"); + +- /* Initialize CPU port pad mode (xMII type, delays...) */ +- phy_mode = of_get_phy_mode(ds->ports[QCA8K_CPU_PORT].dn); +- if (phy_mode < 0) { +- pr_err("Can't find phy-mode for master device\n"); +- return phy_mode; ++ if (of_device_is_compatible(priv->dev->of_node, "qca,qca8327")) { ++ /* Enables the MAC interface configuration for the 148-pin ++ * package. All qca8327 are 148-pin */ ++ qca8k_write(priv, QCA8K_REG_PWS_REG, ++ QCA8K_PWS_REG_8327_PACKAGE148_EN); + } +- ret = qca8k_set_pad_ctrl(priv, QCA8K_CPU_PORT, phy_mode); ++ ++ ret = qca8k_set_pad_ctrl(priv, QCA8K_CPU_PORT); ++ if (ret < 0) ++ return ret; ++ ret = qca8k_set_pad_ctrl(priv, QCA8K_MAC5_PORT); ++ if (ret < 0) ++ return ret; ++ ret = qca8k_set_pad_ctrl(priv, QCA8K_MAC6_PORT); + if (ret < 0) + return ret; + +@@ -530,6 +726,12 @@ qca8k_setup(struct dsa_switch *ds) + qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i), + QCA8K_PORT_LOOKUP_MEMBER, 0); + ++ /* Disable VLAN by default on all ports */ ++ for (i = 0; i < QCA8K_NUM_PORTS; i++) ++ qca8k_reg_clear(priv, ++ QCA8K_PORT_LOOKUP_CTRL(i), ++ QCA8K_PORT_LOOKUP_VLAN_MODE_MASK); ++ + /* Disable MAC by default on all user ports */ + for (i = 1; i < QCA8K_NUM_PORTS; i++) + if (dsa_is_user_port(ds, i)) +@@ -542,6 +744,10 @@ qca8k_setup(struct dsa_switch *ds) + BIT(0) << QCA8K_GLOBAL_FW_CTRL1_MC_DP_S | + BIT(0) << QCA8K_GLOBAL_FW_CTRL1_UC_DP_S); + ++ /* enable jumbo frames */ ++ qca8k_rmw(priv, QCA8K_REG_MAX_FRAME_SIZE, ++ QCA8K_MAX_FRAME_SIZE_MTU, 9018 + 8 + 2); ++ + /* Setup connection between CPU port & user ports */ + for (i = 0; i < DSA_MAX_PORTS; i++) { + /* CPU port gets connected to all user ports of the switch */ +@@ -573,6 +779,12 @@ qca8k_setup(struct dsa_switch *ds) + } + } + ++ if (of_device_is_compatible(priv->dev->of_node, "qca,qca8327")) { ++ for (i = 0; i < DSA_MAX_PORTS; i++) ++ if (dsa_is_user_port(ds, i)) ++ qca8327_phy_fixup(priv, qca8k_to_real_phy(ds, i)); ++ } ++ + /* Flush the FDB table */ + qca8k_fdb_flush(priv); + +@@ -624,16 +836,24 @@ static int + qca8k_phy_read(struct dsa_switch *ds, int phy, int regnum) + { + struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; ++ int realphy = qca8k_to_real_phy(ds, phy); ++ ++ if (realphy < 0) ++ return realphy; + +- return mdiobus_read(priv->bus, phy, regnum); ++ return mdiobus_read(priv->bus, realphy, regnum); + } + + static int + qca8k_phy_write(struct dsa_switch *ds, int phy, int regnum, u16 val) + { + struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; ++ int realphy = qca8k_to_real_phy(ds, phy); ++ ++ if (realphy < 0) ++ return realphy; + +- return mdiobus_write(priv->bus, phy, regnum, val); ++ return mdiobus_write(priv->bus, realphy, regnum, val); + } + + static void +@@ -910,10 +1130,12 @@ qca8k_sw_probe(struct mdio_device *mdiod + + /* read the switches ID register */ + id = qca8k_read(priv, QCA8K_REG_MASK_CTRL); +- id >>= QCA8K_MASK_CTRL_ID_S; +- id &= QCA8K_MASK_CTRL_ID_M; +- if (id != QCA8K_ID_QCA8337) +- return -ENODEV; ++ priv->chip_rev = (id & QCA8K_MASK_CTRL_REVISION_ID_M); ++ priv->chip_id = (id & QCA8K_MASK_CTRL_DEVICE_ID_M) >> ++ QCA8K_MASK_CTRL_DEVICE_ID_S; ++ ++ pr_info("qca8k: chip id:%d revision:%d\n", ++ priv->chip_id, priv->chip_rev); + + priv->ds = dsa_switch_alloc(&mdiodev->dev, DSA_MAX_PORTS); + if (!priv->ds) +@@ -980,6 +1202,7 @@ static SIMPLE_DEV_PM_OPS(qca8k_pm_ops, + static const struct of_device_id qca8k_of_match[] = { + { .compatible = "qca,qca8334" }, + { .compatible = "qca,qca8337" }, ++ { .compatible = "qca,qca8327" }, + { /* sentinel */ }, + }; + diff --git a/target/linux/apm821xx/patches-4.19/704-net-emac-dsa-header-patch b/target/linux/apm821xx/patches-4.19/704-net-emac-dsa-header-patch new file mode 100644 index 0000000000..5ff6e530ce --- /dev/null +++ b/target/linux/apm821xx/patches-4.19/704-net-emac-dsa-header-patch @@ -0,0 +1,80 @@ +--- a/drivers/net/ethernet/ibm/emac/core.c ++++ b/drivers/net/ethernet/ibm/emac/core.c +@@ -469,7 +469,7 @@ static inline u32 emac_iff2rmr(struct ne + + if (emac_has_feature(dev, EMAC_APM821XX_REQ_JUMBO_FRAME_SIZE)) { + r &= ~EMAC4_RMR_MJS_MASK; +- r |= EMAC4_RMR_MJS(ndev->mtu); ++ r |= EMAC4_RMR_MJS(ndev->mtu + dev->dsa_header); + } + + return r; +@@ -629,7 +629,7 @@ static int emac_configure(struct emac_in + tx_size = dev->tx_fifo_size_gige; + rx_size = dev->rx_fifo_size_gige; + +- if (dev->ndev->mtu > ETH_DATA_LEN) { ++ if (dev->ndev->mtu + dev->dsa_header > ETH_DATA_LEN) { + if (emac_has_feature(dev, EMAC_FTR_EMAC4)) + mr1 |= EMAC4_MR1_JPSM; + else +@@ -1102,7 +1102,7 @@ static int emac_resize_rx_ring(struct em + /* This is to prevent starting RX channel in emac_rx_enable() */ + set_bit(MAL_COMMAC_RX_STOPPED, &dev->commac.flags); + +- dev->ndev->mtu = new_mtu; ++ dev->ndev->mtu = new_mtu - dev->dsa_header; + emac_full_tx_reset(dev); + } + +@@ -1129,14 +1129,16 @@ static int emac_change_mtu(struct net_de + + if (netif_running(ndev)) { + /* Check if we really need to reinitialize RX ring */ +- if (emac_rx_skb_size(ndev->mtu) != emac_rx_skb_size(new_mtu)) +- ret = emac_resize_rx_ring(dev, new_mtu); ++ if (emac_rx_skb_size(ndev->mtu + dev->dsa_header) != ++ emac_rx_skb_size(new_mtu + dev->dsa_header)) ++ ret = emac_resize_rx_ring(dev, new_mtu + ++ dev->dsa_header); + } + + if (!ret) { + ndev->mtu = new_mtu; +- dev->rx_skb_size = emac_rx_skb_size(new_mtu); +- dev->rx_sync_size = emac_rx_sync_size(new_mtu); ++ dev->rx_skb_size = emac_rx_skb_size(new_mtu + dev->dsa_header); ++ dev->rx_sync_size = emac_rx_sync_size(new_mtu + dev->dsa_header); + } + + return ret; +@@ -1286,7 +1288,8 @@ static int emac_open(struct net_device * + emac_configure(dev); + mal_poll_add(dev->mal, &dev->commac); + mal_enable_tx_channel(dev->mal, dev->mal_tx_chan); +- mal_set_rcbs(dev->mal, dev->mal_rx_chan, emac_rx_size(ndev->mtu)); ++ mal_set_rcbs(dev->mal, dev->mal_rx_chan, emac_rx_size(ndev->mtu + ++ dev->dsa_header)); + mal_enable_rx_channel(dev->mal, dev->mal_rx_chan); + emac_tx_enable(dev); + emac_rx_enable(dev); +@@ -2896,6 +2899,8 @@ static int emac_init_config(struct emac_ + dev->fifo_entry_size = 16; + if (emac_read_uint_prop(np, "mal-burst-size", &dev->mal_burst_size, 0)) + dev->mal_burst_size = 256; ++ if (emac_read_uint_prop(np, "emac,extra-mtu-size-for-dsa", &dev->dsa_header, 0)) ++ dev->dsa_header = 0; + + /* PHY mode needs some decoding */ + dev->phy_mode = of_get_phy_mode(np); +--- a/drivers/net/ethernet/ibm/emac/core.h ++++ b/drivers/net/ethernet/ibm/emac/core.h +@@ -225,6 +225,8 @@ struct emac_instance { + + /* Max supported MTU */ + u32 max_mtu; ++ /* extra dsa header */ ++ u32 dsa_header; + + /* Feature bits (from probe table) */ + unsigned int features; -- 2.30.2