linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH net-next 00/12] Add lan966x driver
@ 2021-09-20  9:52 Horatiu Vultur
  2021-09-20  9:52 ` [RFC PATCH net-next 01/12] net: mdio: mscc-miim: Fix the mdio controller Horatiu Vultur
                   ` (11 more replies)
  0 siblings, 12 replies; 30+ messages in thread
From: Horatiu Vultur @ 2021-09-20  9:52 UTC (permalink / raw)
  To: davem, kuba, robh+dt, andrew, linux, f.fainelli,
	alexandre.belloni, vladimir.oltean, UNGLinuxDriver, netdev,
	devicetree, linux-kernel, linux-phy, linux-pm
  Cc: Horatiu Vultur

This patch series cover multiple drivers but I have put everything in one
single series so it would be easier to follow the big picture. Eventually
this series will be split in multiple ones once we drop the RFC.

The Microchip LAN966X is a compact and cost-effective, multi-port Gigabit
AVB/TSN Ethernet Switches with two integrated 10/100/1000BASE-T PHYs and a
600 MHz ARM Cortex A7 CPU subsystem. The LAN966X includes eight ports.

In addition to the two integrated PHYs, the lAN966X supports up to
2 RGMII/RMII, up to 3 1000BASE-X/SerDes/ 2.5GBASE-X/KX, and up to
2 Quad-SGMII/Quad-USGMII interfaces. The LAN966X fully supports the IEEE
family of Audio Video Bridging (AVB) and Time Sensitive Networking (TSN)
standards, including the current IEC/IEEE draft 60802 TSN profile,
which in concert provide high Quality of Service (QoS) for latency
sensitive traffic streams over Ethernet.

The LAN966X supports TSN domain protection though IEEE 802.1Qci Per Stream
Filtering and Policing, advanced classification rules, and tunneling by
adding VLAN tags. Each egress port supports eight priorities. Prior to
scheduling, traffic can be shaped using dual-leaky bucket shaping,
IEEE 802.1Qav Credit Based Shaping, and IEEE 802.1Qbv Time Aware Shaping,
thus also supporting IEEE 802.1Q Enhanced Transmission Selection.

Low latency is possible though latency optimized architecture,
cut-through, and IEEE 802.1Qbu/802.3br Preemption. For higher traffic
availability, the LAN966X supports Multiple Spanning Tree, IEEE 802.1CB
Frame Replication and Elimination for Redundancy, IEC 62439-2 MRP,
ODVA DLR, in addition to ITU-T G.8031 and G.8032 linear and ring
protection.

The LAN966X supports IEEE 802.1AS-2020 (gPTP) and IEEE 1588-2019 (PTP)
time synchronization with time stamping in multiple domains in
support of Working Clock and Global Time distribution.

The LAN966X can operate either as a standalone switch or as a system
co-processor with an external host CPU. The external host can manage the
switch via PCIe or an Ethernet port.

This series provides support for:
- support for integrated PHY
- host mode providing register based injection and extraction

More support will be added in future patches.

Horatiu Vultur (12):
  net: mdio: mscc-miim: Fix the mdio controller
  net: phy: mchp: Add support for LAN8804 PHY
  phy: Add lan966x ethernet serdes PHY driver
  dt-bindings: reset: Add lan966x switch reset bindings
  reset: lan966x: Add switch reset driver
  dt-bindings: reset: Add lan966x power reset bindings
  power: reset: Add lan966x power reset driver
  dt-bindings: net: lan966x: Add lan966x-switch bindings
  net: lan966x: add the basic lan966x driver
  net: lan966x: add port module support
  net: lan966x: add mactable support
  net: lan966x: add ethtool configuration and statistics

 .../net/microchip,lan966x-switch.yaml         | 114 ++
 .../bindings/power/lan966x,power.yaml         |  49 +
 .../bindings/reset/lan966x,rst.yaml           |  58 +
 drivers/net/ethernet/microchip/Kconfig        |   1 +
 drivers/net/ethernet/microchip/Makefile       |   1 +
 .../net/ethernet/microchip/lan966x/Kconfig    |   7 +
 .../net/ethernet/microchip/lan966x/Makefile   |   9 +
 .../microchip/lan966x/lan966x_ethtool.c       | 578 ++++++++++
 .../ethernet/microchip/lan966x/lan966x_ifh.h  | 173 +++
 .../ethernet/microchip/lan966x/lan966x_main.c | 994 ++++++++++++++++++
 .../ethernet/microchip/lan966x/lan966x_main.h | 192 ++++
 .../microchip/lan966x/lan966x_phylink.c       |  92 ++
 .../ethernet/microchip/lan966x/lan966x_port.c | 301 ++++++
 .../ethernet/microchip/lan966x/lan966x_regs.h | 704 +++++++++++++
 drivers/net/mdio/mdio-mscc-miim.c             |  14 +-
 drivers/net/phy/micrel.c                      |  73 ++
 drivers/phy/microchip/Kconfig                 |   8 +
 drivers/phy/microchip/Makefile                |   1 +
 drivers/phy/microchip/lan966x_serdes.c        | 525 +++++++++
 drivers/phy/microchip/lan966x_serdes_regs.h   | 482 +++++++++
 drivers/power/reset/Kconfig                   |   6 +
 drivers/power/reset/Makefile                  |   1 +
 drivers/power/reset/lan966x-reset.c           |  90 ++
 drivers/reset/Kconfig                         |   8 +
 drivers/reset/Makefile                        |   1 +
 drivers/reset/reset-lan966x.c                 | 128 +++
 include/dt-bindings/phy/lan966x_serdes.h      |  14 +
 include/linux/micrel_phy.h                    |   1 +
 28 files changed, 4620 insertions(+), 5 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/net/microchip,lan966x-switch.yaml
 create mode 100644 Documentation/devicetree/bindings/power/lan966x,power.yaml
 create mode 100644 Documentation/devicetree/bindings/reset/lan966x,rst.yaml
 create mode 100644 drivers/net/ethernet/microchip/lan966x/Kconfig
 create mode 100644 drivers/net/ethernet/microchip/lan966x/Makefile
 create mode 100644 drivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c
 create mode 100644 drivers/net/ethernet/microchip/lan966x/lan966x_ifh.h
 create mode 100644 drivers/net/ethernet/microchip/lan966x/lan966x_main.c
 create mode 100644 drivers/net/ethernet/microchip/lan966x/lan966x_main.h
 create mode 100644 drivers/net/ethernet/microchip/lan966x/lan966x_phylink.c
 create mode 100644 drivers/net/ethernet/microchip/lan966x/lan966x_port.c
 create mode 100644 drivers/net/ethernet/microchip/lan966x/lan966x_regs.h
 create mode 100644 drivers/phy/microchip/lan966x_serdes.c
 create mode 100644 drivers/phy/microchip/lan966x_serdes_regs.h
 create mode 100644 drivers/power/reset/lan966x-reset.c
 create mode 100644 drivers/reset/reset-lan966x.c
 create mode 100644 include/dt-bindings/phy/lan966x_serdes.h

-- 
2.31.1


^ permalink raw reply	[flat|nested] 30+ messages in thread

* [RFC PATCH net-next 01/12] net: mdio: mscc-miim: Fix the mdio controller
  2021-09-20  9:52 [RFC PATCH net-next 00/12] Add lan966x driver Horatiu Vultur
@ 2021-09-20  9:52 ` Horatiu Vultur
  2021-09-20 11:52   ` Andrew Lunn
  2021-09-20  9:52 ` [RFC PATCH net-next 02/12] net: phy: mchp: Add support for LAN8804 PHY Horatiu Vultur
                   ` (10 subsequent siblings)
  11 siblings, 1 reply; 30+ messages in thread
From: Horatiu Vultur @ 2021-09-20  9:52 UTC (permalink / raw)
  To: davem, kuba, robh+dt, andrew, linux, f.fainelli,
	alexandre.belloni, vladimir.oltean, UNGLinuxDriver, netdev,
	devicetree, linux-kernel, linux-phy, linux-pm
  Cc: Horatiu Vultur

According to the documentation the second resource is optional. But the
blamed commit ignores that and if the resource is not there it just
fails.

This patch reverts that to still allow the second resource to be
optional because other SoC have the some MDIO controller and doesn't
need to second resource.

Fixes: 672a1c394950 ("net: mdio: mscc-miim: Make use of the helper function devm_platform_ioremap_resource()")
Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
---
 drivers/net/mdio/mdio-mscc-miim.c | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/drivers/net/mdio/mdio-mscc-miim.c b/drivers/net/mdio/mdio-mscc-miim.c
index 1ee592d3eae4..bef026a80074 100644
--- a/drivers/net/mdio/mdio-mscc-miim.c
+++ b/drivers/net/mdio/mdio-mscc-miim.c
@@ -134,8 +134,9 @@ static int mscc_miim_reset(struct mii_bus *bus)
 
 static int mscc_miim_probe(struct platform_device *pdev)
 {
-	struct mii_bus *bus;
 	struct mscc_miim_dev *dev;
+	struct resource *res;
+	struct mii_bus *bus;
 	int ret;
 
 	bus = devm_mdiobus_alloc_size(&pdev->dev, sizeof(*dev));
@@ -156,10 +157,13 @@ static int mscc_miim_probe(struct platform_device *pdev)
 		return PTR_ERR(dev->regs);
 	}
 
-	dev->phy_regs = devm_platform_ioremap_resource(pdev, 1);
-	if (IS_ERR(dev->phy_regs)) {
-		dev_err(&pdev->dev, "Unable to map internal phy registers\n");
-		return PTR_ERR(dev->phy_regs);
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (res) {
+		dev->phy_regs = devm_ioremap_resource(&pdev->dev, res);
+		if (IS_ERR(dev->phy_regs)) {
+			dev_err(&pdev->dev, "Unable to map internal phy registers\n");
+			return PTR_ERR(dev->phy_regs);
+		}
 	}
 
 	ret = of_mdiobus_register(bus, pdev->dev.of_node);
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [RFC PATCH net-next 02/12] net: phy: mchp: Add support for LAN8804 PHY
  2021-09-20  9:52 [RFC PATCH net-next 00/12] Add lan966x driver Horatiu Vultur
  2021-09-20  9:52 ` [RFC PATCH net-next 01/12] net: mdio: mscc-miim: Fix the mdio controller Horatiu Vultur
@ 2021-09-20  9:52 ` Horatiu Vultur
  2021-09-20 10:00   ` Alexandre Belloni
  2021-09-20 11:59   ` Andrew Lunn
  2021-09-20  9:52 ` [RFC PATCH net-next 03/12] phy: Add lan966x ethernet serdes PHY driver Horatiu Vultur
                   ` (9 subsequent siblings)
  11 siblings, 2 replies; 30+ messages in thread
From: Horatiu Vultur @ 2021-09-20  9:52 UTC (permalink / raw)
  To: davem, kuba, robh+dt, andrew, linux, f.fainelli,
	alexandre.belloni, vladimir.oltean, UNGLinuxDriver, netdev,
	devicetree, linux-kernel, linux-phy, linux-pm
  Cc: Horatiu Vultur

The LAN8804 SKY has same features as that of LAN8804 SKY except that it
doesn't support 1588, SyncE or Q-USGMII.

This PHY is found inside the LAN966X switches.

Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
---
 drivers/net/phy/micrel.c   | 73 ++++++++++++++++++++++++++++++++++++++
 include/linux/micrel_phy.h |  1 +
 2 files changed, 74 insertions(+)

diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c
index 5c928f827173..34800b547004 100644
--- a/drivers/net/phy/micrel.c
+++ b/drivers/net/phy/micrel.c
@@ -1537,6 +1537,65 @@ static int ksz886x_cable_test_get_status(struct phy_device *phydev,
 	return ret;
 }
 
+#define LAN_EXT_PAGE_ACCESS_CONTROL			0x16
+#define LAN_EXT_PAGE_ACCESS_ADDRESS_DATA		0x17
+#define LAN_EXT_PAGE_ACCESS_CTRL_EP_FUNC		0x4000
+
+#define LAN8804_ALIGN_SWAP				0x4a
+#define LAN8804_ALIGN_TX_A_B_SWAP			0x1
+#define LAN8804_ALIGN_TX_A_B_SWAP_MASK			GENMASK(2, 0)
+#define LAN8814_CLOCK_MANAGEMENT			0xd
+#define LAN8814_LINK_QUALITY				0x8e
+
+static int lanphy_read_page_reg(struct phy_device *phydev, int page, u32 addr)
+{
+	u32 data;
+
+	phy_write(phydev, LAN_EXT_PAGE_ACCESS_CONTROL, page);
+	phy_write(phydev, LAN_EXT_PAGE_ACCESS_ADDRESS_DATA, addr);
+	phy_write(phydev, LAN_EXT_PAGE_ACCESS_CONTROL,
+		  (page | LAN_EXT_PAGE_ACCESS_CTRL_EP_FUNC));
+	data = phy_read(phydev, LAN_EXT_PAGE_ACCESS_ADDRESS_DATA);
+
+	return data;
+}
+
+static int lanphy_write_page_reg(struct phy_device *phydev, int page, u16 addr,
+				 u16 val)
+{
+	phy_write(phydev, LAN_EXT_PAGE_ACCESS_CONTROL, page);
+	phy_write(phydev, LAN_EXT_PAGE_ACCESS_ADDRESS_DATA, addr);
+	phy_write(phydev, LAN_EXT_PAGE_ACCESS_CONTROL,
+		  (page | LAN_EXT_PAGE_ACCESS_CTRL_EP_FUNC));
+
+	val = phy_write(phydev, LAN_EXT_PAGE_ACCESS_ADDRESS_DATA, val);
+	if (val) {
+		phydev_err(phydev, "Error: phy_write has returned error %d\n",
+			   val);
+		return val;
+	}
+	return 0;
+}
+
+static int lan8804_config_init(struct phy_device *phydev)
+{
+	int val;
+
+	/* MDI-X setting for swap A,B transmit */
+	val = lanphy_read_page_reg(phydev, 2, LAN8804_ALIGN_SWAP);
+	val &= ~LAN8804_ALIGN_TX_A_B_SWAP_MASK;
+	val |= LAN8804_ALIGN_TX_A_B_SWAP;
+	lanphy_write_page_reg(phydev, 2, LAN8804_ALIGN_SWAP, val);
+
+	/* Make sure that the PHY will not stop generating the clock when the
+	 * link partner goes down
+	 */
+	lanphy_write_page_reg(phydev, 31, LAN8814_CLOCK_MANAGEMENT, 0x27e);
+	lanphy_read_page_reg(phydev, 1, LAN8814_LINK_QUALITY);
+
+	return 0;
+}
+
 static struct phy_driver ksphy_driver[] = {
 {
 	.phy_id		= PHY_ID_KS8737,
@@ -1718,6 +1777,20 @@ static struct phy_driver ksphy_driver[] = {
 	.get_stats	= kszphy_get_stats,
 	.suspend	= genphy_suspend,
 	.resume		= kszphy_resume,
+}, {
+	.phy_id		= PHY_ID_LAN8804,
+	.phy_id_mask	= MICREL_PHY_ID_MASK,
+	.name		= "Microchip LAN966X Gigabit PHY",
+	.config_init	= lan8804_config_init,
+	.driver_data	= &ksz9021_type,
+	.probe		= kszphy_probe,
+	.soft_reset	= genphy_soft_reset,
+	.read_status	= ksz9031_read_status,
+	.get_sset_count	= kszphy_get_sset_count,
+	.get_strings	= kszphy_get_strings,
+	.get_stats	= kszphy_get_stats,
+	.suspend	= genphy_suspend,
+	.resume		= kszphy_resume,
 }, {
 	.phy_id		= PHY_ID_KSZ9131,
 	.phy_id_mask	= MICREL_PHY_ID_MASK,
diff --git a/include/linux/micrel_phy.h b/include/linux/micrel_phy.h
index 3d43c60b49fa..1f7c33b2f5a3 100644
--- a/include/linux/micrel_phy.h
+++ b/include/linux/micrel_phy.h
@@ -28,6 +28,7 @@
 #define PHY_ID_KSZ9031		0x00221620
 #define PHY_ID_KSZ9131		0x00221640
 #define PHY_ID_LAN8814		0x00221660
+#define PHY_ID_LAN8804		0x00221670
 
 #define PHY_ID_KSZ886X		0x00221430
 #define PHY_ID_KSZ8863		0x00221435
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [RFC PATCH net-next 03/12] phy: Add lan966x ethernet serdes PHY driver
  2021-09-20  9:52 [RFC PATCH net-next 00/12] Add lan966x driver Horatiu Vultur
  2021-09-20  9:52 ` [RFC PATCH net-next 01/12] net: mdio: mscc-miim: Fix the mdio controller Horatiu Vultur
  2021-09-20  9:52 ` [RFC PATCH net-next 02/12] net: phy: mchp: Add support for LAN8804 PHY Horatiu Vultur
@ 2021-09-20  9:52 ` Horatiu Vultur
  2021-09-20 13:42   ` Russell King (Oracle)
  2021-09-23 12:44   ` Rob Herring
  2021-09-20  9:52 ` [RFC PATCH net-next 04/12] dt-bindings: reset: Add lan966x switch reset bindings Horatiu Vultur
                   ` (8 subsequent siblings)
  11 siblings, 2 replies; 30+ messages in thread
From: Horatiu Vultur @ 2021-09-20  9:52 UTC (permalink / raw)
  To: davem, kuba, robh+dt, andrew, linux, f.fainelli,
	alexandre.belloni, vladimir.oltean, UNGLinuxDriver, netdev,
	devicetree, linux-kernel, linux-phy, linux-pm
  Cc: Horatiu Vultur

Add the Microchip lan966x ethernet serdes PHY driver for 1G interfaces
available in the lan966x SoC.

Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
---
 drivers/phy/microchip/Kconfig               |   8 +
 drivers/phy/microchip/Makefile              |   1 +
 drivers/phy/microchip/lan966x_serdes.c      | 525 ++++++++++++++++++++
 drivers/phy/microchip/lan966x_serdes_regs.h | 482 ++++++++++++++++++
 include/dt-bindings/phy/lan966x_serdes.h    |  14 +
 5 files changed, 1030 insertions(+)
 create mode 100644 drivers/phy/microchip/lan966x_serdes.c
 create mode 100644 drivers/phy/microchip/lan966x_serdes_regs.h
 create mode 100644 include/dt-bindings/phy/lan966x_serdes.h

diff --git a/drivers/phy/microchip/Kconfig b/drivers/phy/microchip/Kconfig
index 3728a284bf64..38039ed0754c 100644
--- a/drivers/phy/microchip/Kconfig
+++ b/drivers/phy/microchip/Kconfig
@@ -11,3 +11,11 @@ config PHY_SPARX5_SERDES
 	depends on HAS_IOMEM
 	help
 	  Enable this for support of the 10G/25G SerDes on Microchip Sparx5.
+
+config PHY_LAN966X_SERDES
+	tristate "SerDes PHY driver for Microchip LAN966X"
+	select GENERIC_PHY
+	depends on OF
+	depends on MFD_SYSCON
+	help
+	  Enable this for supporting SerDes muxing with Microchip LAN966X
diff --git a/drivers/phy/microchip/Makefile b/drivers/phy/microchip/Makefile
index 7b98345712aa..fd73b87960a5 100644
--- a/drivers/phy/microchip/Makefile
+++ b/drivers/phy/microchip/Makefile
@@ -4,3 +4,4 @@
 #
 
 obj-$(CONFIG_PHY_SPARX5_SERDES) := sparx5_serdes.o
+obj-$(CONFIG_PHY_LAN966X_SERDES) := lan966x_serdes.o
diff --git a/drivers/phy/microchip/lan966x_serdes.c b/drivers/phy/microchip/lan966x_serdes.c
new file mode 100644
index 000000000000..80811af40dca
--- /dev/null
+++ b/drivers/phy/microchip/lan966x_serdes.c
@@ -0,0 +1,525 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+
+#include <linux/err.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/phy.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <dt-bindings/phy/lan966x_serdes.h>
+#include "lan966x_serdes_regs.h"
+
+static const char *gcb_syscon = "microchip,lan966x-switch-syscon";
+
+#define lan_offset_(id, tinst, tcnt,			\
+		   gbase, ginst, gcnt, gwidth,		\
+		   raddr, rinst, rcnt, rwidth)		\
+	(gbase + ((ginst) * gwidth) + raddr + ((rinst) * rwidth))
+#define lan_offset(...) lan_offset_(__VA_ARGS__)
+
+#define lan_rmw(val, mask, reg, off)			\
+	regmap_update_bits(reg, lan_offset(off), mask, val)
+
+struct serdes_ctrl {
+	struct regmap		*regs;
+	struct device		*dev;
+	struct phy		*phys[SERDES_MAX];
+	int			ref125;
+};
+
+struct serdes_macro {
+	u8			idx;
+	int			port;
+	struct serdes_ctrl	*ctrl;
+};
+
+enum lan966x_sd6g40_mode {
+	LAN966X_SD6G40_MODE_QSGMII,
+	LAN966X_SD6G40_MODE_SGMII,
+};
+
+enum lan966x_sd6g40_ltx2rx {
+	LAN966X_SD6G40_TX2RX_LOOP_NONE,
+	LAN966X_SD6G40_LTX2RX
+};
+
+struct lan966x_sd6g40_setup_args {
+	enum lan966x_sd6g40_mode  mode;
+	enum lan966x_sd6g40_ltx2rx tx2rx_loop;
+	bool txinvert;
+	bool rxinvert;
+	bool refclk125M;
+	bool mute;
+};
+
+struct lan966x_sd6g40_mode_args {
+	enum lan966x_sd6g40_mode  mode;
+	u8 lane_10bit_sel;
+	u8 mpll_multiplier;
+	u8 ref_clkdiv2;
+	u8 tx_rate;
+	u8 rx_rate;
+};
+
+struct lan966x_sd6g40_setup {
+	u8 rx_term_en;
+	u8 lane_10bit_sel;
+	u8 tx_invert;
+	u8 rx_invert;
+	u8 mpll_multiplier;
+	u8 lane_loopbk_en;
+	u8 ref_clkdiv2;
+	u8 tx_rate;
+	u8 rx_rate;
+};
+
+static int lan966x_sd6g40_reg_cfg(struct serdes_macro *macro,
+				  struct lan966x_sd6g40_setup *res_struct,
+				  u32 idx)
+{
+	u32 value;
+
+	/* Note: SerDes HSIO is configured in 1G_LAN mode */
+	lan_rmw(HSIO_SD_CFG_LANE_10BIT_SEL(res_struct->lane_10bit_sel) |
+		HSIO_SD_CFG_RX_RATE(res_struct->rx_rate) |
+		HSIO_SD_CFG_TX_RATE(res_struct->tx_rate) |
+		HSIO_SD_CFG_TX_INVERT(res_struct->tx_invert) |
+		HSIO_SD_CFG_RX_INVERT(res_struct->rx_invert) |
+		HSIO_SD_CFG_LANE_LOOPBK_EN(res_struct->lane_loopbk_en) |
+		HSIO_SD_CFG_RX_RESET(0) |
+		HSIO_SD_CFG_TX_RESET(0),
+		HSIO_SD_CFG_LANE_10BIT_SEL_M |
+		HSIO_SD_CFG_RX_RATE_M |
+		HSIO_SD_CFG_TX_RATE_M |
+		HSIO_SD_CFG_TX_INVERT_M |
+		HSIO_SD_CFG_RX_INVERT_M |
+		HSIO_SD_CFG_LANE_LOOPBK_EN_M |
+		HSIO_SD_CFG_RX_RESET_M |
+		HSIO_SD_CFG_TX_RESET_M,
+		macro->ctrl->regs, HSIO_SD_CFG(idx));
+
+	lan_rmw(HSIO_MPLL_CFG_MPLL_MULTIPLIER(res_struct->mpll_multiplier) |
+		HSIO_MPLL_CFG_REF_CLKDIV2(res_struct->ref_clkdiv2),
+		HSIO_MPLL_CFG_MPLL_MULTIPLIER_M |
+		HSIO_MPLL_CFG_REF_CLKDIV2_M,
+		macro->ctrl->regs, HSIO_MPLL_CFG(idx));
+
+	lan_rmw(HSIO_SD_CFG_RX_TERM_EN(res_struct->rx_term_en),
+		HSIO_SD_CFG_RX_TERM_EN_M,
+		macro->ctrl->regs, HSIO_SD_CFG(idx));
+
+	lan_rmw(HSIO_MPLL_CFG_REF_SSP_EN(1),
+		HSIO_MPLL_CFG_REF_SSP_EN_M,
+		macro->ctrl->regs, HSIO_MPLL_CFG(idx));
+
+	usleep_range(USEC_PER_MSEC, 2 * USEC_PER_MSEC);
+
+	lan_rmw(HSIO_SD_CFG_PHY_RESET(0),
+		HSIO_SD_CFG_PHY_RESET_M,
+		macro->ctrl->regs, HSIO_SD_CFG(idx));
+
+	usleep_range(USEC_PER_MSEC, 2 * USEC_PER_MSEC);
+
+	lan_rmw(HSIO_MPLL_CFG_MPLL_EN(1),
+		HSIO_MPLL_CFG_MPLL_EN_M,
+		macro->ctrl->regs, HSIO_MPLL_CFG(idx));
+
+	usleep_range(7 * USEC_PER_MSEC, 8 * USEC_PER_MSEC);
+
+	regmap_read(macro->ctrl->regs, lan_offset(HSIO_SD_STAT(idx)), &value);
+	value = HSIO_SD_STAT_MPLL_STATE_X(value);
+	if (value != 0x1) {
+		pr_info("Unexpected sd_sd_stat[%u] mpll_state was 0x1 but is 0x%x\n",
+			idx, value);
+		return 1;
+	}
+
+	lan_rmw(HSIO_SD_CFG_TX_CM_EN(1),
+		HSIO_SD_CFG_TX_CM_EN_M,
+		macro->ctrl->regs, HSIO_SD_CFG(idx));
+
+	usleep_range(USEC_PER_MSEC, 2 * USEC_PER_MSEC);
+
+	regmap_read(macro->ctrl->regs, lan_offset(HSIO_SD_STAT(idx)), &value);
+	value = HSIO_SD_STAT_TX_CM_STATE_X(value);
+	if (value != 0x1) {
+		pr_info("Unexpected sd_sd_stat[%u] tx_cm_state was 0x1 but is 0x%x\n",
+			idx, value);
+		return 1;
+	}
+
+	lan_rmw(HSIO_SD_CFG_RX_PLL_EN(1) |
+		HSIO_SD_CFG_TX_EN(1),
+		HSIO_SD_CFG_RX_PLL_EN_M |
+		HSIO_SD_CFG_TX_EN_M,
+		macro->ctrl->regs, HSIO_SD_CFG(idx));
+
+	usleep_range(USEC_PER_MSEC, 2 * USEC_PER_MSEC);
+
+	/* Waiting for serdes 0 rx DPLL to lock...  */
+	regmap_read(macro->ctrl->regs, lan_offset(HSIO_SD_STAT(idx)), &value);
+	value = HSIO_SD_STAT_RX_PLL_STATE_X(value);
+	if (value != 0x1) {
+		pr_info("Unexpected sd_sd_stat[%u] rx_pll_state was 0x1 but is 0x%x\n",
+			idx, value);
+		return 1;
+	}
+
+	/* Waiting for serdes 0 tx operational...  */
+	regmap_read(macro->ctrl->regs, lan_offset(HSIO_SD_STAT(idx)), &value);
+	value = HSIO_SD_STAT_TX_STATE_X(value);
+	if (value != 0x1) {
+		pr_info("Unexpected sd_sd_stat[%u] tx_state was 0x1 but is 0x%x\n",
+			idx, value);
+		return 1;
+	}
+
+	lan_rmw(HSIO_SD_CFG_TX_DATA_EN(1) |
+		HSIO_SD_CFG_RX_DATA_EN(1),
+		HSIO_SD_CFG_TX_DATA_EN_M |
+		HSIO_SD_CFG_RX_DATA_EN_M,
+		macro->ctrl->regs, HSIO_SD_CFG(idx));
+
+	return 0;
+}
+
+static int lan966x_sd6g40_get_conf_from_mode(enum lan966x_sd6g40_mode f_mode,
+					     bool ref125M,
+					     struct lan966x_sd6g40_mode_args *ret_val)
+{
+	switch (f_mode) {
+	case LAN966X_SD6G40_MODE_QSGMII:
+		ret_val->lane_10bit_sel = 0;
+		if (ref125M) {
+			ret_val->mpll_multiplier = 40;
+			ret_val->ref_clkdiv2 = 0x1;
+			ret_val->tx_rate = 0x0;
+			ret_val->rx_rate = 0x0;
+		} else {
+			ret_val->mpll_multiplier = 100;
+			ret_val->ref_clkdiv2 = 0x0;
+			ret_val->tx_rate = 0x0;
+			ret_val->rx_rate = 0x0;
+		}
+		break;
+	case LAN966X_SD6G40_MODE_SGMII:
+		ret_val->lane_10bit_sel = 1;
+		if (ref125M) {
+			ret_val->mpll_multiplier = 40;
+			ret_val->ref_clkdiv2 = 0x1;
+			ret_val->tx_rate = 0x2;
+			ret_val->rx_rate = 0x2;
+		} else {
+			ret_val->mpll_multiplier = 100;
+			ret_val->ref_clkdiv2 = 0x0;
+			ret_val->tx_rate = 0x2;
+			ret_val->rx_rate = 0x2;
+		}
+		break;
+	default:
+		return -1;
+	}
+
+	return 0;
+}
+
+static int lan966x_calc_sd6g40_setup_lane(struct lan966x_sd6g40_setup_args config,
+					  struct lan966x_sd6g40_setup *ret_val)
+{
+	struct lan966x_sd6g40_mode_args sd6g40_mode;
+	struct lan966x_sd6g40_mode_args *mode_args = &sd6g40_mode;
+
+	if (lan966x_sd6g40_get_conf_from_mode(config.mode, config.refclk125M,
+					      mode_args))
+		return -1;
+
+	ret_val->lane_10bit_sel = mode_args->lane_10bit_sel;
+	ret_val->rx_rate = mode_args->rx_rate;
+	ret_val->tx_rate = mode_args->tx_rate;
+	ret_val->mpll_multiplier = mode_args->mpll_multiplier;
+	ret_val->ref_clkdiv2 = mode_args->ref_clkdiv2;
+	ret_val->rx_term_en = 0;
+
+	if (config.tx2rx_loop == LAN966X_SD6G40_LTX2RX)
+		ret_val->lane_loopbk_en = 1;
+	else
+		ret_val->lane_loopbk_en = 0;
+
+	if (config.txinvert)
+		ret_val->tx_invert = 1;
+	else
+		ret_val->tx_invert = 0;
+
+	if (config.rxinvert)
+		ret_val->rx_invert = 1;
+	else
+		ret_val->rx_invert = 0;
+
+	return 0;
+}
+
+static int lan966x_sd6g40_setup_lane(struct serdes_macro *macro,
+				     struct lan966x_sd6g40_setup_args config,
+				     u32 idx)
+{
+	struct lan966x_sd6g40_setup calc_results;
+	int ret;
+
+	memset(&calc_results, 0x0, sizeof(calc_results));
+
+	ret = lan966x_calc_sd6g40_setup_lane(config, &calc_results);
+	if (ret)
+		return ret;
+
+	return lan966x_sd6g40_reg_cfg(macro, &calc_results, idx);
+}
+
+static int lan966x_sd6g40_setup(struct serdes_macro *macro, u32 idx, int mode)
+{
+	struct lan966x_sd6g40_setup_args conf;
+
+	memset(&conf, 0x0, sizeof(conf));
+	conf.refclk125M = macro->ctrl->ref125;
+
+	if (mode == PHY_INTERFACE_MODE_QSGMII)
+		conf.mode = LAN966X_SD6G40_MODE_QSGMII;
+	else
+		conf.mode = LAN966X_SD6G40_MODE_SGMII;
+
+	return lan966x_sd6g40_setup_lane(macro, conf, idx);
+}
+
+struct serdes_mux {
+	u8			idx;
+	u8			port;
+	enum phy_mode		mode;
+	int			submode;
+	u32			mask;
+	u32			mux;
+};
+
+#define SERDES_MUX(_idx, _port, _mode, _submode, _mask, _mux) { \
+	.idx = _idx,						\
+	.port = _port,						\
+	.mode = _mode,						\
+	.submode = _submode,					\
+	.mask = _mask,						\
+	.mux = _mux,						\
+}
+
+#define SERDES_MUX_GMII(i, p, m, c) \
+	SERDES_MUX(i, p, PHY_MODE_ETHERNET, PHY_INTERFACE_MODE_GMII, m, c)
+#define SERDES_MUX_SGMII(i, p, m, c) \
+	SERDES_MUX(i, p, PHY_MODE_ETHERNET, PHY_INTERFACE_MODE_SGMII, m, c)
+#define SERDES_MUX_QSGMII(i, p, m, c) \
+	SERDES_MUX(i, p, PHY_MODE_ETHERNET, PHY_INTERFACE_MODE_QSGMII, m, c)
+#define SERDES_MUX_RGMII(i, p, m, c) \
+	SERDES_MUX(i, p, PHY_MODE_ETHERNET, PHY_INTERFACE_MODE_RGMII, m, c)
+
+static const struct serdes_mux lan966x_serdes_muxes[] = {
+	SERDES_MUX_QSGMII(SERDES6G(1), 0, HSIO_HW_CFG_QSGMII_ENA_M,
+			  HSIO_HW_CFG_QSGMII_ENA(BIT(0))),
+	SERDES_MUX_QSGMII(SERDES6G(1), 1, HSIO_HW_CFG_QSGMII_ENA_M,
+			  HSIO_HW_CFG_QSGMII_ENA(BIT(0))),
+	SERDES_MUX_QSGMII(SERDES6G(1), 2, HSIO_HW_CFG_QSGMII_ENA_M,
+			  HSIO_HW_CFG_QSGMII_ENA(BIT(0))),
+	SERDES_MUX_QSGMII(SERDES6G(1), 3, HSIO_HW_CFG_QSGMII_ENA_M,
+			  HSIO_HW_CFG_QSGMII_ENA(BIT(0))),
+
+	SERDES_MUX_QSGMII(SERDES6G(2), 4, HSIO_HW_CFG_QSGMII_ENA_M,
+			  HSIO_HW_CFG_QSGMII_ENA(BIT(1))),
+	SERDES_MUX_QSGMII(SERDES6G(2), 5, HSIO_HW_CFG_QSGMII_ENA_M,
+			  HSIO_HW_CFG_QSGMII_ENA(BIT(1))),
+	SERDES_MUX_QSGMII(SERDES6G(2), 6, HSIO_HW_CFG_QSGMII_ENA_M,
+			  HSIO_HW_CFG_QSGMII_ENA(BIT(1))),
+	SERDES_MUX_QSGMII(SERDES6G(2), 7, HSIO_HW_CFG_QSGMII_ENA_M,
+			  HSIO_HW_CFG_QSGMII_ENA(BIT(1))),
+
+	SERDES_MUX_GMII(CU(0), 0, HSIO_HW_CFG_GMII_ENA_M,
+			HSIO_HW_CFG_GMII_ENA(BIT(0))),
+	SERDES_MUX_GMII(CU(1), 1, HSIO_HW_CFG_GMII_ENA_M,
+			HSIO_HW_CFG_GMII_ENA(BIT(1))),
+
+	SERDES_MUX_SGMII(SERDES6G(0), 0, HSIO_HW_CFG_SD6G_0_CFG_M, 0),
+	SERDES_MUX_SGMII(SERDES6G(1), 1, HSIO_HW_CFG_SD6G_1_CFG_M, 0),
+	SERDES_MUX_SGMII(SERDES6G(0), 2, HSIO_HW_CFG_SD6G_0_CFG_M,
+			 HSIO_HW_CFG_SD6G_0_CFG(1)),
+	SERDES_MUX_SGMII(SERDES6G(1), 3, HSIO_HW_CFG_SD6G_1_CFG_M,
+			 HSIO_HW_CFG_SD6G_1_CFG(1)),
+
+	SERDES_MUX_RGMII(RG(0), 2, HSIO_HW_CFG_RGMII_0_CFG_M |
+			 HSIO_HW_CFG_RGMII_ENA_M,
+			 HSIO_HW_CFG_RGMII_0_CFG(BIT(0)) |
+			 HSIO_HW_CFG_RGMII_ENA(BIT(0))),
+	SERDES_MUX_RGMII(RG(1), 3, HSIO_HW_CFG_RGMII_1_CFG_M |
+			 HSIO_HW_CFG_RGMII_ENA_M,
+			 HSIO_HW_CFG_RGMII_1_CFG(BIT(0)) |
+			 HSIO_HW_CFG_RGMII_ENA(BIT(1))),
+	SERDES_MUX_RGMII(RG(0), 5, HSIO_HW_CFG_RGMII_0_CFG_M |
+			 HSIO_HW_CFG_RGMII_ENA_M,
+			 HSIO_HW_CFG_RGMII_0_CFG(BIT(0)) |
+			 HSIO_HW_CFG_RGMII_ENA(BIT(0))),
+	SERDES_MUX_RGMII(RG(1), 6, HSIO_HW_CFG_RGMII_1_CFG_M |
+			 HSIO_HW_CFG_RGMII_ENA_M,
+			 HSIO_HW_CFG_RGMII_1_CFG(BIT(0)) |
+			 HSIO_HW_CFG_RGMII_ENA(BIT(1))),
+};
+
+static int serdes_set_mode(struct phy *phy, enum phy_mode mode, int submode)
+{
+	struct serdes_macro *macro = phy_get_drvdata(phy);
+	unsigned int i;
+	int val;
+	int ret;
+
+	/* As of now only PHY_MODE_ETHERNET is supported */
+	if (mode != PHY_MODE_ETHERNET)
+		return -EOPNOTSUPP;
+
+	for (i = 0; i < ARRAY_SIZE(lan966x_serdes_muxes); i++) {
+		if (macro->idx != lan966x_serdes_muxes[i].idx ||
+		    mode != lan966x_serdes_muxes[i].mode ||
+		    submode != lan966x_serdes_muxes[i].submode ||
+		    macro->port != lan966x_serdes_muxes[i].port)
+			continue;
+
+		ret = regmap_read(macro->ctrl->regs, lan_offset(HSIO_HW_CFG),
+				  &val);
+		if (ret)
+			return ret;
+
+		ret = regmap_update_bits(macro->ctrl->regs,
+					 lan_offset(HSIO_HW_CFG),
+					 lan966x_serdes_muxes[i].mask,
+					 val | lan966x_serdes_muxes[i].mux);
+		if (ret)
+			return ret;
+
+		if (macro->idx < CU_MAX)
+			return 0;
+
+		if (macro->idx < SERDES6G_MAX)
+			return lan966x_sd6g40_setup(macro,
+						    macro->idx - (CU_MAX + 1),
+						    lan966x_serdes_muxes[i].submode);
+
+		if (macro->idx < RG_MAX)
+			return 0;
+
+		return -EOPNOTSUPP;
+	}
+
+	return -EINVAL;
+}
+
+static const struct phy_ops serdes_ops = {
+	.set_mode	= serdes_set_mode,
+	.owner		= THIS_MODULE,
+};
+
+static struct phy *serdes_simple_xlate(struct device *dev,
+				       struct of_phandle_args *args)
+{
+	struct serdes_ctrl *ctrl = dev_get_drvdata(dev);
+	unsigned int port, idx, i;
+
+	if (args->args_count != 2)
+		return ERR_PTR(-EINVAL);
+
+	port = args->args[0];
+	idx = args->args[1];
+
+	for (i = 0; i < SERDES_MAX; i++) {
+		struct serdes_macro *macro = phy_get_drvdata(ctrl->phys[i]);
+
+		if (idx != macro->idx)
+			continue;
+
+		macro->port = port;
+		return ctrl->phys[i];
+	}
+
+	return ERR_PTR(-ENODEV);
+}
+
+static int serdes_phy_create(struct serdes_ctrl *ctrl, u8 idx, struct phy **phy)
+{
+	struct serdes_macro *macro;
+
+	*phy = devm_phy_create(ctrl->dev, NULL, &serdes_ops);
+	if (IS_ERR(*phy))
+		return PTR_ERR(*phy);
+
+	macro = devm_kzalloc(ctrl->dev, sizeof(*macro), GFP_KERNEL);
+	if (!macro)
+		return -ENOMEM;
+
+	macro->idx = idx;
+	macro->ctrl = ctrl;
+	macro->port = -1;
+
+	phy_set_drvdata(*phy, macro);
+
+	return 0;
+}
+
+static int serdes_probe(struct platform_device *pdev)
+{
+	struct phy_provider *provider;
+	struct serdes_ctrl *ctrl;
+	struct regmap *gcb_ctrl;
+	unsigned int i;
+	u32 val;
+	int ret;
+
+	ctrl = devm_kzalloc(&pdev->dev, sizeof(*ctrl), GFP_KERNEL);
+	if (!ctrl)
+		return -ENOMEM;
+
+	ctrl->dev = &pdev->dev;
+	ctrl->regs = syscon_node_to_regmap(pdev->dev.parent->of_node);
+	if (IS_ERR(ctrl->regs))
+		return PTR_ERR(ctrl->regs);
+
+	gcb_ctrl = syscon_regmap_lookup_by_compatible(gcb_syscon);
+	if (IS_ERR(gcb_ctrl)) {
+		dev_err(&pdev->dev, "No gcb_syscon: %s\n", gcb_syscon);
+		return PTR_ERR(gcb_ctrl);
+	}
+
+	for (i = 0; i < SERDES_MAX; i++) {
+		ret = serdes_phy_create(ctrl, i, &ctrl->phys[i]);
+		if (ret)
+			return ret;
+	}
+
+	regmap_read(gcb_ctrl, 0x4, &val);
+	val &= GENMASK(2, 0);
+	ctrl->ref125 = (val == 1 || val == 2);
+
+	dev_set_drvdata(&pdev->dev, ctrl);
+
+	provider = devm_of_phy_provider_register(ctrl->dev,
+						 serdes_simple_xlate);
+
+	return PTR_ERR_OR_ZERO(provider);
+}
+
+static const struct of_device_id serdes_ids[] = {
+	{ .compatible = "microchip,lan966x-serdes", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, serdes_ids);
+
+static struct platform_driver mscc_lan966x_serdes = {
+	.probe		= serdes_probe,
+	.driver		= {
+		.name	= "microchip,lan966x-serdes",
+		.of_match_table = of_match_ptr(serdes_ids),
+	},
+};
+
+module_platform_driver(mscc_lan966x_serdes);
diff --git a/drivers/phy/microchip/lan966x_serdes_regs.h b/drivers/phy/microchip/lan966x_serdes_regs.h
new file mode 100644
index 000000000000..c3d3d16c1e97
--- /dev/null
+++ b/drivers/phy/microchip/lan966x_serdes_regs.h
@@ -0,0 +1,482 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
+/*
+ * Microchip LAN966x Switch driver
+ *
+ * License: Dual MIT/GPL
+ * Copyright (c) 2020 Microchip Technology Inc.
+ */
+
+/* This file is autogenerated by cml-utils 2021-05-12 15:48:55 +0200.
+ * Commit ID: dbe188f718027a2c414b90d45f152b73468cbc5c (dirty)
+ */
+
+#ifndef _LAN966X_HSIO_REGS_H_
+#define _LAN966X_HSIO_REGS_H_
+
+#include <linux/bitops.h>
+
+#define LAN966X_BUILD_ID_REG GCB_BUILDID
+enum lan966x_target {
+	TARGET_HSIO = 32,
+	NUM_TARGETS = 66
+};
+
+#define __REG(...)    __VA_ARGS__
+
+/*      HSIO:SYNC_ETH_CFG:SYNC_ETH_CFG */
+#define HSIO_SYNC_ETH_CFG(r)      __REG(TARGET_HSIO,\
+					0, 1, 0, 0, 1, 8, 0, r, 2, 4)
+
+#define HSIO_SYNC_ETH_CFG_SEL_RECO_CLK_SRC(x)    (((x) << 4) & GENMASK(6, 4))
+#define HSIO_SYNC_ETH_CFG_SEL_RECO_CLK_SRC_M     GENMASK(6, 4)
+#define HSIO_SYNC_ETH_CFG_SEL_RECO_CLK_SRC_X(x)  (((x) & GENMASK(6, 4)) >> 4)
+
+#define HSIO_SYNC_ETH_CFG_SEL_RECO_CLK_DIV(x)    (((x) << 1) & GENMASK(3, 1))
+#define HSIO_SYNC_ETH_CFG_SEL_RECO_CLK_DIV_M     GENMASK(3, 1)
+#define HSIO_SYNC_ETH_CFG_SEL_RECO_CLK_DIV_X(x)  (((x) & GENMASK(3, 1)) >> 1)
+
+#define HSIO_SYNC_ETH_CFG_RECO_CLK_ENA(x)        ((x) & GENMASK(0, 0))
+#define HSIO_SYNC_ETH_CFG_RECO_CLK_ENA_M         GENMASK(0, 0)
+#define HSIO_SYNC_ETH_CFG_RECO_CLK_ENA_X(x)      ((x) & GENMASK(0, 0))
+
+/*      HSIO:SD:SD_CFG */
+#define HSIO_SD_CFG(g)            __REG(TARGET_HSIO,\
+					0, 1, 8, g, 3, 32, 0, 0, 1, 4)
+
+#define HSIO_SD_CFG_TEST_POWERDOWN(x)            (((x) << 28) & GENMASK(28, 28))
+#define HSIO_SD_CFG_TEST_POWERDOWN_M             GENMASK(28, 28)
+#define HSIO_SD_CFG_TEST_POWERDOWN_X(x)          (((x) & GENMASK(28, 28)) >> 28)
+
+#define HSIO_SD_CFG_PHY_RESET(x)                 (((x) << 27) & GENMASK(27, 27))
+#define HSIO_SD_CFG_PHY_RESET_M                  GENMASK(27, 27)
+#define HSIO_SD_CFG_PHY_RESET_X(x)               (((x) & GENMASK(27, 27)) >> 27)
+
+#define HSIO_SD_CFG_RX_LOS_FILT_CNT(x)           (((x) << 20) & GENMASK(26, 20))
+#define HSIO_SD_CFG_RX_LOS_FILT_CNT_M            GENMASK(26, 20)
+#define HSIO_SD_CFG_RX_LOS_FILT_CNT_X(x)         (((x) & GENMASK(26, 20)) >> 20)
+
+#define HSIO_SD_CFG_TX_VBOOST_EN(x)              (((x) << 19) & GENMASK(19, 19))
+#define HSIO_SD_CFG_TX_VBOOST_EN_M               GENMASK(19, 19)
+#define HSIO_SD_CFG_TX_VBOOST_EN_X(x)            (((x) & GENMASK(19, 19)) >> 19)
+
+#define HSIO_SD_CFG_TX_RESET(x)                  (((x) << 18) & GENMASK(18, 18))
+#define HSIO_SD_CFG_TX_RESET_M                   GENMASK(18, 18)
+#define HSIO_SD_CFG_TX_RESET_X(x)                (((x) & GENMASK(18, 18)) >> 18)
+
+#define HSIO_SD_CFG_TX_RATE(x)                   (((x) << 16) & GENMASK(17, 16))
+#define HSIO_SD_CFG_TX_RATE_M                    GENMASK(17, 16)
+#define HSIO_SD_CFG_TX_RATE_X(x)                 (((x) & GENMASK(17, 16)) >> 16)
+
+#define HSIO_SD_CFG_TX_INVERT(x)                 (((x) << 15) & GENMASK(15, 15))
+#define HSIO_SD_CFG_TX_INVERT_M                  GENMASK(15, 15)
+#define HSIO_SD_CFG_TX_INVERT_X(x)               (((x) & GENMASK(15, 15)) >> 15)
+
+#define HSIO_SD_CFG_TX_EN(x)                     (((x) << 14) & GENMASK(14, 14))
+#define HSIO_SD_CFG_TX_EN_M                      GENMASK(14, 14)
+#define HSIO_SD_CFG_TX_EN_X(x)                   (((x) & GENMASK(14, 14)) >> 14)
+
+#define HSIO_SD_CFG_TX_DETECT_RX_REQ(x)          (((x) << 13) & GENMASK(13, 13))
+#define HSIO_SD_CFG_TX_DETECT_RX_REQ_M           GENMASK(13, 13)
+#define HSIO_SD_CFG_TX_DETECT_RX_REQ_X(x)        (((x) & GENMASK(13, 13)) >> 13)
+
+#define HSIO_SD_CFG_TX_DATA_EN(x)                (((x) << 12) & GENMASK(12, 12))
+#define HSIO_SD_CFG_TX_DATA_EN_M                 GENMASK(12, 12)
+#define HSIO_SD_CFG_TX_DATA_EN_X(x)              (((x) & GENMASK(12, 12)) >> 12)
+
+#define HSIO_SD_CFG_TX_CM_EN(x)                  (((x) << 11) & GENMASK(11, 11))
+#define HSIO_SD_CFG_TX_CM_EN_M                   GENMASK(11, 11)
+#define HSIO_SD_CFG_TX_CM_EN_X(x)                (((x) & GENMASK(11, 11)) >> 11)
+
+#define HSIO_SD_CFG_LANE_10BIT_SEL(x)            (((x) << 10) & GENMASK(10, 10))
+#define HSIO_SD_CFG_LANE_10BIT_SEL_M             GENMASK(10, 10)
+#define HSIO_SD_CFG_LANE_10BIT_SEL_X(x)          (((x) & GENMASK(10, 10)) >> 10)
+
+#define HSIO_SD_CFG_RX_TERM_EN(x)                (((x) << 9) & GENMASK(9, 9))
+#define HSIO_SD_CFG_RX_TERM_EN_M                 GENMASK(9, 9)
+#define HSIO_SD_CFG_RX_TERM_EN_X(x)              (((x) & GENMASK(9, 9)) >> 9)
+
+#define HSIO_SD_CFG_RX_RESET(x)                  (((x) << 8) & GENMASK(8, 8))
+#define HSIO_SD_CFG_RX_RESET_M                   GENMASK(8, 8)
+#define HSIO_SD_CFG_RX_RESET_X(x)                (((x) & GENMASK(8, 8)) >> 8)
+
+#define HSIO_SD_CFG_RX_RATE(x)                   (((x) << 6) & GENMASK(7, 6))
+#define HSIO_SD_CFG_RX_RATE_M                    GENMASK(7, 6)
+#define HSIO_SD_CFG_RX_RATE_X(x)                 (((x) & GENMASK(7, 6)) >> 6)
+
+#define HSIO_SD_CFG_RX_PLL_EN(x)                 (((x) << 5) & GENMASK(5, 5))
+#define HSIO_SD_CFG_RX_PLL_EN_M                  GENMASK(5, 5)
+#define HSIO_SD_CFG_RX_PLL_EN_X(x)               (((x) & GENMASK(5, 5)) >> 5)
+
+#define HSIO_SD_CFG_RX_LOS_EN(x)                 (((x) << 4) & GENMASK(4, 4))
+#define HSIO_SD_CFG_RX_LOS_EN_M                  GENMASK(4, 4)
+#define HSIO_SD_CFG_RX_LOS_EN_X(x)               (((x) & GENMASK(4, 4)) >> 4)
+
+#define HSIO_SD_CFG_RX_INVERT(x)                 (((x) << 3) & GENMASK(3, 3))
+#define HSIO_SD_CFG_RX_INVERT_M                  GENMASK(3, 3)
+#define HSIO_SD_CFG_RX_INVERT_X(x)               (((x) & GENMASK(3, 3)) >> 3)
+
+#define HSIO_SD_CFG_RX_DATA_EN(x)                (((x) << 2) & GENMASK(2, 2))
+#define HSIO_SD_CFG_RX_DATA_EN_M                 GENMASK(2, 2)
+#define HSIO_SD_CFG_RX_DATA_EN_X(x)              (((x) & GENMASK(2, 2)) >> 2)
+
+#define HSIO_SD_CFG_RX_ALIGN_EN(x)               (((x) << 1) & GENMASK(1, 1))
+#define HSIO_SD_CFG_RX_ALIGN_EN_M                GENMASK(1, 1)
+#define HSIO_SD_CFG_RX_ALIGN_EN_X(x)             (((x) & GENMASK(1, 1)) >> 1)
+
+#define HSIO_SD_CFG_LANE_LOOPBK_EN(x)            ((x) & GENMASK(0, 0))
+#define HSIO_SD_CFG_LANE_LOOPBK_EN_M             GENMASK(0, 0)
+#define HSIO_SD_CFG_LANE_LOOPBK_EN_X(x)          ((x) & GENMASK(0, 0))
+
+/*      HSIO:SD:SD_CFG2 */
+#define HSIO_SD_CFG2(g)           __REG(TARGET_HSIO,\
+					0, 1, 8, g, 3, 32, 4, 0, 1, 4)
+
+#define HSIO_SD_CFG2_RX_EQ(x)                    (((x) << 25) & GENMASK(27, 25))
+#define HSIO_SD_CFG2_RX_EQ_M                     GENMASK(27, 25)
+#define HSIO_SD_CFG2_RX_EQ_X(x)                  (((x) & GENMASK(27, 25)) >> 25)
+
+#define HSIO_SD_CFG2_TX_TERM_OFFSET(x)           (((x) << 20) & GENMASK(24, 20))
+#define HSIO_SD_CFG2_TX_TERM_OFFSET_M            GENMASK(24, 20)
+#define HSIO_SD_CFG2_TX_TERM_OFFSET_X(x)         (((x) & GENMASK(24, 20)) >> 20)
+
+#define HSIO_SD_CFG2_TX_VBOOST_LVL(x)            (((x) << 17) & GENMASK(19, 17))
+#define HSIO_SD_CFG2_TX_VBOOST_LVL_M             GENMASK(19, 17)
+#define HSIO_SD_CFG2_TX_VBOOST_LVL_X(x)          (((x) & GENMASK(19, 17)) >> 17)
+
+#define HSIO_SD_CFG2_LOS_BIAS(x)                 (((x) << 14) & GENMASK(16, 14))
+#define HSIO_SD_CFG2_LOS_BIAS_M                  GENMASK(16, 14)
+#define HSIO_SD_CFG2_LOS_BIAS_X(x)               (((x) & GENMASK(16, 14)) >> 14)
+
+#define HSIO_SD_CFG2_TX_AMPLITUDE(x)             (((x) << 7) & GENMASK(13, 7))
+#define HSIO_SD_CFG2_TX_AMPLITUDE_M              GENMASK(13, 7)
+#define HSIO_SD_CFG2_TX_AMPLITUDE_X(x)           (((x) & GENMASK(13, 7)) >> 7)
+
+#define HSIO_SD_CFG2_TX_PREEMPH(x)               ((x) & GENMASK(6, 0))
+#define HSIO_SD_CFG2_TX_PREEMPH_M                GENMASK(6, 0)
+#define HSIO_SD_CFG2_TX_PREEMPH_X(x)             ((x) & GENMASK(6, 0))
+
+/*      HSIO:SD:MPLL_CFG */
+#define HSIO_MPLL_CFG(g)          __REG(TARGET_HSIO,\
+					0, 1, 8, g, 3, 32, 8, 0, 1, 4)
+
+#define HSIO_MPLL_CFG_REF_SSP_EN(x)              (((x) << 18) & GENMASK(18, 18))
+#define HSIO_MPLL_CFG_REF_SSP_EN_M               GENMASK(18, 18)
+#define HSIO_MPLL_CFG_REF_SSP_EN_X(x)            (((x) & GENMASK(18, 18)) >> 18)
+
+#define HSIO_MPLL_CFG_REF_CLKDIV2(x)             (((x) << 17) & GENMASK(17, 17))
+#define HSIO_MPLL_CFG_REF_CLKDIV2_M              GENMASK(17, 17)
+#define HSIO_MPLL_CFG_REF_CLKDIV2_X(x)           (((x) & GENMASK(17, 17)) >> 17)
+
+#define HSIO_MPLL_CFG_MPLL_EN(x)                 (((x) << 16) & GENMASK(16, 16))
+#define HSIO_MPLL_CFG_MPLL_EN_M                  GENMASK(16, 16)
+#define HSIO_MPLL_CFG_MPLL_EN_X(x)               (((x) & GENMASK(16, 16)) >> 16)
+
+#define HSIO_MPLL_CFG_SSC_REF_CLK_SEL(x)         (((x) << 7) & GENMASK(15, 7))
+#define HSIO_MPLL_CFG_SSC_REF_CLK_SEL_M          GENMASK(15, 7)
+#define HSIO_MPLL_CFG_SSC_REF_CLK_SEL_X(x)       (((x) & GENMASK(15, 7)) >> 7)
+
+#define HSIO_MPLL_CFG_MPLL_MULTIPLIER(x)         ((x) & GENMASK(6, 0))
+#define HSIO_MPLL_CFG_MPLL_MULTIPLIER_M          GENMASK(6, 0)
+#define HSIO_MPLL_CFG_MPLL_MULTIPLIER_X(x)       ((x) & GENMASK(6, 0))
+
+/*      HSIO:SD:SD_STAT */
+#define HSIO_SD_STAT(g)           __REG(TARGET_HSIO,\
+					0, 1, 8, g, 3, 32, 12, 0, 1, 4)
+
+#define HSIO_SD_STAT_MPLL_STATE(x)               (((x) << 6) & GENMASK(6, 6))
+#define HSIO_SD_STAT_MPLL_STATE_M                GENMASK(6, 6)
+#define HSIO_SD_STAT_MPLL_STATE_X(x)             (((x) & GENMASK(6, 6)) >> 6)
+
+#define HSIO_SD_STAT_TX_STATE(x)                 (((x) << 5) & GENMASK(5, 5))
+#define HSIO_SD_STAT_TX_STATE_M                  GENMASK(5, 5)
+#define HSIO_SD_STAT_TX_STATE_X(x)               (((x) & GENMASK(5, 5)) >> 5)
+
+#define HSIO_SD_STAT_TX_DETECT_RX_RESULT(x)      (((x) << 4) & GENMASK(4, 4))
+#define HSIO_SD_STAT_TX_DETECT_RX_RESULT_M       GENMASK(4, 4)
+#define HSIO_SD_STAT_TX_DETECT_RX_RESULT_X(x)    (((x) & GENMASK(4, 4)) >> 4)
+
+#define HSIO_SD_STAT_TX_DETECT_RX_ACK(x)         (((x) << 3) & GENMASK(3, 3))
+#define HSIO_SD_STAT_TX_DETECT_RX_ACK_M          GENMASK(3, 3)
+#define HSIO_SD_STAT_TX_DETECT_RX_ACK_X(x)       (((x) & GENMASK(3, 3)) >> 3)
+
+#define HSIO_SD_STAT_TX_CM_STATE(x)              (((x) << 2) & GENMASK(2, 2))
+#define HSIO_SD_STAT_TX_CM_STATE_M               GENMASK(2, 2)
+#define HSIO_SD_STAT_TX_CM_STATE_X(x)            (((x) & GENMASK(2, 2)) >> 2)
+
+#define HSIO_SD_STAT_RX_VALID(x)                 (((x) << 1) & GENMASK(1, 1))
+#define HSIO_SD_STAT_RX_VALID_M                  GENMASK(1, 1)
+#define HSIO_SD_STAT_RX_VALID_X(x)               (((x) & GENMASK(1, 1)) >> 1)
+
+#define HSIO_SD_STAT_RX_PLL_STATE(x)             ((x) & GENMASK(0, 0))
+#define HSIO_SD_STAT_RX_PLL_STATE_M              GENMASK(0, 0)
+#define HSIO_SD_STAT_RX_PLL_STATE_X(x)           ((x) & GENMASK(0, 0))
+
+/*      HSIO:SD:CR_ACCESS */
+#define HSIO_CR_ACCESS(g)         __REG(TARGET_HSIO,\
+					0, 1, 8, g, 3, 32, 16, 0, 1, 4)
+
+#define HSIO_CR_ACCESS_WRITE(x)                  (((x) << 19) & GENMASK(19, 19))
+#define HSIO_CR_ACCESS_WRITE_M                   GENMASK(19, 19)
+#define HSIO_CR_ACCESS_WRITE_X(x)                (((x) & GENMASK(19, 19)) >> 19)
+
+#define HSIO_CR_ACCESS_READ(x)                   (((x) << 18) & GENMASK(18, 18))
+#define HSIO_CR_ACCESS_READ_M                    GENMASK(18, 18)
+#define HSIO_CR_ACCESS_READ_X(x)                 (((x) & GENMASK(18, 18)) >> 18)
+
+#define HSIO_CR_ACCESS_CAP_DATA(x)               (((x) << 17) & GENMASK(17, 17))
+#define HSIO_CR_ACCESS_CAP_DATA_M                GENMASK(17, 17)
+#define HSIO_CR_ACCESS_CAP_DATA_X(x)             (((x) & GENMASK(17, 17)) >> 17)
+
+#define HSIO_CR_ACCESS_CAP_ADDR(x)               (((x) << 16) & GENMASK(16, 16))
+#define HSIO_CR_ACCESS_CAP_ADDR_M                GENMASK(16, 16)
+#define HSIO_CR_ACCESS_CAP_ADDR_X(x)             (((x) & GENMASK(16, 16)) >> 16)
+
+#define HSIO_CR_ACCESS_DATA_IN(x)                ((x) & GENMASK(15, 0))
+#define HSIO_CR_ACCESS_DATA_IN_M                 GENMASK(15, 0)
+#define HSIO_CR_ACCESS_DATA_IN_X(x)              ((x) & GENMASK(15, 0))
+
+/*      HSIO:SD:CR_OUTPUT */
+#define HSIO_CR_OUTPUT(g)         __REG(TARGET_HSIO,\
+					0, 1, 8, g, 3, 32, 20, 0, 1, 4)
+
+#define HSIO_CR_OUTPUT_ACK(x)                    (((x) << 16) & GENMASK(16, 16))
+#define HSIO_CR_OUTPUT_ACK_M                     GENMASK(16, 16)
+#define HSIO_CR_OUTPUT_ACK_X(x)                  (((x) & GENMASK(16, 16)) >> 16)
+
+#define HSIO_CR_OUTPUT_DATA_OUT(x)               ((x) & GENMASK(15, 0))
+#define HSIO_CR_OUTPUT_DATA_OUT_M                GENMASK(15, 0)
+#define HSIO_CR_OUTPUT_DATA_OUT_X(x)             ((x) & GENMASK(15, 0))
+
+/*      HSIO:SD:SYNC_ETH_SD_CFG */
+#define HSIO_SYNC_ETH_SD_CFG(g)   __REG(TARGET_HSIO,\
+					0, 1, 8, g, 3, 32, 24, 0, 1, 4)
+
+#define HSIO_SYNC_ETH_SD_CFG_SD_RECO_CLK_DIV(x)  (((x) << 4) & GENMASK(5, 4))
+#define HSIO_SYNC_ETH_SD_CFG_SD_RECO_CLK_DIV_M   GENMASK(5, 4)
+#define HSIO_SYNC_ETH_SD_CFG_SD_RECO_CLK_DIV_X(x) (((x) & GENMASK(5, 4)) >> 4)
+
+#define HSIO_SYNC_ETH_SD_CFG_SD_LINK_STAT_ENA(x) (((x) << 1) & GENMASK(1, 1))
+#define HSIO_SYNC_ETH_SD_CFG_SD_LINK_STAT_ENA_M  GENMASK(1, 1)
+#define HSIO_SYNC_ETH_SD_CFG_SD_LINK_STAT_ENA_X(x) (((x) & GENMASK(1, 1)) >> 1)
+
+#define HSIO_SYNC_ETH_SD_CFG_SD_AUTO_SQUELCH_ENA(x) ((x) & GENMASK(0, 0))
+#define HSIO_SYNC_ETH_SD_CFG_SD_AUTO_SQUELCH_ENA_M GENMASK(0, 0)
+#define HSIO_SYNC_ETH_SD_CFG_SD_AUTO_SQUELCH_ENA_X(x) ((x) & GENMASK(0, 0))
+
+/*      HSIO:SD:SIGDET_CFG */
+#define HSIO_SIGDET_CFG(g)        __REG(TARGET_HSIO,\
+					0, 1, 8, g, 3, 32, 28, 0, 1, 4)
+
+#define HSIO_SIGDET_CFG_SD_SEL(x)                (((x) << 2) & GENMASK(2, 2))
+#define HSIO_SIGDET_CFG_SD_SEL_M                 GENMASK(2, 2)
+#define HSIO_SIGDET_CFG_SD_SEL_X(x)              (((x) & GENMASK(2, 2)) >> 2)
+
+#define HSIO_SIGDET_CFG_SD_POL(x)                (((x) << 1) & GENMASK(1, 1))
+#define HSIO_SIGDET_CFG_SD_POL_M                 GENMASK(1, 1)
+#define HSIO_SIGDET_CFG_SD_POL_X(x)              (((x) & GENMASK(1, 1)) >> 1)
+
+#define HSIO_SIGDET_CFG_SD_ENA(x)                ((x) & GENMASK(0, 0))
+#define HSIO_SIGDET_CFG_SD_ENA_M                 GENMASK(0, 0)
+#define HSIO_SIGDET_CFG_SD_ENA_X(x)              ((x) & GENMASK(0, 0))
+
+/*      HSIO:HW_CFGSTAT:HW_CFG */
+#define HSIO_HW_CFG               __REG(TARGET_HSIO,\
+					0, 1, 104, 0, 1, 52, 0, 0, 1, 4)
+
+#define HSIO_HW_CFG_RGMII_1_CFG(x)               (((x) << 15) & GENMASK(15, 15))
+#define HSIO_HW_CFG_RGMII_1_CFG_M                GENMASK(15, 15)
+#define HSIO_HW_CFG_RGMII_1_CFG_X(x)             (((x) & GENMASK(15, 15)) >> 15)
+
+#define HSIO_HW_CFG_RGMII_0_CFG(x)               (((x) << 14) & GENMASK(14, 14))
+#define HSIO_HW_CFG_RGMII_0_CFG_M                GENMASK(14, 14)
+#define HSIO_HW_CFG_RGMII_0_CFG_X(x)             (((x) & GENMASK(14, 14)) >> 14)
+
+#define HSIO_HW_CFG_RGMII_ENA(x)                 (((x) << 12) & GENMASK(13, 12))
+#define HSIO_HW_CFG_RGMII_ENA_M                  GENMASK(13, 12)
+#define HSIO_HW_CFG_RGMII_ENA_X(x)               (((x) & GENMASK(13, 12)) >> 12)
+
+#define HSIO_HW_CFG_SD6G_0_CFG(x)                (((x) << 11) & GENMASK(11, 11))
+#define HSIO_HW_CFG_SD6G_0_CFG_M                 GENMASK(11, 11)
+#define HSIO_HW_CFG_SD6G_0_CFG_X(x)              (((x) & GENMASK(11, 11)) >> 11)
+
+#define HSIO_HW_CFG_SD6G_1_CFG(x)                (((x) << 10) & GENMASK(10, 10))
+#define HSIO_HW_CFG_SD6G_1_CFG_M                 GENMASK(10, 10)
+#define HSIO_HW_CFG_SD6G_1_CFG_X(x)              (((x) & GENMASK(10, 10)) >> 10)
+
+#define HSIO_HW_CFG_GMII_ENA(x)                  (((x) << 2) & GENMASK(9, 2))
+#define HSIO_HW_CFG_GMII_ENA_M                   GENMASK(9, 2)
+#define HSIO_HW_CFG_GMII_ENA_X(x)                (((x) & GENMASK(9, 2)) >> 2)
+
+#define HSIO_HW_CFG_QSGMII_ENA(x)                ((x) & GENMASK(1, 0))
+#define HSIO_HW_CFG_QSGMII_ENA_M                 GENMASK(1, 0)
+#define HSIO_HW_CFG_QSGMII_ENA_X(x)              ((x) & GENMASK(1, 0))
+
+/*      HSIO:HW_CFGSTAT:GPIO_PI_CFG */
+#define HSIO_GPIO_PI_CFG          __REG(TARGET_HSIO,\
+					0, 1, 104, 0, 1, 52, 4, 0, 1, 4)
+
+#define HSIO_GPIO_PI_CFG_PI_MUX_ENA(x)           ((x) & GENMASK(26, 0))
+#define HSIO_GPIO_PI_CFG_PI_MUX_ENA_M            GENMASK(26, 0)
+#define HSIO_GPIO_PI_CFG_PI_MUX_ENA_X(x)         ((x) & GENMASK(26, 0))
+
+/*      HSIO:HW_CFGSTAT:QSGMII_CFG */
+#define HSIO_QSGMII_CFG           __REG(TARGET_HSIO,\
+					0, 1, 104, 0, 1, 52, 8, 0, 1, 4)
+
+#define HSIO_QSGMII_CFG_SHYST_DIS(x)             (((x) << 4) & GENMASK(4, 4))
+#define HSIO_QSGMII_CFG_SHYST_DIS_M              GENMASK(4, 4)
+#define HSIO_QSGMII_CFG_SHYST_DIS_X(x)           (((x) & GENMASK(4, 4)) >> 4)
+
+#define HSIO_QSGMII_CFG_E_DET_ENA(x)             (((x) << 3) & GENMASK(3, 3))
+#define HSIO_QSGMII_CFG_E_DET_ENA_M              GENMASK(3, 3)
+#define HSIO_QSGMII_CFG_E_DET_ENA_X(x)           (((x) & GENMASK(3, 3)) >> 3)
+
+#define HSIO_QSGMII_CFG_USE_I1_ENA(x)            (((x) << 2) & GENMASK(2, 2))
+#define HSIO_QSGMII_CFG_USE_I1_ENA_M             GENMASK(2, 2)
+#define HSIO_QSGMII_CFG_USE_I1_ENA_X(x)          (((x) & GENMASK(2, 2)) >> 2)
+
+#define HSIO_QSGMII_CFG_FLIP_LANES(x)            ((x) & GENMASK(1, 0))
+#define HSIO_QSGMII_CFG_FLIP_LANES_M             GENMASK(1, 0)
+#define HSIO_QSGMII_CFG_FLIP_LANES_X(x)          ((x) & GENMASK(1, 0))
+
+/*      HSIO:HW_CFGSTAT:QSGMII_STAT */
+#define HSIO_QSGMII_STAT(r)       __REG(TARGET_HSIO,\
+					0, 1, 104, 0, 1, 52, 12, r, 2, 4)
+
+#define HSIO_QSGMII_STAT_DELAY_VAR_X200PS(x)     (((x) << 2) & GENMASK(7, 2))
+#define HSIO_QSGMII_STAT_DELAY_VAR_X200PS_M      GENMASK(7, 2)
+#define HSIO_QSGMII_STAT_DELAY_VAR_X200PS_X(x)   (((x) & GENMASK(7, 2)) >> 2)
+
+#define HSIO_QSGMII_STAT_SYNC(x)                 ((x) & GENMASK(1, 0))
+#define HSIO_QSGMII_STAT_SYNC_M                  GENMASK(1, 0)
+#define HSIO_QSGMII_STAT_SYNC_X(x)               ((x) & GENMASK(1, 0))
+
+/*      HSIO:HW_CFGSTAT:RGMII_CFG */
+#define HSIO_RGMII_CFG(r)         __REG(TARGET_HSIO,\
+					0, 1, 104, 0, 1, 52, 20, r, 2, 4)
+
+#define HSIO_RGMII_CFG_IB_RX_LINK_STATUS(x)      (((x) << 15) & GENMASK(15, 15))
+#define HSIO_RGMII_CFG_IB_RX_LINK_STATUS_M       GENMASK(15, 15)
+#define HSIO_RGMII_CFG_IB_RX_LINK_STATUS_X(x)    (((x) & GENMASK(15, 15)) >> 15)
+
+#define HSIO_RGMII_CFG_IB_RX_DUPLEX(x)           (((x) << 14) & GENMASK(14, 14))
+#define HSIO_RGMII_CFG_IB_RX_DUPLEX_M            GENMASK(14, 14)
+#define HSIO_RGMII_CFG_IB_RX_DUPLEX_X(x)         (((x) & GENMASK(14, 14)) >> 14)
+
+#define HSIO_RGMII_CFG_IB_RX_SPEED(x)            (((x) << 12) & GENMASK(13, 12))
+#define HSIO_RGMII_CFG_IB_RX_SPEED_M             GENMASK(13, 12)
+#define HSIO_RGMII_CFG_IB_RX_SPEED_X(x)          (((x) & GENMASK(13, 12)) >> 12)
+
+#define HSIO_RGMII_CFG_IB_TX_LINK_STATUS(x)      (((x) << 11) & GENMASK(11, 11))
+#define HSIO_RGMII_CFG_IB_TX_LINK_STATUS_M       GENMASK(11, 11)
+#define HSIO_RGMII_CFG_IB_TX_LINK_STATUS_X(x)    (((x) & GENMASK(11, 11)) >> 11)
+
+#define HSIO_RGMII_CFG_IB_TX_FDX(x)              (((x) << 10) & GENMASK(10, 10))
+#define HSIO_RGMII_CFG_IB_TX_FDX_M               GENMASK(10, 10)
+#define HSIO_RGMII_CFG_IB_TX_FDX_X(x)            (((x) & GENMASK(10, 10)) >> 10)
+
+#define HSIO_RGMII_CFG_IB_TX_MII_SPD(x)          (((x) << 9) & GENMASK(9, 9))
+#define HSIO_RGMII_CFG_IB_TX_MII_SPD_M           GENMASK(9, 9)
+#define HSIO_RGMII_CFG_IB_TX_MII_SPD_X(x)        (((x) & GENMASK(9, 9)) >> 9)
+
+#define HSIO_RGMII_CFG_IB_TX_SPD_1G(x)           (((x) << 8) & GENMASK(8, 8))
+#define HSIO_RGMII_CFG_IB_TX_SPD_1G_M            GENMASK(8, 8)
+#define HSIO_RGMII_CFG_IB_TX_SPD_1G_X(x)         (((x) & GENMASK(8, 8)) >> 8)
+
+#define HSIO_RGMII_CFG_IB_TX_ENA(x)              (((x) << 7) & GENMASK(7, 7))
+#define HSIO_RGMII_CFG_IB_TX_ENA_M               GENMASK(7, 7)
+#define HSIO_RGMII_CFG_IB_TX_ENA_X(x)            (((x) & GENMASK(7, 7)) >> 7)
+
+#define HSIO_RGMII_CFG_IB_RX_ENA(x)              (((x) << 6) & GENMASK(6, 6))
+#define HSIO_RGMII_CFG_IB_RX_ENA_M               GENMASK(6, 6)
+#define HSIO_RGMII_CFG_IB_RX_ENA_X(x)            (((x) & GENMASK(6, 6)) >> 6)
+
+#define HSIO_RGMII_CFG_IB_ENA(x)                 (((x) << 5) & GENMASK(5, 5))
+#define HSIO_RGMII_CFG_IB_ENA_M                  GENMASK(5, 5)
+#define HSIO_RGMII_CFG_IB_ENA_X(x)               (((x) & GENMASK(5, 5)) >> 5)
+
+#define HSIO_RGMII_CFG_TX_CLK_CFG(x)             (((x) << 2) & GENMASK(4, 2))
+#define HSIO_RGMII_CFG_TX_CLK_CFG_M              GENMASK(4, 2)
+#define HSIO_RGMII_CFG_TX_CLK_CFG_X(x)           (((x) & GENMASK(4, 2)) >> 2)
+
+#define HSIO_RGMII_CFG_RGMII_TX_RST(x)           (((x) << 1) & GENMASK(1, 1))
+#define HSIO_RGMII_CFG_RGMII_TX_RST_M            GENMASK(1, 1)
+#define HSIO_RGMII_CFG_RGMII_TX_RST_X(x)         (((x) & GENMASK(1, 1)) >> 1)
+
+#define HSIO_RGMII_CFG_RGMII_RX_RST(x)           ((x) & GENMASK(0, 0))
+#define HSIO_RGMII_CFG_RGMII_RX_RST_M            GENMASK(0, 0)
+#define HSIO_RGMII_CFG_RGMII_RX_RST_X(x)         ((x) & GENMASK(0, 0))
+
+/*      HSIO:HW_CFGSTAT:RMII_CFG */
+#define HSIO_RMII_CFG(r)          __REG(TARGET_HSIO,\
+					0, 1, 104, 0, 1, 52, 28, r, 2, 4)
+
+#define HSIO_RMII_CFG_REF_CLK_SEL(x)             (((x) << 6) & GENMASK(6, 6))
+#define HSIO_RMII_CFG_REF_CLK_SEL_M              GENMASK(6, 6)
+#define HSIO_RMII_CFG_REF_CLK_SEL_X(x)           (((x) & GENMASK(6, 6)) >> 6)
+
+#define HSIO_RMII_CFG_CFG_TX_EDGE(x)             (((x) << 5) & GENMASK(5, 5))
+#define HSIO_RMII_CFG_CFG_TX_EDGE_M              GENMASK(5, 5)
+#define HSIO_RMII_CFG_CFG_TX_EDGE_X(x)           (((x) & GENMASK(5, 5)) >> 5)
+
+#define HSIO_RMII_CFG_FDX_CFG(x)                 (((x) << 4) & GENMASK(4, 4))
+#define HSIO_RMII_CFG_FDX_CFG_M                  GENMASK(4, 4)
+#define HSIO_RMII_CFG_FDX_CFG_X(x)               (((x) & GENMASK(4, 4)) >> 4)
+
+#define HSIO_RMII_CFG_SPEED_CFG(x)               (((x) << 3) & GENMASK(3, 3))
+#define HSIO_RMII_CFG_SPEED_CFG_M                GENMASK(3, 3)
+#define HSIO_RMII_CFG_SPEED_CFG_X(x)             (((x) & GENMASK(3, 3)) >> 3)
+
+#define HSIO_RMII_CFG_RMII_TX_RST(x)             (((x) << 2) & GENMASK(2, 2))
+#define HSIO_RMII_CFG_RMII_TX_RST_M              GENMASK(2, 2)
+#define HSIO_RMII_CFG_RMII_TX_RST_X(x)           (((x) & GENMASK(2, 2)) >> 2)
+
+#define HSIO_RMII_CFG_RMII_RX_RST(x)             (((x) << 1) & GENMASK(1, 1))
+#define HSIO_RMII_CFG_RMII_RX_RST_M              GENMASK(1, 1)
+#define HSIO_RMII_CFG_RMII_RX_RST_X(x)           (((x) & GENMASK(1, 1)) >> 1)
+
+#define HSIO_RMII_CFG_RMII_ENA(x)                ((x) & GENMASK(0, 0))
+#define HSIO_RMII_CFG_RMII_ENA_M                 GENMASK(0, 0)
+#define HSIO_RMII_CFG_RMII_ENA_X(x)              ((x) & GENMASK(0, 0))
+
+/*      HSIO:HW_CFGSTAT:DLL_CFG */
+#define HSIO_DLL_CFG(r)           __REG(TARGET_HSIO,\
+					0, 1, 104, 0, 1, 52, 36, r, 4, 4)
+
+#define HSIO_DLL_CFG_DLL_CLK_ENA(x)              (((x) << 20) & GENMASK(20, 20))
+#define HSIO_DLL_CFG_DLL_CLK_ENA_M               GENMASK(20, 20)
+#define HSIO_DLL_CFG_DLL_CLK_ENA_X(x)            (((x) & GENMASK(20, 20)) >> 20)
+
+#define HSIO_DLL_CFG_BIST_PASS(x)                (((x) << 19) & GENMASK(19, 19))
+#define HSIO_DLL_CFG_BIST_PASS_M                 GENMASK(19, 19)
+#define HSIO_DLL_CFG_BIST_PASS_X(x)              (((x) & GENMASK(19, 19)) >> 19)
+
+#define HSIO_DLL_CFG_BIST_END(x)                 (((x) << 18) & GENMASK(18, 18))
+#define HSIO_DLL_CFG_BIST_END_M                  GENMASK(18, 18)
+#define HSIO_DLL_CFG_BIST_END_X(x)               (((x) & GENMASK(18, 18)) >> 18)
+
+#define HSIO_DLL_CFG_BIST_START(x)               (((x) << 17) & GENMASK(17, 17))
+#define HSIO_DLL_CFG_BIST_START_M                GENMASK(17, 17)
+#define HSIO_DLL_CFG_BIST_START_X(x)             (((x) & GENMASK(17, 17)) >> 17)
+
+#define HSIO_DLL_CFG_TAP_SEL(x)                  (((x) << 10) & GENMASK(16, 10))
+#define HSIO_DLL_CFG_TAP_SEL_M                   GENMASK(16, 10)
+#define HSIO_DLL_CFG_TAP_SEL_X(x)                (((x) & GENMASK(16, 10)) >> 10)
+
+#define HSIO_DLL_CFG_TAP_ADJ(x)                  (((x) << 3) & GENMASK(9, 3))
+#define HSIO_DLL_CFG_TAP_ADJ_M                   GENMASK(9, 3)
+#define HSIO_DLL_CFG_TAP_ADJ_X(x)                (((x) & GENMASK(9, 3)) >> 3)
+
+#define HSIO_DLL_CFG_DELAY_ENA(x)                (((x) << 2) & GENMASK(2, 2))
+#define HSIO_DLL_CFG_DELAY_ENA_M                 GENMASK(2, 2)
+#define HSIO_DLL_CFG_DELAY_ENA_X(x)              (((x) & GENMASK(2, 2)) >> 2)
+
+#define HSIO_DLL_CFG_DLL_ENA(x)                  (((x) << 1) & GENMASK(1, 1))
+#define HSIO_DLL_CFG_DLL_ENA_M                   GENMASK(1, 1)
+#define HSIO_DLL_CFG_DLL_ENA_X(x)                (((x) & GENMASK(1, 1)) >> 1)
+
+#define HSIO_DLL_CFG_DLL_RST(x)                  ((x) & GENMASK(0, 0))
+#define HSIO_DLL_CFG_DLL_RST_M                   GENMASK(0, 0)
+#define HSIO_DLL_CFG_DLL_RST_X(x)                ((x) & GENMASK(0, 0))
+
+#endif /* _LAN966X_HSIO_REGS_H_ */
diff --git a/include/dt-bindings/phy/lan966x_serdes.h b/include/dt-bindings/phy/lan966x_serdes.h
new file mode 100644
index 000000000000..0e2097b1bfcf
--- /dev/null
+++ b/include/dt-bindings/phy/lan966x_serdes.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
+
+#ifndef __PHY_LAN966X_SERDES_H__
+#define __PHY_LAN966X_SERDES_H__
+
+#define CU(x)		(x)
+#define CU_MAX		CU(2)
+#define SERDES6G(x)	(CU_MAX + 1 + (x))
+#define SERDES6G_MAX	SERDES6G(3)
+#define RG(x)		(SERDES6G_MAX + 1 + (x))
+#define RG_MAX		RG(2)
+#define SERDES_MAX	(RG_MAX + 1)
+
+#endif
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [RFC PATCH net-next 04/12] dt-bindings: reset: Add lan966x switch reset bindings
  2021-09-20  9:52 [RFC PATCH net-next 00/12] Add lan966x driver Horatiu Vultur
                   ` (2 preceding siblings ...)
  2021-09-20  9:52 ` [RFC PATCH net-next 03/12] phy: Add lan966x ethernet serdes PHY driver Horatiu Vultur
@ 2021-09-20  9:52 ` Horatiu Vultur
  2021-09-23 12:49   ` Rob Herring
  2021-09-20  9:52 ` [RFC PATCH net-next 05/12] reset: lan966x: Add switch reset driver Horatiu Vultur
                   ` (7 subsequent siblings)
  11 siblings, 1 reply; 30+ messages in thread
From: Horatiu Vultur @ 2021-09-20  9:52 UTC (permalink / raw)
  To: davem, kuba, robh+dt, andrew, linux, f.fainelli,
	alexandre.belloni, vladimir.oltean, UNGLinuxDriver, netdev,
	devicetree, linux-kernel, linux-phy, linux-pm
  Cc: Horatiu Vultur

Document the lan966x switch reset device driver bindings

Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
---
 .../bindings/reset/lan966x,rst.yaml           | 58 +++++++++++++++++++
 1 file changed, 58 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/reset/lan966x,rst.yaml

diff --git a/Documentation/devicetree/bindings/reset/lan966x,rst.yaml b/Documentation/devicetree/bindings/reset/lan966x,rst.yaml
new file mode 100644
index 000000000000..97d6334e4e0a
--- /dev/null
+++ b/Documentation/devicetree/bindings/reset/lan966x,rst.yaml
@@ -0,0 +1,58 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/reset/lan966x,rst.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: Microchip lan966x Switch Reset Controller
+
+maintainers:
+  - Horatiu Vultur <horatiu.vultur@microchip.com>
+  - UNGLinuxDriver@microchip.com
+
+description: |
+  The Microchip lan966x Switch provides reset control and implements the
+  following
+  functions
+    - One Time Switch Core Reset (Soft Reset)
+
+properties:
+  $nodename:
+    pattern: "^reset-controller$"
+
+  compatible:
+    const: microchip,lan966x-switch-reset
+
+  "#reset-cells":
+    const: 1
+
+  cpu-syscon:
+    $ref: "/schemas/types.yaml#/definitions/phandle"
+    description: syscon used to access CPU reset
+
+  switch-syscon:
+    $ref: "/schemas/types.yaml#/definitions/phandle"
+    description: syscon used to access SWITCH reset
+
+  chip-syscon:
+    $ref: "/schemas/types.yaml#/definitions/phandle"
+    description: syscon used to access CHIP reset
+
+required:
+  - compatible
+  - "#reset-cells"
+  - cpu-syscon
+  - switch-syscon
+  - chip-syscon
+
+additionalProperties: false
+
+examples:
+  - |
+    reset: reset-controller {
+        compatible = "microchip,lan966x-switch-reset";
+        #reset-cells = <1>;
+        cpu-syscon = <&cpu_ctrl>;
+        switch-syscon = <&switch_ctrl>;
+        chip-syscon = <&chip_ctrl>;
+    };
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [RFC PATCH net-next 05/12] reset: lan966x: Add switch reset driver
  2021-09-20  9:52 [RFC PATCH net-next 00/12] Add lan966x driver Horatiu Vultur
                   ` (3 preceding siblings ...)
  2021-09-20  9:52 ` [RFC PATCH net-next 04/12] dt-bindings: reset: Add lan966x switch reset bindings Horatiu Vultur
@ 2021-09-20  9:52 ` Horatiu Vultur
  2021-09-20 12:11   ` Andrew Lunn
  2021-09-20  9:52 ` [RFC PATCH net-next 06/12] dt-bindings: reset: Add lan966x power reset bindings Horatiu Vultur
                   ` (6 subsequent siblings)
  11 siblings, 1 reply; 30+ messages in thread
From: Horatiu Vultur @ 2021-09-20  9:52 UTC (permalink / raw)
  To: davem, kuba, robh+dt, andrew, linux, f.fainelli,
	alexandre.belloni, vladimir.oltean, UNGLinuxDriver, netdev,
	devicetree, linux-kernel, linux-phy, linux-pm
  Cc: Horatiu Vultur

The lan966x switch SoC has a number of components that can be reset
indiviually, but at least the switch core needs to be in a well defined
state at power on, when any of the lan966x drivers starts to access the
switch core, this reset driver is available.

The reset driver is loaded early via the postcore_initcall interface, and
will then be available for the other lan966x drivers (SGPIO, SwitchDev etc)
that are loaded next, and the first of them to be loaded can perform the
one-time switch core reset that is needed.

Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
---
 drivers/reset/Kconfig         |   8 +++
 drivers/reset/Makefile        |   1 +
 drivers/reset/reset-lan966x.c | 128 ++++++++++++++++++++++++++++++++++
 3 files changed, 137 insertions(+)
 create mode 100644 drivers/reset/reset-lan966x.c

diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index be799a5abf8a..93f19303ebac 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -108,6 +108,14 @@ config RESET_LANTIQ
 	help
 	  This enables the reset controller driver for Lantiq / Intel XWAY SoCs.
 
+config RESET_LAN966X
+	bool "Microchip LAN966X Reset Driver"
+	depends on HAS_IOMEM || COMPILE_TEST
+	default y if LAN966X_SWITCH
+	select MFD_SYSCON
+	help
+	  This driver supports switch core reset for the Microchip LAN966X SoC.
+
 config RESET_LPC18XX
 	bool "LPC18xx/43xx Reset Driver" if COMPILE_TEST
 	default ARCH_LPC18XX
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index 21d46d8869ff..3358f491e617 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_RESET_HSDK) += reset-hsdk.o
 obj-$(CONFIG_RESET_IMX7) += reset-imx7.o
 obj-$(CONFIG_RESET_INTEL_GW) += reset-intel-gw.o
 obj-$(CONFIG_RESET_K210) += reset-k210.o
+obj-$(CONFIG_RESET_LAN966X) += reset-lan966x.o
 obj-$(CONFIG_RESET_LANTIQ) += reset-lantiq.o
 obj-$(CONFIG_RESET_LPC18XX) += reset-lpc18xx.o
 obj-$(CONFIG_RESET_MCHP_SPARX5) += reset-microchip-sparx5.o
diff --git a/drivers/reset/reset-lan966x.c b/drivers/reset/reset-lan966x.c
new file mode 100644
index 000000000000..3d4fe31653db
--- /dev/null
+++ b/drivers/reset/reset-lan966x.c
@@ -0,0 +1,128 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* Copyright (c) 2021 Microchip Technology Inc. and its subsidiaries. */
+
+#include <linux/mfd/syscon.h>
+#include <linux/of_device.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/reset-controller.h>
+
+#define PROTECT_REG    0x88
+#define PROTECT_BIT    BIT(5)
+#define SOFT_RESET_REG 0x00
+#define SOFT_RESET_BIT BIT(1)
+#define CHIP_COMMON_REG 0x10
+#define CHIP_COMMON_BIT BIT(0)
+
+struct mchp_reset_context {
+	struct regmap *cpu_ctrl;
+	struct regmap *switch_ctrl;
+	struct regmap *chip_ctrl;
+	struct reset_controller_dev rcdev;
+};
+
+static int lan966x_switch_reset(struct reset_controller_dev *rcdev,
+				unsigned long id)
+{
+	struct mchp_reset_context *ctx =
+		container_of(rcdev, struct mchp_reset_context, rcdev);
+	u32 val;
+	int ret;
+
+	/* Make sure the core is PROTECTED from reset */
+	regmap_update_bits(ctx->cpu_ctrl, PROTECT_REG, PROTECT_BIT, PROTECT_BIT);
+
+	/* Start soft reset */
+	regmap_write(ctx->switch_ctrl, SOFT_RESET_REG, SOFT_RESET_BIT);
+
+	/* Wait for soft reset done */
+	ret = regmap_read_poll_timeout(ctx->switch_ctrl, SOFT_RESET_REG, val,
+				       (val & SOFT_RESET_BIT) == 0, 1, 100);
+	if (ret)
+		return ret;
+
+	/* Release the reset of internal PHY */
+	regmap_update_bits(ctx->chip_ctrl, CHIP_COMMON_REG, CHIP_COMMON_BIT,
+			   CHIP_COMMON_BIT);
+
+	return 0;
+}
+
+static const struct reset_control_ops lan966x_reset_ops = {
+	.reset = lan966x_switch_reset,
+};
+
+static int mchp_lan966x_map_syscon(struct platform_device *pdev, char *name,
+				  struct regmap **target)
+{
+	struct device_node *syscon_np;
+	struct regmap *regmap;
+	int err;
+
+	syscon_np = of_parse_phandle(pdev->dev.of_node, name, 0);
+	if (!syscon_np)
+		return -ENODEV;
+	regmap = syscon_node_to_regmap(syscon_np);
+	of_node_put(syscon_np);
+	if (IS_ERR(regmap)) {
+		err = PTR_ERR(regmap);
+		dev_err(&pdev->dev, "No '%s' map: %d\n", name, err);
+		return err;
+	}
+
+	*target = regmap;
+	return 0;
+}
+
+static int mchp_lan966x_reset_probe(struct platform_device *pdev)
+{
+	struct device_node *dn = pdev->dev.of_node;
+	struct mchp_reset_context *ctx;
+	int err;
+
+	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	err = mchp_lan966x_map_syscon(pdev, "cpu-syscon", &ctx->cpu_ctrl);
+	if (err)
+		return err;
+
+	err = mchp_lan966x_map_syscon(pdev, "switch-syscon", &ctx->switch_ctrl);
+	if (err)
+		return err;
+
+	err = mchp_lan966x_map_syscon(pdev, "chip-syscon", &ctx->chip_ctrl);
+	if (err)
+		return err;
+
+	ctx->rcdev.owner = THIS_MODULE;
+	ctx->rcdev.nr_resets = 1;
+	ctx->rcdev.ops = &lan966x_reset_ops;
+	ctx->rcdev.of_node = dn;
+
+	return devm_reset_controller_register(&pdev->dev, &ctx->rcdev);
+}
+
+static const struct of_device_id mchp_lan966x_reset_of_match[] = {
+	{
+		.compatible = "microchip,lan966x-switch-reset",
+	},
+	{ }
+};
+
+static struct platform_driver mchp_lan966x_reset_driver = {
+	.probe = mchp_lan966x_reset_probe,
+	.driver = {
+		.name = "lan966x-switch-reset",
+		.of_match_table = mchp_lan966x_reset_of_match,
+	},
+};
+
+static int __init mchp_lan966x_reset_init(void)
+{
+	return platform_driver_register(&mchp_lan966x_reset_driver);
+}
+
+postcore_initcall(mchp_lan966x_reset_init);
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [RFC PATCH net-next 06/12] dt-bindings: reset: Add lan966x power reset bindings
  2021-09-20  9:52 [RFC PATCH net-next 00/12] Add lan966x driver Horatiu Vultur
                   ` (4 preceding siblings ...)
  2021-09-20  9:52 ` [RFC PATCH net-next 05/12] reset: lan966x: Add switch reset driver Horatiu Vultur
@ 2021-09-20  9:52 ` Horatiu Vultur
  2021-09-20  9:52 ` [RFC PATCH net-next 07/12] power: reset: Add lan966x power reset driver Horatiu Vultur
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 30+ messages in thread
From: Horatiu Vultur @ 2021-09-20  9:52 UTC (permalink / raw)
  To: davem, kuba, robh+dt, andrew, linux, f.fainelli,
	alexandre.belloni, vladimir.oltean, UNGLinuxDriver, netdev,
	devicetree, linux-kernel, linux-phy, linux-pm
  Cc: Horatiu Vultur

Document the lan966x power reset device driver bindings

Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
---
 .../bindings/power/lan966x,power.yaml         | 49 +++++++++++++++++++
 1 file changed, 49 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/power/lan966x,power.yaml

diff --git a/Documentation/devicetree/bindings/power/lan966x,power.yaml b/Documentation/devicetree/bindings/power/lan966x,power.yaml
new file mode 100644
index 000000000000..d10eec10089b
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/lan966x,power.yaml
@@ -0,0 +1,49 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/power/lan966x,power.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: Microchip Lan966x Power Reset Controller
+
+maintainers:
+  - Horatiu Vultur <horatiu.vultur@microchip.com>
+  - UNGLinuxDriver@microchip.com
+
+description: |
+  The Microchip Lan966x SoC provides power reset control.
+
+properties:
+  $nodename:
+    pattern: "^chip-controller$"
+
+  compatible:
+    const: microchip,lan966x-chip-reset
+
+  "#reset-cells":
+    const: 1
+
+  cpu-syscon:
+    $ref: "/schemas/types.yaml#/definitions/phandle"
+    description: syscon used to access CPU reset
+
+  switch-syscon:
+    $ref: "/schemas/types.yaml#/definitions/phandle"
+    description: syscon used to access SWITCH reset
+
+required:
+  - compatible
+  - "#reset-cells"
+  - cpu-syscon
+  - switch-syscon
+
+additionalProperties: false
+
+examples:
+  - |
+    reset: chip-controller {
+        compatible = "microchip,lan966x-chip-reset";
+        #reset-cells = <1>;
+        cpu-syscon = <&cpu_ctrl>;
+        switch-syscon = <&switch_ctrl>;
+    };
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [RFC PATCH net-next 07/12] power: reset: Add lan966x power reset driver
  2021-09-20  9:52 [RFC PATCH net-next 00/12] Add lan966x driver Horatiu Vultur
                   ` (5 preceding siblings ...)
  2021-09-20  9:52 ` [RFC PATCH net-next 06/12] dt-bindings: reset: Add lan966x power reset bindings Horatiu Vultur
@ 2021-09-20  9:52 ` Horatiu Vultur
  2021-09-20 12:15   ` Andrew Lunn
  2021-09-20  9:52 ` [RFC PATCH net-next 08/12] dt-bindings: net: lan966x: Add lan966x-switch bindings Horatiu Vultur
                   ` (4 subsequent siblings)
  11 siblings, 1 reply; 30+ messages in thread
From: Horatiu Vultur @ 2021-09-20  9:52 UTC (permalink / raw)
  To: davem, kuba, robh+dt, andrew, linux, f.fainelli,
	alexandre.belloni, vladimir.oltean, UNGLinuxDriver, netdev,
	devicetree, linux-kernel, linux-phy, linux-pm
  Cc: Horatiu Vultur

This adds a driver for lan966x to allow a software reset.

Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
---
 drivers/power/reset/Kconfig         |  6 ++
 drivers/power/reset/Makefile        |  1 +
 drivers/power/reset/lan966x-reset.c | 90 +++++++++++++++++++++++++++++
 3 files changed, 97 insertions(+)
 create mode 100644 drivers/power/reset/lan966x-reset.c

diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig
index 4b563db3ab3e..755b60c143da 100644
--- a/drivers/power/reset/Kconfig
+++ b/drivers/power/reset/Kconfig
@@ -158,6 +158,12 @@ config POWER_RESET_PIIX4_POWEROFF
 	  southbridge SOff state is entered in response to a request to
 	  power off the system.
 
+config POWER_RESET_LAN966X
+	bool "Microchip Lan966x reset driver"
+	select MFD_SYSCON
+	help
+	  This driver supports restart for Microchip Lan966x.
+
 config POWER_RESET_LTC2952
 	bool "LTC2952 PowerPath power-off driver"
 	depends on OF_GPIO
diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile
index f606a2f60539..0fbc817c4eb6 100644
--- a/drivers/power/reset/Makefile
+++ b/drivers/power/reset/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_POWER_RESET_OXNAS) += oxnas-restart.o
 obj-$(CONFIG_POWER_RESET_QCOM_PON) += qcom-pon.o
 obj-$(CONFIG_POWER_RESET_OCELOT_RESET) += ocelot-reset.o
 obj-$(CONFIG_POWER_RESET_PIIX4_POWEROFF) += piix4-poweroff.o
+obj-$(CONFIG_POWER_RESET_LAN966X) += lan966x-reset.o
 obj-$(CONFIG_POWER_RESET_LTC2952) += ltc2952-poweroff.o
 obj-$(CONFIG_POWER_RESET_QNAP) += qnap-poweroff.o
 obj-$(CONFIG_POWER_RESET_REGULATOR) += regulator-poweroff.o
diff --git a/drivers/power/reset/lan966x-reset.c b/drivers/power/reset/lan966x-reset.c
new file mode 100644
index 000000000000..612705b680fe
--- /dev/null
+++ b/drivers/power/reset/lan966x-reset.c
@@ -0,0 +1,90 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * License: Dual MIT/GPL
+ * Copyright (c) 2020 Microchip Corporation
+ */
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/notifier.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/reboot.h>
+#include <linux/regmap.h>
+
+static const char *cpu_syscon = "microchip,lan966x-cpu-syscon";
+static const char *gcb_syscon = "microchip,lan966x-switch-syscon";
+
+struct lan966x_reset_context {
+	struct regmap *gcb_ctrl;
+	struct regmap *cpu_ctrl;
+	struct notifier_block restart_handler;
+};
+
+#define PROTECT_REG    0x88
+#define PROTECT_BIT    BIT(5)
+#define SOFT_RESET_REG 0x00
+#define SOFT_RESET_BIT BIT(1)
+
+static int lan966x_restart_handle(struct notifier_block *this,
+				  unsigned long mode, void *cmd)
+{
+	struct lan966x_reset_context *ctx = container_of(this, struct lan966x_reset_context,
+							restart_handler);
+
+	/* Make sure the core is not protected from reset */
+	regmap_update_bits(ctx->cpu_ctrl, PROTECT_REG, PROTECT_BIT, 0);
+
+	pr_emerg("Resetting SoC\n");
+
+	regmap_write(ctx->gcb_ctrl, SOFT_RESET_REG, SOFT_RESET_BIT);
+
+	pr_emerg("Unable to restart system\n");
+	return NOTIFY_DONE;
+}
+
+static int lan966x_reset_probe(struct platform_device *pdev)
+{
+	struct lan966x_reset_context *ctx;
+	struct device *dev = &pdev->dev;
+	int err;
+
+	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	ctx->gcb_ctrl = syscon_regmap_lookup_by_compatible(gcb_syscon);
+	if (IS_ERR(ctx->gcb_ctrl)) {
+		dev_err(dev, "No gcb_syscon map: %s\n", gcb_syscon);
+		return PTR_ERR(ctx->gcb_ctrl);
+	}
+
+	ctx->cpu_ctrl = syscon_regmap_lookup_by_compatible(cpu_syscon);
+	if (IS_ERR(ctx->cpu_ctrl)) {
+		dev_err(dev, "No cpu_syscon map: %s\n", cpu_syscon);
+		return PTR_ERR(ctx->cpu_ctrl);
+	}
+
+	ctx->restart_handler.notifier_call = lan966x_restart_handle;
+	ctx->restart_handler.priority = 192;
+	err = register_restart_handler(&ctx->restart_handler);
+	if (err)
+		dev_err(dev, "can't register restart notifier (err=%d)\n", err);
+
+	return err;
+}
+
+static const struct of_device_id lan966x_reset_of_match[] = {
+	{ .compatible = "microchip,lan966x-chip-reset", },
+	{ /*sentinel*/ }
+};
+
+static struct platform_driver lan966x_reset_driver = {
+	.probe = lan966x_reset_probe,
+	.driver = {
+		.name = "lan966x-chip-reset",
+		.of_match_table = lan966x_reset_of_match,
+	},
+};
+builtin_platform_driver(lan966x_reset_driver);
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [RFC PATCH net-next 08/12] dt-bindings: net: lan966x: Add lan966x-switch bindings
  2021-09-20  9:52 [RFC PATCH net-next 00/12] Add lan966x driver Horatiu Vultur
                   ` (6 preceding siblings ...)
  2021-09-20  9:52 ` [RFC PATCH net-next 07/12] power: reset: Add lan966x power reset driver Horatiu Vultur
@ 2021-09-20  9:52 ` Horatiu Vultur
  2021-09-23 12:53   ` Rob Herring
  2021-09-20  9:52 ` [RFC PATCH net-next 09/12] net: lan966x: add the basic lan966x driver Horatiu Vultur
                   ` (3 subsequent siblings)
  11 siblings, 1 reply; 30+ messages in thread
From: Horatiu Vultur @ 2021-09-20  9:52 UTC (permalink / raw)
  To: davem, kuba, robh+dt, andrew, linux, f.fainelli,
	alexandre.belloni, vladimir.oltean, UNGLinuxDriver, netdev,
	devicetree, linux-kernel, linux-phy, linux-pm
  Cc: Horatiu Vultur

Document the lan966x switch device driver bindings

Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
---
 .../net/microchip,lan966x-switch.yaml         | 114 ++++++++++++++++++
 1 file changed, 114 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/net/microchip,lan966x-switch.yaml

diff --git a/Documentation/devicetree/bindings/net/microchip,lan966x-switch.yaml b/Documentation/devicetree/bindings/net/microchip,lan966x-switch.yaml
new file mode 100644
index 000000000000..53d72a65c168
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/microchip,lan966x-switch.yaml
@@ -0,0 +1,114 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/net/microchip,lan966x-switch.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Microchip Lan966x Ethernet switch controller
+
+maintainers:
+  - Horatiu Vultur <horatiu.vultur@microchip.com>
+  - UNGLinuxDriver@microchip.com
+
+description: |
+  The Lan966x Enterprise Ethernet switch family provides a rich set of
+  Enterprise switching features such as advanced TCAM-based VLAN and
+  QoS processing enabling delivery of differentiated services, and
+  security through TCAM-based frame processing using versatile content
+  aware processor (VCAP).
+
+properties:
+  $nodename:
+    pattern: "^switch@[0-9a-f]+$"
+
+  compatible:
+    const: microchip,lan966x-switch
+
+  reg:
+    items:
+      - description: cpu target
+      - description: devices target
+      - description: general control block target
+
+  reg-names:
+    items:
+      - const: cpu
+      - const: devices
+      - const: gcb
+
+  interrupts:
+    minItems: 1
+    items:
+      - description: register based extraction
+
+  interrupt-names:
+    minItems: 1
+    items:
+      - const: xtr
+
+  mac-address: true
+
+  ethernet-ports:
+    type: object
+    patternProperties:
+      "^port@[0-9a-f]+$":
+        type: object
+
+        properties:
+          '#address-cells':
+            const: 1
+          '#size-cells':
+            const: 0
+
+          reg:
+            description: Switch port number
+
+          phy-mode:
+            description:
+              This specifies the interface used by the Ethernet SerDes towards
+              the PHY or SFP.
+
+          phy-handle:
+            description:
+              phandle of a Ethernet PHY.
+
+        required:
+          - reg
+          - phy-mode
+          - phy-handle
+
+required:
+  - compatible
+  - reg
+  - reg-names
+  - interrupts
+  - interrupt-names
+  - ethernet-ports
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    switch: switch@600000000 {
+      compatible = "microchip,lan966x-switch";
+      reg =  <0 0x401000>,
+             <0x10004000 0x7fc000>,
+             <0x11010000 0xaf0000>;
+      reg-names = "cpu", "devices", "gcb";
+      interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
+      interrupt-names = "xtr";
+      ethernet-ports {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        port0: port@0 {
+          reg = <0>;
+          phy-handle = <&phy0>;
+          phy-mode = "gmii";
+        };
+      };
+    };
+
+...
+#  vim: set ts=2 sw=2 sts=2 tw=80 et cc=80 ft=yaml :
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [RFC PATCH net-next 09/12] net: lan966x: add the basic lan966x driver
  2021-09-20  9:52 [RFC PATCH net-next 00/12] Add lan966x driver Horatiu Vultur
                   ` (7 preceding siblings ...)
  2021-09-20  9:52 ` [RFC PATCH net-next 08/12] dt-bindings: net: lan966x: Add lan966x-switch bindings Horatiu Vultur
@ 2021-09-20  9:52 ` Horatiu Vultur
  2021-09-20 13:46   ` Russell King (Oracle)
  2021-09-20  9:52 ` [RFC PATCH net-next 10/12] net: lan966x: add port module support Horatiu Vultur
                   ` (2 subsequent siblings)
  11 siblings, 1 reply; 30+ messages in thread
From: Horatiu Vultur @ 2021-09-20  9:52 UTC (permalink / raw)
  To: davem, kuba, robh+dt, andrew, linux, f.fainelli,
	alexandre.belloni, vladimir.oltean, UNGLinuxDriver, netdev,
	devicetree, linux-kernel, linux-phy, linux-pm
  Cc: Horatiu Vultur

This patch adds basic SwitchDev driver framework for lan966x. It
includes only the IO range mapping and probing of the switch.

Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
---
 drivers/net/ethernet/microchip/Kconfig        |   1 +
 drivers/net/ethernet/microchip/Makefile       |   1 +
 .../net/ethernet/microchip/lan966x/Kconfig    |   7 +
 .../net/ethernet/microchip/lan966x/Makefile   |   8 +
 .../ethernet/microchip/lan966x/lan966x_main.c | 350 +++++++++
 .../ethernet/microchip/lan966x/lan966x_main.h | 105 +++
 .../ethernet/microchip/lan966x/lan966x_regs.h | 704 ++++++++++++++++++
 7 files changed, 1176 insertions(+)
 create mode 100644 drivers/net/ethernet/microchip/lan966x/Kconfig
 create mode 100644 drivers/net/ethernet/microchip/lan966x/Makefile
 create mode 100644 drivers/net/ethernet/microchip/lan966x/lan966x_main.c
 create mode 100644 drivers/net/ethernet/microchip/lan966x/lan966x_main.h
 create mode 100644 drivers/net/ethernet/microchip/lan966x/lan966x_regs.h

diff --git a/drivers/net/ethernet/microchip/Kconfig b/drivers/net/ethernet/microchip/Kconfig
index 735eea1dacf1..ed7a35c3ceac 100644
--- a/drivers/net/ethernet/microchip/Kconfig
+++ b/drivers/net/ethernet/microchip/Kconfig
@@ -55,6 +55,7 @@ config LAN743X
 	  To compile this driver as a module, choose M here. The module will be
 	  called lan743x.
 
+source "drivers/net/ethernet/microchip/lan966x/Kconfig"
 source "drivers/net/ethernet/microchip/sparx5/Kconfig"
 
 endif # NET_VENDOR_MICROCHIP
diff --git a/drivers/net/ethernet/microchip/Makefile b/drivers/net/ethernet/microchip/Makefile
index c77dc0379bfd..9faa41436198 100644
--- a/drivers/net/ethernet/microchip/Makefile
+++ b/drivers/net/ethernet/microchip/Makefile
@@ -9,4 +9,5 @@ obj-$(CONFIG_LAN743X) += lan743x.o
 
 lan743x-objs := lan743x_main.o lan743x_ethtool.o lan743x_ptp.o
 
+obj-$(CONFIG_LAN966X_SWITCH) += lan966x/
 obj-$(CONFIG_SPARX5_SWITCH) += sparx5/
diff --git a/drivers/net/ethernet/microchip/lan966x/Kconfig b/drivers/net/ethernet/microchip/lan966x/Kconfig
new file mode 100644
index 000000000000..83ac4266b417
--- /dev/null
+++ b/drivers/net/ethernet/microchip/lan966x/Kconfig
@@ -0,0 +1,7 @@
+config LAN966X_SWITCH
+	tristate "Lan966x switch driver"
+	depends on HAS_IOMEM
+	depends on OF
+	select PHYLINK
+	help
+	  This driver supports the Lan966x network switch device.
diff --git a/drivers/net/ethernet/microchip/lan966x/Makefile b/drivers/net/ethernet/microchip/lan966x/Makefile
new file mode 100644
index 000000000000..7ea90410a0b2
--- /dev/null
+++ b/drivers/net/ethernet/microchip/lan966x/Makefile
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Makefile for the Microchip Lan966x network device drivers.
+#
+
+obj-$(CONFIG_LAN966X_SWITCH) += lan966x-switch.o
+
+lan966x-switch-objs  := lan966x_main.o
diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_main.c b/drivers/net/ethernet/microchip/lan966x/lan966x_main.c
new file mode 100644
index 000000000000..2984f510ae27
--- /dev/null
+++ b/drivers/net/ethernet/microchip/lan966x/lan966x_main.c
@@ -0,0 +1,350 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <asm/memory.h>
+#include <linux/module.h>
+#include <linux/if_bridge.h>
+#include <linux/iopoll.h>
+#include <linux/of_platform.h>
+#include <linux/of_net.h>
+#include <linux/reset.h>
+
+#include "lan966x_main.h"
+
+#define READL_SLEEP_US			10
+#define READL_TIMEOUT_US		100000000
+
+#define IO_RANGES 2
+
+static const struct of_device_id lan966x_match[] = {
+	{ .compatible = "microchip,lan966x-switch" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, mchp_lan966x_match);
+
+struct lan966x_main_io_resource {
+	enum lan966x_target id;
+	phys_addr_t offset;
+	int range;
+};
+
+static const struct lan966x_main_io_resource lan966x_main_iomap[] =  {
+	{ TARGET_CPU,                   0xc0000, 0 }, /* 0xe00c0000 */
+	{ TARGET_ORG,                         0, 1 }, /* 0xe2000000 */
+	{ TARGET_GCB,                    0x4000, 1 }, /* 0xe2004000 */
+	{ TARGET_QS,                     0x8000, 1 }, /* 0xe2008000 */
+	{ TARGET_CHIP_TOP,              0x10000, 1 }, /* 0xe2010000 */
+	{ TARGET_REW,                   0x14000, 1 }, /* 0xe2014000 */
+	{ TARGET_SYS,                   0x28000, 1 }, /* 0xe2028000 */
+	{ TARGET_HSIO,                  0x2c000, 1 }, /* 0xe202c000 */
+	{ TARGET_DEV,                   0x34000, 1 }, /* 0xe2034000 */
+	{ TARGET_DEV +  1,              0x38000, 1 }, /* 0xe2038000 */
+	{ TARGET_DEV +  2,              0x3c000, 1 }, /* 0xe203c000 */
+	{ TARGET_DEV +  3,              0x40000, 1 }, /* 0xe2040000 */
+	{ TARGET_DEV +  4,              0x44000, 1 }, /* 0xe2044000 */
+	{ TARGET_DEV +  5,              0x48000, 1 }, /* 0xe2048000 */
+	{ TARGET_DEV +  6,              0x4c000, 1 }, /* 0xe204c000 */
+	{ TARGET_DEV +  7,              0x50000, 1 }, /* 0xe2050000 */
+	{ TARGET_QSYS,                 0x100000, 1 }, /* 0xe2100000 */
+	{ TARGET_AFI,                  0x120000, 1 }, /* 0xe2120000 */
+	{ TARGET_ANA,                  0x140000, 1 }, /* 0xe2140000 */
+};
+
+static int lan966x_create_targets(struct platform_device *pdev,
+				  struct lan966x *lan966x)
+{
+	struct resource *iores[IO_RANGES];
+	void __iomem *iomem[IO_RANGES];
+	void __iomem *begin[IO_RANGES];
+	int idx;
+
+	for (idx = 0; idx < IO_RANGES; idx++) {
+		iores[idx] = platform_get_resource(pdev, IORESOURCE_MEM,
+						   idx);
+		iomem[idx] = devm_ioremap(&pdev->dev,
+					  iores[idx]->start,
+					  resource_size(iores[idx]));
+		if (IS_ERR(iomem[idx])) {
+			dev_err(&pdev->dev, "Unable to get registers: %s\n",
+				iores[idx]->name);
+			return PTR_ERR(iomem[idx]);
+		}
+
+		begin[idx] = iomem[idx];
+	}
+
+	for (idx = 0; idx < ARRAY_SIZE(lan966x_main_iomap); idx++) {
+		const struct lan966x_main_io_resource *iomap =
+			&lan966x_main_iomap[idx];
+
+		lan966x->regs[iomap->id] = begin[iomap->range] + iomap->offset;
+	}
+
+	return 0;
+}
+
+static int lan966x_probe_port(struct lan966x *lan966x, u8 port,
+			      phy_interface_t phy_mode)
+{
+	struct lan966x_port *lan966x_port;
+
+	if (port >= lan966x->num_phys_ports)
+		return -EINVAL;
+
+	lan966x_port = devm_kzalloc(lan966x->dev, sizeof(*lan966x_port),
+				    GFP_KERNEL);
+
+	lan966x_port->lan966x = lan966x;
+	lan966x_port->chip_port = port;
+	lan966x_port->pvid = PORT_PVID;
+	lan966x->ports[port] = lan966x_port;
+
+	return 0;
+}
+
+static void lan966x_init(struct lan966x *lan966x)
+{
+	u32 port, i;
+
+	/* Flush queues */
+	lan_wr(lan_rd(lan966x, QS_XTR_FLUSH) |
+	       GENMASK(1, 0),
+	       lan966x, QS_XTR_FLUSH);
+
+	/* Allow to drain */
+	mdelay(1);
+
+	/* All Queues normal */
+	lan_wr(lan_rd(lan966x, QS_XTR_FLUSH) &
+	       ~(GENMASK(1, 0)),
+	       lan966x, QS_XTR_FLUSH);
+
+	/* Set MAC age time to default value, the entry is aged after
+	 * 2 * AGE_PERIOD
+	 */
+	lan_wr(ANA_AUTOAGE_AGE_PERIOD_SET(BR_DEFAULT_AGEING_TIME / 2 / HZ),
+	       lan966x, ANA_AUTOAGE);
+
+	/* Disable learning for frames discarded by VLAN ingress filtering */
+	lan_rmw(ANA_ADVLEARN_VLAN_CHK_SET(1),
+		ANA_ADVLEARN_VLAN_CHK,
+		lan966x, ANA_ADVLEARN);
+
+	/* Setup frame ageing - "2 sec" - The unit is 6.5 us on lan966x */
+	lan_wr(SYS_FRM_AGING_AGE_TX_ENA_SET(1) |
+	       (20000000 / 65),
+	       lan966x,  SYS_FRM_AGING);
+
+	/* Map the 8 CPU extraction queues to CPU port */
+	lan_wr(0, lan966x, QSYS_CPU_GROUP_MAP);
+
+	/* Do byte-swap and expect status after last data word
+	 * Extraction: Mode: manual extraction) | Byte_swap
+	 */
+	lan_wr(QS_XTR_GRP_CFG_MODE_SET(1) |
+	       QS_XTR_GRP_CFG_BYTE_SWAP_SET(1),
+	       lan966x, QS_XTR_GRP_CFG(0));
+
+	/* Injection: Mode: manual injection | Byte_swap */
+	lan_wr(QS_INJ_GRP_CFG_MODE_SET(1) |
+	       QS_INJ_GRP_CFG_BYTE_SWAP_SET(1),
+	       lan966x, QS_INJ_GRP_CFG(0));
+
+	lan_rmw(QS_INJ_CTRL_GAP_SIZE_SET(0),
+		QS_INJ_CTRL_GAP_SIZE,
+		lan966x, QS_INJ_CTRL(0));
+
+	/* Enable IFH insertion/parsing on CPU ports */
+	lan_wr(SYS_PORT_MODE_INCL_INJ_HDR_SET(1) |
+	       SYS_PORT_MODE_INCL_XTR_HDR_SET(1),
+	       lan966x, SYS_PORT_MODE(CPU_PORT));
+
+	/* Setup flooding PGIDs */
+	lan_wr(ANA_FLOODING_IPMC_FLD_MC4_DATA_SET(PGID_MCIPV4) |
+	       ANA_FLOODING_IPMC_FLD_MC4_CTRL_SET(PGID_MC) |
+	       ANA_FLOODING_IPMC_FLD_MC6_DATA_SET(PGID_MC) |
+	       ANA_FLOODING_IPMC_FLD_MC6_CTRL_SET(PGID_MC),
+	       lan966x, ANA_FLOODING_IPMC);
+
+	/* There are 8 priorities */
+	for (i = 0; i < 8; ++i)
+		lan_rmw(ANA_FLOODING_FLD_MULTICAST_SET(PGID_MC) |
+			ANA_FLOODING_FLD_BROADCAST_SET(PGID_BC),
+			ANA_FLOODING_FLD_MULTICAST |
+			ANA_FLOODING_FLD_BROADCAST,
+			lan966x, ANA_FLOODING(i));
+
+	for (i = 0; i < PGID_ENTRIES; ++i)
+		/* Set all the entries to obey VLAN_VLAN */
+		lan_rmw(ANA_PGID_CFG_OBEY_VLAN_SET(1),
+			ANA_PGID_CFG_OBEY_VLAN,
+			lan966x, ANA_PGID_CFG(i));
+
+	for (port = 0; port < lan966x->num_phys_ports; port++) {
+		/* Disable bridging by default */
+		lan_rmw(ANA_PGID_PGID_SET(0x0),
+			ANA_PGID_PGID,
+			lan966x, ANA_PGID(port + PGID_SRC));
+
+		/* Do not forward BPDU frames to the front ports and copy them
+		 * to CPU
+		 */
+		lan_wr(0xffff, lan966x, ANA_CPU_FWD_BPDU_CFG(port));
+	}
+
+	/* Set source buffer size for each priority and each port to 1500 bytes */
+	for (i = 0; i <= QSYS_Q_RSRV; ++i) {
+		lan_wr(1500 / 64, lan966x, QSYS_RES_CFG(i));
+		lan_wr(1500 / 64, lan966x, QSYS_RES_CFG(512 + i));
+	}
+
+	/* Enable switching to/from cpu port */
+	lan_wr(QSYS_SW_PORT_MODE_PORT_ENA_SET(1) |
+	       QSYS_SW_PORT_MODE_SCH_NEXT_CFG_SET(1) |
+	       QSYS_SW_PORT_MODE_INGRESS_DROP_MODE_SET(1),
+	       lan966x,  QSYS_SW_PORT_MODE(CPU_PORT));
+
+	/* Configure and enable the CPU port */
+	lan_rmw(ANA_PGID_PGID_SET(0),
+		ANA_PGID_PGID,
+		lan966x, ANA_PGID(CPU_PORT));
+	lan_rmw(ANA_PGID_PGID_SET(BIT(CPU_PORT)),
+		ANA_PGID_PGID,
+		lan966x, ANA_PGID(PGID_CPU));
+
+	/* Multicast to all other ports */
+	lan_rmw(GENMASK(lan966x->num_phys_ports - 1, 0),
+		ANA_PGID_PGID,
+		lan966x, ANA_PGID(PGID_MC));
+
+	/* This will be controlled by mrouter ports */
+	lan_rmw(GENMASK(lan966x->num_phys_ports - 1, 0),
+		ANA_PGID_PGID,
+		lan966x, ANA_PGID(PGID_MCIPV4));
+
+	/* Broadcast to the CPU port and to other ports */
+	lan_rmw(ANA_PGID_PGID_SET(BIT(CPU_PORT) | GENMASK(lan966x->num_phys_ports - 1, 0)),
+		ANA_PGID_PGID,
+		lan966x, ANA_PGID(PGID_BC));
+
+	lan_wr(REW_PORT_CFG_NO_REWRITE_SET(1),
+	       lan966x, REW_PORT_CFG(CPU_PORT));
+
+	lan_rmw(ANA_ANAINTR_INTR_ENA_SET(1),
+		ANA_ANAINTR_INTR_ENA,
+		lan966x, ANA_ANAINTR);
+}
+
+static int lan966x_ram_init(struct lan966x *lan966x)
+{
+	return lan_rd(lan966x, SYS_RAM_INIT);
+}
+
+static int lan966x_reset_switch(struct lan966x *lan966x)
+{
+	struct reset_control *reset;
+	int val = 0;
+	int ret;
+
+	reset = devm_reset_control_get_shared(lan966x->dev, "switch");
+	if (IS_ERR(reset))
+		dev_warn(lan966x->dev, "Could not obtain reset control: %ld\n",
+			 PTR_ERR(reset));
+	else
+		reset_control_reset(reset);
+
+	lan_wr(SYS_RESET_CFG_CORE_ENA_SET(0), lan966x, SYS_RESET_CFG);
+	lan_wr(SYS_RAM_INIT_RAM_INIT_SET(1), lan966x, SYS_RAM_INIT);
+	ret = readx_poll_timeout(lan966x_ram_init, lan966x,
+				 val, (val & BIT(1)) == 0, READL_SLEEP_US,
+				 READL_TIMEOUT_US);
+	if (ret)
+		return ret;
+
+	lan_wr(SYS_RESET_CFG_CORE_ENA_SET(1), lan966x, SYS_RESET_CFG);
+
+	return 0;
+}
+
+static int lan966x_probe(struct platform_device *pdev)
+{
+	struct fwnode_handle *ports, *portnp;
+	struct lan966x *lan966x;
+	int err, i;
+
+	lan966x = devm_kzalloc(&pdev->dev, sizeof(*lan966x), GFP_KERNEL);
+	if (!lan966x)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, lan966x);
+	lan966x->dev = &pdev->dev;
+
+	ports = device_get_named_child_node(&pdev->dev, "ethernet-ports");
+	if (!ports) {
+		dev_err(&pdev->dev, "no ethernet-ports child not found\n");
+		err = -ENODEV;
+		goto out;
+	}
+
+	err = lan966x_create_targets(pdev, lan966x);
+	if (err)
+		goto out;
+
+	if (lan966x_reset_switch(lan966x)) {
+		err = -EINVAL;
+		goto out;
+	}
+
+	i = 0;
+	fwnode_for_each_available_child_node(ports, portnp)
+		++i;
+
+	lan966x->num_phys_ports = i;
+	lan966x->ports = devm_kcalloc(&pdev->dev, lan966x->num_phys_ports,
+				      sizeof(struct lan966x_port *),
+				      GFP_KERNEL);
+
+	/* There QS system has 32KB of memory */
+	lan966x->shared_queue_sz = LAN966X_BUFFER_MEMORY;
+
+	/* init switch */
+	lan966x_init(lan966x);
+
+	/* go over the child nodes */
+	fwnode_for_each_available_child_node(ports, portnp) {
+		phy_interface_t phy_mode;
+		struct phy *serdes;
+		u32 port;
+
+		if (fwnode_property_read_u32(portnp, "reg", &port))
+			continue;
+
+		phy_mode = fwnode_get_phy_mode(portnp);
+		err = lan966x_probe_port(lan966x, port, phy_mode);
+		if (err)
+			return err;
+	}
+
+	return 0;
+
+out:
+	return err;
+}
+
+static int lan966x_remove(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static struct platform_driver lan966x_driver = {
+	.probe = lan966x_probe,
+	.remove = lan966x_remove,
+	.driver = {
+		.name = "lan966x-switch",
+		.of_match_table = lan966x_match,
+	},
+};
+module_platform_driver(lan966x_driver);
+
+MODULE_DESCRIPTION("Microchip LAN966X switch driver");
+MODULE_AUTHOR("Horatiu Vultur <horatiu.vultur@microchip.com>");
+MODULE_LICENSE("Dual MIT/GPL");
diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_main.h b/drivers/net/ethernet/microchip/lan966x/lan966x_main.h
new file mode 100644
index 000000000000..0c5fa14437a5
--- /dev/null
+++ b/drivers/net/ethernet/microchip/lan966x/lan966x_main.h
@@ -0,0 +1,105 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+#ifndef __LAN966X_MAIN_H__
+#define __LAN966X_MAIN_H__
+
+#include "lan966x_regs.h"
+
+#define LAN966X_BUFFER_CELL_SZ		64
+#define LAN966X_BUFFER_MEMORY		(160 * 1024)
+#define LAN966X_BUFFER_MIN_SZ		60
+
+#define PGID_AGGR			64
+#define PGID_SRC			80
+#define PGID_ENTRIES			89
+
+#define PORT_PVID			0
+
+/* Reserved amount for (SRC, PRIO) at index 8*SRC + PRIO */
+#define QSYS_Q_RSRV			95
+
+/* Reserved PGIDs */
+#define PGID_CPU			(PGID_AGGR - 6)
+#define PGID_UC				(PGID_AGGR - 5)
+#define PGID_BC				(PGID_AGGR - 4)
+#define PGID_MC				(PGID_AGGR - 3)
+#define PGID_MCIPV4			(PGID_AGGR - 2)
+#define PGID_MCIPV6			(PGID_AGGR - 1)
+
+#define LAN966X_SPEED_NONE		0
+#define LAN966X_SPEED_1000		1
+#define LAN966X_SPEED_100		2
+#define LAN966X_SPEED_10		3
+
+#define CPU_PORT			8
+
+struct lan966x_port;
+
+struct lan966x {
+	struct device *dev;
+
+	u8 num_phys_ports;
+	struct lan966x_port **ports;
+
+	void __iomem *regs[NUM_TARGETS];
+
+	int shared_queue_sz;
+};
+
+struct lan966x_port {
+	struct lan966x *lan966x;
+
+	u8 chip_port;
+	u16 pvid;
+
+	void __iomem *regs;
+};
+
+static inline void __iomem *lan_addr(void __iomem *base[],
+				     int id, int tinst, int tcnt,
+				     int gbase, int ginst,
+				     int gcnt, int gwidth,
+				     int raddr, int rinst,
+				     int rcnt, int rwidth)
+{
+	WARN_ON((tinst) >= tcnt);
+	WARN_ON((ginst) >= gcnt);
+	WARN_ON((rinst) >= rcnt);
+	return base[id + (tinst)] +
+		gbase + ((ginst) * gwidth) +
+		raddr + ((rinst) * rwidth);
+}
+
+static inline u32 lan_rd(struct lan966x *lan966x, int id, int tinst, int tcnt,
+			 int gbase, int ginst, int gcnt, int gwidth,
+			 int raddr, int rinst, int rcnt, int rwidth)
+{
+	return readl(lan_addr(lan966x->regs, id, tinst, tcnt, gbase, ginst,
+			      gcnt, gwidth, raddr, rinst, rcnt, rwidth));
+}
+
+static inline void lan_wr(u32 val, struct lan966x *lan966x,
+			  int id, int tinst, int tcnt,
+			  int gbase, int ginst, int gcnt, int gwidth,
+			  int raddr, int rinst, int rcnt, int rwidth)
+{
+	writel(val, lan_addr(lan966x->regs, id, tinst, tcnt,
+			     gbase, ginst, gcnt, gwidth,
+			     raddr, rinst, rcnt, rwidth));
+}
+
+static inline void lan_rmw(u32 val, u32 mask, struct lan966x *lan966x,
+			   int id, int tinst, int tcnt,
+			   int gbase, int ginst, int gcnt, int gwidth,
+			   int raddr, int rinst, int rcnt, int rwidth)
+{
+	u32 nval;
+
+	nval = readl(lan_addr(lan966x->regs, id, tinst, tcnt, gbase, ginst,
+			      gcnt, gwidth, raddr, rinst, rcnt, rwidth));
+	nval = (nval & ~mask) | (val & mask);
+	writel(nval, lan_addr(lan966x->regs, id, tinst, tcnt, gbase, ginst,
+			      gcnt, gwidth, raddr, rinst, rcnt, rwidth));
+}
+
+#endif /* __LAN966X_MAIN_H__ */
diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_regs.h b/drivers/net/ethernet/microchip/lan966x/lan966x_regs.h
new file mode 100644
index 000000000000..d2ffb4cc122c
--- /dev/null
+++ b/drivers/net/ethernet/microchip/lan966x/lan966x_regs.h
@@ -0,0 +1,704 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
+
+/* This file is autogenerated by cml-utils 2021-07-23 13:13:18 +0200.
+ * Commit ID: 82017f2e7bc0232de70264fd8a07e1fec9257afa (dirty)
+ */
+
+#ifndef _LAN966X_REGS_H_
+#define _LAN966X_REGS_H_
+
+#include <linux/bitfield.h>
+#include <linux/types.h>
+#include <linux/bug.h>
+
+enum lan966x_target {
+	TARGET_AFI = 2,
+	TARGET_ANA = 3,
+	TARGET_CHIP_TOP = 5,
+	TARGET_CPU = 6,
+	TARGET_DEV = 13,
+	TARGET_GCB = 27,
+	TARGET_HSIO = 32,
+	TARGET_ORG = 36,
+	TARGET_QS = 42,
+	TARGET_QSYS = 46,
+	TARGET_REW = 47,
+	TARGET_SYS = 52,
+	NUM_TARGETS = 66
+};
+
+#define __REG(...)    __VA_ARGS__
+
+/*      AFI:PORT_TBL:PORT_FRM_OUT */
+#define AFI_PORT_FRM_OUT(g)       __REG(TARGET_AFI, 0, 1, 98816, g, 10, 8, 0, 0, 1, 4)
+
+#define AFI_PORT_FRM_OUT_FRM_OUT_CNT             GENMASK(26, 16)
+#define AFI_PORT_FRM_OUT_FRM_OUT_CNT_SET(x)\
+	FIELD_PREP(AFI_PORT_FRM_OUT_FRM_OUT_CNT, x)
+#define AFI_PORT_FRM_OUT_FRM_OUT_CNT_GET(x)\
+	FIELD_GET(AFI_PORT_FRM_OUT_FRM_OUT_CNT, x)
+
+/*      AFI:PORT_TBL:PORT_CFG */
+#define AFI_PORT_CFG(g)           __REG(TARGET_AFI, 0, 1, 98816, g, 10, 8, 4, 0, 1, 4)
+
+#define AFI_PORT_CFG_FC_SKIP_TTI_INJ             BIT(16)
+#define AFI_PORT_CFG_FC_SKIP_TTI_INJ_SET(x)\
+	FIELD_PREP(AFI_PORT_CFG_FC_SKIP_TTI_INJ, x)
+#define AFI_PORT_CFG_FC_SKIP_TTI_INJ_GET(x)\
+	FIELD_GET(AFI_PORT_CFG_FC_SKIP_TTI_INJ, x)
+
+#define AFI_PORT_CFG_FRM_OUT_MAX                 GENMASK(9, 0)
+#define AFI_PORT_CFG_FRM_OUT_MAX_SET(x)\
+	FIELD_PREP(AFI_PORT_CFG_FRM_OUT_MAX, x)
+#define AFI_PORT_CFG_FRM_OUT_MAX_GET(x)\
+	FIELD_GET(AFI_PORT_CFG_FRM_OUT_MAX, x)
+
+/*      ANA:ANA:ADVLEARN */
+#define ANA_ADVLEARN              __REG(TARGET_ANA, 0, 1, 29824, 0, 1, 244, 0, 0, 1, 4)
+
+#define ANA_ADVLEARN_VLAN_CHK                    BIT(0)
+#define ANA_ADVLEARN_VLAN_CHK_SET(x)\
+	FIELD_PREP(ANA_ADVLEARN_VLAN_CHK, x)
+#define ANA_ADVLEARN_VLAN_CHK_GET(x)\
+	FIELD_GET(ANA_ADVLEARN_VLAN_CHK, x)
+
+/*      ANA:ANA:ANAINTR */
+#define ANA_ANAINTR               __REG(TARGET_ANA, 0, 1, 29824, 0, 1, 244, 16, 0, 1, 4)
+
+#define ANA_ANAINTR_INTR                         BIT(1)
+#define ANA_ANAINTR_INTR_SET(x)\
+	FIELD_PREP(ANA_ANAINTR_INTR, x)
+#define ANA_ANAINTR_INTR_GET(x)\
+	FIELD_GET(ANA_ANAINTR_INTR, x)
+
+#define ANA_ANAINTR_INTR_ENA                     BIT(0)
+#define ANA_ANAINTR_INTR_ENA_SET(x)\
+	FIELD_PREP(ANA_ANAINTR_INTR_ENA, x)
+#define ANA_ANAINTR_INTR_ENA_GET(x)\
+	FIELD_GET(ANA_ANAINTR_INTR_ENA, x)
+
+/*      ANA:ANA:AUTOAGE */
+#define ANA_AUTOAGE               __REG(TARGET_ANA, 0, 1, 29824, 0, 1, 244, 44, 0, 1, 4)
+
+#define ANA_AUTOAGE_AGE_PERIOD                   GENMASK(20, 1)
+#define ANA_AUTOAGE_AGE_PERIOD_SET(x)\
+	FIELD_PREP(ANA_AUTOAGE_AGE_PERIOD, x)
+#define ANA_AUTOAGE_AGE_PERIOD_GET(x)\
+	FIELD_GET(ANA_AUTOAGE_AGE_PERIOD, x)
+
+/*      ANA:ANA:FLOODING */
+#define ANA_FLOODING(r)           __REG(TARGET_ANA, 0, 1, 29824, 0, 1, 244, 68, r, 8, 4)
+
+#define ANA_FLOODING_FLD_BROADCAST               GENMASK(11, 6)
+#define ANA_FLOODING_FLD_BROADCAST_SET(x)\
+	FIELD_PREP(ANA_FLOODING_FLD_BROADCAST, x)
+#define ANA_FLOODING_FLD_BROADCAST_GET(x)\
+	FIELD_GET(ANA_FLOODING_FLD_BROADCAST, x)
+
+#define ANA_FLOODING_FLD_MULTICAST               GENMASK(5, 0)
+#define ANA_FLOODING_FLD_MULTICAST_SET(x)\
+	FIELD_PREP(ANA_FLOODING_FLD_MULTICAST, x)
+#define ANA_FLOODING_FLD_MULTICAST_GET(x)\
+	FIELD_GET(ANA_FLOODING_FLD_MULTICAST, x)
+
+/*      ANA:ANA:FLOODING_IPMC */
+#define ANA_FLOODING_IPMC         __REG(TARGET_ANA, 0, 1, 29824, 0, 1, 244, 100, 0, 1, 4)
+
+#define ANA_FLOODING_IPMC_FLD_MC4_CTRL           GENMASK(23, 18)
+#define ANA_FLOODING_IPMC_FLD_MC4_CTRL_SET(x)\
+	FIELD_PREP(ANA_FLOODING_IPMC_FLD_MC4_CTRL, x)
+#define ANA_FLOODING_IPMC_FLD_MC4_CTRL_GET(x)\
+	FIELD_GET(ANA_FLOODING_IPMC_FLD_MC4_CTRL, x)
+
+#define ANA_FLOODING_IPMC_FLD_MC4_DATA           GENMASK(17, 12)
+#define ANA_FLOODING_IPMC_FLD_MC4_DATA_SET(x)\
+	FIELD_PREP(ANA_FLOODING_IPMC_FLD_MC4_DATA, x)
+#define ANA_FLOODING_IPMC_FLD_MC4_DATA_GET(x)\
+	FIELD_GET(ANA_FLOODING_IPMC_FLD_MC4_DATA, x)
+
+#define ANA_FLOODING_IPMC_FLD_MC6_CTRL           GENMASK(11, 6)
+#define ANA_FLOODING_IPMC_FLD_MC6_CTRL_SET(x)\
+	FIELD_PREP(ANA_FLOODING_IPMC_FLD_MC6_CTRL, x)
+#define ANA_FLOODING_IPMC_FLD_MC6_CTRL_GET(x)\
+	FIELD_GET(ANA_FLOODING_IPMC_FLD_MC6_CTRL, x)
+
+#define ANA_FLOODING_IPMC_FLD_MC6_DATA           GENMASK(5, 0)
+#define ANA_FLOODING_IPMC_FLD_MC6_DATA_SET(x)\
+	FIELD_PREP(ANA_FLOODING_IPMC_FLD_MC6_DATA, x)
+#define ANA_FLOODING_IPMC_FLD_MC6_DATA_GET(x)\
+	FIELD_GET(ANA_FLOODING_IPMC_FLD_MC6_DATA, x)
+
+/*      ANA:PGID:PGID */
+#define ANA_PGID(g)               __REG(TARGET_ANA, 0, 1, 27648, g, 89, 8, 0, 0, 1, 4)
+
+#define ANA_PGID_PGID                            GENMASK(8, 0)
+#define ANA_PGID_PGID_SET(x)\
+	FIELD_PREP(ANA_PGID_PGID, x)
+#define ANA_PGID_PGID_GET(x)\
+	FIELD_GET(ANA_PGID_PGID, x)
+
+/*      ANA:PGID:PGID_CFG */
+#define ANA_PGID_CFG(g)           __REG(TARGET_ANA, 0, 1, 27648, g, 89, 8, 4, 0, 1, 4)
+
+#define ANA_PGID_CFG_OBEY_VLAN                   BIT(0)
+#define ANA_PGID_CFG_OBEY_VLAN_SET(x)\
+	FIELD_PREP(ANA_PGID_CFG_OBEY_VLAN, x)
+#define ANA_PGID_CFG_OBEY_VLAN_GET(x)\
+	FIELD_GET(ANA_PGID_CFG_OBEY_VLAN, x)
+
+/*      ANA:ANA_TABLES:MACHDATA */
+#define ANA_MACHDATA              __REG(TARGET_ANA, 0, 1, 27520, 0, 1, 128, 40, 0, 1, 4)
+
+/*      ANA:ANA_TABLES:MACLDATA */
+#define ANA_MACLDATA              __REG(TARGET_ANA, 0, 1, 27520, 0, 1, 128, 44, 0, 1, 4)
+
+/*      ANA:ANA_TABLES:MACACCESS */
+#define ANA_MACACCESS             __REG(TARGET_ANA, 0, 1, 27520, 0, 1, 128, 48, 0, 1, 4)
+
+#define ANA_MACACCESS_CHANGE2SW                  BIT(17)
+#define ANA_MACACCESS_CHANGE2SW_SET(x)\
+	FIELD_PREP(ANA_MACACCESS_CHANGE2SW, x)
+#define ANA_MACACCESS_CHANGE2SW_GET(x)\
+	FIELD_GET(ANA_MACACCESS_CHANGE2SW, x)
+
+#define ANA_MACACCESS_VALID                      BIT(12)
+#define ANA_MACACCESS_VALID_SET(x)\
+	FIELD_PREP(ANA_MACACCESS_VALID, x)
+#define ANA_MACACCESS_VALID_GET(x)\
+	FIELD_GET(ANA_MACACCESS_VALID, x)
+
+#define ANA_MACACCESS_ENTRYTYPE                  GENMASK(11, 10)
+#define ANA_MACACCESS_ENTRYTYPE_SET(x)\
+	FIELD_PREP(ANA_MACACCESS_ENTRYTYPE, x)
+#define ANA_MACACCESS_ENTRYTYPE_GET(x)\
+	FIELD_GET(ANA_MACACCESS_ENTRYTYPE, x)
+
+#define ANA_MACACCESS_DEST_IDX                   GENMASK(9, 4)
+#define ANA_MACACCESS_DEST_IDX_SET(x)\
+	FIELD_PREP(ANA_MACACCESS_DEST_IDX, x)
+#define ANA_MACACCESS_DEST_IDX_GET(x)\
+	FIELD_GET(ANA_MACACCESS_DEST_IDX, x)
+
+#define ANA_MACACCESS_MAC_TABLE_CMD              GENMASK(3, 0)
+#define ANA_MACACCESS_MAC_TABLE_CMD_SET(x)\
+	FIELD_PREP(ANA_MACACCESS_MAC_TABLE_CMD, x)
+#define ANA_MACACCESS_MAC_TABLE_CMD_GET(x)\
+	FIELD_GET(ANA_MACACCESS_MAC_TABLE_CMD, x)
+
+/*      ANA:PORT:CPU_FWD_CFG */
+#define ANA_CPU_FWD_CFG(g)        __REG(TARGET_ANA, 0, 1, 28672, g, 9, 128, 96, 0, 1, 4)
+
+#define ANA_CPU_FWD_CFG_SRC_COPY_ENA             BIT(3)
+#define ANA_CPU_FWD_CFG_SRC_COPY_ENA_SET(x)\
+	FIELD_PREP(ANA_CPU_FWD_CFG_SRC_COPY_ENA, x)
+#define ANA_CPU_FWD_CFG_SRC_COPY_ENA_GET(x)\
+	FIELD_GET(ANA_CPU_FWD_CFG_SRC_COPY_ENA, x)
+
+/*      ANA:PORT:CPU_FWD_BPDU_CFG */
+#define ANA_CPU_FWD_BPDU_CFG(g)   __REG(TARGET_ANA, 0, 1, 28672, g, 9, 128, 100, 0, 1, 4)
+
+/*      ANA:PORT:PORT_CFG */
+#define ANA_PORT_CFG(g)           __REG(TARGET_ANA, 0, 1, 28672, g, 9, 128, 112, 0, 1, 4)
+
+#define ANA_PORT_CFG_LEARNAUTO                   BIT(6)
+#define ANA_PORT_CFG_LEARNAUTO_SET(x)\
+	FIELD_PREP(ANA_PORT_CFG_LEARNAUTO, x)
+#define ANA_PORT_CFG_LEARNAUTO_GET(x)\
+	FIELD_GET(ANA_PORT_CFG_LEARNAUTO, x)
+
+#define ANA_PORT_CFG_RECV_ENA                    BIT(4)
+#define ANA_PORT_CFG_RECV_ENA_SET(x)\
+	FIELD_PREP(ANA_PORT_CFG_RECV_ENA, x)
+#define ANA_PORT_CFG_RECV_ENA_GET(x)\
+	FIELD_GET(ANA_PORT_CFG_RECV_ENA, x)
+
+#define ANA_PORT_CFG_PORTID_VAL                  GENMASK(3, 0)
+#define ANA_PORT_CFG_PORTID_VAL_SET(x)\
+	FIELD_PREP(ANA_PORT_CFG_PORTID_VAL, x)
+#define ANA_PORT_CFG_PORTID_VAL_GET(x)\
+	FIELD_GET(ANA_PORT_CFG_PORTID_VAL, x)
+
+/*      ANA:PFC:PFC_CFG */
+#define ANA_PFC_CFG(g)            __REG(TARGET_ANA, 0, 1, 30720, g, 8, 64, 0, 0, 1, 4)
+
+#define ANA_PFC_CFG_FC_LINK_SPEED                GENMASK(1, 0)
+#define ANA_PFC_CFG_FC_LINK_SPEED_SET(x)\
+	FIELD_PREP(ANA_PFC_CFG_FC_LINK_SPEED, x)
+#define ANA_PFC_CFG_FC_LINK_SPEED_GET(x)\
+	FIELD_GET(ANA_PFC_CFG_FC_LINK_SPEED, x)
+
+/*      CHIP_TOP:CUPHY_CFG:CUPHY_PORT_CFG */
+#define CHIP_TOP_CUPHY_PORT_CFG(r) __REG(TARGET_CHIP_TOP, 0, 1, 16, 0, 1, 20, 8, r, 2, 4)
+
+#define CHIP_TOP_CUPHY_PORT_CFG_GTX_CLK_ENA      BIT(0)
+#define CHIP_TOP_CUPHY_PORT_CFG_GTX_CLK_ENA_SET(x)\
+	FIELD_PREP(CHIP_TOP_CUPHY_PORT_CFG_GTX_CLK_ENA, x)
+#define CHIP_TOP_CUPHY_PORT_CFG_GTX_CLK_ENA_GET(x)\
+	FIELD_GET(CHIP_TOP_CUPHY_PORT_CFG_GTX_CLK_ENA, x)
+
+/*      CHIP_TOP:CUPHY_CFG:CUPHY_COMMON_CFG */
+#define CHIP_TOP_CUPHY_COMMON_CFG __REG(TARGET_CHIP_TOP, 0, 1, 16, 0, 1, 20, 16, 0, 1, 4)
+
+#define CHIP_TOP_CUPHY_COMMON_CFG_RESET_N        BIT(0)
+#define CHIP_TOP_CUPHY_COMMON_CFG_RESET_N_SET(x)\
+	FIELD_PREP(CHIP_TOP_CUPHY_COMMON_CFG_RESET_N, x)
+#define CHIP_TOP_CUPHY_COMMON_CFG_RESET_N_GET(x)\
+	FIELD_GET(CHIP_TOP_CUPHY_COMMON_CFG_RESET_N, x)
+
+/*      CPU:CPU_REGS:RESET_PROT_STAT */
+#define CPU_RESET_PROT_STAT       __REG(TARGET_CPU, 0, 1, 0, 0, 1, 168, 136, 0, 1, 4)
+
+#define CPU_RESET_PROT_STAT_SYS_RST_PROT_VCORE   BIT(5)
+#define CPU_RESET_PROT_STAT_SYS_RST_PROT_VCORE_SET(x)\
+	FIELD_PREP(CPU_RESET_PROT_STAT_SYS_RST_PROT_VCORE, x)
+#define CPU_RESET_PROT_STAT_SYS_RST_PROT_VCORE_GET(x)\
+	FIELD_GET(CPU_RESET_PROT_STAT_SYS_RST_PROT_VCORE, x)
+
+/*      DEV:PORT_MODE:CLOCK_CFG */
+#define DEV_CLOCK_CFG(t)          __REG(TARGET_DEV, t, 8, 0, 0, 1, 28, 0, 0, 1, 4)
+
+#define DEV_CLOCK_CFG_MAC_TX_RST                 BIT(7)
+#define DEV_CLOCK_CFG_MAC_TX_RST_SET(x)\
+	FIELD_PREP(DEV_CLOCK_CFG_MAC_TX_RST, x)
+#define DEV_CLOCK_CFG_MAC_TX_RST_GET(x)\
+	FIELD_GET(DEV_CLOCK_CFG_MAC_TX_RST, x)
+
+#define DEV_CLOCK_CFG_MAC_RX_RST                 BIT(6)
+#define DEV_CLOCK_CFG_MAC_RX_RST_SET(x)\
+	FIELD_PREP(DEV_CLOCK_CFG_MAC_RX_RST, x)
+#define DEV_CLOCK_CFG_MAC_RX_RST_GET(x)\
+	FIELD_GET(DEV_CLOCK_CFG_MAC_RX_RST, x)
+
+#define DEV_CLOCK_CFG_PCS_TX_RST                 BIT(5)
+#define DEV_CLOCK_CFG_PCS_TX_RST_SET(x)\
+	FIELD_PREP(DEV_CLOCK_CFG_PCS_TX_RST, x)
+#define DEV_CLOCK_CFG_PCS_TX_RST_GET(x)\
+	FIELD_GET(DEV_CLOCK_CFG_PCS_TX_RST, x)
+
+#define DEV_CLOCK_CFG_PCS_RX_RST                 BIT(4)
+#define DEV_CLOCK_CFG_PCS_RX_RST_SET(x)\
+	FIELD_PREP(DEV_CLOCK_CFG_PCS_RX_RST, x)
+#define DEV_CLOCK_CFG_PCS_RX_RST_GET(x)\
+	FIELD_GET(DEV_CLOCK_CFG_PCS_RX_RST, x)
+
+#define DEV_CLOCK_CFG_PORT_RST                   BIT(3)
+#define DEV_CLOCK_CFG_PORT_RST_SET(x)\
+	FIELD_PREP(DEV_CLOCK_CFG_PORT_RST, x)
+#define DEV_CLOCK_CFG_PORT_RST_GET(x)\
+	FIELD_GET(DEV_CLOCK_CFG_PORT_RST, x)
+
+#define DEV_CLOCK_CFG_LINK_SPEED                 GENMASK(1, 0)
+#define DEV_CLOCK_CFG_LINK_SPEED_SET(x)\
+	FIELD_PREP(DEV_CLOCK_CFG_LINK_SPEED, x)
+#define DEV_CLOCK_CFG_LINK_SPEED_GET(x)\
+	FIELD_GET(DEV_CLOCK_CFG_LINK_SPEED, x)
+
+/*      DEV:MAC_CFG_STATUS:MAC_ENA_CFG */
+#define DEV_MAC_ENA_CFG(t)        __REG(TARGET_DEV, t, 8, 28, 0, 1, 44, 0, 0, 1, 4)
+
+#define DEV_MAC_ENA_CFG_RX_ENA                   BIT(4)
+#define DEV_MAC_ENA_CFG_RX_ENA_SET(x)\
+	FIELD_PREP(DEV_MAC_ENA_CFG_RX_ENA, x)
+#define DEV_MAC_ENA_CFG_RX_ENA_GET(x)\
+	FIELD_GET(DEV_MAC_ENA_CFG_RX_ENA, x)
+
+#define DEV_MAC_ENA_CFG_TX_ENA                   BIT(0)
+#define DEV_MAC_ENA_CFG_TX_ENA_SET(x)\
+	FIELD_PREP(DEV_MAC_ENA_CFG_TX_ENA, x)
+#define DEV_MAC_ENA_CFG_TX_ENA_GET(x)\
+	FIELD_GET(DEV_MAC_ENA_CFG_TX_ENA, x)
+
+/*      DEV:MAC_CFG_STATUS:MAC_MODE_CFG */
+#define DEV_MAC_MODE_CFG(t)       __REG(TARGET_DEV, t, 8, 28, 0, 1, 44, 4, 0, 1, 4)
+
+#define DEV_MAC_MODE_CFG_GIGA_MODE_ENA           BIT(4)
+#define DEV_MAC_MODE_CFG_GIGA_MODE_ENA_SET(x)\
+	FIELD_PREP(DEV_MAC_MODE_CFG_GIGA_MODE_ENA, x)
+#define DEV_MAC_MODE_CFG_GIGA_MODE_ENA_GET(x)\
+	FIELD_GET(DEV_MAC_MODE_CFG_GIGA_MODE_ENA, x)
+
+/*      DEV:MAC_CFG_STATUS:MAC_MAXLEN_CFG */
+#define DEV_MAC_MAXLEN_CFG(t)     __REG(TARGET_DEV, t, 8, 28, 0, 1, 44, 8, 0, 1, 4)
+
+#define DEV_MAC_MAXLEN_CFG_MAX_LEN               GENMASK(15, 0)
+#define DEV_MAC_MAXLEN_CFG_MAX_LEN_SET(x)\
+	FIELD_PREP(DEV_MAC_MAXLEN_CFG_MAX_LEN, x)
+#define DEV_MAC_MAXLEN_CFG_MAX_LEN_GET(x)\
+	FIELD_GET(DEV_MAC_MAXLEN_CFG_MAX_LEN, x)
+
+/*      DEV:MAC_CFG_STATUS:MAC_IFG_CFG */
+#define DEV_MAC_IFG_CFG(t)        __REG(TARGET_DEV, t, 8, 28, 0, 1, 44, 20, 0, 1, 4)
+
+#define DEV_MAC_IFG_CFG_TX_IFG                   GENMASK(12, 8)
+#define DEV_MAC_IFG_CFG_TX_IFG_SET(x)\
+	FIELD_PREP(DEV_MAC_IFG_CFG_TX_IFG, x)
+#define DEV_MAC_IFG_CFG_TX_IFG_GET(x)\
+	FIELD_GET(DEV_MAC_IFG_CFG_TX_IFG, x)
+
+/*      DEV:MAC_CFG_STATUS:MAC_HDX_CFG */
+#define DEV_MAC_HDX_CFG(t)        __REG(TARGET_DEV, t, 8, 28, 0, 1, 44, 24, 0, 1, 4)
+
+#define DEV_MAC_HDX_CFG_SEED                     GENMASK(23, 16)
+#define DEV_MAC_HDX_CFG_SEED_SET(x)\
+	FIELD_PREP(DEV_MAC_HDX_CFG_SEED, x)
+#define DEV_MAC_HDX_CFG_SEED_GET(x)\
+	FIELD_GET(DEV_MAC_HDX_CFG_SEED, x)
+
+#define DEV_MAC_HDX_CFG_SEED_LOAD                BIT(12)
+#define DEV_MAC_HDX_CFG_SEED_LOAD_SET(x)\
+	FIELD_PREP(DEV_MAC_HDX_CFG_SEED_LOAD, x)
+#define DEV_MAC_HDX_CFG_SEED_LOAD_GET(x)\
+	FIELD_GET(DEV_MAC_HDX_CFG_SEED_LOAD, x)
+
+/*      DEV:MAC_CFG_STATUS:MAC_FC_MAC_LOW_CFG */
+#define DEV_FC_MAC_LOW_CFG(t)     __REG(TARGET_DEV, t, 8, 28, 0, 1, 44, 32, 0, 1, 4)
+
+/*      DEV:MAC_CFG_STATUS:MAC_FC_MAC_HIGH_CFG */
+#define DEV_FC_MAC_HIGH_CFG(t)    __REG(TARGET_DEV, t, 8, 28, 0, 1, 44, 36, 0, 1, 4)
+
+/*      DEV:PCS1G_CFG_STATUS:PCS1G_CFG */
+#define DEV_PCS1G_CFG(t)          __REG(TARGET_DEV, t, 8, 72, 0, 1, 68, 0, 0, 1, 4)
+
+#define DEV_PCS1G_CFG_PCS_ENA                    BIT(0)
+#define DEV_PCS1G_CFG_PCS_ENA_SET(x)\
+	FIELD_PREP(DEV_PCS1G_CFG_PCS_ENA, x)
+#define DEV_PCS1G_CFG_PCS_ENA_GET(x)\
+	FIELD_GET(DEV_PCS1G_CFG_PCS_ENA, x)
+
+/*      DEV:PCS1G_CFG_STATUS:PCS1G_SD_CFG */
+#define DEV_PCS1G_SD_CFG(t)       __REG(TARGET_DEV, t, 8, 72, 0, 1, 68, 8, 0, 1, 4)
+
+#define DEV_PCS1G_SD_CFG_SD_ENA                  BIT(0)
+#define DEV_PCS1G_SD_CFG_SD_ENA_SET(x)\
+	FIELD_PREP(DEV_PCS1G_SD_CFG_SD_ENA, x)
+#define DEV_PCS1G_SD_CFG_SD_ENA_GET(x)\
+	FIELD_GET(DEV_PCS1G_SD_CFG_SD_ENA, x)
+
+/*      DEVCPU_GCB:CHIP_REGS:SOFT_RST */
+#define GCB_SOFT_RST              __REG(TARGET_GCB, 0, 1, 0, 0, 1, 68, 12, 0, 1, 4)
+
+/*      HSIO:HW_CFGSTAT:HW_CFG */
+#define HSIO_HW_CFG               __REG(TARGET_HSIO, 0, 1, 104, 0, 1, 52, 0, 0, 1, 4)
+
+#define HSIO_HW_CFG_RGMII_1_CFG                  BIT(15)
+#define HSIO_HW_CFG_RGMII_1_CFG_SET(x)\
+	FIELD_PREP(HSIO_HW_CFG_RGMII_1_CFG, x)
+#define HSIO_HW_CFG_RGMII_1_CFG_GET(x)\
+	FIELD_GET(HSIO_HW_CFG_RGMII_1_CFG, x)
+
+#define HSIO_HW_CFG_RGMII_0_CFG                  BIT(14)
+#define HSIO_HW_CFG_RGMII_0_CFG_SET(x)\
+	FIELD_PREP(HSIO_HW_CFG_RGMII_0_CFG, x)
+#define HSIO_HW_CFG_RGMII_0_CFG_GET(x)\
+	FIELD_GET(HSIO_HW_CFG_RGMII_0_CFG, x)
+
+#define HSIO_HW_CFG_RGMII_ENA                    GENMASK(13, 12)
+#define HSIO_HW_CFG_RGMII_ENA_SET(x)\
+	FIELD_PREP(HSIO_HW_CFG_RGMII_ENA, x)
+#define HSIO_HW_CFG_RGMII_ENA_GET(x)\
+	FIELD_GET(HSIO_HW_CFG_RGMII_ENA, x)
+
+#define HSIO_HW_CFG_SD6G_0_CFG                   BIT(11)
+#define HSIO_HW_CFG_SD6G_0_CFG_SET(x)\
+	FIELD_PREP(HSIO_HW_CFG_SD6G_0_CFG, x)
+#define HSIO_HW_CFG_SD6G_0_CFG_GET(x)\
+	FIELD_GET(HSIO_HW_CFG_SD6G_0_CFG, x)
+
+#define HSIO_HW_CFG_SD6G_1_CFG                   BIT(10)
+#define HSIO_HW_CFG_SD6G_1_CFG_SET(x)\
+	FIELD_PREP(HSIO_HW_CFG_SD6G_1_CFG, x)
+#define HSIO_HW_CFG_SD6G_1_CFG_GET(x)\
+	FIELD_GET(HSIO_HW_CFG_SD6G_1_CFG, x)
+
+#define HSIO_HW_CFG_GMII_ENA                     GENMASK(9, 2)
+#define HSIO_HW_CFG_GMII_ENA_SET(x)\
+	FIELD_PREP(HSIO_HW_CFG_GMII_ENA, x)
+#define HSIO_HW_CFG_GMII_ENA_GET(x)\
+	FIELD_GET(HSIO_HW_CFG_GMII_ENA, x)
+
+#define HSIO_HW_CFG_QSGMII_ENA                   GENMASK(1, 0)
+#define HSIO_HW_CFG_QSGMII_ENA_SET(x)\
+	FIELD_PREP(HSIO_HW_CFG_QSGMII_ENA, x)
+#define HSIO_HW_CFG_QSGMII_ENA_GET(x)\
+	FIELD_GET(HSIO_HW_CFG_QSGMII_ENA, x)
+
+/*      DEVCPU_QS:XTR:XTR_GRP_CFG */
+#define QS_XTR_GRP_CFG(r)         __REG(TARGET_QS, 0, 1, 0, 0, 1, 36, 0, r, 2, 4)
+
+#define QS_XTR_GRP_CFG_MODE                      GENMASK(3, 2)
+#define QS_XTR_GRP_CFG_MODE_SET(x)\
+	FIELD_PREP(QS_XTR_GRP_CFG_MODE, x)
+#define QS_XTR_GRP_CFG_MODE_GET(x)\
+	FIELD_GET(QS_XTR_GRP_CFG_MODE, x)
+
+#define QS_XTR_GRP_CFG_BYTE_SWAP                 BIT(0)
+#define QS_XTR_GRP_CFG_BYTE_SWAP_SET(x)\
+	FIELD_PREP(QS_XTR_GRP_CFG_BYTE_SWAP, x)
+#define QS_XTR_GRP_CFG_BYTE_SWAP_GET(x)\
+	FIELD_GET(QS_XTR_GRP_CFG_BYTE_SWAP, x)
+
+/*      DEVCPU_QS:XTR:XTR_RD */
+#define QS_XTR_RD(r)              __REG(TARGET_QS, 0, 1, 0, 0, 1, 36, 8, r, 2, 4)
+
+/*      DEVCPU_QS:XTR:XTR_FLUSH */
+#define QS_XTR_FLUSH              __REG(TARGET_QS, 0, 1, 0, 0, 1, 36, 24, 0, 1, 4)
+
+/*      DEVCPU_QS:XTR:XTR_DATA_PRESENT */
+#define QS_XTR_DATA_PRESENT       __REG(TARGET_QS, 0, 1, 0, 0, 1, 36, 28, 0, 1, 4)
+
+/*      DEVCPU_QS:INJ:INJ_GRP_CFG */
+#define QS_INJ_GRP_CFG(r)         __REG(TARGET_QS, 0, 1, 36, 0, 1, 40, 0, r, 2, 4)
+
+#define QS_INJ_GRP_CFG_MODE                      GENMASK(3, 2)
+#define QS_INJ_GRP_CFG_MODE_SET(x)\
+	FIELD_PREP(QS_INJ_GRP_CFG_MODE, x)
+#define QS_INJ_GRP_CFG_MODE_GET(x)\
+	FIELD_GET(QS_INJ_GRP_CFG_MODE, x)
+
+#define QS_INJ_GRP_CFG_BYTE_SWAP                 BIT(0)
+#define QS_INJ_GRP_CFG_BYTE_SWAP_SET(x)\
+	FIELD_PREP(QS_INJ_GRP_CFG_BYTE_SWAP, x)
+#define QS_INJ_GRP_CFG_BYTE_SWAP_GET(x)\
+	FIELD_GET(QS_INJ_GRP_CFG_BYTE_SWAP, x)
+
+/*      DEVCPU_QS:INJ:INJ_WR */
+#define QS_INJ_WR(r)              __REG(TARGET_QS, 0, 1, 36, 0, 1, 40, 8, r, 2, 4)
+
+/*      DEVCPU_QS:INJ:INJ_CTRL */
+#define QS_INJ_CTRL(r)            __REG(TARGET_QS, 0, 1, 36, 0, 1, 40, 16, r, 2, 4)
+
+#define QS_INJ_CTRL_GAP_SIZE                     GENMASK(24, 21)
+#define QS_INJ_CTRL_GAP_SIZE_SET(x)\
+	FIELD_PREP(QS_INJ_CTRL_GAP_SIZE, x)
+#define QS_INJ_CTRL_GAP_SIZE_GET(x)\
+	FIELD_GET(QS_INJ_CTRL_GAP_SIZE, x)
+
+#define QS_INJ_CTRL_EOF                          BIT(19)
+#define QS_INJ_CTRL_EOF_SET(x)\
+	FIELD_PREP(QS_INJ_CTRL_EOF, x)
+#define QS_INJ_CTRL_EOF_GET(x)\
+	FIELD_GET(QS_INJ_CTRL_EOF, x)
+
+#define QS_INJ_CTRL_SOF                          BIT(18)
+#define QS_INJ_CTRL_SOF_SET(x)\
+	FIELD_PREP(QS_INJ_CTRL_SOF, x)
+#define QS_INJ_CTRL_SOF_GET(x)\
+	FIELD_GET(QS_INJ_CTRL_SOF, x)
+
+#define QS_INJ_CTRL_VLD_BYTES                    GENMASK(17, 16)
+#define QS_INJ_CTRL_VLD_BYTES_SET(x)\
+	FIELD_PREP(QS_INJ_CTRL_VLD_BYTES, x)
+#define QS_INJ_CTRL_VLD_BYTES_GET(x)\
+	FIELD_GET(QS_INJ_CTRL_VLD_BYTES, x)
+
+/*      DEVCPU_QS:INJ:INJ_STATUS */
+#define QS_INJ_STATUS             __REG(TARGET_QS, 0, 1, 36, 0, 1, 40, 24, 0, 1, 4)
+
+#define QS_INJ_STATUS_WMARK_REACHED              GENMASK(5, 4)
+#define QS_INJ_STATUS_WMARK_REACHED_SET(x)\
+	FIELD_PREP(QS_INJ_STATUS_WMARK_REACHED, x)
+#define QS_INJ_STATUS_WMARK_REACHED_GET(x)\
+	FIELD_GET(QS_INJ_STATUS_WMARK_REACHED, x)
+
+#define QS_INJ_STATUS_FIFO_RDY                   GENMASK(3, 2)
+#define QS_INJ_STATUS_FIFO_RDY_SET(x)\
+	FIELD_PREP(QS_INJ_STATUS_FIFO_RDY, x)
+#define QS_INJ_STATUS_FIFO_RDY_GET(x)\
+	FIELD_GET(QS_INJ_STATUS_FIFO_RDY, x)
+
+/*      QSYS:SYSTEM:PORT_MODE */
+#define QSYS_PORT_MODE(r)         __REG(TARGET_QSYS, 0, 1, 28008, 0, 1, 216, 0, r, 10, 4)
+
+#define QSYS_PORT_MODE_DEQUEUE_DIS               BIT(1)
+#define QSYS_PORT_MODE_DEQUEUE_DIS_SET(x)\
+	FIELD_PREP(QSYS_PORT_MODE_DEQUEUE_DIS, x)
+#define QSYS_PORT_MODE_DEQUEUE_DIS_GET(x)\
+	FIELD_GET(QSYS_PORT_MODE_DEQUEUE_DIS, x)
+
+/*      QSYS:SYSTEM:SWITCH_PORT_MODE */
+#define QSYS_SW_PORT_MODE(r)      __REG(TARGET_QSYS, 0, 1, 28008, 0, 1, 216, 80, r, 9, 4)
+
+#define QSYS_SW_PORT_MODE_PORT_ENA               BIT(18)
+#define QSYS_SW_PORT_MODE_PORT_ENA_SET(x)\
+	FIELD_PREP(QSYS_SW_PORT_MODE_PORT_ENA, x)
+#define QSYS_SW_PORT_MODE_PORT_ENA_GET(x)\
+	FIELD_GET(QSYS_SW_PORT_MODE_PORT_ENA, x)
+
+#define QSYS_SW_PORT_MODE_SCH_NEXT_CFG           GENMASK(16, 14)
+#define QSYS_SW_PORT_MODE_SCH_NEXT_CFG_SET(x)\
+	FIELD_PREP(QSYS_SW_PORT_MODE_SCH_NEXT_CFG, x)
+#define QSYS_SW_PORT_MODE_SCH_NEXT_CFG_GET(x)\
+	FIELD_GET(QSYS_SW_PORT_MODE_SCH_NEXT_CFG, x)
+
+#define QSYS_SW_PORT_MODE_INGRESS_DROP_MODE      BIT(12)
+#define QSYS_SW_PORT_MODE_INGRESS_DROP_MODE_SET(x)\
+	FIELD_PREP(QSYS_SW_PORT_MODE_INGRESS_DROP_MODE, x)
+#define QSYS_SW_PORT_MODE_INGRESS_DROP_MODE_GET(x)\
+	FIELD_GET(QSYS_SW_PORT_MODE_INGRESS_DROP_MODE, x)
+
+#define QSYS_SW_PORT_MODE_TX_PFC_ENA             GENMASK(11, 4)
+#define QSYS_SW_PORT_MODE_TX_PFC_ENA_SET(x)\
+	FIELD_PREP(QSYS_SW_PORT_MODE_TX_PFC_ENA, x)
+#define QSYS_SW_PORT_MODE_TX_PFC_ENA_GET(x)\
+	FIELD_GET(QSYS_SW_PORT_MODE_TX_PFC_ENA, x)
+
+#define QSYS_SW_PORT_MODE_AGING_MODE             GENMASK(1, 0)
+#define QSYS_SW_PORT_MODE_AGING_MODE_SET(x)\
+	FIELD_PREP(QSYS_SW_PORT_MODE_AGING_MODE, x)
+#define QSYS_SW_PORT_MODE_AGING_MODE_GET(x)\
+	FIELD_GET(QSYS_SW_PORT_MODE_AGING_MODE, x)
+
+/*      QSYS:SYSTEM:SW_STATUS */
+#define QSYS_SW_STATUS(r)         __REG(TARGET_QSYS, 0, 1, 28008, 0, 1, 216, 164, r, 9, 4)
+
+#define QSYS_SW_STATUS_EQ_AVAIL                  GENMASK(7, 0)
+#define QSYS_SW_STATUS_EQ_AVAIL_SET(x)\
+	FIELD_PREP(QSYS_SW_STATUS_EQ_AVAIL, x)
+#define QSYS_SW_STATUS_EQ_AVAIL_GET(x)\
+	FIELD_GET(QSYS_SW_STATUS_EQ_AVAIL, x)
+
+/*      QSYS:SYSTEM:CPU_GROUP_MAP */
+#define QSYS_CPU_GROUP_MAP        __REG(TARGET_QSYS, 0, 1, 28008, 0, 1, 216, 204, 0, 1, 4)
+
+/*      QSYS:RES_CTRL:RES_CFG */
+#define QSYS_RES_CFG(g)           __REG(TARGET_QSYS, 0, 1, 32768, g, 1024, 8, 0, 0, 1, 4)
+
+/*      REW:PORT:PORT_CFG */
+#define REW_PORT_CFG(g)           __REG(TARGET_REW, 0, 1, 0, g, 10, 128, 8, 0, 1, 4)
+
+#define REW_PORT_CFG_NO_REWRITE                  BIT(0)
+#define REW_PORT_CFG_NO_REWRITE_SET(x)\
+	FIELD_PREP(REW_PORT_CFG_NO_REWRITE, x)
+#define REW_PORT_CFG_NO_REWRITE_GET(x)\
+	FIELD_GET(REW_PORT_CFG_NO_REWRITE, x)
+
+/*      SYS:SYSTEM:RESET_CFG */
+#define SYS_RESET_CFG             __REG(TARGET_SYS, 0, 1, 4128, 0, 1, 168, 0, 0, 1, 4)
+
+#define SYS_RESET_CFG_CORE_ENA                   BIT(0)
+#define SYS_RESET_CFG_CORE_ENA_SET(x)\
+	FIELD_PREP(SYS_RESET_CFG_CORE_ENA, x)
+#define SYS_RESET_CFG_CORE_ENA_GET(x)\
+	FIELD_GET(SYS_RESET_CFG_CORE_ENA, x)
+
+/*      SYS:SYSTEM:PORT_MODE */
+#define SYS_PORT_MODE(r)          __REG(TARGET_SYS, 0, 1, 4128, 0, 1, 168, 44, r, 10, 4)
+
+#define SYS_PORT_MODE_INCL_INJ_HDR               GENMASK(5, 4)
+#define SYS_PORT_MODE_INCL_INJ_HDR_SET(x)\
+	FIELD_PREP(SYS_PORT_MODE_INCL_INJ_HDR, x)
+#define SYS_PORT_MODE_INCL_INJ_HDR_GET(x)\
+	FIELD_GET(SYS_PORT_MODE_INCL_INJ_HDR, x)
+
+#define SYS_PORT_MODE_INCL_XTR_HDR               GENMASK(3, 2)
+#define SYS_PORT_MODE_INCL_XTR_HDR_SET(x)\
+	FIELD_PREP(SYS_PORT_MODE_INCL_XTR_HDR, x)
+#define SYS_PORT_MODE_INCL_XTR_HDR_GET(x)\
+	FIELD_GET(SYS_PORT_MODE_INCL_XTR_HDR, x)
+
+/*      SYS:SYSTEM:FRONT_PORT_MODE */
+#define SYS_FRONT_PORT_MODE(r)    __REG(TARGET_SYS, 0, 1, 4128, 0, 1, 168, 84, r, 8, 4)
+
+#define SYS_FRONT_PORT_MODE_HDX_MODE             BIT(1)
+#define SYS_FRONT_PORT_MODE_HDX_MODE_SET(x)\
+	FIELD_PREP(SYS_FRONT_PORT_MODE_HDX_MODE, x)
+#define SYS_FRONT_PORT_MODE_HDX_MODE_GET(x)\
+	FIELD_GET(SYS_FRONT_PORT_MODE_HDX_MODE, x)
+
+/*      SYS:SYSTEM:FRM_AGING */
+#define SYS_FRM_AGING             __REG(TARGET_SYS, 0, 1, 4128, 0, 1, 168, 116, 0, 1, 4)
+
+#define SYS_FRM_AGING_AGE_TX_ENA                 BIT(20)
+#define SYS_FRM_AGING_AGE_TX_ENA_SET(x)\
+	FIELD_PREP(SYS_FRM_AGING_AGE_TX_ENA, x)
+#define SYS_FRM_AGING_AGE_TX_ENA_GET(x)\
+	FIELD_GET(SYS_FRM_AGING_AGE_TX_ENA, x)
+
+/*      SYS:SYSTEM:STAT_CFG */
+#define SYS_STAT_CFG              __REG(TARGET_SYS, 0, 1, 4128, 0, 1, 168, 120, 0, 1, 4)
+
+#define SYS_STAT_CFG_STAT_VIEW                   GENMASK(9, 0)
+#define SYS_STAT_CFG_STAT_VIEW_SET(x)\
+	FIELD_PREP(SYS_STAT_CFG_STAT_VIEW, x)
+#define SYS_STAT_CFG_STAT_VIEW_GET(x)\
+	FIELD_GET(SYS_STAT_CFG_STAT_VIEW, x)
+
+/*      SYS:PAUSE_CFG:PAUSE_CFG */
+#define SYS_PAUSE_CFG(r)          __REG(TARGET_SYS, 0, 1, 4296, 0, 1, 112, 0, r, 9, 4)
+
+#define SYS_PAUSE_CFG_PAUSE_START                GENMASK(18, 10)
+#define SYS_PAUSE_CFG_PAUSE_START_SET(x)\
+	FIELD_PREP(SYS_PAUSE_CFG_PAUSE_START, x)
+#define SYS_PAUSE_CFG_PAUSE_START_GET(x)\
+	FIELD_GET(SYS_PAUSE_CFG_PAUSE_START, x)
+
+#define SYS_PAUSE_CFG_PAUSE_STOP                 GENMASK(9, 1)
+#define SYS_PAUSE_CFG_PAUSE_STOP_SET(x)\
+	FIELD_PREP(SYS_PAUSE_CFG_PAUSE_STOP, x)
+#define SYS_PAUSE_CFG_PAUSE_STOP_GET(x)\
+	FIELD_GET(SYS_PAUSE_CFG_PAUSE_STOP, x)
+
+#define SYS_PAUSE_CFG_PAUSE_ENA                  BIT(0)
+#define SYS_PAUSE_CFG_PAUSE_ENA_SET(x)\
+	FIELD_PREP(SYS_PAUSE_CFG_PAUSE_ENA, x)
+#define SYS_PAUSE_CFG_PAUSE_ENA_GET(x)\
+	FIELD_GET(SYS_PAUSE_CFG_PAUSE_ENA, x)
+
+/*      SYS:PAUSE_CFG:ATOP */
+#define SYS_ATOP(r)               __REG(TARGET_SYS, 0, 1, 4296, 0, 1, 112, 40, r, 9, 4)
+
+/*      SYS:PAUSE_CFG:ATOP_TOT_CFG */
+#define SYS_ATOP_TOT_CFG          __REG(TARGET_SYS, 0, 1, 4296, 0, 1, 112, 76, 0, 1, 4)
+
+/*      SYS:PAUSE_CFG:MAC_FC_CFG */
+#define SYS_MAC_FC_CFG(r)         __REG(TARGET_SYS, 0, 1, 4296, 0, 1, 112, 80, r, 8, 4)
+
+#define SYS_MAC_FC_CFG_FC_LINK_SPEED             GENMASK(27, 26)
+#define SYS_MAC_FC_CFG_FC_LINK_SPEED_SET(x)\
+	FIELD_PREP(SYS_MAC_FC_CFG_FC_LINK_SPEED, x)
+#define SYS_MAC_FC_CFG_FC_LINK_SPEED_GET(x)\
+	FIELD_GET(SYS_MAC_FC_CFG_FC_LINK_SPEED, x)
+
+#define SYS_MAC_FC_CFG_FC_LATENCY_CFG            GENMASK(25, 20)
+#define SYS_MAC_FC_CFG_FC_LATENCY_CFG_SET(x)\
+	FIELD_PREP(SYS_MAC_FC_CFG_FC_LATENCY_CFG, x)
+#define SYS_MAC_FC_CFG_FC_LATENCY_CFG_GET(x)\
+	FIELD_GET(SYS_MAC_FC_CFG_FC_LATENCY_CFG, x)
+
+#define SYS_MAC_FC_CFG_ZERO_PAUSE_ENA            BIT(18)
+#define SYS_MAC_FC_CFG_ZERO_PAUSE_ENA_SET(x)\
+	FIELD_PREP(SYS_MAC_FC_CFG_ZERO_PAUSE_ENA, x)
+#define SYS_MAC_FC_CFG_ZERO_PAUSE_ENA_GET(x)\
+	FIELD_GET(SYS_MAC_FC_CFG_ZERO_PAUSE_ENA, x)
+
+#define SYS_MAC_FC_CFG_TX_FC_ENA                 BIT(17)
+#define SYS_MAC_FC_CFG_TX_FC_ENA_SET(x)\
+	FIELD_PREP(SYS_MAC_FC_CFG_TX_FC_ENA, x)
+#define SYS_MAC_FC_CFG_TX_FC_ENA_GET(x)\
+	FIELD_GET(SYS_MAC_FC_CFG_TX_FC_ENA, x)
+
+#define SYS_MAC_FC_CFG_RX_FC_ENA                 BIT(16)
+#define SYS_MAC_FC_CFG_RX_FC_ENA_SET(x)\
+	FIELD_PREP(SYS_MAC_FC_CFG_RX_FC_ENA, x)
+#define SYS_MAC_FC_CFG_RX_FC_ENA_GET(x)\
+	FIELD_GET(SYS_MAC_FC_CFG_RX_FC_ENA, x)
+
+#define SYS_MAC_FC_CFG_PAUSE_VAL_CFG             GENMASK(15, 0)
+#define SYS_MAC_FC_CFG_PAUSE_VAL_CFG_SET(x)\
+	FIELD_PREP(SYS_MAC_FC_CFG_PAUSE_VAL_CFG, x)
+#define SYS_MAC_FC_CFG_PAUSE_VAL_CFG_GET(x)\
+	FIELD_GET(SYS_MAC_FC_CFG_PAUSE_VAL_CFG, x)
+
+/*      SYS:STAT:CNT */
+#define SYS_CNT(g)                __REG(TARGET_SYS, 0, 1, 0, g, 896, 4, 0, 0, 1, 4)
+
+/*      SYS:RAM_CTRL:RAM_INIT */
+#define SYS_RAM_INIT              __REG(TARGET_SYS, 0, 1, 4432, 0, 1, 4, 0, 0, 1, 4)
+
+#define SYS_RAM_INIT_RAM_INIT                    BIT(1)
+#define SYS_RAM_INIT_RAM_INIT_SET(x)\
+	FIELD_PREP(SYS_RAM_INIT_RAM_INIT, x)
+#define SYS_RAM_INIT_RAM_INIT_GET(x)\
+	FIELD_GET(SYS_RAM_INIT_RAM_INIT, x)
+
+#endif /* _LAN966X_REGS_H_ */
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [RFC PATCH net-next 10/12] net: lan966x: add port module support
  2021-09-20  9:52 [RFC PATCH net-next 00/12] Add lan966x driver Horatiu Vultur
                   ` (8 preceding siblings ...)
  2021-09-20  9:52 ` [RFC PATCH net-next 09/12] net: lan966x: add the basic lan966x driver Horatiu Vultur
@ 2021-09-20  9:52 ` Horatiu Vultur
  2021-09-20 13:54   ` Russell King (Oracle)
  2021-09-20  9:52 ` [RFC PATCH net-next 11/12] net: lan966x: add mactable support Horatiu Vultur
  2021-09-20  9:52 ` [RFC PATCH net-next 12/12] net: lan966x: add ethtool configuration and statistics Horatiu Vultur
  11 siblings, 1 reply; 30+ messages in thread
From: Horatiu Vultur @ 2021-09-20  9:52 UTC (permalink / raw)
  To: davem, kuba, robh+dt, andrew, linux, f.fainelli,
	alexandre.belloni, vladimir.oltean, UNGLinuxDriver, netdev,
	devicetree, linux-kernel, linux-phy, linux-pm
  Cc: Horatiu Vultur

This patch adds support for netdev and phylink in the switch. The
injection + extraction is register based. This will be replaced with DMA
accees.

Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
---
 .../net/ethernet/microchip/lan966x/Makefile   |   2 +-
 .../ethernet/microchip/lan966x/lan966x_ifh.h  | 173 +++++++
 .../ethernet/microchip/lan966x/lan966x_main.c | 481 +++++++++++++++++-
 .../ethernet/microchip/lan966x/lan966x_main.h |  38 ++
 .../microchip/lan966x/lan966x_phylink.c       |  92 ++++
 .../ethernet/microchip/lan966x/lan966x_port.c | 301 +++++++++++
 6 files changed, 1083 insertions(+), 4 deletions(-)
 create mode 100644 drivers/net/ethernet/microchip/lan966x/lan966x_ifh.h
 create mode 100644 drivers/net/ethernet/microchip/lan966x/lan966x_phylink.c
 create mode 100644 drivers/net/ethernet/microchip/lan966x/lan966x_port.c

diff --git a/drivers/net/ethernet/microchip/lan966x/Makefile b/drivers/net/ethernet/microchip/lan966x/Makefile
index 7ea90410a0b2..e18c9b2d0bb7 100644
--- a/drivers/net/ethernet/microchip/lan966x/Makefile
+++ b/drivers/net/ethernet/microchip/lan966x/Makefile
@@ -5,4 +5,4 @@
 
 obj-$(CONFIG_LAN966X_SWITCH) += lan966x-switch.o
 
-lan966x-switch-objs  := lan966x_main.o
+lan966x-switch-objs  := lan966x_main.o lan966x_phylink.o lan966x_port.o
diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_ifh.h b/drivers/net/ethernet/microchip/lan966x/lan966x_ifh.h
new file mode 100644
index 000000000000..ca3314789d18
--- /dev/null
+++ b/drivers/net/ethernet/microchip/lan966x/lan966x_ifh.h
@@ -0,0 +1,173 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+#ifndef __LAN966X_IFH_H__
+#define __LAN966X_IFH_H__
+
+/* Fields with description (*) should just be cleared upon injection
+ * IFH is transmitted MSByte first (Highest bit pos sent as MSB of first byte)
+ */
+
+#define IFH_LEN                      7
+
+/* Timestamp for frame */
+#define IFH_POS_TIMESTAMP            192
+
+/* Bypass analyzer with a prefilled IFH */
+#define IFH_POS_BYPASS               191
+
+/* Masqueraded injection with masq_port defining logical source port */
+#define IFH_POS_MASQ                 190
+
+/* Masqueraded port number for injection */
+#define IFH_POS_MASQ_PORT            186
+
+/* Frame length (*) */
+#define IFH_POS_LEN                  178
+
+/* Cell filling mode. Full(0),Etype(1), LlctOpt(2), Llct(3) */
+#define IFH_POS_WRDMODE              176
+
+/* Frame has 16 bits rtag removed compared to line data */
+#define IFH_POS_RTAG48               175
+
+/* Frame has a redundancy tag */
+#define IFH_POS_HAS_RED_TAG          174
+
+/* Frame has been cut through forwarded (*) */
+#define IFH_POS_CUTTHRU              173
+
+/* Rewriter command */
+#define IFH_POS_REW_CMD              163
+
+/* Enable OAM-related rewriting. PDU_TYPE encodes OAM type. */
+#define IFH_POS_REW_OAM              162
+
+/* PDU type. Encoding: (0-NONE, 1-Y1731_CCM, 2-MRP_TST, 3-MRP_ITST, 4-DLR_BCN,
+ * 5-DLR_ADV, 6-RTE_NULL_INJ, 7-IPV4, 8-IPV6, 9-Y1731_NON_CCM).
+ */
+#define IFH_POS_PDU_TYPE             158
+
+/* Update FCS before transmission */
+#define IFH_POS_FCS_UPD              157
+
+/* Classified DSCP value of frame */
+#define IFH_POS_DSCP                 151
+
+/* Yellow indication */
+#define IFH_POS_DP                   150
+
+/* Process in RTE/inbound */
+#define IFH_POS_RTE_INB_UPDATE       149
+
+/* Number of tags to pop from frame */
+#define IFH_POS_POP_CNT              147
+
+/* Number of tags in front of the ethertype */
+#define IFH_POS_ETYPE_OFS            145
+
+/* Logical source port of frame (*) */
+#define IFH_POS_SRCPORT              141
+
+/* Sequence number in redundancy tag */
+#define IFH_POS_SEQ_NUM              120
+
+/* Stagd flag and classified TCI of frame (PCP/DEI/VID) */
+#define IFH_POS_TCI                  103
+
+/* Classified internal priority for queuing */
+#define IFH_POS_QOS_CLASS            100
+
+/* Bit mask with eight cpu copy classses */
+#define IFH_POS_CPUQ                 92
+
+/* Relearn + learn flags (*) */
+#define IFH_POS_LEARN_FLAGS          90
+
+/* SFLOW identifier for frame (0-8: Tx port, 9: Rx sampling, 15: No sampling) */
+#define IFH_POS_SFLOW_ID             86
+
+/* Set if an ACL/S2 rule was hit (*).
+ * Super priority: acl_hit=0 and acl_hit(4)=1.
+ */
+#define IFH_POS_ACL_HIT              85
+
+/* S2 rule index hit (*) */
+#define IFH_POS_ACL_IDX              79
+
+/* ISDX as classified by S1 */
+#define IFH_POS_ISDX                 71
+
+/* Destination ports for frame */
+#define IFH_POS_DSTS                 62
+
+/* Storm policer to be applied: None/Uni/Multi/Broad (*) */
+#define IFH_POS_FLOOD                60
+
+/* Redundancy tag operation */
+#define IFH_POS_SEQ_OP               58
+
+/* Classified internal priority for resourcemgt, tagging etc */
+#define IFH_POS_IPV                  55
+
+/* Frame is for AFI use */
+#define IFH_POS_AFI                  54
+
+/* Internal aging value (*) */
+#define IFH_POS_AGED                 52
+
+/* RTP Identifier */
+#define IFH_POS_RTP_ID               42
+
+/* RTP MRPD flow */
+#define IFH_POS_RTP_SUBID            41
+
+/* Profinet DataStatus or opcua GroupVersion MSB */
+#define IFH_POS_PN_DATA_STATUS       33
+
+/* Profinet transfer status (1 iff the status is 0) */
+#define IFH_POS_PN_TRANSF_STATUS_ZERO 32
+
+/* Profinet cycle counter or opcua NetworkMessageNumber */
+#define IFH_POS_PN_CC                16
+
+#define IFH_WID_TIMESTAMP            32
+#define IFH_WID_BYPASS               1
+#define IFH_WID_MASQ                 1
+#define IFH_WID_MASQ_PORT            4
+#define IFH_WID_LEN                  14
+#define IFH_WID_WRDMODE              2
+#define IFH_WID_RTAG48               1
+#define IFH_WID_HAS_RED_TAG          1
+#define IFH_WID_CUTTHRU              1
+#define IFH_WID_REW_CMD              10
+#define IFH_WID_REW_OAM              1
+#define IFH_WID_PDU_TYPE             4
+#define IFH_WID_FCS_UPD              1
+#define IFH_WID_DSCP                 6
+#define IFH_WID_DP                   1
+#define IFH_WID_RTE_INB_UPDATE       1
+#define IFH_WID_POP_CNT              2
+#define IFH_WID_ETYPE_OFS            2
+#define IFH_WID_SRCPORT              4
+#define IFH_WID_SEQ_NUM              16
+#define IFH_WID_TCI                  17
+#define IFH_WID_QOS_CLASS            3
+#define IFH_WID_CPUQ                 8
+#define IFH_WID_LEARN_FLAGS          2
+#define IFH_WID_SFLOW_ID             4
+#define IFH_WID_ACL_HIT              1
+#define IFH_WID_ACL_IDX              6
+#define IFH_WID_ISDX                 8
+#define IFH_WID_DSTS                 9
+#define IFH_WID_FLOOD                2
+#define IFH_WID_SEQ_OP               2
+#define IFH_WID_IPV                  3
+#define IFH_WID_AFI                  1
+#define IFH_WID_AGED                 2
+#define IFH_WID_RTP_ID               10
+#define IFH_WID_RTP_SUBID            1
+#define IFH_WID_PN_DATA_STATUS       8
+#define IFH_WID_PN_TRANSF_STATUS_ZERO 1
+#define IFH_WID_PN_CC                16
+
+#endif /* __LAN966X_IFH_H__ */
diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_main.c b/drivers/net/ethernet/microchip/lan966x/lan966x_main.c
index 2984f510ae27..cf147d44b345 100644
--- a/drivers/net/ethernet/microchip/lan966x/lan966x_main.c
+++ b/drivers/net/ethernet/microchip/lan966x/lan966x_main.c
@@ -3,13 +3,25 @@
 #include <asm/memory.h>
 #include <linux/module.h>
 #include <linux/if_bridge.h>
+#include <linux/if_vlan.h>
 #include <linux/iopoll.h>
 #include <linux/of_platform.h>
 #include <linux/of_net.h>
+#include <linux/phy/phy.h>
 #include <linux/reset.h>
 
 #include "lan966x_main.h"
 
+#define XTR_EOF_0			0x00000080U
+#define XTR_EOF_1			0x01000080U
+#define XTR_EOF_2			0x02000080U
+#define XTR_EOF_3			0x03000080U
+#define XTR_PRUNED			0x04000080U
+#define XTR_ABORT			0x05000080U
+#define XTR_ESCAPE			0x06000080U
+#define XTR_NOT_READY			0x07000080U
+#define XTR_VALID_BYTES(x)		(4 - (((x) >> 24) & 3))
+
 #define READL_SLEEP_US			10
 #define READL_TIMEOUT_US		100000000
 
@@ -82,23 +94,450 @@ static int lan966x_create_targets(struct platform_device *pdev,
 	return 0;
 }
 
+static int lan966x_port_get_phys_port_name(struct net_device *dev,
+					   char *buf, size_t len)
+{
+	struct lan966x_port *port = netdev_priv(dev);
+	int ret;
+
+	ret = snprintf(buf, len, "p%d", port->chip_port);
+	if (ret >= len)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int lan966x_port_open(struct net_device *dev)
+{
+	struct lan966x_port *port = netdev_priv(dev);
+	struct lan966x *lan966x = port->lan966x;
+	int err;
+
+	if (port->serdes) {
+		err = phy_set_mode_ext(port->serdes, PHY_MODE_ETHERNET,
+				       port->config.phy_mode);
+		if (err) {
+			netdev_err(dev, "Could not set mode of SerDes\n");
+			return err;
+		}
+	}
+
+	/* Enable receiving frames on the port, and activate auto-learning of
+	 * MAC addresses.
+	 */
+	lan_wr(ANA_PORT_CFG_LEARNAUTO_SET(1) |
+	       ANA_PORT_CFG_RECV_ENA_SET(1) |
+	       ANA_PORT_CFG_PORTID_VAL_SET(port->chip_port),
+	       lan966x, ANA_PORT_CFG(port->chip_port));
+
+	err = phylink_of_phy_connect(port->phylink, to_of_node(port->fwnode), 0);
+	if (err) {
+		netdev_err(dev, "Could not attach to PHY\n");
+		return err;
+	}
+
+	phylink_start(port->phylink);
+
+	return 0;
+}
+
+static int lan966x_port_stop(struct net_device *dev)
+{
+	struct lan966x_port *port = netdev_priv(dev);
+
+	lan966x_port_config_down(port);
+	phylink_stop(port->phylink);
+	phylink_disconnect_phy(port->phylink);
+
+	return 0;
+}
+
+static void lan966x_ifh_inject(u32 *ifh, size_t val, size_t pos, size_t length)
+{
+	int i;
+
+	for (i = pos; i < pos + length; ++i) {
+		if (val & BIT(i - pos))
+			ifh[IFH_LEN - i / 32 - 1] |= BIT(i % 32);
+		else
+			ifh[IFH_LEN - i / 32 - 1] &= ~(BIT(i % 32));
+	}
+}
+
+static void lan966x_gen_ifh(u32 *ifh, struct lan966x_frame_info *info,
+			    struct lan966x *lan966x)
+{
+	lan966x_ifh_inject(ifh, 1, IFH_POS_BYPASS, 1);
+	lan966x_ifh_inject(ifh, info->port, IFH_POS_DSTS, IFH_WID_DSTS);
+	lan966x_ifh_inject(ifh, info->qos_class, IFH_POS_QOS_CLASS,
+			   IFH_WID_QOS_CLASS);
+	lan966x_ifh_inject(ifh, info->ipv, IFH_POS_IPV, IFH_WID_IPV);
+}
+
+static int lan966x_port_ifh_xmit(struct sk_buff *skb,
+				 struct lan966x_frame_info *info,
+				 struct net_device *dev)
+{
+	struct lan966x_port *port = netdev_priv(dev);
+	struct lan966x *lan966x = port->lan966x;
+	u32 i, count, last;
+	u32 ifh[IFH_LEN];
+	u8 grp = 0;
+	u32 val;
+
+	val = lan_rd(lan966x, QS_INJ_STATUS);
+	if (!(QS_INJ_STATUS_FIFO_RDY_GET(val) & BIT(grp)) ||
+	    (QS_INJ_STATUS_WMARK_REACHED_GET(val) & BIT(grp)))
+		return NETDEV_TX_BUSY;
+
+	/* Write start of frame */
+	lan_wr(QS_INJ_CTRL_GAP_SIZE_SET(1) |
+	       QS_INJ_CTRL_SOF_SET(1),
+	       lan966x, QS_INJ_CTRL(grp));
+
+	memset(ifh, 0x0, sizeof(u32) * IFH_LEN);
+	lan966x_gen_ifh(ifh, info, lan966x);
+
+	/* Write IFH header */
+	for (i = 0; i < IFH_LEN; ++i) {
+		/* Wait until the fifo is ready */
+		while (!(QS_INJ_STATUS_FIFO_RDY_GET(lan_rd(lan966x, QS_INJ_STATUS)) &
+			 BIT(grp)))
+			;
+
+		lan_wr((__force u32)cpu_to_be32(ifh[i]), lan966x,
+		       QS_INJ_WR(grp));
+	}
+
+	/* Write frame */
+	count = DIV_ROUND_UP(skb->len, 4);
+	last = skb->len % 4;
+	for (i = 0; i < count; ++i) {
+		/* Wait until the fifo is ready */
+		while (!(QS_INJ_STATUS_FIFO_RDY_GET(lan_rd(lan966x, QS_INJ_STATUS)) &
+			 BIT(grp)))
+			;
+
+		lan_wr(((u32 *)skb->data)[i], lan966x, QS_INJ_WR(grp));
+	}
+
+	/* Add padding */
+	while (i < (LAN966X_BUFFER_MIN_SZ / 4)) {
+		/* Wait until the fifo is ready */
+		while (!(QS_INJ_STATUS_FIFO_RDY_GET(lan_rd(lan966x, QS_INJ_STATUS)) &
+			 BIT(grp)))
+			;
+
+		lan_wr(0, lan966x, QS_INJ_WR(grp));
+		++i;
+	}
+
+	/* Inidcate EOF and valid bytes in the last word */
+	lan_wr(QS_INJ_CTRL_GAP_SIZE_SET(1) |
+	       QS_INJ_CTRL_VLD_BYTES_SET(skb->len < LAN966X_BUFFER_MIN_SZ ?
+				     0 : last) |
+	       QS_INJ_CTRL_EOF_SET(1),
+	       lan966x, QS_INJ_CTRL(grp));
+
+	/* Add dummy CRC */
+	lan_wr(0, lan966x, QS_INJ_WR(grp));
+	skb_tx_timestamp(skb);
+
+	dev->stats.tx_packets++;
+	dev->stats.tx_bytes += skb->len;
+
+	dev_kfree_skb_any(skb);
+	return NETDEV_TX_OK;
+}
+
+static int lan966x_port_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct lan966x_port *port = netdev_priv(dev);
+	struct lan966x_frame_info info;
+
+	memset(&info, 0, sizeof(info));
+
+	info.port = BIT(port->chip_port);
+	info.vid = skb_vlan_tag_get(skb);
+
+	/* Adjust frame priority to priority queue */
+	info.qos_class = skb->priority >= 0x7 ? 0x7 : skb->priority;
+	info.ipv = info.qos_class;
+
+	return lan966x_port_ifh_xmit(skb, &info, dev);
+}
+
+static void lan966x_set_promisc(struct lan966x_port *port, bool enable)
+{
+	struct lan966x *lan966x = port->lan966x;
+
+	lan_rmw(ANA_CPU_FWD_CFG_SRC_COPY_ENA_SET(enable),
+		ANA_CPU_FWD_CFG_SRC_COPY_ENA,
+		lan966x, ANA_CPU_FWD_CFG(port->chip_port));
+}
+
+static void lan966x_change_rx_flags(struct net_device *dev, int flags)
+{
+	struct lan966x_port *port = netdev_priv(dev);
+
+	if (!(flags & IFF_PROMISC))
+		return;
+
+	if (dev->flags & IFF_PROMISC)
+		lan966x_set_promisc(port, true);
+	else
+		lan966x_set_promisc(port, false);
+}
+
+static int lan966x_change_mtu(struct net_device *dev, int new_mtu)
+{
+	struct lan966x_port *port = netdev_priv(dev);
+	struct lan966x *lan966x = port->lan966x;
+
+	lan_wr(DEV_MAC_MAXLEN_CFG_MAX_LEN_SET(new_mtu),
+	       lan966x, DEV_MAC_MAXLEN_CFG(port->chip_port));
+	dev->mtu = new_mtu;
+
+	return 0;
+}
+
+static const struct net_device_ops lan966x_port_netdev_ops = {
+	.ndo_open			= lan966x_port_open,
+	.ndo_stop			= lan966x_port_stop,
+	.ndo_start_xmit			= lan966x_port_xmit,
+	.ndo_change_rx_flags		= lan966x_change_rx_flags,
+	.ndo_change_mtu			= lan966x_change_mtu,
+	.ndo_get_phys_port_name		= lan966x_port_get_phys_port_name,
+};
+
+static int lan966x_ifh_extract(u32 *ifh, size_t pos, size_t length)
+{
+	int val = 0;
+	int i;
+
+	for (i = pos; i < pos + length; ++i)
+		val |= ((ifh[IFH_LEN - i / 32 - 1] & BIT(i % 32)) >>
+			(i % 32)) << (i - pos);
+
+	return val;
+}
+
+static int lan966x_parse_ifh(u32 *ifh, struct lan966x_frame_info *info)
+{
+	int i;
+
+	/* The IFH is in network order, switch to CPU order */
+	for (i = 0; i < IFH_LEN; i++)
+		ifh[i] = ntohl((__force __be32)ifh[i]);
+
+	info->len = lan966x_ifh_extract(ifh, IFH_POS_LEN, IFH_WID_LEN);
+	info->port = lan966x_ifh_extract(ifh, IFH_POS_SRCPORT, IFH_WID_SRCPORT);
+
+	info->vid = lan966x_ifh_extract(ifh, IFH_POS_TCI, IFH_WID_TCI);
+	info->timestamp = lan966x_ifh_extract(ifh, IFH_POS_TIMESTAMP,
+					      IFH_WID_TIMESTAMP);
+	return 0;
+}
+
+static int lan966x_rx_frame_word(struct lan966x *lan966x, u8 grp, bool ifh,
+				 u32 *rval)
+{
+	u32 bytes_valid;
+	u32 val;
+
+	val = lan_rd(lan966x, QS_XTR_RD(grp));
+	if (val == XTR_NOT_READY) {
+		if (ifh)
+			return -EIO;
+
+		do {
+			val = lan_rd(lan966x, QS_XTR_RD(grp));
+		} while (val == XTR_NOT_READY);
+	}
+
+	switch (val) {
+	case XTR_ABORT:
+		return -EIO;
+	case XTR_EOF_0:
+	case XTR_EOF_1:
+	case XTR_EOF_2:
+	case XTR_EOF_3:
+	case XTR_PRUNED:
+		bytes_valid = XTR_VALID_BYTES(val);
+		val = lan_rd(lan966x, QS_XTR_RD(grp));
+		if (val == XTR_ESCAPE)
+			*rval = lan_rd(lan966x, QS_XTR_RD(grp));
+		else
+			*rval = val;
+
+		return bytes_valid;
+	case XTR_ESCAPE:
+		*rval = lan_rd(lan966x, QS_XTR_RD(grp));
+
+		return 4;
+	default:
+		*rval = val;
+
+		return 4;
+	}
+}
+
+static irqreturn_t lan966x_xtr_irq_handler(int irq, void *args)
+{
+	struct lan966x *lan966x = args;
+	int i, grp = 0, err = 0;
+
+	if (!(lan_rd(lan966x, QS_XTR_DATA_PRESENT) & BIT(grp)))
+		return IRQ_NONE;
+
+	do {
+		u32 ifh[IFH_LEN] = { 0 };
+		struct lan966x_frame_info info;
+		struct net_device *dev;
+		int sz, len, buf_len;
+		struct sk_buff *skb;
+		u32 *buf;
+		u32 val;
+
+		for (i = 0; i < IFH_LEN; i++) {
+			err = lan966x_rx_frame_word(lan966x, grp, true,
+						    &ifh[i]);
+			if (err != 4)
+				break;
+		}
+
+		if (err != 4)
+			break;
+
+		err = 0;
+
+		lan966x_parse_ifh(ifh, &info);
+		WARN_ON(info.port >= lan966x->num_phys_ports);
+
+		dev = lan966x->ports[info.port]->dev;
+		skb = netdev_alloc_skb(dev, info.len);
+		if (unlikely(!skb)) {
+			netdev_err(dev, "Unable to allocate sk_buff\n");
+			err = -ENOMEM;
+			break;
+		}
+		buf_len = info.len - ETH_FCS_LEN;
+		buf = (u32 *)skb_put(skb, buf_len);
+
+		len = 0;
+		do {
+			sz = lan966x_rx_frame_word(lan966x, grp, false, &val);
+			*buf++ = val;
+			len += sz;
+		} while (len < buf_len);
+
+		/* Read the FCS */
+		sz = lan966x_rx_frame_word(lan966x, grp, false, &val);
+
+		/* Update the statistics if part of the FCS was read before */
+		len -= ETH_FCS_LEN - sz;
+
+		if (unlikely(dev->features & NETIF_F_RXFCS)) {
+			buf = (u32 *)skb_put(skb, ETH_FCS_LEN);
+			*buf = val;
+		}
+
+		if (sz < 0) {
+			err = sz;
+			break;
+		}
+
+		skb->protocol = eth_type_trans(skb, dev);
+
+		netif_rx_ni(skb);
+		dev->stats.rx_bytes += len;
+		dev->stats.rx_packets++;
+	} while (lan_rd(lan966x, QS_XTR_DATA_PRESENT) & BIT(grp));
+
+	if (err)
+		while (lan_rd(lan966x, QS_XTR_DATA_PRESENT) & BIT(grp))
+			lan_rd(lan966x, QS_XTR_RD(grp));
+
+	return IRQ_HANDLED;
+}
+
+static void lan966x_cleanup_ports(struct lan966x *lan966x)
+{
+	struct lan966x_port *port;
+	int portno;
+
+	for (portno = 0; portno < lan966x->num_phys_ports; portno++) {
+		port = lan966x->ports[portno];
+		if (!port)
+			continue;
+
+		if (port->phylink) {
+			rtnl_lock();
+			lan966x_port_stop(port->dev);
+			rtnl_unlock();
+			port->phylink = NULL;
+		}
+
+		if (port->fwnode)
+			fwnode_handle_put(port->fwnode);
+
+		if (port->dev)
+			unregister_netdev(port->dev);
+	}
+}
+
 static int lan966x_probe_port(struct lan966x *lan966x, u8 port,
 			      phy_interface_t phy_mode)
 {
 	struct lan966x_port *lan966x_port;
+	struct phylink *phylink;
+	struct net_device *dev;
+	int err;
 
 	if (port >= lan966x->num_phys_ports)
 		return -EINVAL;
 
-	lan966x_port = devm_kzalloc(lan966x->dev, sizeof(*lan966x_port),
-				    GFP_KERNEL);
+	dev = devm_alloc_etherdev_mqs(lan966x->dev,
+				      sizeof(struct lan966x_port), 8, 1);
+	if (!dev)
+		return -ENOMEM;
 
+	SET_NETDEV_DEV(dev, lan966x->dev);
+	lan966x_port = netdev_priv(dev);
+	lan966x_port->dev = dev;
 	lan966x_port->lan966x = lan966x;
 	lan966x_port->chip_port = port;
 	lan966x_port->pvid = PORT_PVID;
 	lan966x->ports[port] = lan966x_port;
 
+	dev->max_mtu = ETH_MAX_MTU;
+
+	dev->netdev_ops = &lan966x_port_netdev_ops;
+	dev->needed_headroom = IFH_LEN * sizeof(u32);
+
+	err = register_netdev(dev);
+	if (err) {
+		dev_err(lan966x->dev, "register_netdev failed\n");
+		goto err_register_netdev;
+	}
+
+	lan966x_port->phylink_config.dev = &lan966x_port->dev->dev;
+	lan966x_port->phylink_config.type = PHYLINK_NETDEV;
+	lan966x_port->phylink_config.pcs_poll = true;
+
+	phylink = phylink_create(&lan966x_port->phylink_config,
+				 lan966x_port->fwnode,
+				 phy_mode,
+				 &lan966x_phylink_mac_ops);
+	if (IS_ERR(phylink))
+		return PTR_ERR(phylink);
+
+	lan966x_port->phylink = phylink;
+
 	return 0;
+
+err_register_netdev:
+	return err;
 }
 
 static void lan966x_init(struct lan966x *lan966x)
@@ -306,6 +745,19 @@ static int lan966x_probe(struct platform_device *pdev)
 	/* There QS system has 32KB of memory */
 	lan966x->shared_queue_sz = LAN966X_BUFFER_MEMORY;
 
+	/* set irq */
+	lan966x->xtr_irq = platform_get_irq_byname(pdev, "xtr");
+	if (lan966x->xtr_irq <= 0)
+		return -EINVAL;
+
+	err = devm_request_threaded_irq(&pdev->dev, lan966x->xtr_irq, NULL,
+					lan966x_xtr_irq_handler, IRQF_ONESHOT,
+					"frame extraction", lan966x);
+	if (err) {
+		pr_err("Unable to use xtr irq");
+		return -ENODEV;
+	}
+
 	/* init switch */
 	lan966x_init(lan966x);
 
@@ -321,17 +773,40 @@ static int lan966x_probe(struct platform_device *pdev)
 		phy_mode = fwnode_get_phy_mode(portnp);
 		err = lan966x_probe_port(lan966x, port, phy_mode);
 		if (err)
-			return err;
+			goto cleanup_ports;
+
+		/* Read needed configuration */
+		lan966x->ports[port]->config.phy_mode = phy_mode;
+		lan966x->ports[port]->config.portmode = phy_mode;
+		lan966x->ports[port]->fwnode = portnp;
+
+		serdes = devm_of_phy_get(lan966x->dev, to_of_node(portnp), NULL);
+		if (!IS_ERR(serdes))
+			lan966x->ports[port]->serdes = serdes;
+
+		lan966x_port_init(lan966x->ports[port]);
 	}
 
 	return 0;
 
+cleanup_ports:
+	fwnode_handle_put(portnp);
+
+	disable_irq(lan966x->xtr_irq);
+	lan966x->xtr_irq = -ENXIO;
+	lan966x_cleanup_ports(lan966x);
 out:
 	return err;
 }
 
 static int lan966x_remove(struct platform_device *pdev)
 {
+	struct lan966x *lan966x = platform_get_drvdata(pdev);
+
+	disable_irq(lan966x->xtr_irq);
+	lan966x->xtr_irq = -ENXIO;
+	lan966x_cleanup_ports(lan966x);
+
 	return 0;
 }
 
diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_main.h b/drivers/net/ethernet/microchip/lan966x/lan966x_main.h
index 0c5fa14437a5..9ae1582f5cdb 100644
--- a/drivers/net/ethernet/microchip/lan966x/lan966x_main.h
+++ b/drivers/net/ethernet/microchip/lan966x/lan966x_main.h
@@ -3,7 +3,12 @@
 #ifndef __LAN966X_MAIN_H__
 #define __LAN966X_MAIN_H__
 
+#include <linux/etherdevice.h>
+#include <linux/phy.h>
+#include <linux/phylink.h>
+
 #include "lan966x_regs.h"
+#include "lan966x_ifh.h"
 
 #define LAN966X_BUFFER_CELL_SZ		64
 #define LAN966X_BUFFER_MEMORY		(160 * 1024)
@@ -35,6 +40,15 @@
 
 struct lan966x_port;
 
+struct lan966x_frame_info {
+	u32 len;
+	u16 port; /* Bit mask */
+	u16 vid;
+	u32 timestamp;
+	u8 qos_class;
+	u8 ipv;
+};
+
 struct lan966x {
 	struct device *dev;
 
@@ -44,17 +58,41 @@ struct lan966x {
 	void __iomem *regs[NUM_TARGETS];
 
 	int shared_queue_sz;
+
+	/* interrupts */
+	int xtr_irq;
+};
+
+struct lan966x_port_config {
+	phy_interface_t portmode;
+	phy_interface_t phy_mode;
+	int speed;
+	int duplex;
+	u32 pause;
 };
 
 struct lan966x_port {
+	struct net_device *dev;
 	struct lan966x *lan966x;
 
 	u8 chip_port;
 	u16 pvid;
 
+	struct phylink_config phylink_config;
+	struct lan966x_port_config config;
+	struct phylink *phylink;
+	struct phy *serdes;
+	struct fwnode_handle *fwnode;
+
 	void __iomem *regs;
 };
 
+extern const struct phylink_mac_ops lan966x_phylink_mac_ops;
+
+void lan966x_port_config_down(struct lan966x_port *port);
+void lan966x_port_config_up(struct lan966x_port *port);
+void lan966x_port_init(struct lan966x_port *port);
+
 static inline void __iomem *lan_addr(void __iomem *base[],
 				     int id, int tinst, int tcnt,
 				     int gbase, int ginst,
diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_phylink.c b/drivers/net/ethernet/microchip/lan966x/lan966x_phylink.c
new file mode 100644
index 000000000000..23687492869f
--- /dev/null
+++ b/drivers/net/ethernet/microchip/lan966x/lan966x_phylink.c
@@ -0,0 +1,92 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* Copyright (C) 2020 Microchip Technology Inc. */
+
+#include <linux/module.h>
+#include <linux/phylink.h>
+#include <linux/device.h>
+#include <linux/netdevice.h>
+#include <linux/sfp.h>
+
+#include "lan966x_main.h"
+
+static void lan966x_phylink_validate(struct phylink_config *config,
+				     unsigned long *supported,
+				     struct phylink_link_state *state)
+{
+	__ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
+
+	phylink_set_port_modes(mask);
+	phylink_set(mask, Autoneg);
+	phylink_set(mask, Pause);
+	phylink_set(mask, Asym_Pause);
+
+	switch (state->interface) {
+	case PHY_INTERFACE_MODE_NA:
+	case PHY_INTERFACE_MODE_GMII:
+	case PHY_INTERFACE_MODE_MII:
+	case PHY_INTERFACE_MODE_SGMII:
+	case PHY_INTERFACE_MODE_QSGMII:
+		phylink_set(mask, 10baseT_Half);
+		phylink_set(mask, 10baseT_Full);
+		phylink_set(mask, 100baseT_Half);
+		phylink_set(mask, 100baseT_Full);
+		phylink_set(mask, 1000baseT_Full);
+		phylink_set(mask, 1000baseX_Full);
+		break;
+	default:
+		bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS);
+		return;
+	}
+	bitmap_and(supported, supported, mask, __ETHTOOL_LINK_MODE_MASK_NBITS);
+	bitmap_and(state->advertising, state->advertising, mask,
+		   __ETHTOOL_LINK_MODE_MASK_NBITS);
+}
+
+static void lan966x_phylink_mac_config(struct phylink_config *config,
+				       unsigned int mode,
+				       const struct phylink_link_state *state)
+{
+}
+
+static void lan966x_phylink_mac_link_up(struct phylink_config *config,
+					struct phy_device *phy,
+					unsigned int mode,
+					phy_interface_t interface,
+					int speed, int duplex,
+					bool tx_pause, bool rx_pause)
+{
+	struct lan966x_port *port = netdev_priv(to_net_dev(config->dev));
+	struct lan966x_port_config *port_config = &port->config;
+
+	port_config->duplex = duplex;
+	port_config->speed = speed;
+	port_config->pause = 0;
+	port_config->pause |= tx_pause ? MLO_PAUSE_TX : 0;
+	port_config->pause |= rx_pause ? MLO_PAUSE_RX : 0;
+
+	lan966x_port_config_up(port);
+}
+
+static void lan966x_phylink_mac_link_down(struct phylink_config *config,
+					  unsigned int mode,
+					  phy_interface_t interface)
+{
+}
+
+static void lan966x_phylink_mac_link_state(struct phylink_config *config,
+					   struct phylink_link_state *state)
+{
+}
+
+static void lan966x_phylink_mac_aneg_restart(struct phylink_config *config)
+{
+}
+
+const struct phylink_mac_ops lan966x_phylink_mac_ops = {
+	.validate = lan966x_phylink_validate,
+	.mac_pcs_get_state = lan966x_phylink_mac_link_state,
+	.mac_config = lan966x_phylink_mac_config,
+	.mac_an_restart = lan966x_phylink_mac_aneg_restart,
+	.mac_link_down = lan966x_phylink_mac_link_down,
+	.mac_link_up = lan966x_phylink_mac_link_up,
+};
diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_port.c b/drivers/net/ethernet/microchip/lan966x/lan966x_port.c
new file mode 100644
index 000000000000..7d6a3c968bd3
--- /dev/null
+++ b/drivers/net/ethernet/microchip/lan966x/lan966x_port.c
@@ -0,0 +1,301 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <linux/netdevice.h>
+
+#include "lan966x_main.h"
+
+/* Watermark encode */
+#define MULTIPLIER_BIT BIT(8)
+static u32 lan966x_wm_enc(u32 value)
+{
+	value /= LAN966X_BUFFER_CELL_SZ;
+
+	if (value >= MULTIPLIER_BIT) {
+		value /= 16;
+		if (value >= MULTIPLIER_BIT)
+			value = (MULTIPLIER_BIT - 1);
+
+		value |= MULTIPLIER_BIT;
+	}
+
+	return value;
+}
+
+static void lan966x_port_link_down(struct lan966x_port *port)
+{
+	struct lan966x *lan966x = port->lan966x;
+	u32 val, delay = 0;
+
+	/* 0.5: Disable any AFI */
+	lan_rmw(AFI_PORT_CFG_FC_SKIP_TTI_INJ_SET(1) |
+		AFI_PORT_CFG_FRM_OUT_MAX_SET(0),
+		AFI_PORT_CFG_FC_SKIP_TTI_INJ |
+		AFI_PORT_CFG_FRM_OUT_MAX,
+		lan966x, AFI_PORT_CFG(port->chip_port));
+
+	/* wait for reg afi_port_frm_out to become 0 for the port */
+	while (true) {
+		val = lan_rd(lan966x, AFI_PORT_FRM_OUT(port->chip_port));
+		if (!AFI_PORT_FRM_OUT_FRM_OUT_CNT_GET(val))
+			break;
+
+		usleep_range(USEC_PER_MSEC, 2 * USEC_PER_MSEC);
+		delay++;
+		if (delay == 2000) {
+			pr_err("AFI timeout chip port %u", port->chip_port);
+			break;
+		}
+	}
+
+	delay = 0;
+
+	/* 1: Reset the PCS Rx clock domain  */
+	lan_rmw(DEV_CLOCK_CFG_PCS_RX_RST_SET(1),
+		DEV_CLOCK_CFG_PCS_RX_RST,
+		lan966x, DEV_CLOCK_CFG(port->chip_port));
+
+	/* 2: Disable MAC frame reception */
+	lan_rmw(DEV_MAC_ENA_CFG_RX_ENA_SET(0),
+		DEV_MAC_ENA_CFG_RX_ENA,
+		lan966x, DEV_MAC_ENA_CFG(port->chip_port));
+
+	/* 3: Disable traffic being sent to or from switch port */
+	lan_rmw(QSYS_SW_PORT_MODE_PORT_ENA_SET(0),
+		QSYS_SW_PORT_MODE_PORT_ENA,
+		lan966x, QSYS_SW_PORT_MODE(port->chip_port));
+
+	/* 4: Disable dequeuing from the egress queues  */
+	lan_rmw(QSYS_PORT_MODE_DEQUEUE_DIS_SET(1),
+		QSYS_PORT_MODE_DEQUEUE_DIS,
+		lan966x, QSYS_PORT_MODE(port->chip_port));
+
+	/* 5: Disable Flowcontrol */
+	lan_rmw(SYS_PAUSE_CFG_PAUSE_ENA_SET(0),
+		SYS_PAUSE_CFG_PAUSE_ENA,
+		lan966x, SYS_PAUSE_CFG(port->chip_port));
+
+	/* 5.1: Disable PFC */
+	lan_rmw(QSYS_SW_PORT_MODE_TX_PFC_ENA_SET(0),
+		QSYS_SW_PORT_MODE_TX_PFC_ENA,
+		lan966x, QSYS_SW_PORT_MODE(port->chip_port));
+
+	/* 6: Wait a worst case time 8ms (jumbo/10Mbit) */
+	usleep_range(8 * USEC_PER_MSEC, 9 * USEC_PER_MSEC);
+
+	/* 7: Disable HDX backpressure */
+	lan_rmw(SYS_FRONT_PORT_MODE_HDX_MODE_SET(0),
+		SYS_FRONT_PORT_MODE_HDX_MODE,
+		lan966x, SYS_FRONT_PORT_MODE(port->chip_port));
+
+	/* 8: Flush the queues accociated with the port */
+	lan_rmw(QSYS_SW_PORT_MODE_AGING_MODE_SET(3),
+		QSYS_SW_PORT_MODE_AGING_MODE,
+		lan966x, QSYS_SW_PORT_MODE(port->chip_port));
+
+	/* 9: Enable dequeuing from the egress queues */
+	lan_rmw(QSYS_PORT_MODE_DEQUEUE_DIS_SET(0),
+		QSYS_PORT_MODE_DEQUEUE_DIS,
+		lan966x, QSYS_PORT_MODE(port->chip_port));
+
+	/* 10: Wait until flushing is complete */
+	while (true) {
+		val = lan_rd(lan966x, QSYS_SW_STATUS(port->chip_port));
+		if (!QSYS_SW_STATUS_EQ_AVAIL_GET(val))
+			break;
+
+		usleep_range(USEC_PER_MSEC, 2 * USEC_PER_MSEC);
+		delay++;
+		if (delay == 2000) {
+			pr_err("Flush timeout chip port %u", port->chip_port);
+			break;
+		}
+	}
+
+	/* 11: Reset the Port and MAC clock domains */
+	lan_rmw(DEV_MAC_ENA_CFG_TX_ENA_SET(0),
+		DEV_MAC_ENA_CFG_TX_ENA,
+		lan966x, DEV_MAC_ENA_CFG(port->chip_port)); /* Bugzilla#19076 */
+
+	lan_rmw(DEV_CLOCK_CFG_PORT_RST_SET(1),
+		DEV_CLOCK_CFG_PORT_RST,
+		lan966x, DEV_CLOCK_CFG(port->chip_port));
+
+	usleep_range(USEC_PER_MSEC, 2 * USEC_PER_MSEC);
+
+	lan_rmw(DEV_CLOCK_CFG_MAC_TX_RST_SET(1) |
+		DEV_CLOCK_CFG_MAC_RX_RST_SET(1) |
+		DEV_CLOCK_CFG_PORT_RST_SET(1),
+		DEV_CLOCK_CFG_MAC_TX_RST |
+		DEV_CLOCK_CFG_MAC_RX_RST |
+		DEV_CLOCK_CFG_PORT_RST,
+		lan966x, DEV_CLOCK_CFG(port->chip_port));
+
+	/* 12: Clear flushing */
+	lan_rmw(QSYS_SW_PORT_MODE_AGING_MODE_SET(2),
+		QSYS_SW_PORT_MODE_AGING_MODE,
+		lan966x, QSYS_SW_PORT_MODE(port->chip_port));
+
+	/* The port is disabled and flushed, now set up the port in the
+	 * new operating mode
+	 */
+}
+
+static void lan966x_port_link_up(struct lan966x_port *port)
+{
+	struct lan966x_port_config *config = &port->config;
+	struct lan966x *lan966x = port->lan966x;
+	int speed = 0, mode = 0;
+	int atop_wm = 0;
+
+	switch (config->speed) {
+	case SPEED_10:
+		speed = LAN966X_SPEED_10;
+		break;
+	case SPEED_100:
+		speed = LAN966X_SPEED_100;
+		break;
+	case SPEED_1000:
+		speed = LAN966X_SPEED_1000;
+		mode = DEV_MAC_MODE_CFG_GIGA_MODE_ENA_SET(1);
+		break;
+	}
+
+	/* Also the GIGA_MODE_ENA(1) needs to be set regardless of the
+	 * port speed for QSGMII ports.
+	 */
+	if (config->phy_mode == PHY_INTERFACE_MODE_QSGMII)
+		mode = DEV_MAC_MODE_CFG_GIGA_MODE_ENA_SET(1);
+
+	lan_wr(config->duplex | mode,
+	       lan966x, DEV_MAC_MODE_CFG(port->chip_port));
+
+	lan_rmw(DEV_MAC_IFG_CFG_TX_IFG_SET(5),
+		DEV_MAC_IFG_CFG_TX_IFG,
+		lan966x, DEV_MAC_IFG_CFG(port->chip_port));
+
+	lan_rmw(DEV_MAC_HDX_CFG_SEED_SET(4) |
+		DEV_MAC_HDX_CFG_SEED_LOAD_SET(1),
+		DEV_MAC_HDX_CFG_SEED |
+		DEV_MAC_HDX_CFG_SEED_LOAD,
+		lan966x, DEV_MAC_HDX_CFG(port->chip_port));
+
+	if (config->phy_mode != PHY_INTERFACE_MODE_QSGMII) {
+		if (config->speed == SPEED_1000)
+			lan_rmw(CHIP_TOP_CUPHY_PORT_CFG_GTX_CLK_ENA_SET(1),
+				CHIP_TOP_CUPHY_PORT_CFG_GTX_CLK_ENA,
+				lan966x,
+				CHIP_TOP_CUPHY_PORT_CFG(port->chip_port));
+		else
+			lan_rmw(CHIP_TOP_CUPHY_PORT_CFG_GTX_CLK_ENA_SET(0),
+				CHIP_TOP_CUPHY_PORT_CFG_GTX_CLK_ENA,
+				lan966x,
+				CHIP_TOP_CUPHY_PORT_CFG(port->chip_port));
+	}
+
+	/* No PFC */
+	lan_wr(ANA_PFC_CFG_FC_LINK_SPEED_SET(speed),
+	       lan966x, ANA_PFC_CFG(port->chip_port));
+
+	if (config->phy_mode == PHY_INTERFACE_MODE_QSGMII) {
+		lan_rmw(DEV_PCS1G_CFG_PCS_ENA_SET(1),
+			DEV_PCS1G_CFG_PCS_ENA,
+			lan966x, DEV_PCS1G_CFG(port->chip_port));
+
+		lan_rmw(DEV_PCS1G_SD_CFG_SD_ENA_SET(0),
+			DEV_PCS1G_SD_CFG_SD_ENA,
+			lan966x, DEV_PCS1G_SD_CFG(port->chip_port));
+	}
+
+	lan_rmw(DEV_PCS1G_CFG_PCS_ENA_SET(1),
+		DEV_PCS1G_CFG_PCS_ENA,
+		lan966x, DEV_PCS1G_CFG(port->chip_port));
+
+	lan_rmw(DEV_PCS1G_SD_CFG_SD_ENA_SET(0),
+		DEV_PCS1G_SD_CFG_SD_ENA,
+		lan966x, DEV_PCS1G_SD_CFG(port->chip_port));
+
+	/* Set Pause WM hysteresis, start/stop are in 1518 byte units */
+	lan_wr(SYS_PAUSE_CFG_PAUSE_ENA_SET(1) |
+	       SYS_PAUSE_CFG_PAUSE_STOP_SET(lan966x_wm_enc(4 * 1518)) |
+	       SYS_PAUSE_CFG_PAUSE_START_SET(lan966x_wm_enc(6 * 1518)),
+	       lan966x, SYS_PAUSE_CFG(port->chip_port));
+
+	/* Set SMAC of Pause frame (00:00:00:00:00:00) */
+	lan_wr(0, lan966x, DEV_FC_MAC_LOW_CFG(port->chip_port));
+	lan_wr(0, lan966x, DEV_FC_MAC_HIGH_CFG(port->chip_port));
+
+	/* Flow control */
+	lan_rmw(SYS_MAC_FC_CFG_FC_LINK_SPEED_SET(speed) |
+		SYS_MAC_FC_CFG_FC_LATENCY_CFG_SET(7) |
+		SYS_MAC_FC_CFG_ZERO_PAUSE_ENA_SET(1) |
+		SYS_MAC_FC_CFG_PAUSE_VAL_CFG_SET(0xffff) |
+		SYS_MAC_FC_CFG_RX_FC_ENA_SET(config->pause & MLO_PAUSE_RX ? 1 : 0) |
+		SYS_MAC_FC_CFG_TX_FC_ENA_SET(config->pause & MLO_PAUSE_TX ? 1 : 0),
+		SYS_MAC_FC_CFG_FC_LINK_SPEED |
+		SYS_MAC_FC_CFG_FC_LATENCY_CFG |
+		SYS_MAC_FC_CFG_ZERO_PAUSE_ENA |
+		SYS_MAC_FC_CFG_PAUSE_VAL_CFG |
+		SYS_MAC_FC_CFG_RX_FC_ENA |
+		SYS_MAC_FC_CFG_TX_FC_ENA,
+		lan966x, SYS_MAC_FC_CFG(port->chip_port));
+
+	/* Tail dropping watermark */
+	atop_wm = lan966x->shared_queue_sz;
+
+	/* The total memory size is diveded by number of front ports plus CPU
+	 * port
+	 */
+	lan_wr(lan966x_wm_enc(atop_wm / lan966x->num_phys_ports + 1), lan966x,
+	       SYS_ATOP(port->chip_port));
+	lan_wr(lan966x_wm_enc(atop_wm), lan966x, SYS_ATOP_TOT_CFG);
+
+	/* This needs to be at the end */
+	/* Enable MAC module */
+	lan_wr(DEV_MAC_ENA_CFG_RX_ENA_SET(1) |
+	       DEV_MAC_ENA_CFG_TX_ENA_SET(1),
+	       lan966x, DEV_MAC_ENA_CFG(port->chip_port));
+
+	/* Take out the clock from reset */
+	lan_wr(DEV_CLOCK_CFG_LINK_SPEED_SET(speed),
+	       lan966x, DEV_CLOCK_CFG(port->chip_port));
+
+	/* Core: Enable port for frame transfer */
+	lan_wr(QSYS_SW_PORT_MODE_PORT_ENA_SET(1) |
+	       QSYS_SW_PORT_MODE_SCH_NEXT_CFG_SET(1) |
+	       QSYS_SW_PORT_MODE_INGRESS_DROP_MODE_SET(1),
+	       lan966x, QSYS_SW_PORT_MODE(port->chip_port));
+
+	lan_rmw(AFI_PORT_CFG_FC_SKIP_TTI_INJ_SET(0) |
+		AFI_PORT_CFG_FRM_OUT_MAX_SET(16),
+		AFI_PORT_CFG_FC_SKIP_TTI_INJ |
+		AFI_PORT_CFG_FRM_OUT_MAX,
+		lan966x, AFI_PORT_CFG(port->chip_port));
+}
+
+void lan966x_port_config_down(struct lan966x_port *port)
+{
+	lan966x_port_link_down(port);
+}
+
+void lan966x_port_config_up(struct lan966x_port *port)
+{
+	lan966x_port_link_down(port);
+	lan966x_port_link_up(port);
+}
+
+void lan966x_port_init(struct lan966x_port *port)
+{
+	struct lan966x_port_config *config = &port->config;
+	struct lan966x *lan966x = port->lan966x;
+
+	if (config->phy_mode != PHY_INTERFACE_MODE_QSGMII)
+		return;
+
+	lan_rmw(DEV_CLOCK_CFG_PCS_RX_RST_SET(0) |
+		DEV_CLOCK_CFG_PCS_TX_RST_SET(0) |
+		DEV_CLOCK_CFG_LINK_SPEED_SET(LAN966X_SPEED_1000),
+		DEV_CLOCK_CFG_PCS_RX_RST |
+		DEV_CLOCK_CFG_PCS_TX_RST |
+		DEV_CLOCK_CFG_LINK_SPEED,
+		lan966x, DEV_CLOCK_CFG(port->chip_port));
+}
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [RFC PATCH net-next 11/12] net: lan966x: add mactable support
  2021-09-20  9:52 [RFC PATCH net-next 00/12] Add lan966x driver Horatiu Vultur
                   ` (9 preceding siblings ...)
  2021-09-20  9:52 ` [RFC PATCH net-next 10/12] net: lan966x: add port module support Horatiu Vultur
@ 2021-09-20  9:52 ` Horatiu Vultur
  2021-09-20  9:52 ` [RFC PATCH net-next 12/12] net: lan966x: add ethtool configuration and statistics Horatiu Vultur
  11 siblings, 0 replies; 30+ messages in thread
From: Horatiu Vultur @ 2021-09-20  9:52 UTC (permalink / raw)
  To: davem, kuba, robh+dt, andrew, linux, f.fainelli,
	alexandre.belloni, vladimir.oltean, UNGLinuxDriver, netdev,
	devicetree, linux-kernel, linux-phy, linux-pm
  Cc: Horatiu Vultur

This patch adds support for MAC table operations like add and forget.
Also add the functionality to read the MAC address from DT, if there is
no MAC set in DT it would use a random one.

Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
---
 .../ethernet/microchip/lan966x/lan966x_main.c | 158 ++++++++++++++++++
 .../ethernet/microchip/lan966x/lan966x_main.h |  29 ++++
 2 files changed, 187 insertions(+)

diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_main.c b/drivers/net/ethernet/microchip/lan966x/lan966x_main.c
index cf147d44b345..53b88bb5b718 100644
--- a/drivers/net/ethernet/microchip/lan966x/lan966x_main.c
+++ b/drivers/net/ethernet/microchip/lan966x/lan966x_main.c
@@ -24,6 +24,8 @@
 
 #define READL_SLEEP_US			10
 #define READL_TIMEOUT_US		100000000
+#define TABLE_UPDATE_SLEEP_US		10
+#define TABLE_UPDATE_TIMEOUT_US		100000
 
 #define IO_RANGES 2
 
@@ -94,6 +96,107 @@ static int lan966x_create_targets(struct platform_device *pdev,
 	return 0;
 }
 
+static int lan966x_mact_get_status(struct lan966x *lan966x)
+{
+	return lan_rd(lan966x, ANA_MACACCESS);
+}
+
+static int lan966x_mact_wait_for_completion(struct lan966x *lan966x)
+{
+	u32 val;
+
+	return readx_poll_timeout(lan966x_mact_get_status,
+		lan966x, val,
+		(ANA_MACACCESS_MAC_TABLE_CMD_GET(val)) ==
+		MACACCESS_CMD_IDLE,
+		TABLE_UPDATE_SLEEP_US, TABLE_UPDATE_TIMEOUT_US);
+}
+
+static void lan966x_mact_select(struct lan966x *lan966x,
+				const unsigned char mac[ETH_ALEN],
+				unsigned int vid)
+{
+	u32 macl = 0, mach = 0;
+
+	/* Set the MAC address to handle and the vlan associated in a format
+	 * understood by the hardware.
+	 */
+	mach |= vid    << 16;
+	mach |= mac[0] << 8;
+	mach |= mac[1] << 0;
+	macl |= mac[2] << 24;
+	macl |= mac[3] << 16;
+	macl |= mac[4] << 8;
+	macl |= mac[5] << 0;
+
+	lan_wr(macl, lan966x, ANA_MACLDATA);
+	lan_wr(mach, lan966x, ANA_MACHDATA);
+}
+
+static int lan966x_mact_learn(struct lan966x *lan966x, int port,
+			      const unsigned char mac[ETH_ALEN],
+			      unsigned int vid,
+			      enum macaccess_entry_type type)
+{
+	lan966x_mact_select(lan966x, mac, vid);
+
+	/* Issue a write command */
+	lan_wr(ANA_MACACCESS_VALID_SET(1) |
+	       ANA_MACACCESS_CHANGE2SW_SET(0) |
+	       ANA_MACACCESS_DEST_IDX_SET(port) |
+	       ANA_MACACCESS_ENTRYTYPE_SET(type) |
+	       ANA_MACACCESS_MAC_TABLE_CMD_SET(MACACCESS_CMD_LEARN),
+	       lan966x, ANA_MACACCESS);
+
+	return lan966x_mact_wait_for_completion(lan966x);
+}
+
+static int lan966x_mact_forget(struct lan966x *lan966x,
+			       const unsigned char mac[ETH_ALEN],
+			       unsigned int vid,
+			       enum macaccess_entry_type type)
+{
+	lan966x_mact_select(lan966x, mac, vid);
+
+	/* Issue a forget command */
+	lan_wr(ANA_MACACCESS_ENTRYTYPE_SET(type) |
+	       ANA_MACACCESS_MAC_TABLE_CMD_SET(MACACCESS_CMD_FORGET),
+	       lan966x, ANA_MACACCESS);
+
+	return lan966x_mact_wait_for_completion(lan966x);
+}
+
+static void lan966x_mact_init(struct lan966x *lan966x)
+{
+	/* Clear the MAC table */
+	lan_wr(MACACCESS_CMD_INIT,
+	       lan966x, ANA_MACACCESS);
+	lan966x_mact_wait_for_completion(lan966x);
+}
+
+static int lan966x_port_set_mac_address(struct net_device *dev, void *p)
+{
+	struct lan966x_port *port = netdev_priv(dev);
+	struct lan966x *lan966x = port->lan966x;
+	const struct sockaddr *addr = p;
+	int ret;
+
+	/* Learn the new net device MAC address in the mac table. */
+	ret = lan966x_mact_learn(lan966x, PGID_CPU, addr->sa_data, port->pvid,
+				 ENTRYTYPE_LOCKED);
+	if (ret)
+		return ret;
+
+	/* Then forget the previous one. */
+	ret = lan966x_mact_forget(lan966x, dev->dev_addr, port->pvid,
+				  ENTRYTYPE_LOCKED);
+	if (ret)
+		return ret;
+
+	ether_addr_copy(dev->dev_addr, addr->sa_data);
+	return ret;
+}
+
 static int lan966x_port_get_phys_port_name(struct net_device *dev,
 					   char *buf, size_t len)
 {
@@ -301,13 +404,50 @@ static int lan966x_change_mtu(struct net_device *dev, int new_mtu)
 	return 0;
 }
 
+static int lan966x_mc_unsync(struct net_device *dev, const unsigned char *addr)
+{
+	struct lan966x_port *port = netdev_priv(dev);
+	struct lan966x *lan966x = port->lan966x;
+
+	return lan966x_mact_forget(lan966x, addr, port->pvid, ENTRYTYPE_LOCKED);
+}
+
+static int lan966x_mc_sync(struct net_device *dev, const unsigned char *addr)
+{
+	struct lan966x_port *port = netdev_priv(dev);
+	struct lan966x *lan966x = port->lan966x;
+
+	return lan966x_mact_learn(lan966x, PGID_CPU, addr, port->pvid,
+				  ENTRYTYPE_LOCKED);
+}
+
+static void lan966x_set_rx_mode(struct net_device *dev)
+{
+	__dev_mc_sync(dev, lan966x_mc_sync, lan966x_mc_unsync);
+}
+
+static int lan966x_port_get_parent_id(struct net_device *dev,
+				      struct netdev_phys_item_id *ppid)
+{
+	struct lan966x_port *lan966x_port = netdev_priv(dev);
+	struct lan966x *lan966x = lan966x_port->lan966x;
+
+	ppid->id_len = sizeof(lan966x->base_mac);
+	memcpy(&ppid->id, &lan966x->base_mac, ppid->id_len);
+
+	return 0;
+}
+
 static const struct net_device_ops lan966x_port_netdev_ops = {
 	.ndo_open			= lan966x_port_open,
 	.ndo_stop			= lan966x_port_stop,
 	.ndo_start_xmit			= lan966x_port_xmit,
 	.ndo_change_rx_flags		= lan966x_change_rx_flags,
 	.ndo_change_mtu			= lan966x_change_mtu,
+	.ndo_set_rx_mode		= lan966x_set_rx_mode,
 	.ndo_get_phys_port_name		= lan966x_port_get_phys_port_name,
+	.ndo_set_mac_address		= lan966x_port_set_mac_address,
+	.ndo_get_port_parent_id		= lan966x_port_get_parent_id,
 };
 
 static int lan966x_ifh_extract(u32 *ifh, size_t pos, size_t length)
@@ -515,6 +655,12 @@ static int lan966x_probe_port(struct lan966x *lan966x, u8 port,
 	dev->netdev_ops = &lan966x_port_netdev_ops;
 	dev->needed_headroom = IFH_LEN * sizeof(u32);
 
+	ether_addr_copy(dev->dev_addr, lan966x->base_mac);
+	dev->dev_addr[ETH_ALEN - 1] += port + 1;
+
+	lan966x_mact_learn(lan966x, PGID_CPU, dev->dev_addr, lan966x_port->pvid,
+			   ENTRYTYPE_LOCKED);
+
 	err = register_netdev(dev);
 	if (err) {
 		dev_err(lan966x->dev, "register_netdev failed\n");
@@ -544,6 +690,9 @@ static void lan966x_init(struct lan966x *lan966x)
 {
 	u32 port, i;
 
+	/* MAC table initialization */
+	lan966x_mact_init(lan966x);
+
 	/* Flush queues */
 	lan_wr(lan_rd(lan966x, QS_XTR_FLUSH) |
 	       GENMASK(1, 0),
@@ -708,6 +857,7 @@ static int lan966x_probe(struct platform_device *pdev)
 {
 	struct fwnode_handle *ports, *portnp;
 	struct lan966x *lan966x;
+	u8 mac_addr[ETH_ALEN];
 	int err, i;
 
 	lan966x = devm_kzalloc(&pdev->dev, sizeof(*lan966x), GFP_KERNEL);
@@ -717,6 +867,14 @@ static int lan966x_probe(struct platform_device *pdev)
 	platform_set_drvdata(pdev, lan966x);
 	lan966x->dev = &pdev->dev;
 
+	if (device_get_mac_address(&pdev->dev, mac_addr, sizeof(mac_addr))) {
+		ether_addr_copy(lan966x->base_mac, mac_addr);
+	} else {
+		pr_info("MAC addr was not set, use random MAC\n");
+		eth_random_addr(lan966x->base_mac);
+		lan966x->base_mac[5] &= 0xf0;
+	}
+
 	ports = device_get_named_child_node(&pdev->dev, "ethernet-ports");
 	if (!ports) {
 		dev_err(&pdev->dev, "no ethernet-ports child not found\n");
diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_main.h b/drivers/net/ethernet/microchip/lan966x/lan966x_main.h
index 9ae1582f5cdb..d499f654e316 100644
--- a/drivers/net/ethernet/microchip/lan966x/lan966x_main.h
+++ b/drivers/net/ethernet/microchip/lan966x/lan966x_main.h
@@ -4,6 +4,9 @@
 #define __LAN966X_MAIN_H__
 
 #include <linux/etherdevice.h>
+#include "linux/ethtool.h"
+#include <linux/jiffies.h>
+#include <linux/spinlock.h>
 #include <linux/phy.h>
 #include <linux/phylink.h>
 
@@ -38,6 +41,30 @@
 
 #define CPU_PORT			8
 
+#define LAN966X_MACT_COLUMNS		4
+#define MACACCESS_CMD_IDLE		0
+#define MACACCESS_CMD_LEARN		1
+#define MACACCESS_CMD_FORGET		2
+#define MACACCESS_CMD_AGE		3
+#define MACACCESS_CMD_GET_NEXT		4
+#define MACACCESS_CMD_INIT		5
+#define MACACCESS_CMD_READ		6
+#define MACACCESS_CMD_WRITE		7
+#define MACACCESS_CMD_SYNC_GET_NEXT	8
+
+/* MAC table entry types.
+ * ENTRYTYPE_NORMAL is subject to aging.
+ * ENTRYTYPE_LOCKED is not subject to aging.
+ * ENTRYTYPE_MACv4 is not subject to aging. For IPv4 multicast.
+ * ENTRYTYPE_MACv6 is not subject to aging. For IPv6 multicast.
+ */
+enum macaccess_entry_type {
+	ENTRYTYPE_NORMAL = 0,
+	ENTRYTYPE_LOCKED,
+	ENTRYTYPE_MACV4,
+	ENTRYTYPE_MACV6,
+};
+
 struct lan966x_port;
 
 struct lan966x_frame_info {
@@ -59,6 +86,8 @@ struct lan966x {
 
 	int shared_queue_sz;
 
+	u8 base_mac[ETH_ALEN];
+
 	/* interrupts */
 	int xtr_irq;
 };
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [RFC PATCH net-next 12/12] net: lan966x: add ethtool configuration and statistics
  2021-09-20  9:52 [RFC PATCH net-next 00/12] Add lan966x driver Horatiu Vultur
                   ` (10 preceding siblings ...)
  2021-09-20  9:52 ` [RFC PATCH net-next 11/12] net: lan966x: add mactable support Horatiu Vultur
@ 2021-09-20  9:52 ` Horatiu Vultur
  2021-09-20 20:31   ` Jakub Kicinski
  11 siblings, 1 reply; 30+ messages in thread
From: Horatiu Vultur @ 2021-09-20  9:52 UTC (permalink / raw)
  To: davem, kuba, robh+dt, andrew, linux, f.fainelli,
	alexandre.belloni, vladimir.oltean, UNGLinuxDriver, netdev,
	devicetree, linux-kernel, linux-phy, linux-pm
  Cc: Horatiu Vultur

This patch adds support for statistics counters for the network
interfaces. Also adds support for configuring the network interface via
ethtool like: speed, duplex etc.

Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
---
 .../net/ethernet/microchip/lan966x/Makefile   |   3 +-
 .../microchip/lan966x/lan966x_ethtool.c       | 578 ++++++++++++++++++
 .../ethernet/microchip/lan966x/lan966x_main.c |  11 +
 .../ethernet/microchip/lan966x/lan966x_main.h |  20 +
 4 files changed, 611 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c

diff --git a/drivers/net/ethernet/microchip/lan966x/Makefile b/drivers/net/ethernet/microchip/lan966x/Makefile
index e18c9b2d0bb7..445a2abc47ff 100644
--- a/drivers/net/ethernet/microchip/lan966x/Makefile
+++ b/drivers/net/ethernet/microchip/lan966x/Makefile
@@ -5,4 +5,5 @@
 
 obj-$(CONFIG_LAN966X_SWITCH) += lan966x-switch.o
 
-lan966x-switch-objs  := lan966x_main.o lan966x_phylink.o lan966x_port.o
+lan966x-switch-objs  := lan966x_main.o lan966x_phylink.o lan966x_port.o \
+	lan966x_ethtool.o
diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c b/drivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c
new file mode 100644
index 000000000000..90fe2d872afa
--- /dev/null
+++ b/drivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c
@@ -0,0 +1,578 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* Copyright (C) 2019 Microchip Technology Inc. */
+
+#include <linux/netdevice.h>
+
+#include "lan966x_main.h"
+
+/* Number of traffic classes */
+#define LAN966X_NUM_TC			8
+#define LAN966X_STATS_CHECK_DELAY	(2 * HZ)
+
+static const struct lan966x_stat_layout lan966x_stats_layout[] = {
+	{ .name = "rx_octets", .offset = 0x00, },
+	{ .name = "rx_unicast", .offset = 0x01, },
+	{ .name = "rx_multicast", .offset = 0x02 },
+	{ .name = "rx_broadcast", .offset = 0x03 },
+	{ .name = "rx_short", .offset = 0x04 },
+	{ .name = "rx_frag", .offset = 0x05 },
+	{ .name = "rx_jabber", .offset = 0x06 },
+	{ .name = "rx_crc", .offset = 0x07 },
+	{ .name = "rx_symbol_err", .offset = 0x08 },
+	{ .name = "rx_sz_64", .offset = 0x09 },
+	{ .name = "rx_sz_65_127", .offset = 0x0a},
+	{ .name = "rx_sz_128_255", .offset = 0x0b},
+	{ .name = "rx_sz_256_511", .offset = 0x0c },
+	{ .name = "rx_sz_512_1023", .offset = 0x0d },
+	{ .name = "rx_sz_1024_1526", .offset = 0x0e },
+	{ .name = "rx_sz_jumbo", .offset = 0x0f },
+	{ .name = "rx_pause", .offset = 0x10 },
+	{ .name = "rx_control", .offset = 0x11 },
+	{ .name = "rx_long", .offset = 0x12 },
+	{ .name = "rx_cat_drop", .offset = 0x13 },
+	{ .name = "rx_red_prio_0", .offset = 0x14 },
+	{ .name = "rx_red_prio_1", .offset = 0x15 },
+	{ .name = "rx_red_prio_2", .offset = 0x16 },
+	{ .name = "rx_red_prio_3", .offset = 0x17 },
+	{ .name = "rx_red_prio_4", .offset = 0x18 },
+	{ .name = "rx_red_prio_5", .offset = 0x19 },
+	{ .name = "rx_red_prio_6", .offset = 0x1a },
+	{ .name = "rx_red_prio_7", .offset = 0x1b },
+	{ .name = "rx_yellow_prio_0", .offset = 0x1c },
+	{ .name = "rx_yellow_prio_1", .offset = 0x1d },
+	{ .name = "rx_yellow_prio_2", .offset = 0x1e },
+	{ .name = "rx_yellow_prio_3", .offset = 0x1f },
+	{ .name = "rx_yellow_prio_4", .offset = 0x20 },
+	{ .name = "rx_yellow_prio_5", .offset = 0x21 },
+	{ .name = "rx_yellow_prio_6", .offset = 0x22 },
+	{ .name = "rx_yellow_prio_7", .offset = 0x23 },
+	{ .name = "rx_green_prio_0", .offset = 0x24 },
+	{ .name = "rx_green_prio_1", .offset = 0x25 },
+	{ .name = "rx_green_prio_2", .offset = 0x26 },
+	{ .name = "rx_green_prio_3", .offset = 0x27 },
+	{ .name = "rx_green_prio_4", .offset = 0x28 },
+	{ .name = "rx_green_prio_5", .offset = 0x29 },
+	{ .name = "rx_green_prio_6", .offset = 0x2a },
+	{ .name = "rx_green_prio_7", .offset = 0x2b },
+	{ .name = "rx_assembly_err", .offset = 0x2c },
+	{ .name = "rx_smd_err", .offset = 0x2d },
+	{ .name = "rx_assembly_ok", .offset = 0x2e },
+	{ .name = "rx_merge_frag", .offset = 0x2f },
+	{ .name = "rx_pmac_octets", .offset = 0x30, },
+	{ .name = "rx_pmac_unicast", .offset = 0x31, },
+	{ .name = "rx_pmac_multicast", .offset = 0x32 },
+	{ .name = "rx_pmac_broadcast", .offset = 0x33 },
+	{ .name = "rx_pmac_short", .offset = 0x34 },
+	{ .name = "rx_pmac_frag", .offset = 0x35 },
+	{ .name = "rx_pmac_jabber", .offset = 0x36 },
+	{ .name = "rx_pmac_crc", .offset = 0x37 },
+	{ .name = "rx_pmac_symbol_err", .offset = 0x38 },
+	{ .name = "rx_pmac_sz_64", .offset = 0x39 },
+	{ .name = "rx_pmac_sz_65_127", .offset = 0x3a },
+	{ .name = "rx_pmac_sz_128_255", .offset = 0x3b },
+	{ .name = "rx_pmac_sz_256_511", .offset = 0x3c },
+	{ .name = "rx_pmac_sz_512_1023", .offset = 0x3d },
+	{ .name = "rx_pmac_sz_1024_1526", .offset = 0x3e },
+	{ .name = "rx_pmac_sz_jumbo", .offset = 0x3f },
+	{ .name = "rx_pmac_pause", .offset = 0x40 },
+	{ .name = "rx_pmac_control", .offset = 0x41 },
+	{ .name = "rx_pmac_long", .offset = 0x42 },
+
+	{ .name = "tx_octets", .offset = 0x80, },
+	{ .name = "tx_unicast", .offset = 0x81, },
+	{ .name = "tx_multicast", .offset = 0x82 },
+	{ .name = "tx_broadcast", .offset = 0x83 },
+	{ .name = "tx_col", .offset = 0x84 },
+	{ .name = "tx_drop", .offset = 0x85 },
+	{ .name = "tx_pause", .offset = 0x86 },
+	{ .name = "tx_sz_64", .offset = 0x87 },
+	{ .name = "tx_sz_65_127", .offset = 0x88 },
+	{ .name = "tx_sz_128_255", .offset = 0x89 },
+	{ .name = "tx_sz_256_511", .offset = 0x8a },
+	{ .name = "tx_sz_512_1023", .offset = 0x8b },
+	{ .name = "tx_sz_1024_1526", .offset = 0x8c },
+	{ .name = "tx_sz_jumbo", .offset = 0x8d },
+	{ .name = "tx_yellow_prio_0", .offset = 0x8e },
+	{ .name = "tx_yellow_prio_1", .offset = 0x8f },
+	{ .name = "tx_yellow_prio_2", .offset = 0x90 },
+	{ .name = "tx_yellow_prio_3", .offset = 0x91 },
+	{ .name = "tx_yellow_prio_4", .offset = 0x92 },
+	{ .name = "tx_yellow_prio_5", .offset = 0x93 },
+	{ .name = "tx_yellow_prio_6", .offset = 0x94 },
+	{ .name = "tx_yellow_prio_7", .offset = 0x95 },
+	{ .name = "tx_green_prio_0", .offset = 0x96 },
+	{ .name = "tx_green_prio_1", .offset = 0x97 },
+	{ .name = "tx_green_prio_2", .offset = 0x98 },
+	{ .name = "tx_green_prio_3", .offset = 0x99 },
+	{ .name = "tx_green_prio_4", .offset = 0x9a },
+	{ .name = "tx_green_prio_5", .offset = 0x9b },
+	{ .name = "tx_green_prio_6", .offset = 0x9c },
+	{ .name = "tx_green_prio_7", .offset = 0x9d },
+	{ .name = "tx_aged", .offset = 0x9e },
+	{ .name = "tx_llct", .offset = 0x9f },
+	{ .name = "tx_ct", .offset = 0xa0 },
+	{ .name = "tx_mm_hold", .offset = 0xa1 },
+	{ .name = "tx_merge_frag", .offset = 0xa2 },
+	{ .name = "tx_pmac_octets", .offset = 0xa3, },
+	{ .name = "tx_pmac_unicast", .offset = 0xa4, },
+	{ .name = "tx_pmac_multicast", .offset = 0xa5 },
+	{ .name = "tx_pmac_broadcast", .offset = 0xa6 },
+	{ .name = "tx_pmac_pause", .offset = 0xa7 },
+	{ .name = "tx_pmac_sz_64", .offset = 0xa8 },
+	{ .name = "tx_pmac_sz_65_127", .offset = 0xa9 },
+	{ .name = "tx_pmac_sz_128_255", .offset = 0xaa },
+	{ .name = "tx_pmac_sz_256_511", .offset = 0xab },
+	{ .name = "tx_pmac_sz_512_1023", .offset = 0xac },
+	{ .name = "tx_pmac_sz_1024_1526", .offset = 0xad },
+	{ .name = "tx_pmac_sz_jumbo", .offset = 0xae },
+
+	{ .name = "dr_local", .offset = 0x100 },
+	{ .name = "dr_tail", .offset = 0x101 },
+	{ .name = "dr_yellow_prio_0", .offset = 0x102 },
+	{ .name = "dr_yellow_prio_1", .offset = 0x103 },
+	{ .name = "dr_yellow_prio_2", .offset = 0x104 },
+	{ .name = "dr_yellow_prio_3", .offset = 0x105 },
+	{ .name = "dr_yellow_prio_4", .offset = 0x106 },
+	{ .name = "dr_yellow_prio_5", .offset = 0x107 },
+	{ .name = "dr_yellow_prio_6", .offset = 0x108 },
+	{ .name = "dr_yellow_prio_7", .offset = 0x109 },
+	{ .name = "dr_green_prio_0", .offset = 0x10a },
+	{ .name = "dr_green_prio_1", .offset = 0x10b },
+	{ .name = "dr_green_prio_2", .offset = 0x10c },
+	{ .name = "dr_green_prio_3", .offset = 0x10d },
+	{ .name = "dr_green_prio_4", .offset = 0x10e },
+	{ .name = "dr_green_prio_5", .offset = 0x10f },
+	{ .name = "dr_green_prio_6", .offset = 0x110 },
+	{ .name = "dr_green_prio_7", .offset = 0x111 },
+};
+
+/* The following numbers are indexes into lan966x_stats_layout[] */
+#define SYS_COUNT_RX_OCT		  0
+#define SYS_COUNT_RX_UC			  1
+#define SYS_COUNT_RX_MC			  2
+#define SYS_COUNT_RX_BC			  3
+#define SYS_COUNT_RX_SHORT		  4
+#define SYS_COUNT_RX_FRAG		  5
+#define SYS_COUNT_RX_JABBER		  6
+#define SYS_COUNT_RX_CRC		  7
+#define SYS_COUNT_RX_SYMBOL_ERR		  8
+#define SYS_COUNT_RX_SZ_64		  9
+#define SYS_COUNT_RX_SZ_65_127		 10
+#define SYS_COUNT_RX_SZ_128_255		 11
+#define SYS_COUNT_RX_SZ_256_511		 12
+#define SYS_COUNT_RX_SZ_512_1023	 13
+#define SYS_COUNT_RX_SZ_1024_1526	 14
+#define SYS_COUNT_RX_SZ_JUMBO		 15
+#define SYS_COUNT_RX_PAUSE		 16
+#define SYS_COUNT_RX_CONTROL		 17
+#define SYS_COUNT_RX_LONG		 18
+#define SYS_COUNT_RX_CAT_DROP		 19
+#define SYS_COUNT_RX_RED_PRIO_0		 20
+#define SYS_COUNT_RX_RED_PRIO_1		 21
+#define SYS_COUNT_RX_RED_PRIO_2		 22
+#define SYS_COUNT_RX_RED_PRIO_3		 23
+#define SYS_COUNT_RX_RED_PRIO_4		 24
+#define SYS_COUNT_RX_RED_PRIO_5		 25
+#define SYS_COUNT_RX_RED_PRIO_6		 26
+#define SYS_COUNT_RX_RED_PRIO_7		 27
+#define SYS_COUNT_RX_YELLOW_PRIO_0	 28
+#define SYS_COUNT_RX_YELLOW_PRIO_1	 29
+#define SYS_COUNT_RX_YELLOW_PRIO_2	 30
+#define SYS_COUNT_RX_YELLOW_PRIO_3	 31
+#define SYS_COUNT_RX_YELLOW_PRIO_4	 32
+#define SYS_COUNT_RX_YELLOW_PRIO_5	 33
+#define SYS_COUNT_RX_YELLOW_PRIO_6	 34
+#define SYS_COUNT_RX_YELLOW_PRIO_7	 35
+#define SYS_COUNT_RX_GREEN_PRIO_0	 36
+#define SYS_COUNT_RX_GREEN_PRIO_1	 37
+#define SYS_COUNT_RX_GREEN_PRIO_2	 38
+#define SYS_COUNT_RX_GREEN_PRIO_3	 39
+#define SYS_COUNT_RX_GREEN_PRIO_4	 40
+#define SYS_COUNT_RX_GREEN_PRIO_5	 41
+#define SYS_COUNT_RX_GREEN_PRIO_6	 42
+#define SYS_COUNT_RX_GREEN_PRIO_7	 43
+#define SYS_COUNT_RX_ASSEMBLY_ERR	 44
+#define SYS_COUNT_RX_SMD_ERR		 45
+#define SYS_COUNT_RX_ASSEMBLY_OK	 46
+#define SYS_COUNT_RX_MERGE_FRAG		 47
+#define SYS_COUNT_RX_PMAC_OCT		 48
+#define SYS_COUNT_RX_PMAC_UC		 49
+#define SYS_COUNT_RX_PMAC_MC		 50
+#define SYS_COUNT_RX_PMAC_BC		 51
+#define SYS_COUNT_RX_PMAC_SHORT		 52
+#define SYS_COUNT_RX_PMAC_FRAG		 53
+#define SYS_COUNT_RX_PMAC_JABBER	 54
+#define SYS_COUNT_RX_PMAC_CRC		 55
+#define SYS_COUNT_RX_PMAC_SYMBOL_ERR	 56
+#define SYS_COUNT_RX_PMAC_SZ_64		 57
+#define SYS_COUNT_RX_PMAC_SZ_65_127	 58
+#define SYS_COUNT_RX_PMAC_SZ_128_255	 59
+#define SYS_COUNT_RX_PMAC_SZ_256_511	 60
+#define SYS_COUNT_RX_PMAC_SZ_512_1023	 61
+#define SYS_COUNT_RX_PMAC_SZ_1024_1526	 62
+#define SYS_COUNT_RX_PMAC_SZ_JUMBO	 63
+#define SYS_COUNT_RX_PMAC_PAUSE		 64
+#define SYS_COUNT_RX_PMAC_CONTROL	 65
+#define SYS_COUNT_RX_PMAC_LONG		 66
+
+#define SYS_COUNT_TX_OCT		 67
+#define SYS_COUNT_TX_UC			 68
+#define SYS_COUNT_TX_MC			 69
+#define SYS_COUNT_TX_BC			 70
+#define SYS_COUNT_TX_COL		 71
+#define SYS_COUNT_TX_DROP		 72
+#define SYS_COUNT_TX_PAUSE		 73
+#define SYS_COUNT_TX_SZ_64		 74
+#define SYS_COUNT_TX_SZ_65_127		 75
+#define SYS_COUNT_TX_SZ_128_255		 76
+#define SYS_COUNT_TX_SZ_256_511		 77
+#define SYS_COUNT_TX_SZ_512_1023	 78
+#define SYS_COUNT_TX_SZ_1024_1526	 79
+#define SYS_COUNT_TX_SZ_JUMBO		 80
+#define SYS_COUNT_TX_YELLOW_PRIO_0	 81
+#define SYS_COUNT_TX_YELLOW_PRIO_1	 82
+#define SYS_COUNT_TX_YELLOW_PRIO_2	 83
+#define SYS_COUNT_TX_YELLOW_PRIO_3	 84
+#define SYS_COUNT_TX_YELLOW_PRIO_4	 85
+#define SYS_COUNT_TX_YELLOW_PRIO_5	 86
+#define SYS_COUNT_TX_YELLOW_PRIO_6	 87
+#define SYS_COUNT_TX_YELLOW_PRIO_7	 88
+#define SYS_COUNT_TX_GREEN_PRIO_0	 89
+#define SYS_COUNT_TX_GREEN_PRIO_1	 90
+#define SYS_COUNT_TX_GREEN_PRIO_2	 91
+#define SYS_COUNT_TX_GREEN_PRIO_3	 92
+#define SYS_COUNT_TX_GREEN_PRIO_4	 93
+#define SYS_COUNT_TX_GREEN_PRIO_5	 94
+#define SYS_COUNT_TX_GREEN_PRIO_6	 95
+#define SYS_COUNT_TX_GREEN_PRIO_7	 96
+#define SYS_COUNT_TX_AGED		 97
+#define SYS_COUNT_TX_LLCT		 98
+#define SYS_COUNT_TX_CT			 99
+#define SYS_COUNT_TX_MM_HOLD		100
+#define SYS_COUNT_TX_MERGE_FRAG		101
+#define SYS_COUNT_TX_PMAC_OCT		102
+#define SYS_COUNT_TX_PMAC_UC		103
+#define SYS_COUNT_TX_PMAC_MC		104
+#define SYS_COUNT_TX_PMAC_BC		105
+#define SYS_COUNT_TX_PMAC_PAUSE		106
+#define SYS_COUNT_TX_PMAC_SZ_64		107
+#define SYS_COUNT_TX_PMAC_SZ_65_127	108
+#define SYS_COUNT_TX_PMAC_SZ_128_255	109
+#define SYS_COUNT_TX_PMAC_SZ_256_511	110
+#define SYS_COUNT_TX_PMAC_SZ_512_1023	111
+#define SYS_COUNT_TX_PMAC_SZ_1024_1526	112
+#define SYS_COUNT_TX_PMAC_SZ_JUMBO	113
+
+#define SYS_COUNT_DR_LOCAL		114
+#define SYS_COUNT_DR_TAIL		115
+#define SYS_COUNT_DR_YELLOW_PRIO_0	116
+#define SYS_COUNT_DR_YELLOW_PRIO_1	117
+#define SYS_COUNT_DR_YELLOW_PRIO_2	118
+#define SYS_COUNT_DR_YELLOW_PRIO_3	119
+#define SYS_COUNT_DR_YELLOW_PRIO_4	120
+#define SYS_COUNT_DR_YELLOW_PRIO_5	121
+#define SYS_COUNT_DR_YELLOW_PRIO_6	122
+#define SYS_COUNT_DR_YELLOW_PRIO_7	123
+#define SYS_COUNT_DR_GREEN_PRIO_0	124
+#define SYS_COUNT_DR_GREEN_PRIO_1	125
+#define SYS_COUNT_DR_GREEN_PRIO_2	126
+#define SYS_COUNT_DR_GREEN_PRIO_3	127
+#define SYS_COUNT_DR_GREEN_PRIO_4	128
+#define SYS_COUNT_DR_GREEN_PRIO_5	129
+#define SYS_COUNT_DR_GREEN_PRIO_6	130
+#define SYS_COUNT_DR_GREEN_PRIO_7	131
+
+/* Add a possibly wrapping 32 bit value to a 64 bit counter */
+static void lan966x_add_cnt(u64 *cnt, u32 val)
+{
+	if (val < (*cnt & U32_MAX))
+		*cnt += (u64)1 << 32; /* value has wrapped */
+
+	*cnt = (*cnt & ~(u64)U32_MAX) + val;
+}
+
+static void lan966x_stats_update(struct lan966x *lan966x)
+{
+	int i, j;
+
+	mutex_lock(&lan966x->stats_lock);
+
+	for (i = 0; i < lan966x->num_phys_ports; i++) {
+		uint idx = i * lan966x->num_stats;
+
+		lan_wr(SYS_STAT_CFG_STAT_VIEW_SET(i),
+		       lan966x, SYS_STAT_CFG);
+
+		for (j = 0; j < lan966x->num_stats; j++) {
+			u32 offset = lan966x->stats_layout[j].offset;
+
+			lan966x_add_cnt(&lan966x->stats[idx++],
+					lan_rd(lan966x, SYS_CNT(offset)));
+		}
+	}
+
+	mutex_unlock(&lan966x->stats_lock);
+}
+
+static int lan966x_get_sset_count(struct net_device *dev, int sset)
+{
+	struct lan966x_port *port = netdev_priv(dev);
+	struct lan966x *lan966x = port->lan966x;
+
+	if (sset != ETH_SS_STATS)
+		return -EOPNOTSUPP;
+
+	return lan966x->num_stats;
+}
+
+static void lan966x_get_strings(struct net_device *netdev, u32 sset, u8 *data)
+{
+	struct lan966x_port *port = netdev_priv(netdev);
+	struct lan966x *lan966x = port->lan966x;
+	int i;
+
+	if (sset != ETH_SS_STATS)
+		return;
+
+	for (i = 0; i < lan966x->num_stats; i++)
+		memcpy(data + i * ETH_GSTRING_LEN,
+		       lan966x->stats_layout[i].name, ETH_GSTRING_LEN);
+}
+
+static void lan966x_get_ethtool_stats(struct net_device *dev,
+				      struct ethtool_stats *stats, u64 *data)
+{
+	struct lan966x_port *port = netdev_priv(dev);
+	struct lan966x *lan966x = port->lan966x;
+	int i;
+
+	/* check and update now */
+	lan966x_stats_update(lan966x);
+
+	/* Copy all counters */
+	for (i = 0; i < lan966x->num_stats; i++)
+		*data++ = lan966x->stats[port->chip_port *
+					 lan966x->num_stats + i];
+}
+
+static void lan966x_get_eth_mac_stats(struct net_device *dev,
+				      struct ethtool_eth_mac_stats *mac_stats)
+{
+	struct lan966x_port *port = netdev_priv(dev);
+	struct lan966x *lan966x = port->lan966x;
+	u32 idx;
+
+	lan966x_stats_update(lan966x);
+
+	idx = port->chip_port * lan966x->num_stats;
+
+	mutex_lock(&lan966x->stats_lock);
+
+	mac_stats->FramesTransmittedOK =
+		lan966x->stats[idx + SYS_COUNT_TX_UC] +
+		lan966x->stats[idx + SYS_COUNT_TX_MC] +
+		lan966x->stats[idx + SYS_COUNT_TX_BC] +
+		lan966x->stats[idx + SYS_COUNT_TX_PMAC_UC] +
+		lan966x->stats[idx + SYS_COUNT_TX_PMAC_MC] +
+		lan966x->stats[idx + SYS_COUNT_TX_PMAC_BC];
+	mac_stats->SingleCollisionFrames =
+		lan966x->stats[idx + SYS_COUNT_TX_COL];
+	mac_stats->MultipleCollisionFrames = 0;
+	mac_stats->FramesReceivedOK =
+		lan966x->stats[idx + SYS_COUNT_RX_UC] +
+		lan966x->stats[idx + SYS_COUNT_RX_MC] +
+		lan966x->stats[idx + SYS_COUNT_RX_BC];
+	mac_stats->FrameCheckSequenceErrors =
+		lan966x->stats[idx + SYS_COUNT_RX_CRC] +
+		lan966x->stats[idx + SYS_COUNT_RX_CRC];
+	mac_stats->AlignmentErrors = 0;
+	mac_stats->OctetsTransmittedOK =
+		lan966x->stats[idx + SYS_COUNT_TX_OCT] +
+		lan966x->stats[idx + SYS_COUNT_TX_PMAC_OCT];
+	mac_stats->FramesWithDeferredXmissions =
+		lan966x->stats[idx + SYS_COUNT_TX_MM_HOLD];
+	mac_stats->LateCollisions = 0;
+	mac_stats->FramesAbortedDueToXSColls = 0;
+	mac_stats->FramesLostDueToIntMACXmitError = 0;
+	mac_stats->CarrierSenseErrors = 0;
+	mac_stats->OctetsReceivedOK =
+		lan966x->stats[idx + SYS_COUNT_RX_OCT];
+	mac_stats->FramesLostDueToIntMACRcvError = 0;
+	mac_stats->MulticastFramesXmittedOK =
+		lan966x->stats[idx + SYS_COUNT_TX_MC] +
+		lan966x->stats[idx + SYS_COUNT_TX_PMAC_MC];
+	mac_stats->BroadcastFramesXmittedOK =
+		lan966x->stats[idx + SYS_COUNT_TX_BC] +
+		lan966x->stats[idx + SYS_COUNT_TX_PMAC_BC];
+	mac_stats->FramesWithExcessiveDeferral = 0;
+	mac_stats->MulticastFramesReceivedOK =
+		lan966x->stats[idx + SYS_COUNT_RX_MC];
+	mac_stats->BroadcastFramesReceivedOK =
+		lan966x->stats[idx + SYS_COUNT_RX_BC];
+	mac_stats->InRangeLengthErrors =
+		lan966x->stats[idx + SYS_COUNT_RX_FRAG] +
+		lan966x->stats[idx + SYS_COUNT_RX_JABBER] +
+		lan966x->stats[idx + SYS_COUNT_RX_CRC] +
+		lan966x->stats[idx + SYS_COUNT_RX_PMAC_FRAG] +
+		lan966x->stats[idx + SYS_COUNT_RX_PMAC_JABBER] +
+		lan966x->stats[idx + SYS_COUNT_RX_PMAC_CRC];
+	mac_stats->OutOfRangeLengthField =
+		lan966x->stats[idx + SYS_COUNT_RX_SHORT] +
+		lan966x->stats[idx + SYS_COUNT_RX_PMAC_SHORT] +
+		lan966x->stats[idx + SYS_COUNT_RX_LONG] +
+		lan966x->stats[idx + SYS_COUNT_RX_PMAC_LONG];
+	mac_stats->FrameTooLongErrors =
+		lan966x->stats[idx + SYS_COUNT_RX_LONG] +
+		lan966x->stats[idx + SYS_COUNT_RX_PMAC_LONG];
+
+	mutex_unlock(&lan966x->stats_lock);
+}
+
+static int lan966x_get_link_ksettings(struct net_device *ndev,
+				      struct ethtool_link_ksettings *cmd)
+{
+	struct lan966x_port *port = netdev_priv(ndev);
+
+	return phylink_ethtool_ksettings_get(port->phylink, cmd);
+}
+
+static int lan966x_set_link_ksettings(struct net_device *ndev,
+				      const struct ethtool_link_ksettings *cmd)
+{
+	struct lan966x_port *port = netdev_priv(ndev);
+
+	return phylink_ethtool_ksettings_set(port->phylink, cmd);
+}
+
+const struct ethtool_ops lan966x_ethtool_ops = {
+	.get_link_ksettings     = lan966x_get_link_ksettings,
+	.set_link_ksettings     = lan966x_set_link_ksettings,
+	.get_sset_count		= lan966x_get_sset_count,
+	.get_strings		= lan966x_get_strings,
+	.get_ethtool_stats	= lan966x_get_ethtool_stats,
+	.get_eth_mac_stats      = lan966x_get_eth_mac_stats,
+	.get_link		= ethtool_op_get_link,
+};
+
+static void lan966x_check_stats_work(struct work_struct *work)
+{
+	struct delayed_work *del_work = to_delayed_work(work);
+	struct lan966x *lan966x = container_of(del_work, struct lan966x,
+					       stats_work);
+
+	lan966x_stats_update(lan966x);
+
+	queue_delayed_work(lan966x->stats_queue, &lan966x->stats_work,
+			   LAN966X_STATS_CHECK_DELAY);
+}
+
+void lan966x_stats_get(struct net_device *dev,
+		       struct rtnl_link_stats64 *stats)
+{
+	struct lan966x_port *port = netdev_priv(dev);
+	struct lan966x *lan966x = port->lan966x;
+	u32 idx;
+	int i;
+
+	idx = port->chip_port * lan966x->num_stats;
+
+	mutex_lock(&lan966x->stats_lock);
+
+	stats->rx_bytes = lan966x->stats[idx + SYS_COUNT_RX_OCT] +
+		lan966x->stats[idx + SYS_COUNT_RX_PMAC_OCT];
+
+	stats->rx_packets = lan966x->stats[idx + SYS_COUNT_RX_SHORT] +
+		lan966x->stats[idx + SYS_COUNT_RX_FRAG] +
+		lan966x->stats[idx + SYS_COUNT_RX_JABBER] +
+		lan966x->stats[idx + SYS_COUNT_RX_CRC] +
+		lan966x->stats[idx + SYS_COUNT_RX_SYMBOL_ERR] +
+		lan966x->stats[idx + SYS_COUNT_RX_SZ_64] +
+		lan966x->stats[idx + SYS_COUNT_RX_SZ_65_127] +
+		lan966x->stats[idx + SYS_COUNT_RX_SZ_128_255] +
+		lan966x->stats[idx + SYS_COUNT_RX_SZ_256_511] +
+		lan966x->stats[idx + SYS_COUNT_RX_SZ_512_1023] +
+		lan966x->stats[idx + SYS_COUNT_RX_SZ_1024_1526] +
+		lan966x->stats[idx + SYS_COUNT_RX_SZ_JUMBO] +
+		lan966x->stats[idx + SYS_COUNT_RX_LONG] +
+		lan966x->stats[idx + SYS_COUNT_RX_PMAC_SHORT] +
+		lan966x->stats[idx + SYS_COUNT_RX_PMAC_FRAG] +
+		lan966x->stats[idx + SYS_COUNT_RX_PMAC_JABBER] +
+		lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_64] +
+		lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_65_127] +
+		lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_128_255] +
+		lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_256_511] +
+		lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_512_1023] +
+		lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_1024_1526] +
+		lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_JUMBO];
+
+	stats->multicast = lan966x->stats[idx + SYS_COUNT_RX_MC] +
+		lan966x->stats[idx + SYS_COUNT_RX_PMAC_MC];
+
+	stats->rx_errors = lan966x->stats[idx + SYS_COUNT_RX_SHORT] +
+		lan966x->stats[idx + SYS_COUNT_RX_FRAG] +
+		lan966x->stats[idx + SYS_COUNT_RX_JABBER] +
+		lan966x->stats[idx + SYS_COUNT_RX_CRC] +
+		lan966x->stats[idx + SYS_COUNT_RX_SYMBOL_ERR] +
+		lan966x->stats[idx + SYS_COUNT_RX_LONG];
+
+	stats->rx_dropped = dev->stats.rx_dropped +
+		lan966x->stats[idx + SYS_COUNT_RX_LONG] +
+		lan966x->stats[idx + SYS_COUNT_DR_LOCAL] +
+		lan966x->stats[idx + SYS_COUNT_DR_TAIL];
+
+	for (i = 0; i < LAN966X_NUM_TC; i++) {
+		stats->rx_dropped +=
+			(lan966x->stats[idx + SYS_COUNT_DR_YELLOW_PRIO_0 + i] +
+			 lan966x->stats[idx + SYS_COUNT_DR_GREEN_PRIO_0 + i]);
+	}
+
+	/* Get Tx stats */
+	stats->tx_bytes = lan966x->stats[idx + SYS_COUNT_TX_OCT] +
+		lan966x->stats[idx + SYS_COUNT_TX_PMAC_OCT];
+
+	stats->tx_packets = lan966x->stats[idx + SYS_COUNT_TX_SZ_64] +
+		lan966x->stats[idx + SYS_COUNT_TX_SZ_65_127] +
+		lan966x->stats[idx + SYS_COUNT_TX_SZ_128_255] +
+		lan966x->stats[idx + SYS_COUNT_TX_SZ_256_511] +
+		lan966x->stats[idx + SYS_COUNT_TX_SZ_512_1023] +
+		lan966x->stats[idx + SYS_COUNT_TX_SZ_1024_1526] +
+		lan966x->stats[idx + SYS_COUNT_TX_SZ_JUMBO] +
+		lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_64] +
+		lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_65_127] +
+		lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_128_255] +
+		lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_256_511] +
+		lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_512_1023] +
+		lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_1024_1526] +
+		lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_JUMBO];
+
+	stats->tx_dropped = lan966x->stats[idx + SYS_COUNT_TX_DROP] +
+		lan966x->stats[idx + SYS_COUNT_TX_AGED];
+
+	stats->collisions = lan966x->stats[idx + SYS_COUNT_TX_COL];
+
+	mutex_unlock(&lan966x->stats_lock);
+}
+
+int lan966x_stats_init(struct lan966x *lan966x)
+{
+	char queue_name[32];
+
+	lan966x->stats_layout = lan966x_stats_layout;
+	lan966x->num_stats = ARRAY_SIZE(lan966x_stats_layout);
+	lan966x->stats = devm_kcalloc(lan966x->dev, lan966x->num_phys_ports *
+				      lan966x->num_stats,
+				      sizeof(u64), GFP_KERNEL);
+	if (!lan966x->stats)
+		return -ENOMEM;
+
+	/* Init stats worker */
+	mutex_init(&lan966x->stats_lock);
+	snprintf(queue_name, sizeof(queue_name), "%s-stats",
+		 dev_name(lan966x->dev));
+	lan966x->stats_queue = create_singlethread_workqueue(queue_name);
+	INIT_DELAYED_WORK(&lan966x->stats_work, lan966x_check_stats_work);
+	queue_delayed_work(lan966x->stats_queue, &lan966x->stats_work,
+			   LAN966X_STATS_CHECK_DELAY);
+
+	return 0;
+}
diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_main.c b/drivers/net/ethernet/microchip/lan966x/lan966x_main.c
index 53b88bb5b718..7448d414c6cc 100644
--- a/drivers/net/ethernet/microchip/lan966x/lan966x_main.c
+++ b/drivers/net/ethernet/microchip/lan966x/lan966x_main.c
@@ -446,6 +446,7 @@ static const struct net_device_ops lan966x_port_netdev_ops = {
 	.ndo_change_mtu			= lan966x_change_mtu,
 	.ndo_set_rx_mode		= lan966x_set_rx_mode,
 	.ndo_get_phys_port_name		= lan966x_port_get_phys_port_name,
+	.ndo_get_stats64		= lan966x_stats_get,
 	.ndo_set_mac_address		= lan966x_port_set_mac_address,
 	.ndo_get_port_parent_id		= lan966x_port_get_parent_id,
 };
@@ -653,6 +654,7 @@ static int lan966x_probe_port(struct lan966x *lan966x, u8 port,
 	dev->max_mtu = ETH_MAX_MTU;
 
 	dev->netdev_ops = &lan966x_port_netdev_ops;
+	dev->ethtool_ops = &lan966x_ethtool_ops;
 	dev->needed_headroom = IFH_LEN * sizeof(u32);
 
 	ether_addr_copy(dev->dev_addr, lan966x->base_mac);
@@ -918,6 +920,7 @@ static int lan966x_probe(struct platform_device *pdev)
 
 	/* init switch */
 	lan966x_init(lan966x);
+	lan966x_stats_init(lan966x);
 
 	/* go over the child nodes */
 	fwnode_for_each_available_child_node(ports, portnp) {
@@ -950,6 +953,10 @@ static int lan966x_probe(struct platform_device *pdev)
 cleanup_ports:
 	fwnode_handle_put(portnp);
 
+	cancel_delayed_work_sync(&lan966x->stats_work);
+	destroy_workqueue(lan966x->stats_queue);
+	mutex_destroy(&lan966x->stats_lock);
+
 	disable_irq(lan966x->xtr_irq);
 	lan966x->xtr_irq = -ENXIO;
 	lan966x_cleanup_ports(lan966x);
@@ -961,6 +968,10 @@ static int lan966x_remove(struct platform_device *pdev)
 {
 	struct lan966x *lan966x = platform_get_drvdata(pdev);
 
+	cancel_delayed_work_sync(&lan966x->stats_work);
+	destroy_workqueue(lan966x->stats_queue);
+	mutex_destroy(&lan966x->stats_lock);
+
 	disable_irq(lan966x->xtr_irq);
 	lan966x->xtr_irq = -ENXIO;
 	lan966x_cleanup_ports(lan966x);
diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_main.h b/drivers/net/ethernet/microchip/lan966x/lan966x_main.h
index d499f654e316..fa484226656e 100644
--- a/drivers/net/ethernet/microchip/lan966x/lan966x_main.h
+++ b/drivers/net/ethernet/microchip/lan966x/lan966x_main.h
@@ -76,6 +76,11 @@ struct lan966x_frame_info {
 	u8 ipv;
 };
 
+struct lan966x_stat_layout {
+	u32 offset;
+	char name[ETH_GSTRING_LEN];
+};
+
 struct lan966x {
 	struct device *dev;
 
@@ -88,6 +93,16 @@ struct lan966x {
 
 	u8 base_mac[ETH_ALEN];
 
+	/* stats */
+	const struct lan966x_stat_layout *stats_layout;
+	u32 num_stats;
+
+	/* workqueue for reading stats */
+	struct mutex stats_lock;
+	u64 *stats;
+	struct delayed_work stats_work;
+	struct workqueue_struct *stats_queue;
+
 	/* interrupts */
 	int xtr_irq;
 };
@@ -117,6 +132,11 @@ struct lan966x_port {
 };
 
 extern const struct phylink_mac_ops lan966x_phylink_mac_ops;
+extern const struct ethtool_ops lan966x_ethtool_ops;
+
+void lan966x_stats_get(struct net_device *dev,
+		       struct rtnl_link_stats64 *stats);
+int lan966x_stats_init(struct lan966x *lan966x);
 
 void lan966x_port_config_down(struct lan966x_port *port);
 void lan966x_port_config_up(struct lan966x_port *port);
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* Re: [RFC PATCH net-next 02/12] net: phy: mchp: Add support for LAN8804 PHY
  2021-09-20  9:52 ` [RFC PATCH net-next 02/12] net: phy: mchp: Add support for LAN8804 PHY Horatiu Vultur
@ 2021-09-20 10:00   ` Alexandre Belloni
  2021-09-20 11:59   ` Andrew Lunn
  1 sibling, 0 replies; 30+ messages in thread
From: Alexandre Belloni @ 2021-09-20 10:00 UTC (permalink / raw)
  To: Horatiu Vultur
  Cc: davem, kuba, robh+dt, andrew, linux, f.fainelli, vladimir.oltean,
	UNGLinuxDriver, netdev, devicetree, linux-kernel, linux-phy,
	linux-pm

Hi,

On 20/09/2021 11:52:08+0200, Horatiu Vultur wrote:
> The LAN8804 SKY has same features as that of LAN8804 SKY except that it

On of those part name should be different ;)

> doesn't support 1588, SyncE or Q-USGMII.
> 
> This PHY is found inside the LAN966X switches.
> 
> Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
> ---
>  drivers/net/phy/micrel.c   | 73 ++++++++++++++++++++++++++++++++++++++
>  include/linux/micrel_phy.h |  1 +
>  2 files changed, 74 insertions(+)
> 
> diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c
> index 5c928f827173..34800b547004 100644
> --- a/drivers/net/phy/micrel.c
> +++ b/drivers/net/phy/micrel.c
> @@ -1537,6 +1537,65 @@ static int ksz886x_cable_test_get_status(struct phy_device *phydev,
>  	return ret;
>  }
>  
> +#define LAN_EXT_PAGE_ACCESS_CONTROL			0x16
> +#define LAN_EXT_PAGE_ACCESS_ADDRESS_DATA		0x17
> +#define LAN_EXT_PAGE_ACCESS_CTRL_EP_FUNC		0x4000
> +
> +#define LAN8804_ALIGN_SWAP				0x4a
> +#define LAN8804_ALIGN_TX_A_B_SWAP			0x1
> +#define LAN8804_ALIGN_TX_A_B_SWAP_MASK			GENMASK(2, 0)
> +#define LAN8814_CLOCK_MANAGEMENT			0xd
> +#define LAN8814_LINK_QUALITY				0x8e
> +
> +static int lanphy_read_page_reg(struct phy_device *phydev, int page, u32 addr)
> +{
> +	u32 data;
> +
> +	phy_write(phydev, LAN_EXT_PAGE_ACCESS_CONTROL, page);
> +	phy_write(phydev, LAN_EXT_PAGE_ACCESS_ADDRESS_DATA, addr);
> +	phy_write(phydev, LAN_EXT_PAGE_ACCESS_CONTROL,
> +		  (page | LAN_EXT_PAGE_ACCESS_CTRL_EP_FUNC));
> +	data = phy_read(phydev, LAN_EXT_PAGE_ACCESS_ADDRESS_DATA);
> +
> +	return data;
> +}
> +
> +static int lanphy_write_page_reg(struct phy_device *phydev, int page, u16 addr,
> +				 u16 val)
> +{
> +	phy_write(phydev, LAN_EXT_PAGE_ACCESS_CONTROL, page);
> +	phy_write(phydev, LAN_EXT_PAGE_ACCESS_ADDRESS_DATA, addr);
> +	phy_write(phydev, LAN_EXT_PAGE_ACCESS_CONTROL,
> +		  (page | LAN_EXT_PAGE_ACCESS_CTRL_EP_FUNC));
> +
> +	val = phy_write(phydev, LAN_EXT_PAGE_ACCESS_ADDRESS_DATA, val);
> +	if (val) {
> +		phydev_err(phydev, "Error: phy_write has returned error %d\n",
> +			   val);
> +		return val;
> +	}
> +	return 0;
> +}
> +
> +static int lan8804_config_init(struct phy_device *phydev)
> +{
> +	int val;
> +
> +	/* MDI-X setting for swap A,B transmit */
> +	val = lanphy_read_page_reg(phydev, 2, LAN8804_ALIGN_SWAP);
> +	val &= ~LAN8804_ALIGN_TX_A_B_SWAP_MASK;
> +	val |= LAN8804_ALIGN_TX_A_B_SWAP;
> +	lanphy_write_page_reg(phydev, 2, LAN8804_ALIGN_SWAP, val);
> +
> +	/* Make sure that the PHY will not stop generating the clock when the
> +	 * link partner goes down
> +	 */
> +	lanphy_write_page_reg(phydev, 31, LAN8814_CLOCK_MANAGEMENT, 0x27e);
> +	lanphy_read_page_reg(phydev, 1, LAN8814_LINK_QUALITY);
> +
> +	return 0;
> +}
> +
>  static struct phy_driver ksphy_driver[] = {
>  {
>  	.phy_id		= PHY_ID_KS8737,
> @@ -1718,6 +1777,20 @@ static struct phy_driver ksphy_driver[] = {
>  	.get_stats	= kszphy_get_stats,
>  	.suspend	= genphy_suspend,
>  	.resume		= kszphy_resume,
> +}, {
> +	.phy_id		= PHY_ID_LAN8804,
> +	.phy_id_mask	= MICREL_PHY_ID_MASK,
> +	.name		= "Microchip LAN966X Gigabit PHY",
> +	.config_init	= lan8804_config_init,
> +	.driver_data	= &ksz9021_type,
> +	.probe		= kszphy_probe,
> +	.soft_reset	= genphy_soft_reset,
> +	.read_status	= ksz9031_read_status,
> +	.get_sset_count	= kszphy_get_sset_count,
> +	.get_strings	= kszphy_get_strings,
> +	.get_stats	= kszphy_get_stats,
> +	.suspend	= genphy_suspend,
> +	.resume		= kszphy_resume,
>  }, {
>  	.phy_id		= PHY_ID_KSZ9131,
>  	.phy_id_mask	= MICREL_PHY_ID_MASK,
> diff --git a/include/linux/micrel_phy.h b/include/linux/micrel_phy.h
> index 3d43c60b49fa..1f7c33b2f5a3 100644
> --- a/include/linux/micrel_phy.h
> +++ b/include/linux/micrel_phy.h
> @@ -28,6 +28,7 @@
>  #define PHY_ID_KSZ9031		0x00221620
>  #define PHY_ID_KSZ9131		0x00221640
>  #define PHY_ID_LAN8814		0x00221660
> +#define PHY_ID_LAN8804		0x00221670
>  
>  #define PHY_ID_KSZ886X		0x00221430
>  #define PHY_ID_KSZ8863		0x00221435
> -- 
> 2.31.1
> 

-- 
Alexandre Belloni, co-owner and COO, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [RFC PATCH net-next 01/12] net: mdio: mscc-miim: Fix the mdio controller
  2021-09-20  9:52 ` [RFC PATCH net-next 01/12] net: mdio: mscc-miim: Fix the mdio controller Horatiu Vultur
@ 2021-09-20 11:52   ` Andrew Lunn
  2021-09-22  8:24     ` Horatiu Vultur
  0 siblings, 1 reply; 30+ messages in thread
From: Andrew Lunn @ 2021-09-20 11:52 UTC (permalink / raw)
  To: Horatiu Vultur
  Cc: davem, kuba, robh+dt, linux, f.fainelli, alexandre.belloni,
	vladimir.oltean, UNGLinuxDriver, netdev, devicetree,
	linux-kernel, linux-phy, linux-pm

On Mon, Sep 20, 2021 at 11:52:07AM +0200, Horatiu Vultur wrote:
> According to the documentation the second resource is optional. But the
> blamed commit ignores that and if the resource is not there it just
> fails.
> 
> This patch reverts that to still allow the second resource to be
> optional because other SoC have the some MDIO controller and doesn't
> need to second resource.
> 
> Fixes: 672a1c394950 ("net: mdio: mscc-miim: Make use of the helper function devm_platform_ioremap_resource()")
> Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>

Hi Moratiu

The script kiddies might come long and 'fix' this again. Maybe
consider adding devm_platform_ioremap_resource_optional(), following
the pattern of other _optional() API calls. Otherwise add a comment.

    Andrew

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [RFC PATCH net-next 02/12] net: phy: mchp: Add support for LAN8804 PHY
  2021-09-20  9:52 ` [RFC PATCH net-next 02/12] net: phy: mchp: Add support for LAN8804 PHY Horatiu Vultur
  2021-09-20 10:00   ` Alexandre Belloni
@ 2021-09-20 11:59   ` Andrew Lunn
  2021-09-22  8:35     ` Horatiu Vultur
  1 sibling, 1 reply; 30+ messages in thread
From: Andrew Lunn @ 2021-09-20 11:59 UTC (permalink / raw)
  To: Horatiu Vultur
  Cc: davem, kuba, robh+dt, linux, f.fainelli, alexandre.belloni,
	vladimir.oltean, UNGLinuxDriver, netdev, devicetree,
	linux-kernel, linux-phy, linux-pm

On Mon, Sep 20, 2021 at 11:52:08AM +0200, Horatiu Vultur wrote:
> The LAN8804 SKY has same features as that of LAN8804 SKY except that it
> doesn't support 1588, SyncE or Q-USGMII.
> 
> This PHY is found inside the LAN966X switches.

Please add the new PHY to the micrel_tbl[].

       Andrew
 

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [RFC PATCH net-next 05/12] reset: lan966x: Add switch reset driver
  2021-09-20  9:52 ` [RFC PATCH net-next 05/12] reset: lan966x: Add switch reset driver Horatiu Vultur
@ 2021-09-20 12:11   ` Andrew Lunn
  2021-09-22  9:59     ` Horatiu Vultur
  0 siblings, 1 reply; 30+ messages in thread
From: Andrew Lunn @ 2021-09-20 12:11 UTC (permalink / raw)
  To: Horatiu Vultur
  Cc: davem, kuba, robh+dt, linux, f.fainelli, alexandre.belloni,
	vladimir.oltean, UNGLinuxDriver, netdev, devicetree,
	linux-kernel, linux-phy, linux-pm

On Mon, Sep 20, 2021 at 11:52:11AM +0200, Horatiu Vultur wrote:
> The lan966x switch SoC has a number of components that can be reset
> indiviually, but at least the switch core needs to be in a well defined
> state at power on, when any of the lan966x drivers starts to access the
> switch core, this reset driver is available.
> 
> The reset driver is loaded early via the postcore_initcall interface, and
> will then be available for the other lan966x drivers (SGPIO, SwitchDev etc)
> that are loaded next, and the first of them to be loaded can perform the
> one-time switch core reset that is needed.

A lot of this looks very similar to
reset-microchip-sparx5.c. PROTECT_REG is 0x88 rather than 0x84, but
actually using the value is the same. SOFT_RESET_REG is identical.  So
rather than adding a new driver, maybe you can generalize
reset-microchip-sparx5.c, and add a second compatible string?

	Andrew

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [RFC PATCH net-next 07/12] power: reset: Add lan966x power reset driver
  2021-09-20  9:52 ` [RFC PATCH net-next 07/12] power: reset: Add lan966x power reset driver Horatiu Vultur
@ 2021-09-20 12:15   ` Andrew Lunn
  0 siblings, 0 replies; 30+ messages in thread
From: Andrew Lunn @ 2021-09-20 12:15 UTC (permalink / raw)
  To: Horatiu Vultur
  Cc: davem, kuba, robh+dt, linux, f.fainelli, alexandre.belloni,
	vladimir.oltean, UNGLinuxDriver, netdev, devicetree,
	linux-kernel, linux-phy, linux-pm

> +struct lan966x_reset_context {
> +	struct regmap *gcb_ctrl;
> +	struct regmap *cpu_ctrl;
> +	struct notifier_block restart_handler;
> +};
> +
> +#define PROTECT_REG    0x88
> +#define PROTECT_BIT    BIT(5)
> +#define SOFT_RESET_REG 0x00
> +#define SOFT_RESET_BIT BIT(1)
> +
> +static int lan966x_restart_handle(struct notifier_block *this,
> +				  unsigned long mode, void *cmd)
> +{
> +	struct lan966x_reset_context *ctx = container_of(this, struct lan966x_reset_context,
> +							restart_handler);
> +
> +	/* Make sure the core is not protected from reset */
> +	regmap_update_bits(ctx->cpu_ctrl, PROTECT_REG, PROTECT_BIT, 0);

This all looks familiar...

Maybe yet another compatible added to reset-microchip-sparx5.c ?

      Andrew

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [RFC PATCH net-next 03/12] phy: Add lan966x ethernet serdes PHY driver
  2021-09-20  9:52 ` [RFC PATCH net-next 03/12] phy: Add lan966x ethernet serdes PHY driver Horatiu Vultur
@ 2021-09-20 13:42   ` Russell King (Oracle)
  2021-09-22 10:04     ` Horatiu Vultur
  2021-09-23 12:44   ` Rob Herring
  1 sibling, 1 reply; 30+ messages in thread
From: Russell King (Oracle) @ 2021-09-20 13:42 UTC (permalink / raw)
  To: Horatiu Vultur
  Cc: davem, kuba, robh+dt, andrew, f.fainelli, alexandre.belloni,
	vladimir.oltean, UNGLinuxDriver, netdev, devicetree,
	linux-kernel, linux-phy, linux-pm

On Mon, Sep 20, 2021 at 11:52:09AM +0200, Horatiu Vultur wrote:
> +static int lan966x_calc_sd6g40_setup_lane(struct lan966x_sd6g40_setup_args config,
> +					  struct lan966x_sd6g40_setup *ret_val)
> +{
> +	struct lan966x_sd6g40_mode_args sd6g40_mode;
> +	struct lan966x_sd6g40_mode_args *mode_args = &sd6g40_mode;
> +
> +	if (lan966x_sd6g40_get_conf_from_mode(config.mode, config.refclk125M,
> +					      mode_args))
> +		return -1;

This needs fixing to be a real negative error number.
lan966x_sd6g40_setup_lane() propagates this functions non-zero
return value, which is then propagated through lan966x_sd6g40_setup(),
and then through serdes_set_mode() to the PHY layer.

In general, I would suggest that _all_ int-returning functions in the
kernel that return a negative failure value _should_ _always_ return a
negative error code, so that your reviewers don't have to chase code
paths to work out whether a mistake such as the above exists.

To put it another way: never use "return -1" in the kernel.

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 40Mbps down 10Mbps up. Decent connectivity at last!

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [RFC PATCH net-next 09/12] net: lan966x: add the basic lan966x driver
  2021-09-20  9:52 ` [RFC PATCH net-next 09/12] net: lan966x: add the basic lan966x driver Horatiu Vultur
@ 2021-09-20 13:46   ` Russell King (Oracle)
  0 siblings, 0 replies; 30+ messages in thread
From: Russell King (Oracle) @ 2021-09-20 13:46 UTC (permalink / raw)
  To: Horatiu Vultur
  Cc: davem, kuba, robh+dt, andrew, f.fainelli, alexandre.belloni,
	vladimir.oltean, UNGLinuxDriver, netdev, devicetree,
	linux-kernel, linux-phy, linux-pm

On Mon, Sep 20, 2021 at 11:52:15AM +0200, Horatiu Vultur wrote:
> diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_main.c b/drivers/net/ethernet/microchip/lan966x/lan966x_main.c
> new file mode 100644
> index 000000000000..2984f510ae27
> --- /dev/null
> +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_main.c
> @@ -0,0 +1,350 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +
> +#include <asm/memory.h>
> +#include <linux/module.h>
> +#include <linux/if_bridge.h>
> +#include <linux/iopoll.h>
> +#include <linux/of_platform.h>
> +#include <linux/of_net.h>
> +#include <linux/reset.h>
> +
> +#include "lan966x_main.h"
> +
> +#define READL_SLEEP_US			10
> +#define READL_TIMEOUT_US		100000000
> +
> +#define IO_RANGES 2
> +
> +static const struct of_device_id lan966x_match[] = {
> +	{ .compatible = "microchip,lan966x-switch" },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(of, mchp_lan966x_match);
> +
> +struct lan966x_main_io_resource {
> +	enum lan966x_target id;
> +	phys_addr_t offset;
> +	int range;
> +};
> +
> +static const struct lan966x_main_io_resource lan966x_main_iomap[] =  {
> +	{ TARGET_CPU,                   0xc0000, 0 }, /* 0xe00c0000 */
> +	{ TARGET_ORG,                         0, 1 }, /* 0xe2000000 */
> +	{ TARGET_GCB,                    0x4000, 1 }, /* 0xe2004000 */
> +	{ TARGET_QS,                     0x8000, 1 }, /* 0xe2008000 */
> +	{ TARGET_CHIP_TOP,              0x10000, 1 }, /* 0xe2010000 */
> +	{ TARGET_REW,                   0x14000, 1 }, /* 0xe2014000 */
> +	{ TARGET_SYS,                   0x28000, 1 }, /* 0xe2028000 */
> +	{ TARGET_HSIO,                  0x2c000, 1 }, /* 0xe202c000 */
> +	{ TARGET_DEV,                   0x34000, 1 }, /* 0xe2034000 */
> +	{ TARGET_DEV +  1,              0x38000, 1 }, /* 0xe2038000 */
> +	{ TARGET_DEV +  2,              0x3c000, 1 }, /* 0xe203c000 */
> +	{ TARGET_DEV +  3,              0x40000, 1 }, /* 0xe2040000 */
> +	{ TARGET_DEV +  4,              0x44000, 1 }, /* 0xe2044000 */
> +	{ TARGET_DEV +  5,              0x48000, 1 }, /* 0xe2048000 */
> +	{ TARGET_DEV +  6,              0x4c000, 1 }, /* 0xe204c000 */
> +	{ TARGET_DEV +  7,              0x50000, 1 }, /* 0xe2050000 */
> +	{ TARGET_QSYS,                 0x100000, 1 }, /* 0xe2100000 */
> +	{ TARGET_AFI,                  0x120000, 1 }, /* 0xe2120000 */
> +	{ TARGET_ANA,                  0x140000, 1 }, /* 0xe2140000 */
> +};
> +
> +static int lan966x_create_targets(struct platform_device *pdev,
> +				  struct lan966x *lan966x)
> +{
> +	struct resource *iores[IO_RANGES];
> +	void __iomem *iomem[IO_RANGES];
> +	void __iomem *begin[IO_RANGES];
> +	int idx;
> +
> +	for (idx = 0; idx < IO_RANGES; idx++) {
> +		iores[idx] = platform_get_resource(pdev, IORESOURCE_MEM,
> +						   idx);
> +		iomem[idx] = devm_ioremap(&pdev->dev,
> +					  iores[idx]->start,
> +					  resource_size(iores[idx]));

This is buggy. If platform_get_resource() returns NULL, you will oops
the kernel.

In any case, this code will be ripe for janitor patching. Please
consider using devm_platform_ioremap_resource() now, before someone
converts your code to use this function.

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 40Mbps down 10Mbps up. Decent connectivity at last!

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [RFC PATCH net-next 10/12] net: lan966x: add port module support
  2021-09-20  9:52 ` [RFC PATCH net-next 10/12] net: lan966x: add port module support Horatiu Vultur
@ 2021-09-20 13:54   ` Russell King (Oracle)
  2021-09-23  8:02     ` Horatiu Vultur
  0 siblings, 1 reply; 30+ messages in thread
From: Russell King (Oracle) @ 2021-09-20 13:54 UTC (permalink / raw)
  To: Horatiu Vultur
  Cc: davem, kuba, robh+dt, andrew, f.fainelli, alexandre.belloni,
	vladimir.oltean, UNGLinuxDriver, netdev, devicetree,
	linux-kernel, linux-phy, linux-pm

On Mon, Sep 20, 2021 at 11:52:16AM +0200, Horatiu Vultur wrote:
> +static void lan966x_cleanup_ports(struct lan966x *lan966x)
> +{
> +	struct lan966x_port *port;
> +	int portno;
> +
> +	for (portno = 0; portno < lan966x->num_phys_ports; portno++) {
> +		port = lan966x->ports[portno];
> +		if (!port)
> +			continue;
> +
> +		if (port->phylink) {
> +			rtnl_lock();
> +			lan966x_port_stop(port->dev);
> +			rtnl_unlock();
> +			port->phylink = NULL;

This leaks the phylink structure. You need to call phylink_destroy().

>  static int lan966x_probe_port(struct lan966x *lan966x, u8 port,
>  			      phy_interface_t phy_mode)
>  {
>  	struct lan966x_port *lan966x_port;
> +	struct phylink *phylink;
> +	struct net_device *dev;
> +	int err;
>  
>  	if (port >= lan966x->num_phys_ports)
>  		return -EINVAL;
>  
> -	lan966x_port = devm_kzalloc(lan966x->dev, sizeof(*lan966x_port),
> -				    GFP_KERNEL);
> +	dev = devm_alloc_etherdev_mqs(lan966x->dev,
> +				      sizeof(struct lan966x_port), 8, 1);
> +	if (!dev)
> +		return -ENOMEM;
>  
> +	SET_NETDEV_DEV(dev, lan966x->dev);
> +	lan966x_port = netdev_priv(dev);
> +	lan966x_port->dev = dev;
>  	lan966x_port->lan966x = lan966x;
>  	lan966x_port->chip_port = port;
>  	lan966x_port->pvid = PORT_PVID;
>  	lan966x->ports[port] = lan966x_port;
>  
> +	dev->max_mtu = ETH_MAX_MTU;
> +
> +	dev->netdev_ops = &lan966x_port_netdev_ops;
> +	dev->needed_headroom = IFH_LEN * sizeof(u32);
> +
> +	err = register_netdev(dev);
> +	if (err) {
> +		dev_err(lan966x->dev, "register_netdev failed\n");
> +		goto err_register_netdev;
> +	}

register_netdev() publishes the network device.

> +
> +	lan966x_port->phylink_config.dev = &lan966x_port->dev->dev;
> +	lan966x_port->phylink_config.type = PHYLINK_NETDEV;
> +	lan966x_port->phylink_config.pcs_poll = true;
> +
> +	phylink = phylink_create(&lan966x_port->phylink_config,
> +				 lan966x_port->fwnode,
> +				 phy_mode,
> +				 &lan966x_phylink_mac_ops);

phylink_create() should always be called _prior_ to the network device
being published. In any case...

> +	if (IS_ERR(phylink))
> +		return PTR_ERR(phylink);

If this fails, this function returns an error, but leaves the network
device published - which is a bug in itself.

> +static void lan966x_phylink_mac_link_down(struct phylink_config *config,
> +					  unsigned int mode,
> +					  phy_interface_t interface)
> +{

Hmm? Shouldn't this do something?

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 40Mbps down 10Mbps up. Decent connectivity at last!

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [RFC PATCH net-next 12/12] net: lan966x: add ethtool configuration and statistics
  2021-09-20  9:52 ` [RFC PATCH net-next 12/12] net: lan966x: add ethtool configuration and statistics Horatiu Vultur
@ 2021-09-20 20:31   ` Jakub Kicinski
  0 siblings, 0 replies; 30+ messages in thread
From: Jakub Kicinski @ 2021-09-20 20:31 UTC (permalink / raw)
  To: Horatiu Vultur
  Cc: davem, robh+dt, andrew, linux, f.fainelli, alexandre.belloni,
	vladimir.oltean, UNGLinuxDriver, netdev, devicetree,
	linux-kernel, linux-phy, linux-pm

On Mon, 20 Sep 2021 11:52:18 +0200 Horatiu Vultur wrote:
> +static void lan966x_get_eth_mac_stats(struct net_device *dev,
> +				      struct ethtool_eth_mac_stats *mac_stats)

Great to see this API used, please also consider adding RMON stats
since the seem to be present.

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [RFC PATCH net-next 01/12] net: mdio: mscc-miim: Fix the mdio controller
  2021-09-20 11:52   ` Andrew Lunn
@ 2021-09-22  8:24     ` Horatiu Vultur
  0 siblings, 0 replies; 30+ messages in thread
From: Horatiu Vultur @ 2021-09-22  8:24 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: davem, kuba, robh+dt, linux, f.fainelli, alexandre.belloni,
	vladimir.oltean, UNGLinuxDriver, netdev, devicetree,
	linux-kernel, linux-phy, linux-pm

The 09/20/2021 13:52, Andrew Lunn wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
> 
> On Mon, Sep 20, 2021 at 11:52:07AM +0200, Horatiu Vultur wrote:
> > According to the documentation the second resource is optional. But the
> > blamed commit ignores that and if the resource is not there it just
> > fails.
> >
> > This patch reverts that to still allow the second resource to be
> > optional because other SoC have the some MDIO controller and doesn't
> > need to second resource.
> >
> > Fixes: 672a1c394950 ("net: mdio: mscc-miim: Make use of the helper function devm_platform_ioremap_resource()")
> > Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>

Hi Andrew,
> 
> Hi Moratiu
> 
> The script kiddies might come long and 'fix' this again. Maybe
> consider adding devm_platform_ioremap_resource_optional(), following
> the pattern of other _optional() API calls. Otherwise add a comment.

Initially I think I will go with the comment. Because this patch
actually needs to go on net.

> 
>     Andrew

-- 
/Horatiu

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [RFC PATCH net-next 02/12] net: phy: mchp: Add support for LAN8804 PHY
  2021-09-20 11:59   ` Andrew Lunn
@ 2021-09-22  8:35     ` Horatiu Vultur
  0 siblings, 0 replies; 30+ messages in thread
From: Horatiu Vultur @ 2021-09-22  8:35 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: davem, kuba, robh+dt, linux, f.fainelli, alexandre.belloni,
	vladimir.oltean, UNGLinuxDriver, netdev, devicetree,
	linux-kernel, linux-phy, linux-pm

The 09/20/2021 13:59, Andrew Lunn wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
> 
> On Mon, Sep 20, 2021 at 11:52:08AM +0200, Horatiu Vultur wrote:
> > The LAN8804 SKY has same features as that of LAN8804 SKY except that it
> > doesn't support 1588, SyncE or Q-USGMII.
> >
> > This PHY is found inside the LAN966X switches.
> 
> Please add the new PHY to the micrel_tbl[].

Will do that. Thanks
> 
>        Andrew
> 

-- 
/Horatiu

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [RFC PATCH net-next 05/12] reset: lan966x: Add switch reset driver
  2021-09-20 12:11   ` Andrew Lunn
@ 2021-09-22  9:59     ` Horatiu Vultur
  0 siblings, 0 replies; 30+ messages in thread
From: Horatiu Vultur @ 2021-09-22  9:59 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: davem, kuba, robh+dt, linux, f.fainelli, alexandre.belloni,
	vladimir.oltean, UNGLinuxDriver, netdev, devicetree,
	linux-kernel, linux-phy, linux-pm

The 09/20/2021 14:11, Andrew Lunn wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
> 
> On Mon, Sep 20, 2021 at 11:52:11AM +0200, Horatiu Vultur wrote:
> > The lan966x switch SoC has a number of components that can be reset
> > indiviually, but at least the switch core needs to be in a well defined
> > state at power on, when any of the lan966x drivers starts to access the
> > switch core, this reset driver is available.
> >
> > The reset driver is loaded early via the postcore_initcall interface, and
> > will then be available for the other lan966x drivers (SGPIO, SwitchDev etc)
> > that are loaded next, and the first of them to be loaded can perform the
> > one-time switch core reset that is needed.
> 
> A lot of this looks very similar to
> reset-microchip-sparx5.c. PROTECT_REG is 0x88 rather than 0x84, but
> actually using the value is the same. SOFT_RESET_REG is identical.  So
> rather than adding a new driver, maybe you can generalize
> reset-microchip-sparx5.c, and add a second compatible string?

You are right, they look similar.
I will try to add a new compatible string.

> 
>         Andrew

-- 
/Horatiu

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [RFC PATCH net-next 03/12] phy: Add lan966x ethernet serdes PHY driver
  2021-09-20 13:42   ` Russell King (Oracle)
@ 2021-09-22 10:04     ` Horatiu Vultur
  0 siblings, 0 replies; 30+ messages in thread
From: Horatiu Vultur @ 2021-09-22 10:04 UTC (permalink / raw)
  To: Russell King (Oracle)
  Cc: davem, kuba, robh+dt, andrew, f.fainelli, alexandre.belloni,
	vladimir.oltean, UNGLinuxDriver, netdev, devicetree,
	linux-kernel, linux-phy, linux-pm

The 09/20/2021 14:42, Russell King (Oracle) wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
> 
> On Mon, Sep 20, 2021 at 11:52:09AM +0200, Horatiu Vultur wrote:
> > +static int lan966x_calc_sd6g40_setup_lane(struct lan966x_sd6g40_setup_args config,
> > +                                       struct lan966x_sd6g40_setup *ret_val)
> > +{
> > +     struct lan966x_sd6g40_mode_args sd6g40_mode;
> > +     struct lan966x_sd6g40_mode_args *mode_args = &sd6g40_mode;
> > +
> > +     if (lan966x_sd6g40_get_conf_from_mode(config.mode, config.refclk125M,
> > +                                           mode_args))
> > +             return -1;
> 
> This needs fixing to be a real negative error number.
> lan966x_sd6g40_setup_lane() propagates this functions non-zero
> return value, which is then propagated through lan966x_sd6g40_setup(),
> and then through serdes_set_mode() to the PHY layer.
> 
> In general, I would suggest that _all_ int-returning functions in the
> kernel that return a negative failure value _should_ _always_ return a
> negative error code, so that your reviewers don't have to chase code
> paths to work out whether a mistake such as the above exists.
> 
> To put it another way: never use "return -1" in the kernel.

Hi Russell,

Thanks for the suggestion. I will fix this in the next version.

> 
> --
> RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
> FTTP is here! 40Mbps down 10Mbps up. Decent connectivity at last!

-- 
/Horatiu

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [RFC PATCH net-next 10/12] net: lan966x: add port module support
  2021-09-20 13:54   ` Russell King (Oracle)
@ 2021-09-23  8:02     ` Horatiu Vultur
  0 siblings, 0 replies; 30+ messages in thread
From: Horatiu Vultur @ 2021-09-23  8:02 UTC (permalink / raw)
  To: Russell King (Oracle)
  Cc: davem, kuba, robh+dt, andrew, f.fainelli, alexandre.belloni,
	vladimir.oltean, UNGLinuxDriver, netdev, devicetree,
	linux-kernel, linux-phy, linux-pm

The 09/20/2021 14:54, Russell King (Oracle) wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe

Hi Russell,

> 
> On Mon, Sep 20, 2021 at 11:52:16AM +0200, Horatiu Vultur wrote:
> > +static void lan966x_cleanup_ports(struct lan966x *lan966x)
> > +{
> > +     struct lan966x_port *port;
> > +     int portno;
> > +
> > +     for (portno = 0; portno < lan966x->num_phys_ports; portno++) {
> > +             port = lan966x->ports[portno];
> > +             if (!port)
> > +                     continue;
> > +
> > +             if (port->phylink) {
> > +                     rtnl_lock();
> > +                     lan966x_port_stop(port->dev);
> > +                     rtnl_unlock();
> > +                     port->phylink = NULL;
> 
> This leaks the phylink structure. You need to call phylink_destroy().
> 
> >  static int lan966x_probe_port(struct lan966x *lan966x, u8 port,
> >                             phy_interface_t phy_mode)
> >  {
> >       struct lan966x_port *lan966x_port;
> > +     struct phylink *phylink;
> > +     struct net_device *dev;
> > +     int err;
> >
> >       if (port >= lan966x->num_phys_ports)
> >               return -EINVAL;
> >
> > -     lan966x_port = devm_kzalloc(lan966x->dev, sizeof(*lan966x_port),
> > -                                 GFP_KERNEL);
> > +     dev = devm_alloc_etherdev_mqs(lan966x->dev,
> > +                                   sizeof(struct lan966x_port), 8, 1);
> > +     if (!dev)
> > +             return -ENOMEM;
> >
> > +     SET_NETDEV_DEV(dev, lan966x->dev);
> > +     lan966x_port = netdev_priv(dev);
> > +     lan966x_port->dev = dev;
> >       lan966x_port->lan966x = lan966x;
> >       lan966x_port->chip_port = port;
> >       lan966x_port->pvid = PORT_PVID;
> >       lan966x->ports[port] = lan966x_port;
> >
> > +     dev->max_mtu = ETH_MAX_MTU;
> > +
> > +     dev->netdev_ops = &lan966x_port_netdev_ops;
> > +     dev->needed_headroom = IFH_LEN * sizeof(u32);
> > +
> > +     err = register_netdev(dev);
> > +     if (err) {
> > +             dev_err(lan966x->dev, "register_netdev failed\n");
> > +             goto err_register_netdev;
> > +     }
> 
> register_netdev() publishes the network device.
> 
> > +
> > +     lan966x_port->phylink_config.dev = &lan966x_port->dev->dev;
> > +     lan966x_port->phylink_config.type = PHYLINK_NETDEV;
> > +     lan966x_port->phylink_config.pcs_poll = true;
> > +
> > +     phylink = phylink_create(&lan966x_port->phylink_config,
> > +                              lan966x_port->fwnode,
> > +                              phy_mode,
> > +                              &lan966x_phylink_mac_ops);
> 
> phylink_create() should always be called _prior_ to the network device
> being published. In any case...
> 
> > +     if (IS_ERR(phylink))
> > +             return PTR_ERR(phylink);
> 
> If this fails, this function returns an error, but leaves the network
> device published - which is a bug in itself.

If this fails it should eventually call lan966x_cleaup_ports where the
net_device will be unregister. But first I will need to make
phylink_create() be called prior the network device.

> 
> > +static void lan966x_phylink_mac_link_down(struct phylink_config *config,
> > +                                       unsigned int mode,
> > +                                       phy_interface_t interface)
> > +{
> 
> Hmm? Shouldn't this do something?

I don't think I need to do anything here. The current setup is that
there is a PHY in front of the MAC.
So when the link partner goes down, the PHY will go down and the MAC
will still be up. Is this a problem?
When we force the port to be set down, then in the function
lan966x_port_stop we actually shutdown the port.

> 
> --
> RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
> FTTP is here! 40Mbps down 10Mbps up. Decent connectivity at last!

-- 
/Horatiu

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [RFC PATCH net-next 03/12] phy: Add lan966x ethernet serdes PHY driver
  2021-09-20  9:52 ` [RFC PATCH net-next 03/12] phy: Add lan966x ethernet serdes PHY driver Horatiu Vultur
  2021-09-20 13:42   ` Russell King (Oracle)
@ 2021-09-23 12:44   ` Rob Herring
  1 sibling, 0 replies; 30+ messages in thread
From: Rob Herring @ 2021-09-23 12:44 UTC (permalink / raw)
  To: Horatiu Vultur
  Cc: davem, kuba, andrew, linux, f.fainelli, alexandre.belloni,
	vladimir.oltean, UNGLinuxDriver, netdev, devicetree,
	linux-kernel, linux-phy, linux-pm

On Mon, Sep 20, 2021 at 11:52:09AM +0200, Horatiu Vultur wrote:
> Add the Microchip lan966x ethernet serdes PHY driver for 1G interfaces
> available in the lan966x SoC.
> 
> Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
> ---
>  drivers/phy/microchip/Kconfig               |   8 +
>  drivers/phy/microchip/Makefile              |   1 +
>  drivers/phy/microchip/lan966x_serdes.c      | 525 ++++++++++++++++++++
>  drivers/phy/microchip/lan966x_serdes_regs.h | 482 ++++++++++++++++++
>  include/dt-bindings/phy/lan966x_serdes.h    |  14 +

This belongs with the binding change. 

>  5 files changed, 1030 insertions(+)
>  create mode 100644 drivers/phy/microchip/lan966x_serdes.c
>  create mode 100644 drivers/phy/microchip/lan966x_serdes_regs.h
>  create mode 100644 include/dt-bindings/phy/lan966x_serdes.h

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [RFC PATCH net-next 04/12] dt-bindings: reset: Add lan966x switch reset bindings
  2021-09-20  9:52 ` [RFC PATCH net-next 04/12] dt-bindings: reset: Add lan966x switch reset bindings Horatiu Vultur
@ 2021-09-23 12:49   ` Rob Herring
  0 siblings, 0 replies; 30+ messages in thread
From: Rob Herring @ 2021-09-23 12:49 UTC (permalink / raw)
  To: Horatiu Vultur
  Cc: davem, kuba, andrew, linux, f.fainelli, alexandre.belloni,
	vladimir.oltean, UNGLinuxDriver, netdev, devicetree,
	linux-kernel, linux-phy, linux-pm

On Mon, Sep 20, 2021 at 11:52:10AM +0200, Horatiu Vultur wrote:
> Document the lan966x switch reset device driver bindings
> 
> Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
> ---
>  .../bindings/reset/lan966x,rst.yaml           | 58 +++++++++++++++++++
>  1 file changed, 58 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/reset/lan966x,rst.yaml
> 
> diff --git a/Documentation/devicetree/bindings/reset/lan966x,rst.yaml b/Documentation/devicetree/bindings/reset/lan966x,rst.yaml
> new file mode 100644
> index 000000000000..97d6334e4e0a
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/reset/lan966x,rst.yaml
> @@ -0,0 +1,58 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: "http://devicetree.org/schemas/reset/lan966x,rst.yaml#"
> +$schema: "http://devicetree.org/meta-schemas/core.yaml#"
> +
> +title: Microchip lan966x Switch Reset Controller
> +
> +maintainers:
> +  - Horatiu Vultur <horatiu.vultur@microchip.com>
> +  - UNGLinuxDriver@microchip.com
> +
> +description: |
> +  The Microchip lan966x Switch provides reset control and implements the
> +  following
> +  functions
> +    - One Time Switch Core Reset (Soft Reset)

This looks like just some grouping of separate reset controllers. If 
there are 3 h/w blocks providing resets, then the DT should have 3 reset 
providers.

> +
> +properties:
> +  $nodename:
> +    pattern: "^reset-controller$"

Don't use 'pattern' for fixed strings.

> +
> +  compatible:
> +    const: microchip,lan966x-switch-reset
> +
> +  "#reset-cells":
> +    const: 1
> +
> +  cpu-syscon:
> +    $ref: "/schemas/types.yaml#/definitions/phandle"
> +    description: syscon used to access CPU reset
> +
> +  switch-syscon:
> +    $ref: "/schemas/types.yaml#/definitions/phandle"
> +    description: syscon used to access SWITCH reset
> +
> +  chip-syscon:
> +    $ref: "/schemas/types.yaml#/definitions/phandle"
> +    description: syscon used to access CHIP reset
> +
> +required:
> +  - compatible
> +  - "#reset-cells"
> +  - cpu-syscon
> +  - switch-syscon
> +  - chip-syscon
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    reset: reset-controller {
> +        compatible = "microchip,lan966x-switch-reset";
> +        #reset-cells = <1>;
> +        cpu-syscon = <&cpu_ctrl>;
> +        switch-syscon = <&switch_ctrl>;
> +        chip-syscon = <&chip_ctrl>;
> +    };
> -- 
> 2.31.1
> 
> 

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [RFC PATCH net-next 08/12] dt-bindings: net: lan966x: Add lan966x-switch bindings
  2021-09-20  9:52 ` [RFC PATCH net-next 08/12] dt-bindings: net: lan966x: Add lan966x-switch bindings Horatiu Vultur
@ 2021-09-23 12:53   ` Rob Herring
  0 siblings, 0 replies; 30+ messages in thread
From: Rob Herring @ 2021-09-23 12:53 UTC (permalink / raw)
  To: Horatiu Vultur
  Cc: davem, kuba, andrew, linux, f.fainelli, alexandre.belloni,
	vladimir.oltean, UNGLinuxDriver, netdev, devicetree,
	linux-kernel, linux-phy, linux-pm

On Mon, Sep 20, 2021 at 11:52:14AM +0200, Horatiu Vultur wrote:
> Document the lan966x switch device driver bindings
> 
> Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
> ---
>  .../net/microchip,lan966x-switch.yaml         | 114 ++++++++++++++++++
>  1 file changed, 114 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/net/microchip,lan966x-switch.yaml
> 
> diff --git a/Documentation/devicetree/bindings/net/microchip,lan966x-switch.yaml b/Documentation/devicetree/bindings/net/microchip,lan966x-switch.yaml
> new file mode 100644
> index 000000000000..53d72a65c168
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/net/microchip,lan966x-switch.yaml
> @@ -0,0 +1,114 @@
> +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/net/microchip,lan966x-switch.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Microchip Lan966x Ethernet switch controller
> +
> +maintainers:
> +  - Horatiu Vultur <horatiu.vultur@microchip.com>
> +  - UNGLinuxDriver@microchip.com
> +
> +description: |
> +  The Lan966x Enterprise Ethernet switch family provides a rich set of
> +  Enterprise switching features such as advanced TCAM-based VLAN and
> +  QoS processing enabling delivery of differentiated services, and
> +  security through TCAM-based frame processing using versatile content
> +  aware processor (VCAP).
> +
> +properties:
> +  $nodename:
> +    pattern: "^switch@[0-9a-f]+$"
> +
> +  compatible:
> +    const: microchip,lan966x-switch
> +
> +  reg:
> +    items:
> +      - description: cpu target
> +      - description: devices target
> +      - description: general control block target
> +
> +  reg-names:
> +    items:
> +      - const: cpu
> +      - const: devices
> +      - const: gcb
> +
> +  interrupts:
> +    minItems: 1

Don't need minItems unless it is less than number of entries for 
'items'.

> +    items:
> +      - description: register based extraction
> +
> +  interrupt-names:
> +    minItems: 1
> +    items:
> +      - const: xtr
> +
> +  mac-address: true
> +
> +  ethernet-ports:
> +    type: object
> +    patternProperties:
> +      "^port@[0-9a-f]+$":

ethernet-port is preferred on new bindings.

> +        type: object
> +
> +        properties:
> +          '#address-cells':
> +            const: 1
> +          '#size-cells':
> +            const: 0
> +
> +          reg:
> +            description: Switch port number
> +
> +          phy-mode:
> +            description:
> +              This specifies the interface used by the Ethernet SerDes towards
> +              the PHY or SFP.
> +
> +          phy-handle:
> +            description:
> +              phandle of a Ethernet PHY.
> +
> +        required:
> +          - reg
> +          - phy-mode
> +          - phy-handle
> +
> +required:
> +  - compatible
> +  - reg
> +  - reg-names
> +  - interrupts
> +  - interrupt-names
> +  - ethernet-ports
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    #include <dt-bindings/interrupt-controller/arm-gic.h>
> +    switch: switch@600000000 {

Drop unused labels.

> +      compatible = "microchip,lan966x-switch";
> +      reg =  <0 0x401000>,
> +             <0x10004000 0x7fc000>,
> +             <0x11010000 0xaf0000>;
> +      reg-names = "cpu", "devices", "gcb";
> +      interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
> +      interrupt-names = "xtr";
> +      ethernet-ports {
> +        #address-cells = <1>;
> +        #size-cells = <0>;
> +
> +        port0: port@0 {
> +          reg = <0>;
> +          phy-handle = <&phy0>;
> +          phy-mode = "gmii";
> +        };
> +      };
> +    };
> +
> +...
> +#  vim: set ts=2 sw=2 sts=2 tw=80 et cc=80 ft=yaml :

Ummm, no.

> -- 
> 2.31.1
> 
> 

^ permalink raw reply	[flat|nested] 30+ messages in thread

end of thread, other threads:[~2021-09-23 12:53 UTC | newest]

Thread overview: 30+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-09-20  9:52 [RFC PATCH net-next 00/12] Add lan966x driver Horatiu Vultur
2021-09-20  9:52 ` [RFC PATCH net-next 01/12] net: mdio: mscc-miim: Fix the mdio controller Horatiu Vultur
2021-09-20 11:52   ` Andrew Lunn
2021-09-22  8:24     ` Horatiu Vultur
2021-09-20  9:52 ` [RFC PATCH net-next 02/12] net: phy: mchp: Add support for LAN8804 PHY Horatiu Vultur
2021-09-20 10:00   ` Alexandre Belloni
2021-09-20 11:59   ` Andrew Lunn
2021-09-22  8:35     ` Horatiu Vultur
2021-09-20  9:52 ` [RFC PATCH net-next 03/12] phy: Add lan966x ethernet serdes PHY driver Horatiu Vultur
2021-09-20 13:42   ` Russell King (Oracle)
2021-09-22 10:04     ` Horatiu Vultur
2021-09-23 12:44   ` Rob Herring
2021-09-20  9:52 ` [RFC PATCH net-next 04/12] dt-bindings: reset: Add lan966x switch reset bindings Horatiu Vultur
2021-09-23 12:49   ` Rob Herring
2021-09-20  9:52 ` [RFC PATCH net-next 05/12] reset: lan966x: Add switch reset driver Horatiu Vultur
2021-09-20 12:11   ` Andrew Lunn
2021-09-22  9:59     ` Horatiu Vultur
2021-09-20  9:52 ` [RFC PATCH net-next 06/12] dt-bindings: reset: Add lan966x power reset bindings Horatiu Vultur
2021-09-20  9:52 ` [RFC PATCH net-next 07/12] power: reset: Add lan966x power reset driver Horatiu Vultur
2021-09-20 12:15   ` Andrew Lunn
2021-09-20  9:52 ` [RFC PATCH net-next 08/12] dt-bindings: net: lan966x: Add lan966x-switch bindings Horatiu Vultur
2021-09-23 12:53   ` Rob Herring
2021-09-20  9:52 ` [RFC PATCH net-next 09/12] net: lan966x: add the basic lan966x driver Horatiu Vultur
2021-09-20 13:46   ` Russell King (Oracle)
2021-09-20  9:52 ` [RFC PATCH net-next 10/12] net: lan966x: add port module support Horatiu Vultur
2021-09-20 13:54   ` Russell King (Oracle)
2021-09-23  8:02     ` Horatiu Vultur
2021-09-20  9:52 ` [RFC PATCH net-next 11/12] net: lan966x: add mactable support Horatiu Vultur
2021-09-20  9:52 ` [RFC PATCH net-next 12/12] net: lan966x: add ethtool configuration and statistics Horatiu Vultur
2021-09-20 20:31   ` Jakub Kicinski

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).