From 900b0ec574e271f5c6635acce741c677a479ab58 Mon Sep 17 00:00:00 2001
From: Ondrej Jirman <megi@xff.cz>
Date: Thu, 18 Jul 2024 17:43:03 +0200
Subject: [PATCH 467/484] net: ethernet: stmmac: Add support for Rockchip
 RV1106

This chip has internal PHY RK630 and it needs to be powered up before
use.

Signed-off-by: Ondrej Jirman <megi@xff.cz>
---
 .../net/ethernet/stmicro/stmmac/dwmac-rk.c    | 95 +++++++++++++++++++
 1 file changed, 95 insertions(+)

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
index 700858ff6f7c..a7a46ace1b43 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
@@ -20,6 +20,7 @@
 #include <linux/mfd/syscon.h>
 #include <linux/regmap.h>
 #include <linux/pm_runtime.h>
+#include <linux/nvmem-consumer.h>
 
 #include "stmmac_platform.h"
 
@@ -68,6 +69,7 @@ struct rk_priv_data {
 	bool clk_enabled;
 	bool clock_input;
 	bool integrated_phy;
+	unsigned char bgs;
 
 	struct clk_bulk_data *clks;
 	int num_clks;
@@ -1409,6 +1411,94 @@ static const struct rk_gmac_ops rk3588_ops = {
 	},
 };
 
+#define RV1106_VOGRF_GMAC_CLK_CON               0X60004
+
+#define RV1106_VOGRF_MACPHY_RMII_MODE           GRF_BIT(0)
+#define RV1106_VOGRF_GMAC_CLK_RMII_DIV2         GRF_BIT(2)
+#define RV1106_VOGRF_GMAC_CLK_RMII_DIV20        GRF_CLR_BIT(2)
+
+#define RV1106_VOGRF_MACPHY_CON0                0X60028
+#define RV1106_VOGRF_MACPHY_CON1                0X6002C
+
+static void rv1106_set_to_rmii(struct rk_priv_data *bsp_priv)
+{
+	regmap_write(bsp_priv->grf, RV1106_VOGRF_GMAC_CLK_CON,
+		     RV1106_VOGRF_MACPHY_RMII_MODE |
+		     RV1106_VOGRF_GMAC_CLK_RMII_DIV2);
+}
+
+static void rv1106_set_rmii_speed(struct rk_priv_data *bsp_priv, int speed)
+{
+	struct device *dev = &bsp_priv->pdev->dev;
+	unsigned int val = 0;
+
+	if (speed == 10) {
+		val = RV1106_VOGRF_GMAC_CLK_RMII_DIV20;
+	} else if (speed == 100) {
+		val = RV1106_VOGRF_GMAC_CLK_RMII_DIV2;
+	} else {
+		dev_err(dev, "unknown speed value for RMII! speed=%d", speed);
+		return;
+	}
+
+	regmap_write(bsp_priv->grf, RV1106_VOGRF_GMAC_CLK_CON, val);
+}
+
+#define RK_FEPHY_BGS                    HIWORD_UPDATE(0x0, 0xf, 0)
+#define RK_FEPHY_BGS_MAX                7
+
+static void rv1106_integrated_phy_powerup(struct rk_priv_data *priv)
+{
+	struct device *dev = &priv->pdev->dev;
+	const unsigned int bgs_increment = 2;
+	unsigned int bgs = priv->bgs;
+
+	dev_info(dev, "%s: poweron phy\n", __func__);
+
+	reset_control_assert(priv->phy_reset);
+	udelay(20);
+	regmap_write(priv->grf, RV1106_VOGRF_MACPHY_CON0,
+		     RK_FEPHY_POWERUP |
+		     RK_FEPHY_INTERNAL_RMII_SEL |
+		     RK_FEPHY_24M_CLK_SEL |
+		     RK_FEPHY_PHY_ID);
+
+	if (bgs > (RK_FEPHY_BGS_MAX - bgs_increment) &&
+	    bgs <= RK_FEPHY_BGS_MAX) {
+		bgs = HIWORD_UPDATE(RK_FEPHY_BGS_MAX, 0xf, 0);
+	} else {
+		bgs += bgs_increment;
+		bgs &= 0xf;
+		bgs = HIWORD_UPDATE(bgs, 0xf, 0);
+	}
+
+	regmap_write(priv->grf, RV1106_VOGRF_MACPHY_CON1, bgs);
+	usleep_range(10 * 1000, 12 * 1000);
+	reset_control_deassert(priv->phy_reset);
+	usleep_range(50 * 1000, 60 * 1000);
+
+	rk_gmac_integrated_ephy_powerup(priv);
+}
+
+static void rv1106_integrated_phy_powerdown(struct rk_priv_data *priv)
+{
+	struct device *dev = &priv->pdev->dev;
+
+	dev_info(dev, "%s: powerdown phy\n", __func__);
+
+	regmap_write(priv->grf, RV1106_VOGRF_MACPHY_CON0,
+		     RK_FEPHY_SHUTDOWN);
+
+	rk_gmac_integrated_ephy_powerdown(priv);
+}
+
+static const struct rk_gmac_ops rv1106_ops = {
+	.set_to_rmii = rv1106_set_to_rmii,
+	.set_rmii_speed = rv1106_set_rmii_speed,
+	.integrated_phy_powerup = rv1106_integrated_phy_powerup,
+	.integrated_phy_powerdown = rv1106_integrated_phy_powerdown,
+};
+
 #define RV1108_GRF_GMAC_CON0		0X0900
 
 /* RV1108_GRF_GMAC_CON0 */
@@ -1740,6 +1830,10 @@ static struct rk_priv_data *rk_gmac_setup(struct platform_device *pdev,
 		bsp_priv->rx_delay = value;
 	}
 
+	ret = nvmem_cell_read_u8(dev, "bgs", &bsp_priv->bgs);
+	if (ret && ret != -ENOENT)
+		return ERR_PTR(dev_err_probe(dev, ret, "failed to read bgs cell\n"));
+
 	bsp_priv->grf = syscon_regmap_lookup_by_phandle(dev->of_node,
 							"rockchip,grf");
 	if (IS_ERR(bsp_priv->grf)) {
@@ -1999,6 +2093,7 @@ static const struct of_device_id rk_gmac_dwmac_match[] = {
 	{ .compatible = "rockchip,rk3568-gmac", .data = &rk3568_ops },
 	{ .compatible = "rockchip,rk3576-gmac", .data = &rk3576_ops },
 	{ .compatible = "rockchip,rk3588-gmac", .data = &rk3588_ops },
+	{ .compatible = "rockchip,rv1106-gmac", .data = &rv1106_ops },
 	{ .compatible = "rockchip,rv1108-gmac", .data = &rv1108_ops },
 	{ .compatible = "rockchip,rv1126-gmac", .data = &rv1126_ops },
 	{ }
-- 
2.49.0

