From: Christian Lamparter Date: Sun, 3 Feb 2019 23:05:20 +0000 (+0100) Subject: ipq8064: ipq8064-mdio + dsa test X-Git-Url: http://git.openwrt.org/?a=commitdiff_plain;h=d2abec51764c8627705cf9fce2a0d1a24c1244f1;p=openwrt%2Fstaging%2Fchunkeey.git ipq8064: ipq8064-mdio + dsa test --- diff --git a/target/linux/ipq806x/base-files/etc/board.d/02_network b/target/linux/ipq806x/base-files/etc/board.d/02_network index 529a8d9f39..98c08b7628 100755 --- a/target/linux/ipq806x/base-files/etc/board.d/02_network +++ b/target/linux/ipq806x/base-files/etc/board.d/02_network @@ -19,8 +19,8 @@ netgear,r7500 |\ netgear,r7500v2 |\ qcom,ipq8064-ap148 |\ tplink,vr2600v) - ucidef_add_switch "switch0" \ - "1:lan" "2:lan" "3:lan" "4:lan" "6@eth1" "5:wan" "0@eth0" + ucidef_set_interface_lan "lan1 lan2 lan3 lan4" + ucidef_set_interface_wan "wan" ;; qcom,ipq8064-ap161) ucidef_set_interface_lan "eth1 eth2" diff --git a/target/linux/ipq806x/config-4.19 b/target/linux/ipq806x/config-4.19 index f61883a6db..b315110f9d 100644 --- a/target/linux/ipq806x/config-4.19 +++ b/target/linux/ipq806x/config-4.19 @@ -1,7 +1,7 @@ CONFIG_ALIGNMENT_TRAP=y # CONFIG_APQ_GCC_8084 is not set # CONFIG_APQ_MMCC_8084 is not set -CONFIG_AR8216_PHY=y +# CONFIG_AR8216_PHY is not set CONFIG_ARCH_CLOCKSOURCE_DATA=y CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y CONFIG_ARCH_HAS_ELF_RANDOMIZE=y @@ -268,6 +268,7 @@ CONFIG_MDIO_BITBANG=y CONFIG_MDIO_BUS=y CONFIG_MDIO_DEVICE=y CONFIG_MDIO_GPIO=y +CONFIG_MDIO_IPQ8064=y # CONFIG_MDM_GCC_9615 is not set # CONFIG_MDM_LCC_9615 is not set CONFIG_MEMFD_CREATE=y diff --git a/target/linux/ipq806x/files-4.19/arch/arm/boot/dts/qcom-ipq8064-wpq864.dts b/target/linux/ipq806x/files-4.19/arch/arm/boot/dts/qcom-ipq8064-wpq864.dts index a1e7791d12..6d08ad5dcb 100644 --- a/target/linux/ipq806x/files-4.19/arch/arm/boot/dts/qcom-ipq8064-wpq864.dts +++ b/target/linux/ipq806x/files-4.19/arch/arm/boot/dts/qcom-ipq8064-wpq864.dts @@ -217,6 +217,7 @@ }; }; +#if 0 mdio0: mdio { #address-cells = <1>; #size-cells = <0>; @@ -246,6 +247,125 @@ reg = <4>; }; }; +#endif + + mdio0: mdio@37000000 { + #address-cells = <1>; + #size-cells = <0>; + + compatible = "qcom,ipq8064-mdio", "syscon"; + reg = <0x37000000 0x200000>; + resets = <&gcc GMAC_CORE1_RESET>; + reset-names = "stmmaceth"; + clocks = <&gcc GMAC_CORE1_CLK>; + clock-names = "stmmaceth"; + + pinctrl-0 = <&mdio0_pins>; + pinctrl-names = "default"; + + phy_port1: ethernet-phy@0 { + reg = <0>; +#if 0 + qca,ar8327-initvals = < + 0x00004 0x7600000 /* PAD0_MODE = RMII MASTER+SLAVE ENABLE CLOCK INVERSE, MAC0 RGMII + TXDELAY */ + 0x00008 0x1000000 /* PAD5_MODE = RGMII_RX_DELAY_EN */ + 0x0000c 0x80 /* PAD6_MODE = SGMII*/ + 0x000e4 0x6a545 /* MAC_POWER_SEL */ + 0x000e0 0xc74164de /* SGMII_CTRL = */ + 0x0007c 0x4e /* PORT0_STATUS */ + 0x00094 0x4e /* PORT6_STATUS */ + >; +#endif + }; + + phy_port2: ethernet-phy@1 { + reg = <1>; + }; + + phy_port3: ethernet-phy@2 { + reg = <2>; + }; + + phy_port4: ethernet-phy@3 { + reg = <3>; + }; + + phy_port5: ethernet-phy@4 { + reg = <4>; + }; + + switch@10 { + compatible = "qca,qca8337"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x10>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + label = "cpu"; + ethernet = <&gmac1>; + phy-mode = "rgmii"; + + fixed-link { + speed = <1000>; + full-duplex; + pause; + asym-pause; + }; + }; + + port@1 { + reg = <1>; + label = "lan1"; + phy-handle = <&phy_port1>; + }; + + port@2 { + reg = <2>; + label = "lan2"; + phy-handle = <&phy_port2>; + }; + + port@3 { + reg = <3>; + label = "lan3"; + phy-handle = <&phy_port3>; + }; + + port@4 { + reg = <4>; + label = "lan4"; + phy-handle = <&phy_port4>; + }; + + port@5 { + reg = <5>; + label = "wan"; + phy-handle = <&phy_port5>; + }; + + /* + port@6 { + reg = <0>; + label = "cpu"; + ethernet = <&gmac2>; + phy-mode = "rgmii"; + + fixed-link { + speed = <1000>; + full-duplex; + pause; + asym-pause; + }; + }; + */ + }; + }; + }; leds { compatible = "gpio-leds"; @@ -334,6 +454,8 @@ fixed-link { speed = <1000>; full-duplex; + pause; + asym-pause; }; }; @@ -346,6 +468,8 @@ fixed-link { speed = <1000>; full-duplex; + pause; + asym-pause; }; }; @@ -531,7 +655,7 @@ mdio0_pins: mdio0_pins { mux { pins = "gpio0", "gpio1"; - function = "gpio"; + function = "mdio"; drive-strength = <8>; bias-disable; }; diff --git a/target/linux/ipq806x/patches-4.19/700-net-mdio-add-ipq8064-mdio-driver.patch b/target/linux/ipq806x/patches-4.19/700-net-mdio-add-ipq8064-mdio-driver.patch new file mode 100644 index 0000000000..6f25b895ca --- /dev/null +++ b/target/linux/ipq806x/patches-4.19/700-net-mdio-add-ipq8064-mdio-driver.patch @@ -0,0 +1,216 @@ +From 5de1da6c862de6a92ac9aed521f21fd5a180f22b Mon Sep 17 00:00:00 2001 +From: Christian Lamparter +Date: Sat, 2 Feb 2019 02:48:35 +0100 +Subject: [PATCH] net: mdio: add ipq8064 mdio driver + +Signed-off-by: Christian Lamparter +--- + drivers/net/phy/Kconfig | 8 ++ + drivers/net/phy/Makefile | 1 + + drivers/net/phy/mdio-ipq8064.c | 163 +++++++++++++++++++++++++++++++++ + 3 files changed, 172 insertions(+) + create mode 100644 drivers/net/phy/mdio-ipq8064.c + +diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig +index 3d187cd50eb0..883439dc2d5e 100644 +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -117,6 +117,14 @@ config MDIO_I2C + + This is library mode. + ++config MDIO_IPQ8064 ++ tristate "Qualcomm IPQ8064 MDIO interface support" ++ depends on HAS_IOMEM && OF_MDIO ++ depends on MFD_SYSCON ++ help ++ This driver supports the MDIO interface found in the network ++ interface units of the IPQ8064 SoC ++ + config MDIO_MOXART + tristate "MOXA ART MDIO interface support" + depends on ARCH_MOXART || COMPILE_TEST +diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile +index 5805c0b7d60e..4d8493e2e1a0 100644 +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -33,6 +33,7 @@ obj-$(CONFIG_MDIO_CAVIUM) += mdio-cavium.o + obj-$(CONFIG_MDIO_GPIO) += mdio-gpio.o + obj-$(CONFIG_MDIO_HISI_FEMAC) += mdio-hisi-femac.o + obj-$(CONFIG_MDIO_I2C) += mdio-i2c.o ++obj-$(CONFIG_MDIO_IPQ8064) += mdio-ipq8064.o + obj-$(CONFIG_MDIO_MOXART) += mdio-moxart.o + obj-$(CONFIG_MDIO_MSCC_MIIM) += mdio-mscc-miim.o + obj-$(CONFIG_MDIO_OCTEON) += mdio-octeon.o +diff --git a/drivers/net/phy/mdio-ipq8064.c b/drivers/net/phy/mdio-ipq8064.c +new file mode 100644 +index 000000000000..3802d92d18ca +--- /dev/null ++++ b/drivers/net/phy/mdio-ipq8064.c +@@ -0,0 +1,163 @@ ++// SPDX-License-Identifier: GPL-2.0 ++// ++// Qualcomm IPQ8064 MDIO interface driver ++// ++// Copyright (C) 2019 Christian Lamparter ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* MII address register definitions */ ++#define MII_ADDR_REG_ADDR 0x10 ++#define MII_BUSY BIT(0) ++#define MII_WRITE BIT(1) ++#define MII_CLKRANGE_60_100M (0 << 2) ++#define MII_CLKRANGE_100_150M (1 << 2) ++#define MII_CLKRANGE_20_35M (2 << 2) ++#define MII_CLKRANGE_35_60M (3 << 2) ++#define MII_CLKRANGE_150_250M (4 << 2) ++#define MII_CLKRANGE_250_300M (5 << 2) ++#define MII_CLKRANGE_MASK GENMASK(4, 2) ++#define MII_REG_SHIFT 6 ++#define MII_REG_MASK GENMASK(10, 6) ++#define MII_ADDR_SHIFT 11 ++#define MII_ADDR_MASK GENMASK(15, 11) ++ ++#define MII_DATA_REG_ADDR 0x14 ++ ++#define MII_MDIO_DELAY (1000) ++#define MII_MDIO_RETRY (10) ++ ++struct ipq8064_mdio { ++ struct regmap *base; /* NSS_GMAC0_BASE */ ++}; ++ ++static int ++ipq8064_mdio_wait_busy(struct ipq8064_mdio *priv) ++{ ++ int i; ++ ++ for (i = 0; i < MII_MDIO_RETRY; i++) { ++ unsigned int busy; ++ ++ regmap_read(priv->base, MII_ADDR_REG_ADDR, &busy); ++ if (!(busy & MII_BUSY)) ++ return 0; ++ ++ udelay(MII_MDIO_DELAY); ++ } ++ ++ return -ETIMEDOUT; ++} ++ ++static int ++ipq8064_mdio_read(struct mii_bus *bus, int phy_addr, int reg_offset) ++{ ++ struct ipq8064_mdio *priv = bus->priv; ++ u32 miiaddr = MII_BUSY | MII_CLKRANGE_250_300M; ++ u32 ret_val; ++ int err; ++ ++ miiaddr |= ((phy_addr << MII_ADDR_SHIFT) & MII_ADDR_MASK) | ++ ((reg_offset << MII_REG_SHIFT) & MII_REG_MASK); ++ ++ regmap_write(priv->base, MII_ADDR_REG_ADDR, miiaddr); ++ udelay(10); ++ ++ err = ipq8064_mdio_wait_busy(priv); ++ if (err) ++ return err; ++ ++ regmap_read(priv->base, MII_DATA_REG_ADDR, &ret_val); ++ return (int)ret_val; ++} ++ ++static int ++ipq8064_mdio_write(struct mii_bus *bus, int phy_addr, int reg_offset, u16 data) ++{ ++ struct ipq8064_mdio *priv = bus->priv; ++ u32 miiaddr = MII_WRITE | MII_BUSY | MII_CLKRANGE_250_300M; ++ ++ regmap_write(priv->base, MII_DATA_REG_ADDR, data); ++ ++ miiaddr |= ((phy_addr << MII_ADDR_SHIFT) & MII_ADDR_MASK) | ++ ((reg_offset << MII_REG_SHIFT) & MII_REG_MASK); ++ ++ regmap_write(priv->base, MII_ADDR_REG_ADDR, miiaddr); ++ udelay(10); ++ ++ return ipq8064_mdio_wait_busy(priv); ++} ++ ++static int ++ipq8064_mdio_probe(struct platform_device *pdev) ++{ ++ struct device_node *np = pdev->dev.of_node; ++ struct ipq8064_mdio *priv; ++ struct mii_bus *bus; ++ int ret; ++ ++ bus = devm_mdiobus_alloc_size(&pdev->dev, sizeof(*priv)); ++ if (!bus) ++ return -ENOMEM; ++ ++ bus->name = "ipq8064_mdio_bus"; ++ bus->read = ipq8064_mdio_read; ++ bus->write = ipq8064_mdio_write; ++ snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii", dev_name(&pdev->dev)); ++ bus->parent = &pdev->dev; ++ ++ priv = bus->priv; ++ priv->base = syscon_node_to_regmap(np); ++ if (IS_ERR_OR_NULL(priv->base)) { ++ priv->base = syscon_regmap_lookup_by_phandle(np, "master"); ++ if (IS_ERR_OR_NULL(priv->base)) { ++ pr_err("master phandle not found\n"); ++ return -EINVAL; ++ } ++ } ++ ++ ret = of_mdiobus_register(bus, np); ++ if (ret) ++ return ret; ++ ++ platform_set_drvdata(pdev, bus); ++ return 0; ++} ++ ++static int ++ipq8064_mdio_remove(struct platform_device *pdev) ++{ ++ struct mii_bus *bus = platform_get_drvdata(pdev); ++ ++ mdiobus_unregister(bus); ++ ++ return 0; ++} ++ ++static const struct of_device_id ipq8064_mdio_dt_ids[] = { ++ { .compatible = "qcom,ipq8064-mdio" }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, ipq8064_mdio_dt_ids); ++ ++static struct platform_driver ipq8064_mdio_driver = { ++ .probe = ipq8064_mdio_probe, ++ .remove = ipq8064_mdio_remove, ++ .driver = { ++ .name = "ipq8064-mdio", ++ .of_match_table = ipq8064_mdio_dt_ids, ++ }, ++}; ++ ++module_platform_driver(ipq8064_mdio_driver); ++ ++MODULE_DESCRIPTION("Qualcomm IPQ8064 MDIO interface driver"); ++MODULE_AUTHOR("Christian Lamparter "); ++MODULE_LICENSE("GPL"); +-- +2.20.1 + diff --git a/target/linux/ipq806x/patches-4.19/701-net-dsa-qca8k-implement-DT-based-ports-phy-translati.patch b/target/linux/ipq806x/patches-4.19/701-net-dsa-qca8k-implement-DT-based-ports-phy-translati.patch new file mode 100644 index 0000000000..7c904abe35 --- /dev/null +++ b/target/linux/ipq806x/patches-4.19/701-net-dsa-qca8k-implement-DT-based-ports-phy-translati.patch @@ -0,0 +1,89 @@ +From 0f1827db3a7760b0c4d418307c62fbb61415bd45 Mon Sep 17 00:00:00 2001 +From: Christian Lamparter +Date: Fri, 1 Feb 2019 22:54:32 +0100 +Subject: [PATCH] net: dsa: qca8k: implement DT-based ports <-> phy translation + +The QCA8337 enumerates 5 PHYs on the MDC/MDIO access: PHY0-PHY4. +These PHYs are internally connected to PORT 1 to PORT 5 MAC of +the switch based on the System Block Diagram in Section 1.2 +of the datasheet. + +This patch version of the patch uses the existing phy-handle +properties of each specified DSA Port in the DT to map each +PORT/MAC to its proper PHY. + +Signed-off-by: Christian Lamparter +--- + drivers/net/dsa/qca8k.c | 37 +++++++++++++++++++++++++++++++++++-- + 1 file changed, 35 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/dsa/qca8k.c b/drivers/net/dsa/qca8k.c +index a4b6cda38016..5879a70e803d 100644 +--- a/drivers/net/dsa/qca8k.c ++++ b/drivers/net/dsa/qca8k.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -612,20 +613,52 @@ qca8k_adjust_link(struct dsa_switch *ds, int port, struct phy_device *phy) + qca8k_port_set_status(priv, port, 1); + } + ++static int ++qca8k_to_real_phy(struct dsa_switch *ds, int phy) ++{ ++ struct device_node *phy_dn, *port_dn; ++ int id; ++ ++ if (phy >= ds->num_ports) ++ return -EINVAL; ++ ++ port_dn = ds->ports[phy].dn; ++ if (!port_dn) ++ return -EINVAL; ++ ++ phy_dn = of_parse_phandle(port_dn, "phy-handle", 0); ++ if (!phy_dn) { ++ /* remain compatible with existing users */ ++ return phy; ++ } ++ ++ id = of_mdio_parse_addr(ds->dev, phy_dn); ++ of_node_put(phy_dn); ++ return id; ++} ++ + 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 +-- +2.20.1 +