From 15e70eb335652f61fdf1b645736f7782b88368c0 Mon Sep 17 00:00:00 2001
From: Lei Wei <quic_leiwei@quicinc.com>
Date: Fri, 1 Mar 2024 13:36:26 +0800
Subject: [PATCH] net: ethernet: qualcomm: Add PPE port MAC address and EEE
 functions

Add PPE port MAC address set and EEE set API functions which
will be used by netdev ops and ethtool.

Change-Id: Id2b3b06ae940b3b6f5227d927316329cdf3caeaa
Signed-off-by: Lei Wei <quic_leiwei@quicinc.com>
Alex G: use struct ethtool_keee instead of ethtool_eee
Signed-off-by: Alexandru Gagniuc <mr.nuke.me@gmail.com>
---
 drivers/net/ethernet/qualcomm/ppe/ppe_port.c | 75 ++++++++++++++++++++
 drivers/net/ethernet/qualcomm/ppe/ppe_port.h |  3 +
 drivers/net/ethernet/qualcomm/ppe/ppe_regs.h | 29 ++++++++
 3 files changed, 107 insertions(+)

--- a/drivers/net/ethernet/qualcomm/ppe/ppe_port.c
+++ b/drivers/net/ethernet/qualcomm/ppe/ppe_port.c
@@ -462,6 +462,81 @@ void ppe_port_get_stats64(struct ppe_por
 	}
 }
 
+/**
+ * ppe_port_set_mac_address() - Set PPE port MAC address
+ * @ppe_port: PPE port
+ * @addr: MAC address
+ *
+ * Description: Set MAC address for the given PPE port.
+ *
+ * Return: 0 upon success or a negative error upon failure.
+ */
+int ppe_port_set_mac_address(struct ppe_port *ppe_port, const u8 *addr)
+{
+	struct ppe_device *ppe_dev = ppe_port->ppe_dev;
+	int port = ppe_port->port_id;
+	u32 reg, val;
+	int ret;
+
+	if (ppe_port->mac_type == PPE_MAC_TYPE_GMAC) {
+		reg = PPE_PORT_GMAC_ADDR(port);
+		val = (addr[5] << 8) | addr[4];
+		ret = regmap_write(ppe_dev->regmap, reg + GMAC_GOL_ADDR0_ADDR, val);
+		if (ret)
+			return ret;
+
+		val = (addr[0] << 24) | (addr[1] << 16) |
+		      (addr[2] << 8) | addr[3];
+		ret = regmap_write(ppe_dev->regmap, reg + GMAC_GOL_ADDR1_ADDR, val);
+		if (ret)
+			return ret;
+	} else {
+		reg = PPE_PORT_XGMAC_ADDR(port);
+		val = (addr[5] << 8) | addr[4] | XGMAC_ADDR_EN;
+		ret = regmap_write(ppe_dev->regmap, reg + XGMAC_ADDR0_H_ADDR, val);
+		if (ret)
+			return ret;
+
+		val = (addr[3] << 24) | (addr[2] << 16) |
+		      (addr[1] << 8) | addr[0];
+		ret = regmap_write(ppe_dev->regmap, reg + XGMAC_ADDR0_L_ADDR, val);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+/**
+ * ppe_port_set_mac_eee() - Set EEE configuration for PPE port MAC
+ * @ppe_port: PPE port
+ * @eee: EEE settings
+ *
+ * Description: Set port MAC EEE settings for the given PPE port.
+ *
+ * Return: 0 upon success or a negative error upon failure.
+ */
+int ppe_port_set_mac_eee(struct ppe_port *ppe_port, struct ethtool_keee *eee)
+{
+	struct ppe_device *ppe_dev = ppe_port->ppe_dev;
+	int port = ppe_port->port_id;
+	u32 val;
+	int ret;
+
+	ret = regmap_read(ppe_dev->regmap, PPE_LPI_EN_ADDR, &val);
+	if (ret)
+		return ret;
+
+	if (eee->tx_lpi_enabled)
+		val |= PPE_LPI_PORT_EN(port);
+	else
+		val &= ~PPE_LPI_PORT_EN(port);
+
+	ret = regmap_write(ppe_dev->regmap, PPE_LPI_EN_ADDR, val);
+
+	return ret;
+}
+
 /* PPE port and MAC reset */
 static int ppe_port_mac_reset(struct ppe_port *ppe_port)
 {
--- a/drivers/net/ethernet/qualcomm/ppe/ppe_port.h
+++ b/drivers/net/ethernet/qualcomm/ppe/ppe_port.h
@@ -8,6 +8,7 @@
 
 #include <linux/phylink.h>
 
+struct ethtool_keee;
 struct rtnl_link_stats64;
 
 /**
@@ -86,4 +87,6 @@ void ppe_port_get_strings(struct ppe_por
 void ppe_port_get_ethtool_stats(struct ppe_port *ppe_port, u64 *data);
 void ppe_port_get_stats64(struct ppe_port *ppe_port,
 			  struct rtnl_link_stats64 *s);
+int ppe_port_set_mac_address(struct ppe_port *ppe_port, const u8 *addr);
+int ppe_port_set_mac_eee(struct ppe_port *ppe_port, struct ethtool_keee *eee);
 #endif
--- a/drivers/net/ethernet/qualcomm/ppe/ppe_regs.h
+++ b/drivers/net/ethernet/qualcomm/ppe/ppe_regs.h
@@ -20,6 +20,16 @@
 #define PPE_PORT5_SEL_PCS1			BIT(4)
 #define PPE_PORT_SEL_XGMAC(x)			(BIT(8) << ((x) - 1))
 
+/* PPE port LPI enable register */
+#define PPE_LPI_EN_ADDR				0x400
+#define PPE_LPI_PORT1_EN			BIT(0)
+#define PPE_LPI_PORT2_EN			BIT(1)
+#define PPE_LPI_PORT3_EN			BIT(2)
+#define PPE_LPI_PORT4_EN			BIT(3)
+#define PPE_LPI_PORT5_EN			BIT(4)
+#define PPE_LPI_PORT6_EN			BIT(5)
+#define PPE_LPI_PORT_EN(x)			(BIT(0) << ((x) - 1))
+
 /* PPE scheduler configurations for buffer manager block. */
 #define PPE_BM_SCH_CTRL_ADDR			0xb000
 #define PPE_BM_SCH_CTRL_INC			4
@@ -592,6 +602,17 @@
 #define GMAC_SPEED_100				1
 #define GMAC_SPEED_1000				2
 
+/* GMAC MAC address register */
+#define GMAC_GOL_ADDR0_ADDR			0x8
+#define GMAC_ADDR_BYTE5				GENMASK(15, 8)
+#define GMAC_ADDR_BYTE4				GENMASK(7, 0)
+
+#define GMAC_GOL_ADDR1_ADDR			0xC
+#define GMAC_ADDR_BYTE0				GENMASK(31, 24)
+#define GMAC_ADDR_BYTE1				GENMASK(23, 16)
+#define GMAC_ADDR_BYTE2				GENMASK(15, 8)
+#define GMAC_ADDR_BYTE3				GENMASK(7, 0)
+
 /* GMAC control register */
 #define GMAC_CTRL_ADDR				0x18
 #define GMAC_TX_THD_M				GENMASK(27, 24)
@@ -717,6 +738,14 @@
 #define XGMAC_RX_FLOW_CTRL_ADDR			0x90
 #define XGMAC_RXFCEN				BIT(0)
 
+/* XGMAC MAC address register */
+#define XGMAC_ADDR0_H_ADDR			0x300
+#define XGMAC_ADDR_EN				BIT(31)
+#define XGMAC_ADDRH				GENMASK(15, 0)
+
+#define XGMAC_ADDR0_L_ADDR			0x304
+#define XGMAC_ADDRL				GENMASK(31, 0)
+
 /* XGMAC management counters control register */
 #define XGMAC_MMC_CTRL_ADDR			0x800
 #define XGMAC_MCF				BIT(3)
